Serious-Engine/Sources/EntitiesMP/Common/Common.cpp

1427 lines
48 KiB
C++
Raw Normal View History

2016-03-11 14:57:17 +01:00
/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#include "StdH.h"
#include <Engine/Base/Shell.h>
#include "EntitiesMP/Reminder.h"
#include "EntitiesMP/Flame.h"
#include "EntitiesMP/Debris.h"
#include "EntitiesMP/Player.h"
#include "EntitiesMP/Bullet.h"
#include "EntitiesMP/BackgroundViewer.h"
#include "EntitiesMP/SoundHolder.h"
#include "GameMP/PlayerSettings.h"
#include "ModelsMP/Player/SeriousSam/Player.h"
#include "ModelsMP/Player/SeriousSam/Body.h"
#include "ModelsMP/Player/SeriousSam/Head.h"
extern INDEX ent_bReportBrokenChains;
void CCompMessageID::Clear(void)
{
cmi_fnmFileName.Clear();
cmi_ulHash = 0;
}
void CCompMessageID::Read_t(CTStream &strm) // throw char *
{
strm>>cmi_fnmFileName;
strm>>(INDEX&)cmi_cmtType;
strm>>(INDEX&)cmi_bRead;
cmi_ulHash = cmi_fnmFileName.GetHash();
}
void CCompMessageID::Write_t(CTStream &strm) // throw char *
{
strm<<cmi_fnmFileName;
strm<<(INDEX&)cmi_cmtType;
strm<<(INDEX&)cmi_bRead;
}
void CCompMessageID::NewMessage(const CTFileName &fnm)
{
// remember filename
cmi_fnmFileName = fnm;
cmi_ulHash = cmi_fnmFileName.GetHash();
// decode type from filename
CTString strName = fnm;
if (strName.Matches("*messages\\information*")) {
cmi_cmtType = CMT_INFORMATION;
} else if (strName.Matches("*messages\\weapons*")) {
cmi_cmtType = CMT_WEAPONS;
} else if (strName.Matches("*messages\\enemies*")) {
cmi_cmtType = CMT_ENEMIES;
} else if (strName.Matches("*messages\\background*")) {
cmi_cmtType = CMT_BACKGROUND;
} else if (strName.Matches("*messages\\statistics*")) {
cmi_cmtType = CMT_STATISTICS;
} else {
CPrintF("Unknown message type: %s\n", (const CTString&) fnm);
cmi_cmtType = CMT_INFORMATION;
}
// mark as unread
cmi_bRead = FALSE;
}
/************************************************************
* COMMON FUNCTIONS FOR ENTITY CLASSES *
************************************************************/
// world change
struct WorldChange _SwcWorldChange;
// get info position for entity
void GetEntityInfoPosition(CEntity *pen, FLOAT *pf, FLOAT3D &vPos) {
ASSERT(pen!=NULL);
vPos = pen->GetPlacement().pl_PositionVector;
if (pf != NULL) {
FLOATmatrix3D mRotation;
MakeRotationMatrixFast(mRotation, pen->GetPlacement().pl_OrientationAngle);
vPos += FLOAT3D(pf[0], pf[1], pf[2])*mRotation;
}
};
// get source and target positions for ray cast
void GetPositionCastRay(CEntity *penSource, CEntity *penTarget, FLOAT3D &vSource, FLOAT3D &vTarget) {
EntityInfo *peiSource = (EntityInfo*) (penSource->GetEntityInfo());
EntityInfo *peiTarget = (EntityInfo*) (penTarget->GetEntityInfo());
ASSERT(peiSource!=NULL && peiTarget!=NULL);
// source
if (peiSource!=NULL) {
GetEntityInfoPosition(penSource, peiSource->vSourceCenter, vSource);
} else {
vSource = penSource->GetPlacement().pl_PositionVector;
}
// target
if (peiTarget!=NULL) {
GetEntityInfoPosition(penTarget, peiTarget->vTargetCenter, vTarget);
} else {
vTarget = penTarget->GetPlacement().pl_PositionVector;
}
};
// set bool from bool enum type
void SetBoolFromBoolEType(BOOL &bSet, BoolEType bet) {
switch (bet) {
case BET_TRUE:
bSet = TRUE;
break;
case BET_FALSE:
bSet = FALSE;
break;
//case BET_IGNORE:
//bSet = bSet;
// break
}
};
// send event to target
void SendToTarget(CEntity *penSendEvent, EventEType eetEventType, CEntity *penCaused) {
// if target is valid
if (penSendEvent != NULL) {
switch (eetEventType) {
// send START event
case EET_START: {
EStart eStart;
eStart.penCaused = penCaused;
penSendEvent->SendEvent(eStart);
} break;
// send STOP event
case EET_STOP:
penSendEvent->SendEvent(EStop());
break;
// send TRIGGER event
case EET_TRIGGER: {
ETrigger eTrigger;
eTrigger.penCaused = penCaused;
penSendEvent->SendEvent(eTrigger);
} break;
// don't send event (IGNORE)
case EET_IGNORE:
break;
// send ACTIVATE event
case EET_ACTIVATE:
penSendEvent->SendEvent(EActivate());
break;
// send DEACTIVATE event
case EET_DEACTIVATE:
penSendEvent->SendEvent(EDeactivate());
break;
// send ENVIRONMENTSTART event
case EET_ENVIRONMENTSTART:
penSendEvent->SendEvent(EEnvironmentStart());
break;
// send ENVIRONMENTSTOP event
case EET_ENVIRONMENTSTOP:
penSendEvent->SendEvent(EEnvironmentStop());
break;
// send STARTATTACK event
case EET_STARTATTACK:
penSendEvent->SendEvent(EStartAttack());
break;
// send STOPATTACK event
case EET_STOPATTACK:
penSendEvent->SendEvent(EStopAttack());
break;
case EET_STOPBLINDNESS:
penSendEvent->SendEvent(EStopBlindness());
break;
case EET_STOPDEAFNESS:
penSendEvent->SendEvent(EStopDeafness());
break;
case EET_TELEPORTMOVINGBRUSH:
penSendEvent->SendEvent(ETeleportMovingBrush());
break;
}
}
};
// send event in range
void SendInRange(CEntity *penSource, EventEType eetEventType, const FLOATaabbox3D &boxRange) {
switch (eetEventType) {
// send START event
case EET_START:
penSource->SendEventInRange(EStart(), boxRange);
break;
// send STOP event
case EET_STOP:
penSource->SendEventInRange(EStop(), boxRange);
break;
// send TRIGGER event
case EET_TRIGGER:
penSource->SendEventInRange(ETrigger(), boxRange);
break;
// don't send event (IGNORE)
case EET_IGNORE:
break;
// send ACTIVATE event
case EET_ACTIVATE:
penSource->SendEventInRange(EActivate(), boxRange);
break;
// send DEACTIVATE event
case EET_DEACTIVATE:
penSource->SendEventInRange(EDeactivate(), boxRange);
break;
// send ENVIRONMENTSTART event
case EET_ENVIRONMENTSTART:
penSource->SendEventInRange(EEnvironmentStart(), boxRange);
break;
// send ENVIRONMENTSTOP event
case EET_ENVIRONMENTSTOP:
penSource->SendEventInRange(EEnvironmentStop(), boxRange);
break;
// send STARTATTACK event
case EET_STARTATTACK:
penSource->SendEventInRange(EStartAttack(), boxRange);
break;
// send STOPATTACK event
case EET_STOPATTACK:
penSource->SendEventInRange(EStopAttack(), boxRange);
break;
case EET_STOPBLINDNESS:
penSource->SendEventInRange(EStopBlindness(), boxRange);
break;
case EET_STOPDEAFNESS:
penSource->SendEventInRange(EStopDeafness(), boxRange);
break;
}
};
// spawn reminder
CEntityPointer SpawnReminder(CEntity *penOwner, FLOAT fWaitTime, INDEX iValue) {
CEntityPointer penReminder;
try {
penReminder = penOwner->GetWorld()->CreateEntity_t
(penOwner->GetPlacement(), CTFILENAME("Classes\\Reminder.ecl"));
} catch (char *strError) {
FatalError(TRANS("Cannot create reminder entity class: %s"), strError);
}
EReminderInit eri;
eri.penOwner = penOwner;
eri.fWaitTime = fWaitTime;
eri.iValue = iValue;
penReminder->Initialize(eri);
return penReminder;
};
EffectParticlesType GetParticleEffectTypeForSurface(INDEX iSurfaceType)
{
EffectParticlesType eptType = EPT_BULLET_STONE;
switch( iSurfaceType)
{
case SURFACE_SAND: {eptType=EPT_BULLET_SAND; break;}
case SURFACE_RED_SAND: {eptType=EPT_BULLET_RED_SAND; break;}
case SURFACE_WATER: {eptType=EPT_BULLET_WATER; break;}
case SURFACE_GRASS:
case SURFACE_GRASS_SLIDING:
case SURFACE_GRASS_NOIMPACT:
{eptType=EPT_BULLET_GRASS; break;}
case SURFACE_WOOD: {eptType=EPT_BULLET_WOOD; break;}
case SURFACE_SNOW: {eptType=EPT_BULLET_SNOW; break;}
}
return eptType;
}
BulletHitType GetBulletHitTypeForSurface(INDEX iSurfaceType)
{
BulletHitType bhtType = BHT_BRUSH_STONE;
switch( iSurfaceType)
{
case SURFACE_SAND: {bhtType=BHT_BRUSH_SAND; break;}
case SURFACE_RED_SAND: {bhtType=BHT_BRUSH_RED_SAND; break;}
case SURFACE_WATER: {bhtType=BHT_BRUSH_WATER; break;}
case SURFACE_GRASS:
case SURFACE_GRASS_SLIDING:
case SURFACE_GRASS_NOIMPACT:
{bhtType=BHT_BRUSH_GRASS; break;}
case SURFACE_WOOD: {bhtType=BHT_BRUSH_WOOD; break;}
case SURFACE_SNOW: {bhtType=BHT_BRUSH_SNOW; break;}
}
return bhtType;
}
// spawn effect from hit type
void SpawnHitTypeEffect(CEntity *pen, enum BulletHitType bhtType, BOOL bSound, FLOAT3D vHitNormal, FLOAT3D vHitPoint,
FLOAT3D vIncommingBulletDir, FLOAT3D vDistance)
{
switch (bhtType)
{
case BHT_BRUSH_STONE:
case BHT_BRUSH_SAND:
case BHT_BRUSH_RED_SAND:
case BHT_BRUSH_WATER:
case BHT_BRUSH_UNDER_WATER:
case BHT_BRUSH_GRASS:
case BHT_BRUSH_WOOD:
case BHT_BRUSH_SNOW:
{
// bullet stain
ESpawnEffect ese;
if( bSound)
{
if( bhtType == BHT_BRUSH_STONE) {ese.betType = BET_BULLETSTAINSTONE;};
if( bhtType == BHT_BRUSH_SAND) {ese.betType = BET_BULLETSTAINSAND;};
if( bhtType == BHT_BRUSH_RED_SAND) {ese.betType = BET_BULLETSTAINREDSAND;};
if( bhtType == BHT_BRUSH_WATER) {ese.betType = BET_BULLETSTAINWATER;};
if( bhtType == BHT_BRUSH_UNDER_WATER) {ese.betType = BET_BULLETSTAINUNDERWATER;};
if( bhtType == BHT_BRUSH_GRASS) {ese.betType = BET_BULLETSTAINGRASS;};
if( bhtType == BHT_BRUSH_WOOD) {ese.betType = BET_BULLETSTAINWOOD;};
if( bhtType == BHT_BRUSH_SNOW) {ese.betType = BET_BULLETSTAINSNOW;};
}
else
{
if( bhtType == BHT_BRUSH_STONE) {ese.betType = BET_BULLETSTAINSTONENOSOUND;};
if( bhtType == BHT_BRUSH_SAND) {ese.betType = BET_BULLETSTAINSANDNOSOUND;};
if( bhtType == BHT_BRUSH_RED_SAND) {ese.betType = BET_BULLETSTAINREDSANDNOSOUND;};
if( bhtType == BHT_BRUSH_WATER) {ese.betType = BET_BULLETSTAINWATERNOSOUND;};
if( bhtType == BHT_BRUSH_UNDER_WATER) {ese.betType = BET_BULLETSTAINUNDERWATERNOSOUND;};
if( bhtType == BHT_BRUSH_GRASS) {ese.betType = BET_BULLETSTAINGRASSNOSOUND;};
if( bhtType == BHT_BRUSH_WOOD) {ese.betType = BET_BULLETSTAINWOODNOSOUND;};
if( bhtType == BHT_BRUSH_SNOW) {ese.betType = BET_BULLETSTAINSNOWNOSOUND;};
}
ese.vNormal = vHitNormal;
ese.colMuliplier = C_WHITE|CT_OPAQUE;
// reflect direction arround normal
FLOAT fNx = vHitNormal(1);
FLOAT fNy = vHitNormal(2);
FLOAT fNz = vHitNormal(3);
FLOAT fNV = fNx*vIncommingBulletDir(1) + fNy*vIncommingBulletDir(2) + fNz*vIncommingBulletDir(3);
FLOAT fRVx = vIncommingBulletDir(1) - 2*fNx*fNV;
FLOAT fRVy = vIncommingBulletDir(2) - 2*fNy*fNV;
FLOAT fRVz = vIncommingBulletDir(3) - 2*fNz*fNV;
ese.vStretch = FLOAT3D( fRVx, fRVy, fRVz);
try
{
// spawn effect
CPlacement3D plHit = CPlacement3D(vHitPoint-vIncommingBulletDir*0.1f, pen->GetPlacement().pl_OrientationAngle);
CEntityPointer penHit = pen->GetWorld()->CreateEntity_t(plHit , CTFILENAME("Classes\\BasicEffect.ecl"));
penHit->Initialize(ese);
}
catch (char *strError)
{
FatalError(TRANS("Cannot create basic effect class: %s"), strError);
}
break;
}
case BHT_FLESH:
case BHT_ACID:
{
// spawn bullet entry wound
ESpawnEffect ese;
ese.colMuliplier = C_WHITE|CT_OPAQUE;
// if there is exit wound blood spill place
FLOAT fDistance = vDistance.Length();
if( fDistance>0.01f && !(pen->IRnd()%2) )
{
// spawn bullet exit wound blood patch
ese.betType = BET_BLOODSPILL;
if( bhtType == BHT_ACID)
{
ese.colMuliplier = BLOOD_SPILL_GREEN;
}
else
{
ese.colMuliplier = BLOOD_SPILL_RED;
}
ese.vNormal = vHitNormal;
if (fDistance<25.0f)
{
GetNormalComponent( vDistance/fDistance, vHitNormal, ese.vDirection);
FLOAT fLength = ese.vDirection.Length();
fLength = Clamp( fLength*3.0f, 1.0f, 3.0f);
fDistance = Clamp( (FLOAT)log10(fDistance), 0.5f, 2.0f);
ese.vStretch = FLOAT3D( fDistance, fLength*fDistance, 1.0f);
try
{
// spawn effect
CPlacement3D plHit = CPlacement3D(vHitPoint-vIncommingBulletDir*0.1f, pen->GetPlacement().pl_OrientationAngle);
CEntityPointer penHit = pen->GetWorld()->CreateEntity_t(plHit , CTFILENAME("Classes\\BasicEffect.ecl"));
penHit->Initialize(ese);
}
catch (char *strError)
{
FatalError(TRANS("Cannot create basic effect class: %s"), strError);
}
}
}
break;
}
}
}
// spawn flame
CEntityPointer SpawnFlame(CEntity *penOwner, CEntity *penAttach, const FLOAT3D &vSource)
{
// owner can't flame himself
if( penOwner==penAttach) return NULL;
FLOAT3D vPos = vSource;
// prepare flame event
EFlame ef;
ef.penOwner = penOwner;
ef.penAttach = penAttach;
CEntityPointer penFlame;
// if the target entity is model
if (penAttach->GetRenderType()==CEntity::RT_MODEL ||
penAttach->GetRenderType()==CEntity::RT_SKAMODEL) {
vPos = penAttach->GetPlacement().pl_PositionVector;
// if the entity already has a flame attached
penFlame = penAttach->GetChildOfClass("Flame");
if (penFlame!=NULL) {
// just send it the event
penFlame->SendEvent(ef);
return penFlame;
}
}
// create new flame
try {
CPlacement3D plFlame(vPos, ANGLE3D(0, 0, 0));
penFlame = penAttach->GetWorld()->CreateEntity_t(plFlame, CTFILENAME("Classes\\Flame.ecl"));
} catch (char *strError) {
FatalError(TRANS("Cannot create flame entity class: %s"), strError);
}
penFlame->Initialize(ef);
return penFlame;
};
// Kick entity
void KickEntity(CEntity *penTarget, FLOAT3D vSpeed) {
// if the entity is not allowed to execute now
if (!penTarget->IsAllowedForPrediction()) {
// do nothing
return;
}
EntityInfo *peiTarget = (EntityInfo*) (penTarget->GetEntityInfo());
if (penTarget->GetPhysicsFlags()&EPF_MOVABLE && peiTarget!=NULL) {
// calc new speed acording to target mass
vSpeed *= 100.0f/peiTarget->fMass;
((CMovableEntity&)*penTarget).en_vCurrentTranslationAbsolute = vSpeed;
((CMovableEntity&)*penTarget).AddToMovers();
}
};
/************************************************************
* SET MODEL AND ATTACHMENT *
************************************************************/
// Set components
void SetComponents(CEntity *pen, CModelObject &mo, ULONG ulIDModel, ULONG ulIDTexture,
ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) {
// model data
mo.SetData(pen->GetModelDataForComponent(ulIDModel));
// texture data
mo.mo_toTexture.SetData(pen->GetTextureDataForComponent(ulIDTexture));
// reflection texture data
if (ulIDReflectionTexture>0) {
mo.mo_toReflection.SetData(pen->GetTextureDataForComponent(ulIDReflectionTexture));
} else {
mo.mo_toReflection.SetData(NULL);
}
// specular texture data
if (ulIDSpecularTexture>0) {
mo.mo_toSpecular.SetData(pen->GetTextureDataForComponent(ulIDSpecularTexture));
} else {
mo.mo_toSpecular.SetData(NULL);
}
// bump texture data
if (ulIDBumpTexture>0) {
mo.mo_toBump.SetData(pen->GetTextureDataForComponent(ulIDBumpTexture));
} else {
mo.mo_toBump.SetData(NULL);
}
};
// Add attachment to model
void AddAttachmentToModel(CEntity *pen, CModelObject &mo, INDEX iAttachment, ULONG ulIDModel, ULONG ulIDTexture,
ULONG ulIDReflectionTexture, ULONG ulIDSpecularTexture, ULONG ulIDBumpTexture) {
SetComponents(pen, mo.AddAttachmentModel(iAttachment)->amo_moModelObject, ulIDModel,
ulIDTexture, ulIDReflectionTexture, ulIDSpecularTexture, ulIDBumpTexture);
};
// Remove attachment from model
void RemoveAttachmentFromModel(CModelObject &mo, INDEX iAttachment) {
mo.RemoveAttachmentModel(iAttachment);
};
/************************************************************
* FLARES *
************************************************************/
// lens flare variables
CLensFlareType _lftStandard;
CLensFlareType _lftStandardReflections;
CLensFlareType _lftYellowStarRedRing;
CLensFlareType _lftYellowStarRedRingFar;
CLensFlareType _lftWhiteGlowStarRedRing;
CLensFlareType _lftWhiteGlowStar;
CLensFlareType _lftWhiteGlowStarNG;
CLensFlareType _lftWhiteStarRedRingStreaks;
CLensFlareType _lftWhiteStarRedReflections;
CLensFlareType _lftBlueStarBlueReflections;
CLensFlareType _lftProjectileStarGlow;
CLensFlareType _lftProjectileWhiteBubbleGlow;
CLensFlareType _lftProjectileYellowBubbleGlow;
CLensFlareType _lftPVSpaceShipWindowFlare;
CLensFlareType _lftCatmanFireGlow;
CLensFlareType _lftWhiteGlowFar;
static BOOL _bLensFlaresLoaded = FALSE;
#define FLARE_CREATE(type,noof,tex,pos,rot,i,j,flags,amp,des,falloff)\
type.lft_aolfFlares.New(noof);\
type.lft_aolfFlares[0].olf_toTexture.SetData_t(CTFILENAME("Textures\\Effects\\Flares\\" tex));\
type.lft_aolfFlares[0].olf_fReflectionPosition = pos;\
type.lft_aolfFlares[0].olf_aRotationFactor = AngleDeg(rot);\
type.lft_aolfFlares[0].olf_fSizeIOverScreenSizeI = i;\
type.lft_aolfFlares[0].olf_fSizeJOverScreenSizeI = j;\
type.lft_aolfFlares[0].olf_ulFlags = flags;\
type.lft_aolfFlares[0].olf_fLightAmplification = amp;\
type.lft_aolfFlares[0].olf_fLightDesaturation = des;\
type.lft_aolfFlares[0].oft_fFallOffFactor = falloff;
#define FLARE_GLARE(type,compression,intensity,des,falloff)\
type.lft_fGlareCompression = compression;\
type.lft_fGlareIntensity = intensity;\
type.lft_fGlareDesaturation = des;\
type.lft_fGlareFallOffFactor = falloff;
#define REFLECTION(type,i,fnm,pos,size) \
type.lft_aolfFlares[i].olf_toTexture.SetData_t(CTFILENAME("Textures\\Effects\\Flares\\" fnm));\
type.lft_aolfFlares[i].olf_fReflectionPosition = pos;\
type.lft_aolfFlares[i].olf_aRotationFactor = AngleDeg(0.0f);\
type.lft_aolfFlares[i].olf_fSizeIOverScreenSizeI = size;\
type.lft_aolfFlares[i].olf_fSizeJOverScreenSizeI = size;\
type.lft_aolfFlares[i].olf_ulFlags = OLF_FADEINTENSITY|OLF_FADEOFCENTER;\
type.lft_aolfFlares[i].olf_fLightAmplification = 7.0f;\
type.lft_aolfFlares[i].olf_fLightDesaturation = 0.5f;\
type.lft_aolfFlares[i].oft_fFallOffFactor = 5.0f;
// init lens flare effects
void InitLensFlares(void) {
if (_bLensFlaresLoaded) {
return; // Player class is not auto-freed, so the engine may attempt to access this function several times
}
// standard flare
FLARE_CREATE(_lftStandard, 1, "01\\WhiteRedRing2.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftStandard, 20.0f, 0.3f, 0.8f, 1.0f);
// standard flare with huge reflections
FLARE_CREATE(_lftStandardReflections, 15, "01\\WhiteRedRing2.tex", 0.0f, 180.0f, 1.36f, 1.36f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftStandardReflections, 20.0f, 0.3f, 0.8f, 1.0f);
REFLECTION(_lftStandardReflections, 1, "01\\WhiteRing.tex", -0.3f, 0.1f);
REFLECTION(_lftStandardReflections, 2, "01\\BlueDisc.tex", 1-0.5f, 0.047f);
REFLECTION(_lftStandardReflections, 3, "01\\BlueDisc.tex", 1-0.41f, 0.078f);
REFLECTION(_lftStandardReflections, 4, "01\\BlueDiscWeak.tex", 1-0.45f, 0.15f);
REFLECTION(_lftStandardReflections, 5, "01\\BrownDisc.tex", 1-0.2f, 0.05f);
REFLECTION(_lftStandardReflections, 6, "01\\WhiteGradient.tex", 1-0.1f, 0.016f);
REFLECTION(_lftStandardReflections, 7, "01\\WhiteGradient.tex", 1+0.29f, 0.027f);
REFLECTION(_lftStandardReflections, 8, "01\\BrownDisc.tex", 1+0.5f, 0.05f);
REFLECTION(_lftStandardReflections, 9, "01\\BrownDisc.tex", 1+0.43f, 0.11f);
REFLECTION(_lftStandardReflections,10, "01\\BrownRing.tex", 1+0.49f, 0.19f);
REFLECTION(_lftStandardReflections,11, "01\\BlueDisc.tex", 1+0.68f, 0.08f);
REFLECTION(_lftStandardReflections,12, "01\\BlueGradient.tex", 1+0.7f, 0.043f);
REFLECTION(_lftStandardReflections,13, "01\\GreenRing.tex", 1+1.04f, 0.27f);
REFLECTION(_lftStandardReflections,14, "01\\RainbowRing.tex", 1+1.35f, 0.53f);
// nice yellow star with red ring
FLARE_CREATE(_lftYellowStarRedRing, 1, "02\\Flare05.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftYellowStarRedRing, 20.0f, 0.3f, 0.8f, 1.0f);
// same yellow star with red ring but visible from far away
FLARE_CREATE(_lftYellowStarRedRingFar, 1, "02\\Flare05.tex", 0.0f, 180.0f, 1/12.0f, 1/12.0f, OLF_FADESIZE, 0.25f, 0.5f, 128.0f);
FLARE_GLARE(_lftYellowStarRedRingFar, 20.0f, 0.3f, 0.8f, 1.0f);
// nice yellow star with red ring
FLARE_CREATE(_lftWhiteGlowStarRedRing, 1, "03\\Flare06.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftWhiteGlowStarRedRing, 20.0f, 0.3f, 0.8f, 1.0f);
FLARE_CREATE(_lftWhiteGlowStar, 1, "04\\Flare07.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftWhiteGlowStar, 20.0f, 0.3f, 0.8f, 1.0f);
FLARE_CREATE(_lftWhiteGlowStarNG, 1, "04\\Flare07.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_CREATE(_lftWhiteStarRedRingStreaks, 1, "05\\Flare09.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftWhiteStarRedRingStreaks, 20.0f, 0.3f, 0.8f, 1.0f);
// white star flare with many red and brown hexagons
FLARE_CREATE(_lftWhiteStarRedReflections, 12, "06\\WhiteStarManyStreaks.tex", 0.0f, 0.0f, 0.20625f, 0.20625f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftWhiteStarRedReflections, 20.0f, 0.3f, 0.8f, 1.0f);
REFLECTION(_lftWhiteStarRedReflections, 1, "06\\DarkRedPentagram.tex" ,-0.92424242f,0.06875f);
REFLECTION(_lftWhiteStarRedReflections, 2, "06\\LillaPentagram.tex" ,0.28787879f,0.0296875f);
REFLECTION(_lftWhiteStarRedReflections, 3, "06\\MagentaPentagram.tex" ,0.43939394f,0.05f);
REFLECTION(_lftWhiteStarRedReflections, 4, "06\\MagentaGlow.tex" ,1.52272727f,0.009375f);
REFLECTION(_lftWhiteStarRedReflections, 5, "06\\DarkRedPentagram.tex" ,1.9469697f,0.06875f);
REFLECTION(_lftWhiteStarRedReflections, 6, "06\\MagentaGlow.tex" ,1.96212121f,0.05f);
REFLECTION(_lftWhiteStarRedReflections, 7, "06\\DarkRedPentagram.tex" ,1.08333333f,0.06875f);
REFLECTION(_lftWhiteStarRedReflections, 8, "06\\DarkRedPentagram.tex" ,1.59848485f,0.06875f);
REFLECTION(_lftWhiteStarRedReflections, 9, "06\\DarkRedPentagram.tex" ,1.67424242f,0.06875f);
REFLECTION(_lftWhiteStarRedReflections,10, "06\\DarkRedPentagram.tex" ,-0.12878788f,0.03125f);
REFLECTION(_lftWhiteStarRedReflections,11, "06\\BrownPentagram.tex" ,0.03030303f,0.021875f);
// blue star flare with many blue flares
FLARE_CREATE(_lftBlueStarBlueReflections, 21, "07\\BlueStarManyStreaks.tex", 0.0f, 0.0f, 0.4f, 0.4f, OLF_FADESIZE, 7.0f, 0.5f, 5.0f);
FLARE_GLARE(_lftBlueStarBlueReflections, 20.0f, 0.3f, 0.8f, 1.0f);
REFLECTION(_lftBlueStarBlueReflections, 1, "07\\BlueGlow.tex", -0.5f,0.05f);
REFLECTION(_lftBlueStarBlueReflections, 2, "07\\BluePentagram.tex", -0.25f,0.03f);
REFLECTION(_lftBlueStarBlueReflections, 3, "07\\GreenGlow.tex", -0.05f,0.04f);
REFLECTION(_lftBlueStarBlueReflections, 4, "07\\GreenGlow.tex", 0.3f,0.02f);
REFLECTION(_lftBlueStarBlueReflections, 5, "07\\BluePentagram.tex", 0.5f,0.05f);
REFLECTION(_lftBlueStarBlueReflections, 6, "07\\DarkBluePentagram.tex", 0.8f,0.04f);
REFLECTION(_lftBlueStarBlueReflections, 7, "07\\LittleBluePentagram.tex", 1.2f,0.02f);
REFLECTION(_lftBlueStarBlueReflections, 8, "07\\MagentaPentagram.tex", 1.13f,0.08f);
REFLECTION(_lftBlueStarBlueReflections, 9, "07\\DarkBluePentagram.tex", 1.24f,0.03f);
REFLECTION(_lftBlueStarBlueReflections,10, "07\\BlueGlow.tex", 1.4f,0.06f);
REFLECTION(_lftBlueStarBlueReflections,11, "07\\GreenGlow.tex", 1.5f,0.02f);
REFLECTION(_lftBlueStarBlueReflections,12, "07\\BluePentagram.tex", 1.64f,0.05f);
REFLECTION(_lftBlueStarBlueReflections,13, "07\\LittleBluePentagram.tex", 1.7f,0.05f);
REFLECTION(_lftBlueStarBlueReflections,14, "07\\BluePentagram.tex", 1.8f,0.06f);
REFLECTION(_lftBlueStarBlueReflections,15, "07\\MagentaPentagram.tex", 2.0f,0.01f);
REFLECTION(_lftBlueStarBlueReflections,16, "07\\BlueGlow.tex", 2.0f,0.06f);
REFLECTION(_lftBlueStarBlueReflections,17, "07\\MagentaPentagram.tex", 2.0f,0.02f);
REFLECTION(_lftBlueStarBlueReflections,18, "07\\GreenGlow.tex", 2.1f,0.015f);
REFLECTION(_lftBlueStarBlueReflections,19, "07\\BluePentagram.tex", 2.4f,0.05f);
REFLECTION(_lftBlueStarBlueReflections,20, "07\\DarkBluePentagram.tex", 2.8f,0.03f);
FLARE_CREATE(_lftProjectileStarGlow, 1, "08\\FlarePower.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f);
FLARE_GLARE(_lftProjectileStarGlow, 20.0f, 0.3f, 0.8f, 1.0f);
FLARE_CREATE(_lftProjectileWhiteBubbleGlow, 1, "09\\FlareWhiteBubble.tex", 0.0f, 180.0f, 1/5.0f, 1/5.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f);
FLARE_GLARE(_lftProjectileWhiteBubbleGlow, 20.0f, 0.3f, 0.8f, 1.0f);
FLARE_CREATE(_lftProjectileYellowBubbleGlow, 1, "10\\FlareYellowBubble.tex", 0.0f, 180.0f, 1/10.0f, 1/10.0f, OLF_FADESIZE, 7.0f, 0.5f, 10.0f);
FLARE_GLARE(_lftProjectileYellowBubbleGlow, 20.0f, 0.3f, 0.8f, 1.0f);
FLARE_CREATE(_lftPVSpaceShipWindowFlare, 1, "05\\Flare09.tex", 0.0f, 180.0f, 1/10.0f, 1/10.0f, OLF_FADESIZE, 1.0f, 0.0f, 10.0f);
FLARE_CREATE(_lftCatmanFireGlow, 1, "12\\Flare12.tex", 0.0f, 180.0f, 1/12.0f, 1/12.0f, OLF_FADESIZE, 7.0f, 0.5f, 128.0f);
FLARE_CREATE(_lftWhiteGlowFar, 1, "13\\Flare13.tex", 0.0f, 180.0f, 1/16.0f, 1/16.0f, OLF_FADESIZE, 7.0f, 0.5f, 128.0f);
_bLensFlaresLoaded = TRUE;
};
// close lens flares effects
void CloseLensFlares(void) {
_lftStandard.lft_aolfFlares.Clear();
_lftStandardReflections.lft_aolfFlares.Clear();
_lftYellowStarRedRing.lft_aolfFlares.Clear();
_lftYellowStarRedRingFar.lft_aolfFlares.Clear();
_lftWhiteGlowStarRedRing.lft_aolfFlares.Clear();
_lftWhiteGlowStar.lft_aolfFlares.Clear();
_lftWhiteGlowStarNG.lft_aolfFlares.Clear();
_lftWhiteStarRedRingStreaks.lft_aolfFlares.Clear();
_lftWhiteStarRedReflections.lft_aolfFlares.Clear();
_lftBlueStarBlueReflections.lft_aolfFlares.Clear();
_lftProjectileStarGlow.lft_aolfFlares.Clear();
_lftProjectileWhiteBubbleGlow.lft_aolfFlares.Clear();
_lftProjectileYellowBubbleGlow.lft_aolfFlares.Clear();
_lftPVSpaceShipWindowFlare.lft_aolfFlares.Clear();
_lftCatmanFireGlow.lft_aolfFlares.Clear();
_lftWhiteGlowFar.lft_aolfFlares.Clear();
_bLensFlaresLoaded = FALSE;
};
static BOOL _bFatalChecks = FALSE;
/************************************************************
* PLAYER APPEARANCE *
************************************************************/
/* Set the model data */
void SetModelData_t(CModelObject *pmo, const CTFileName &fnmModel) {
ASSERT(pmo != NULL);
pmo->SetData_t(fnmModel); // load the new model data
};
/* Set the texture data */
void SetTextureData_t(CModelObject *pmo, const CTFileName &fnmTexture) {
ASSERT(pmo != NULL);
pmo->mo_toTexture.SetData_t(fnmTexture); // load the texture data
};
/* Set model */
void SetModel_t(CModelObject *pmo, const CTFileName &fnmModel, const CTFileName &fnmTexture) {
SetModelData_t(pmo, fnmModel);
SetTextureData_t(pmo, fnmTexture);
};
/* Add attachment to model */
void ModelAddAttachment_t(CModelObject *pmo, INDEX iAttachment,
const CTFileName &fnmModel, const CTFileName &fnmTexture) {
ASSERT(pmo != NULL);
if (fnmModel==CTString("")) return;
if (pmo==NULL) return;
CAttachmentModelObject *pamo = pmo->AddAttachmentModel(iAttachment);
SetModel_t(&(pamo->amo_moModelObject), fnmModel, fnmTexture);
};
CTString _strFile;
INDEX _ctLines;
CTString GetNonEmptyLine_t(CTStream &strm)
{
FOREVER {
if(strm.AtEOF()) {
ThrowF_t(TRANS("Unexpected end of file"));
}
CTString str;
_ctLines++;
strm.GetLine_t(str);
str.TrimSpacesLeft();
if (str.RemovePrefix("//")) { // skip comments
continue;
}
if (str!="") {
str.TrimSpacesRight();
return str;
}
}
}
void FixupFileName_t(CTString &strFnm)
{
strFnm.TrimSpacesLeft();
if (!strFnm.RemovePrefix(CTString("TF") +"NM ")) { // must not directly have ids in code
ThrowF_t(TRANS("Expected %s%s before filename"), "TF", "NM");
}
}
// skip one block in pmc
void SkipBlock_t(CTStream &strm)
{
CTString strLine;
// expect to begin with an open bracket
strLine = GetNonEmptyLine_t(strm);
if (strLine!="{") {
ThrowF_t(TRANS("Expected '{'"));
}
// start at level one
INDEX ctLevel = 1;
// repeat
do {
strLine = GetNonEmptyLine_t(strm);
// count brackets
if (strLine=="{") {
ctLevel++;
} else if (strLine=="}") {
ctLevel--;
}
// until we close down all brackets
} while(ctLevel>0);
}
void ParseAMC_t(CModelObject *pmo, CTStream &strm, BOOL bPreview)
{
CTString strLine;
// expect to begin with an open bracket
strLine = GetNonEmptyLine_t(strm);
if (strLine!="{") {
ThrowF_t(TRANS("Expected '{'"));
}
// repeat
FOREVER {
// read one line
strLine = GetNonEmptyLine_t(strm);
// if closed bracket
if (strLine == "}") {
// finish parsing
return;
}
// if a preview-only block
if (strLine.RemovePrefix("PreviewOnly")) {
// if this is a preview
if (bPreview) {
// keep parsing it
ParseAMC_t(pmo, strm, bPreview);
// if this is not a preview
} else {
// skip that block
SkipBlock_t(strm);
}
// if include block
} else if (strLine.RemovePrefix("Include:")) {
// open the new file
FixupFileName_t(strLine);
CTFileStream strmIncluded;
strmIncluded.Open_t(strLine);
// include it
INDEX ctLinesOld = _ctLines;
CTString strFileOld = _strFile;
_ctLines = 0;
_strFile = strLine;
ParseAMC_t(pmo, strmIncluded, bPreview);
strmIncluded.Close();
_ctLines = ctLinesOld;
_strFile = strFileOld;
// if setting the model
} else if (strLine.RemovePrefix("Model:")) {
// set the model
FixupFileName_t(strLine);
pmo->SetData_t(strLine);
// if setting an anim for the model
} else if (strLine.RemovePrefix("Animation:")) {
// get animation number
INDEX iAnim = -1;
strLine.ScanF("%d", &iAnim);
if (iAnim<0) {
ThrowF_t(TRANS("Invalid animation number"));
}
// check it
if (iAnim>=pmo->GetAnimsCt()) {
ThrowF_t(TRANS("Animation %d does not exist in that model"), iAnim);
};
// set it
pmo->PlayAnim(iAnim, AOF_LOOPING);
// if texture
} else if (strLine.RemovePrefix("Texture:")) {
// set texture
FixupFileName_t(strLine);
pmo->mo_toTexture.SetData_t(strLine);
// if specular
} else if (strLine.RemovePrefix("Specular:")) {
// set texture
FixupFileName_t(strLine);
pmo->mo_toSpecular.SetData_t(strLine);
// if reflection
} else if (strLine.RemovePrefix("Reflection:")) {
// set texture
FixupFileName_t(strLine);
pmo->mo_toReflection.SetData_t(strLine);
// if specular
} else if (strLine.RemovePrefix("Bump:")) {
// set texture
FixupFileName_t(strLine);
pmo->mo_toBump.SetData_t(strLine);
// if attachment
} else if (strLine.RemovePrefix("Attachment:")) {
// get attachment number
INDEX iAtt = -1;
strLine.ScanF("%d", &iAtt);
if (iAtt<0) {
ThrowF_t(TRANS("Invalid attachment number"));
}
// create attachment
CModelData *pmd = (CModelData*)pmo->GetData();
if (iAtt>=pmd->md_aampAttachedPosition.Count()) {
ThrowF_t(TRANS("Attachment %d does not exist in that model"), iAtt);
};
CAttachmentModelObject *pamo = pmo->AddAttachmentModel(iAtt);
// recursively parse it
ParseAMC_t(&pamo->amo_moModelObject, strm, bPreview);
} else {
ThrowF_t(TRANS("Expected texture or attachment"));
}
}
}
/* Set player appearance */
BOOL SetPlayerAppearance_internal(CModelObject *pmo, const CTFileName &fnmAMC, CTString &strName, BOOL bPreview)
{
// try to
try {
// open the config file
CTFileStream strm;
strm.Open_t(fnmAMC);
_ctLines = 0;
_strFile = fnmAMC;
// read the name
CTString strLine = GetNonEmptyLine_t(strm);
if (!strLine.RemovePrefix("Name: ")) {
ThrowF_t(TRANS("Expected name"));
}
strName = strLine;
strName.TrimSpacesLeft();
// parse the file recursively starting at root model object and add everything
ParseAMC_t(pmo, strm, bPreview);
return TRUE;
// if anything failed
} catch (char *strError) {
// report error
CPrintF(TRANS("Cannot load player model:\n%s (%d) : %s\n"),
(const char*)_strFile, _ctLines, strError);
return FALSE;
}
}
BOOL SetPlayerAppearance(CModelObject *pmo, CPlayerCharacter *ppc, CTString &strName, BOOL bPreview)
{
// first kill any existing model
pmo->SetData(NULL);
pmo->mo_toTexture.SetData(NULL);
pmo->mo_toSpecular.SetData(NULL);
pmo->mo_toReflection.SetData(NULL);
pmo->mo_toBump.SetData(NULL);
pmo->RemoveAllAttachmentModels();
DECLARE_CTFILENAME(fnmDefault, "ModelsMP\\Player\\SeriousSam.amc");
// if no character, or player models are disabled
if (ppc==NULL) {
// set default appearance
BOOL bSucceeded = SetPlayerAppearance_internal(pmo, fnmDefault, strName, bPreview);
if (!bSucceeded) {
FatalError(TRANS("Cannot load default player model!"));
}
return FALSE;
}
// get filename from the settings
CPlayerSettings *pps = (CPlayerSettings *)ppc->pc_aubAppearance;
CTFileName fnmModelFile = pps->GetModelFilename();
// if dummy (empty settings)
if (fnmModelFile.FileName()=="") {
// use default
fnmModelFile = fnmDefault;
}
extern INDEX plr_bOnlySam;
if (!plr_bOnlySam && SetPlayerAppearance_internal(pmo, fnmModelFile, strName, bPreview)) {
return TRUE;
} else if (SetPlayerAppearance_internal(pmo, fnmDefault, strName, bPreview)) { // HAVE TO SET DEFAULT HERE!
return TRUE;
} else {
return FALSE;
}
}
/************************************************************
* DEBUGGING FUNCTIONS *
************************************************************/
// debugging functions
const char *PrintConsole(void)
{
_RPT1(_CRT_WARN, "%s", CON_GetBuffer());
return NULL;
}
const char *PrintStack(CEntity *pen)
{
return pen->PrintStackDebug();
}
/************************************************************
* DEBRIS *
************************************************************/
EntityInfoBodyType _Eeibt;
enum DebrisParticlesType _dptParticles;
enum BasicEffectType _betStain;
FLOAT3D _vSpeed;
FLOAT3D _vSpawnerSpeed;
FLOAT _fEntitySize;
FLOAT _fConeSize;
FLOAT _fSpeedUp;
COLOR _colDebris;
// debris spawning
void Debris_Begin(
EntityInfoBodyType Eeibt,
enum DebrisParticlesType dptParticles,
enum BasicEffectType betStain,
FLOAT fEntitySize, // entity size in meters
const FLOAT3D &vSpeed,
const FLOAT3D &vSpawnerSpeed, // how fast was the entity moving
const FLOAT fConeSize, // size multiplier for debris cone
const FLOAT fSpeedUp, // size multiplier for debris catapulting up (0-no multiply)
const COLOR colDebris /*=C_WHITE*/ // multiply color
)
{
_Eeibt = Eeibt ;
_dptParticles = dptParticles;
_betStain = betStain ;
_vSpeed = vSpeed ;
_vSpawnerSpeed = vSpawnerSpeed;
_fEntitySize = fEntitySize ;
_fConeSize = fConeSize ;
_fSpeedUp = fSpeedUp ;
_colDebris = colDebris ;
}
CEntityPointer Debris_Spawn(
CEntity *penSpawner,
CEntity *penComponents,
SLONG idModelComponent,
SLONG idTextureComponent,
SLONG idReflectionTextureComponent,
SLONG idSpecularTextureComponent,
SLONG idBumpTextureComponent,
INDEX iModelAnim,
FLOAT fSize,
const FLOAT3D &vPosRatio)
{
// create debris at same world as spawner
FLOAT3D vPos;
FLOAT3D vStretch=FLOAT3D(1,1,1);
if( (penSpawner->en_RenderType==CEntity::RT_MODEL ||
penSpawner->en_RenderType==CEntity::RT_EDITORMODEL) &&
penSpawner->GetModelObject()!=NULL)
{
vStretch=penSpawner->GetModelObject()->mo_Stretch;
}
penSpawner->GetEntityPointRatio(vPosRatio, vPos);
CEntityPointer penDebris = penSpawner->GetWorld()->CreateEntity_t(
CPlacement3D(vPos, ANGLE3D(0,0,0)), CTFILENAME("Classes\\Debris.ecl"));
// prepare parameters
ESpawnDebris eSpawn;
eSpawn.bImmaterialASAP=FALSE;
eSpawn.bCustomShading=FALSE;
eSpawn.Eeibt = _Eeibt;
eSpawn.dptParticles = _dptParticles;
eSpawn.betStain = _betStain;
eSpawn.pmd = penComponents->GetModelDataForComponent(idModelComponent);
eSpawn.ptd = penComponents->GetTextureDataForComponent(idTextureComponent);
eSpawn.ptdRefl = penComponents->GetTextureDataForComponent(idReflectionTextureComponent);
eSpawn.ptdSpec = penComponents->GetTextureDataForComponent(idSpecularTextureComponent);
eSpawn.ptdBump = penComponents->GetTextureDataForComponent(idBumpTextureComponent);
eSpawn.iModelAnim = iModelAnim;
eSpawn.colDebris = _colDebris;
eSpawn.vStretch = FLOAT3D(1,1,1);
if (fSize==0) {
eSpawn.fSize = 1.0f;
} else {
eSpawn.fSize = _fEntitySize*fSize;
}
// initialize it
penDebris->Initialize(eSpawn);
FLOAT fCone = _fEntitySize*1.0f;
if (_vSpeed.Length()==0) {
fCone = 0;
}
FLOAT fRndX = (penSpawner->FRnd()*2-1)*fCone*_fConeSize;
FLOAT fRndY = (penSpawner->FRnd()*2-1)*fCone*_fConeSize;
FLOAT fRndZ = (penSpawner->FRnd()*2-1)*fCone*_fConeSize;
FLOAT fRndH = penSpawner->FRnd();
FLOAT fRndP = penSpawner->FRnd();
FLOAT fRndB = penSpawner->FRnd();
FLOAT3D vUp;
const FLOATmatrix3D &m = penSpawner->GetRotationMatrix();
vUp(1) = m(1,2);
vUp(2) = m(2,2);
vUp(3) = m(3,2);
//FLOAT fStrength = _vSpeed.Length();
// speed it up
((CMovableEntity&)*penDebris).LaunchAsFreeProjectile(
_vSpawnerSpeed+_vSpeed+FLOAT3D(fRndX, fRndY, fRndZ)+vUp*_fSpeedUp, (CMovableEntity*)penSpawner);
((CMovableEntity&)*penDebris).SetDesiredRotation(
ANGLE3D(fRndH*360.0f-180.0f, fRndP*360.0f-180.0f, fRndB*360.0f-180.0f));
return penDebris;
}
CEntityPointer Debris_Spawn_Independent(
CEntity *penSpawner,
CEntity *penComponents,
SLONG idModelComponent,
SLONG idTextureComponent,
SLONG idReflectionTextureComponent,
SLONG idSpecularTextureComponent,
SLONG idBumpTextureComponent,
INDEX iModelAnim,
FLOAT fSize,
CPlacement3D plAbsolutePlacement,
FLOAT3D vTranslation,
ANGLE3D aRotation)
{
// create debris at same world as spawner
CEntityPointer penDebris = penSpawner->GetWorld()->CreateEntity_t(
plAbsolutePlacement, CTFILENAME("Classes\\Debris.ecl"));
// prepare parameters
ESpawnDebris eSpawn;
eSpawn.bImmaterialASAP=FALSE;
eSpawn.bCustomShading=FALSE;
eSpawn.Eeibt = _Eeibt;
eSpawn.dptParticles = _dptParticles;
eSpawn.betStain = _betStain;
eSpawn.pmd = penComponents->GetModelDataForComponent(idModelComponent);
eSpawn.ptd = penComponents->GetTextureDataForComponent(idTextureComponent);
eSpawn.ptdRefl = penComponents->GetTextureDataForComponent(idReflectionTextureComponent);
eSpawn.ptdSpec = penComponents->GetTextureDataForComponent(idSpecularTextureComponent);
eSpawn.ptdBump = penComponents->GetTextureDataForComponent(idBumpTextureComponent);
eSpawn.iModelAnim = iModelAnim;
eSpawn.colDebris = _colDebris;
eSpawn.fSize = fSize;
eSpawn.vStretch = FLOAT3D(1,1,1);
// initialize it
penDebris->Initialize(eSpawn);
// move it
((CMovableEntity&)*penDebris).LaunchAsFreeProjectile(
vTranslation, (CMovableEntity*)penSpawner);
((CMovableEntity&)*penDebris).SetDesiredRotation(aRotation);
return penDebris;
}
CEntityPointer Debris_Spawn_Template(
EntityInfoBodyType eibt,
enum DebrisParticlesType dptParticles,
enum BasicEffectType betStain,
CModelHolder2 *penmhDestroyed,
CEntity *penComponents,
CModelHolder2 *penmhTemplate,
FLOAT3D vStretch,
FLOAT fSize,
CPlacement3D plAbsolutePlacement,
FLOAT3D vLaunchSpeed,
ANGLE3D aRotSpeed,
BOOL bDebrisImmaterialASAP,
FLOAT fDustStretch,
COLOR colBurning)
{
if(penmhTemplate==NULL || penmhTemplate->GetModelObject()==NULL)
{
return NULL;
}
// create debris at same world as spawner
CEntityPointer penDebris = penmhDestroyed->GetWorld()->CreateEntity_t(
plAbsolutePlacement, CTFILENAME("Classes\\Debris.ecl"));
// prepare parameters
ESpawnDebris eSpawn;
eSpawn.bImmaterialASAP=bDebrisImmaterialASAP;
eSpawn.fDustStretch=fDustStretch;
eSpawn.Eeibt = eibt;
eSpawn.dptParticles = dptParticles;
eSpawn.betStain = betStain;
CModelObject &mo=*penmhTemplate->GetModelObject();
eSpawn.pmd = mo.GetData();
eSpawn.ptd = (CTextureData*)mo.mo_toTexture.GetData();
eSpawn.ptdRefl = (CTextureData*)mo.mo_toReflection.GetData();
eSpawn.ptdSpec = (CTextureData*)mo.mo_toSpecular.GetData();
eSpawn.ptdBump = (CTextureData*)mo.mo_toBump.GetData();
eSpawn.iModelAnim = mo.GetAnim();
eSpawn.colDebris = colBurning;
eSpawn.fSize = 1.0f;
eSpawn.vStretch = vStretch;
eSpawn.bCustomShading=FALSE;
eSpawn.penFallFXPapa=penmhTemplate;
if( penmhDestroyed->m_cstCustomShading==CST_FULL_CUSTOMIZED)
{
eSpawn.bCustomShading=TRUE;
eSpawn.aShadingDirection=penmhDestroyed->m_aShadingDirection;
eSpawn.colCustomDiffuse=penmhDestroyed->m_colLight;
eSpawn.colCustomAmbient=penmhDestroyed->m_colAmbient;
}
// initialize it
penDebris->Initialize(eSpawn);
// move it
const FLOATmatrix3D &m = penDebris->GetRotationMatrix();
((CMovableEntity&)*penDebris).LaunchAsFreeProjectile( vLaunchSpeed*!m, (CMovableEntity*)penmhDestroyed);
((CMovableEntity&)*penDebris).SetDesiredRotation(aRotSpeed);
return penDebris;
}
// info structure
static EntityInfo eiFlesh = {EIBT_FLESH};
static EntityInfo eiWater = {EIBT_WATER};
static EntityInfo eiRock = {EIBT_ROCK };
static EntityInfo eiFire = {EIBT_FIRE };
static EntityInfo eiAir = {EIBT_AIR };
static EntityInfo eiBones = {EIBT_BONES};
static EntityInfo eiWood = {EIBT_WOOD };
static EntityInfo eiMetal = {EIBT_METAL};
static EntityInfo eiRobot = {EIBT_ROBOT};
static EntityInfo eiIce = {EIBT_ICE };
// get default entity info for given body type
EntityInfo *GetStdEntityInfo(EntityInfoBodyType eibt)
{
switch(eibt) {
case EIBT_FLESH: {return &eiFlesh; } break;
case EIBT_WATER: {return &eiWater; } break;
case EIBT_ROCK : {return &eiRock ; } break;
case EIBT_FIRE : {return &eiFire ; } break;
case EIBT_AIR : {return &eiAir ; } break;
case EIBT_BONES: {return &eiBones; } break;
case EIBT_WOOD : {return &eiWood ; } break;
case EIBT_METAL: {return &eiMetal; } break;
case EIBT_ROBOT: {return &eiRobot; } break;
case EIBT_ICE : {return &eiIce ; } break;
default: {return NULL;} break;
};
}
/************************************************************
* DAMAGE CONTROL FUNCTIONS *
************************************************************/
// damage control functions
FLOAT DamageStrength(EntityInfoBodyType eibtBody, enum DamageType dtDamage)
{
switch(eibtBody) {
case EIBT_FLESH:
return 1.0f;
case EIBT_WATER:
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.0f;
case DMT_BURNING: return 0.0f;
case DMT_DROWNING: return 0.0f;
}
return 1.0f;
case EIBT_ROCK :
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.0f;
case DMT_BURNING: return 0.0f;
case DMT_FREEZING: return 0.0f;
}
return 1.0f;
case EIBT_ICE :
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.5f;
case DMT_BURNING: return 3.0f;
case DMT_FREEZING: return 0.0f;
}
return 1.0f;
case EIBT_FIRE :
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.5f;
case DMT_BURNING: return 0.0f;
}
return 1.0f;
case EIBT_AIR :
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.0f;
case DMT_BURNING: return 0.5f;
}
return 1.0f;
case EIBT_BONES:
switch(dtDamage) {
case DMT_FREEZING: return 0.0f;
}
return 1.0f;
case EIBT_WOOD :
switch(dtDamage) {
case DMT_FREEZING: return 0.0f;
}
return 1.0f;
case EIBT_METAL:
switch(dtDamage) {
case DMT_CLOSERANGE: return 0.0f;
case DMT_BURNING: return 0.0f;
case DMT_FREEZING: return 0.0f;
}
return 1.0f;
case EIBT_ROBOT:
switch(dtDamage) {
case DMT_CLOSERANGE:return 0.5f;
case DMT_BURNING: return 0.5f;
case DMT_FREEZING: return 0.5f;
}
return 1.0f;
default:
ASSERT(FALSE);
return 1.0f;
}
}
// Print center screen message
void PrintCenterMessage(CEntity *penThis, CEntity *penCaused,
const CTString &strMessage, TIME tmLength, enum MessageSound mssSound)
{
penCaused = FixupCausedToPlayer(penThis, penCaused);
ECenterMessage eMsg;
eMsg.strMessage = strMessage;
eMsg.tmLength = tmLength;
eMsg.mssSound = mssSound;
penCaused->SendEvent(eMsg);
}
// i.e. weapon sound when fireing or exploding
void SpawnRangeSound( CEntity *penPlayer, CEntity *penPos, enum SoundType st, FLOAT fRange)
{
// if not really player
if (!IsDerivedFromClass(penPlayer, "Player")) {
// do nothing
return;
}
// sound event
ESound eSound;
eSound.EsndtSound = st;
eSound.penTarget = penPlayer;
penPos->SendEventInRange( eSound, FLOATaabbox3D(penPos->GetPlacement().pl_PositionVector, fRange));
}
// get some player for trigger source if any is existing
CEntity *FixupCausedToPlayer(CEntity *penThis, CEntity *penCaused, BOOL bWarning/*=TRUE*/)
{
if (penCaused!=NULL && IsOfClass(penCaused, "Player")) {
return penCaused;
}
if (bWarning && (ent_bReportBrokenChains || GetSP()->sp_bQuickTest)) {
CPrintF(TRANS("WARNING: Triggering chain broken, entity: %s-%s(%s)\n"),
(const char*)penThis->GetName(),
(const char*)penThis->GetDescription(),
(const char*)penThis->GetClass()->GetName());
}
INDEX ctPlayers = penThis->GetMaxPlayers();
if (ctPlayers==0) {
return NULL;
}
CEntity *penClosestPlayer = NULL;
FLOAT fClosestPlayer = UpperLimit(0.0f);
// for all players
for (INDEX iPlayer=0; iPlayer<penThis->GetMaxPlayers(); iPlayer++) {
CEntity *penPlayer = penThis->GetPlayerEntity(iPlayer);
// if player exists
if (penPlayer!=NULL) {
// calculate distance to player
FLOAT fDistance =
(penPlayer->GetPlacement().pl_PositionVector-penThis->GetPlacement().pl_PositionVector).Length();
// update if closer
if (fDistance<fClosestPlayer) {
fClosestPlayer = fDistance;
penClosestPlayer = penPlayer;
}
}
}
return penClosestPlayer;
}
// precisely lerp between two placement using quaternions
CPlacement3D LerpPlacementsPrecise(const CPlacement3D &pl0, const CPlacement3D &pl1, FLOAT fRatio)
{
CPlacement3D pl;
FLOATquat3D q0; q0.FromEuler(pl0.pl_OrientationAngle);
FLOATquat3D q1; q1.FromEuler(pl1.pl_OrientationAngle);
FLOAT3D v0 = pl0.pl_PositionVector;
FLOAT3D v1 = pl1.pl_PositionVector;
FLOATquat3D q = Slerp<FLOAT>(fRatio, q0, q1);
FLOAT3D v = Lerp(v0, v1, fRatio);
pl.pl_PositionVector = v;
FLOATmatrix3D m;
q.ToMatrix(m);
DecomposeRotationMatrixNoSnap(pl.pl_OrientationAngle, m);
return pl;
}
FLOAT GetGameDamageMultiplier(void)
{
FLOAT fGameDamageMultiplier = 1.0f;
FLOAT fExtraStrength = GetSP()->sp_fExtraEnemyStrength;
if (fExtraStrength>0) {
fGameDamageMultiplier*=1.0f/(1+fExtraStrength);
}
FLOAT fExtraStrengthPerPlayer = GetSP()->sp_fExtraEnemyStrengthPerPlayer;
if (fExtraStrengthPerPlayer>0) {
INDEX ctPlayers = _pNetwork->ga_sesSessionState.GetPlayersCount();
fGameDamageMultiplier*=1.0f/(1+fExtraStrengthPerPlayer*ClampDn(ctPlayers-1.0f, 0.0f));
}
if (GetSP()->sp_gdGameDifficulty==CSessionProperties::GD_TOURIST) {
fGameDamageMultiplier *= 2.0f;
}
return fGameDamageMultiplier;
}
// get entity's serious damage multiplier
FLOAT GetSeriousDamageMultiplier( CEntity *pen)
{
if( !IsOfClass(pen,"Player")) return 1.0f;
const TIME tmNow = _pTimer->CurrentTick();
const TIME tmDamage = ((CPlayer*)pen)->m_tmSeriousDamage;
if( tmDamage>tmNow) return 4.0f;
return 1.0f;
}
class CWorldSettingsController *GetWSC(CEntity *pen)
{
CWorldSettingsController *pwsc = NULL;
// obtain bcg viewer
class CBackgroundViewer *penBcgViewer = (CBackgroundViewer *) pen->GetWorld()->GetBackgroundViewer();
if( penBcgViewer != NULL) {
// obtain world settings controller
pwsc = (CWorldSettingsController *) &*penBcgViewer->m_penWorldSettingsController;
}
return pwsc;
}