mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-25 11:45:53 +01:00
744 lines
25 KiB
C++
744 lines
25 KiB
C++
330
|
|
%{
|
|
#include "Entities/StdH/StdH.h"
|
|
#include "Models/Enemies/Cyborg/Cyborg.h"
|
|
%}
|
|
|
|
|
|
uses "Entities/EnemyFly";
|
|
uses "Entities/Projectile";
|
|
uses "Entities/CyborgBike";
|
|
|
|
|
|
enum CyborgType {
|
|
0 CBT_GROUND "Ground",
|
|
1 CBT_FLY "Fly",
|
|
2 CBT_FLYGROUND "Fly-Ground",
|
|
};
|
|
|
|
|
|
%{
|
|
// info structure
|
|
static EntityInfo eiCyborgStand = {
|
|
EIBT_ROBOT, 200.0f,
|
|
0.0f, 1.55f, 0.0f,
|
|
0.0f, 1.0f, 0.0f,
|
|
};
|
|
static EntityInfo eiCyborgFly = {
|
|
EIBT_ROBOT, 1500.0f,
|
|
0.0f, 0.0f, 0.0f,
|
|
0.0f, 0.0f, 0.0f,
|
|
};
|
|
|
|
#define FIRE_BIKE FLOAT3D(-0.35f, 0.1f, -1.2f)
|
|
#define FIRE_LASER FLOAT3D(-0.5f, 1.7f, -0.75f)
|
|
|
|
#define IGNORE_RANGE 400.0f
|
|
|
|
#define BIKE_ATTACHMENT FLOAT3D(0, 0, -0.271f)
|
|
%}
|
|
|
|
|
|
class CCyborg : CEnemyBase {
|
|
name "Cyborg";
|
|
thumbnail "Thumbnails\\Cyborg.tbn";
|
|
|
|
properties:
|
|
1 enum CyborgType m_EctType "Type" 'T' = CBT_GROUND, // type
|
|
2 INDEX m_iCloseHit = 0, // close hit hand (left or right)
|
|
3 INDEX m_iFireLaserCount = 0, // fire laser binary divider
|
|
4 INDEX m_ctBombsToDrop = 0, // counter of bombs to drop in fly-over
|
|
10 FLOAT m_tmLastBombDropped = -1.0f, // when last bomb was dropped
|
|
5 FLOAT m_fFlyAboveEnemy = 0.0f, // fly above enemy height
|
|
6 FLOAT m_fFlySpeed = 0.0f,
|
|
7 FLOAT m_aFlyRotateSpeed = 0.0f,
|
|
8 FLOAT m_fFallStartTime = 0.0f,
|
|
9 BOOL m_bBombing "Bombing" 'B' = FALSE, // enable bombing
|
|
|
|
{
|
|
CEntity *penBullet; // bullet
|
|
}
|
|
|
|
components:
|
|
0 class CLASS_BASE "Classes\\EnemyFly.ecl",
|
|
1 class CLASS_BULLET "Classes\\Bullet.ecl",
|
|
2 class CLASS_CYBORG_BIKE "Classes\\CyborgBike.ecl",
|
|
3 class CLASS_PROJECTILE "Classes\\Projectile.ecl",
|
|
4 class CLASS_BASIC_EFFECT "Classes\\BasicEffect.ecl",
|
|
|
|
10 model MODEL_CYBORG "Models\\Enemies\\Cyborg\\Cyborg.mdl",
|
|
11 model MODEL_ASS "Models\\Enemies\\Cyborg\\AssHole.mdl",
|
|
12 model MODEL_TORSO "Models\\Enemies\\Cyborg\\Torso.mdl",
|
|
13 model MODEL_HEAD "Models\\Enemies\\Cyborg\\Head.mdl",
|
|
14 model MODEL_RIGHT_UPPER_ARM "Models\\Enemies\\Cyborg\\RightUpperArm.mdl",
|
|
15 model MODEL_RIGHT_LOWER_ARM "Models\\Enemies\\Cyborg\\RightLowerArm.mdl",
|
|
16 model MODEL_LEFT_UPPER_ARM "Models\\Enemies\\Cyborg\\LeftUpperArm.mdl",
|
|
17 model MODEL_LEFT_LOWER_ARM "Models\\Enemies\\Cyborg\\LeftLowerArm.mdl",
|
|
18 model MODEL_RIGHT_UPPER_LEG "Models\\Enemies\\Cyborg\\RightUpperLeg.mdl",
|
|
19 model MODEL_RIGHT_LOWER_LEG "Models\\Enemies\\Cyborg\\RightLowerLeg.mdl",
|
|
20 model MODEL_LEFT_UPPER_LEG "Models\\Enemies\\Cyborg\\LeftUpperLeg.mdl",
|
|
21 model MODEL_LEFT_LOWER_LEG "Models\\Enemies\\Cyborg\\LeftLowerLeg.mdl",
|
|
22 model MODEL_FOOT "Models\\Enemies\\Cyborg\\Foot.mdl",
|
|
23 model MODEL_BIKE "Models\\Enemies\\Cyborg\\Bike.mdl",
|
|
30 texture TEXTURE_CYBORG "Models\\Enemies\\Cyborg\\Cyborg.tex",
|
|
31 texture TEXTURE_BIKE "Models\\Enemies\\Cyborg\\Bike.tex",
|
|
|
|
// ************** SOUNDS **************
|
|
50 sound SOUND_IDLE "Models\\Enemies\\Cyborg\\Sounds\\Idle.wav",
|
|
51 sound SOUND_SIGHT "Models\\Enemies\\Cyborg\\Sounds\\Sight.wav",
|
|
52 sound SOUND_WOUND "Models\\Enemies\\Cyborg\\Sounds\\Wound.wav",
|
|
53 sound SOUND_FIRE "Models\\Enemies\\Cyborg\\Sounds\\Fire.wav",
|
|
54 sound SOUND_KICK "Models\\Enemies\\Cyborg\\Sounds\\Kick.wav",
|
|
55 sound SOUND_DEATH "Models\\Enemies\\Cyborg\\Sounds\\Death.wav",
|
|
|
|
// ************** REFLECTIONS **************
|
|
202 texture TEX_REFL_LIGHTMETAL01 "Models\\ReflectionTextures\\LightMetal01.tex",
|
|
|
|
// ************** SPECULAR **************
|
|
211 texture TEX_SPEC_MEDIUM "Models\\SpecularTextures\\Medium.tex",
|
|
212 texture TEX_SPEC_STRONG "Models\\SpecularTextures\\Strong.tex",
|
|
|
|
functions:
|
|
/* Entity info */
|
|
void *GetEntityInfo(void) {
|
|
if (m_EctType!=CBT_GROUND) {
|
|
return &eiCyborgFly;
|
|
} else {
|
|
return &eiCyborgStand;
|
|
}
|
|
};
|
|
|
|
/* Receive damage */
|
|
void ReceiveDamage(CEntity *penInflictor, enum DamageType dmtType,
|
|
FLOAT fDamageAmmount, const FLOAT3D &vHitPoint, const FLOAT3D &vDirection)
|
|
{
|
|
// cyborg can't harm cyborg
|
|
if (!IsOfClass(penInflictor, "Cyborg")) {
|
|
CEnemyBase::ReceiveDamage(penInflictor, dmtType, fDamageAmmount, vHitPoint, vDirection);
|
|
}
|
|
};
|
|
|
|
|
|
// damage anim
|
|
INDEX AnimForDamage(FLOAT fDamage) {
|
|
INDEX iAnim;
|
|
switch (IRnd()%4) {
|
|
case 0: iAnim = CYBORG_ANIM_WOUND01; break;
|
|
case 1: iAnim = CYBORG_ANIM_WOUND02; break;
|
|
case 2: iAnim = CYBORG_ANIM_WOUND03; break;
|
|
case 3: iAnim = CYBORG_ANIM_WOUND04; break;
|
|
default: ASSERTALWAYS("Cyborg unknown damage");
|
|
}
|
|
StartModelAnim(iAnim, 0);
|
|
return iAnim;
|
|
};
|
|
|
|
// death
|
|
INDEX AnimForDeath(void) {
|
|
INDEX iAnim;
|
|
switch (IRnd()%2) {
|
|
case 0: iAnim = CYBORG_ANIM_DEATH01; break;
|
|
case 1: iAnim = CYBORG_ANIM_DEATH02; break;
|
|
default: ASSERTALWAYS("Cyborg unknown death");
|
|
}
|
|
StartModelAnim(iAnim, 0);
|
|
return iAnim;
|
|
};
|
|
|
|
|
|
// virtual anim functions
|
|
void StandingAnim(void) {
|
|
if (m_EctType!=CBT_GROUND) {
|
|
StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_WAIT01, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void WalkingAnim(void) {
|
|
if (m_EctType!=CBT_GROUND) {
|
|
StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void RunningAnim(void) {
|
|
if (m_EctType!=CBT_GROUND) {
|
|
StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void RotatingAnim(void) {
|
|
if (m_EctType!=CBT_GROUND) {
|
|
StartModelAnim(CYBORG_ANIM_BIKEREST, AOF_LOOPING|AOF_NORESTART);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_WALK01, AOF_LOOPING|AOF_NORESTART);
|
|
}
|
|
};
|
|
void ChangeCollisionToAir() {
|
|
ChangeCollisionBoxIndexWhenPossible(CYBORG_COLLISION_BOX_BIKE);
|
|
};
|
|
void ChangeCollisionToGround() {
|
|
ChangeCollisionBoxIndexWhenPossible(CYBORG_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();
|
|
|
|
// spawn debris
|
|
Debris_Begin(EIBT_ROBOT, DPR_SMOKETRAIL, BET_EXPLOSIONSTAIN, fEntitySize, m_vDamage*0.3f,
|
|
en_vCurrentTranslationAbsolute, 1.0f, 0.0f);
|
|
|
|
Debris_Spawn(this, this, MODEL_ASS, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_TORSO, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_STRONG, 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_HEAD, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_RIGHT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_RIGHT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_LEFT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_LEFT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_RIGHT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_RIGHT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_LEFT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_LEFT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 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_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0,
|
|
0, 0.0f, FLOAT3D(FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f, FRnd()*0.6f+0.2f));
|
|
|
|
// spawn explosion
|
|
CPlacement3D plExplosion = GetPlacement();
|
|
CEntityPointer penExplosion = CreateEntity(plExplosion, CLASS_BASIC_EFFECT);
|
|
ESpawnEffect eSpawnEffect;
|
|
eSpawnEffect.colMuliplier = C_WHITE|CT_OPAQUE;
|
|
eSpawnEffect.betType = BET_BOMB;
|
|
FLOAT fSize = fEntitySize*0.3f;
|
|
eSpawnEffect.vStretch = FLOAT3D(fSize,fSize,fSize);
|
|
penExplosion->Initialize(eSpawnEffect);
|
|
|
|
// hide yourself (must do this after spawning debris)
|
|
SwitchToEditorModel();
|
|
SetPhysicsFlags(EPF_MODEL_IMMATERIAL);
|
|
SetCollisionFlags(ECF_IMMATERIAL);
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* MOVING FUNCTIONS *
|
|
************************************************************/
|
|
// fly desired position for attack
|
|
virtual void FlyDesiredPosition(FLOAT3D &vPos) {
|
|
FLOAT fDist = (m_penEnemy->GetPlacement().pl_PositionVector -
|
|
GetPlacement().pl_PositionVector).Length();
|
|
vPos = m_penEnemy->GetPlacement().pl_PositionVector;
|
|
vPos += FLOAT3D(m_penEnemy->en_mRotation(1, 2),
|
|
m_penEnemy->en_mRotation(2, 2),
|
|
m_penEnemy->en_mRotation(3, 2)) * m_fFlyAboveEnemy;
|
|
};
|
|
|
|
// fly move in direction
|
|
void FlyInDirection() {
|
|
/* !!!!
|
|
RotateToAngle();
|
|
|
|
// determine translation speed
|
|
FLOAT3D vTranslation = (m_vDesiredPosition - GetPlacement().pl_PositionVector) * !en_mRotation;
|
|
vTranslation(1) = 0.0f;
|
|
vTranslation.Normalize();
|
|
vTranslation *= m_fMoveSpeed;
|
|
|
|
// start moving
|
|
SetDesiredTranslation(vTranslation);
|
|
*/
|
|
};
|
|
|
|
// fly entity to desired position
|
|
void FlyToPosition() {
|
|
|
|
/* !!!!
|
|
CalcAngleFromPosition();
|
|
FlyInDirection();
|
|
*/
|
|
};
|
|
|
|
|
|
|
|
procedures:
|
|
/************************************************************
|
|
* CLASS INTERNAL *
|
|
************************************************************/
|
|
// fall to floor
|
|
FallToFloor(EVoid) {
|
|
// spawn bike
|
|
CPlacement3D plBike = GetPlacement();
|
|
FLOATmatrix3D mRotation;
|
|
MakeRotationMatrixFast(mRotation, GetPlacement().pl_OrientationAngle);
|
|
plBike.pl_PositionVector += BIKE_ATTACHMENT*mRotation;
|
|
|
|
ECyborgBike ecb;
|
|
ecb.fSpeed = m_fFlySpeed*2.0f;
|
|
CEntityPointer penBike = CreateEntity(plBike, CLASS_CYBORG_BIKE);
|
|
penBike->Initialize(ecb);
|
|
|
|
// drop to floor
|
|
m_EctType = CBT_GROUND;
|
|
SetPhysicsFlags(EPF_MODEL_WALKING);
|
|
ChangeCollisionToGround();
|
|
|
|
// remove bike
|
|
RemoveAttachmentFromModel(*GetModelObject(), CYBORG_ATTACHMENT_BIKE);
|
|
|
|
// anim
|
|
if (IRnd()&1) {
|
|
StartModelAnim(CYBORG_ANIM_FALL01, 0);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_FALL02, 0);
|
|
}
|
|
|
|
// wait to touch brush or time limit
|
|
m_fFallStartTime = _pTimer->CurrentTick();
|
|
wait (10.0f) {
|
|
on (EBegin) : { resume; }
|
|
// brush touched
|
|
on (ETouch et) : {
|
|
if (et.penOther->GetRenderType()&RT_BRUSH) {
|
|
StopMoving();
|
|
stop;
|
|
}
|
|
resume;
|
|
}
|
|
on (EDamage) : { resume; }
|
|
on (EWatch) : { resume; }
|
|
on (ETimer) : { stop; }
|
|
}
|
|
|
|
// wait fall anim
|
|
if (_pTimer->CurrentTick() < m_fFallStartTime+1.5f) {
|
|
wait(m_fFallStartTime+1.5f - _pTimer->CurrentTick()) {
|
|
on (EBegin) : { resume; }
|
|
on (EDamage) : { resume; }
|
|
on (EWatch) : { resume; }
|
|
on (ETimer) : { stop; }
|
|
}
|
|
}
|
|
return EReturn();
|
|
};
|
|
|
|
// get up
|
|
GetUp(EVoid) {
|
|
// get up
|
|
StartModelAnim(CYBORG_ANIM_GETUP, 0);
|
|
wait(GetModelObject()->GetAnimLength(CYBORG_ANIM_GETUP)) {
|
|
on (EBegin) : { resume; }
|
|
on (EDamage) : { resume; }
|
|
on (EWatch) : { resume; }
|
|
on (ETimer) : { stop; }
|
|
}
|
|
return EReturn();
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* PROCEDURES WHEN NO ANY SPECIAL ACTION *
|
|
************************************************************/
|
|
// Move to destination
|
|
/* !!!!
|
|
MoveToDestination(EVoid) : CEnemyBase::MoveToDestination {
|
|
// animation
|
|
if (m_bRunToMarker) {
|
|
RunningAnim();
|
|
} else {
|
|
WalkingAnim();
|
|
}
|
|
// fly to position
|
|
if (m_EctType!=CBT_GROUND) {
|
|
m_fMoveFrequency = 0.25f;
|
|
m_fMovePrecision = m_fMoveSpeed*m_fMoveFrequency*2.0f;
|
|
while ((m_vDesiredPosition-GetPlacement().pl_PositionVector).Length()>m_fMovePrecision) {
|
|
wait (0.25f) {
|
|
on (EBegin) : { FlyToPosition(); }
|
|
on (ETimer) : { stop; }
|
|
}
|
|
}
|
|
return EReturn();
|
|
// move to position
|
|
} else {
|
|
jump CEnemyBase::MoveToDestination();
|
|
}
|
|
};
|
|
*/
|
|
|
|
|
|
|
|
/************************************************************
|
|
* PROCEDURES WHEN HARMED *
|
|
************************************************************/
|
|
// Play wound animation and falling body part
|
|
BeWounded(EDamage eDamage) : CEnemyBase::BeWounded {
|
|
// damage only on ground
|
|
if (m_EctType==CBT_GROUND) {
|
|
jump CEnemyBase::BeWounded(eDamage);
|
|
// fall on ground
|
|
} else if (m_EctType==CBT_FLYGROUND && GetHealth()<=60.0f) {
|
|
SetHealth(60.0f);
|
|
m_fMaxHealth = 60.0f;
|
|
autocall FallToFloor() EReturn;
|
|
autocall GetUp() EReturn;
|
|
SendEvent(ERestartAttack());
|
|
}
|
|
return EReturn();
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* A T T A C K E N E M Y *
|
|
************************************************************/
|
|
AttackEnemy(EVoid) : CEnemyBase::AttackEnemy {
|
|
// air attack
|
|
if (m_EctType!=CBT_GROUND) {
|
|
jump FlyAttackEnemy();
|
|
// ground attack
|
|
} else if (TRUE) {
|
|
jump CEnemyBase::AttackEnemy();
|
|
}
|
|
};
|
|
|
|
// fly attack enemy
|
|
FlyAttackEnemy(EVoid) {
|
|
// initial preparation
|
|
autocall CEnemyBase::InitializeAttack() EReturn;
|
|
|
|
// while you have some enemy
|
|
while (m_penEnemy != NULL) {
|
|
// to far cease attack
|
|
if (CalcDist(m_penEnemy) > IGNORE_RANGE) {
|
|
SetTargetNone();
|
|
}
|
|
|
|
if (m_penEnemy != NULL) {
|
|
// attack run
|
|
if (SeeEntity(m_penEnemy, CosFast(90.0f))) {
|
|
autocall FlyAttackRun() EReturn;
|
|
// go away and rotate
|
|
} else if (TRUE) {
|
|
autocall GoAwayAndRotate() EReturn;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop attack
|
|
autocall CEnemyBase::StopAttack() EReturn;
|
|
|
|
// return to Move() procedure
|
|
return EBegin();
|
|
};
|
|
|
|
// fly attack run
|
|
FlyAttackRun(EVoid) {
|
|
m_iFireLaserCount = 0;
|
|
if (m_bBombing) {
|
|
m_ctBombsToDrop = 3;
|
|
}
|
|
while (SeeEntity(m_penEnemy, CosFast(90.0f))) {
|
|
m_fMoveFrequency = 0.1f;
|
|
wait(m_fMoveFrequency) {
|
|
on (EBegin) : {
|
|
if (IsInFrustum(m_penEnemy, CosFast(55.0f))) {
|
|
// fire laser
|
|
if (m_iFireLaserCount==0) {
|
|
ShootProjectile(PRT_CYBORG_LASER, FIRE_BIKE, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
}
|
|
if (m_iFireLaserCount++ == 2) {
|
|
m_iFireLaserCount = 0;
|
|
}
|
|
}
|
|
|
|
// if a bomb may be dropped
|
|
if (m_ctBombsToDrop>0 && _pTimer->CurrentTick()>=m_tmLastBombDropped+0.3f) {
|
|
// calculate where it would hit
|
|
FLOAT fV = en_vCurrentTranslationAbsolute.Length();
|
|
FLOAT fD = CalcDist(m_penEnemy);
|
|
FLOAT fDP = CalcPlaneDist(m_penEnemy);
|
|
FLOAT fH = Sqrt(fD*fD-fDP*fDP);
|
|
FLOAT fHitD = fDP-fV*Sqrt(2*fH/en_fGravityA);
|
|
|
|
// if close enough
|
|
if( Abs(fHitD)<10.0f) {
|
|
// drop it
|
|
CPlacement3D pl(FLOAT3D(FRnd()*2.0f-1.0f, -1.0f, 0.0f), ANGLE3D(0, 0, 0)); ;
|
|
pl.RelativeToAbsoluteSmooth(GetPlacement());
|
|
CEntityPointer penProjectile = CreateEntity(pl, CLASS_PROJECTILE);
|
|
ELaunchProjectile eLaunch;
|
|
eLaunch.penLauncher = this;
|
|
eLaunch.prtType = PRT_CYBORG_BOMB;
|
|
eLaunch.fSpeed = fV;
|
|
penProjectile->Initialize(eLaunch);
|
|
m_ctBombsToDrop--;
|
|
m_tmLastBombDropped = _pTimer->CurrentTick();
|
|
}
|
|
}
|
|
|
|
// inside attack radius
|
|
if (MayMoveToAttack()) {
|
|
m_fMoveSpeed = m_fFlySpeed;
|
|
m_aRotateSpeed = m_aFlyRotateSpeed;
|
|
FlyDesiredPosition(m_vDesiredPosition);
|
|
FlyToPosition();
|
|
RunningAnim();
|
|
// outside attack radius
|
|
} else {
|
|
StopMoving();
|
|
StandingAnim();
|
|
}
|
|
}
|
|
on (ETimer) : { stop; }
|
|
}
|
|
}
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
GoAwayAndRotate(EVoid) {
|
|
// go away
|
|
SetDesiredTranslation(FLOAT3D(0, 1.25f, -m_fFlySpeed));
|
|
StopRotating();
|
|
autowait(1.0f);
|
|
|
|
// rotate side
|
|
if (IRnd()&1) {
|
|
SetDesiredRotation(ANGLE3D( 100.0f, 0, 0));
|
|
} else {
|
|
SetDesiredRotation(ANGLE3D(-100.0f, 0, 0));
|
|
}
|
|
|
|
// rotate to enemy
|
|
SetDesiredTranslation(FLOAT3D(0, 0, -m_fFlySpeed));
|
|
while (!SeeEntityInPlane(m_penEnemy, CosFast(5.0f))) {
|
|
autowait(_pTimer->TickQuantum);
|
|
}
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
Fire(EVoid) : CEnemyBase::Fire {
|
|
// to fire
|
|
StartModelAnim(CYBORG_ANIM_TOFIRE, 0);
|
|
m_fLockOnEnemyTime = GetModelObject()->GetAnimLength(CYBORG_ANIM_TOFIRE) + FRnd()/3;
|
|
autocall CEnemyBase::LockOnEnemy() EReturn;
|
|
|
|
StartModelAnim(CYBORG_ANIM_FIRE02, 0);
|
|
ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
|
|
m_fLockOnEnemyTime = 0.5f;
|
|
autocall CEnemyBase::LockOnEnemy() EReturn;
|
|
StartModelAnim(CYBORG_ANIM_FIRE02, 0);
|
|
ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
|
|
m_fLockOnEnemyTime = 0.5f;
|
|
autocall CEnemyBase::LockOnEnemy() EReturn;
|
|
StartModelAnim(CYBORG_ANIM_FIRE02, 0);
|
|
ShootProjectile(PRT_CYBORG_LASER, FIRE_LASER, ANGLE3D(0, 0, 0));
|
|
PlaySound(m_soSound, SOUND_FIRE, SOF_3D);
|
|
autowait(0.1f + FRnd()/3);
|
|
|
|
m_fShootTime = _pTimer->CurrentTick() + m_fAttackFireTime*(1.0f + FRnd()/3.0f);
|
|
|
|
// from fire
|
|
StartModelAnim(CYBORG_ANIM_FROMFIRE, 0);
|
|
autowait(GetModelObject()->GetAnimLength(CYBORG_ANIM_FROMFIRE));
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
Hit(EVoid) : CEnemyBase::Hit {
|
|
// animation
|
|
m_iCloseHit = IRnd()&1;
|
|
if (m_iCloseHit==0) {
|
|
StartModelAnim(CYBORG_ANIM_ATTACKCLOSE01, 0);
|
|
} else {
|
|
StartModelAnim(CYBORG_ANIM_ATTACKCLOSE02, 0);
|
|
}
|
|
|
|
autowait(0.9f);
|
|
PlaySound(m_soSound, SOUND_KICK, SOF_3D);
|
|
if (CalcDist(m_penEnemy)<m_fCloseDistance) {
|
|
// damage enemy
|
|
FLOAT3D vDirection = m_penEnemy->GetPlacement().pl_PositionVector-GetPlacement().pl_PositionVector;
|
|
vDirection.Normalize();
|
|
InflictDirectDamage(m_penEnemy, this, DMT_CLOSERANGE, 15.0f, FLOAT3D(0, 0, 0), vDirection);
|
|
// push target left/right
|
|
FLOAT3D vSpeed;
|
|
if (m_iCloseHit==0) {
|
|
GetHeadingDirection(AngleDeg(90.0f), vSpeed);
|
|
} else {
|
|
GetHeadingDirection(AngleDeg(-90.0f), vSpeed);
|
|
}
|
|
vSpeed = vSpeed * 5.0f;
|
|
KickEntity(m_penEnemy, vSpeed);
|
|
}
|
|
|
|
return EReturn();
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* D E A T H *
|
|
************************************************************/
|
|
Death(EVoid) : CEnemyBase::Death {
|
|
StopMoving(); // stop moving
|
|
DeathSound(); // death sound
|
|
|
|
// death notify (usually change collision box and change body density)
|
|
ChangeCollisionBoxIndexWhenPossible(CYBORG_COLLISION_BOX_DEATH);
|
|
|
|
// set physic flags
|
|
SetPhysicsFlags(EPF_MODEL_CORPSE);
|
|
SetCollisionFlags(ECF_CORPSE);
|
|
|
|
if (m_EctType==CBT_FLY || m_EctType==CBT_FLYGROUND) {
|
|
autocall FallToFloor() EReturn;
|
|
} else if (TRUE) {
|
|
// start death anim
|
|
INDEX iAnim = AnimForDeath();
|
|
autowait(GetModelObject()->GetAnimLength(iAnim));
|
|
}
|
|
|
|
// death twist
|
|
StartModelAnim(CYBORG_ANIM_DEATHTWIST, AOF_LOOPING);
|
|
autowait(FRnd()*5.0f + 1.0f);
|
|
StartModelAnim(CYBORG_ANIM_DEATHREST, 0);
|
|
|
|
// explode
|
|
SetHealth(-45.0f);
|
|
ReceiveDamage(NULL, DMT_EXPLOSION, 10.0f, FLOAT3D(0,0,0), FLOAT3D(0,1,0));
|
|
|
|
return EEnd();
|
|
};
|
|
|
|
|
|
|
|
/************************************************************
|
|
* M A I N *
|
|
************************************************************/
|
|
Main(EVoid) {
|
|
// declare yourself as a model
|
|
InitAsModel();
|
|
SetCollisionFlags(ECF_MODEL);
|
|
SetFlags(GetFlags()|ENF_ALIVE);
|
|
en_fDensity = 5000.0f;
|
|
|
|
// set your appearance
|
|
SetModel(MODEL_CYBORG);
|
|
SetModelMainTexture(TEXTURE_CYBORG);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_ASS,
|
|
MODEL_ASS, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_TORSO,
|
|
MODEL_TORSO, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_STRONG, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_HEAD,
|
|
MODEL_HEAD, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTUPPERARM,
|
|
MODEL_RIGHT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTLOWERARM,
|
|
MODEL_RIGHT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTUPPERARM,
|
|
MODEL_LEFT_UPPER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTLOWERARM,
|
|
MODEL_LEFT_LOWER_ARM, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTUPPERLEG,
|
|
MODEL_RIGHT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_RIGHTLOWERLEG,
|
|
MODEL_RIGHT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTUPPERLEG,
|
|
MODEL_LEFT_UPPER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_LEFTLOWERLEG,
|
|
MODEL_LEFT_LOWER_LEG, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_FOOTRIGHT,
|
|
MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_FOOTLEFT,
|
|
MODEL_FOOT, TEXTURE_CYBORG, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
if (m_EctType!=CBT_GROUND) {
|
|
AddAttachmentToModel(this, *GetModelObject(), CYBORG_ATTACHMENT_BIKE,
|
|
MODEL_BIKE, TEXTURE_BIKE, TEX_REFL_LIGHTMETAL01, TEX_SPEC_MEDIUM, 0);
|
|
// fly in air
|
|
SetHealth(90.0f);
|
|
m_fMaxHealth = 90.0f;
|
|
ChangeCollisionToAir();
|
|
SetPhysicsFlags(EPF_MODEL_FLYING);
|
|
m_iScore = 1000;
|
|
} else {
|
|
// walk on ground
|
|
SetHealth(60.0f);
|
|
m_fMaxHealth = 60.0f;
|
|
ChangeCollisionToGround();
|
|
SetPhysicsFlags(EPF_MODEL_WALKING);
|
|
m_iScore = 500;
|
|
}
|
|
StandingAnim();
|
|
// setup moving speed
|
|
m_fWalkSpeed = FRnd()*3.0f + 6.0f;
|
|
m_aWalkRotateSpeed = FRnd()*20.0f + 700.0f;
|
|
m_fAttackRunSpeed = m_fWalkSpeed;
|
|
m_aAttackRotateSpeed = m_aWalkRotateSpeed;
|
|
m_fCloseRunSpeed = m_fWalkSpeed;
|
|
m_aCloseRotateSpeed = m_aWalkRotateSpeed;
|
|
m_fWalkSpeed/=3;
|
|
|
|
// setup attack distances
|
|
m_fAttackDistance = 100.0f;
|
|
m_fCloseDistance = 2.5f;
|
|
m_fStopDistance = 1.5;
|
|
m_fAttackFireTime = 3.0f;
|
|
m_fCloseFireTime = 2.0f;
|
|
m_fIgnoreRange = 200.0f;
|
|
// fly moving properties
|
|
m_fFlyAboveEnemy = 10.0f+FRnd()*1.0f;
|
|
m_fFlySpeed = FRnd()*5.0f + 20.0f;
|
|
m_aFlyRotateSpeed = FRnd()*25.0f + 100.0f;
|
|
// damage/explode properties
|
|
m_fBlowUpAmount = 90.0f;
|
|
m_fDamageWounded = 50.0f;
|
|
|
|
// continue behavior in base class
|
|
jump CEnemyBase::MainLoop();
|
|
};
|
|
};
|