Merge branch 'master' into pvs

This commit is contained in:
BjossiAlfreds 2019-09-28 15:25:51 +00:00
commit 51b1eeb6a9
11 changed files with 770 additions and 126 deletions

View file

@ -1113,7 +1113,7 @@ ai_run_slide(edict_t *self, float distance)
/* clamp maximum sideways move for non flyers to make them look less jerky */
if (!(self->flags & FL_FLY))
{
distance = min(distance, 0.8);
distance = min(distance, 8.0);
}
if (M_walkmove(self, self->ideal_yaw + ofs, distance))

View file

@ -159,7 +159,7 @@ mframe_t berserk_frames_run1[] = {
{ai_run, 21, NULL},
{ai_run, 11, NULL},
{ai_run, 21, NULL},
{ai_run, 25, NULL},
{ai_run, 25, monster_done_dodge},
{ai_run, 18, NULL},
{ai_run, 19, NULL}
};
@ -179,6 +179,8 @@ berserk_run(edict_t *self)
return;
}
monster_done_dodge(self);
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
self->monsterinfo.currentmove = &berserk_move_stand;
@ -303,6 +305,8 @@ berserk_melee(edict_t *self)
return;
}
monster_done_dodge(self);
if ((rand() % 2) == 0)
{
self->monsterinfo.currentmove = &berserk_move_attack_spike;
@ -383,6 +387,8 @@ berserk_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
return; /* no pain anims in nightmare */
}
monster_done_dodge(self);
if ((damage < 20) || (random() < 0.5))
{
self->monsterinfo.currentmove = &berserk_move_pain1;
@ -499,6 +505,158 @@ berserk_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
}
}
void
berserk_jump_now(edict_t *self)
{
vec3_t forward, up;
if (!self)
{
return;
}
monster_jump_start(self);
AngleVectors(self->s.angles, forward, NULL, up);
VectorMA(self->velocity, 100, forward, self->velocity);
VectorMA(self->velocity, 300, up, self->velocity);
}
void
berserk_jump2_now(edict_t *self)
{
vec3_t forward,up;
if (!self)
{
return;
}
monster_jump_start(self);
AngleVectors(self->s.angles, forward, NULL, up);
VectorMA(self->velocity, 150, forward, self->velocity);
VectorMA(self->velocity, 400, up, self->velocity);
}
void
berserk_jump_wait_land(edict_t *self)
{
if (!self)
{
return;
}
if (self->groundentity == NULL)
{
self->monsterinfo.nextframe = self->s.frame;
if (monster_jump_finished(self))
{
self->monsterinfo.nextframe = self->s.frame + 1;
}
}
else
{
self->monsterinfo.nextframe = self->s.frame + 1;
}
}
mframe_t berserk_frames_jump[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, berserk_jump_now},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, berserk_jump_wait_land},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t berserk_move_jump = {
FRAME_jump1,
FRAME_jump9,
berserk_frames_jump,
berserk_run
};
mframe_t berserk_frames_jump2[] = {
{ai_move, -8, NULL},
{ai_move, -4, NULL},
{ai_move, -4, NULL},
{ai_move, 0, berserk_jump_now},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, berserk_jump_wait_land},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t berserk_move_jump2 = {
FRAME_jump1,
FRAME_jump9,
berserk_frames_jump2,
berserk_run
};
void
berserk_jump(edict_t *self)
{
if (!self || !self->enemy)
{
return;
}
monster_done_dodge(self);
if (self->enemy->s.origin[2] > self->s.origin[2])
{
self->monsterinfo.currentmove = &berserk_move_jump2;
}
else
{
self->monsterinfo.currentmove = &berserk_move_jump;
}
}
qboolean
berserk_blocked(edict_t *self, float dist)
{
if (blocked_checkjump(self, dist, 256, 40))
{
berserk_jump(self);
return true;
}
if (blocked_checkplat(self, dist))
{
return true;
}
return false;
}
void
berserk_sidestep(edict_t *self)
{
if (!self)
{
return;
}
if ((self->monsterinfo.currentmove == &berserk_move_jump) ||
(self->monsterinfo.currentmove == &berserk_move_jump2))
{
return;
}
if (self->monsterinfo.currentmove != &berserk_move_run1)
{
self->monsterinfo.currentmove = &berserk_move_run1;
}
}
/*
* QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
@ -540,11 +698,13 @@ SP_monster_berserk(edict_t *self)
self->monsterinfo.stand = berserk_stand;
self->monsterinfo.walk = berserk_walk;
self->monsterinfo.run = berserk_run;
self->monsterinfo.dodge = NULL;
self->monsterinfo.dodge = M_MonsterDodge;
self->monsterinfo.sidestep = berserk_sidestep;
self->monsterinfo.attack = NULL;
self->monsterinfo.melee = berserk_melee;
self->monsterinfo.sight = berserk_sight;
self->monsterinfo.search = berserk_search;
self->monsterinfo.blocked = berserk_blocked;
self->monsterinfo.currentmove = &berserk_move_stand;
self->monsterinfo.scale = MODEL_SCALE;

View file

@ -8,6 +8,8 @@
#include "../../header/local.h"
#include "boss2.h"
#define BOSS2_ROCKET_SPEED 750
qboolean infront(edict_t *self, edict_t *other);
void BossExplode(edict_t *self);
void boss2_run(edict_t *self);
@ -39,52 +41,125 @@ boss2_search(edict_t *self)
}
void
Boss2Rocket(edict_t *self)
Boss2PredictiveRocket(edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
float time, dist;
if (!self)
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
AngleVectors(self->s.angles, forward, right, NULL);
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1],
forward, right, start);
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
//1
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
VectorSubtract(self->enemy->s.origin, start, dir);
dist = VectorLength(dir);
time = dist / BOSS2_ROCKET_SPEED;
VectorMA(self->enemy->s.origin, time-0.3, self->enemy->velocity, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, BOSS2_ROCKET_SPEED, MZ2_BOSS2_ROCKET_1);
//2
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
VectorSubtract(self->enemy->s.origin, start, dir);
dist = VectorLength(dir);
time = dist / BOSS2_ROCKET_SPEED;
VectorMA(self->enemy->s.origin, time-0.15, self->enemy->velocity, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, BOSS2_ROCKET_SPEED, MZ2_BOSS2_ROCKET_2);
//3
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
VectorSubtract(self->enemy->s.origin, start, dir);
dist = VectorLength(dir);
time = dist / BOSS2_ROCKET_SPEED;
VectorMA(self->enemy->s.origin, time, self->enemy->velocity, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, BOSS2_ROCKET_SPEED, MZ2_BOSS2_ROCKET_3);
//4
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
VectorSubtract(self->enemy->s.origin, start, dir);
dist = VectorLength(dir);
time = dist / BOSS2_ROCKET_SPEED;
VectorMA(self->enemy->s.origin, time+0.15, self->enemy->velocity, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, BOSS2_ROCKET_SPEED, MZ2_BOSS2_ROCKET_4);
}
void
Boss2Rocket(edict_t *self)
{
vec3_t forward, right;
vec3_t start;
vec3_t dir;
vec3_t vec;
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
if (self->enemy->client && random() < 0.9)
{
Boss2PredictiveRocket(self);
return;
}
AngleVectors (self->s.angles, forward, right, NULL);
//1
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_1], forward, right, start);
VectorCopy(self->enemy->s.origin, vec);
vec[2] -= 15;
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
VectorMA(dir, 0.4, right, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_1);
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2],
forward, right, start);
//2
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_2], forward, right, start);
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
VectorMA(dir, 0.025, right, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_2);
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3],
forward, right, start);
//3
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_3], forward, right, start);
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
VectorMA(dir, -0.025, right, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_3);
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4],
forward, right, start);
//4
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_ROCKET_4], forward, right, start);
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
vec[2] -= 15;
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
VectorMA(dir, -0.4, right, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
}
}
void
boss2_firebullet_right(edict_t *self)
@ -101,12 +176,12 @@ boss2_firebullet_right(edict_t *self)
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_R1],
forward, right, start);
VectorMA(self->enemy->s.origin, -0.2, self->enemy->velocity, target);
VectorMA(self->enemy->s.origin, 0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract(target, start, forward);
VectorNormalize(forward);
monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD,
monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3,
DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_R1);
}
@ -125,13 +200,13 @@ boss2_firebullet_left(edict_t *self)
G_ProjectSource(self->s.origin, monster_flash_offset[MZ2_BOSS2_MACHINEGUN_L1],
forward, right, start);
VectorMA(self->enemy->s.origin, -0.2, self->enemy->velocity, target);
VectorMA(self->enemy->s.origin, 0.2, self->enemy->velocity, target);
target[2] += self->enemy->viewheight;
VectorSubtract(target, start, forward);
VectorNormalize(forward);
monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD,
monster_fire_bullet(self, start, forward, 6, 4, DEFAULT_BULLET_HSPREAD*3,
DEFAULT_BULLET_VSPREAD, MZ2_BOSS2_MACHINEGUN_L1);
}
@ -219,26 +294,26 @@ mmove_t boss2_move_fidget = {
};
mframe_t boss2_frames_walk[] = {
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL}
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL}
};
mmove_t boss2_move_walk = {
@ -249,26 +324,26 @@ mmove_t boss2_move_walk = {
};
mframe_t boss2_frames_run[] = {
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL}
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL}
};
mmove_t boss2_move_run = {
@ -279,15 +354,15 @@ mmove_t boss2_move_run = {
};
mframe_t boss2_frames_attack_pre_mg[] = {
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, boss2_attack_mg}
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, boss2_attack_mg}
};
mmove_t boss2_move_attack_pre_mg = {
@ -299,12 +374,12 @@ mmove_t boss2_move_attack_pre_mg = {
/* Loop this */
mframe_t boss2_frames_attack_mg[] = {
{ai_charge, 1, Boss2MachineGun},
{ai_charge, 1, Boss2MachineGun},
{ai_charge, 1, Boss2MachineGun},
{ai_charge, 1, Boss2MachineGun},
{ai_charge, 1, Boss2MachineGun},
{ai_charge, 1, boss2_reattack_mg}
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, boss2_reattack_mg}
};
mmove_t boss2_move_attack_mg = {
@ -315,10 +390,10 @@ mmove_t boss2_move_attack_mg = {
};
mframe_t boss2_frames_attack_post_mg[] = {
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL}
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL}
};
@ -330,27 +405,27 @@ mmove_t boss2_move_attack_post_mg = {
};
mframe_t boss2_frames_attack_rocket[] = {
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_move, -20, Boss2Rocket},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL}
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_move, -5, Boss2Rocket},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL}
};
mmove_t boss2_move_attack_rocket = {FRAME_attack20,
@ -666,7 +741,11 @@ Boss2_CheckAttack(edict_t *self)
/* do we have a clear shot? */
if (tr.ent != self->enemy)
{
return false;
/* we want them to go ahead and shoot at info_notnulls if they can */
if (self->enemy->solid != SOLID_NOT || tr.fraction < 1.0)
{
return false;
}
}
}
@ -724,7 +803,7 @@ Boss2_CheckAttack(edict_t *self)
return false;
}
if (random() < chance)
if ((random() < chance) || (self->enemy->solid == SOLID_NOT))
{
self->monsterinfo.attack_state = AS_MISSILE;
self->monsterinfo.attack_finished = level.time + 2 * random();

View file

@ -54,7 +54,7 @@ floater_fire_blaster(edict_t *self)
vec3_t dir;
int effect;
if (!self)
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
@ -285,6 +285,31 @@ mmove_t floater_move_attack1 = {
floater_run
};
/* circle strafe frames */
mframe_t floater_frames_attack1a[] = {
{ai_charge, 10, NULL}, // Blaster attack
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
{ai_charge, 10, floater_fire_blaster}, // BOOM (0, -25.8, 32.5) -- LOOP Starts
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, floater_fire_blaster},
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
{ai_charge, 10, NULL} // -- LOOP Ends
};
mmove_t floater_move_attack1a = {
FRAME_attak101,
FRAME_attak114,
floater_frames_attack1a,
floater_run
};
mframe_t floater_frames_attack2[] = {
{ai_charge, 0, NULL}, /* Claws */
{ai_charge, 0, NULL},
@ -640,7 +665,7 @@ floater_zap(edict_t *self)
gi.WriteByte(1); /* sparks */
gi.multicast(origin, MULTICAST_PVS);
if (range(self, self->enemy) && infront(self, self->enemy) &&
if (range(self, self->enemy) == RANGE_MELEE && infront(self, self->enemy) &&
visible(self, self->enemy))
{
T_Damage(self->enemy, self, self, dir, self->enemy->s.origin,
@ -651,12 +676,41 @@ floater_zap(edict_t *self)
void
floater_attack(edict_t *self)
{
float chance;
if (!self)
{
return;
}
self->monsterinfo.currentmove = &floater_move_attack1;
// 0% chance of circle in easy
// 50% chance in normal
// 75% chance in hard
// 86.67% chance in nightmare
if (!skill->value)
{
chance = 0;
}
else
{
chance = 1.0 - (0.5/(float)(skill->value));
}
if (random() > chance)
{
self->monsterinfo.attack_state = AS_STRAIGHT;
self->monsterinfo.currentmove = &floater_move_attack1;
}
else // circle strafe
{
if (random () <= 0.5) // switch directions
{
self->monsterinfo.lefty = 1 - self->monsterinfo.lefty;
}
self->monsterinfo.attack_state = AS_SLIDING;
self->monsterinfo.currentmove = &floater_move_attack1a;
}
}
void
@ -747,6 +801,22 @@ floater_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
BecomeExplosion1(self);
}
qboolean
floater_blocked(edict_t *self, float dist)
{
if (!self)
{
return false;
}
if (blocked_checkshot(self, 0.25 + (0.05 * skill->value)))
{
return true;
}
return false;
}
/*
* QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
@ -796,6 +866,7 @@ SP_monster_floater(edict_t *self)
self->monsterinfo.melee = floater_melee;
self->monsterinfo.sight = floater_sight;
self->monsterinfo.idle = floater_idle;
self->monsterinfo.blocked = floater_blocked;
gi.linkentity(self);

View file

@ -466,6 +466,27 @@ gladiator_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker
self->monsterinfo.currentmove = &gladiator_move_death;
}
qboolean
gladiator_blocked(edict_t *self, float dist)
{
if (!self)
{
return false;
}
if (blocked_checkshot(self, 0.25 + (0.05 * skill->value) ))
{
return true;
}
if (blocked_checkplat(self, dist))
{
return true;
}
return false;
}
/*
* QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight
*/
@ -516,6 +537,7 @@ SP_monster_gladiator(edict_t *self)
self->monsterinfo.sight = gladiator_sight;
self->monsterinfo.idle = gladiator_idle;
self->monsterinfo.search = gladiator_search;
self->monsterinfo.blocked = gladiator_blocked;
gi.linkentity(self);
self->monsterinfo.currentmove = &gladiator_move_stand;

View file

@ -804,6 +804,117 @@ mutant_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
}
}
void
mutant_jump_down(edict_t *self)
{
vec3_t forward, up;
if (!self)
{
return;
}
AngleVectors(self->s.angles, forward, NULL, up);
VectorMA(self->velocity, 100, forward, self->velocity);
VectorMA(self->velocity, 300, up, self->velocity);
}
void
mutant_jump_up(edict_t *self)
{
vec3_t forward, up;
if (!self)
{
return;
}
AngleVectors(self->s.angles, forward, NULL, up);
VectorMA(self->velocity, 200, forward, self->velocity);
VectorMA(self->velocity, 450, up, self->velocity);
}
void
mutant_jump_wait_land(edict_t *self)
{
if (self->groundentity == NULL)
{
self->monsterinfo.nextframe = self->s.frame;
}
else
{
self->monsterinfo.nextframe = self->s.frame + 1;
}
}
mframe_t mutant_frames_jump_up[] = {
{ai_move, -8, NULL},
{ai_move, -8, mutant_jump_up},
{ai_move, 0, mutant_jump_wait_land},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t mutant_move_jump_up = {
FRAME_jump01,
FRAME_jump05,
mutant_frames_jump_up,
mutant_run
};
mframe_t mutant_frames_jump_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, mutant_jump_down},
{ai_move, 0, mutant_jump_wait_land},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t mutant_move_jump_down = {
FRAME_jump01,
FRAME_jump05,
mutant_frames_jump_down,
mutant_run
};
void
mutant_jump_updown(edict_t *self)
{
if (!self || !self->enemy)
{
return;
}
if (self->enemy->s.origin[2] > self->s.origin[2])
{
self->monsterinfo.currentmove = &mutant_move_jump_up;
}
else
{
self->monsterinfo.currentmove = &mutant_move_jump_down;
}
}
qboolean
mutant_blocked(edict_t *self, float dist)
{
if (!self)
{
return false;
}
if (blocked_checkjump(self, dist, 256, 68))
{
mutant_jump_updown(self);
return true;
}
if (blocked_checkplat(self, dist))
return true;
return false;
}
/*
* QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
*/
@ -858,6 +969,7 @@ SP_monster_mutant(edict_t *self)
self->monsterinfo.search = mutant_search;
self->monsterinfo.idle = mutant_idle;
self->monsterinfo.checkattack = mutant_checkattack;
self->monsterinfo.blocked = mutant_blocked;
gi.linkentity(self);

View file

@ -394,6 +394,8 @@ tank_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
return; /* no pain anims in nightmare */
}
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
if (damage <= 30)
{
self->monsterinfo.currentmove = &tank_move_pain1;
@ -465,12 +467,25 @@ TankRocket(edict_t *self)
vec3_t dir;
vec3_t vec;
int flash_number;
trace_t trace;
int rocketSpeed;
vec3_t target;
qboolean blindfire = false;
if (!self)
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
{
blindfire = true;
}
else
{
blindfire = false;
}
if (self->s.frame == FRAME_attak324)
{
flash_number = MZ2_TANK_ROCKET_1;
@ -485,15 +500,111 @@ TankRocket(edict_t *self)
}
AngleVectors(self->s.angles, forward, right, NULL);
G_ProjectSource(self->s.origin, monster_flash_offset[flash_number], forward,
right, start);
G_ProjectSource(self->s.origin, monster_flash_offset[flash_number], forward, right, start);
rocketSpeed = 500 + (100 * skill->value);
if (blindfire)
{
VectorCopy (self->monsterinfo.blind_fire_target, target);
}
else
{
VectorCopy (self->enemy->s.origin, target);
}
if (blindfire)
{
VectorCopy(target, vec);
VectorSubtract(vec, start, dir);
}
else if(random() < 0.66 || (start[2] < self->enemy->absmin[2]))
{
// Don't shoot at the feed if enemy is above.
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract(vec, start, dir);
}
else
{
// Shoot at the feed.
VectorCopy(self->enemy->s.origin, vec);
vec[2] = self->enemy->absmin[2];
VectorSubtract(vec, start, dir);
}
// Lead target: 20, 35, 50, 65 chance of leading.
if ((!blindfire) && ((random() < (0.2 + ((3 - skill->value) * 0.15)))))
{
float dist;
float time;
dist = VectorLength(dir);
time = dist/rocketSpeed;
VectorMA(vec, time, self->enemy->velocity, vec);
VectorSubtract(vec, start, dir);
}
VectorCopy(self->enemy->s.origin, vec);
vec[2] += self->enemy->viewheight;
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 550, flash_number);
// Blindfire doesn't check target (done in checkattack). Paranoia:
// Make sure we're not shooting a target right next to us.
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (blindfire)
{
// Blindfire has different fail criteria for the trace
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else
{
// Try shifting the target to the left a little (to help counter large offset)
VectorCopy(target, vec);
VectorMA(vec, -20, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else
{
// OK, that failed. Try to the right.
VectorCopy(target, vec);
VectorMA(vec, 20, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else if ((g_showlogic) && (g_showlogic->value))
{
gi.dprintf ("tank avoiding blindfire shot\n");
}
}
}
}
else
{
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (trace.ent == self->enemy || trace.ent == world)
{
if (trace.fraction > 0.5 || (trace.ent && trace.ent->client))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
}
}
}
void
@ -505,7 +616,7 @@ TankMachineGun(edict_t *self)
vec3_t forward, right;
int flash_number;
if (!self)
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
@ -564,9 +675,12 @@ mframe_t tank_frames_attack_blast[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, TankBlaster} /* 16 */
};
mmove_t tank_move_attack_blast =
{FRAME_attak101, FRAME_attak116, tank_frames_attack_blast,
tank_reattack_blaster};
mmove_t tank_move_attack_blast = {
FRAME_attak101,
FRAME_attak116,
tank_frames_attack_blast,
tank_reattack_blaster
};
mframe_t tank_frames_reattack_blast[] = {
{ai_charge, 0, NULL},
@ -820,6 +934,13 @@ tank_refire_rocket(edict_t *self)
return;
}
if (self->monsterinfo.aiflags & AI_MANUAL_STEERING)
{
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
return;
}
/* Only on hard or nightmare */
if (skill->value >= 2)
{
@ -856,8 +977,9 @@ tank_attack(edict_t *self)
vec3_t vec;
float range;
float r;
float chance;
if (!self)
if (!self || !self->enemy || !self->enemy->inuse)
{
return;
}
@ -869,6 +991,45 @@ tank_attack(edict_t *self)
return;
}
if (self->monsterinfo.attack_state == AS_BLIND)
{
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();
self->monsterinfo.blind_fire_delay += 3.2 + 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)
{
return;
}
// turn on manual steering to signal both manual steering and blindfire
self->monsterinfo.aiflags |= AI_MANUAL_STEERING;
self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
self->monsterinfo.attack_finished = level.time + 3.0 + 2*random();
self->pain_debounce_time = level.time + 5.0; // no pain for a while
return;
}
VectorSubtract(self->enemy->s.origin, self->s.origin, vec);
range = VectorLength(vec);
@ -986,8 +1147,7 @@ tank_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* un
/* check for gib */
if (self->health <= self->gib_health)
{
gi.sound(self, CHAN_VOICE, gi.soundindex(
"misc/udeath.wav"), 1, ATTN_NORM, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 1 /*4*/; n++)
{
@ -1018,6 +1178,20 @@ tank_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* un
self->monsterinfo.currentmove = &tank_move_death;
}
qboolean tank_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;
}
/*
* QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
@ -1086,6 +1260,7 @@ SP_monster_tank(edict_t *self)
self->monsterinfo.melee = NULL;
self->monsterinfo.sight = tank_sight;
self->monsterinfo.idle = tank_idle;
self->monsterinfo.blocked = tank_blocked;
gi.linkentity(self);
@ -1094,6 +1269,9 @@ SP_monster_tank(edict_t *self)
walkmonster_start(self);
self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
self->monsterinfo.blindfire = true;
if (strcmp(self->classname, "monster_tank_commander") == 0)
{
self->s.skinnum = 2;

View file

@ -329,6 +329,7 @@ extern void tank_windup ( edict_t * self ) ;
extern void tank_thud ( edict_t * self ) ;
extern void tank_footstep ( edict_t * self ) ;
extern void tank_sight ( edict_t * self , edict_t * other ) ;
extern qboolean tank_blocked( edict_t *self, float dist );
extern void SP_monster_supertank ( edict_t * self ) ;
extern qboolean supertank_blocked ( edict_t * self , float dist ) ;
extern void supertank_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
@ -442,6 +443,7 @@ extern void parasite_sight ( edict_t * self , edict_t * other ) ;
extern void parasite_reel_in ( edict_t * self ) ;
extern void parasite_launch ( edict_t * self ) ;
extern void SP_monster_mutant ( edict_t * self ) ;
extern qboolean mutant_blocked ( edict_t * self , float dist ) ;
extern void mutant_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void mutant_dead ( edict_t * self ) ;
extern void mutant_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
@ -586,6 +588,7 @@ extern void gunner_search ( edict_t * self ) ;
extern void gunner_sight ( edict_t * self , edict_t * other ) ;
extern void gunner_idlesound ( edict_t * self ) ;
extern void SP_monster_gladiator ( edict_t * self ) ;
qboolean gladiator_blocked ( edict_t *self , float dist ) ;
extern void gladiator_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void gladiator_dead ( edict_t * self ) ;
extern void gladiator_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
@ -628,6 +631,7 @@ extern void flyer_pop_blades ( edict_t * self ) ;
extern void flyer_idle ( edict_t * self ) ;
extern void flyer_sight ( edict_t * self , edict_t * other ) ;
extern void SP_monster_floater ( edict_t * self ) ;
extern qboolean floater_blocked ( edict_t * self , float dist ) ;
extern void floater_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void floater_dead ( edict_t * self ) ;
extern void floater_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
@ -792,6 +796,8 @@ extern void boss2_firebullet_right ( edict_t * self ) ;
extern void Boss2Rocket ( edict_t * self ) ;
extern void boss2_search ( edict_t * self ) ;
extern void SP_monster_berserk ( edict_t * self ) ;
extern void berserk_sidestep ( edict_t * self ) ;
extern qboolean berserk_blocked ( edict_t * self , float dist ) ;
extern void berserk_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void berserk_dead ( edict_t * self ) ;
extern void berserk_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;

View file

@ -329,6 +329,7 @@
{"tank_thud", (byte *)tank_thud},
{"tank_footstep", (byte *)tank_footstep},
{"tank_sight", (byte *)tank_sight},
{"tank_blocked", (byte *)tank_blocked},
{"SP_monster_supertank", (byte *)SP_monster_supertank},
{"supertank_blocked", (byte *)supertank_blocked},
{"supertank_die", (byte *)supertank_die},
@ -442,6 +443,7 @@
{"parasite_reel_in", (byte *)parasite_reel_in},
{"parasite_launch", (byte *)parasite_launch},
{"SP_monster_mutant", (byte *)SP_monster_mutant},
{"mutant_blocked", (byte *)mutant_blocked},
{"mutant_die", (byte *)mutant_die},
{"mutant_dead", (byte *)mutant_dead},
{"mutant_pain", (byte *)mutant_pain},
@ -586,6 +588,7 @@
{"gunner_sight", (byte *)gunner_sight},
{"gunner_idlesound", (byte *)gunner_idlesound},
{"SP_monster_gladiator", (byte *)SP_monster_gladiator},
{"gladiator_blocked", (byte *)gladiator_blocked},
{"gladiator_die", (byte *)gladiator_die},
{"gladiator_dead", (byte *)gladiator_dead},
{"gladiator_pain", (byte *)gladiator_pain},
@ -628,6 +631,7 @@
{"flyer_idle", (byte *)flyer_idle},
{"flyer_sight", (byte *)flyer_sight},
{"SP_monster_floater", (byte *)SP_monster_floater},
{"floater_blocked", (byte *)floater_blocked},
{"floater_die", (byte *)floater_die},
{"floater_dead", (byte *)floater_dead},
{"floater_pain", (byte *)floater_pain},
@ -792,6 +796,8 @@
{"Boss2Rocket", (byte *)Boss2Rocket},
{"boss2_search", (byte *)boss2_search},
{"SP_monster_berserk", (byte *)SP_monster_berserk},
{"berserk_sidestep", (byte *)berserk_sidestep},
{"berserk_blocked", (byte *)berserk_blocked},
{"berserk_die", (byte *)berserk_die},
{"berserk_dead", (byte *)berserk_dead},
{"berserk_pain", (byte *)berserk_pain},

View file

@ -133,6 +133,8 @@ extern mmove_t parasite_move_stand ;
extern mmove_t parasite_move_end_fidget ;
extern mmove_t parasite_move_fidget ;
extern mmove_t parasite_move_start_fidget ;
extern mmove_t mutant_move_jump_down ;
extern mmove_t mutant_move_jump_up ;
extern mmove_t mutant_move_death2 ;
extern mmove_t mutant_move_death1 ;
extern mmove_t mutant_move_pain3 ;
@ -252,6 +254,7 @@ extern mmove_t floater_move_pain1 ;
extern mmove_t floater_move_death ;
extern mmove_t floater_move_attack3 ;
extern mmove_t floater_move_attack2 ;
extern mmove_t floater_move_attack1a ;
extern mmove_t floater_move_attack1 ;
extern mmove_t floater_move_activate ;
extern mmove_t floater_move_stand2 ;
@ -346,6 +349,8 @@ extern mmove_t boss2_move_run ;
extern mmove_t boss2_move_walk ;
extern mmove_t boss2_move_fidget ;
extern mmove_t boss2_move_stand ;
extern mmove_t berserk_move_jump2 ;
extern mmove_t berserk_move_jump ;
extern mmove_t berserk_move_death2 ;
extern mmove_t berserk_move_death1 ;
extern mmove_t berserk_move_pain2 ;

View file

@ -133,6 +133,8 @@
{"parasite_move_end_fidget", &parasite_move_end_fidget},
{"parasite_move_fidget", &parasite_move_fidget},
{"parasite_move_start_fidget", &parasite_move_start_fidget},
{"mutant_move_jump_down", &mutant_move_jump_down},
{"mutant_move_jump_up", &mutant_move_jump_up},
{"mutant_move_death2", &mutant_move_death2},
{"mutant_move_death1", &mutant_move_death1},
{"mutant_move_pain3", &mutant_move_pain3},
@ -252,6 +254,7 @@
{"floater_move_death", &floater_move_death},
{"floater_move_attack3", &floater_move_attack3},
{"floater_move_attack2", &floater_move_attack2},
{"floater_move_attack1a", &floater_move_attack1a},
{"floater_move_attack1", &floater_move_attack1},
{"floater_move_activate", &floater_move_activate},
{"floater_move_stand2", &floater_move_stand2},
@ -346,6 +349,8 @@
{"boss2_move_walk", &boss2_move_walk},
{"boss2_move_fidget", &boss2_move_fidget},
{"boss2_move_stand", &boss2_move_stand},
{"berserk_move_jump2", &berserk_move_jump2},
{"berserk_move_jump", &berserk_move_jump},
{"berserk_move_death2", &berserk_move_death2},
{"berserk_move_death1", &berserk_move_death1},
{"berserk_move_pain2", &berserk_move_pain2},