thirtyflightsofloving/missionpack/m_soldier.c
Knightmare66 0d4e872ce9 Added LMCTF / LM Escape plasma rifle to missionpack DLL.
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.
2020-08-09 02:45:19 -04:00

3475 lines
81 KiB
C

/*
==============================================================================
SOLDIER
==============================================================================
*/
#include "g_local.h"
#include "m_soldier.h"
//ROGUE
#define RUN_SHOOT 1
#define CHECK_TARGET 1
//ROGUE
static int sound_idle;
static int sound_sight1;
static int sound_sight2;
static int sound_pain_light;
static int sound_pain;
static int sound_pain_ss;
static int sound_death_light;
static int sound_death;
static int sound_death_ss;
static int sound_cock;
void soldier_duck_up (edict_t *self);
void soldier_start_charge (edict_t *self)
{
self->monsterinfo.aiflags |= AI_CHARGING;
}
void soldier_stop_charge (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_CHARGING;
}
void soldier_idle (edict_t *self)
{
if (!(self->spawnflags & SF_MONSTER_AMBUSH))
{
if (random() > 0.8)
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
}
void soldier_cock (edict_t *self)
{
if (self->s.frame == FRAME_stand322)
gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
else
gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
}
// STAND
void soldier_stand (edict_t *self);
mframe_t soldier_frames_stand1 [] =
{
ai_stand, 0, soldier_idle,
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,
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,
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
};
mmove_t soldier_move_stand1 = {FRAME_stand101, FRAME_stand130, soldier_frames_stand1, soldier_stand};
mframe_t soldier_frames_stand3 [] =
{
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,
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,
ai_stand, 0, NULL,
ai_stand, 0, soldier_cock,
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,
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
};
mmove_t soldier_move_stand3 = {FRAME_stand301, FRAME_stand339, soldier_frames_stand3, soldier_stand};
#if 0
mframe_t soldier_frames_stand4 [] =
{
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,
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,
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,
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,
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, 4, NULL,
ai_stand, 1, NULL,
ai_stand, -1, NULL,
ai_stand, -2, NULL,
ai_stand, 0, NULL,
ai_stand, 0, NULL
};
//mmove_t soldier_move_stand4 = {FRAME_stand401, FRAME_stand452, soldier_frames_stand4, NULL};
#endif
void soldier_stand (edict_t *self)
{
if ((self->monsterinfo.currentmove == &soldier_move_stand3) || (random() < 0.8))
self->monsterinfo.currentmove = &soldier_move_stand1;
else
self->monsterinfo.currentmove = &soldier_move_stand3;
}
//
// WALK
//
void soldier_walk1_random (edict_t *self)
{
if (random() > 0.1)
self->monsterinfo.nextframe = FRAME_walk101;
}
mframe_t soldier_frames_walk1 [] =
{
ai_walk, 3, NULL,
ai_walk, 6, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 1, NULL,
ai_walk, 6, NULL,
ai_walk, 5, NULL,
ai_walk, 3, NULL,
ai_walk, -1, soldier_walk1_random,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL
};
mmove_t soldier_move_walk1 = {FRAME_walk101, FRAME_walk133, soldier_frames_walk1, NULL};
mframe_t soldier_frames_walk2 [] =
{
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 9, NULL,
ai_walk, 8, NULL,
ai_walk, 5, NULL,
ai_walk, 1, NULL,
ai_walk, 3, NULL,
ai_walk, 7, NULL,
ai_walk, 6, NULL,
ai_walk, 7, NULL
};
mmove_t soldier_move_walk2 = {FRAME_walk209, FRAME_walk218, soldier_frames_walk2, NULL};
void soldier_walk (edict_t *self)
{
if (random() < 0.5)
self->monsterinfo.currentmove = &soldier_move_walk1;
else
self->monsterinfo.currentmove = &soldier_move_walk2;
}
//
// RUN
//
void soldier_run (edict_t *self);
mframe_t soldier_frames_start_run [] =
{
ai_run, 7, NULL,
ai_run, 5, NULL
};
mmove_t soldier_move_start_run = {FRAME_run01, FRAME_run02, soldier_frames_start_run, soldier_run};
#ifdef RUN_SHOOT
void soldier_fire (edict_t *self, int);
void soldier_fire_run (edict_t *self)
{
// if ( ((self->s.skinnum % 6) <= 1) && (self->enemy) && visible(self, self->enemy) )
if ( (self->skinnum <= 1) && (self->enemy) && visible(self, self->enemy) )
{
soldier_fire(self, 0);
}
}
#endif
mframe_t soldier_frames_run [] =
{
ai_run, 10, NULL,
ai_run, 11, monster_done_dodge,
ai_run, 11, NULL,
ai_run, 16, NULL,
ai_run, 10, NULL,
ai_run, 15, monster_done_dodge
};
mmove_t soldier_move_run = {FRAME_run03, FRAME_run08, soldier_frames_run, NULL};
void soldier_run (edict_t *self)
{
monster_done_dodge (self);
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
self->monsterinfo.currentmove = &soldier_move_stand1;
return;
}
if (self->monsterinfo.currentmove == &soldier_move_walk1 ||
self->monsterinfo.currentmove == &soldier_move_walk2 ||
self->monsterinfo.currentmove == &soldier_move_start_run)
{
self->monsterinfo.currentmove = &soldier_move_run;
}
else
{
self->monsterinfo.currentmove = &soldier_move_start_run;
}
}
//
// PAIN
//
mframe_t soldier_frames_pain1 [] =
{
ai_move, -3, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL
};
mmove_t soldier_move_pain1 = {FRAME_pain101, FRAME_pain105, soldier_frames_pain1, soldier_run};
mframe_t soldier_frames_pain2 [] =
{
ai_move, -13, NULL,
ai_move, -1, NULL,
ai_move, 2, NULL,
ai_move, 4, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL
};
mmove_t soldier_move_pain2 = {FRAME_pain201, FRAME_pain207, soldier_frames_pain2, soldier_run};
mframe_t soldier_frames_pain3 [] =
{
ai_move, -8, NULL,
ai_move, 10, NULL,
ai_move, -4, NULL,
ai_move, -1, NULL,
ai_move, -3, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 4, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL
};
mmove_t soldier_move_pain3 = {FRAME_pain301, FRAME_pain318, soldier_frames_pain3, soldier_run};
mframe_t soldier_frames_pain4 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -10, NULL,
ai_move, -6, NULL,
ai_move, 8, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 5, NULL,
ai_move, 2, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL
};
mmove_t soldier_move_pain4 = {FRAME_pain401, FRAME_pain417, soldier_frames_pain4, soldier_run};
void soldier_pain (edict_t *self, edict_t *other, float kick, int damage)
{
float r;
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum |= 1;
monster_done_dodge (self);
soldier_stop_charge(self);
// if we're blind firing, this needs to be turned off here
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
if (level.time < self->pain_debounce_time)
{
if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldier_move_pain1) || (self->monsterinfo.currentmove == &soldier_move_pain2) || (self->monsterinfo.currentmove == &soldier_move_pain3)))
{
// PMM - clear duck flag
if (self->monsterinfo.aiflags & AI_DUCKED)
monster_duck_up(self);
self->monsterinfo.currentmove = &soldier_move_pain4;
}
return;
}
self->pain_debounce_time = level.time + 3;
n = self->s.skinnum | 1;
if (n == 1)
gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
else if (n == 3)
gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
if (self->velocity[2] > 100)
{
// PMM - clear duck flag
if (self->monsterinfo.aiflags & AI_DUCKED)
monster_duck_up(self);
self->monsterinfo.currentmove = &soldier_move_pain4;
// self->monsterinfo.pausetime = 0;
return;
}
if (skill->value == 3)
return; // no pain anims in nightmare
r = random();
if (r < 0.33)
self->monsterinfo.currentmove = &soldier_move_pain1;
else if (r < 0.66)
self->monsterinfo.currentmove = &soldier_move_pain2;
else
self->monsterinfo.currentmove = &soldier_move_pain3;
// PMM - clear duck flag
if (self->monsterinfo.aiflags & AI_DUCKED)
monster_duck_up(self);
// self->monsterinfo.pausetime = 0;
}
//
// ATTACK
//
static int blaster_flash [] = {MZ2_SOLDIER_BLASTER_1, MZ2_SOLDIER_BLASTER_2, MZ2_SOLDIER_BLASTER_3, MZ2_SOLDIER_BLASTER_4, MZ2_SOLDIER_BLASTER_5, MZ2_SOLDIER_BLASTER_6, MZ2_SOLDIER_BLASTER_7, MZ2_SOLDIER_BLASTER_8};
static int shotgun_flash [] = {MZ2_SOLDIER_SHOTGUN_1, MZ2_SOLDIER_SHOTGUN_2, MZ2_SOLDIER_SHOTGUN_3, MZ2_SOLDIER_SHOTGUN_4, MZ2_SOLDIER_SHOTGUN_5, MZ2_SOLDIER_SHOTGUN_6, MZ2_SOLDIER_SHOTGUN_7, MZ2_SOLDIER_SHOTGUN_8};
static int machinegun_flash [] = {MZ2_SOLDIER_MACHINEGUN_1, MZ2_SOLDIER_MACHINEGUN_2, MZ2_SOLDIER_MACHINEGUN_3, MZ2_SOLDIER_MACHINEGUN_4, MZ2_SOLDIER_MACHINEGUN_5, MZ2_SOLDIER_MACHINEGUN_6, MZ2_SOLDIER_MACHINEGUN_7, MZ2_SOLDIER_MACHINEGUN_8};
//void soldier_fire (edict_t *self, int flash_number) PMM
void soldier_fire (edict_t *self, int in_flash_number)
{
vec3_t start;
vec3_t forward, right, up;
vec3_t aim;
vec3_t dir;
vec3_t end;
float r, u;
int flash_index;
int flash_number;
#ifdef RUN_SHOOT
vec3_t aim_norm;
float angle;
#endif
#ifdef CHECK_TARGET
trace_t tr;
vec3_t aim_good;
#endif
if ((!self->enemy) || (!self->enemy->inuse))
{
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
return;
}
if (in_flash_number < 0)
{
flash_number = -1 * in_flash_number;
}
else
flash_number = in_flash_number;
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
flash_index = blaster_flash[flash_number];
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
flash_index = shotgun_flash[flash_number];
else if (self->skinnum < 6)
flash_index = machinegun_flash[flash_number];
else // if (self->skinnum < 8)
flash_index = blaster_flash[flash_number];
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start);
if (flash_number == 5 || flash_number == 6) // he's dead
{
VectorCopy (forward, aim);
}
else
{
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
// Lazarus fog reduction of accuracy
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
{
end[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
end[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
end[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
}
VectorSubtract (end, start, aim);
#ifdef CHECK_TARGET
VectorCopy (end, aim_good);
#endif
#ifdef RUN_SHOOT
//PMM
if (in_flash_number < 0)
{
VectorCopy (aim, aim_norm);
VectorNormalize (aim_norm);
angle = DotProduct (aim_norm, forward);
//gi.dprintf ("Dot Product: %f", DotProduct (aim_norm, forward));
if (angle < 0.9) // ~25 degree angle
{
// if (g_showlogic && g_showlogic->value)
// gi.dprintf (" not firing due to bad dotprod %f\n", angle);
return;
}
// else
// {
// if (g_showlogic && g_showlogic->value)
// gi.dprintf (" firing: dotprod = %f\n", angle);
// }
}
//-PMM
#endif
vectoangles (aim, dir);
AngleVectors (dir, forward, right, up);
if (skill->value < 2)
{
r = crandom()*1000;
u = crandom()*500;
}
else
{
r = crandom()*500;
u = crandom()*250;
}
// Knightmare- adjust spread for expanded world size
#ifdef KMQUAKE2_ENGINE_MOD
r *= (WORLD_SIZE / 8192);
u *= (WORLD_SIZE / 8192);
#endif
VectorMA (start, WORLD_SIZE, forward, end); // was 8192
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
VectorSubtract (end, start, aim);
VectorNormalize (aim);
}
#ifdef CHECK_TARGET
if (!(flash_number == 5 || flash_number == 6)) // he's dead
{
tr = gi.trace (start, NULL, NULL, aim_good, self, MASK_SHOT);
if ((tr.ent != self->enemy) && (tr.ent != world))
{
// if (g_showlogic && g_showlogic->value)
// gi.dprintf ("infantry shot aborted due to bad target\n");
return;
}
}
#endif
// if ((self->s.skinnum % 6) <= 1)
if (self->skinnum <= 1)
{
monster_fire_blaster (self, start, aim, 5, 600, flash_index, EF_BLASTER, BLASTER_ORANGE);
}
// else if ((self->s.skinnum % 6) <= 3)
else if (self->skinnum <= 3)
{
monster_fire_shotgun (self, start, aim, 2, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SHOTGUN_COUNT, flash_index);
}
else if (self->skinnum <= 5)
{
// PMM - changed to wait from pausetime to not interfere with dodge code
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
self->wait = level.time + (3 + rand() % 8) * FRAMETIME;
monster_fire_bullet (self, start, aim, 2, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_index);
if (level.time >= self->wait)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
else // if (self->skinnum <= 7)
{
if (self->moreflags & FL2_WEAPON_ALT)
monster_fire_plasma_rifle (self, start, aim, PLASMA_SPREAD_DAMAGE, PLASMA_SPREAD_SPEED, flash_index, true);
else
monster_fire_plasma_rifle (self, start, aim, PLASMA_BOUNCE_DAMAGE, PLASMA_BOUNCE_SPEED, flash_index, false);
}
}
// ATTACK1 (blaster/shotgun)
void soldier_fire1 (edict_t *self)
{
soldier_fire (self, 0);
}
void soldier_attack1_refire1 (edict_t *self)
{
// PMM - blindfire
if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
{
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
return;
}
// pmm
if (!self->enemy)
return;
// if ((self->s.skinnum % 6) > 1)
if (self->skinnum > 1)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak102;
else
self->monsterinfo.nextframe = FRAME_attak110;
}
void soldier_attack1_refire2 (edict_t *self)
{
if (!self->enemy)
return;
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak102;
}
mframe_t soldier_frames_attack1 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_fire1,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_attack1_refire1,
ai_charge, 0, NULL,
ai_charge, 0, soldier_cock,
ai_charge, 0, soldier_attack1_refire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldier_move_attack1 = {FRAME_attak101, FRAME_attak112, soldier_frames_attack1, soldier_run};
// ATTACK2 (blaster/shotgun)
void soldier_fire2 (edict_t *self)
{
soldier_fire (self, 1);
}
void soldier_attack2_refire1 (edict_t *self)
{
if (!self->enemy)
return;
// if ((self->s.skinnum % 6) > 1)
if (self->skinnum > 1)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak204;
else
self->monsterinfo.nextframe = FRAME_attak216;
}
void soldier_attack2_refire2 (edict_t *self)
{
if (!self->enemy)
return;
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak204;
}
mframe_t soldier_frames_attack2 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_fire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_attack2_refire1,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_cock,
ai_charge, 0, NULL,
ai_charge, 0, soldier_attack2_refire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldier_move_attack2 = {FRAME_attak201, FRAME_attak218, soldier_frames_attack2, soldier_run};
// ATTACK3 (duck and shoot)
/*
void soldier_duck_down (edict_t *self)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("duck down - %d!\n", self->s.frame);
self->monsterinfo.aiflags |= AI_DUCKED;
// self->maxs[2] -= 32;
self->maxs[2] = self->monsterinfo.base_height - 32;
self->takedamage = DAMAGE_YES;
if (self->monsterinfo.duck_wait_time < level.time)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("soldier duck with no time!\n");
self->monsterinfo.duck_wait_time = level.time + 1;
}
gi.linkentity (self);
}
void soldier_duck_up (edict_t *self)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("duck up - %d!\n", self->s.frame);
self->monsterinfo.aiflags &= ~AI_DUCKED;
// self->maxs[2] += 32;
self->maxs[2] = self->monsterinfo.base_height;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
*/
void soldier_fire3 (edict_t *self)
{
monster_duck_down (self);
soldier_fire (self, 2);
}
void soldier_attack3_refire (edict_t *self)
{
if ((level.time + 0.4) < self->monsterinfo.duck_wait_time)
self->monsterinfo.nextframe = FRAME_attak303;
}
mframe_t soldier_frames_attack3 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_fire3,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_attack3_refire,
ai_charge, 0, monster_duck_up,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldier_move_attack3 = {FRAME_attak301, FRAME_attak309, soldier_frames_attack3, soldier_run};
// ATTACK4 (machinegun)
void soldier_fire4 (edict_t *self)
{
soldier_fire (self, 3);
//
// if (self->enemy->health <= 0)
// return;
//
// if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
// self->monsterinfo.nextframe = FRAME_attak402;
}
mframe_t soldier_frames_attack4 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_fire4,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldier_move_attack4 = {FRAME_attak401, FRAME_attak406, soldier_frames_attack4, soldier_run};
#if 0
// ATTACK5 (prone)
void soldier_fire5 (edict_t *self)
{
soldier_fire (self, 4);
}
void soldier_attack5_refire (edict_t *self)
{
if (!self->enemy)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak505;
}
mframe_t soldier_frames_attack5 [] =
{
ai_charge, 8, NULL,
ai_charge, 8, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_fire5,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldier_attack5_refire
};
//mmove_t soldier_move_attack5 = {FRAME_attak501, FRAME_attak508, soldier_frames_attack5, soldier_run};
#endif
// ATTACK6 (run & shoot)
void soldier_fire8 (edict_t *self)
{
soldier_fire (self, -7);
// self->monsterinfo.aiflags |= AI_HOLD_FRAME;
// self->monsterinfo.pausetime = level.time + 1000000;
}
void soldier_attack6_refire (edict_t *self)
{
// PMM - make sure dodge & charge bits are cleared
monster_done_dodge (self);
soldier_stop_charge (self);
if (!self->enemy)
return;
if (self->enemy->health <= 0)
return;
// if (range(self, self->enemy) < RANGE_MID)
if (range(self, self->enemy) < RANGE_NEAR)
return;
if ((skill->value == 3) || ((random() < (0.25*((float)skill->value)))))
self->monsterinfo.nextframe = FRAME_runs03;
}
mframe_t soldier_frames_attack6 [] =
{
// PMM
// ai_run, 10, NULL,
ai_run, 10, soldier_start_charge,
ai_run, 4, NULL,
ai_run, 12, soldier_fire8,
ai_run, 11, NULL,
ai_run, 13, monster_done_dodge,
ai_run, 18, NULL,
ai_run, 15, NULL,
ai_run, 14, NULL,
ai_run, 11, NULL,
ai_run, 8, NULL,
ai_run, 11, NULL,
ai_run, 12, NULL,
ai_run, 12, NULL,
ai_run, 17, soldier_attack6_refire
};
mmove_t soldier_move_attack6 = {FRAME_runs01, FRAME_runs14, soldier_frames_attack6, soldier_run};
void soldier_attack(edict_t *self)
{
float r, chance;
monster_done_dodge (self);
// PMM - blindfire!
if (self->monsterinfo.attack_state == AS_BLIND)
{
// setup shot probabilities
if (self->monsterinfo.blind_fire_delay < 1.0)
chance = 1.0;
else if (self->monsterinfo.blind_fire_delay < 7.5)
chance = 0.4;
else
chance = 0.1;
r = random();
// minimum of 2 seconds, plus 0-3, after the shots are done
self->monsterinfo.blind_fire_delay += 2.1 + 2.0 + random()*3.0;
// don't shoot at the origin
if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
return;
// don't shoot if the dice say not to
if (r > chance)
{
// if ((g_showlogic) && (g_showlogic->value))
// gi.dprintf ("blindfire - NO SHOT\n");
return;
}
// turn on manual steering to signal both manual steering and blindfire
self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
self->monsterinfo.currentmove = &soldier_move_attack1;
self->monsterinfo.attack_finished = level.time + 1.5 + random();
return;
}
// pmm
// PMM - added this so the soldiers now run toward you and shoot instead of just stopping and shooting
// if ((range(self, self->enemy) >= RANGE_MID) && (r < (skill->value*0.25) && ((self->s.skinnum % 6) <= 3)))
r = random();
if ( (!(self->monsterinfo.aiflags & (AI_BLOCKED|AI_STAND_GROUND))) &&
(range(self, self->enemy) >= RANGE_NEAR) &&
(r < (skill->value*0.25) &&
// ((self->s.skinnum % 6) <= 3)) )
(self->skinnum <= 3)) )
{
self->monsterinfo.currentmove = &soldier_move_attack6;
}
else
{
// if ((self->s.skinnum % 6) < 4)
if (self->skinnum < 4)
{
if (random() < 0.5)
{
self->monsterinfo.currentmove = &soldier_move_attack1;
}
else
{
self->monsterinfo.currentmove = &soldier_move_attack2;
}
}
else
{
self->monsterinfo.currentmove = &soldier_move_attack4;
}
}
}
//
// SIGHT
//
void soldier_sight (edict_t *self, edict_t *other)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
// if ((skill->value > 0) && (self->enemy) && (range(self, self->enemy) >= RANGE_MID))
if ((skill->value > 0) && (self->enemy) && (range(self, self->enemy) >= RANGE_NEAR))
{
// PMM - don't let machinegunners run & shoot
// if ((random() > 0.75) && ((self->s.skinnum % 6) <= 3))
if ((random() > 0.75) && (self->skinnum <= 3))
{
// if ((self->classname == "monster_soldier_ripper") || (self->classname == "monster_soldier_hypergun") || (self->classname == "monster_soldier_lasergun"))
// self->monsterinfo.currentmove = &soldierh_move_attack6;
// else
self->monsterinfo.currentmove = &soldier_move_attack6;
}
}
}
//
// DUCK
//
/*
void soldier_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.duck_wait_time)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
*/
mframe_t soldier_frames_duck [] =
{
ai_move, 5, monster_duck_down,
ai_move, -1, monster_duck_hold,
ai_move, 1, NULL,
ai_move, 0, monster_duck_up,
ai_move, 5, NULL
};
mmove_t soldier_move_duck = {FRAME_duck01, FRAME_duck05, soldier_frames_duck, soldier_run};
/*
void soldier_dodge (edict_t *self, edict_t *attacker, float eta, trace_t *tr)
{
//===========
//PMM - rogue rewrite of dodge code.
// lots o' changes in here. Basically, they now check the tr and see if ducking would help,
// and if it doesn't, they dodge like mad
float r = random();
float height;
if ((g_showlogic) && (g_showlogic->value))
{
if (self->monsterinfo.aiflags & AI_DODGING)
gi.dprintf ("dodging - ");
if (self->monsterinfo.aiflags & AI_DUCKED)
gi.dprintf ("ducked - ");
}
if (!self->enemy)
{
self->enemy = attacker;
FoundTarget (self);
}
// PMM - don't bother if it's going to hit anyway; fix for weird in-your-face etas (I was
// seeing numbers like 13 and 14)
if ((eta < 0.1) || (eta > 5))
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("timeout\n");
return;
}
// skill level determination..
if (r > (0.25*((skill->value)+1)))
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("skillout\n");
return;
}
// stop charging, since we're going to dodge (somehow) instead
soldier_stop_charge (self);
height = self->absmax[2]-32-1; // the -1 is because the absmax is s.origin + maxs + 1
// if we're ducking already, or the shot is at our knees
if ((tr->endpos[2] <= height) || (self->monsterinfo.aiflags & AI_DUCKED))
{
vec3_t right, diff;
// if we're already dodging, just finish the sequence, i.e. don't do anything else
if (self->monsterinfo.aiflags & AI_DODGING)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("already dodging\n");
return;
}
AngleVectors (self->s.angles, NULL, right, NULL);
VectorSubtract (tr->endpos, self->s.origin, diff);
if (DotProduct (right, diff) < 0)
{
self->monsterinfo.lefty = 1;
// gi.dprintf ("left\n");
} else {
// gi.dprintf ("right\n");
}
// if it doesn't sense to duck, try to strafe and shoot
// we don't want the machine gun guys running & shooting (looks bad)
// if we are currently ducked, unduck
if (self->monsterinfo.aiflags & AI_DUCKED)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("unducking - ");
soldier_duck_up(self);
}
self->monsterinfo.aiflags |= AI_DODGING;
self->monsterinfo.attack_state = AS_SLIDING;
// else if ((self->s.skinnum % 6) <= 3)
else if (self->skinnum <= 3)
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("shooting back!\n");
self->monsterinfo.currentmove = &soldier_move_attack6;
}
else
{
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("strafing away!\n");
self->monsterinfo.currentmove = &soldier_move_start_run;
}
return;
}
// if we're here, we're ducking, so clear the dodge bit if it's set
if ((g_showlogic) && (g_showlogic->value))
gi.dprintf ("ducking!\n");
if (skill->value == 0)
{
// set this prematurely; it doesn't hurt, and prevents extra iterations
self->monsterinfo.aiflags |= AI_DUCKED;
monster_done_dodge (self);
self->monsterinfo.currentmove = &soldier_move_duck;
// PMM - stupid dodge
self->monsterinfo.duck_wait_time = level.time + eta + 1;
return;
}
// PMM - since we're only ducking some of the time, this needs to be moved down below
// self->monsterinfo.duck_wait_time = level.time + eta + 0.3;
r = random();
// set this prematurely; it doesn't hurt, and prevents extra iterations
self->monsterinfo.aiflags |= AI_DUCKED;
monster_done_dodge (self);
if (r > (skill->value * 0.33))
{
self->monsterinfo.currentmove = &soldier_move_duck;
self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
// has to be done immediately otherwise he can get stuck
soldier_duck_down(self);
}
else
{
// has to be done immediately otherwise he can get stuck
soldier_duck_down(self);
self->monsterinfo.duck_wait_time = level.time + eta + 1;
self->monsterinfo.currentmove = &soldier_move_attack3;
self->monsterinfo.nextframe = FRAME_attak301;
}
return;
//PMM
//===========
}
*/
// pmm - blocking code
qboolean soldier_blocked (edict_t *self, float dist)
{
// don't do anything if you're dodging
if ((self->monsterinfo.aiflags & AI_DODGING) || (self->monsterinfo.aiflags & AI_DUCKED))
return false;
if (blocked_checkshot (self, 0.25 + (0.05 * skill->value) ))
return true;
// if (blocked_checkjump (self, dist, 192, 40))
// {
// soldier_jump(self);
// return true;
// }
if (blocked_checkplat (self, dist))
return true;
return false;
}
//
// DEATH
//
void soldier_fire6 (edict_t *self)
{
soldier_fire (self, 5);
}
void soldier_fire7 (edict_t *self)
{
soldier_fire (self, 6);
}
void soldier_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
M_FlyCheck (self);
// Lazarus monster fade
if (world->effects & FX_WORLDSPAWN_CORPSEFADE)
{
self->think = FadeDieSink;
self->nextthink = level.time+corpse_fadetime->value;
}
}
// pmm - this quickie does a location trace to try to grow the bounding box
//
// this is because the frames are off; the origin is at the guy's feet.
void soldier_dead2 (edict_t *self)
{
vec3_t tempmins, tempmaxs, temporg;
trace_t tr;
VectorCopy (self->s.origin, temporg);
// this is because location traces done at the floor are guaranteed to hit the floor
// (inside the sv_trace code it grows the bbox by 1 in all directions)
temporg[2] += 1;
VectorSet (tempmins, -32, -32, -24);
VectorSet (tempmaxs, 32, 32, -8);
tr = gi.trace (temporg, tempmins, tempmaxs, temporg, self, MASK_SOLID);
if (tr.startsolid || tr.allsolid)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
}
else
{
VectorCopy (tempmins, self->mins);
VectorCopy (tempmaxs, self->maxs);
}
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
}
mframe_t soldier_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, -10, NULL,
ai_move, -10, NULL,
ai_move, -10, NULL,
ai_move, -5, 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, soldier_fire6,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, soldier_fire7,
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 soldier_move_death1 = {FRAME_death101, FRAME_death136, soldier_frames_death1, soldier_dead};
mframe_t soldier_frames_death2 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
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 soldier_move_death2 = {FRAME_death201, FRAME_death235, soldier_frames_death2, soldier_dead};
mframe_t soldier_frames_death3 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
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,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
};
mmove_t soldier_move_death3 = {FRAME_death301, FRAME_death345, soldier_frames_death3, soldier_dead};
mframe_t soldier_frames_death4 [] =
{
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,
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,
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
};
// PMM -changed to soldier_dead2 to get a larger bounding box
mmove_t soldier_move_death4 = {FRAME_death401, FRAME_death453, soldier_frames_death4, soldier_dead2};
mframe_t soldier_frames_death5 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t soldier_move_death5 = {FRAME_death501, FRAME_death524, soldier_frames_death5, soldier_dead};
mframe_t soldier_frames_death6 [] =
{
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 soldier_move_death6 = {FRAME_death601, FRAME_death610, soldier_frames_death6, soldier_dead};
void soldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// 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 < 3; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->s.skinnum |= 1;
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
// if ((self->s.skinnum % 6) == 1)
if (self->s.skinnum <= 1)
gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
// else if ((self->s.skinnum % 6) == 3)
else if (self->s.skinnum <= 3)
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
else // ((self->s.skinnum % 6) == 5)
gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4)
{
// head shot
self->monsterinfo.currentmove = &soldier_move_death3;
return;
}
n = rand() % 5;
if (n == 0)
self->monsterinfo.currentmove = &soldier_move_death1;
else if (n == 1)
self->monsterinfo.currentmove = &soldier_move_death2;
else if (n == 2)
self->monsterinfo.currentmove = &soldier_move_death4;
else if (n == 3)
self->monsterinfo.currentmove = &soldier_move_death5;
else
self->monsterinfo.currentmove = &soldier_move_death6;
}
//=========
//ROGUE
void soldier_blind (edict_t *self);
mframe_t soldier_frames_blind [] =
{
ai_move, 0, soldier_idle,
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,
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 soldier_move_blind = {FRAME_stand101, FRAME_stand130, soldier_frames_blind, soldier_blind};
void soldier_blind (edict_t *self)
{
self->monsterinfo.currentmove = &soldier_move_blind;
}
//ROGUE
//=========
// RAFAEL 13-APR-98
#include "m_soldierh.h"
void soldierh_idle (edict_t *self)
{
if (!(self->spawnflags & SF_MONSTER_AMBUSH))
{
if (random() > 0.8)
gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
}
void soldierh_cock (edict_t *self)
{
if (self->s.frame == FRAME_stand322)
gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_IDLE, 0);
else
gi.sound (self, CHAN_WEAPON, sound_cock, 1, ATTN_NORM, 0);
}
// STAND
void soldierh_stand (edict_t *self);
mframe_t soldierh_frames_stand1 [] =
{
ai_stand, 0, soldierh_idle,
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,
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,
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
};
mmove_t soldierh_move_stand1 = {FRAME_stand101, FRAME_stand130, soldierh_frames_stand1, soldierh_stand};
mframe_t soldierh_frames_stand3 [] =
{
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,
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,
ai_stand, 0, NULL,
ai_stand, 0, soldierh_cock,
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,
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
};
mmove_t soldierh_move_stand3 = {FRAME_stand301, FRAME_stand339, soldierh_frames_stand3, soldierh_stand};
void soldierh_stand (edict_t *self)
{
if ((self->monsterinfo.currentmove == &soldierh_move_stand3) || (random() < 0.8))
self->monsterinfo.currentmove = &soldierh_move_stand1;
else
self->monsterinfo.currentmove = &soldierh_move_stand3;
}
//
// WALK
//
void soldierh_walk1_random (edict_t *self)
{
if (random() > 0.1)
self->monsterinfo.nextframe = FRAME_walk101;
}
mframe_t soldierh_frames_walk1 [] =
{
ai_walk, 3, NULL,
ai_walk, 6, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 2, NULL,
ai_walk, 1, NULL,
ai_walk, 6, NULL,
ai_walk, 5, NULL,
ai_walk, 3, NULL,
ai_walk, -1, soldierh_walk1_random,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL,
ai_walk, 0, NULL
};
mmove_t soldierh_move_walk1 = {FRAME_walk101, FRAME_walk133, soldierh_frames_walk1, NULL};
mframe_t soldierh_frames_walk2 [] =
{
ai_walk, 4, NULL,
ai_walk, 4, NULL,
ai_walk, 9, NULL,
ai_walk, 8, NULL,
ai_walk, 5, NULL,
ai_walk, 1, NULL,
ai_walk, 3, NULL,
ai_walk, 7, NULL,
ai_walk, 6, NULL,
ai_walk, 7, NULL
};
mmove_t soldierh_move_walk2 = {FRAME_walk209, FRAME_walk218, soldierh_frames_walk2, NULL};
void soldierh_walk (edict_t *self)
{
if (random() < 0.5)
self->monsterinfo.currentmove = &soldierh_move_walk1;
else
self->monsterinfo.currentmove = &soldierh_move_walk2;
}
//
// RUN
//
void soldierh_run (edict_t *self);
mframe_t soldierh_frames_start_run [] =
{
ai_run, 7, NULL,
ai_run, 5, NULL
};
mmove_t soldierh_move_start_run = {FRAME_run01, FRAME_run02, soldierh_frames_start_run, soldierh_run};
mframe_t soldierh_frames_run [] =
{
ai_run, 10, NULL,
ai_run, 11, NULL,
ai_run, 11, NULL,
ai_run, 16, NULL,
ai_run, 10, NULL,
ai_run, 15, NULL
};
mmove_t soldierh_move_run = {FRAME_run03, FRAME_run08, soldierh_frames_run, NULL};
void soldierh_run (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
self->monsterinfo.currentmove = &soldierh_move_stand1;
return;
}
if (self->monsterinfo.currentmove == &soldierh_move_walk1 ||
self->monsterinfo.currentmove == &soldierh_move_walk2 ||
self->monsterinfo.currentmove == &soldierh_move_start_run)
{
self->monsterinfo.currentmove = &soldierh_move_run;
}
else
{
self->monsterinfo.currentmove = &soldierh_move_start_run;
}
}
//
// PAIN
//
mframe_t soldierh_frames_pain1 [] =
{
ai_move, -3, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL
};
mmove_t soldierh_move_pain1 = {FRAME_pain101, FRAME_pain105, soldierh_frames_pain1, soldierh_run};
mframe_t soldierh_frames_pain2 [] =
{
ai_move, -13, NULL,
ai_move, -1, NULL,
ai_move, 2, NULL,
ai_move, 4, NULL,
ai_move, 2, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL
};
mmove_t soldierh_move_pain2 = {FRAME_pain201, FRAME_pain207, soldierh_frames_pain2, soldierh_run};
mframe_t soldierh_frames_pain3 [] =
{
ai_move, -8, NULL,
ai_move, 10, NULL,
ai_move, -4, NULL,
ai_move, -1, NULL,
ai_move, -3, NULL,
ai_move, 0, NULL,
ai_move, 3, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 1, NULL,
ai_move, 2, NULL,
ai_move, 4, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL
};
mmove_t soldierh_move_pain3 = {FRAME_pain301, FRAME_pain318, soldierh_frames_pain3, soldierh_run};
mframe_t soldierh_frames_pain4 [] =
{
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, -10, NULL,
ai_move, -6, NULL,
ai_move, 8, NULL,
ai_move, 4, NULL,
ai_move, 1, NULL,
ai_move, 0, NULL,
ai_move, 2, NULL,
ai_move, 5, NULL,
ai_move, 2, NULL,
ai_move, -1, NULL,
ai_move, -1, NULL,
ai_move, 3, NULL,
ai_move, 2, NULL,
ai_move, 0, NULL
};
mmove_t soldierh_move_pain4 = {FRAME_pain401, FRAME_pain417, soldierh_frames_pain4, soldierh_run};
void soldierh_pain (edict_t *self, edict_t *other, float kick, int damage)
{
float r;
int n;
if (self->health < (self->max_health / 2))
self->s.skinnum |= 1;
if (level.time < self->pain_debounce_time)
{
if ((self->velocity[2] > 100) && ( (self->monsterinfo.currentmove == &soldierh_move_pain1) || (self->monsterinfo.currentmove == &soldierh_move_pain2) || (self->monsterinfo.currentmove == &soldierh_move_pain3)))
self->monsterinfo.currentmove = &soldierh_move_pain4;
return;
}
self->pain_debounce_time = level.time + 3;
n = self->s.skinnum | 1;
if (n == 1)
gi.sound (self, CHAN_VOICE, sound_pain_light, 1, ATTN_NORM, 0);
else if (n == 3)
gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_pain_ss, 1, ATTN_NORM, 0);
if (self->velocity[2] > 100)
{
self->monsterinfo.currentmove = &soldierh_move_pain4;
return;
}
if (skill->value == 3)
return; // no pain anims in nightmare
r = random();
if (r < 0.33)
self->monsterinfo.currentmove = &soldierh_move_pain1;
else if (r < 0.66)
self->monsterinfo.currentmove = &soldierh_move_pain2;
else
self->monsterinfo.currentmove = &soldierh_move_pain3;
}
//
// ATTACK
//
extern void brain_dabeam (edict_t *self);
void soldierh_laserbeam (edict_t *self, int flash_index)
{
vec3_t forward, right, up;
vec3_t tempang, start;
vec3_t dir, angles, end;
vec3_t tempvec;
edict_t *ent;
// RAFAEL
// this sound can't be called this frequent
// if (random() > 0.8)
// gi.sound (self, CHAN_AUTO, gi.soundindex("misc/lasfly.wav"), 1, ATTN_STATIC, 0);
VectorCopy (self->s.origin, start);
VectorCopy (self->enemy->s.origin, end);
VectorSubtract (end, start, dir);
vectoangles (dir, angles);
VectorCopy (monster_flash_offset[flash_index], tempvec);
// Zaero add
if (EMPNukeCheck(self, self->s.origin))
{
gi.sound (self, CHAN_AUTO, gi.soundindex("items/empnuke/emp_missfire.wav"), 1, ATTN_NORM, 0);
return;
}
// end Zaero
// RAFAEL
// this sound can't be called this frequent
if (random() > 0.8)
gi.sound (self, CHAN_AUTO, gi.soundindex("misc/lasfly.wav"), 1, ATTN_STATIC, 0);
ent = G_Spawn ();
VectorCopy (self->s.origin, ent->s.origin);
VectorCopy (angles, tempang);
AngleVectors (tempang, forward, right, up);
VectorCopy (tempang, ent->s.angles);
VectorCopy (ent->s.origin, start);
if (flash_index == 85)
{
VectorMA (start, tempvec[0]-14, right, start);
VectorMA (start, tempvec[2]+8, up, start);
VectorMA (start, tempvec[1], forward, start);
}
else
{
VectorMA (start, tempvec[0]+2, right, start);
VectorMA (start, tempvec[2]+8, up, start);
VectorMA (start, tempvec[1], forward, start);
}
VectorCopy (start, ent->s.origin);
ent->enemy = self->enemy;
ent->owner = self;
ent->dmg = 2;
monster_dabeam (ent);
}
void soldierh_fire (edict_t *self, int flash_number)
{
vec3_t start;
vec3_t forward, right, up;
vec3_t aim;
vec3_t dir;
vec3_t end;
float r, u;
int flash_index;
qboolean tone = true;
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
flash_index = blaster_flash[flash_number]; // ripper
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
flash_index = blaster_flash[flash_number]; // hyperblaster
else
flash_index = machinegun_flash[flash_number]; // laserbeam
AngleVectors (self->s.angles, forward, right, NULL);
G_ProjectSource (self->s.origin, monster_flash_offset[flash_index], forward, right, start);
if (flash_number == 5 || flash_number == 6)
{
VectorCopy (forward, aim);
}
else
{
VectorCopy (self->enemy->s.origin, end);
end[2] += self->enemy->viewheight;
// Lazarus fog reduction of accuracy
if (self->monsterinfo.visibility < FOG_CANSEEGOOD)
{
end[0] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
end[1] += crandom() * 640 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
end[2] += crandom() * 320 * (FOG_CANSEEGOOD - self->monsterinfo.visibility);
}
VectorSubtract (end, start, aim);
vectoangles (aim, dir);
AngleVectors (dir, forward, right, up);
r = crandom()*100;
u = crandom()*50;
// Knightmare- adjust spread for expanded world size
#ifdef KMQUAKE2_ENGINE_MOD
r *= (WORLD_SIZE / 8192);
u *= (WORLD_SIZE / 8192);
#endif
VectorMA (start, WORLD_SIZE, forward, end); // was 8192
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
VectorSubtract (end, start, aim);
VectorNormalize (aim);
}
// if ((self->s.skinnum % 6) <= 1)
if (self->skinnum <= 1)
{
// RAFAEL 24-APR-98
// droped the damage from 15 to 5
monster_fire_ionripper (self, start, aim, 8, 600, flash_index, EF_IONRIPPER);
}
// else if ((self->s.skinnum % 6) <= 3)
else if (self->skinnum <= 3)
{
// monster_fire_blaster (self, start, aim, 4, 600, MZ_BLUEHYPERBLASTER, EF_BLUEHYPERBLASTER, BLASTER_BLUE);
monster_fire_blueblaster (self, start, aim, 4, 600, MZ_BLUEHYPERBLASTER, EF_BLUEHYPERBLASTER);
}
else
{
if (!(self->monsterinfo.aiflags & AI_HOLD_FRAME))
self->monsterinfo.pausetime = level.time + (3 + rand() % 8) * FRAMETIME;
soldierh_laserbeam (self, flash_index);
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
}
// ATTACK1 (blaster/shotgun)
void soldierh_hyper_refire1 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
{
if (random() < 0.7)
self->s.frame = FRAME_attak103;
else
gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
}
}
void soldierh_ripper1 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
soldierh_fire (self, 0);
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
soldierh_fire (self, 0);
}
void soldierh_fire1 (edict_t *self)
{
soldierh_fire (self, 0);
}
void soldierh_attack1_refire1 (edict_t *self)
{
// if ((self->s.skinnum % 6) > 1)
if (self->skinnum > 1)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak102;
else
self->monsterinfo.nextframe = FRAME_attak110;
}
void soldierh_attack1_refire2 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak102;
}
void soldierh_hyper_sound (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/hyprbl1a.wav"), 1, ATTN_NORM, 0);
else
return;
}
mframe_t soldierh_frames_attack1 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, soldierh_hyper_sound,
ai_charge, 0, soldierh_fire1,
ai_charge, 0, soldierh_ripper1,
ai_charge, 0, soldierh_ripper1,
ai_charge, 0, soldierh_attack1_refire1,
ai_charge, 0, soldierh_hyper_refire1,
ai_charge, 0, soldierh_cock,
ai_charge, 0, soldierh_attack1_refire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldierh_move_attack1 = {FRAME_attak101, FRAME_attak112, soldierh_frames_attack1, soldierh_run};
// ATTACK2 (blaster/shotgun)
void soldierh_hyper_refire2 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
{
if (random() < 0.7)
self->s.frame = FRAME_attak205;
else
gi.sound(self, CHAN_AUTO, gi.soundindex("weapons/hyprbd1a.wav"), 1, ATTN_NORM, 0);
}
}
void soldierh_ripper2 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
soldierh_fire (self, 1);
// else if ((self->s.skinnum % 6) < 4)
else if (self->skinnum < 4)
soldierh_fire (self, 1);
}
void soldierh_fire2 (edict_t *self)
{
soldierh_fire (self, 1);
}
void soldierh_attack2_refire1 (edict_t *self)
{
// if ((self->s.skinnum % 6) > 1)
if (self->skinnum > 1)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE))
self->monsterinfo.nextframe = FRAME_attak204;
else
self->monsterinfo.nextframe = FRAME_attak216;
}
void soldierh_attack2_refire2 (edict_t *self)
{
// if ((self->s.skinnum % 6) < 2)
if (self->skinnum < 2)
return;
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5))
// || (range(self, self->enemy) == RANGE_MELEE) && (self->s.skinnum % 6) < 4)
|| (range(self, self->enemy) == RANGE_MELEE) && (self->skinnum < 4) )
self->monsterinfo.nextframe = FRAME_attak204;
}
mframe_t soldierh_frames_attack2 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_hyper_sound,
ai_charge, 0, soldierh_fire2,
ai_charge, 0, soldierh_ripper2,
ai_charge, 0, soldierh_ripper2,
ai_charge, 0, soldierh_attack2_refire1,
ai_charge, 0, soldierh_hyper_refire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_cock,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_attack2_refire2,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldierh_move_attack2 = {FRAME_attak201, FRAME_attak218, soldierh_frames_attack2, soldierh_run};
// ATTACK3 (duck and shoot)
void soldierh_duck_down (edict_t *self)
{
if (self->monsterinfo.aiflags & AI_DUCKED)
return;
self->monsterinfo.aiflags |= AI_DUCKED;
self->maxs[2] -= 32;
self->takedamage = DAMAGE_YES;
self->monsterinfo.pausetime = level.time + 1;
gi.linkentity (self);
}
void soldierh_duck_up (edict_t *self)
{
self->monsterinfo.aiflags &= ~AI_DUCKED;
self->maxs[2] += 32;
self->takedamage = DAMAGE_AIM;
gi.linkentity (self);
}
void soldierh_fire3 (edict_t *self)
{
soldierh_duck_down (self);
soldierh_fire (self, 2);
}
void soldierh_attack3_refire (edict_t *self)
{
if ((level.time + 0.4) < self->monsterinfo.pausetime)
self->monsterinfo.nextframe = FRAME_attak303;
}
mframe_t soldierh_frames_attack3 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_fire3,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_attack3_refire,
ai_charge, 0, soldierh_duck_up,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldierh_move_attack3 = {FRAME_attak301, FRAME_attak309, soldierh_frames_attack3, soldierh_run};
// ATTACK4 (machinegun)
void soldierh_fire4 (edict_t *self)
{
soldierh_fire (self, 3);
//
// if (self->enemy->health <= 0)
// return;
//
// if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
// self->monsterinfo.nextframe = FRAME_attak402;
}
mframe_t soldierh_frames_attack4 [] =
{
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_fire4,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL
};
mmove_t soldierh_move_attack4 = {FRAME_attak401, FRAME_attak406, soldierh_frames_attack4, soldierh_run};
#if 0
// ATTACK5 (prone)
void soldierh_fire5 (edict_t *self)
{
soldierh_fire (self, 4);
}
void soldierh_attack5_refire (edict_t *self)
{
if (self->enemy->health <= 0)
return;
if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
self->monsterinfo.nextframe = FRAME_attak505;
}
mframe_t soldierh_frames_attack5 [] =
{
ai_charge, 8, NULL,
ai_charge, 8, NULL,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_fire5,
ai_charge, 0, NULL,
ai_charge, 0, NULL,
ai_charge, 0, soldierh_attack5_refire
};
//mmove_t soldierh_move_attack5 = {FRAME_attak501, FRAME_attak508, soldierh_frames_attack5, soldierh_run};
#endif
// ATTACK6 (run & shoot)
void soldierh_fire8 (edict_t *self)
{
soldierh_fire (self, 7);
}
void soldierh_attack6_refire (edict_t *self)
{
if (self->enemy->health <= 0)
return;
if (range(self, self->enemy) < RANGE_MID)
return;
if (skill->value == 3)
self->monsterinfo.nextframe = FRAME_runs03;
}
mframe_t soldierh_frames_attack6 [] =
{
ai_charge, 10, NULL,
ai_charge, 4, NULL,
ai_charge, 12, NULL,
ai_charge, 11, soldierh_fire8,
ai_charge, 13, NULL,
ai_charge, 18, NULL,
ai_charge, 15, NULL,
ai_charge, 14, NULL,
ai_charge, 11, NULL,
ai_charge, 8, NULL,
ai_charge, 11, NULL,
ai_charge, 12, NULL,
ai_charge, 12, NULL,
ai_charge, 17, soldierh_attack6_refire
};
mmove_t soldierh_move_attack6 = {FRAME_runs01, FRAME_runs14, soldierh_frames_attack6, soldierh_run};
void soldierh_attack (edict_t *self)
{
float r, chance;
monster_done_dodge (self);
//Knightmare- no blindfire for ripper soldiers in old levels
if (mp_monster_replace->value && (self->monsterinfo.aiflags & AI_BLOCKED))
return;
// PMM - blindfire!
if (self->monsterinfo.attack_state == AS_BLIND)
{
// setup shot probabilities
if (self->monsterinfo.blind_fire_delay < 1.0)
chance = 1.0;
else if (self->monsterinfo.blind_fire_delay < 7.5)
chance = 0.4;
else
chance = 0.1;
r = random();
// minimum of 2 seconds, plus 0-3, after the shots are done
self->monsterinfo.blind_fire_delay += 2.1 + 2.0 + random()*3.0;
// don't shoot at the origin
if (VectorCompare (self->monsterinfo.blind_fire_target, vec3_origin))
return;
// don't shoot if the dice say not to
if (r > chance)
{
// if ((g_showlogic) && (g_showlogic->value))
// gi.dprintf ("blindfire - NO SHOT\n");
return;
}
// turn on manual steering to signal both manual steering and blindfire
self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
self->monsterinfo.currentmove = &soldierh_move_attack1;
self->monsterinfo.attack_finished = level.time + 1.5 + random();
return;
}
// pmm
// PMM - added this so the soldiers now run toward you and shoot instead of just stopping and shooting
// if ((range(self, self->enemy) >= RANGE_MID) && (r < (skill->value*0.25) && ((self->s.skinnum % 6) <= 3)))
r = random();
if ((!(self->monsterinfo.aiflags & (AI_BLOCKED|AI_STAND_GROUND))) &&
(range(self, self->enemy) >= RANGE_NEAR) &&
(r < (skill->value*0.25) &&
// ((self->s.skinnum % 6) <= 3)))
(self->skinnum <= 3)))
{
self->monsterinfo.currentmove = &soldierh_move_attack6;
}
else
{
// if ((self->s.skinnum % 6) < 4)
if (self->skinnum < 4)
{
if (random() < 0.5)
self->monsterinfo.currentmove = &soldierh_move_attack1;
else
self->monsterinfo.currentmove = &soldierh_move_attack2;
}
else
{
self->monsterinfo.currentmove = &soldierh_move_attack4;
}
}
}
//
// SIGHT
//
void soldierh_sight (edict_t *self, edict_t *other)
{
if (random() < 0.5)
gi.sound (self, CHAN_VOICE, sound_sight1, 1, ATTN_NORM, 0);
else
gi.sound (self, CHAN_VOICE, sound_sight2, 1, ATTN_NORM, 0);
if ((skill->value > 0) && (range(self, self->enemy) >= RANGE_MID))
{
if (random() > 0.5)
{
// if ((self->s.skinnum % 6) < 4)
if (self->skinnum < 4)
self->monsterinfo.currentmove = &soldierh_move_attack6;
else
self->monsterinfo.currentmove = &soldierh_move_attack4;
}
}
}
//
// DUCK
//
void soldierh_duck_hold (edict_t *self)
{
if (level.time >= self->monsterinfo.pausetime)
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
else
self->monsterinfo.aiflags |= AI_HOLD_FRAME;
}
mframe_t soldierh_frames_duck [] =
{
ai_move, 5, soldierh_duck_down,
ai_move, -1, soldierh_duck_hold,
ai_move, 1, NULL,
ai_move, 0, soldierh_duck_up,
ai_move, 5, NULL
};
mmove_t soldierh_move_duck = {FRAME_duck01, FRAME_duck05, soldierh_frames_duck, soldierh_run};
void soldierh_dodge (edict_t *self, edict_t *attacker, float eta)
{
float r;
r = random();
if (r > 0.25)
return;
if (!self->enemy)
self->enemy = attacker;
if (skill->value == 0)
{
self->monsterinfo.currentmove = &soldierh_move_duck;
return;
}
self->monsterinfo.pausetime = level.time + eta + 0.3;
r = random();
if (skill->value == 1)
{
if (r > 0.33)
self->monsterinfo.currentmove = &soldierh_move_duck;
else
self->monsterinfo.currentmove = &soldierh_move_attack3;
return;
}
if (skill->value >= 2)
{
if (r > 0.66)
self->monsterinfo.currentmove = &soldierh_move_duck;
else
self->monsterinfo.currentmove = &soldierh_move_attack3;
return;
}
self->monsterinfo.currentmove = &soldierh_move_attack3;
}
//
// NEW DODGE CODE
//
// Knightmare- moved this code down here below soldierh frame declarations
void soldier_sidestep (edict_t *self)
{
// if ((self->s.skinnum % 6) <= 3)
if (self->skinnum <= 3)
{
// if ((g_showlogic) && (g_showlogic->value))
// gi.dprintf ("shooting back!\n");
if ((self->monsterinfo.currentmove != &soldier_move_attack6)
|| (self->monsterinfo.currentmove != &soldierh_move_attack6))
{ //Knightmare- make sure the Xatrix grunts fire the right weapon!!
if ((!strcmp(self->classname, "monster_soldier_ripper"))
|| (!strcmp(self->classname, "monster_soldier_hypergun"))
|| (!strcmp(self->classname, "monster_soldier_lasergun")))
self->monsterinfo.currentmove = &soldierh_move_attack6;
else
self->monsterinfo.currentmove = &soldier_move_attack6;
}
}
else
{
// if ((g_showlogic) && (g_showlogic->value))
// gi.dprintf ("strafing away!\n");
if (self->monsterinfo.currentmove != &soldier_move_start_run)
self->monsterinfo.currentmove = &soldier_move_start_run;
}
}
void soldier_duck (edict_t *self, float eta)
{
float r;
// has to be done immediately otherwise he can get stuck
monster_duck_down(self);
if (skill->value == 0)
{
// PMM - stupid dodge
self->monsterinfo.nextframe = FRAME_duck01;
self->monsterinfo.currentmove = &soldier_move_duck;
self->monsterinfo.duck_wait_time = level.time + eta + 1;
return;
}
r = random();
if (r > (skill->value * 0.3))
{
self->monsterinfo.nextframe = FRAME_duck01;
self->monsterinfo.currentmove = &soldier_move_duck;
self->monsterinfo.duck_wait_time = level.time + eta + (0.1 * (3 - skill->value));
}
else
{
self->monsterinfo.nextframe = FRAME_attak301;
if ((!strcmp(self->classname, "monster_soldier_ripper"))
|| (!strcmp(self->classname, "monster_soldier_hypergun"))
|| (!strcmp(self->classname, "monster_soldier_lasergun")))
self->monsterinfo.currentmove = &soldierh_move_attack3;
else
self->monsterinfo.currentmove = &soldier_move_attack3;
self->monsterinfo.duck_wait_time = level.time + eta + 1;
}
return;
}
//
// DEATH
//
void soldierh_fire6 (edict_t *self)
{
// no fire laser
// if ((self->s.skinnum % 6) < 4)
if (self->skinnum < 4)
soldierh_fire (self, 5);
}
void soldierh_fire7 (edict_t *self)
{
// no fire laser
// if ((self->s.skinnum % 6) < 4)
if (self->skinnum < 4)
soldierh_fire (self, 6);
}
void soldierh_dead (edict_t *self)
{
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, -8);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity (self);
M_FlyCheck (self);
// Lazarus monster fade
if (world->effects & FX_WORLDSPAWN_CORPSEFADE)
{
self->think=FadeDieSink;
self->nextthink=level.time+corpse_fadetime->value;
}
}
mframe_t soldierh_frames_death1 [] =
{
ai_move, 0, NULL,
ai_move, -10, NULL,
ai_move, -10, NULL,
ai_move, -10, NULL,
ai_move, -5, 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, soldierh_fire6,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, soldierh_fire7,
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 soldierh_move_death1 = {FRAME_death101, FRAME_death136, soldierh_frames_death1, soldierh_dead};
mframe_t soldierh_frames_death2 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
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 soldierh_move_death2 = {FRAME_death201, FRAME_death235, soldierh_frames_death2, soldierh_dead};
mframe_t soldierh_frames_death3 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
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,
ai_move, 0, NULL,
ai_move, 0, NULL,
ai_move, 0, NULL,
};
mmove_t soldierh_move_death3 = {FRAME_death301, FRAME_death345, soldierh_frames_death3, soldierh_dead};
mframe_t soldierh_frames_death4 [] =
{
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,
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,
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 soldierh_move_death4 = {FRAME_death401, FRAME_death453, soldierh_frames_death4, soldierh_dead};
mframe_t soldierh_frames_death5 [] =
{
ai_move, -5, NULL,
ai_move, -5, NULL,
ai_move, -5, 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,
ai_move, 0, NULL,
ai_move, 0, NULL
};
mmove_t soldierh_move_death5 = {FRAME_death501, FRAME_death524, soldierh_frames_death5, soldierh_dead};
mframe_t soldierh_frames_death6 [] =
{
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 soldierh_move_death6 = {FRAME_death601, FRAME_death610, soldierh_frames_death6, soldierh_dead};
void soldierh_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
int n;
// 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 < 3; n++)
ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
if (self->deadflag == DEAD_DEAD)
return;
// regular death
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
self->s.skinnum |= 1;
self->monsterinfo.power_armor_type = POWER_ARMOR_NONE;
// if ((self->s.skinnum % 6) == 1)
if (self->skinnum <= 1)
gi.sound (self, CHAN_VOICE, sound_death_light, 1, ATTN_NORM, 0);
// else if ((self->s.skinnum % 6) == 3)
else if (self->skinnum <= 3)
gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
else // ((self->s.skinnum % 6) == 5)
gi.sound (self, CHAN_VOICE, sound_death_ss, 1, ATTN_NORM, 0);
if (fabs((self->s.origin[2] + self->viewheight) - point[2]) <= 4)
{
// head shot
self->monsterinfo.currentmove = &soldierh_move_death3;
return;
}
n = rand() % 5;
if (n == 0)
self->monsterinfo.currentmove = &soldierh_move_death1;
else if (n == 1)
self->monsterinfo.currentmove = &soldierh_move_death2;
else if (n == 2)
self->monsterinfo.currentmove = &soldierh_move_death4;
else if (n == 3)
self->monsterinfo.currentmove = &soldierh_move_death5;
else
self->monsterinfo.currentmove = &soldierh_move_death6;
}
//
// SPAWN
//
void SP_monster_soldier_x (edict_t *self)
{
// Lazarus: special purpose skins
if ( self->style )
PatchMonsterModel("models/monsters/soldier/tris.md2");
self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2");
//PMM
// self->s.effects |= EF_SPLATTER;
//PMM
self->monsterinfo.scale = MODEL_SCALE;
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
sound_idle = gi.soundindex ("soldier/solidle1.wav");
sound_sight1 = gi.soundindex ("soldier/solsght1.wav");
sound_sight2 = gi.soundindex ("soldier/solsrch1.wav");
sound_cock = gi.soundindex ("infantry/infatck3.wav");
if (!self->mass)
self->mass = 100;
self->pain = soldier_pain;
self->die = soldier_die;
self->monsterinfo.stand = soldier_stand;
self->monsterinfo.walk = soldier_walk;
self->monsterinfo.run = soldier_run;
self->monsterinfo.dodge = M_MonsterDodge;
self->monsterinfo.attack = soldier_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = soldier_sight;
//=====
//ROGUE
self->monsterinfo.blocked = soldier_blocked;
self->monsterinfo.duck = soldier_duck;
self->monsterinfo.unduck = monster_duck_up;
self->monsterinfo.sidestep = soldier_sidestep;
//ROGUE
//=====
// 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;
}
if (!self->monsterinfo.flies)
self->monsterinfo.flies = 0.40;
gi.linkentity (self);
self->monsterinfo.stand (self);
if (self->health < 0)
{
mmove_t *deathmoves[] = {&soldier_move_death1,
&soldier_move_death2,
&soldier_move_death3,
&soldier_move_death4,
&soldier_move_death5,
&soldier_move_death6,
NULL};
M_SetDeath(self,(mmove_t **)&deathmoves);
}
walkmonster_start (self);
}
/*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_light (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_light = gi.soundindex ("soldier/solpain2.wav");
sound_death_light = gi.soundindex ("soldier/soldeth2.wav");
gi.modelindex ("models/objects/laser/tris.md2");
gi.soundindex ("misc/lasfly.wav");
gi.soundindex ("soldier/solatck2.wav");
self->common_name = "Light Guard";
// self->s.skinnum = 0;
if (!self->health)
self->health = 20;
if (!self->gib_health)
self->gib_health = -40; // was -30
// PMM - blindfire
self->monsterinfo.blindfire = true;
//Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_x (self);
// Lazarus: custom skins
self->s.skinnum = 0 + 8 * self->style; // was 0 + 6 * self->style
self->skinnum = 0; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain = gi.soundindex ("soldier/solpain1.wav");
sound_death = gi.soundindex ("soldier/soldeth1.wav");
gi.soundindex ("soldier/solatck1.wav");
self->common_name = "Shotgun Guard";
// self->s.skinnum = 2;
if (!self->health)
self->health = 30;
if (!self->gib_health)
self->gib_health = -40;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_x (self);
// Lazarus: custom skins
self->s.skinnum = 2 + 8 * self->style; // was 2 + 6 * self->style
self->skinnum = 2; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_ss (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
gi.soundindex ("soldier/solatck3.wav");
self->common_name = "Machinegun Guard";
// self->s.skinnum = 4;
if (!self->health)
self->health = 40;
if (!self->gib_health)
self->gib_health = -40;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_x (self);
// Lazarus: custom skins
self->s.skinnum = 4 + 8 * self->style; // was 4 + 6 * self->style
self->skinnum = 4; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier_plasma_re (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_plasma_re (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
gi.modelindex ("models/objects/laser/tris.md2");
gi.soundindex ("misc/lasfly.wav");
gi.soundindex ("soldier/solatck2.wav");
self->common_name = "Plasma Guard";
// self->s.skinnum = 0;
if (!self->health)
self->health = 50;
if (!self->gib_health)
self->gib_health = -40; // was -30
// PMM - blindfire
self->monsterinfo.blindfire = false;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_x (self);
// Lazarus: custom skins
self->s.skinnum = 6 + 8 * self->style;
self->skinnum = 6; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier_plasma_sp (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_plasma_sp (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
gi.soundindex ("soldier/solatck1.wav");
self->common_name = "Plasma Guard";
// self->s.skinnum = 2;
if (!self->health)
self->health = 50;
if (!self->gib_health)
self->gib_health = -40;
// PMM - blindfire
self->monsterinfo.blindfire = true;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_x (self);
// Lazarus: custom skins
self->s.skinnum = 6 + 8 * self->style;
self->skinnum = 6; // Knightmare- simplify skinnum checks by excluding custom styles
self->moreflags |= FL2_WEAPON_ALT; // special flag for spread mode
}
//
// SPAWN
//
void SP_monster_soldier_h (edict_t *self)
{
// Lazarus: special purpose skins
if ( self->style )
PatchMonsterModel("models/monsters/soldierh/tris.md2");
self->s.modelindex = gi.modelindex ("models/monsters/soldierh/tris.md2");
self->monsterinfo.scale = MODEL_SCALE;
VectorSet (self->mins, -16, -16, -24);
VectorSet (self->maxs, 16, 16, 32);
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
sound_idle = gi.soundindex ("soldier/solidle1.wav");
sound_sight1 = gi.soundindex ("soldier/solsght1.wav");
sound_sight2 = gi.soundindex ("soldier/solsrch1.wav");
sound_cock = gi.soundindex ("infantry/infatck3.wav");
if (!self->mass)
self->mass = 100;
self->pain = soldierh_pain;
self->die = soldierh_die;
self->monsterinfo.stand = soldierh_stand;
self->monsterinfo.walk = soldierh_walk;
self->monsterinfo.run = soldierh_run;
self->monsterinfo.dodge = M_MonsterDodge;
self->monsterinfo.attack = soldierh_attack;
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = soldierh_sight;
//=====
//ROGUE
self->monsterinfo.blocked = soldier_blocked;
self->monsterinfo.duck = soldier_duck;
self->monsterinfo.unduck = monster_duck_up;
self->monsterinfo.sidestep = soldier_sidestep;
//ROGUE
//=====
// 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;
}
if (!self->monsterinfo.flies)
self->monsterinfo.flies = 0.40;
gi.linkentity (self);
// self->monsterinfo.stand (self);
self->monsterinfo.currentmove = &soldierh_move_stand3;
if (self->health < 0)
{
mmove_t *deathmoves[] = {&soldierh_move_death1,
&soldierh_move_death2,
&soldierh_move_death3,
&soldierh_move_death4,
&soldierh_move_death5,
&soldierh_move_death6,
NULL};
M_SetDeath(self,(mmove_t **)&deathmoves);
}
walkmonster_start (self);
}
/*QUAKED monster_soldier_ripper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_ripper (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_light = gi.soundindex ("soldier/solpain2.wav");
sound_death_light = gi.soundindex ("soldier/soldeth2.wav");
gi.modelindex ("models/objects/boomrang/tris.md2");
gi.soundindex ("misc/lasfly.wav");
gi.soundindex ("soldier/solatck2.wav");
self->common_name = "Ripper Guard";
//self->s.skinnum = 0;
if (!self->health)
self->health = 50;
if (!self->gib_health)
self->gib_health = -40;
// PMM - blindfire
self->monsterinfo.blindfire = true;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_h (self);
// Lazarus: custom skins
self->s.skinnum = 0 + 6 * self->style;
self->skinnum = 0; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier_hypergun (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib
*/
void SP_monster_soldier_hypergun (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
gi.modelindex ("models/objects/blaser/tris.md2");
sound_pain = gi.soundindex ("soldier/solpain1.wav");
sound_death = gi.soundindex ("soldier/soldeth1.wav");
gi.soundindex ("soldier/solatck1.wav");
self->common_name = "Hyperblaster Guard";
//self->s.skinnum = 2;
if (!self->health)
self->health = 60;
if (!self->gib_health)
self->gib_health = -40;
// PMM - blindfire
self->monsterinfo.blindfire = true;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_h (self);
// Lazarus: custom skins
self->s.skinnum = 2 + 6 * self->style;
self->skinnum = 2; // Knightmare- simplify skinnum checks by excluding custom styles
}
/*QUAKED monster_soldier_lasergun (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight GoodGuy NoGib ThroughGlass
*/
void SP_monster_soldier_lasergun (edict_t *self)
{
if (deathmatch->value)
{
G_FreeEdict (self);
return;
}
sound_pain_ss = gi.soundindex ("soldier/solpain3.wav");
sound_death_ss = gi.soundindex ("soldier/soldeth3.wav");
gi.soundindex ("soldier/solatck3.wav");
self->common_name = "Laser Guard";
//self->s.skinnum = 4;
if (!self->health)
self->health = 70;
if (!self->gib_health)
self->gib_health = -40;
// Knightmare- call generic spawn function LAST, because it
// calls walkmonster_start, which the health and everything else need to be set up for
SP_monster_soldier_h (self);
// Lazarus: custom skins
self->s.skinnum = 4 + 6 * self->style;
self->skinnum = 4; // Knightmare- simplify skinnum checks by excluding custom styles
}
// END 13-APR-98