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
XSPRITE * pXSprite = & actor - > x ( ) ;
spritetype * pSprite = & actor - > s ( ) ;
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
spritetype * pTarget = & actor - > GetTarget ( ) - > s ( ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
DUDEINFO * pDudeInfoT = getDudeInfo ( pTarget - > type ) ;
2021-12-22 10:57:10 +00:00
int tx = pXSprite - > targetX - pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int ty = pXSprite - > targetY - pSprite - > pos . Y ;
2021-09-16 19:59:39 +00:00
int nAngle = getangle ( tx , ty ) ;
int height = ( pSprite - > yrepeat * pDudeInfo - > eyeHeight ) < < 2 ;
int height2 = ( pTarget - > yrepeat * pDudeInfoT - > eyeHeight ) < < 2 ;
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-09-16 19:59:39 +00:00
auto pXSprite = & actor - > x ( ) ;
aiChooseDirection ( actor , pXSprite - > goalAng ) ;
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-09-16 19:59:39 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
2021-12-22 10:57:10 +00:00
int dx = pXSprite - > targetX - pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int dy = pXSprite - > targetY - pSprite - > pos . Y ;
2021-09-16 19:59:39 +00:00
int nAngle = getangle ( dx , dy ) ;
int nDist = approxDist ( dx , dy ) ;
aiChooseDirection ( actor , nAngle ) ;
if ( nDist < 921 & & abs ( pSprite - > ang - nAngle ) < pDudeInfo - > periphery )
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
auto pSprite = & actor - > s ( ) ;
if ( actor - > GetTarget ( ) = = nullptr )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
spritetype * pTarget = & actor - > GetTarget ( ) - > s ( ) ;
XSPRITE * pXTarget = & actor - > GetTarget ( ) - > x ( ) ;
2021-12-22 10:57:10 +00:00
int dx = pTarget - > pos . X - pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int dy = pTarget - > pos . Y - pSprite - > pos . Y ;
2021-09-16 19:59:39 +00:00
aiChooseDirection ( actor , getangle ( dx , dy ) ) ;
if ( pXTarget - > health = = 0 )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
if ( IsPlayerSprite ( pTarget ) & & ( powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
{
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.
if ( ! VanillaMode ( ) & & pSprite - > type = = kDudeZombieAxeBuried )
pSprite - > 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 )
{
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - pSprite - > ang ) & 2047 ) - 1024 ;
int height = ( pDudeInfo - > eyeHeight * pSprite - > yrepeat ) < < 2 ;
2021-12-22 11:29:00 +00:00
if ( cansee ( pTarget - > pos . X , pTarget - > pos . Y , pTarget - > pos . Z , pTarget - > sector ( ) , pSprite - > pos . X , pSprite - > pos . Y , pSprite - > pos . Z - height , pSprite - > 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
auto pSprite = & actor - > s ( ) ;
if ( actor - > GetTarget ( ) = = nullptr )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
if ( ! actor - > ValidateTarget ( __FUNCTION__ ) ) return ;
spritetype * pTarget = & actor - > GetTarget ( ) - > s ( ) ;
XSPRITE * pXTarget = & actor - > GetTarget ( ) - > x ( ) ;
2021-12-22 10:57:10 +00:00
int dx = pTarget - > pos . X - pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int dy = pTarget - > pos . Y - pSprite - > pos . Y ;
2021-09-16 19:59:39 +00:00
aiChooseDirection ( actor , getangle ( dx , dy ) ) ;
if ( pXTarget - > health = = 0 )
{
aiNewState ( actor , & zombieASearch ) ;
return ;
}
if ( IsPlayerSprite ( pTarget ) & & ( powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
{
aiNewState ( actor , & zombieAGoto ) ;
return ;
}
int nDist = approxDist ( dx , dy ) ;
if ( nDist < = pDudeInfo - > seeDist )
{
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - pSprite - > ang ) & 2047 ) - 1024 ;
int height = ( pDudeInfo - > eyeHeight * pSprite - > yrepeat ) < < 2 ;
2021-12-22 11:29:00 +00:00
if ( cansee ( pTarget - > pos . X , pTarget - > pos . Y , pTarget - > pos . Z , pTarget - > sector ( ) , pSprite - > pos . X , pSprite - > pos . Y , pSprite - > pos . Z - height , pSprite - > 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-09-16 19:59:39 +00:00
auto pSprite = & actor - > s ( ) ;
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
for ( int p = connecthead ; p > = 0 ; p = connectpoint2 [ p ] )
{
PLAYER * pPlayer = & gPlayer [ p ] ;
2021-09-04 18:43:03 +00:00
auto owneractor = actor - > GetOwner ( ) ;
2021-09-05 07:53:06 +00:00
if ( owneractor = = nullptr | | owneractor = = pPlayer - > actor | | pPlayer - > pXSprite - > health = = 0 | | powerupCheck ( pPlayer , kPwUpShadowCloak ) > 0 )
2021-09-16 19:59:39 +00:00
continue ;
2021-12-22 10:57:10 +00:00
int x = pPlayer - > pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int y = pPlayer - > pSprite - > pos . Y ;
2021-12-22 11:29:00 +00:00
int z = pPlayer - > pSprite - > pos . Z ;
2021-11-23 23:35:46 +00:00
auto pSector = pPlayer - > pSprite - > sector ( ) ;
2021-12-22 10:57:10 +00:00
int dx = x - pSprite - > pos . X ;
2021-12-22 11:17:17 +00:00
int dy = y - pSprite - > pos . Y ;
2021-09-16 19:59:39 +00:00
int nDist = approxDist ( dx , dy ) ;
if ( nDist > pDudeInfo - > seeDist & & nDist > pDudeInfo - > hearDist )
continue ;
2021-12-22 11:29:00 +00:00
if ( ! cansee ( x , y , z , pSector , pSprite - > pos . X , pSprite - > pos . Y , pSprite - > pos . Z - ( ( pDudeInfo - > eyeHeight * pSprite - > yrepeat ) < < 2 ) , pSprite - > sector ( ) ) )
2021-09-16 19:59:39 +00:00
continue ;
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - pSprite - > ang ) & 2047 ) - 1024 ;
if ( nDist < pDudeInfo - > seeDist & & abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
{
2021-09-05 07:53:06 +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-09-16 19:59:39 +00:00
auto pXSprite = & actor - > x ( ) ;
aiChooseDirection ( actor , pXSprite - > goalAng ) ;
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-09-16 19:59:39 +00:00
auto pSprite = & actor - > s ( ) ;
pSprite - > type = kDudeZombieAxeNormal ;
pSprite - > 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-09-16 19:59:39 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2021-11-28 09:24:42 +00:00
sfxPlay3DSound ( actor , 1100 , - 1 , 0 ) ;
2021-12-22 11:17:17 +00:00
pSprite - > ang = getangle ( pXSprite - > targetX - pSprite - > pos . X , pXSprite - > targetY - pSprite - > pos . Y ) ;
2019-09-19 22:42:45 +00:00
}
2019-09-22 06:39:22 +00:00
END_BLD_NS