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 "compat.h"
# include "build.h"
# include "pragmas.h"
# include "mmulti.h"
# include "blood.h"
2019-09-22 06:39:22 +00:00
BEGIN_BLD_NS
2020-11-06 21:48:22 +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
{
2020-11-07 14:16:12 +00:00
XSPRITE * pXSprite = & actor - > x ( ) ;
spritetype * pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
spritetype * pTarget = & sprite [ pXSprite - > target ] ;
2020-02-05 21:17:05 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
DUDEINFO * pDudeInfoT = getDudeInfo ( pTarget - > type ) ;
2019-09-19 22:42:45 +00:00
int tx = pXSprite - > targetX - pSprite - > x ;
int ty = pXSprite - > targetY - pSprite - > y ;
int nAngle = getangle ( tx , ty ) ;
int height = ( pSprite - > yrepeat * pDudeInfo - > eyeHeight ) < < 2 ;
int height2 = ( pTarget - > yrepeat * pDudeInfoT - > eyeHeight ) < < 2 ;
int dz = height - height2 ;
2020-09-01 13:00:35 +00:00
int dx = CosScale16 ( nAngle ) ;
int dy = SinScale16 ( nAngle ) ;
2019-09-19 22:42:45 +00:00
sfxPlay3DSound ( pSprite , 1101 , 1 , 0 ) ;
actFireVector ( pSprite , 0 , 0 , dx , dy , dz , VECTOR_TYPE_10 ) ;
}
2020-11-07 14:16:12 +00:00
void StandSeqCallback ( int , DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2020-11-07 14:16:12 +00:00
sfxPlay3DSound ( & actor - > s ( ) , 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
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
aiChooseDirection ( pSprite , pXSprite , pXSprite - > goalAng ) ;
sub_5F15C ( pSprite , pXSprite ) ;
}
2020-11-06 21:48:22 +00:00
static void zombaThinkGoto ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2020-10-11 10:38:17 +00:00
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
2020-02-05 21:17:05 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
2019-09-19 22:42:45 +00:00
int dx = pXSprite - > targetX - pSprite - > x ;
int dy = pXSprite - > targetY - pSprite - > y ;
int nAngle = getangle ( dx , dy ) ;
int nDist = approxDist ( dx , dy ) ;
aiChooseDirection ( pSprite , pXSprite , nAngle ) ;
2021-01-04 12:02:00 +00:00
if ( nDist < 921 & & abs ( pSprite - > ang - nAngle ) < pDudeInfo - > periphery )
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieASearch ) ;
2020-11-06 21:48:22 +00:00
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
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
if ( pXSprite - > target = = - 1 )
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieASearch ) ;
2019-09-19 22:42:45 +00:00
return ;
}
2020-10-11 10:38:17 +00:00
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
2020-02-05 21:17:05 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
2020-10-11 10:38:17 +00:00
assert ( pXSprite - > target > = 0 & & pXSprite - > target < kMaxSprites ) ;
2019-09-19 22:42:45 +00:00
spritetype * pTarget = & sprite [ pXSprite - > target ] ;
XSPRITE * pXTarget = & xsprite [ pTarget - > extra ] ;
int dx = pTarget - > x - pSprite - > x ;
int dy = pTarget - > y - pSprite - > y ;
aiChooseDirection ( pSprite , pXSprite , getangle ( dx , dy ) ) ;
if ( pXTarget - > health = = 0 )
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieASearch ) ;
2019-09-19 22:42:45 +00:00
return ;
}
2019-10-19 19:11:39 +00:00
if ( IsPlayerSprite ( pTarget ) & & ( powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
2019-09-19 22:42:45 +00:00
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieAGoto ) ;
2019-09-19 22:42:45 +00:00
return ;
}
2020-02-15 20:47:02 +00:00
// 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 ;
2019-09-19 22:42:45 +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 ;
if ( cansee ( pTarget - > x , pTarget - > y , pTarget - > z , pTarget - > sectnum , pSprite - > x , pSprite - > y , pSprite - > z - height , pSprite - > sectnum ) )
{
2021-01-04 12:02:00 +00:00
if ( abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
2019-09-19 22:42:45 +00:00
{
aiSetTarget ( pXSprite , pXSprite - > target ) ;
2021-01-04 12:02:00 +00:00
if ( nDist < 0x400 & & abs ( nDeltaAngle ) < 85 )
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieAHack ) ;
2019-09-19 22:42:45 +00:00
return ;
}
}
}
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieAGoto ) ;
2019-09-19 22:42:45 +00:00
pXSprite - > target = - 1 ;
}
2020-11-06 21:48:22 +00:00
static void zombaThinkPonder ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
if ( pXSprite - > target = = - 1 )
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieASearch ) ;
2019-09-19 22:42:45 +00:00
return ;
}
2020-10-11 10:38:17 +00:00
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
2020-02-05 21:17:05 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
2020-10-11 10:38:17 +00:00
assert ( pXSprite - > target > = 0 & & pXSprite - > target < kMaxSprites ) ;
2019-09-19 22:42:45 +00:00
spritetype * pTarget = & sprite [ pXSprite - > target ] ;
XSPRITE * pXTarget = & xsprite [ pTarget - > extra ] ;
int dx = pTarget - > x - pSprite - > x ;
int dy = pTarget - > y - pSprite - > y ;
aiChooseDirection ( pSprite , pXSprite , getangle ( dx , dy ) ) ;
if ( pXTarget - > health = = 0 )
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieASearch ) ;
2019-09-19 22:42:45 +00:00
return ;
}
2019-10-19 19:11:39 +00:00
if ( IsPlayerSprite ( pTarget ) & & ( powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpShadowCloak ) > 0 | | powerupCheck ( & gPlayer [ pTarget - > type - kDudePlayer1 ] , kPwUpDeathMaskUseless ) > 0 ) )
2019-09-19 22:42:45 +00:00
{
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieAGoto ) ;
2019-09-19 22:42:45 +00:00
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 ;
if ( cansee ( pTarget - > x , pTarget - > y , pTarget - > z , pTarget - > sectnum , pSprite - > x , pSprite - > y , pSprite - > z - height , pSprite - > sectnum ) )
{
2021-01-04 12:02:00 +00:00
if ( abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
2019-09-19 22:42:45 +00:00
{
aiSetTarget ( pXSprite , pXSprite - > target ) ;
if ( nDist < 0x400 )
{
2021-01-04 12:02:00 +00:00
if ( abs ( nDeltaAngle ) < 85 )
2019-09-19 22:42:45 +00:00
{
sfxPlay3DSound ( pSprite , 1101 , 1 , 0 ) ;
2020-11-07 12:46:03 +00:00
aiNewState ( actor , & zombieAHack ) ;
2019-09-19 22:42:45 +00:00
}
return ;
}
}
}
}
2020-11-07 12:46:03 +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
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2020-10-11 10:38:17 +00:00
assert ( pSprite - > type > = kDudeBase & & pSprite - > type < kDudeMax ) ;
2020-02-05 21:17:05 +00:00
DUDEINFO * pDudeInfo = getDudeInfo ( pSprite - > type ) ;
2019-09-19 22:42:45 +00:00
for ( int p = connecthead ; p > = 0 ; p = connectpoint2 [ p ] )
{
PLAYER * pPlayer = & gPlayer [ p ] ;
int nOwner = ( pSprite - > owner & 0x1000 ) ? ( pSprite - > owner & 0xfff ) : - 1 ;
2019-10-21 19:46:41 +00:00
if ( nOwner = = pPlayer - > nSprite | | pPlayer - > pXSprite - > health = = 0 | | powerupCheck ( pPlayer , kPwUpShadowCloak ) > 0 )
2019-09-19 22:42:45 +00:00
continue ;
int x = pPlayer - > pSprite - > x ;
int y = pPlayer - > pSprite - > y ;
int z = pPlayer - > pSprite - > z ;
int nSector = pPlayer - > pSprite - > sectnum ;
int dx = x - pSprite - > x ;
int dy = y - pSprite - > y ;
int nDist = approxDist ( dx , dy ) ;
if ( nDist > pDudeInfo - > seeDist & & nDist > pDudeInfo - > hearDist )
continue ;
if ( ! cansee ( x , y , z , nSector , pSprite - > x , pSprite - > y , pSprite - > z - ( ( pDudeInfo - > eyeHeight * pSprite - > yrepeat ) < < 2 ) , pSprite - > sectnum ) )
continue ;
int nDeltaAngle = ( ( getangle ( dx , dy ) + 1024 - pSprite - > ang ) & 2047 ) - 1024 ;
2021-01-04 12:02:00 +00:00
if ( nDist < pDudeInfo - > seeDist & & abs ( nDeltaAngle ) < = pDudeInfo - > periphery )
2019-09-19 22:42:45 +00:00
{
2019-10-21 19:46:41 +00:00
aiSetTarget ( pXSprite , pPlayer - > nSprite ) ;
2020-11-06 21:48:22 +00:00
aiActivateDude ( & bloodActors [ pXSprite - > reference ] ) ;
2019-09-19 22:42:45 +00:00
}
else if ( nDist < pDudeInfo - > hearDist )
{
aiSetTarget ( pXSprite , x , y , z ) ;
2020-11-06 21:48:22 +00:00
aiActivateDude ( & bloodActors [ pXSprite - > reference ] ) ;
2019-09-19 22:42:45 +00:00
}
else
continue ;
break ;
}
}
2020-11-06 21:48:22 +00:00
static void myThinkSearch ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
aiChooseDirection ( pSprite , pXSprite , pXSprite - > goalAng ) ;
2020-11-06 21:48:22 +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
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-10-11 21:59:39 +00:00
pSprite - > type = kDudeZombieAxeNormal ;
2019-09-30 07:18:01 +00:00
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
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
2019-09-19 22:42:45 +00:00
pXSprite - > target = - 1 ;
}
2020-11-06 21:48:22 +00:00
static void entryEStand ( DBloodActor * actor )
2019-09-19 22:42:45 +00:00
{
2020-11-06 21:48:22 +00:00
auto pXSprite = & actor - > x ( ) ;
auto pSprite = & actor - > s ( ) ;
2019-09-19 22:42:45 +00:00
sfxPlay3DSound ( pSprite , 1100 , - 1 , 0 ) ;
pSprite - > ang = getangle ( pXSprite - > targetX - pSprite - > x , pXSprite - > targetY - pSprite - > y ) ;
}
2019-09-22 06:39:22 +00:00
END_BLD_NS