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