Work on Shiphealth, Safezone, Selfdestruct

Modified all of them to bertter support maps like rpg_runabout with more than one ship
both selfdestruct and shiphealth now allow for a safezones targetname to be added that is freed before called to list
that required modifications to the associated commands.
Now selfdestruct start asks for a safezone as it's 2nd to last argument and requires it if any safezone is spawnflaged as SHIP
shipdamage now has a 2nd argument that specifies the healthEnt it shall deal to. It requires that argument if it finds at least 2 healthEnts
shiphealth now displays the status of all healthEnts that exist and displays it's targetname in line one of the output
There ar also a few other things associated with this (e.g. healthEnt now frees at spawn if it misses required parameters)

Expanded description of target_safezone

Signed-off-by: Harry Young <hendrik.gerritzen@googlemail.com>
This commit is contained in:
Harry Young 2012-10-31 20:54:37 +01:00
parent f5694b17c0
commit 0d2d9aac3d
2 changed files with 99 additions and 43 deletions

View file

@ -6279,8 +6279,8 @@ Harry Young | 25/07/2012
================= =================
*/ */
static void Cmd_selfdestruct_f(gentity_t *ent) { static void Cmd_selfdestruct_f(gentity_t *ent) {
gentity_t *destructEnt; gentity_t *destructEnt, *safezone=NULL;
char arg[16], arg2[16], arg3[16], arg4[16], arg5[16], arg6[16], arg7[16]; char arg[16], arg2[16], arg3[16], arg4[16], arg5[16], arg6[16], arg7[16], arg8[16];
double ETAmin, ETAsec; double ETAmin, ETAsec;
if(!ent || !ent->client) if(!ent || !ent->client)
return; return;
@ -6321,10 +6321,11 @@ static void Cmd_selfdestruct_f(gentity_t *ent) {
destructEnt->health = atoi(arg5); destructEnt->health = atoi(arg5);
trap_Argv(6, arg6, sizeof(arg6)); trap_Argv(6, arg6, sizeof(arg6));
destructEnt->flags = atoi(arg6); destructEnt->flags = atoi(arg6);
if(trap_Argc() == 7) { trap_Argv(7, arg7, sizeof(arg7));
trap_Argv(7, arg7, sizeof(arg7)); destructEnt->bluename = G_NewString(arg7);
destructEnt->target = G_NewString(arg7); trap_Argv(8, arg8, sizeof(arg8));
} destructEnt->target = G_NewString(arg8);
destructEnt->spawnflags = 1; //tells ent to free once aborted. 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. //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. } else { //sth's wrong so lets tell them what is.
G_PrintfClient(ent, "^1ERROR: The following arguments are missing:"); G_PrintfClient(ent, "^1ERROR: The following arguments are missing:");
if ( destructEnt->wait == 0 ) 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 ) 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 ) 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 ) 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_PrintfClient(ent, "^1Removing entity.");
G_FreeEntity(destructEnt); G_FreeEntity(destructEnt);
return; 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 destructEnt->use(destructEnt, NULL, NULL); // Use-Function will simply manage the abort
} else { } else {
G_PrintfClient(ent, "^1ERROR: Invalid or no command-Argument. Arguments are start, remaining and abort"); 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, "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: 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-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, "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, "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, "^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, "^2Try this for example: selfdestruct start 131 10 10 1 1");
G_PrintfClient(ent, "\n^3Usage: selfdestruct remaining"); G_PrintfClient(ent, "\n^3Usage: selfdestruct remaining");
@ -6412,8 +6420,9 @@ Harry Young | 02/08/2012
================= =================
*/ */
static void Cmd_shipdamage_f(gentity_t *ent) { static void Cmd_shipdamage_f(gentity_t *ent) {
gentity_t *healthEnt; gentity_t *healthEnt=NULL;
char arg[16]; char arg[16];
char target[512];
#ifndef SQL #ifndef SQL
if ( !IsAdmin( ent ) ) { if ( !IsAdmin( ent ) ) {
@ -6427,17 +6436,36 @@ static void Cmd_shipdamage_f(gentity_t *ent) {
} }
#endif #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){ if(!healthEnt){
trap_SendServerCommand( ent-g_entities, "print \"^4This map does not support the shiphealth system.\n\"" ); trap_SendServerCommand( ent-g_entities, "print \"^4This map does not support the shiphealth system.\n\"" );
return; return;
} }
trap_Argv(1, arg, sizeof(arg)); 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(atoi(arg) > 0){
if(healthEnt->count > 0){ if(healthEnt->count > 0){
@ -6461,17 +6489,17 @@ Harry Young | 02/08/2012
================= =================
*/ */
static void Cmd_shiphealth_f(gentity_t *ent) { static void Cmd_shiphealth_f(gentity_t *ent) {
gentity_t *healthEnt; gentity_t *healthEnt=NULL;
int THS, CHS, HCI, TSS, CSS, SCI, SI; int THS, CHS, HCI, TSS, CSS, SCI, SI;
float RHS, RSS; float RHS, RSS;
healthEnt = G_Find(NULL, FOFS(classname), "target_shiphealth"); if(!G_Find(NULL, FOFS(classname), "target_shiphealth")){
if(!healthEnt){
trap_SendServerCommand( ent-g_entities, "print \"^3This map does not support the shiphealth system.\n\"" ); trap_SendServerCommand( ent-g_entities, "print \"^3This map does not support the shiphealth system.\n\"" );
return; return;
} }
while((healthEnt = G_Find(healthEnt, FOFS(classname), "target_shiphealth")) != NULL){ //do this for every healthEnt you find
THS = healthEnt->health; THS = healthEnt->health;
CHS = healthEnt->count; CHS = healthEnt->count;
TSS = healthEnt->splashRadius; TSS = healthEnt->splashRadius;
@ -6495,9 +6523,9 @@ static void Cmd_shiphealth_f(gentity_t *ent) {
SCI = 1; SCI = 1;
if(CHS == 0){ 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 { } 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){ switch(SI){
case -2: case -2:
trap_SendServerCommand( ent-g_entities, "print \"^1 Shields are offline\n\"" ); 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 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) ); trap_SendServerCommand( ent-g_entities, va("print \"^%i Structual Integrity at %.0f Percent (%i of %i Points)\n\n\"", HCI, RHS, CHS, THS) );
} }
}
return; return;
} }

View file

@ -2581,7 +2581,7 @@ void SP_target_shaderremap(gentity_t *ent) {
/*QUAKED target_selfdestruct (1 0 0) (-8 -8 -8) (8 8 8) /*QUAKED target_selfdestruct (1 0 0) (-8 -8 -8) (8 8 8)
This entity manages the self destruct. 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. 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: Keys:
wait: total Countdown-Time in secs 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 n00bCount: warning intervall within 60 secs in secs
health: warning intervall within 10 secs in secs health: warning intervall within 10 secs in secs
flags: are audio warnings 1 or 0? 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 target: Things like fx to fire once the countdown hits 0
damage: leveltime of countdowns end 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) { void target_selfdestruct_think(gentity_t *ent) {
gentity_t* client; gentity_t* client;
gentity_t *healthEnt, *savezone=NULL; gentity_t *healthEnt, *safezone=NULL;
double ETAmin, ETAsec, temp = 0.0f; double ETAmin, ETAsec, temp = 0.0f;
int i = 0; 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) { if (ent->wait == 50) {
while ((savezone = G_Find( savezone, FOFS( classname ), "target_safezone" )) != NULL ){ while ((safezone = G_Find( safezone, FOFS( classname ), "target_safezone" )) != NULL ){
savezone->use(savezone, ent, ent); 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->wait = 0;
ent->nextthink = level.time + 50; ent->nextthink = level.time + 50;
@ -2733,7 +2737,7 @@ void target_selfdestruct_think(gentity_t *ent) {
} }
if (ent->nextthink == ent->damage){ 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->nextthink = ent->nextthink - 50;
ent->wait = 50; ent->wait = 50;
} }
@ -2909,7 +2913,7 @@ void SP_target_selfdestruct(gentity_t *ent) {
} }
if (ent->nextthink == ent->damage){ 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->nextthink = ent->nextthink - 50;
ent->wait = 50; ent->wait = 50;
} }
@ -2917,15 +2921,27 @@ void SP_target_selfdestruct(gentity_t *ent) {
trap_LinkEntity(ent); trap_LinkEntity(ent);
} }
/*QUAKED target_safezone (1 0 0) ? STARTON /*QUAKED target_safezone (1 0 0) ? STARTON SHIP
This is a safezone for the self destruct sequence. 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)); safeZone_t* sz = (safeZone_t *)malloc(sizeof(safeZone_s));
if(!Q_stricmp(activator->classname, "target_selfdestruct") || !Q_stricmp(activator->classname, "target_shiphealth")){ 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.maxs, sz->maxs);
VectorCopy(ent->r.mins, sz->mins); VectorCopy(ent->r.mins, sz->mins);
VectorAdd(ent->s.origin, 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) { void SP_target_safezone(gentity_t *ent) {
if(!ent->targetname || !ent->targetname[0]) { 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; return;
} }
@ -2976,7 +2993,7 @@ void SP_target_safezone(gentity_t *ent) {
} }
if(ent->spawnflags & 1) if(ent->spawnflags & 1)
ent->count = 1; ent->count = 1;
ent->use = target_savezone_use; ent->use = target_safezone_use;
ent->r.contents = CONTENTS_NONE; ent->r.contents = CONTENTS_NONE;
ent->r.svFlags |= SVF_NOCLIENT; ent->r.svFlags |= SVF_NOCLIENT;
trap_LinkEntity(ent); 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. 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. 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. 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 health: Total Hull strength
splashRadius: total shield strenght splashRadius: total shield strenght
angle: Hull repair in % per minute 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) { void target_shiphealth_use(gentity_t *ent, gentity_t *other, gentity_t *activator) {
double NSS, NHS, SD, HD, BT; 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 if(ent->damage <= 0){ //failsave
return; return;
@ -3158,11 +3176,14 @@ void target_shiphealth_use(gentity_t *ent, gentity_t *other, gentity_t *activato
//let's reset the repair-timer //let's reset the repair-timer
ent->nextthink = level.time + 60000; 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){ if(ent->count <= 0){
while ((savezone = G_Find( savezone, FOFS( classname ), "target_safezone" )) != NULL ){ while ((safezone = G_Find( safezone, FOFS( classname ), "target_safezone" )) != NULL ){
savezone->use(savezone, ent, ent); 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->think = target_shiphealth_die;
ent->nextthink = level.time + 50; ent->nextthink = level.time + 50;
@ -3243,6 +3264,12 @@ void target_shiphealth_think(gentity_t *ent) {
void SP_target_shiphealth(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 //we need to put the total health in for the current
ent->count = ent->health; ent->count = ent->health;
ent->n00bCount = ent->splashRadius; ent->n00bCount = ent->splashRadius;