1 #include "g_local.h"
2
3 //void plat_CalcMove (edict_t *ent, vec3_t dest, void(*func)(edict_t*));
4 void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*));
5
6 void fd_secret_move1(edict_t *self);
7 void fd_secret_move2(edict_t *self);
8 void fd_secret_move3(edict_t *self);
9 void fd_secret_move4(edict_t *self);
10 void fd_secret_move5(edict_t *self);
11 void fd_secret_move6(edict_t *self);
12 void fd_secret_done(edict_t *self);
13
14 /*
15 =============================================================================
16
17 SECRET DOORS
18
19 =============================================================================
20 */
21
22 #define SEC_OPEN_ONCE 1 // stays open
23 #define SEC_1ST_LEFT 2 // 1st move is left of arrow
24 #define SEC_1ST_DOWN 4 // 1st move is down from arrow
25 #define SEC_NO_SHOOT 8 // only opened by trigger
26 #define SEC_YES_SHOOT 16 // shootable even if targeted
27 #define SEC_MOVE_RIGHT 32
28 #define SEC_MOVE_FORWARD 64
29
fd_secret_use(edict_t * self,edict_t * other,edict_t * activator)30 void fd_secret_use (edict_t *self, edict_t *other, edict_t *activator)
31 {
32 edict_t *ent;
33
34 // gi.dprintf("fd_secret_use\n");
35 if (self->flags & FL_TEAMSLAVE)
36 return;
37
38 // trigger all paired doors
39 for (ent = self ; ent ; ent = ent->teamchain)
40 Move_Calc(ent, ent->moveinfo.start_origin, fd_secret_move1);
41
42 }
43
fd_secret_killed(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)44 void fd_secret_killed (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
45 {
46 // gi.dprintf("fd_secret_killed\n");
47 self->health = self->max_health;
48 self->takedamage = DAMAGE_NO;
49
50 if (self->flags & FL_TEAMSLAVE && self->teammaster && self->teammaster->takedamage != DAMAGE_NO)
51 fd_secret_killed (self->teammaster, inflictor, attacker, damage, point);
52 else
53 fd_secret_use (self, inflictor, attacker);
54 }
55
56 // Wait after first movement...
fd_secret_move1(edict_t * self)57 void fd_secret_move1(edict_t *self)
58 {
59 // gi.dprintf("fd_secret_move1\n");
60 self->nextthink = level.time + 1.0;
61 self->think = fd_secret_move2;
62 }
63
64 // Start moving sideways w/sound...
fd_secret_move2(edict_t * self)65 void fd_secret_move2(edict_t *self)
66 {
67 // gi.dprintf("fd_secret_move2\n");
68 Move_Calc(self, self->moveinfo.end_origin, fd_secret_move3);
69 }
70
71 // Wait here until time to go back...
fd_secret_move3(edict_t * self)72 void fd_secret_move3(edict_t *self)
73 {
74 // gi.dprintf("fd_secret_move3\n");
75 if (!(self->spawnflags & SEC_OPEN_ONCE))
76 {
77 self->nextthink = level.time + self->wait;
78 self->think = fd_secret_move4;
79 }
80 }
81
82 // Move backward...
fd_secret_move4(edict_t * self)83 void fd_secret_move4(edict_t *self)
84 {
85 // gi.dprintf("fd_secret_move4\n");
86 Move_Calc(self, self->moveinfo.start_origin, fd_secret_move5);
87 }
88
89 // Wait 1 second...
fd_secret_move5(edict_t * self)90 void fd_secret_move5(edict_t *self)
91 {
92 // gi.dprintf("fd_secret_move5\n");
93 self->nextthink = level.time + 1.0;
94 self->think = fd_secret_move6;
95 }
96
fd_secret_move6(edict_t * self)97 void fd_secret_move6(edict_t *self)
98 {
99 // gi.dprintf("fd_secret_move6\n");
100 Move_Calc(self, self->move_origin, fd_secret_done);
101 }
102
fd_secret_done(edict_t * self)103 void fd_secret_done(edict_t *self)
104 {
105 // gi.dprintf("fd_secret_done\n");
106 if (!self->targetname || self->spawnflags & SEC_YES_SHOOT)
107 {
108 self->health = 1;
109 self->takedamage = DAMAGE_YES;
110 self->die = fd_secret_killed;
111 }
112 }
113
secret_blocked(edict_t * self,edict_t * other)114 void secret_blocked(edict_t *self, edict_t *other)
115 {
116 if (!(self->flags & FL_TEAMSLAVE))
117 T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 0, 0, MOD_CRUSH);
118
119 // if (time < self->attack_finished)
120 // return;
121 // self->attack_finished = time + 0.5;
122 // T_Damage (other, self, self, self->dmg);
123 }
124
125 /*
126 ================
127 secret_touch
128
129 Prints messages
130 ================
131 */
secret_touch(edict_t * self,edict_t * other,cplane_t * plane,csurface_t * surf)132 void secret_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
133 {
134 if (other->health <= 0)
135 return;
136
137 if (!(other->client))
138 return;
139
140 if (self->monsterinfo.attack_finished > level.time)
141 return;
142
143 self->monsterinfo.attack_finished = level.time + 2;
144
145 if (self->message)
146 {
147 gi.centerprintf (other, self->message);
148 // fixme - put this sound back??
149 // gi.sound (other, CHAN_BODY, "misc/talk.wav", 1, ATTN_NORM);
150 }
151 }
152
153
154 /*QUAKED func_door_secret2 (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot slide_right slide_forward
155 Basic secret door. Slides back, then to the left. Angle determines direction.
156
157 FLAGS:
158 open_once = not implemented yet
159 1st_left = 1st move is left/right of arrow
160 1st_down = 1st move is forwards/backwards
161 no_shoot = not implemented yet
162 always_shoot = even if targeted, keep shootable
163 reverse_left = the sideways move will be to right of arrow
164 reverse_back = the to/fro move will be forward
165
166 VALUES:
167 wait = # of seconds before coming back (5 default)
168 dmg = damage to inflict when blocked (2 default)
169
170 */
171
SP_func_door_secret2(edict_t * ent)172 void SP_func_door_secret2 (edict_t *ent)
173 {
174 vec3_t forward,right,up;
175 float lrSize, fbSize;
176
177 ent->moveinfo.sound_start = gi.soundindex ("doors/dr1_strt.wav");
178 ent->moveinfo.sound_middle = gi.soundindex ("doors/dr1_mid.wav");
179 ent->moveinfo.sound_end = gi.soundindex ("doors/dr1_end.wav");
180
181 if (!ent->dmg)
182 ent->dmg = 2;
183
184 AngleVectors(ent->s.angles, forward, right, up);
185 VectorCopy(ent->s.origin, ent->move_origin);
186 VectorCopy(ent->s.angles, ent->move_angles);
187
188 G_SetMovedir (ent->s.angles, ent->movedir);
189 ent->movetype = MOVETYPE_PUSH;
190 ent->solid = SOLID_BSP;
191 gi.setmodel (ent, ent->model);
192
193 if(ent->move_angles[1] == 0 || ent->move_angles[1] == 180)
194 {
195 lrSize = ent->size[1];
196 fbSize = ent->size[0];
197 }
198 else if(ent->move_angles[1] == 90 || ent->move_angles[1] == 270)
199 {
200 lrSize = ent->size[0];
201 fbSize = ent->size[1];
202 }
203 else
204 {
205 gi.dprintf("Secret door not at 0,90,180,270!\n");
206 }
207
208 if(ent->spawnflags & SEC_MOVE_FORWARD)
209 VectorScale(forward, fbSize, forward);
210 else
211 {
212 VectorScale(forward, fbSize * -1 , forward);
213 }
214
215 if(ent->spawnflags & SEC_MOVE_RIGHT)
216 VectorScale(right, lrSize, right);
217 else
218 {
219 VectorScale(right, lrSize * -1, right);
220 }
221
222 if(ent->spawnflags & SEC_1ST_DOWN)
223 {
224 VectorAdd(ent->s.origin, forward, ent->moveinfo.start_origin);
225 VectorAdd(ent->moveinfo.start_origin, right, ent->moveinfo.end_origin);
226 }
227 else
228 {
229 VectorAdd(ent->s.origin, right, ent->moveinfo.start_origin);
230 VectorAdd(ent->moveinfo.start_origin, forward, ent->moveinfo.end_origin);
231 }
232
233 ent->touch = secret_touch;
234 ent->blocked = secret_blocked;
235 ent->use = fd_secret_use;
236 ent->moveinfo.speed = 50;
237 ent->moveinfo.accel = 50;
238 ent->moveinfo.decel = 50;
239
240 if (!ent->targetname || ent->spawnflags & SEC_YES_SHOOT)
241 {
242 ent->health = 1;
243 ent->max_health = ent->health;
244 ent->takedamage = DAMAGE_YES;
245 ent->die = fd_secret_killed;
246 }
247 if (!ent->wait)
248 ent->wait = 5; // 5 seconds before closing
249
250 gi.linkentity(ent);
251 }
252
253 // ==================================================
254
255 #define FWALL_START_ON 1
256
force_wall_think(edict_t * self)257 void force_wall_think(edict_t *self)
258 {
259 if(!self->wait)
260 {
261 gi.WriteByte (svc_temp_entity);
262 gi.WriteByte (TE_FORCEWALL);
263 gi.WritePosition (self->pos1);
264 gi.WritePosition (self->pos2);
265 gi.WriteByte (self->style);
266 gi.multicast (self->offset, MULTICAST_PVS);
267 }
268
269 self->think = force_wall_think;
270 self->nextthink = level.time + 0.1;
271 }
272
force_wall_use(edict_t * self,edict_t * other,edict_t * activator)273 void force_wall_use (edict_t *self, edict_t *other, edict_t *activator)
274 {
275 if(!self->wait)
276 {
277 self->wait = 1;
278 self->think = NULL;
279 self->nextthink = 0;
280 self->solid = SOLID_NOT;
281 gi.linkentity( self );
282 }
283 else
284 {
285 self->wait = 0;
286 self->think = force_wall_think;
287 self->nextthink = level.time + 0.1;
288 self->solid = SOLID_BSP;
289 KillBox(self); // Is this appropriate?
290 gi.linkentity (self);
291 }
292 }
293
294 /*QUAKED func_force_wall (1 0 1) ? start_on
295 A vertical particle force wall. Turns on and solid when triggered.
296 If someone is in the force wall when it turns on, they're telefragged.
297
298 start_on - forcewall begins activated. triggering will turn it off.
299 style - color of particles to use.
300 208: green, 240: red, 241: blue, 224: orange
301 */
SP_func_force_wall(edict_t * ent)302 void SP_func_force_wall(edict_t *ent)
303 {
304 gi.setmodel (ent, ent->model);
305
306 ent->offset[0] = (ent->absmax[0] + ent->absmin[0]) / 2;
307 ent->offset[1] = (ent->absmax[1] + ent->absmin[1]) / 2;
308 ent->offset[2] = (ent->absmax[2] + ent->absmin[2]) / 2;
309
310 ent->pos1[2] = ent->absmax[2];
311 ent->pos2[2] = ent->absmax[2];
312 if(ent->size[0] > ent->size[1])
313 {
314 ent->pos1[0] = ent->absmin[0];
315 ent->pos2[0] = ent->absmax[0];
316 ent->pos1[1] = ent->offset[1];
317 ent->pos2[1] = ent->offset[1];
318 }
319 else
320 {
321 ent->pos1[0] = ent->offset[0];
322 ent->pos2[0] = ent->offset[0];
323 ent->pos1[1] = ent->absmin[1];
324 ent->pos2[1] = ent->absmax[1];
325 }
326
327 if(!ent->style)
328 ent->style = 208;
329
330 ent->movetype = MOVETYPE_NONE;
331 ent->wait = 1;
332
333 if(ent->spawnflags & FWALL_START_ON)
334 {
335 ent->solid = SOLID_BSP;
336 ent->think = force_wall_think;
337 ent->nextthink = level.time + 0.1;
338 }
339 else
340 ent->solid = SOLID_NOT;
341
342 ent->use = force_wall_use;
343
344 ent->svflags = SVF_NOCLIENT;
345
346 gi.linkentity(ent);
347 }
348