Serious-Engine/Sources/EntitiesMP/Eyeman.es

544 lines
17 KiB
JavaScript

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
323
%{
#include "StdH.h"
#include "Models/Enemies/Eyeman/Eyeman.h"
%}
uses "EntitiesMP/EnemyFly";
enum EyemanChar {
0 EYC_SOLDIER "Soldier", // soldier
1 EYC_SERGEANT "Sergeant", // sergeant
};
enum EyemanEnv {
0 EYE_NORMAL "Normal",
1 EYE_LAVA "Lava",
};
%{
// info structure
static EntityInfo eiEyemanBig = {
EIBT_FLESH, 140.0f,
0.0f, 1.4f, 0.0f,
0.0f, 1.0f, 0.0f,
};
static EntityInfo eiEyemanSmall = {
EIBT_FLESH, 120.0f,
0.0f, 1.4f, 0.0f,
0.0f, 1.0f, 0.0f,
};
#define BITE_AIR 3.0f
#define HIT_GROUND 2.0f
#define FIRE_GROUND FLOAT3D(0.75f, 1.5f, -1.25f)
%}
class CEyeman : CEnemyFly {
name "Eyeman";
thumbnail "Thumbnails\\Eyeman.tbn";
properties:
1 enum EyemanChar m_EecChar "Character" 'C' = EYC_SOLDIER, // character
2 BOOL m_bInvisible "Invisible" 'I'=FALSE,
3 enum EyemanEnv m_eeEnv "Environment" 'E' = EYE_NORMAL,
4 BOOL m_bMumbleSoundPlaying = FALSE,
5 CSoundObject m_soMumble,
components:
0 class CLASS_BASE "Classes\\EnemyFly.ecl",
1 model MODEL_EYEMAN "Models\\Enemies\\Eyeman\\Eyeman.mdl",
2 texture TEXTURE_EYEMAN_SOLDIER "Models\\Enemies\\Eyeman\\Eyeman4.tex",
3 texture TEXTURE_EYEMAN_SERGEANT "Models\\Enemies\\Eyeman\\Eyeman5.tex",
5 texture TEXTURE_EYEMAN_LAVA "Models\\Enemies\\Eyeman\\Eyeman6.tex",
4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl",
// ************** SOUNDS **************
50 sound SOUND_IDLE "Models\\Enemies\\Eyeman\\Sounds\\Idle.wav",
51 sound SOUND_SIGHT "Models\\Enemies\\Eyeman\\Sounds\\Sight.wav",
52 sound SOUND_WOUND "Models\\Enemies\\Eyeman\\Sounds\\Wound.wav",
53 sound SOUND_BITE "Models\\Enemies\\Eyeman\\Sounds\\Bite.wav",
54 sound SOUND_PUNCH "Models\\Enemies\\Eyeman\\Sounds\\Punch.wav",
55 sound SOUND_DEATH "Models\\Enemies\\Eyeman\\Sounds\\Death.wav",
56 sound SOUND_MUMBLE "Models\\Enemies\\Eyeman\\Sounds\\Mumble.wav",
/*
60 model MODEL_EYEMAN_BODY "Models\\Enemies\\Eyeman\\Debris\\Torso.mdl",
61 model MODEL_EYEMAN_HAND "Models\\Enemies\\Eyeman\\Debris\\Arm.mdl",
62 model MODEL_EYEMAN_LEGS "Models\\Enemies\\Eyeman\\Debris\\Leg.mdl",
*/
functions:
// describe how this enemy killed player
virtual CTString GetPlayerKillDescription(const CTString &strPlayerName, const EDeath &eDeath)
{
CTString str;
if (m_bInAir) {
str.PrintF(TRANSV("A Gnaar bit %s to death"), (const char *) strPlayerName);
} else {
str.PrintF(TRANSV("%s was beaten up by a Gnaar"), (const char *) strPlayerName);
}
return str;
}
void Precache(void) {
CEnemyBase::Precache();
PrecacheSound(SOUND_IDLE );
PrecacheSound(SOUND_SIGHT);
PrecacheSound(SOUND_WOUND);
PrecacheSound(SOUND_BITE );
PrecacheSound(SOUND_PUNCH);
PrecacheSound(SOUND_DEATH);
PrecacheSound(SOUND_MUMBLE);
};
/* Entity info */
void *GetEntityInfo(void) {
if (m_EecChar==EYC_SERGEANT) {
return &eiEyemanBig;
} else {
return &eiEyemanSmall;
}
};
/* Receive damage */
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
{
// eyeman can't harm eyeman
if (!IsOfClass(penInflictor, "Eyeman")) {
CEnemyFly::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
// if died of chainsaw
if (dmtType==DMT_CHAINSAW && GetHealth()<=0) {
// must always blowup
m_fBlowUpAmount = 0;
}
}
};
/* Fill in entity statistics - for AI purposes only */
BOOL FillEntityStatistics(EntityStats *pes)
{
CEnemyBase::FillEntityStatistics(pes);
switch(m_EecChar) {
case EYC_SERGEANT: { pes->es_strName+=" Sergeant"; } break;
case EYC_SOLDIER : { pes->es_strName+=" Soldier"; } break;
}
if (m_bInvisible) {
pes->es_strName+=" Invisible";
}
return TRUE;
}
virtual const CTFileName &GetComputerMessageName(void) const {
static DECLARE_CTFILENAME(fnmSergeant, "Data\\Messages\\Enemies\\EyemanGreen.txt");
static DECLARE_CTFILENAME(fnmSoldier , "Data\\Messages\\Enemies\\EyemanPurple.txt");
switch(m_EecChar) {
default: ASSERT(FALSE);
case EYC_SERGEANT: return fnmSergeant;
case EYC_SOLDIER : return fnmSoldier;
}
};
/* Adjust model shading parameters if needed. */
BOOL AdjustShadingParameters(FLOAT3D &vLightDirection, COLOR &colLight, COLOR &colAmbient)
{
// no shadows for invisibles
if (m_bInvisible) {
colAmbient = C_WHITE;
return FALSE;
} else {
return CEnemyBase::AdjustShadingParameters(vLightDirection, colLight, colAmbient);
}
}
// damage anim
INDEX AnimForDamage(FLOAT fDamage) {
DeactivateMumblingSound();
INDEX iAnim;
if (m_bInAir) {
switch (IRnd()%2) {
case 0: iAnim = EYEMAN_ANIM_MORPHWOUND01; break;
case 1: iAnim = EYEMAN_ANIM_MORPHWOUND02; break;
default: ASSERTALWAYS("Eyeman unknown fly damage");
}
} else {
FLOAT3D vFront;
GetHeadingDirection(0, vFront);
FLOAT fDamageDir = m_vDamage%vFront;
if (Abs(fDamageDir)<=10) {
switch (IRnd()%3) {
case 0: iAnim = EYEMAN_ANIM_WOUND03; break;
case 1: iAnim = EYEMAN_ANIM_WOUND06; break;
case 2: iAnim = EYEMAN_ANIM_WOUND07; break;
}
} else {
if (fDamageDir<0) {
iAnim = EYEMAN_ANIM_FALL01;
} else {
iAnim = EYEMAN_ANIM_FALL02;
}
}
}
StartModelAnim(iAnim, 0);
return iAnim;
};
// death
INDEX AnimForDeath(void) {
DeactivateMumblingSound();
INDEX iAnim;
if (m_bInAir) {
iAnim = EYEMAN_ANIM_MORPHDEATH;
} else {
FLOAT3D vFront;
GetHeadingDirection(0, vFront);
FLOAT fDamageDir = m_vDamage%vFront;
if (fDamageDir<0) {
iAnim = EYEMAN_ANIM_DEATH02;
} else {
iAnim = EYEMAN_ANIM_DEATH01;
}
}
StartModelAnim(iAnim, 0);
return iAnim;
};
FLOAT WaitForDust(FLOAT3D &vStretch) {
if(GetModelObject()->GetAnim()==EYEMAN_ANIM_DEATH01)
{
vStretch=FLOAT3D(1,1,1)*0.75f;
return 0.5f;
}
else if(GetModelObject()->GetAnim()==EYEMAN_ANIM_DEATH02)
{
vStretch=FLOAT3D(1,1,1)*0.75f;
return 0.5f;
}
else if(GetModelObject()->GetAnim()==EYEMAN_ANIM_MORPHDEATH)
{
vStretch=FLOAT3D(1,1,1)*1.0f;
return 0.5f;
}
return -1.0f;
};
void DeathNotify(void) {
ChangeCollisionBoxIndexWhenPossible(EYEMAN_COLLISION_BOX_DEATH);
en_fDensity = 500.0f;
};
// mumbling sounds
void ActivateMumblingSound(void)
{
if (!m_bMumbleSoundPlaying) {
PlaySound(m_soMumble, SOUND_MUMBLE, SOF_3D|SOF_LOOP);
m_bMumbleSoundPlaying = TRUE;
}
}
void DeactivateMumblingSound(void)
{
m_soMumble.Stop();
m_bMumbleSoundPlaying = FALSE;
}
// virtual anim functions
void StandingAnim(void) {
DeactivateMumblingSound();
if (m_bInAir) {
StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART);
} else {
StartModelAnim(EYEMAN_ANIM_STAND, AOF_LOOPING|AOF_NORESTART);
}
};
void WalkingAnim(void) {
ActivateMumblingSound();
if (m_bInAir) {
StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART);
} else {
StartModelAnim(EYEMAN_ANIM_WALK, AOF_LOOPING|AOF_NORESTART);
}
};
void RunningAnim(void) {
ActivateMumblingSound();
if (m_bInAir) {
StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART);
} else {
StartModelAnim(EYEMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART);
}
};
void RotatingAnim(void) {
if (m_bInAir) {
StartModelAnim(EYEMAN_ANIM_MORPHATTACKFLY, AOF_LOOPING|AOF_NORESTART);
} else {
StartModelAnim(EYEMAN_ANIM_RUN, AOF_LOOPING|AOF_NORESTART);
}
};
FLOAT AirToGroundAnim(void) {
StartModelAnim(EYEMAN_ANIM_MORPHUP, 0);
return(GetModelObject()->GetAnimLength(EYEMAN_ANIM_MORPHUP));
};
FLOAT GroundToAirAnim(void) {
StartModelAnim(EYEMAN_ANIM_MORPHDOWN, 0);
return(GetModelObject()->GetAnimLength(EYEMAN_ANIM_MORPHDOWN));
};
void ChangeCollisionToAir() {
ChangeCollisionBoxIndexWhenPossible(EYEMAN_COLLISION_BOX_AIR);
};
void ChangeCollisionToGround() {
ChangeCollisionBoxIndexWhenPossible(EYEMAN_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);
};
/************************************************************
* BLOW UP FUNCTIONS *
************************************************************/
// spawn body parts
/*void BlowUp(void)
{
// get your size
FLOATaabbox3D box;
GetBoundingBox(box);
FLOAT fEntitySize = box.Size().MaxNorm();
FLOAT3D vNormalizedDamage = m_vDamage-m_vDamage*(m_fBlowUpAmount/m_vDamage.Length());
vNormalizedDamage /= Sqrt(vNormalizedDamage.Length());
vNormalizedDamage *= 0.75f;
FLOAT3D vBodySpeed = en_vCurrentTranslationAbsolute-en_vGravityDir*(en_vGravityDir%en_vCurrentTranslationAbsolute);
// spawn debris
Debris_Begin(EIBT_FLESH, DPT_BLOODTRAIL, BET_BLOODSTAIN, fEntitySize, vNormalizedDamage, vBodySpeed, 1.0f, 0.0f);
INDEX iTextureID = TEXTURE_EYEMAN_SOLDIER;
if (m_EecChar==EYC_SERGEANT)
{
iTextureID = TEXTURE_EYEMAN_SERGEANT;
}
Debris_Spawn(this, this, MODEL_EYEMAN_BODY, iTextureID, 0, 0, 0, 0, 0.0f,
FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f));
Debris_Spawn(this, this, MODEL_EYEMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f,
FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f));
Debris_Spawn(this, this, MODEL_EYEMAN_HAND, iTextureID, 0, 0, 0, 0, 0.0f,
FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f));
Debris_Spawn(this, this, MODEL_EYEMAN_LEGS, iTextureID, 0, 0, 0, 0, 0.0f,
FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f));
// hide yourself (must do this after spawning debris)
SwitchToEditorModel();
SetPhysicsFlags(EPF_MODEL_IMMATERIAL);
SetCollisionFlags(ECF_IMMATERIAL);
};*/
/************************************************************
* MOVING FUNCTIONS *
************************************************************/
// check whether may move while attacking
BOOL MayMoveToAttack(void)
{
if (m_bInAir) {
return WouldNotLeaveAttackRadius();
} else {
return CEnemyBase::MayMoveToAttack();
}
}
// must be more relaxed about hitting then usual enemies
BOOL CanHitEnemy(CEntity *penTarget, FLOAT fCosAngle) {
if (IsInPlaneFrustum(penTarget, fCosAngle)) {
return IsVisibleCheckAll(penTarget);
}
return FALSE;
};
procedures:
/************************************************************
* A T T A C K E N E M Y *
************************************************************/
FlyHit(EVoid) : CEnemyFly::FlyHit {
if (CalcDist(m_penEnemy) > BITE_AIR) {
m_fShootTime = _pTimer->CurrentTick() + 0.25f;
return EReturn();
}
StartModelAnim(EYEMAN_ANIM_MORPHATTACK, 0);
StopMoving();
PlaySound(m_soSound, SOUND_BITE, SOF_3D);
// damage enemy
autowait(0.4f);
// damage enemy
if (CalcDist(m_penEnemy) < BITE_AIR) {
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
vDirection.SafeNormalize();
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection);
// spawn blood cloud
ESpawnEffect eSpawnEffect;
eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE;
eSpawnEffect.betType = BET_BLOODEXPLODE;
eSpawnEffect.vStretch = FLOAT3D(1,1,1);
CPlacement3D plOne = GetPlacement();
GetEntityPointRatio(
FLOAT3D(Lerp(-0.2f, +0.2f, FRnd()), Lerp(-0.2f, +0.2f, FRnd()), -1.0f),
plOne.pl_PositionVector);
CEntityPointer penBloodCloud = CreateEntity( plOne, CLASS_BASIC_EFFECT);
penBloodCloud->Initialize( eSpawnEffect);
}
autowait(0.24f);
StandingAnim();
return EReturn();
};
GroundHit(EVoid) : CEnemyFly::GroundHit {
if (CalcDist(m_penEnemy) > HIT_GROUND) {
m_fShootTime = _pTimer->CurrentTick() + 0.25f;
return EReturn();
}
StartModelAnim(EYEMAN_ANIM_ATTACK02, 0);
StopMoving();
// damage enemy
autowait(0.2f);
// damage enemy
if (CalcDist(m_penEnemy) < HIT_GROUND) {
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
vDirection.SafeNormalize();
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection);
PlaySound(m_soSound, SOUND_PUNCH, SOF_3D);
}
autowait(0.3f);
// damage enemy
if (CalcDist(m_penEnemy) < HIT_GROUND) {
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
vDirection.SafeNormalize();
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 3.5f, FLOAT3D(0, 0, 0), vDirection);
PlaySound(m_soSound, SOUND_PUNCH, SOF_3D);
}
autowait(0.4f);
StandingAnim();
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);
if (m_EecChar==EYC_SERGEANT) {
SetHealth(90.0f);
m_fMaxHealth = 90.0f;
// damage/explode properties
m_fBlowUpAmount = 130.0f;
m_fBodyParts = 5;
m_fBlowUpSize = 2.5f;
m_fDamageWounded = 40.0f;
} else {
SetHealth(60.0f);
m_fMaxHealth = 60.0f;
// damage/explode properties
m_fBlowUpAmount = 100.0f;
m_fBodyParts = 5;
m_fBlowUpSize = 2.0f;
m_fDamageWounded = 25.0f;
}
en_fDensity = 2000.0f;
if (m_EeftType == EFT_GROUND_ONLY) {
en_tmMaxHoldBreath = 5.0f;
} else {
en_tmMaxHoldBreath = 30.0f;
}
// set your appearance
SetModel(MODEL_EYEMAN);
if (m_EecChar==EYC_SERGEANT) {
SetModelMainTexture(TEXTURE_EYEMAN_SERGEANT);
GetModelObject()->StretchModel(FLOAT3D(1.3f, 1.3f, 1.3f));
ModelChangeNotify();
m_iScore = 1000;
} else {
m_iScore = 500;
if (m_eeEnv == EYE_LAVA) {
SetModelMainTexture(TEXTURE_EYEMAN_LAVA);
} else {
SetModelMainTexture(TEXTURE_EYEMAN_SOLDIER);
}
GetModelObject()->StretchModel(FLOAT3D(1.0f, 1.0f, 1.0f));
ModelChangeNotify();
}
if (m_bInvisible) {
GetModelObject()->mo_colBlendColor = C_WHITE|0x25;
m_iScore*=2;
}
// setup moving speed
m_fWalkSpeed = FRnd() + 1.5f;
m_aWalkRotateSpeed = FRnd()*10.0f + 500.0f;
if (m_EecChar==EYC_SERGEANT) {
m_fAttackRunSpeed = FRnd()*2.0f + 10.0f;
m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f);
m_fCloseRunSpeed = FRnd()*2.0f + 10.0f;
m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 600.0f);
} else {
m_fAttackRunSpeed = FRnd()*2.0f + 9.0f;
m_aAttackRotateSpeed = AngleDeg(FRnd()*100 + 600.0f);
m_fCloseRunSpeed = FRnd()*2.0f + 9.0f;
m_aCloseRotateSpeed = AngleDeg(FRnd()*100 + 600.0f);
}
// setup attack distances
m_fAttackDistance = 100.0f;
m_fCloseDistance = 3.5f;
m_fStopDistance = 1.5f;
m_fAttackFireTime = 2.0f;
m_fCloseFireTime = 0.5f;
m_fIgnoreRange = 200.0f;
// fly moving properties
m_fFlyWalkSpeed = FRnd()*2.0f + 3.0f;
m_aFlyWalkRotateSpeed = FRnd()*20.0f + 600.0f;
if (m_EecChar==EYC_SERGEANT) {
m_fFlyAttackRunSpeed = FRnd()*2.0f + 9.5f;
m_aFlyAttackRotateSpeed = FRnd()*25 + 350.0f;
m_fFlyCloseRunSpeed = FRnd()*2.0f + 9.5f;
m_aFlyCloseRotateSpeed = FRnd()*50 + 400.0f;
} else {
m_fFlyAttackRunSpeed = FRnd()*2.0f + 9.5f;
m_aFlyAttackRotateSpeed = FRnd()*25 + 300.0f;
m_fFlyCloseRunSpeed = FRnd()*2.0f + 9.5f;
m_aFlyCloseRotateSpeed = FRnd()*50 + 300.0f;
}
m_fGroundToAirSpeed = 2.5f;
m_fAirToGroundSpeed = 2.5f;
m_fAirToGroundMin = 0.1f;
m_fAirToGroundMax = 0.1f;
m_fFlyHeight = 1.0f;
// attack properties - CAN BE SET
m_fFlyAttackDistance = 100.0f;
m_fFlyCloseDistance = 10.0f;
m_fFlyStopDistance = 1.5f;
m_fFlyAttackFireTime = 2.0f;
m_fFlyCloseFireTime = 0.5f;
m_fFlyIgnoreRange = 200.0f;
m_soMumble.Set3DParameters(25.0f, 0.0f, 1.0f, 1.0f);
// continue behavior in base class
jump CEnemyFly::MainLoop();
};
};