1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240 |
- // leave this line at the top for all g_xxxx.cpp files...
- #include "g_headers.h"
- #include "Q3_Interface.h"
- #include "g_local.h"
- #include "g_functions.h"
- extern void G_SetEnemy( gentity_t *self, gentity_t *enemy );
- //==========================================================
- /*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
- Gives the activator all the items pointed to.
- */
- void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
- gentity_t *t;
- trace_t trace;
- if ( !activator->client ) {
- return;
- }
- if ( !ent->target ) {
- return;
- }
- G_ActivateBehavior(ent,BSET_USE);
- memset( &trace, 0, sizeof( trace ) );
- t = NULL;
- while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
- if ( !t->item ) {
- continue;
- }
- Touch_Item( t, activator, &trace );
- // make sure it isn't going to respawn or show any events
- t->nextthink = 0;
- gi.unlinkentity( t );
- }
- }
- void SP_target_give( gentity_t *ent ) {
- ent->e_UseFunc = useF_Use_Target_Give;
- }
- //==========================================================
- /*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
- "wait" seconds to pause before firing targets.
- "random" delay variance, total delay = delay +/- random seconds
- */
- void Think_Target_Delay( gentity_t *ent )
- {
- G_UseTargets( ent, ent->activator );
- }
- void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator )
- {
- G_ActivateBehavior(ent,BSET_USE);
- ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
- ent->e_ThinkFunc = thinkF_Think_Target_Delay;
- ent->activator = activator;
- }
- void SP_target_delay( gentity_t *ent )
- {
- // check delay for backwards compatability
- if ( !G_SpawnFloat( "delay", "0", &ent->wait ) )
- {
- G_SpawnFloat( "wait", "1", &ent->wait );
- }
- if ( !ent->wait )
- {
- ent->wait = 1;
- }
- ent->e_UseFunc = useF_Use_Target_Delay;
- }
- //==========================================================
- /*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
- "count" number of points to add, default 1
- The activator is given this many points.
- */
- void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(ent,BSET_USE);
- AddScore( activator, ent->count );
- }
- void SP_target_score( gentity_t *ent ) {
- if ( !ent->count ) {
- ent->count = 1;
- }
- ent->e_UseFunc = useF_Use_Target_Score;
- }
- //==========================================================
- /*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8)
- "message" text to print
- If "private", only the activator gets the message. If no checks, all clients get the message.
- */
- void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(ent,BSET_USE);
- if ( activator->client ) {
- gi.SendServerCommand( activator-g_entities, "cp \"%s\"", ent->message );
- }
- }
- void SP_target_print( gentity_t *ent ) {
- ent->e_UseFunc = useF_Use_Target_Print;
- }
- //==========================================================
- /*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
- "noise" wav file to play
- "sounds" va() min max, so if your sound string is borgtalk%d.wav, and you set a "sounds" value of 4, it will randomly play borgtalk1.wav - borgtalk4.wav when triggered
- to use this, you must store the wav name in "soundGroup", NOT "noise"
- A global sound will play full volume throughout the level.
- Activator sounds will play on the player that activated the target.
- Global and activator sounds can't be combined with looping.
- Normal sounds play each time the target is used.
- Looped sounds will be toggled by use functions.
- Multiple identical looping sounds will just increase volume without any speed cost.
- "wait" : Seconds between triggerings, 0 = don't auto trigger
- "random" wait variance, default is 0
- */
- void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
- if(ent->painDebounceTime > level.time)
- {
- return;
- }
- G_ActivateBehavior(ent,BSET_USE);
- if ( ent->sounds )
- {
- ent->noise_index = G_SoundIndex( va( ent->paintarget, Q_irand(1, ent->sounds ) ) );
- }
- if (ent->spawnflags & 3) { // looping sound toggles
- gentity_t *looper = ent;
- if ( ent->spawnflags & 8 ) {
- looper = activator;
- }
- if (looper->s.loopSound)
- looper->s.loopSound = 0; // turn it off
- else
- looper->s.loopSound = ent->noise_index; // start it
- }else { // normal sound
- if ( ent->spawnflags & 8 ) {
- G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
- } else if (ent->spawnflags & 4) {
- G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
- } else {
- G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
- }
- }
- if(ent->wait < 0)
- {//BYE!
- ent->e_UseFunc = useF_NULL;
- }
- else
- {
- ent->painDebounceTime = level.time + ent->wait;
- }
- }
- void SP_target_speaker( gentity_t *ent ) {
- char buffer[MAX_QPATH];
- char *s;
- int i;
- if ( VALIDSTRING( ent->soundSet ) )
- {
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- gi.linkentity (ent);
- return;
- }
- G_SpawnFloat( "wait", "0", &ent->wait );
- G_SpawnFloat( "random", "0", &ent->random );
- if(!ent->sounds)
- {
- if ( !G_SpawnString( "noise", "*NOSOUND*", &s ) ) {
- G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
- }
- Q_strncpyz( buffer, s, sizeof(buffer) );
- COM_DefaultExtension( buffer, sizeof(buffer), ".wav");
- ent->noise_index = G_SoundIndex(buffer);
- }
- else
- {//Precache all possible sounds
- for( i = 0; i < ent->sounds; i++ )
- {
- ent->noise_index = G_SoundIndex( va( ent->paintarget, i+1 ) );
- }
- }
- // a repeating speaker can be done completely client side
- ent->s.eType = ET_SPEAKER;
- ent->s.eventParm = ent->noise_index;
- ent->s.frame = ent->wait * 10;
- ent->s.clientNum = ent->random * 10;
- ent->wait *= 1000;
- // check for prestarted looping sound
- if ( ent->spawnflags & 1 ) {
- ent->s.loopSound = ent->noise_index;
- }
- ent->e_UseFunc = useF_Use_Target_Speaker;
- if (ent->spawnflags & 4) {
- ent->svFlags |= SVF_BROADCAST;
- }
- VectorCopy( ent->s.origin, ent->s.pos.trBase );
- // must link the entity so we get areas and clusters so
- // the server can determine who to send updates to
- gi.linkentity (ent);
- }
- //==========================================================
- /*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
- When triggered, fires a laser. You can either set a target or a direction.
- */
- void target_laser_think (gentity_t *self) {
- vec3_t end;
- trace_t tr;
- vec3_t point;
- // if pointed at another entity, set movedir to point at it
- if ( self->enemy ) {
- VectorMA (self->enemy->s.origin, 0.5, self->enemy->mins, point);
- VectorMA (point, 0.5, self->enemy->maxs, point);
- VectorSubtract (point, self->s.origin, self->movedir);
- VectorNormalize (self->movedir);
- }
- // fire forward and see what we hit
- VectorMA (self->s.origin, 2048, self->movedir, end);
- gi.trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
- if ( tr.entityNum ) {
- // hurt it if we can
- G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir,
- tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_ENERGY );
- }
- VectorCopy (tr.endpos, self->s.origin2);
- gi.linkentity( self );
- self->nextthink = level.time + FRAMETIME;
- }
- void target_laser_on (gentity_t *self)
- {
- if (!self->activator)
- self->activator = self;
- target_laser_think (self);
- }
- void target_laser_off (gentity_t *self)
- {
- gi.unlinkentity( self );
- self->nextthink = 0;
- }
- void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(self,BSET_USE);
- self->activator = activator;
- if ( self->nextthink > 0 )
- target_laser_off (self);
- else
- target_laser_on (self);
- }
- void target_laser_start (gentity_t *self)
- {
- gentity_t *ent;
- self->s.eType = ET_BEAM;
- if (self->target) {
- ent = G_Find (NULL, FOFS(targetname), self->target);
- if (!ent) {
- gi.Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
- }
- G_SetEnemy( self, ent );
- } else {
- G_SetMovedir (self->s.angles, self->movedir);
- }
- self->e_UseFunc = useF_target_laser_use;
- self->e_ThinkFunc = thinkF_target_laser_think;
- if ( !self->damage ) {
- self->damage = 1;
- }
- if (self->spawnflags & 1)
- target_laser_on (self);
- else
- target_laser_off (self);
- }
- void SP_target_laser (gentity_t *self)
- {
- // let everything else get spawned before we start firing
- self->e_ThinkFunc = thinkF_target_laser_start;
- self->nextthink = level.time + START_TIME_LINK_ENTS;
- }
- //==========================================================
- void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- gentity_t *dest;
- if (!activator->client)
- return;
- G_ActivateBehavior(self,BSET_USE);
- dest = G_PickTarget( self->target );
- if (!dest) {
- gi.Printf ("Couldn't find teleporter destination\n");
- return;
- }
- TeleportPlayer( activator, dest->s.origin, dest->s.angles );
- }
- /*QUAK-ED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
- The activator will be teleported away.
- */
- void SP_target_teleporter( gentity_t *self ) {
- if (!self->targetname)
- gi.Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
- self->e_UseFunc = useF_target_teleporter_use;
- }
- //==========================================================
- /*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM x x x x INACTIVE
- This doesn't perform any actions except fire its targets.
- The activator can be forced to be from a certain team.
- if RANDOM is checked, only one of the targets will be fired, not all of them
- INACTIVE Can't be used until activated
- "delay" - Will actually fire this many seconds after being used
- "wait" - Cannot be fired again until this many seconds after the last time it was used
- */
- void target_relay_use_go (gentity_t *self )
- {
- G_ActivateBehavior( self, BSET_USE );
-
- if ( self->spawnflags & 4 )
- {
- gentity_t *ent;
- ent = G_PickTarget( self->target );
- if ( ent && (ent->e_UseFunc != useF_NULL) )
- { // e_UseFunc check can be omitted
- GEntity_UseFunc( ent, self, self->activator );
- }
- return;
- }
- G_UseTargets( self, self->activator );
- }
- void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- if ( ( self->spawnflags & 1 ) && activator->client )
- {//&& activator->client->ps.persistant[PERS_TEAM] != TEAM_RED ) {
- return;
- }
- if ( ( self->spawnflags & 2 ) && activator->client )
- {//&& activator->client->ps.persistant[PERS_TEAM] != TEAM_BLUE ) {
- return;
- }
- if ( self->svFlags & SVF_INACTIVE )
- {//set by target_deactivate
- return;
- }
- if ( self->painDebounceTime > level.time )
- {
- return;
- }
- G_SetEnemy( self, other );
- self->activator = activator;
- if ( self->delay )
- {
- self->e_ThinkFunc = thinkF_target_relay_use_go;
- self->nextthink = level.time + self->delay;
- return;
- }
- target_relay_use_go( self );
- if ( self->wait < 0 )
- {
- self->e_UseFunc = useF_NULL;
- }
- else
- {
- self->painDebounceTime = level.time + self->wait;
- }
- }
- void SP_target_relay (gentity_t *self)
- {
- self->e_UseFunc = useF_target_relay_use;
- self->wait *= 1000;
- self->delay *= 1000;
- if ( self->spawnflags&128 )
- {
- self->svFlags |= SVF_INACTIVE;
- }
- }
- //==========================================================
- /*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8) FALLING ELECTRICAL
- Kills the activator.
- */
- void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
- G_ActivateBehavior(self,BSET_USE);
- if ( self->spawnflags & 1 )
- {//falling death
- G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_FALLING );
- if ( !activator->s.number && activator->health <= 0 && 1 )
- {
- extern void CGCam_Fade( vec4_t source, vec4_t dest, float duration );
- float src[4] = {0,0,0,0},dst[4]={0,0,0,1};
- CGCam_Fade( src, dst, 10000 );
- }
- }
- else if ( self->spawnflags & 2 ) // electrical
- {
- G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_ELECTROCUTE );
-
- if ( activator->client )
- {
- activator->s.powerups |= ( 1 << PW_SHOCKED );
- activator->client->ps.powerups[PW_SHOCKED] = level.time + 4000;
- }
- }
- else
- {
- G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_UNKNOWN);
- }
- }
- void SP_target_kill( gentity_t *self )
- {
- self->e_UseFunc = useF_target_kill_use;
- }
- /*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
- Used as a positional target for in-game calculation, like jumppad targets.
- info_notnull does the same thing
- */
- void SP_target_position( gentity_t *self ){
- G_SetOrigin( self, self->s.origin );
- }
- //static -slc
- void target_location_linkup(gentity_t *ent)
- {
- int i;
- if (level.locationLinked)
- return;
- level.locationLinked = qtrue;
- level.locationHead = NULL;
- for (i = 0, ent = g_entities; i < globals.num_entities; i++, ent++) {
- if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
- ent->nextTrain = level.locationHead;
- level.locationHead = ent;
- }
- }
- // All linked together now
- }
- /*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
- Set "message" to the name of this location.
- Set "count" to 0-7 for color.
- 0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
- Closest target_location in sight used for the location, if none
- in site, closest in distance
- */
- void SP_target_location( gentity_t *self ){
- self->e_ThinkFunc = thinkF_target_location_linkup;
- self->nextthink = level.time + 1000; // Let them all spawn first
- G_SetOrigin( self, self->s.origin );
- }
- //===NEW===================================================================
- /*QUAKED target_counter (1.0 0 0) (-4 -4 -4) (4 4 4) x x x x x x x INACTIVE
- Acts as an intermediary for an action that takes multiple inputs.
- INACTIVE cannot be used until used by a target_activate
- target2 - what the counter should fire each time it's incremented and does NOT reach it's count
- After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
- bounceCount - number of times the counter should reset to it's full count when it's done
- */
- void target_counter_use( gentity_t *self, gentity_t *other, gentity_t *activator )
- {
- if ( self->count == 0 )
- {
- return;
- }
-
- //gi.Printf("target_counter %s used by %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number );
- self->count--;
- if ( activator )
- {
- Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_counter %s used by %s (%d/%d)\n", self->targetname, activator->targetname, (self->max_health-self->count), self->max_health );
- }
- if ( self->count )
- {
- if ( self->target2 )
- {
- //gi.Printf("target_counter %s firing target2 from %s, entnum %d\n", self->targetname, activator->targetname, activator->s.number );
- G_UseTargets2( self, activator, self->target2 );
- }
- return;
- }
-
- G_ActivateBehavior( self,BSET_USE );
- if ( self->spawnflags & 128 )
- {
- self->svFlags |= SVF_INACTIVE;
- }
- self->activator = activator;
- G_UseTargets( self, activator );
- if ( self->count == 0 )
- {
- if ( self->bounceCount == 0 )
- {
- return;
- }
- self->count = self->max_health;
- if ( self->bounceCount > 0 )
- {//-1 means bounce back forever
- self->bounceCount--;
- }
- }
- }
- void SP_target_counter (gentity_t *self)
- {
- self->wait = -1;
- if (!self->count)
- {
- self->count = 2;
- }
- //if ( self->bounceCount > 0 )//let's always set this anyway
- {//we will reset when we use up our count, remember our initial count
- self->max_health = self->count;
- }
- self->e_UseFunc = useF_target_counter_use;
- }
- /*QUAKED target_random (.5 .5 .5) (-4 -4 -4) (4 4 4) USEONCE
- Randomly fires off only one of it's targets each time used
- USEONCE set to never fire again
- */
- void target_random_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- int t_count = 0, pick;
- gentity_t *t = NULL;
- //gi.Printf("target_random %s used by %s (entnum %d)\n", self->targetname, activator->targetname, activator->s.number );
- G_ActivateBehavior(self,BSET_USE);
- if(self->spawnflags & 1)
- {
- self->e_UseFunc = useF_NULL;
- }
- while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
- {
- if (t != self)
- {
- t_count++;
- }
- }
- if(!t_count)
- {
- return;
- }
- if(t_count == 1)
- {
- G_UseTargets (self, activator);
- return;
- }
- //FIXME: need a seed
- pick = Q_irand(1, t_count);
- t_count = 0;
- while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL )
- {
- if (t != self)
- {
- t_count++;
- }
- else
- {
- continue;
- }
-
- if (t == self)
- {
- // gi.Printf ("WARNING: Entity used itself.\n");
- }
- else if(t_count == pick)
- {
- if (t->e_UseFunc != useF_NULL) // check can be omitted
- {
- GEntity_UseFunc(t, self, activator);
- return;
- }
- }
- if (!self->inuse)
- {
- gi.Printf("entity was removed while using targets\n");
- return;
- }
- }
- }
- void SP_target_random (gentity_t *self)
- {
- self->e_UseFunc = useF_target_random_use;
- }
- int numNewICARUSEnts = 0;
- void scriptrunner_run (gentity_t *self)
- {
- /*
- if (self->behaviorSet[BSET_USE])
- {
- char newname[MAX_FILENAME_LENGTH];
- sprintf((char *) &newname, "%s/%s", Q3_SCRIPT_DIR, self->behaviorSet[BSET_USE] );
- ICARUS_RunScript( self, newname );
- }
- */
- if ( self->count != -1 )
- {
- if ( self->count <= 0 )
- {
- self->e_UseFunc = useF_NULL;
- self->behaviorSet[BSET_USE] = NULL;
- return;
- }
- else
- {
- --self->count;
- }
- }
- if (self->behaviorSet[BSET_USE])
- {
- if ( self->spawnflags & 1 )
- {
- if ( !self->activator )
- {
- Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid entity!\n");
- return;
- }
- if ( self->activator->m_iIcarusID == IIcarusInterface::ICARUS_INVALID )
- {//Need to be initialized through ICARUS
- if ( !self->activator->script_targetname || !self->activator->script_targetname[0] )
- {
- //We don't have a script_targetname, so create a new one
- self->activator->script_targetname = va( "newICARUSEnt%d", numNewICARUSEnts++ );
- }
- if ( Quake3Game()->ValidEntity( self->activator ) )
- {
- Quake3Game()->InitEntity( self->activator );
- }
- else
- {
- Quake3Game()->DebugPrint( IGameInterface::WL_ERROR, "target_scriptrunner tried to run on invalid ICARUS activator!\n");
- return;
- }
- }
- Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner running %s on activator %s\n", self->behaviorSet[BSET_USE], self->activator->targetname );
- Quake3Game()->RunScript( self->activator, self->behaviorSet[BSET_USE] );
- }
- else
- {
- if ( self->activator )
- {
- Quake3Game()->DebugPrint( IGameInterface::WL_VERBOSE, "target_scriptrunner %s used by %s\n", self->targetname, self->activator->targetname );
- }
- G_ActivateBehavior( self, BSET_USE );
- }
- }
- if ( self->wait )
- {
- self->nextthink = level.time + self->wait;
- }
- }
- void target_scriptrunner_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- if ( self->nextthink > level.time )
- {
- return;
- }
- self->activator = activator;
- G_SetEnemy( self, other );
- if ( self->delay )
- {//delay before firing scriptrunner
- self->e_ThinkFunc = thinkF_scriptrunner_run;
- self->nextthink = level.time + self->delay;
- }
- else
- {
- scriptrunner_run (self);
- }
- }
- /*QUAKED target_scriptrunner (1 0 0) (-4 -4 -4) (4 4 4) runonactivator x x x x x x INACTIVE
- --- SPAWNFLAGS ---
- runonactivator - Will run the script on the entity that used this or tripped the trigger that used this
- INACTIVE - start off
- ----- KEYS ------
- Usescript - Script to run when used
- count - how many times to run, -1 = infinite. Default is once
- wait - can't be used again in this amount of seconds (Default is 1 second if it's multiple-use)
- delay - how long to wait after use to run script
- */
- void SP_target_scriptrunner( gentity_t *self )
- {
- if (!self->behaviorSet[BSET_USE])
- {
- gi.Printf(S_COLOR_RED "SP_target_scriptrunner %s has no USESCRIPT\n", self->targetname );
- }
- if ( self->spawnflags & 128 )
- {
- self->svFlags |= SVF_INACTIVE;
- }
- if ( !self->count )
- {
- self->count = 1;//default 1 use only
- }
- /*
- else if ( !self->wait )
- {
- self->wait = 1;//default wait of 1 sec
- }
- */
- // FIXME: this is a hack... because delay is read in as an int, so I'm bypassing that because it's too late in the project to change it and I want to be able to set less than a second delays
- // no one should be setting a radius on a scriptrunner, if they are this would be bad, take this out for the next project
- self->radius = 0.0f;
- G_SpawnFloat( "delay", "0", &self->radius );
- self->delay = self->radius * 1000;//sec to ms
- self->wait *= 1000;//sec to ms
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_scriptrunner_use;
- }
- void target_gravity_change_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(self,BSET_USE);
- if ( self->spawnflags & 1 )
- {
- gi.cvar_set("g_gravity", va("%f", self->speed));
- }
- else if ( activator->client )
- {
- int grav = floor(self->speed);
- /*
- if ( activator->client->ps.gravity != grav )
- {
- gi.Printf("%s gravity changed to %d\n", activator->targetname, grav );
- }
- */
- activator->client->ps.gravity = grav;
- activator->svFlags |= SVF_CUSTOM_GRAVITY;
- //FIXME: need a way to set this back to normal?
- }
- }
- /*QUAKED target_gravity_change (1 0 0) (-4 -4 -4) (4 4 4) GLOBAL
- "gravity" - Normal = 800, Valid range: any
- GLOBAL - Apply to entire world, not just the activator
- */
- void SP_target_gravity_change( gentity_t *self )
- {
- G_SetOrigin( self, self->s.origin );
- G_SpawnFloat( "gravity", "0", &self->speed );
- self->e_UseFunc = useF_target_gravity_change_use;
- }
- void target_friction_change_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(self,BSET_USE);
- if(self->spawnflags & 1)
- {//FIXME - make a global?
- //gi.Cvar_Set("g_friction", va("%d", self->health));
- }
- else if(activator->client)
- {
- activator->client->ps.friction = self->health;
- }
- }
- /*QUAKED target_friction_change (1 0 0) (-4 -4 -4) (4 4 4)
- "friction" Normal = 6, Valid range 0 - 10
- */
- void SP_target_friction_change( gentity_t *self )
- {
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_friction_change_use;
- }
- void set_mission_stats_cvars( void )
- {
- char text[1024]={0};
- //we'll assume that the activator is the player
- gclient_t* const client = &level.clients[0];
- if (!client)
- {
- return;
- }
- cg_entities[0].gent->client->sess.missionStats.enemiesKilled;
- gi.cvar_set("ui_stats_enemieskilled", va("%d",client->sess.missionStats.enemiesKilled)); //pass this on to the menu
- if (cg_entities[0].gent->client->sess.missionStats.totalSecrets)
- {
- cgi_SP_GetStringTextString( "SP_INGAME_SECRETAREAS_OF", text, sizeof(text) );
- gi.cvar_set("ui_stats_secretsfound", va("%d %s %d",
- cg_entities[0].gent->client->sess.missionStats.secretsFound,
- text,
- cg_entities[0].gent->client->sess.missionStats.totalSecrets));
- }
- else // Setting ui_stats_secretsfound to 0 will hide the text on screen
- {
- gi.cvar_set("ui_stats_secretsfound", "0");
- }
- // Find the favorite weapon
- int wpn=0,i;
- int max_wpn = cg_entities[0].gent->client->sess.missionStats.weaponUsed[0];
- for (i = 1; i<WP_NUM_WEAPONS; i++)
- {
- if (cg_entities[0].gent->client->sess.missionStats.weaponUsed[i] > max_wpn)
- {
- max_wpn = cg_entities[0].gent->client->sess.missionStats.weaponUsed[i];
- wpn = i;
- }
- }
- if ( wpn )
- {
- gitem_t *wItem= FindItemForWeapon( (weapon_t)wpn);
- cgi_SP_GetStringTextString( va("SP_INGAME_%s",wItem->classname ), text, sizeof( text ));
- gi.cvar_set("ui_stats_fave", va("%s",text)); //pass this on to the menu
- }
- gi.cvar_set("ui_stats_shots", va("%d",client->sess.missionStats.shotsFired)); //pass this on to the menu
- gi.cvar_set("ui_stats_hits", va("%d",client->sess.missionStats.hits)); //pass this on to the menu
- const float percent = cg_entities[0].gent->client->sess.missionStats.shotsFired? 100.0f * (float)cg_entities[0].gent->client->sess.missionStats.hits / cg_entities[0].gent->client->sess.missionStats.shotsFired : 0;
- gi.cvar_set("ui_stats_accuracy", va("%.2f%%",percent)); //pass this on to the menu
- gi.cvar_set("ui_stats_thrown", va("%d",client->sess.missionStats.saberThrownCnt)); //pass this on to the menu
- gi.cvar_set("ui_stats_blocks", va("%d",client->sess.missionStats.saberBlocksCnt));
- gi.cvar_set("ui_stats_legattacks", va("%d",client->sess.missionStats.legAttacksCnt));
- gi.cvar_set("ui_stats_armattacks", va("%d",client->sess.missionStats.armAttacksCnt));
- gi.cvar_set("ui_stats_bodyattacks", va("%d",client->sess.missionStats.torsoAttacksCnt));
- gi.cvar_set("ui_stats_absorb", va("%d",client->sess.missionStats.forceUsed[FP_ABSORB]));
- gi.cvar_set("ui_stats_heal", va("%d",client->sess.missionStats.forceUsed[FP_HEAL]));
- gi.cvar_set("ui_stats_mindtrick", va("%d",client->sess.missionStats.forceUsed[FP_TELEPATHY]));
- gi.cvar_set("ui_stats_protect", va("%d",client->sess.missionStats.forceUsed[FP_PROTECT]));
- gi.cvar_set("ui_stats_jump", va("%d",client->sess.missionStats.forceUsed[FP_LEVITATION]));
- gi.cvar_set("ui_stats_pull", va("%d",client->sess.missionStats.forceUsed[FP_PULL]));
- gi.cvar_set("ui_stats_push", va("%d",client->sess.missionStats.forceUsed[FP_PUSH]));
- gi.cvar_set("ui_stats_sense", va("%d",client->sess.missionStats.forceUsed[FP_SEE]));
- gi.cvar_set("ui_stats_speed", va("%d",client->sess.missionStats.forceUsed[FP_SPEED]));
- gi.cvar_set("ui_stats_defense", va("%d",client->sess.missionStats.forceUsed[FP_SABER_DEFENSE]));
- gi.cvar_set("ui_stats_offense", va("%d",client->sess.missionStats.forceUsed[FP_SABER_OFFENSE]));
- gi.cvar_set("ui_stats_throw", va("%d",client->sess.missionStats.forceUsed[FP_SABERTHROW]));
- gi.cvar_set("ui_stats_drain", va("%d",client->sess.missionStats.forceUsed[FP_DRAIN]));
- gi.cvar_set("ui_stats_grip", va("%d",client->sess.missionStats.forceUsed[FP_GRIP]));
- gi.cvar_set("ui_stats_lightning", va("%d",client->sess.missionStats.forceUsed[FP_LIGHTNING]));
- gi.cvar_set("ui_stats_rage", va("%d",client->sess.missionStats.forceUsed[FP_RAGE]));
- }
- #include "..\cgame\cg_media.h" //access to cgs
- extern void G_ChangeMap (const char *mapname, const char *spawntarget, qboolean hub); //g_utils
- void target_level_change_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(self,BSET_USE);
- if( self->message && !Q_stricmp( "disconnect", self->message ) )
- {
- gi.SendConsoleCommand( "disconnect\n");
- }
- else
- {
- G_ChangeMap( self->message, self->target, (self->spawnflags&1) );
- }
- if (self->count>=0)
- {
- gi.cvar_set("tier_storyinfo", va("%i",self->count));
- if (level.mapname[0] == 't' && level.mapname[2] == '_'
- && ( level.mapname[1] == '1' || level.mapname[1] == '2' || level.mapname[1] == '3' )
- )
- {
- char s[2048];
- gi.Cvar_VariableStringBuffer("tiers_complete", s, sizeof(s)); //get the current list
- if (*s)
- {
- gi.cvar_set("tiers_complete", va("%s %s", s, level.mapname)); //strcat this level into the existing list
- }
- else
- {
- gi.cvar_set("tiers_complete", level.mapname); //set this level into the list
- }
- }
- if (self->noise_index)
- {
- cgi_S_StopSounds();
- cgi_S_StartSound( NULL, 0, CHAN_VOICE, cgs.sound_precache[ self->noise_index ] );
- }
- }
- set_mission_stats_cvars();
- }
- /*QUAKED target_level_change (1 0 0) (-4 -4 -4) (4 4 4) HUB NO_STORYSOUND
- HUB - Will save the current map's status and load the next map with any saved status it may have
- NO_STORYSOUND - will not play storyinfo wav file, even if you '++' or set tier_storyinfo
- "mapname" - Name of map to change to or "+menuname" to launch a menu instead
- "target" - Name of spawnpoint to start at in the new map
- "tier_storyinfo" - integer to set cvar or "++" to just increment
- "storyhead" - which head to show on menu [luke, kyle, or prot]
- "saber_menu" - integer to set cvar for menu
- "weapon_menu" - integer to set cvar for ingame weapon menu
- */
- void SP_target_level_change( gentity_t *self )
- {
- if ( !self->message )
- {
- G_Error( "target_level_change with no mapname!\n");
- return;
- }
-
- char *s;
- if (G_SpawnString( "tier_storyinfo", "", &s ))
- {
- if (*s == '+')
- {
- self->noise_index = G_SoundIndex(va("sound/chars/tiervictory/%s.mp3",level.mapname) );
- self->count = gi.Cvar_VariableIntegerValue("tier_storyinfo")+1;
- G_SoundIndex(va("sound/chars/storyinfo/%d.mp3",self->count)); //cache for menu
- }
- else
- {
- self->count = atoi(s);
- if( !(self->spawnflags & 2) )
- {
- self->noise_index = G_SoundIndex(va("sound/chars/storyinfo/%d.mp3",self->count) );
- }
- }
- if (G_SpawnString( "storyhead", "", &s ))
- { //[luke, kyle, or prot]
- gi.cvar_set("storyhead", s); //pass this on to the menu
- }
- else
- { //show head based on mapname
- gi.cvar_set("storyhead", level.mapname); //pass this on to the menu
- }
- }
- if (G_SpawnString( "saber_menu", "", &s ))
- {
- gi.cvar_set("saber_menu", s); //pass this on to the menu
- }
- if (G_SpawnString( "weapon_menu", "1", &s ))
- {
- gi.cvar_set("weapon_menu", s); //pass this on to the menu
- }
- else
- {
- gi.cvar_set("weapon_menu", "0"); //pass this on to the menu
- }
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_level_change_use;
- }
- /*QUAKED target_change_parm (1 0 0) (-4 -4 -4) (4 4 4)
- Copies any parms set on this ent to the entity that fired the trigger/button/whatever that uses this
- parm1
- parm2
- parm3
- parm4
- parm5
- parm6
- parm7
- parm8
- parm9
- parm10
- parm11
- parm12
- parm13
- parm14
- parm15
- parm16
- */
- void Q3_SetParm (int entID, int parmNum, const char *parmValue);
- void target_change_parm_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- if ( !activator || !self )
- {
- return;
- }
- //FIXME: call capyparms
- if ( self->parms )
- {
- for ( int parmNum = 0; parmNum < MAX_PARMS; parmNum++ )
- {
- if ( self->parms->parm[parmNum] && self->parms->parm[parmNum][0] )
- {
- Q3_SetParm( activator->s.number, parmNum, self->parms->parm[parmNum] );
- }
- }
- }
- }
- void SP_target_change_parm( gentity_t *self )
- {
- if ( !self->parms )
- {//ERROR!
- return;
- }
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_change_parm_use;
- }
- void target_play_music_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- G_ActivateBehavior(self,BSET_USE);
- gi.SetConfigstring( CS_MUSIC, self->message );
- }
- /*QUAKED target_play_music (1 0 0) (-4 -4 -4) (4 4 4)
- target_play_music
- Plays the requested music files when this target is used.
- "targetname"
- "music" music WAV or MP3 file ( music/introfile.mp3 [optional] music/loopfile.mp3 )
- If an intro file and loop file are specified, the intro plays first, then the looping
- portion will start and loop indefinetly. If no introfile is entered, only the loopfile
- will play.
- */
- void SP_target_play_music( gentity_t *self )
- {
- char *s;
- G_SetOrigin( self, self->s.origin );
- if (!G_SpawnString( "music", "", &s )) {
- G_Error( "target_play_music without a music key at %s", vtos( self->s.origin ) );
- }
- self->message = G_NewString (s);
- self->e_UseFunc = useF_target_play_music_use;
- extern cvar_t *com_buildScript;
- //Precache!
- if (com_buildScript->integer) {//copy this puppy over
- char buffer[MAX_QPATH];
- fileHandle_t hFile;
- Q_strncpyz( buffer, s, sizeof(buffer) );
- COM_DefaultExtension( buffer, sizeof(buffer), ".mp3");
-
- gi.FS_FOpenFile(buffer, &hFile, FS_READ);
- if (hFile) {
- gi.FS_FCloseFile( hFile );
- }
- }
- }
- extern bool allowNormalAutosave;
- void target_autosave_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- if(!allowNormalAutosave)
- return;
- G_ActivateBehavior(self,BSET_USE);
- //gi.SendServerCommand( NULL, "cp @SP_INGAME_CHECKPOINT" );
- CG_CenterPrint( "@SP_INGAME_CHECKPOINT", SCREEN_HEIGHT * 0.25 ); //jump the network
- gi.SendConsoleCommand( "wait 2;save auto\n" );
- }
- /*QUAKED target_autosave (1 0 0) (-4 -4 -4) (4 4 4)
- Auto save the game in two frames.
- Make sure it won't trigger during dialogue or cinematic or it will stutter!
- */
- void SP_target_autosave( gentity_t *self )
- {
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_autosave_use;
- }
- void target_secret_use(gentity_t *self, gentity_t *other, gentity_t *activator)
- {
- //we'll assume that the activator is the player
- gclient_t* const client = &level.clients[0];
- client->sess.missionStats.secretsFound++;
- if ( activator )
- {
- G_Sound( activator, self->noise_index );
- }
- else
- {
- G_Sound( self, self->noise_index );
- }
- gi.SendServerCommand( NULL, "cp @SP_INGAME_SECRET_AREA" );
- assert(client->sess.missionStats.totalSecrets);
- }
- /*QUAKED target_secret (1 0 1) (-4 -4 -4) (4 4 4)
- You found a Secret!
- "count" - how many secrets on this level,
- if more than one on a level, be sure they all have the same count!
- */
- void SP_target_secret( gentity_t *self )
- {
- G_SetOrigin( self, self->s.origin );
- self->e_UseFunc = useF_target_secret_use;
- self->noise_index = G_SoundIndex("sound/interface/secret_area");
- if (self->count)
- {
- gi.cvar_set("newTotalSecrets", va("%i",self->count));
- }
- }
|