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