1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 /*
21 ==============================================================================
22 
23 FLIPPER
24 
25 ==============================================================================
26 */
27 
28 #include "g_local.h"
29 #include "m_flipper.h"
30 
31 
32 static int	sound_chomp;
33 static int	sound_attack;
34 static int	sound_pain1;
35 static int	sound_pain2;
36 static int	sound_death;
37 static int	sound_idle;
38 static int	sound_search;
39 static int	sound_sight;
40 
41 
42 void flipper_stand (edict_t *self);
43 
44 mframe_t flipper_frames_stand [] =
45 {
46 	ai_stand, 0, NULL
47 };
48 
49 mmove_t	flipper_move_stand = {FRAME_flphor01, FRAME_flphor01, flipper_frames_stand, NULL};
50 
flipper_stand(edict_t * self)51 void flipper_stand (edict_t *self)
52 {
53 		self->monsterinfo.currentmove = &flipper_move_stand;
54 }
55 
56 #define FLIPPER_RUN_SPEED	24
57 
58 mframe_t flipper_frames_run [] =
59 {
60 	ai_run, FLIPPER_RUN_SPEED, NULL,	// 6
61 	ai_run, FLIPPER_RUN_SPEED, NULL,
62 	ai_run, FLIPPER_RUN_SPEED, NULL,
63 	ai_run, FLIPPER_RUN_SPEED, NULL,
64 	ai_run, FLIPPER_RUN_SPEED, NULL,	// 10
65 
66 	ai_run, FLIPPER_RUN_SPEED, NULL,
67 	ai_run, FLIPPER_RUN_SPEED, NULL,
68 	ai_run, FLIPPER_RUN_SPEED, NULL,
69 	ai_run, FLIPPER_RUN_SPEED, NULL,
70 	ai_run, FLIPPER_RUN_SPEED, NULL,
71 	ai_run, FLIPPER_RUN_SPEED, NULL,
72 	ai_run, FLIPPER_RUN_SPEED, NULL,
73 	ai_run, FLIPPER_RUN_SPEED, NULL,
74 	ai_run, FLIPPER_RUN_SPEED, NULL,
75 	ai_run, FLIPPER_RUN_SPEED, NULL,	// 20
76 
77 	ai_run, FLIPPER_RUN_SPEED, NULL,
78 	ai_run, FLIPPER_RUN_SPEED, NULL,
79 	ai_run, FLIPPER_RUN_SPEED, NULL,
80 	ai_run, FLIPPER_RUN_SPEED, NULL,
81 	ai_run, FLIPPER_RUN_SPEED, NULL,
82 	ai_run, FLIPPER_RUN_SPEED, NULL,
83 	ai_run, FLIPPER_RUN_SPEED, NULL,
84 	ai_run, FLIPPER_RUN_SPEED, NULL,
85 	ai_run, FLIPPER_RUN_SPEED, NULL		// 29
86 };
87 mmove_t flipper_move_run_loop = {FRAME_flpver06, FRAME_flpver29, flipper_frames_run, NULL};
88 
flipper_run_loop(edict_t * self)89 void flipper_run_loop (edict_t *self)
90 {
91 	self->monsterinfo.currentmove = &flipper_move_run_loop;
92 }
93 
94 mframe_t flipper_frames_run_start [] =
95 {
96 	ai_run, 8, NULL,
97 	ai_run, 8, NULL,
98 	ai_run, 8, NULL,
99 	ai_run, 8, NULL,
100 	ai_run, 8, NULL,
101 	ai_run, 8, NULL
102 };
103 mmove_t flipper_move_run_start = {FRAME_flpver01, FRAME_flpver06, flipper_frames_run_start, flipper_run_loop};
104 
flipper_run(edict_t * self)105 void flipper_run (edict_t *self)
106 {
107 	self->monsterinfo.currentmove = &flipper_move_run_start;
108 }
109 
110 /* Standard Swimming */
111 mframe_t flipper_frames_walk [] =
112 {
113 	ai_walk, 4, NULL,
114 	ai_walk, 4, NULL,
115 	ai_walk, 4, NULL,
116 	ai_walk, 4, NULL,
117 	ai_walk, 4, NULL,
118 	ai_walk, 4, NULL,
119 	ai_walk, 4, NULL,
120 	ai_walk, 4, NULL,
121 	ai_walk, 4, NULL,
122 	ai_walk, 4, NULL,
123 	ai_walk, 4, NULL,
124 	ai_walk, 4, NULL,
125 	ai_walk, 4, NULL,
126 	ai_walk, 4, NULL,
127 	ai_walk, 4, NULL,
128 	ai_walk, 4, NULL,
129 	ai_walk, 4, NULL,
130 	ai_walk, 4, NULL,
131 	ai_walk, 4, NULL,
132 	ai_walk, 4, NULL,
133 	ai_walk, 4, NULL,
134 	ai_walk, 4, NULL,
135 	ai_walk, 4, NULL,
136 	ai_walk, 4, NULL
137 };
138 mmove_t flipper_move_walk = {FRAME_flphor01, FRAME_flphor24, flipper_frames_walk, NULL};
139 
flipper_walk(edict_t * self)140 void flipper_walk (edict_t *self)
141 {
142 	self->monsterinfo.currentmove = &flipper_move_walk;
143 }
144 
145 mframe_t flipper_frames_start_run [] =
146 {
147 	ai_run, 8, NULL,
148 	ai_run, 8, NULL,
149 	ai_run, 8, NULL,
150 	ai_run, 8, NULL,
151 	ai_run, 8, flipper_run
152 };
153 mmove_t flipper_move_start_run = {FRAME_flphor01, FRAME_flphor05, flipper_frames_start_run, NULL};
154 
flipper_start_run(edict_t * self)155 void flipper_start_run (edict_t *self)
156 {
157 	self->monsterinfo.currentmove = &flipper_move_start_run;
158 }
159 
160 mframe_t flipper_frames_pain2 [] =
161 {
162 	ai_move, 0, NULL,
163 	ai_move, 0, NULL,
164 	ai_move, 0,	NULL,
165 	ai_move, 0,	NULL,
166 	ai_move, 0, NULL
167 };
168 mmove_t flipper_move_pain2 = {FRAME_flppn101, FRAME_flppn105, flipper_frames_pain2, flipper_run};
169 
170 mframe_t flipper_frames_pain1 [] =
171 {
172 	ai_move, 0, NULL,
173 	ai_move, 0, NULL,
174 	ai_move, 0,	NULL,
175 	ai_move, 0,	NULL,
176 	ai_move, 0, NULL
177 };
178 mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_frames_pain1, flipper_run};
179 
flipper_bite(edict_t * self)180 void flipper_bite (edict_t *self)
181 {
182 	vec3_t	aim;
183 
184 	VectorSet (aim, MELEE_DISTANCE, 0, 0);
185 	fire_hit (self, aim, 5, 0);
186 }
187 
flipper_preattack(edict_t * self)188 void flipper_preattack (edict_t *self)
189 {
190 	gi.sound (self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
191 }
192 
193 mframe_t flipper_frames_attack [] =
194 {
195 	ai_charge, 0,	flipper_preattack,
196 	ai_charge, 0,	NULL,
197 	ai_charge, 0,	NULL,
198 	ai_charge, 0,	NULL,
199 	ai_charge, 0,	NULL,
200 	ai_charge, 0,	NULL,
201 	ai_charge, 0,	NULL,
202 	ai_charge, 0,	NULL,
203 	ai_charge, 0,	NULL,
204 	ai_charge, 0,	NULL,
205 	ai_charge, 0,	NULL,
206 	ai_charge, 0,	NULL,
207 	ai_charge, 0,	NULL,
208 	ai_charge, 0,	flipper_bite,
209 	ai_charge, 0,	NULL,
210 	ai_charge, 0,	NULL,
211 	ai_charge, 0,	NULL,
212 	ai_charge, 0,	NULL,
213 	ai_charge, 0,	flipper_bite,
214 	ai_charge, 0,	NULL
215 };
216 mmove_t flipper_move_attack = {FRAME_flpbit01, FRAME_flpbit20, flipper_frames_attack, flipper_run};
217 
flipper_melee(edict_t * self)218 void flipper_melee(edict_t *self)
219 {
220 	self->monsterinfo.currentmove = &flipper_move_attack;
221 }
222 
flipper_pain(edict_t * self,edict_t * other,float kick,int damage)223 void flipper_pain (edict_t *self, edict_t *other, float kick, int damage)
224 {
225 	int		n;
226 
227 	if (self->health < (self->max_health / 2))
228 		self->s.skinnum = 1;
229 
230 	if (level.time < self->pain_debounce_time)
231 		return;
232 
233 	self->pain_debounce_time = level.time + 3;
234 
235 	if (skill->value == 3)
236 		return;		// no pain anims in nightmare
237 
238 	n = (rand() + 1) % 2;
239 	if (n == 0)
240 	{
241 		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
242 		self->monsterinfo.currentmove = &flipper_move_pain1;
243 	}
244 	else
245 	{
246 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
247 		self->monsterinfo.currentmove = &flipper_move_pain2;
248 	}
249 }
250 
flipper_dead(edict_t * self)251 void flipper_dead (edict_t *self)
252 {
253 	VectorSet (self->mins, -16, -16, -24);
254 	VectorSet (self->maxs, 16, 16, -8);
255 	self->movetype = MOVETYPE_TOSS;
256 	self->svflags |= SVF_DEADMONSTER;
257 	self->nextthink = 0;
258 	gi.linkentity (self);
259 }
260 
261 mframe_t flipper_frames_death [] =
262 {
263 	ai_move, 0,	 NULL,
264 	ai_move, 0,	 NULL,
265 	ai_move, 0,	 NULL,
266 	ai_move, 0,	 NULL,
267 	ai_move, 0,	 NULL,
268 	ai_move, 0,	 NULL,
269 	ai_move, 0,	 NULL,
270 	ai_move, 0,	 NULL,
271 	ai_move, 0,	 NULL,
272 	ai_move, 0,	 NULL,
273 
274 	ai_move, 0,	 NULL,
275 	ai_move, 0,	 NULL,
276 	ai_move, 0,	 NULL,
277 	ai_move, 0,	 NULL,
278 	ai_move, 0,	 NULL,
279 	ai_move, 0,	 NULL,
280 	ai_move, 0,	 NULL,
281 	ai_move, 0,	 NULL,
282 	ai_move, 0,	 NULL,
283 	ai_move, 0,	 NULL,
284 
285 	ai_move, 0,	 NULL,
286 	ai_move, 0,	 NULL,
287 	ai_move, 0,	 NULL,
288 	ai_move, 0,	 NULL,
289 	ai_move, 0,	 NULL,
290 	ai_move, 0,	 NULL,
291 	ai_move, 0,	 NULL,
292 	ai_move, 0,	 NULL,
293 	ai_move, 0,	 NULL,
294 	ai_move, 0,	 NULL,
295 
296 	ai_move, 0,	 NULL,
297 	ai_move, 0,	 NULL,
298 	ai_move, 0,	 NULL,
299 	ai_move, 0,	 NULL,
300 	ai_move, 0,	 NULL,
301 	ai_move, 0,	 NULL,
302 	ai_move, 0,	 NULL,
303 	ai_move, 0,	 NULL,
304 	ai_move, 0,	 NULL,
305 	ai_move, 0,	 NULL,
306 
307 	ai_move, 0,	 NULL,
308 	ai_move, 0,	 NULL,
309 	ai_move, 0,	 NULL,
310 	ai_move, 0,	 NULL,
311 	ai_move, 0,	 NULL,
312 	ai_move, 0,	 NULL,
313 	ai_move, 0,	 NULL,
314 	ai_move, 0,	 NULL,
315 	ai_move, 0,	 NULL,
316 	ai_move, 0,	 NULL,
317 
318 	ai_move, 0,	 NULL,
319 	ai_move, 0,	 NULL,
320 	ai_move, 0,	 NULL,
321 	ai_move, 0,	 NULL,
322 	ai_move, 0,	 NULL,
323 	ai_move, 0,	 NULL
324 };
325 mmove_t flipper_move_death = {FRAME_flpdth01, FRAME_flpdth56, flipper_frames_death, flipper_dead};
326 
flipper_sight(edict_t * self,edict_t * other)327 void flipper_sight (edict_t *self, edict_t *other)
328 {
329 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
330 }
331 
flipper_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)332 void flipper_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
333 {
334 	int		n;
335 
336 // check for gib
337 	if (self->health <= self->gib_health)
338 	{
339 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
340 		for (n= 0; n < 2; n++)
341 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
342 		for (n= 0; n < 2; n++)
343 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
344 		ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
345 		self->deadflag = DEAD_DEAD;
346 		return;
347 	}
348 
349 	if (self->deadflag == DEAD_DEAD)
350 		return;
351 
352 // regular death
353 	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
354 	self->deadflag = DEAD_DEAD;
355 	self->takedamage = DAMAGE_YES;
356 	self->monsterinfo.currentmove = &flipper_move_death;
357 }
358 
359 /*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
360 */
SP_monster_flipper(edict_t * self)361 void SP_monster_flipper (edict_t *self)
362 {
363 	if (deathmatch->value)
364 	{
365 		G_FreeEdict (self);
366 		return;
367 	}
368 
369 	sound_pain1		= gi.soundindex ("flipper/flppain1.wav");
370 	sound_pain2		= gi.soundindex ("flipper/flppain2.wav");
371 	sound_death		= gi.soundindex ("flipper/flpdeth1.wav");
372 	sound_chomp		= gi.soundindex ("flipper/flpatck1.wav");
373 	sound_attack	= gi.soundindex ("flipper/flpatck2.wav");
374 	sound_idle		= gi.soundindex ("flipper/flpidle1.wav");
375 	sound_search	= gi.soundindex ("flipper/flpsrch1.wav");
376 	sound_sight		= gi.soundindex ("flipper/flpsght1.wav");
377 
378 	self->movetype = MOVETYPE_STEP;
379 	self->solid = SOLID_BBOX;
380 	self->s.modelindex = gi.modelindex ("models/monsters/flipper/tris.md2");
381 	VectorSet (self->mins, -16, -16, 0);
382 	VectorSet (self->maxs, 16, 16, 32);
383 
384 	self->health = 50;
385 	self->gib_health = -30;
386 	self->mass = 100;
387 
388 	self->pain = flipper_pain;
389 	self->die = flipper_die;
390 
391 	self->monsterinfo.stand = flipper_stand;
392 	self->monsterinfo.walk = flipper_walk;
393 	self->monsterinfo.run = flipper_start_run;
394 	self->monsterinfo.melee = flipper_melee;
395 	self->monsterinfo.sight = flipper_sight;
396 
397 	gi.linkentity (self);
398 
399 	self->monsterinfo.currentmove = &flipper_move_stand;
400 	self->monsterinfo.scale = MODEL_SCALE;
401 
402 	swimmonster_start (self);
403 }
404