123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // leave this line at the top for all g_xxxx.cpp files...
- #include "g_headers.h"
- #include "g_local.h"
- #include "g_functions.h"
- extern void InitMover( gentity_t *ent );
- extern gentity_t *G_TestEntityPosition( gentity_t *ent );
- void func_wait_return_solid( gentity_t *self )
- {
- //once a frame, see if it's clear.
- self->clipmask = CONTENTS_BODY;//|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;
- if ( !(self->spawnflags&16) || G_TestEntityPosition( self ) == NULL )
- {
- gi.SetBrushModel( self, self->model );
- VectorCopy( self->currentOrigin, self->pos1 );
- InitMover( self );
- /*
- VectorCopy( self->s.origin, self->s.pos.trBase );
- VectorCopy( self->s.origin, self->currentOrigin );
- */
- //if we moved, we want the *current* origin, not our start origin!
- VectorCopy( self->currentOrigin, self->s.pos.trBase );
- gi.linkentity( self );
- self->svFlags &= ~SVF_NOCLIENT;
- self->s.eFlags &= ~EF_NODRAW;
- self->e_UseFunc = useF_func_usable_use;
- self->clipmask = 0;
- if ( self->target2 && self->target2[0] )
- {
- G_UseTargets2( self, self->activator, self->target2 );
- }
- if ( self->s.eFlags & EF_ANIM_ONCE )
- {//Start our anim
- self->s.frame = 0;
- }
- //NOTE: be sure to reset the brushmodel before doing this or else CONTENTS_OPAQUE may not be on when you call this
- if ( !(self->spawnflags&1) )
- {//START_OFF doesn't effect area portals
- gi.AdjustAreaPortalState( self, qfalse );
- }
- }
- else
- {
- self->clipmask = 0;
- self->e_ThinkFunc = thinkF_func_wait_return_solid;
- self->nextthink = level.time + FRAMETIME;
- }
- }
- void func_usable_think( gentity_t *self )
- {
- if ( self->spawnflags & 8 )
- {
- self->svFlags |= SVF_PLAYER_USABLE; //Replace the usable flag
- self->e_UseFunc = useF_func_usable_use;
- self->e_ThinkFunc = thinkF_NULL;
- }
- }
- qboolean G_EntIsRemovableUsable( int entNum )
- {
- gentity_t *ent = &g_entities[entNum];
- if ( ent->classname && !Q_stricmp( "func_usable", ent->classname ) )
- {
- if ( !(ent->s.eFlags&EF_SHADER_ANIM) && !(ent->spawnflags&8) && ent->targetname )
- {//not just a shader-animator and not ALWAYS_ON, so it must be removable somehow
- return qtrue;
- }
- }
- return qfalse;
- }
- void func_usable_use( gentity_t *self, gentity_t *other, gentity_t *activator )
- {//Toggle on and off
- if ( other == activator )
- {//directly used by use button trace
- if ( (self->spawnflags&32) )
- {//only usable by NPCs
- if ( activator->NPC == NULL )
- {//Not an NPC
- return;
- }
- }
- }
- G_ActivateBehavior( self, BSET_USE );
- if ( self->s.eFlags & EF_SHADER_ANIM )
- {//animate shader when used
- self->s.frame++;//inc frame
- if ( self->s.frame > self->endFrame )
- {//wrap around
- self->s.frame = 0;
- }
- if ( self->target && self->target[0] )
- {
- G_UseTargets( self, activator );
- }
- }
- else if ( self->spawnflags & 8 )
- {//ALWAYS_ON
- //Remove the ability to use the entity directly
- self->svFlags &= ~SVF_PLAYER_USABLE;
- //also remove ability to call any use func at all!
- self->e_UseFunc = useF_NULL;
-
- if(self->target && self->target[0])
- {
- G_UseTargets(self, activator);
- }
-
- if ( self->wait )
- {
- self->e_ThinkFunc = thinkF_func_usable_think;
- self->nextthink = level.time + ( self->wait * 1000 );
- }
- return;
- }
- else if ( !self->count )
- {//become solid again
- self->count = 1;
- self->activator = activator;
- func_wait_return_solid( self );
- }
- else
- {
- //NOTE: MUST do this BEFORE clearing contents, or you may not open the area portal!!!
- if ( !(self->spawnflags&1) )
- {//START_OFF doesn't effect area portals
- gi.AdjustAreaPortalState( self, qtrue );
- }
- self->s.solid = 0;
- self->contents = 0;
- self->clipmask = 0;
- self->svFlags |= SVF_NOCLIENT;
- self->s.eFlags |= EF_NODRAW;
- self->count = 0;
- if(self->target && self->target[0])
- {
- G_UseTargets(self, activator);
- }
- self->e_ThinkFunc = thinkF_NULL;
- self->nextthink = -1;
- }
- }
- void func_usable_pain(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc)
- {
- if ( self->paintarget )
- {
- G_UseTargets2 (self, self->activator, self->paintarget);
- }
- else
- {
- GEntity_UseFunc( self, attacker, attacker );
- }
- }
- void func_usable_die(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc)
- {
- self->takedamage = qfalse;
- GEntity_UseFunc( self, inflictor, attacker );
- }
- /*QUAKED func_usable (0 .5 .8) ? STARTOFF AUTOANIMATE ANIM_ONCE ALWAYS_ON BLOCKCHECK NPC_USE PLAYER_USE INACTIVE
- START_OFF - the wall will not be there
- AUTOANIMATE - if a model is used it will animate
- ANIM_ONCE - When turned on, goes through anim once
- ALWAYS_ON - Doesn't toggle on and off when used, just runs usescript and fires target
- NPC_ONLY - Only NPCs can directly use this
- PLAYER_USE - Player can use it with the use button
- BLOCKCHECK - Will not turn on while something is inside it
- A bmodel that just sits there, doing nothing. Can be used for conditional walls and models.
- "targetname" - When used, will toggle on and off
- "target" Will fire this target every time it is toggled OFF
- "target2" Will fire this target every time it is toggled ON
- "model2" .md3 model to also draw
- "modelAngles" md3 model's angles <pitch yaw roll> (in addition to any rotation on the part of the brush entity itself)
- "color" constantLight color
- "light" constantLight radius
- "usescript" script to run when turned on
- "deathscript" script to run when turned off
- "wait" amount of time before the object is usable again (only valid with ALWAYS_ON flag)
- "health" if it has health, it will be used whenever shot at/killed - if you want it to only be used once this way, set health to 1
- "endframe" Will make it animate to next shader frame when used, not turn on/off... set this to number of frames in the shader, minus 1
- "forcevisible" - When you turn on force sight (any level), you can see these draw through the entire level...
- */
- void SP_func_usable( gentity_t *self )
- {
- gi.SetBrushModel( self, self->model );
- InitMover( self );
- VectorCopy( self->s.origin, self->s.pos.trBase );
- VectorCopy( self->s.origin, self->currentOrigin );
- VectorCopy( self->s.origin, self->pos1 );
- self->count = 1;
- if (self->spawnflags & 1)
- {
- self->spawnContents = self->contents; // It Navs can temporarly turn it "on"
- self->s.solid = 0;
- self->contents = 0;
- self->clipmask = 0;
- self->svFlags |= SVF_NOCLIENT;
- self->s.eFlags |= EF_NODRAW;
- self->count = 0;
- }
- if (self->spawnflags & 2)
- {
- self->s.eFlags |= EF_ANIM_ALLFAST;
- }
- if (self->spawnflags & 4)
- {//FIXME: need to be able to do change to something when it's done? Or not be usable until it's done?
- self->s.eFlags |= EF_ANIM_ONCE;
- }
- self->e_UseFunc = useF_func_usable_use;
- if ( self->health )
- {
- self->takedamage = qtrue;
- self->e_DieFunc = dieF_func_usable_die;
- self->e_PainFunc = painF_func_usable_pain;
- }
- if ( self->endFrame > 0 )
- {
- self->s.frame = self->startFrame = 0;
- self->s.eFlags |= EF_SHADER_ANIM;
- }
- gi.linkentity (self);
- int forceVisible = 0;
- G_SpawnInt( "forcevisible", "0", &forceVisible );
- if ( forceVisible )
- {//can see these through walls with force sight, so must be broadcast
- if ( VectorCompare( self->s.origin, vec3_origin ) )
- {//no origin brush
- self->svFlags |= SVF_BROADCAST;
- }
- self->s.eFlags |= EF_FORCE_VISIBLE;
- }
- }
|