2019-09-19 22:42:45 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2010 - 2019 EDuke32 developers and contributors
Copyright ( C ) 2019 Nuke . YKT
This file is part of NBlood .
NBlood is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
//-------------------------------------------------------------------------
2019-09-21 18:59:54 +00:00
# include "ns.h" // Must come before everything else!
2019-09-19 22:42:45 +00:00
# include "build.h"
# include "blood.h"
2019-09-22 06:39:22 +00:00
BEGIN_BLD_NS
2021-09-16 19:59:39 +00:00
static void zombaThinkSearch ( DBloodActor * ) ;
static void zombaThinkGoto ( DBloodActor * ) ;
static void zombaThinkChase ( DBloodActor * ) ;
static void zombaThinkPonder ( DBloodActor * ) ;
static void myThinkTarget ( DBloodActor * ) ;
static void myThinkSearch ( DBloodActor * ) ;
static void entryEZombie ( DBloodActor * ) ;
static void entryAIdle ( DBloodActor * ) ;
static void entryEStand ( DBloodActor * ) ;
2019-09-19 22:42:45 +00:00
AISTATE zombieAIdle = { kAiStateIdle , 0 , - 1 , 0 , entryAIdle , NULL , aiThinkTarget , NULL } ;
2020-10-11 09:56:27 +00:00
AISTATE zombieAChase = { kAiStateChase , 8 , - 1 , 0 , NULL , aiMoveForward , zombaThinkChase , NULL } ;
AISTATE zombieAPonder = { kAiStateOther , 0 , - 1 , 0 , NULL , aiMoveTurn , zombaThinkPonder , NULL } ;
AISTATE zombieAGoto = { kAiStateMove , 8 , - 1 , 1800 , NULL , aiMoveForward , zombaThinkGoto , & zombieAIdle } ;
2019-09-19 22:42:45 +00:00
AISTATE zombieAHack = { kAiStateChase , 6 , nHackClient , 80 , NULL , NULL , NULL , & zombieAPonder } ;
2020-10-11 09:56:27 +00:00
AISTATE zombieASearch = { kAiStateSearch , 8 , - 1 , 1800 , NULL , aiMoveForward , zombaThinkSearch , & zombieAIdle } ;
2019-09-19 22:42:45 +00:00
AISTATE zombieARecoil = { kAiStateRecoil , 5 , - 1 , 0 , NULL , NULL , NULL , & zombieAPonder } ;
AISTATE zombieATeslaRecoil = { kAiStateRecoil , 4 , - 1 , 0 , NULL , NULL , NULL , & zombieAPonder } ;
AISTATE zombieARecoil2 = { kAiStateRecoil , 1 , - 1 , 360 , NULL , NULL , NULL , & zombieAStand } ;
AISTATE zombieAStand = { kAiStateMove , 11 , nStandClient , 0 , NULL , NULL , NULL , & zombieAPonder } ;
AISTATE zombieEIdle = { kAiStateIdle , 12 , - 1 , 0 , NULL , NULL , aiThinkTarget , NULL } ;
AISTATE zombieEUp2 = { kAiStateMove , 0 , - 1 , 1 , entryEZombie , NULL , NULL , & zombieASearch } ;
AISTATE zombieEUp = { kAiStateMove , 9 , - 1 , 180 , entryEStand , NULL , NULL , & zombieEUp2 } ;
AISTATE zombie2Idle = { kAiStateIdle , 0 , - 1 , 0 , entryAIdle , NULL , myThinkTarget , NULL } ;
AISTATE zombie2Search = { kAiStateSearch , 8 , - 1 , 1800 , NULL , NULL , myThinkSearch , & zombie2Idle } ;
AISTATE zombieSIdle = { kAiStateIdle , 10 , - 1 , 0 , NULL , NULL , aiThinkTarget , NULL } ;
AISTATE zombie13AC2C = { kAiStateOther , 11 , nStandClient , 0 , entryEZombie , NULL , NULL , & zombieAPonder } ;
2020-11-07 14:16:12 +00:00
void HackSeqCallback ( int , DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-09-16 19:59:39 +00:00
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
2021-12-22 19:02:43 +00:00
auto target = actor - > GetTarget ( ) ;
2021-12-22 19:22:35 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( actor - > spr . type ) ;
2021-12-22 19:02:43 +00:00
DUDEINFO * pDudeInfoT = getDudeInfo ( target - > spr . type ) ;
2022-08-22 16:31:23 +00:00
int tx = actor - > xspr . int_TargetPos ( ) . X - actor - > int_pos ( ) . X ;
int ty = actor - > xspr . int_TargetPos ( ) . Y - actor - > int_pos ( ) . Y ;
2021-09-16 19:59:39 +00:00
int nAngle = getangle ( tx , ty ) ;
2021-12-22 19:22:35 +00:00
int height = ( actor - > spr . yrepeat * pDudeInfo - > eyeHeight ) < < 2 ;
2021-12-22 19:02:43 +00:00
int height2 = ( target - > spr . yrepeat * pDudeInfoT - > eyeHeight ) < < 2 ;
2021-09-16 19:59:39 +00:00
int dz = height - height2 ;
2021-10-30 06:22:27 +00:00
int dx = bcos ( nAngle ) ;
2021-10-30 06:22:17 +00:00
int dy = bsin ( nAngle ) ;
2021-11-28 09:24:42 +00:00
sfxPlay3DSound ( actor , 1101 , 1 , 0 ) ;
2021-09-16 19:59:39 +00:00
actFireVector ( actor , 0 , 0 , dx , dy , dz , kVectorAxe ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-07 14:16:12 +00:00
void StandSeqCallback ( int , DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-09-16 19:59:39 +00:00
sfxPlay3DSound ( actor , 1102 , - 1 , 0 ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void zombaThinkSearch ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-12-22 21:49:50 +00:00
aiChooseDirection ( actor , actor - > xspr . goalAng ) ;
2021-09-16 19:59:39 +00:00
aiLookForTarget ( actor ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void zombaThinkGoto ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-12-22 19:22:35 +00:00
assert ( actor - > spr . type > = kDudeBase & & actor - > spr . type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( actor - > spr . type ) ;
2022-08-22 16:31:23 +00:00
int dx = actor - > xspr . int_TargetPos ( ) . X - actor - > int_pos ( ) . X ;
int dy = actor - > xspr . int_TargetPos ( ) . Y - actor - > int_pos ( ) . Y ;
2021-09-16 19:59:39 +00:00
int nAngle = getangle ( dx , dy ) ;
int nDist = approxDist ( dx , dy ) ;
aiChooseDirection ( actor , nAngle ) ;
2022-08-16 21:15:49 +00:00
if ( nDist < 921 & & abs ( actor - > int_ang ( ) - nAngle ) < pDudeInfo - > periphery )
2021-09-16 19:59:39 +00:00
aiNewState ( actor , & zombieASearch ) ;
aiThinkTarget ( actor ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void zombaThinkChase ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-09-16 19:59:39 +00:00
if ( actor - > GetTarget ( ) = = nullptr )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
2021-12-22 19:22:35 +00:00
assert ( actor - > spr . type > = kDudeBase & & actor - > spr . type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( actor - > spr . type ) ;
2021-09-16 19:59:39 +00:00
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
2021-12-22 19:02:43 +00:00
auto target = actor - > GetTarget ( ) ;
2021-12-29 18:41:41 +00:00
2022-01-30 17:09:26 +00:00
int dx = target - > int_pos ( ) . X - actor - > int_pos ( ) . X ;
int dy = target - > int_pos ( ) . Y - actor - > int_pos ( ) . Y ;
2021-09-16 19:59:39 +00:00
aiChooseDirection ( actor , getangle ( dx , dy ) ) ;
2021-12-22 19:48:11 +00:00
if ( target - > xspr . health = = 0 )
2021-09-16 19:59:39 +00:00
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
2021-12-22 19:02:43 +00:00
if ( target - > IsPlayerActor ( ) & & ( powerupCheck ( & gPlayer [ target - > spr . type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ target - > spr . type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
2021-09-16 19:59:39 +00:00
{
aiNewState ( actor , & zombieAGoto ) ;
return ;
}
// If the zombie gets whacked while rising from the grave it never executes this change and if it isn't done here at the very latest, will just aimlessly run around.
2021-12-22 19:22:35 +00:00
if ( ! VanillaMode ( ) & & actor - > spr . type = = kDudeZombieAxeBuried )
actor - > spr . type = kDudeZombieAxeNormal ;
2020-02-15 20:47:02 +00:00
2021-09-16 19:59:39 +00:00
int nDist = approxDist ( dx , dy ) ;
if ( nDist < = pDudeInfo - > seeDist )
{
2022-08-16 21:17:01 +00:00
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - actor - > int_ang ( ) ) & 2047 ) - 1024 ;
2022-08-22 16:37:10 +00:00
double height = ( pDudeInfo - > eyeHeight * actor - > spr . yrepeat ) * REPEAT_SCALE ;
if ( cansee ( target - > spr . pos , target - > sector ( ) , actor - > spr . pos . plusZ ( - height ) , actor - > sector ( ) ) )
2021-09-16 19:59:39 +00:00
{
if ( abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
{
aiSetTarget ( actor , actor - > GetTarget ( ) ) ;
if ( nDist < 0x400 & & abs ( nDeltaAngle ) < 85 )
aiNewState ( actor , & zombieAHack ) ;
return ;
}
}
}
2019-09-19 22:42:45 +00:00
2021-09-16 19:59:39 +00:00
aiNewState ( actor , & zombieAGoto ) ;
actor - > SetTarget ( nullptr ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void zombaThinkPonder ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-09-16 19:59:39 +00:00
if ( actor - > GetTarget ( ) = = nullptr )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
2021-12-22 19:22:35 +00:00
assert ( actor - > spr . type > = kDudeBase & & actor - > spr . type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( actor - > spr . type ) ;
2021-09-16 19:59:39 +00:00
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
2021-12-22 19:02:43 +00:00
auto target = actor - > GetTarget ( ) ;
2021-12-29 18:41:41 +00:00
2022-01-30 17:09:26 +00:00
int dx = target - > int_pos ( ) . X - actor - > int_pos ( ) . X ;
int dy = target - > int_pos ( ) . Y - actor - > int_pos ( ) . Y ;
2021-09-16 19:59:39 +00:00
aiChooseDirection ( actor , getangle ( dx , dy ) ) ;
2021-12-22 19:48:11 +00:00
if ( target - > xspr . health = = 0 )
2021-09-16 19:59:39 +00:00
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
2021-12-22 19:02:43 +00:00
if ( target - > IsPlayerActor ( ) & & ( powerupCheck ( & gPlayer [ target - > spr . type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ target - > spr . type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
2021-09-16 19:59:39 +00:00
{
aiNewState ( actor , & zombieAGoto ) ;
return ;
}
int nDist = approxDist ( dx , dy ) ;
if ( nDist < = pDudeInfo - > seeDist )
{
2022-08-16 21:17:01 +00:00
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - actor - > int_ang ( ) ) & 2047 ) - 1024 ;
2022-08-22 16:37:10 +00:00
double height = ( pDudeInfo - > eyeHeight * actor - > spr . yrepeat ) * REPEAT_SCALE ;
if ( cansee ( target - > spr . pos , target - > sector ( ) , actor - > spr . pos . plusZ ( - height ) , actor - > sector ( ) ) )
2021-09-16 19:59:39 +00:00
{
if ( abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
{
aiSetTarget ( actor , actor - > GetTarget ( ) ) ;
if ( nDist < 0x400 )
{
if ( abs ( nDeltaAngle ) < 85 )
{
2021-11-28 09:24:42 +00:00
sfxPlay3DSound ( actor , 1101 , 1 , 0 ) ;
2021-09-16 19:59:39 +00:00
aiNewState ( actor , & zombieAHack ) ;
}
return ;
}
}
}
}
2019-09-19 22:42:45 +00:00
2021-09-16 19:59:39 +00:00
aiNewState ( actor , & zombieAChase ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void myThinkTarget ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-12-22 19:22:35 +00:00
assert ( actor - > spr . type > = kDudeBase & & actor - > spr . type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( actor - > spr . type ) ;
2021-09-16 19:59:39 +00:00
for ( int p = connecthead ; p > = 0 ; p = connectpoint2 [ p ] )
{
PLAYER * pPlayer = & gPlayer [ p ] ;
2021-12-29 18:41:41 +00:00
auto owneractor = actor - > GetOwner ( ) ;
if ( owneractor = = nullptr | | owneractor = = pPlayer - > actor | | pPlayer - > actor - > xspr . health = = 0 | | powerupCheck ( pPlayer , kPwUpShadowCloak ) > 0 )
2021-09-16 19:59:39 +00:00
continue ;
2022-08-22 16:37:46 +00:00
auto ppos = pPlayer - > actor - > spr . pos ;
2022-01-30 17:09:26 +00:00
int x = pPlayer - > actor - > int_pos ( ) . X ;
int y = pPlayer - > actor - > int_pos ( ) . Y ;
int z = pPlayer - > actor - > int_pos ( ) . Z ;
2021-12-30 15:51:56 +00:00
auto pSector = pPlayer - > actor - > sector ( ) ;
2022-01-30 17:09:26 +00:00
int dx = x - actor - > int_pos ( ) . X ;
int dy = y - actor - > int_pos ( ) . Y ;
2021-09-16 19:59:39 +00:00
int nDist = approxDist ( dx , dy ) ;
if ( nDist > pDudeInfo - > seeDist & & nDist > pDudeInfo - > hearDist )
continue ;
2022-08-22 16:37:46 +00:00
double height = ( pDudeInfo - > eyeHeight * actor - > spr . yrepeat ) * REPEAT_SCALE ;
if ( ! cansee ( ppos , pSector , actor - > spr . pos . plusZ ( - height ) , actor - > sector ( ) ) )
2021-09-16 19:59:39 +00:00
continue ;
2022-08-16 21:17:01 +00:00
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - actor - > int_ang ( ) ) & 2047 ) - 1024 ;
2021-09-16 19:59:39 +00:00
if ( nDist < pDudeInfo - > seeDist & & abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
{
2021-12-29 18:41:41 +00:00
aiSetTarget ( actor , pPlayer - > actor ) ;
2021-09-16 19:59:39 +00:00
aiActivateDude ( actor ) ;
}
else if ( nDist < pDudeInfo - > hearDist )
{
aiSetTarget ( actor , x , y , z ) ;
aiActivateDude ( actor ) ;
}
else
continue ;
break ;
}
2019-09-19 22:42:45 +00:00
}
2021-10-13 22:01:18 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-11-06 21:48:22 +00:00
static void myThinkSearch ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-12-22 21:49:50 +00:00
aiChooseDirection ( actor , actor - > xspr . goalAng ) ;
2021-09-16 19:59:39 +00:00
myThinkTarget ( actor ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void entryEZombie ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-12-22 19:22:35 +00:00
actor - > spr . type = kDudeZombieAxeNormal ;
actor - > spr . flags | = 1 ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void entryAIdle ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-09-16 19:59:39 +00:00
actor - > SetTarget ( nullptr ) ;
2019-09-19 22:42:45 +00:00
}
2020-11-06 21:48:22 +00:00
static void entryEStand ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2021-11-28 09:24:42 +00:00
sfxPlay3DSound ( actor , 1100 , - 1 , 0 ) ;
2022-08-22 16:31:45 +00:00
actor - > spr . angle = VecToAngle ( actor - > xspr . TargetPos - actor - > spr . pos ) ;
2019-09-19 22:42:45 +00:00
}
2019-09-22 06:39:22 +00:00
END_BLD_NS