/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */ 312 %{ #include "StdH.h" %} uses "EntitiesMP/EnemyBase"; class export CEnemyRunInto : CEnemyBase { name "Enemy Run Into"; thumbnail ""; properties: 1 CEntityPointer m_penLastTouched, // last touched live entity 2 FLOAT m_fLastTouchedTime = 0.0f, // last touched live entity time 3 BOOL m_bWhileLoop = FALSE, // internal for loops 5 FLOAT m_fMassKicked = 0.0f, // total mass kicked in one attack 7 FLOAT m_fInertionRunTime = 1.3f, // time to run before turning due to inertion 8 FLOAT m_fStopApproachDistance = 6.75f, // at which distamce to start runnin away from enemy 9 FLOAT m_fChargeDistance = 15.0f, // at which distance to prepare for charge 10 BOOL m_bUseChargeAnimation = FALSE, // does this monster use charging animation? // moving properties - CAN BE SET 20 ANGLE m_fAttackRotateRunInto = 1.0f, // attack rotate speed before run into enemy components: 1 class CLASS_BASE "Classes\\EnemyBase.ecl", functions: virtual void AdjustDifficulty(void) { FLOAT fMoveSpeed = GetSP()->sp_fEnemyMovementSpeed; m_fAttackRotateRunInto *= fMoveSpeed; CEnemyBase::AdjustDifficulty(); } /************************************************************ * ATTACK SPECIFIC * ************************************************************/ void IncreaseKickedMass(CEntity *pen) { EntityInfo *peiTarget = (EntityInfo*) (pen->GetEntityInfo()); if (peiTarget!=NULL) { m_fMassKicked += peiTarget->fMass; } }; /************************************************************ * VIRTUAL ATTACK FUNCTIONS THAT NEED OVERRIDE * ************************************************************/ // touched another live entity virtual void LiveEntityTouched(ETouch etouch) {}; // touched entity with higher mass virtual BOOL HigherMass(void) { return FALSE; } virtual void ChargeAnim(void) {}; procedures: /************************************************************ * ATTACK ENEMY PROCEDURES * ************************************************************/ // attack range -> fire and move toward enemy Fire() : CEnemyBase::Fire { m_fMassKicked = 0.0f; m_penLastTouched = NULL; jump RotateToEnemy(); }; RotateToEnemy() { // if the enemy not alive or deleted if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { SetTargetNone(); return EReturn(); } // rotate to enemy m_bWhileLoop = TRUE; while (m_penEnemy!=NULL && m_bWhileLoop) { m_fMoveFrequency = 0.1f; wait(m_fMoveFrequency) { // attack target on (EBegin) : { m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; // rotate to enemy if (!IsInPlaneFrustum(m_penEnemy, CosFast(15.0f))) { m_aRotateSpeed = m_fAttackRotateRunInto; m_fMoveSpeed = 0.0f; // adjust direction and speed ULONG ulFlags = SetDesiredMovement(); MovementAnimation(ulFlags); } else { m_aRotateSpeed = 0.0f; m_fMoveSpeed = 0.0f; m_bWhileLoop = FALSE; } resume; } on (ESound) : { resume; } // ignore all sounds on (EWatch) : { resume; } // ignore watch on (ETimer) : { stop; } // timer tick expire } } jump RunIntoEnemy(); }; /* WalkToEnemy() { // if the enemy not alive or deleted if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { SetTargetNone(); return EReturn(); } // walk to enemy if can't be seen while (!CanAttackEnemy(m_penEnemy, CosFast(30.0f))) { m_fMoveFrequency = 0.1f; wait(m_fMoveFrequency) { // move to target on (EBegin) : { m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; m_fMoveSpeed = m_fWalkSpeed; m_aRotateSpeed = m_aWalkRotateSpeed; // adjust direction and speed ULONG ulFlags = SetDesiredMovement(); MovementAnimation(ulFlags); } on (ESound) : { resume; } // ignore all sounds on (EWatch) : { resume; } // ignore watch on (ETimer) : { stop; } // timer tick expire } } jump StartRunIntoEnemy(); }; StartRunIntoEnemy() { // if the enemy not alive or deleted if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { SetTargetNone(); return EReturn(); } // run to enemy m_bWhileLoop = TRUE; m_fMoveFrequency = 0.5f; wait(m_fMoveFrequency) { on (EBegin) : { // if enemy can't be seen stop running if (!SeeEntity(m_penEnemy, CosFast(90.0f))) { m_bWhileLoop = FALSE; stop; } m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector; // move to enemy m_fMoveSpeed = m_fAttackRunSpeed; m_aRotateSpeed = m_aAttackRotateSpeed; // adjust direction and speed SetDesiredMovement(); RunningAnim(); resume; } on (ETouch) : { resume; } on (ETimer) : { stop; } // timer tick expire } jump RunIntoEnemy(); }; */ RunIntoEnemy() { // if the enemy not alive or deleted if (!(m_penEnemy->GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { SetTargetNone(); return EReturn(); } // run to enemy m_bWhileLoop = TRUE; while(m_penEnemy!=NULL && m_bWhileLoop) { m_fMoveFrequency = 0.1f; wait(m_fMoveFrequency) { on (EBegin) : { // if enemy can't be seen, or too close if (!SeeEntity(m_penEnemy, CosFast(90.0f)) || CalcDist(m_penEnemy)GetPlacement().pl_PositionVector; SetDesiredMovement(); if (m_bUseChargeAnimation && CalcDist(m_penEnemy)GetFlags()&ENF_ALIVE) { // react to hitting it LiveEntityTouched(etouch); // if hit something bigger than us if (HigherMass()) { // stop attack m_penLastTouched = NULL; return EReturn(); } // if hit the enemy if (etouch.penOther==m_penEnemy) { // continue past it m_bWhileLoop = FALSE; stop; } // if hit wall } else if (!(etouch.penOther->GetPhysicsFlags()&EPF_MOVABLE) && (FLOAT3D(etouch.plCollision)% -en_vGravityDir)GetFlags()&ENF_ALIVE) || m_penEnemy->GetFlags()&ENF_DELETED) { SetTargetNone(); return EReturn(); } // run in direction due to inertion before turning StopRotating(); wait(m_fInertionRunTime) { on (EBegin) : { resume; } on (ETouch etouch) : { // live entity touched if (etouch.penOther->GetFlags()&ENF_ALIVE) { LiveEntityTouched(etouch); // stop moving on higher mass if (HigherMass()) { m_penLastTouched = NULL; return EReturn(); } // stop go away from enemy } else if (!(etouch.penOther->GetPhysicsFlags()&EPF_MOVABLE) && (FLOAT3D(etouch.plCollision)% -en_vGravityDir)