]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/trigger/multi.qc
Merge branch 'master' into terencehill/glowmod_color_fix
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapobjects / 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                 SetResourceExplicit(this, RES_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 & ONLY_PLAYERS) && !IS_PLAYER(this.enemy))
28         {
29                 return; // only players
30         }
31
32         if (this.noise && this.noise != "")
33         {
34                 _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
35         }
36
37         // don't trigger again until reset
38         this.takedamage = DAMAGE_NO;
39
40         SUB_UseTargets(this, this.enemy, this.goalentity);
41
42         if (this.wait > 0)
43         {
44                 setthink(this, multi_wait);
45                 this.nextthink = time + this.wait;
46         }
47         else if (this.wait == 0)
48         {
49                 multi_wait(this); // waiting finished
50         }
51         else
52         {       // we can't just delete(this) here, because this is a touch function
53                 // called while C code is looping through area links...
54                 settouch(this, func_null);
55         }
56 }
57
58 void multi_use(entity this, entity actor, entity trigger)
59 {
60         this.goalentity = trigger;
61         this.enemy = actor;
62         multi_trigger(this);
63 }
64
65 void multi_touch(entity this, entity toucher)
66 {
67         if(!(this.spawnflags & ALL_ENTITIES) && !toucher.iscreature)
68         {
69                 return;
70         }
71
72         if(this.team)
73         {
74                 if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != toucher.team))
75                 {
76                         return;
77                 }
78         }
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 && IS_PLAYER(toucher)) // only for players
90         {
91                 if(!(CS(toucher).pressedkeys & this.pressedkeys))
92                 {
93                         return;
94                 }
95         }
96
97         EXACTTRIGGER_TOUCH(this, toucher);
98
99         this.enemy = toucher;
100         this.goalentity = toucher;
101         multi_trigger(this);
102 }
103
104 void multi_eventdamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
105 {
106         if(!this.takedamage)
107                 return;
108         if(this.spawnflags & NOSPLASH)
109                 if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
110                         return;
111         if(this.team)
112                 if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != attacker.team))
113                         return;
114         TakeResource(this, RES_HEALTH, damage);
115         if (GetResource(this, RES_HEALTH) <= 0)
116         {
117                 this.enemy = attacker;
118                 this.goalentity = inflictor;
119                 multi_trigger(this);
120         }
121 }
122
123 void multi_reset(entity this)
124 {
125         if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
126                 settouch(this, multi_touch);
127         if (this.max_health)
128         {
129                 SetResourceExplicit(this, RES_HEALTH, this.max_health);
130                 this.takedamage = DAMAGE_YES;
131                 this.solid = SOLID_BBOX;
132         }
133         setthink(this, func_null);
134         this.nextthink = 0;
135         this.team = this.team_saved;
136 }
137
138 /*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
139 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.
140 If "delay" is set, the trigger waits some time after activating before firing.
141 "wait" : Seconds between triggerings. (.2 default)
142 If notouch is set, the trigger is only fired by other entities, not by touching.
143 NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
144 sounds
145 1)      secret
146 2)      beep beep
147 3)      large switch
148 4)
149 set "message" to text string
150 */
151 spawnfunc(trigger_multiple)
152 {
153         this.reset = multi_reset;
154         if (this.sounds == 1)
155                 this.noise = "misc/secret.wav";
156         else if (this.sounds == 2)
157                 this.noise = strzone(SND(TALK));
158         else if (this.sounds == 3)
159                 this.noise = "misc/trigger1.wav";
160
161         if(this.noise && this.noise != "")
162                 precache_sound(this.noise);
163
164         if (!this.wait)
165                 this.wait = 0.2;
166         else if(this.wait < -1)
167                 this.wait = 0;
168         this.use = multi_use;
169
170         if(this.wait == -1 && autocvar_sv_q3defragcompat)
171                 this.wait = 0.1; // compatibility for q3df: "instant" return
172
173         EXACTTRIGGER_INIT;
174
175         this.team_saved = this.team;
176         IL_PUSH(g_saved_team, this);
177
178         if (GetResource(this, RES_HEALTH))
179         {
180                 if (this.spawnflags & SPAWNFLAG_NOTOUCH)
181                         objerror (this, "health and notouch don't make sense\n");
182                 this.canteamdamage = true;
183                 this.max_health = GetResource(this, RES_HEALTH);
184                 this.event_damage = multi_eventdamage;
185                 this.takedamage = DAMAGE_YES;
186                 this.solid = SOLID_BBOX;
187                 setorigin(this, this.origin);   // make sure it links into the world
188         }
189         else
190         {
191                 if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
192                 {
193                         settouch(this, multi_touch);
194                         setorigin(this, this.origin);   // make sure it links into the world
195                 }
196         }
197 }
198
199
200 /*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
201 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
202 "targetname".  If "health" is set, the trigger must be killed to activate.
203 If notouch is set, the trigger is only fired by other entities, not by touching.
204 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
205 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.
206 sounds
207 1)      secret
208 2)      beep beep
209 3)      large switch
210 4)
211 set "message" to text string
212 */
213 spawnfunc(trigger_once)
214 {
215         this.wait = -1;
216         spawnfunc_trigger_multiple(this);
217 }
218 #endif