g_usable.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // leave this line at the top for all g_xxxx.cpp files...
  2. #include "g_headers.h"
  3. #include "g_local.h"
  4. #include "g_functions.h"
  5. extern void InitMover( gentity_t *ent );
  6. extern gentity_t *G_TestEntityPosition( gentity_t *ent );
  7. void func_wait_return_solid( gentity_t *self )
  8. {
  9. //once a frame, see if it's clear.
  10. self->clipmask = CONTENTS_BODY;//|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;
  11. if ( !(self->spawnflags&16) || G_TestEntityPosition( self ) == NULL )
  12. {
  13. gi.SetBrushModel( self, self->model );
  14. VectorCopy( self->currentOrigin, self->pos1 );
  15. InitMover( self );
  16. /*
  17. VectorCopy( self->s.origin, self->s.pos.trBase );
  18. VectorCopy( self->s.origin, self->currentOrigin );
  19. */
  20. //if we moved, we want the *current* origin, not our start origin!
  21. VectorCopy( self->currentOrigin, self->s.pos.trBase );
  22. gi.linkentity( self );
  23. self->svFlags &= ~SVF_NOCLIENT;
  24. self->s.eFlags &= ~EF_NODRAW;
  25. self->e_UseFunc = useF_func_usable_use;
  26. self->clipmask = 0;
  27. if ( self->target2 && self->target2[0] )
  28. {
  29. G_UseTargets2( self, self->activator, self->target2 );
  30. }
  31. if ( self->s.eFlags & EF_ANIM_ONCE )
  32. {//Start our anim
  33. self->s.frame = 0;
  34. }
  35. //NOTE: be sure to reset the brushmodel before doing this or else CONTENTS_OPAQUE may not be on when you call this
  36. if ( !(self->spawnflags&1) )
  37. {//START_OFF doesn't effect area portals
  38. gi.AdjustAreaPortalState( self, qfalse );
  39. }
  40. }
  41. else
  42. {
  43. self->clipmask = 0;
  44. self->e_ThinkFunc = thinkF_func_wait_return_solid;
  45. self->nextthink = level.time + FRAMETIME;
  46. }
  47. }
  48. void func_usable_think( gentity_t *self )
  49. {
  50. if ( self->spawnflags & 8 )
  51. {
  52. self->svFlags |= SVF_PLAYER_USABLE; //Replace the usable flag
  53. self->e_UseFunc = useF_func_usable_use;
  54. self->e_ThinkFunc = thinkF_NULL;
  55. }
  56. }
  57. qboolean G_EntIsRemovableUsable( int entNum )
  58. {
  59. gentity_t *ent = &g_entities[entNum];
  60. if ( ent->classname && !Q_stricmp( "func_usable", ent->classname ) )
  61. {
  62. if ( !(ent->s.eFlags&EF_SHADER_ANIM) && !(ent->spawnflags&8) && ent->targetname )
  63. {//not just a shader-animator and not ALWAYS_ON, so it must be removable somehow
  64. return qtrue;
  65. }
  66. }
  67. return qfalse;
  68. }
  69. void func_usable_use( gentity_t *self, gentity_t *other, gentity_t *activator )
  70. {//Toggle on and off
  71. if ( other == activator )
  72. {//directly used by use button trace
  73. if ( (self->spawnflags&32) )
  74. {//only usable by NPCs
  75. if ( activator->NPC == NULL )
  76. {//Not an NPC
  77. return;
  78. }
  79. }
  80. }
  81. G_ActivateBehavior( self, BSET_USE );
  82. if ( self->s.eFlags & EF_SHADER_ANIM )
  83. {//animate shader when used
  84. self->s.frame++;//inc frame
  85. if ( self->s.frame > self->endFrame )
  86. {//wrap around
  87. self->s.frame = 0;
  88. }
  89. if ( self->target && self->target[0] )
  90. {
  91. G_UseTargets( self, activator );
  92. }
  93. }
  94. else if ( self->spawnflags & 8 )
  95. {//ALWAYS_ON
  96. //Remove the ability to use the entity directly
  97. self->svFlags &= ~SVF_PLAYER_USABLE;
  98. //also remove ability to call any use func at all!
  99. self->e_UseFunc = useF_NULL;
  100. if(self->target && self->target[0])
  101. {
  102. G_UseTargets(self, activator);
  103. }
  104. if ( self->wait )
  105. {
  106. self->e_ThinkFunc = thinkF_func_usable_think;
  107. self->nextthink = level.time + ( self->wait * 1000 );
  108. }
  109. return;
  110. }
  111. else if ( !self->count )
  112. {//become solid again
  113. self->count = 1;
  114. self->activator = activator;
  115. func_wait_return_solid( self );
  116. }
  117. else
  118. {
  119. //NOTE: MUST do this BEFORE clearing contents, or you may not open the area portal!!!
  120. if ( !(self->spawnflags&1) )
  121. {//START_OFF doesn't effect area portals
  122. gi.AdjustAreaPortalState( self, qtrue );
  123. }
  124. self->s.solid = 0;
  125. self->contents = 0;
  126. self->clipmask = 0;
  127. self->svFlags |= SVF_NOCLIENT;
  128. self->s.eFlags |= EF_NODRAW;
  129. self->count = 0;
  130. if(self->target && self->target[0])
  131. {
  132. G_UseTargets(self, activator);
  133. }
  134. self->e_ThinkFunc = thinkF_NULL;
  135. self->nextthink = -1;
  136. }
  137. }
  138. void func_usable_pain(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, const vec3_t point, int damage, int mod,int hitLoc)
  139. {
  140. if ( self->paintarget )
  141. {
  142. G_UseTargets2 (self, self->activator, self->paintarget);
  143. }
  144. else
  145. {
  146. GEntity_UseFunc( self, attacker, attacker );
  147. }
  148. }
  149. void func_usable_die(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc)
  150. {
  151. self->takedamage = qfalse;
  152. GEntity_UseFunc( self, inflictor, attacker );
  153. }
  154. /*QUAKED func_usable (0 .5 .8) ? STARTOFF AUTOANIMATE ANIM_ONCE ALWAYS_ON BLOCKCHECK NPC_USE PLAYER_USE INACTIVE
  155. START_OFF - the wall will not be there
  156. AUTOANIMATE - if a model is used it will animate
  157. ANIM_ONCE - When turned on, goes through anim once
  158. ALWAYS_ON - Doesn't toggle on and off when used, just runs usescript and fires target
  159. NPC_ONLY - Only NPCs can directly use this
  160. PLAYER_USE - Player can use it with the use button
  161. BLOCKCHECK - Will not turn on while something is inside it
  162. A bmodel that just sits there, doing nothing. Can be used for conditional walls and models.
  163. "targetname" - When used, will toggle on and off
  164. "target" Will fire this target every time it is toggled OFF
  165. "target2" Will fire this target every time it is toggled ON
  166. "model2" .md3 model to also draw
  167. "modelAngles" md3 model's angles <pitch yaw roll> (in addition to any rotation on the part of the brush entity itself)
  168. "color" constantLight color
  169. "light" constantLight radius
  170. "usescript" script to run when turned on
  171. "deathscript" script to run when turned off
  172. "wait" amount of time before the object is usable again (only valid with ALWAYS_ON flag)
  173. "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
  174. "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
  175. "forcevisible" - When you turn on force sight (any level), you can see these draw through the entire level...
  176. */
  177. void SP_func_usable( gentity_t *self )
  178. {
  179. gi.SetBrushModel( self, self->model );
  180. InitMover( self );
  181. VectorCopy( self->s.origin, self->s.pos.trBase );
  182. VectorCopy( self->s.origin, self->currentOrigin );
  183. VectorCopy( self->s.origin, self->pos1 );
  184. self->count = 1;
  185. if (self->spawnflags & 1)
  186. {
  187. self->spawnContents = self->contents; // It Navs can temporarly turn it "on"
  188. self->s.solid = 0;
  189. self->contents = 0;
  190. self->clipmask = 0;
  191. self->svFlags |= SVF_NOCLIENT;
  192. self->s.eFlags |= EF_NODRAW;
  193. self->count = 0;
  194. }
  195. if (self->spawnflags & 2)
  196. {
  197. self->s.eFlags |= EF_ANIM_ALLFAST;
  198. }
  199. if (self->spawnflags & 4)
  200. {//FIXME: need to be able to do change to something when it's done? Or not be usable until it's done?
  201. self->s.eFlags |= EF_ANIM_ONCE;
  202. }
  203. self->e_UseFunc = useF_func_usable_use;
  204. if ( self->health )
  205. {
  206. self->takedamage = qtrue;
  207. self->e_DieFunc = dieF_func_usable_die;
  208. self->e_PainFunc = painF_func_usable_pain;
  209. }
  210. if ( self->endFrame > 0 )
  211. {
  212. self->s.frame = self->startFrame = 0;
  213. self->s.eFlags |= EF_SHADER_ANIM;
  214. }
  215. gi.linkentity (self);
  216. int forceVisible = 0;
  217. G_SpawnInt( "forcevisible", "0", &forceVisible );
  218. if ( forceVisible )
  219. {//can see these through walls with force sight, so must be broadcast
  220. if ( VectorCompare( self->s.origin, vec3_origin ) )
  221. {//no origin brush
  222. self->svFlags |= SVF_BROADCAST;
  223. }
  224. self->s.eFlags |= EF_FORCE_VISIBLE;
  225. }
  226. }