mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-09 23:02:02 +00:00
game: Add ReRelease Shambler Monster
This commit is contained in:
parent
1151c91069
commit
9958db18d6
6 changed files with 860 additions and 5 deletions
1
Makefile
1
Makefile
|
@ -921,6 +921,7 @@ GAME_OBJS_ = \
|
|||
src/game/monster/soldier/soldier.o \
|
||||
src/game/monster/stalker/stalker.o \
|
||||
src/game/monster/supertank/supertank.o \
|
||||
src/game/monster/shambler/shambler.o \
|
||||
src/game/monster/tank/tank.o \
|
||||
src/game/monster/turret/turret.o \
|
||||
src/game/monster/widow/widow2.o \
|
||||
|
|
|
@ -30,6 +30,10 @@ State:
|
|||
* q64/outpost: no known issies
|
||||
* mguhub: loaded, transparent walls and broken logic for surface fall in next maps
|
||||
|
||||
Monsters:
|
||||
* incorrect weapon effect for Shambler
|
||||
* incorrect dead animation for Arachnoid
|
||||
|
||||
Goals (none of it finished):
|
||||
* Single player support,
|
||||
* BSPX DECOUPLEDLM light map support (base1),
|
||||
|
|
|
@ -162,6 +162,7 @@ void SP_turret_breach(edict_t *self);
|
|||
void SP_turret_base(edict_t *self);
|
||||
void SP_turret_driver(edict_t *self);
|
||||
|
||||
void SP_monster_shambler(edict_t *self);
|
||||
void SP_monster_soldier_hypergun(edict_t *self);
|
||||
void SP_monster_soldier_lasergun(edict_t *self);
|
||||
void SP_monster_soldier_ripper(edict_t *self);
|
||||
|
@ -352,6 +353,7 @@ static spawn_t spawns[] = {
|
|||
{"monster_makron", SP_monster_makron},
|
||||
{"monster_jorg", SP_monster_jorg},
|
||||
{"monster_commander_body", SP_monster_commander_body},
|
||||
{"monster_shambler", SP_monster_shambler},
|
||||
{"monster_soldier_hypergun", SP_monster_soldier_hypergun},
|
||||
{"monster_soldier_lasergun", SP_monster_soldier_lasergun},
|
||||
{"monster_soldier_ripper", SP_monster_soldier_ripper},
|
||||
|
|
|
@ -305,7 +305,8 @@ mmove_t guardian_atk1_out =
|
|||
guardian_run
|
||||
};
|
||||
|
||||
void guardian_atk1_finish(edict_t *self)
|
||||
void
|
||||
guardian_atk1_finish(edict_t *self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
|
@ -315,12 +316,14 @@ void guardian_atk1_finish(edict_t *self)
|
|||
self->monsterinfo.currentmove = &guardian_atk1_out;
|
||||
}
|
||||
|
||||
void guardian_atk1_charge(edict_t *self)
|
||||
void
|
||||
guardian_atk1_charge(edict_t *self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_charge, 1.f, ATTN_NORM, 0.f);
|
||||
}
|
||||
|
||||
void guardian_fire_blaster(edict_t *self)
|
||||
void
|
||||
guardian_fire_blaster(edict_t *self)
|
||||
{
|
||||
vec3_t forward, right, target;
|
||||
vec3_t start;
|
||||
|
@ -426,7 +429,8 @@ mmove_t guardian_move_atk2_out =
|
|||
guardian_run
|
||||
};
|
||||
|
||||
void guardian_atk2_out(edict_t *self)
|
||||
void
|
||||
guardian_atk2_out(edict_t *self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
|
@ -443,7 +447,8 @@ static vec3_t laser_positions[] = {
|
|||
{ 112.0f, -62.f, 60.f }
|
||||
};
|
||||
|
||||
void guardian_laser_fire(edict_t *self)
|
||||
void
|
||||
guardian_laser_fire(edict_t *self)
|
||||
{
|
||||
vec3_t forward, right, up;
|
||||
vec3_t tempang, start;
|
||||
|
|
719
src/game/monster/shambler/shambler.c
Normal file
719
src/game/monster/shambler/shambler.c
Normal file
|
@ -0,0 +1,719 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||
* Copyright (c) ZeniMax Media Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* SHAMBLER
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include "../../header/local.h"
|
||||
#include "shambler.h"
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_idle;
|
||||
static int sound_die;
|
||||
static int sound_sight;
|
||||
static int sound_windup;
|
||||
static int sound_melee1;
|
||||
static int sound_melee2;
|
||||
static int sound_smack;
|
||||
static int sound_boom;
|
||||
|
||||
//
|
||||
// misc
|
||||
//
|
||||
|
||||
void
|
||||
shambler_sight(edict_t* self, edict_t* other)
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
static vec3_t lightning_left_hand[] = {
|
||||
{ 44, 36, 25},
|
||||
{ 10, 44, 57},
|
||||
{ -1, 40, 70},
|
||||
{ -10, 34, 75},
|
||||
{ 7.4f, 24, 89 }
|
||||
};
|
||||
|
||||
static vec3_t lightning_right_hand[] = {
|
||||
{ 28, -38, 25},
|
||||
{ 31, -7, 70},
|
||||
{ 20, 0, 80},
|
||||
{ 16, 1.2f, 81},
|
||||
{ 27, -11, 83 }
|
||||
};
|
||||
|
||||
void
|
||||
shambler_lightning_update(edict_t *self)
|
||||
{
|
||||
edict_t *lightning;
|
||||
vec3_t f, r;
|
||||
|
||||
if (self->s.frame >= FRAME_magic01 + sizeof(lightning_left_hand) / sizeof(*lightning_left_hand))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lightning = G_Spawn();
|
||||
lightning->s.modelindex = gi.modelindex("models/proj/lightning/tris.md2");
|
||||
lightning->s.renderfx |= RF_BEAM;
|
||||
lightning->owner = self;
|
||||
|
||||
AngleVectors(self->s.angles, f, r, NULL);
|
||||
G_ProjectSource(self->s.origin, lightning_left_hand[self->s.frame - FRAME_magic01], f, r, lightning->s.origin);
|
||||
G_ProjectSource(self->s.origin, lightning_right_hand[self->s.frame - FRAME_magic01], f, r, lightning->s.old_origin);
|
||||
gi.linkentity(lightning);
|
||||
}
|
||||
|
||||
void shambler_windup(edict_t* self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
|
||||
|
||||
shambler_lightning_update(self);
|
||||
}
|
||||
|
||||
void
|
||||
shambler_idle(edict_t* self)
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
|
||||
}
|
||||
|
||||
void
|
||||
shambler_maybe_idle(edict_t* self)
|
||||
{
|
||||
if (random() > 0.8)
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// stand
|
||||
//
|
||||
|
||||
static mframe_t shambler_frames_stand[] =
|
||||
{
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{ai_stand, 0, NULL},
|
||||
{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 shambler_move_stand =
|
||||
{
|
||||
FRAME_stand01,
|
||||
FRAME_stand17,
|
||||
shambler_frames_stand,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
shambler_stand(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_move_stand;
|
||||
}
|
||||
|
||||
//
|
||||
// walk
|
||||
//
|
||||
|
||||
void shambler_walk(edict_t* self);
|
||||
|
||||
static mframe_t shambler_frames_walk[] =
|
||||
{
|
||||
{ai_walk, 10, NULL}, /* FIXME: add footsteps? */
|
||||
{ai_walk, 9, NULL},
|
||||
{ai_walk, 9, NULL},
|
||||
{ai_walk, 5, NULL},
|
||||
{ai_walk, 6, NULL},
|
||||
{ai_walk, 12, NULL},
|
||||
{ai_walk, 8, NULL},
|
||||
{ai_walk, 3, NULL},
|
||||
{ai_walk, 13, NULL},
|
||||
{ai_walk, 9, NULL},
|
||||
{ai_walk, 7, shambler_maybe_idle},
|
||||
{ai_walk, 5, NULL},
|
||||
};
|
||||
|
||||
mmove_t shambler_move_walk =
|
||||
{
|
||||
FRAME_walk01,
|
||||
FRAME_walk12,
|
||||
shambler_frames_walk,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
shambler_walk(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_move_walk;
|
||||
}
|
||||
|
||||
//
|
||||
// run
|
||||
//
|
||||
|
||||
void shambler_run(edict_t* self);
|
||||
|
||||
static mframe_t shambler_frames_run[] =
|
||||
{
|
||||
{ai_run, 20, NULL}, /* FIXME: add footsteps? */
|
||||
{ai_run, 24, NULL},
|
||||
{ai_run, 20, NULL},
|
||||
{ai_run, 20, NULL},
|
||||
{ai_run, 24, NULL},
|
||||
{ai_run, 20, shambler_maybe_idle},
|
||||
};
|
||||
|
||||
mmove_t shambler_move_run =
|
||||
{
|
||||
FRAME_run01,
|
||||
FRAME_run06,
|
||||
shambler_frames_run,
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
shambler_run(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->enemy && self->enemy->client)
|
||||
{
|
||||
self->monsterinfo.aiflags |= AI_BRUTAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_BRUTAL;
|
||||
}
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_move_stand;
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_move_run;
|
||||
}
|
||||
|
||||
//
|
||||
// pain
|
||||
//
|
||||
|
||||
// FIXME: needs halved explosion damage
|
||||
|
||||
static mframe_t shambler_frames_pain[] = {
|
||||
{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 shambler_move_pain =
|
||||
{
|
||||
FRAME_pain01,
|
||||
FRAME_pain06,
|
||||
shambler_frames_pain,
|
||||
shambler_run
|
||||
};
|
||||
|
||||
void
|
||||
shambler_pain(edict_t *self, edict_t *other /* unused */,
|
||||
float kick /* unused */, int damage /* unused */)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (level.time < self->timestamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->timestamp = level.time + (1.0f / 1000.0f);
|
||||
gi.sound(self, CHAN_AUTO, sound_pain, 1, ATTN_NORM, 0);
|
||||
|
||||
if (damage <= 30 && random() > 0.2f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If hard or nightmare, don't go into pain while attacking */
|
||||
if (skill->value >= SKILL_HARDPLUS)
|
||||
{
|
||||
if ((self->s.frame >= FRAME_smash01) && (self->s.frame <= FRAME_smash12))
|
||||
return;
|
||||
|
||||
if ((self->s.frame >= FRAME_swingl01) && (self->s.frame <= FRAME_swingl09))
|
||||
return;
|
||||
|
||||
if ((self->s.frame >= FRAME_swingr01) && (self->s.frame <= FRAME_swingr09))
|
||||
return;
|
||||
}
|
||||
|
||||
if (skill->value == SKILL_HARDPLUS)
|
||||
{
|
||||
return; /* no pain anims in nightmare */
|
||||
}
|
||||
|
||||
if (level.time < self->pain_debounce_time)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->pain_debounce_time = level.time + 2;
|
||||
self->monsterinfo.currentmove = &shambler_move_pain;
|
||||
}
|
||||
|
||||
/*
|
||||
* attacks
|
||||
*/
|
||||
|
||||
void
|
||||
ShamblerSaveLoc(edict_t* self)
|
||||
{
|
||||
/* save for aiming the shot */
|
||||
VectorCopy(self->enemy->s.origin, self->pos1);
|
||||
self->pos1[2] += self->enemy->viewheight;
|
||||
self->monsterinfo.nextframe = FRAME_magic09;
|
||||
|
||||
gi.sound(self, CHAN_WEAPON, sound_boom, 1, ATTN_NORM, 0);
|
||||
shambler_lightning_update(self);
|
||||
}
|
||||
|
||||
void
|
||||
ShamblerCastLightning(edict_t* self)
|
||||
{
|
||||
vec3_t start;
|
||||
vec3_t forward, right, target;
|
||||
vec3_t offset = {0, 0, 60.f};
|
||||
|
||||
if (!self->enemy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AngleVectors(self->s.angles, forward, right, NULL);
|
||||
G_ProjectSource(self->s.origin, offset, forward, right, start);
|
||||
VectorCopy(self->enemy->s.origin, target);
|
||||
target[2] += self->enemy->viewheight;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
target[i] += (randk() % 10) - 5.f;
|
||||
}
|
||||
|
||||
/* calc direction to where we targeted */
|
||||
VectorSubtract(target, start, forward);
|
||||
VectorNormalize(forward);
|
||||
|
||||
/* TODO should be tesla effect */
|
||||
monster_fire_railgun(self, start, forward, 2, 1000, MZ2_WIDOW_RAIL);
|
||||
}
|
||||
|
||||
static mframe_t shambler_frames_magic[] = {
|
||||
{ai_charge, 0, shambler_windup},
|
||||
{ai_charge, 0, shambler_lightning_update},
|
||||
{ai_charge, 0, shambler_lightning_update},
|
||||
{ai_move, 0, shambler_lightning_update},
|
||||
{ai_move, 0, shambler_lightning_update},
|
||||
{ai_move, 0, ShamblerSaveLoc},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_charge, 0, NULL},
|
||||
{ai_move, 0, ShamblerCastLightning},
|
||||
{ai_move, 0, ShamblerCastLightning},
|
||||
{ai_move, 0, ShamblerCastLightning},
|
||||
{ai_move, 0, NULL},
|
||||
};
|
||||
|
||||
mmove_t shambler_attack_magic =
|
||||
{
|
||||
FRAME_magic01,
|
||||
FRAME_magic12,
|
||||
shambler_frames_magic,
|
||||
shambler_run
|
||||
};
|
||||
|
||||
void
|
||||
shambler_attack(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_attack_magic;
|
||||
}
|
||||
|
||||
//
|
||||
// melee
|
||||
//
|
||||
|
||||
void shambler_melee1(edict_t* self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_melee1, 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
void shambler_melee2(edict_t* self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_melee2, 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
void sham_swingl9(edict_t* self);
|
||||
void sham_swingr9(edict_t* self);
|
||||
|
||||
void sham_smash10(edict_t* self)
|
||||
{
|
||||
if (!self->enemy)
|
||||
return;
|
||||
|
||||
ai_charge(self, 0);
|
||||
|
||||
if (!CanDamage(self->enemy, self))
|
||||
return;
|
||||
|
||||
vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 };
|
||||
if (fire_hit(self, aim, (110 + (randk() % 10)), 120))
|
||||
{
|
||||
/* Slower attack */
|
||||
gi.sound(self, CHAN_WEAPON, sound_smack, 1, ATTN_NORM, 0);
|
||||
}
|
||||
};
|
||||
|
||||
void ShamClaw(edict_t* self)
|
||||
{
|
||||
if (!self->enemy)
|
||||
return;
|
||||
|
||||
ai_charge(self, 10);
|
||||
|
||||
if (!CanDamage(self->enemy, self))
|
||||
return;
|
||||
|
||||
vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 };
|
||||
if (fire_hit(self, aim, (70 + (randk() % 10)), 80))
|
||||
{
|
||||
/* Slower attack */
|
||||
gi.sound(self, CHAN_WEAPON, sound_smack, 1, ATTN_NORM, 0);
|
||||
}
|
||||
};
|
||||
|
||||
static mframe_t shambler_frames_smash[] = {
|
||||
{ai_charge, 2, shambler_melee1},
|
||||
{ai_charge, 6},
|
||||
{ai_charge, 6},
|
||||
{ai_charge, 5},
|
||||
{ai_charge, 4},
|
||||
{ai_charge, 1},
|
||||
{ai_charge, 0},
|
||||
{ai_charge, 0},
|
||||
{ai_charge, 0},
|
||||
{ai_charge, 0, sham_smash10},
|
||||
{ai_charge, 5},
|
||||
{ai_charge, 4},
|
||||
};
|
||||
|
||||
mmove_t shambler_attack_smash =
|
||||
{
|
||||
FRAME_smash01,
|
||||
FRAME_smash12,
|
||||
shambler_frames_smash,
|
||||
shambler_run
|
||||
};
|
||||
|
||||
static mframe_t shambler_frames_swingl[] = {
|
||||
{ai_charge, 5, shambler_melee1},
|
||||
{ai_charge, 3},
|
||||
{ai_charge, 7},
|
||||
{ai_charge, 3},
|
||||
{ai_charge, 7},
|
||||
{ai_charge, 9},
|
||||
{ai_charge, 5, ShamClaw},
|
||||
{ai_charge, 4},
|
||||
{ai_charge, 8, sham_swingl9},
|
||||
};
|
||||
|
||||
mmove_t shambler_attack_swingl =
|
||||
{
|
||||
FRAME_swingl01,
|
||||
FRAME_swingl09,
|
||||
shambler_frames_swingl,
|
||||
shambler_run
|
||||
};
|
||||
|
||||
static mframe_t shambler_frames_swingr[] = {
|
||||
{ai_charge, 1, shambler_melee2},
|
||||
{ai_charge, 8},
|
||||
{ai_charge, 14},
|
||||
{ai_charge, 7},
|
||||
{ai_charge, 3},
|
||||
{ai_charge, 6},
|
||||
{ai_charge, 6, ShamClaw},
|
||||
{ai_charge, 3},
|
||||
{ai_charge, 8, sham_swingr9},
|
||||
};
|
||||
|
||||
mmove_t shambler_attack_swingr =
|
||||
{
|
||||
FRAME_swingr01,
|
||||
FRAME_swingr09,
|
||||
shambler_frames_swingr,
|
||||
shambler_run
|
||||
};
|
||||
|
||||
void
|
||||
sham_swingl9(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ai_charge(self, 8);
|
||||
|
||||
if (self->enemy)
|
||||
{
|
||||
float real_enemy_range;
|
||||
|
||||
real_enemy_range = realrange(self, self->enemy);
|
||||
|
||||
if ((randk() % 2) && self->enemy && real_enemy_range < MELEE_DISTANCE)
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_attack_swingr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sham_swingr9(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ai_charge(self, 1);
|
||||
ai_charge(self, 10);
|
||||
|
||||
if (self->enemy)
|
||||
{
|
||||
float real_enemy_range;
|
||||
|
||||
real_enemy_range = realrange(self, self->enemy);
|
||||
|
||||
if ((randk() % 2) && self->enemy && real_enemy_range < MELEE_DISTANCE)
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_attack_swingl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
shambler_melee(edict_t* self)
|
||||
{
|
||||
float chance = random();
|
||||
if (chance > 0.6 || self->health == 600)
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_attack_smash;
|
||||
}
|
||||
else if (chance > 0.3)
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_attack_swingl;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->monsterinfo.currentmove = &shambler_attack_swingr;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// death
|
||||
//
|
||||
|
||||
void
|
||||
shambler_dead(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
shambler_shrink(edict_t* self)
|
||||
{
|
||||
self->maxs[2] = 0;
|
||||
self->svflags |= SVF_DEADMONSTER;
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
static mframe_t shambler_frames_death[] = {
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, shambler_shrink},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL},
|
||||
{ai_move, 0, NULL}, /* FIXME: thud? */
|
||||
};
|
||||
|
||||
mmove_t shambler_move_death =
|
||||
{
|
||||
FRAME_death01,
|
||||
FRAME_death11,
|
||||
shambler_frames_death,
|
||||
shambler_dead
|
||||
};
|
||||
|
||||
void
|
||||
shambler_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
|
||||
int damage, vec3_t point /* unused */)
|
||||
{
|
||||
/* check for gib */
|
||||
if (self->health <= self->gib_health)
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
|
||||
|
||||
/* FIXME: better gibs for shambler, shambler head */
|
||||
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 = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->deadflag)
|
||||
return;
|
||||
|
||||
// regular death
|
||||
gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
|
||||
self->deadflag = true;
|
||||
self->takedamage = true;
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_move_death;
|
||||
}
|
||||
|
||||
void SP_monster_shambler(edict_t* self)
|
||||
{
|
||||
if (!self)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (deathmatch->value)
|
||||
{
|
||||
G_FreeEdict(self);
|
||||
return;
|
||||
}
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/shambler/tris.md2");
|
||||
VectorSet (self->mins, -32, -32, -24);
|
||||
VectorSet (self->maxs, 32, 32, 64);
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
gi.modelindex("models/proj/lightning/tris.md2");
|
||||
sound_pain = gi.soundindex("shambler/shurt2.wav");
|
||||
sound_idle = gi.soundindex("shambler/sidle.wav");
|
||||
sound_die = gi.soundindex("shambler/sdeath.wav");
|
||||
sound_windup = gi.soundindex("shambler/sattck1.wav");
|
||||
sound_melee1 = gi.soundindex("shambler/melee1.wav");
|
||||
sound_melee2 = gi.soundindex("shambler/melee2.wav");
|
||||
sound_sight = gi.soundindex("shambler/ssight.wav");
|
||||
sound_smack = gi.soundindex("shambler/smack.wav");
|
||||
sound_boom = gi.soundindex("shambler/sboom.wav");
|
||||
|
||||
self->health = 600;
|
||||
self->gib_health = -60;
|
||||
|
||||
self->mass = 500;
|
||||
|
||||
self->pain = shambler_pain;
|
||||
self->die = shambler_die;
|
||||
self->monsterinfo.stand = shambler_stand;
|
||||
self->monsterinfo.walk = shambler_walk;
|
||||
self->monsterinfo.run = shambler_run;
|
||||
self->monsterinfo.dodge = NULL;
|
||||
self->monsterinfo.attack = shambler_attack;
|
||||
self->monsterinfo.melee = shambler_melee;
|
||||
self->monsterinfo.sight = shambler_sight;
|
||||
self->monsterinfo.idle = shambler_idle;
|
||||
self->monsterinfo.blocked = NULL;
|
||||
|
||||
gi.linkentity(self);
|
||||
|
||||
if (self->spawnflags & 1)
|
||||
{
|
||||
self->monsterinfo.aiflags |= AI_IGNORE_SHOTS;
|
||||
}
|
||||
|
||||
self->monsterinfo.currentmove = &shambler_move_stand;
|
||||
self->monsterinfo.scale = MODEL_SCALE;
|
||||
|
||||
walkmonster_start(self);
|
||||
}
|
124
src/game/monster/shambler/shambler.h
Normal file
124
src/game/monster/shambler/shambler.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (C) 1997-2001 Id Software 30 Inc.
|
||||
* Copyright (c) ZeniMax Media Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License 30 or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful 30 but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not 30 write to the Free Software
|
||||
* Foundation 30 Inc. 30 59 Temple Place - Suite 330 30 Boston 30 MA
|
||||
* 02111-1307 30 USA.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* Tank and Tank Commander animations.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#define FRAME_stand01 0
|
||||
#define FRAME_stand02 1
|
||||
#define FRAME_stand03 2
|
||||
#define FRAME_stand04 3
|
||||
#define FRAME_stand05 4
|
||||
#define FRAME_stand06 5
|
||||
#define FRAME_stand07 6
|
||||
#define FRAME_stand08 7
|
||||
#define FRAME_stand09 8
|
||||
#define FRAME_stand10 9
|
||||
#define FRAME_stand11 10
|
||||
#define FRAME_stand12 11
|
||||
#define FRAME_stand13 12
|
||||
#define FRAME_stand14 13
|
||||
#define FRAME_stand15 14
|
||||
#define FRAME_stand16 15
|
||||
#define FRAME_stand17 16
|
||||
#define FRAME_stand18 17
|
||||
#define FRAME_walk01 18
|
||||
#define FRAME_walk02 19
|
||||
#define FRAME_walk03 20
|
||||
#define FRAME_walk04 21
|
||||
#define FRAME_walk05 22
|
||||
#define FRAME_walk06 23
|
||||
#define FRAME_walk07 24
|
||||
#define FRAME_walk08 25
|
||||
#define FRAME_walk09 26
|
||||
#define FRAME_walk10 27
|
||||
#define FRAME_walk11 28
|
||||
#define FRAME_walk12 29
|
||||
#define FRAME_run01 30
|
||||
#define FRAME_run02 31
|
||||
#define FRAME_run03 32
|
||||
#define FRAME_run04 33
|
||||
#define FRAME_run05 34
|
||||
#define FRAME_run06 35
|
||||
#define FRAME_smash01 36
|
||||
#define FRAME_smash02 37
|
||||
#define FRAME_smash03 38
|
||||
#define FRAME_smash04 39
|
||||
#define FRAME_smash05 40
|
||||
#define FRAME_smash06 41
|
||||
#define FRAME_smash07 42
|
||||
#define FRAME_smash08 43
|
||||
#define FRAME_smash09 44
|
||||
#define FRAME_smash10 45
|
||||
#define FRAME_smash11 46
|
||||
#define FRAME_smash12 47
|
||||
#define FRAME_swingr01 48
|
||||
#define FRAME_swingr02 49
|
||||
#define FRAME_swingr03 50
|
||||
#define FRAME_swingr04 51
|
||||
#define FRAME_swingr05 52
|
||||
#define FRAME_swingr06 53
|
||||
#define FRAME_swingr07 54
|
||||
#define FRAME_swingr08 55
|
||||
#define FRAME_swingr09 56
|
||||
#define FRAME_swingl01 57
|
||||
#define FRAME_swingl02 58
|
||||
#define FRAME_swingl03 59
|
||||
#define FRAME_swingl04 60
|
||||
#define FRAME_swingl05 61
|
||||
#define FRAME_swingl06 62
|
||||
#define FRAME_swingl07 63
|
||||
#define FRAME_swingl08 64
|
||||
#define FRAME_swingl09 65
|
||||
#define FRAME_magic01 66
|
||||
#define FRAME_magic02 67
|
||||
#define FRAME_magic03 68
|
||||
#define FRAME_magic04 69
|
||||
#define FRAME_magic05 70
|
||||
#define FRAME_magic06 71
|
||||
#define FRAME_magic07 72
|
||||
#define FRAME_magic08 73
|
||||
#define FRAME_magic09 74
|
||||
#define FRAME_magic10 75
|
||||
#define FRAME_magic11 76
|
||||
#define FRAME_magic12 77
|
||||
#define FRAME_pain01 78
|
||||
#define FRAME_pain02 79
|
||||
#define FRAME_pain03 80
|
||||
#define FRAME_pain04 81
|
||||
#define FRAME_pain05 82
|
||||
#define FRAME_pain06 83
|
||||
#define FRAME_death01 84
|
||||
#define FRAME_death02 85
|
||||
#define FRAME_death03 86
|
||||
#define FRAME_death04 87
|
||||
#define FRAME_death05 88
|
||||
#define FRAME_death06 89
|
||||
#define FRAME_death07 90
|
||||
#define FRAME_death08 91
|
||||
#define FRAME_death09 92
|
||||
#define FRAME_death10 93
|
||||
#define FRAME_death11 94
|
||||
|
||||
#define MODEL_SCALE 1.000000
|
Loading…
Reference in a new issue