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