Trigger.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition 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() {
  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 != NULL && 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() {
  99. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  100. GetPhysics()->EnableClip();
  101. }
  102. /*
  103. ================
  104. idTrigger::Disable
  105. ================
  106. */
  107. void idTrigger::Disable() {
  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() 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() 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() {
  167. Enable();
  168. }
  169. /*
  170. ================
  171. idTrigger::Event_Disable
  172. ================
  173. */
  174. void idTrigger::Event_Disable() {
  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() {
  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() {
  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() {
  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. // If the player spawned inside the trigger, the player Spawn function called Think directly,
  347. // allowing for multiple triggers on a trigger_once. Increasing the nextTriggerTime prevents it.
  348. nextTriggerTime = gameLocal.time + 99999;
  349. PostEventMS( &EV_Remove, 0 );
  350. }
  351. }
  352. /*
  353. ================
  354. idTrigger_Multi::Event_TriggerAction
  355. ================
  356. */
  357. void idTrigger_Multi::Event_TriggerAction( idEntity *activator ) {
  358. TriggerAction( activator );
  359. }
  360. /*
  361. ================
  362. idTrigger_Multi::Event_Trigger
  363. the trigger was just activated
  364. activated should be the entity that originated the activation sequence (ie. the original target)
  365. activator should be set to the activator so it can be held through a delay
  366. so wait for the delay time before firing
  367. ================
  368. */
  369. void idTrigger_Multi::Event_Trigger( idEntity *activator ) {
  370. if ( nextTriggerTime > gameLocal.time ) {
  371. // can't retrigger until the wait is over
  372. return;
  373. }
  374. // see if this trigger requires an item
  375. if ( !gameLocal.RequirementMet( activator, requires, removeItem ) ) {
  376. return;
  377. }
  378. if ( !CheckFacing( activator ) ) {
  379. return;
  380. }
  381. if ( triggerFirst ) {
  382. triggerFirst = false;
  383. return;
  384. }
  385. // don't allow it to trigger twice in a single frame
  386. nextTriggerTime = gameLocal.time + 1;
  387. if ( delay > 0 ) {
  388. // don't allow it to trigger again until our delay has passed
  389. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  390. PostEventSec( &EV_TriggerAction, delay, activator );
  391. } else {
  392. TriggerAction( activator );
  393. }
  394. }
  395. /*
  396. ================
  397. idTrigger_Multi::Event_Touch
  398. ================
  399. */
  400. void idTrigger_Multi::Event_Touch( idEntity *other, trace_t *trace ) {
  401. if ( common->IsClient() ) {
  402. return;
  403. }
  404. if( triggerFirst ) {
  405. return;
  406. }
  407. bool player = other->IsType( idPlayer::Type );
  408. if ( player ) {
  409. if ( !touchClient ) {
  410. return;
  411. }
  412. if ( static_cast< idPlayer * >( other )->spectating ) {
  413. return;
  414. }
  415. } else if ( !touchOther ) {
  416. return;
  417. }
  418. if ( nextTriggerTime > gameLocal.time ) {
  419. // can't retrigger until the wait is over
  420. return;
  421. }
  422. // see if this trigger requires an item
  423. if ( !gameLocal.RequirementMet( other, requires, removeItem ) ) {
  424. return;
  425. }
  426. if ( !CheckFacing( other ) ) {
  427. return;
  428. }
  429. if ( spawnArgs.GetBool( "toggleTriggerFirst" ) ) {
  430. triggerFirst = true;
  431. }
  432. nextTriggerTime = gameLocal.time + 1;
  433. if ( delay > 0 ) {
  434. // don't allow it to trigger again until our delay has passed
  435. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  436. PostEventSec( &EV_TriggerAction, delay, other );
  437. } else {
  438. TriggerAction( other );
  439. }
  440. }
  441. /*
  442. ===============================================================================
  443. idTrigger_EntityName
  444. ===============================================================================
  445. */
  446. CLASS_DECLARATION( idTrigger, idTrigger_EntityName )
  447. EVENT( EV_Touch, idTrigger_EntityName::Event_Touch )
  448. EVENT( EV_Activate, idTrigger_EntityName::Event_Trigger )
  449. EVENT( EV_TriggerAction, idTrigger_EntityName::Event_TriggerAction )
  450. END_CLASS
  451. /*
  452. ================
  453. idTrigger_EntityName::idTrigger_EntityName
  454. ================
  455. */
  456. idTrigger_EntityName::idTrigger_EntityName() {
  457. wait = 0.0f;
  458. random = 0.0f;
  459. delay = 0.0f;
  460. random_delay = 0.0f;
  461. nextTriggerTime = 0;
  462. triggerFirst = false;
  463. testPartialName = 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. savefile->WriteBool( testPartialName );
  479. }
  480. /*
  481. ================
  482. idTrigger_EntityName::Restore
  483. ================
  484. */
  485. void idTrigger_EntityName::Restore( idRestoreGame *savefile ) {
  486. savefile->ReadFloat( wait );
  487. savefile->ReadFloat( random );
  488. savefile->ReadFloat( delay );
  489. savefile->ReadFloat( random_delay );
  490. savefile->ReadInt( nextTriggerTime );
  491. savefile->ReadBool( triggerFirst );
  492. savefile->ReadString( entityName );
  493. savefile->ReadBool( testPartialName );
  494. }
  495. /*
  496. ================
  497. idTrigger_EntityName::Spawn
  498. ================
  499. */
  500. void idTrigger_EntityName::Spawn() {
  501. spawnArgs.GetFloat( "wait", "0.5", wait );
  502. spawnArgs.GetFloat( "random", "0", random );
  503. spawnArgs.GetFloat( "delay", "0", delay );
  504. spawnArgs.GetFloat( "random_delay", "0", random_delay );
  505. if ( random && ( random >= wait ) && ( wait >= 0 ) ) {
  506. random = wait - 1;
  507. gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  508. }
  509. if ( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) {
  510. random_delay = delay - 1;
  511. gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  512. }
  513. spawnArgs.GetBool( "triggerFirst", "0", triggerFirst );
  514. entityName = spawnArgs.GetString( "entityname" );
  515. if ( !entityName.Length() ) {
  516. gameLocal.Error( "idTrigger_EntityName '%s' at (%s) doesn't have 'entityname' key specified", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  517. }
  518. nextTriggerTime = 0;
  519. if ( !spawnArgs.GetBool( "noTouch" ) ) {
  520. GetPhysics()->SetContents( CONTENTS_TRIGGER );
  521. }
  522. testPartialName = spawnArgs.GetBool( "testPartialName", testPartialName );
  523. }
  524. /*
  525. ================
  526. idTrigger_EntityName::TriggerAction
  527. ================
  528. */
  529. void idTrigger_EntityName::TriggerAction( idEntity *activator ) {
  530. ActivateTargets( activator );
  531. CallScript();
  532. if ( wait >= 0 ) {
  533. nextTriggerTime = gameLocal.time + SEC2MS( wait + random * gameLocal.random.CRandomFloat() );
  534. } else {
  535. // we can't just remove (this) here, because this is a touch function
  536. // called while looping through area links...
  537. nextTriggerTime = gameLocal.time + 1;
  538. PostEventMS( &EV_Remove, 0 );
  539. }
  540. }
  541. /*
  542. ================
  543. idTrigger_EntityName::Event_TriggerAction
  544. ================
  545. */
  546. void idTrigger_EntityName::Event_TriggerAction( idEntity *activator ) {
  547. TriggerAction( activator );
  548. }
  549. /*
  550. ================
  551. idTrigger_EntityName::Event_Trigger
  552. the trigger was just activated
  553. activated should be the entity that originated the activation sequence (ie. the original target)
  554. activator should be set to the activator so it can be held through a delay
  555. so wait for the delay time before firing
  556. ================
  557. */
  558. void idTrigger_EntityName::Event_Trigger( idEntity *activator ) {
  559. if ( nextTriggerTime > gameLocal.time ) {
  560. // can't retrigger until the wait is over
  561. return;
  562. }
  563. bool validEntity = false;
  564. if ( activator ) {
  565. if ( testPartialName ) {
  566. if ( activator->name.Find( entityName, false ) >= 0 ) {
  567. validEntity = true;
  568. }
  569. }
  570. if ( activator->name == entityName ) {
  571. validEntity = true;
  572. }
  573. }
  574. if ( !validEntity ) {
  575. return;
  576. }
  577. if ( triggerFirst ) {
  578. triggerFirst = false;
  579. return;
  580. }
  581. // don't allow it to trigger twice in a single frame
  582. nextTriggerTime = gameLocal.time + 1;
  583. if ( delay > 0 ) {
  584. // don't allow it to trigger again until our delay has passed
  585. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  586. PostEventSec( &EV_TriggerAction, delay, activator );
  587. } else {
  588. TriggerAction( activator );
  589. }
  590. }
  591. /*
  592. ================
  593. idTrigger_EntityName::Event_Touch
  594. ================
  595. */
  596. void idTrigger_EntityName::Event_Touch( idEntity *other, trace_t *trace ) {
  597. if ( common->IsClient() ) {
  598. return;
  599. }
  600. if( triggerFirst ) {
  601. return;
  602. }
  603. if ( nextTriggerTime > gameLocal.time ) {
  604. // can't retrigger until the wait is over
  605. return;
  606. }
  607. bool validEntity = false;
  608. if ( other ) {
  609. if ( testPartialName ) {
  610. if ( other->name.Find( entityName, false ) >= 0 ) {
  611. validEntity = true;
  612. }
  613. }
  614. if ( other->name == entityName ) {
  615. validEntity = true;
  616. }
  617. }
  618. if ( !validEntity ) {
  619. return;
  620. }
  621. nextTriggerTime = gameLocal.time + 1;
  622. if ( delay > 0 ) {
  623. // don't allow it to trigger again until our delay has passed
  624. nextTriggerTime += SEC2MS( delay + random_delay * gameLocal.random.CRandomFloat() );
  625. PostEventSec( &EV_TriggerAction, delay, other );
  626. } else {
  627. TriggerAction( other );
  628. }
  629. }
  630. /*
  631. ===============================================================================
  632. idTrigger_Timer
  633. ===============================================================================
  634. */
  635. const idEventDef EV_Timer( "<timer>", NULL );
  636. CLASS_DECLARATION( idTrigger, idTrigger_Timer )
  637. EVENT( EV_Timer, idTrigger_Timer::Event_Timer )
  638. EVENT( EV_Activate, idTrigger_Timer::Event_Use )
  639. END_CLASS
  640. /*
  641. ================
  642. idTrigger_Timer::idTrigger_Timer
  643. ================
  644. */
  645. idTrigger_Timer::idTrigger_Timer() {
  646. random = 0.0f;
  647. wait = 0.0f;
  648. on = false;
  649. delay = 0.0f;
  650. }
  651. /*
  652. ================
  653. idTrigger_Timer::Save
  654. ================
  655. */
  656. void idTrigger_Timer::Save( idSaveGame *savefile ) const {
  657. savefile->WriteFloat( random );
  658. savefile->WriteFloat( wait );
  659. savefile->WriteBool( on );
  660. savefile->WriteFloat( delay );
  661. savefile->WriteString( onName );
  662. savefile->WriteString( offName );
  663. }
  664. /*
  665. ================
  666. idTrigger_Timer::Restore
  667. ================
  668. */
  669. void idTrigger_Timer::Restore( idRestoreGame *savefile ) {
  670. savefile->ReadFloat( random );
  671. savefile->ReadFloat( wait );
  672. savefile->ReadBool( on );
  673. savefile->ReadFloat( delay );
  674. savefile->ReadString( onName );
  675. savefile->ReadString( offName );
  676. }
  677. /*
  678. ================
  679. idTrigger_Timer::Spawn
  680. Repeatedly fires its targets.
  681. Can be turned on or off by using.
  682. ================
  683. */
  684. void idTrigger_Timer::Spawn() {
  685. spawnArgs.GetFloat( "random", "1", random );
  686. spawnArgs.GetFloat( "wait", "1", wait );
  687. spawnArgs.GetBool( "start_on", "0", on );
  688. spawnArgs.GetFloat( "delay", "0", delay );
  689. onName = spawnArgs.GetString( "onName" );
  690. offName = spawnArgs.GetString( "offName" );
  691. if ( random >= wait && wait >= 0 ) {
  692. random = wait - 0.001;
  693. gameLocal.Warning( "idTrigger_Timer '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
  694. }
  695. if ( on ) {
  696. PostEventSec( &EV_Timer, delay );
  697. }
  698. }
  699. /*
  700. ================
  701. idTrigger_Timer::Enable
  702. ================
  703. */
  704. void idTrigger_Timer::Enable() {
  705. // if off, turn it on
  706. if ( !on ) {
  707. on = true;
  708. PostEventSec( &EV_Timer, delay );
  709. }
  710. }
  711. /*
  712. ================
  713. idTrigger_Timer::Disable
  714. ================
  715. */
  716. void idTrigger_Timer::Disable() {
  717. // if on, turn it off
  718. if ( on ) {
  719. on = false;
  720. CancelEvents( &EV_Timer );
  721. }
  722. }
  723. /*
  724. ================
  725. idTrigger_Timer::Event_Timer
  726. ================
  727. */
  728. void idTrigger_Timer::Event_Timer() {
  729. ActivateTargets( this );
  730. // set time before next firing
  731. if ( wait >= 0.0f ) {
  732. PostEventSec( &EV_Timer, wait + gameLocal.random.CRandomFloat() * random );
  733. }
  734. }
  735. /*
  736. ================
  737. idTrigger_Timer::Event_Use
  738. ================
  739. */
  740. void idTrigger_Timer::Event_Use( idEntity *activator ) {
  741. // if on, turn it off
  742. if ( on ) {
  743. if ( offName.Length() && offName.Icmp( activator->GetName() ) ) {
  744. return;
  745. }
  746. on = false;
  747. CancelEvents( &EV_Timer );
  748. } else {
  749. // turn it on
  750. if ( onName.Length() && onName.Icmp( activator->GetName() ) ) {
  751. return;
  752. }
  753. on = true;
  754. PostEventSec( &EV_Timer, delay );
  755. }
  756. }
  757. /*
  758. ===============================================================================
  759. idTrigger_Count
  760. ===============================================================================
  761. */
  762. CLASS_DECLARATION( idTrigger, idTrigger_Count )
  763. EVENT( EV_Activate, idTrigger_Count::Event_Trigger )
  764. EVENT( EV_TriggerAction, idTrigger_Count::Event_TriggerAction )
  765. END_CLASS
  766. /*
  767. ================
  768. idTrigger_Count::idTrigger_Count
  769. ================
  770. */
  771. idTrigger_Count::idTrigger_Count() {
  772. goal = 0;
  773. count = 0;
  774. delay = 0.0f;
  775. }
  776. /*
  777. ================
  778. idTrigger_Count::Save
  779. ================
  780. */
  781. void idTrigger_Count::Save( idSaveGame *savefile ) const {
  782. savefile->WriteInt( goal );
  783. savefile->WriteInt( count );
  784. savefile->WriteFloat( delay );
  785. }
  786. /*
  787. ================
  788. idTrigger_Count::Restore
  789. ================
  790. */
  791. void idTrigger_Count::Restore( idRestoreGame *savefile ) {
  792. savefile->ReadInt( goal );
  793. savefile->ReadInt( count );
  794. savefile->ReadFloat( delay );
  795. }
  796. /*
  797. ================
  798. idTrigger_Count::Spawn
  799. ================
  800. */
  801. void idTrigger_Count::Spawn() {
  802. spawnArgs.GetInt( "count", "1", goal );
  803. spawnArgs.GetFloat( "delay", "0", delay );
  804. count = 0;
  805. }
  806. /*
  807. ================
  808. idTrigger_Count::Event_Trigger
  809. ================
  810. */
  811. void idTrigger_Count::Event_Trigger( idEntity *activator ) {
  812. // goal of -1 means trigger has been exhausted
  813. if (goal >= 0) {
  814. count++;
  815. if ( count >= goal ) {
  816. if (spawnArgs.GetBool("repeat")) {
  817. count = 0;
  818. } else {
  819. goal = -1;
  820. }
  821. PostEventSec( &EV_TriggerAction, delay, activator );
  822. }
  823. }
  824. }
  825. /*
  826. ================
  827. idTrigger_Count::Event_TriggerAction
  828. ================
  829. */
  830. void idTrigger_Count::Event_TriggerAction( idEntity *activator ) {
  831. ActivateTargets( activator );
  832. CallScript();
  833. if ( goal == -1 ) {
  834. PostEventMS( &EV_Remove, 0 );
  835. }
  836. }
  837. /*
  838. ===============================================================================
  839. idTrigger_Hurt
  840. ===============================================================================
  841. */
  842. CLASS_DECLARATION( idTrigger, idTrigger_Hurt )
  843. EVENT( EV_Touch, idTrigger_Hurt::Event_Touch )
  844. EVENT( EV_Activate, idTrigger_Hurt::Event_Toggle )
  845. END_CLASS
  846. /*
  847. ================
  848. idTrigger_Hurt::idTrigger_Hurt
  849. ================
  850. */
  851. idTrigger_Hurt::idTrigger_Hurt() {
  852. on = false;
  853. delay = 0.0f;
  854. nextTime = 0;
  855. }
  856. /*
  857. ================
  858. idTrigger_Hurt::Save
  859. ================
  860. */
  861. void idTrigger_Hurt::Save( idSaveGame *savefile ) const {
  862. savefile->WriteBool( on );
  863. savefile->WriteFloat( delay );
  864. savefile->WriteInt( nextTime );
  865. }
  866. /*
  867. ================
  868. idTrigger_Hurt::Restore
  869. ================
  870. */
  871. void idTrigger_Hurt::Restore( idRestoreGame *savefile ) {
  872. savefile->ReadBool( on );
  873. savefile->ReadFloat( delay );
  874. savefile->ReadInt( nextTime );
  875. }
  876. /*
  877. ================
  878. idTrigger_Hurt::Spawn
  879. Damages activator
  880. Can be turned on or off by using.
  881. ================
  882. */
  883. void idTrigger_Hurt::Spawn() {
  884. spawnArgs.GetBool( "on", "1", on );
  885. spawnArgs.GetFloat( "delay", "1.0", delay );
  886. nextTime = gameLocal.time;
  887. Enable();
  888. }
  889. /*
  890. ================
  891. idTrigger_Hurt::Event_Touch
  892. ================
  893. */
  894. void idTrigger_Hurt::Event_Touch( idEntity *other, trace_t *trace ) {
  895. const char *damage;
  896. if ( common->IsClient() ) {
  897. return;
  898. }
  899. if ( on && other && gameLocal.time >= nextTime ) {
  900. bool playerOnly = spawnArgs.GetBool( "playerOnly" );
  901. if ( playerOnly ) {
  902. if ( !other->IsType( idPlayer::Type ) ) {
  903. return;
  904. }
  905. }
  906. damage = spawnArgs.GetString( "def_damage", "damage_painTrigger" );
  907. idVec3 dir = vec3_origin;
  908. if(spawnArgs.GetBool("kick_from_center", "0")) {
  909. dir = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin();
  910. dir.Normalize();
  911. }
  912. other->Damage( NULL, NULL, dir, damage, 1.0f, INVALID_JOINT );
  913. ActivateTargets( other );
  914. CallScript();
  915. nextTime = gameLocal.time + SEC2MS( delay );
  916. }
  917. }
  918. /*
  919. ================
  920. idTrigger_Hurt::Event_Toggle
  921. ================
  922. */
  923. void idTrigger_Hurt::Event_Toggle( idEntity *activator ) {
  924. on = !on;
  925. }
  926. /*
  927. ===============================================================================
  928. idTrigger_Fade
  929. ===============================================================================
  930. */
  931. CLASS_DECLARATION( idTrigger, idTrigger_Fade )
  932. EVENT( EV_Activate, idTrigger_Fade::Event_Trigger )
  933. END_CLASS
  934. /*
  935. ================
  936. idTrigger_Fade::Event_Trigger
  937. ================
  938. */
  939. void idTrigger_Fade::Event_Trigger( idEntity *activator ) {
  940. idVec4 fadeColor;
  941. int fadeTime;
  942. idPlayer *player;
  943. player = gameLocal.GetLocalPlayer();
  944. if ( player ) {
  945. fadeColor = spawnArgs.GetVec4( "fadeColor", "0, 0, 0, 1" );
  946. fadeTime = SEC2MS( spawnArgs.GetFloat( "fadeTime", "0.5" ) );
  947. player->playerView.Fade( fadeColor, fadeTime );
  948. PostEventMS( &EV_ActivateTargets, fadeTime, activator );
  949. }
  950. }
  951. /*
  952. ===============================================================================
  953. idTrigger_Touch
  954. ===============================================================================
  955. */
  956. CLASS_DECLARATION( idTrigger, idTrigger_Touch )
  957. EVENT( EV_Activate, idTrigger_Touch::Event_Trigger )
  958. END_CLASS
  959. /*
  960. ================
  961. idTrigger_Touch::idTrigger_Touch
  962. ================
  963. */
  964. idTrigger_Touch::idTrigger_Touch() {
  965. clipModel = NULL;
  966. }
  967. /*
  968. ================
  969. idTrigger_Touch::Spawn
  970. ================
  971. */
  972. void idTrigger_Touch::Spawn() {
  973. // get the clip model
  974. clipModel = new (TAG_THREAD) idClipModel( GetPhysics()->GetClipModel() );
  975. // remove the collision model from the physics object
  976. GetPhysics()->SetClipModel( NULL, 1.0f );
  977. if ( spawnArgs.GetBool( "start_on" ) ) {
  978. BecomeActive( TH_THINK );
  979. }
  980. }
  981. /*
  982. ================
  983. idTrigger_Touch::Save
  984. ================
  985. */
  986. void idTrigger_Touch::Save( idSaveGame *savefile ) {
  987. savefile->WriteClipModel( clipModel );
  988. }
  989. /*
  990. ================
  991. idTrigger_Touch::Restore
  992. ================
  993. */
  994. void idTrigger_Touch::Restore( idRestoreGame *savefile ) {
  995. savefile->ReadClipModel( clipModel );
  996. }
  997. /*
  998. ================
  999. idTrigger_Touch::TouchEntities
  1000. ================
  1001. */
  1002. void idTrigger_Touch::TouchEntities() {
  1003. int numClipModels, i;
  1004. idBounds bounds;
  1005. idClipModel *cm, *clipModelList[ MAX_GENTITIES ];
  1006. if ( clipModel == NULL || scriptFunction == NULL ) {
  1007. return;
  1008. }
  1009. bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() );
  1010. numClipModels = gameLocal.clip.ClipModelsTouchingBounds( bounds, -1, clipModelList, MAX_GENTITIES );
  1011. for ( i = 0; i < numClipModels; i++ ) {
  1012. cm = clipModelList[ i ];
  1013. if ( !cm->IsTraceModel() ) {
  1014. continue;
  1015. }
  1016. idEntity *entity = cm->GetEntity();
  1017. if ( !entity ) {
  1018. continue;
  1019. }
  1020. if ( !gameLocal.clip.ContentsModel( cm->GetOrigin(), cm, cm->GetAxis(), -1,
  1021. clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) {
  1022. continue;
  1023. }
  1024. ActivateTargets( entity );
  1025. idThread *thread = new idThread();
  1026. thread->CallFunction( entity, scriptFunction, false );
  1027. thread->DelayedStart( 0 );
  1028. }
  1029. }
  1030. /*
  1031. ================
  1032. idTrigger_Touch::Think
  1033. ================
  1034. */
  1035. void idTrigger_Touch::Think() {
  1036. if ( thinkFlags & TH_THINK ) {
  1037. TouchEntities();
  1038. }
  1039. idEntity::Think();
  1040. }
  1041. /*
  1042. ================
  1043. idTrigger_Touch::Event_Trigger
  1044. ================
  1045. */
  1046. void idTrigger_Touch::Event_Trigger( idEntity *activator ) {
  1047. if ( thinkFlags & TH_THINK ) {
  1048. BecomeInactive( TH_THINK );
  1049. } else {
  1050. BecomeActive( TH_THINK );
  1051. }
  1052. }
  1053. /*
  1054. ================
  1055. idTrigger_Touch::Enable
  1056. ================
  1057. */
  1058. void idTrigger_Touch::Enable() {
  1059. BecomeActive( TH_THINK );
  1060. }
  1061. /*
  1062. ================
  1063. idTrigger_Touch::Disable
  1064. ================
  1065. */
  1066. void idTrigger_Touch::Disable() {
  1067. BecomeInactive( TH_THINK );
  1068. }
  1069. /*
  1070. ===============================================================================
  1071. idTrigger_Flag
  1072. ===============================================================================
  1073. */
  1074. CLASS_DECLARATION( idTrigger_Multi, idTrigger_Flag )
  1075. EVENT( EV_Touch, idTrigger_Flag::Event_Touch )
  1076. END_CLASS
  1077. idTrigger_Flag::idTrigger_Flag() {
  1078. team = -1;
  1079. player = false;
  1080. eventFlag = NULL;
  1081. }
  1082. void idTrigger_Flag::Spawn() {
  1083. team = spawnArgs.GetInt( "team", "0" );
  1084. player = spawnArgs.GetBool( "player", "0" );
  1085. idStr funcname = spawnArgs.GetString( "eventflag", "" );
  1086. if ( funcname.Length() ) {
  1087. eventFlag = idEventDef::FindEvent( funcname );// gameLocal.program.FindFunction( funcname );//, &idItemTeam::Type );
  1088. if ( eventFlag == NULL ) {
  1089. gameLocal.Warning( "trigger '%s' at (%s) event unknown '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), funcname.c_str() );
  1090. }
  1091. } else {
  1092. eventFlag = NULL;
  1093. }
  1094. idTrigger_Multi::Spawn();
  1095. }
  1096. void idTrigger_Flag::Event_Touch( idEntity *other, trace_t *trace ) {
  1097. idItemTeam * flag = NULL;
  1098. if ( common->IsClient() ) {
  1099. return;
  1100. }
  1101. if ( player ) {
  1102. if ( !other->IsType( idPlayer::Type ) )
  1103. return;
  1104. idPlayer * player = static_cast<idPlayer *>(other);
  1105. if ( player->carryingFlag == false )
  1106. return;
  1107. if ( team != -1 && ( player->team != team || (player->team != 0 && player->team != 1)) )
  1108. return;
  1109. idItemTeam * flags[2];
  1110. flags[0] = gameLocal.mpGame.GetTeamFlag( 0 );
  1111. flags[1] = gameLocal.mpGame.GetTeamFlag( 1 );
  1112. int iFriend = 1 - player->team; // index to the flag player team wants
  1113. int iOpp = player->team; // index to the flag opp team wants
  1114. // flag is captured if :
  1115. // 1)flag is truely bound to the player
  1116. // 2)opponent flag has been return
  1117. if ( flags[iFriend]->carried && !flags[iFriend]->dropped && //flags[iFriend]->IsBoundTo( player ) &&
  1118. !flags[iOpp]->carried && !flags[iOpp]->dropped )
  1119. flag = flags[iFriend];
  1120. else
  1121. return;
  1122. } else {
  1123. if ( !other->IsType( idItemTeam::Type ) )
  1124. return;
  1125. idItemTeam * item = static_cast<idItemTeam *>( other );
  1126. if ( item->team == team || team == -1 ) {
  1127. flag = item;
  1128. }
  1129. else
  1130. return;
  1131. }
  1132. if ( flag ) {
  1133. switch ( eventFlag->GetNumArgs() ) {
  1134. default :
  1135. case 0 :
  1136. flag->PostEventMS( eventFlag, 0 );
  1137. break;
  1138. case 1 :
  1139. flag->PostEventMS( eventFlag, 0, NULL );
  1140. break;
  1141. case 2 :
  1142. flag->PostEventMS( eventFlag, 0, NULL, NULL );
  1143. break;
  1144. }
  1145. /*
  1146. ServerSendEvent( eventFlag->GetEventNum(), NULL, true );
  1147. idThread *thread;
  1148. if ( scriptFlag ) {
  1149. thread = new idThread();
  1150. thread->CallFunction( flag, scriptFlag, false );
  1151. thread->DelayedStart( 0 );
  1152. }
  1153. */
  1154. idTrigger_Multi::Event_Touch( other, trace );
  1155. }
  1156. }