336 %{ #include "Entities/StdH/StdH.h" #include "Models/Enemies/Beast/Beast.h" #include "Entities/WorldSettingsController.h" #include "Entities/BackgroundViewer.h" %} uses "Entities/EnemyBase"; uses "Entities/BasicEffects"; enum BeastType { 0 BT_NORMAL "Small", // normal (fighter) 1 BT_BIG "Big", // big }; %{ static int _tmLastStandingAnim =0; #define BEAST_STRETCH 2.0f #define BIG_BEAST_STRETCH 12.0f // info structure static EntityInfo eiBeastNormal = { EIBT_FLESH, 1500.0f, 0.0f, 2.0f*BEAST_STRETCH, 0.0f, // source (eyes) 0.0f, 1.5f*BEAST_STRETCH, 0.0f, // target (body) }; static EntityInfo eiBeastBig = { EIBT_FLESH, 5000.0f, 0.0f, 2.0f*BIG_BEAST_STRETCH, 0.0f, // source (eyes) 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f, // target (body) }; %} class CBeast : CEnemyBase { name "Beast"; thumbnail "Thumbnails\\Beast.tbn"; properties: 1 enum BeastType m_bcType "Character" 'C' = BT_NORMAL, 2 INDEX m_iCounter = 0, 3 BOOL m_bBeBoss "Boss" 'B' = FALSE, components: 0 class CLASS_BASE "Classes\\EnemyBase.ecl", 1 class CLASS_PROJECTILE "Classes\\Projectile.ecl", 10 model MODEL_BEAST "Models\\Enemies\\Beast\\Beast.mdl", 11 texture TEXTURE_BEAST_NORMAL "Models\\Enemies\\Beast\\Beast.tex", 12 texture TEXTURE_BEAST_BIG "Models\\Enemies\\Beast\\BeastBig.tex", // ************** SOUNDS ************** 50 sound SOUND_IDLE "Models\\Enemies\\Beast\\Sounds\\Idle.wav", 51 sound SOUND_SIGHT "Models\\Enemies\\Beast\\Sounds\\Sight.wav", 52 sound SOUND_WOUND "Models\\Enemies\\Beast\\Sounds\\Wound.wav", 53 sound SOUND_FIRE "Models\\Enemies\\Beast\\Sounds\\Fire.wav", 54 sound SOUND_KICK "Models\\Enemies\\Beast\\Sounds\\Kick.wav", 55 sound SOUND_DEATH "Models\\Enemies\\Beast\\Sounds\\Death.wav", 56 sound SOUND_DEATHBIG "Models\\Enemies\\Beast\\Sounds\\DeathBig.wav", 57 sound SOUND_ANGER "Models\\Enemies\\Beast\\Sounds\\Anger.wav", functions: // describe how this enemy killed player virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) { CTString str; str.PrintF(TRANS("A Reptiloid killed %s"),(const char*) strPlayerName); return str; } virtual const CTFileName &GetComputerMessageName(void) const { static DECLARE_CTFILENAME(fnmNormal, "Data\\Messages\\Enemies\\BeastNormal.txt"); static DECLARE_CTFILENAME(fnmBig, "Data\\Messages\\Enemies\\BeastBig.txt"); switch(m_bcType) { default: ASSERT(FALSE); case BT_NORMAL: return fnmNormal; case BT_BIG: return fnmBig; } }; void Precache(void) { CEnemyBase::Precache(); PrecacheSound(SOUND_IDLE ); PrecacheSound(SOUND_SIGHT); PrecacheSound(SOUND_WOUND); PrecacheSound(SOUND_ANGER); PrecacheSound(SOUND_FIRE); PrecacheSound(SOUND_KICK); PrecacheModel(MODEL_BEAST); PrecacheTexture(TEXTURE_BEAST_NORMAL); PrecacheTexture(TEXTURE_BEAST_BIG); if (m_bcType == BT_NORMAL) { PrecacheSound(SOUND_DEATH); PrecacheClass(CLASS_PROJECTILE, PRT_BEAST_PROJECTILE); } else { PrecacheSound(SOUND_DEATHBIG); PrecacheClass(CLASS_PROJECTILE, PRT_BEAST_BIG_PROJECTILE); } }; /* Entity info */ void *GetEntityInfo(void) { if (m_bcType == BT_NORMAL) { return &eiBeastNormal; } else { return &eiBeastBig; } }; class CWorldSettingsController *GetWSC(void) { CWorldSettingsController *pwsc = NULL; // obtain bcg viewer CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) GetWorld()->GetBackgroundViewer(); if( penBcgViewer != NULL) { // obtain world settings controller pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController; } return pwsc; } void ShakeItBaby(FLOAT tmShaketime, FLOAT fPower) { CWorldSettingsController *pwsc = GetWSC(); if (pwsc!=NULL) { pwsc->m_tmShakeStarted = tmShaketime; pwsc->m_vShakePos = GetPlacement().pl_PositionVector; pwsc->m_fShakeFalloff = 400.0f; pwsc->m_fShakeFade = 3.0f; pwsc->m_fShakeIntensityZ = 0.0f; pwsc->m_tmShakeFrequencyZ = 5.0f; pwsc->m_fShakeIntensityY = 0.1f*fPower; pwsc->m_tmShakeFrequencyY = 5.0f; pwsc->m_fShakeIntensityB = 2.5f*fPower; pwsc->m_tmShakeFrequencyB = 7.2f; } } FLOAT GetCrushHealth(void) { if (m_bcType == BT_BIG) { return 100.0f; } return 0.0f; } /* Receive damage */ void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) { // can't harm own class if (!IsOfClass(penInflictor, "Beast")) { CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); } }; // damage anim INDEX AnimForDamage(FLOAT fDamage) { INDEX iAnim; if(m_bcType==BT_BIG && GetHealth() <= m_fMaxHealth/2) { iAnim = BEAST_ANIM_ANGER; } else { iAnim = BEAST_ANIM_WOUND; } StartModelAnim(iAnim, 0); return iAnim; }; // death INDEX AnimForDeath(void) { INDEX iAnim; if(m_bcType==BT_BIG) { iAnim = BEAST_ANIM_DEATHBIG; } else { iAnim = BEAST_ANIM_DEATH; } StartModelAnim(iAnim, 0); return iAnim; }; void DeathNotify(void) { ChangeCollisionBoxIndexWhenPossible(BEAST_COLLISION_BOX_DEATH); en_fDensity = 500.0f; }; // virtual anim functions void StandingAnim(void) { _tmLastStandingAnim = _pTimer->CurrentTick(); StartModelAnim(BEAST_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART); }; void WalkingAnim(void) { if(_pTimer->CurrentTick()>=_tmLastStandingAnim-_pTimer->TickQuantum && _pTimer->CurrentTick()<=_tmLastStandingAnim+_pTimer->TickQuantum) { BREAKPOINT; } if(m_bcType==BT_BIG) { StartModelAnim(BEAST_ANIM_WALKBIG, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(BEAST_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); } }; void RunningAnim(void) { WalkingAnim(); }; void RotatingAnim(void) { WalkingAnim(); }; // virtual sound functions void IdleSound(void) { PlaySound(m_soSound, SOUND_IDLE, SOF_3D); }; void SightSound(void) { PlaySound(m_soSound, SOUND_SIGHT, SOF_3D); }; void WoundSound(void) { if(m_bcType==BT_BIG && GetHealth() <= m_fMaxHealth/2) { PlaySound(m_soSound, SOUND_ANGER, SOF_3D); } else { PlaySound(m_soSound, SOUND_WOUND, SOF_3D); } }; void DeathSound(void) { if (m_bcType == BT_NORMAL) { PlaySound(m_soSound, SOUND_DEATH, SOF_3D); } else { PlaySound(m_soSound, SOUND_DEATHBIG, SOF_3D); } }; // adjust sound and watcher parameters here if needed void EnemyPostInit(void) { m_soSound.Set3DParameters(160.0f, 50.0f, 2.0f, 1.0f); }; procedures: /************************************************************ * D E A T H * ************************************************************/ Death(EVoid) : CEnemyBase::Death { if (m_bcType == BT_NORMAL) { jump CEnemyBase::Death(); } // stop moving StopMoving(); DeathSound(); // death sound LeaveStain(TRUE); // set physic flags SetPhysicsFlags(EPF_MODEL_CORPSE); SetCollisionFlags(ECF_CORPSE); SetFlags(GetFlags() | ENF_SEETHROUGH); // stop making fuss RemoveFromFuss(); // death notify (usually change collision box and change body density) DeathNotify(); // start death anim AnimForDeath(); autowait(1.0f); ShakeItBaby(_pTimer->CurrentTick(), 2.0f); autowait(2.4f-1.0f); ShakeItBaby(_pTimer->CurrentTick(), 5.0f); autowait(GetModelObject()->GetAnimLength(BEAST_ANIM_DEATHBIG)-3.4f); return EEnd(); }; /************************************************************ * A T T A C K E N E M Y * ************************************************************/ Fire(EVoid) : CEnemyBase::Fire { // wait to finish walk and smooth change to idle StartModelAnim(BEAST_ANIM_WALKTOIDLE, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; if( m_bcType == BT_NORMAL) { StartModelAnim(BEAST_ANIM_ATTACK, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.51f); ShootProjectile(PRT_BEAST_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BEAST_STRETCH, 0.0f), ANGLE3D(AngleDeg((FRnd()-0.5)*30.0f), AngleDeg(FRnd()*10.0f), 0)); autowait(0.3f); } if( m_bcType == BT_BIG) { if( GetHealth() <= m_fMaxHealth/2) { m_iCounter = 0; while ( m_iCounter<6) { StartModelAnim(BEAST_ANIM_ATTACKFAST, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.34f); ShootProjectile(PRT_BEAST_BIG_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f), ANGLE3D( AngleDeg(40.0f*Cos(m_iCounter*360.0/6.0f)), AngleDeg(20.0f*Sin(m_iCounter*180.0/6.0f)), 0)); //autowait(0.15f); m_iCounter++; } m_fAttackFireTime = 7.0f; } if( GetHealth() > m_fMaxHealth/2) { m_iCounter = 0; while ( m_iCounter<3) { StartModelAnim(BEAST_ANIM_ATTACK, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.5f); ShootProjectile(PRT_BEAST_BIG_PROJECTILE, FLOAT3D( 0.0f, 1.5f*BIG_BEAST_STRETCH, 0.0f), ANGLE3D( AngleDeg(20.0f*Cos(m_iCounter*360.0/3.0f)), AngleDeg(10.0f*Sin(m_iCounter*180.0/3.0f)), 0)); //autowait(0.25f); m_iCounter++; } } } MaybeSwitchToAnotherPlayer(); autowait(FRnd()/2 + _pTimer->TickQuantum); if( m_penEnemy != NULL) { FLOAT fEnemyDistance = CalcDist(m_penEnemy); if( fEnemyDistance>m_fCloseDistance*1.25f) { StartModelAnim(BEAST_ANIM_IDLETOWALK, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; autowait(GetModelObject()->GetAnimLength(BEAST_ANIM_IDLETOWALK)/2.0f - _pTimer->TickQuantum); } } return EReturn(); }; // hit enemy Hit(EVoid) : CEnemyBase::Hit { // close attack StartModelAnim(BEAST_ANIM_KICK, 0); autowait(0.45f); /* StartModelAnim(BEAST_ANIM_KICK, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; */ PlaySound(m_soSound, SOUND_KICK, SOF_3D); if (CalcDist(m_penEnemy) < m_fCloseDistance) { FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector; vDirection.Normalize(); if (m_bcType == BT_BIG) { InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 80.0f, FLOAT3D(0, 0, 0), vDirection); } else { InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 40.0f, FLOAT3D(0, 0, 0), vDirection); } } /* StartModelAnim(BEAST_ANIM_IDLE, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; */ autowait(0.45f); MaybeSwitchToAnotherPlayer(); return EReturn(); }; /************************************************************ * M A I N * ************************************************************/ Main(EVoid) { // declare yourself as a model InitAsModel(); SetPhysicsFlags(EPF_MODEL_WALKING); SetCollisionFlags(ECF_MODEL); SetFlags(GetFlags()|ENF_ALIVE); en_fDensity = 1100.0f; // set your appearance SetModel(MODEL_BEAST); StandingAnim(); // setup moving speed m_fWalkSpeed = FRnd()*2 + 5.0f; m_aWalkRotateSpeed = AngleDeg(FRnd()*20.0f + 50.0f); m_fCloseRunSpeed = FRnd() + 10.0f; m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 900.0f); // setup attack distances m_fAttackDistance = 500.0f; m_fCloseDistance = 0.0f; m_fStopDistance = 0.0f; m_fCloseFireTime = 1.0f; m_fIgnoreRange = 750.0f; m_bBoss = m_bBeBoss; m_fStopDistance = 5.0f; m_fCloseDistance = 7.0f; m_tmGiveUp = Max(m_tmGiveUp, 10.0f); // damage/explode properties if( m_bcType == BT_NORMAL) { m_fAttackRunSpeed = 6.0f;//6 m_aAttackRotateSpeed = AngleDeg(3600.0f); SetHealth(400.0f); SetModelMainTexture(TEXTURE_BEAST_NORMAL); m_fBlowUpAmount = 10000.0f; m_fBodyParts = 4; m_fDamageWounded = 250.0f; m_iScore = 5000;//500 // set stretch factor GetModelObject()->StretchModel(FLOAT3D(BEAST_STRETCH, BEAST_STRETCH, BEAST_STRETCH)); ModelChangeNotify(); m_sptType = SPT_SLIME; m_fAttackFireTime = 3.0f; } else { m_fAttackRunSpeed = 8.0f;//8 m_aAttackRotateSpeed = AngleDeg(600.0f); SetHealth(2000.0f);//500 SetModelMainTexture(TEXTURE_BEAST_BIG); m_fBlowUpAmount = 10000.0f;//500 m_fBodyParts = 6; m_fDamageWounded = 650.0f;//500 m_iScore = 25000; //1000 m_fStopDistance = 15; m_fCloseDistance = 20; // set stretch factor GetModelObject()->StretchModel(FLOAT3D(BIG_BEAST_STRETCH, BIG_BEAST_STRETCH, BIG_BEAST_STRETCH)); ModelChangeNotify(); m_sptType = SPT_BLOOD; m_fAttackFireTime = 5.0f; } m_fMaxHealth = GetHealth(); // continue behavior in base class jump CEnemyBase::MainLoop(); }; };