mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-12-27 07:54:51 +01:00
663 lines
20 KiB
C++
663 lines
20 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. */
|
|
|
|
306
|
|
%{
|
|
#include "StdH.h"
|
|
#include "Models/Enemies/Scorpman/Scorpman.h"
|
|
#include "Models/Enemies/Scorpman/Gun.h"
|
|
%}
|
|
|
|
uses "EntitiesMP/EnemyBase";
|
|
uses "EntitiesMP/Bullet";
|
|
uses "EntitiesMP/Reminder";
|
|
|
|
enum ScorpmanType {
|
|
0 SMT_SOLDIER "Soldier",
|
|
1 SMT_GENERAL "General",
|
|
2 SMT_MONSTER "Obsolete",
|
|
};
|
|
|
|
|
|
%{
|
|
#define GUN_X 0.375f
|
|
#define GUN_Y 0.6f
|
|
#define GUN_Z -1.85f
|
|
#define STRETCH_SOLDIER 2
|
|
#define STRETCH_GENERAL 3
|
|
#define STRETCH_MONSTER 4
|
|
// info structure
|
|
static EntityInfo eiScorpman = {
|
|
EIBT_FLESH, 1000.0f,
|
|
0, 1.6f*STRETCH_SOLDIER, 0, // source (eyes)
|
|
0.0f, 1.0f*STRETCH_SOLDIER, 0.0f, // target (body)
|
|
};
|
|
|
|
static EntityInfo eiScorpmanGeneral = {
|
|
EIBT_FLESH, 1500.0f,
|
|
0, 1.6f*STRETCH_GENERAL, 0, // source (eyes)
|
|
0.0f, 1.0f*STRETCH_GENERAL, 0.0f, // target (body)
|
|
};
|
|
|
|
static EntityInfo eiScorpmanMonster = {
|
|
EIBT_FLESH, 2000.0f,
|
|
0, 1.6f*STRETCH_MONSTER, 0, // source (eyes)
|
|
0.0f, 1.0f*STRETCH_MONSTER, 0.0f, // target (body)
|
|
};
|
|
#define LIGHT_ANIM_FIRE 3
|
|
#define LIGHT_ANIM_NONE 5
|
|
%}
|
|
|
|
|
|
class CScorpman : CEnemyBase {
|
|
name "Scorpman";
|
|
thumbnail "Thumbnails\\Scorpman.tbn";
|
|
|
|
properties:
|
|
1 enum ScorpmanType m_smtType "Type" 'Y' = SMT_SOLDIER,
|
|
2 INDEX m_bFireBulletCount = 0, // fire bullet binary divider
|
|
3 INDEX m_iSpawnEffect = 0, // counter for spawn effect every 'x' times
|
|
4 FLOAT m_fFireTime = 0.0f, // time to fire bullets
|
|
5 CAnimObject m_aoLightAnimation, // light animation object
|
|
6 BOOL m_bSleeping "Sleeping" 'S' = FALSE, // set to make scorpman sleep initally
|
|
|
|
{
|
|
CEntity *penBullet; // bullet
|
|
CLightSource m_lsLightSource;
|
|
}
|
|
|
|
components:
|
|
0 class CLASS_BASE "Classes\\EnemyBase.ecl",
|
|
1 class CLASS_BULLET "Classes\\Bullet.ecl",
|
|
5 model MODEL_SCORPMAN "Models\\Enemies\\Scorpman\\Scorpman.mdl",
|
|
6 texture TEXTURE_SOLDIER "Models\\Enemies\\Scorpman\\Soldier.tex",
|
|
7 texture TEXTURE_GENERAL "Models\\Enemies\\Scorpman\\General.tex",
|
|
// 8 texture TEXTURE_MONSTER "Models\\Enemies\\Scorpman\\Monster.tex",
|
|
12 texture TEXTURE_SPECULAR "Models\\SpecularTextures\\Medium.tex",
|
|
9 model MODEL_GUN "Models\\Enemies\\Scorpman\\Gun.mdl",
|
|
10 model MODEL_FLARE "Models\\Enemies\\Scorpman\\Flare.mdl",
|
|
11 texture TEXTURE_GUN "Models\\Enemies\\Scorpman\\Gun.tex",
|
|
|
|
// ************** SOUNDS **************
|
|
50 sound SOUND_IDLE "Models\\Enemies\\Scorpman\\Sounds\\Idle.wav",
|
|
51 sound SOUND_SIGHT "Models\\Enemies\\Scorpman\\Sounds\\Sight.wav",
|
|
52 sound SOUND_WOUND "Models\\Enemies\\Scorpman\\Sounds\\Wound.wav",
|
|
53 sound SOUND_FIRE "Models\\Enemies\\Scorpman\\Sounds\\Fire.wav",
|
|
54 sound SOUND_KICK "Models\\Enemies\\Scorpman\\Sounds\\Kick.wav",
|
|
55 sound SOUND_DEATH "Models\\Enemies\\Scorpman\\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 stabbed by an Arachnoid"), strPlayerName);
|
|
} else {
|
|
str.PrintF(TRANS("An Arachnoid poured lead into %s"), strPlayerName);
|
|
}
|
|
return str;
|
|
}
|
|
void Precache(void) {
|
|
CEnemyBase::Precache();
|
|
PrecacheModel(MODEL_FLARE);
|
|
PrecacheSound(SOUND_IDLE );
|
|
PrecacheSound(SOUND_SIGHT);
|
|
PrecacheSound(SOUND_WOUND);
|
|
PrecacheSound(SOUND_FIRE );
|
|
PrecacheSound(SOUND_KICK );
|
|
PrecacheSound(SOUND_DEATH);
|
|
};
|
|
|
|
/* Read from stream. */
|
|
void Read_t( CTStream *istr) { // throw char *
|
|
CEnemyBase::Read_t(istr);
|
|
|
|
// setup light source
|
|
SetupLightSource();
|
|
}
|
|
|
|
/* Fill in entity statistics - for AI purposes only */
|
|
BOOL FillEntityStatistics(EntityStats *pes)
|
|
{
|
|
CEnemyBase::FillEntityStatistics(pes);
|
|
switch(m_smtType) {
|
|
case SMT_MONSTER: { pes->es_strName+=" Monster"; } break;
|
|
case SMT_GENERAL: { pes->es_strName+=" General"; } break;
|
|
case SMT_SOLDIER: { pes->es_strName+=" Soldier"; } break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
virtual const CTFileName &GetComputerMessageName(void) const {
|
|
//static DECLARE_CTFILENAME(fnmMonster, "Data\\Messages\\Enemies\\ScorpmanMonster.txt");
|
|
static DECLARE_CTFILENAME(fnmGeneral, "Data\\Messages\\Enemies\\ScorpmanGeneral.txt");
|
|
static DECLARE_CTFILENAME(fnmSoldier, "Data\\Messages\\Enemies\\ScorpmanSoldier.txt");
|
|
switch(m_smtType) {
|
|
default: ASSERT(FALSE);
|
|
case SMT_MONSTER: //return fnmMonster;
|
|
case SMT_GENERAL: return fnmGeneral;
|
|
case SMT_SOLDIER: return fnmSoldier;
|
|
}
|
|
};
|
|
|
|
/* Get static light source information. */
|
|
CLightSource *GetLightSource(void) {
|
|
if (!IsPredictor()) {
|
|
return &m_lsLightSource;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOL ForcesCannonballToExplode(void)
|
|
{
|
|
if (m_smtType!=SMT_SOLDIER) {
|
|
return TRUE;
|
|
}
|
|
return CEnemyBase::ForcesCannonballToExplode();
|
|
}
|
|
|
|
// Setup light source
|
|
void SetupLightSource(void) {
|
|
// setup light source
|
|
CLightSource lsNew;
|
|
lsNew.ls_ulFlags = LSF_NONPERSISTENT|LSF_DYNAMIC;
|
|
lsNew.ls_rHotSpot = 2.0f;
|
|
lsNew.ls_rFallOff = 8.0f;
|
|
lsNew.ls_colColor = RGBToColor(128, 128, 128);
|
|
lsNew.ls_plftLensFlare = NULL;
|
|
lsNew.ls_ubPolygonalMask = 0;
|
|
lsNew.ls_paoLightAnimation = &m_aoLightAnimation;
|
|
|
|
m_lsLightSource.ls_penEntity = this;
|
|
m_lsLightSource.SetLightSource(lsNew);
|
|
}
|
|
// play light animation
|
|
void PlayLightAnim(INDEX iAnim, ULONG ulFlags) {
|
|
if (m_aoLightAnimation.GetData()!=NULL) {
|
|
m_aoLightAnimation.PlayAnim(iAnim, ulFlags);
|
|
}
|
|
};
|
|
|
|
// fire minigun on/off
|
|
void MinigunOn(void)
|
|
{
|
|
PlayLightAnim(LIGHT_ANIM_FIRE, AOF_LOOPING);
|
|
CModelObject *pmoGun = &GetModelObject()->GetAttachmentModel(SCORPMAN_ATTACHMENT_MINIGUN)->
|
|
amo_moModelObject;
|
|
pmoGun->PlayAnim(GUN_ANIM_FIRE, AOF_LOOPING);
|
|
AddAttachmentToModel(this, *pmoGun, GUN_ATTACHMENT_FLAME, MODEL_FLARE, TEXTURE_GUN, 0, 0, 0);
|
|
switch (m_smtType) {
|
|
case SMT_SOLDIER: pmoGun->StretchModel(FLOAT3D(2.0f, 2.0f, 2.0f)); break;
|
|
case SMT_GENERAL: pmoGun->StretchModel(FLOAT3D(3.0f, 3.0f, 3.0f)); break;
|
|
case SMT_MONSTER: pmoGun->StretchModel(FLOAT3D(4.0f, 4.0f, 4.0f)); break;
|
|
}
|
|
}
|
|
void MinigunOff(void)
|
|
{
|
|
PlayLightAnim(LIGHT_ANIM_NONE, 0);
|
|
CModelObject *pmoGun = &GetModelObject()->GetAttachmentModel(SCORPMAN_ATTACHMENT_MINIGUN)->
|
|
amo_moModelObject;
|
|
pmoGun->PlayAnim(GUN_ANIM_IDLE, AOF_LOOPING);
|
|
pmoGun->RemoveAttachmentModel(GUN_ATTACHMENT_FLAME);
|
|
}
|
|
/* Entity info */
|
|
void *GetEntityInfo(void) {
|
|
if (m_smtType == SMT_MONSTER) {
|
|
return &eiScorpmanMonster;
|
|
} else if (m_smtType == SMT_GENERAL) {
|
|
return &eiScorpmanGeneral;
|
|
} else {
|
|
return &eiScorpman;
|
|
}
|
|
};
|
|
|
|
/* Receive damage */
|
|
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
|
|
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
|
|
{
|
|
// scorpman can't harm scorpman
|
|
if (!IsOfClass(penInflictor, "Scorpman")) {
|
|
CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
|
|
}
|
|
};
|
|
|
|
|
|
// damage anim
|
|
INDEX AnimForDamage(FLOAT fDamage) {
|
|
INDEX iAnim;
|
|
switch (IRnd()%3) {
|
|
case 0: iAnim = SCORPMAN_ANIM_WOUND01; break;
|
|
case 1: iAnim = SCORPMAN_ANIM_WOUND02; break;
|
|
case 2: iAnim = SCORPMAN_ANIM_WOUND03; break;
|
|
default: ASSERTALWAYS("Scorpman unknown damage");
|
|
}
|
|
StartModelAnim(iAnim, 0);
|
|
MinigunOff();
|
|
return iAnim;
|
|
};
|
|
|
|
// death
|
|
INDEX AnimForDeath(void) {
|
|
StartModelAnim(SCORPMAN_ANIM_DEATH, 0);
|
|
MinigunOff();
|
|
return SCORPMAN_ANIM_DEATH;
|
|
};
|
|
|
|
FLOAT WaitForDust(FLOAT3D &vStretch) {
|
|
if(GetModelObject()->GetAnim()==SCORPMAN_ANIM_DEATH)
|
|
{
|
|
vStretch=FLOAT3D(1,1,1)*1.5f;
|
|
return 1.3f;
|
|
}
|
|
return -1.0f;
|
|
};
|
|
|
|
void DeathNotify(void) {
|
|
ChangeCollisionBoxIndexWhenPossible(SCORPMAN_COLLISION_BOX_DEATH);
|
|
SetCollisionFlags(ECF_MODEL);
|
|
};
|
|
|
|
// virtual anim functions
|
|
void StandingAnim(void) {
|
|
StartModelAnim(SCORPMAN_ANIM_IDLE, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
void WalkingAnim(void) {
|
|
StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
void RunningAnim(void) {
|
|
StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
void RotatingAnim(void) {
|
|
StartModelAnim(SCORPMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
|
|
};
|
|
|
|
// 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);
|
|
};
|
|
|
|
|
|
/************************************************************
|
|
* FIRE BULLET / RAIL *
|
|
************************************************************/
|
|
BOOL CanFireAtPlayer(void)
|
|
{
|
|
// get ray source and target
|
|
FLOAT3D vSource, vTarget;
|
|
GetPositionCastRay(this, m_penEnemy, vSource, vTarget);
|
|
|
|
// bullet start position
|
|
CPlacement3D plBullet;
|
|
plBullet.pl_OrientationAngle = ANGLE3D(0,0,0);
|
|
plBullet.pl_PositionVector = FLOAT3D(GUN_X, GUN_Y, 0);
|
|
// offset are changed according to stretch factor
|
|
if (m_smtType == SMT_MONSTER) {
|
|
plBullet.pl_PositionVector*=STRETCH_MONSTER;
|
|
} else if (m_smtType == SMT_GENERAL) {
|
|
plBullet.pl_PositionVector*=STRETCH_GENERAL;
|
|
} else {
|
|
plBullet.pl_PositionVector*=STRETCH_SOLDIER;
|
|
}
|
|
plBullet.RelativeToAbsolute(GetPlacement());
|
|
vSource = plBullet.pl_PositionVector;
|
|
|
|
// cast the ray
|
|
CCastRay crRay(this, vSource, vTarget);
|
|
crRay.cr_ttHitModels = CCastRay::TT_NONE; // check for brushes only
|
|
crRay.cr_bHitTranslucentPortals = FALSE;
|
|
en_pwoWorld->CastRay(crRay);
|
|
|
|
// if hit nothing (no brush) the entity can be seen
|
|
return (crRay.cr_penHit==NULL);
|
|
}
|
|
|
|
void PrepareBullet(FLOAT fDamage) {
|
|
// bullet start position
|
|
CPlacement3D plBullet;
|
|
plBullet.pl_OrientationAngle = ANGLE3D(0,0,0);
|
|
plBullet.pl_PositionVector = FLOAT3D(GUN_X, GUN_Y, 0);
|
|
// offset are changed according to stretch factor
|
|
if (m_smtType == SMT_MONSTER) {
|
|
plBullet.pl_PositionVector*=STRETCH_MONSTER;
|
|
} else if (m_smtType == SMT_GENERAL) {
|
|
plBullet.pl_PositionVector*=STRETCH_GENERAL;
|
|
} else {
|
|
plBullet.pl_PositionVector*=STRETCH_SOLDIER;
|
|
}
|
|
plBullet.RelativeToAbsolute(GetPlacement());
|
|
// create bullet
|
|
penBullet = CreateEntity(plBullet, CLASS_BULLET);
|
|
// init bullet
|
|
EBulletInit eInit;
|
|
eInit.penOwner = this;
|
|
eInit.fDamage = fDamage;
|
|
penBullet->Initialize(eInit);
|
|
};
|
|
|
|
// fire bullet
|
|
void FireBullet(void) {
|
|
// binary divide counter
|
|
m_bFireBulletCount++;
|
|
if (m_bFireBulletCount>1) { m_bFireBulletCount = 0; }
|
|
if (m_bFireBulletCount==1) { return; }
|
|
// bullet
|
|
PrepareBullet(3.0f);
|
|
((CBullet&)*penBullet).CalcTarget(m_penEnemy, 250);
|
|
((CBullet&)*penBullet).CalcJitterTarget(10);
|
|
((CBullet&)*penBullet).LaunchBullet( TRUE, TRUE, TRUE);
|
|
((CBullet&)*penBullet).DestroyBullet();
|
|
};
|
|
|
|
|
|
// adjust sound and watcher parameters here if needed
|
|
void EnemyPostInit(void)
|
|
{
|
|
// set sound default parameters
|
|
m_soSound.Set3DParameters(160.0f, 50.0f, 1.0f, 1.0f);
|
|
};
|
|
|
|
procedures:
|
|
/************************************************************
|
|
* A T T A C K E N E M Y *
|
|
************************************************************/
|
|
// shoot
|
|
Fire(EVoid) : CEnemyBase::Fire{
|
|
if (!CanFireAtPlayer()) {
|
|
return EReturn();
|
|
}
|
|
|
|
// confused amount
|
|
switch (m_smtType) {
|
|
case SMT_MONSTER:
|
|
m_fDamageConfused = 200;
|
|
m_fFireTime = 8.0f;
|
|
break;
|
|
case SMT_GENERAL:
|
|
m_fDamageConfused = 100;
|
|
m_fFireTime = 4.0f;
|
|
break;
|
|
case SMT_SOLDIER:
|
|
m_fDamageConfused = 50;
|
|
m_fFireTime = 2.0f;
|
|
break;
|
|
}
|
|
if (GetSP()->sp_gdGameDifficulty<=CSessionProperties::GD_EASY) {
|
|
m_fFireTime *= 0.5f;
|
|
}
|
|
// to fire
|
|
StartModelAnim(SCORPMAN_ANIM_STANDTOFIRE, 0);
|
|
m_fLockOnEnemyTime = GetModelObject()->GetAnimLength(SCORPMAN_ANIM_STANDTOFIRE) + 0.5f + FRnd()/3;
|
|
autocall CEnemyBase::LockOnEnemy() EReturn;
|
|
|
|
// fire
|
|
m_iSpawnEffect = 0; // effect every 'x' frames
|
|
m_fFireTime += _pTimer->CurrentTick();
|
|
m_bFireBulletCount = 0;
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D|SOF_LOOP);
|
|
MinigunOn();
|
|
|
|
while (m_fFireTime > _pTimer->CurrentTick()) {
|
|
m_fMoveFrequency = 0.1f;
|
|
wait(m_fMoveFrequency) {
|
|
on (EBegin) : {
|
|
// make fuss
|
|
AddToFuss();
|
|
// fire bullet
|
|
FireBullet();
|
|
m_vDesiredPosition = m_penEnemy->GetPlacement().pl_PositionVector;
|
|
// rotate to enemy
|
|
if (!IsInPlaneFrustum(m_penEnemy, CosFast(5.0f))) {
|
|
m_fMoveSpeed = 0.0f;
|
|
m_aRotateSpeed = 4000.0f;
|
|
StartModelAnim(SCORPMAN_ANIM_WALK_AND_FIRE, AOF_LOOPING|AOF_NORESTART);
|
|
// stand in place
|
|
} else {
|
|
m_fMoveSpeed = 0.0f;
|
|
m_aRotateSpeed = 0.0f;
|
|
StartModelAnim(SCORPMAN_ANIM_FIRE_MINIGUN, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
// adjust direction and speed
|
|
SetDesiredMovement();
|
|
resume;
|
|
}
|
|
on (ETimer) : { stop; }
|
|
}
|
|
}
|
|
m_soSound.Stop();
|
|
MinigunOff();
|
|
// set next shoot time
|
|
m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/3.0f);
|
|
|
|
// from fire
|
|
StartModelAnim(SCORPMAN_ANIM_FIRETOSTAND, 0);
|
|
autowait(GetModelObject()->GetAnimLength(SCORPMAN_ANIM_FIRETOSTAND));
|
|
|
|
MaybeSwitchToAnotherPlayer();
|
|
|
|
// shoot completed
|
|
return EReturn();
|
|
};
|
|
|
|
// hit enemy
|
|
Hit(EVoid) : CEnemyBase::Hit {
|
|
// close attack
|
|
StartModelAnim(SCORPMAN_ANIM_SPIKEHIT, 0);
|
|
autowait(0.5f);
|
|
PlaySound(m_soSound, SOUND_KICK, SOF_3D);
|
|
if (CalcDist(m_penEnemy) < m_fCloseDistance) {
|
|
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
|
|
vDirection.Normalize();
|
|
if (m_smtType == SMT_MONSTER) {
|
|
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 80.0f, FLOAT3D(0, 0, 0), vDirection);
|
|
} else if (m_smtType == SMT_GENERAL) {
|
|
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 40.0f, FLOAT3D(0, 0, 0), vDirection);
|
|
} else {
|
|
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 20.0f, FLOAT3D(0, 0, 0), vDirection);
|
|
}
|
|
}
|
|
autowait(0.3f);
|
|
MaybeSwitchToAnotherPlayer();
|
|
return EReturn();
|
|
};
|
|
|
|
Sleep(EVoid)
|
|
{
|
|
// start sleeping anim
|
|
StartModelAnim(SCORPMAN_ANIM_SLEEP, AOF_LOOPING);
|
|
// repeat
|
|
wait() {
|
|
// if triggered
|
|
on(ETrigger eTrigger) : {
|
|
// remember enemy
|
|
SetTargetSoft(eTrigger.penCaused);
|
|
// wake up
|
|
jump WakeUp();
|
|
}
|
|
// if damaged
|
|
on(EDamage eDamage) : {
|
|
// wake up
|
|
jump WakeUp();
|
|
}
|
|
otherwise() : {
|
|
resume;
|
|
}
|
|
}
|
|
}
|
|
|
|
WakeUp(EVoid)
|
|
{
|
|
// wakeup anim
|
|
SightSound();
|
|
StartModelAnim(SCORPMAN_ANIM_WAKEUP, 0);
|
|
autowait(GetModelObject()->GetCurrentAnimLength());
|
|
|
|
// trigger your target
|
|
SendToTarget(m_penDeathTarget, m_eetDeathType);
|
|
// proceed with normal functioning
|
|
return EReturn();
|
|
}
|
|
|
|
// overridable called before main enemy loop actually begins
|
|
PreMainLoop(EVoid) : CEnemyBase::PreMainLoop
|
|
{
|
|
// if sleeping
|
|
if (m_bSleeping) {
|
|
m_bSleeping = FALSE;
|
|
// go to sleep until waken up
|
|
wait() {
|
|
on (EBegin) : {
|
|
call Sleep();
|
|
}
|
|
on (EReturn) : {
|
|
stop;
|
|
};
|
|
// if dead
|
|
on(EDeath eDeath) : {
|
|
// die
|
|
jump CEnemyBase::Die(eDeath);
|
|
}
|
|
}
|
|
}
|
|
return EReturn();
|
|
}
|
|
|
|
/************************************************************
|
|
* M A I N *
|
|
************************************************************/
|
|
Main(EVoid) {
|
|
if (m_smtType==SMT_MONSTER) {
|
|
m_smtType=SMT_GENERAL;
|
|
}
|
|
|
|
// declare yourself as a model
|
|
InitAsModel();
|
|
SetPhysicsFlags(EPF_MODEL_WALKING|EPF_HASLUNGS);
|
|
SetCollisionFlags(ECF_MODEL);
|
|
SetFlags(GetFlags()|ENF_ALIVE);
|
|
en_tmMaxHoldBreath = 25.0f;
|
|
en_fDensity = 3000.0f;
|
|
|
|
// set your appearance
|
|
SetModel(MODEL_SCORPMAN);
|
|
switch (m_smtType) {
|
|
case SMT_SOLDIER:
|
|
// set your texture
|
|
SetModelMainTexture(TEXTURE_SOLDIER);
|
|
SetModelSpecularTexture(TEXTURE_SPECULAR);
|
|
SetHealth(300.0f);
|
|
m_fMaxHealth = 300.0f;
|
|
// damage/explode properties
|
|
m_fDamageWounded = 200.0f;
|
|
m_fBlowUpAmount = 1E10f;
|
|
m_fBodyParts = 30;
|
|
// setup attack distances
|
|
m_fAttackDistance = 200.0f;
|
|
m_fCloseDistance = 5.0f;
|
|
m_fStopDistance = 4.5f;
|
|
m_fAttackFireTime = 0.5f;
|
|
m_fCloseFireTime = 1.0f;
|
|
m_fIgnoreRange = 350.0f;
|
|
m_iScore = 1000;
|
|
break;
|
|
|
|
case SMT_GENERAL:
|
|
// set your texture
|
|
SetModelMainTexture(TEXTURE_GENERAL);
|
|
SetModelSpecularTexture(TEXTURE_SPECULAR);
|
|
SetHealth(600.0f);
|
|
m_fMaxHealth = 600.0f;
|
|
// damage/explode properties
|
|
m_fDamageWounded = 400.0f;
|
|
m_fBlowUpAmount = 1E10f;
|
|
m_fBodyParts = 30;
|
|
// setup attack distances
|
|
m_fAttackDistance = 200.0f;
|
|
m_fCloseDistance = 5.0f;
|
|
m_fStopDistance = 4.5f;
|
|
m_fAttackFireTime = 2.0f;
|
|
m_fCloseFireTime = 1.0f;
|
|
m_fIgnoreRange = 350.0f;
|
|
m_iScore = 5000;
|
|
break;
|
|
|
|
case SMT_MONSTER:
|
|
// set your texture
|
|
SetModelMainTexture(TEXTURE_GENERAL);
|
|
SetModelSpecularTexture(TEXTURE_SPECULAR);
|
|
SetHealth(1200.0f);
|
|
m_fMaxHealth = 1200.0f;
|
|
// damage/explode properties
|
|
m_fDamageWounded = 800.0f;
|
|
m_fBlowUpAmount = 1E10f;
|
|
m_fBodyParts = 60;
|
|
// setup attack distances
|
|
m_fAttackDistance = 250.0f;
|
|
m_fCloseDistance = 11.0f;
|
|
m_fStopDistance = 9.0f;
|
|
m_fAttackFireTime = 2.0f;
|
|
m_fCloseFireTime = 1.0f;
|
|
m_fIgnoreRange = 500.0f;
|
|
m_iScore = 10000;
|
|
break;
|
|
}
|
|
|
|
AddAttachment(SCORPMAN_ATTACHMENT_MINIGUN, MODEL_GUN, TEXTURE_GUN);
|
|
|
|
// set stretch factors for height and width - MUST BE DONE BEFORE SETTING MODEL!
|
|
switch (m_smtType) {
|
|
case SMT_SOLDIER: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_SOLDIER); break;
|
|
case SMT_GENERAL: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_GENERAL); break;
|
|
case SMT_MONSTER: GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f)*STRETCH_MONSTER); break;
|
|
}
|
|
|
|
ModelChangeNotify();
|
|
|
|
// setup moving speed
|
|
m_fWalkSpeed = FRnd() + 1.5f;
|
|
m_aWalkRotateSpeed = AngleDeg(FRnd()*20.0f + 550.0f);
|
|
m_fAttackRunSpeed = FRnd()*1.5f + 4.5f;
|
|
m_aAttackRotateSpeed = AngleDeg(FRnd()*50.0f + 275.0f);
|
|
m_fCloseRunSpeed = FRnd()*1.5f + 4.5f;
|
|
m_aCloseRotateSpeed = AngleDeg(FRnd()*50.0f + 275.0f);
|
|
|
|
// set stretch factors for height and width
|
|
CEnemyBase::SizeModel();
|
|
// setup light source
|
|
SetupLightSource();
|
|
// set light animation if available
|
|
try {
|
|
m_aoLightAnimation.SetData_t(CTFILENAME("Animations\\BasicEffects.ani"));
|
|
} catch (char *strError) {
|
|
WarningMessage(TRANS("Cannot load Animations\\BasicEffects.ani: %s"), strError);
|
|
}
|
|
MinigunOff();
|
|
|
|
// continue behavior in base class
|
|
jump CEnemyBase::MainLoop();
|
|
|
|
};
|
|
};
|