]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/trigger/multi.qc
Merge branch 't0uYK8Ne/set_slick_friction' into 'master'
[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         EXACTTRIGGER_INIT;
180
181         this.team_saved = this.team;
182         IL_PUSH(g_saved_team, this);
183
184         if (GetResource(this, RES_HEALTH))
185         {
186                 if (this.spawnflags & SPAWNFLAG_NOTOUCH)
187                         objerror (this, "health and notouch don't make sense\n");
188                 this.canteamdamage = true;
189                 this.max_health = GetResource(this, RES_HEALTH);
190                 this.event_damage = multi_eventdamage;
191                 this.takedamage = DAMAGE_YES;
192                 this.solid = SOLID_BBOX;
193                 setorigin(this, this.origin);   // make sure it links into the world
194         }
195         else
196         {
197                 if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
198                 {
199                         settouch(this, multi_touch);
200                         setorigin(this, this.origin);   // make sure it links into the world
201                 }
202         }
203 }
204
205
206 /*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
207 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
208 "targetname".  If "health" is set, the trigger must be killed to activate.
209 If notouch is set, the trigger is only fired by other entities, not by touching.
210 if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
211 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.
212 sounds
213 1)      secret
214 2)      beep beep
215 3)      large switch
216 4)
217 set "message" to text string
218 */
219 spawnfunc(trigger_once)
220 {
221         this.wait = -1;
222         spawnfunc_trigger_multiple(this);
223 }
224 #endif