subs.qc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. void() SUB_Null = {};
  2. void() SUB_Remove = {remove(self);};
  3. /*
  4. QuakeEd only writes a single float for angles (bad idea), so up and down are
  5. just constant angles.
  6. */
  7. vector() SetMovedir =
  8. {
  9. if (self.angles == '0 -1 0')
  10. self.movedir = '0 0 1';
  11. else if (self.angles == '0 -2 0')
  12. self.movedir = '0 0 -1';
  13. else
  14. {
  15. makevectors (self.angles);
  16. self.movedir = v_forward;
  17. }
  18. self.angles = '0 0 0';
  19. };
  20. /*
  21. ================
  22. InitTrigger
  23. ================
  24. */
  25. void() InitTrigger =
  26. {
  27. // trigger angles are used for one-way touches. An angle of 0 is assumed
  28. // to mean no restrictions, so use a yaw of 360 instead.
  29. if (self.angles != '0 0 0')
  30. SetMovedir ();
  31. self.solid = SOLID_TRIGGER;
  32. setmodel (self, self.model); // set size and link into world
  33. self.movetype = MOVETYPE_NONE;
  34. self.modelindex = 0;
  35. self.model = "";
  36. };
  37. /*
  38. =============
  39. SUB_CalcMove
  40. calculate self.velocity and self.nextthink to reach dest from
  41. self.origin traveling at speed
  42. ===============
  43. */
  44. void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt =
  45. {
  46. local entity stemp;
  47. stemp = self;
  48. self = ent;
  49. SUB_CalcMove (tdest, tspeed, func);
  50. self = stemp;
  51. };
  52. void(vector tdest, float tspeed, void() func) SUB_CalcMove =
  53. {
  54. local vector vdestdelta;
  55. local float len, traveltime;
  56. if (!tspeed)
  57. objerror("No speed is defined!");
  58. self.think1 = func;
  59. self.finaldest = tdest;
  60. self.think = SUB_CalcMoveDone;
  61. if (tdest == self.origin)
  62. {
  63. self.velocity = '0 0 0';
  64. self.nextthink = self.ltime + 0.1;
  65. return;
  66. }
  67. // set destdelta to the vector needed to move
  68. vdestdelta = tdest - self.origin;
  69. // calculate length of vector
  70. len = vlen (vdestdelta);
  71. // divide by speed to get time to reach dest
  72. traveltime = len / tspeed;
  73. if (traveltime < 0.03)
  74. traveltime = 0.03;
  75. // set nextthink to trigger a think when dest is reached
  76. self.nextthink = self.ltime + traveltime;
  77. // scale the destdelta vector by the time spent traveling to get velocity
  78. self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float
  79. };
  80. /*
  81. ============
  82. After moving, set origin to exact final destination
  83. ============
  84. */
  85. void() SUB_CalcMoveDone =
  86. {
  87. setorigin(self, self.finaldest);
  88. self.velocity = '0 0 0';
  89. self.nextthink = -1;
  90. if (self.think1)
  91. self.think1();
  92. };
  93. /*
  94. =============
  95. SUB_CalcAngleMove
  96. calculate self.avelocity and self.nextthink to reach destangle from
  97. self.angles rotating
  98. The calling function should make sure self.think is valid
  99. ===============
  100. */
  101. void(entity ent, vector destangle, float tspeed, void() func) SUB_CalcAngleMoveEnt =
  102. {
  103. local entity stemp;
  104. stemp = self;
  105. self = ent;
  106. SUB_CalcAngleMove (destangle, tspeed, func);
  107. self = stemp;
  108. };
  109. void(vector destangle, float tspeed, void() func) SUB_CalcAngleMove =
  110. {
  111. local vector destdelta;
  112. local float len, traveltime;
  113. if (!tspeed)
  114. objerror("No speed is defined!");
  115. // set destdelta to the vector needed to move
  116. destdelta = destangle - self.angles;
  117. // calculate length of vector
  118. len = vlen (destdelta);
  119. // divide by speed to get time to reach dest
  120. traveltime = len / tspeed;
  121. // set nextthink to trigger a think when dest is reached
  122. self.nextthink = self.ltime + traveltime;
  123. // scale the destdelta vector by the time spent traveling to get velocity
  124. self.avelocity = destdelta * (1 / traveltime);
  125. self.think1 = func;
  126. self.finalangle = destangle;
  127. self.think = SUB_CalcAngleMoveDone;
  128. };
  129. /*
  130. ============
  131. After rotating, set angle to exact final angle
  132. ============
  133. */
  134. void() SUB_CalcAngleMoveDone =
  135. {
  136. self.angles = self.finalangle;
  137. self.avelocity = '0 0 0';
  138. self.nextthink = -1;
  139. if (self.think1)
  140. self.think1();
  141. };
  142. //=============================================================================
  143. void() DelayThink =
  144. {
  145. activator = self.enemy;
  146. SUB_UseTargets ();
  147. remove(self);
  148. };
  149. /*
  150. ==============================
  151. SUB_UseTargets
  152. the global "activator" should be set to the entity that initiated the firing.
  153. If self.delay is set, a DelayedUse entity will be created that will actually
  154. do the SUB_UseTargets after that many seconds have passed.
  155. Centerprints any self.message to the activator.
  156. Removes all entities with a targetname that match self.killtarget,
  157. and removes them, so some events can remove other triggers.
  158. Search for (string)targetname in all entities that
  159. match (string)self.target and call their .use function
  160. ==============================
  161. */
  162. void() SUB_UseTargets =
  163. {
  164. local entity t, stemp, otemp, act;
  165. //
  166. // check for a delay
  167. //
  168. if (self.delay)
  169. {
  170. // create a temp object to fire at a later time
  171. t = spawn();
  172. t.classname = "DelayedUse";
  173. t.nextthink = time + self.delay;
  174. t.think = DelayThink;
  175. t.enemy = activator;
  176. t.message = self.message;
  177. t.killtarget = self.killtarget;
  178. t.target = self.target;
  179. return;
  180. }
  181. //
  182. // print the message
  183. //
  184. if (activator.classname == "player" && self.message != "")
  185. {
  186. centerprint (activator, self.message);
  187. if (!self.noise)
  188. sound (activator, CHAN_VOICE, "misc/talk.wav", 1, ATTN_NORM);
  189. }
  190. //
  191. // kill the killtagets
  192. //
  193. if (self.killtarget)
  194. {
  195. t = world;
  196. do
  197. {
  198. t = find (t, targetname, self.killtarget);
  199. if (!t)
  200. return;
  201. remove (t);
  202. } while ( 1 );
  203. }
  204. //
  205. // fire targets
  206. //
  207. if (self.target)
  208. {
  209. act = activator;
  210. t = world;
  211. do
  212. {
  213. t = find (t, targetname, self.target);
  214. if (!t)
  215. {
  216. return;
  217. }
  218. stemp = self;
  219. otemp = other;
  220. self = t;
  221. other = stemp;
  222. if (self.use != SUB_Null)
  223. {
  224. if (self.use)
  225. self.use ();
  226. }
  227. self = stemp;
  228. other = otemp;
  229. activator = act;
  230. } while ( 1 );
  231. }
  232. };