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