Serious-Engine/Sources/EntitiesMP/DestroyableArchitecture.es
2016-03-11 18:20:51 -06:00

459 lines
16 KiB
JavaScript

/* 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. */
107
%{
#include "StdH.h"
#include "EntitiesMP/Effector.h"
#include "EntitiesMP/MovingBrush.h"
%}
uses "EntitiesMP/Devil";
uses "EntitiesMP/Debris";
uses "EntitiesMP\GradientMarker";
%{
struct DebrisInfo {
ULONG ulModelID;
ULONG ulTextureID;
FLOAT vOffset[3];
};
static struct DebrisInfo _ObeliskDebrisInfo[] =
{
{ MODEL_OBELISK01, TEXTURE_OBELISK, 0.0f, 114.4989f, 0.0f},
{ MODEL_OBELISK02, TEXTURE_OBELISK, 0.035f, 106.8628f, 0.0f},
{ MODEL_OBELISK03, TEXTURE_OBELISK, 0.0f, 98.628f, 0.0f},
{ MODEL_OBELISK04, TEXTURE_OBELISK, 0.0f, 90.4996f, 0.0f},
{ MODEL_OBELISK05, TEXTURE_OBELISK, 0.0f, 82.174f, 0.0f},
{ MODEL_OBELISK06, TEXTURE_OBELISK, 0.0f, 71.0425f, 0.0f},
{ MODEL_OBELISK07, TEXTURE_OBELISK, 0.0f, 59.2f, 0.0f},
{ MODEL_OBELISK08, TEXTURE_OBELISK, 0.0f, 46.65f, 0.0f},
{ MODEL_OBELISK09, TEXTURE_OBELISK, 0.0f, 36.6f, 0.0f},
};
static struct DebrisInfo _PylonDebrisInfo[] =
{
{ MODEL_PYLON01, TEXTURE_PYLON, -17.3379f, 55.92f, 0},
{ MODEL_PYLON02, TEXTURE_PYLON, -10.525f, 58.045f, 0},
{ MODEL_PYLON03, TEXTURE_PYLON, -17.66f, 42.32f, 0},
{ MODEL_PYLON04, TEXTURE_PYLON, -0.815000f, 54.69f, 0 },
{ MODEL_PYLON05, TEXTURE_PYLON, 14.795f, 51.65f, 0},
{ MODEL_PYLON06, TEXTURE_PYLON, 0.02f, 36.18f, 0},
{ MODEL_PYLON07, TEXTURE_PYLON, -10.289f, 33.982f, 0},
{ MODEL_PYLON08, TEXTURE_PYLON, -22.9152f, 28.6205f, 0},
{ MODEL_PYLON09, TEXTURE_PYLON, 21.932f, 47.2453f, 0},
};
%}
class CDestroyableArchitecture: CMovableBrushEntity {
name "DestroyableArchitecture";
thumbnail "Thumbnails\\DestroyableArchitecture.tbn";
features "HasName", "IsTargetable";
properties:
1 CTString m_strName "Name" 'N' = "DestroyableArchitecture", // name
2 FLOAT m_fHealth "Health" 'H' = -1.0f, // health
3 enum EffectorEffectType m_etType "Type" 'Y' = ET_DESTROY_OBELISK, // name
4 FLOAT3D m_vDamageDir = FLOAT3D(0,0,0), // direction of damage
5 FLOAT m_fStretch "Stretch" 'S' = 1.0f, // debris stretch
6 CEntityPointer m_penGradient "Gradient" 'R',
10 COLOR m_colDebrises "Color of debrises" = C_WHITE,
11 INDEX m_ctDebrises "Debris count" = 12,
12 FLOAT m_fCandyEffect "Debris blow power" = 0.0f,
13 FLOAT m_fCubeFactor "Cube factor" = 1.0f,
14 BOOL m_bBlowupByDamager "Blowup by Damager" = FALSE, // if only damager can destroy brush
15 FLOAT m_fDustStretch "Dust stretch" = 0.0f,
components:
// ************** DEBRIS PARTS **************
10 texture TEXTURE_OBELISK "Models\\CutSequences\\Obelisk\\Obelisk.tex",
11 model MODEL_OBELISK01 "Models\\CutSequences\\Obelisk\\Part01.mdl",
12 model MODEL_OBELISK02 "Models\\CutSequences\\Obelisk\\Part02.mdl",
13 model MODEL_OBELISK03 "Models\\CutSequences\\Obelisk\\Part03.mdl",
14 model MODEL_OBELISK04 "Models\\CutSequences\\Obelisk\\Part04.mdl",
15 model MODEL_OBELISK05 "Models\\CutSequences\\Obelisk\\Part05.mdl",
16 model MODEL_OBELISK06 "Models\\CutSequences\\Obelisk\\Part06.mdl",
17 model MODEL_OBELISK07 "Models\\CutSequences\\Obelisk\\Part07.mdl",
18 model MODEL_OBELISK08 "Models\\CutSequences\\Obelisk\\Part08.mdl",
19 model MODEL_OBELISK09 "Models\\CutSequences\\Obelisk\\Part09.mdl",
20 texture TEXTURE_PYLON "Models\\CutSequences\\Pylon\\Pylon.tex",
21 model MODEL_PYLON01 "Models\\CutSequences\\Pylon\\Part01.mdl",
22 model MODEL_PYLON02 "Models\\CutSequences\\Pylon\\Part02.mdl",
23 model MODEL_PYLON03 "Models\\CutSequences\\Pylon\\Part03.mdl",
24 model MODEL_PYLON04 "Models\\CutSequences\\Pylon\\Part04.mdl",
25 model MODEL_PYLON05 "Models\\CutSequences\\Pylon\\Part05.mdl",
26 model MODEL_PYLON06 "Models\\CutSequences\\Pylon\\Part06.mdl",
27 model MODEL_PYLON07 "Models\\CutSequences\\Pylon\\Part07.mdl",
28 model MODEL_PYLON08 "Models\\CutSequences\\Pylon\\Part08.mdl",
29 model MODEL_PYLON09 "Models\\CutSequences\\Pylon\\Part09.mdl",
// ************** NEEDED CLASSES **************
30 class CLASS_DEBRIS "Classes\\Debris.ecl",
31 class CLASS_EFFECTOR "Classes\\Effector.ecl",
// ************** STONE PARTS **************
32 model MODEL_STONE "Models\\Effects\\Debris\\Stone\\Stone.mdl",
33 texture TEXTURE_STONE "Models\\Effects\\Debris\\Stone\\Stone.tex",
functions:
void Precache(void)
{
PrecacheClass (CLASS_DEBRIS , ET_DISAPPEAR_MODEL);
PrecacheClass (CLASS_EFFECTOR , ET_DISAPPEAR_MODEL);
PrecacheModel (MODEL_STONE );
PrecacheTexture (TEXTURE_STONE );
// precache acording to destroying architecture
switch( m_etType)
{
case ET_DESTROY_OBELISK:
PrecacheTexture (TEXTURE_OBELISK );
PrecacheModel (MODEL_OBELISK01 );
PrecacheModel (MODEL_OBELISK02 );
PrecacheModel (MODEL_OBELISK03 );
PrecacheModel (MODEL_OBELISK04 );
PrecacheModel (MODEL_OBELISK05 );
PrecacheModel (MODEL_OBELISK06 );
PrecacheModel (MODEL_OBELISK07 );
PrecacheModel (MODEL_OBELISK08 );
PrecacheModel (MODEL_OBELISK09 );
break;
case ET_DESTROY_PYLON:
PrecacheTexture (TEXTURE_PYLON );
PrecacheModel (MODEL_PYLON01 );
PrecacheModel (MODEL_PYLON02 );
PrecacheModel (MODEL_PYLON03 );
PrecacheModel (MODEL_PYLON04 );
PrecacheModel (MODEL_PYLON05 );
PrecacheModel (MODEL_PYLON06 );
PrecacheModel (MODEL_PYLON07 );
PrecacheModel (MODEL_PYLON08 );
PrecacheModel (MODEL_PYLON09 );
break;
}
}
// Validate offered target for one property
BOOL IsTargetValid(SLONG slPropertyOffset, CEntity *penTarget)
{
if(penTarget==NULL)
{
return FALSE;
}
// if gradient marker
if( slPropertyOffset==offsetof(CDestroyableArchitecture, m_penGradient) )
{
return (IsDerivedFromClass(penTarget, "Gradient Marker"));
}
return CEntity::IsTargetValid(slPropertyOffset, penTarget);
}
/* Get gradient type name, return empty string if not used. */
const CTString &GetGradientName(INDEX iGradient)
{
static const CTString strDummyName("");
static const CTString strMarkerUnused("Marker not set");
if (iGradient==1)
{
CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient;
if (pgm != NULL) {
return pgm->GetGradientName();
} else {
return strMarkerUnused;
}
}
return strDummyName;
}
/* Uncache shadows for given gradient */
void UncacheShadowsForGradient(class CGradientMarker *penDiscard)
{
CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient;
if(pgm == penDiscard)
{
CEntity::UncacheShadowsForGradient(1);
}
}
/* Get gradient, return FALSE for none. */
BOOL GetGradient(INDEX iGradient, class CGradientParameters &fpGradient)
{
if ( iGradient==1)
{
CGradientMarker *pgm = (CGradientMarker *)&*m_penGradient;
if (pgm != NULL) {
return pgm->GetGradient(0, fpGradient);
}
}
return FALSE;
}
/* Receive damage */
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
{
// if not destroyable
if(m_fHealth<0) {
// ignore damages
return;
}
if(m_bBlowupByDamager)
{
if( dmtType == DMT_DAMAGER)
{
CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
}
}
else
{
// react only on explosions
if( (dmtType == DMT_EXPLOSION) ||
(dmtType == DMT_PROJECTILE) ||
(dmtType == DMT_CANNONBALL) )
{
CMovableBrushEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
}
}
}
void DestroyObelisk()
{
for( INDEX iDebris=0; iDebris<ARRAYCOUNT(_ObeliskDebrisInfo); iDebris++)
{
DebrisInfo &di = _ObeliskDebrisInfo[iDebris];
FLOAT3D vOffset = FLOAT3D( di.vOffset[0], di.vOffset[1], di.vOffset[2])*m_fStretch;
FLOAT3D vPos = GetPlacement().pl_PositionVector+vOffset;
CEntityPointer penDebris = GetWorld()->CreateEntity_t(
CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl"));
// prepare parameters
ESpawnDebris eSpawn;
eSpawn.fDustStretch=m_fDustStretch;
eSpawn.bCustomShading=FALSE;
eSpawn.bImmaterialASAP=FALSE;
eSpawn.colDebris = C_WHITE|CT_OPAQUE;
eSpawn.Eeibt = EIBT_ROCK;
eSpawn.dptParticles = DPT_NONE;
eSpawn.betStain = BET_NONE;
eSpawn.pmd = GetModelDataForComponent(di.ulModelID);
eSpawn.ptd = GetTextureDataForComponent(di.ulTextureID);
eSpawn.ptdRefl = NULL;
eSpawn.ptdSpec = NULL;
eSpawn.ptdBump = NULL;
eSpawn.iModelAnim = 0;
eSpawn.fSize = m_fStretch;
eSpawn.vStretch = FLOAT3D(1,1,1);
eSpawn.penFallFXPapa=NULL;
// initialize it
penDebris->Initialize(eSpawn);
// speed it up
FLOAT fHeightRatio = di.vOffset[1]*m_fStretch/120.0f;
FLOAT3D vSpeed = FLOAT3D( FRnd()-0.5f, 0.0f, FRnd()-0.5f)*(1.0f-fHeightRatio)*160.0f;
FLOAT3D vRot = FLOAT3D( FRnd()-0.5f, (FRnd()-0.5f)*(1.0f-fHeightRatio), FRnd()-0.5f)*200.0f;
/*
vSpeed = FLOAT3D( 0,0,0);
vRot = FLOAT3D( 0,0,0);*/
((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( vSpeed, NULL);
((CMovableEntity&)*penDebris).SetDesiredRotation( vRot);
}
// notify children
FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) {
iten->SendEvent( EBrushDestroyed());
}
m_fHealth = -1;
ForceFullStop();
SetDefaultProperties();
CPlacement3D plObelisk = GetPlacement();
// notify engine to kickstart entities that are cached in stationary position,
// before we turn off, so they can fall
NotifyCollisionChanged();
SetFlags( GetFlags()|ENF_HIDDEN);
SetCollisionFlags(ECF_IMMATERIAL);
// spawn spray spray
CEntity *penEffector = CreateEntity( plObelisk, CLASS_EFFECTOR);
// set spawn parameters
ESpawnEffector eSpawnEffector;
eSpawnEffector.tmLifeTime = 6.0f;
eSpawnEffector.eetType = ET_DESTROY_OBELISK;
// initialize spray
penEffector->Initialize( eSpawnEffector);
}
void DestroyPylon()
{
for( INDEX iDebris=0; iDebris<ARRAYCOUNT(_PylonDebrisInfo); iDebris++)
{
DebrisInfo &di = _PylonDebrisInfo[iDebris];
FLOAT3D vOffset = FLOAT3D( di.vOffset[0], di.vOffset[1], di.vOffset[2])*m_fStretch;
FLOAT3D vPos = GetPlacement().pl_PositionVector+vOffset;
CEntityPointer penDebris = GetWorld()->CreateEntity_t(
CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl"));
// prepare parameters
ESpawnDebris eSpawn;
eSpawn.fDustStretch=m_fDustStretch;
eSpawn.bImmaterialASAP=FALSE;
eSpawn.bCustomShading=FALSE;
eSpawn.colDebris = C_WHITE|CT_OPAQUE;
eSpawn.Eeibt = EIBT_ROCK;
eSpawn.dptParticles = DPT_NONE;
eSpawn.betStain = BET_NONE;
eSpawn.pmd = GetModelDataForComponent(di.ulModelID);
eSpawn.ptd = GetTextureDataForComponent(di.ulTextureID);
eSpawn.ptdRefl = NULL;
eSpawn.ptdSpec = NULL;
eSpawn.ptdBump = NULL;
eSpawn.iModelAnim = 0;
eSpawn.fSize = m_fStretch;
eSpawn.vStretch = FLOAT3D(1,1,1);
eSpawn.penFallFXPapa=NULL;
// initialize it
penDebris->Initialize(eSpawn);
// speed it up
FLOAT fHeightRatio = di.vOffset[1]*m_fStretch/120.0f;
FLOAT3D vSpeed = (m_vDamageDir*2.0f+FLOAT3D( FRnd()-0.5f, 0.0f, FRnd()))*fHeightRatio*160.0f;
FLOAT3D vRot = FLOAT3D( FRnd()-0.5f, (FRnd()-0.5f)*fHeightRatio, FRnd()-0.5f)*300.0f;
((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( vSpeed, NULL);
((CMovableEntity&)*penDebris).SetDesiredRotation( vRot);
}
// notify children
FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) {
iten->SendEvent( EBrushDestroyed());
}
m_fHealth = -1;
CPlacement3D plObelisk = GetPlacement();
// spawn spray spray
CEntity *penEffector = CreateEntity( plObelisk, CLASS_EFFECTOR);
// set spawn parameters
ESpawnEffector eSpawnEffector;
eSpawnEffector.eetType = ET_DESTROY_PYLON;
eSpawnEffector.tmLifeTime = 6.0f;
eSpawnEffector.vDamageDir = m_vDamageDir;
// initialize spray
penEffector->Initialize( eSpawnEffector);
ForceFullStop();
SetDefaultProperties();
// notify engine to kickstart entities that are cached in stationary position,
// before we turn off, so they can fall
NotifyCollisionChanged();
SetFlags( GetFlags()|ENF_HIDDEN);
SetCollisionFlags(ECF_IMMATERIAL);
}
// returns bytes of memory used by this object
SLONG GetUsedMemory(void)
{
// initial
SLONG slUsedMemory = sizeof(CDestroyableArchitecture) - sizeof(CMovableBrushEntity) + CMovableBrushEntity::GetUsedMemory();
// add some more
slUsedMemory += m_strName.Length();
return slUsedMemory;
}
procedures:
Main() {
// declare yourself as a brush
InitAsBrush();
SetPhysicsFlags(EPF_BRUSH_MOVING);
SetCollisionFlags(ECF_BRUSH);
// non-zoning brush
SetFlags(GetFlags()&~ENF_ZONING);
SetHealth(m_fHealth);
// start moving
wait() {
on (EBegin) : {
resume;
}
on (EBrushDestroyedByDevil ebdbd) :
{
m_vDamageDir = ebdbd.vDamageDir;
switch( m_etType)
{
case ET_DESTROY_OBELISK:
DestroyObelisk();
break;
case ET_DESTROY_PYLON:
DestroyPylon();
break;
}
stop;
}
on (EDeath eDeath) : {
// get your size
FLOATaabbox3D box;
GetSize(box);
if( m_ctDebrises<=0)
{
m_ctDebrises=1;
}
FLOAT fEntitySize = pow(box.Size()(1)*box.Size()(2)*box.Size()(3)/m_ctDebrises, 1.0f/3.0f)*m_fCubeFactor;
Debris_Begin(EIBT_ROCK, DPT_NONE, BET_NONE, fEntitySize, FLOAT3D(1.0f,2.0f,3.0f),
FLOAT3D(0,0,0), 1.0f+m_fCandyEffect/2.0f, m_fCandyEffect, m_colDebrises);
for(INDEX iDebris = 0; iDebris<m_ctDebrises; iDebris++) {
Debris_Spawn(this, this, MODEL_STONE, TEXTURE_STONE, 0, 0, 0, IRnd()%4, 1.0f,
FLOAT3D(FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f, FRnd()*0.8f+0.1f));
}
// notify children
FOREACHINLIST( CEntity, en_lnInParent, en_lhChildren, iten) {
iten->SendEvent( EBrushDestroyed());
}
m_fHealth = -1;
ForceFullStop();
SetDefaultProperties();
// notify engine to kickstart entities that are cached in stationary position,
// before we turn off, so they can fall
NotifyCollisionChanged();
SetFlags( GetFlags()|ENF_HIDDEN);
SetCollisionFlags(ECF_IMMATERIAL);
// for each child of this entity
{FOREACHINLIST(CEntity, en_lnInParent, en_lhChildren, itenChild) {
// send it destruction event
itenChild->SendEvent(ERangeModelDestruction());
}}
stop;
}
on (EReturn) :
{
stop;
}
}
return;
}
};