/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ 320 %{ #include "EntitiesMP/StdH/StdH.h" #include "ModelsMP/Enemies/Woman/Woman.h" #include "Models/Enemies/Headman/headman.h" #include "EntitiesMP/Headman.h" %} uses "EntitiesMP/EnemyFly"; %{ // info structure static EntityInfo eiWomanStand = { EIBT_FLESH, 100.0f, 0.0f, 1.55f, 0.0f, 0.0f, 1.0f, 0.0f, }; static EntityInfo eiWomanFly = { EIBT_FLESH, 80.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; #define FIRE_AIR FLOAT3D(0.0f, 0.25f, -0.65f) #define FIRE_GROUND FLOAT3D(0.0f, 1.3f, -0.5f) #define KAMIKAZE_ATTACH FLOAT3D(0.0f, -0.43f, -0.28f) %} class CWoman : CEnemyFly { name "Woman"; thumbnail "Thumbnails\\Woman.tbn"; properties: 10 BOOL m_bKamikazeCarrier "Kamikaze Carrier" = FALSE, 11 RANGE m_rKamikazeDropDistance "Kamikaze Drop Range" = 40.0f, 20 BOOL m_bKamikazeAttached = FALSE, components: 0 class CLASS_BASE "Classes\\EnemyFly.ecl", 1 model MODEL_WOMAN "ModelsMP\\Enemies\\Woman\\Woman.mdl", 2 texture TEXTURE_WOMAN "Models\\Enemies\\Woman\\Woman.tex", 3 class CLASS_PROJECTILE "Classes\\Projectile.ecl", 5 class CLASS_HEADMAN "Classes\\Headman.ecl", 7 model MODEL_HEADMAN "Models\\Enemies\\Headman\\Headman.mdl", 8 texture TEXTURE_HEADMAN "Models\\Enemies\\Headman\\Kamikaze.tex", 9 model MODEL_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.mdl", 10 texture TEXTURE_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.tex", // ************** SOUNDS ************** 50 sound SOUND_IDLE "Models\\Enemies\\Woman\\Sounds\\Idle.wav", 51 sound SOUND_SIGHT "Models\\Enemies\\Woman\\Sounds\\Sight.wav", 52 sound SOUND_WOUND "Models\\Enemies\\Woman\\Sounds\\Wound.wav", 53 sound SOUND_FIRE "Models\\Enemies\\Woman\\Sounds\\Fire.wav", 54 sound SOUND_KICK "Models\\Enemies\\Woman\\Sounds\\Kick.wav", 55 sound SOUND_DEATH "Models\\Enemies\\Woman\\Sounds\\Death.wav", functions: // describe how this enemy killed player virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath) { CTString str; if (eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) { str.PrintF(TRANSV("%s was beaten by a Scythian Harpy"), (const char *) strPlayerName); } else { str.PrintF(TRANSV("A Scythian Harpy got %s spellbound"), (const char *) strPlayerName); } return str; } virtual const CTFileName &GetComputerMessageName(void) const { static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Woman.txt"); return fnm; } void Precache(void) { CEnemyBase::Precache(); PrecacheSound(SOUND_IDLE ); PrecacheSound(SOUND_SIGHT); PrecacheSound(SOUND_WOUND); PrecacheSound(SOUND_FIRE ); PrecacheSound(SOUND_KICK ); PrecacheSound(SOUND_DEATH); PrecacheClass(CLASS_PROJECTILE, PRT_WOMAN_FIRE); }; /* Entity info */ void *GetEntityInfo(void) { if (m_bInAir) { return &eiWomanFly; } else { return &eiWomanStand; } }; /* Receive damage */ void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType, FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) { // woman can't harm woman if (!IsOfClass(penInflictor, "Woman")) { CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection); } }; // damage anim INDEX AnimForDamage(FLOAT fDamage) { INDEX iAnim; if (m_bInAir) { iAnim = WOMAN_ANIM_AIRWOUND02; } else { iAnim = WOMAN_ANIM_GROUNDWOUND04; } StartModelAnim(iAnim, 0); return iAnim; }; // death INDEX AnimForDeath(void) { INDEX iAnim; if (m_bInAir) { iAnim = WOMAN_ANIM_AIRDEATH; } else { iAnim = WOMAN_ANIM_GROUNDDEATH01; } StartModelAnim(iAnim, 0); return iAnim; }; FLOAT WaitForDust(FLOAT3D &vStretch) { if(GetModelObject()->GetAnim()==WOMAN_ANIM_AIRDEATH) { vStretch=FLOAT3D(1,1,2)*1.0f; return 0.6f; } else if(GetModelObject()->GetAnim()==WOMAN_ANIM_GROUNDDEATH01) { vStretch=FLOAT3D(1,1,2)*0.75f; return 0.525f; } return -1.0f; }; void DeathNotify(void) { ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_DEATH); en_fDensity = 500.0f; }; // virtual anim functions void StandingAnim(void) { if (m_bInAir) { StartModelAnim(WOMAN_ANIM_AIRSTAND, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(WOMAN_ANIM_GROUNDSTAND, AOF_LOOPING|AOF_NORESTART); } }; void WalkingAnim(void) { if (m_bInAir) { StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); } }; void RunningAnim(void) { if (m_bInAir) { StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(WOMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART); } }; void RotatingAnim(void) { if (m_bInAir) { StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART); } else { StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART); } }; FLOAT AirToGroundAnim(void) { StartModelAnim(WOMAN_ANIM_AIRTOGROUND, 0); return(GetModelObject()->GetAnimLength(WOMAN_ANIM_AIRTOGROUND)); }; FLOAT GroundToAirAnim(void) { StartModelAnim(WOMAN_ANIM_GROUNDTOAIR, 0); return(GetModelObject()->GetAnimLength(WOMAN_ANIM_GROUNDTOAIR)); }; void ChangeCollisionToAir() { ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_AIR); }; void ChangeCollisionToGround() { ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_GROUND); }; // 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) { PlaySound(m_soSound, SOUND_WOUND, SOF_3D); }; void DeathSound(void) { PlaySound(m_soSound, SOUND_DEATH, SOF_3D); }; void AttachKamikaze() { AddAttachmentToModel(this, *GetModelObject(), WOMAN_ATTACHMENT_KAMIKAZE, MODEL_HEADMAN, TEXTURE_HEADMAN, 0, 0, 0); CModelObject &amo = GetModelObject()->GetAttachmentModel(WOMAN_ATTACHMENT_KAMIKAZE)->amo_moModelObject; AddAttachmentToModel(this, amo, HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND, MODEL_BOMB, TEXTURE_BOMB, 0, 0, 0); AddAttachmentToModel(this, amo, HEADMAN_ATTACHMENT_BOMB_LEFT_HAND, MODEL_BOMB, TEXTURE_BOMB, 0, 0, 0); amo.PlayAnim(HEADMAN_ANIM_KAMIKAZE_ATTACK, AOF_LOOPING); m_bKamikazeAttached = TRUE; } void RemoveKamikaze() { RemoveAttachmentFromModel(*GetModelObject(), WOMAN_ATTACHMENT_KAMIKAZE); } void DropKamikaze() { if (!m_bKamikazeAttached) { return; } CEntity *pen = NULL; CPlacement3D pl; pl = GetPlacement(); pl.pl_PositionVector += KAMIKAZE_ATTACH*GetRotationMatrix(); pen = CreateEntity(pl, CLASS_HEADMAN); ((CHeadman *)&*pen)->m_hdtType = HDT_KAMIKAZE; // change needed properties pen->End(); CEnemyBase *peb = ((CEnemyBase*)pen); peb->m_bTemplate = FALSE; pen->Initialize(); // mark that we don't have the kamikaze any more m_bKamikazeAttached = FALSE; // deattach the kamikaze model RemoveKamikaze(); } void PreMoving() { if (m_bKamikazeAttached && m_bKamikazeCarrier) { // see if any of players are close enough to drop the kamikaze INDEX ctMaxPlayers = GetMaxPlayers(); CEntity *penPlayer; for(INDEX i=0; iTickQuantum); return EReturn(); }; FlyHit(EVoid) : CEnemyFly::FlyHit { if (m_bKamikazeAttached) { return EReturn(); } // if enemy near if (CalcDist(m_penEnemy) <= 5.0f) { // if enemy is not in water CMovableEntity *pen = (CMovableEntity *)&*m_penEnemy; CContentType &ctDn = pen->en_pwoWorld->wo_actContentTypes[pen->en_iDnContent]; BOOL bEnemySwimming = !(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS); if (bEnemySwimming) { jump FlyFire(); } else { jump FlyOnEnemy(); } } // run to enemy m_fShootTime = _pTimer->CurrentTick() + 0.25f; return EReturn(); }; /************************************************************ * D E A T H * ************************************************************/ Death(EVoid) : CEnemyFly::Death { DropKamikaze(); jump CEnemyFly::Death(); }; AirToGround(EVoid) : CEnemyFly::AirToGround { DropKamikaze(); jump CEnemyFly::AirToGround(EVoid()); }; FlyOnEnemy(EVoid) { StartModelAnim(WOMAN_ANIM_AIRATTACK01, 0); // jump FLOAT3D vDir = PlayerDestinationPos(); vDir = (vDir - GetPlacement().pl_PositionVector).Normalize(); vDir *= !GetRotationMatrix(); vDir *= m_fFlyCloseRunSpeed*1.9f; SetDesiredTranslation(vDir); PlaySound(m_soSound, SOUND_KICK, SOF_3D); // animation - IGNORE DAMAGE WOUND - SpawnReminder(this, 0.9f, 0); m_iChargeHitAnimation = WOMAN_ANIM_AIRATTACK01; m_fChargeHitDamage = 20.0f; m_fChargeHitAngle = 0.0f; m_fChargeHitSpeed = 10.0f; autocall CEnemyBase::ChargeHitEnemy() EReturn; StandingAnim(); autowait(0.3f); return EReturn(); } GroundFire(EVoid) : CEnemyFly::GroundFire { // fire projectile StartModelAnim(WOMAN_ANIM_GROUNDATTACK02, 0); autowait(0.3f); ShootProjectile(PRT_WOMAN_FIRE, FIRE_GROUND, ANGLE3D(0, 0, 0)); PlaySound(m_soSound, SOUND_FIRE, SOF_3D); autowait(0.3f); StandingAnim(); autowait(FRnd()/2 + _pTimer->TickQuantum); return EReturn(); }; GroundHit(EVoid) : CEnemyFly::GroundHit { StartModelAnim(WOMAN_ANIM_GROUNDATTACK01, 0); // jump FLOAT3D vDir = (m_penEnemy->GetPlacement().pl_PositionVector - GetPlacement().pl_PositionVector).Normalize(); vDir *= !GetRotationMatrix(); vDir *= m_fCloseRunSpeed*1.75f; vDir(2) = 2.5f; SetDesiredTranslation(vDir); PlaySound(m_soSound, SOUND_KICK, SOF_3D); // animation - IGNORE DAMAGE WOUND - SpawnReminder(this, 0.9f, 0); m_iChargeHitAnimation = WOMAN_ANIM_GROUNDATTACK01; m_fChargeHitDamage = 20.0f; m_fChargeHitAngle = 0.0f; m_fChargeHitSpeed = 10.0f; autocall CEnemyBase::ChargeHitEnemy() EReturn; StandingAnim(); autowait(0.3f); return EReturn(); }; /************************************************************ * M A I N * ************************************************************/ Main(EVoid) { // declare yourself as a model InitAsModel(); SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS); SetCollisionFlags(ECF_MODEL); SetFlags(GetFlags()|ENF_ALIVE); SetHealth(100.0f); m_fMaxHealth = 100.0f; en_tmMaxHoldBreath = 5.0f; en_fDensity = 2000.0f; m_sptType = SPT_FEATHER; // set your appearance SetModel(MODEL_WOMAN); SetModelMainTexture(TEXTURE_WOMAN); // setup moving speed m_fWalkSpeed = FRnd() + 1.5f; m_aWalkRotateSpeed = FRnd()*10.0f + 25.0f; m_fAttackRunSpeed = FRnd()*2.0f + 9.0f; m_aAttackRotateSpeed = FRnd()*50 + 245.0f; m_fCloseRunSpeed = FRnd()*2.0f + 4.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_fFlyWalkSpeed = FRnd()/2 + 1.0f; m_aFlyWalkRotateSpeed = FRnd()*10.0f + 25.0f; m_fFlyAttackRunSpeed = FRnd()*2.0f + 10.0f; m_aFlyAttackRotateSpeed = FRnd()*25 + 150.0f; m_fFlyCloseRunSpeed = FRnd()*2.0f + 10.0f; m_aFlyCloseRotateSpeed = FRnd()*50 + 500.0f; m_fGroundToAirSpeed = m_fFlyCloseRunSpeed; m_fAirToGroundSpeed = m_fFlyCloseRunSpeed; m_fAirToGroundMin = 0.1f; m_fAirToGroundMax = 0.1f; // attack properties - CAN BE SET m_fFlyAttackDistance = 50.0f; m_fFlyCloseDistance = 12.5f; m_fFlyStopDistance = 0.0f; m_fFlyAttackFireTime = 3.0f; m_fFlyCloseFireTime = 2.0f; m_fFlyIgnoreRange = 200.0f; // damage/explode properties m_fBlowUpAmount = 100.0f; m_fBodyParts = 4; m_fDamageWounded = 20.0f; m_iScore = 1000; if (m_bKamikazeCarrier) { AttachKamikaze(); } autowait(0.05f); // continue behavior in base class jump CEnemyFly::MainLoop(); }; };