g_func.c 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. /*
  5. =========================================================
  6. PLATS
  7. movement options:
  8. linear
  9. smooth start, hard stop
  10. smooth start, smooth stop
  11. start
  12. end
  13. acceleration
  14. speed
  15. deceleration
  16. begin sound
  17. end sound
  18. target fired when reaching end
  19. wait at end
  20. object characteristics that use move segments
  21. ---------------------------------------------
  22. movetype_push, or movetype_stop
  23. action when touched
  24. action when blocked
  25. action when used
  26. disabled?
  27. auto trigger spawning
  28. =========================================================
  29. */
  30. #define PLAT_LOW_TRIGGER 1
  31. //====
  32. //PGM
  33. #define PLAT2_TOGGLE 2
  34. #define PLAT2_TOP 4
  35. #define PLAT2_TRIGGER_TOP 8
  36. #define PLAT2_TRIGGER_BOTTOM 16
  37. #define PLAT2_BOX_LIFT 32
  38. void plat2_spawn_danger_area (edict_t *ent);
  39. void plat2_kill_danger_area (edict_t *ent);
  40. //PGM
  41. //====
  42. #define STATE_TOP 0
  43. #define STATE_BOTTOM 1
  44. #define STATE_UP 2
  45. #define STATE_DOWN 3
  46. #define DOOR_START_OPEN 1
  47. #define DOOR_REVERSE 2
  48. #define DOOR_CRUSHER 4
  49. #define DOOR_NOMONSTER 8
  50. #define DOOR_TOGGLE 32
  51. #define DOOR_X_AXIS 64
  52. #define DOOR_Y_AXIS 128
  53. // !easy 256
  54. // !med 512
  55. // !hard 1024
  56. // !dm 2048
  57. // !coop 4096
  58. #define DOOR_INACTIVE 8192
  59. //
  60. // Support routines for movement (changes in origin using velocity)
  61. //
  62. void Move_Done (edict_t *ent)
  63. {
  64. VectorClear (ent->velocity);
  65. ent->moveinfo.endfunc (ent);
  66. }
  67. void Move_Final (edict_t *ent)
  68. {
  69. if (ent->moveinfo.remaining_distance == 0)
  70. {
  71. Move_Done (ent);
  72. return;
  73. }
  74. VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity);
  75. ent->think = Move_Done;
  76. ent->nextthink = level.time + FRAMETIME;
  77. }
  78. void Move_Begin (edict_t *ent)
  79. {
  80. float frames;
  81. if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance)
  82. {
  83. Move_Final (ent);
  84. return;
  85. }
  86. VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity);
  87. frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME);
  88. ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME;
  89. ent->nextthink = level.time + (frames * FRAMETIME);
  90. ent->think = Move_Final;
  91. }
  92. void Think_AccelMove (edict_t *ent);
  93. void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*))
  94. {
  95. VectorClear (ent->velocity);
  96. VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir);
  97. ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir);
  98. ent->moveinfo.endfunc = func;
  99. if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel)
  100. {
  101. if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
  102. {
  103. Move_Begin (ent);
  104. }
  105. else
  106. {
  107. ent->nextthink = level.time + FRAMETIME;
  108. ent->think = Move_Begin;
  109. }
  110. }
  111. else
  112. {
  113. // accelerative
  114. ent->moveinfo.current_speed = 0;
  115. ent->think = Think_AccelMove;
  116. ent->nextthink = level.time + FRAMETIME;
  117. }
  118. }
  119. //
  120. // Support routines for angular movement (changes in angle using avelocity)
  121. //
  122. void AngleMove_Done (edict_t *ent)
  123. {
  124. VectorClear (ent->avelocity);
  125. ent->moveinfo.endfunc (ent);
  126. }
  127. void AngleMove_Final (edict_t *ent)
  128. {
  129. vec3_t move;
  130. if (ent->moveinfo.state == STATE_UP)
  131. VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move);
  132. else
  133. VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move);
  134. if (VectorCompare (move, vec3_origin))
  135. {
  136. AngleMove_Done (ent);
  137. return;
  138. }
  139. VectorScale (move, 1.0/FRAMETIME, ent->avelocity);
  140. ent->think = AngleMove_Done;
  141. ent->nextthink = level.time + FRAMETIME;
  142. }
  143. void AngleMove_Begin (edict_t *ent)
  144. {
  145. vec3_t destdelta;
  146. float len;
  147. float traveltime;
  148. float frames;
  149. //PGM accelerate as needed
  150. if(ent->moveinfo.speed < ent->speed)
  151. {
  152. ent->moveinfo.speed += ent->accel;
  153. if(ent->moveinfo.speed > ent->speed)
  154. ent->moveinfo.speed = ent->speed;
  155. }
  156. //PGM
  157. // set destdelta to the vector needed to move
  158. if (ent->moveinfo.state == STATE_UP)
  159. VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta);
  160. else
  161. VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta);
  162. // calculate length of vector
  163. len = VectorLength (destdelta);
  164. // divide by speed to get time to reach dest
  165. traveltime = len / ent->moveinfo.speed;
  166. if (traveltime < FRAMETIME)
  167. {
  168. AngleMove_Final (ent);
  169. return;
  170. }
  171. frames = floor(traveltime / FRAMETIME);
  172. // scale the destdelta vector by the time spent traveling to get velocity
  173. VectorScale (destdelta, 1.0 / traveltime, ent->avelocity);
  174. //PGM
  175. // if we're done accelerating, act as a normal rotation
  176. if(ent->moveinfo.speed >= ent->speed)
  177. {
  178. // set nextthink to trigger a think when dest is reached
  179. ent->nextthink = level.time + frames * FRAMETIME;
  180. ent->think = AngleMove_Final;
  181. }
  182. else
  183. {
  184. ent->nextthink = level.time + FRAMETIME;
  185. ent->think = AngleMove_Begin;
  186. }
  187. //PGM
  188. }
  189. void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*))
  190. {
  191. VectorClear (ent->avelocity);
  192. ent->moveinfo.endfunc = func;
  193. //PGM
  194. // if we're supposed to accelerate, this will tell anglemove_begin to do so
  195. if(ent->accel != ent->speed)
  196. ent->moveinfo.speed = 0;
  197. //PGM
  198. if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
  199. {
  200. AngleMove_Begin (ent);
  201. }
  202. else
  203. {
  204. ent->nextthink = level.time + FRAMETIME;
  205. ent->think = AngleMove_Begin;
  206. }
  207. }
  208. /*
  209. ==============
  210. Think_AccelMove
  211. The team has completed a frame of movement, so
  212. change the speed for the next frame
  213. ==============
  214. */
  215. #define AccelerationDistance(target, rate) (target * ((target / rate) + 1) / 2)
  216. void plat_CalcAcceleratedMove(moveinfo_t *moveinfo)
  217. {
  218. float accel_dist;
  219. float decel_dist;
  220. moveinfo->move_speed = moveinfo->speed;
  221. if (moveinfo->remaining_distance < moveinfo->accel)
  222. {
  223. moveinfo->current_speed = moveinfo->remaining_distance;
  224. return;
  225. }
  226. accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel);
  227. decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel);
  228. if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0)
  229. {
  230. float f;
  231. f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel);
  232. moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f);
  233. decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel);
  234. }
  235. moveinfo->decel_distance = decel_dist;
  236. };
  237. void plat_Accelerate (moveinfo_t *moveinfo)
  238. {
  239. // are we decelerating?
  240. if (moveinfo->remaining_distance <= moveinfo->decel_distance)
  241. {
  242. if (moveinfo->remaining_distance < moveinfo->decel_distance)
  243. {
  244. if (moveinfo->next_speed)
  245. {
  246. moveinfo->current_speed = moveinfo->next_speed;
  247. moveinfo->next_speed = 0;
  248. return;
  249. }
  250. if (moveinfo->current_speed > moveinfo->decel)
  251. moveinfo->current_speed -= moveinfo->decel;
  252. }
  253. return;
  254. }
  255. // are we at full speed and need to start decelerating during this move?
  256. if (moveinfo->current_speed == moveinfo->move_speed)
  257. if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance)
  258. {
  259. float p1_distance;
  260. float p2_distance;
  261. float distance;
  262. p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
  263. p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed));
  264. distance = p1_distance + p2_distance;
  265. moveinfo->current_speed = moveinfo->move_speed;
  266. moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
  267. return;
  268. }
  269. // are we accelerating?
  270. if (moveinfo->current_speed < moveinfo->speed)
  271. {
  272. float old_speed;
  273. float p1_distance;
  274. float p1_speed;
  275. float p2_distance;
  276. float distance;
  277. old_speed = moveinfo->current_speed;
  278. // figure simple acceleration up to move_speed
  279. moveinfo->current_speed += moveinfo->accel;
  280. if (moveinfo->current_speed > moveinfo->speed)
  281. moveinfo->current_speed = moveinfo->speed;
  282. // are we accelerating throughout this entire move?
  283. if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance)
  284. return;
  285. // during this move we will accelrate from current_speed to move_speed
  286. // and cross over the decel_distance; figure the average speed for the
  287. // entire move
  288. p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance;
  289. p1_speed = (old_speed + moveinfo->move_speed) / 2.0;
  290. p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed));
  291. distance = p1_distance + p2_distance;
  292. moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance));
  293. moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance);
  294. return;
  295. }
  296. // we are at constant velocity (move_speed)
  297. return;
  298. };
  299. void Think_AccelMove (edict_t *ent)
  300. {
  301. ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed;
  302. // PGM 04/21/98 - this should fix sthoms' sinking drop pod. Hopefully it wont break stuff.
  303. // if (ent->moveinfo.current_speed == 0) // starting or blocked
  304. plat_CalcAcceleratedMove(&ent->moveinfo);
  305. plat_Accelerate (&ent->moveinfo);
  306. // will the entire move complete on next frame?
  307. if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed)
  308. {
  309. Move_Final (ent);
  310. return;
  311. }
  312. VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity);
  313. ent->nextthink = level.time + FRAMETIME;
  314. ent->think = Think_AccelMove;
  315. }
  316. void plat_go_down (edict_t *ent);
  317. void plat_hit_top (edict_t *ent)
  318. {
  319. if (!(ent->flags & FL_TEAMSLAVE))
  320. {
  321. if (ent->moveinfo.sound_end)
  322. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  323. ent->s.sound = 0;
  324. }
  325. ent->moveinfo.state = STATE_TOP;
  326. ent->think = plat_go_down;
  327. ent->nextthink = level.time + 3;
  328. }
  329. void plat_hit_bottom (edict_t *ent)
  330. {
  331. if (!(ent->flags & FL_TEAMSLAVE))
  332. {
  333. if (ent->moveinfo.sound_end)
  334. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  335. ent->s.sound = 0;
  336. }
  337. ent->moveinfo.state = STATE_BOTTOM;
  338. plat2_kill_danger_area (ent); // PGM
  339. }
  340. void plat_go_down (edict_t *ent)
  341. {
  342. if (!(ent->flags & FL_TEAMSLAVE))
  343. {
  344. if (ent->moveinfo.sound_start)
  345. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  346. ent->s.sound = ent->moveinfo.sound_middle;
  347. }
  348. ent->moveinfo.state = STATE_DOWN;
  349. Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom);
  350. }
  351. void plat_go_up (edict_t *ent)
  352. {
  353. if (!(ent->flags & FL_TEAMSLAVE))
  354. {
  355. if (ent->moveinfo.sound_start)
  356. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  357. ent->s.sound = ent->moveinfo.sound_middle;
  358. }
  359. ent->moveinfo.state = STATE_UP;
  360. Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top);
  361. plat2_spawn_danger_area(ent); // PGM
  362. }
  363. void plat_blocked (edict_t *self, edict_t *other)
  364. {
  365. if (!(other->svflags & SVF_MONSTER) && (!other->client) )
  366. {
  367. // give it a chance to go away on it's own terms (like gibs)
  368. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
  369. // if it's still there, nuke it
  370. if (other && other->inuse) // PGM
  371. BecomeExplosion1 (other);
  372. return;
  373. }
  374. //PGM
  375. // gib dead things
  376. if(other->health < 1)
  377. {
  378. T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100, 1, 0, MOD_CRUSH);
  379. }
  380. //PGM
  381. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  382. if (self->moveinfo.state == STATE_UP)
  383. plat_go_down (self);
  384. else if (self->moveinfo.state == STATE_DOWN)
  385. plat_go_up (self);
  386. }
  387. void Use_Plat (edict_t *ent, edict_t *other, edict_t *activator)
  388. {
  389. //======
  390. //ROGUE
  391. // if a monster is using us, then allow the activity when stopped.
  392. if (other->svflags & SVF_MONSTER)
  393. {
  394. if (ent->moveinfo.state == STATE_TOP)
  395. plat_go_down (ent);
  396. else if (ent->moveinfo.state == STATE_BOTTOM)
  397. plat_go_up (ent);
  398. return;
  399. }
  400. //ROGUE
  401. //======
  402. if (ent->think)
  403. return; // already down
  404. plat_go_down (ent);
  405. }
  406. void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
  407. {
  408. if (!other->client)
  409. return;
  410. if (other->health <= 0)
  411. return;
  412. ent = ent->enemy; // now point at the plat, not the trigger
  413. if (ent->moveinfo.state == STATE_BOTTOM)
  414. plat_go_up (ent);
  415. else if (ent->moveinfo.state == STATE_TOP)
  416. ent->nextthink = level.time + 1; // the player is still on the plat, so delay going down
  417. }
  418. // PGM - plat2's change the trigger field
  419. //void plat_spawn_inside_trigger (edict_t *ent)
  420. edict_t *plat_spawn_inside_trigger (edict_t *ent)
  421. {
  422. edict_t *trigger;
  423. vec3_t tmin, tmax;
  424. //
  425. // middle trigger
  426. //
  427. trigger = G_Spawn();
  428. trigger->touch = Touch_Plat_Center;
  429. trigger->movetype = MOVETYPE_NONE;
  430. trigger->solid = SOLID_TRIGGER;
  431. trigger->enemy = ent;
  432. tmin[0] = ent->mins[0] + 25;
  433. tmin[1] = ent->mins[1] + 25;
  434. tmin[2] = ent->mins[2];
  435. tmax[0] = ent->maxs[0] - 25;
  436. tmax[1] = ent->maxs[1] - 25;
  437. tmax[2] = ent->maxs[2] + 8;
  438. tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip);
  439. if (ent->spawnflags & PLAT_LOW_TRIGGER)
  440. tmax[2] = tmin[2] + 8;
  441. if (tmax[0] - tmin[0] <= 0)
  442. {
  443. tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5;
  444. tmax[0] = tmin[0] + 1;
  445. }
  446. if (tmax[1] - tmin[1] <= 0)
  447. {
  448. tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5;
  449. tmax[1] = tmin[1] + 1;
  450. }
  451. VectorCopy (tmin, trigger->mins);
  452. VectorCopy (tmax, trigger->maxs);
  453. gi.linkentity (trigger);
  454. return trigger; // PGM 11/17/97
  455. }
  456. /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER
  457. speed default 150
  458. Plats are always drawn in the extended position, so they will light correctly.
  459. If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
  460. "speed" overrides default 200.
  461. "accel" overrides default 500
  462. "lip" overrides default 8 pixel lip
  463. If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
  464. Set "sounds" to one of the following:
  465. 1) base fast
  466. 2) chain slow
  467. */
  468. void SP_func_plat (edict_t *ent)
  469. {
  470. VectorClear (ent->s.angles);
  471. ent->solid = SOLID_BSP;
  472. ent->movetype = MOVETYPE_PUSH;
  473. gi.setmodel (ent, ent->model);
  474. ent->blocked = plat_blocked;
  475. if (!ent->speed)
  476. ent->speed = 20;
  477. else
  478. ent->speed *= 0.1;
  479. if (!ent->accel)
  480. ent->accel = 5;
  481. else
  482. ent->accel *= 0.1;
  483. if (!ent->decel)
  484. ent->decel = 5;
  485. else
  486. ent->decel *= 0.1;
  487. if (!ent->dmg)
  488. ent->dmg = 2;
  489. if (!st.lip)
  490. st.lip = 8;
  491. // pos1 is the top position, pos2 is the bottom
  492. VectorCopy (ent->s.origin, ent->pos1);
  493. VectorCopy (ent->s.origin, ent->pos2);
  494. if (st.height)
  495. ent->pos2[2] -= st.height;
  496. else
  497. ent->pos2[2] -= (ent->maxs[2] - ent->mins[2]) - st.lip;
  498. ent->use = Use_Plat;
  499. plat_spawn_inside_trigger (ent); // the "start moving" trigger
  500. if (ent->targetname)
  501. {
  502. ent->moveinfo.state = STATE_UP;
  503. }
  504. else
  505. {
  506. VectorCopy (ent->pos2, ent->s.origin);
  507. gi.linkentity (ent);
  508. ent->moveinfo.state = STATE_BOTTOM;
  509. }
  510. ent->moveinfo.speed = ent->speed;
  511. ent->moveinfo.accel = ent->accel;
  512. ent->moveinfo.decel = ent->decel;
  513. ent->moveinfo.wait = ent->wait;
  514. VectorCopy (ent->pos1, ent->moveinfo.start_origin);
  515. VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
  516. VectorCopy (ent->pos2, ent->moveinfo.end_origin);
  517. VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
  518. ent->moveinfo.sound_start = gi.soundindex ("plats/pt1_strt.wav");
  519. ent->moveinfo.sound_middle = gi.soundindex ("plats/pt1_mid.wav");
  520. ent->moveinfo.sound_end = gi.soundindex ("plats/pt1_end.wav");
  521. }
  522. // ==========================================
  523. // PLAT 2
  524. // ==========================================
  525. #define PLAT2_CALLED 1
  526. #define PLAT2_MOVING 2
  527. #define PLAT2_WAITING 4
  528. void plat2_go_down (edict_t *ent);
  529. void plat2_go_up (edict_t *ent);
  530. void plat2_spawn_danger_area (edict_t *ent)
  531. {
  532. vec3_t mins, maxs;
  533. VectorCopy(ent->mins, mins);
  534. VectorCopy(ent->maxs, maxs);
  535. maxs[2] = ent->mins[2] + 64;
  536. SpawnBadArea(mins, maxs, 0, ent);
  537. }
  538. void plat2_kill_danger_area (edict_t *ent)
  539. {
  540. edict_t *t;
  541. t = NULL;
  542. while ((t = G_Find (t, FOFS(classname), "bad_area")))
  543. {
  544. if(t->owner == ent)
  545. G_FreeEdict(t);
  546. }
  547. }
  548. void plat2_hit_top (edict_t *ent)
  549. {
  550. if (!(ent->flags & FL_TEAMSLAVE))
  551. {
  552. if (ent->moveinfo.sound_end)
  553. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  554. ent->s.sound = 0;
  555. }
  556. ent->moveinfo.state = STATE_TOP;
  557. if(ent->plat2flags & PLAT2_CALLED)
  558. {
  559. ent->plat2flags = PLAT2_WAITING;
  560. if(!(ent->spawnflags & PLAT2_TOGGLE))
  561. {
  562. ent->think = plat2_go_down;
  563. ent->nextthink = level.time + 5.0;
  564. }
  565. if(deathmatch->value)
  566. ent->last_move_time = level.time - 1.0;
  567. else
  568. ent->last_move_time = level.time - 2.0;
  569. }
  570. else if(!(ent->spawnflags & PLAT2_TOP) && !(ent->spawnflags & PLAT2_TOGGLE))
  571. {
  572. ent->plat2flags = 0;
  573. ent->think = plat2_go_down;
  574. ent->nextthink = level.time + 2.0;
  575. ent->last_move_time = level.time;
  576. }
  577. else
  578. {
  579. ent->plat2flags = 0;
  580. ent->last_move_time = level.time;
  581. }
  582. G_UseTargets (ent, ent);
  583. }
  584. void plat2_hit_bottom (edict_t *ent)
  585. {
  586. if (!(ent->flags & FL_TEAMSLAVE))
  587. {
  588. if (ent->moveinfo.sound_end)
  589. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  590. ent->s.sound = 0;
  591. }
  592. ent->moveinfo.state = STATE_BOTTOM;
  593. if(ent->plat2flags & PLAT2_CALLED)
  594. {
  595. ent->plat2flags = PLAT2_WAITING;
  596. if(!(ent->spawnflags & PLAT2_TOGGLE))
  597. {
  598. ent->think = plat2_go_up;
  599. ent->nextthink = level.time + 5.0;
  600. }
  601. if(deathmatch->value)
  602. ent->last_move_time = level.time - 1.0;
  603. else
  604. ent->last_move_time = level.time - 2.0;
  605. }
  606. else if ((ent->spawnflags & PLAT2_TOP) && !(ent->spawnflags & PLAT2_TOGGLE))
  607. {
  608. ent->plat2flags = 0;
  609. ent->think = plat2_go_up;
  610. ent->nextthink = level.time + 2.0;
  611. ent->last_move_time = level.time;
  612. }
  613. else
  614. {
  615. ent->plat2flags = 0;
  616. ent->last_move_time = level.time;
  617. }
  618. plat2_kill_danger_area (ent);
  619. G_UseTargets (ent, ent);
  620. }
  621. void plat2_go_down (edict_t *ent)
  622. {
  623. if (!(ent->flags & FL_TEAMSLAVE))
  624. {
  625. if (ent->moveinfo.sound_start)
  626. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  627. ent->s.sound = ent->moveinfo.sound_middle;
  628. }
  629. ent->moveinfo.state = STATE_DOWN;
  630. ent->plat2flags |= PLAT2_MOVING;
  631. Move_Calc (ent, ent->moveinfo.end_origin, plat2_hit_bottom);
  632. }
  633. void plat2_go_up (edict_t *ent)
  634. {
  635. if (!(ent->flags & FL_TEAMSLAVE))
  636. {
  637. if (ent->moveinfo.sound_start)
  638. gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  639. ent->s.sound = ent->moveinfo.sound_middle;
  640. }
  641. ent->moveinfo.state = STATE_UP;
  642. ent->plat2flags |= PLAT2_MOVING;
  643. plat2_spawn_danger_area(ent);
  644. Move_Calc (ent, ent->moveinfo.start_origin, plat2_hit_top);
  645. }
  646. void plat2_operate (edict_t *ent, edict_t *other)
  647. {
  648. int otherState;
  649. float pauseTime;
  650. float platCenter;
  651. edict_t *trigger;
  652. trigger = ent;
  653. ent = ent->enemy; // now point at the plat, not the trigger
  654. if (ent->plat2flags & PLAT2_MOVING)
  655. return;
  656. if ((ent->last_move_time + 2) > level.time)
  657. return;
  658. platCenter = (trigger->absmin[2] + trigger->absmax[2]) / 2;
  659. if(ent->moveinfo.state == STATE_TOP)
  660. {
  661. otherState = STATE_TOP;
  662. if(ent->spawnflags & PLAT2_BOX_LIFT)
  663. {
  664. if(platCenter > other->s.origin[2])
  665. otherState = STATE_BOTTOM;
  666. }
  667. else
  668. {
  669. if(trigger->absmax[2] > other->s.origin[2])
  670. otherState = STATE_BOTTOM;
  671. }
  672. }
  673. else
  674. {
  675. otherState = STATE_BOTTOM;
  676. if(other->s.origin[2] > platCenter)
  677. otherState = STATE_TOP;
  678. }
  679. ent->plat2flags = PLAT2_MOVING;
  680. if(deathmatch->value)
  681. pauseTime = 0.3;
  682. else
  683. pauseTime = 0.5;
  684. if(ent->moveinfo.state != otherState)
  685. {
  686. ent->plat2flags |= PLAT2_CALLED;
  687. pauseTime = 0.1;
  688. }
  689. ent->last_move_time = level.time;
  690. if(ent->moveinfo.state == STATE_BOTTOM)
  691. {
  692. ent->think = plat2_go_up;
  693. ent->nextthink = level.time + pauseTime;
  694. }
  695. else
  696. {
  697. ent->think = plat2_go_down;
  698. ent->nextthink = level.time + pauseTime;
  699. }
  700. }
  701. void Touch_Plat_Center2 (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
  702. {
  703. // this requires monsters to actively trigger plats, not just step on them.
  704. //FIXME - commented out for E3
  705. //if (!other->client)
  706. // return;
  707. if (other->health <= 0)
  708. return;
  709. // PMM - don't let non-monsters activate plat2s
  710. if ((!(other->svflags & SVF_MONSTER)) && (!other->client))
  711. return;
  712. plat2_operate(ent, other);
  713. }
  714. void plat2_blocked (edict_t *self, edict_t *other)
  715. {
  716. if (!(other->svflags & SVF_MONSTER) && (!other->client))
  717. {
  718. // give it a chance to go away on it's own terms (like gibs)
  719. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
  720. // if it's still there, nuke it
  721. if(other && other->inuse)
  722. BecomeExplosion1 (other);
  723. return;
  724. }
  725. // gib dead things
  726. if(other->health < 1)
  727. {
  728. T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100, 1, 0, MOD_CRUSH);
  729. }
  730. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  731. if (self->moveinfo.state == STATE_UP)
  732. plat2_go_down (self);
  733. else if (self->moveinfo.state == STATE_DOWN)
  734. plat2_go_up (self);
  735. }
  736. void Use_Plat2 (edict_t *ent, edict_t *other, edict_t *activator)
  737. {
  738. edict_t *trigger;
  739. int i;
  740. if(ent->moveinfo.state > STATE_BOTTOM)
  741. return;
  742. if((ent->last_move_time + 2) > level.time)
  743. return;
  744. for (i = 1, trigger = g_edicts + 1; i < globals.num_edicts; i++, trigger++)
  745. {
  746. if (!trigger->inuse)
  747. continue;
  748. if (trigger->touch == Touch_Plat_Center2)
  749. {
  750. if (trigger->enemy == ent)
  751. {
  752. // Touch_Plat_Center2 (trigger, activator, NULL, NULL);
  753. plat2_operate (trigger, activator);
  754. return;
  755. }
  756. }
  757. }
  758. }
  759. void plat2_activate (edict_t *ent, edict_t *other, edict_t *activator)
  760. {
  761. edict_t *trigger;
  762. // if(ent->targetname)
  763. // ent->targetname[0] = 0;
  764. ent->use = Use_Plat2;
  765. trigger = plat_spawn_inside_trigger (ent); // the "start moving" trigger
  766. trigger->maxs[0]+=10;
  767. trigger->maxs[1]+=10;
  768. trigger->mins[0]-=10;
  769. trigger->mins[1]-=10;
  770. gi.linkentity (trigger);
  771. trigger->touch = Touch_Plat_Center2; // Override trigger touch function
  772. plat2_go_down(ent);
  773. }
  774. /*QUAKED func_plat2 (0 .5 .8) ? PLAT_LOW_TRIGGER PLAT2_TOGGLE PLAT2_TOP PLAT2_TRIGGER_TOP PLAT2_TRIGGER_BOTTOM BOX_LIFT
  775. speed default 150
  776. PLAT_LOW_TRIGGER - creates a short trigger field at the bottom
  777. PLAT2_TOGGLE - plat will not return to default position.
  778. PLAT2_TOP - plat's default position will the the top.
  779. PLAT2_TRIGGER_TOP - plat will trigger it's targets each time it hits top
  780. PLAT2_TRIGGER_BOTTOM - plat will trigger it's targets each time it hits bottom
  781. BOX_LIFT - this indicates that the lift is a box, rather than just a platform
  782. Plats are always drawn in the extended position, so they will light correctly.
  783. If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.
  784. "speed" overrides default 200.
  785. "accel" overrides default 500
  786. "lip" no default
  787. If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height.
  788. */
  789. void SP_func_plat2 (edict_t *ent)
  790. {
  791. edict_t *trigger;
  792. VectorClear (ent->s.angles);
  793. ent->solid = SOLID_BSP;
  794. ent->movetype = MOVETYPE_PUSH;
  795. gi.setmodel (ent, ent->model);
  796. ent->blocked = plat2_blocked;
  797. if (!ent->speed)
  798. ent->speed = 20;
  799. else
  800. ent->speed *= 0.1;
  801. if (!ent->accel)
  802. ent->accel = 5;
  803. else
  804. ent->accel *= 0.1;
  805. if (!ent->decel)
  806. ent->decel = 5;
  807. else
  808. ent->decel *= 0.1;
  809. if (deathmatch->value)
  810. {
  811. ent->speed *= 2;
  812. ent->accel *= 2;
  813. ent->decel *= 2;
  814. }
  815. //PMM Added to kill things it's being blocked by
  816. if (!ent->dmg)
  817. ent->dmg = 2;
  818. // if (!st.lip)
  819. // st.lip = 8;
  820. // pos1 is the top position, pos2 is the bottom
  821. VectorCopy (ent->s.origin, ent->pos1);
  822. VectorCopy (ent->s.origin, ent->pos2);
  823. if (st.height)
  824. ent->pos2[2] -= (st.height - st.lip);
  825. else
  826. ent->pos2[2] -= (ent->maxs[2] - ent->mins[2]) - st.lip;
  827. ent->moveinfo.state = STATE_TOP;
  828. if(ent->targetname)
  829. {
  830. ent->use = plat2_activate;
  831. }
  832. else
  833. {
  834. ent->use = Use_Plat2;
  835. trigger = plat_spawn_inside_trigger (ent); // the "start moving" trigger
  836. // PGM - debugging??
  837. trigger->maxs[0]+=10;
  838. trigger->maxs[1]+=10;
  839. trigger->mins[0]-=10;
  840. trigger->mins[1]-=10;
  841. gi.linkentity (trigger);
  842. trigger->touch = Touch_Plat_Center2; // Override trigger touch function
  843. if(!(ent->spawnflags & PLAT2_TOP))
  844. {
  845. VectorCopy (ent->pos2, ent->s.origin);
  846. ent->moveinfo.state = STATE_BOTTOM;
  847. }
  848. }
  849. gi.linkentity (ent);
  850. ent->moveinfo.speed = ent->speed;
  851. ent->moveinfo.accel = ent->accel;
  852. ent->moveinfo.decel = ent->decel;
  853. ent->moveinfo.wait = ent->wait;
  854. VectorCopy (ent->pos1, ent->moveinfo.start_origin);
  855. VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
  856. VectorCopy (ent->pos2, ent->moveinfo.end_origin);
  857. VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
  858. ent->moveinfo.sound_start = gi.soundindex ("plats/pt1_strt.wav");
  859. ent->moveinfo.sound_middle = gi.soundindex ("plats/pt1_mid.wav");
  860. ent->moveinfo.sound_end = gi.soundindex ("plats/pt1_end.wav");
  861. }
  862. //====================================================================
  863. /*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS TOUCH_PAIN STOP ANIMATED ANIMATED_FAST EAST MED HARD DM COOP ACCEL
  864. You need to have an origin brush as part of this entity. The center of that brush will be
  865. the point around which it is rotated. It will rotate around the Z axis by default. You can
  866. check either the X_AXIS or Y_AXIS box to change that.
  867. func_rotating will use it's targets when it stops and starts.
  868. "speed" determines how fast it moves; default value is 100.
  869. "dmg" damage to inflict when blocked (2 default)
  870. "accel" if specified, is how much the rotation speed will increase per .1sec.
  871. REVERSE will cause the it to rotate in the opposite direction.
  872. STOP mean it will stop moving instead of pushing entities
  873. ACCEL means it will accelerate to it's final speed and decelerate when shutting down.
  874. */
  875. //============
  876. //PGM
  877. void rotating_accel (edict_t *self)
  878. {
  879. float current_speed;
  880. current_speed = VectorLength (self->avelocity);
  881. if(current_speed >= (self->speed - self->accel)) // done
  882. {
  883. VectorScale (self->movedir, self->speed, self->avelocity);
  884. G_UseTargets (self, self);
  885. }
  886. else
  887. {
  888. current_speed += self->accel;
  889. VectorScale (self->movedir, current_speed, self->avelocity);
  890. self->think = rotating_accel;
  891. self->nextthink = level.time + FRAMETIME;
  892. }
  893. }
  894. void rotating_decel (edict_t *self)
  895. {
  896. float current_speed;
  897. current_speed = VectorLength (self->avelocity);
  898. if(current_speed <= self->decel) // done
  899. {
  900. VectorClear (self->avelocity);
  901. G_UseTargets (self, self);
  902. self->touch = NULL;
  903. }
  904. else
  905. {
  906. current_speed -= self->decel;
  907. VectorScale (self->movedir, current_speed, self->avelocity);
  908. self->think = rotating_decel;
  909. self->nextthink = level.time + FRAMETIME;
  910. }
  911. }
  912. //PGM
  913. //============
  914. void rotating_blocked (edict_t *self, edict_t *other)
  915. {
  916. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  917. }
  918. void rotating_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  919. {
  920. if (self->avelocity[0] || self->avelocity[1] || self->avelocity[2])
  921. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  922. }
  923. void rotating_use (edict_t *self, edict_t *other, edict_t *activator)
  924. {
  925. if (!VectorCompare (self->avelocity, vec3_origin))
  926. {
  927. self->s.sound = 0;
  928. //PGM
  929. if(self->spawnflags & 8192) // Decelerate
  930. rotating_decel (self);
  931. else
  932. {
  933. VectorClear (self->avelocity);
  934. G_UseTargets (self, self);
  935. self->touch = NULL;
  936. }
  937. //PGM
  938. }
  939. else
  940. {
  941. self->s.sound = self->moveinfo.sound_middle;
  942. //PGM
  943. if(self->spawnflags & 8192) // accelerate
  944. rotating_accel (self);
  945. else
  946. {
  947. VectorScale (self->movedir, self->speed, self->avelocity);
  948. G_UseTargets (self, self);
  949. }
  950. if (self->spawnflags & 16)
  951. self->touch = rotating_touch;
  952. //PGM
  953. }
  954. }
  955. void SP_func_rotating (edict_t *ent)
  956. {
  957. ent->solid = SOLID_BSP;
  958. if (ent->spawnflags & 32)
  959. ent->movetype = MOVETYPE_STOP;
  960. else
  961. ent->movetype = MOVETYPE_PUSH;
  962. // set the axis of rotation
  963. VectorClear(ent->movedir);
  964. if (ent->spawnflags & 4)
  965. ent->movedir[2] = 1.0;
  966. else if (ent->spawnflags & 8)
  967. ent->movedir[0] = 1.0;
  968. else // Z_AXIS
  969. ent->movedir[1] = 1.0;
  970. // check for reverse rotation
  971. if (ent->spawnflags & 2)
  972. VectorNegate (ent->movedir, ent->movedir);
  973. if (!ent->speed)
  974. ent->speed = 100;
  975. if (!ent->dmg)
  976. ent->dmg = 2;
  977. // ent->moveinfo.sound_middle = "doors/hydro1.wav";
  978. ent->use = rotating_use;
  979. if (ent->dmg)
  980. ent->blocked = rotating_blocked;
  981. if (ent->spawnflags & 1)
  982. ent->use (ent, NULL, NULL);
  983. if (ent->spawnflags & 64)
  984. ent->s.effects |= EF_ANIM_ALL;
  985. if (ent->spawnflags & 128)
  986. ent->s.effects |= EF_ANIM_ALLFAST;
  987. //PGM
  988. if(ent->spawnflags & 8192) // Accelerate / Decelerate
  989. {
  990. if(!ent->accel)
  991. ent->accel = 1;
  992. else if (ent->accel > ent->speed)
  993. ent->accel = ent->speed;
  994. if(!ent->decel)
  995. ent->decel = 1;
  996. else if (ent->decel > ent->speed)
  997. ent->decel = ent->speed;
  998. }
  999. //PGM
  1000. gi.setmodel (ent, ent->model);
  1001. gi.linkentity (ent);
  1002. }
  1003. /*
  1004. ======================================================================
  1005. BUTTONS
  1006. ======================================================================
  1007. */
  1008. /*QUAKED func_button (0 .5 .8) ?
  1009. When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
  1010. "angle" determines the opening direction
  1011. "target" all entities with a matching targetname will be used
  1012. "speed" override the default 40 speed
  1013. "wait" override the default 1 second wait (-1 = never return)
  1014. "lip" override the default 4 pixel lip remaining at end of move
  1015. "health" if set, the button must be killed instead of touched
  1016. "sounds"
  1017. 1) silent
  1018. 2) steam metal
  1019. 3) wooden clunk
  1020. 4) metallic click
  1021. 5) in-out
  1022. */
  1023. void button_done (edict_t *self)
  1024. {
  1025. self->moveinfo.state = STATE_BOTTOM;
  1026. self->s.effects &= ~EF_ANIM23;
  1027. self->s.effects |= EF_ANIM01;
  1028. }
  1029. void button_return (edict_t *self)
  1030. {
  1031. self->moveinfo.state = STATE_DOWN;
  1032. Move_Calc (self, self->moveinfo.start_origin, button_done);
  1033. self->s.frame = 0;
  1034. if (self->health)
  1035. self->takedamage = DAMAGE_YES;
  1036. }
  1037. void button_wait (edict_t *self)
  1038. {
  1039. self->moveinfo.state = STATE_TOP;
  1040. self->s.effects &= ~EF_ANIM01;
  1041. self->s.effects |= EF_ANIM23;
  1042. G_UseTargets (self, self->activator);
  1043. self->s.frame = 1;
  1044. if (self->moveinfo.wait >= 0)
  1045. {
  1046. self->nextthink = level.time + self->moveinfo.wait;
  1047. self->think = button_return;
  1048. }
  1049. }
  1050. void button_fire (edict_t *self)
  1051. {
  1052. if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
  1053. return;
  1054. self->moveinfo.state = STATE_UP;
  1055. if (self->moveinfo.sound_start && !(self->flags & FL_TEAMSLAVE))
  1056. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  1057. Move_Calc (self, self->moveinfo.end_origin, button_wait);
  1058. }
  1059. void button_use (edict_t *self, edict_t *other, edict_t *activator)
  1060. {
  1061. self->activator = activator;
  1062. button_fire (self);
  1063. }
  1064. void button_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  1065. {
  1066. if (!other->client)
  1067. return;
  1068. if (other->health <= 0)
  1069. return;
  1070. self->activator = other;
  1071. button_fire (self);
  1072. }
  1073. void button_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  1074. {
  1075. self->activator = attacker;
  1076. self->health = self->max_health;
  1077. self->takedamage = DAMAGE_NO;
  1078. button_fire (self);
  1079. }
  1080. void SP_func_button (edict_t *ent)
  1081. {
  1082. vec3_t abs_movedir;
  1083. float dist;
  1084. G_SetMovedir (ent->s.angles, ent->movedir);
  1085. ent->movetype = MOVETYPE_STOP;
  1086. ent->solid = SOLID_BSP;
  1087. gi.setmodel (ent, ent->model);
  1088. if (ent->sounds != 1)
  1089. ent->moveinfo.sound_start = gi.soundindex ("switches/butn2.wav");
  1090. if (!ent->speed)
  1091. ent->speed = 40;
  1092. if (!ent->accel)
  1093. ent->accel = ent->speed;
  1094. if (!ent->decel)
  1095. ent->decel = ent->speed;
  1096. if (!ent->wait)
  1097. ent->wait = 3;
  1098. if (!st.lip)
  1099. st.lip = 4;
  1100. VectorCopy (ent->s.origin, ent->pos1);
  1101. abs_movedir[0] = fabs(ent->movedir[0]);
  1102. abs_movedir[1] = fabs(ent->movedir[1]);
  1103. abs_movedir[2] = fabs(ent->movedir[2]);
  1104. dist = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
  1105. VectorMA (ent->pos1, dist, ent->movedir, ent->pos2);
  1106. ent->use = button_use;
  1107. ent->s.effects |= EF_ANIM01;
  1108. if (ent->health)
  1109. {
  1110. ent->max_health = ent->health;
  1111. ent->die = button_killed;
  1112. ent->takedamage = DAMAGE_YES;
  1113. }
  1114. else if (! ent->targetname)
  1115. ent->touch = button_touch;
  1116. ent->moveinfo.state = STATE_BOTTOM;
  1117. ent->moveinfo.speed = ent->speed;
  1118. ent->moveinfo.accel = ent->accel;
  1119. ent->moveinfo.decel = ent->decel;
  1120. ent->moveinfo.wait = ent->wait;
  1121. VectorCopy (ent->pos1, ent->moveinfo.start_origin);
  1122. VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
  1123. VectorCopy (ent->pos2, ent->moveinfo.end_origin);
  1124. VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
  1125. gi.linkentity (ent);
  1126. }
  1127. /*
  1128. ======================================================================
  1129. DOORS
  1130. spawn a trigger surrounding the entire team unless it is
  1131. already targeted by another
  1132. ======================================================================
  1133. */
  1134. /*QUAKED func_door (0 .5 .8) ? START_OPEN x CRUSHER NOMONSTER ANIMATED TOGGLE ANIMATED_FAST
  1135. TOGGLE wait in both the start and end states for a trigger event.
  1136. START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
  1137. NOMONSTER monsters will not trigger this door
  1138. "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
  1139. "angle" determines the opening direction
  1140. "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
  1141. "health" if set, door must be shot open
  1142. "speed" movement speed (100 default)
  1143. "wait" wait before returning (3 default, -1 = never return)
  1144. "lip" lip remaining at end of move (8 default)
  1145. "dmg" damage to inflict when blocked (2 default)
  1146. "sounds"
  1147. 1) silent
  1148. 2) light
  1149. 3) medium
  1150. 4) heavy
  1151. */
  1152. void door_use_areaportals (edict_t *self, qboolean open)
  1153. {
  1154. edict_t *t = NULL;
  1155. if (!self->target)
  1156. return;
  1157. while ((t = G_Find (t, FOFS(targetname), self->target)))
  1158. {
  1159. if (Q_stricmp(t->classname, "func_areaportal") == 0)
  1160. {
  1161. gi.SetAreaPortalState (t->style, open);
  1162. }
  1163. }
  1164. }
  1165. void door_go_down (edict_t *self);
  1166. void door_hit_top (edict_t *self)
  1167. {
  1168. if (!(self->flags & FL_TEAMSLAVE))
  1169. {
  1170. if (self->moveinfo.sound_end)
  1171. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  1172. self->s.sound = 0;
  1173. }
  1174. self->moveinfo.state = STATE_TOP;
  1175. if (self->spawnflags & DOOR_TOGGLE)
  1176. return;
  1177. if (self->moveinfo.wait >= 0)
  1178. {
  1179. self->think = door_go_down;
  1180. self->nextthink = level.time + self->moveinfo.wait;
  1181. }
  1182. }
  1183. void door_hit_bottom (edict_t *self)
  1184. {
  1185. if (!(self->flags & FL_TEAMSLAVE))
  1186. {
  1187. if (self->moveinfo.sound_end)
  1188. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  1189. self->s.sound = 0;
  1190. }
  1191. self->moveinfo.state = STATE_BOTTOM;
  1192. door_use_areaportals (self, false);
  1193. }
  1194. void door_go_down (edict_t *self)
  1195. {
  1196. if (!(self->flags & FL_TEAMSLAVE))
  1197. {
  1198. if (self->moveinfo.sound_start)
  1199. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  1200. self->s.sound = self->moveinfo.sound_middle;
  1201. }
  1202. if (self->max_health)
  1203. {
  1204. self->takedamage = DAMAGE_YES;
  1205. self->health = self->max_health;
  1206. }
  1207. self->moveinfo.state = STATE_DOWN;
  1208. if (strcmp(self->classname, "func_door") == 0)
  1209. Move_Calc (self, self->moveinfo.start_origin, door_hit_bottom);
  1210. else if (strcmp(self->classname, "func_door_rotating") == 0)
  1211. AngleMove_Calc (self, door_hit_bottom);
  1212. }
  1213. void door_go_up (edict_t *self, edict_t *activator)
  1214. {
  1215. if (self->moveinfo.state == STATE_UP)
  1216. return; // already going up
  1217. if (self->moveinfo.state == STATE_TOP)
  1218. { // reset top wait time
  1219. if (self->moveinfo.wait >= 0)
  1220. self->nextthink = level.time + self->moveinfo.wait;
  1221. return;
  1222. }
  1223. if (!(self->flags & FL_TEAMSLAVE))
  1224. {
  1225. if (self->moveinfo.sound_start)
  1226. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  1227. self->s.sound = self->moveinfo.sound_middle;
  1228. }
  1229. self->moveinfo.state = STATE_UP;
  1230. if (strcmp(self->classname, "func_door") == 0)
  1231. Move_Calc (self, self->moveinfo.end_origin, door_hit_top);
  1232. else if (strcmp(self->classname, "func_door_rotating") == 0)
  1233. AngleMove_Calc (self, door_hit_top);
  1234. G_UseTargets (self, activator);
  1235. door_use_areaportals (self, true);
  1236. }
  1237. //======
  1238. //PGM
  1239. void smart_water_go_up (edict_t *self)
  1240. {
  1241. float distance;
  1242. edict_t *lowestPlayer;
  1243. edict_t *ent;
  1244. float lowestPlayerPt;
  1245. int i;
  1246. if (self->moveinfo.state == STATE_TOP)
  1247. { // reset top wait time
  1248. if (self->moveinfo.wait >= 0)
  1249. self->nextthink = level.time + self->moveinfo.wait;
  1250. return;
  1251. }
  1252. if (self->health)
  1253. {
  1254. if(self->absmax[2] >= self->health)
  1255. {
  1256. VectorClear (self->velocity);
  1257. self->nextthink = 0;
  1258. self->moveinfo.state = STATE_TOP;
  1259. return;
  1260. }
  1261. }
  1262. if (!(self->flags & FL_TEAMSLAVE))
  1263. {
  1264. if (self->moveinfo.sound_start)
  1265. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  1266. self->s.sound = self->moveinfo.sound_middle;
  1267. }
  1268. // find the lowest player point.
  1269. lowestPlayerPt = 999999;
  1270. lowestPlayer = NULL;
  1271. for (i=0 ; i<game.maxclients ; i++)
  1272. {
  1273. ent = &g_edicts[1+i];
  1274. // don't count dead or unused player slots
  1275. if((ent->inuse) && (ent->health > 0))
  1276. {
  1277. if (ent->absmin[2] < lowestPlayerPt)
  1278. {
  1279. lowestPlayerPt = ent->absmin[2];
  1280. lowestPlayer = ent;
  1281. }
  1282. }
  1283. }
  1284. if(!lowestPlayer)
  1285. {
  1286. return;
  1287. }
  1288. distance = lowestPlayerPt - self->absmax[2];
  1289. // for the calculations, make sure we intend to go up at least a little.
  1290. if(distance < self->accel)
  1291. {
  1292. distance = 100;
  1293. self->moveinfo.speed = 5;
  1294. }
  1295. else
  1296. self->moveinfo.speed = distance / self->accel;
  1297. if(self->moveinfo.speed < 5)
  1298. self->moveinfo.speed = 5;
  1299. else if(self->moveinfo.speed > self->speed)
  1300. self->moveinfo.speed = self->speed;
  1301. // FIXME - should this allow any movement other than straight up?
  1302. VectorSet(self->moveinfo.dir, 0, 0, 1);
  1303. VectorScale (self->moveinfo.dir, self->moveinfo.speed, self->velocity);
  1304. self->moveinfo.remaining_distance = distance;
  1305. if(self->moveinfo.state != STATE_UP)
  1306. {
  1307. G_UseTargets (self, lowestPlayer);
  1308. door_use_areaportals (self, true);
  1309. self->moveinfo.state = STATE_UP;
  1310. }
  1311. self->think = smart_water_go_up;
  1312. self->nextthink = level.time + FRAMETIME;
  1313. }
  1314. //PGM
  1315. //======
  1316. void door_use (edict_t *self, edict_t *other, edict_t *activator)
  1317. {
  1318. edict_t *ent;
  1319. vec3_t center; //PGM
  1320. if (self->flags & FL_TEAMSLAVE)
  1321. return;
  1322. if (self->spawnflags & DOOR_TOGGLE)
  1323. {
  1324. if (self->moveinfo.state == STATE_UP || self->moveinfo.state == STATE_TOP)
  1325. {
  1326. // trigger all paired doors
  1327. for (ent = self ; ent ; ent = ent->teamchain)
  1328. {
  1329. ent->message = NULL;
  1330. ent->touch = NULL;
  1331. door_go_down (ent);
  1332. }
  1333. return;
  1334. }
  1335. }
  1336. //PGM
  1337. // smart water is different
  1338. VectorAdd(self->mins, self->maxs, center);
  1339. VectorScale(center, 0.5, center);
  1340. if ((gi.pointcontents (center) & MASK_WATER) && self->spawnflags & 2)
  1341. {
  1342. self->message = NULL;
  1343. self->touch = NULL;
  1344. self->enemy = activator;
  1345. smart_water_go_up (self);
  1346. return;
  1347. }
  1348. //PGM
  1349. // trigger all paired doors
  1350. for (ent = self ; ent ; ent = ent->teamchain)
  1351. {
  1352. ent->message = NULL;
  1353. ent->touch = NULL;
  1354. door_go_up (ent, activator);
  1355. }
  1356. };
  1357. void Touch_DoorTrigger (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  1358. {
  1359. if (other->health <= 0)
  1360. return;
  1361. if (!(other->svflags & SVF_MONSTER) && (!other->client))
  1362. return;
  1363. if ((self->owner->spawnflags & DOOR_NOMONSTER) && (other->svflags & SVF_MONSTER))
  1364. return;
  1365. if (level.time < self->touch_debounce_time)
  1366. return;
  1367. self->touch_debounce_time = level.time + 1.0;
  1368. door_use (self->owner, other, other);
  1369. }
  1370. void Think_CalcMoveSpeed (edict_t *self)
  1371. {
  1372. edict_t *ent;
  1373. float min;
  1374. float time;
  1375. float newspeed;
  1376. float ratio;
  1377. float dist;
  1378. if (self->flags & FL_TEAMSLAVE)
  1379. return; // only the team master does this
  1380. // find the smallest distance any member of the team will be moving
  1381. min = fabs(self->moveinfo.distance);
  1382. for (ent = self->teamchain; ent; ent = ent->teamchain)
  1383. {
  1384. dist = fabs(ent->moveinfo.distance);
  1385. if (dist < min)
  1386. min = dist;
  1387. }
  1388. time = min / self->moveinfo.speed;
  1389. // adjust speeds so they will all complete at the same time
  1390. for (ent = self; ent; ent = ent->teamchain)
  1391. {
  1392. newspeed = fabs(ent->moveinfo.distance) / time;
  1393. ratio = newspeed / ent->moveinfo.speed;
  1394. if (ent->moveinfo.accel == ent->moveinfo.speed)
  1395. ent->moveinfo.accel = newspeed;
  1396. else
  1397. ent->moveinfo.accel *= ratio;
  1398. if (ent->moveinfo.decel == ent->moveinfo.speed)
  1399. ent->moveinfo.decel = newspeed;
  1400. else
  1401. ent->moveinfo.decel *= ratio;
  1402. ent->moveinfo.speed = newspeed;
  1403. }
  1404. }
  1405. void Think_SpawnDoorTrigger (edict_t *ent)
  1406. {
  1407. edict_t *other;
  1408. vec3_t mins, maxs;
  1409. if (ent->flags & FL_TEAMSLAVE)
  1410. return; // only the team leader spawns a trigger
  1411. VectorCopy (ent->absmin, mins);
  1412. VectorCopy (ent->absmax, maxs);
  1413. for (other = ent->teamchain ; other ; other=other->teamchain)
  1414. {
  1415. AddPointToBounds (other->absmin, mins, maxs);
  1416. AddPointToBounds (other->absmax, mins, maxs);
  1417. }
  1418. // expand
  1419. mins[0] -= 60;
  1420. mins[1] -= 60;
  1421. maxs[0] += 60;
  1422. maxs[1] += 60;
  1423. other = G_Spawn ();
  1424. VectorCopy (mins, other->mins);
  1425. VectorCopy (maxs, other->maxs);
  1426. other->owner = ent;
  1427. other->solid = SOLID_TRIGGER;
  1428. other->movetype = MOVETYPE_NONE;
  1429. other->touch = Touch_DoorTrigger;
  1430. gi.linkentity (other);
  1431. if (ent->spawnflags & DOOR_START_OPEN)
  1432. door_use_areaportals (ent, true);
  1433. Think_CalcMoveSpeed (ent);
  1434. }
  1435. void door_blocked (edict_t *self, edict_t *other)
  1436. {
  1437. edict_t *ent;
  1438. if (!(other->svflags & SVF_MONSTER) && (!other->client) )
  1439. {
  1440. // give it a chance to go away on it's own terms (like gibs)
  1441. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
  1442. // if it's still there, nuke it
  1443. if (other && other->inuse)
  1444. BecomeExplosion1 (other);
  1445. return;
  1446. }
  1447. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  1448. if (self->spawnflags & DOOR_CRUSHER)
  1449. return;
  1450. // if a door has a negative wait, it would never come back if blocked,
  1451. // so let it just squash the object to death real fast
  1452. if (self->moveinfo.wait >= 0)
  1453. {
  1454. if (self->moveinfo.state == STATE_DOWN)
  1455. {
  1456. for (ent = self->teammaster ; ent ; ent = ent->teamchain)
  1457. door_go_up (ent, ent->activator);
  1458. }
  1459. else
  1460. {
  1461. for (ent = self->teammaster ; ent ; ent = ent->teamchain)
  1462. door_go_down (ent);
  1463. }
  1464. }
  1465. }
  1466. void door_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  1467. {
  1468. edict_t *ent;
  1469. for (ent = self->teammaster ; ent ; ent = ent->teamchain)
  1470. {
  1471. ent->health = ent->max_health;
  1472. ent->takedamage = DAMAGE_NO;
  1473. }
  1474. door_use (self->teammaster, attacker, attacker);
  1475. }
  1476. void door_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  1477. {
  1478. if (!other->client)
  1479. return;
  1480. if (level.time < self->touch_debounce_time)
  1481. return;
  1482. self->touch_debounce_time = level.time + 5.0;
  1483. gi.centerprintf (other, "%s", self->message);
  1484. gi.sound (other, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);
  1485. }
  1486. void SP_func_door (edict_t *ent)
  1487. {
  1488. vec3_t abs_movedir;
  1489. if (ent->sounds != 1)
  1490. {
  1491. ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
  1492. ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
  1493. ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
  1494. }
  1495. G_SetMovedir (ent->s.angles, ent->movedir);
  1496. ent->movetype = MOVETYPE_PUSH;
  1497. ent->solid = SOLID_BSP;
  1498. gi.setmodel (ent, ent->model);
  1499. ent->blocked = door_blocked;
  1500. ent->use = door_use;
  1501. if (!ent->speed)
  1502. ent->speed = 100;
  1503. if (deathmatch->value)
  1504. ent->speed *= 2;
  1505. if (!ent->accel)
  1506. ent->accel = ent->speed;
  1507. if (!ent->decel)
  1508. ent->decel = ent->speed;
  1509. if (!ent->wait)
  1510. ent->wait = 3;
  1511. if (!st.lip)
  1512. st.lip = 8;
  1513. if (!ent->dmg)
  1514. ent->dmg = 2;
  1515. // calculate second position
  1516. VectorCopy (ent->s.origin, ent->pos1);
  1517. abs_movedir[0] = fabs(ent->movedir[0]);
  1518. abs_movedir[1] = fabs(ent->movedir[1]);
  1519. abs_movedir[2] = fabs(ent->movedir[2]);
  1520. ent->moveinfo.distance = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip;
  1521. VectorMA (ent->pos1, ent->moveinfo.distance, ent->movedir, ent->pos2);
  1522. // if it starts open, switch the positions
  1523. if (ent->spawnflags & DOOR_START_OPEN)
  1524. {
  1525. VectorCopy (ent->pos2, ent->s.origin);
  1526. VectorCopy (ent->pos1, ent->pos2);
  1527. VectorCopy (ent->s.origin, ent->pos1);
  1528. }
  1529. ent->moveinfo.state = STATE_BOTTOM;
  1530. if (ent->health)
  1531. {
  1532. ent->takedamage = DAMAGE_YES;
  1533. ent->die = door_killed;
  1534. ent->max_health = ent->health;
  1535. }
  1536. else if (ent->targetname && ent->message)
  1537. {
  1538. gi.soundindex ("misc/talk.wav");
  1539. ent->touch = door_touch;
  1540. }
  1541. ent->moveinfo.speed = ent->speed;
  1542. ent->moveinfo.accel = ent->accel;
  1543. ent->moveinfo.decel = ent->decel;
  1544. ent->moveinfo.wait = ent->wait;
  1545. VectorCopy (ent->pos1, ent->moveinfo.start_origin);
  1546. VectorCopy (ent->s.angles, ent->moveinfo.start_angles);
  1547. VectorCopy (ent->pos2, ent->moveinfo.end_origin);
  1548. VectorCopy (ent->s.angles, ent->moveinfo.end_angles);
  1549. if (ent->spawnflags & 16)
  1550. ent->s.effects |= EF_ANIM_ALL;
  1551. if (ent->spawnflags & 64)
  1552. ent->s.effects |= EF_ANIM_ALLFAST;
  1553. // to simplify logic elsewhere, make non-teamed doors into a team of one
  1554. if (!ent->team)
  1555. ent->teammaster = ent;
  1556. gi.linkentity (ent);
  1557. ent->nextthink = level.time + FRAMETIME;
  1558. if (ent->health || ent->targetname)
  1559. ent->think = Think_CalcMoveSpeed;
  1560. else
  1561. ent->think = Think_SpawnDoorTrigger;
  1562. }
  1563. //PGM
  1564. void Door_Activate (edict_t *self, edict_t *other, edict_t *activator)
  1565. {
  1566. self->use = NULL;
  1567. if (self->health)
  1568. {
  1569. self->takedamage = DAMAGE_YES;
  1570. self->die = door_killed;
  1571. self->max_health = self->health;
  1572. }
  1573. if (self->health)
  1574. self->think = Think_CalcMoveSpeed;
  1575. else
  1576. self->think = Think_SpawnDoorTrigger;
  1577. self->nextthink = level.time + FRAMETIME;
  1578. }
  1579. //PGM
  1580. /*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN REVERSE CRUSHER NOMONSTER ANIMATED TOGGLE X_AXIS Y_AXIS EASY MED HARD DM COOP INACTIVE
  1581. TOGGLE causes the door to wait in both the start and end states for a trigger event.
  1582. START_OPEN the door to moves to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
  1583. NOMONSTER monsters will not trigger this door
  1584. You need to have an origin brush as part of this entity. The center of that brush will be
  1585. the point around which it is rotated. It will rotate around the Z axis by default. You can
  1586. check either the X_AXIS or Y_AXIS box to change that.
  1587. "distance" is how many degrees the door will be rotated.
  1588. "speed" determines how fast the door moves; default value is 100.
  1589. "accel" if specified,is how much the rotation speed will increase each .1 sec. (default: no accel)
  1590. REVERSE will cause the door to rotate in the opposite direction.
  1591. INACTIVE will cause the door to be inactive until triggered.
  1592. "message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
  1593. "angle" determines the opening direction
  1594. "targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
  1595. "health" if set, door must be shot open
  1596. "speed" movement speed (100 default)
  1597. "wait" wait before returning (3 default, -1 = never return)
  1598. "dmg" damage to inflict when blocked (2 default)
  1599. "sounds"
  1600. 1) silent
  1601. 2) light
  1602. 3) medium
  1603. 4) heavy
  1604. */
  1605. void SP_func_door_rotating (edict_t *ent)
  1606. {
  1607. VectorClear (ent->s.angles);
  1608. // set the axis of rotation
  1609. VectorClear(ent->movedir);
  1610. if (ent->spawnflags & DOOR_X_AXIS)
  1611. ent->movedir[2] = 1.0;
  1612. else if (ent->spawnflags & DOOR_Y_AXIS)
  1613. ent->movedir[0] = 1.0;
  1614. else // Z_AXIS
  1615. ent->movedir[1] = 1.0;
  1616. // check for reverse rotation
  1617. if (ent->spawnflags & DOOR_REVERSE)
  1618. VectorNegate (ent->movedir, ent->movedir);
  1619. if (!st.distance)
  1620. {
  1621. gi.dprintf("%s at %s with no distance set\n", ent->classname, vtos(ent->s.origin));
  1622. st.distance = 90;
  1623. }
  1624. VectorCopy (ent->s.angles, ent->pos1);
  1625. VectorMA (ent->s.angles, st.distance, ent->movedir, ent->pos2);
  1626. ent->moveinfo.distance = st.distance;
  1627. ent->movetype = MOVETYPE_PUSH;
  1628. ent->solid = SOLID_BSP;
  1629. gi.setmodel (ent, ent->model);
  1630. ent->blocked = door_blocked;
  1631. ent->use = door_use;
  1632. if (!ent->speed)
  1633. ent->speed = 100;
  1634. if (!ent->accel)
  1635. ent->accel = ent->speed;
  1636. if (!ent->decel)
  1637. ent->decel = ent->speed;
  1638. if (!ent->wait)
  1639. ent->wait = 3;
  1640. if (!ent->dmg)
  1641. ent->dmg = 2;
  1642. if (ent->sounds != 1)
  1643. {
  1644. ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
  1645. ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
  1646. ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
  1647. }
  1648. // if it starts open, switch the positions
  1649. if (ent->spawnflags & DOOR_START_OPEN)
  1650. {
  1651. VectorCopy (ent->pos2, ent->s.angles);
  1652. VectorCopy (ent->pos1, ent->pos2);
  1653. VectorCopy (ent->s.angles, ent->pos1);
  1654. VectorNegate (ent->movedir, ent->movedir);
  1655. }
  1656. if (ent->health)
  1657. {
  1658. ent->takedamage = DAMAGE_YES;
  1659. ent->die = door_killed;
  1660. ent->max_health = ent->health;
  1661. }
  1662. if (ent->targetname && ent->message)
  1663. {
  1664. gi.soundindex ("misc/talk.wav");
  1665. ent->touch = door_touch;
  1666. }
  1667. ent->moveinfo.state = STATE_BOTTOM;
  1668. ent->moveinfo.speed = ent->speed;
  1669. ent->moveinfo.accel = ent->accel;
  1670. ent->moveinfo.decel = ent->decel;
  1671. ent->moveinfo.wait = ent->wait;
  1672. VectorCopy (ent->s.origin, ent->moveinfo.start_origin);
  1673. VectorCopy (ent->pos1, ent->moveinfo.start_angles);
  1674. VectorCopy (ent->s.origin, ent->moveinfo.end_origin);
  1675. VectorCopy (ent->pos2, ent->moveinfo.end_angles);
  1676. if (ent->spawnflags & 16)
  1677. ent->s.effects |= EF_ANIM_ALL;
  1678. // to simplify logic elsewhere, make non-teamed doors into a team of one
  1679. if (!ent->team)
  1680. ent->teammaster = ent;
  1681. gi.linkentity (ent);
  1682. ent->nextthink = level.time + FRAMETIME;
  1683. if (ent->health || ent->targetname)
  1684. ent->think = Think_CalcMoveSpeed;
  1685. else
  1686. ent->think = Think_SpawnDoorTrigger;
  1687. //PGM
  1688. if (ent->spawnflags & DOOR_INACTIVE)
  1689. {
  1690. ent->takedamage = DAMAGE_NO;
  1691. ent->die = NULL;
  1692. ent->think = NULL;
  1693. ent->nextthink = 0;
  1694. ent->use = Door_Activate;
  1695. }
  1696. //PGM
  1697. }
  1698. void smart_water_blocked (edict_t *self, edict_t *other)
  1699. {
  1700. if (!(other->svflags & SVF_MONSTER) && (!other->client) )
  1701. {
  1702. // give it a chance to go away on it's own terms (like gibs)
  1703. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_LAVA);
  1704. // if it's still there, nuke it
  1705. if (other && other->inuse) // PGM
  1706. BecomeExplosion1 (other);
  1707. return;
  1708. }
  1709. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100, 1, 0, MOD_LAVA);
  1710. }
  1711. /*QUAKED func_water (0 .5 .8) ? START_OPEN SMART
  1712. func_water is a moveable water brush. It must be targeted to operate. Use a non-water texture at your own risk.
  1713. START_OPEN causes the water to move to its destination when spawned and operate in reverse.
  1714. SMART causes the water to adjust its speed depending on distance to player.
  1715. (speed = distance/accel, min 5, max self->speed)
  1716. "accel" for smart water, the divisor to determine water speed. default 20 (smaller = faster)
  1717. "health" maximum height of this water brush
  1718. "angle" determines the opening direction (up or down only)
  1719. "speed" movement speed (25 default)
  1720. "wait" wait before returning (-1 default, -1 = TOGGLE)
  1721. "lip" lip remaining at end of move (0 default)
  1722. "sounds" (yes, these need to be changed)
  1723. 0) no sound
  1724. 1) water
  1725. 2) lava
  1726. */
  1727. void SP_func_water (edict_t *self)
  1728. {
  1729. vec3_t abs_movedir;
  1730. G_SetMovedir (self->s.angles, self->movedir);
  1731. self->movetype = MOVETYPE_PUSH;
  1732. self->solid = SOLID_BSP;
  1733. gi.setmodel (self, self->model);
  1734. switch (self->sounds)
  1735. {
  1736. default:
  1737. break;
  1738. case 1: // water
  1739. self->moveinfo.sound_start = gi.soundindex ("world/mov_watr.wav");
  1740. self->moveinfo.sound_end = gi.soundindex ("world/stp_watr.wav");
  1741. break;
  1742. case 2: // lava
  1743. self->moveinfo.sound_start = gi.soundindex ("world/mov_watr.wav");
  1744. self->moveinfo.sound_end = gi.soundindex ("world/stp_watr.wav");
  1745. break;
  1746. }
  1747. // calculate second position
  1748. VectorCopy (self->s.origin, self->pos1);
  1749. abs_movedir[0] = fabs(self->movedir[0]);
  1750. abs_movedir[1] = fabs(self->movedir[1]);
  1751. abs_movedir[2] = fabs(self->movedir[2]);
  1752. self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * self->size[2] - st.lip;
  1753. VectorMA (self->pos1, self->moveinfo.distance, self->movedir, self->pos2);
  1754. // if it starts open, switch the positions
  1755. if (self->spawnflags & DOOR_START_OPEN)
  1756. {
  1757. VectorCopy (self->pos2, self->s.origin);
  1758. VectorCopy (self->pos1, self->pos2);
  1759. VectorCopy (self->s.origin, self->pos1);
  1760. }
  1761. VectorCopy (self->pos1, self->moveinfo.start_origin);
  1762. VectorCopy (self->s.angles, self->moveinfo.start_angles);
  1763. VectorCopy (self->pos2, self->moveinfo.end_origin);
  1764. VectorCopy (self->s.angles, self->moveinfo.end_angles);
  1765. self->moveinfo.state = STATE_BOTTOM;
  1766. if (!self->speed)
  1767. self->speed = 25;
  1768. self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed = self->speed;
  1769. if ( self->spawnflags & 2) // smart water
  1770. {
  1771. // this is actually the divisor of the lowest player's distance to determine speed.
  1772. // self->speed then becomes the cap of the speed.
  1773. if(!self->accel)
  1774. self->accel = 20;
  1775. self->blocked = smart_water_blocked;
  1776. }
  1777. if (!self->wait)
  1778. self->wait = -1;
  1779. self->moveinfo.wait = self->wait;
  1780. self->use = door_use;
  1781. if (self->wait == -1)
  1782. self->spawnflags |= DOOR_TOGGLE;
  1783. self->classname = "func_door";
  1784. gi.linkentity (self);
  1785. }
  1786. #define TRAIN_START_ON 1
  1787. #define TRAIN_TOGGLE 2
  1788. #define TRAIN_BLOCK_STOPS 4
  1789. /*QUAKED func_train (0 .5 .8) ? START_ON TOGGLE BLOCK_STOPS
  1790. Trains are moving platforms that players can ride.
  1791. The targets origin specifies the min point of the train at each corner.
  1792. The train spawns at the first target it is pointing at.
  1793. If the train is the target of a button or trigger, it will not begin moving until activated.
  1794. speed default 100
  1795. dmg default 2
  1796. noise looping sound to play when the train is in motion
  1797. To have other entities move with the train, set all the piece's team value to the same thing. They will move in unison.
  1798. */
  1799. void train_next (edict_t *self);
  1800. void train_blocked (edict_t *self, edict_t *other)
  1801. {
  1802. if (!(other->svflags & SVF_MONSTER) && (!other->client) )
  1803. {
  1804. // give it a chance to go away on it's own terms (like gibs)
  1805. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
  1806. // if it's still there, nuke it
  1807. if (other && other->inuse)
  1808. BecomeExplosion1 (other);
  1809. return;
  1810. }
  1811. if (level.time < self->touch_debounce_time)
  1812. return;
  1813. if (!self->dmg)
  1814. return;
  1815. self->touch_debounce_time = level.time + 0.5;
  1816. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  1817. }
  1818. void train_wait (edict_t *self)
  1819. {
  1820. if (self->target_ent->pathtarget)
  1821. {
  1822. char *savetarget;
  1823. edict_t *ent;
  1824. ent = self->target_ent;
  1825. savetarget = ent->target;
  1826. ent->target = ent->pathtarget;
  1827. G_UseTargets (ent, self->activator);
  1828. ent->target = savetarget;
  1829. // make sure we didn't get killed by a killtarget
  1830. if (!self->inuse)
  1831. return;
  1832. }
  1833. if (self->moveinfo.wait)
  1834. {
  1835. if (self->moveinfo.wait > 0)
  1836. {
  1837. self->nextthink = level.time + self->moveinfo.wait;
  1838. self->think = train_next;
  1839. }
  1840. else if (self->spawnflags & TRAIN_TOGGLE) // && wait < 0
  1841. {
  1842. // PMM - clear target_ent, let train_next get called when we get used
  1843. // train_next (self);
  1844. self->target_ent = NULL;
  1845. // pmm
  1846. self->spawnflags &= ~TRAIN_START_ON;
  1847. VectorClear (self->velocity);
  1848. self->nextthink = 0;
  1849. }
  1850. if (!(self->flags & FL_TEAMSLAVE))
  1851. {
  1852. if (self->moveinfo.sound_end)
  1853. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_end, 1, ATTN_STATIC, 0);
  1854. self->s.sound = 0;
  1855. }
  1856. }
  1857. else
  1858. {
  1859. train_next (self);
  1860. }
  1861. }
  1862. //PGM
  1863. void train_piece_wait (edict_t *self)
  1864. {
  1865. }
  1866. //PGM
  1867. void train_next (edict_t *self)
  1868. {
  1869. edict_t *ent;
  1870. vec3_t dest;
  1871. qboolean first;
  1872. first = true;
  1873. again:
  1874. if (!self->target)
  1875. {
  1876. // gi.dprintf ("train_next: no next target\n");
  1877. return;
  1878. }
  1879. ent = G_PickTarget (self->target);
  1880. if (!ent)
  1881. {
  1882. gi.dprintf ("train_next: bad target %s\n", self->target);
  1883. return;
  1884. }
  1885. self->target = ent->target;
  1886. // check for a teleport path_corner
  1887. if (ent->spawnflags & 1)
  1888. {
  1889. if (!first)
  1890. {
  1891. gi.dprintf ("connected teleport path_corners, see %s at %s\n", ent->classname, vtos(ent->s.origin));
  1892. return;
  1893. }
  1894. first = false;
  1895. VectorSubtract (ent->s.origin, self->mins, self->s.origin);
  1896. VectorCopy (self->s.origin, self->s.old_origin);
  1897. self->s.event = EV_OTHER_TELEPORT;
  1898. gi.linkentity (self);
  1899. goto again;
  1900. }
  1901. //PGM
  1902. if (ent->speed)
  1903. {
  1904. self->speed = ent->speed;
  1905. self->moveinfo.speed = ent->speed;
  1906. if(ent->accel)
  1907. self->moveinfo.accel = ent->accel;
  1908. else
  1909. self->moveinfo.accel = ent->speed;
  1910. if(ent->decel)
  1911. self->moveinfo.decel = ent->decel;
  1912. else
  1913. self->moveinfo.decel = ent->speed;
  1914. self->moveinfo.current_speed = 0;
  1915. }
  1916. //PGM
  1917. self->moveinfo.wait = ent->wait;
  1918. self->target_ent = ent;
  1919. if (!(self->flags & FL_TEAMSLAVE))
  1920. {
  1921. if (self->moveinfo.sound_start)
  1922. gi.sound (self, CHAN_NO_PHS_ADD+CHAN_VOICE, self->moveinfo.sound_start, 1, ATTN_STATIC, 0);
  1923. self->s.sound = self->moveinfo.sound_middle;
  1924. }
  1925. VectorSubtract (ent->s.origin, self->mins, dest);
  1926. self->moveinfo.state = STATE_TOP;
  1927. VectorCopy (self->s.origin, self->moveinfo.start_origin);
  1928. VectorCopy (dest, self->moveinfo.end_origin);
  1929. Move_Calc (self, dest, train_wait);
  1930. self->spawnflags |= TRAIN_START_ON;
  1931. //PGM
  1932. if(self->team)
  1933. {
  1934. edict_t *e;
  1935. vec3_t dir, dst;
  1936. VectorSubtract (dest, self->s.origin, dir);
  1937. for (e=self->teamchain; e ; e = e->teamchain)
  1938. {
  1939. VectorAdd(dir, e->s.origin, dst);
  1940. VectorCopy(e->s.origin, e->moveinfo.start_origin);
  1941. VectorCopy(dst, e->moveinfo.end_origin);
  1942. e->moveinfo.state = STATE_TOP;
  1943. e->speed = self->speed;
  1944. e->moveinfo.speed = self->moveinfo.speed;
  1945. e->moveinfo.accel = self->moveinfo.accel;
  1946. e->moveinfo.decel = self->moveinfo.decel;
  1947. e->movetype = MOVETYPE_PUSH;
  1948. Move_Calc (e, dst, train_piece_wait);
  1949. }
  1950. }
  1951. //PGM
  1952. }
  1953. void train_resume (edict_t *self)
  1954. {
  1955. edict_t *ent;
  1956. vec3_t dest;
  1957. ent = self->target_ent;
  1958. VectorSubtract (ent->s.origin, self->mins, dest);
  1959. self->moveinfo.state = STATE_TOP;
  1960. VectorCopy (self->s.origin, self->moveinfo.start_origin);
  1961. VectorCopy (dest, self->moveinfo.end_origin);
  1962. Move_Calc (self, dest, train_wait);
  1963. self->spawnflags |= TRAIN_START_ON;
  1964. }
  1965. void func_train_find (edict_t *self)
  1966. {
  1967. edict_t *ent;
  1968. if (!self->target)
  1969. {
  1970. gi.dprintf ("train_find: no target\n");
  1971. return;
  1972. }
  1973. ent = G_PickTarget (self->target);
  1974. if (!ent)
  1975. {
  1976. gi.dprintf ("train_find: target %s not found\n", self->target);
  1977. return;
  1978. }
  1979. self->target = ent->target;
  1980. VectorSubtract (ent->s.origin, self->mins, self->s.origin);
  1981. gi.linkentity (self);
  1982. // if not triggered, start immediately
  1983. if (!self->targetname)
  1984. self->spawnflags |= TRAIN_START_ON;
  1985. if (self->spawnflags & TRAIN_START_ON)
  1986. {
  1987. self->nextthink = level.time + FRAMETIME;
  1988. self->think = train_next;
  1989. self->activator = self;
  1990. }
  1991. }
  1992. void train_use (edict_t *self, edict_t *other, edict_t *activator)
  1993. {
  1994. self->activator = activator;
  1995. if (self->spawnflags & TRAIN_START_ON)
  1996. {
  1997. if (!(self->spawnflags & TRAIN_TOGGLE))
  1998. return;
  1999. self->spawnflags &= ~TRAIN_START_ON;
  2000. VectorClear (self->velocity);
  2001. self->nextthink = 0;
  2002. }
  2003. else
  2004. {
  2005. if (self->target_ent)
  2006. train_resume(self);
  2007. else
  2008. train_next(self);
  2009. }
  2010. }
  2011. void SP_func_train (edict_t *self)
  2012. {
  2013. self->movetype = MOVETYPE_PUSH;
  2014. VectorClear (self->s.angles);
  2015. self->blocked = train_blocked;
  2016. if (self->spawnflags & TRAIN_BLOCK_STOPS)
  2017. self->dmg = 0;
  2018. else
  2019. {
  2020. if (!self->dmg)
  2021. self->dmg = 100;
  2022. }
  2023. self->solid = SOLID_BSP;
  2024. gi.setmodel (self, self->model);
  2025. if (st.noise)
  2026. self->moveinfo.sound_middle = gi.soundindex (st.noise);
  2027. if (!self->speed)
  2028. self->speed = 100;
  2029. self->moveinfo.speed = self->speed;
  2030. self->moveinfo.accel = self->moveinfo.decel = self->moveinfo.speed;
  2031. self->use = train_use;
  2032. gi.linkentity (self);
  2033. if (self->target)
  2034. {
  2035. // start trains on the second frame, to make sure their targets have had
  2036. // a chance to spawn
  2037. self->nextthink = level.time + FRAMETIME;
  2038. self->think = func_train_find;
  2039. }
  2040. else
  2041. {
  2042. gi.dprintf ("func_train without a target at %s\n", vtos(self->absmin));
  2043. }
  2044. }
  2045. /*QUAKED trigger_elevator (0.3 0.1 0.6) (-8 -8 -8) (8 8 8)
  2046. */
  2047. void trigger_elevator_use (edict_t *self, edict_t *other, edict_t *activator)
  2048. {
  2049. edict_t *target;
  2050. if (self->movetarget->nextthink)
  2051. {
  2052. // gi.dprintf("elevator busy\n");
  2053. return;
  2054. }
  2055. if (!other->pathtarget)
  2056. {
  2057. gi.dprintf("elevator used with no pathtarget\n");
  2058. return;
  2059. }
  2060. target = G_PickTarget (other->pathtarget);
  2061. if (!target)
  2062. {
  2063. gi.dprintf("elevator used with bad pathtarget: %s\n", other->pathtarget);
  2064. return;
  2065. }
  2066. self->movetarget->target_ent = target;
  2067. train_resume (self->movetarget);
  2068. }
  2069. void trigger_elevator_init (edict_t *self)
  2070. {
  2071. if (!self->target)
  2072. {
  2073. gi.dprintf("trigger_elevator has no target\n");
  2074. return;
  2075. }
  2076. self->movetarget = G_PickTarget (self->target);
  2077. if (!self->movetarget)
  2078. {
  2079. gi.dprintf("trigger_elevator unable to find target %s\n", self->target);
  2080. return;
  2081. }
  2082. if (strcmp(self->movetarget->classname, "func_train") != 0)
  2083. {
  2084. gi.dprintf("trigger_elevator target %s is not a train\n", self->target);
  2085. return;
  2086. }
  2087. self->use = trigger_elevator_use;
  2088. self->svflags = SVF_NOCLIENT;
  2089. }
  2090. void SP_trigger_elevator (edict_t *self)
  2091. {
  2092. self->think = trigger_elevator_init;
  2093. self->nextthink = level.time + FRAMETIME;
  2094. }
  2095. /*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
  2096. "wait" base time between triggering all targets, default is 1
  2097. "random" wait variance, default is 0
  2098. so, the basic time between firing is a random time between
  2099. (wait - random) and (wait + random)
  2100. "delay" delay before first firing when turned on, default is 0
  2101. "pausetime" additional delay used only the very first time
  2102. and only if spawned with START_ON
  2103. These can used but not touched.
  2104. */
  2105. void func_timer_think (edict_t *self)
  2106. {
  2107. G_UseTargets (self, self->activator);
  2108. self->nextthink = level.time + self->wait + crandom() * self->random;
  2109. }
  2110. void func_timer_use (edict_t *self, edict_t *other, edict_t *activator)
  2111. {
  2112. self->activator = activator;
  2113. // if on, turn it off
  2114. if (self->nextthink)
  2115. {
  2116. self->nextthink = 0;
  2117. return;
  2118. }
  2119. // turn it on
  2120. if (self->delay)
  2121. self->nextthink = level.time + self->delay;
  2122. else
  2123. func_timer_think (self);
  2124. }
  2125. void SP_func_timer (edict_t *self)
  2126. {
  2127. if (!self->wait)
  2128. self->wait = 1.0;
  2129. self->use = func_timer_use;
  2130. self->think = func_timer_think;
  2131. if (self->random >= self->wait)
  2132. {
  2133. self->random = self->wait - FRAMETIME;
  2134. gi.dprintf("func_timer at %s has random >= wait\n", vtos(self->s.origin));
  2135. }
  2136. if (self->spawnflags & 1)
  2137. {
  2138. self->nextthink = level.time + 1.0 + st.pausetime + self->delay + self->wait + crandom() * self->random;
  2139. self->activator = self;
  2140. }
  2141. self->svflags = SVF_NOCLIENT;
  2142. }
  2143. /*QUAKED func_conveyor (0 .5 .8) ? START_ON TOGGLE
  2144. Conveyors are stationary brushes that move what's on them.
  2145. The brush should be have a surface with at least one current content enabled.
  2146. speed default 100
  2147. */
  2148. void func_conveyor_use (edict_t *self, edict_t *other, edict_t *activator)
  2149. {
  2150. if (self->spawnflags & 1)
  2151. {
  2152. self->speed = 0;
  2153. self->spawnflags &= ~1;
  2154. }
  2155. else
  2156. {
  2157. self->speed = self->count;
  2158. self->spawnflags |= 1;
  2159. }
  2160. if (!(self->spawnflags & 2))
  2161. self->count = 0;
  2162. }
  2163. void SP_func_conveyor (edict_t *self)
  2164. {
  2165. if (!self->speed)
  2166. self->speed = 100;
  2167. if (!(self->spawnflags & 1))
  2168. {
  2169. self->count = self->speed;
  2170. self->speed = 0;
  2171. }
  2172. self->use = func_conveyor_use;
  2173. gi.setmodel (self, self->model);
  2174. self->solid = SOLID_BSP;
  2175. gi.linkentity (self);
  2176. }
  2177. /*QUAKED func_door_secret (0 .5 .8) ? always_shoot 1st_left 1st_down
  2178. A secret door. Slide back and then to the side.
  2179. open_once doors never closes
  2180. 1st_left 1st move is left of arrow
  2181. 1st_down 1st move is down from arrow
  2182. always_shoot door is shootebale even if targeted
  2183. "angle" determines the direction
  2184. "dmg" damage to inflic when blocked (default 2)
  2185. "wait" how long to hold in the open position (default 5, -1 means hold)
  2186. */
  2187. #define SECRET_ALWAYS_SHOOT 1
  2188. #define SECRET_1ST_LEFT 2
  2189. #define SECRET_1ST_DOWN 4
  2190. void door_secret_move1 (edict_t *self);
  2191. void door_secret_move2 (edict_t *self);
  2192. void door_secret_move3 (edict_t *self);
  2193. void door_secret_move4 (edict_t *self);
  2194. void door_secret_move5 (edict_t *self);
  2195. void door_secret_move6 (edict_t *self);
  2196. void door_secret_done (edict_t *self);
  2197. void door_secret_use (edict_t *self, edict_t *other, edict_t *activator)
  2198. {
  2199. // make sure we're not already moving
  2200. if (!VectorCompare(self->s.origin, vec3_origin))
  2201. return;
  2202. Move_Calc (self, self->pos1, door_secret_move1);
  2203. door_use_areaportals (self, true);
  2204. }
  2205. void door_secret_move1 (edict_t *self)
  2206. {
  2207. self->nextthink = level.time + 1.0;
  2208. self->think = door_secret_move2;
  2209. }
  2210. void door_secret_move2 (edict_t *self)
  2211. {
  2212. Move_Calc (self, self->pos2, door_secret_move3);
  2213. }
  2214. void door_secret_move3 (edict_t *self)
  2215. {
  2216. if (self->wait == -1)
  2217. return;
  2218. self->nextthink = level.time + self->wait;
  2219. self->think = door_secret_move4;
  2220. }
  2221. void door_secret_move4 (edict_t *self)
  2222. {
  2223. Move_Calc (self, self->pos1, door_secret_move5);
  2224. }
  2225. void door_secret_move5 (edict_t *self)
  2226. {
  2227. self->nextthink = level.time + 1.0;
  2228. self->think = door_secret_move6;
  2229. }
  2230. void door_secret_move6 (edict_t *self)
  2231. {
  2232. Move_Calc (self, vec3_origin, door_secret_done);
  2233. }
  2234. void door_secret_done (edict_t *self)
  2235. {
  2236. if (!(self->targetname) || (self->spawnflags & SECRET_ALWAYS_SHOOT))
  2237. {
  2238. self->health = 0;
  2239. self->takedamage = DAMAGE_YES;
  2240. }
  2241. door_use_areaportals (self, false);
  2242. }
  2243. void door_secret_blocked (edict_t *self, edict_t *other)
  2244. {
  2245. if (!(other->svflags & SVF_MONSTER) && (!other->client) )
  2246. {
  2247. // give it a chance to go away on it's own terms (like gibs)
  2248. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
  2249. // if it's still there, nuke it
  2250. if (other && other->inuse)
  2251. BecomeExplosion1 (other);
  2252. return;
  2253. }
  2254. if (level.time < self->touch_debounce_time)
  2255. return;
  2256. self->touch_debounce_time = level.time + 0.5;
  2257. T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  2258. }
  2259. void door_secret_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  2260. {
  2261. self->takedamage = DAMAGE_NO;
  2262. door_secret_use (self, attacker, attacker);
  2263. }
  2264. void SP_func_door_secret (edict_t *ent)
  2265. {
  2266. vec3_t forward, right, up;
  2267. float side;
  2268. float width;
  2269. float length;
  2270. ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
  2271. ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
  2272. ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
  2273. ent->movetype = MOVETYPE_PUSH;
  2274. ent->solid = SOLID_BSP;
  2275. gi.setmodel (ent, ent->model);
  2276. ent->blocked = door_secret_blocked;
  2277. ent->use = door_secret_use;
  2278. if (!(ent->targetname) || (ent->spawnflags & SECRET_ALWAYS_SHOOT))
  2279. {
  2280. ent->health = 0;
  2281. ent->takedamage = DAMAGE_YES;
  2282. ent->die = door_secret_die;
  2283. }
  2284. if (!ent->dmg)
  2285. ent->dmg = 2;
  2286. if (!ent->wait)
  2287. ent->wait = 5;
  2288. ent->moveinfo.accel =
  2289. ent->moveinfo.decel =
  2290. ent->moveinfo.speed = 50;
  2291. // calculate positions
  2292. AngleVectors (ent->s.angles, forward, right, up);
  2293. VectorClear (ent->s.angles);
  2294. side = 1.0 - (ent->spawnflags & SECRET_1ST_LEFT);
  2295. if (ent->spawnflags & SECRET_1ST_DOWN)
  2296. width = fabs(DotProduct(up, ent->size));
  2297. else
  2298. width = fabs(DotProduct(right, ent->size));
  2299. length = fabs(DotProduct(forward, ent->size));
  2300. if (ent->spawnflags & SECRET_1ST_DOWN)
  2301. VectorMA (ent->s.origin, -1 * width, up, ent->pos1);
  2302. else
  2303. VectorMA (ent->s.origin, side * width, right, ent->pos1);
  2304. VectorMA (ent->pos1, length, forward, ent->pos2);
  2305. if (ent->health)
  2306. {
  2307. ent->takedamage = DAMAGE_YES;
  2308. ent->die = door_killed;
  2309. ent->max_health = ent->health;
  2310. }
  2311. else if (ent->targetname && ent->message)
  2312. {
  2313. gi.soundindex ("misc/talk.wav");
  2314. ent->touch = door_touch;
  2315. }
  2316. ent->classname = "func_door";
  2317. gi.linkentity (ent);
  2318. }
  2319. /*QUAKED func_killbox (1 0 0) ?
  2320. Kills everything inside when fired, irrespective of protection.
  2321. */
  2322. void use_killbox (edict_t *self, edict_t *other, edict_t *activator)
  2323. {
  2324. KillBox (self);
  2325. }
  2326. void SP_func_killbox (edict_t *ent)
  2327. {
  2328. gi.setmodel (ent, ent->model);
  2329. ent->use = use_killbox;
  2330. ent->svflags = SVF_NOCLIENT;
  2331. }