326
%{
#include "StdH.h"
#include "Models/Enemies/Mamutman/Mamutman.h"
%}

uses "Entities/EnemyBase";
uses "Entities/Bullet";

%{
// info structure
static EntityInfo eiMamutman = {
  EIBT_FLESH, 60.0f,
  0.0f, 2.0f, 0.0f,
  0.0f, 1.5f, 0.0f,
};

#define FIRE    FLOAT3D(0.0f, 0.8f, 0.0f)

#define FRONT 0
#define MIDDLE 1
#define REAR 2
%}


class CMamutman : CEnemyBase {
name      "Mamutman";
thumbnail "Thumbnails\\Mamutman.tbn";

properties:
  1 CEntityPointer m_penBullet,     // bullet
  2 BOOL m_bSpawned = FALSE,
  3 INDEX m_bSpawnedPosition = 0,

components:
  0 class   CLASS_BASE        "Classes\\EnemyBase.ecl",
  1 class   CLASS_BULLET      "Classes\\Bullet.ecl",

  5 model   MODEL_MAMUTMAN    "Models\\Enemies\\Mamutman\\Mamutman.mdl",
  6 texture TEXTURE_MAMUTMAN  "Models\\Enemies\\Mamutman\\Mamutman.tex",

// ************** SOUNDS **************
 50 sound   SOUND_IDLE      "Models\\Enemies\\Mamutman\\Sounds\\Idle.wav",
 51 sound   SOUND_SIGHT     "Models\\Enemies\\Mamutman\\Sounds\\Sight.wav",
 52 sound   SOUND_WOUND     "Models\\Enemies\\Mamutman\\Sounds\\Wound.wav",
 53 sound   SOUND_DEATH     "Models\\Enemies\\Mamutman\\Sounds\\Death.wav",
 54 sound   SOUND_FIRE      "Models\\Weapons\\Colt\\Sounds\\Fire.wav",

functions:
  /* Entity info */
  void *GetEntityInfo(void) {
    return &eiMamutman;
  };

  /* Receive damage */
  void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
    FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection) 
  {
    // mamutman and mamut can't harm mamutman
    if (!IsOfClass(penInflictor, "Mamutman") && !IsOfClass(penInflictor, "Mamut")) {
      CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
    }
  };


  // death
  INDEX AnimForDeath(void) {
    INDEX iAnim;
    switch (IRnd()%2) {
      case 0: iAnim = MAMUTMAN_ANIM_DEATH01; break;
      case 1: iAnim = MAMUTMAN_ANIM_DEATH01; break;
      default: ASSERTALWAYS("Mamutman unknown death");
    }
    StartModelAnim(iAnim, 0);
    return iAnim;
  };

  void DeathNotify(void) {
    ChangeCollisionBoxIndexWhenPossible(MAMUTMAN_COLLISION_BOX_DEATH);
    en_fDensity = 500.0f;
  };

  // virtual anim functions
  void StandingAnim(void) {
    StartModelAnim(MAMUTMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART);
  };
  void WalkingAnim(void) {
    StartModelAnim(MAMUTMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
  };
  void RunningAnim(void) {
    StartModelAnim(MAMUTMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART);
  };
  void RotatingAnim(void) {
    StartModelAnim(MAMUTMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
  };

  // 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);
  };


/************************************************************
 *                       FIRE BULLET                        *
 ************************************************************/
  void PrepareBullet(void) {
    // bullet start position
    CPlacement3D plBullet;
    plBullet.pl_OrientationAngle = ANGLE3D(0,0,0);
    plBullet.pl_PositionVector = FIRE;
    plBullet.RelativeToAbsolute(GetPlacement());
    // create bullet
    m_penBullet = CreateEntity(plBullet, CLASS_BULLET);
    // init bullet
    EBulletInit eInit;
    eInit.penOwner = this;
    eInit.fDamage = 1.0f;
    m_penBullet->Initialize(eInit);
    ((CBullet&)*m_penBullet).CalcTarget(m_penEnemy, 100);
  };

  // fire bullet
  void FireBullet(void) {
    ((CBullet&)*m_penBullet).LaunchBullet(TRUE, TRUE, TRUE);
    ((CBullet&)*m_penBullet).DestroyBullet();
  };



procedures:
/************************************************************
 *                    CLASS INTERNAL                        *
 ************************************************************/
  FallOnFloor(EVoid) {
    // drop to floor
    m_bSpawned = FALSE;
    switch (m_bSpawnedPosition) {
      case FRONT:
        StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTFIRST, 0);
        GiveImpulseTranslationRelative(FLOAT3D(FRnd()*4+8.0f, FRnd()+10.0f, FRnd()+2.0f));
        break;
      case MIDDLE:
        StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTSECOND, 0);
        GiveImpulseTranslationRelative(FLOAT3D(-FRnd()*4-8.0f, FRnd()+10.0f, FRnd()+2.0f));
        break;
      case REAR:
        StartModelAnim(MAMUTMAN_ANIM_FALLFROMMAMUTTHIRD, 0);
        GiveImpulseTranslationRelative(FLOAT3D(0.0f, FRnd()+10.0f, FRnd()*2+2.0f));
        break;
    }
    // wait to touch brush or time limit
    wait (10.0f) {
      on (EBegin) : { resume; }
      // brush touched
      on (ETouch et) : {
        if (et.penOther->GetRenderType()&RT_BRUSH) {
          StopMoving();
          stop;
        }
        resume;
      }
      // death
      on (EDeath) : {
        StopMoving();
        SendEvent(EDeath());
        jump CEnemyBase::MainLoop();
      }
      on (ETimer) : { stop; }
    }

    // get up
    StopMoving();
    StartModelAnim(MAMUTMAN_ANIM_GETUP01, 0);
    wait (GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP01)) {
      on (EBegin) : { resume; }
      on (ETimer) : { stop; }
      // death
      on (EDeath) : {
        StopMoving();
        SendEvent(EDeath());
        jump CEnemyBase::MainLoop();
      }
    }
    return EReturn();
  };



/************************************************************
 *                PROCEDURES WHEN HARMED                    *
 ************************************************************/
  // Play wound animation and falling body part
  BeWounded(EDamage eDamage) : CEnemyBase::BeWounded
  { 
    StopMoving();
    // determine damage anim and play the wounding
    if (IRnd()&1) {
      StartModelAnim(MAMUTMAN_ANIM_FALL01, 0);
      autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_FALL01));
      autowait(0.2f + FRnd()/3);
      StartModelAnim(MAMUTMAN_ANIM_GETUP01, 0);
      autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP01));

    } else if (TRUE) {
      StartModelAnim(MAMUTMAN_ANIM_FALL02, 0);
      autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_FALL02));
      autowait(0.2f + FRnd()/3);
      StartModelAnim(MAMUTMAN_ANIM_GETUP02, 0);
      autowait(GetModelObject()->GetAnimLength(MAMUTMAN_ANIM_GETUP02));
    }
    return EReturn();
  };



/************************************************************
 *                A T T A C K   E N E M Y                   *
 ************************************************************/
  Fire(EVoid) : CEnemyBase::Fire {
    // wait for a while
    StandingAnim();
    PrepareBullet();
    m_fLockOnEnemyTime = 0.2f + FRnd()/8;
    autocall CEnemyBase::LockOnEnemy() EReturn;

    // fire bullet
    StartModelAnim(MAMUTMAN_ANIM_ATTACK02, 0);
    PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
    FireBullet();
    autowait(FRnd()/3 + 0.6f);

    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(40.0f);
    m_fMaxHealth = 40.0f;
    en_tmMaxHoldBreath = 5.0f;
    en_fDensity = 1000.0f;

    // set your appearance
    SetModel(MODEL_MAMUTMAN);
    SetModelMainTexture(TEXTURE_MAMUTMAN);
    if (!m_bSpawned) {
      StandingAnim();
    }
    // setup moving speed
    m_fWalkSpeed = FRnd() + 1.5f;
    m_aWalkRotateSpeed = AngleDeg(FRnd()*10.0f + 25.0f);
    m_fAttackRunSpeed = FRnd()*2.0f + 10.0f;
    m_aAttackRotateSpeed = AngleDeg(FRnd()*50 + 245.0f);
    m_fCloseRunSpeed = FRnd()*2.0f + 10.0f;
    m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 245.0f);
    // setup attack distances
    m_fAttackDistance = 60.0f;
    m_fCloseDistance = 0.0f;
    m_fStopDistance = 17.0f;
    m_fAttackFireTime = 1.0f;
    m_fCloseFireTime = 1.0f;
    m_fIgnoreRange = 200.0f;
    // damage/explode properties
    m_fBlowUpAmount = 20.0f;
    m_fBodyParts = 4;
    m_fDamageWounded = 30.0f;
    m_iScore = 500;

    // continue behavior in base class
    jump CEnemyBase::MainLoop();
  };
};
