Serious-Engine/Sources/EntitiesMP/ModelDestruction.es

330 lines
13 KiB
C++
Raw Normal View History

2016-03-12 01:20:51 +01:00
/* 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. */
2016-03-11 14:57:17 +01:00
217
%{
#include "StdH.h"
%}
uses "EntitiesMP/ModelHolder2";
uses "EntitiesMP/BasicEffects";
uses "EntitiesMP/Debris";
uses "EntitiesMP/BloodSpray";
uses "EntitiesMP/SoundHolder";
// event sent to entities in range of model destroy
// (e.g light can turn off)
event ERangeModelDestruction {
};
// type of debris
enum DestructionDebrisType {
1 DDT_STONE "Stone",
2 DDT_WOOD "Wood",
3 DDT_PALM "Palm",
4 DDT_CHILDREN_CUSTOM "Custom (children)",
};
class CModelDestruction : CEntity {
name "ModelDestruction";
thumbnail "Thumbnails\\ModelDestruction.tbn";
features "HasName", "IsTargetable", "IsImportant";
properties:
1 CTString m_strName "Name" 'N' = "ModelDestruction",
2 CTString m_strDescription = "",
10 CEntityPointer m_penModel0 "Model 0" 'M' COLOR(C_RED|0x80),
11 CEntityPointer m_penModel1 "Model 1" COLOR(C_RED|0x80),
12 CEntityPointer m_penModel2 "Model 2" COLOR(C_RED|0x80),
13 CEntityPointer m_penModel3 "Model 3" COLOR(C_RED|0x80),
14 CEntityPointer m_penModel4 "Model 4" COLOR(C_RED|0x80),
20 FLOAT m_fHealth "Health" 'H' = 50.0f, // health of the model pointing to this
22 enum DestructionDebrisType m_ddtDebris "Debris" 'D' = DDT_STONE, // type of debris
23 INDEX m_ctDebris "Debris Count" = 3,
24 FLOAT m_fDebrisSize "Debris Size" = 1.0f,
25 enum EntityInfoBodyType m_eibtBodyType "Body Type" = EIBT_ROCK,
26 enum SprayParticlesType m_sptType "Particle Type" = SPT_NONE, // type of particles
27 FLOAT m_fParticleSize "Particle Size" 'Z' = 1.0f, // size of particles
28 BOOL m_bRequireExplosion "Requires Explosion" = FALSE,
29 FLOAT m_fDebrisLaunchPower "CC: Debris Launch Power" 'L' = 1.0f, // launch power of debris
30 enum DebrisParticlesType m_dptParticles "CC: Trail particles" = DPT_NONE,
31 enum BasicEffectType m_betStain "CC: Leave stain" = BET_NONE,
32 FLOAT m_fLaunchCone "CC: Launch cone" = 45.0f,
33 FLOAT m_fRndRotH "CC: Rotation heading" = 720.0f,
34 FLOAT m_fRndRotP "CC: Rotation pitch" = 720.0f,
35 FLOAT m_fRndRotB "CC: Rotation banking" = 720.0f,
36 FLOAT m_fParticleLaunchPower "Particle Launch Power" 'P' = 1.0f, // launch power of particles
37 COLOR m_colParticles "Central Particle Color" 'C' = COLOR(C_WHITE|CT_OPAQUE),
40 ANIMATION m_iStartAnim "Start anim" = -1,
41 BOOL m_bDebrisImmaterialASAP "Immaterial ASAP" = TRUE,
50 INDEX m_ctDustFall "Dusts Count" = 1, // count of spawned dust falls
51 FLOAT m_fMinDustFallHeightRatio "Dust Min Height Ratio" = 0.1f, // min ratio of model height for dust
52 FLOAT m_fMaxDustFallHeightRatio "Dust Max Height Ratio" = 0.6f, // max ratio of model height for dust
53 FLOAT m_fDustStretch "Dust Stretch" = 1.0f, // dust stretch
54 FLOAT m_fDebrisDustRandom "Dust Debris Random" = 0.25f, // random for spawning dusts on debris fall
55 FLOAT m_fDebrisDustStretch "Dust Debris Stretch" = 1.0f, // size of spawned dust
56 CEntityPointer m_penShake "Shake marker" 'A',
components:
1 model MODEL_MODELDESTRUCTION "Models\\Editor\\ModelDestruction.mdl",
2 texture TEXTURE_MODELDESTRUCTION "Models\\Editor\\ModelDestruction.tex",
3 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl",
// ************** WOOD PARTS **************
10 model MODEL_WOOD "Models\\Effects\\Debris\\Wood01\\Wood.mdl",
11 texture TEXTURE_WOOD "Models\\Effects\\Debris\\Wood01\\Wood.tex",
12 model MODEL_BRANCH "ModelsMP\\Effects\\Debris\\Tree\\Tree.mdl",
13 texture TEXTURE_BRANCH "ModelsMP\\Plants\\Tree01\\Tree01.tex",
// ************** STONE PARTS **************
14 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl",
15 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex",
functions:
void Precache(void) {
PrecacheClass(CLASS_BASIC_EFFECT, BET_EXPLOSIONSTAIN);
switch(m_ddtDebris) {
case DDT_STONE: {
PrecacheModel(MODEL_STONE);
PrecacheTexture(TEXTURE_STONE);
} break;
case DDT_WOOD: {
PrecacheModel(MODEL_WOOD);
PrecacheTexture(TEXTURE_WOOD);
} break;
case DDT_PALM: {
PrecacheModel(MODEL_WOOD);
PrecacheTexture(TEXTURE_WOOD);
} break;
}
};
/* Get anim data for given animation property - return NULL for none. */
CAnimData *GetAnimData(SLONG slPropertyOffset)
{
if(slPropertyOffset==offsetof(CModelDestruction, m_iStartAnim))
{
CModelHolder2 *pmh=GetModel(0);
if(pmh!=NULL)
{
return pmh->GetModelObject()->GetData();
}
}
return CEntity::GetAnimData(slPropertyOffset);
}
const CTString &GetDescription(void) const {
INDEX ct = GetModelsCount();
if(ct==0) {
((CTString&)m_strDescription).PrintF("(%g): no more", m_fHealth);
} else if(ct==1) {
((CTString&)m_strDescription).PrintF("(%g): %s", m_fHealth, m_penModel0->GetName());
} else if (TRUE) {
((CTString&)m_strDescription).PrintF("(%g): %s,...(%d)", m_fHealth, m_penModel0->GetName(), ct);
}
return m_strDescription;
}
// check if one model target is valid
void CheckOneModelTarget(CEntityPointer &pen)
{
if (pen!=NULL && !IsOfClass(pen, "ModelHolder2")) {
WarningMessage("Model '%s' is not ModelHolder2!", pen->GetName());
pen=NULL;
}
}
// get next phase in destruction
class CModelHolder2 *GetNextPhase(void)
{
INDEX ct = GetModelsCount();
// if not more models
if (ct==0) {
// return none
return NULL;
// if there are some
} else {
// choose by random
return GetModel(IRnd()%ct);
}
}
// get number of models set by user
INDEX GetModelsCount(void) const
{
// note: only first N that are no NULL are used
if (m_penModel0==NULL) { return 0; };
if (m_penModel1==NULL) { return 1; };
if (m_penModel2==NULL) { return 2; };
if (m_penModel3==NULL) { return 3; };
if (m_penModel4==NULL) { return 4; };
return 5;
}
// get model by its index
class CModelHolder2 *GetModel(INDEX iModel)
{
ASSERT(iModel<=GetModelsCount());
iModel = Clamp(iModel, INDEX(0), GetModelsCount());
return (CModelHolder2 *)&*(&m_penModel0)[iModel];
}
// spawn debris for given model
void SpawnDebris(CModelHolder2 *penmhDestroyed)
{
FLOATaabbox3D box;
penmhDestroyed->GetBoundingBox(box);
FLOAT fEntitySize = box.Size().MaxNorm();
switch(m_ddtDebris) {
case DDT_STONE: {
Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(0,0,0), FLOAT3D(0,0,0), 1.0f, 0.0f);
for(INDEX iDebris = 0; iDebris<m_ctDebris; iDebris++) {
Debris_Spawn(penmhDestroyed, this, MODEL_STONE, TEXTURE_STONE, 0, 0, 0, IRnd()%4, m_fDebrisSize,
FLOAT3D(FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f));
}
} break;
case DDT_WOOD:
{
Debris_Begin(EIBT_WOOD, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(0,0,0), FLOAT3D(0,0,0), 1.0f, 0.0f);
for(INDEX iDebris = 0; iDebris<m_ctDebris; iDebris++)
{
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 0, m_fDebrisSize,
FLOAT3D(0.5f, 0.5f, 0.5f));
}
break;
}
case DDT_CHILDREN_CUSTOM:
{
Debris_Begin(EIBT_WOOD, DPT_NONE, BET_NONE, 1.0f, FLOAT3D(10,10,10), FLOAT3D(0,0,0), 5.0f, 2.0f);
// launch all children of model holder type
FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten)
{
if( IsOfClass(&*iten, "ModelHolder2"))
{
CModelHolder2 &mhTemplate=(CModelHolder2 &)*iten;
if( mhTemplate.GetModelObject()==NULL || penmhDestroyed->GetModelObject()==NULL)
{
continue;
}
CModelObject &moNew=*mhTemplate.GetModelObject();
CModelObject &moOld=*penmhDestroyed->GetModelObject();
CPlacement3D plRel=mhTemplate.GetPlacement();
plRel.AbsoluteToRelative(this->GetPlacement());
CPlacement3D plLaunch=plRel;
FLOAT3D vStretch=moOld.mo_Stretch;
plLaunch.pl_PositionVector(1)=plLaunch.pl_PositionVector(1)*vStretch(1);
plLaunch.pl_PositionVector(2)=plLaunch.pl_PositionVector(2)*vStretch(2);
plLaunch.pl_PositionVector(3)=plLaunch.pl_PositionVector(3)*vStretch(3);
plLaunch.RelativeToAbsolute(penmhDestroyed->GetPlacement());
ANGLE3D angLaunch=ANGLE3D(FRnd()*360.0f,90.0f+m_fLaunchCone*(FRnd()-0.5f),0);
FLOAT3D vLaunchDir;
FLOAT3D vStretchTemplate=FLOAT3D(
moOld.mo_Stretch(1)*moNew.mo_Stretch(1),
moOld.mo_Stretch(2)*moNew.mo_Stretch(2),
moOld.mo_Stretch(3)*moNew.mo_Stretch(3));
AnglesToDirectionVector(angLaunch, vLaunchDir);
vLaunchDir.Normalize();
vLaunchDir=vLaunchDir*m_fDebrisLaunchPower;
ANGLE3D angRotSpeed=ANGLE3D(m_fRndRotH*2.0f*(FRnd()-0.5f),m_fRndRotP*(FRnd()-0.5f),m_fRndRotB*(FRnd()-0.5f));
FLOAT fDustSize=0.0f;
if( FRnd()<m_fDebrisDustRandom)
{
fDustSize=m_fDebrisDustStretch;
}
Debris_Spawn_Template( m_eibtBodyType, m_dptParticles, m_betStain,
penmhDestroyed, this, &mhTemplate, vStretchTemplate, mhTemplate.m_fStretchAll, plLaunch,
vLaunchDir, angRotSpeed, m_bDebrisImmaterialASAP, fDustSize, penmhDestroyed->m_colBurning);
}
if( IsOfClass(&*iten, "SoundHolder"))
{
CSoundHolder &ensh=(CSoundHolder &)*iten;
// copy it at the placement of destroyed model
CEntity *penNewSH = GetWorld()->CopyEntityInWorld( ensh, penmhDestroyed->GetPlacement());
penNewSH->SetParent(NULL);
penNewSH->SendEvent(EStart());
}
}
break;
}
case DDT_PALM: {
Debris_Begin(EIBT_WOOD, DPT_NONE, BET_NONE, fEntitySize, penmhDestroyed->m_vDamage*0.3f, FLOAT3D(0,0,0), 1.0f, 0.0f);
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 0, m_fDebrisSize,
FLOAT3D(0.5f, 0.2f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, m_fDebrisSize,
FLOAT3D(0.5f, 0.3f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 2, m_fDebrisSize,
FLOAT3D(0.5f, 0.4f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 3, m_fDebrisSize,
FLOAT3D(0.5f, 0.5f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, m_fDebrisSize,
FLOAT3D(0.5f, 0.6f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 2, m_fDebrisSize,
FLOAT3D(0.5f, 0.8f, 0.5f));
Debris_Spawn(penmhDestroyed, this, MODEL_WOOD, TEXTURE_WOOD, 0, 0, 0, 1, m_fDebrisSize,
FLOAT3D(0.5f, 0.9f, 0.5f));
} break;
default: {} break;
};
if( m_ctDustFall>0)
{
FLOAT fHeight=box.Size()(2);
FLOAT fMinHeight=fHeight*m_fMinDustFallHeightRatio;
FLOAT fMaxHeight=fHeight*m_fMaxDustFallHeightRatio;
FLOAT fHeightSteep=(fMaxHeight-fMinHeight)/m_ctDustFall;
for(INDEX iDust=0; iDust<m_ctDustFall; iDust++)
{
FLOAT fY=fMinHeight+iDust*fHeightSteep;
CPlacement3D plDust=penmhDestroyed->GetPlacement();
plDust.pl_PositionVector=plDust.pl_PositionVector+FLOAT3D(0,fY,0);
// spawn dust effect
ESpawnEffect ese;
ese.colMuliplier = C_WHITE|CT_OPAQUE;
ese.vStretch = FLOAT3D(m_fDustStretch,m_fDustStretch,m_fDustStretch);
ese.vNormal = FLOAT3D(0,1,0);
ese.betType = BET_DUST_FALL;
CEntityPointer penFX = CreateEntity(plDust, CLASS_BASIC_EFFECT);
penFX->Initialize(ese);
}
}
}
procedures:
Main()
{
// must not allow invalid classes
CheckOneModelTarget(m_penModel0);
CheckOneModelTarget(m_penModel1);
CheckOneModelTarget(m_penModel2);
CheckOneModelTarget(m_penModel3);
CheckOneModelTarget(m_penModel4);
InitAsEditorModel();
SetPhysicsFlags(EPF_MODEL_IMMATERIAL);
SetCollisionFlags(ECF_IMMATERIAL);
// set appearance
SetModel(MODEL_MODELDESTRUCTION);
SetModelMainTexture(TEXTURE_MODELDESTRUCTION);
return;
}
};