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