#include "monsters" const string Q1_KNIGHT_MODEL = "models/quake1/m_knight.mdl"; const string Q1_KNIGHT_IDLE = "quake1/monsters/knight/idle.wav"; const string Q1_KNIGHT_SIGHT = "quake1/monsters/knight/sight.wav"; const string Q1_KNIGHT_PAIN = "quake1/monsters/knight/pain.wav"; const string Q1_KNIGHT_DEATH = "quake1/monsters/knight/death.wav"; const string Q1_KNIGHT_MELEE = "quake1/monsters/knight/melee.wav"; enum Q1_KNIGHT_EVENTS { KNIGHT_START_RUNATTACK = 1, KNIGHT_END_RUNATTACK = 2, KNIGHT_IDLE_SOUND = 3 } class monster_qknight : ScriptBaseMonsterEntity, monster_qgeneric { void Spawn() { Precache(); g_EntityFuncs.SetModel(self, Q1_KNIGHT_MODEL); g_EntityFuncs.SetSize(self.pev, Vector(-16, -16, -24), Vector(16, 16, 40)); self.m_bloodColor = BLOOD_COLOR_RED; self.pev.health = 75; self.pev.solid = SOLID_SLIDEBOX; self.pev.movetype = MOVETYPE_STEP; self.StartMonster(); self.m_MonsterState = MONSTERSTATE_NONE; self.m_FormattedName = "Knight"; self.pev.pain_finished = 0.0; self.pev.yaw_speed = 15; m_iGibHealth = -50; WalkMonsterInit(); } void Precache() { g_Game.PrecacheModel(Q1_KNIGHT_MODEL); g_SoundSystem.PrecacheSound(Q1_KNIGHT_IDLE); g_SoundSystem.PrecacheSound(Q1_KNIGHT_SIGHT); g_SoundSystem.PrecacheSound(Q1_KNIGHT_DEATH); g_SoundSystem.PrecacheSound(Q1_KNIGHT_MELEE); g_SoundSystem.PrecacheSound(Q1_KNIGHT_PAIN); } void MonsterIdle() { m_iAIState = STATE_IDLE; SetActivity(ACT_IDLE); m_flMonsterSpeed = 0; } void MonsterSight() { g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_KNIGHT_SIGHT, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf)); } void MonsterWalk() { m_iAIState = STATE_WALK; SetActivity(ACT_WALK); m_flMonsterSpeed = 5; AI_Turn(); } void MonsterRun() { m_iAIState = STATE_RUN; SetActivity(ACT_RUN); m_flMonsterSpeed = 18; } void MonsterMeleeAttack() { if (!m_hEnemy) return; CBaseEntity@ pEnemy = m_hEnemy; m_iAIState = STATE_ATTACK; float flDist = (pEnemy.EyePosition() - self.EyePosition()).Length(); g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_WEAPON, Q1_KNIGHT_MELEE, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf)); if( flDist < 80 ){ SetActivity(ACT_MELEE_ATTACK1); m_flMonsterSpeed = 0; } else { SetActivity(ACT_MELEE_ATTACK2); m_flMonsterSpeed = 18; } } void MonsterPain(CBaseEntity@ pAttacker, float flDamage) { if (self.pev.pain_finished > g_Engine.time) return; m_iAIState = STATE_PAIN; SetActivity(ACT_BIG_FLINCH); g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_KNIGHT_PAIN, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf)); self.pev.pain_finished = g_Engine.time + 1; } bool MonsterHasMissileAttack() { return false; } bool MonsterHasMeleeAttack() { return true; } bool MonsterHasPain() { return true; } void MonsterAttack() { if (m_fAttackDone) { MonsterRun(); m_fAttackDone = false; } if (m_flMonsterSpeed != 0) { // we in runattack! if (m_fInAttack) { AI_Melee_Side(); } else { AI_Charge_Side(); } } else { AI_Charge(5); // standard attack if (m_fInAttack) AI_Melee(); } } void MonsterKilled(entvars_t@ pevAttacker, int iGib) { if (ShouldGibMonster(iGib)) { g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, "quake1/gib.wav", Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf)); g_EntityFuncs.SpawnRandomGibs(self.pev, 1, 1); g_EntityFuncs.Remove(self); return; } g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_KNIGHT_DEATH, Math.RandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + Math.RandomLong(0, 0xf)); } void HandleAnimEvent(MonsterEvent@ pEvent) { switch (pEvent.event) { case KNIGHT_START_RUNATTACK: m_fInAttack = true; break; case KNIGHT_END_RUNATTACK: m_fInAttack = false; m_fAttackDone = true; break; case KNIGHT_IDLE_SOUND: if (Math.RandomFloat(0, 1) < 0.05) g_SoundSystem.EmitSoundDyn(self.edict(), CHAN_VOICE, Q1_KNIGHT_IDLE, Math.RandomFloat(0.95, 1.0), ATTN_IDLE, 0, 93 + Math.RandomLong(0, 0xf)); break; default: BaseClass.HandleAnimEvent(pEvent); } } } void q1_RegisterMonster_KNIGHT() { g_CustomEntityFuncs.RegisterCustomEntity("monster_qknight", "monster_qknight"); }