mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-25 23:24:51 +01:00
473 lines
14 KiB
C++
473 lines
14 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. */
|
|
|
|
320
|
|
%{
|
|
#include "StdH.h"
|
|
#include "ModelsMP/Enemies/Woman/Woman.h"
|
|
#include "Models/Enemies/Headman/Headman.h"
|
|
#include "EntitiesMP/Headman.h"
|
|
%}
|
|
|
|
uses "EntitiesMP/EnemyFly";
|
|
|
|
%{
|
|
// info structure
|
|
static EntityInfo eiWomanStand = {
|
|
EIBT_FLESH, 100.0f,
|
|
0.0f, 1.55f, 0.0f,
|
|
0.0f, 1.0f, 0.0f,
|
|
};
|
|
static EntityInfo eiWomanFly = {
|
|
EIBT_FLESH, 80.0f,
|
|
0.0f, 0.0f, 0.0f,
|
|
0.0f, 0.0f, 0.0f,
|
|
};
|
|
|
|
#define FIRE_AIR FLOAT3D(0.0f, 0.25f, -0.65f)
|
|
#define FIRE_GROUND FLOAT3D(0.0f, 1.3f, -0.5f)
|
|
#define KAMIKAZE_ATTACH FLOAT3D(0.0f, -0.43f, -0.28f)
|
|
%}
|
|
|
|
|
|
class CWoman : CEnemyFly {
|
|
name "Woman";
|
|
thumbnail "Thumbnails\\Woman.tbn";
|
|
|
|
properties:
|
|
|
|
10 BOOL m_bKamikazeCarrier "Kamikaze Carrier" = FALSE,
|
|
11 RANGE m_rKamikazeDropDistance "Kamikaze Drop Range" = 40.0f,
|
|
20 BOOL m_bKamikazeAttached = FALSE,
|
|
|
|
components:
|
|
0 class CLASS_BASE "Classes\\EnemyFly.ecl",
|
|
1 model MODEL_WOMAN "ModelsMP\\Enemies\\Woman\\Woman.mdl",
|
|
2 texture TEXTURE_WOMAN "Models\\Enemies\\Woman\\Woman.tex",
|
|
3 class CLASS_PROJECTILE "Classes\\Projectile.ecl",
|
|
5 class CLASS_HEADMAN "Classes\\Headman.ecl",
|
|
7 model MODEL_HEADMAN "Models\\Enemies\\Headman\\Headman.mdl",
|
|
8 texture TEXTURE_HEADMAN "Models\\Enemies\\Headman\\Kamikaze.tex",
|
|
9 model MODEL_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.mdl",
|
|
10 texture TEXTURE_BOMB "Models\\Enemies\\Headman\\Projectile\\Bomb.tex",
|
|
|
|
// ************** SOUNDS **************
|
|
50 sound SOUND_IDLE "Models\\Enemies\\Woman\\Sounds\\Idle.wav",
|
|
51 sound SOUND_SIGHT "Models\\Enemies\\Woman\\Sounds\\Sight.wav",
|
|
52 sound SOUND_WOUND "Models\\Enemies\\Woman\\Sounds\\Wound.wav",
|
|
53 sound SOUND_FIRE "Models\\Enemies\\Woman\\Sounds\\Fire.wav",
|
|
54 sound SOUND_KICK "Models\\Enemies\\Woman\\Sounds\\Kick.wav",
|
|
55 sound SOUND_DEATH "Models\\Enemies\\Woman\\Sounds\\Death.wav",
|
|
|
|
functions:
|
|
// describe how this enemy killed player
|
|
virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath)
|
|
{
|
|
CTString str;
|
|
if (eDeath.eLastDamage.dmtType==DMT_CLOSERANGE) {
|
|
str.PrintF(TRANS("%s was beaten by a Scythian Harpy"), strPlayerName);
|
|
} else {
|
|
str.PrintF(TRANS("A Scythian Harpy got %s spellbound"), strPlayerName);
|
|
}
|
|
return str;
|
|
}
|
|
virtual const CTFileName &GetComputerMessageName(void) const {
|
|
static DECLARE_CTFILENAME(fnm, "Data\\Messages\\Enemies\\Woman.txt");
|
|
return fnm;
|
|
}
|
|
void Precache(void) {
|
|
CEnemyBase::Precache();
|
|
PrecacheSound(SOUND_IDLE );
|
|
PrecacheSound(SOUND_SIGHT);
|
|
PrecacheSound(SOUND_WOUND);
|
|
PrecacheSound(SOUND_FIRE );
|
|
PrecacheSound(SOUND_KICK );
|
|
PrecacheSound(SOUND_DEATH);
|
|
PrecacheClass(CLASS_PROJECTILE, PRT_WOMAN_FIRE);
|
|
};
|
|
|
|
/* Entity info */
|
|
void *GetEntityInfo(void) {
|
|
if (m_bInAir) {
|
|
return &eiWomanFly;
|
|
} else {
|
|
return &eiWomanStand;
|
|
}
|
|
};
|
|
|
|
/* Receive damage */
|
|
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
|
|
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
|
|
{
|
|
// woman can't harm woman
|
|
if (!IsOfClass(penInflictor, "Woman")) {
|
|
CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
|
|
}
|
|
};
|
|
|
|
|
|
// damage anim
|
|
INDEX AnimForDamage(FLOAT fDamage) {
|
|
INDEX iAnim;
|
|
if (m_bInAir) {
|
|
iAnim = WOMAN_ANIM_AIRWOUND02;
|
|
} else {
|
|
iAnim = WOMAN_ANIM_GROUNDWOUND04;
|
|
}
|
|
StartModelAnim(iAnim, 0);
|
|
return iAnim;
|
|
};
|
|
|
|
// death
|
|
INDEX AnimForDeath(void) {
|
|
INDEX iAnim;
|
|
if (m_bInAir) {
|
|
iAnim = WOMAN_ANIM_AIRDEATH;
|
|
} else {
|
|
iAnim = WOMAN_ANIM_GROUNDDEATH01;
|
|
}
|
|
StartModelAnim(iAnim, 0);
|
|
return iAnim;
|
|
};
|
|
|
|
FLOAT WaitForDust(FLOAT3D &vStretch) {
|
|
if(GetModelObject()->GetAnim()==WOMAN_ANIM_AIRDEATH)
|
|
{
|
|
vStretch=FLOAT3D(1,1,2)*1.0f;
|
|
return 0.6f;
|
|
}
|
|
else if(GetModelObject()->GetAnim()==WOMAN_ANIM_GROUNDDEATH01)
|
|
{
|
|
vStretch=FLOAT3D(1,1,2)*0.75f;
|
|
return 0.525f;
|
|
}
|
|
return -1.0f;
|
|
};
|
|
|
|
void DeathNotify(void) {
|
|
ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_DEATH);
|
|
en_fDensity = 500.0f;
|
|
};
|
|
|
|
// virtual anim functions
|
|
void StandingAnim(void) {
|
|
if (m_bInAir) {
|
|
StartModelAnim(WOMAN_ANIM_AIRSTAND, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDSTAND, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void WalkingAnim(void) {
|
|
if (m_bInAir) {
|
|
StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void RunningAnim(void) {
|
|
if (m_bInAir) {
|
|
StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDRUN, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void RotatingAnim(void) {
|
|
if (m_bInAir) {
|
|
StartModelAnim(WOMAN_ANIM_AIRFLY, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDWALK, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
FLOAT AirToGroundAnim(void) {
|
|
StartModelAnim(WOMAN_ANIM_AIRTOGROUND, 0);
|
|
return(GetModelObject()->GetAnimLength(WOMAN_ANIM_AIRTOGROUND));
|
|
};
|
|
FLOAT GroundToAirAnim(void) {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDTOAIR, 0);
|
|
return(GetModelObject()->GetAnimLength(WOMAN_ANIM_GROUNDTOAIR));
|
|
};
|
|
void ChangeCollisionToAir() {
|
|
ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_AIR);
|
|
};
|
|
void ChangeCollisionToGround() {
|
|
ChangeCollisionBoxIndexWhenPossible(WOMAN_COLLISION_BOX_GROUND);
|
|
};
|
|
|
|
// virtual sound functions
|
|
void IdleSound(void) {
|
|
PlaySound(m_soSound, SOUND_IDLE, SOF_3D);
|
|
};
|
|
void SightSound(void) {
|
|
PlaySound(m_soSound, SOUND_SIGHT, SOF_3D);
|
|
};
|
|
void WoundSound(void) {
|
|
PlaySound(m_soSound, SOUND_WOUND, SOF_3D);
|
|
};
|
|
void DeathSound(void) {
|
|
PlaySound(m_soSound, SOUND_DEATH, SOF_3D);
|
|
};
|
|
|
|
void AttachKamikaze()
|
|
{
|
|
AddAttachmentToModel(this, *GetModelObject(), WOMAN_ATTACHMENT_KAMIKAZE, MODEL_HEADMAN, TEXTURE_HEADMAN, 0, 0, 0);
|
|
CModelObject &amo = GetModelObject()->GetAttachmentModel(WOMAN_ATTACHMENT_KAMIKAZE)->amo_moModelObject;
|
|
AddAttachmentToModel(this, amo, HEADMAN_ATTACHMENT_BOMB_RIGHT_HAND, MODEL_BOMB, TEXTURE_BOMB, 0, 0, 0);
|
|
AddAttachmentToModel(this, amo, HEADMAN_ATTACHMENT_BOMB_LEFT_HAND, MODEL_BOMB, TEXTURE_BOMB, 0, 0, 0);
|
|
amo.PlayAnim(HEADMAN_ANIM_KAMIKAZE_ATTACK, AOF_LOOPING);
|
|
m_bKamikazeAttached = TRUE;
|
|
}
|
|
|
|
void RemoveKamikaze()
|
|
{
|
|
RemoveAttachmentFromModel(*GetModelObject(), WOMAN_ATTACHMENT_KAMIKAZE);
|
|
}
|
|
|
|
void DropKamikaze()
|
|
{
|
|
if (!m_bKamikazeAttached) { return; }
|
|
|
|
CEntity *pen = NULL;
|
|
|
|
CPlacement3D pl;
|
|
pl = GetPlacement();
|
|
pl.pl_PositionVector += KAMIKAZE_ATTACH*GetRotationMatrix();
|
|
pen = CreateEntity(pl, CLASS_HEADMAN);
|
|
|
|
((CHeadman *)&*pen)->m_hdtType = HDT_KAMIKAZE;
|
|
|
|
// change needed properties
|
|
pen->End();
|
|
|
|
CEnemyBase *peb = ((CEnemyBase*)pen);
|
|
peb->m_bTemplate = FALSE;
|
|
pen->Initialize();
|
|
|
|
// mark that we don't have the kamikaze any more
|
|
m_bKamikazeAttached = FALSE;
|
|
|
|
// deattach the kamikaze model
|
|
RemoveKamikaze();
|
|
}
|
|
|
|
|
|
void PreMoving() {
|
|
if (m_bKamikazeAttached && m_bKamikazeCarrier) {
|
|
// see if any of players are close enough to drop the kamikaze
|
|
INDEX ctMaxPlayers = GetMaxPlayers();
|
|
CEntity *penPlayer;
|
|
for(INDEX i=0; i<ctMaxPlayers; i++) {
|
|
penPlayer=GetPlayerEntity(i);
|
|
if (penPlayer!=NULL) {
|
|
if (DistanceTo(this, penPlayer)<m_rKamikazeDropDistance && IsVisible(penPlayer)) {
|
|
DropKamikaze();
|
|
}
|
|
}
|
|
} // end for
|
|
}
|
|
CEnemyFly::PreMoving();
|
|
}
|
|
|
|
void BlowUp(void)
|
|
{
|
|
DropKamikaze();
|
|
CEnemyFly::BlowUp();
|
|
}
|
|
|
|
|
|
procedures:
|
|
/************************************************************
|
|
* A T T A C K E N E M Y *
|
|
************************************************************/
|
|
FlyFire(EVoid) : CEnemyFly::FlyFire {
|
|
if (m_bKamikazeAttached) { return EReturn(); }
|
|
|
|
// fire projectile
|
|
StartModelAnim(WOMAN_ANIM_AIRATTACK02, 0);
|
|
autowait(0.6f);
|
|
ShootProjectile(PRT_WOMAN_FIRE, FIRE_AIR, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
autowait(0.6f);
|
|
StandingAnim();
|
|
autowait(FRnd()/2 + _pTimer->TickQuantum);
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
FlyHit(EVoid) : CEnemyFly::FlyHit {
|
|
if (m_bKamikazeAttached) { return EReturn(); }
|
|
|
|
// if enemy near
|
|
if (CalcDist(m_penEnemy) <= 5.0f) {
|
|
// if enemy is not in water
|
|
CMovableEntity *pen = (CMovableEntity *)&*m_penEnemy;
|
|
CContentType &ctDn = pen->en_pwoWorld->wo_actContentTypes[pen->en_iDnContent];
|
|
BOOL bEnemySwimming = !(ctDn.ct_ulFlags&CTF_BREATHABLE_LUNGS);
|
|
if (bEnemySwimming) {
|
|
jump FlyFire();
|
|
} else {
|
|
jump FlyOnEnemy();
|
|
}
|
|
}
|
|
|
|
// run to enemy
|
|
m_fShootTime = _pTimer->CurrentTick() + 0.25f;
|
|
return EReturn();
|
|
};
|
|
|
|
/************************************************************
|
|
* D E A T H *
|
|
************************************************************/
|
|
Death(EVoid) : CEnemyFly::Death {
|
|
DropKamikaze();
|
|
jump CEnemyFly::Death();
|
|
};
|
|
|
|
AirToGround(EVoid) : CEnemyFly::AirToGround {
|
|
DropKamikaze();
|
|
jump CEnemyFly::AirToGround(EVoid());
|
|
};
|
|
|
|
FlyOnEnemy(EVoid) {
|
|
StartModelAnim(WOMAN_ANIM_AIRATTACK01, 0);
|
|
|
|
// jump
|
|
FLOAT3D vDir = PlayerDestinationPos();
|
|
vDir = (vDir - GetPlacement().pl_PositionVector).Normalize();
|
|
vDir *= !GetRotationMatrix();
|
|
vDir *= m_fFlyCloseRunSpeed*1.9f;
|
|
SetDesiredTranslation(vDir);
|
|
PlaySound(m_soSound, SOUND_KICK, SOF_3D);
|
|
|
|
// animation - IGNORE DAMAGE WOUND -
|
|
SpawnReminder(this, 0.9f, 0);
|
|
m_iChargeHitAnimation = WOMAN_ANIM_AIRATTACK01;
|
|
m_fChargeHitDamage = 20.0f;
|
|
m_fChargeHitAngle = 0.0f;
|
|
m_fChargeHitSpeed = 10.0f;
|
|
autocall CEnemyBase::ChargeHitEnemy() EReturn;
|
|
|
|
StandingAnim();
|
|
autowait(0.3f);
|
|
return EReturn();
|
|
}
|
|
|
|
GroundFire(EVoid) : CEnemyFly::GroundFire {
|
|
// fire projectile
|
|
StartModelAnim(WOMAN_ANIM_GROUNDATTACK02, 0);
|
|
autowait(0.3f);
|
|
ShootProjectile(PRT_WOMAN_FIRE, FIRE_GROUND, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
autowait(0.3f);
|
|
StandingAnim();
|
|
autowait(FRnd()/2 + _pTimer->TickQuantum);
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
GroundHit(EVoid) : CEnemyFly::GroundHit {
|
|
StartModelAnim(WOMAN_ANIM_GROUNDATTACK01, 0);
|
|
|
|
// jump
|
|
FLOAT3D vDir = (m_penEnemy->GetPlacement().pl_PositionVector -
|
|
GetPlacement().pl_PositionVector).Normalize();
|
|
vDir *= !GetRotationMatrix();
|
|
vDir *= m_fCloseRunSpeed*1.75f;
|
|
vDir(2) = 2.5f;
|
|
SetDesiredTranslation(vDir);
|
|
PlaySound(m_soSound, SOUND_KICK, SOF_3D);
|
|
|
|
// animation - IGNORE DAMAGE WOUND -
|
|
SpawnReminder(this, 0.9f, 0);
|
|
m_iChargeHitAnimation = WOMAN_ANIM_GROUNDATTACK01;
|
|
m_fChargeHitDamage = 20.0f;
|
|
m_fChargeHitAngle = 0.0f;
|
|
m_fChargeHitSpeed = 10.0f;
|
|
autocall CEnemyBase::ChargeHitEnemy() EReturn;
|
|
|
|
StandingAnim();
|
|
autowait(0.3f);
|
|
return EReturn();
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* M A I N *
|
|
************************************************************/
|
|
Main(EVoid) {
|
|
// declare yourself as a model
|
|
InitAsModel();
|
|
SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS);
|
|
SetCollisionFlags(ECF_MODEL);
|
|
SetFlags(GetFlags()|ENF_ALIVE);
|
|
SetHealth(100.0f);
|
|
m_fMaxHealth = 100.0f;
|
|
en_tmMaxHoldBreath = 5.0f;
|
|
en_fDensity = 2000.0f;
|
|
|
|
m_sptType = SPT_FEATHER;
|
|
|
|
// set your appearance
|
|
SetModel(MODEL_WOMAN);
|
|
SetModelMainTexture(TEXTURE_WOMAN);
|
|
// setup moving speed
|
|
m_fWalkSpeed = FRnd() + 1.5f;
|
|
m_aWalkRotateSpeed = FRnd()*10.0f + 25.0f;
|
|
m_fAttackRunSpeed = FRnd()*2.0f + 9.0f;
|
|
m_aAttackRotateSpeed = FRnd()*50 + 245.0f;
|
|
m_fCloseRunSpeed = FRnd()*2.0f + 4.0f;
|
|
m_aCloseRotateSpeed = FRnd()*50 + 245.0f;
|
|
// setup attack distances
|
|
m_fAttackDistance = 50.0f;
|
|
m_fCloseDistance = 5.0f;
|
|
m_fStopDistance = 0.0f;
|
|
m_fAttackFireTime = 3.0f;
|
|
m_fCloseFireTime = 2.0f;
|
|
m_fIgnoreRange = 200.0f;
|
|
// fly moving properties
|
|
m_fFlyWalkSpeed = FRnd()/2 + 1.0f;
|
|
m_aFlyWalkRotateSpeed = FRnd()*10.0f + 25.0f;
|
|
m_fFlyAttackRunSpeed = FRnd()*2.0f + 10.0f;
|
|
m_aFlyAttackRotateSpeed = FRnd()*25 + 150.0f;
|
|
m_fFlyCloseRunSpeed = FRnd()*2.0f + 10.0f;
|
|
m_aFlyCloseRotateSpeed = FRnd()*50 + 500.0f;
|
|
m_fGroundToAirSpeed = m_fFlyCloseRunSpeed;
|
|
m_fAirToGroundSpeed = m_fFlyCloseRunSpeed;
|
|
m_fAirToGroundMin = 0.1f;
|
|
m_fAirToGroundMax = 0.1f;
|
|
// attack properties - CAN BE SET
|
|
m_fFlyAttackDistance = 50.0f;
|
|
m_fFlyCloseDistance = 12.5f;
|
|
m_fFlyStopDistance = 0.0f;
|
|
m_fFlyAttackFireTime = 3.0f;
|
|
m_fFlyCloseFireTime = 2.0f;
|
|
m_fFlyIgnoreRange = 200.0f;
|
|
// damage/explode properties
|
|
m_fBlowUpAmount = 100.0f;
|
|
m_fBodyParts = 4;
|
|
m_fDamageWounded = 20.0f;
|
|
m_iScore = 1000;
|
|
|
|
if (m_bKamikazeCarrier) {
|
|
AttachKamikaze();
|
|
}
|
|
|
|
autowait(0.05f);
|
|
|
|
// continue behavior in base class
|
|
jump CEnemyFly::MainLoop();
|
|
};
|
|
};
|