diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c index 3e849c8..98d3306 100644 --- a/code/game/g_cmds.c +++ b/code/game/g_cmds.c @@ -6279,8 +6279,8 @@ Harry Young | 25/07/2012 ================= */ static void Cmd_selfdestruct_f(gentity_t *ent) { - gentity_t *destructEnt; - char arg[16], arg2[16], arg3[16], arg4[16], arg5[16], arg6[16], arg7[16]; + gentity_t *destructEnt, *safezone=NULL; + char arg[16], arg2[16], arg3[16], arg4[16], arg5[16], arg6[16], arg7[16], arg8[16]; double ETAmin, ETAsec; if(!ent || !ent->client) return; @@ -6321,10 +6321,11 @@ static void Cmd_selfdestruct_f(gentity_t *ent) { destructEnt->health = atoi(arg5); trap_Argv(6, arg6, sizeof(arg6)); destructEnt->flags = atoi(arg6); - if(trap_Argc() == 7) { - trap_Argv(7, arg7, sizeof(arg7)); - destructEnt->target = G_NewString(arg7); - } + trap_Argv(7, arg7, sizeof(arg7)); + destructEnt->bluename = G_NewString(arg7); + trap_Argv(8, arg8, sizeof(arg8)); + destructEnt->target = G_NewString(arg8); + destructEnt->spawnflags = 1; //tells ent to free once aborted. //we need to check a few things here to make sure the entity works properly. Else we free it. @@ -6333,13 +6334,19 @@ static void Cmd_selfdestruct_f(gentity_t *ent) { } else { //sth's wrong so lets tell them what is. G_PrintfClient(ent, "^1ERROR: The following arguments are missing:"); if ( destructEnt->wait == 0 ) - G_PrintfClient(ent, "^1duration must not be 0."); + G_PrintfClient(ent, "^1-duration must not be 0."); if ( destructEnt->count == 0 ) - G_PrintfClient(ent, "^1intervall must not be 0."); + G_PrintfClient(ent, "^1-intervall must not be 0."); if ( destructEnt->n00bCount == 0 ) - G_PrintfClient(ent, "^1intervall-60 must not be 0."); + G_PrintfClient(ent, "^1-intervall-60 must not be 0."); if ( destructEnt->health == 0 ) - G_PrintfClient(ent, "^1intervall-10 must not be 0."); + G_PrintfClient(ent, "^1-intervall-10 must not be 0."); + while((safezone = G_Find(safezone, FOFS(classname), "target_safezone")) != NULL){ + if(!destructEnt->bluename && safezone->spawnflags & 2){ + G_PrintfClient(ent, "^1-safezone must be given for maps consisting of multiple ships/stations (like rpg_runabout)."); + break; + } + } G_PrintfClient(ent, "^1Removing entity."); G_FreeEntity(destructEnt); return; @@ -6388,13 +6395,14 @@ static void Cmd_selfdestruct_f(gentity_t *ent) { destructEnt->use(destructEnt, NULL, NULL); // Use-Function will simply manage the abort } else { G_PrintfClient(ent, "^1ERROR: Invalid or no command-Argument. Arguments are start, remaining and abort"); - G_PrintfClient(ent, "^3Usage: selfdestruct start duration intervall intervall-60 intervall-10 audio [target]"); + G_PrintfClient(ent, "^3Usage: selfdestruct start duration intervall intervall-60 intervall-10 audio [safezone] [target]"); G_PrintfClient(ent, "duration: total countdown-duration in seconds. Must not be 0."); G_PrintfClient(ent, "intervall: intervall of audio warnings up to T-60 seconds in seconds. Must not be 0."); G_PrintfClient(ent, "intervall-60: intervall of audio warnings within T-60 seconds in seconds. Must not be 0."); G_PrintfClient(ent, "intervall-10: intervall of audio warnings within T-10 seconds in seconds. Must not be 0."); G_PrintfClient(ent, "audio: set this 0 if you do want a muted countdown, else set this 1."); - G_PrintfClient(ent, "target: Optional Argument for Effects to fire once the countdown hist 0. The entity will automatically shake everyones screen and kill all clienst outside an active target_savezone."); + G_PrintfClient(ent, "safezone: safezone to toggle unsafe at T-50ms. Only for maps with multiple ships (like rpg_runabout). Set NULL to skip."); + G_PrintfClient(ent, "target: Optional Argument for Effects to fire once the countdown hist 0. The entity will automatically shake everyones screen and kill all clienst outside an active target_safezone."); G_PrintfClient(ent, "^2Hint: Make sure your duration and intervalls are synced up. There is a failsave for the countdown to hit it's mark however there is nothing to make sure that you don't get your warnings at unexpected times..."); G_PrintfClient(ent, "^2Try this for example: selfdestruct start 131 10 10 1 1"); G_PrintfClient(ent, "\n^3Usage: selfdestruct remaining"); @@ -6412,8 +6420,9 @@ Harry Young | 02/08/2012 ================= */ static void Cmd_shipdamage_f(gentity_t *ent) { - gentity_t *healthEnt; + gentity_t *healthEnt=NULL; char arg[16]; + char target[512]; #ifndef SQL if ( !IsAdmin( ent ) ) { @@ -6427,17 +6436,36 @@ static void Cmd_shipdamage_f(gentity_t *ent) { } #endif - healthEnt = G_Find(NULL, FOFS(classname), "target_shiphealth"); + if(trap_Argc() == 0){ + G_PrintfClient(ent, "Usage: shipdamage damage [target] where damage is the total amount dealt and target is the target_shiphealth to recieve it. It is case-dependent and required on maps with 2 or more of such (like rpg_runabout).\n"); + G_PrintfClient(ent, "It will be rendered to shields and hull respectively by the entity. Must be positive. You can not heal with this command.\n"); + return; + } + + if(trap_Argc() > 1){ + Q_strncpyz( target, ConcatArgs( 2 ), sizeof( target ) ); + + while((healthEnt = G_Find(healthEnt, FOFS(classname), "target_shiphealth")) != NULL){ + if(!Q_stricmp(healthEnt->targetname, target))//find the right entity if we have a target + break; + } + } + + if(!healthEnt){//specific search did not turn up any results so fall back to the first entity + trap_SendServerCommand( ent-g_entities, va("print \"^3 Warning: no healthEnt with targetname '%s' found, falling back to first entity found.\n\"", target ) ); + healthEnt = G_Find(NULL, FOFS(classname), "target_shiphealth"); + if(G_Find(healthEnt, FOFS(classname), "target_shiphealth")){//abort if we do have more than one healthEnt + trap_SendServerCommand( ent-g_entities, va("print \"^1 ERROR: This map has more than one target_shiphealth, therefore a target needs to be specified. Aborting call.\n\"" ) ); + return; + } + } + if(!healthEnt){ trap_SendServerCommand( ent-g_entities, "print \"^4This map does not support the shiphealth system.\n\"" ); return; } trap_Argv(1, arg, sizeof(arg)); - if(atoi(arg) == 0){ - G_PrintfClient(ent, "Usage: shipdamage [damage] where damage is the total amount dealt. It will be rendered to shields and hull respectively by the entity. Must be positive. You can not heal with this command.\n"); - return; - } if(atoi(arg) > 0){ if(healthEnt->count > 0){ @@ -6461,17 +6489,17 @@ Harry Young | 02/08/2012 ================= */ static void Cmd_shiphealth_f(gentity_t *ent) { - gentity_t *healthEnt; + gentity_t *healthEnt=NULL; int THS, CHS, HCI, TSS, CSS, SCI, SI; float RHS, RSS; - healthEnt = G_Find(NULL, FOFS(classname), "target_shiphealth"); - - if(!healthEnt){ + if(!G_Find(NULL, FOFS(classname), "target_shiphealth")){ trap_SendServerCommand( ent-g_entities, "print \"^3This map does not support the shiphealth system.\n\"" ); return; } + while((healthEnt = G_Find(healthEnt, FOFS(classname), "target_shiphealth")) != NULL){ //do this for every healthEnt you find + THS = healthEnt->health; CHS = healthEnt->count; TSS = healthEnt->splashRadius; @@ -6495,9 +6523,9 @@ static void Cmd_shiphealth_f(gentity_t *ent) { SCI = 1; if(CHS == 0){ - trap_SendServerCommand( ent-g_entities, "print \"\n^1 The Ship is destroyed.\n\n\"" ); + trap_SendServerCommand( ent-g_entities, va("print \"\n^1 %s is destroyed.\n\n\"", healthEnt->targetname ) ); } else { - trap_SendServerCommand( ent-g_entities, "print \"\n^3 Tactical Master Systems Display\n\"" ); + trap_SendServerCommand( ent-g_entities, va("print \"\n^3 %s : Tactical Master Systems Display\n\"", healthEnt->targetname ) ); switch(SI){ case -2: trap_SendServerCommand( ent-g_entities, "print \"^1 Shields are offline\n\"" ); @@ -6516,6 +6544,7 @@ static void Cmd_shiphealth_f(gentity_t *ent) { trap_SendServerCommand( ent-g_entities, va("print \"^%i Shield Capactiy at %.0f Percent (%i of %i Points)\n\"", SCI, RSS, CSS, TSS) ); trap_SendServerCommand( ent-g_entities, va("print \"^%i Structual Integrity at %.0f Percent (%i of %i Points)\n\n\"", HCI, RHS, CHS, THS) ); } + } return; } diff --git a/code/game/g_target.c b/code/game/g_target.c index 31abb57..0c070b5 100644 --- a/code/game/g_target.c +++ b/code/game/g_target.c @@ -2581,7 +2581,7 @@ void SP_target_shaderremap(gentity_t *ent) { /*QUAKED target_selfdestruct (1 0 0) (-8 -8 -8) (8 8 8) This entity manages the self destruct. For now this should only be used via the selfdestruct console command, however it might be usable from within the radiant at a later date. -Should this thing hit 0 the killing part for everyone outside a target_savezone will be done automatically. +Should this thing hit 0 the killing part for everyone outside a target_safezone will be done automatically. Keys: wait: total Countdown-Time in secs @@ -2589,6 +2589,7 @@ count: warning intervall up to 60 secs in secs n00bCount: warning intervall within 60 secs in secs health: warning intervall within 10 secs in secs flags: are audio warnings 1 or 0? +bluename: target_safezone this thing affects (multi-ship-maps only) will switch it unsafe at T-50ms target: Things like fx to fire once the countdown hits 0 damage: leveltime of countdowns end @@ -2654,14 +2655,17 @@ void target_selfdestruct_use(gentity_t *ent, gentity_t *other, gentity_t *activa void target_selfdestruct_think(gentity_t *ent) { gentity_t* client; - gentity_t *healthEnt, *savezone=NULL; + gentity_t *healthEnt, *safezone=NULL; double ETAmin, ETAsec, temp = 0.0f; int i = 0; - //this is for calling the savezones to list. It needs to stand here to not screw up the remainder of the think. + //this is for calling the safezones to list. It needs to stand here to not screw up the remainder of the think. if (ent->wait == 50) { - while ((savezone = G_Find( savezone, FOFS( classname ), "target_safezone" )) != NULL ){ - savezone->use(savezone, ent, ent); + while ((safezone = G_Find( safezone, FOFS( classname ), "target_safezone" )) != NULL ){ + if(!Q_stricmp(safezone->targetname, ent->bluename))//free shipwide safezone if it exists + G_FreeEntity(safezone); + else + safezone->use(safezone, ent, ent); } ent->wait = 0; ent->nextthink = level.time + 50; @@ -2733,7 +2737,7 @@ void target_selfdestruct_think(gentity_t *ent) { } if (ent->nextthink == ent->damage){ - //we need to get the savezones operational and it is highly unlikely that it'll happen in the last .05 secs of the count + //we need to get the safezones operational and it is highly unlikely that it'll happen in the last .05 secs of the count ent->nextthink = ent->nextthink - 50; ent->wait = 50; } @@ -2909,7 +2913,7 @@ void SP_target_selfdestruct(gentity_t *ent) { } if (ent->nextthink == ent->damage){ - //we need to get the savezones operational and it is highly unlikely that it'll happen in the last .05 secs of the count + //we need to get the safezones operational and it is highly unlikely that it'll happen in the last .05 secs of the count ent->nextthink = ent->nextthink - 50; ent->wait = 50; } @@ -2917,15 +2921,27 @@ void SP_target_selfdestruct(gentity_t *ent) { trap_LinkEntity(ent); } -/*QUAKED target_safezone (1 0 0) ? STARTON -This is a safezone for the self destruct sequence. +/*QUAKED target_safezone (1 0 0) ? STARTON SHIP +This is a safezone for when the ship/station is destroyed via shiphelath or selfdestruct. +It is used like a trigger and requires a targetname or else it will be removed at spawn. + +STARTON has this Entity spawned in it's Safe configurartion +SHIP is used as a failsave for maps with multiple ships/stations + +Usage for Escape Pods and similar: +Fill your escape pod Interior with this trigger and have it targeted by a func_usable/target_relay/target_delay to toggle it between safe and unsafe states. + +Usage for multiple ships (and stations) like on rpg_runabout: +Surround your entire ship with this trigger (or it's seperate elements with one each) and set it to STARTON and SHIP (spawnflags = 3). +Have it's targetname match the targetname of it's target_shiphealth-counterpart exactly (case-dependent) to automatically switch this savezone to unsafe should it be about to die. +In case of a selfdestruct you will need to enter the targetname to automatically switch it to unsafe 50ms prior to the countdowns end. */ -void target_savezone_use(gentity_t *ent, gentity_t *other, gentity_t *activator){ +void target_safezone_use(gentity_t *ent, gentity_t *other, gentity_t *activator){ safeZone_t* sz = (safeZone_t *)malloc(sizeof(safeZone_s)); if(!Q_stricmp(activator->classname, "target_selfdestruct") || !Q_stricmp(activator->classname, "target_shiphealth")){ - //our ship is about to die so compose the list of savezones + //our ship is about to die so compose the list of safezones VectorCopy(ent->r.maxs, sz->maxs); VectorCopy(ent->r.mins, sz->mins); VectorAdd(ent->s.origin, ent->r.mins, sz->mins); @@ -2962,7 +2978,8 @@ void target_safezone_destructor(void *p) { void SP_target_safezone(gentity_t *ent) { if(!ent->targetname || !ent->targetname[0]) { - DEVELOPER(G_Printf(S_COLOR_YELLOW "[Entity-Error] Safezone without targetname at %s.\n", vtos(ent->s.origin));); + DEVELOPER(G_Printf(S_COLOR_YELLOW "[Entity-Error] Safezone without targetname at %s, removing entity.\n", vtos(ent->s.origin));); + G_FreeEntity(ent); return; } @@ -2976,7 +2993,7 @@ void SP_target_safezone(gentity_t *ent) { } if(ent->spawnflags & 1) ent->count = 1; - ent->use = target_savezone_use; + ent->use = target_safezone_use; ent->r.contents = CONTENTS_NONE; ent->r.svFlags |= SVF_NOCLIENT; trap_LinkEntity(ent); @@ -2987,9 +3004,10 @@ This Entity manages a ships healt. Ship Health is reduced via administrative/del Repairing is based on a % per minute basis for both shields and hull. The entity features interconnectivity with other systems such as warpdrive or turbolift with a random yet incresing chance to turn them off whenever hulldamage occurs. This includes Shields. Further more the entity will automatically toggle red alert should it be any other and will activate shields if alert is set to any but green. -If hull health hit's 0 it will kill any client outside an active savezone. +If hull health hit's 0 it will kill any client outside an active safezone. -Keys: +Required Keys (If any of them are not given the entity will be removed at spawn): +targetname: Name of the Ship/Station this entity represents. please use underscores (_) instead of spaces ( ). See target_safezone for additional use of this key. health: Total Hull strength splashRadius: total shield strenght angle: Hull repair in % per minute @@ -3071,7 +3089,7 @@ void target_shiphealth_die(gentity_t *ent){ void target_shiphealth_use(gentity_t *ent, gentity_t *other, gentity_t *activator) { double NSS, NHS, SD, HD, BT; - gentity_t *alertEnt, *warpEnt, *turboEnt, *transEnt, *savezone=NULL; + gentity_t *alertEnt, *warpEnt, *turboEnt, *transEnt, *safezone=NULL; if(ent->damage <= 0){ //failsave return; @@ -3158,11 +3176,14 @@ void target_shiphealth_use(gentity_t *ent, gentity_t *other, gentity_t *activato //let's reset the repair-timer ent->nextthink = level.time + 60000; - //if we hit 0 use all the savezones and blow in 50 ms + //if we hit 0 use all the safezones and blow in 50 ms if(ent->count <= 0){ - while ((savezone = G_Find( savezone, FOFS( classname ), "target_safezone" )) != NULL ){ - savezone->use(savezone, ent, ent); + while ((safezone = G_Find( safezone, FOFS( classname ), "target_safezone" )) != NULL ){ + if(!Q_stricmp(safezone->targetname, ent->targetname))//free shipwide safezone if it exists + G_FreeEntity(safezone); + else + safezone->use(safezone, ent, ent); } ent->think = target_shiphealth_die; ent->nextthink = level.time + 50; @@ -3243,6 +3264,12 @@ void target_shiphealth_think(gentity_t *ent) { void SP_target_shiphealth(gentity_t *ent) { + if(!ent->targetname || !ent->health || !ent->splashRadius || !ent->angle || !ent->speed){ + DEVELOPER(G_Printf(S_COLOR_YELLOW "[Entity-Error] target_shiphealth at %s is missing one or more parameters, removing entity.\n", vtos(ent->s.origin));); + trap_LinkEntity(ent); + return; + } + //we need to put the total health in for the current ent->count = ent->health; ent->n00bCount = ent->splashRadius;