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