1 /*
2 ==============================================================================
3 
4 chick
5 
6 ==============================================================================
7 */
8 
9 #include "g_local.h"
10 #include "m_chick.h"
11 
12 // ROGUE
13 #define LEAD_TARGET		1
14 // ROGUE
15 
16 qboolean visible (edict_t *self, edict_t *other);
17 
18 void chick_stand (edict_t *self);
19 void chick_run (edict_t *self);
20 void chick_reslash(edict_t *self);
21 void chick_rerocket(edict_t *self);
22 void chick_attack1(edict_t *self);
23 
24 static int	sound_missile_prelaunch;
25 static int	sound_missile_launch;
26 static int	sound_melee_swing;
27 static int	sound_melee_hit;
28 static int	sound_missile_reload;
29 static int	sound_death1;
30 static int	sound_death2;
31 static int	sound_fall_down;
32 static int	sound_idle1;
33 static int	sound_idle2;
34 static int	sound_pain1;
35 static int	sound_pain2;
36 static int	sound_pain3;
37 static int	sound_sight;
38 static int	sound_search;
39 
ChickMoan(edict_t * self)40 void ChickMoan (edict_t *self)
41 {
42 	if (random() < 0.5)
43 		gi.sound (self, CHAN_VOICE, sound_idle1, 1, ATTN_IDLE, 0);
44 	else
45 		gi.sound (self, CHAN_VOICE, sound_idle2, 1, ATTN_IDLE, 0);
46 }
47 
48 mframe_t chick_frames_fidget [] =
49 {
50 	ai_stand, 0,  NULL,
51 	ai_stand, 0,  NULL,
52 	ai_stand, 0,  NULL,
53 	ai_stand, 0,  NULL,
54 	ai_stand, 0,  NULL,
55 	ai_stand, 0,  NULL,
56 	ai_stand, 0,  NULL,
57 	ai_stand, 0,  NULL,
58 	ai_stand, 0,  ChickMoan,
59 	ai_stand, 0,  NULL,
60 	ai_stand, 0,  NULL,
61 	ai_stand, 0,  NULL,
62 	ai_stand, 0,  NULL,
63 	ai_stand, 0,  NULL,
64 	ai_stand, 0,  NULL,
65 	ai_stand, 0,  NULL,
66 	ai_stand, 0,  NULL,
67 	ai_stand, 0,  NULL,
68 	ai_stand, 0,  NULL,
69 	ai_stand, 0,  NULL,
70 	ai_stand, 0,  NULL,
71 	ai_stand, 0,  NULL,
72 	ai_stand, 0,  NULL,
73 	ai_stand, 0,  NULL,
74 	ai_stand, 0,  NULL,
75 	ai_stand, 0,  NULL,
76 	ai_stand, 0,  NULL,
77 	ai_stand, 0,  NULL,
78 	ai_stand, 0,  NULL,
79 	ai_stand, 0,  NULL
80 };
81 mmove_t chick_move_fidget = {FRAME_stand201, FRAME_stand230, chick_frames_fidget, chick_stand};
82 
chick_fidget(edict_t * self)83 void chick_fidget (edict_t *self)
84 {
85 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
86 		return;
87 	if (random() <= 0.3)
88 		self->monsterinfo.currentmove = &chick_move_fidget;
89 }
90 
91 mframe_t chick_frames_stand [] =
92 {
93 	ai_stand, 0, NULL,
94 	ai_stand, 0, NULL,
95 	ai_stand, 0, NULL,
96 	ai_stand, 0, NULL,
97 	ai_stand, 0, NULL,
98 	ai_stand, 0, NULL,
99 	ai_stand, 0, NULL,
100 	ai_stand, 0, NULL,
101 	ai_stand, 0, NULL,
102 	ai_stand, 0, NULL,
103 	ai_stand, 0, NULL,
104 	ai_stand, 0, NULL,
105 	ai_stand, 0, NULL,
106 	ai_stand, 0, NULL,
107 	ai_stand, 0, NULL,
108 	ai_stand, 0, NULL,
109 	ai_stand, 0, NULL,
110 	ai_stand, 0, NULL,
111 	ai_stand, 0, NULL,
112 	ai_stand, 0, NULL,
113 	ai_stand, 0, NULL,
114 	ai_stand, 0, NULL,
115 	ai_stand, 0, NULL,
116 	ai_stand, 0, NULL,
117 	ai_stand, 0, NULL,
118 	ai_stand, 0, NULL,
119 	ai_stand, 0, NULL,
120 	ai_stand, 0, NULL,
121 	ai_stand, 0, NULL,
122 	ai_stand, 0, chick_fidget,
123 
124 };
125 mmove_t chick_move_stand = {FRAME_stand101, FRAME_stand130, chick_frames_stand, NULL};
126 
chick_stand(edict_t * self)127 void chick_stand (edict_t *self)
128 {
129 	self->monsterinfo.currentmove = &chick_move_stand;
130 }
131 
132 mframe_t chick_frames_start_run [] =
133 {
134 	ai_run, 1,  NULL,
135 	ai_run, 0,  NULL,
136 	ai_run, 0,	 NULL,
137 	ai_run, -1, NULL,
138 	ai_run, -1, NULL,
139 	ai_run, 0,  NULL,
140 	ai_run, 1,  NULL,
141 	ai_run, 3,  NULL,
142 	ai_run, 6,	 NULL,
143 	ai_run, 3,	 NULL
144 };
145 mmove_t chick_move_start_run = {FRAME_walk01, FRAME_walk10, chick_frames_start_run, chick_run};
146 
147 mframe_t chick_frames_run [] =
148 {
149 	ai_run, 6,	NULL,
150 	ai_run, 8,  NULL,
151 	ai_run, 13, NULL,
152 	ai_run, 5,  monster_done_dodge,  // make sure to clear dodge bit
153 	ai_run, 7,  NULL,
154 	ai_run, 4,  NULL,
155 	ai_run, 11, NULL,
156 	ai_run, 5,  NULL,
157 	ai_run, 9,  NULL,
158 	ai_run, 7,  NULL
159 };
160 
161 mmove_t chick_move_run = {FRAME_walk11, FRAME_walk20, chick_frames_run, NULL};
162 
163 mframe_t chick_frames_walk [] =
164 {
165 	ai_walk, 6,	 NULL,
166 	ai_walk, 8,  NULL,
167 	ai_walk, 13, NULL,
168 	ai_walk, 5,  NULL,
169 	ai_walk, 7,  NULL,
170 	ai_walk, 4,  NULL,
171 	ai_walk, 11, NULL,
172 	ai_walk, 5,  NULL,
173 	ai_walk, 9,  NULL,
174 	ai_walk, 7,  NULL
175 };
176 
177 mmove_t chick_move_walk = {FRAME_walk11, FRAME_walk20, chick_frames_walk, NULL};
178 
chick_walk(edict_t * self)179 void chick_walk (edict_t *self)
180 {
181 	self->monsterinfo.currentmove = &chick_move_walk;
182 }
183 
chick_run(edict_t * self)184 void chick_run (edict_t *self)
185 {
186 	monster_done_dodge (self);
187 
188 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
189 	{
190 		self->monsterinfo.currentmove = &chick_move_stand;
191 		return;
192 	}
193 
194 	if (self->monsterinfo.currentmove == &chick_move_walk ||
195 		self->monsterinfo.currentmove == &chick_move_start_run)
196 	{
197 		self->monsterinfo.currentmove = &chick_move_run;
198 	}
199 	else
200 	{
201 		self->monsterinfo.currentmove = &chick_move_start_run;
202 	}
203 }
204 
205 mframe_t chick_frames_pain1 [] =
206 {
207 	ai_move, 0, NULL,
208 	ai_move, 0, NULL,
209 	ai_move, 0, NULL,
210 	ai_move, 0, NULL,
211 	ai_move, 0, NULL
212 };
213 mmove_t chick_move_pain1 = {FRAME_pain101, FRAME_pain105, chick_frames_pain1, chick_run};
214 
215 mframe_t chick_frames_pain2 [] =
216 {
217 	ai_move, 0, NULL,
218 	ai_move, 0, NULL,
219 	ai_move, 0, NULL,
220 	ai_move, 0, NULL,
221 	ai_move, 0, NULL
222 };
223 mmove_t chick_move_pain2 = {FRAME_pain201, FRAME_pain205, chick_frames_pain2, chick_run};
224 
225 mframe_t chick_frames_pain3 [] =
226 {
227 	ai_move, 0,		NULL,
228 	ai_move, 0,		NULL,
229 	ai_move, -6,	NULL,
230 	ai_move, 3,		NULL,
231 	ai_move, 11,	NULL,
232 	ai_move, 3,		NULL,
233 	ai_move, 0,		NULL,
234 	ai_move, 0,		NULL,
235 	ai_move, 4,		NULL,
236 	ai_move, 1,		NULL,
237 	ai_move, 0,		NULL,
238 	ai_move, -3,	NULL,
239 	ai_move, -4,	NULL,
240 	ai_move, 5,		NULL,
241 	ai_move, 7,		NULL,
242 	ai_move, -2,	NULL,
243 	ai_move, 3,		NULL,
244 	ai_move, -5,	NULL,
245 	ai_move, -2,	NULL,
246 	ai_move, -8,	NULL,
247 	ai_move, 2,		NULL
248 };
249 mmove_t chick_move_pain3 = {FRAME_pain301, FRAME_pain321, chick_frames_pain3, chick_run};
250 
chick_pain(edict_t * self,edict_t * other,float kick,int damage)251 void chick_pain (edict_t *self, edict_t *other, float kick, int damage)
252 {
253 	float	r;
254 
255 	monster_done_dodge(self);
256 
257 	if (self->health < (self->max_health / 2))
258 		self->s.skinnum = 1;
259 
260 	if (level.time < self->pain_debounce_time)
261 		return;
262 
263 	self->pain_debounce_time = level.time + 3;
264 
265 	r = random();
266 	if (r < 0.33)
267 		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
268 	else if (r < 0.66)
269 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
270 	else
271 		gi.sound (self, CHAN_VOICE, sound_pain3, 1, ATTN_NORM, 0);
272 
273 	if (skill->value == 3)
274 		return;		// no pain anims in nightmare
275 
276 	// PMM - clear this from blindfire
277 	self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
278 
279 	if (damage <= 10)
280 		self->monsterinfo.currentmove = &chick_move_pain1;
281 	else if (damage <= 25)
282 		self->monsterinfo.currentmove = &chick_move_pain2;
283 	else
284 		self->monsterinfo.currentmove = &chick_move_pain3;
285 
286 	// PMM - clear duck flag
287 	if (self->monsterinfo.aiflags & AI_DUCKED)
288 		monster_duck_up(self);
289 }
290 
chick_dead(edict_t * self)291 void chick_dead (edict_t *self)
292 {
293 	VectorSet (self->mins, -16, -16, 0);
294 	VectorSet (self->maxs, 16, 16, 16);
295 	self->movetype = MOVETYPE_TOSS;
296 	self->svflags |= SVF_DEADMONSTER;
297 	self->nextthink = 0;
298 	gi.linkentity (self);
299 }
300 
301 mframe_t chick_frames_death2 [] =
302 {
303 	ai_move, -6, NULL,
304 	ai_move, 0,  NULL,
305 	ai_move, -1,  NULL,
306 	ai_move, -5, NULL,
307 	ai_move, 0, NULL,
308 	ai_move, -1,  NULL,
309 	ai_move, -2,  NULL,
310 	ai_move, 1,  NULL,
311 	ai_move, 10, NULL,
312 	ai_move, 2,  NULL,
313 	ai_move, 3,  NULL,
314 	ai_move, 1,  NULL,
315 	ai_move, 2, NULL,
316 	ai_move, 0,  NULL,
317 	ai_move, 3,  NULL,
318 	ai_move, 3,  NULL,
319 	ai_move, 1,  NULL,
320 	ai_move, -3,  NULL,
321 	ai_move, -5, NULL,
322 	ai_move, 4, NULL,
323 	ai_move, 15, NULL,
324 	ai_move, 14, NULL,
325 	ai_move, 1, NULL
326 };
327 mmove_t chick_move_death2 = {FRAME_death201, FRAME_death223, chick_frames_death2, chick_dead};
328 
329 mframe_t chick_frames_death1 [] =
330 {
331 	ai_move, 0,  NULL,
332 	ai_move, 0,  NULL,
333 	ai_move, -7, NULL,
334 	ai_move, 4,  NULL,
335 	ai_move, 11, NULL,
336 	ai_move, 0,  NULL,
337 	ai_move, 0,  NULL,
338 	ai_move, 0,  NULL,
339 	ai_move, 0,  NULL,
340 	ai_move, 0,  NULL,
341 	ai_move, 0,  NULL,
342 	ai_move, 0,  NULL
343 
344 };
345 mmove_t chick_move_death1 = {FRAME_death101, FRAME_death112, chick_frames_death1, chick_dead};
346 
chick_die(edict_t * self,edict_t * inflictor,edict_t * attacker,int damage,vec3_t point)347 void chick_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
348 {
349 	int		n;
350 
351 // check for gib
352 	if (self->health <= self->gib_health)
353 	{
354 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
355 		for (n= 0; n < 2; n++)
356 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
357 		for (n= 0; n < 4; n++)
358 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
359 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
360 		self->deadflag = DEAD_DEAD;
361 		return;
362 	}
363 
364 	if (self->deadflag == DEAD_DEAD)
365 		return;
366 
367 // regular death
368 	self->deadflag = DEAD_DEAD;
369 	self->takedamage = DAMAGE_YES;
370 
371 	n = rand() % 2;
372 	if (n == 0)
373 	{
374 		self->monsterinfo.currentmove = &chick_move_death1;
375 		gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
376 	}
377 	else
378 	{
379 		self->monsterinfo.currentmove = &chick_move_death2;
380 		gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
381 	}
382 }
383 
384 // PMM - changes to duck code for new dodge
385 
386 mframe_t chick_frames_duck [] =
387 {
388 	ai_move, 0, monster_duck_down,
389 	ai_move, 1, NULL,
390 	ai_move, 4, monster_duck_hold,
391 	ai_move, -4,  NULL,
392 	ai_move, -5,  monster_duck_up,
393 	ai_move, 3, NULL,
394 	ai_move, 1,  NULL
395 };
396 mmove_t chick_move_duck = {FRAME_duck01, FRAME_duck07, chick_frames_duck, chick_run};
397 
398 /*
399 void chick_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
400 {
401 // begin orig code
402 	if (random() > 0.25)
403 		return;
404 
405 	if (!self->enemy)
406 		self->enemy = attacker;
407 
408 	self->monsterinfo.currentmove = &chick_move_duck;
409 // end
410 
411 	float	r;
412 	float	height;
413 	int		shooting = 0;
414 
415 	if (!self->enemy)
416 	{
417 		self->enemy = attacker;
418 		FoundTarget (self);
419 	}
420 
421 	// PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
422 	// seeing numbers like 13 and 14)
423 	if ((eta < 0.1) || (eta > 5))
424 		return;
425 
426 	r = random();
427 	if (r > (0.25*((skill->value)+1)))
428 		return;
429 
430 	if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
431 		(self->monsterinfo.currentmove == &chick_move_attack1))
432 	{
433 		shooting = 1;
434 	}
435 	if (self->monsterinfo.aiflags & AI_DODGING)
436 	{
437 		height = self->absmax[2];
438 	}
439 	else
440 	{
441 		height = self->absmax[2]-32-1;  // the -1 is because the absmax is s.origin + maxs + 1
442 	}
443 
444 	// check to see if it makes sense to duck
445 	if (tr->endpos[2] <= height)
446 	{
447 		vec3_t right, diff;
448 		if (shooting)
449 		{
450 			self->monsterinfo.attack_state = AS_SLIDING;
451 			return;
452 		}
453 		AngleVectors (self->s.angles, NULL, right, NULL);
454 		VectorSubtract (tr->endpos, self->s.origin, diff);
455 		if (DotProduct (right, diff) < 0)
456 		{
457 			self->monsterinfo.lefty = 1;
458 		}
459 		// if it doesn't sense to duck, try to strafe away
460 		monster_done_dodge (self);
461 		self->monsterinfo.currentmove = &chick_move_run;
462 		self->monsterinfo.attack_state = AS_SLIDING;
463 		return;
464 	}
465 
466 	if (skill->value == 0)
467 	{
468 		self->monsterinfo.currentmove = &chick_move_duck;
469 		// PMM - stupid dodge
470 		self->monsterinfo.duck_wait_time = level.time + eta + 1;
471 		self->monsterinfo.aiflags |= AI_DODGING;
472 		return;
473 	}
474 
475 	if (!shooting)
476 	{
477 		self->monsterinfo.currentmove = &chick_move_duck;
478 		self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
479 		self->monsterinfo.aiflags |= AI_DODGING;
480 	}
481 	return;
482 
483 }
484 */
ChickSlash(edict_t * self)485 void ChickSlash (edict_t *self)
486 {
487 	vec3_t	aim;
488 
489 	VectorSet (aim, MELEE_DISTANCE, self->mins[0], 10);
490 	gi.sound (self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
491 	fire_hit (self, aim, (10 + (rand() %6)), 100);
492 }
493 
494 
ChickRocket(edict_t * self)495 void ChickRocket (edict_t *self)
496 {
497 	vec3_t	forward, right;
498 	vec3_t	start;
499 	vec3_t	dir;
500 	vec3_t	vec;
501 	trace_t	trace;	// PMM - check target
502 	int		rocketSpeed;
503 	float	dist;
504 	// pmm - blindfire
505 	vec3_t	target;
506 	qboolean blindfire = false;
507 
508 	if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
509 		blindfire = true;
510 	else
511 		blindfire = false;
512 
513 	if(!self->enemy || !self->enemy->inuse)		//PGM
514 		return;									//PGM
515 
516 	AngleVectors (self->s.angles, forward, right, NULL);
517 	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_CHICK_ROCKET_1], forward, right, start);
518 
519 	rocketSpeed = 500 + (100 * skill->value);	// PGM rock & roll.... :)
520 
521 	// put a debug trail from start to endpoint, confirm that the start point is
522 	// correct for the trace
523 
524 	// PMM
525 	if (blindfire)
526 		VectorCopy (self->monsterinfo.blind_fire_target, target);
527 	else
528 		VectorCopy (self->enemy->s.origin, target);
529 	// pmm
530 //PGM
531 	// PMM - blindfire shooting
532 	if (blindfire)
533 	{
534 		VectorCopy (target, vec);
535 		VectorSubtract (vec, start, dir);
536 	}
537 	// pmm
538 	// don't shoot at feet if they're above where i'm shooting from.
539 	else if(random() < 0.33 || (start[2] < self->enemy->absmin[2]))
540 	{
541 //		gi.dprintf("normal shot\n");
542 		VectorCopy (target, vec);
543 		vec[2] += self->enemy->viewheight;
544 		VectorSubtract (vec, start, dir);
545 	}
546 	else
547 	{
548 //		gi.dprintf("shooting at feet!\n");
549 		VectorCopy (target, vec);
550 		vec[2] = self->enemy->absmin[2];
551 		VectorSubtract (vec, start, dir);
552 	}
553 //PGM
554 
555 //======
556 //PMM - lead target  (not when blindfiring)
557 	// 20, 35, 50, 65 chance of leading
558 	if((!blindfire) && ((random() < (0.2 + ((3 - skill->value) * 0.15)))))
559 	{
560 		float	time;
561 
562 //		gi.dprintf ("leading target\n");
563 		dist = VectorLength (dir);
564 		time = dist/rocketSpeed;
565 		VectorMA(vec, time, self->enemy->velocity, vec);
566 		VectorSubtract(vec, start, dir);
567 	}
568 //PMM - lead target
569 //======
570 
571 	VectorNormalize (dir);
572 
573 	// pmm blindfire doesn't check target (done in checkattack)
574 	// paranoia, make sure we're not shooting a target right next to us
575 	trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
576 	if (blindfire)
577 	{
578 		// blindfire has different fail criteria for the trace
579 		if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
580 			monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
581 		else
582 		{
583 			// geez, this is bad.  she's avoiding about 80% of her blindfires due to hitting things.
584 			// hunt around for a good shot
585 			// try shifting the target to the left a little (to help counter her large offset)
586 			VectorCopy (target, vec);
587 			VectorMA (vec, -10, right, vec);
588 			VectorSubtract(vec, start, dir);
589 			VectorNormalize (dir);
590 			trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
591 			if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
592 				monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
593 			else
594 			{
595 				// ok, that failed.  try to the right
596 				VectorCopy (target, vec);
597 				VectorMA (vec, 10, right, vec);
598 				VectorSubtract(vec, start, dir);
599 				VectorNormalize (dir);
600 				trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
601 				if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
602 					monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
603 //				else if ((g_showlogic) && (g_showlogic->value))
604 //					// ok, I give up
605 //					gi.dprintf ("chick avoiding blindfire shot\n");
606 			}
607 		}
608 	}
609 	else
610 	{
611 		trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
612 		if(trace.ent == self->enemy || trace.ent == world)
613 		{
614 			if(trace.fraction > 0.5 || (trace.ent && trace.ent->client))
615 				monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
616 	//		else
617 	//			gi.dprintf("didn't make it halfway to target...aborting\n");
618 		}
619 	}
620 }
621 
Chick_PreAttack1(edict_t * self)622 void Chick_PreAttack1 (edict_t *self)
623 {
624 	gi.sound (self, CHAN_VOICE, sound_missile_prelaunch, 1, ATTN_NORM, 0);
625 }
626 
ChickReload(edict_t * self)627 void ChickReload (edict_t *self)
628 {
629 	gi.sound (self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
630 }
631 
632 
633 mframe_t chick_frames_start_attack1 [] =
634 {
635 	ai_charge, 0,	Chick_PreAttack1,
636 	ai_charge, 0,	NULL,
637 	ai_charge, 0,	NULL,
638 	ai_charge, 4,	NULL,
639 	ai_charge, 0,	NULL,
640 	ai_charge, -3,  NULL,
641 	ai_charge, 3,	NULL,
642 	ai_charge, 5,	NULL,
643 	ai_charge, 7,	NULL,
644 	ai_charge, 0,	NULL,
645 	ai_charge, 0,	NULL,
646 	ai_charge, 0,	NULL,
647 	ai_charge, 0,	chick_attack1
648 };
649 mmove_t chick_move_start_attack1 = {FRAME_attak101, FRAME_attak113, chick_frames_start_attack1, NULL};
650 
651 
652 mframe_t chick_frames_attack1 [] =
653 {
654 	ai_charge, 19,	ChickRocket,
655 	ai_charge, -6,	NULL,
656 	ai_charge, -5,	NULL,
657 	ai_charge, -2,	NULL,
658 	ai_charge, -7,	NULL,
659 	ai_charge, 0,	NULL,
660 	ai_charge, 1,	NULL,
661 	ai_charge, 10,	ChickReload,
662 	ai_charge, 4,	NULL,
663 	ai_charge, 5,	NULL,
664 	ai_charge, 6,	NULL,
665 	ai_charge, 6,	NULL,
666 	ai_charge, 4,	NULL,
667 	ai_charge, 3,	chick_rerocket
668 
669 };
670 mmove_t chick_move_attack1 = {FRAME_attak114, FRAME_attak127, chick_frames_attack1, NULL};
671 
672 mframe_t chick_frames_end_attack1 [] =
673 {
674 	ai_charge, -3,	NULL,
675 	ai_charge, 0,	NULL,
676 	ai_charge, -6,	NULL,
677 	ai_charge, -4,	NULL,
678 	ai_charge, -2,  NULL
679 };
680 mmove_t chick_move_end_attack1 = {FRAME_attak128, FRAME_attak132, chick_frames_end_attack1, chick_run};
681 
chick_rerocket(edict_t * self)682 void chick_rerocket(edict_t *self)
683 {
684 	if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
685 	{
686 		self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
687 		self->monsterinfo.currentmove = &chick_move_end_attack1;
688 		return;
689 	}
690 	if (self->enemy->health > 0)
691 	{
692 		if (range (self, self->enemy) > RANGE_MELEE)
693 			if ( visible (self, self->enemy) )
694 				if (random() <= (0.6 + (0.05*((float)skill->value))))
695 				{
696 					self->monsterinfo.currentmove = &chick_move_attack1;
697 					return;
698 				}
699 	}
700 	self->monsterinfo.currentmove = &chick_move_end_attack1;
701 }
702 
chick_attack1(edict_t * self)703 void chick_attack1(edict_t *self)
704 {
705 	self->monsterinfo.currentmove = &chick_move_attack1;
706 }
707 
708 mframe_t chick_frames_slash [] =
709 {
710 	ai_charge, 1,	NULL,
711 	ai_charge, 7,	ChickSlash,
712 	ai_charge, -7,	NULL,
713 	ai_charge, 1,	NULL,
714 	ai_charge, -1,	NULL,
715 	ai_charge, 1,	NULL,
716 	ai_charge, 0,	NULL,
717 	ai_charge, 1,	NULL,
718 	ai_charge, -2,	chick_reslash
719 };
720 mmove_t chick_move_slash = {FRAME_attak204, FRAME_attak212, chick_frames_slash, NULL};
721 
722 mframe_t chick_frames_end_slash [] =
723 {
724 	ai_charge, -6,	NULL,
725 	ai_charge, -1,	NULL,
726 	ai_charge, -6,	NULL,
727 	ai_charge, 0,	NULL
728 };
729 mmove_t chick_move_end_slash = {FRAME_attak213, FRAME_attak216, chick_frames_end_slash, chick_run};
730 
731 
chick_reslash(edict_t * self)732 void chick_reslash(edict_t *self)
733 {
734 	if (self->enemy->health > 0)
735 	{
736 		if (range (self, self->enemy) == RANGE_MELEE)
737 			if (random() <= 0.9)
738 			{
739 				self->monsterinfo.currentmove = &chick_move_slash;
740 				return;
741 			}
742 			else
743 			{
744 				self->monsterinfo.currentmove = &chick_move_end_slash;
745 				return;
746 			}
747 	}
748 	self->monsterinfo.currentmove = &chick_move_end_slash;
749 }
750 
chick_slash(edict_t * self)751 void chick_slash(edict_t *self)
752 {
753 	self->monsterinfo.currentmove = &chick_move_slash;
754 }
755 
756 
757 mframe_t chick_frames_start_slash [] =
758 {
759 	ai_charge, 1,	NULL,
760 	ai_charge, 8,	NULL,
761 	ai_charge, 3,	NULL
762 };
763 mmove_t chick_move_start_slash = {FRAME_attak201, FRAME_attak203, chick_frames_start_slash, chick_slash};
764 
765 
766 
chick_melee(edict_t * self)767 void chick_melee(edict_t *self)
768 {
769 	self->monsterinfo.currentmove = &chick_move_start_slash;
770 }
771 
772 
chick_attack(edict_t * self)773 void chick_attack(edict_t *self)
774 {
775 	float r, chance;
776 
777 	monster_done_dodge (self);
778 
779 	// PMM
780 	if (self->monsterinfo.attack_state == AS_BLIND)
781 	{
782 		// setup shot probabilities
783 		if (self->monsterinfo.blind_fire_delay < 1.0)
784 			chance = 1.0;
785 		else if (self->monsterinfo.blind_fire_delay < 7.5)
786 			chance = 0.4;
787 		else
788 			chance = 0.1;
789 
790 		r = random();
791 
792 		// minimum of 2 seconds, plus 0-3, after the shots are done
793 		self->monsterinfo.blind_fire_delay += 4.0 + 1.5 + random();
794 
795 		// don't shoot at the origin
796 		if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
797 			return;
798 
799 		// don't shoot if the dice say not to
800 		if (r > chance)
801 		{
802 //			if ((g_showlogic) && (g_showlogic->value))
803 //				gi.dprintf ("blindfire - NO SHOT\n");
804 			return;
805 		}
806 
807 		// turn on manual steering to signal both manual steering and blindfire
808 		self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
809 		self->monsterinfo.currentmove = &chick_move_start_attack1;
810 		self->monsterinfo.attack_finished = level.time + 2*random();
811 		return;
812 	}
813 	// pmm
814 
815 	self->monsterinfo.currentmove = &chick_move_start_attack1;
816 }
817 
chick_sight(edict_t * self,edict_t * other)818 void chick_sight(edict_t *self, edict_t *other)
819 {
820 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
821 }
822 
823 //===========
824 //PGM
chick_blocked(edict_t * self,float dist)825 qboolean chick_blocked (edict_t *self, float dist)
826 {
827 	if(blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
828 		return true;
829 
830 	if(blocked_checkplat (self, dist))
831 		return true;
832 
833 	return false;
834 }
835 //PGM
836 //===========
837 
chick_duck(edict_t * self,float eta)838 void chick_duck (edict_t *self, float eta)
839 {
840 	if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
841 		(self->monsterinfo.currentmove == &chick_move_attack1))
842 	{
843 		// if we're shooting, and not on easy, don't dodge
844 		if (skill->value)
845 		{
846 			self->monsterinfo.aiflags &= ~AI_DUCKED;
847 			return;
848 		}
849 	}
850 
851 	if (skill->value == 0)
852 		// PMM - stupid dodge
853 		self->monsterinfo.duck_wait_time = level.time + eta + 1;
854 	else
855 		self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
856 
857 	// has to be done immediately otherwise she can get stuck
858 	monster_duck_down(self);
859 
860 	self->monsterinfo.nextframe = FRAME_duck01;
861 	self->monsterinfo.currentmove = &chick_move_duck;
862 	return;
863 }
864 
chick_sidestep(edict_t * self)865 void chick_sidestep (edict_t *self)
866 {
867 	if ((self->monsterinfo.currentmove == &chick_move_start_attack1) ||
868 		(self->monsterinfo.currentmove == &chick_move_attack1))
869 	{
870 		// if we're shooting, and not on easy, don't dodge
871 		if (skill->value)
872 		{
873 			self->monsterinfo.aiflags &= ~AI_DODGING;
874 			return;
875 		}
876 	}
877 
878 	if (self->monsterinfo.currentmove != &chick_move_run)
879 		self->monsterinfo.currentmove = &chick_move_run;
880 }
881 
882 /*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
883 */
SP_monster_chick(edict_t * self)884 void SP_monster_chick (edict_t *self)
885 {
886 	if (deathmatch->value)
887 	{
888 		G_FreeEdict (self);
889 		return;
890 	}
891 
892 	sound_missile_prelaunch	= gi.soundindex ("chick/chkatck1.wav");
893 	sound_missile_launch	= gi.soundindex ("chick/chkatck2.wav");
894 	sound_melee_swing		= gi.soundindex ("chick/chkatck3.wav");
895 	sound_melee_hit			= gi.soundindex ("chick/chkatck4.wav");
896 	sound_missile_reload	= gi.soundindex ("chick/chkatck5.wav");
897 	sound_death1			= gi.soundindex ("chick/chkdeth1.wav");
898 	sound_death2			= gi.soundindex ("chick/chkdeth2.wav");
899 	sound_fall_down			= gi.soundindex ("chick/chkfall1.wav");
900 	sound_idle1				= gi.soundindex ("chick/chkidle1.wav");
901 	sound_idle2				= gi.soundindex ("chick/chkidle2.wav");
902 	sound_pain1				= gi.soundindex ("chick/chkpain1.wav");
903 	sound_pain2				= gi.soundindex ("chick/chkpain2.wav");
904 	sound_pain3				= gi.soundindex ("chick/chkpain3.wav");
905 	sound_sight				= gi.soundindex ("chick/chksght1.wav");
906 	sound_search			= gi.soundindex ("chick/chksrch1.wav");
907 
908 	self->movetype = MOVETYPE_STEP;
909 	self->solid = SOLID_BBOX;
910 	self->s.modelindex = gi.modelindex ("models/monsters/bitch2/tris.md2");
911 	VectorSet (self->mins, -16, -16, 0);
912 	VectorSet (self->maxs, 16, 16, 56);
913 
914 	self->health = 175;
915 	self->gib_health = -70;
916 	self->mass = 200;
917 
918 	self->pain = chick_pain;
919 	self->die = chick_die;
920 
921 	self->monsterinfo.stand = chick_stand;
922 	self->monsterinfo.walk = chick_walk;
923 	self->monsterinfo.run = chick_run;
924 	// pmm
925 	self->monsterinfo.dodge = M_MonsterDodge;
926 	self->monsterinfo.duck = chick_duck;
927 	self->monsterinfo.unduck = monster_duck_up;
928 	self->monsterinfo.sidestep = chick_sidestep;
929 //	self->monsterinfo.dodge = chick_dodge;
930 	// pmm
931 	self->monsterinfo.attack = chick_attack;
932 	self->monsterinfo.melee = chick_melee;
933 	self->monsterinfo.sight = chick_sight;
934 	self->monsterinfo.blocked = chick_blocked;		// PGM
935 
936 	gi.linkentity (self);
937 
938 	self->monsterinfo.currentmove = &chick_move_stand;
939 	self->monsterinfo.scale = MODEL_SCALE;
940 
941 	// PMM
942 	self->monsterinfo.blindfire = true;
943 	// pmm
944 	walkmonster_start (self);
945 }
946 
947