504
%{
#include "StdH.h"
%}

uses "Entities/Light";

// input parameter for flame
event EFlame {
  CEntityPointer penOwner,        // entity which owns it
  CEntityPointer penAttach,       // entity on which flame is attached (his parent)
};

%{
void CFlame_OnPrecache(CDLLEntityClass *pdec, INDEX iUser) 
{
  pdec->PrecacheModel(MODEL_FLAME);
  pdec->PrecacheTexture(TEXTURE_FLAME);
  pdec->PrecacheSound(SOUND_FLAME);
}
%}

class CFlame : CMovableModelEntity {
name      "Flame";
thumbnail "";
features "ImplementsOnPrecache", "CanBePredictable";

properties:
  1 CEntityPointer m_penOwner,    // entity which owns it
  2 CEntityPointer m_penAttach,   // entity on which flame is attached (his parent)
  5 BOOL m_bLoop = FALSE,                 // internal for loops

 10 CSoundObject m_soEffect,      // sound channel

{
  CLightSource m_lsLightSource;
}

components:
  1 class   CLASS_LIGHT         "Classes\\Light.ecl",

// ********* FLAME *********
 10 model   MODEL_FLAME         "Models\\Effects\\Flame\\Flame.mdl",
 //"Models\\Weapons\\Flamer\\Projectile\\Invisible.mdl",
 11 texture TEXTURE_FLAME       "Models\\Effects\\Flame\\Flame.tex",
 12 sound   SOUND_FLAME         "Sounds\\Fire\\Fire4.wav",

functions:
  // add to prediction any entities that this entity depends on
  void AddDependentsToPrediction(void)
  {
    m_penOwner->AddToPrediction();
  }
  // postmoving
  void PostMoving(void) {
    CMovableModelEntity::PostMoving();

    // if no air
    CContentType &ctDn = GetWorld()->wo_actContentTypes[en_iDnContent];
    // stop existing
    if (!(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS)) {
      SendEvent(EEnd());
    }

    // never remove from list of movers
    en_ulFlags &= ~ENF_INRENDERING;
    // not moving in fact, only moving with its parent
    en_plLastPlacement = en_plPlacement;
  };

  /* Read from stream. */
  void Read_t( CTStream *istr) // throw char *
  {
    CRationalEntity::Read_t(istr);
    SetupLightSource();
  }

  /* Get static light source information. */
  CLightSource *GetLightSource(void)
  {
    if (!IsPredictor()) {
      return &m_lsLightSource;
    } else {
      return NULL;
    }
  }

  // Setup light source
  void SetupLightSource(void)
  {
    // setup light source
    CLightSource lsNew;
    lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC;
    lsNew.ls_colColor = C_dYELLOW;
    lsNew.ls_rFallOff = 2.0f;
    lsNew.ls_rHotSpot = 0.2f;
    lsNew.ls_plftLensFlare = NULL;
    lsNew.ls_ubPolygonalMask = 0;
    lsNew.ls_paoLightAnimation = NULL;

    m_lsLightSource.ls_penEntity = this;
    m_lsLightSource.SetLightSource(lsNew);
  }

/************************************************************
 *                   P R O C E D U R E S                    *
 ************************************************************/
procedures:
  // --->>> MAIN
  Main(EFlame ef) {
    // attach to parent (another entity)
    ASSERT(ef.penOwner!=NULL);
    ASSERT(ef.penAttach!=NULL);
    m_penOwner = ef.penOwner;
    m_penAttach = ef.penAttach;
    SetParent(ef.penAttach);

    // initialization
    InitAsModel();
    SetPhysicsFlags(EPF_MODEL_FLYING);
    SetCollisionFlags(ECF_FLAME);
    SetFlags(GetFlags() | ENF_SEETHROUGH);

    // if parent is model
    if (m_penAttach->GetRenderType()==CEntity::RT_MODEL) {
      // stretch to its size
      FLOATaabbox3D box;
      m_penAttach->GetBoundingBox(box);
      GetModelObject()->StretchModel(box.Size());
    }
    ModelChangeNotify();

    SetModel(MODEL_FLAME);
    SetModelMainTexture(TEXTURE_FLAME);
    // play the burning sound
    m_soEffect.Set3DParameters(5.0f, 1.0f, 1.0f, 1.0f);
    PlaySound(m_soEffect, SOUND_FLAME, SOF_3D|SOF_LOOP);

    // setup light source
    SetupLightSource();

    // must always be in movers, to find sector content type
    AddToMovers();

    // burning damage
    SpawnReminder(this, 7.5f, 0);
    m_bLoop = TRUE;
    while(m_bLoop) {
      wait(0.25f) {
        // damage to parent
        on (EBegin) : {
          // if parent does not exist anymore
          if (m_penAttach==NULL || (m_penAttach->GetFlags()&ENF_DELETED)) {
            // stop existing
            m_bLoop = FALSE;
            stop;
          }
          // inflict damage to parent
          m_penAttach->InflictDirectDamage(m_penAttach, m_penOwner, DMT_BURNING, 1.0f, FLOAT3D(0, 0, 0), -en_vGravityDir);
          resume;
        }
        on (EFlame ef) : {
          m_penOwner = ef.penOwner;
          resume;
        };
        on (ETimer) : { stop; }
        on (EReminder) : {
          m_bLoop = FALSE;
          stop;
        }
        on (EEnd) : {
          m_bLoop = FALSE;
          stop;
        }
      }
    }

    // cease to exist
    Destroy();
    return;
  }
};
