/* Generates (and regenerates) borg cubes at each object specified from the arguments. Usage: [-opm ] [-n ] [-e ] [-i ] [-d ] [obj#_num...] */ #include #include #include #include #include #include "../include/swserv-plugins.h" /* * Object Reference: * * Relates each borg to a reference object. This is used to check * when a borg has been destroyed (when it has become garbage) and * to respawn it. It also can be used to check if the reference * object has been destroyed (when it has become garbage) and to no * longer respawn a borg. */ typedef struct { int obj_num, /* The borg object */ ref_obj_num, /* The reference object */ locked_on; /* Previous locked on object */ float distance; /* How far away in real units */ } ObjRef; typedef struct { char *opm_name, *name, *empire; ObjRef **objref_list; int nobjrefs; time_t next_regenerate, /* In seconds */ regenerate_int, next_ai, ai_int; } Core; #define CORE(p) ((Core *)(p)) static Core *BorgCoreNew(void); static void BorgCoreDelete(Core *core); static int BorgIsPositionValid( SWServContext *ctx, int n ); static void BorgAnnounceYouWillBeAssimilated( SWServContext *ctx, int obj_num, /* Borg */ int tar_obj_num, /* Target */ int channel /* Com channel */ ); static void BorgRegenerate( SWServContext *ctx, ObjRef *objref, const int opm_num ); static void BorgUpdateRegenerate(SWServContext *ctx); static void BorgUpdateAI(SWServContext *ctx); #define BORG_DEF_NAME "Borg Cube" #define BORG_DEF_OPM_NAME "Borg Cube AI" #define BORG_DEF_REGENERATE_INT (10 * 60) /* In seconds */ #define BORG_DEF_AI_INT (5) #define USAGE_MESG "\ Usage: [-opm ] [-n ] [-e ]\ [-i ] [-d ]\ [obj#_num...]" #define ATOI(s) (((s) != NULL) ? atoi(s) : 0) #define ATOL(s) (((s) != NULL) ? atol(s) : 0) #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f) #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define STRLEN(s) (((s) != NULL) ? strlen(s) : 0) #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : 1) #ifndef PI # define PI 3.141592654 #endif static Core *BorgCoreNew(void) { return(CORE(calloc(1, sizeof(Core)))); } static void BorgCoreDelete(Core *core) { int i; if(core == NULL) return; free(core->opm_name); free(core->name); free(core->empire); for(i = 0; i < core->nobjrefs; i++) free(core->objref_list[i]); free(core->objref_list); free(core); } /* * Checks if the object's position is valid, that is if there are * no other objects in contact with it. */ static int BorgIsPositionValid( SWServContext *ctx, int n ) { const int total = SWServTotalObjects(ctx); int i; xsw_object_struct *obj; for(i = 0; i < total; i++) { obj = SWServObjectGetPointer(ctx, i); if(obj == NULL) continue; if(obj->type <= SW_OBJ_TYPE_GARBAGE) continue; if(i == n) continue; if(SWServObjectsInContact(ctx, i, n)) return(0); } return(1); } /* * Sends the "you will be assimilated" message from the Borg * object specified by obj_num to the target object specified by * tar_obj_num. */ static void BorgAnnounceYouWillBeAssimilated( SWServContext *ctx, int obj_num, /* Borg */ int tar_obj_num, /* Target */ int channel /* Com channel */ ) { SWServObjectSendMessage( ctx, obj_num, /* Sender */ tar_obj_num, /* Recipient */ channel, "We are the borg..." ); SWServObjectSendMessage( ctx, obj_num, tar_obj_num, channel, "Your technology and distinctiveness will be added to our own..." ); SWServObjectSendMessage( ctx, obj_num, tar_obj_num, channel, "You will be assimilated, resistance is futile." ); } /* * Recreates a borg object at the object at the specified objref. * * Does not check if the objref's object already exists or not. * * The reference object must be checked for existance prior to * calling this function. */ static void BorgRegenerate( SWServContext *ctx, ObjRef *objref, const int opm_num ) { Core *core = CORE(SWServGetData(ctx)); int n, obj_num; float c, theta; xsw_object_struct *obj, *ref_obj; /* Create a new Borg */ objref->obj_num = obj_num = SWServObjectCreate( ctx, SW_OBJ_TYPE_CONTROLLED ); obj = SWServObjectGetPointer(ctx, obj_num); /* Get the reference object */ ref_obj = SWServObjectGetPointer(ctx, objref->ref_obj_num); if((obj == NULL) || (ref_obj == NULL)) return; /* Model the new Borg */ SWServOPMModelObject(ctx, opm_num, obj_num); obj->owner = ref_obj->owner; obj->sect_x = ref_obj->sect_x; obj->sect_y = ref_obj->sect_y; obj->sect_z = ref_obj->sect_z; for(n = 0; n < 100; n++) { c = (float)rand() / (float)RAND_MAX; theta = 2.0 * PI * c; obj->x = ref_obj->x + ((float)sin((double)theta) * objref->distance); obj->y = ref_obj->y + ((float)cos((double)theta) * objref->distance); obj->z = ref_obj->z; if(BorgIsPositionValid(ctx, obj_num)) break; } if(!STRISEMPTY(core->name)) { strncpy(obj->name, core->name, sizeof(obj->name)); obj->name[sizeof(obj->name) - 1] = '\0'; } if(!STRISEMPTY(core->empire)) { strncpy(obj->empire, core->empire, sizeof(obj->empire)); obj->empire[sizeof(obj->empire) - 1] = '\0'; } /* Reset the objref's locked on object */ objref->locked_on = -1; SWServObjectSyncConnections(ctx, obj_num, 1); } /* * Checks all object references to see if any borgs have been * destroyed and regenerates them as needed. * * If the refering object has been destroyed then the object * reference is removed from the list. */ static void BorgUpdateRegenerate(SWServContext *ctx) { Core *core = CORE(SWServGetData(ctx)); const char *opm_name = core->opm_name; const int opm_num = SWServOPMGetByName(ctx, opm_name); int i, obj_num; ObjRef *objref; if(opm_num < 0) { char *s = (char *)malloc(STRLEN(opm_name) + 80); sprintf( s, "OPM `%s' not defined.\n", opm_name ); SWServPrintError(ctx, s); free(s); return; } /* Initialize random number generator */ srand((unsigned int)core->next_regenerate); /* Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; /* This Borg no longer exists? */ obj_num = objref->obj_num; if(SWServObjectIsGarbage(ctx, obj_num)) { /* Reference object no longer exists? */ if(SWServObjectGetPointer( ctx, objref->ref_obj_num ) == NULL) { /* Delete this objref */ free(objref); core->objref_list[i] = NULL; continue; } /* Recreate the Borg for this objref */ BorgRegenerate(ctx, objref, opm_num); } } } /* * Updates each Borg object in the object references. */ static void BorgUpdateAI(SWServContext *ctx) { Core *core = CORE(SWServGetData(ctx)); int i, obj_num; xsw_object_struct *obj; ObjRef *objref; /* Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; obj_num = objref->obj_num; obj = SWServObjectGetPointer(ctx, obj_num); if(obj == NULL) continue; /* Changed locked on object? */ if((obj->locked_on != objref->locked_on) && (obj->locked_on > -1) ) { xsw_object_struct *tar_obj = SWServObjectGetPointer(ctx, obj->locked_on); if(tar_obj != NULL) BorgAnnounceYouWillBeAssimilated( ctx, obj_num, /* Borg */ obj->locked_on, /* Target */ tar_obj->com_channel ); objref->locked_on = obj->locked_on; } } } /* * SWServ Plugin hail notify. */ SWPLUGIN_HAIL_NOTIFY_FUNCRTN SWPLUGIN_HAIL_NOTIFY_FUNC( int con_num, int send_obj_num, int recv_obj_num, int channel, const char *msg, SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); int i; const float com_range = SWServSysparmGetF(ctx, "com_range"); xsw_object_struct *send_obj, *recv_obj; ObjRef *objref; if(core == NULL) return; /* Ignore general hails and messages */ if((recv_obj_num < 0) || (msg != NULL)) return; /* Skip itself */ if(send_obj_num == recv_obj_num) return; recv_obj = SWServObjectGetPointer(ctx, recv_obj_num); if(recv_obj == NULL) return; /* Hailed one of our borgs? * * Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; /* Is this object not one of our borgs? */ if(objref->obj_num != recv_obj_num) continue; /* Out of com range? */ if(!SWServObjectsInRange( ctx, send_obj_num, recv_obj_num, com_range )) break; /* Get the pointer to the object sending the hail */ send_obj = SWServObjectGetPointer(ctx, send_obj_num); if(send_obj == NULL) break; /* Different empires? */ if(strcasecmp(send_obj->empire, recv_obj->empire)) { /* Adjust to the sender's com channel */ recv_obj->com_channel = channel; /* Send response */ BorgAnnounceYouWillBeAssimilated( ctx, recv_obj_num, /* Borg */ send_obj_num, /* Target */ channel ); } } } /* * SWServ Plugin destroy notify. */ SWPLUGIN_DESTROY_NOTIFY_FUNCRTN SWPLUGIN_DESTROY_NOTIFY_FUNC( int reason, int destroyed_obj_num, int destroyer_obj_num, int destroyer_obj_owner_num, SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); int i; ObjRef *objref; if(core == NULL) return; /* Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; /* This Borg destroyed? */ if(objref->obj_num == destroyed_obj_num) { objref->obj_num = -1; break; } } } /* * SWServ Plugin initialize. */ SWPLUGIN_INIT_FUNCRTN SWPLUGIN_INIT_FUNC( int argc, char **argv, int con_num, SWServContext *ctx ) { int i; const char *arg; float distance = 1.5f; Core *core = BorgCoreNew(); if(core == NULL) return(1); core->opm_name = STRDUP(BORG_DEF_OPM_NAME); core->name = STRDUP(BORG_DEF_NAME); core->empire = NULL; core->objref_list = NULL; core->nobjrefs = 0; core->regenerate_int = BORG_DEF_REGENERATE_INT; core->next_regenerate = SWServCurrentTimeSeconds(ctx); core->ai_int = BORG_DEF_AI_INT; core->next_ai = SWServCurrentTimeSeconds(ctx); SWServSetData(ctx, core); for(i = 0; i < argc; i++) { arg = argv[i]; if(arg == NULL) continue; if(!strcasecmp(arg, "--help") || !strcasecmp(arg, "-help") || !strcasecmp(arg, "--h") || !strcasecmp(arg, "-h") ) { if(con_num > -1) SWServConNotify( ctx, con_num, USAGE_MESG ); else SWServPrint( ctx, USAGE_MESG "\n" ); BorgCoreDelete(core); return(1); } else if(!strcasecmp(arg, "--opm_name") || !strcasecmp(arg, "-opm_name") || !strcasecmp(arg, "--opm") || !strcasecmp(arg, "-opm") ) { i++; if(i < argc) { free(core->opm_name); core->opm_name = STRDUP(argv[i]); } } else if(!strcasecmp(arg, "--name") || !strcasecmp(arg, "-name") || !strcasecmp(arg, "--n") || !strcasecmp(arg, "-n") ) { i++; if(i < argc) { free(core->name); core->name = STRDUP(argv[i]); } } else if(!strcasecmp(arg, "--empire") || !strcasecmp(arg, "-empire") || !strcasecmp(arg, "--e") || !strcasecmp(arg, "-e") ) { i++; if(i < argc) { free(core->empire); core->empire = STRDUP(argv[i]); } } else if(!strcasecmp(arg, "--interval") || !strcasecmp(arg, "-interval") || !strcasecmp(arg, "--int") || !strcasecmp(arg, "-int") || !strcasecmp(arg, "-i") ) { /* In seconds */ i++; if(i < argc) core->regenerate_int = MAX(atol(argv[i]), 0l); } else if(!strcasecmp(arg, "--distance") || !strcasecmp(arg, "-distance") || !strcasecmp(arg, "--d") || !strcasecmp(arg, "-d") ) { /* In real units */ i++; if(i < argc) distance = MAX(atof(argv[i]), 0.0); } else { /* All else assume object number */ int n; const int obj_num = ATOI( (*arg == '#') ? (arg + 1) : arg ); ObjRef *objref = (ObjRef *)calloc( 1, sizeof(ObjRef) ); objref->obj_num = -1; objref->ref_obj_num = obj_num; objref->locked_on = -1; objref->distance = distance; n = core->nobjrefs; core->nobjrefs = n + 1; core->objref_list = (ObjRef **)realloc( core->objref_list, core->nobjrefs * sizeof(ObjRef *) ); core->objref_list[n] = objref; } } /* No reference objects spcified? */ if(core->nobjrefs <= 0) { if(con_num > -1) SWServConNotify( ctx, con_num, USAGE_MESG ); else SWServPrintError( ctx, USAGE_MESG "\n" ); BorgCoreDelete(core); return(1); } return(0); } /* * SWServ Plugin manage. */ SWPLUGIN_MANAGE_FUNCRTN SWPLUGIN_MANAGE_FUNC( SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); const time_t t = SWServCurrentTimeSeconds(ctx); if(core == NULL) return(1); /* Update regenerate? */ if(core->next_regenerate <= t) { BorgUpdateRegenerate(ctx); core->next_regenerate = t + core->regenerate_int; } /* Update ai? */ if(core->next_ai <= t) { BorgUpdateAI(ctx); core->next_ai = t + core->ai_int; } return(0); } /* * SWServ Plugin shutdown. */ SWPLUGIN_SHUTDOWN_FUNCRTN SWPLUGIN_SHUTDOWN_FUNC( SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); int i; ObjRef *objref; if(core == NULL) return; /* Recycle all Borg objects */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; SWServObjectRecycle(ctx, objref->obj_num); } BorgCoreDelete(core); SWServSetData(ctx, NULL); }