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