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