mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-29 21:25:54 +01:00
374 lines
11 KiB
C++
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;
|
|
};
|
|
};
|