322 %{ #include "Entities/StdH/StdH.h" //#include "Models/Enemies/Elementals/AirMan.h" //#include "Models/Enemies/Elementals/IceMan.h" #include "Models/Enemies/Elementals/Stoneman.h" //#include "Models/Enemies/Elementals/Twister.h" //#include "Models/Enemies/Elementals/WaterMan.h" //#include "Models/Enemies/Elementals/Projectile/IcePyramid.h" #include "Models/Enemies/Elementals/Projectile/LavaStone.h" #include "Models/Enemies/ElementalLava/ElementalLava.h" #include "Entities/WorldSettingsController.h" #include "Entities/BackgroundViewer.h" // lava elemental definitions #define LAVAMAN_SMALL_STRETCH (2.0f*0.75f) #define LAVAMAN_BIG_STRETCH (4.0f*1.25f) #define LAVAMAN_LARGE_STRETCH (16.0f*2.5f) #define LAVAMAN_BOSS_FIRE_RIGHT FLOAT3D(1.01069f, 0.989616f, -1.39743f) #define LAVAMAN_BOSS_FIRE_LEFT FLOAT3D(-0.39656f, 1.08619f, -1.34373f) #define LAVAMAN_FIRE_LEFT FLOAT3D(-0.432948f, 1.51133f, -0.476662f) #define LAVAMAN_FIRE_SMALL (LAVAMAN_FIRE_LEFT*LAVAMAN_SMALL_STRETCH) #define LAVAMAN_FIRE_BIG (LAVAMAN_FIRE_LEFT*LAVAMAN_BIG_STRETCH) #define LAVAMAN_FIRE_LARGE_LEFT (LAVAMAN_BOSS_FIRE_LEFT*LAVAMAN_LARGE_STRETCH) #define LAVAMAN_FIRE_LARGE_RIGHT (LAVAMAN_BOSS_FIRE_RIGHT*LAVAMAN_LARGE_STRETCH) #define LAVAMAN_SPAWN_BIG (FLOAT3D(0.0171274f, 1.78397f, -0.291414f)*LAVAMAN_BIG_STRETCH) #define LAVAMAN_SPAWN_LARGE (FLOAT3D(0.0171274f, 1.78397f, -0.291414f)*LAVAMAN_LARGE_STRETCH) %} uses "Entities/EnemyBase"; //uses "Entities/Twister"; //uses "Entities/Water"; enum ElementalType { 0 ELT_AIR "obsolete", // air elemental 1 ELT_ICE "obsolete", // ice elemental 2 ELT_LAVA "Lava", // lava elemental 3 ELT_STONE "obsolete", // stone elemental 4 ELT_WATER "obsolete", // water elemental }; enum ElementalCharacter { 0 ELC_SMALL "Small", // small (fighter) 1 ELC_BIG "Big", // big 2 ELC_LARGE "Large", // large }; enum ElementalState { 0 ELS_NORMAL "Normal", // normal state 1 ELS_BOX "Box", // in box 2 ELS_PLANE "Plane", // as plane }; %{ #define ECF_AIR ( \ ((ECBI_BRUSH|ECBI_MODEL|ECBI_CORPSE|ECBI_ITEM|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)<<ECB_TEST) |\ ((ECBI_MODEL|ECBI_CORPSE|ECBI_ITEM|ECBI_PROJECTILE_MAGIC|ECBI_PROJECTILE_SOLID)<<ECB_PASS) |\ ((ECBI_MODEL)<<ECB_IS)) // info structure // air static EntityInfo eiAirElementalSmall = { EIBT_AIR, 50.0f, 0.0f, 1.7f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiAirElementalBig = { EIBT_AIR, 200.0f, 0.0f, 6.8f, 0.0f, 0.0f, 4.0f, 0.0f, }; static EntityInfo eiAirElementalLarge = { EIBT_AIR, 800.0f, 0.0f, 27.2f, 0.0f, 0.0f, 16.0f, 0.0f, }; // ice static EntityInfo eiIceElementalSmall = { EIBT_ICE, 400.0f, 0.0f, 1.7f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiIceElementalBig = { EIBT_ICE, 1600.0f, 0.0f, 6.8f, 0.0f, 0.0f, 4.0f, 0.0f, }; static EntityInfo eiIceElementalLarge = { EIBT_ICE, 6400.0f, 0.0f, 27.2f, 0.0f, 0.0f, 16.0f, 0.0f, }; // lava static EntityInfo eiLavaElementalSmall = { EIBT_FIRE, 2000.0f, 0.0f, 1.7f*LAVAMAN_SMALL_STRETCH, 0.0f, 0.0f, LAVAMAN_SMALL_STRETCH, 0.0f, }; static EntityInfo eiLavaElementalBig = { EIBT_FIRE, 2800.0f, 0.0f, 1.7f*LAVAMAN_BIG_STRETCH, 0.0f, 0.0f, LAVAMAN_BIG_STRETCH, 0.0f, }; static EntityInfo eiLavaElementalLarge = { EIBT_FIRE, 11200.0f, 0.0f, 1.7f*LAVAMAN_LARGE_STRETCH, 0.0f, 0.0f, LAVAMAN_LARGE_STRETCH, 0.0f, }; // stone static EntityInfo eiStoneElementalSmall = { EIBT_ROCK, 1000.0f, 0.0f, 1.7f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiStoneElementalBig = { EIBT_ROCK, 4000.0f, 0.0f, 6.8f, 0.0f, 0.0f, 4.0f, 0.0f, }; static EntityInfo eiStoneElementalLarge = { EIBT_ROCK, 16000.0f, 0.0f, 27.2f, 0.0f, 0.0f, 16.0f, 0.0f, }; // water static EntityInfo eiWaterElementalSmall = { EIBT_WATER, 500.0f, 0.0f, 1.7f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiWaterElementalBig = { EIBT_WATER, 2000.0f, 0.0f, 6.8f, 0.0f, 0.0f, 4.0f, 0.0f, }; static EntityInfo eiWaterElementalLarge = { EIBT_WATER, 8000.0f, 0.0f, 27.2f, 0.0f, 0.0f, 16.0f, 0.0f, }; // obsolete #define EPF_BOX_PLANE_ELEMENTAL (EPF_ORIENTEDBYGRAVITY|EPF_MOVABLE) #define FIRE_ROCKS FLOAT3D(-0.9f, 1.6f, -1.0f) #define FIRE_ROCKS_BIG FLOAT3D(-3.6f, 6.4f, -4.0f) #define FIRE_ROCKS_LARGE FLOAT3D(-14.4f, 25.6f, -16.0f) #define WATER_LEFT FLOAT3D(-0.75f, 1.3f, -1.2f) #define WATER_RIGHT FLOAT3D( 0.75f, 1.3f, -1.2f) #define WATER_BIG_LEFT FLOAT3D(-3.0f, 5.2f, -4.8f) #define WATER_BIG_RIGHT FLOAT3D( 3.0f, 5.2f, -4.8f) #define WATER_LARGE_LEFT FLOAT3D(-12.0f, 20.8f, -19.2f) #define WATER_LARGE_RIGHT FLOAT3D( 12.0f, 20.8f, -19.2f) %} class CElemental : CEnemyBase { name "Elemental"; thumbnail "Thumbnails\\Elemental.tbn"; properties: 1 enum ElementalType m_EetType "Type" 'Y' = ELT_STONE, 2 enum ElementalCharacter m_EecChar "Character" 'C' = ELC_SMALL, 3 enum ElementalState m_EesStartState "State" 'S' = ELS_NORMAL, 4 BOOL m_bSpawnWhenHarmed "Damage spawn" 'N' = TRUE, 5 BOOL m_bSpawnOnBlowUp "Blowup spawn" 'B' = TRUE, 6 enum ElementalState m_EesCurrentState = ELS_NORMAL, 7 BOOL m_bSpawned = FALSE, 8 BOOL m_bMovable "Movable" 'V' = TRUE, 9 RANGE m_fLookRange "Look range" 'O' = 30.0f, 10 INDEX m_iFireCount "Fire count" = 2, 11 FLOAT m_fWaitTime = 0.0f, 12 INDEX m_iCounter = 0, 13 FLOAT m_fDensity "Density" 'D' = 10000.0f, // placement for non movable elemental 20 CEntityPointer m_penPosition1 "Position 1", 21 CEntityPointer m_penPosition2 "Position 2", 22 CEntityPointer m_penPosition3 "Position 3", 23 CEntityPointer m_penPosition4 "Position 4", 24 CEntityPointer m_penPosition5 "Position 5", 25 CEntityPointer m_penPosition6 "Position 6", 30 CSoundObject m_soBackground, // sound channel for background noise 31 INDEX m_ctSpawned = 0, 32 FLOAT m_fSpawnDamage = 1e6f, 33 BOOL m_bSpawnEnabled = FALSE, 34 CSoundObject m_soFireL, 35 CSoundObject m_soFireR, 36 INDEX m_bCountAsKill = TRUE, components: 0 class CLASS_BASE "Classes\\EnemyBase.ecl", 1 class CLASS_TWISTER "Classes\\Twister.ecl", 2 class CLASS_WATER "Classes\\Water.ecl", 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", 4 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl", /* // air 10 model MODEL_AIR "Models\\Enemies\\Elementals\\AirMan.mdl", 11 model MODEL_AIR_TWISTER "Models\\Enemies\\Elementals\\Twister.mdl", 12 texture TEXTURE_AIR "Models\\Enemies\\Elementals\\AirMan01.tex", // ice 20 model MODEL_ICE "Models\\Enemies\\Elementals\\IceMan.mdl", 21 model MODEL_ICE_PICK "Models\\Enemies\\Elementals\\IcePick.mdl", 22 texture TEXTURE_ICE "Models\\Enemies\\Elementals\\IceMan01.tex", */ // lava 30 model MODEL_LAVA "Models\\Enemies\\ElementalLava\\ElementalLava.mdl", 31 model MODEL_LAVA_BODY_FLARE "Models\\Enemies\\ElementalLava\\BodyFlare.mdl", 32 model MODEL_LAVA_HAND_FLARE "Models\\Enemies\\ElementalLava\\HandFlare.mdl", 33 texture TEXTURE_LAVA "Models\\Enemies\\ElementalLava\\Lava04Fx.tex", 34 texture TEXTURE_LAVA_DETAIL "Models\\Enemies\\ElementalLava\\Detail.tex", 35 texture TEXTURE_LAVA_FLARE "Models\\Enemies\\ElementalLava\\Flare.tex", /* // stone 40 model MODEL_STONE "Models\\Enemies\\Elementals\\StoneMan.mdl", 41 model MODEL_STONE_MAUL "Models\\Enemies\\Elementals\\Maul.mdl", 42 texture TEXTURE_STONE "Models\\Enemies\\Elementals\\StoneMan01.tex", // water 50 model MODEL_WATER "Models\\Enemies\\Elementals\\WaterMan.mdl", 51 model MODEL_WATER_BODY_FLARE "Models\\Enemies\\Elementals\\WaterManFX\\BodyFlare.mdl", 52 texture TEXTURE_WATER "Models\\Enemies\\Elementals\\WaterManFX.tex", 53 texture TEXTURE_WATER_FLARE "Models\\Enemies\\Elementals\\WaterManFX\\BodyFlare.tex", */ // debris // 80 model MODEL_ELEM_STONE "Models\\Enemies\\Elementals\\Projectile\\Stone.mdl", // 82 model MODEL_ELEM_LAVASTONE "Models\\Enemies\\ElementalLava\\Projectile\\LavaStone.mdl", // 83 model MODEL_ELEM_LAVASTONE_FLARE "Models\\Enemies\\ElementalLava\\Projectile\\LavaStoneFlare.mdl", // 84 model MODEL_ELEM_ICE "Models\\Enemies\\Elementals\\Projectile\\IcePyramid.mdl", // 85 model MODEL_ELEM_ICE_FLARE "Models\\Enemies\\Elementals\\Projectile\\IcePyramidFlare.mdl", // 90 texture TEXTURE_ELEM_STONE "Models\\Enemies\\Elementals\\Projectile\\Stone.tex", // 92 texture TEXTURE_ELEM_LAVASTONE "Models\\Enemies\\ElementalLava\\Projectile\\LavaStone.tex", // 93 texture TEXTURE_ELEM_ICE "Models\\Enemies\\Elementals\\Projectile\\IcePyramid.tex", // 94 texture TEXTURE_ELEM_FLARE "Textures\\Effects\\Flares\\03\\Flaire06.tex", // ************** SPECULAR ************** //210 texture TEX_SPEC_WEAK "Models\\SpecularTextures\\Weak.tex", //211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex", //212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex", // ************** SOUNDS ************** 250 sound SOUND_LAVA_IDLE "Models\\Enemies\\ElementalLava\\Sounds\\Idle.wav", //251 sound SOUND_LAVA_SIGHT "Models\\Enemies\\ElementalLava\\Sounds\\Sight.wav", 252 sound SOUND_LAVA_WOUND "Models\\Enemies\\ElementalLava\\Sounds\\Wound.wav", 253 sound SOUND_LAVA_FIRE "Models\\Enemies\\ElementalLava\\Sounds\\Fire.wav", 254 sound SOUND_LAVA_KICK "Models\\Enemies\\ElementalLava\\Sounds\\Kick.wav", 255 sound SOUND_LAVA_DEATH "Models\\Enemies\\ElementalLava\\Sounds\\Death.wav", 220 sound SOUND_LAVA_LAVABURN "Models\\Enemies\\ElementalLava\\Sounds\\LavaBurn.wav", 221 sound SOUND_LAVA_ANGER "Models\\Enemies\\ElementalLava\\Sounds\\Anger.wav", functions: // describe how this enemy killed player virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) { CTString str; str.PrintF(TRANS("%s was killed by a Lava Golem"),(const char*) strPlayerName); return str; } virtual const CTFileName &GetComputerMessageName(void) const { static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\ElementalLava.txt"); return fnm; }; void Precache(void) { CEnemyBase::Precache(); switch(m_EetType) { case ELT_LAVA: { if( m_EecChar == ELC_LARGE) { PrecacheClass(CLASS_PROJECTILE, PRT_LAVAMAN_BIG_BOMB); } if( (m_EecChar == ELC_LARGE) || (m_EecChar == ELC_BIG) ) { PrecacheClass(CLASS_PROJECTILE, PRT_LAVAMAN_BOMB); } PrecacheClass(CLASS_PROJECTILE, PRT_LAVAMAN_STONE); PrecacheModel(MODEL_LAVA ); PrecacheModel(MODEL_LAVA_BODY_FLARE); PrecacheModel(MODEL_LAVA_HAND_FLARE); PrecacheTexture(TEXTURE_LAVA ); PrecacheTexture(TEXTURE_LAVA_DETAIL); PrecacheTexture(TEXTURE_LAVA_FLARE ); PrecacheSound(SOUND_LAVA_IDLE ); //PrecacheSound(SOUND_LAVA_SIGHT ); PrecacheSound(SOUND_LAVA_WOUND ); PrecacheSound(SOUND_LAVA_FIRE ); PrecacheSound(SOUND_LAVA_KICK ); PrecacheSound(SOUND_LAVA_DEATH ); PrecacheSound(SOUND_LAVA_ANGER); PrecacheSound(SOUND_LAVA_LAVABURN); break; } } }; /* Entity info */ void *GetEntityInfo(void) { switch (m_EetType) { case ELT_AIR: switch(m_EecChar) { case ELC_LARGE: return &eiAirElementalLarge; case ELC_BIG: return &eiAirElementalBig; default: { return &eiAirElementalSmall; } } break; case ELT_ICE: switch(m_EecChar) { case ELC_LARGE: return &eiIceElementalLarge; case ELC_BIG: return &eiIceElementalBig; default: { return &eiIceElementalSmall; } } break; case ELT_LAVA: switch(m_EecChar) { case ELC_LARGE: return &eiLavaElementalLarge; case ELC_BIG: return &eiLavaElementalBig; default: { return &eiLavaElementalSmall; } } break; case ELT_STONE: switch(m_EecChar) { case ELC_LARGE: return &eiStoneElementalLarge; case ELC_BIG: return &eiStoneElementalBig; default: { return &eiStoneElementalSmall; } } break; //case ELT_WATER: default: { switch(m_EecChar) { case ELC_LARGE: return &eiWaterElementalLarge; case ELC_BIG: return &eiWaterElementalBig; default: { return &eiWaterElementalSmall; } }} } }; /* Fill in entity statistics - for AI purposes only */ BOOL FillEntityStatistics(EntityStats *pes) { CEnemyBase::FillEntityStatistics(pes); switch(m_EetType) { case ELT_WATER : { pes->es_strName+=" Water"; } break; case ELT_AIR : { pes->es_strName+=" Air"; } break; case ELT_STONE : { pes->es_strName+=" Stone"; } break; case ELT_LAVA : { pes->es_strName+=" Lava"; } break; case ELT_ICE : { pes->es_strName+=" Ice"; } break; } switch(m_EecChar) { case ELC_LARGE: pes->es_strName+=" Large"; break; case ELC_BIG: pes->es_strName+=" Big"; break; case ELC_SMALL: pes->es_strName+=" Small"; break; } return TRUE; } /* Receive damage */ void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) { // elemental can't harm elemental if( IsOfClass(penInflictor, "Elemental")) { return; } // boss can't be telefragged if( m_EecChar==ELC_LARGE && dmtType==DMT_TELEPORT) { return; } INDEX ctShouldSpawn = Clamp( INDEX((m_fMaxHealth-GetHealth())/m_fSpawnDamage), INDEX(0), INDEX(10)); CTString strChar = ElementalCharacter_enum.NameForValue(INDEX(m_EecChar)); //CPrintF( "Character: %s, MaxHlt = %g, Hlt = %g, SpwnDmg = %g, Spawned: %d, Should: %d\n", // strChar, m_fMaxHealth, GetHealth(), m_fSpawnDamage, m_ctSpawned, ctShouldSpawn); if (m_bSpawnEnabled && m_bSpawnWhenHarmed && (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG)) { INDEX ctShouldSpawn = Clamp( INDEX((m_fMaxHealth-GetHealth())/m_fSpawnDamage), INDEX(0), INDEX(10)); if(m_ctSpawned<ctShouldSpawn) { SendEvent( EForceWound() ); } } // if not in normal state can't be harmed if (m_EesCurrentState!=ELS_NORMAL) { return; } CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); }; // damage anim INDEX AnimForDamage(FLOAT fDamage) { INDEX iAnim; if (m_EetType == ELT_LAVA) { switch (IRnd()%3) { case 0: iAnim = ELEMENTALLAVA_ANIM_WOUND01; break; case 1: iAnim = ELEMENTALLAVA_ANIM_WOUND02; break; default: iAnim = ELEMENTALLAVA_ANIM_WOUND03; break; } } else { iAnim = 0; // DG: should at least have deterministic value /* switch (IRnd()%3) { case 0: iAnim = STONEMAN_ANIM_WOUND01; break; case 1: iAnim = STONEMAN_ANIM_WOUND02; break; default: iAnim = STONEMAN_ANIM_WOUND03; break; }*/ } StartModelAnim(iAnim, 0); return iAnim; }; void StandingAnimFight(void) { StartModelAnim(ELEMENTALLAVA_ANIM_STANDFIGHT, AOF_LOOPING|AOF_NORESTART); } // virtual anim functions void StandingAnim(void) { if (m_EetType == ELT_LAVA) { switch (m_EesCurrentState) { case ELS_NORMAL: StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_LOOPING|AOF_NORESTART); break; case ELS_BOX: StartModelAnim(ELEMENTALLAVA_ANIM_MELTFLY, AOF_LOOPING|AOF_NORESTART); break; //case ELS_PLANE: default: StartModelAnim(ELEMENTALLAVA_ANIM_STANDPLANE, AOF_LOOPING|AOF_NORESTART); break; } } else { /* switch (m_EesCurrentState) { case ELS_NORMAL: StartModelAnim(STONEMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART); break; case ELS_BOX: StartModelAnim(STONEMAN_ANIM_STANDBOX, AOF_LOOPING|AOF_NORESTART); break; //case ELS_PLANE: default: StartModelAnim(STONEMAN_ANIM_STANDPLANE, AOF_LOOPING|AOF_NORESTART); break; }*/ } }; void WalkingAnim(void) { if (m_EetType == ELT_LAVA) { if (m_EecChar==ELC_LARGE) { StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_LOOPING|AOF_NORESTART); } else if (m_EecChar==ELC_BIG) { StartModelAnim(ELEMENTALLAVA_ANIM_RUNMEDIUM, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(ELEMENTALLAVA_ANIM_RUNSMALL, AOF_LOOPING|AOF_NORESTART); } } else { // StartModelAnim(STONEMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); } }; void RunningAnim(void) { if (m_EetType == ELT_LAVA) { WalkingAnim(); } else { // StartModelAnim(STONEMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART); } }; void RotatingAnim(void) { if (m_EetType == ELT_LAVA) { WalkingAnim(); } else { // StartModelAnim(STONEMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART); } }; INDEX AnimForDeath(void) { INDEX iAnim; if (m_EetType == ELT_LAVA) { iAnim = ELEMENTALLAVA_ANIM_DEATH03; } else { iAnim = 0; // DG: should at least have deterministic value // iAnim = STONEMAN_ANIM_DEATH03; } StartModelAnim(iAnim, 0); return iAnim; }; // virtual sound functions void IdleSound(void) { PlaySound(m_soSound, SOUND_LAVA_IDLE, SOF_3D); }; void SightSound(void) { //PlaySound(m_soSound, SOUND_LAVA_SIGHT, SOF_3D); }; void WoundSound(void) { PlaySound(m_soSound, SOUND_LAVA_WOUND, SOF_3D); }; void DeathSound(void) { PlaySound(m_soSound, SOUND_LAVA_DEATH, SOF_3D); }; BOOL CountAsKill(void) { return m_bCountAsKill; } // spawn new elemental void SpawnNewElemental(void) { INDEX ctShouldSpawn = Clamp( INDEX((m_fMaxHealth-GetHealth())/m_fSpawnDamage), INDEX(0), INDEX(10)); // disable too much spawning if (m_bSpawnOnBlowUp && (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG) && (GetHealth()<=0.0f) ) { ctShouldSpawn+=2; } ASSERT(m_ctSpawned<=ctShouldSpawn); if(m_ctSpawned>=ctShouldSpawn) { return; } CPlacement3D pl; // spawn placement if (m_EecChar==ELC_LARGE) { pl = CPlacement3D(LAVAMAN_SPAWN_LARGE, ANGLE3D(-90.0f+FRnd()*180.0f, 30+FRnd()*30, 0)); } else { pl = CPlacement3D(LAVAMAN_SPAWN_BIG, ANGLE3D(-90.0f+FRnd()*180.0f, 40+FRnd()*20, 0)); } pl.RelativeToAbsolute(GetPlacement()); // create entity CEntityPointer pen = GetWorld()->CreateEntity(pl, GetClass()); ((CElemental&)*pen).m_EetType = m_EetType; // elemental size if (m_EecChar==ELC_LARGE) { ((CElemental&)*pen).m_EecChar = ELC_BIG; } else { ((CElemental&)*pen).m_EecChar = ELC_SMALL; } // start properties ((CElemental&)*pen).m_EesStartState = ELS_BOX; ((CElemental&)*pen).m_fDensity = m_fDensity; ((CElemental&)*pen).m_colColor = m_colColor; ((CElemental&)*pen).m_penEnemy = m_penEnemy; ((CElemental&)*pen).m_ttTarget = m_ttTarget; ((CElemental&)*pen).m_bSpawned = TRUE; pen->Initialize(EVoid()); // set moving if (m_EecChar==ELC_LARGE) { ((CElemental&)*pen).LaunchAsFreeProjectile(FLOAT3D(0, 0, -40.0f), this); } else { ((CElemental&)*pen).LaunchAsFreeProjectile(FLOAT3D(0, 0, -20.0f), this); } ((CElemental&)*pen).SetDesiredRotation(ANGLE3D(0, 0, FRnd()*360-180)); // spawn particle debris explosion CEntity *penSpray = CreateEntity( pl, CLASS_BLOOD_SPRAY); penSpray->SetParent( pen); ESpawnSpray eSpawnSpray; eSpawnSpray.fDamagePower = 4.0f; eSpawnSpray.fSizeMultiplier = 0.5f; eSpawnSpray.sptType = SPT_LAVA_STONES; eSpawnSpray.vDirection = FLOAT3D(0,-0.5f,0); eSpawnSpray.penOwner = pen; penSpray->Initialize( eSpawnSpray); m_ctSpawned++; }; // throw rocks void ThrowRocks(ProjectileType EptProjectile) { // projectile type and position FLOAT3D vPos; ANGLE3D aAngle; // throw rocks switch (m_EecChar) { case ELC_LARGE: { vPos = FIRE_ROCKS_LARGE; ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); aAngle = ANGLE3D(FRnd()*5.0f+5.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); aAngle = ANGLE3D(FRnd()*-5.0f-5.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); break; } case ELC_BIG: { vPos = FIRE_ROCKS_BIG; ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); aAngle = ANGLE3D(FRnd()*4.0f+4.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); aAngle = ANGLE3D(FRnd()*-4.0f-4.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); break; } default: { vPos = FIRE_ROCKS; ShootProjectile(EptProjectile, vPos, ANGLE3D(0, 0, 0)); aAngle = ANGLE3D(FRnd()*3.0f+3.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); aAngle = ANGLE3D(FRnd()*-3.0f-3.0f, FRnd()*3.0f-2.0f, 0); ShootProjectile(EptProjectile, vPos, aAngle); } } }; void BossFirePredictedLavaRock(FLOAT3D vFireingRel) { FLOAT3D vShooting = GetPlacement().pl_PositionVector+vFireingRel*GetRotationMatrix(); FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; FLOAT3D vSpeedDest = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute; FLOAT fLaunchSpeed; FLOAT fRelativeHdg; FLOAT fDistanceFactor = ClampUp( (vShooting-vTarget).Length()/150.0f, 1.0f)-0.75f; FLOAT fPitch = fDistanceFactor*45.0f; // calculate parameters for predicted angular launch curve EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); CalculateAngularLaunchParams( vShooting, peiTarget->vTargetCenter[1]-6.0f/3.0f, vTarget, vSpeedDest, fPitch, fLaunchSpeed, fRelativeHdg); // target enemy body FLOAT3D vShootTarget; GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); // launch CPlacement3D pl; PrepareFreeFlyingProjectile(pl, vShootTarget, vFireingRel, ANGLE3D( fRelativeHdg, fPitch, 0)); CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); ELaunchProjectile eLaunch; eLaunch.penLauncher = this; eLaunch.prtType = PRT_LAVAMAN_BIG_BOMB; eLaunch.fSpeed = fLaunchSpeed; penProjectile->Initialize(eLaunch); } 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; } /* Shake ground */ 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 = 450.0f; pwsc->m_fShakeFade = 3.0f; pwsc->m_fShakeIntensityZ = 0; 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; } } // hit ground void HitGround(void) { FLOAT3D vSource; if( m_penEnemy != NULL) { vSource = GetPlacement().pl_PositionVector + FLOAT3D(m_penEnemy->en_mRotation(1, 2), m_penEnemy->en_mRotation(2, 2), m_penEnemy->en_mRotation(3, 2)); } else { vSource = GetPlacement().pl_PositionVector; } // damage if (m_EecChar==ELC_LARGE) { InflictRangeDamage(this, DMT_IMPACT, 150.0f, vSource, 7.5f, m_fCloseDistance); ShakeItBaby(_pTimer->CurrentTick(), 5.0f); } else if (m_EecChar==ELC_BIG) { InflictRangeDamage(this, DMT_IMPACT, 75.0f, vSource, 5.0f, m_fCloseDistance); ShakeItBaby(_pTimer->CurrentTick(), 2.0f); } else { InflictRangeDamage(this, DMT_IMPACT, 25.0f, vSource, 2.5f, m_fCloseDistance); } }; // fire water /* void FireWater(void) { // target enemy body EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); FLOAT3D vShootTarget; GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); // water projectile CPlacement3D pl; EWater ew; ew.penLauncher = this; if (m_EecChar==ELC_LARGE) { ew.EwsSize = WTS_LARGE; // launch PreparePropelledProjectile(pl, vShootTarget, WATER_LARGE_LEFT, ANGLE3D(0, 0, 0)); CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); // launch PreparePropelledProjectile(pl, vShootTarget, WATER_LARGE_RIGHT, ANGLE3D(0, 0, 0)); penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); } else if (m_EecChar==ELC_BIG) { ew.EwsSize = WTS_BIG; // launch PreparePropelledProjectile(pl, vShootTarget, WATER_BIG_LEFT, ANGLE3D(0, 0, 0)); CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); // launch PreparePropelledProjectile(pl, vShootTarget, WATER_BIG_RIGHT, ANGLE3D(0, 0, 0)); penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); } else { ew.EwsSize = WTS_SMALL; // launch PreparePropelledProjectile(pl, vShootTarget, WATER_LEFT, ANGLE3D(0, 0, 0)); CEntityPointer penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); // launch PreparePropelledProjectile(pl, vShootTarget, WATER_RIGHT, ANGLE3D(0, 0, 0)); penWater = CreateEntity(pl, CLASS_WATER); penWater->Initialize(ew); } }; */ // add attachments void AddAttachments(void) { switch (m_EetType) { /* case ELT_AIR: if (GetModelObject()->GetAttachmentModel(AIRMAN_ATTACHMENT_TWISTER)==NULL) { AddAttachmentToModel(this, *GetModelObject(), AIRMAN_ATTACHMENT_TWISTER, MODEL_AIR_TWISTER, TEXTURE_AIR, 0, 0, 0); GetModelObject()->mo_ColorMask &= ~AIRMAN_PART_BODYDOWN; } break; case ELT_ICE: if (GetModelObject()->GetAttachmentModel(ICEMAN_ATTACHMENT_ICEPICK)==NULL) { AddAttachmentToModel(this, *GetModelObject(), ICEMAN_ATTACHMENT_ICEPICK, MODEL_ICE_PICK, TEXTURE_ICE, TEXTURE_ICE, TEX_SPEC_STRONG, 0); } break;*/ case ELT_LAVA: if (GetModelObject()->GetAttachmentModel(ELEMENTALLAVA_ATTACHMENT_BODY_FLARE)==NULL) { AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_BODY_FLARE, MODEL_LAVA_BODY_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_RIGHT_HAND_FLARE, MODEL_LAVA_HAND_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); AddAttachmentToModel(this, *GetModelObject(), ELEMENTALLAVA_ATTACHMENT_LEFT_HAND_FLARE, MODEL_LAVA_HAND_FLARE, TEXTURE_LAVA_FLARE, 0, 0, 0); } break; /* case ELT_STONE: if (GetModelObject()->GetAttachmentModel(STONEMAN_ATTACHMENT_MAUL)==NULL) { AddAttachmentToModel(this, *GetModelObject(), STONEMAN_ATTACHMENT_MAUL, MODEL_STONE_MAUL, TEXTURE_STONE, 0, 0, 0); } break; case ELT_WATER: if (GetModelObject()->GetAttachmentModel(WATERMAN_ATTACHMENT_BODY_FLARE)==NULL) { AddAttachmentToModel(this, *GetModelObject(), WATERMAN_ATTACHMENT_BODY_FLARE, MODEL_WATER_BODY_FLARE, TEXTURE_WATER_FLARE, 0, 0, 0); } break;*/ } GetModelObject()->StretchModel(GetModelObject()->mo_Stretch); ModelChangeNotify(); }; // remove attachments void RemoveAttachments(void) { switch (m_EetType) { /* case ELT_AIR: RemoveAttachmentFromModel(*GetModelObject(), AIRMAN_ATTACHMENT_TWISTER); GetModelObject()->mo_ColorMask |= AIRMAN_PART_BODYDOWN; break; case ELT_ICE: RemoveAttachmentFromModel(*GetModelObject(), ICEMAN_ATTACHMENT_ICEPICK); break;*/ case ELT_LAVA: RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_BODY_FLARE); RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_RIGHT_HAND_FLARE); RemoveAttachmentFromModel(*GetModelObject(), ELEMENTALLAVA_ATTACHMENT_LEFT_HAND_FLARE); break; /* case ELT_STONE: RemoveAttachmentFromModel(*GetModelObject(), STONEMAN_ATTACHMENT_MAUL); break; case ELT_WATER: RemoveAttachmentFromModel(*GetModelObject(), WATERMAN_ATTACHMENT_BODY_FLARE); break;*/ } }; /************************************************************ * BLOW UP FUNCTIONS * ************************************************************/ // spawn body parts void BlowUp(void) { // get your size FLOATaabbox3D box; GetBoundingBox(box); FLOAT fEntitySize = box.Size().MaxNorm()/2; /* INDEX iCount = 1; switch (m_EecChar) { case ELC_SMALL: iCount = 3; break; case ELC_BIG: iCount = 5; break; case ELC_LARGE: iCount = 7; break; } */ FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length()); vNormalizedDamage /= Sqrt(vNormalizedDamage.Length()); vNormalizedDamage *= 1.75f; /* FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute); // spawn debris switch (m_EetType) { case ELT_ICE: { Debris_Begin(EIBT_ICE, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); for (iDebris=0; iDebris<iCount; iDebris++) { CEntityPointer pen; pen = Debris_Spawn(this, this, MODEL_ELEM_ICE, TEXTURE_ELEM_ICE, 0, 0, 0, 0, 0.5f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); AddAttachmentToModel(this, *(pen->GetModelObject()), ICEPYRAMID_ATTACHMENT_FLARE, MODEL_ELEM_ICE_FLARE, TEXTURE_ELEM_FLARE, 0, 0, 0); pen->GetModelObject()->StretchModel(pen->GetModelObject()->mo_Stretch); ModelChangeNotify(); }} break; case ELT_LAVA: { Debris_Begin(EIBT_FIRE, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); for (iDebris=0; iDebris<iCount; iDebris++) { CEntityPointer pen; pen = Debris_Spawn(this, this, MODEL_ELEM_LAVASTONE, TEXTURE_ELEM_LAVASTONE, 0, 0, 0, 0, 0.5f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); AddAttachmentToModel(this, *(pen->GetModelObject()), LAVASTONE_ATTACHMENT_FLARE, MODEL_ELEM_LAVASTONE_FLARE, TEXTURE_ELEM_FLARE, 0, 0, 0); pen->GetModelObject()->StretchModel(pen->GetModelObject()->mo_Stretch); ModelChangeNotify(); }} break; case ELT_STONE: { Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f); for (iDebris=0; iDebris<iCount; iDebris++) { Debris_Spawn(this, this, MODEL_ELEM_STONE, TEXTURE_ELEM_STONE, 0, 0, 0, 0, 0.5f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f)); }} break; } */ // hide yourself (must do this after spawning debris) SwitchToEditorModel(); SetPhysicsFlags(EPF_MODEL_IMMATERIAL); SetCollisionFlags(ECF_IMMATERIAL); }; // adjust sound and watcher parameters here if needed void EnemyPostInit(void) { if (m_EecChar==ELC_LARGE && m_EetType==ELT_LAVA) { m_soBackground.Set3DParameters(400.0f, 0.0f, 1.0f, 1.0f); m_soSound.Set3DParameters(400.0f, 50.0f, 1.0f, 1.0f); m_soFireL.Set3DParameters(400.0f, 50.0f, 1.0f, 1.0f); m_soFireR.Set3DParameters(400.0f, 50.0f, 1.0f, 1.0f); } else if (m_EecChar==ELC_BIG && m_EetType==ELT_LAVA) { m_soBackground.Set3DParameters(150.0f, 15.0f, 0.5f, 1.0f); m_soSound.Set3DParameters(200.0f, 0.0f, 1.0f, 1.0f); m_soFireL.Set3DParameters(200.0f, 0.0f, 1.0f, 1.0f); m_soFireR.Set3DParameters(200.0f, 0.0f, 1.0f, 1.0f); } }; procedures: /************************************************************ * CLASS INTERNAL * ************************************************************/ FallOnFloor(EVoid) { // drop to floor SetPhysicsFlags(EPF_MODEL_WALKING); // wait at most 10 seconds wait (10.0f) { on (ETimer) : { stop; } on (EBegin) : { resume; } // if a brush is touched on (ETouch et) : { if (et.penOther->GetRenderType()&RT_BRUSH) { // stop waiting StopMoving(); stop; } resume; } otherwise() : { resume; } } StartModelAnim(ELEMENTALLAVA_ANIM_MELTUP, 0); return EReturn(); }; /************************************************************ * FIRE PROCEDURES * ************************************************************/ // // STONEMAN // /* StonemanFire(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK05, 0); autowait(0.7f); // throw rocks if (m_EecChar==ELC_LARGE) { ThrowRocks(PRT_STONEMAN_LARGE_FIRE); } else if (m_EecChar==ELC_BIG) { ThrowRocks(PRT_STONEMAN_BIG_FIRE); } else { ThrowRocks(PRT_STONEMAN_FIRE); } PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); autowait(0.9f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; StonemanHit(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK06, 0); autowait(0.6f); HitGround(); PlaySound(m_soSound, SOUND_LAVA_KICK, SOF_3D); autowait(0.5f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; */ // // LAVAMAN // LavamanFire(EVoid) { m_bSpawnEnabled = TRUE; // shoot projectiles if (m_EecChar==ELC_LARGE) { CModelObject &mo = *GetModelObject(); FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKBOSS, AOF_SMOOTHCHANGE); autowait(tmWait+0.95f); BossFirePredictedLavaRock(LAVAMAN_FIRE_LARGE_RIGHT); PlaySound(m_soFireR, SOUND_LAVA_FIRE, SOF_3D); autowait(2.0150f-0.95f); BossFirePredictedLavaRock(LAVAMAN_FIRE_LARGE_LEFT); PlaySound(m_soFireL, SOUND_LAVA_FIRE, SOF_3D); StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; MaybeSwitchToAnotherPlayer(); // set next shoot time m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/5.0f); return EReturn(); } else if (m_EecChar==ELC_BIG) { CModelObject &mo = *GetModelObject(); FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, AOF_SMOOTHCHANGE); autowait(tmWait+0.90f); FLOAT3D vShooting = GetPlacement().pl_PositionVector; FLOAT3D vTarget = m_penEnemy->GetPlacement().pl_PositionVector; FLOAT3D vSpeedDest = ((CMovableEntity&) *m_penEnemy).en_vCurrentTranslationAbsolute; FLOAT fLaunchSpeed; FLOAT fRelativeHdg; FLOAT fPitch = 20.0f; // calculate parameters for predicted angular launch curve EntityInfo *peiTarget = (EntityInfo*) (m_penEnemy->GetEntityInfo()); CalculateAngularLaunchParams( vShooting, LAVAMAN_FIRE_BIG(2)-peiTarget->vTargetCenter[1]-1.5f/3.0f, vTarget, vSpeedDest, fPitch, fLaunchSpeed, fRelativeHdg); // target enemy body FLOAT3D vShootTarget; GetEntityInfoPosition(m_penEnemy, peiTarget->vTargetCenter, vShootTarget); // launch CPlacement3D pl; PrepareFreeFlyingProjectile(pl, vShootTarget, LAVAMAN_FIRE_BIG, ANGLE3D( fRelativeHdg, fPitch, 0)); CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE); ELaunchProjectile eLaunch; eLaunch.penLauncher = this; eLaunch.prtType = PRT_LAVAMAN_BOMB; eLaunch.fSpeed = fLaunchSpeed; penProjectile->Initialize(eLaunch); PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); } else if (TRUE) { CModelObject &mo = *GetModelObject(); FLOAT tmWait = mo.GetAnimLength( mo.ao_iCurrentAnim )-mo.GetPassedTime(); StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, AOF_SMOOTHCHANGE); autowait(tmWait+0.8f); ShootProjectile(PRT_LAVAMAN_STONE, LAVAMAN_FIRE_SMALL, ANGLE3D(0, 0, 0)); PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); } autowait( GetModelObject()->GetAnimLength( ELEMENTALLAVA_ANIM_ATTACKLEFTHAND) - 0.9f); StandingAnim(); autowait(_pTimer->TickQuantum); if (m_EecChar!=ELC_SMALL) { MaybeSwitchToAnotherPlayer(); } // set next shoot time m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/5.0f); return EReturn(); }; LavamanStones(EVoid) { StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKLEFTHAND, 0); autowait(0.7f); // throw rocks if (m_EecChar==ELC_LARGE) { ThrowRocks(PRT_LAVAMAN_STONE); } else if (m_EecChar==ELC_BIG) { ThrowRocks(PRT_LAVAMAN_STONE); } else { ThrowRocks(PRT_LAVAMAN_STONE); } PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); autowait(0.9f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; LavamanHit(EVoid) { StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, 0); autowait(0.6f); HitGround(); PlaySound(m_soFireL, SOUND_LAVA_KICK, SOF_3D); StartModelAnim(ELEMENTALLAVA_ANIM_WALKBIG, AOF_SMOOTHCHANGE); autocall CMovableModelEntity::WaitUntilScheduledAnimStarts() EReturn; return EReturn(); }; /* // // ICEMAN // IcemanFire(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK05, 0); autowait(0.7f); // throw rocks if (m_EecChar==ELC_LARGE) { ThrowRocks(PRT_ICEMAN_LARGE_FIRE); } else if (m_EecChar==ELC_BIG) { ThrowRocks(PRT_ICEMAN_BIG_FIRE); } else { ThrowRocks(PRT_ICEMAN_FIRE); } PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); autowait(0.9f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; IcemanHit(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK01, 0); autowait(0.6f); HitGround(); PlaySound(m_soSound, SOUND_LAVA_KICK, SOF_3D); autowait(0.5f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; // // AIRMAN // AirmanFire(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK06, 0); autowait(1.0f); // spawn twister CPlacement3D pl = m_penEnemy->GetPlacement(); FLOAT fR, fA; ETwister et; fA = FRnd()*360.0f; if (m_EecChar==ELC_LARGE) { fR = FRnd()*10.0f; et.EtsSize = TWS_LARGE; } else if (m_EecChar==ELC_BIG) { fR = FRnd()*7.5f; et.EtsSize = TWS_BIG; } else { fR = FRnd()*5.0f; et.EtsSize = TWS_SMALL; } pl.pl_PositionVector += FLOAT3D(CosFast(fA)*fR, 0, SinFast(fA)*fR);; CEntityPointer penTwister = CreateEntity(pl, CLASS_TWISTER); et.penOwner = this; penTwister->Initialize(et); PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); autowait(0.6f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; // // WATERMAN // WatermanFire(EVoid) { StartModelAnim(STONEMAN_ANIM_ATTACK02, 0); autowait(0.5f); // throw rocks FireWater(); PlaySound(m_soSound, SOUND_LAVA_FIRE, SOF_3D); autowait(0.6f); // stand a while StandingAnim(); autowait(FRnd()/3+_pTimer->TickQuantum); return EReturn(); }; */ /************************************************************ * PROCEDURES WHEN HARMED * ************************************************************/ // Play wound animation and falling body part BeWounded(EDamage eDamage) : CEnemyBase::BeWounded { // spawn additional elemental if( m_bSpawnEnabled) { SpawnNewElemental(); } jump CEnemyBase::BeWounded(eDamage); }; /************************************************************ * CHANGE STATE PROCEDURES * ************************************************************/ // box to normal BoxToNormal(EVoid) { m_EesCurrentState = ELS_NORMAL; SetPhysicsFlags(EPF_MODEL_WALKING); ChangeCollisionBoxIndexWhenPossible(STONEMAN_COLLISION_BOX_NORMAL); StartModelAnim(STONEMAN_ANIM_MORPHBOXUP, 0); AddAttachments(); autowait(GetModelObject()->GetAnimLength(STONEMAN_ANIM_MORPHBOXUP)); return EReturn(); }; // normal to box /* NormalToBox(EVoid) { StartModelAnim(STONEMAN_ANIM_MORPHBOXDOWN, 0); autowait(GetModelObject()->GetAnimLength(STONEMAN_ANIM_MORPHBOXDOWN)); m_EesCurrentState = ELS_BOX; SetPhysicsFlags(EPF_BOX_PLANE_ELEMENTAL); ChangeCollisionBoxIndexWhenPossible(STONEMAN_COLLISION_BOX_BOX); RemoveAttachments(); return EReturn(); };*/ // plane to normal PlaneToNormal(EVoid) { m_EesCurrentState = ELS_NORMAL; SwitchToModel(); SetPhysicsFlags(EPF_MODEL_WALKING); ChangeCollisionBoxIndexWhenPossible(ELEMENTALLAVA_COLLISION_BOX_NORMAL); INDEX iAnim; if (m_EetType == ELT_LAVA) { iAnim = ELEMENTALLAVA_ANIM_MELTUP; } else { iAnim = 0; // DG: should at least have deterministic value // iAnim = STONEMAN_ANIM_MORPHPLANEUP; } StartModelAnim(iAnim, 0); AddAttachments(); autowait(GetModelObject()->GetAnimLength(iAnim)); return EReturn(); }; /************************************************************ * A T T A C K E N E M Y * ************************************************************/ InitializeAttack(EVoid) : CEnemyBase::InitializeAttack { // change state from box to normal if (m_EesCurrentState==ELS_BOX) { autocall BoxToNormal() EReturn; } // change state from plane to normal else if (m_EesCurrentState==ELS_PLANE) { autocall PlaneToNormal() EReturn; } jump CEnemyBase::InitializeAttack(); }; Fire(EVoid) : CEnemyBase::Fire { // fire projectile switch (m_EetType) { // case ELT_STONE: jump StonemanFire(); break; case ELT_LAVA: jump LavamanFire(); break; // case ELT_ICE: jump IcemanFire(); break; // case ELT_AIR: jump AirmanFire(); break; // case ELT_WATER: jump WatermanFire(); break; } return EReturn(); }; Hit(EVoid) : CEnemyBase::Hit { // hit ground switch (m_EetType) { // case ELT_STONE: jump StonemanHit(); break; case ELT_LAVA: jump LavamanHit(); break; // case ELT_ICE: jump IcemanHit(); break; // case ELT_AIR: jump AirmanFire(); break; // case ELT_WATER: jump WatermanFire(); break; } return EReturn(); }; /************************************************************ * D E A T H * ************************************************************/ Death(EVoid) : CEnemyBase::Death { if (m_bSpawnOnBlowUp && (m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG)) { SpawnNewElemental(); SpawnNewElemental(); } // air fade out if (m_EetType == ELT_AIR) { m_fFadeStartTime = _pTimer->CurrentTick(); m_bFadeOut = TRUE; m_fFadeTime = 2.0f; autowait(m_fFadeTime); } autocall CEnemyBase::Death() EEnd; GetModelObject()->mo_toBump.SetData( NULL); return EEnd(); }; BossAppear(EVoid) { autowait(2.0f); m_fFadeStartTime = _pTimer->CurrentTick(); GetModelObject()->PlayAnim(ELEMENTALLAVA_ANIM_ANGER, 0); PlaySound(m_soSound, SOUND_LAVA_ANGER, SOF_3D); autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ANGER)-_pTimer->TickQuantum); StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, AOF_SMOOTHCHANGE); autowait(0.7f); HitGround(); PlaySound(m_soFireL, SOUND_LAVA_KICK, SOF_3D); autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS)-0.7f-_pTimer->TickQuantum); StartModelAnim(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS, 0); autowait(0.6f); HitGround(); PlaySound(m_soFireR, SOUND_LAVA_KICK, SOF_3D); autowait(GetModelObject()->GetAnimLength(ELEMENTALLAVA_ANIM_ATTACKTWOHANDS)-0.6f-_pTimer->TickQuantum); return EReturn(); } // overridable called before main enemy loop actually begins PreMainLoop(EVoid) : CEnemyBase::PreMainLoop { // if spawned by other entity if (m_bSpawned) { m_bSpawned = FALSE; m_bCountAsKill = FALSE; // wait till touching the ground autocall FallOnFloor() EReturn; } if ((m_EecChar==ELC_LARGE || m_EecChar==ELC_BIG) && m_EetType==ELT_LAVA) { PlaySound(m_soBackground, SOUND_LAVA_LAVABURN, SOF_3D|SOF_LOOP); } if( m_EecChar==ELC_LARGE) { autocall BossAppear() EReturn; } return EReturn(); } /************************************************************ * M A I N * ************************************************************/ Main(EVoid) { if (m_EetType!=ELT_LAVA) { m_EetType=ELT_LAVA; } // declare yourself as a model InitAsModel(); // movable if (m_bMovable) { SetPhysicsFlags(EPF_MODEL_WALKING); // non movable } else { SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); } // air elemental if (m_EetType==ELT_AIR) { SetCollisionFlags(ECF_AIR); // solid elemental } else { SetCollisionFlags(ECF_MODEL); } SetFlags(GetFlags()|ENF_ALIVE); en_fDensity = m_fDensity; m_fSpawnDamage = 1e6f; m_fDamageWounded = 1e6f; m_bSpawnEnabled = FALSE; m_bBoss = FALSE; // set your appearance switch (m_EetType) { /* case ELT_AIR: SetComponents(this, *GetModelObject(), MODEL_AIR, TEXTURE_AIR, 0, 0, 0); break; case ELT_ICE: SetComponents(this, *GetModelObject(), MODEL_ICE, TEXTURE_ICE, TEXTURE_ICE, TEX_SPEC_STRONG, 0); break;*/ case ELT_LAVA: m_fBlowUpAmount = 1E30f; SetComponents(this, *GetModelObject(), MODEL_LAVA, TEXTURE_LAVA, 0, 0, TEXTURE_LAVA_DETAIL); break; /* case ELT_STONE: SetComponents(this, *GetModelObject(), MODEL_STONE, TEXTURE_STONE, 0, 0, 0); break; case ELT_WATER: SetComponents(this, *GetModelObject(), MODEL_WATER, TEXTURE_WATER, TEXTURE_WATER, TEX_SPEC_STRONG, 0); break;*/ } ModelChangeNotify(); // character settings if (m_EecChar==ELC_LARGE) { // this one is boss! m_sptType = SPT_SMALL_LAVA_STONES; m_bBoss = TRUE; SetHealth(10000.0f); m_fMaxHealth = 10000.0f; // after loosing this ammount of damage we will spawn new elemental m_fSpawnDamage = 2000.0f; // setup moving speed m_fWalkSpeed = FRnd()/2 + 1.0f; m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); m_fAttackRunSpeed = FRnd() + 2.0f; m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); m_fCloseRunSpeed = FRnd() + 2.0f; m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f); // setup attack distances m_fAttackDistance = 300.0f; m_fCloseDistance = 60.0f; m_fStopDistance = 30.0f; m_fAttackFireTime = 0.5f; m_fCloseFireTime = 1.0f; m_fIgnoreRange = 600.0f; m_iScore = 50000; } else if (m_EecChar==ELC_BIG) { m_sptType = SPT_LAVA_STONES; SetHealth(800.0f); m_fMaxHealth = 800.0f; // after loosing this ammount of damage we will spawn new elemental m_fSpawnDamage = 500.0f; // setup moving speed m_fWalkSpeed = FRnd() + 1.5f; m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); m_fAttackRunSpeed = FRnd()*1.0f + 6.0f; m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 300.0f); m_fCloseRunSpeed = FRnd()*2.0f + 2.0f; m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 300.0f); // setup attack distances m_fAttackDistance = 150.0f; m_fCloseDistance = 20.0f; m_fStopDistance = 5.0f; m_fAttackFireTime = 0.5f; m_fCloseFireTime = 1.0f; m_fIgnoreRange = 400.0f; // damage/explode properties m_iScore = 2500; } else { m_sptType = SPT_LAVA_STONES; SetHealth(100.0f); m_fMaxHealth = 100.0f; // setup moving speed m_fWalkSpeed = FRnd() + 1.5f; m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f); m_fAttackRunSpeed = FRnd()*2.0f + 6.0f; m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 500.0f); m_fCloseRunSpeed = FRnd()*3.0f + 4.0f; m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 500.0f); // setup attack distances m_fAttackDistance = 100.0f; m_fCloseDistance = 10.0f; m_fStopDistance = 5.0f; m_fAttackFireTime = 1.5f; m_fCloseFireTime = 1.0f; m_fIgnoreRange = 200.0f; // damage/explode properties m_iScore = 500; } // non movable if (!m_bMovable) { m_EesStartState = ELS_NORMAL; m_bSpawnWhenHarmed = FALSE; m_bSpawnOnBlowUp = FALSE; // fire count if (m_iFireCount <= 0) { WarningMessage("Entity: %s - Fire count must be greater than zero",(const char*) GetName()); m_iFireCount = 1; } } // state and flare attachments m_EesCurrentState = m_EesStartState; RemoveAttachments(); switch (m_EesCurrentState) { case ELS_NORMAL: SetPhysicsFlags(EPF_MODEL_WALKING); AddAttachments(); break; case ELS_BOX: SetPhysicsFlags(EPF_BOX_PLANE_ELEMENTAL); break; case ELS_PLANE: SetPhysicsFlags(EPF_MODEL_IMMATERIAL|EPF_MOVABLE); SwitchToEditorModel(); break; } StandingAnim(); // stretch if (m_EecChar==ELC_SMALL) { GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_SMALL_STRETCH, LAVAMAN_SMALL_STRETCH, LAVAMAN_SMALL_STRETCH)); } else if (m_EecChar==ELC_LARGE) { GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_LARGE_STRETCH, LAVAMAN_LARGE_STRETCH, LAVAMAN_LARGE_STRETCH)); } else if (m_EecChar==ELC_BIG) { GetModelObject()->StretchModel(FLOAT3D(LAVAMAN_BIG_STRETCH, LAVAMAN_BIG_STRETCH, LAVAMAN_BIG_STRETCH)); } ModelChangeNotify(); // continue behavior in base class jump CEnemyBase::MainLoop(); }; };