]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mapobjects/platforms.qc
Sort most common includes alphabetically
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapobjects / platforms.qc
1 #include "platforms.qh"
2
3 void generic_plat_blocked(entity this, entity blocker)
4 {
5 #ifdef SVQC
6         if(this.dmg && blocker.takedamage != DAMAGE_NO)
7         {
8                 if(this.dmgtime2 < time)
9                 {
10                         Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
11                         this.dmgtime2 = time + this.dmgtime;
12                 }
13
14                 // Gib dead/dying stuff
15                 if(IS_DEAD(blocker))
16                         Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
17         }
18 #endif
19 }
20
21 void plat_spawn_inside_trigger(entity this)
22 {
23         entity trigger;
24         vector tmin, tmax;
25
26         trigger = spawn();
27         settouch(trigger, plat_center_touch);
28         set_movetype(trigger, MOVETYPE_NONE);
29         trigger.solid = SOLID_TRIGGER;
30         trigger.enemy = this;
31
32         tmin = this.absmin + '25 25 0';
33         tmax = this.absmax - '25 25 -8';
34         tmin_z = tmax_z - (this.pos1_z - this.pos2_z + 8);
35         if (this.spawnflags & PLAT_LOW_TRIGGER)
36                 tmax_z = tmin_z + 8;
37
38         if (this.size_x <= 50)
39         {
40                 tmin_x = (this.mins_x + this.maxs_x) / 2;
41                 tmax_x = tmin_x + 1;
42         }
43         if (this.size_y <= 50)
44         {
45                 tmin_y = (this.mins_y + this.maxs_y) / 2;
46                 tmax_y = tmin_y + 1;
47         }
48
49         if(tmin_x < tmax_x)
50                 if(tmin_y < tmax_y)
51                         if(tmin_z < tmax_z)
52                         {
53                                 setsize (trigger, tmin, tmax);
54                                 return;
55                         }
56
57         // otherwise, something is fishy...
58         delete(trigger);
59         objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
60 }
61
62 void plat_hit_top(entity this)
63 {
64         _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
65         this.state = STATE_TOP;
66
67         setthink(this, plat_go_down);
68         this.nextthink = this.ltime + 3;
69 }
70
71 void plat_hit_bottom(entity this)
72 {
73         _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
74         this.state = STATE_BOTTOM;
75 }
76
77 void plat_go_down(entity this)
78 {
79         _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
80         this.state = STATE_DOWN;
81         SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, plat_hit_bottom);
82 }
83
84 void plat_go_up(entity this)
85 {
86         _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
87         this.state = STATE_UP;
88         SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, plat_hit_top);
89 }
90
91 void plat_center_touch(entity this, entity toucher)
92 {
93 #ifdef SVQC
94         if (!toucher.iscreature)
95                 return;
96
97         if (GetResource(toucher, RES_HEALTH) <= 0)
98                 return;
99 #elif defined(CSQC)
100         if (!IS_PLAYER(toucher))
101                 return;
102         if(IS_DEAD(toucher))
103                 return;
104 #endif
105
106         if (this.enemy.state == STATE_BOTTOM) {
107                 plat_go_up(this.enemy);
108         } else if (this.enemy.state == STATE_TOP)
109                 this.enemy.nextthink = this.enemy.ltime + 1;
110 }
111
112 void plat_outside_touch(entity this, entity toucher)
113 {
114 #ifdef SVQC
115         if (!toucher.iscreature)
116                 return;
117
118         if (GetResource(toucher, RES_HEALTH) <= 0)
119                 return;
120 #elif defined(CSQC)
121         if (!IS_PLAYER(toucher))
122                 return;
123 #endif
124
125         if (this.enemy.state == STATE_TOP) {
126             entity e = this.enemy;
127                 plat_go_down(e);
128     }
129 }
130
131 void plat_trigger_use(entity this, entity actor, entity trigger)
132 {
133         if (getthink(this))
134                 return;         // already activated
135         plat_go_down(this);
136 }
137
138
139 void plat_crush(entity this, entity blocker)
140 {
141         if((this.spawnflags & CRUSH) && (blocker.takedamage != DAMAGE_NO))
142         { // KIll Kill Kill!!
143 #ifdef SVQC
144                 Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
145 #endif
146         }
147         else
148         {
149 #ifdef SVQC
150                 if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
151                 {   // Shall we bite?
152                         Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
153                         // Gib dead/dying stuff
154                         if(IS_DEAD(blocker))
155                                 Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
156                 }
157 #endif
158
159                 if (this.state == STATE_UP)
160                         plat_go_down (this);
161                 else if (this.state == STATE_DOWN)
162                         plat_go_up (this);
163         // when in other states, then the plat_crush event came delayed after
164         // plat state already had changed
165         // this isn't a bug per se!
166         }
167 }
168
169 void plat_use(entity this, entity actor, entity trigger)
170 {
171         this.use = func_null;
172         if (this.state != STATE_UP)
173                 objerror (this, "plat_use: not in up state");
174         plat_go_down(this);
175 }
176
177 // WARNING: backwards compatibility because people don't use already existing fields :(
178 // TODO: Check if any maps use these fields and remove these fields if it doesn't break maps
179 .string sound1, sound2;
180
181 void plat_reset(entity this)
182 {
183         if(this.targetname && this.targetname != "")
184         {
185                 setorigin(this, this.pos1);
186                 this.state = STATE_UP;
187                 this.use = plat_use;
188         }
189         else
190         {
191                 setorigin(this, this.pos2);
192                 this.state = STATE_BOTTOM;
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(e, "Invalid platform move type; platform would go in reverse, which is not allowed.");
224                 return false;
225         }
226
227         return true;
228 }