mirror of
https://github.com/InfinityLoader/IL-GSC.git
synced 2025-06-07 17:17:50 -05:00
502 lines
13 KiB
Plaintext
502 lines
13 KiB
Plaintext
#include maps\_utility;
|
||
#include animscripts\zombie_utility;
|
||
#include animscripts\zombie_SetPoseMovement;
|
||
#include animscripts\Combat_Utility;
|
||
#include animscripts\Debug;
|
||
#include common_scripts\utility;
|
||
#using_animtree ("generic_human");
|
||
MeleeCombat()
|
||
{
|
||
self endon( "end_melee" );
|
||
self endon("killanimscript");
|
||
self melee_notify_wrapper();
|
||
assert( CanMeleeAnyRange() );
|
||
if(IsDefined(level.allow_ai_vs_ai_melee ))
|
||
{
|
||
doingAIMelee = (isAI( self.enemy ) && self.enemy.type == "human");
|
||
}
|
||
else
|
||
{
|
||
doingAIMelee = false;
|
||
}
|
||
if ( doingAiMelee )
|
||
{
|
||
assert( animscripts\zombie_utility::okToMelee( self.enemy ) );
|
||
animscripts\zombie_utility::IAmMeleeing( self.enemy );
|
||
AiVsAiMeleeCombat();
|
||
animscripts\zombie_utility::ImNotMeleeing( self.enemy );
|
||
scriptChange();
|
||
return;
|
||
}
|
||
realMelee = true;
|
||
if ( animscripts\zombie_utility::okToMelee(self.enemy) )
|
||
{
|
||
animscripts\zombie_utility::IAmMeleeing(self.enemy);
|
||
}
|
||
else
|
||
{
|
||
realMelee = false;
|
||
}
|
||
self thread EyesAtEnemy();
|
||
self OrientMode("face enemy");
|
||
MeleeDebugPrint("Melee begin");
|
||
self AnimMode( "zonly_physics" );
|
||
resetGiveUpTime();
|
||
for ( ;; )
|
||
{
|
||
if ( IsDefined(self.marked_for_death) )
|
||
{
|
||
return;
|
||
}
|
||
MeleeDebugPrint("Melee main loop" + RandomInt(100));
|
||
if ( !realMelee && animscripts\zombie_utility::okToMelee(self.enemy) )
|
||
{
|
||
realMelee = true;
|
||
animscripts\zombie_utility::IAmMeleeing(self.enemy);
|
||
}
|
||
self thread EyesAtEnemy();
|
||
self animscripts\battleChatter_ai::evaluateMeleeEvent();
|
||
if( IsDefined( self.enemy ) )
|
||
{
|
||
angles = VectorToAngles( self.enemy.origin - self.origin );
|
||
self OrientMode( "face angle", angles[1] );
|
||
}
|
||
if( !IsDefined(level.zombietron_mode) )
|
||
{
|
||
switch( self.animname )
|
||
{
|
||
case "zombie":
|
||
self PlaySound( "zmb_vocals_zombie_attack" );
|
||
break;
|
||
case "quad_zombie":
|
||
self PlaySound( "zmb_vocals_quad_attack" );
|
||
break;
|
||
case "boss_zombie":
|
||
self PlaySound( "zmb_vocals_boss_attack" );
|
||
break;
|
||
case "napalm_zombie":
|
||
self PlaySound( "zmb_vocals_napalm_attack" );
|
||
break;
|
||
case "sonic_zombie":
|
||
self PlaySound( "zmb_vocals_sonic_attack" );
|
||
break;
|
||
}
|
||
}
|
||
if ( is_true( self.noChangeDuringMelee ) )
|
||
{
|
||
self.safeToChangeScript = false;
|
||
}
|
||
zombie_attack = pick_zombie_melee_anim( self );
|
||
if ( isDefined( self.melee_anim_func ) )
|
||
{
|
||
self thread [[ self.melee_anim_func ]]( zombie_attack );
|
||
}
|
||
self SetFlaggedAnimKnobAllRestart("meleeanim", zombie_attack, %body, 1, .2, 1);
|
||
while ( 1 )
|
||
{
|
||
self waittill("meleeanim", note);
|
||
if ( note == "end" )
|
||
{
|
||
break;
|
||
}
|
||
else if ( note == "fire" )
|
||
{
|
||
if ( !IsDefined( self.enemy ) )
|
||
{
|
||
break;
|
||
}
|
||
oldhealth = self.enemy.health;
|
||
self melee();
|
||
if ( self.enemy.health < oldhealth )
|
||
{
|
||
resetGiveUpTime();
|
||
}
|
||
else
|
||
{
|
||
if ( isDefined( self.melee_miss_func ) )
|
||
{
|
||
self [[ self.melee_miss_func ]]();
|
||
}
|
||
else if ( isDefined( level.melee_miss_func ) )
|
||
{
|
||
self [[ level.melee_miss_func ]]();
|
||
}
|
||
}
|
||
}
|
||
else if ( note == "stop" )
|
||
{
|
||
if ( !CanContinueToMelee() )
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
self OrientMode("face default");
|
||
if ( is_true( self.noChangeDuringMelee ) )
|
||
{
|
||
if ( isDefined( self.enemy ) )
|
||
{
|
||
dist_sq = DistanceSquared( self.origin, self.enemy.origin );
|
||
if ( dist_sq > self.meleeAttackDist * self.meleeAttackDist )
|
||
{
|
||
self.safeToChangeScript = true;
|
||
wait_network_frame();
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
self.safeToChangeScript = true;
|
||
wait_network_frame();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (realMelee)
|
||
{
|
||
animscripts\zombie_utility::ImNotMeleeing(self.enemy);
|
||
}
|
||
self AnimMode("none");
|
||
self thread animscripts\zombie_combat::main();
|
||
self notify ("stop EyesAtEnemy");
|
||
self notify ("stop_melee_debug_print");
|
||
scriptChange();
|
||
}
|
||
resetGiveUpTime()
|
||
{
|
||
if ( DistanceSquared( self.origin, self.enemy.origin ) > anim.chargeRangeSq )
|
||
{
|
||
self.giveUpOnMeleeTime = GetTime() + randomintrange( 2700, 3300 );
|
||
}
|
||
else
|
||
{
|
||
self.giveUpOnMeleeTime = GetTime() + randomintrange( 1700, 2300 );
|
||
}
|
||
}
|
||
MeleeDebugPrint(text)
|
||
{
|
||
return;
|
||
self.meleedebugprint = text;
|
||
self thread meleeDebugPrintThreadWrapper();
|
||
}
|
||
meleeDebugPrintThreadWrapper()
|
||
{
|
||
if ( !IsDefined(self.meleedebugthread) )
|
||
{
|
||
self.meleedebugthread = true;
|
||
self meleeDebugPrintThread();
|
||
self.meleedebugthread = undefined;
|
||
}
|
||
}
|
||
meleeDebugPrintThread()
|
||
{
|
||
self endon("death");
|
||
self endon("killanimscript");
|
||
self endon("stop_melee_debug_print");
|
||
while(1)
|
||
{
|
||
Print3d(self.origin + (0,0,60), self.meleedebugprint, (1,1,1), 1, .1);
|
||
wait .05;
|
||
}
|
||
}
|
||
debug_melee_on_actor()
|
||
{
|
||
return false;
|
||
}
|
||
debug_melee( msg )
|
||
{
|
||
if ( !debug_melee_on_actor() )
|
||
{
|
||
return;
|
||
}
|
||
PrintLn( msg );
|
||
}
|
||
debug_melee_line( start, end, color, duration )
|
||
{
|
||
}
|
||
CanContinueToMelee()
|
||
{
|
||
return CanMeleeInternal( "already started" );
|
||
}
|
||
CanMeleeAnyRange()
|
||
{
|
||
return CanMeleeInternal( "any range" );
|
||
}
|
||
CanMeleeDesperate()
|
||
{
|
||
return CanMeleeInternal( "long range" );
|
||
}
|
||
CanMelee()
|
||
{
|
||
return CanMeleeInternal( "normal" );
|
||
}
|
||
CanMeleeInternal( state )
|
||
{
|
||
if ( !IsSentient( self.enemy ) )
|
||
{
|
||
debug_melee( "Not doing melee - Does not have a valid target." );
|
||
return false;
|
||
}
|
||
if (!IsAlive(self.enemy))
|
||
{
|
||
return false;
|
||
}
|
||
if ( IsDefined( self.disableMelee ) )
|
||
{
|
||
assert( self.disableMelee );
|
||
debug_melee( "Not doing melee - Melee is disabled, self.disableMelee is set to true." );
|
||
return false;
|
||
}
|
||
yaw = abs(getYawToEnemy());
|
||
if ( (yaw > 60 && state != "already started") || yaw > 110 )
|
||
{
|
||
debug_melee( "Not doing melee - Not facing the enemy." );
|
||
return false;
|
||
}
|
||
enemyPoint = self.enemy GetOrigin();
|
||
vecToEnemy = enemyPoint - self.origin;
|
||
self.enemyDistanceSq = lengthSquared( vecToEnemy );
|
||
nearest_enemy_sqrd_dist = self GetClosestEnemySqDist();
|
||
epsilon = 0.1;
|
||
if( IsDefined( nearest_enemy_sqrd_dist ) && ( nearest_enemy_sqrd_dist - epsilon > self.enemyDistanceSq ) )
|
||
{
|
||
debug_melee( "Not doing melee - Entity " + self getEntityNumber() + " can't melee entity " + self.enemy getEntityNumber() + " at distSq " + self.enemyDistanceSq + " because there is a closer enemy at distSq " + nearest_enemy_sqrd_dist + "." );
|
||
return false;
|
||
}
|
||
if(IsDefined(level.allow_ai_vs_ai_melee ))
|
||
{
|
||
doingAIMelee = (isAI( self.enemy ) && self.enemy.type == "human");
|
||
}
|
||
else
|
||
{
|
||
doingAIMelee = false;
|
||
}
|
||
if ( doingAIMelee )
|
||
{
|
||
if ( !animscripts\zombie_utility::okToMelee(self.enemy) )
|
||
{
|
||
debug_melee( "Not doing melee - Enemy is already being meleed." );
|
||
return false;
|
||
}
|
||
if ( IsDefined( self.magic_bullet_shield ) && self.magic_bullet_shield && IsDefined( self.enemy.magic_bullet_shield ) && self.enemy.magic_bullet_shield )
|
||
{
|
||
debug_melee( "Not doing melee - Enemy has magic bullet shield." );
|
||
return false;
|
||
}
|
||
if ( !isMeleePathClear( vecToEnemy, enemyPoint ) )
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( IsDefined( self.enemy.magic_bullet_shield ) && self.enemy.magic_bullet_shield )
|
||
{
|
||
if ( !( self is_banzai() ) )
|
||
{
|
||
debug_melee( "Not doing melee - Enemy has magic bullet shield." );
|
||
return false;
|
||
}
|
||
}
|
||
if (self.enemyDistanceSq <= anim.meleeRangeSq)
|
||
{
|
||
if ( !isMeleePathClear( vecToEnemy, enemyPoint ) )
|
||
{
|
||
if ( !self is_banzai() )
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
else if ( self is_banzai() )
|
||
{
|
||
return false;
|
||
}
|
||
if ( state != "any range" )
|
||
{
|
||
chargeRangeSq = anim.chargeRangeSq;
|
||
if ( state == "long range" )
|
||
{
|
||
chargeRangeSq = anim.chargeLongRangeSq;
|
||
}
|
||
if (self.enemyDistanceSq > chargeRangeSq)
|
||
{
|
||
debug_melee( "Not doing melee - Enemy is not close enough to charge." );
|
||
return false;
|
||
}
|
||
}
|
||
if ( state == "already started" )
|
||
{
|
||
return false;
|
||
}
|
||
if ( ( !self is_banzai() || IsPlayer( self.enemy ) ) && IsDefined( self.lastMeleeGiveUpTime ) && GetTime() - self.lastMeleeGiveUpTime < 3000 )
|
||
{
|
||
debug_melee( "Not doing melee - Recently meleed someone and missed." );
|
||
return false;
|
||
}
|
||
if ( !animscripts\zombie_utility::okToMelee(self.enemy) )
|
||
{
|
||
debug_melee( "Not doing melee - Enemy is being meleed." );
|
||
return false;
|
||
}
|
||
if ( is_true( self.check_melee_path ) )
|
||
{
|
||
if( !isMeleePathClear( vecToEnemy, enemyPoint ) )
|
||
{
|
||
self notify("melee_path_blocked");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
isMeleePathClear( vecToEnemy, enemyPoint )
|
||
{
|
||
dirToEnemy = VectorNormalize( (vecToEnemy[0], vecToEnemy[1], 0 ) );
|
||
meleePoint = enemyPoint - ( dirToEnemy[0]*28, dirToEnemy[1]*28, 0 );
|
||
thread debug_melee_line( self.origin, meleePoint, ( 1,0,0 ), 1.5 );
|
||
if ( !self IsInGoal( meleePoint ) )
|
||
{
|
||
debug_melee( "Not doing melee - Enemy is outside not in goal." );
|
||
return false;
|
||
}
|
||
if ( self maymovetopoint(meleePoint) )
|
||
{
|
||
return true;
|
||
}
|
||
trace1 = bullettrace( self.origin + (0,0,20), meleePoint + (0,0,20), true, self );
|
||
trace2 = bullettrace( self.origin + (0,0,72), meleePoint + (0,0,72), true, self );
|
||
if ( isDefined(trace1["fraction"]) && trace1["fraction"] == 1 &&
|
||
isDefined(trace2["fraction"]) && trace2["fraction"] == 1 )
|
||
{
|
||
return true;
|
||
}
|
||
if ( isDefined(trace1["entity"]) && trace1["entity"] == self.enemy &&
|
||
isDefined(trace2["entity"]) && trace2["entity"] == self.enemy )
|
||
{
|
||
return true;
|
||
}
|
||
if ( is_true( level.zombie_melee_in_water ) )
|
||
{
|
||
if ( isDefined( trace1["surfacetype"] ) && trace1["surfacetype"] == "water" &&
|
||
isDefined( trace2["fraction"] ) && trace2["fraction"] == 1 )
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
debug_melee( "Not doing melee - Can not move to the melee point, MayMoveToPoint failed." );
|
||
return false;
|
||
}
|
||
PlayMeleeSound()
|
||
{
|
||
if ( !IsDefined ( self.a.nextMeleeChargeSound ) )
|
||
{
|
||
self.a.nextMeleeChargeSound = 0;
|
||
}
|
||
if ( GetTime() > self.a.nextMeleeChargeSound )
|
||
{
|
||
self animscripts\face::SaySpecificDialogue( undefined, "chr_play_grunt_" + self.voice, 0.3 );
|
||
self.a.nextMeleeChargeSound = GetTime() + 8000;
|
||
}
|
||
}
|
||
AiVsAiMeleeCombat()
|
||
{
|
||
self endon("killanimscript");
|
||
self melee_notify_wrapper();
|
||
self OrientMode("face enemy");
|
||
self ClearAnim( %root, 0.3 );
|
||
IWin = ( RandomInt(10) < 8 );
|
||
if ( IsDefined( self.magic_bullet_shield ) && self.magic_bullet_shield )
|
||
{
|
||
IWin = true;
|
||
}
|
||
if ( IsDefined( self.enemy.magic_bullet_shield ) && self.enemy.magic_bullet_shield )
|
||
{
|
||
IWin = false;
|
||
}
|
||
winAnim = %bog_melee_R_attack;
|
||
loseAnim = %bog_melee_R_defend;
|
||
if ( IWin )
|
||
{
|
||
myAnim = winAnim;
|
||
theirAnim = loseAnim;
|
||
}
|
||
else
|
||
{
|
||
myAnim = loseAnim;
|
||
theirAnim = winAnim;
|
||
}
|
||
desiredDistSqrd = 72 * 72;
|
||
self PlayMeleeSound();
|
||
AiVsAiMeleeCharge( desiredDistSqrd );
|
||
if ( DistanceSquared( self.origin, self.enemy.origin ) > desiredDistSqrd )
|
||
{
|
||
return false;
|
||
}
|
||
self.meleePartner = self.enemy;
|
||
self.enemy.meleePartner = self;
|
||
self.enemy.meleeAnim = theirAnim;
|
||
self.enemy animcustom( ::AiVsAiAnimCustom );
|
||
self.meleeAnim = myAnim;
|
||
self animcustom( ::AiVsAiAnimCustom );
|
||
}
|
||
AiVsAiMeleeCharge( desiredDistSqrd )
|
||
{
|
||
giveUpTime = GetTime() + 2500;
|
||
self SetAnimKnobAll( animscripts\zombie_run::GetRunAnim(), %body, 1, 0.2 );
|
||
while ( DistanceSquared( self.origin, self.enemy.origin ) > desiredDistSqrd && GetTime() < giveUpTime )
|
||
{
|
||
wait .05;
|
||
}
|
||
}
|
||
AiVsAiAnimCustom()
|
||
{
|
||
self endon("killanimscript");
|
||
self AiVsAiMeleeAnim( self.meleeAnim );
|
||
}
|
||
AiVsAiMeleeAnim( myAnim )
|
||
{
|
||
self endon("end_melee");
|
||
self thread endMeleeOnKillanimscript();
|
||
partnerDir = self.meleePartner.origin - self.origin;
|
||
self OrientMode( "face angle", VectorToAngles( partnerDir )[1] );
|
||
self AnimMode( "zonly_physics" );
|
||
self SetFlaggedAnimKnobAllRestart( "meleeAnim", myAnim, %body, 1, 0.2 );
|
||
self animscripts\zombie_shared::DoNoteTracks( "meleeAnim" );
|
||
self notify("end_melee");
|
||
}
|
||
endMeleeOnKillanimscript()
|
||
{
|
||
self endon("end_melee");
|
||
self waittill("killanimscript");
|
||
self.meleePartner notify("end_melee");
|
||
}
|
||
pick_zombie_melee_anim( zombie_guy )
|
||
{
|
||
melee_anim = undefined;
|
||
if ( zombie_guy.has_legs )
|
||
{
|
||
switch(zombie_guy.zombie_move_speed)
|
||
{
|
||
case "walk":
|
||
anims = array_combine(level._zombie_melee[zombie_guy.animname],level._zombie_walk_melee[zombie_guy.animname]);
|
||
melee_anim = random(anims);
|
||
break;
|
||
case "run":
|
||
case "sprint":
|
||
anims = array_combine(level._zombie_melee[zombie_guy.animname],level._zombie_run_melee[zombie_guy.animname]);
|
||
melee_anim = random(anims);
|
||
break;
|
||
}
|
||
}
|
||
else if(zombie_guy.a.gib_ref == "no_legs")
|
||
{
|
||
melee_anim = random(level._zombie_stumpy_melee[zombie_guy.animname]);
|
||
}
|
||
else
|
||
{
|
||
melee_anim = random(level._zombie_melee_crawl[zombie_guy.animname]);
|
||
}
|
||
return melee_anim;
|
||
} |