3819e9c7fc97d7549fb1cd2d0c9883588ac433be
[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(entity this)
21 {
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(entity this)
62 {
63         _sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
64         self.state = 1;
65
66         SUB_THINK(self, plat_go_down);
67         self.SUB_NEXTTHINK = self.SUB_LTIME + 3;
68 }
69
70 void plat_hit_bottom(entity this)
71 {
72         _sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
73         self.state = 2;
74 }
75
76 void plat_go_down(entity this)
77 {
78         _sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
79         self.state = 3;
80         SUB_CalcMove (self, self.pos2, TSPEED_LINEAR, self.speed, plat_hit_bottom);
81 }
82
83 void plat_go_up(entity this)
84 {
85         _sound (self, CH_TRIGGER_SINGLE, self.noise, VOL_BASE, ATTEN_NORM);
86         self.state = 4;
87         SUB_CalcMove (self, self.pos1, TSPEED_LINEAR, self.speed, plat_hit_top);
88 }
89
90 void plat_center_touch(entity this)
91 {
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                 entity e = self.enemy;
107                 WITHSELF(e, plat_go_up(e));
108         } else if (self.enemy.state == 1)
109                 self.enemy.SUB_NEXTTHINK = self.enemy.SUB_LTIME + 1;
110 }
111
112 void plat_outside_touch(entity this)
113 {
114 #ifdef SVQC
115         if (!other.iscreature)
116                 return;
117
118         if (other.health <= 0)
119                 return;
120 #elif defined(CSQC)
121         if (!IS_PLAYER(other))
122                 return;
123 #endif
124
125         if (self.enemy.state == 1) {
126             entity e = self.enemy;
127                 WITHSELF(e, plat_go_down(e));
128     }
129 }
130
131 void plat_trigger_use(entity this, entity actor, entity trigger)
132 {
133 #ifdef SVQC
134         if (getthink(this))
135                 return;         // already activated
136 #elif defined(CSQC)
137         if(this.move_think)
138                 return;
139 #endif
140         WITHSELF(this, plat_go_down(this));
141 }
142
143
144 void plat_crush()
145 {SELFPARAM();
146         if((self.spawnflags & 4) && (other.takedamage != DAMAGE_NO))
147         { // KIll Kill Kill!!
148 #ifdef SVQC
149                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
150 #endif
151         }
152         else
153         {
154 #ifdef SVQC
155                 if((self.dmg) && (other.takedamage != DAMAGE_NO))
156                 {   // Shall we bite?
157                         Damage (other, self, self, self.dmg, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
158                         // Gib dead/dying stuff
159                         if(IS_DEAD(other))
160                                 Damage (other, self, self, 10000, DEATH_HURTTRIGGER.m_id, other.origin, '0 0 0');
161                 }
162 #endif
163
164                 if (self.state == 4)
165                         plat_go_down (self);
166                 else if (self.state == 3)
167                         plat_go_up (self);
168         // when in other states, then the plat_crush event came delayed after
169         // plat state already had changed
170         // this isn't a bug per se!
171         }
172 }
173
174 void plat_use(entity this, entity actor, entity trigger)
175 {
176         this.use = func_null;
177         if (this.state != 4)
178                 objerror ("plat_use: not in up state");
179         WITHSELF(this, plat_go_down(this));
180 }
181
182 .string sound1, sound2;
183
184 void plat_reset(entity this)
185 {
186         IFTARGETED
187         {
188                 setorigin (this, this.pos1);
189                 this.state = 4;
190                 this.use = plat_use;
191         }
192         else
193         {
194                 setorigin (this, this.pos2);
195                 this.state = 2;
196                 this.use = plat_trigger_use;
197         }
198
199 #ifdef SVQC
200         this.SendFlags |= SF_TRIGGER_RESET;
201 #endif
202 }
203
204 .float platmovetype_start_default, platmovetype_end_default;
205 bool set_platmovetype(entity e, string s)
206 {
207         // sets platmovetype_start and platmovetype_end based on a string consisting of two values
208
209         int n = tokenize_console(s);
210         if(n > 0)
211                 e.platmovetype_start = stof(argv(0));
212         else
213                 e.platmovetype_start = 0;
214
215         if(n > 1)
216                 e.platmovetype_end = stof(argv(1));
217         else
218                 e.platmovetype_end = e.platmovetype_start;
219
220         if(n > 2)
221                 if(argv(2) == "force")
222                         return true; // no checking, return immediately
223
224         if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
225         {
226                 objerror("Invalid platform move type; platform would go in reverse, which is not allowed.");
227                 return false;
228         }
229
230         return true;
231 }