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