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

374 lines
11 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. */
345
%{
#include "StdH.h"
%}
uses "EntitiesMP/ModelHolder2";
uses "EntitiesMP/Projectile";
uses "EntitiesMP/SoundHolder";
uses "EntitiesMP/BloodSpray";
uses "EntitiesMP/CannonBall";
enum FireType {
0 SFT_WOODEN_DART "Wooden dart",
1 SFT_FIRE "Fire",
2 SFT_GAS "-none-",
3 SFT_IRONBALL "Ironball",
4 SFT_FIREBALL "Fireball",
};
class CShooter: CModelHolder2 {
name "Shooter";
thumbnail "Thumbnails\\Shooter.tbn";
features "HasName", "IsTargetable";
properties:
2 FLOAT m_fShootingPeriod "Shooting Period" = 1.0f,
5 enum FireType m_sftType "Type" 'Y' = SFT_WOODEN_DART,
7 FLOAT m_fHealth "Health" = 0.0f,
8 FLOAT m_fCannonBallSize "Cannon/fire ball size" = 1.0f,
9 FLOAT m_fCannonBallPower "Cannon/fire ball power" = 10.0f,
10 ANIMATION m_iModelPreFireAnimation "Model pre-fire animation" = 0,
11 ANIMATION m_iTexturePreFireAnimation "Texture pre-fire animation" = 0,
12 ANIMATION m_iModelPostFireAnimation "Model post-fire animation" = 0,
13 ANIMATION m_iTexturePostFireAnimation "Texture post-fire animation" = 0,
14 FLOAT m_fFlameBurstDuration "Flame burst duration" = 1.0f,
15 FLOAT m_fRndBeginWait "Random begin wait time" = 0.0f,
20 CEntityPointer m_penSoundLaunch "Sound launch", // sound when firing
21 CSoundObject m_soLaunch,
30 CEntityPointer m_penFlame,
//internal:
50 BOOL m_bFiring = FALSE,
51 BOOL m_bIndestructable = FALSE,
60 FLOAT m_tmFlameStart = 0.0f,
components:
1 class CLASS_PROJECTILE "Classes\\Projectile.ecl",
2 class CLASS_BLOOD_SPRAY "Classes\\BloodSpray.ecl",
3 class CLASS_CANNONBALL "Classes\\CannonBall.ecl",
functions:
void Precache(void) {
CModelHolder2::Precache();
PrecacheClass(CLASS_PROJECTILE, PRT_SHOOTER_WOODEN_DART);
PrecacheClass(CLASS_PROJECTILE, PRT_SHOOTER_FIREBALL);
PrecacheClass(CLASS_CANNONBALL);
};
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
{
// receive damage if not indestructable, and shooter can't hurt another shooter
if (!m_bIndestructable && !IsOfClass(penInflictor, "Shooter")) {
if (m_tmSpraySpawned<=_pTimer->CurrentTick()-_pTimer->TickQuantum*8
&& m_penDestruction!=NULL) {
CModelDestruction *penDestruction = GetDestruction();
// spawn blood spray
CPlacement3D plSpray = CPlacement3D( vHitPoint, ANGLE3D(0, 0, 0));
m_penSpray = CreateEntity( plSpray, CLASS_BLOOD_SPRAY);
m_penSpray->SetParent(this);
ESpawnSpray eSpawnSpray;
eSpawnSpray.colBurnColor=C_WHITE|CT_OPAQUE;
// adjust spray power
if( fDamageAmmount > 50.0f) {
eSpawnSpray.fDamagePower = 3.0f;
} else if(fDamageAmmount > 25.0f ) {
eSpawnSpray.fDamagePower = 2.0f;
} else {
eSpawnSpray.fDamagePower = 1.0f;
}
// remember spray type
eSpawnSpray.sptType = penDestruction->m_sptType;
eSpawnSpray.fSizeMultiplier = 1.0f;
// get your down vector (simulates gravity)
FLOAT3D vDn(-en_mRotation(1,2), -en_mRotation(2,2), -en_mRotation(3,2));
// setup direction of spray
FLOAT3D vHitPointRelative = vHitPoint - GetPlacement().pl_PositionVector;
FLOAT3D vReflectingNormal;
GetNormalComponent( vHitPointRelative, vDn, vReflectingNormal);
vReflectingNormal.Normalize();
vReflectingNormal(1)/=5.0f;
FLOAT3D vProjectedComponent = vReflectingNormal*(vDirection%vReflectingNormal);
FLOAT3D vSpilDirection = vDirection-vProjectedComponent*2.0f-vDn*0.5f;
eSpawnSpray.vDirection = vSpilDirection;
eSpawnSpray.penOwner = this;
// initialize spray
m_penSpray->Initialize( eSpawnSpray);
m_tmSpraySpawned = _pTimer->CurrentTick();
}
CRationalEntity::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
}
}
// render particles
void RenderParticles(void)
{
// fire particles
if (m_sftType==SFT_FIRE) {
}
CModelHolder2::RenderParticles();
}
/* Get anim data for given animation property - return NULL for none. */
CAnimData *GetAnimData(SLONG slPropertyOffset)
{
if (slPropertyOffset==offsetof(CShooter, m_iModelPreFireAnimation) ||
slPropertyOffset==offsetof(CShooter, m_iModelPostFireAnimation)) {
return GetModelObject()->GetData();
} else if (slPropertyOffset==offsetof(CShooter, m_iTexturePreFireAnimation) ||
slPropertyOffset==offsetof(CShooter, m_iTexturePostFireAnimation)) {
return GetModelObject()->mo_toTexture.GetData();
} else {
return CModelHolder2::GetAnimData(slPropertyOffset);
}
}
// shoot projectile on enemy
CEntity *ShootProjectile(enum ProjectileType pt, FLOAT3D &vOffset, ANGLE3D &aOffset) {
// launch
CPlacement3D pl;
pl = GetPlacement();
CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE);
ELaunchProjectile eLaunch;
eLaunch.penLauncher = this;
eLaunch.prtType = pt;
penProjectile->Initialize(eLaunch);
return penProjectile;
};
// fire flame
void FireFlame(void) {
// flame start position
CPlacement3D plFlame;
plFlame = GetPlacement();
FLOAT3D vNormDir;
AnglesToDirectionVector(plFlame.pl_OrientationAngle, vNormDir);
plFlame.pl_PositionVector += vNormDir*0.1f;
// create flame
CEntityPointer penFlame = CreateEntity(plFlame, CLASS_PROJECTILE);
// init and launch flame
ELaunchProjectile eLaunch;
eLaunch.penLauncher = this;
eLaunch.prtType = PRT_SHOOTER_FLAME;
penFlame->Initialize(eLaunch);
// link last flame with this one (if not NULL or deleted)
if (m_penFlame!=NULL && !(m_penFlame->GetFlags()&ENF_DELETED)) {
((CProjectile&)*m_penFlame).m_penParticles = penFlame;
}
// link to this
((CProjectile&)*penFlame).m_penParticles = this;
// store last flame
m_penFlame = penFlame;
};
void StopFlame(void) {
((CProjectile&)*m_penFlame).m_penParticles = NULL;
//m_penFlame = NULL;
}
void PlayFireSound(void) {
// if sound entity exists
if (m_penSoundLaunch!=NULL) {
CSoundHolder &sh = (CSoundHolder&)*m_penSoundLaunch;
m_soLaunch.Set3DParameters(FLOAT(sh.m_rFallOffRange), FLOAT(sh.m_rHotSpotRange), sh.m_fVolume, 1.0f);
PlaySound(m_soLaunch, sh.m_fnSound, sh.m_iPlayType);
}
};
void ShootCannonball()
{
// cannon ball start position
CPlacement3D plBall = GetPlacement();
// create cannon ball
CEntityPointer penBall = CreateEntity(plBall, CLASS_CANNONBALL);
// init and launch cannon ball
ELaunchCannonBall eLaunch;
eLaunch.penLauncher = this;
eLaunch.fLaunchPower = 10.0f+m_fCannonBallPower; // ranges from 50-150 (since iPower can be max 100)
eLaunch.cbtType = CBT_IRON;
eLaunch.fSize = m_fCannonBallSize;
penBall->Initialize(eLaunch);
};
void ShootFireball()
{
// cannon ball start position
CPlacement3D plBall = GetPlacement();
// create cannon ball
CEntityPointer penBall = CreateEntity(plBall, CLASS_CANNONBALL);
// init and launch cannon ball
ELaunchCannonBall eLaunch;
eLaunch.penLauncher = this;
eLaunch.fLaunchPower = 10.0f+m_fCannonBallPower; // ranges from 50-150 (since iPower can be max 100)
eLaunch.cbtType = CBT_IRON;
eLaunch.fSize = m_fCannonBallSize;
penBall->Initialize(eLaunch);
};
procedures:
FireOnce()
{
if (m_sftType==SFT_FIRE) { jump FlameBurst(); }
PlayFireSound();
GetModelObject()->PlayAnim(m_iModelPreFireAnimation, 0);
GetModelObject()->mo_toTexture.PlayAnim(m_iTexturePreFireAnimation, 0);
autowait(GetModelObject()->GetAnimLength(m_iModelPreFireAnimation));
switch (m_sftType) {
case SFT_WOODEN_DART:
ShootProjectile(PRT_SHOOTER_WOODEN_DART, FLOAT3D (0.0f, 0.0f, 0.0f), ANGLE3D (0.0f, 0.0f, 0.0f));
break;
case SFT_GAS:
break;
case SFT_IRONBALL:
ShootCannonball();
break;
case SFT_FIREBALL:
ShootProjectile(PRT_SHOOTER_FIREBALL, FLOAT3D (0.0f, 0.0f, 0.0f), ANGLE3D (0.0f, 0.0f, 0.0f));
break;
}
GetModelObject()->PlayAnim(m_iModelPostFireAnimation, 0);
GetModelObject()->mo_toTexture.PlayAnim(m_iTexturePostFireAnimation, 0);
autowait(GetModelObject()->GetAnimLength(m_iModelPostFireAnimation));
return EEnd();
}
FireContinuous() {
// possible random wait
if (m_fRndBeginWait>0.0f)
{
FLOAT fRndWait = FRnd()*m_fRndBeginWait+0.05;
autowait(fRndWait);
}
while(m_bFiring) {
autocall FireOnce() EEnd;
autowait(m_fShootingPeriod);
}
return EReturn();
};
FlameBurst() {
PlayFireSound();
m_penFlame = NULL;
m_tmFlameStart = _pTimer->CurrentTick();
while(_pTimer->CurrentTick( ) < m_tmFlameStart + m_fFlameBurstDuration)
{
// wait a bit and fire
autowait(0.05f);
FireFlame();
}
StopFlame();
return EEnd();
};
MainLoop() {
//main loop
wait() {
on (EBegin) : {
resume;
}
on (ETrigger) : {
if (!m_bFiring) {
call FireOnce();
} else {
resume;
}
}
on (EActivate) : {
m_bFiring = TRUE;
call FireContinuous();
}
on (EDeactivate) : {
m_bFiring = FALSE;
resume;
}
on (EDeath) : {
if (m_penDestruction!=NULL) {
jump CModelHolder2::Die();
} else {
Destroy();
return;
}
}
on (EReturn) : {
resume;
}
}
};
Main() {
// init as model
CModelHolder2::InitModelHolder();
if (m_fHealth>0.0f) {
SetHealth(m_fHealth);
m_bIndestructable = FALSE;
} else {
SetHealth(10000.0f);
m_bIndestructable = TRUE;
}
ClampUp(m_fCannonBallSize, 10.0f);
ClampDn(m_fCannonBallSize, 0.1f);
ClampUp(m_fCannonBallPower, 100.0f);
ClampDn(m_fCannonBallPower, 0.0f);
if (m_penSoundLaunch!=NULL && !IsOfClass(m_penSoundLaunch, "SoundHolder")) {
WarningMessage( "Entity '%s' is not of class SoundHolder!", m_penSoundLaunch);
m_penSoundLaunch=NULL;
}
if (m_penDestruction!=NULL && !IsOfClass(m_penDestruction, "ModelDestruction")) {
WarningMessage( "Entity '%s' is not of class ModelDestruction!", m_penDestruction);
m_penDestruction=NULL;
}
autowait(_pTimer->TickQuantum);
jump MainLoop();
return;
};
};