mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 23:21:35 +00:00
1807 lines
No EOL
39 KiB
Text
1807 lines
No EOL
39 KiB
Text
/***********************************************************************
|
|
|
|
ai_monster_hunter_berserk.script
|
|
|
|
monster_hunter_berserk
|
|
|
|
***********************************************************************/
|
|
|
|
//Hunter States
|
|
#define BERSERK_STATE_WAIT 0
|
|
#define BERSERK_STATE_BERSERK 1
|
|
#define BERSERK_STATE_NORMAL 2
|
|
#define BERSERK_STATE_BERSERK_START 3
|
|
|
|
//Movement States
|
|
#define HUNTER_MOVE_WALK 0
|
|
#define HUNTER_MOVE_RUN 1
|
|
#define HUNTER_MOVE_CHARGE 2
|
|
|
|
//Leap Variables
|
|
#define BERSERK_LEAP_RANGE_MIN 50
|
|
#define BERSERK_LEAP_RANGE_MAX 10000
|
|
#define BERSERK_LEAP_RATE 1
|
|
#define BERSERK_LEAP_SPEED 900
|
|
#define BERSERK_LEAP_MAXHEIGHT 1000
|
|
|
|
#define MAX_BERSERK_DAMAGE 2000
|
|
|
|
|
|
#define BERSERK_RANGE_ATTACK_RATE 1
|
|
|
|
#define BERSERK_DAMAGE_MULTIPLIER_HELLTIME 30
|
|
#define BERSERK_DAMAGE_MULTIPLIER_NORMAL 0
|
|
|
|
|
|
|
|
|
|
#define HUNTER_BERSERK_HOP_RATE 2
|
|
#define HUNTER_BERSERK_IDEAL_RANGE 256
|
|
#define HUNTER_EVADE_RANGE 200
|
|
#define HUNTER_EVADE_RATE 1
|
|
|
|
|
|
#define HUNTER_BERSERK_DURATION 15
|
|
|
|
//1/5/2005: Decrease normal time
|
|
//#define HUNTER_NORMAL_DURATION 15
|
|
#define HUNTER_NORMAL_DURATION 10
|
|
|
|
#define HUNTER_CHARGE_SPEED 440
|
|
#define HUNTER_CHARGE_RUNPAST_DIST 100
|
|
#define CHARGE_CONTINUE_ANGLE 10
|
|
|
|
|
|
|
|
#define ATTACK_EVADE_LEFT 1
|
|
#define ATTACK_EVADE_RIGHT 2
|
|
#define ATTACK_EVADE_BACK 4
|
|
#define ATTACK_EVADE_BACK_LONG 8
|
|
#define ATTACK_EVADE_BACK_LEFT 16
|
|
#define ATTACK_EVADE_BACK_RIGHT 32
|
|
#define ATTACK_EVADE_FRONT 64
|
|
#define ATTACK_EVADE_FRONT_LEFT 128
|
|
#define ATTACK_EVADE_FRONT_RIGHT 256
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
monster_hunter_berserk
|
|
|
|
***********************************************************************/
|
|
object monster_hunter_berserk : monster_base {
|
|
float nextEvade;
|
|
float nextDodge;
|
|
float nextAttack;
|
|
float nextLeap;
|
|
float nextHop;
|
|
|
|
vector jumpVelocity;
|
|
|
|
float hunterState;
|
|
float stateEndTime;
|
|
float moveState;
|
|
|
|
vector chargeTarget;
|
|
|
|
string range_attack_anim;
|
|
|
|
float leavingBerserkDamage;
|
|
float hitEnemy;
|
|
|
|
float minBerserkHealth;
|
|
|
|
|
|
//Hack Array
|
|
float array0;
|
|
float array1;
|
|
float array2;
|
|
float array3;
|
|
float array4;
|
|
float array5;
|
|
float array6;
|
|
float array7;
|
|
float array8;
|
|
|
|
float GetArrayVal(float index);
|
|
void SetArrayVal(float index, float val);
|
|
|
|
void SetHeartDamage(float damage);
|
|
|
|
|
|
//
|
|
// States
|
|
//
|
|
void state_Begin();
|
|
void state_Idle();
|
|
void state_Dead();
|
|
|
|
|
|
//berserk States
|
|
void state_BeginBerserk();
|
|
void state_Berserk();
|
|
void state_EndBerserk();
|
|
void state_BerserkPain();
|
|
|
|
//Normal States
|
|
void state_BeginNormal();
|
|
void state_EndNormal();
|
|
|
|
//Combat States
|
|
void state_Combat();
|
|
|
|
// attacks
|
|
float check_attacks();
|
|
void do_attack( float attack_flags );
|
|
float combat_berserk();
|
|
float combat_normal();
|
|
void combat_range();
|
|
void combat_leap();
|
|
void combat_melee();
|
|
void combat_melee_berserk();
|
|
|
|
void path_jump();
|
|
|
|
void combat_evade_left();
|
|
void combat_evade_right();
|
|
void combat_evade_back();
|
|
void combat_evade_back_long();
|
|
void combat_evade_back_left();
|
|
void combat_evade_back_right();
|
|
void combat_evade_front();
|
|
void combat_evade_front_left();
|
|
void combat_evade_front_right();
|
|
|
|
void combat_berserk_charge();
|
|
|
|
boolean combat_chase_berserk();
|
|
float combat_evade();
|
|
float combat_hop();
|
|
|
|
void checkDamage();
|
|
|
|
void init();
|
|
void destroy();
|
|
|
|
//A couple of skin changing functions used by the intro cinematic
|
|
void setSkinToBerserk();
|
|
void setSkinToBerserkCinematic();
|
|
void setSkinBerserk();
|
|
void setSkinToNormal();
|
|
void setSkinNormal();
|
|
|
|
// torso anim states
|
|
void Torso_Idle();
|
|
void Torso_Pain();
|
|
void Torso_Death();
|
|
void Torso_MeleeAttack();
|
|
void Torso_RangeAttack();
|
|
void Torso_LeapAttack();
|
|
|
|
void Torso_BerserkBegin();
|
|
void Torso_BerserkEnd();
|
|
void Torso_BerserkRage();
|
|
void Torso_BerserkCharge();
|
|
void Torso_BerserkPain();
|
|
|
|
|
|
// legs anim states
|
|
void Legs_Idle();
|
|
void Legs_Walk();
|
|
void Legs_Run();
|
|
void Legs_Charge();
|
|
void Legs_EvadeLeft();
|
|
void Legs_EvadeRight();
|
|
void Legs_EvadeBack();
|
|
void Legs_EvadeBackLong();
|
|
void Legs_EvadeBackLeft();
|
|
void Legs_EvadeBackRight();
|
|
void Legs_EvadeFront();
|
|
void Legs_EvadeFrontLeft();
|
|
void Legs_EvadeFrontRight();
|
|
void Legs_Slide();
|
|
};
|
|
|
|
|
|
float monster_hunter_berserk::GetArrayVal(float index) {
|
|
if (index == 0) {
|
|
return array0;
|
|
} else if (index == 1) {
|
|
return array1;
|
|
} else if (index == 2) {
|
|
return array2;
|
|
} else if (index == 3) {
|
|
return array3;
|
|
} else if (index == 4) {
|
|
return array4;
|
|
} else if (index == 5) {
|
|
return array5;
|
|
} else if (index == 6) {
|
|
return array6;
|
|
} else if (index == 7) {
|
|
return array7;
|
|
} else if (index == 8) {
|
|
return array8;
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::SetArrayVal(float index, float val) {
|
|
if (index == 0) {
|
|
array0 = val;
|
|
} else if (index == 1) {
|
|
array1 = val;
|
|
} else if (index == 2) {
|
|
array2 = val;
|
|
} else if (index == 3) {
|
|
array3 = val;
|
|
} else if (index == 4) {
|
|
array4 = val;
|
|
} else if (index == 5) {
|
|
array5 = val;
|
|
} else if (index == 6) {
|
|
array6 = val;
|
|
} else if (index == 7) {
|
|
array7 = val;
|
|
} else if (index == 8) {
|
|
array8 = val;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
Torso animation control
|
|
|
|
***********************************************************************/
|
|
|
|
void monster_hunter_berserk::Torso_Idle() {
|
|
idleAnim( ANIMCHANNEL_TORSO, "idle" );
|
|
|
|
eachFrame {
|
|
if ( AI_PAIN ) {
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Pain", 3 );
|
|
}
|
|
waitFrame();
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_Pain() {
|
|
string animname;
|
|
float nextpain;
|
|
float currenttime;
|
|
|
|
animname = getPainAnim();
|
|
playAnim( ANIMCHANNEL_TORSO, animname );
|
|
|
|
nextpain = sys.getTime() + 0.25;
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, 6 ) ) {
|
|
if ( AI_PAIN ) {
|
|
currenttime = sys.getTime();
|
|
if ( currenttime > nextpain ) {
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Pain", 3 );
|
|
}
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "pain" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 6 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_Death() {
|
|
|
|
//sys.print("Torso Death!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
|
|
if (hunterState == BERSERK_STATE_NORMAL) {
|
|
//sys.print("Summon\n");
|
|
|
|
setSkinToBerserk();
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_summon_death" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
} else {
|
|
//sys.print("Already Berserk\n");
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_death" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
}
|
|
|
|
finishAction( "dead" );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_MeleeAttack() {
|
|
if (hunterState == BERSERK_STATE_BERSERK) {
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_hit" );
|
|
} else {
|
|
playAnim( ANIMCHANNEL_TORSO, "melee" );
|
|
}
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "melee_attack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_RangeAttack() {
|
|
string anim;
|
|
|
|
disablePain();
|
|
|
|
allowMovement( false );
|
|
playAnim( ANIMCHANNEL_TORSO, "ranged" );
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
lookAt( getEnemy(), 1 );
|
|
waitFrame();
|
|
}
|
|
|
|
allowMovement( true );
|
|
enablePain();
|
|
|
|
finishAction( "range_attack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
|
|
}
|
|
|
|
|
|
void monster_hunter_berserk::Torso_LeapAttack() {
|
|
overrideAnim( ANIMCHANNEL_LEGS );
|
|
disablePain();
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_leap_start" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 2 ) ) {
|
|
if(leavingBerserkDamage) {
|
|
leavingBerserkDamage = false;
|
|
setState("state_BerserkPain");
|
|
return;
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
setBlendFrames( ANIMCHANNEL_TORSO, 2 );
|
|
attackBegin( "melee_hunter_berserk_ChargeAttack" );
|
|
setLinearVelocity( jumpVelocity );
|
|
|
|
float changedLoop;
|
|
changedLoop = false;
|
|
|
|
playCycle( ANIMCHANNEL_TORSO, "berzerk_leap_loop" );
|
|
do {
|
|
if(leavingBerserkDamage) {
|
|
if(!changedLoop) {
|
|
setBlendFrames( ANIMCHANNEL_TORSO, 4 );
|
|
playCycle( ANIMCHANNEL_TORSO, "berzerk_leap_loop_pain" );
|
|
changedLoop = true;
|
|
}
|
|
attackEnd();
|
|
}
|
|
waitFrame();
|
|
} while( !AI_ONGROUND );
|
|
|
|
attackEnd();
|
|
|
|
if(leavingBerserkDamage) {
|
|
//sys.print("Playing pain landing\n");
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_leap_pain" );
|
|
} else {
|
|
if(hitEnemy) {
|
|
hitEnemy = false;
|
|
//sys.print("playing hit landing\n");
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_leap_hit" );
|
|
} else {
|
|
//sys.print("playing miss landing\n");
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_leap_miss" );
|
|
}
|
|
}
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "leap_attack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_BerserkBegin() {
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_summon" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "berserkbegin" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 6 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_BerserkEnd() {
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_2_norm" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "berserkend" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 6 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_BerserkRage() {
|
|
|
|
finishAction( "beginrage" );
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_rage" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "berserkrage" );
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_BerserkCharge() {
|
|
|
|
idleAnim( ANIMCHANNEL_TORSO, "idle" );
|
|
|
|
eachFrame {
|
|
waitFrame();
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Torso_BerserkPain() {
|
|
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_pain" );
|
|
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "berserkpain" );
|
|
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
Legs animation control
|
|
|
|
***********************************************************************/
|
|
|
|
void monster_hunter_berserk::Legs_Idle() {
|
|
idleAnim( ANIMCHANNEL_LEGS, "idle" );
|
|
|
|
eachFrame {
|
|
if ( moveState == HUNTER_MOVE_CHARGE && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Charge", 4 ); }
|
|
if ( moveState == HUNTER_MOVE_RUN && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Run", 4 ); }
|
|
if ( moveState == HUNTER_MOVE_WALK && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 4 ); }
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_Walk() {
|
|
playCycle( ANIMCHANNEL_LEGS, "walk" );
|
|
|
|
eachFrame {
|
|
if ( moveState == HUNTER_MOVE_CHARGE && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Charge", 4 ); }
|
|
if ( moveState == HUNTER_MOVE_RUN && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Run", 4 ); }
|
|
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); }
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_Run() {
|
|
playCycle( ANIMCHANNEL_LEGS, "berzerk_run" );
|
|
|
|
eachFrame {
|
|
if ( moveState == HUNTER_MOVE_CHARGE && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Charge", 4 ); }
|
|
if ( moveState == HUNTER_MOVE_WALK && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 4 ); }
|
|
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); }
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_Charge() {
|
|
playCycle( ANIMCHANNEL_LEGS, "berzerk_charge" );
|
|
|
|
eachFrame {
|
|
if ( moveState == HUNTER_MOVE_RUN && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Run", 4 ); }
|
|
if ( moveState == HUNTER_MOVE_WALK && AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Walk", 4 ); }
|
|
if ( !AI_FORWARD ) { animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 ); }
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeLeft() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_left" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeRight() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_right" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeBack() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_back" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeBackLong() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_back_192" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeBackLeft() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_backleft" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeBackRight() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_backright" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeFront() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_front" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeFrontLeft() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_frontleft" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_EvadeFrontRight() {
|
|
playAnim( ANIMCHANNEL_LEGS, "evade_frontright" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
|
|
finishAction( "evade" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
void monster_hunter_berserk::Legs_Slide() {
|
|
|
|
playAnim( ANIMCHANNEL_LEGS, "berzerk_miss" );
|
|
|
|
while( !animDone( ANIMCHANNEL_LEGS, 4 ) ) {
|
|
waitFrame();
|
|
}
|
|
finishAction( "legslide" );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 4 );
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
AI
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::init
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::init() {
|
|
|
|
nextHop = 0;
|
|
moveState = HUNTER_MOVE_RUN;
|
|
nextLeap = 0;
|
|
nextAttack = 0;
|
|
|
|
leavingBerserkDamage = false;
|
|
|
|
setState( "state_Begin" );
|
|
}
|
|
|
|
void monster_hunter_berserk::destroy() {
|
|
}
|
|
|
|
|
|
void monster_hunter_berserk::setSkinToBerserk() {
|
|
setSkin("skins/monsters/hunter_berserk/hunter_berserk_toberserk");
|
|
setShaderTime( self );
|
|
}
|
|
|
|
void monster_hunter_berserk::setSkinToBerserkCinematic() {
|
|
setSkin("skins/monsters/hunter_berserk/hunter_berserk_cinematic");
|
|
setShaderTime( self );
|
|
}
|
|
|
|
void monster_hunter_berserk::setSkinBerserk() {
|
|
setSkin("skins/monsters/hunter_berserk/hunter_berserk_enrage");
|
|
}
|
|
|
|
void monster_hunter_berserk::setSkinToNormal() {
|
|
setSkin("skins/monsters/hunter_berserk/hunter_berserk_tonormal");
|
|
setShaderTime( self );
|
|
}
|
|
|
|
void monster_hunter_berserk::setSkinNormal() {
|
|
setSkin("skins/monsters/hunter_berserk/hunter_berserk");
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
States
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::state_Begin
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::state_Begin() {
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 0 );
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 0 );
|
|
monster_begin();
|
|
|
|
setState( "state_Idle" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::state_Idle
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::state_Idle() {
|
|
|
|
hunterState = BERSERK_STATE_WAIT;
|
|
|
|
wait_for_enemy();
|
|
|
|
|
|
nextAttack = 0;
|
|
nextEvade = RandomTime( HUNTER_EVADE_RATE );
|
|
nextDodge = 0;
|
|
|
|
//Bouncy Monster - Tests the random evade selection
|
|
/*while(1) {
|
|
combat_evade();
|
|
waitFrame();
|
|
}*/
|
|
|
|
setState( "state_Berserk" );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_base::state_Dead
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::state_Dead() {
|
|
|
|
|
|
//Todo: Probably need to warp to a point for the cutscene
|
|
//I am dead so for now just stop moving
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Idle", 8 );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkPain", 8 );
|
|
waitAction( "berserkpain" );
|
|
|
|
remove();
|
|
}
|
|
|
|
|
|
//berserk States
|
|
void monster_hunter_berserk::state_BeginBerserk() {
|
|
hunterState = BERSERK_STATE_BERSERK_START;
|
|
|
|
|
|
setSkinToBerserk();
|
|
|
|
//Play an animation when he goes into berserk mode
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkBegin", 4 );
|
|
setWaitState("berserkbegin");
|
|
while(getWaitState() == "berserkbegin") {
|
|
checkDamage();
|
|
waitFrame();
|
|
}
|
|
|
|
setState("state_Berserk");
|
|
}
|
|
|
|
void monster_hunter_berserk::state_Berserk() {
|
|
|
|
hunterState = BERSERK_STATE_BERSERK;
|
|
stateEndTime = sys.getTime() + HUNTER_BERSERK_DURATION;
|
|
|
|
minBerserkHealth = getHealth() - MAX_BERSERK_DAMAGE;
|
|
//sys.print("Min Berserk Health " + minBerserkHealth + "\n");
|
|
|
|
//Hunter is invulnerable while in berserk
|
|
//Use damage group scales to set invulnerability
|
|
setDamageGroupScaleAll(0);
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_HELLTIME);
|
|
|
|
startEmitter("heartemitter", "heart1", "hunter_bezerk_heart_burn.prt");
|
|
|
|
avoidObstacles(0);
|
|
|
|
setSkinBerserk();
|
|
setState( "state_Combat" );
|
|
}
|
|
|
|
void monster_hunter_berserk::state_EndBerserk() {
|
|
|
|
setSkinToNormal();
|
|
|
|
|
|
|
|
//1/5/2005: The hunter is now invulnerable in normal mode
|
|
//setDamageGroupScaleAll(1);
|
|
setDamageGroupScaleAll(0);
|
|
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_NORMAL);
|
|
stopEmitter("heartemitter");
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkEnd", 4 );
|
|
waitAction( "berserkend" );
|
|
|
|
avoidObstacles(1);
|
|
|
|
setSkinNormal();
|
|
|
|
setState( "state_BeginNormal");
|
|
}
|
|
|
|
void monster_hunter_berserk::state_BerserkPain() {
|
|
|
|
|
|
if(AI_FORWARD) {
|
|
//He was moving forward so blend in a slide animation to the legs
|
|
animState( ANIMCHANNEL_LEGS, "Legs_Slide", 4 );
|
|
}
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkPain", 4 );
|
|
waitAction( "berserkpain" );
|
|
|
|
stopMove();
|
|
|
|
setState( "state_EndBerserk");
|
|
|
|
}
|
|
|
|
//Normal States
|
|
void monster_hunter_berserk::state_BeginNormal() {
|
|
hunterState = BERSERK_STATE_NORMAL;
|
|
stateEndTime = sys.getTime() + HUNTER_NORMAL_DURATION;
|
|
|
|
//The end of berserk will play any appropriate animations
|
|
|
|
stopMove();
|
|
|
|
//Turn on damage while in normal mode
|
|
//Turn damage back on using the damage scale
|
|
setDamageGroupScaleAll(0);
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_NORMAL);
|
|
|
|
stopEmitter("heartemitter");
|
|
|
|
setState( "state_Combat" );
|
|
}
|
|
|
|
void monster_hunter_berserk::state_EndNormal() {
|
|
|
|
//The beginning of berserk will play the animations
|
|
setState( "state_BeginBerserk");
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_base::state_Combat
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::state_Combat() {
|
|
float attack_flags;
|
|
float currentTime;
|
|
|
|
|
|
eachFrame {
|
|
currentTime = sys.getTime();
|
|
|
|
//Check for damage group settings and shader settings
|
|
checkDamage();
|
|
|
|
if(leavingBerserkDamage) {
|
|
leavingBerserkDamage = false;
|
|
setState( "state_EndBerserk" );
|
|
}
|
|
|
|
//Are we ready to switch out of our current state
|
|
if(currentTime > stateEndTime) {
|
|
if (hunterState == BERSERK_STATE_BERSERK) {
|
|
setState( "state_EndBerserk" );
|
|
} else if (hunterState == BERSERK_STATE_NORMAL) {
|
|
setState( "state_EndNormal" );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//This section is the same as the state_combat in the monster_base
|
|
faceEnemy();
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
lookAtEnemy( 1 );
|
|
}
|
|
|
|
if ( sys.influenceActive() ) {
|
|
waitFrame();
|
|
continue;
|
|
}
|
|
|
|
if ( AI_ENEMY_DEAD ) {
|
|
enemy_dead();
|
|
}
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
if (hunterState == BERSERK_STATE_BERSERK) {
|
|
if(combat_berserk()) {
|
|
continue;
|
|
}
|
|
} else if (hunterState == BERSERK_STATE_NORMAL) {
|
|
// Do some hopping around occasionally
|
|
if ( currentTime >= nextHop ) {
|
|
|
|
if(combat_hop()) {
|
|
waitFrame();
|
|
}
|
|
nextHop = DelayTime( HUNTER_BERSERK_HOP_RATE );
|
|
}
|
|
|
|
if(combat_normal()) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*if ( !enemyPositionValid() ) {
|
|
locateEnemy();
|
|
}*/
|
|
|
|
|
|
|
|
waitFrame();
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
attacks
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_berserk
|
|
|
|
berserk combat is a single sequnce of actions than are not interrupted
|
|
- If in melee range then melee attack
|
|
- Otherwise charge
|
|
|
|
=====================
|
|
*/
|
|
float monster_hunter_berserk::combat_berserk() {
|
|
|
|
/*float canMelee;
|
|
|
|
faceEnemy();
|
|
|
|
canMelee = testMeleeAttack();
|
|
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
|
|
if ( canMelee ) {
|
|
combat_melee();
|
|
return 1;
|
|
}
|
|
combat_berserk_charge();
|
|
}
|
|
return 0;*/
|
|
|
|
float attack_flags;
|
|
|
|
attack_flags = check_attacks();
|
|
if ( attack_flags ) {
|
|
do_attack( attack_flags );
|
|
return 1;
|
|
}
|
|
|
|
if ( !combat_chase_berserk() ) {
|
|
locateEnemy();
|
|
if ( !combat_chase_berserk() ) {
|
|
combat_lost();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_chase_berserk
|
|
=====================
|
|
*/
|
|
boolean monster_hunter_berserk::combat_chase_berserk() {
|
|
float delta;
|
|
boolean do_run;
|
|
float range;
|
|
float attack_flags;
|
|
|
|
moveToEnemy();
|
|
if ( AI_MOVE_DONE ) {
|
|
return false;
|
|
}
|
|
|
|
waitFrame();
|
|
if ( AI_MOVE_DONE ) {
|
|
attack_flags = check_attacks();
|
|
if ( attack_flags ) {
|
|
do_attack( attack_flags );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
while( !AI_MOVE_DONE && !AI_DEST_UNREACHABLE ) {
|
|
|
|
checkDamage();
|
|
if(leavingBerserkDamage) {
|
|
//Go immediately into a berserk pain state
|
|
leavingBerserkDamage = false;
|
|
setState("state_BerserkPain");
|
|
}
|
|
|
|
if ( AI_ENEMY_DEAD ) {
|
|
enemy_dead();
|
|
}
|
|
|
|
if ( sys.influenceActive() ) {
|
|
return true;
|
|
}
|
|
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
lookAtEnemy( 1 );
|
|
}
|
|
|
|
attack_flags = check_attacks();
|
|
if ( attack_flags ) {
|
|
do_attack( attack_flags );
|
|
return true;
|
|
}
|
|
|
|
if ( check_blocked() ) {
|
|
return true;
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
attacks
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::do_attack
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::do_attack( float attack_flags ) {
|
|
|
|
/*if ( attack_flags & ATTACK_DODGE_LEFT ) {
|
|
combat_dodge_left();
|
|
} else if ( attack_flags & ATTACK_DODGE_RIGHT ) {
|
|
combat_dodge_right();
|
|
} else*/ if ( attack_flags & ATTACK_MELEE ) {
|
|
if(hunterState == BERSERK_STATE_NORMAL) {
|
|
combat_melee();
|
|
} else {
|
|
combat_melee_berserk();
|
|
}
|
|
} else if ( attack_flags & ATTACK_LEAP ) {
|
|
combat_leap();
|
|
} else if ( attack_flags & ATTACK_MISSILE ) {
|
|
combat_range();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::check_attacks
|
|
=====================
|
|
*/
|
|
float monster_hunter_berserk::check_attacks() {
|
|
float range;
|
|
float currentTime;
|
|
float canMelee;
|
|
float attack_flags;
|
|
float checkLeap;
|
|
vector vel;
|
|
float t;
|
|
string anim;
|
|
vector jumpTarget;
|
|
|
|
attack_flags = 0;
|
|
|
|
canMelee = testMeleeAttack();
|
|
currentTime = sys.getTime();
|
|
if ( !canMelee ) {
|
|
//Check for a dodge attack...He won't dodge in berserk mode
|
|
if ( hunterState == BERSERK_STATE_NORMAL && AI_PAIN && ( currentTime >= nextDodge ) ) {
|
|
if ( testAnimMove( "evade_left" ) ) {
|
|
attack_flags |= ATTACK_DODGE_LEFT;
|
|
}
|
|
if ( testAnimMove( "evade_right" ) ) {
|
|
attack_flags |= ATTACK_DODGE_RIGHT;
|
|
|
|
// if we can dodge either direction, pick one
|
|
if ( attack_flags & ATTACK_DODGE_LEFT ) {
|
|
if ( sys.random( 100 ) < 50 ) {
|
|
attack_flags &= ~ATTACK_DODGE_RIGHT;
|
|
} else {
|
|
attack_flags &= ~ATTACK_DODGE_LEFT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( canMelee ) {
|
|
attack_flags |= ATTACK_MELEE;
|
|
}
|
|
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
range = enemyRange();
|
|
//Only leap in berserk mode
|
|
if ( hunterState == BERSERK_STATE_BERSERK && ( range >= BERSERK_LEAP_RANGE_MIN ) && ( range < BERSERK_LEAP_RANGE_MAX ) && ( currentTime >= nextLeap ) ) {
|
|
if ( canHitEnemy() ) {
|
|
t = animLength( ANIMCHANNEL_TORSO, "berzerk_leap_start" );
|
|
jumpTarget = predictEnemyPos( t );
|
|
jumpVelocity = getJumpVelocity( jumpTarget, BERSERK_LEAP_SPEED, BERSERK_LEAP_MAXHEIGHT );
|
|
if ( jumpVelocity != '0 0 0' ) {
|
|
attack_flags |= ATTACK_LEAP;
|
|
} else {
|
|
nextLeap = DelayTime( BERSERK_LEAP_RATE );
|
|
}
|
|
}
|
|
}
|
|
|
|
//Only missle attack while in normal mode
|
|
if ( hunterState == BERSERK_STATE_NORMAL && (!canReachEnemy() || ( currentTime >= nextAttack )) ) {
|
|
|
|
anim = chooseAnim( ANIMCHANNEL_TORSO, "ranged" );
|
|
if ( testAnimMoveTowardEnemy( anim ) ) {
|
|
if ( canHitEnemyFromAnim( anim ) ) {
|
|
range_attack_anim = anim;
|
|
attack_flags |= ATTACK_MISSILE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return attack_flags;
|
|
}
|
|
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_normal
|
|
=====================
|
|
*/
|
|
float monster_hunter_berserk::combat_normal() {
|
|
|
|
float currentTime;
|
|
float range;
|
|
float canMelee;
|
|
|
|
|
|
|
|
currentTime = sys.getTime();
|
|
|
|
canMelee = testMeleeAttack();
|
|
if ( AI_ENEMY_IN_FOV ) {
|
|
if ( canMelee ) {
|
|
combat_melee();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
range = enemyRange();
|
|
if(range <= HUNTER_EVADE_RANGE) {
|
|
|
|
//The player is too close...I'm sooooo scared
|
|
if(combat_evade() == 1) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
if ( currentTime >= nextAttack ) {
|
|
if ( canHitEnemy() ) {
|
|
combat_range();
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
float monster_hunter_berserk::combat_evade() {
|
|
|
|
float selection;
|
|
float selectedEvade;
|
|
float evadeCount;
|
|
|
|
selectedEvade = 0;
|
|
evadeCount = 0;
|
|
|
|
//Which directions can we evade
|
|
if ( testAnimMove( "evade_left" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_right" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_back" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK);
|
|
evadeCount++;
|
|
}
|
|
//if ( testAnimMove( "evade_back_192" ) ) {
|
|
//SetArrayVal(evadeCount, ATTACK_EVADE_BACK_LONG);
|
|
//evadeCount++;
|
|
//}
|
|
if ( testAnimMove( "evade_backleft" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_backright" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
|
|
// Check front evades as a last resort
|
|
if ( evadeCount == 0 ) {
|
|
if ( testAnimMove( "evade_frontleft" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_FRONT_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_frontright" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_FRONT_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
}
|
|
|
|
if(evadeCount > 0) {
|
|
|
|
selection = sys.randomInt( evadeCount );
|
|
selectedEvade = GetArrayVal(selection);
|
|
|
|
if(selectedEvade == ATTACK_EVADE_LEFT) {
|
|
combat_evade_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_RIGHT) {
|
|
combat_evade_right();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_BACK) {
|
|
combat_evade_back();
|
|
return 1;
|
|
}
|
|
//if(selectedEvade == ATTACK_EVADE_BACK_LONG) {
|
|
//combat_evade_back_long();
|
|
//return 1;
|
|
//}
|
|
if(selectedEvade == ATTACK_EVADE_BACK_LEFT) {
|
|
combat_evade_back_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_BACK_RIGHT) {
|
|
combat_evade_back_right();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_FRONT_LEFT) {
|
|
combat_evade_front_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_FRONT_RIGHT) {
|
|
combat_evade_front_right();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_hop
|
|
=====================
|
|
*/
|
|
float monster_hunter_berserk::combat_hop() {
|
|
float selection;
|
|
float selectedEvade;
|
|
float evadeCount;
|
|
float range;
|
|
|
|
selectedEvade = 0;
|
|
evadeCount = 0;
|
|
|
|
// Always allow a side hop
|
|
if ( testAnimMove( "evade_left" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_right" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
|
|
// We should try and keep a steady range from the enemy
|
|
range = enemyRange();
|
|
|
|
if ( range > HUNTER_BERSERK_IDEAL_RANGE ) {
|
|
if ( testAnimMove( "evade_front" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_FRONT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_frontleft" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_FRONT_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_frontright" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_FRONT_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
} else {
|
|
if ( testAnimMove( "evade_back" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_backleft" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK_LEFT);
|
|
evadeCount++;
|
|
}
|
|
if ( testAnimMove( "evade_backright" ) ) {
|
|
SetArrayVal(evadeCount, ATTACK_EVADE_BACK_RIGHT);
|
|
evadeCount++;
|
|
}
|
|
}
|
|
|
|
if(evadeCount > 0) {
|
|
|
|
selection = sys.randomInt( evadeCount );
|
|
selectedEvade = GetArrayVal(selection);
|
|
|
|
if(selectedEvade == ATTACK_EVADE_LEFT) {
|
|
combat_evade_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_RIGHT) {
|
|
combat_evade_right();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_FRONT) {
|
|
combat_evade_front();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_FRONT_LEFT) {
|
|
combat_evade_front_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_FRONT_RIGHT) {
|
|
combat_evade_front_right();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_BACK) {
|
|
combat_evade_back();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_BACK_LEFT) {
|
|
combat_evade_back_left();
|
|
return 1;
|
|
}
|
|
if(selectedEvade == ATTACK_EVADE_BACK_RIGHT) {
|
|
combat_evade_back_right();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_range
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_range() {
|
|
faceEnemy();
|
|
// stopMove();
|
|
animState( ANIMCHANNEL_TORSO, "Torso_RangeAttack", 4 );
|
|
waitAction( "range_attack" );
|
|
|
|
// don't attack for a bit
|
|
nextAttack = DelayTime( BERSERK_RANGE_ATTACK_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_leap
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_leap() {
|
|
stopMove();
|
|
turnToPos( getOrigin() + jumpVelocity );
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_LeapAttack", 4 );
|
|
|
|
//While he is leaping check for damage to we know the player has knocked him out of berserk mode
|
|
setWaitState("leap_attack");
|
|
while(getWaitState() == "leap_attack") {
|
|
|
|
//Check for a hit so the torso will know which land animation to play
|
|
if(AI_HIT_ENEMY) {
|
|
hitEnemy = true;
|
|
}
|
|
checkDamage();
|
|
waitFrame();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_berserk_charge
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_berserk_charge() {
|
|
|
|
vector chargeBegin;
|
|
|
|
vector dir;
|
|
float dist;
|
|
float endtime;
|
|
|
|
float animD;
|
|
float animT;
|
|
entity curEnemy;
|
|
|
|
disablePain();
|
|
moveState = HUNTER_MOVE_CHARGE;
|
|
avoidObstacles(0);
|
|
|
|
float canMelee;
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkRage", 4);
|
|
waitAction("beginrage");
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
|
|
checkDamage();
|
|
|
|
//While raging make sure the player is not to close
|
|
faceEnemy();
|
|
canMelee = testMeleeAttack();
|
|
if ( canMelee ) {
|
|
combat_melee();
|
|
return;
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
|
|
|
|
attackBegin( "melee_hunter_berserk_ChargeAttack" );
|
|
animState( ANIMCHANNEL_TORSO, "Torso_BerserkCharge", 4);
|
|
|
|
|
|
|
|
|
|
curEnemy = getEnemy();
|
|
|
|
stopMove();
|
|
|
|
while(1) {
|
|
|
|
//sys.print("Beginning Charge...\n");
|
|
|
|
turnToPos( curEnemy.getOrigin() );
|
|
|
|
chargeBegin = getOrigin();
|
|
chargeTarget = curEnemy.getOrigin();
|
|
|
|
dir = chargeTarget - chargeBegin;
|
|
|
|
moveToPosition(chargeTarget);
|
|
|
|
animD = animDistance( ANIMCHANNEL_LEGS, "berzerk_charge" );
|
|
animT = animLength( ANIMCHANNEL_LEGS, "berzerk_charge" );
|
|
|
|
dist = sys.vecLength(dir) + 256;
|
|
endtime = sys.getTime() + (dist / animD * animT);
|
|
while( !AI_HIT_ENEMY && !AI_MOVE_DONE && !AI_BLOCKED && ( sys.getTime() < endtime ) ) {
|
|
//while( !AI_HIT_ENEMY && !AI_MOVE_DONE && !AI_BLOCKED) {
|
|
|
|
kickObstacles(getObstacle(), 200);
|
|
|
|
checkDamage();
|
|
waitFrame();
|
|
}
|
|
|
|
if(!AI_HIT_ENEMY) {
|
|
|
|
//sys.print("Missed the enemy\n");
|
|
|
|
//Check to see if the enemy is still right in front of me
|
|
vector newDir;
|
|
float ang;
|
|
|
|
newDir = curEnemy.getOrigin() - chargeBegin;
|
|
ang = sys.DotProduct(sys.vecNormalize(dir), sys.vecNormalize(newDir));
|
|
ang = sys.acos(ang);
|
|
if(ang > CHARGE_CONTINUE_ANGLE || ang < -CHARGE_CONTINUE_ANGLE) {
|
|
|
|
//sys.print("Sliding...\n");
|
|
attackEnd();
|
|
|
|
//The player got out of the way so lets get pissed and end the charge
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_miss" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
checkDamage();
|
|
waitFrame();
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( AI_BLOCKED ) {
|
|
faceEnemy();
|
|
waitFrame();
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
//sys.print("Hit the enemy\n");
|
|
//We hit the player...do a quick melee attack
|
|
playAnim( ANIMCHANNEL_TORSO, "berzerk_hit" );
|
|
while( !animDone( ANIMCHANNEL_TORSO, 4 ) ) {
|
|
checkDamage();
|
|
waitFrame();
|
|
}
|
|
stopMove();
|
|
attackEnd();
|
|
break;
|
|
}
|
|
|
|
waitFrame();
|
|
}
|
|
|
|
avoidObstacles(1);
|
|
moveState = HUNTER_MOVE_RUN;
|
|
enablePain();
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_Idle", 4);
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_melee
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_melee() {
|
|
lookAt( getEnemy(), 100 );
|
|
faceEnemy();
|
|
animState( ANIMCHANNEL_TORSO, "Torso_MeleeAttack", 5 );
|
|
waitAction( "melee_attack" );
|
|
lookAt( getEnemy(), 1 );
|
|
stopMove();
|
|
combat_evade();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_melee_berserk
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_melee_berserk() {
|
|
lookAt( getEnemy(), 100 );
|
|
faceEnemy();
|
|
animState( ANIMCHANNEL_TORSO, "Torso_MeleeAttack", 5 );
|
|
setWaitState("melee_attack");
|
|
while(getWaitState() == "melee_attack") {
|
|
checkDamage();
|
|
if(leavingBerserkDamage) {
|
|
//Go immediately into a berserk pain state
|
|
leavingBerserkDamage = false;
|
|
setState("state_BerserkPain");
|
|
}
|
|
waitFrame();
|
|
}
|
|
lookAt( getEnemy(), 1 );
|
|
stopMove();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_left
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_left() {
|
|
//sys.print("Evade Left\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeLeft", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_right
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_right() {
|
|
//sys.print("Evade Right\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeRight", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_back
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_back() {
|
|
//sys.print("Evade Back\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeBack", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_back_long
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_back_long() {
|
|
//sys.print("Evade Back Long\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeBackLong", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_back_left
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_back_left() {
|
|
//sys.print("Evade Back Left\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeBackLeft", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_back_right
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_back_right() {
|
|
//sys.print("Evade Back Right\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeBackRight", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_front
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_front() {
|
|
//sys.print("Evade Front\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeFront", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_front_left
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_front_left() {
|
|
//sys.print("Evade Front Left\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeFrontLeft", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::combat_evade_front_right
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::combat_evade_front_right() {
|
|
//sys.print("Evade Front Right\n");
|
|
faceEnemy();
|
|
stopMove();
|
|
animState( ANIMCHANNEL_LEGS, "Legs_EvadeFrontRight", 2 );
|
|
waitAction( "evade" );
|
|
nextEvade = DelayTime( HUNTER_EVADE_RATE );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
monster_hunter_berserk::path_jump
|
|
=====================
|
|
*/
|
|
void monster_hunter_berserk::path_jump() {
|
|
entity target;
|
|
vector dir;
|
|
vector jumpTarget;
|
|
|
|
// walk to the path entity first
|
|
path_corner();
|
|
|
|
if ( checkForEnemy( true ) ) {
|
|
return;
|
|
}
|
|
|
|
target = current_path.randomTarget( current_path.getName() );
|
|
if ( !target ) {
|
|
sys.error( "missing target for '" + current_path.getName() + "'" );
|
|
}
|
|
jumpTarget = target.getOrigin();
|
|
if ( !current_path.getKey( "up" ) ) {
|
|
jumpVelocity = getJumpVelocity( jumpTarget, BERSERK_LEAP_SPEED, 1024 );
|
|
if ( jumpVelocity == '0 0 0' ) {
|
|
sys.error( "Monster '" + getName() + "' couldn't make jump from '" + current_path.getName() + "' to '" + target.getName() + "'" );
|
|
}
|
|
} else {
|
|
float forward = current_path.getFloatKey( "forward" );
|
|
if ( forward <= 0 ) {
|
|
sys.error( "Invalid forward velocity on path_jump entity '" + current_path.getName() + "'\n" );
|
|
}
|
|
dir = jumpTarget - getOrigin();
|
|
dir_z = 0;
|
|
dir = sys.vecNormalize( dir );
|
|
dir = dir * forward;
|
|
dir_z = current_path.getFloatKey( "up" );
|
|
jumpVelocity = dir;
|
|
}
|
|
|
|
stopMove();
|
|
turnToPos( jumpTarget );
|
|
while( !facingIdeal() ) {
|
|
if ( checkForEnemy( true ) ) {
|
|
return;
|
|
}
|
|
waitFrame();
|
|
}
|
|
|
|
animState( ANIMCHANNEL_TORSO, "Torso_LeapAttack", 4 );
|
|
waitAction( "leap_attack" );
|
|
|
|
stopMove();
|
|
}
|
|
|
|
|
|
|
|
void monster_hunter_berserk::checkDamage() {
|
|
|
|
if (hunterState == BERSERK_STATE_BERSERK || hunterState == BERSERK_STATE_BERSERK_START) {
|
|
|
|
//Helltime Damage will knock the hunter out of berserk mode
|
|
//Need to check the scale to make sure the code has executed and the player is able to do the serious damage
|
|
//before knocking the monster out of berserk
|
|
float scale;
|
|
scale = getDamageGroupScale("heart");
|
|
|
|
if(hunterState == BERSERK_STATE_BERSERK && AI_DAMAGE && $player1.isPowerupActive(HELLTIME) && scale == BERSERK_DAMAGE_MULTIPLIER_HELLTIME) {
|
|
AI_DAMAGE = false;
|
|
if(!leavingBerserkDamage) {
|
|
//sys.print("!!!!!!!!!!!!!!!!!!!! Damage While In Berserk !!!!!!!!!!!!!!!!!\n");
|
|
leavingBerserkDamage = true;
|
|
//SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_NORMAL);
|
|
|
|
}
|
|
}
|
|
|
|
/*if($player1.isPowerupActive(HELLTIME)) {
|
|
//if(!leavingBerserkDamage) {
|
|
//You can only damage him while he is in berserk when you are in hell time
|
|
if(hunterState == BERSERK_STATE_BERSERK) {
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_HELLTIME);
|
|
}
|
|
startEmitter("heartemitter", "heart1", "hunter_bezerk_heart_burn.prt");
|
|
//}
|
|
|
|
|
|
} else {
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_NORMAL);
|
|
stopEmitter("heartemitter");
|
|
}*/
|
|
} /*else {
|
|
SetHeartDamage(BERSERK_DAMAGE_MULTIPLIER_NORMAL);
|
|
stopEmitter("heartemitter");
|
|
}*/
|
|
|
|
if(AI_DAMAGE) {
|
|
AI_DAMAGE = false;
|
|
}
|
|
}
|
|
|
|
void monster_hunter_berserk::SetHeartDamage(float damage) {
|
|
//sys.print("Heart Damage Scale = " + damage + "\n");
|
|
setDamageGroupScale("heart", damage);
|
|
|
|
if(damage == BERSERK_DAMAGE_MULTIPLIER_HELLTIME) {
|
|
setDamageCap(minBerserkHealth);
|
|
} else {
|
|
setDamageCap(-1);
|
|
}
|
|
|
|
} |