mirror of
https://github.com/id-Software/quake2-rerelease-dll.git
synced 2026-03-20 00:49:33 +01:00
Initial commit
This commit is contained in:
385
rerelease/m_arachnid.cpp
Normal file
385
rerelease/m_arachnid.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
// Copyright (c) ZeniMax Media Inc.
|
||||
// Licensed under the GNU General Public License 2.0.
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
TANK
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
#include "m_arachnid.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_death;
|
||||
static int sound_sight;
|
||||
|
||||
MONSTERINFO_SIGHT(arachnid_sight) (edict_t *self, edict_t *other) -> void
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// stand
|
||||
//
|
||||
|
||||
mframe_t arachnid_frames_stand[] = {
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand },
|
||||
{ ai_stand }
|
||||
};
|
||||
MMOVE_T(arachnid_move_stand) = { FRAME_idle1, FRAME_idle13, arachnid_frames_stand, nullptr };
|
||||
|
||||
MONSTERINFO_STAND(arachnid_stand) (edict_t *self) -> void
|
||||
{
|
||||
M_SetAnimation(self, &arachnid_move_stand);
|
||||
}
|
||||
|
||||
//
|
||||
// walk
|
||||
//
|
||||
|
||||
static int sound_step;
|
||||
|
||||
void arachnid_footstep(edict_t *self)
|
||||
{
|
||||
gi.sound(self, CHAN_BODY, sound_step, 0.5f, ATTN_IDLE, 0.0f);
|
||||
}
|
||||
|
||||
mframe_t arachnid_frames_walk[] = {
|
||||
{ ai_walk, 8, arachnid_footstep },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8, arachnid_footstep },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 },
|
||||
{ ai_walk, 8 }
|
||||
};
|
||||
MMOVE_T(arachnid_move_walk) = { FRAME_walk1, FRAME_walk10, arachnid_frames_walk, nullptr };
|
||||
|
||||
MONSTERINFO_WALK(arachnid_walk) (edict_t *self) -> void
|
||||
{
|
||||
M_SetAnimation(self, &arachnid_move_walk);
|
||||
}
|
||||
|
||||
//
|
||||
// run
|
||||
//
|
||||
|
||||
mframe_t arachnid_frames_run[] = {
|
||||
{ ai_run, 8, arachnid_footstep },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8, arachnid_footstep },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 },
|
||||
{ ai_run, 8 }
|
||||
};
|
||||
MMOVE_T(arachnid_move_run) = { FRAME_walk1, FRAME_walk10, arachnid_frames_run, nullptr };
|
||||
|
||||
MONSTERINFO_RUN(arachnid_run) (edict_t *self) -> void
|
||||
{
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
M_SetAnimation(self, &arachnid_move_stand);
|
||||
return;
|
||||
}
|
||||
|
||||
M_SetAnimation(self, &arachnid_move_run);
|
||||
}
|
||||
|
||||
//
|
||||
// pain
|
||||
//
|
||||
|
||||
mframe_t arachnid_frames_pain1[] = {
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move }
|
||||
};
|
||||
MMOVE_T(arachnid_move_pain1) = { FRAME_pain11, FRAME_pain15, arachnid_frames_pain1, arachnid_run };
|
||||
|
||||
mframe_t arachnid_frames_pain2[] = {
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move }
|
||||
};
|
||||
MMOVE_T(arachnid_move_pain2) = { FRAME_pain21, FRAME_pain26, arachnid_frames_pain2, arachnid_run };
|
||||
|
||||
PAIN(arachnid_pain) (edict_t *self, edict_t *other, float kick, int damage, const mod_t &mod) -> void
|
||||
{
|
||||
if (level.time < self->pain_debounce_time)
|
||||
return;
|
||||
|
||||
self->pain_debounce_time = level.time + 3_sec;
|
||||
gi.sound(self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
|
||||
|
||||
if (!M_ShouldReactToPain(self, mod))
|
||||
return; // no pain anims in nightmare
|
||||
|
||||
float r = frandom();
|
||||
|
||||
if (r < 0.5f)
|
||||
M_SetAnimation(self, &arachnid_move_pain1);
|
||||
else
|
||||
M_SetAnimation(self, &arachnid_move_pain2);
|
||||
}
|
||||
|
||||
static int sound_charge;
|
||||
|
||||
void arachnid_charge_rail(edict_t *self)
|
||||
{
|
||||
if (!self->enemy || !self->enemy->inuse)
|
||||
return;
|
||||
|
||||
gi.sound(self, CHAN_WEAPON, sound_charge, 1.f, ATTN_NORM, 0.f);
|
||||
self->pos1 = self->enemy->s.origin;
|
||||
self->pos1[2] += self->enemy->viewheight;
|
||||
}
|
||||
|
||||
void arachnid_rail(edict_t *self)
|
||||
{
|
||||
vec3_t start;
|
||||
vec3_t dir;
|
||||
vec3_t forward, right;
|
||||
monster_muzzleflash_id_t id;
|
||||
|
||||
switch (self->s.frame)
|
||||
{
|
||||
case FRAME_rails4:
|
||||
default:
|
||||
id = MZ2_ARACHNID_RAIL1;
|
||||
break;
|
||||
case FRAME_rails8:
|
||||
id = MZ2_ARACHNID_RAIL2;
|
||||
break;
|
||||
case FRAME_rails_up7:
|
||||
id = MZ2_ARACHNID_RAIL_UP1;
|
||||
break;
|
||||
case FRAME_rails_up11:
|
||||
id = MZ2_ARACHNID_RAIL_UP2;
|
||||
break;
|
||||
}
|
||||
|
||||
AngleVectors(self->s.angles, forward, right, nullptr);
|
||||
start = M_ProjectFlashSource(self, monster_flash_offset[id], forward, right);
|
||||
|
||||
// calc direction to where we targeted
|
||||
dir = self->pos1 - start;
|
||||
dir.normalize();
|
||||
|
||||
monster_fire_railgun(self, start, dir, 35, 100, id);
|
||||
}
|
||||
|
||||
mframe_t arachnid_frames_attack1[] = {
|
||||
{ ai_charge, 0, arachnid_charge_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_rail },
|
||||
{ ai_charge, 0, arachnid_charge_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge }
|
||||
};
|
||||
MMOVE_T(arachnid_attack1) = { FRAME_rails1, FRAME_rails11, arachnid_frames_attack1, arachnid_run };
|
||||
|
||||
mframe_t arachnid_frames_attack_up1[] = {
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_charge_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_rail },
|
||||
{ ai_charge, 0, arachnid_charge_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_rail },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
};
|
||||
MMOVE_T(arachnid_attack_up1) = { FRAME_rails_up1, FRAME_rails_up16, arachnid_frames_attack_up1, arachnid_run };
|
||||
|
||||
static int sound_melee, sound_melee_hit;
|
||||
|
||||
void arachnid_melee_charge(edict_t *self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_melee, 1.f, ATTN_NORM, 0.f);
|
||||
}
|
||||
|
||||
void arachnid_melee_hit(edict_t *self)
|
||||
{
|
||||
if (!fire_hit(self, { MELEE_DISTANCE, 0, 0 }, 15, 50))
|
||||
self->monsterinfo.melee_debounce_time = level.time + 1000_ms;
|
||||
}
|
||||
|
||||
mframe_t arachnid_frames_melee[] = {
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_melee_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_melee_hit },
|
||||
{ ai_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_melee_charge },
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, arachnid_melee_hit },
|
||||
{ ai_charge }
|
||||
};
|
||||
MMOVE_T(arachnid_melee) = { FRAME_melee_atk1, FRAME_melee_atk12, arachnid_frames_melee, arachnid_run };
|
||||
|
||||
MONSTERINFO_ATTACK(arachnid_attack) (edict_t *self) -> void
|
||||
{
|
||||
if (!self->enemy || !self->enemy->inuse)
|
||||
return;
|
||||
|
||||
if (self->monsterinfo.melee_debounce_time < level.time && range_to(self, self->enemy) < MELEE_DISTANCE)
|
||||
M_SetAnimation(self, &arachnid_melee);
|
||||
else if ((self->enemy->s.origin[2] - self->s.origin[2]) > 150.f)
|
||||
M_SetAnimation(self, &arachnid_attack_up1);
|
||||
else
|
||||
M_SetAnimation(self, &arachnid_attack1);
|
||||
}
|
||||
|
||||
//
|
||||
// death
|
||||
//
|
||||
|
||||
void arachnid_dead(edict_t *self)
|
||||
{
|
||||
self->mins = { -16, -16, -24 };
|
||||
self->maxs = { 16, 16, -8 };
|
||||
self->movetype = MOVETYPE_TOSS;
|
||||
self->svflags |= SVF_DEADMONSTER;
|
||||
self->nextthink = 0_ms;
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
mframe_t arachnid_frames_death1[] = {
|
||||
{ ai_move, 0 },
|
||||
{ ai_move, -1.23f },
|
||||
{ ai_move, -1.23f },
|
||||
{ ai_move, -1.23f },
|
||||
{ ai_move, -1.23f },
|
||||
{ ai_move, -1.64f },
|
||||
{ ai_move, -1.64f },
|
||||
{ ai_move, -2.45f },
|
||||
{ ai_move, -8.63f },
|
||||
{ ai_move, -4.0f },
|
||||
{ ai_move, -4.5f },
|
||||
{ ai_move, -6.8f },
|
||||
{ ai_move, -8.0f },
|
||||
{ ai_move, -5.4f },
|
||||
{ ai_move, -3.4f },
|
||||
{ ai_move, -1.9f },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move }
|
||||
};
|
||||
MMOVE_T(arachnid_move_death) = { FRAME_death1, FRAME_death20, arachnid_frames_death1, arachnid_dead };
|
||||
|
||||
DIE(arachnid_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
|
||||
{
|
||||
// check for gib
|
||||
if (M_CheckGib(self, mod))
|
||||
{
|
||||
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
|
||||
ThrowGibs(self, damage, {
|
||||
{ 2, "models/objects/gibs/bone/tris.md2" },
|
||||
{ 4, "models/objects/gibs/sm_meat/tris.md2" },
|
||||
{ "models/objects/gibs/head2/tris.md2", GIB_HEAD }
|
||||
});
|
||||
self->deadflag = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->deadflag)
|
||||
return;
|
||||
|
||||
// regular death
|
||||
gi.sound(self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
|
||||
self->deadflag = true;
|
||||
self->takedamage = true;
|
||||
|
||||
M_SetAnimation(self, &arachnid_move_death);
|
||||
}
|
||||
|
||||
//
|
||||
// monster_arachnid
|
||||
//
|
||||
|
||||
/*QUAKED monster_arachnid (1 .5 0) (-48 -48 -20) (48 48 48) Ambush Trigger_Spawn Sight
|
||||
*/
|
||||
void SP_monster_arachnid(edict_t *self)
|
||||
{
|
||||
if ( !M_AllowSpawn( self ) ) {
|
||||
G_FreeEdict( self );
|
||||
return;
|
||||
}
|
||||
|
||||
sound_step = gi.soundindex("insane/insane11.wav");
|
||||
sound_charge = gi.soundindex("gladiator/railgun.wav");
|
||||
sound_melee = gi.soundindex("gladiator/melee3.wav");
|
||||
sound_melee_hit = gi.soundindex("gladiator/melee2.wav");
|
||||
sound_pain = gi.soundindex("arachnid/pain.wav");
|
||||
sound_death = gi.soundindex("arachnid/death.wav");
|
||||
sound_sight = gi.soundindex("arachnid/sight.wav");
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/arachnid/tris.md2");
|
||||
self->mins = { -48, -48, -20 };
|
||||
self->maxs = { 48, 48, 48 };
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
self->health = 1000 * st.health_multiplier;
|
||||
self->gib_health = -200;
|
||||
|
||||
self->monsterinfo.scale = MODEL_SCALE;
|
||||
|
||||
self->mass = 450;
|
||||
|
||||
self->pain = arachnid_pain;
|
||||
self->die = arachnid_die;
|
||||
self->monsterinfo.stand = arachnid_stand;
|
||||
self->monsterinfo.walk = arachnid_walk;
|
||||
self->monsterinfo.run = arachnid_run;
|
||||
self->monsterinfo.attack = arachnid_attack;
|
||||
self->monsterinfo.sight = arachnid_sight;
|
||||
|
||||
gi.linkentity(self);
|
||||
|
||||
M_SetAnimation(self, &arachnid_move_stand);
|
||||
|
||||
walkmonster_start(self);
|
||||
}
|
||||
Reference in New Issue
Block a user