328 %{ #include "Entities/StdH/StdH.h" #include "Models/Enemies/Fishman/fishman.h" %} uses "Entities/EnemyDive"; %{ static EntityInfo eiFishmanGround = { EIBT_FLESH, 100.0f, 0.0f, 1.4f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiFishmanLiquid = { EIBT_FLESH, 33.3f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; #define FIRE_WATER FLOAT3D(0.0f, 0.3f, -1.1f) #define FIRE_GROUND FLOAT3D(0.0f, 0.8f, -1.25f) #define SPEAR_HIT 1.75f %} class CFishman : CEnemyDive { name "Fishman"; thumbnail "Thumbnails\\Fishman.tbn"; properties: components: 0 class CLASS_BASE "Classes\\EnemyDive.ecl", 1 model MODEL_FISHMAN "Models\\Enemies\\Fishman\\Fishman.mdl", 2 texture TEXTURE_FISHMAN "Models\\Enemies\\Fishman\\Fishman.tex", // ************** SOUNDS ************** 50 sound SOUND_IDLE_WATER "Models\\Enemies\\Fishman\\Sounds\\IdleWater.wav", 51 sound SOUND_IDLE_GROUND "Models\\Enemies\\Fishman\\Sounds\\IdleGround.wav", 52 sound SOUND_SIGHT_WATER "Models\\Enemies\\Fishman\\Sounds\\SightWater.wav", 53 sound SOUND_SIGHT_GROUND "Models\\Enemies\\Fishman\\Sounds\\SightGround.wav", 54 sound SOUND_WOUND_WATER "Models\\Enemies\\Fishman\\Sounds\\WoundWater.wav", 55 sound SOUND_WOUND_GROUND "Models\\Enemies\\Fishman\\Sounds\\WoundGround.wav", 56 sound SOUND_DEATH_WATER "Models\\Enemies\\Fishman\\Sounds\\DeathWater.wav", 57 sound SOUND_DEATH_GROUND "Models\\Enemies\\Fishman\\Sounds\\DeathGround.wav", 58 sound SOUND_FIRE "Models\\Enemies\\Fishman\\Sounds\\Fire.wav", 59 sound SOUND_KICK "Models\\Enemies\\Fishman\\Sounds\\Kick.wav", functions: /* Entity info */ void *GetEntityInfo(void) { if (m_bInLiquid) { return &eiFishmanLiquid; } else { return &eiFishmanGround; } }; /* Receive damage */ void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) { // fishman can't harm fishman if (!IsOfClass(penInflictor, "Fishman")) { CEnemyDive::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); } }; // damage anim INDEX AnimForDamage(FLOAT fDamage) { INDEX iAnim; if (m_bInLiquid) { switch (IRnd()%2) { case 0: iAnim = FISHMAN_ANIM_WATERWOUND01; break; case 1: iAnim = FISHMAN_ANIM_WATERWOUND02; break; default: ASSERTALWAYS("Fishman unknown liquid damage"); } } else { switch (IRnd()%3) { case 0: iAnim = FISHMAN_ANIM_GROUNDWOUND03; break; case 1: iAnim = FISHMAN_ANIM_GROUNDWOUND04; break; case 2: iAnim = FISHMAN_ANIM_GROUNDWOUND05; break; default: ASSERTALWAYS("Fishman unknown ground damage"); } } StartModelAnim(iAnim, 0); return iAnim; }; // death INDEX AnimForDeath(void) { INDEX iAnim; if (m_bInLiquid) { iAnim = FISHMAN_ANIM_WATERDEATH; } else { iAnim = FISHMAN_ANIM_GROUNDDEATH; } StartModelAnim(iAnim, 0); return iAnim; }; void DeathNotify(void) { if (m_bInLiquid) { ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_DEATH_WATER); } else { ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_DEATH_GROUND); } en_fDensity = 500.0f; }; // virtual anim functions void StandingAnim(void) { if (m_bInLiquid) { StartModelAnim(FISHMAN_ANIM_WATERSTAND, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(FISHMAN_ANIM_GROUNDSTAND, AOF_LOOPING|AOF_NORESTART); } }; void WalkingAnim(void) { if (m_bInLiquid) { StartModelAnim(FISHMAN_ANIM_WATERSWIM02, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(FISHMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); } }; void RunningAnim(void) { if (m_bInLiquid) { StartModelAnim(FISHMAN_ANIM_WATERSWIM01, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(FISHMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART); } }; void RotatingAnim(void) { if (m_bInLiquid) { StartModelAnim(FISHMAN_ANIM_WATERSWIM02, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(FISHMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); } }; void ChangeCollisionToLiquid() { ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_WATER); }; void ChangeCollisionToGround() { ChangeCollisionBoxIndexWhenPossible(FISHMAN_COLLISION_BOX_GROUND); }; // virtual sound functions void IdleSound(void) { if (m_bInLiquid) { PlaySound(m_soSound, SOUND_IDLE_WATER , SOF_3D); } else { PlaySound(m_soSound, SOUND_IDLE_GROUND, SOF_3D); } }; void SightSound(void) { if (m_bInLiquid) { PlaySound(m_soSound, SOUND_SIGHT_WATER , SOF_3D); } else { PlaySound(m_soSound, SOUND_SIGHT_GROUND, SOF_3D); } }; void WoundSound(void) { if (m_bInLiquid) { PlaySound(m_soSound, SOUND_WOUND_WATER , SOF_3D); } else { PlaySound(m_soSound, SOUND_WOUND_GROUND, SOF_3D); } }; void DeathSound(void) { if (m_bInLiquid) { PlaySound(m_soSound, SOUND_DEATH_WATER , SOF_3D); } else { PlaySound(m_soSound, SOUND_DEATH_GROUND, SOF_3D); } }; procedures: /************************************************************ * A T T A C K E N E M Y * ************************************************************/ DiveFire(EVoid) : CEnemyDive::DiveFire { // fire projectile StartModelAnim(FISHMAN_ANIM_WATERATTACK02, 0); autowait(0.4f); ShootProjectile(PRT_FISHMAN_FIRE, FIRE_WATER, ANGLE3D(0, 0, 0)); PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.95f); StandingAnim(); autowait(FRnd()/3 + _pTimer->TickQuantum); return EReturn(); }; DiveHit(EVoid) : CEnemyDive::DiveHit { if (CalcDist(m_penEnemy) > SPEAR_HIT) { // run to enemy m_fShootTime = _pTimer->CurrentTick() + 0.25f; return EReturn(); } // attack with spear StartModelAnim(FISHMAN_ANIM_WATERATTACK01, 0); // to left hit autowait(0.5f); PlaySound(m_soSound, SOUND_KICK, SOF_3D); if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; vDirection.Normalize(); InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 5.0f, FLOAT3D(0, 0, 0), vDirection); // push target away FLOAT3D vSpeed; GetHeadingDirection(0.0f, vSpeed); vSpeed = vSpeed * 5.0f; KickEntity(m_penEnemy, vSpeed); } autowait(0.5f); StandingAnim(); autowait(0.2f + FRnd()/3); return EReturn(); }; Fire(EVoid) : CEnemyBase::Fire { // wait anim end if (!GetModelObject()->IsAnimFinished()) { autowait(GetModelObject()->GetCurrentAnimLength() - GetModelObject()->GetPassedTime()); } // fire projectile StartModelAnim(FISHMAN_ANIM_GROUNDATTACK02, 0); autowait(0.3f); ShootProjectile(PRT_FISHMAN_FIRE, FIRE_GROUND, ANGLE3D(0, 0, 0)); PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.4f); StandingAnim(); autowait(FRnd()/3 + _pTimer->TickQuantum); return EReturn(); }; Hit(EVoid) : CEnemyBase::Hit { if (CalcDist(m_penEnemy) > SPEAR_HIT) { // run to enemy m_fShootTime = _pTimer->CurrentTick() + 0.25f; return EReturn(); } // wait anim end if (!GetModelObject()->IsAnimFinished()) { autowait(GetModelObject()->GetCurrentAnimLength() - GetModelObject()->GetPassedTime()); } // attack with spear StartModelAnim(FISHMAN_ANIM_GROUNDATTACKLOOP, 0); // to left hit autowait(0.5f); PlaySound(m_soSound, SOUND_KICK, SOF_3D); if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; vDirection.Normalize(); InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 2.5f, FLOAT3D(0, 0, 0), vDirection); // push target left FLOAT3D vSpeed; GetHeadingDirection(90.0f, vSpeed); vSpeed = vSpeed * 5.0f; KickEntity(m_penEnemy, vSpeed); } autowait(0.5f); PlaySound(m_soSound, SOUND_KICK, SOF_3D); if (CalcDist(m_penEnemy)GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; vDirection.Normalize(); InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 2.5f, FLOAT3D(0, 0, 0), vDirection); // push target right FLOAT3D vSpeed; GetHeadingDirection(-90.0f, vSpeed); vSpeed = vSpeed * 5.0f; KickEntity(m_penEnemy, vSpeed); } autowait(0.6f); StandingAnim(); autowait(0.2f + FRnd()/3); return EReturn(); }; /************************************************************ * M A I N * ************************************************************/ Main(EVoid) { // declare yourself as a model InitAsModel(); SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS|EPF_HASGILLS); SetCollisionFlags(ECF_MODEL); SetFlags(GetFlags()|ENF_ALIVE); SetHealth(30.0f); m_fMaxHealth = 30.0f; en_tmMaxHoldBreath = 5.0f; en_fDensity = 1000.0f; // set your appearance SetModel(MODEL_FISHMAN); SetModelMainTexture(TEXTURE_FISHMAN); // setup moving speed m_fWalkSpeed = FRnd() + 1.5f; m_aWalkRotateSpeed = FRnd()*10.0f + 500.0f; m_fAttackRunSpeed = FRnd()*0.5f + 5.0f; m_aAttackRotateSpeed = FRnd()*50 + 245.0f; m_fCloseRunSpeed = FRnd()*0.5f + 5.0f; m_aCloseRotateSpeed = FRnd()*50 + 245.0f; // setup attack distances m_fAttackDistance = 50.0f; m_fCloseDistance = 5.0f; m_fStopDistance = 0.0f; m_fAttackFireTime = 3.0f; m_fCloseFireTime = 2.0f; m_fIgnoreRange = 200.0f; // fly moving properties m_fDiveWalkSpeed = FRnd() + 3.0f; m_aDiveWalkRotateSpeed = FRnd()*10.0f + 500.0f; m_fDiveAttackRunSpeed = FRnd()*4.0f + 14.0f; m_aDiveAttackRotateSpeed = FRnd()*25 + 500.0f; m_fDiveCloseRunSpeed = FRnd()*2.0f + 8.0f; m_aDiveCloseRotateSpeed = FRnd()*50 + 800.0f; // attack properties m_fDiveAttackDistance = 50.0f; m_fDiveCloseDistance = 3.0f; m_fDiveStopDistance = 0.0f; m_fDiveAttackFireTime = 3.0f; m_fDiveCloseFireTime = 2.0f; m_fDiveIgnoreRange = 200.0f; // damage/explode properties m_fBlowUpAmount = 60.0f; m_fBodyParts = 4; m_fDamageWounded = 15.0f; m_iScore = 500; // continue behavior in base class jump CEnemyDive::MainLoop(); }; };