diff --git a/Makefile b/Makefile index 2f3e50a6..0b1bbe98 100644 --- a/Makefile +++ b/Makefile @@ -909,6 +909,7 @@ GAME_OBJS_ = \ src/game/monster/gekk/gekk.o \ src/game/monster/gladiator/gladb.o \ src/game/monster/gladiator/gladiator.o \ + src/game/monster/guardian/guardian.o \ src/game/monster/gunner/gunner.o \ src/game/monster/hover/hover.o \ src/game/monster/infantry/infantry.o \ diff --git a/src/common/szone.c b/src/common/szone.c index afb689e1..d9f672c7 100644 --- a/src/common/szone.c +++ b/src/common/szone.c @@ -50,18 +50,19 @@ SZ_GetSpace(sizebuf_t *buf, int length) { if (!buf->allowoverflow) { - Com_Error(ERR_FATAL, "SZ_GetSpace: overflow without allowoverflow set"); + Com_Error(ERR_FATAL, "%s: overflow without allowoverflow set", + __func__); } if (length > buf->maxsize) { - Com_Error(ERR_FATAL, "SZ_GetSpace: %i is > full buffer size", - length); + Com_Error(ERR_FATAL, "%s: %i is > full buffer size", + __func__, length); } SZ_Clear(buf); buf->overflowed = true; - Com_Printf("SZ_GetSpace: overflow\n"); + Com_Printf("%s: overflow\n", __func__); } data = buf->data + buf->cursize; diff --git a/src/game/g_misc.c b/src/game/g_misc.c index 7d0be413..fc46560e 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -193,7 +193,7 @@ gib_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unu } void -ThrowGib(edict_t *self, char *gibname, int damage, int type) +ThrowGib(edict_t *self, const char *gibname, int damage, int type) { edict_t *gib; vec3_t vd; @@ -262,7 +262,7 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type) } void -ThrowHead(edict_t *self, char *gibname, int damage, int type) +ThrowHead(edict_t *self, const char *gibname, int damage, int type) { vec3_t vd; float vscale; @@ -319,7 +319,7 @@ ThrowHead(edict_t *self, char *gibname, int damage, int type) } void -ThrowGibACID(edict_t *self, char *gibname, int damage, int type) +ThrowGibACID(edict_t *self, const char *gibname, int damage, int type) { edict_t *gib; vec3_t vd; @@ -387,7 +387,7 @@ ThrowGibACID(edict_t *self, char *gibname, int damage, int type) } void -ThrowHeadACID(edict_t *self, char *gibname, int damage, int type) +ThrowHeadACID(edict_t *self, const char *gibname, int damage, int type) { vec3_t vd; float vscale; diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index ce855f9e..cf9561b3 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -135,6 +135,7 @@ void SP_monster_berserk(edict_t *self); void SP_monster_gladiator(edict_t *self); void SP_monster_gunner(edict_t *self); void SP_monster_guncmdr(edict_t *self); +void SP_monster_guardian(edict_t *self); void SP_monster_infantry(edict_t *self); void SP_monster_soldier_light(edict_t *self); void SP_monster_soldier(edict_t *self); @@ -328,6 +329,7 @@ static spawn_t spawns[] = { {"monster_gladiator", SP_monster_gladiator}, {"monster_gunner", SP_monster_gunner}, {"monster_guncmdr", SP_monster_guncmdr}, + {"monster_guardian", SP_monster_guardian}, {"monster_infantry", SP_monster_infantry}, {"monster_soldier_light", SP_monster_soldier_light}, {"monster_soldier", SP_monster_soldier}, diff --git a/src/game/header/local.h b/src/game/header/local.h index 92fba34f..950f6cc6 100644 --- a/src/game/header/local.h +++ b/src/game/header/local.h @@ -878,12 +878,12 @@ void stationarymonster_start(edict_t *self); void monster_done_dodge(edict_t *self); /* g_misc.c */ -void ThrowHead(edict_t *self, char *gibname, int damage, int type); +void ThrowHead(edict_t *self, const char *gibname, int damage, int type); void ThrowClientHead(edict_t *self, int damage); -void ThrowGib(edict_t *self, char *gibname, int damage, int type); +void ThrowGib(edict_t *self, const char *gibname, int damage, int type); void BecomeExplosion1(edict_t *self); -void ThrowHeadACID(edict_t *self, char *gibname, int damage, int type); -void ThrowGibACID(edict_t *self, char *gibname, int damage, int type); +void ThrowHeadACID(edict_t *self, const char *gibname, int damage, int type); +void ThrowGibACID(edict_t *self, const char *gibname, int damage, int type); /* g_ai.c */ void AI_SetSightClient(void); diff --git a/src/game/monster/guardian/guardian.c b/src/game/monster/guardian/guardian.c new file mode 100644 index 00000000..37f17714 --- /dev/null +++ b/src/game/monster/guardian/guardian.c @@ -0,0 +1,776 @@ +/* + * 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. + * + * ======================================================================= + * + * The Guardian. + * + * ======================================================================= + */ + +#include "../../header/local.h" +#include "guardian.h" + +void BossExplode(edict_t *self); + +static int sound_charge; +static int sound_spin_loop; + +// +// stand +// + +static mframe_t guardian_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}, + {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} +}; + +mmove_t guardian_move_stand = +{ + FRAME_idle1, + FRAME_idle52, + guardian_frames_stand, + NULL +}; + +void +guardian_stand(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_move_stand; +} + +// +// walk +// + +static int sound_step; + +void guardian_footstep(edict_t *self) +{ + gi.sound(self, CHAN_BODY, sound_step, 1.f, ATTN_NORM, 0.0f); +} + +static mframe_t guardian_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, guardian_footstep}, + {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, guardian_footstep}, + {ai_walk, 8, NULL} +}; + +mmove_t guardian_move_walk = +{ + FRAME_walk1, + FRAME_walk19, + guardian_frames_walk, + NULL +}; + +void +guardian_walk(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_move_walk; +} + +// +// run +// + +static mframe_t guardian_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, guardian_footstep}, + {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, guardian_footstep}, + {ai_run, 8, NULL} +}; + +mmove_t guardian_move_run = +{ + FRAME_walk1, + FRAME_walk19, + guardian_frames_run, + NULL +}; + +void +guardian_run(edict_t *self) +{ + if (!self) + { + return; + } + + if (self->monsterinfo.aiflags & AI_STAND_GROUND) + { + self->monsterinfo.currentmove = &guardian_move_stand; + return; + } + + self->monsterinfo.currentmove = &guardian_move_run; +} + +// +// pain +// + +static mframe_t guardian_frames_pain1[] = { + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {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 guardian_move_pain1 = +{ + FRAME_pain1_1, + FRAME_pain1_8, + guardian_frames_pain1, + guardian_run +}; + +void +guardian_pain(edict_t *self, edict_t *other /* other */, + float kick /* other */, int damage) +{ + if (!self) + { + return; + } + + if (damage <= 10) + { + return; + } + + if (level.time < self->pain_debounce_time) + { + return; + } + + if (damage <= 75) + { + if (random() > 0.2) + { + return; + } + } + + /* don't go into pain while attacking */ + if ((self->s.frame >= FRAME_atk1_spin1) && (self->s.frame <= FRAME_atk1_spin15)) + { + return; + } + + if ((self->s.frame >= FRAME_atk2_fire1) && (self->s.frame <= FRAME_atk2_fire4)) + { + return; + } + + if ((self->s.frame >= FRAME_kick_in1) && (self->s.frame <= FRAME_kick_in13)) + { + return; + } + + self->pain_debounce_time = level.time + 3; + + if (skill->value == SKILL_HARDPLUS) + { + return; /* no pain anims in nightmare */ + } + + self->monsterinfo.currentmove = &guardian_move_pain1; +} + +static mframe_t guardian_frames_atk1_out[] = { + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL} +}; + +mmove_t guardian_atk1_out = +{ + FRAME_atk1_out1, + FRAME_atk1_out3, + guardian_frames_atk1_out, + guardian_run +}; + +void guardian_atk1_finish(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_atk1_out; +} + +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) +{ + vec3_t forward, right, target; + vec3_t start; + int id = MZ2_TANK_BLASTER_1; + + AngleVectors(self->s.angles, forward, right, NULL); + G_ProjectSource(self->s.origin, monster_flash_offset[id], 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); + + monster_fire_blaster(self, start, forward, 2, 1000, id, (self->s.frame % 4) ? 0 : EF_HYPERBLASTER); + + if (self->enemy && self->enemy->health > 0 && + self->s.frame == FRAME_atk1_spin12 && self->timestamp > level.time && visible(self, self->enemy)) + self->monsterinfo.nextframe = FRAME_atk1_spin5; +} + +void +guardian_hyper_sound(edict_t *self) +{ + if (!self) + { + return; + } + + gi.sound(self, CHAN_WEAPON, sound_spin_loop, 1.f, ATTN_NORM, 0.f); +} + +static mframe_t guardian_frames_atk1_spin[] = { + {ai_charge, 0, guardian_atk1_charge}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_hyper_sound}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0, guardian_fire_blaster}, + {ai_charge, 0}, + {ai_charge, 0}, + {ai_charge, 0} +}; + +mmove_t guardian_move_atk1_spin = +{ + FRAME_atk1_spin1, + FRAME_atk1_spin15, + guardian_frames_atk1_spin, + guardian_atk1_finish +}; + +void guardian_atk1(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_move_atk1_spin; + self->timestamp = level.time + 0.650f + (randk() % 10 ) / 10.f * 1.5f; +} + +static mframe_t guardian_frames_atk1_in[] = { + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL} +}; + +mmove_t guardian_move_atk1_in = +{ + FRAME_atk1_in1, + FRAME_atk1_in3, + guardian_frames_atk1_in, + guardian_atk1 +}; + +static mframe_t guardian_frames_atk2_out[] = { + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL} +}; + +mmove_t guardian_move_atk2_out = +{ + FRAME_atk2_out1, + FRAME_atk2_out7, + guardian_frames_atk2_out, + guardian_run +}; + +void guardian_atk2_out(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_move_atk2_out; +} + +static int sound_laser; + +static vec3_t laser_positions[] = { + { 125.0f, -70.f, 60.f}, + { 112.0f, -62.f, 60.f } +}; + +void guardian_laser_fire(edict_t *self) +{ + vec3_t forward, right, up; + vec3_t tempang, start; + vec3_t dir, angles, end; + vec3_t tempvec; + edict_t *ent; + + if (!self) + { + return; + } + + gi.sound(self, CHAN_WEAPON, sound_laser, 1.f, ATTN_NORM, 0.f); + + 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(laser_positions[1 - (self->s.frame & 1)], tempvec); + + 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); + + 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 = 25; + + monster_dabeam(ent); +} + +static mframe_t guardian_frames_atk2_fire[] = { + {ai_charge, 0, guardian_laser_fire}, + {ai_charge, 0, guardian_laser_fire}, + {ai_charge, 0, guardian_laser_fire}, + {ai_charge, 0, guardian_laser_fire } +}; + +mmove_t guardian_move_atk2_fire = +{ + FRAME_atk2_fire1, + FRAME_atk2_fire4, + guardian_frames_atk2_fire, + guardian_atk2_out +}; + +void guardian_atk2(edict_t *self) +{ + if (!self) + { + return; + } + + self->monsterinfo.currentmove = &guardian_move_atk2_fire; +} + +static mframe_t guardian_frames_atk2_in[] = { + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL} +}; + +mmove_t guardian_move_atk2_in = +{ + FRAME_atk2_in1, + FRAME_atk2_in12, + guardian_frames_atk2_in, + guardian_atk2 +}; + +void +guardian_kick(edict_t *self) +{ + vec3_t aim = {MELEE_DISTANCE, 0, -80}; + fire_hit(self, aim, 85, 700); +} + +static mframe_t guardian_frames_kick[] = +{ + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_kick}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL}, + {ai_charge, 0, guardian_footstep}, + {ai_charge, 0, NULL}, + {ai_charge, 0, NULL} +}; + +mmove_t guardian_move_kick = +{ + FRAME_kick_in1, + FRAME_kick_in13, + guardian_frames_kick, + guardian_run +}; + +void +guardian_attack(edict_t *self) +{ + float r; + + if (!self->enemy || !self->enemy->inuse) + { + return; + } + + r = realrange(self, self->enemy); + + if (r > RANGE_NEAR) + { + self->monsterinfo.currentmove = &guardian_move_atk2_in; + } + else if (r < 120.f) + { + self->monsterinfo.currentmove = &guardian_move_kick; + } + else + { + self->monsterinfo.currentmove = &guardian_move_atk1_in; + } +} + +// +// death +// + +void guardian_explode(edict_t *self) +{ + vec3_t start, pos; + int i; + + VectorAdd(self->s.origin, self->mins, start); + + VectorCopy(self->size, pos); + for (i = 0; i < 3; i++) + { + pos[i] *= random(); + } + + VectorAdd(start, pos, pos); + + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_EXPLOSION1_BIG); + gi.WritePosition(pos); + gi.multicast(self->s.origin, MULTICAST_ALL); +} + +static const char *gibs[] = { + "models/monsters/guardian/gib1.md2", + "models/monsters/guardian/gib2.md2", + "models/monsters/guardian/gib3.md2", + "models/monsters/guardian/gib4.md2", + "models/monsters/guardian/gib5.md2", + "models/monsters/guardian/gib6.md2", + "models/monsters/guardian/gib7.md2" +}; + +void guardian_dead(edict_t *self) +{ + int i, n; + + for (i = 0; i < 3; i++) + { + guardian_explode(self); + } + + for (n = 0; n < 2; n++) + { + ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", + 125, GIB_ORGANIC); + } + + for (n = 0; n < 4; n++) + { + ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", + 125, GIB_METALLIC); + } + + for (n = 0; n < 6; n++) + { + for (i = 0; i < 2; i++) + { + ThrowGib(self, gibs[n], 125, GIB_METALLIC); + } + } + + ThrowHead(self, gibs[6], 125, GIB_METALLIC); +} + +static mframe_t guardian_frames_death1[FRAME_death26 - FRAME_death1 + 1] = { + {ai_move, 0, BossExplode}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {ai_move, 0, NULL}, + {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 guardian_move_death = +{ + FRAME_death1, + FRAME_death26, + guardian_frames_death1, + guardian_dead +}; + +void +guardian_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */, + int damage, vec3_t point /* unused */) +{ + if (!self) + { + return; + } + + /* regular death */ + self->deadflag = true; + self->takedamage = true; + + self->monsterinfo.currentmove = &guardian_move_death; +} + +// +// monster_tank +// + +/* + * QUAKED monster_guardian (1 .5 0) (-96 -96 -66) (96 96 62) Ambush Trigger_Spawn Sight + */ +void +SP_monster_guardian(edict_t *self) +{ + int i; + + if (!self) + { + return; + } + + if (deathmatch->value) + { + G_FreeEdict(self); + return; + } + + sound_step = gi.soundindex("zortemp/step.wav"); + sound_charge = gi.soundindex("weapons/hyprbu1a.wav"); + sound_spin_loop = gi.soundindex("weapons/hyprbl1a.wav"); + sound_laser = gi.soundindex("weapons/laser2.wav"); + + for(i = 0; i < sizeof(gibs) / sizeof(*gibs); i++) + { + gi.modelindex(gibs[i]); + } + + self->s.modelindex = gi.modelindex("models/monsters/guardian/tris.md2"); + VectorSet(self->mins, -96, -96, -66); + VectorSet(self->maxs, 96, 96, 62); + self->movetype = MOVETYPE_STEP; + self->solid = SOLID_BBOX; + + self->health = 2500; + self->gib_health = -200; + + self->monsterinfo.scale = MODEL_SCALE; + + self->mass = 850; + + self->pain = guardian_pain; + self->die = guardian_die; + self->monsterinfo.stand = guardian_stand; + self->monsterinfo.walk = guardian_walk; + self->monsterinfo.run = guardian_run; + self->monsterinfo.attack = guardian_attack; + + gi.linkentity(self); + + self->monsterinfo.currentmove = &guardian_move_stand; + + walkmonster_start(self); +} diff --git a/src/game/monster/guardian/guardian.h b/src/game/monster/guardian/guardian.h new file mode 100644 index 00000000..4807349d --- /dev/null +++ b/src/game/monster/guardian/guardian.h @@ -0,0 +1,244 @@ +/* + * 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. + * + * ======================================================================= + * + * Guardian animations. + * + * ======================================================================= + */ + +#define FRAME_sleep1 0 +#define FRAME_sleep2 1 +#define FRAME_sleep3 2 +#define FRAME_sleep4 3 +#define FRAME_sleep5 4 +#define FRAME_sleep6 5 +#define FRAME_sleep7 6 +#define FRAME_sleep8 7 +#define FRAME_sleep9 8 +#define FRAME_sleep10 9 +#define FRAME_sleep11 10 +#define FRAME_sleep12 11 +#define FRAME_sleep13 12 +#define FRAME_sleep14 13 +#define FRAME_death1 14 +#define FRAME_death2 15 +#define FRAME_death3 16 +#define FRAME_death4 17 +#define FRAME_death5 18 +#define FRAME_death6 19 +#define FRAME_death7 20 +#define FRAME_death8 21 +#define FRAME_death9 22 +#define FRAME_death10 23 +#define FRAME_death11 24 +#define FRAME_death12 25 +#define FRAME_death13 26 +#define FRAME_death14 27 +#define FRAME_death15 28 +#define FRAME_death16 29 +#define FRAME_death17 30 +#define FRAME_death18 31 +#define FRAME_death19 32 +#define FRAME_death20 33 +#define FRAME_death21 34 +#define FRAME_death22 35 +#define FRAME_death23 36 +#define FRAME_death24 37 +#define FRAME_death25 38 +#define FRAME_death26 39 +#define FRAME_atk1_out1 40 +#define FRAME_atk1_out2 41 +#define FRAME_atk1_out3 42 +#define FRAME_atk2_out1 43 +#define FRAME_atk2_out2 44 +#define FRAME_atk2_out3 45 +#define FRAME_atk2_out4 46 +#define FRAME_atk2_out5 47 +#define FRAME_atk2_out6 48 +#define FRAME_atk2_out7 49 +#define FRAME_kick_out1 50 +#define FRAME_kick_out2 51 +#define FRAME_kick_out3 52 +#define FRAME_kick_out4 53 +#define FRAME_kick_out5 54 +#define FRAME_kick_out6 55 +#define FRAME_kick_out7 56 +#define FRAME_kick_out8 57 +#define FRAME_kick_out9 58 +#define FRAME_kick_out10 59 +#define FRAME_kick_out11 60 +#define FRAME_kick_out12 61 +#define FRAME_pain1_1 62 +#define FRAME_pain1_2 63 +#define FRAME_pain1_3 64 +#define FRAME_pain1_4 65 +#define FRAME_pain1_5 66 +#define FRAME_pain1_6 67 +#define FRAME_pain1_7 68 +#define FRAME_pain1_8 69 +#define FRAME_idle1 70 +#define FRAME_idle2 71 +#define FRAME_idle3 72 +#define FRAME_idle4 73 +#define FRAME_idle5 74 +#define FRAME_idle6 75 +#define FRAME_idle7 76 +#define FRAME_idle8 77 +#define FRAME_idle9 78 +#define FRAME_idle10 79 +#define FRAME_idle11 80 +#define FRAME_idle12 81 +#define FRAME_idle13 82 +#define FRAME_idle14 83 +#define FRAME_idle15 84 +#define FRAME_idle16 85 +#define FRAME_idle17 86 +#define FRAME_idle18 87 +#define FRAME_idle19 88 +#define FRAME_idle20 89 +#define FRAME_idle21 90 +#define FRAME_idle22 91 +#define FRAME_idle23 92 +#define FRAME_idle24 93 +#define FRAME_idle25 94 +#define FRAME_idle26 95 +#define FRAME_idle27 96 +#define FRAME_idle28 97 +#define FRAME_idle29 98 +#define FRAME_idle30 99 +#define FRAME_idle31 100 +#define FRAME_idle32 101 +#define FRAME_idle33 102 +#define FRAME_idle34 103 +#define FRAME_idle35 104 +#define FRAME_idle36 105 +#define FRAME_idle37 106 +#define FRAME_idle38 107 +#define FRAME_idle39 108 +#define FRAME_idle40 109 +#define FRAME_idle41 110 +#define FRAME_idle42 111 +#define FRAME_idle43 112 +#define FRAME_idle44 113 +#define FRAME_idle45 114 +#define FRAME_idle46 115 +#define FRAME_idle47 116 +#define FRAME_idle48 117 +#define FRAME_idle49 118 +#define FRAME_idle50 119 +#define FRAME_idle51 120 +#define FRAME_idle52 121 +#define FRAME_atk1_in1 122 +#define FRAME_atk1_in2 123 +#define FRAME_atk1_in3 124 +#define FRAME_kick_in1 125 +#define FRAME_kick_in2 126 +#define FRAME_kick_in3 127 +#define FRAME_kick_in4 128 +#define FRAME_kick_in5 129 +#define FRAME_kick_in6 130 +#define FRAME_kick_in7 131 +#define FRAME_kick_in8 132 +#define FRAME_kick_in9 133 +#define FRAME_kick_in10 134 +#define FRAME_kick_in11 135 +#define FRAME_kick_in12 136 +#define FRAME_kick_in13 137 +#define FRAME_walk1 138 +#define FRAME_walk2 139 +#define FRAME_walk3 140 +#define FRAME_walk4 141 +#define FRAME_walk5 142 +#define FRAME_walk6 143 +#define FRAME_walk7 144 +#define FRAME_walk8 145 +#define FRAME_walk9 146 +#define FRAME_walk10 147 +#define FRAME_walk11 148 +#define FRAME_walk12 149 +#define FRAME_walk13 150 +#define FRAME_walk14 151 +#define FRAME_walk15 152 +#define FRAME_walk16 153 +#define FRAME_walk17 154 +#define FRAME_walk18 155 +#define FRAME_walk19 156 +#define FRAME_wake1 157 +#define FRAME_wake2 158 +#define FRAME_wake3 159 +#define FRAME_wake4 160 +#define FRAME_wake5 161 +#define FRAME_atk1_spin1 162 +#define FRAME_atk1_spin2 163 +#define FRAME_atk1_spin3 164 +#define FRAME_atk1_spin4 165 +#define FRAME_atk1_spin5 166 +#define FRAME_atk1_spin6 167 +#define FRAME_atk1_spin7 168 +#define FRAME_atk1_spin8 169 +#define FRAME_atk1_spin9 170 +#define FRAME_atk1_spin10 171 +#define FRAME_atk1_spin11 172 +#define FRAME_atk1_spin12 173 +#define FRAME_atk1_spin13 174 +#define FRAME_atk1_spin14 175 +#define FRAME_atk1_spin15 176 +#define FRAME_atk2_fire1 177 +#define FRAME_atk2_fire2 178 +#define FRAME_atk2_fire3 179 +#define FRAME_atk2_fire4 180 +#define FRAME_turnl_1 181 +#define FRAME_turnl_2 182 +#define FRAME_turnl_3 183 +#define FRAME_turnl_4 184 +#define FRAME_turnl_5 185 +#define FRAME_turnl_6 186 +#define FRAME_turnl_7 187 +#define FRAME_turnl_8 188 +#define FRAME_turnl_9 189 +#define FRAME_turnl_10 190 +#define FRAME_turnl_11 191 +#define FRAME_turnr_1 192 +#define FRAME_turnr_2 193 +#define FRAME_turnr_3 194 +#define FRAME_turnr_4 195 +#define FRAME_turnr_5 196 +#define FRAME_turnr_6 197 +#define FRAME_turnr_7 198 +#define FRAME_turnr_8 199 +#define FRAME_turnr_9 200 +#define FRAME_turnr_10 201 +#define FRAME_turnr_11 202 +#define FRAME_atk2_in1 203 +#define FRAME_atk2_in2 204 +#define FRAME_atk2_in3 205 +#define FRAME_atk2_in4 206 +#define FRAME_atk2_in5 207 +#define FRAME_atk2_in6 208 +#define FRAME_atk2_in7 209 +#define FRAME_atk2_in8 210 +#define FRAME_atk2_in9 211 +#define FRAME_atk2_in10 212 +#define FRAME_atk2_in11 213 +#define FRAME_atk2_in12 214 + +#define MODEL_SCALE 1.000000 diff --git a/src/game/monster/soldier/soldier.c b/src/game/monster/soldier/soldier.c index 4df145f5..07f89880 100644 --- a/src/game/monster/soldier/soldier.c +++ b/src/game/monster/soldier/soldier.c @@ -2630,7 +2630,7 @@ soldierh_laserbeam(edict_t *self, int flash_index) VectorCopy(tempang, ent->s.angles); VectorCopy(ent->s.origin, start); - if (flash_index == 85) + if (flash_index == MZ2_SOLDIER_MACHINEGUN_3) { VectorMA(start, tempvec[0] - 14, right, start); VectorMA(start, tempvec[2] + 8, up, start); diff --git a/src/game/savegame/tables/gamefunc_decs.h b/src/game/savegame/tables/gamefunc_decs.h index dd718112..bab8ca05 100644 --- a/src/game/savegame/tables/gamefunc_decs.h +++ b/src/game/savegame/tables/gamefunc_decs.h @@ -235,6 +235,7 @@ extern void ThrowWidowGibLoc ( edict_t * self , char * gibname , int damage , in extern void ThrowWidowGib ( edict_t * self , char * gibname , int damage , int type ) ; extern void widow_gib_touch ( edict_t * self , edict_t * other , cplane_t * plane , csurface_t * surf ) ; extern void WidowVelocityForDamage ( int damage , vec3_t v ) ; +extern void SP_monster_guardian(edict_t *self); extern void SP_monster_widow2 ( edict_t * self ) ; extern void Widow2Precache ( void ) ; extern qboolean Widow2_CheckAttack ( edict_t * self ) ; @@ -1499,10 +1500,10 @@ extern void BecomeExplosion1 ( edict_t * self ) ; extern void ThrowDebris ( edict_t * self , char * modelname , float speed , vec3_t origin ) ; extern void debris_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ; extern void ThrowClientHead ( edict_t * self , int damage ) ; -extern void ThrowHeadACID ( edict_t * self , char * gibname , int damage , int type ) ; -extern void ThrowGibACID ( edict_t * self , char * gibname , int damage , int type ) ; -extern void ThrowHead ( edict_t * self , char * gibname , int damage , int type ) ; -extern void ThrowGib ( edict_t * self , char * gibname , int damage , int type ) ; +extern void ThrowHeadACID ( edict_t * self , const char * gibname , int damage , int type ) ; +extern void ThrowGibACID ( edict_t * self , const char * gibname , int damage , int type ) ; +extern void ThrowHead ( edict_t * self , const char * gibname , int damage , int type ) ; +extern void ThrowGib ( edict_t * self , const char * gibname , int damage , int type ) ; extern void gib_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ; extern void gib_touch ( edict_t * self , edict_t * other , cplane_t * plane , csurface_t * surf ) ; extern void gib_think ( edict_t * self ) ; diff --git a/src/game/savegame/tables/gamefunc_list.h b/src/game/savegame/tables/gamefunc_list.h index 47117a58..c2691143 100644 --- a/src/game/savegame/tables/gamefunc_list.h +++ b/src/game/savegame/tables/gamefunc_list.h @@ -237,6 +237,7 @@ {"ThrowWidowGib", (byte *)ThrowWidowGib}, {"widow_gib_touch", (byte *)widow_gib_touch}, {"WidowVelocityForDamage", (byte *)WidowVelocityForDamage}, +{"SP_monster_guardian", (byte *)SP_monster_guardian}, {"SP_monster_widow2", (byte *)SP_monster_widow2}, {"Widow2Precache", (byte *)Widow2Precache}, {"Widow2_CheckAttack", (byte *)Widow2_CheckAttack},