mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-26 07:34:52 +01:00
416 lines
13 KiB
C++
416 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. */
|
|
|
|
342
|
|
%{
|
|
#include "StdH.h"
|
|
#include "ModelsMP/Enemies/ChainSawFreak/Freak.h"
|
|
#include "ModelsMP/Enemies/ChainSawFreak/Saw.h"
|
|
%}
|
|
|
|
uses "EntitiesMP/EnemyBase";
|
|
uses "EntitiesMP/EnemyRunInto";
|
|
|
|
%{
|
|
#define FREAK_SIZE 1.05f
|
|
|
|
// info structure
|
|
static EntityInfo eiChainsawFreak = {
|
|
EIBT_FLESH, 350.0f,
|
|
0.0f, 2.5f*FREAK_SIZE, 0.0f, // source (eyes)
|
|
0.0f, 1.5f*FREAK_SIZE, 0.0f, // target (body)
|
|
};
|
|
|
|
#define HIT_DISTANCE 4.0f
|
|
%}
|
|
|
|
|
|
class CChainsawFreak : CEnemyRunInto {
|
|
name "ChainsawFreak";
|
|
thumbnail "Thumbnails\\ChainsawFreak.tbn";
|
|
|
|
properties:
|
|
1 BOOL m_bRunAttack = FALSE, // run attack (attack local)
|
|
2 BOOL m_bSawHit = FALSE, // close attack local
|
|
3 CEntityPointer m_penLastTouched, // last touched
|
|
4 CSoundObject m_soFeet, // for running sound
|
|
5 BOOL m_bRunSoundPlaying = FALSE,
|
|
6 INDEX m_iRunType = 0, // which running animation?
|
|
|
|
10 BOOL m_bAttacking = FALSE,
|
|
11 FLOAT m_fSightSoundBegin = 0.0f, // when sight sound was played
|
|
|
|
components:
|
|
0 class CLASS_BASE "Classes\\EnemyRunInto.ecl",
|
|
1 model MODEL_FREAK "ModelsMP\\Enemies\\ChainsawFreak\\Freak.mdl",
|
|
2 model MODEL_CHAINSAW "ModelsMP\\Enemies\\ChainsawFreak\\Saw.mdl",
|
|
3 texture TEXTURE_FREAK "ModelsMP\\Enemies\\ChainsawFreak\\Freak.tex",
|
|
4 texture TEXTURE_CHAINSAW "ModelsMP\\Enemies\\ChainsawFreak\\Saw.tex",
|
|
|
|
// ************** SOUNDS **************
|
|
50 sound SOUND_IDLE "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Idle.wav",
|
|
51 sound SOUND_RUN "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Run.wav",
|
|
// 53 sound SOUND_RUNATTACK "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\RunAttack.wav",
|
|
54 sound SOUND_ATTACK "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Attack.wav",
|
|
55 sound SOUND_WOUND "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Wound.wav",
|
|
56 sound SOUND_DEATH "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Death.wav",
|
|
57 sound SOUND_SIGHT "ModelsMP\\Enemies\\ChainsawFreak\\Sounds\\Sight.wav",
|
|
|
|
functions:
|
|
|
|
// describe how this enemy killed player
|
|
virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath)
|
|
{
|
|
CTString str;
|
|
str.PrintF(TRANS("Chainsaw freak dismembered %s"), strPlayerName);
|
|
return str;
|
|
}
|
|
|
|
void Precache(void) {
|
|
CEnemyBase::Precache();
|
|
PrecacheSound(SOUND_IDLE );
|
|
PrecacheSound(SOUND_RUN );
|
|
// PrecacheSound(SOUND_RUNATTACK);
|
|
PrecacheSound(SOUND_ATTACK );
|
|
PrecacheSound(SOUND_WOUND );
|
|
PrecacheSound(SOUND_DEATH );
|
|
PrecacheSound(SOUND_SIGHT );
|
|
};
|
|
|
|
/* Entity info */
|
|
void *GetEntityInfo(void) {
|
|
return &eiChainsawFreak;
|
|
};
|
|
|
|
FLOAT GetCrushHealth(void)
|
|
{
|
|
return 60.0f;
|
|
}
|
|
|
|
virtual const CTFileName &GetComputerMessageName(void) const {
|
|
static DECLARE_CTFILENAME(fnm, "DataMP\\Messages\\Enemies\\ChainsawFreak.txt");
|
|
return fnm;
|
|
};
|
|
|
|
// render particles
|
|
/*void RenderParticles(void)
|
|
{
|
|
Particles_RunningDust(this);
|
|
}*/
|
|
|
|
/* Receive damage */
|
|
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
|
|
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
|
|
{
|
|
// note: chainsawfreaks can't hurt each others
|
|
if (!IsOfClass(penInflictor, "ChainsawFreak")) {
|
|
CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
|
|
}
|
|
};
|
|
|
|
void AdjustDifficulty(void)
|
|
{
|
|
// chainsaw freak must not change his speed at different difficulties
|
|
}
|
|
|
|
// death
|
|
INDEX AnimForDeath(void) {
|
|
INDEX iAnim;
|
|
if (en_vCurrentTranslationAbsolute.Length()>5.0f) {
|
|
iAnim = FREAK_ANIM_DEATHRUN;
|
|
} else {
|
|
iAnim = FREAK_ANIM_DEATHSTAND;
|
|
}
|
|
ChangeCollisionBoxIndexWhenPossible(FREAK_COLLISION_BOX_DEATHRUN);
|
|
StartModelAnim(iAnim, 0);
|
|
m_bAttacking = FALSE;
|
|
DeactivateRunningSound();
|
|
return iAnim;
|
|
};
|
|
|
|
FLOAT WaitForDust(FLOAT3D &vStretch) {
|
|
if(GetModelObject()->GetAnim()==FREAK_ANIM_DEATHRUN)
|
|
{
|
|
vStretch=FLOAT3D(1,1,2)*1.0f;
|
|
return 0.65f;
|
|
}
|
|
else if(GetModelObject()->GetAnim()==FREAK_ANIM_DEATHSTAND)
|
|
{
|
|
vStretch=FLOAT3D(1,1,2)*1.5f;
|
|
return 0.72f;
|
|
}
|
|
return -1.0f;
|
|
};
|
|
|
|
void DeathNotify() {
|
|
ChangeCollisionBoxIndexWhenPossible(FREAK_COLLISION_BOX_DEATH);
|
|
SetCollisionFlags(ECF_MODEL);
|
|
};
|
|
|
|
// virtual anim functions
|
|
void StandingAnim(void) {
|
|
StartModelAnim(FREAK_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART);
|
|
//DeactivateRunningSound();
|
|
};
|
|
void WalkingAnim(void) {
|
|
StartModelAnim(FREAK_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
|
|
//DeactivateRunningSound();
|
|
};
|
|
void RunningAnim(void) {
|
|
switch(m_iRunType)
|
|
{
|
|
case 0:
|
|
StartModelAnim(FREAK_ANIM_ATTACKRUN, AOF_LOOPING|AOF_NORESTART);
|
|
break;
|
|
case 1:
|
|
StartModelAnim(FREAK_ANIM_ATTACKRUNFAR, AOF_LOOPING|AOF_NORESTART);
|
|
break;
|
|
case 2:
|
|
StartModelAnim(FREAK_ANIM_ATTACKCHARGE, AOF_LOOPING|AOF_NORESTART);
|
|
break;
|
|
default:
|
|
ASSERTALWAYS("Unknown Chainsaw freak run type!");
|
|
}
|
|
//ActivateRunningSound();
|
|
};
|
|
void ChargeAnim(void) {
|
|
StartModelAnim(FREAK_ANIM_RUNSLASHING, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
void RotatingAnim(void) {
|
|
m_iRunType = IRnd()%3;
|
|
StartModelAnim(FREAK_ANIM_ATTACKSTART, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
|
|
// virtual sound functions
|
|
void IdleSound(void) {
|
|
PlaySound(m_soSound, SOUND_IDLE, SOF_3D);
|
|
};
|
|
/*void SightSound(void) {
|
|
PlaySound(m_soFeet, SOUND_SIGHT, SOF_3D|SOF_SMOOTHCHANGE);
|
|
};*/
|
|
void WoundSound(void) {
|
|
PlaySound(m_soSound, SOUND_WOUND, SOF_3D);
|
|
};
|
|
void DeathSound(void) {
|
|
PlaySound(m_soSound, SOUND_DEATH, SOF_3D);
|
|
};
|
|
|
|
// running sounds
|
|
void ActivateRunningSound(void)
|
|
{
|
|
if (!m_bRunSoundPlaying) {
|
|
PlaySound(m_soFeet, SOUND_RUN, SOF_3D|SOF_LOOP);
|
|
m_bRunSoundPlaying = TRUE;
|
|
}
|
|
}
|
|
void DeactivateRunningSound(void)
|
|
{
|
|
m_soFeet.Stop();
|
|
m_bRunSoundPlaying = FALSE;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
* ATTACK FUNCTIONS *
|
|
************************************************************/
|
|
// touched another live entity
|
|
void LiveEntityTouched(ETouch etouch) {
|
|
if (m_penLastTouched!=etouch.penOther || _pTimer->CurrentTick()>=m_fLastTouchedTime+0.25f) {
|
|
// hit angle
|
|
FLOAT3D vDirection = en_vCurrentTranslationAbsolute;
|
|
vDirection.Normalize();
|
|
ANGLE aHitAngle = FLOAT3D(etouch.plCollision)%vDirection;
|
|
// only hit target in front of you
|
|
if (aHitAngle < 0.0f) {
|
|
// increase mass - only if not another bull
|
|
if (!IsOfSameClass(this, etouch.penOther)) {
|
|
IncreaseKickedMass(etouch.penOther);
|
|
}
|
|
PlaySound(m_soSound, SOUND_ATTACK, SOF_3D);
|
|
// store last touched
|
|
m_penLastTouched = etouch.penOther;
|
|
m_fLastTouchedTime = _pTimer->CurrentTick();
|
|
// damage
|
|
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
|
|
vDirection.Normalize();
|
|
InflictDirectDamage(etouch.penOther, this, DMT_CHAINSAW, -aHitAngle*40.0f,
|
|
FLOAT3D(0, 0, 0), vDirection);
|
|
// kick touched entity
|
|
FLOAT3D vSpeed = -FLOAT3D(etouch.plCollision);
|
|
vSpeed = vSpeed*10.0f;
|
|
const FLOATmatrix3D &m = GetRotationMatrix();
|
|
FLOAT3D vSpeedRel = vSpeed*!m;
|
|
if (vSpeedRel(1)<-0.1f) {
|
|
vSpeedRel(1)-=5.0f;
|
|
} else {
|
|
vSpeedRel(1)+=5.0f;
|
|
}
|
|
vSpeedRel(2)=5.0f;
|
|
|
|
vSpeed = vSpeedRel*m;
|
|
KickEntity(etouch.penOther, vSpeed);
|
|
}
|
|
}
|
|
};
|
|
|
|
// touched entity with higher mass
|
|
BOOL HigherMass(void) {
|
|
return (m_fMassKicked > 500.0f);
|
|
};
|
|
|
|
// adjust sound and watcher parameters here if needed
|
|
void EnemyPostInit(void)
|
|
{
|
|
// set sound default parameters
|
|
m_soFeet.Set3DParameters(500.0f, 50.0f, 1.0f, 1.0f);
|
|
m_bRunSoundPlaying = FALSE;
|
|
m_soSound.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f);
|
|
};
|
|
|
|
void PreMoving() {
|
|
if (!m_bRunSoundPlaying && _pTimer->CurrentTick()>m_fSightSoundBegin+2.0f && m_bAttacking)
|
|
{
|
|
ActivateRunningSound();
|
|
}
|
|
CEnemyBase::PreMoving();
|
|
};
|
|
|
|
procedures:
|
|
/************************************************************
|
|
* A T T A C K E N E M Y *
|
|
************************************************************/
|
|
// hit enemy
|
|
Hit(EVoid) : CEnemyBase::Hit {
|
|
if (CalcDist(m_penEnemy) < HIT_DISTANCE) {
|
|
// attack with saw
|
|
StartModelAnim(FREAK_ANIM_ATTACKSLASH, 0);
|
|
// jump
|
|
FLOAT3D vDir = (m_penEnemy->GetPlacement().pl_PositionVector -
|
|
GetPlacement().pl_PositionVector).Normalize();
|
|
vDir *= !GetRotationMatrix();
|
|
vDir *= m_fCloseRunSpeed*1.5f;
|
|
vDir(2) = 1.0f;
|
|
|
|
GiveImpulseTranslationRelative(vDir);
|
|
|
|
//DeactivateRunningSound();
|
|
m_bSawHit = FALSE;
|
|
autowait(0.4f);
|
|
PlaySound(m_soSound, SOUND_ATTACK, SOF_3D);
|
|
if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bSawHit = TRUE; }
|
|
autowait(0.1f);
|
|
if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bSawHit = TRUE; }
|
|
autowait(0.1f);
|
|
if (CalcDist(m_penEnemy) < HIT_DISTANCE) { m_bSawHit = TRUE; }
|
|
if (m_bSawHit) {
|
|
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
|
|
vDirection.Normalize();
|
|
InflictDirectDamage(m_penEnemy, this, DMT_CHAINSAW, 20.0f, FLOAT3D(0, 0, 0), vDirection);
|
|
|
|
vDirection = vDirection * 10.0f;
|
|
//GetPitchDirection(AngleDeg(90.0f), vSpeed);
|
|
FLOATmatrix3D mDirection;
|
|
MakeRotationMatrixFast(mDirection, ANGLE3D(0.0f, 30.0f, 0.0f));
|
|
vDirection = vDirection * mDirection;
|
|
KickEntity(m_penEnemy, vDirection);
|
|
}
|
|
autowait(0.6f);
|
|
}
|
|
|
|
// run to enemy
|
|
m_fShootTime = _pTimer->CurrentTick() + 0.5f;
|
|
return EReturn();
|
|
};
|
|
|
|
AttackEnemy(EVoid) : CEnemyBase::AttackEnemy {
|
|
m_bAttacking = TRUE;
|
|
PlaySound(m_soSound, SOUND_SIGHT, SOF_3D|SOF_SMOOTHCHANGE);
|
|
m_fSightSoundBegin = _pTimer->CurrentTick();
|
|
jump CEnemyBase::AttackEnemy();
|
|
}
|
|
|
|
BeIdle(EVoid) : CEnemyBase::BeIdle {
|
|
m_bAttacking = FALSE;
|
|
DeactivateRunningSound();
|
|
jump CEnemyBase::BeIdle();
|
|
}
|
|
|
|
|
|
PostRunAwayFromEnemy(EVoid) : CEnemyRunInto::PostRunAwayFromEnemy {
|
|
StartModelAnim(FREAK_ANIM_ATTACKRUNFAR, 0);
|
|
autowait(0.25f);
|
|
SetDesiredTranslation(FLOAT3D(0,0,0));
|
|
StartModelAnim(FREAK_ANIM_IDLE, 0);
|
|
autowait(0.25f);
|
|
return EReturn();
|
|
};
|
|
|
|
/************************************************************
|
|
* M A I N *
|
|
************************************************************/
|
|
Main(EVoid) {
|
|
// declare yourself as a model
|
|
InitAsModel();
|
|
SetPhysicsFlags(EPF_MODEL_WALKING);
|
|
SetCollisionFlags(ECF_MODEL);
|
|
SetFlags(GetFlags()|ENF_ALIVE);
|
|
SetHealth(175.0f);
|
|
m_fMaxHealth = 175.0f;
|
|
en_fDensity = 2000.0f;
|
|
// set your appearance
|
|
SetModel(MODEL_FREAK);
|
|
SetModelMainTexture(TEXTURE_FREAK);
|
|
AddAttachment(FREAK_ATTACHMENT_CHAINSAW, MODEL_CHAINSAW, TEXTURE_CHAINSAW);
|
|
StandingAnim();
|
|
// setup moving speed
|
|
m_fWalkSpeed = FRnd() + 2.5f;
|
|
m_aWalkRotateSpeed = AngleDeg(FRnd()*25.0f + 45.0f);
|
|
m_fAttackRunSpeed = FRnd()*2.0f + 13.0f;
|
|
m_fAttackRotateRunInto = AngleDeg(FRnd()*30 + 50.0f);
|
|
m_aAttackRotateSpeed = m_fAttackRotateRunInto;
|
|
m_fCloseRunSpeed = FRnd() + 10.5f;
|
|
m_aCloseRotateSpeed = AngleDeg(FRnd()*50 + 250.0f);
|
|
// setup attack distances
|
|
m_fAttackDistance = 50.0f;
|
|
m_fCloseDistance = 7.0f;
|
|
m_fStopDistance = 0.0f;
|
|
m_fAttackFireTime = 0.05f;
|
|
m_fCloseFireTime = 1.0f;
|
|
m_fIgnoreRange = 150.0f;
|
|
// damage/explode properties6
|
|
m_fBlowUpAmount = 1E10f;
|
|
m_fBodyParts = 6;
|
|
m_fDamageWounded = 100000.0f;
|
|
m_iScore = 1500;
|
|
if (m_fStepHeight==-1) {
|
|
m_fStepHeight = 4.0f;
|
|
}
|
|
m_fStopApproachDistance = 0.0f;
|
|
ASSERT(m_fStopApproachDistance<m_fCloseDistance);
|
|
m_bUseChargeAnimation = TRUE;
|
|
m_fChargeDistance = 20.0f;
|
|
m_fInertionRunTime = 0.15f;
|
|
m_iRunType = IRnd()%3;
|
|
|
|
GetModelObject()->StretchModel(FLOAT3D(FREAK_SIZE, FREAK_SIZE, FREAK_SIZE));
|
|
ModelChangeNotify();
|
|
|
|
m_bAttacking = FALSE;
|
|
|
|
// continue behavior in base class
|
|
jump CEnemyRunInto::MainLoop();
|
|
};
|
|
};
|