mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-25 07:14:50 +01:00
330 lines
13 KiB
C++
330 lines
13 KiB
C++
/* 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. */
|
|
|
|
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;
|
|
}
|
|
};
|
|
|