mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
0d4e872ce9
Added plasma guards (monster_soldier_plasma_re and monster_soldier_plasma_sp) from LM Escape to missionpack DLL. Added Zaero items/weapons to missionpack DLL. Added support for Zaero doors to missionpack DLL. Fixed crash caused by killtargeting sentien (laser edict not freed) in missionpack DLL. Fixed bug with broken Rogue turrets in missionpack DLL. Fixed crash in g_combat.c->M_ReactToDamage() caused by attacker with NULL classname in missionpack DLL.
1036 lines
24 KiB
C
1036 lines
24 KiB
C
/*
|
|
==============================================================================
|
|
|
|
Makron -- Final Boss
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#include "g_local.h"
|
|
#include "m_boss32.h"
|
|
|
|
qboolean visible (edict_t *self, edict_t *other);
|
|
|
|
void MakronRailgun (edict_t *self);
|
|
void MakronSaveloc (edict_t *self);
|
|
void MakronHyperblaster (edict_t *self);
|
|
void makron_step_left (edict_t *self);
|
|
void makron_step_right (edict_t *self);
|
|
void makronBFG (edict_t *self);
|
|
void makron_dead (edict_t *self);
|
|
void SP_monster_makron_put (edict_t *self);
|
|
|
|
static int sound_pain4;
|
|
static int sound_pain5;
|
|
static int sound_pain6;
|
|
static int sound_death;
|
|
static int sound_step_left;
|
|
static int sound_step_right;
|
|
static int sound_attack_bfg;
|
|
static int sound_brainsplorch;
|
|
static int sound_prerailgun;
|
|
static int sound_popup;
|
|
static int sound_taunt1;
|
|
static int sound_taunt2;
|
|
static int sound_taunt3;
|
|
static int sound_hit;
|
|
|
|
void makron_taunt (edict_t *self)
|
|
{
|
|
float r;
|
|
|
|
r=random();
|
|
if (r <= 0.3)
|
|
gi.sound (self, CHAN_AUTO, sound_taunt1, 1, ATTN_NONE, 0);
|
|
else if (r <= 0.6)
|
|
gi.sound (self, CHAN_AUTO, sound_taunt2, 1, ATTN_NONE, 0);
|
|
else
|
|
gi.sound (self, CHAN_AUTO, sound_taunt3, 1, ATTN_NONE, 0);
|
|
}
|
|
|
|
//
|
|
// stand
|
|
//
|
|
|
|
mframe_t makron_frames_stand []=
|
|
{
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL, // 10
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL, // 20
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL, // 30
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL, // 40
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL, // 50
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL,
|
|
ai_stand, 0, NULL // 60
|
|
};
|
|
mmove_t makron_move_stand = {FRAME_stand201, FRAME_stand260, makron_frames_stand, NULL};
|
|
|
|
void makron_stand (edict_t *self)
|
|
{
|
|
self->monsterinfo.currentmove = &makron_move_stand;
|
|
}
|
|
|
|
mframe_t makron_frames_run [] =
|
|
{
|
|
ai_run, 3, makron_step_left,
|
|
ai_run, 12, NULL,
|
|
ai_run, 8, NULL,
|
|
ai_run, 8, NULL,
|
|
ai_run, 8, makron_step_right,
|
|
ai_run, 6, NULL,
|
|
ai_run, 12, NULL,
|
|
ai_run, 9, NULL,
|
|
ai_run, 6, NULL,
|
|
ai_run, 12, NULL
|
|
};
|
|
mmove_t makron_move_run = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
|
|
|
|
void makron_hit (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_AUTO, sound_hit, 1, ATTN_NONE,0);
|
|
}
|
|
|
|
void makron_popup (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_BODY, sound_popup, 1, ATTN_NONE,0);
|
|
}
|
|
|
|
void makron_step_left (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_BODY, sound_step_left, 1, ATTN_NORM,0);
|
|
}
|
|
|
|
void makron_step_right (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_BODY, sound_step_right, 1, ATTN_NORM,0);
|
|
}
|
|
|
|
void makron_brainsplorch (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, sound_brainsplorch, 1, ATTN_NORM,0);
|
|
}
|
|
|
|
void makron_prerailgun (edict_t *self)
|
|
{
|
|
gi.sound (self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM,0);
|
|
}
|
|
|
|
|
|
mframe_t makron_frames_walk [] =
|
|
{
|
|
ai_walk, 3, makron_step_left,
|
|
ai_walk, 12, NULL,
|
|
ai_walk, 8, NULL,
|
|
ai_walk, 8, NULL,
|
|
ai_walk, 8, makron_step_right,
|
|
ai_walk, 6, NULL,
|
|
ai_walk, 12, NULL,
|
|
ai_walk, 9, NULL,
|
|
ai_walk, 6, NULL,
|
|
ai_walk, 12, NULL
|
|
};
|
|
mmove_t makron_move_walk = {FRAME_walk204, FRAME_walk213, makron_frames_run, NULL};
|
|
|
|
void makron_walk (edict_t *self)
|
|
{
|
|
self->monsterinfo.currentmove = &makron_move_walk;
|
|
}
|
|
|
|
void makron_run (edict_t *self)
|
|
{
|
|
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
|
self->monsterinfo.currentmove = &makron_move_stand;
|
|
else
|
|
self->monsterinfo.currentmove = &makron_move_run;
|
|
}
|
|
|
|
mframe_t makron_frames_pain6 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 10
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, makron_popup,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 20
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, makron_taunt,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_pain6 = {FRAME_pain601, FRAME_pain627, makron_frames_pain6, makron_run};
|
|
|
|
mframe_t makron_frames_pain5 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_pain5 = {FRAME_pain501, FRAME_pain504, makron_frames_pain5, makron_run};
|
|
|
|
mframe_t makron_frames_pain4 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_pain4 = {FRAME_pain401, FRAME_pain404, makron_frames_pain4, makron_run};
|
|
|
|
mframe_t makron_frames_death2 [] =
|
|
{
|
|
ai_move, -15, NULL,
|
|
ai_move, 3, NULL,
|
|
ai_move, -12, NULL,
|
|
ai_move, 0, makron_step_left,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 10
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 11, NULL,
|
|
ai_move, 12, NULL,
|
|
ai_move, 11, makron_step_right,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 20
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 30
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 5, NULL,
|
|
ai_move, 7, NULL,
|
|
ai_move, 6, makron_step_left,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, -1, NULL,
|
|
ai_move, 2, NULL, // 40
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 50
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, -6, NULL,
|
|
ai_move, -4, NULL,
|
|
ai_move, -6, makron_step_right,
|
|
ai_move, -4, NULL,
|
|
ai_move, -4, makron_step_left,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 60
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, -2, NULL,
|
|
ai_move, -5, NULL,
|
|
ai_move, -3, makron_step_right,
|
|
ai_move, -8, NULL,
|
|
ai_move, -3, makron_step_left,
|
|
ai_move, -7, NULL,
|
|
ai_move, -4, NULL,
|
|
ai_move, -4, makron_step_right, // 70
|
|
ai_move, -6, NULL,
|
|
ai_move, -7, NULL,
|
|
ai_move, 0, makron_step_left,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL, // 80
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, -2, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 2, NULL,
|
|
ai_move, 0, NULL, // 90
|
|
ai_move, 27, makron_hit,
|
|
ai_move, 26, NULL,
|
|
ai_move, 0, makron_brainsplorch,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL // 95
|
|
};
|
|
mmove_t makron_move_death2 = {FRAME_death201, FRAME_death295, makron_frames_death2, makron_dead};
|
|
|
|
mframe_t makron_frames_death3 [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_death3 = {FRAME_death301, FRAME_death320, makron_frames_death3, NULL};
|
|
|
|
mframe_t makron_frames_sight [] =
|
|
{
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_sight= {FRAME_active01, FRAME_active13, makron_frames_sight, makron_run};
|
|
|
|
void makronBFG (edict_t *self)
|
|
{
|
|
vec3_t forward, right;
|
|
vec3_t start;
|
|
vec3_t dir;
|
|
vec3_t vec;
|
|
|
|
AngleVectors (self->s.angles, forward, right, NULL);
|
|
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_BFG], forward, right, start);
|
|
|
|
// Zaero add
|
|
if (EMPNukeCheck(self, start))
|
|
{
|
|
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
// end Zaero
|
|
|
|
VectorCopy (self->enemy->s.origin, vec);
|
|
vec[2] += self->enemy->viewheight;
|
|
|
|
// Lazarus fog reduction of accuracy
|
|
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
|
|
{
|
|
vec[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
}
|
|
|
|
VectorSubtract (vec, start, dir);
|
|
VectorNormalize (dir);
|
|
gi.sound (self, CHAN_VOICE, sound_attack_bfg, 1, ATTN_NORM, 0);
|
|
monster_fire_bfg (self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
|
|
}
|
|
|
|
|
|
mframe_t makron_frames_attack3 []=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, makronBFG,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_attack3 = {FRAME_attak301, FRAME_attak308, makron_frames_attack3, makron_run};
|
|
|
|
mframe_t makron_frames_attack4[]=
|
|
{
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, MakronHyperblaster, // fire
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_attack4 = {FRAME_attak401, FRAME_attak426, makron_frames_attack4, makron_run};
|
|
|
|
mframe_t makron_frames_attack5[]=
|
|
{
|
|
ai_charge, 0, makron_prerailgun,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, NULL,
|
|
ai_charge, 0, MakronSaveloc,
|
|
ai_move, 0, MakronRailgun, // Fire railgun
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL,
|
|
ai_move, 0, NULL
|
|
};
|
|
mmove_t makron_move_attack5 = {FRAME_attak501, FRAME_attak516, makron_frames_attack5, makron_run};
|
|
|
|
void MakronSaveloc (edict_t *self)
|
|
{
|
|
VectorCopy (self->enemy->s.origin, self->pos1); //save for aiming the shot
|
|
self->pos1[2] += self->enemy->viewheight;
|
|
}
|
|
|
|
// FIXME: He's not firing from the proper Z
|
|
void MakronRailgun (edict_t *self)
|
|
{
|
|
vec3_t start;
|
|
vec3_t dir;
|
|
vec3_t forward, right;
|
|
|
|
AngleVectors (self->s.angles, forward, right, NULL);
|
|
G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_MAKRON_RAILGUN_1], forward, right, start);
|
|
|
|
// Lazarus fog reduction of accuracy
|
|
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
|
|
{
|
|
self->pos1[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
self->pos1[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
self->pos1[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
}
|
|
|
|
// calc direction to where we targted
|
|
VectorSubtract (self->pos1, start, dir);
|
|
VectorNormalize (dir);
|
|
|
|
monster_fire_railgun (self, start, dir, 50, 100, MZ2_MAKRON_RAILGUN_1);
|
|
}
|
|
|
|
// FIXME: This is all wrong. He's not firing at the proper angles.
|
|
void MakronHyperblaster (edict_t *self)
|
|
{
|
|
vec3_t dir;
|
|
vec3_t vec;
|
|
vec3_t start;
|
|
vec3_t forward, right;
|
|
int flash_number;
|
|
|
|
flash_number = MZ2_MAKRON_BLASTER_1 + (self->s.frame - FRAME_attak405);
|
|
|
|
AngleVectors (self->s.angles, forward, right, NULL);
|
|
G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
|
|
|
|
if (self->enemy)
|
|
{
|
|
VectorCopy (self->enemy->s.origin, vec);
|
|
vec[2] += self->enemy->viewheight;
|
|
// Lazarus fog reduction of accuracy
|
|
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
|
|
{
|
|
vec[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
vec[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
|
|
}
|
|
VectorSubtract (vec, start, vec);
|
|
vectoangles (vec, vec);
|
|
dir[0] = vec[0];
|
|
}
|
|
else
|
|
{
|
|
dir[0] = 0;
|
|
}
|
|
if (self->s.frame <= FRAME_attak413)
|
|
dir[1] = self->s.angles[1] - 10 * (self->s.frame - FRAME_attak413);
|
|
else
|
|
dir[1] = self->s.angles[1] + 10 * (self->s.frame - FRAME_attak421);
|
|
dir[2] = 0;
|
|
|
|
AngleVectors (dir, forward, NULL, NULL);
|
|
|
|
monster_fire_blaster (self, start, forward, 15, 1000, MZ2_MAKRON_BLASTER_1, EF_BLASTER, BLASTER_ORANGE);
|
|
}
|
|
|
|
|
|
void makron_pain (edict_t *self, edict_t *other, float kick, int damage)
|
|
{
|
|
if (self->health < (self->max_health / 2))
|
|
{
|
|
self->s.skinnum |= 1;
|
|
if (!(self->fogclip & 2)) // custom bloodtype flag check
|
|
self->blood_type = 3; // sparks and blood
|
|
}
|
|
|
|
if (level.time < self->pain_debounce_time)
|
|
return;
|
|
|
|
// Lessen the chance of him going into his pain frames
|
|
if (damage <=25)
|
|
if (random()<0.2)
|
|
return;
|
|
|
|
self->pain_debounce_time = level.time + 3;
|
|
if (skill->value == 3)
|
|
return; // no pain anims in nightmare
|
|
|
|
|
|
if (damage <= 40)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, sound_pain4, 1, ATTN_NONE,0);
|
|
self->monsterinfo.currentmove = &makron_move_pain4;
|
|
}
|
|
else if (damage <= 110)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, sound_pain5, 1, ATTN_NONE,0);
|
|
self->monsterinfo.currentmove = &makron_move_pain5;
|
|
}
|
|
else if (damage <= 150)
|
|
{
|
|
if (random() <= 0.45)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
|
|
self->monsterinfo.currentmove = &makron_move_pain6;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (random() <= 0.35)
|
|
{
|
|
gi.sound (self, CHAN_VOICE, sound_pain6, 1, ATTN_NONE,0);
|
|
self->monsterinfo.currentmove = &makron_move_pain6;
|
|
}
|
|
}
|
|
}
|
|
|
|
void makron_sight(edict_t *self, edict_t *other)
|
|
{
|
|
self->monsterinfo.currentmove = &makron_move_sight;
|
|
}
|
|
|
|
void makron_attack(edict_t *self)
|
|
{
|
|
vec3_t vec;
|
|
float range;
|
|
float r;
|
|
|
|
r = random();
|
|
|
|
VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
|
|
range = VectorLength (vec);
|
|
|
|
//Knightmare- gross hack for map6 of COS3- no BFG attack
|
|
if (Q_stricmp(level.mapname, "grinsp3f") == 0)
|
|
{
|
|
if (r <= 0.5)
|
|
self->monsterinfo.currentmove = &makron_move_attack4;
|
|
else
|
|
self->monsterinfo.currentmove = &makron_move_attack5;
|
|
}
|
|
else
|
|
{
|
|
if (r <= 0.3)
|
|
self->monsterinfo.currentmove = &makron_move_attack3;
|
|
else if (r <= 0.6)
|
|
self->monsterinfo.currentmove = &makron_move_attack4;
|
|
else
|
|
self->monsterinfo.currentmove = &makron_move_attack5;
|
|
}
|
|
}
|
|
|
|
/*
|
|
---
|
|
Makron Torso. This needs to be spawned in
|
|
---
|
|
*/
|
|
|
|
void makron_torso_think (edict_t *self)
|
|
{
|
|
if (++self->s.frame < 365)
|
|
self->nextthink = level.time + FRAMETIME;
|
|
else
|
|
{
|
|
self->s.frame = 346;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
}
|
|
}
|
|
|
|
void makron_torso (edict_t *ent)
|
|
{
|
|
ent->movetype = MOVETYPE_NONE;
|
|
ent->solid = SOLID_NOT;
|
|
VectorSet (ent->mins, -8, -8, 0);
|
|
VectorSet (ent->maxs, 8, 8, 8);
|
|
ent->s.frame = 346;
|
|
ent->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
|
|
ent->think = makron_torso_think;
|
|
ent->nextthink = level.time + 2 * FRAMETIME;
|
|
ent->s.sound = gi.soundindex ("makron/spine.wav");
|
|
gi.linkentity (ent);
|
|
}
|
|
|
|
|
|
//
|
|
// death
|
|
//
|
|
|
|
void makron_dead (edict_t *self)
|
|
{
|
|
VectorSet (self->mins, -60, -60, 0);
|
|
VectorSet (self->maxs, 60, 60, 72);
|
|
self->movetype = MOVETYPE_TOSS;
|
|
self->svflags |= SVF_DEADMONSTER;
|
|
self->nextthink = 0;
|
|
gi.linkentity (self);
|
|
M_FlyCheck (self);
|
|
}
|
|
|
|
|
|
void makron_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
{
|
|
edict_t *tempent;
|
|
|
|
int n;
|
|
|
|
self->s.sound = 0;
|
|
self->s.skinnum |= 1;
|
|
if (!(self->fogclip & 2)) //custom bloodtype flag check
|
|
self->blood_type = 3; //sparks and blood
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
|
|
|
|
// check for gib
|
|
if (self->health <= self->gib_health && !(self->spawnflags & SF_MONSTER_NOGIB))
|
|
{
|
|
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
|
|
for (n= 0; n < 4 /*4*/; n++)
|
|
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
|
|
for (n= 0; n < 4; n++)
|
|
ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
|
|
ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
|
|
self->deadflag = DEAD_DEAD;
|
|
return;
|
|
}
|
|
|
|
if (self->deadflag == DEAD_DEAD)
|
|
return;
|
|
|
|
// regular death
|
|
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NONE, 0);
|
|
self->deadflag = DEAD_DEAD;
|
|
self->takedamage = DAMAGE_YES;
|
|
|
|
tempent = G_Spawn();
|
|
VectorCopy (self->s.origin, tempent->s.origin);
|
|
VectorCopy (self->s.angles, tempent->s.angles);
|
|
|
|
#ifdef KMQUAKE2_ENGINE_MOD
|
|
// If Makron was transparent, make the torso transparent
|
|
if (self->s.alpha)
|
|
tempent->s.alpha = self->s.alpha;
|
|
#endif
|
|
|
|
tempent->s.origin[1] -= 84;
|
|
makron_torso (tempent);
|
|
|
|
self->monsterinfo.currentmove = &makron_move_death2;
|
|
}
|
|
|
|
qboolean Makron_CheckAttack (edict_t *self)
|
|
{
|
|
vec3_t spot1, spot2;
|
|
vec3_t temp;
|
|
float chance;
|
|
trace_t tr;
|
|
qboolean enemy_infront;
|
|
int enemy_range;
|
|
float enemy_yaw;
|
|
|
|
if (self->enemy->health > 0)
|
|
{
|
|
// see if any entities are in the way of the shot
|
|
VectorCopy (self->s.origin, spot1);
|
|
spot1[2] += self->viewheight;
|
|
VectorCopy (self->enemy->s.origin, spot2);
|
|
spot2[2] += self->enemy->viewheight;
|
|
|
|
//Knightmare- don't shoot from behind a window
|
|
tr = gi.trace (spot1, NULL, NULL, spot2, self, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_WINDOW);
|
|
|
|
// do we have a clear shot?
|
|
if (tr.ent != self->enemy)
|
|
return false;
|
|
}
|
|
|
|
enemy_infront = infront(self, self->enemy);
|
|
enemy_range = range(self, self->enemy);
|
|
VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
|
|
enemy_yaw = vectoyaw(temp);
|
|
|
|
self->ideal_yaw = enemy_yaw;
|
|
|
|
|
|
// melee attack
|
|
if (enemy_range == RANGE_MELEE)
|
|
{
|
|
if (self->monsterinfo.melee)
|
|
self->monsterinfo.attack_state = AS_MELEE;
|
|
else
|
|
self->monsterinfo.attack_state = AS_MISSILE;
|
|
return true;
|
|
}
|
|
|
|
// missile attack
|
|
if (!self->monsterinfo.attack)
|
|
return false;
|
|
|
|
if (level.time < self->monsterinfo.attack_finished)
|
|
return false;
|
|
|
|
if (enemy_range == RANGE_FAR)
|
|
return false;
|
|
|
|
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
|
{
|
|
chance = 0.4;
|
|
}
|
|
else if (enemy_range == RANGE_MELEE)
|
|
{
|
|
chance = 0.8;
|
|
}
|
|
else if (enemy_range == RANGE_NEAR)
|
|
{
|
|
chance = 0.4;
|
|
}
|
|
else if (enemy_range == RANGE_MID)
|
|
{
|
|
chance = 0.2;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (random () < chance)
|
|
{
|
|
self->monsterinfo.attack_state = AS_MISSILE;
|
|
self->monsterinfo.attack_finished = level.time + 2*random();
|
|
return true;
|
|
}
|
|
|
|
if (self->flags & FL_FLY)
|
|
{
|
|
if (random() < 0.3)
|
|
self->monsterinfo.attack_state = AS_SLIDING;
|
|
else
|
|
self->monsterinfo.attack_state = AS_STRAIGHT;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// monster_makron
|
|
//
|
|
|
|
void MakronPrecache (void)
|
|
{
|
|
sound_pain4 = gi.soundindex ("makron/pain3.wav");
|
|
sound_pain5 = gi.soundindex ("makron/pain2.wav");
|
|
sound_pain6 = gi.soundindex ("makron/pain1.wav");
|
|
sound_death = gi.soundindex ("makron/death.wav");
|
|
sound_step_left = gi.soundindex ("makron/step1.wav");
|
|
sound_step_right = gi.soundindex ("makron/step2.wav");
|
|
sound_attack_bfg = gi.soundindex ("makron/bfg_fire.wav");
|
|
sound_brainsplorch = gi.soundindex ("makron/brain1.wav");
|
|
sound_prerailgun = gi.soundindex ("makron/rail_up.wav");
|
|
sound_popup = gi.soundindex ("makron/popup.wav");
|
|
sound_taunt1 = gi.soundindex ("makron/voice4.wav");
|
|
sound_taunt2 = gi.soundindex ("makron/voice3.wav");
|
|
sound_taunt3 = gi.soundindex ("makron/voice.wav");
|
|
sound_hit = gi.soundindex ("makron/bhit.wav");
|
|
|
|
gi.modelindex ("models/monsters/boss3/rider/tris.md2");
|
|
}
|
|
|
|
//===========
|
|
//PGM
|
|
qboolean Makron_blocked (edict_t *self, float dist)
|
|
{
|
|
if (blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
|
|
return true;
|
|
|
|
if (blocked_checkplat (self, dist))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
//PGM
|
|
//===========
|
|
|
|
/*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight GoodGuy NoGib
|
|
*/
|
|
//Knightmare- direct spawn function, sets nojump flag
|
|
void SP_monster_makron (edict_t *self)
|
|
{
|
|
self->fogclip |= 1;
|
|
SP_monster_makron_put (self);
|
|
}
|
|
|
|
void SP_monster_makron_put (edict_t *self)
|
|
{
|
|
if (deathmatch->value)
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
MakronPrecache ();
|
|
|
|
self->movetype = MOVETYPE_STEP;
|
|
self->solid = SOLID_BBOX;
|
|
|
|
// Lazarus: special purpose skins
|
|
if ( self->style )
|
|
{
|
|
PatchMonsterModel("models/monsters/boss3/rider/tris.md2");
|
|
self->s.skinnum = self->style * 2;
|
|
// self->style = 0; //clear for custom bloodtype flag
|
|
}
|
|
|
|
self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2");
|
|
VectorSet (self->mins, -30, -30, 0);
|
|
VectorSet (self->maxs, 30, 30, 90);
|
|
|
|
if (!self->health)
|
|
self->health = 3000 + 1000 * (skill->value);
|
|
if (coop->value)
|
|
self->health += 500 * (skill->value);
|
|
if (!self->gib_health)
|
|
self->gib_health = -800;
|
|
if (!self->mass)
|
|
self->mass = 500;
|
|
|
|
self->pain = makron_pain;
|
|
self->die = makron_die;
|
|
self->monsterinfo.stand = makron_stand;
|
|
self->monsterinfo.walk = makron_walk;
|
|
self->monsterinfo.run = makron_run;
|
|
self->monsterinfo.dodge = NULL;
|
|
self->monsterinfo.attack = makron_attack;
|
|
self->monsterinfo.melee = NULL;
|
|
//Knightmare- don't jump flag
|
|
if (self->fogclip & 1)
|
|
self->monsterinfo.sight = NULL;
|
|
else
|
|
self->monsterinfo.sight = makron_sight;
|
|
self->monsterinfo.checkattack = Makron_CheckAttack;
|
|
self->monsterinfo.blocked = Makron_blocked; //PGM
|
|
|
|
if (!self->blood_type)
|
|
self->blood_type = 2; //sparks
|
|
else
|
|
self->fogclip |= 2; //custom bloodtype flag
|
|
|
|
// Lazarus
|
|
if (self->powerarmor)
|
|
{
|
|
if (self->powerarmortype == 1)
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN;
|
|
else
|
|
self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
|
|
self->monsterinfo.power_armor_power = self->powerarmor;
|
|
}
|
|
|
|
self->common_name = "Makron";
|
|
|
|
gi.linkentity (self);
|
|
//Knightmare- nojump flag
|
|
if (self->fogclip & 1)
|
|
self->monsterinfo.currentmove = &makron_move_stand;
|
|
else
|
|
self->monsterinfo.currentmove = &makron_move_sight;
|
|
|
|
self->monsterinfo.scale = MODEL_SCALE;
|
|
|
|
walkmonster_start(self);
|
|
//PMM
|
|
//self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
|
|
//PMM
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
MakronSpawn
|
|
|
|
=================
|
|
*/
|
|
void MakronSpawn (edict_t *self)
|
|
{
|
|
vec3_t vec;
|
|
edict_t *player;
|
|
SP_monster_makron_put (self);
|
|
|
|
//Knightmare- gross hack for map6 of COS3- don't jump
|
|
if (Q_stricmp(level.mapname, "grinsp3f") == 0)
|
|
return;
|
|
// jump at player
|
|
player = level.sight_client;
|
|
if (!player)
|
|
return;
|
|
|
|
VectorSubtract (player->s.origin, self->s.origin, vec);
|
|
self->s.angles[YAW] = vectoyaw(vec);
|
|
VectorNormalize (vec);
|
|
VectorMA (vec3_origin, 400, vec, self->velocity);
|
|
self->velocity[2] = 200;
|
|
self->groundentity = NULL;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
MakronToss
|
|
|
|
Jorg is just about dead, so set up to launch Makron out
|
|
=================
|
|
*/
|
|
void MakronToss (edict_t *self)
|
|
{
|
|
edict_t *ent;
|
|
|
|
// Knightmare- make sure this only gets called once
|
|
if (self->fogclip & 1)
|
|
return;
|
|
|
|
self->fogclip |= 1;
|
|
ent = G_Spawn ();
|
|
ent->nextthink = level.time + 0.8;
|
|
ent->think = MakronSpawn;
|
|
ent->target = self->target;
|
|
// Knightmare- if Jorg was killed by a trigger_hurt, set nojump flag
|
|
if (self->fogclip & 4)
|
|
ent->fogclip |= 1;
|
|
|
|
#ifdef KMQUAKE2_ENGINE_MOD
|
|
// If the Jorg was transparent, make Makron transparent, too.
|
|
if (self->s.alpha)
|
|
ent->s.alpha = self->s.alpha;
|
|
#endif
|
|
|
|
VectorCopy (self->s.origin, ent->s.origin);
|
|
self->s.modelindex2 = 0; // Knightmare- remove Makron model from dead Jorg
|
|
}
|