/* Generates (and regenerates) a Dominion JemHadar Fighter at each object specified from the arguments. Usage: [-i ] [-d ] [obj#_num...] */ #include #include #include #include #include #include "../include/swserv-plugins.h" /* * Object Reference: * * Relates each fighter to a reference object. This is used to * check when a fighter 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 fighter. */ typedef struct { int ref_obj_num, /* The reference object */ obj_num; /* The fighter object */ float distance; /* How far away in real units */ } ObjRef; typedef struct { ObjRef **objref_list; int nobjrefs; time_t next_update, /* In seconds */ update_int; } Core; #define CORE(p) ((Core *)(p)) static int FighterIsPositionValid( SWServContext *ctx, int n ); static void FighterUpdate( SWServContext *ctx, const char *opm_name ); #define FIGHTER_DEF_NAME "Jemhadar Fighter" #define FIGHTER_DEF_OPM_NAME "Jemhadar Fighter AI" #define FIGHTER_DEF_EMPIRE "DOM" #define FIGHTER_DEF_UPDATE_INVERVAL (10 * 60) /* In seconds */ #define USAGE_MESG "\ Usage: [-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') : TRUE) #ifndef PI # define PI 3.141592654 #endif /* * Checks if the object's position is valid, that is if there are * no other objects in contact with it. */ static int FighterIsPositionValid( 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); } /* * Checks all object references to see if any fighters have been * destroyed and regenerates them when needed. * * If the refering object has been destroyed then the object * reference is removed from the list. * * The opm_name specifies the name of the object parameter model * for the fighter. */ static void FighterUpdate( SWServContext *ctx, const char *opm_name ) { Core *core = CORE(SWServGetData(ctx)); int i, obj_num, opm_num = SWServOPMGetByName(ctx, opm_name); xsw_object_struct *obj, *ref_obj; ObjRef *objref; if(opm_num < 0) { char *s = (char *)malloc(STRLEN(FIGHTER_DEF_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_update); /* Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; /* This fighter still there? */ if(!SWServObjectIsGarbage(ctx, objref->obj_num)) continue; /* The fighter for this object no longer exists, so create * a new fighter for this object */ /* Get the reference object */ ref_obj = SWServObjectGetPointer( ctx, objref->ref_obj_num ); if(ref_obj == NULL) { /* This reference object no longer exists, so delete * this reference */ free(objref); core->objref_list[i] = NULL; continue; } /* Create a new fighter */ objref->obj_num = obj_num = SWServObjectCreate( ctx, SW_OBJ_TYPE_CONTROLLED ); obj = SWServObjectGetPointer(ctx, obj_num); ref_obj = SWServObjectGetPointer(ctx, objref->ref_obj_num); if((obj != NULL) && (ref_obj != NULL)) { int n; float c, theta; 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(FighterIsPositionValid(ctx, obj_num)) break; } strncpy(obj->name, FIGHTER_DEF_NAME, sizeof(obj->name)); obj->name[sizeof(obj->name) - 1] = '\0'; strncpy(obj->empire, FIGHTER_DEF_EMPIRE, sizeof(obj->empire)); obj->empire[sizeof(obj->empire) - 1] = '\0'; SWServObjectSyncConnections(ctx, obj_num, 1); } } } /* * SWServ Plugin hail notify. */ SWPLUGIN_HAIL_NOTIFY_FUNCRTN SWPLUGIN_HAIL_NOTIFY_FUNC( int con_num, int obj_num, int tar_obj_num, int channel, const char *msg, SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); int i; float com_range = SWServSysparmGetF(ctx, "com_range"); xsw_object_struct *obj, *tar_obj; ObjRef *objref; if(core == NULL) return; /* Ignore general hails and messages */ if((tar_obj_num < 0) || (msg != NULL)) return; /* Skip itself */ if(obj_num == tar_obj_num) return; tar_obj = SWServObjectGetPointer(ctx, tar_obj_num); if(tar_obj == NULL) return; /* Hailed one of our fighters? */ /* Iterate through the object references list */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; if(objref->obj_num != tar_obj_num) continue; if(!SWServObjectsInRange( ctx, obj_num, tar_obj_num, com_range )) break; obj = SWServObjectGetPointer(ctx, obj_num); if(obj == NULL) break; /* Different empires? */ if(strcasecmp(tar_obj->empire, obj->empire)) { char *s = (char *)malloc( strlen(tar_obj->empire) + 128 ); sprintf( s, "You have violated %s territory, you will be destroyed!", tar_obj->empire ); SWServObjectSendMessage( ctx, tar_obj_num, obj_num, obj->com_channel, s ); free(s); } } } /* * 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 fighter 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.5; Core *core = CORE(calloc(1, sizeof(Core))); if(core == NULL) return(1); core->objref_list = NULL; core->nobjrefs = 0; core->update_int = FIGHTER_DEF_UPDATE_INVERVAL; core->next_update = 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" ); free(core); return(1); } else if(!strcasecmp(arg, "--interval") || !strcasecmp(arg, "-interval") || !strcasecmp(arg, "--int") || !strcasecmp(arg, "-int") || !strcasecmp(arg, "-i") ) { /* In seconds */ i++; if(i < argc) core->update_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->ref_obj_num = obj_num; objref->obj_num = -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" ); free(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); /* Time to update? */ if(core->next_update <= t) { FighterUpdate( ctx, FIGHTER_DEF_OPM_NAME /* Fighter OPM name */ ); core->next_update = t + core->update_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 fighter objects and delete all object * references */ for(i = 0; i < core->nobjrefs; i++) { objref = core->objref_list[i]; if(objref == NULL) continue; SWServObjectRecycle(ctx, objref->obj_num); free(objref); } free(core->objref_list); free(core); SWServSetData(ctx, NULL); }