]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/platforms.qc
710a6db3f573cf44d6eb54c11d397b4aa3bd74eb
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / platforms.qc
1 void generic_plat_blocked()
2 {
3 #ifdef SVQC
4     SELFPARAM();
5         if(self.dmg && other.takedamage != DAMAGE_NO)
6         {
7                 if(self.dmgtime2 < time)
8                 {
9                         Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
10                         self.dmgtime2 = time + self.dmgtime;
11                 }
12
13                 // Gib dead/dying stuff
14                 if(IS_DEAD(other))
15                         Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
16         }
17 #endif
18 }
19
20 void plat_spawn_inside_trigger()
21 {SELFPARAM();
22         entity trigger;
23         vector tmin, tmax;
24
25         trigger = spawn();
26         trigger.touch = plat_center_touch;
27         trigger.movetype = MOVETYPE_NONE;
28         trigger.solid = SOLID_TRIGGER;
29         trigger.enemy = self;
30
31 #ifdef CSQC
32         trigger.drawmask = MASK_NORMAL;
33         trigger.trigger_touch = plat_center_touch;
34         trigger.draw = trigger_draw_generic;
35 #endif
36
37         tmin = self.absmin + '25 25 0';
38         tmax = self.absmax - '25 25 -8';
39         tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
40         if (self.spawnflags & PLAT_LOW_TRIGGER)
41                 tmax_z = tmin_z + 8;
42
43         if (self.size_x <= 50)
44         {
45                 tmin_x = (self.mins_x + self.maxs_x) / 2;
46                 tmax_x = tmin_x + 1;
47         }
48         if (self.size_y <= 50)
49         {
50                 tmin_y = (self.mins_y + self.maxs_y) / 2;
51                 tmax_y = tmin_y + 1;
52         }
53
54         if(tmin_x < tmax_x)
55                 if(tmin_y < tmax_y)
56                         if(tmin_z < tmax_z)
57                         {
58                                 setsize (trigger, tmin, tmax);
59                                 return;
60                         }
61
62         // otherwise, something is fishy...
63         remove(trigger);
64         objerror("plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
65 }
66
67 void plat_hit_top()
68 {SELFPARAM();
69         _sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
70         self.state = 1;
71
72         self.SUB_THINK = plat_go_down;
73         self.SUB_NEXTTHINK = self.SUB_LTIME + 3;
74 }
75
76 void plat_hit_bottom()
77 {SELFPARAM();
78         _sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
79         self.state = 2;
80 }
81
82 void plat_go_down()
83 {SELFPARAM();
84         _sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
85         self.state = 3;
86         SUB_CalcMove (self.pos2, TSPEED_LINEAR, self.speed, plat_hit_bottom);
87 }
88
89 void plat_go_up()
90 {SELFPARAM();
91         _sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
92         self.state = 4;
93         SUB_CalcMove (self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
94 }
95
96 void plat_center_touch()
97 {SELFPARAM();
98 #ifdef SVQC
99         if (!other.iscreature)
100                 return;
101
102         if (other.health <= 0)
103                 return;
104 #elif defined(CSQC)
105         if (!IS_PLAYER(other))
106                 return;
107         if(IS_DEAD(other))
108                 return;
109 #endif
110
111         if (self.enemy.state == 2)
112                 WITHSELF(self.enemy, plat_go_up());
113         else if (self.enemy.state == 1)
114                 self.enemy.SUB_NEXTTHINK = self.enemy.SUB_LTIME + 1;
115 }
116
117 void plat_outside_touch()
118 {SELFPARAM();
119 #ifdef SVQC
120         if (!other.iscreature)
121                 return;
122
123         if (other.health <= 0)
124                 return;
125 #elif defined(CSQC)
126         if (!IS_PLAYER(other))
127                 return;
128 #endif
129
130         if (self.enemy.state == 1)
131                 WITHSELF(self.enemy, plat_go_down());
132 }
133
134 void plat_trigger_use(entity this, entity actor, entity trigger)
135 {
136 #ifdef SVQC
137         if (this.think)
138                 return;         // already activated
139 #elif defined(CSQC)
140         if(this.move_think)
141                 return;
142 #endif
143         WITHSELF(this, plat_go_down());
144 }
145
146
147 void plat_crush()
148 {SELFPARAM();
149         if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO))
150         { // KIll Kill Kill!!
151 #ifdef SVQC
152                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
153 #endif
154         }
155         else
156         {
157 #ifdef SVQC
158                 if((self.dmg) && (other.takedamage != DAMAGE_NO))
159                 {   // Shall we bite?
160                         Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
161                         // Gib dead/dying stuff
162                         if(IS_DEAD(other))
163                                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
164                 }
165 #endif
166
167                 if (self.state == 4)
168                         plat_go_down ();
169                 else if (self.state == 3)
170                         plat_go_up ();
171         // when in other states, then the plat_crush event came delayed after
172         // plat state already had changed
173         // this isn't a bug per se!
174         }
175 }
176
177 void plat_use(entity this, entity actor, entity trigger)
178 {
179         this.use = func_null;
180         if (this.state != 4)
181                 objerror ("plat_use: not in up state");
182         WITHSELF(this, plat_go_down());
183 }
184
185 .string sound1, sound2;
186
187 void plat_reset(entity this)
188 {
189         IFTARGETED
190         {
191                 setorigin (this, this.pos1);
192                 this.state = 4;
193                 this.use = plat_use;
194         }
195         else
196         {
197                 setorigin (this, this.pos2);
198                 this.state = 2;
199                 this.use = plat_trigger_use;
200         }
201
202 #ifdef SVQC
203         this.SendFlags |= SF_TRIGGER_RESET;
204 #endif
205 }
206
207 .float platmovetype_start_default, platmovetype_end_default;
208 bool set_platmovetype(entity e, string s)
209 {
210         // sets platmovetype_start and platmovetype_end based on a string consisting of two values
211
212         int n = tokenize_console(s);
213         if(n > 0)
214                 e.platmovetype_start = stof(argv(0));
215         else
216                 e.platmovetype_start = 0;
217
218         if(n > 1)
219                 e.platmovetype_end = stof(argv(1));
220         else
221                 e.platmovetype_end = e.platmovetype_start;
222
223         if(n > 2)
224                 if(argv(2) == "force")
225                         return true; // no checking, return immediately
226
227         if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
228         {
229                 objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
230                 return false;
231         }
232
233         return true;
234 }