]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/platforms.qc
b9937f04d36bcaf7627717ca58582df14db1d56e
[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         setself(self.enemy);
112         if (self.state == 2)
113                 plat_go_up ();
114         else if (self.state == 1)
115                 self.SUB_NEXTTHINK = self.SUB_LTIME + 1;
116 }
117
118 void plat_outside_touch()
119 {SELFPARAM();
120 #ifdef SVQC
121         if (!other.iscreature)
122                 return;
123
124         if (other.health <= 0)
125                 return;
126 #elif defined(CSQC)
127         if (!IS_PLAYER(other))
128                 return;
129 #endif
130
131         setself(self.enemy);
132         if (self.state == 1)
133                 plat_go_down ();
134 }
135
136 void plat_trigger_use(entity this, entity actor, entity trigger)
137 {
138 #ifdef SVQC
139         if (this.think)
140                 return;         // already activated
141 #elif defined(CSQC)
142         if(this.move_think)
143                 return;
144 #endif
145         WITHSELF(this, plat_go_down());
146 }
147
148
149 void plat_crush()
150 {SELFPARAM();
151         if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO))
152         { // KIll Kill Kill!!
153 #ifdef SVQC
154                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
155 #endif
156         }
157         else
158         {
159 #ifdef SVQC
160                 if((self.dmg) && (other.takedamage != DAMAGE_NO))
161                 {   // Shall we bite?
162                         Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
163                         // Gib dead/dying stuff
164                         if(IS_DEAD(other))
165                                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
166                 }
167 #endif
168
169                 if (self.state == 4)
170                         plat_go_down ();
171                 else if (self.state == 3)
172                         plat_go_up ();
173         // when in other states, then the plat_crush event came delayed after
174         // plat state already had changed
175         // this isn't a bug per se!
176         }
177 }
178
179 void plat_use(entity this, entity actor, entity trigger)
180 {
181         this.use1 = func_null;
182         if (this.state != 4)
183                 objerror ("plat_use: not in up state");
184         WITHSELF(this, plat_go_down());
185 }
186
187 .string sound1, sound2;
188
189 void plat_reset(entity this)
190 {
191         IFTARGETED
192         {
193                 setorigin (this, this.pos1);
194                 this.state = 4;
195                 this.use1 = plat_use;
196         }
197         else
198         {
199                 setorigin (this, this.pos2);
200                 this.state = 2;
201                 this.use1 = plat_trigger_use;
202         }
203
204 #ifdef SVQC
205         this.SendFlags |= SF_TRIGGER_RESET;
206 #endif
207 }
208
209 .float platmovetype_start_default, platmovetype_end_default;
210 bool set_platmovetype(entity e, string s)
211 {
212         // sets platmovetype_start and platmovetype_end based on a string consisting of two values
213
214         int n = tokenize_console(s);
215         if(n > 0)
216                 e.platmovetype_start = stof(argv(0));
217         else
218                 e.platmovetype_start = 0;
219
220         if(n > 1)
221                 e.platmovetype_end = stof(argv(1));
222         else
223                 e.platmovetype_end = e.platmovetype_start;
224
225         if(n > 2)
226                 if(argv(2) == "force")
227                         return true; // no checking, return immediately
228
229         if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
230         {
231                 objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
232                 return false;
233         }
234
235         return true;
236 }