/* Remote scan */ #include #include #include #include #include #include "../include/swserv-plugins.h" typedef struct { time_t next_update, /* In seconds */ update_int, next_respawn, respawn_int; int probe_ocs_num, buoy_ocs_num; } Core; #define CORE(p) ((Core *)(p)) #if 0 char **swplugin_help_commands_list( int *ncommands, SWServContext *ctx ); int swplugin_command( const char *cmd, const char *arg, int con_num, int obj_num, int uid, int gid, SWServContext *ctx ); #endif static void ProbeNotifyContact( SWServContext *ctx, const int obj_num, const int owner_obj_num, const int tar_obj_num ); static int ProbeGetNearestObject( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj, const int owner_obj_num, xsw_object_struct **obj_rtn ); static void ProbeUpdateProbeIterate( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj ); static void ProbeUpdateBuoyIterate( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj ); static void ProbeUpdate(SWServContext *ctx); static void ProbeRespawn(SWServContext *ctx); #define PROBE_DEF_UPDATE_INT 3 /* In seconds */ #define PROBE_DEF_RESPAWN_INT (10 * 60) /* In seconds */ #define PROBE_DEF_PROBE_OCS_NUM 110 #define PROBE_DEF_BUOY_OCS_NUM 115 #define USAGE_MESG "\ Usage: [-i ] [-respawn ] [-probe ] [-buoy ]" #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 #if 0 /* * SWServ Plugin help commands list. */ char **swplugin_help_commands_list( int *ncommands, SWServContext *ctx ) { static char *help_list[] = { "remotescan", "rscan" }; if(ncommands != NULL) *ncommands = sizeof(help_list) / sizeof(char *); return(help_list); } #endif #if 0 /* * SWServ Plugin command. */ int swplugin_command( const char *cmd, const char *arg, int con_num, int obj_num, int uid, int gid, SWServContext *ctx ) { int status = 0; if((cmd == NULL) || (arg == NULL) || (ctx == NULL)) return(status); /* Begin checking which command is given */ if(!strcasecmp(cmd, "remotescan") || !strcasecmp(cmd, "rscan") ) { status = 1; } return(status); } #endif /* * Notifies the specified object about contact with the * specified target object. */ static void ProbeNotifyContact( SWServContext *ctx, const int obj_num, const int owner_obj_num, const int tar_obj_num ) { const int total_connections = SWServTotalConnections(ctx); int i; char *msg; float bearing, ru_to_au, d; xsw_object_struct *obj = SWServObjectGetPointer(ctx, obj_num), *owner_obj = SWServObjectGetPointer(ctx, owner_obj_num), *tar_obj = SWServObjectGetPointer(ctx, tar_obj_num); sw_legend_struct *legend = SWServGetLegend(ctx); if((obj == NULL) || (owner_obj == NULL) || (tar_obj == NULL) || (legend == NULL) ) return; ru_to_au = (float)legend->ru_to_au; /* Calculate the bearing from the owner to the target object */ if(SWServObjectsInSameSector(ctx, owner_obj_num, tar_obj_num)) { d = hypot( tar_obj->x - owner_obj->x, tar_obj->y - owner_obj->y ); bearing = (float)((0.5 * PI) - (float)atan2( (double)(tar_obj->y - owner_obj->y), (double)(tar_obj->x - owner_obj->x) )); } else { d = 0.0; bearing = (float)((0.5 * PI) - (float)atan2( (double)(tar_obj->sect_y - owner_obj->sect_y), (double)(tar_obj->sect_x - owner_obj->sect_x) )); } while(bearing > (2 * PI)) bearing -= (2 * PI); while(bearing < (0 * PI)) bearing += (2 * PI); /* Format message */ msg = (char *)malloc( STRLEN(obj->name) + STRLEN(tar_obj->name) + STRLEN(tar_obj->description) + 40 + 40 + 40 + 40 + 40 + 40 + 40 + 256 ); if(!STRISEMPTY(tar_obj->description)) { if(d > 0.0) sprintf( msg, "%s detected `%s' bearing %.0f', distance %.1f au,\ hull %.0f(%.0f), power %.0f(%.0f), %s.", obj->name, tar_obj->name, (float)(bearing * 180.0 / PI), (d * ru_to_au), tar_obj->hp, tar_obj->hp_max, tar_obj->power, tar_obj->power_max, tar_obj->description ); else sprintf( msg, "%s detected `%s' bearing %.0f',\ hull %.0f(%.0f), power %.0f(%.0f), %s.", obj->name, tar_obj->name, (float)(bearing * 180.0 / PI), tar_obj->hp, tar_obj->hp_max, tar_obj->power, tar_obj->power_max, tar_obj->description ); } else { if(d > 0.0) sprintf( msg, "%s detected `%s' bearing %.0f', distance %.1f au,\ hull %.0f(%.0f), power %.0f(%.0f).", obj->name, tar_obj->name, (float)(bearing * 180.0 / PI), (d * ru_to_au), tar_obj->hp, tar_obj->hp_max, tar_obj->power, tar_obj->power_max ); else sprintf( msg, "%s detected `%s' bearing %.0f',\ hull %.0f(%.0f), power %.0f(%.0f).", obj->name, tar_obj->name, (float)(bearing * 180.0 / PI), tar_obj->hp, tar_obj->hp_max, tar_obj->power, tar_obj->power_max ); } /* Notify the owner object's connection */ for(i = 0; i < total_connections; i++) { if(SWServConGetObjNum(ctx, i) == owner_obj_num) SWServConNotify(ctx, i, msg); } free(msg); } /* * Returns the nearest object of interest relative to the specified * object. */ static int ProbeGetNearestObject( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj, const int owner_obj_num, xsw_object_struct **obj_rtn ) { const int total = SWServTotalObjects(ctx); const char in_nebula = (obj->loc_type == SW_LOC_TYPE_NEBULA) ? 1 : 0; int i, closest_obj_num = -1; float d, closest_distance = 0.0; const float scanner_range = obj->scanner_range; xsw_object_struct *tar_obj; *obj_rtn = NULL; /* Note that the scanner range is always at maximum * effectiveness, that is the other object's stealthiness or * cloak state is not accounted for * * The object being in a nebula is also not accounted for with * the exception that if this object is outside of a nebula * and the target object is inside a nebula is checked for */ /* Iterate through all objects */ for(i = 0; i < total; i++) { tar_obj = SWServObjectGetPointer(ctx, i); if(tar_obj == NULL) continue; if((i == obj_num) || (i == owner_obj_num)) continue; /* Skip non controlled and player objects */ if((tar_obj->type != SW_OBJ_TYPE_CONTROLLED) && (tar_obj->type != SW_OBJ_TYPE_PLAYER) ) continue; if(SWServObjectIsHidden(ctx, i)) continue; /* Target object out of scanner range? */ if(!SWServObjectsInRange( ctx, obj_num, i, scanner_range )) continue; /* Skip if our object is outside of a nebula and the * target object is inside a nebula */ if(!in_nebula && (tar_obj->loc_type == SW_LOC_TYPE_NEBULA)) continue; /* Calculate the distance in SW real units between the two * objects */ d = hypot( tar_obj->x - obj->x, tar_obj->y - obj->y ); /* Was there a previous closer object? */ if(closest_obj_num > -1) { /* This object closer? */ if(d < closest_distance) { closest_obj_num = i; closest_distance = d; *obj_rtn = tar_obj; } } else { /* Record this initial closest object */ closest_obj_num = i; closest_distance = d; *obj_rtn = tar_obj; } } return(closest_obj_num); } /* * Updates this probe. */ static void ProbeUpdateProbeIterate( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj ) { /* Get the closest object of interest (if any), and check if * it is different with this probe's scanner locked object */ xsw_object_struct *closest_obj; const int owner = SWServObjectGetPlayerOwner(ctx, obj_num); const int closest_obj_num = ProbeGetNearestObject( ctx, core, obj_num, obj, owner, &closest_obj ); if(closest_obj_num != obj->locked_on) { /* Lost scanner contact? */ if(closest_obj_num < 0) { obj->locked_on = -1; } /* New closest object in scanner range? */ else if(closest_obj != NULL) { ProbeNotifyContact( ctx, obj_num, owner, closest_obj_num ); obj->locked_on = closest_obj_num; } } } /* * Updates this buoy. */ static void ProbeUpdateBuoyIterate( SWServContext *ctx, Core *core, const int obj_num, xsw_object_struct *obj ) { /* Same as updating the probe */ ProbeUpdateProbeIterate( ctx, core, obj_num, obj ); } /* * Updates all active probes and buoys. */ static void ProbeUpdate(SWServContext *ctx) { int i, total; xsw_object_struct *obj; Core *core = CORE(SWServGetData(ctx)); if(core == NULL) return; /* Iterate through all objects */ total = SWServTotalObjects(ctx); for(i = 0; i < total; i++) { obj = SWServObjectGetPointer(ctx, i); if(obj == NULL) continue; if(obj->type == SW_OBJ_TYPE_GARBAGE) continue; /* Is this a probe? */ if(obj->creation_ocs == core->probe_ocs_num) ProbeUpdateProbeIterate( ctx, core, i, obj ); /* Is this a buoy? */ else if(obj->creation_ocs == core->buoy_ocs_num) ProbeUpdateBuoyIterate( ctx, core, i, obj ); } } /* * Updates the quantity of probes and buoys on all players that * can carry them. */ static void ProbeRespawn(SWServContext *ctx) { int i, total; xsw_object_struct *obj; Core *core = CORE(SWServGetData(ctx)); if(core == NULL) return; /* Iterate through all objects */ total = SWServTotalObjects(ctx); for(i = 0; i < total; i++) { obj = SWServObjectGetPointer(ctx, i); if(obj == NULL) continue; /* Only handle controlled and player objects */ if((obj->type != SW_OBJ_TYPE_CONTROLLED) && (obj->type != SW_OBJ_TYPE_PLAYER) ) continue; /* This object has weapons? */ if(obj->total_weapons > 0) { const int m = obj->total_weapons; int n; xsw_weapon_struct *wep; /* Iterate through this object's weapons */ for(n = 0; n < m; n++) { wep = obj->weapons[n]; if(wep == NULL) continue; /* Has probes? */ if((wep->ocs_code == core->probe_ocs_num) && (core->probe_ocs_num > -1) ) { if((wep->amount < wep->max) && (wep->amount > -1) ) { wep->amount++; SWServObjectSyncConnections(ctx, i, 0); } } /* Has buoys? */ else if((wep->ocs_code == core->buoy_ocs_num) && (core->buoy_ocs_num > -1) ) { if((wep->amount < wep->max) && (wep->amount > -1) ) { wep->amount++; SWServObjectSyncConnections(ctx, i, 0); } } } } } } /* * 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; } /* * SWServ Plugin initialize. */ SWPLUGIN_INIT_FUNCRTN SWPLUGIN_INIT_FUNC( int argc, char **argv, int con_num, SWServContext *ctx ) { int i; const char *arg; Core *core = CORE(calloc(1, sizeof(Core))); if(core == NULL) return(1); core->update_int = PROBE_DEF_UPDATE_INT; core->respawn_int = PROBE_DEF_RESPAWN_INT; core->probe_ocs_num = PROBE_DEF_PROBE_OCS_NUM; core->buoy_ocs_num = PROBE_DEF_BUOY_OCS_NUM; 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); } /* 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); } /* Respawn interval */ else if(!strcasecmp(arg, "--respawn") || !strcasecmp(arg, "-respawn") || !strcasecmp(arg, "--r") || !strcasecmp(arg, "-r") ) { /* In seconds */ i++; if(i < argc) core->respawn_int = MAX(ATOL(argv[i]), 1l); } /* Probe OCS number */ else if(!strcasecmp(arg, "--probe") || !strcasecmp(arg, "-probe") ) { i++; if(i < argc) core->probe_ocs_num = ATOI(argv[i]); } /* Buoy OCS number */ else if(!strcasecmp(arg, "--buoy") || !strcasecmp(arg, "-buoy") ) { i++; if(i < argc) core->buoy_ocs_num = ATOI(argv[i]); } } /* Schedual initial updates */ core->next_update = SWServCurrentTimeSeconds(ctx) + 0; core->next_respawn = SWServCurrentTimeSeconds(ctx) + core->respawn_int; 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) { ProbeUpdate(ctx); core->next_update = t + core->update_int; } /* Time to respawn? */ if(core->next_respawn <= t) { ProbeRespawn(ctx); core->next_respawn = t + core->respawn_int; } return(0); } /* * SWServ Plugin shutdown. */ SWPLUGIN_SHUTDOWN_FUNCRTN SWPLUGIN_SHUTDOWN_FUNC( SWServContext *ctx ) { Core *core = CORE(SWServGetData(ctx)); if(core == NULL) return; free(core); SWServSetData(ctx, NULL); }