Trigger.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. idTrigger
  26. ===============================================================================
  27. */
  28. const idEventDef EV_Enable( "enable", NULL );
  29. const idEventDef EV_Disable( "disable", NULL );
  30. CLASS_DECLARATION( idEntity, idTrigger )
  31. EVENT( EV_Enable, idTrigger::Event_Enable )
  32. EVENT( EV_Disable, idTrigger::Event_Disable )
  33. END_CLASS
  34. /*
  35. ================
  36. idTrigger::DrawDebugInfo
  37. ================
  38. */
  39. void idTrigger::DrawDebugInfo( void ) {
  40. idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3();
  41. idVec3 up = axis[ 2 ] * 5.0f;
  42. idBounds viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
  43. idBounds viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
  44. idBounds box( idVec3( -4.0f, -4.0f, -4.0f ), idVec3( 4.0f, 4.0f, 4.0f ) );
  45. idEntity *ent;
  46. idEntity *target;
  47. int i;
  48. bool show;
  49. const function_t *func;
  50. viewTextBounds.ExpandSelf( 128.0f );
  51. viewBounds.ExpandSelf( 512.0f );
  52. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  53. if ( ent->GetPhysics()->GetContents() & ( CONTENTS_TRIGGER | CONTENTS_FLASHLIGHT_TRIGGER ) ) {
  54. show = viewBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() );
  55. if ( !show ) {
  56. for( i = 0; i < ent->targets.Num(); i++ ) {
  57. target = ent->targets[ i ].GetEntity();
  58. if ( target && viewBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) ) {
  59. show = true;
  60. break;
  61. }
  62. }
  63. }
  64. if ( !show ) {
  65. continue;
  66. }
  67. gameRenderWorld->DebugBounds( colorOrange, ent->GetPhysics()->GetAbsBounds() );
  68. if ( viewTextBounds.IntersectsBounds( ent->GetPhysics()->GetAbsBounds() ) ) {
  69. gameRenderWorld->DrawText( ent->name.c_str(), ent->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 );
  70. gameRenderWorld->DrawText( ent->GetEntityDefName(), ent->GetPhysics()->GetAbsBounds().GetCenter() + up, 0.1f, colorWhite, axis, 1 );
  71. if ( ent->IsType( idTrigger::Type ) ) {
  72. func = static_cast<idTrigger *>( ent )->GetScriptFunction();
  73. } else {
  74. func = NULL;
  75. }
  76. if ( func ) {
  77. gameRenderWorld->DrawText( va( "call script '%s'", func->Name() ), ent->GetPhysics()->GetAbsBounds().GetCenter() - up, 0.1f, colorWhite, axis, 1 );
  78. }
  79. }
  80. for( i = 0; i < ent->targets.Num(); i++ ) {
  81. target = ent->targets[ i ].GetEntity();
  82. if ( target ) {
  83. gameRenderWorld->DebugArrow( colorYellow, ent->GetPhysics()->GetAbsBounds().GetCenter(), target->GetPhysics()->GetOrigin(), 10, 0 );
  84. gameRenderWorld->DebugBounds( colorGreen, box, target->GetPhysics()->GetOrigin() );
  85. if ( viewTextBounds.IntersectsBounds( target->GetPhysics()->GetAbsBounds() ) ) {
  86. gameRenderWorld->DrawText( target->name.c_str(), target->GetPhysics()->GetAbsBounds().GetCenter(), 0.1f, colorWhite, axis, 1 );
  87. }
  88. }
  89. }
  90. }
  91. }
  92. }
  93. /*
  94. ================
  95. idTrigger::Enable
  96. ================
  97. */
  98. void idTrigger::Enable( void ) {
  99. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  100. GetPhysics()->EnableClip();
  101. }
  102. /*
  103. ================
  104. idTrigger::Disable
  105. ================
  106. */
  107. void idTrigger::Disable( void ) {
  108. // we may be relinked if we're bound to another object, so clear the contents as well
  109. GetPhysics()->SetContents( 0 );
  110. GetPhysics()->DisableClip();
  111. }
  112. /*
  113. ================
  114. idTrigger::CallScript
  115. ================
  116. */
  117. void idTrigger::CallScript( void ) const {
  118. idThread *thread;
  119. if ( scriptFunction ) {
  120. thread = new idThread( scriptFunction );
  121. thread->DelayedStart( 0 );
  122. }
  123. }
  124. /*
  125. ================
  126. idTrigger::GetScriptFunction
  127. ================
  128. */
  129. const function_t *idTrigger::GetScriptFunction( void ) const {
  130. return scriptFunction;
  131. }
  132. /*
  133. ================
  134. idTrigger::Save
  135. ================
  136. */
  137. void idTrigger::Save( idSaveGame *savefile ) const {
  138. if ( scriptFunction ) {
  139. savefile->WriteString( scriptFunction->Name() );
  140. } else {
  141. savefile->WriteString( "" );
  142. }
  143. }
  144. /*
  145. ================
  146. idTrigger::Restore
  147. ================
  148. */
  149. void idTrigger::Restore( idRestoreGame *savefile ) {
  150. idStr funcname;
  151. savefile->ReadString( funcname );
  152. if ( funcname.Length() ) {
  153. scriptFunction = gameLocal.program.FindFunction( funcname );
  154. if ( scriptFunction == NULL ) {
  155. gameLocal.Warning( "idTrigger_Multi '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  156. }
  157. } else {
  158. scriptFunction = NULL;
  159. }
  160. }
  161. /*
  162. ================
  163. idTrigger::Event_Enable
  164. ================
  165. */
  166. void idTrigger::Event_Enable( void ) {
  167. Enable();
  168. }
  169. /*
  170. ================
  171. idTrigger::Event_Disable
  172. ================
  173. */
  174. void idTrigger::Event_Disable( void ) {
  175. Disable();
  176. }
  177. /*
  178. ================
  179. idTrigger::idTrigger
  180. ================
  181. */
  182. idTrigger::idTrigger() {
  183. scriptFunction = NULL;
  184. }
  185. /*
  186. ================
  187. idTrigger::Spawn
  188. ================
  189. */
  190. void idTrigger::Spawn( void ) {
  191. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  192. idStr funcname = spawnArgs.GetString( "call", "" );
  193. if ( funcname.Length() ) {
  194. scriptFunction = gameLocal.program.FindFunction( funcname );
  195. if ( scriptFunction == NULL ) {
  196. gameLocal.Warning( "trigger '%s' at (%s) calls unknown function '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  197. }
  198. } else {
  199. scriptFunction = NULL;
  200. }
  201. }
  202. /*
  203. ===============================================================================
  204. idTrigger_Multi
  205. ===============================================================================
  206. */
  207. const idEventDef EV_TriggerAction( "<triggerAction>", "e" );
  208. CLASS_DECLARATION( idTrigger, idTrigger_Multi )
  209. EVENT( EV_Touch, idTrigger_Multi::Event_Touch )
  210. EVENT( EV_Activate, idTrigger_Multi::Event_Trigger )
  211. EVENT( EV_TriggerAction, idTrigger_Multi::Event_TriggerAction )
  212. END_CLASS
  213. /*
  214. ================
  215. idTrigger_Multi::idTrigger_Multi
  216. ================
  217. */
  218. idTrigger_Multi::idTrigger_Multi( void ) {
  219. wait = 0.0f;
  220. random = 0.0f;
  221. delay = 0.0f;
  222. random_delay = 0.0f;
  223. nextTriggerTime = 0;
  224. removeItem = 0;
  225. touchClient = false;
  226. touchOther = false;
  227. triggerFirst = false;
  228. triggerWithSelf = false;
  229. }
  230. /*
  231. ================
  232. idTrigger_Multi::Save
  233. ================
  234. */
  235. void idTrigger_Multi::Save( idSaveGame *savefile ) const {
  236. savefile->WriteFloat( wait );
  237. savefile->WriteFloat( random );
  238. savefile->WriteFloat( delay );
  239. savefile->WriteFloat( random_delay );
  240. savefile->WriteInt( nextTriggerTime );
  241. savefile->WriteString( requires );
  242. savefile->WriteInt( removeItem );
  243. savefile->WriteBool( touchClient );
  244. savefile->WriteBool( touchOther );
  245. savefile->WriteBool( triggerFirst );
  246. savefile->WriteBool( triggerWithSelf );
  247. }
  248. /*
  249. ================
  250. idTrigger_Multi::Restore
  251. ================
  252. */
  253. void idTrigger_Multi::Restore( idRestoreGame *savefile ) {
  254. savefile->ReadFloat( wait );
  255. savefile->ReadFloat( random );
  256. savefile->ReadFloat( delay );
  257. savefile->ReadFloat( random_delay );
  258. savefile->ReadInt( nextTriggerTime );
  259. savefile->ReadString( requires );
  260. savefile->ReadInt( removeItem );
  261. savefile->ReadBool( touchClient );
  262. savefile->ReadBool( touchOther );
  263. savefile->ReadBool( triggerFirst );
  264. savefile->ReadBool( triggerWithSelf );
  265. }
  266. /*
  267. ================
  268. idTrigger_Multi::Spawn
  269. "wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
  270. "call" : Script function to call when triggered
  271. "random" wait variance, default is 0
  272. Variable sized repeatable trigger. Must be targeted at one or more entities.
  273. so, the basic time between firing is a random time between
  274. (wait - random) and (wait + random)
  275. ================
  276. */
  277. void idTrigger_Multi::Spawn( void ) {
  278. spawnArgs.GetFloat( "wait", "0.5", wait );
  279. spawnArgs.GetFloat( "random", "0", random );
  280. spawnArgs.GetFloat( "delay", "0", delay );
  281. spawnArgs.GetFloat( "random_delay", "0", random_delay );
  282. if ( random && ( random >= wait ) && ( wait >= 0 ) ) {
  283. random = wait - 1;
  284. gameLocal.Warning( "idTrigger_Multi '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  285. }
  286. if ( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) {
  287. random_delay = delay - 1;
  288. gameLocal.Warning( "idTrigger_Multi '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  289. }
  290. spawnArgs.GetString( "requires", "", requires );
  291. spawnArgs.GetInt( "removeItem", "0", removeItem );
  292. spawnArgs.GetBool( "triggerFirst", "0", triggerFirst );
  293. spawnArgs.GetBool( "triggerWithSelf", "0", triggerWithSelf );
  294. if ( spawnArgs.GetBool( "anyTouch" ) ) {
  295. touchClient = true;
  296. touchOther = true;
  297. } else if ( spawnArgs.GetBool( "noTouch" ) ) {
  298. touchClient = false;
  299. touchOther = false;
  300. } else if ( spawnArgs.GetBool( "noClient" ) ) {
  301. touchClient = false;
  302. touchOther = true;
  303. } else {
  304. touchClient = true;
  305. touchOther = false;
  306. }
  307. nextTriggerTime = 0;
  308. if ( spawnArgs.GetBool( "flashlight_trigger" ) ) {
  309. GetPhysics()->SetContents( CONTENTS_FLASHLIGHT_TRIGGER );
  310. } else {
  311. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  312. }
  313. }
  314. /*
  315. ================
  316. idTrigger_Multi::CheckFacing
  317. ================
  318. */
  319. bool idTrigger_Multi::CheckFacing( idEntity *activator ) {
  320. if ( spawnArgs.GetBool( "facing" ) ) {
  321. if ( !activator->IsType( idPlayer::Type ) ) {
  322. return true;
  323. }
  324. idPlayer *player = static_cast< idPlayer* >( activator );
  325. float dot = player->viewAngles.ToForward() * GetPhysics()->GetAxis()[0];
  326. float angle = RAD2DEG( idMath::ACos( dot ) );
  327. if ( angle > spawnArgs.GetFloat( "angleLimit", "30" ) ) {
  328. return false;
  329. }
  330. }
  331. return true;
  332. }
  333. /*
  334. ================
  335. idTrigger_Multi::TriggerAction
  336. ================
  337. */
  338. void idTrigger_Multi::TriggerAction( idEntity *activator ) {
  339. ActivateTargets( triggerWithSelf ? this : activator );
  340. CallScript();
  341. if ( wait >= 0 ) {
  342. nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  343. } else {
  344. // we can't just remove (this) here, because this is a touch function
  345. // called while looping through area links...
  346. #ifdef _D3XP
  347. // If the player spawned inside the trigger, the player Spawn function called Think directly,
  348. // allowing for multiple triggers on a trigger_once. Increasing the nextTriggerTime prevents it.
  349. nextTriggerTime = gameLocal.time + 99999;
  350. #else
  351. nextTriggerTime = gameLocal.time + 1;
  352. #endif
  353. PostEventMS( &EV_Remove, 0 );
  354. }
  355. }
  356. /*
  357. ================
  358. idTrigger_Multi::Event_TriggerAction
  359. ================
  360. */
  361. void idTrigger_Multi::Event_TriggerAction( idEntity *activator ) {
  362. TriggerAction( activator );
  363. }
  364. /*
  365. ================
  366. idTrigger_Multi::Event_Trigger
  367. the trigger was just activated
  368. activated should be the entity that originated the activation sequence (ie. the original target)
  369. activator should be set to the activator so it can be held through a delay
  370. so wait for the delay time before firing
  371. ================
  372. */
  373. void idTrigger_Multi::Event_Trigger( idEntity *activator ) {
  374. if ( nextTriggerTime > gameLocal.time ) {
  375. // can't retrigger until the wait is over
  376. return;
  377. }
  378. // see if this trigger requires an item
  379. if ( !gameLocal.RequirementMet( activator, requires, removeItem ) ) {
  380. return;
  381. }
  382. if ( !CheckFacing( activator ) ) {
  383. return;
  384. }
  385. if ( triggerFirst ) {
  386. triggerFirst = false;
  387. return;
  388. }
  389. // don't allow it to trigger twice in a single frame
  390. nextTriggerTime = gameLocal.time + 1;
  391. if ( delay > 0 ) {
  392. // don't allow it to trigger again until our delay has passed
  393. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  394. PostEventSec( &EV_TriggerAction, delay, activator );
  395. } else {
  396. TriggerAction( activator );
  397. }
  398. }
  399. /*
  400. ================
  401. idTrigger_Multi::Event_Touch
  402. ================
  403. */
  404. void idTrigger_Multi::Event_Touch( idEntity *other, trace_t *trace ) {
  405. if( triggerFirst ) {
  406. return;
  407. }
  408. bool player = other->IsType( idPlayer::Type );
  409. if ( player ) {
  410. if ( !touchClient ) {
  411. return;
  412. }
  413. if ( static_cast< idPlayer * >( other )->spectating ) {
  414. return;
  415. }
  416. } else if ( !touchOther ) {
  417. return;
  418. }
  419. if ( nextTriggerTime > gameLocal.time ) {
  420. // can't retrigger until the wait is over
  421. return;
  422. }
  423. // see if this trigger requires an item
  424. if ( !gameLocal.RequirementMet( other, requires, removeItem ) ) {
  425. return;
  426. }
  427. if ( !CheckFacing( other ) ) {
  428. return;
  429. }
  430. if ( spawnArgs.GetBool( "toggleTriggerFirst" ) ) {
  431. triggerFirst = true;
  432. }
  433. nextTriggerTime = gameLocal.time + 1;
  434. if ( delay > 0 ) {
  435. // don't allow it to trigger again until our delay has passed
  436. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  437. PostEventSec( &EV_TriggerAction, delay, other );
  438. } else {
  439. TriggerAction( other );
  440. }
  441. }
  442. /*
  443. ===============================================================================
  444. idTrigger_EntityName
  445. ===============================================================================
  446. */
  447. CLASS_DECLARATION( idTrigger, idTrigger_EntityName )
  448. EVENT( EV_Touch, idTrigger_EntityName::Event_Touch )
  449. EVENT( EV_Activate, idTrigger_EntityName::Event_Trigger )
  450. EVENT( EV_TriggerAction, idTrigger_EntityName::Event_TriggerAction )
  451. END_CLASS
  452. /*
  453. ================
  454. idTrigger_EntityName::idTrigger_EntityName
  455. ================
  456. */
  457. idTrigger_EntityName::idTrigger_EntityName( void ) {
  458. wait = 0.0f;
  459. random = 0.0f;
  460. delay = 0.0f;
  461. random_delay = 0.0f;
  462. nextTriggerTime = 0;
  463. triggerFirst = false;
  464. }
  465. /*
  466. ================
  467. idTrigger_EntityName::Save
  468. ================
  469. */
  470. void idTrigger_EntityName::Save( idSaveGame *savefile ) const {
  471. savefile->WriteFloat( wait );
  472. savefile->WriteFloat( random );
  473. savefile->WriteFloat( delay );
  474. savefile->WriteFloat( random_delay );
  475. savefile->WriteInt( nextTriggerTime );
  476. savefile->WriteBool( triggerFirst );
  477. savefile->WriteString( entityName );
  478. }
  479. /*
  480. ================
  481. idTrigger_EntityName::Restore
  482. ================
  483. */
  484. void idTrigger_EntityName::Restore( idRestoreGame *savefile ) {
  485. savefile->ReadFloat( wait );
  486. savefile->ReadFloat( random );
  487. savefile->ReadFloat( delay );
  488. savefile->ReadFloat( random_delay );
  489. savefile->ReadInt( nextTriggerTime );
  490. savefile->ReadBool( triggerFirst );
  491. savefile->ReadString( entityName );
  492. }
  493. /*
  494. ================
  495. idTrigger_EntityName::Spawn
  496. ================
  497. */
  498. void idTrigger_EntityName::Spawn( void ) {
  499. spawnArgs.GetFloat( "wait", "0.5", wait );
  500. spawnArgs.GetFloat( "random", "0", random );
  501. spawnArgs.GetFloat( "delay", "0", delay );
  502. spawnArgs.GetFloat( "random_delay", "0", random_delay );
  503. if ( random && ( random >= wait ) && ( wait >= 0 ) ) {
  504. random = wait - 1;
  505. gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  506. }
  507. if ( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) {
  508. random_delay = delay - 1;
  509. gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  510. }
  511. spawnArgs.GetBool( "triggerFirst", "0", triggerFirst );
  512. entityName = spawnArgs.GetString( "entityname" );
  513. if ( !entityName.Length() ) {
  514. gameLocal.Error( "idTrigger_EntityName '%s' at (%s) doesn't have 'entityname' key specified", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  515. }
  516. nextTriggerTime = 0;
  517. if ( !spawnArgs.GetBool( "noTouch" ) ) {
  518. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  519. }
  520. }
  521. /*
  522. ================
  523. idTrigger_EntityName::TriggerAction
  524. ================
  525. */
  526. void idTrigger_EntityName::TriggerAction( idEntity *activator ) {
  527. ActivateTargets( activator );
  528. CallScript();
  529. if ( wait >= 0 ) {
  530. nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  531. } else {
  532. // we can't just remove (this) here, because this is a touch function
  533. // called while looping through area links...
  534. nextTriggerTime = gameLocal.time + 1;
  535. PostEventMS( &EV_Remove, 0 );
  536. }
  537. }
  538. /*
  539. ================
  540. idTrigger_EntityName::Event_TriggerAction
  541. ================
  542. */
  543. void idTrigger_EntityName::Event_TriggerAction( idEntity *activator ) {
  544. TriggerAction( activator );
  545. }
  546. /*
  547. ================
  548. idTrigger_EntityName::Event_Trigger
  549. the trigger was just activated
  550. activated should be the entity that originated the activation sequence (ie. the original target)
  551. activator should be set to the activator so it can be held through a delay
  552. so wait for the delay time before firing
  553. ================
  554. */
  555. void idTrigger_EntityName::Event_Trigger( idEntity *activator ) {
  556. if ( nextTriggerTime > gameLocal.time ) {
  557. // can't retrigger until the wait is over
  558. return;
  559. }
  560. if ( !activator || ( activator->name != entityName ) ) {
  561. return;
  562. }
  563. if ( triggerFirst ) {
  564. triggerFirst = false;
  565. return;
  566. }
  567. // don't allow it to trigger twice in a single frame
  568. nextTriggerTime = gameLocal.time + 1;
  569. if ( delay > 0 ) {
  570. // don't allow it to trigger again until our delay has passed
  571. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  572. PostEventSec( &EV_TriggerAction, delay, activator );
  573. } else {
  574. TriggerAction( activator );
  575. }
  576. }
  577. /*
  578. ================
  579. idTrigger_EntityName::Event_Touch
  580. ================
  581. */
  582. void idTrigger_EntityName::Event_Touch( idEntity *other, trace_t *trace ) {
  583. if( triggerFirst ) {
  584. return;
  585. }
  586. if ( nextTriggerTime > gameLocal.time ) {
  587. // can't retrigger until the wait is over
  588. return;
  589. }
  590. if ( !other || ( other->name != entityName ) ) {
  591. return;
  592. }
  593. nextTriggerTime = gameLocal.time + 1;
  594. if ( delay > 0 ) {
  595. // don't allow it to trigger again until our delay has passed
  596. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  597. PostEventSec( &EV_TriggerAction, delay, other );
  598. } else {
  599. TriggerAction( other );
  600. }
  601. }
  602. /*
  603. ===============================================================================
  604. idTrigger_Timer
  605. ===============================================================================
  606. */
  607. const idEventDef EV_Timer( "<timer>", NULL );
  608. CLASS_DECLARATION( idTrigger, idTrigger_Timer )
  609. EVENT( EV_Timer, idTrigger_Timer::Event_Timer )
  610. EVENT( EV_Activate, idTrigger_Timer::Event_Use )
  611. END_CLASS
  612. /*
  613. ================
  614. idTrigger_Timer::idTrigger_Timer
  615. ================
  616. */
  617. idTrigger_Timer::idTrigger_Timer( void ) {
  618. random = 0.0f;
  619. wait = 0.0f;
  620. on = false;
  621. delay = 0.0f;
  622. }
  623. /*
  624. ================
  625. idTrigger_Timer::Save
  626. ================
  627. */
  628. void idTrigger_Timer::Save( idSaveGame *savefile ) const {
  629. savefile->WriteFloat( random );
  630. savefile->WriteFloat( wait );
  631. savefile->WriteBool( on );
  632. savefile->WriteFloat( delay );
  633. savefile->WriteString( onName );
  634. savefile->WriteString( offName );
  635. }
  636. /*
  637. ================
  638. idTrigger_Timer::Restore
  639. ================
  640. */
  641. void idTrigger_Timer::Restore( idRestoreGame *savefile ) {
  642. savefile->ReadFloat( random );
  643. savefile->ReadFloat( wait );
  644. savefile->ReadBool( on );
  645. savefile->ReadFloat( delay );
  646. savefile->ReadString( onName );
  647. savefile->ReadString( offName );
  648. }
  649. /*
  650. ================
  651. idTrigger_Timer::Spawn
  652. Repeatedly fires its targets.
  653. Can be turned on or off by using.
  654. ================
  655. */
  656. void idTrigger_Timer::Spawn( void ) {
  657. spawnArgs.GetFloat( "random", "1", random );
  658. spawnArgs.GetFloat( "wait", "1", wait );
  659. spawnArgs.GetBool( "start_on", "0", on );
  660. spawnArgs.GetFloat( "delay", "0", delay );
  661. onName = spawnArgs.GetString( "onName" );
  662. offName = spawnArgs.GetString( "offName" );
  663. if ( random >= wait && wait >= 0 ) {
  664. random = wait - 0.001;
  665. gameLocal.Warning( "idTrigger_Timer '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  666. }
  667. if ( on ) {
  668. PostEventSec( &EV_Timer, delay );
  669. }
  670. }
  671. /*
  672. ================
  673. idTrigger_Timer::Enable
  674. ================
  675. */
  676. void idTrigger_Timer::Enable( void ) {
  677. // if off, turn it on
  678. if ( !on ) {
  679. on = true;
  680. PostEventSec( &EV_Timer, delay );
  681. }
  682. }
  683. /*
  684. ================
  685. idTrigger_Timer::Disable
  686. ================
  687. */
  688. void idTrigger_Timer::Disable( void ) {
  689. // if on, turn it off
  690. if ( on ) {
  691. on = false;
  692. CancelEvents( &EV_Timer );
  693. }
  694. }
  695. /*
  696. ================
  697. idTrigger_Timer::Event_Timer
  698. ================
  699. */
  700. void idTrigger_Timer::Event_Timer( void ) {
  701. ActivateTargets( this );
  702. // set time before next firing
  703. if ( wait >= 0.0f ) {
  704. PostEventSec( &EV_Timer, wait + gameLocal.random.CRandomFloat() * random );
  705. }
  706. }
  707. /*
  708. ================
  709. idTrigger_Timer::Event_Use
  710. ================
  711. */
  712. void idTrigger_Timer::Event_Use( idEntity *activator ) {
  713. // if on, turn it off
  714. if ( on ) {
  715. if ( offName.Length() && offName.Icmp( activator->GetName() ) ) {
  716. return;
  717. }
  718. on = false;
  719. CancelEvents( &EV_Timer );
  720. } else {
  721. // turn it on
  722. if ( onName.Length() && onName.Icmp( activator->GetName() ) ) {
  723. return;
  724. }
  725. on = true;
  726. PostEventSec( &EV_Timer, delay );
  727. }
  728. }
  729. /*
  730. ===============================================================================
  731. idTrigger_Count
  732. ===============================================================================
  733. */
  734. CLASS_DECLARATION( idTrigger, idTrigger_Count )
  735. EVENT( EV_Activate, idTrigger_Count::Event_Trigger )
  736. EVENT( EV_TriggerAction, idTrigger_Count::Event_TriggerAction )
  737. END_CLASS
  738. /*
  739. ================
  740. idTrigger_Count::idTrigger_Count
  741. ================
  742. */
  743. idTrigger_Count::idTrigger_Count( void ) {
  744. goal = 0;
  745. count = 0;
  746. delay = 0.0f;
  747. }
  748. /*
  749. ================
  750. idTrigger_Count::Save
  751. ================
  752. */
  753. void idTrigger_Count::Save( idSaveGame *savefile ) const {
  754. savefile->WriteInt( goal );
  755. savefile->WriteInt( count );
  756. savefile->WriteFloat( delay );
  757. }
  758. /*
  759. ================
  760. idTrigger_Count::Restore
  761. ================
  762. */
  763. void idTrigger_Count::Restore( idRestoreGame *savefile ) {
  764. savefile->ReadInt( goal );
  765. savefile->ReadInt( count );
  766. savefile->ReadFloat( delay );
  767. }
  768. /*
  769. ================
  770. idTrigger_Count::Spawn
  771. ================
  772. */
  773. void idTrigger_Count::Spawn( void ) {
  774. spawnArgs.GetInt( "count", "1", goal );
  775. spawnArgs.GetFloat( "delay", "0", delay );
  776. count = 0;
  777. }
  778. /*
  779. ================
  780. idTrigger_Count::Event_Trigger
  781. ================
  782. */
  783. void idTrigger_Count::Event_Trigger( idEntity *activator ) {
  784. // goal of -1 means trigger has been exhausted
  785. if (goal >= 0) {
  786. count++;
  787. if ( count >= goal ) {
  788. if (spawnArgs.GetBool("repeat")) {
  789. count = 0;
  790. } else {
  791. goal = -1;
  792. }
  793. PostEventSec( &EV_TriggerAction, delay, activator );
  794. }
  795. }
  796. }
  797. /*
  798. ================
  799. idTrigger_Count::Event_TriggerAction
  800. ================
  801. */
  802. void idTrigger_Count::Event_TriggerAction( idEntity *activator ) {
  803. ActivateTargets( activator );
  804. CallScript();
  805. if ( goal == -1 ) {
  806. PostEventMS( &EV_Remove, 0 );
  807. }
  808. }
  809. /*
  810. ===============================================================================
  811. idTrigger_Hurt
  812. ===============================================================================
  813. */
  814. CLASS_DECLARATION( idTrigger, idTrigger_Hurt )
  815. EVENT( EV_Touch, idTrigger_Hurt::Event_Touch )
  816. EVENT( EV_Activate, idTrigger_Hurt::Event_Toggle )
  817. END_CLASS
  818. /*
  819. ================
  820. idTrigger_Hurt::idTrigger_Hurt
  821. ================
  822. */
  823. idTrigger_Hurt::idTrigger_Hurt( void ) {
  824. on = false;
  825. delay = 0.0f;
  826. nextTime = 0;
  827. }
  828. /*
  829. ================
  830. idTrigger_Hurt::Save
  831. ================
  832. */
  833. void idTrigger_Hurt::Save( idSaveGame *savefile ) const {
  834. savefile->WriteBool( on );
  835. savefile->WriteFloat( delay );
  836. savefile->WriteInt( nextTime );
  837. }
  838. /*
  839. ================
  840. idTrigger_Hurt::Restore
  841. ================
  842. */
  843. void idTrigger_Hurt::Restore( idRestoreGame *savefile ) {
  844. savefile->ReadBool( on );
  845. savefile->ReadFloat( delay );
  846. savefile->ReadInt( nextTime );
  847. }
  848. /*
  849. ================
  850. idTrigger_Hurt::Spawn
  851. Damages activator
  852. Can be turned on or off by using.
  853. ================
  854. */
  855. void idTrigger_Hurt::Spawn( void ) {
  856. spawnArgs.GetBool( "on", "1", on );
  857. spawnArgs.GetFloat( "delay", "1.0", delay );
  858. nextTime = gameLocal.time;
  859. Enable();
  860. }
  861. /*
  862. ================
  863. idTrigger_Hurt::Event_Touch
  864. ================
  865. */
  866. void idTrigger_Hurt::Event_Touch( idEntity *other, trace_t *trace ) {
  867. const char *damage;
  868. if ( on && other && gameLocal.time >= nextTime ) {
  869. #ifdef _D3XP
  870. bool playerOnly = spawnArgs.GetBool( "playerOnly" );
  871. if ( playerOnly ) {
  872. if ( !other->IsType( idPlayer::Type ) ) {
  873. return;
  874. }
  875. }
  876. #endif
  877. damage = spawnArgs.GetString( "def_damage", "damage_painTrigger" );
  878. #ifdef _D3XP
  879. idVec3 dir = vec3_origin;
  880. if(spawnArgs.GetBool("kick_from_center", "0")) {
  881. dir = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  882. dir.Normalize();
  883. }
  884. other->Damage( NULL, NULL, dir, damage, 1.0f, INVALID_JOINT );
  885. #else
  886. other->Damage( NULL, NULL, vec3_origin, damage, 1.0f, INVALID_JOINT );
  887. #endif
  888. ActivateTargets( other );
  889. CallScript();
  890. nextTime = gameLocal.time + SEC2MS( delay );
  891. }
  892. }
  893. /*
  894. ================
  895. idTrigger_Hurt::Event_Toggle
  896. ================
  897. */
  898. void idTrigger_Hurt::Event_Toggle( idEntity *activator ) {
  899. on = !on;
  900. }
  901. /*
  902. ===============================================================================
  903. idTrigger_Fade
  904. ===============================================================================
  905. */
  906. CLASS_DECLARATION( idTrigger, idTrigger_Fade )
  907. EVENT( EV_Activate, idTrigger_Fade::Event_Trigger )
  908. END_CLASS
  909. /*
  910. ================
  911. idTrigger_Fade::Event_Trigger
  912. ================
  913. */
  914. void idTrigger_Fade::Event_Trigger( idEntity *activator ) {
  915. idVec4 fadeColor;
  916. int fadeTime;
  917. idPlayer *player;
  918. player = gameLocal.GetLocalPlayer();
  919. if ( player ) {
  920. fadeColor = spawnArgs.GetVec4( "fadeColor", "0, 0, 0, 1" );
  921. fadeTime = SEC2MS( spawnArgs.GetFloat( "fadeTime", "0.5" ) );
  922. player->playerView.Fade( fadeColor, fadeTime );
  923. PostEventMS( &EV_ActivateTargets, fadeTime, activator );
  924. }
  925. }
  926. /*
  927. ===============================================================================
  928. idTrigger_Touch
  929. ===============================================================================
  930. */
  931. CLASS_DECLARATION( idTrigger, idTrigger_Touch )
  932. EVENT( EV_Activate, idTrigger_Touch::Event_Trigger )
  933. END_CLASS
  934. /*
  935. ================
  936. idTrigger_Touch::idTrigger_Touch
  937. ================
  938. */
  939. idTrigger_Touch::idTrigger_Touch( void ) {
  940. clipModel = NULL;
  941. }
  942. /*
  943. ================
  944. idTrigger_Touch::Spawn
  945. ================
  946. */
  947. void idTrigger_Touch::Spawn( void ) {
  948. // get the clip model
  949. clipModel = new idClipModel( GetPhysics()->GetClipModel() );
  950. // remove the collision model from the physics object
  951. GetPhysics()->SetClipModel( NULL, 1.0f );
  952. if ( spawnArgs.GetBool( "start_on" ) ) {
  953. BecomeActive( TH_THINK );
  954. }
  955. }
  956. /*
  957. ================
  958. idTrigger_Touch::Save
  959. ================
  960. */
  961. void idTrigger_Touch::Save( idSaveGame *savefile ) {
  962. savefile->WriteClipModel( clipModel );
  963. }
  964. /*
  965. ================
  966. idTrigger_Touch::Restore
  967. ================
  968. */
  969. void idTrigger_Touch::Restore( idRestoreGame *savefile ) {
  970. savefile->ReadClipModel( clipModel );
  971. }
  972. /*
  973. ================
  974. idTrigger_Touch::TouchEntities
  975. ================
  976. */
  977. void idTrigger_Touch::TouchEntities( void ) {
  978. int numClipModels, i;
  979. idBounds bounds;
  980. idClipModel *cm, *clipModelList[ MAX_GENTITIES ];
  981. if ( clipModel == NULL || scriptFunction == NULL ) {
  982. return;
  983. }
  984. bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() );
  985. numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
  986. for ( i = 0; i < numClipModels; i++ ) {
  987. cm = clipModelList[ i ];
  988. if ( !cm->IsTraceModel() ) {
  989. continue;
  990. }
  991. idEntity *entity = cm->GetEntity();
  992. if ( !entity ) {
  993. continue;
  994. }
  995. if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1,
  996. clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) {
  997. continue;
  998. }
  999. ActivateTargets( entity );
  1000. idThread *thread = new idThread();
  1001. thread->CallFunction( entity, scriptFunction, false );
  1002. thread->DelayedStart( 0 );
  1003. }
  1004. }
  1005. /*
  1006. ================
  1007. idTrigger_Touch::Think
  1008. ================
  1009. */
  1010. void idTrigger_Touch::Think( void ) {
  1011. if ( thinkFlags & TH_THINK ) {
  1012. TouchEntities();
  1013. }
  1014. idEntity::Think();
  1015. }
  1016. /*
  1017. ================
  1018. idTrigger_Touch::Event_Trigger
  1019. ================
  1020. */
  1021. void idTrigger_Touch::Event_Trigger( idEntity *activator ) {
  1022. if ( thinkFlags & TH_THINK ) {
  1023. BecomeInactive( TH_THINK );
  1024. } else {
  1025. BecomeActive( TH_THINK );
  1026. }
  1027. }
  1028. /*
  1029. ================
  1030. idTrigger_Touch::Enable
  1031. ================
  1032. */
  1033. void idTrigger_Touch::Enable( void ) {
  1034. BecomeActive( TH_THINK );
  1035. }
  1036. /*
  1037. ================
  1038. idTrigger_Touch::Disable
  1039. ================
  1040. */
  1041. void idTrigger_Touch::Disable( void ) {
  1042. BecomeInactive( TH_THINK );
  1043. }
  1044. #ifdef CTF
  1045. /*
  1046. ===============================================================================
  1047. idTrigger_Flag
  1048. ===============================================================================
  1049. */
  1050. CLASS_DECLARATION( idTrigger_Multi, idTrigger_Flag )
  1051. EVENT( EV_Touch, idTrigger_Flag::Event_Touch )
  1052. END_CLASS
  1053. idTrigger_Flag::idTrigger_Flag( void ) {
  1054. team = -1;
  1055. player = false;
  1056. eventFlag = NULL;
  1057. }
  1058. void idTrigger_Flag::Spawn( void ) {
  1059. team = spawnArgs.GetInt( "team", "0" );
  1060. player = spawnArgs.GetBool( "player", "0" );
  1061. idStr funcname = spawnArgs.GetString( "eventflag", "" );
  1062. if ( funcname.Length() ) {
  1063. eventFlag = idEventDef::FindEvent( funcname );// gameLocal.program.FindFunction( funcname );//, &idItemTeam::Type );
  1064. if ( eventFlag == NULL ) {
  1065. gameLocal.Warning( "trigger '%s' at (%s) event unknown '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  1066. }
  1067. } else {
  1068. eventFlag = NULL;
  1069. }
  1070. idTrigger_Multi::Spawn();
  1071. }
  1072. void idTrigger_Flag::Event_Touch( idEntity *other, trace_t *trace ) {
  1073. bool bTrigger = false;
  1074. idItemTeam * flag = NULL;
  1075. if ( player ) {
  1076. if ( !other->IsType( idPlayer::Type ) )
  1077. return;
  1078. idPlayer * player = static_cast<idPlayer *>(other);
  1079. if ( player->carryingFlag == false )
  1080. return;
  1081. if ( team != -1 && ( player->team != team || (player->team != 0 && player->team != 1)) )
  1082. return;
  1083. idItemTeam * flags[2];
  1084. flags[0] = gameLocal.mpGame.GetTeamFlag( 0 );
  1085. flags[1] = gameLocal.mpGame.GetTeamFlag( 1 );
  1086. int iFriend = 1 - player->team; // index to the flag player team wants
  1087. int iOpp = player->team; // index to the flag opp team wants
  1088. // flag is captured if :
  1089. // 1)flag is truely bound to the player
  1090. // 2)opponent flag has been return
  1091. if ( flags[iFriend]->carried && !flags[iFriend]->dropped && //flags[iFriend]->IsBoundTo( player ) &&
  1092. !flags[iOpp]->carried && !flags[iOpp]->dropped )
  1093. flag = flags[iFriend];
  1094. else
  1095. return;
  1096. } else {
  1097. if ( !other->IsType( idItemTeam::Type ) )
  1098. return;
  1099. idItemTeam * item = static_cast<idItemTeam *>( other );
  1100. if ( item->team == team || team == -1 ) {
  1101. flag = item;
  1102. }
  1103. else
  1104. return;
  1105. }
  1106. if ( flag ) {
  1107. switch ( eventFlag->GetNumArgs() ) {
  1108. default :
  1109. case 0 :
  1110. flag->PostEventMS( eventFlag, 0 );
  1111. break;
  1112. case 1 :
  1113. flag->PostEventMS( eventFlag, 0, NULL );
  1114. break;
  1115. case 2 :
  1116. flag->PostEventMS( eventFlag, 0, NULL, NULL );
  1117. break;
  1118. }
  1119. /*
  1120. ServerSendEvent( eventFlag->GetEventNum(), NULL, true, false );
  1121. idThread *thread;
  1122. if ( scriptFlag ) {
  1123. thread = new idThread();
  1124. thread->CallFunction( flag, scriptFlag, false );
  1125. thread->DelayedStart( 0 );
  1126. }
  1127. */
  1128. idTrigger_Multi::Event_Touch( other, trace );
  1129. }
  1130. }
  1131. #endif