adapted ai.cpp and callback.cpp.

This commit is contained in:
Christoph Oelckers 2023-10-15 19:33:33 +02:00
parent 62753c02f0
commit 4f338ab8a2
4 changed files with 99 additions and 221 deletions

View file

@ -197,8 +197,17 @@ bool CanMove(DBloodActor* actor, DBloodActor* target, DAngle nAngle, double nRan
if (Underwater) if (Underwater)
return true; return true;
break; break;
case kDudeCerberusTwoHead:
case kDudeCerberusOneHead: case kDudeCerberusOneHead:
if (VanillaMode())
{
if (Crusher)
return false;
if ((!pSector->hasX() || (!pSector->xs().Underwater && !pSector->xs().Depth)) && floorZ - bottom > 0x2000)
return false;
break;
}
[[fallthrough]];
case kDudeCerberusTwoHead:
// by NoOne: a quick fix for Cerberus spinning in E3M7-like maps, where damage sectors is used. // by NoOne: a quick fix for Cerberus spinning in E3M7-like maps, where damage sectors is used.
// It makes ignore danger if enemy immune to N damageType. As result Cerberus start acting like // It makes ignore danger if enemy immune to N damageType. As result Cerberus start acting like
// in Blood 1.0 so it can move normally to player. It's up to you for adding rest of enemies here as // in Blood 1.0 so it can move normally to player. It's up to you for adding rest of enemies here as
@ -222,9 +231,7 @@ bool CanMove(DBloodActor* actor, DBloodActor* target, DAngle nAngle, double nRan
break; break;
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
case kDudeModernCustom: case kDudeModernCustom:
if ((Crusher && !nnExtIsImmune(actor, pXSector->damageType)) || ((Water || Underwater) && !canSwim(actor))) return false; return cdudeGet(actor)->CanMove(pSector, Crusher, Water, Underwater, Depth, bottom, floorZ);
return true;
[[fallthrough]];
#endif #endif
case kDudeZombieAxeNormal: case kDudeZombieAxeNormal:
case kDudePhantasm: case kDudePhantasm:
@ -420,25 +427,8 @@ void aiActivateDude(DBloodActor* actor)
} }
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
case kDudeModernCustom: case kDudeModernCustom:
{ cdudeGet(actor)->Activate();
return;
actor->dudeExtra.active = 1;
if (actor->GetTarget() == nullptr)
{
if (spriteIsUnderwater(actor, false)) aiGenDudeNewState(actor, &genDudeSearchW);
else aiGenDudeNewState(actor, &genDudeSearchL);
}
else
{
if (Chance(0x4000)) playGenDudeSound(actor,kGenDudeSndTargetSpot);
if (spriteIsUnderwater(actor, false)) aiGenDudeNewState(actor, &genDudeChaseW);
else aiGenDudeNewState(actor, &genDudeChaseL);
}
break;
}
if (actor->GetTarget() == nullptr) aiGenDudeNewState(actor, &genDudeBurnSearch);
else aiGenDudeNewState(actor, &genDudeBurnChase);
break;
#endif #endif
case kDudeCultistTommyProne: case kDudeCultistTommyProne:
{ {
@ -971,7 +961,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
auto pPlayer = getPlayer(source->GetType()); auto pPlayer = getPlayer(source->GetType());
if (!pPlayer) return nDamage; if (!pPlayer) return nDamage;
//if (powerupCheck(pPlayer, kPwUpShadowCloak)) pPlayer->pwUpTime[kPwUpShadowCloak] = 0;
if (readyForCrit(source, actor)) if (readyForCrit(source, actor))
{ {
nDamage += aiDamageSprite(actor, source, nDmgType, nDamage * (10 - gGameOptions.nDifficulty)); nDamage += aiDamageSprite(actor, source, nDmgType, nDamage * (10 - gGameOptions.nDifficulty));
@ -984,84 +974,13 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
RecoilDude(actor); RecoilDude(actor);
} }
} }
DPrintf(DMSG_SPAMMY, "Player #%d does the critical damage to patrol dude #%d!", pPlayer->pnum + 1, actor->GetIndex());
} }
return nDamage; return nDamage;
} }
if (IsCustomDude(actor))
return cdudeGet(actor)->Damage(source, nDmgType, nDamage);
if (actor->GetType() == kDudeModernCustom)
{
GENDUDEEXTRA* pExtra = &actor->genDudeExtra;
if (nDmgType == kDamageBurn)
{
if (actor->xspr.health > (uint32_t)pDudeInfo->fleeHealth) return nDamage;
else if (actor->xspr.txID <= 0 || getNextIncarnation(actor) == nullptr)
{
removeDudeStuff(actor);
if (pExtra->weaponType == kGenDudeWeaponKamikaze)
doExplosion(actor, actor->xspr.data1 - kTrapExploder);
if (spriteIsUnderwater(actor))
{
actor->xspr.health = 0;
return nDamage;
}
if (actor->xspr.burnTime <= 0)
actor->xspr.burnTime = 1200;
if (pExtra->canBurn && pExtra->availDeaths[kDamageBurn] > 0) {
aiPlay3DSound(actor, 361, AI_SFX_PRIORITY_0, -1);
playGenDudeSound(actor,kGenDudeSndBurning);
//actor->ChangeType(kDudeModernCustomBurning);
if (actor->xspr.data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation
actor->spr.pal = 0;
aiGenDudeNewState(actor, &genDudeBurnGoto);
actHealDude(actor, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
actor->dudeExtra.time = PlayClock + 360;
evKillActor(actor, AF(fxFlameLick));
}
}
else
{
actKillDude(actor, actor, kDamageFall, 65535);
}
}
else if (canWalk(actor) && !inDodge(actor->xspr.aiState) && !inRecoil(actor->xspr.aiState))
{
if (!dudeIsMelee(actor))
{
if (inIdle(actor->xspr.aiState) || Chance(getDodgeChance(actor)))
{
if (!spriteIsUnderwater(actor))
{
if (!canDuck(actor) || !dudeIsPlayingSeq(actor, 14)) aiGenDudeNewState(actor, &genDudeDodgeShortL);
else aiGenDudeNewState(actor, &genDudeDodgeShortD);
if (Chance(0x0200))
playGenDudeSound(actor,kGenDudeSndGotHit);
}
else if (dudeIsPlayingSeq(actor, 13))
{
aiGenDudeNewState(actor, &genDudeDodgeShortW);
}
}
}
else if (Chance(0x0200))
{
playGenDudeSound(actor,kGenDudeSndGotHit);
}
}
return nDamage;
}
} }
#endif #endif
@ -1211,56 +1130,8 @@ void RecoilDude(DBloodActor* actor)
{ {
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
case kDudeModernCustom: case kDudeModernCustom:
{ cdudeGet(actor)->Recoil();
GENDUDEEXTRA* pExtra = &actor->genDudeExtra;
int rChance = getRecoilChance(actor);
if (pExtra->canElectrocute && pDudeExtra->teslaHit && !spriteIsUnderwater(actor, false))
{
if (Chance(rChance << 3) || (dudeIsMelee(actor) && Chance(rChance << 4))) aiGenDudeNewState(actor, &genDudeRecoilTesla);
else if (pExtra->canRecoil && Chance(rChance)) aiGenDudeNewState(actor, &genDudeRecoilL);
else if (canWalk(actor))
{
if (Chance(rChance >> 2)) aiGenDudeNewState(actor, &genDudeDodgeL);
else if (Chance(rChance >> 1)) aiGenDudeNewState(actor, &genDudeDodgeShortL);
}
}
else if (pExtra->canRecoil && Chance(rChance))
{
if (inDuck(actor->xspr.aiState) && Chance(rChance >> 2)) aiGenDudeNewState(actor, &genDudeRecoilD);
else if (spriteIsUnderwater(actor, false)) aiGenDudeNewState(actor, &genDudeRecoilW);
else aiGenDudeNewState(actor, &genDudeRecoilL);
}
int rState = inRecoil(actor->xspr.aiState);
if (rState > 0)
{
if (!canWalk(actor))
{
if (rState == 1) actor->xspr.aiState->nextState = &genDudeChaseNoWalkL;
else if (rState == 2) actor->xspr.aiState->nextState = &genDudeChaseNoWalkD;
else actor->xspr.aiState->nextState = &genDudeChaseNoWalkW;
}
else if (!dudeIsMelee(actor) || Chance(rChance >> 2))
{
if (rState == 1) actor->xspr.aiState->nextState = (Chance(rChance) ? &genDudeDodgeL : &genDudeDodgeShortL);
else if (rState == 2) actor->xspr.aiState->nextState = (Chance(rChance) ? &genDudeDodgeD : &genDudeDodgeShortD);
else if (rState == 3) actor->xspr.aiState->nextState = (Chance(rChance) ? &genDudeDodgeW : &genDudeDodgeShortW);
}
else if (rState == 1) actor->xspr.aiState->nextState = &genDudeChaseL;
else if (rState == 2) actor->xspr.aiState->nextState = &genDudeChaseD;
else actor->xspr.aiState->nextState = &genDudeChaseW;
playGenDudeSound(actor,kGenDudeSndGotHit);
}
pDudeExtra->teslaHit = 0;
break; break;
}
#endif #endif
case kDudeCultistTommy: case kDudeCultistTommy:
case kDudeCultistShotgun: case kDudeCultistShotgun:
@ -1570,9 +1441,14 @@ void aiProcessDudes(void)
BloodStatIterator it(kStatDude); BloodStatIterator it(kStatDude);
while (auto actor = it.Next()) while (auto actor = it.Next())
{ {
if (actor->spr.flags & 32) continue; if (actor->spr.flags & kHitagFree || actor->IsPlayerActor()) continue;
DUDEINFO* pDudeInfo = getDudeInfo(actor); if (IsCustomDude(actor))
if (actor->IsPlayerActor() || actor->xspr.health == 0) continue; {
cdudeGet(actor)->Process();
continue;
}
if (actor->xspr.health == 0) continue;
actor->xspr.stateTimer = ClipLow(actor->xspr.stateTimer - 4, 0); actor->xspr.stateTimer = ClipLow(actor->xspr.stateTimer - 4, 0);
@ -1585,26 +1461,6 @@ void aiProcessDudes(void)
callActorFunction(*actor->xspr.aiState->thinkFunc, actor); callActorFunction(*actor->xspr.aiState->thinkFunc, actor);
} }
#ifdef NOONE_EXTENSIONS
switch (actor->GetType()) {
case kDudeModernCustom:
{
GENDUDEEXTRA* pExtra = &actor->genDudeExtra;
if (pExtra->slaveCount > 0) updateTargetOfSlaves(actor);
if (pExtra->pLifeLeech != nullptr) updateTargetOfLeech(actor);
if (actor->xspr.stateTimer == 0 && actor->xspr.aiState && actor->xspr.aiState->nextState
&& (actor->xspr.aiState->stateTicks > 0 || seqGetStatus(actor) < 0))
{
aiGenDudeNewState(actor, actor->xspr.aiState->nextState);
}
int hinder = ((pExtra->isMelee) ? 25 : 5) << 4;
if (actor->xspr.health <= 0 || hinder > actor->cumulDamage) break;
actor->xspr.data3 = actor->cumulDamage;
RecoilDude(actor);
break;
}
default:
#endif
if (actor->xspr.stateTimer == 0 && actor->xspr.aiState && actor->xspr.aiState->nextState) { if (actor->xspr.stateTimer == 0 && actor->xspr.aiState && actor->xspr.aiState->nextState) {
if (actor->xspr.aiState->stateTicks > 0) if (actor->xspr.aiState->stateTicks > 0)
aiNewState(actor, actor->xspr.aiState->nextState); aiNewState(actor, actor->xspr.aiState->nextState);
@ -1612,15 +1468,11 @@ void aiProcessDudes(void)
aiNewState(actor, actor->xspr.aiState->nextState); aiNewState(actor, actor->xspr.aiState->nextState);
} }
if (actor->xspr.health > 0 && ((pDudeInfo->hinderDamage << 4) <= actor->cumulDamage)) if (actor->xspr.health > 0 && ((getDudeInfo(actor)->hinderDamage << 4) <= actor->cumulDamage))
{ {
actor->xspr.data3 = actor->cumulDamage; actor->xspr.data3 = actor->cumulDamage;
RecoilDude(actor); RecoilDude(actor);
} }
#ifdef NOONE_EXTENSIONS
break;
}
#endif
} }
it.Reset(kStatDude); it.Reset(kStatDude);
@ -1653,19 +1505,15 @@ void aiInitSprite(DBloodActor* actor)
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
unsigned int stateTimer = 0; unsigned int stateTimer = 0;
DVector3 targetV(0,0,0); DVector3 targetV(0,0,0);
DBloodActor* pTargetMarker = nullptr; DBloodActor* pTarget = nullptr;
// dude patrol init // dude patrol init
if (gModernMap) if (gModernMap)
{
// must keep it in case of loading save
if (actor->xspr.dudeFlag4 && actor->GetTarget() && actor->GetTarget()->GetType() == kMarkerPath)
{ {
stateTimer = actor->xspr.stateTimer; stateTimer = actor->xspr.stateTimer;
pTargetMarker = actor->GetTarget(); pTarget = actor->GetTarget();
targetV = actor->xspr.TargetPos; targetV = actor->xspr.TargetPos;
} }
}
#endif #endif
switch (actor->GetType()) switch (actor->GetType())
@ -1816,8 +1664,8 @@ void aiInitSprite(DBloodActor* actor)
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
case kDudeModernCustom: case kDudeModernCustom:
if (!gModernMap) break; if (!gModernMap) break;
aiGenDudeInitSprite(actor); CUSTOMDUDE_SETUP::Setup(actor);
genDudePrepare(actor, kGenDudePropertyAll); cdudeGet(actor)->InitSprite();
break; break;
#endif #endif
default: default:
@ -1878,23 +1726,36 @@ void aiInitSprite(DBloodActor* actor)
{ {
if (actor->xspr.dudeFlag4) if (actor->xspr.dudeFlag4)
{ {
// restore dude's path bool patrol = false;
if (pTargetMarker) if (pTarget == nullptr)
{ {
actor->SetTarget(pTargetMarker); patrol = true;
actor->xspr.TargetPos = targetV; stateTimer = 0;
// start new patrol
actor->xspr.target = -1;
aiPatrolSetMarker(actor);
} }
else
{
if (pTarget->IsDudeActor()) patrol = false;
else if (pTarget->GetType() == kMarkerPath)
{
// continue patrol
actor->xspr.target = pTarget;
actor->xspr.TargetPos = targetV;
patrol = true;
}
}
if (patrol)
{
// reset target spot progress // reset target spot progress
actor->xspr.data3 = 0; actor->xspr.data3 = 0;
// make dude follow the markers // make dude follow the markers
bool uwater = spriteIsUnderwater(actor); bool uwater = spriteIsUnderwater(actor);
if (actor->GetTarget() == nullptr || actor->GetTarget()->GetType() != kMarkerPath)
{
actor->SetTarget(nullptr);
aiPatrolSetMarker(actor);
}
if (stateTimer > 0) if (stateTimer > 0)
{ {
@ -1908,6 +1769,7 @@ void aiInitSprite(DBloodActor* actor)
else aiPatrolState(actor, kAiStatePatrolMoveL); else aiPatrolState(actor, kAiStatePatrolMoveL);
} }
} }
}
#endif #endif
} }

View file

@ -264,8 +264,10 @@ DEF_ANIMATOR(fxPodBloodSpray) // 18
DEF_ANIMATOR(fxPodBloodSplat) // 19 DEF_ANIMATOR(fxPodBloodSplat) // 19
DEF_ANIMATOR(LeechStateTimer) // 20 DEF_ANIMATOR(LeechStateTimer) // 20
DEF_ANIMATOR(DropVoodooCb) // unused DEF_ANIMATOR(DropVoodooCb) // unused
DEF_ANIMATOR(callbackMakeMissileBlocking) // 23
DEF_ANIMATOR(callbackMissileBurst) DEF_ANIMATOR(callbackMissileBurst)
DEF_ANIMATOR(callbackMakeMissileBlocking) // 23
DEF_ANIMATOR(fxPodGreenBloodSpray) // 24
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
DEF_ANIMATOR(forcePunch) DEF_ANIMATOR(forcePunch)

View file

@ -291,6 +291,13 @@ void Respawn(DBloodActor* actor) // 9
actor->xspr.health = getDudeInfo(actor)->startHealth << 4; actor->xspr.health = getDudeInfo(actor)->startHealth << 4;
#ifdef NOONE_EXTENSIONS #ifdef NOONE_EXTENSIONS
// return dude to the patrol state
if (gModernMap && actor->xspr.dudeFlag4)
{
actor->xspr.data3 = 0;
actor->SetTarget(nullptr);
}
switch (actor->GetType()) { switch (actor->GetType()) {
default: default:
actor->clipdist = getDudeInfo(nType + kDudeBase)->fClipdist(); actor->clipdist = getDudeInfo(nType + kDudeBase)->fClipdist();
@ -302,11 +309,6 @@ void Respawn(DBloodActor* actor) // 9
break; break;
} }
// return dude to the patrol state
if (gModernMap && actor->xspr.dudeFlag4) {
actor->xspr.data3 = 0;
actor->SetTarget(nullptr);
}
#else #else
actor->clipdist = getDudeInfo(nType + kDudeBase)->fClipdist(); actor->clipdist = getDudeInfo(nType + kDudeBase)->fClipdist();
if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID)) if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID))
@ -888,5 +890,17 @@ void callbackMakeMissileBlocking(DBloodActor* actor) // 23
actor->spr.cstat |= CSTAT_SPRITE_BLOCK; actor->spr.cstat |= CSTAT_SPRITE_BLOCK;
} }
void fxPodGreenBloodSpray(DBloodActor* actor) // 24
{
auto pFX = gFX.fxSpawnActor(FX_53, actor->sector(), actor->spr.pos);
if (pFX)
{
pFX->spr.Angles.Yaw = nullAngle;
pFX->vel = actor->vel / 256.;
}
evPostActor(actor, 6, AF(fxPodGreenBloodSpray));
}
END_BLD_NS END_BLD_NS

View file

@ -1252,7 +1252,7 @@ class CUSTOMDUDE
void Process(void); void Process(void);
void ProcessEffects(void); void ProcessEffects(void);
void Recoil(void); void Recoil(void);
int Damage(int nFrom, int nDmgType, int nDmg); int Damage(DBloodActor* nFrom, int nDmgType, int nDmg);
void Kill(DBloodActor* nFrom, int nDmgType, int nDmg); void Kill(DBloodActor* nFrom, int nDmgType, int nDmg);
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
char CanMove(sectortype* pXSect, char Crusher, char Water, char Uwater, char Depth, int bottom, int floorZ); char CanMove(sectortype* pXSect, char Crusher, char Water, char Uwater, char Depth, int bottom, int floorZ);
@ -1332,7 +1332,7 @@ class CUSTOMDUDE_SETUP
char IsFirst(CUSTOMDUDE* pCmp); char IsFirst(CUSTOMDUDE* pCmp);
public: public:
char FindAiState(AISTATE stateArr[][kCdudePostureMax], int arrLen, AISTATE* pNeedle, int* nType, int* nPosture); char FindAiState(AISTATE stateArr[][kCdudePostureMax], int arrLen, AISTATE* pNeedle, int* nType, int* nPosture);
void Setup(spritetype* pSpr, XSPRITE* pXSpr); static void Setup(DBloodActor* actor);
static void Setup(CUSTOMDUDE* pOver = nullptr); static void Setup(CUSTOMDUDE* pOver = nullptr);
}; };