/* Generates (and regenerates) a freighter at the first object and instructs it to fly to each subsequent object until it goes back to the initial object, then repeats infinately. Usage: [-i ] [-r ] [-d ] [-opm ] [-n ] [-e ] [obj#_num...] */ #include #include #include #include #include #include "../include/swserv-plugins.h" typedef struct { time_t next_update, /* All these are in seconds */ update_int, next_regenerate, regenerate_int; float distance; /* Intercept destination radius * in real units */ char *opm_name; char *name; char *empire; int obj_num; /* The freighter object */ int *dest_obj_list; int cur_dest_obj, /* Index in dest_obj_list */ ndest_objs; } Core; #define CORE(p) ((Core *)(p)) static void FreighterUpdate(SWServContext *ctx); static void FreighterRegenerate(SWServContext *ctx); static void CoreDelete(Core *core); #define FREIGHTER_DEF_NAME "DY300 Freighter" #define FREIGHTER_DEF_OPM_NAME "DY300 Freighter AI" #define FREIGHTER_DEF_EMPIRE "IND" #define FREIGHTER_DEF_UPDATE_INT 3 /* In seconds */ #define FREIGHTER_DEF_REGENERATE_INT (5 * 60) /* In seconds */ #define USAGE_MESG "\ Usage: [-i ] [-r ] [-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) ? (int)strlen(s) : 0) #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : 1) #ifndef PI # define PI 3.141592654 #endif /* * Creates or recreates the freighter at the first destination * object as needed. * * Checks if the freighter has reached the current destination * object and if so then changes its intercept to go to the next * destination object. */ static void FreighterUpdate(SWServContext *ctx) { int ref_obj_num; xsw_object_struct *ref_obj; Core *core = CORE(SWServGetData(ctx)); int obj_num = core->obj_num; xsw_object_struct *obj = SWServObjectGetPointer(ctx, obj_num); if(obj == NULL) return; /* Get the current destination object */ ref_obj_num = ((core->cur_dest_obj >= 0) && (core->cur_dest_obj < core->ndest_objs)) ? core->dest_obj_list[core->cur_dest_obj] : -1; ref_obj = SWServObjectGetPointer(ctx, ref_obj_num); /* Current destination object no longer valid? */ if(ref_obj == NULL) { /* Set intercept to the next destination object */ core->cur_dest_obj++; if(core->cur_dest_obj >= core->ndest_objs) core->cur_dest_obj = 0; ref_obj_num = ((core->cur_dest_obj >= 0) && (core->cur_dest_obj < core->ndest_objs)) ? core->dest_obj_list[core->cur_dest_obj] : -1; obj->intercepting_object = ref_obj_num; obj->throttle = 0.0f; obj->engine_state = SW_ENGINE_STATE_ON; SWServObjectSyncConnections(ctx, obj_num, 0); return; } /* Reached the current destination object? */ if(SWServObjectsInRange(ctx, obj_num, ref_obj_num, core->distance)) { /* Set intercept to the next destination object */ core->cur_dest_obj++; if(core->cur_dest_obj >= core->ndest_objs) core->cur_dest_obj = 0; ref_obj_num = ((core->cur_dest_obj >= 0) && (core->cur_dest_obj < core->ndest_objs)) ? core->dest_obj_list[core->cur_dest_obj] : -1; obj->intercepting_object = ref_obj_num; obj->throttle = 0.0f; obj->engine_state = SW_ENGINE_STATE_ON; /* Replenish antimatter */ obj->antimatter = obj->antimatter_max; SWServObjectSyncConnections(ctx, obj_num, 0); return; } if(obj->intercepting_object != ref_obj_num) obj->intercepting_object = ref_obj_num; /* Adjust throttle and engine state */ obj->throttle = 1.0f; if(obj->engine_state != SW_ENGINE_STATE_ON) obj->engine_state = SW_ENGINE_STATE_ON; SWServObjectSyncConnections(ctx, obj_num, 0); } /* * Regenerates the freighter as needed. */ static void FreighterRegenerate(SWServContext *ctx) { int opm_num, obj_num, ref_obj_num; xsw_object_struct *obj, *ref_obj; Core *core = CORE(SWServGetData(ctx)); /* Exists? */ if(!SWServObjectIsGarbage(ctx, core->obj_num)) return; /* Get the first destination object */ ref_obj_num = (core->ndest_objs > 0) ? core->dest_obj_list[0] : -1; ref_obj = SWServObjectGetPointer(ctx, ref_obj_num); if(ref_obj == NULL) return; /* Create a new freighter */ core->obj_num = obj_num = SWServObjectCreate( ctx, SW_OBJ_TYPE_CONTROLLED ); obj = SWServObjectGetPointer(ctx, obj_num); if(obj == NULL) { core->obj_num = -1; return; } /* Get the model */ opm_num = SWServOPMGetByName(ctx, core->opm_name); if(opm_num > -1) { float c, theta; /* Model the new freighter */ 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; /* Initialize random number generator */ srand((unsigned int)core->next_regenerate); c = (float)rand() / (float)RAND_MAX; theta = 2.0 * PI * c; obj->x = ref_obj->x + ((float)sin((double)theta) * core->distance); obj->y = ref_obj->y + ((float)cos((double)theta) * core->distance); obj->z = ref_obj->z; } 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'; } /* Set initial intercept to the second destination object */ ref_obj_num = (core->ndest_objs > 1) ? core->dest_obj_list[1] : -1; obj->intercepting_object = ref_obj_num; core->cur_dest_obj = (core->ndest_objs > 1) ? 1 : 0; SWServObjectSyncConnections(ctx, obj_num, 1); } /* * Deletes the core. */ static void CoreDelete(Core *core) { if(core == NULL) return; free(core->opm_name); free(core->name); free(core->empire); free(core->dest_obj_list); free(core); } /* * 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)); float com_range = SWServSysparmGetF(ctx, "com_range"); xsw_object_struct *obj, *tar_obj; 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; /* Did not hail our freighter? */ if(tar_obj_num != core->obj_num) return; obj = SWServObjectGetPointer(ctx, obj_num); tar_obj = SWServObjectGetPointer(ctx, tar_obj_num); if((obj == NULL) || (tar_obj == NULL)) return; /* Not in com range? */ if(!SWServObjectsInRange( ctx, obj_num, tar_obj_num, com_range )) return; if((core->cur_dest_obj >= 0) && (core->cur_dest_obj < core->ndest_objs) ) { int dest_obj_num = core->dest_obj_list[core->cur_dest_obj]; xsw_object_struct *dest_obj = SWServObjectGetPointer( ctx, dest_obj_num ); if(dest_obj != NULL) { char *s = (char *)malloc( STRLEN(tar_obj->name) + STRLEN(dest_obj->name) + 80 ); sprintf( s, "This is %s enroute to %s.", tar_obj->name, dest_obj->name ); 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)); if(core == NULL) return; /* Our freighter was destroyed? */ if(core->obj_num == destroyed_obj_num) { /* Mark that our freighter was destroyed */ core->obj_num = -1; } } /* * 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 = 2.0; Core *core = CORE(calloc(1, sizeof(Core))); if(core == NULL) return(1); core->update_int = FREIGHTER_DEF_UPDATE_INT; core->regenerate_int = FREIGHTER_DEF_REGENERATE_INT; core->distance = distance; core->opm_name = STRDUP(FREIGHTER_DEF_OPM_NAME); core->name = STRDUP(FREIGHTER_DEF_NAME); core->empire = STRDUP(FREIGHTER_DEF_EMPIRE); core->obj_num = -1; core->dest_obj_list = NULL; core->cur_dest_obj = 0; core->ndest_objs = 0; 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" ); CoreDelete(core); return(1); } /* Update interval */ 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]), 1l); } /* Regenerate interval */ else if(!strcasecmp(arg, "--regenerate") || !strcasecmp(arg, "-regenerate") || !strcasecmp(arg, "--r") || !strcasecmp(arg, "-r") ) { /* In seconds */ i++; if(i < argc) core->regenerate_int = MAX(atol(argv[i]), 1l); } /* Distance */ else if(!strcasecmp(arg, "--distance") || !strcasecmp(arg, "-distance") || !strcasecmp(arg, "--d") || !strcasecmp(arg, "-d") ) { /* In real units */ i++; if(i < argc) core->distance = MAX(atof(argv[i]), 0.0f); } /* Object Parameters Model */ else if(!strcasecmp(arg, "--opm") || !strcasecmp(arg, "-opm") ) { i++; if(i < argc) { free(core->opm_name); core->opm_name = STRDUP(argv[i]); } } /* Name */ 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]); } } /* Empire */ 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 { /* All else assume object number */ int n = core->ndest_objs; const int obj_num = ATOI( (*arg == '#') ? (arg + 1) : arg ); core->ndest_objs = n + 1; core->dest_obj_list = (int *)realloc( core->dest_obj_list, core->ndest_objs * sizeof(int) ); core->dest_obj_list[n] = obj_num; } } /* No destination objects spcified? */ if(core->dest_obj_list == NULL) { if(con_num > -1) SWServConNotify( ctx, con_num, USAGE_MESG ); else SWServPrintError( ctx, USAGE_MESG "\n" ); CoreDelete(core); return(1); } /* Schedual initial updates */ core->next_update = SWServCurrentTimeSeconds(ctx); core->next_regenerate = SWServCurrentTimeSeconds(ctx); SWServSetData(ctx, core); 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) { FreighterUpdate(ctx); core->next_update = t + core->update_int; } /* Time to regenerate? */ if(core->next_regenerate <= t) { FreighterRegenerate(ctx); core->next_regenerate = t + core->regenerate_int; } return(0); } /* * SWServ Plugin shutdown. */ SWPLUGIN_SHUTDOWN_FUNCRTN SWPLUGIN_SHUTDOWN_FUNC( SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); if(core == NULL) return; /* Recycle our freighter as needed */ if(core->obj_num > -1) { SWServObjectRecycle(ctx, core->obj_num); core->obj_num = -1; } CoreDelete(core); SWServSetData(ctx, NULL); }