]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/trigger/multi.qc
Use the constants for player hitbox size when applicable (should fix observer hitbox)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / trigger / multi.qc
1 #include "multi.qh"
2 // NOTE: also contains trigger_once at bottom
3
4 #ifdef SVQC
5 // the wait time has passed, so set back up for another activation
6 void multi_wait(entity this)
7 {
8         if (this.max_health)
9         {
10                 this.health = this.max_health;
11                 this.takedamage = DAMAGE_YES;
12                 this.solid = SOLID_BBOX;
13         }
14 }
15
16
17 // the trigger was just touched/killed/used
18 // this.enemy should be set to the activator so it can be held through a delay
19 // so wait for the delay time before firing
20 void multi_trigger(entity this)
21 {
22         if (this.nextthink > time)
23         {
24                 return;         // allready been triggered
25         }
26
27         if(this.spawnflags & 16384)
28         if(!IS_PLAYER(this.enemy))
29                 return; // only players
30
31         if (this.classname == "trigger_secret")
32         {
33                 if (!IS_PLAYER(this.enemy))
34                         return;
35                 found_secrets = found_secrets + 1;
36                 WriteByte (MSG_ALL, SVC_FOUNDSECRET);
37         }
38
39         if (this.noise)
40                 _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
41
42 // don't trigger again until reset
43         this.takedamage = DAMAGE_NO;
44
45         SUB_UseTargets(this, this.enemy, this.goalentity);
46
47         if (this.wait > 0)
48         {
49                 setthink(this, multi_wait);
50                 this.nextthink = time + this.wait;
51         }
52         else if (this.wait == 0)
53         {
54                 multi_wait(this); // waiting finished
55         }
56         else
57         {       // we can't just remove (this) here, because this is a touch function
58                 // called wheil C code is looping through area links...
59                 settouch(this, func_null);
60         }
61 }
62
63 void multi_use(entity this, entity actor, entity trigger)
64 {
65         this.goalentity = trigger;
66         this.enemy = actor;
67         multi_trigger(this);
68 }
69
70 void multi_touch(entity this, entity toucher)
71 {
72         if(!(this.spawnflags & 2))
73         if(!toucher.iscreature)
74                         return;
75
76         if(this.team)
77                 if(((this.spawnflags & 4) == 0) == (this.team != toucher.team))
78                         return;
79
80 // if the trigger has an angles field, check player's facing direction
81         if (this.movedir != '0 0 0')
82         {
83                 makevectors (toucher.angles);
84                 if (v_forward * this.movedir < 0)
85                         return;         // not facing the right way
86         }
87
88         // if the trigger has pressed keys, check that the player is pressing those keys
89         if(this.pressedkeys)
90         if(IS_PLAYER(toucher)) // only for players
91         if(!(toucher.pressedkeys & this.pressedkeys))
92                 return;
93
94         EXACTTRIGGER_TOUCH(this, toucher);
95
96         this.enemy = toucher;
97         this.goalentity = toucher;
98         multi_trigger(this);
99 }
100
101 void multi_eventdamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
102 {
103         if(!this.takedamage)
104                 return;
105         if(this.spawnflags & DOOR_NOSPLASH)
106                 if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
107                         return;
108         this.health = this.health - damage;
109         if (this.health <= 0)
110         {
111                 this.enemy = attacker;
112                 this.goalentity = inflictor;
113                 multi_trigger(this);
114         }
115 }
116
117 void multi_reset(entity this)
118 {
119         if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
120                 settouch(this, multi_touch);
121         if (this.max_health)
122         {
123                 this.health = this.max_health;
124                 this.takedamage = DAMAGE_YES;
125                 this.solid = SOLID_BBOX;
126         }
127         setthink(this, func_null);
128         this.nextthink = 0;
129         this.team = this.team_saved;
130 }
131
132 /*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
133 Variable sized repeatable trigger.  Must be targeted at one or more entities.  If "health" is set, the trigger must be killed to activate each time.
134 If "delay" is set, the trigger waits some time after activating before firing.
135 "wait" : Seconds between triggerings. (.2 default)
136 If notouch is set, the trigger is only fired by other entities, not by touching.
137 NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
138 sounds
139 1)      secret
140 2)      beep beep
141 3)      large switch
142 4)
143 set "message" to text string
144 */
145 spawnfunc(trigger_multiple)
146 {
147         this.reset = multi_reset;
148         if (this.sounds == 1)
149                 this.noise = "misc/secret.wav";
150         else if (this.sounds == 2)
151                 this.noise = strzone(SND(TALK));
152         else if (this.sounds == 3)
153                 this.noise = "misc/trigger1.wav";
154
155         if(this.noise)
156                 precache_sound(this.noise);
157
158         if (!this.wait)
159                 this.wait = 0.2;
160         else if(this.wait < -1)
161                 this.wait = 0;
162         this.use = multi_use;
163
164         EXACTTRIGGER_INIT;
165
166         this.team_saved = this.team;
167
168         if (this.health)
169         {
170                 if (this.spawnflags & SPAWNFLAG_NOTOUCH)
171                         objerror (this, "health and notouch don't make sense\n");
172                 this.max_health = this.health;
173                 this.event_damage = multi_eventdamage;
174                 this.takedamage = DAMAGE_YES;
175                 this.solid = SOLID_BBOX;
176                 setorigin(this, this.origin);   // make sure it links into the world
177         }
178         else
179         {
180                 if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
181                 {
182                         settouch(this, multi_touch);
183                         setorigin(this, this.origin);   // make sure it links into the world
184                 }
185         }
186 }
187
188
189 /*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
190 Variable sized trigger. Triggers once, then removes itself.  You must set the key "target" to the name of another object in the level that has a matching
191 "targetname".  If "health" is set, the trigger must be killed to activate.
192 If notouch is set, the trigger is only fired by other entities, not by touching.
193 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
194 if "angle" is set, the trigger will only fire when someone is facing the direction of the angle.  Use "360" for an angle of 0.
195 sounds
196 1)      secret
197 2)      beep beep
198 3)      large switch
199 4)
200 set "message" to text string
201 */
202 spawnfunc(trigger_once)
203 {
204         this.wait = -1;
205         spawnfunc_trigger_multiple(this);
206 }
207 #endif