diff --git a/source/games/exhumed/src/aistuff.h b/source/games/exhumed/src/aistuff.h index dbf2c36715b..a0c0ad20871 100644 --- a/source/games/exhumed/src/aistuff.h +++ b/source/games/exhumed/src/aistuff.h @@ -492,6 +492,14 @@ struct AILavaDudeLimb : public ExhumedAI void Draw(RunListEvent* ev) override; }; +struct AILion : public ExhumedAI +{ + void Tick(RunListEvent* ev) override; + void Damage(RunListEvent* ev) override; + void Draw(RunListEvent* ev) override; + void RadialDamage(RunListEvent* ev) override; +}; + void runlist_DispatchEvent(ExhumedAI* ai, int nObject, int nMessage, int nDamage, int nRun); diff --git a/source/games/exhumed/src/lion.cpp b/source/games/exhumed/src/lion.cpp index d476009aebb..db81c3d1dce 100644 --- a/source/games/exhumed/src/lion.cpp +++ b/source/games/exhumed/src/lion.cpp @@ -139,469 +139,481 @@ void BuildLion(short nSprite, int x, int y, int z, short nSector, short nAngle) nCreaturesTotal++; } -void FuncLion(int nObject, int nMessage, int nDamage, int nRun) +void AILion::Draw(RunListEvent* ev) +{ + short nLion = RunData[ev->nRun].nVal; + assert(nLion >= 0 && nLion < (int)LionList.Size()); + short nAction = LionList[nLion].nAction; + + seq_PlotSequence(ev->nIndex, SeqOffsets[kSeqLion] + LionSeq[nAction].a, LionList[nLion].nFrame, LionSeq[nAction].b); +} + +void AILion::RadialDamage(RunListEvent* ev) { - short nLion = RunData[nRun].nVal; + short nLion = RunData[ev->nRun].nVal; assert(nLion >= 0 && nLion < (int)LionList.Size()); short nSprite = LionList[nLion].nSprite; - auto pSprite = &sprite[nSprite]; - short nAction = LionList[nLion].nAction; - bool bVal = false; + ev->nDamage = runlist_CheckRadialDamage(nSprite); + // now fall through to 0x80000 + Damage(ev); +} + +void AILion::Damage(RunListEvent* ev) +{ + short nLion = RunData[ev->nRun].nVal; + assert(nLion >= 0 && nLion < (int)LionList.Size()); - switch (nMessage) + short nSprite = LionList[nLion].nSprite; + auto pSprite = &sprite[nSprite]; + short nAction = LionList[nLion].nAction; + + if (ev->nDamage && LionList[nLion].nHealth > 0) { - default: + LionList[nLion].nHealth -= dmgAdjust(ev->nDamage); + if (LionList[nLion].nHealth <= 0) { - Printf("unknown msg %d for Lion\n", nMessage); - return; - } + // R.I.P. + pSprite->xvel = 0; + pSprite->yvel = 0; + pSprite->zvel = 0; + pSprite->cstat &= 0xFEFE; - case 0x90000: - { - seq_PlotSequence(nObject, SeqOffsets[kSeqLion] + LionSeq[nAction].a, LionList[nLion].nFrame, LionSeq[nAction].b); - return; - } + LionList[nLion].nHealth = 0; - case 0xA0000: - { - nDamage = runlist_CheckRadialDamage(nSprite); - // now fall through to 0x80000 - fallthrough__; - } - case 0x80000: - { - if (nDamage && LionList[nLion].nHealth > 0) + nCreaturesKilled++; + + if (nAction < 10) { - LionList[nLion].nHealth -= dmgAdjust(nDamage); - if (LionList[nLion].nHealth <= 0) + DropMagic(nSprite); + + if (ev->nMessage == EMessageType::RadialDamage) { - // R.I.P. - pSprite->xvel = 0; - pSprite->yvel = 0; - pSprite->zvel = 0; - pSprite->cstat &= 0xFEFE; + LionList[nLion].nAction = 11; + } + else + { + LionList[nLion].nAction = 10; + } - LionList[nLion].nHealth = 0; + LionList[nLion].nFrame = 0; + return; + } + } + else + { + short nTarget = ev->nIndex; - nCreaturesKilled++; + if (nTarget > -1) + { + if (sprite[nTarget].statnum < 199) { + LionList[nLion].nTarget = nTarget; + } - if (nAction < 10) + if (nAction != 6) + { + if (RandomSize(8) <= (LionList[nLion].nHealth >> 2)) { - DropMagic(nSprite); - - if (nMessage == 0xA0000) { - LionList[nLion].nAction = 11; - } - else - { - LionList[nLion].nAction = 10; - } - - LionList[nLion].nFrame = 0; - return; + LionList[nLion].nAction = 4; + pSprite->xvel = 0; + pSprite->yvel = 0; } - } - else - { - short nTarget = nObject; - - if (nTarget > -1) + else if (RandomSize(1)) { - if (sprite[nTarget].statnum < 199) { - LionList[nLion].nTarget = nTarget; - } - - if (nAction != 6) - { - if (RandomSize(8) <= (LionList[nLion].nHealth >> 2)) - { - LionList[nLion].nAction = 4; - pSprite->xvel = 0; - pSprite->yvel = 0; - } - else if (RandomSize(1)) - { - PlotCourseToSprite(nSprite, nTarget); - LionList[nLion].nAction = 5; - LionList[nLion].nCount = RandomSize(3); - pSprite->ang = (pSprite->ang - (RandomSize(1) << 8)) + (RandomSize(1) << 8); // NOTE: no angle mask in original code - } - else - { - LionList[nLion].nAction = 8; - pSprite->xvel = 0; - pSprite->yvel = 0; - pSprite->cstat &= 0xFEFE; - } - - LionList[nLion].nFrame = 0; - } + PlotCourseToSprite(nSprite, nTarget); + LionList[nLion].nAction = 5; + LionList[nLion].nCount = RandomSize(3); + pSprite->ang = (pSprite->ang - (RandomSize(1) << 8)) + (RandomSize(1) << 8); // NOTE: no angle mask in original code } + else + { + LionList[nLion].nAction = 8; + pSprite->xvel = 0; + pSprite->yvel = 0; + pSprite->cstat &= 0xFEFE; + } + + LionList[nLion].nFrame = 0; } } - return; } + } +} - case 0x20000: - { - if (nAction != 7) { - Gravity(nSprite); - } +void AILion::Tick(RunListEvent* ev) +{ + short nLion = RunData[ev->nRun].nVal; + assert(nLion >= 0 && nLion < (int)LionList.Size()); - short nSeq = SeqOffsets[kSeqLion] + LionSeq[nAction].a; + short nSprite = LionList[nLion].nSprite; + auto pSprite = &sprite[nSprite]; + short nAction = LionList[nLion].nAction; - pSprite->picnum = seq_GetSeqPicnum2(nSeq, LionList[nLion].nFrame); + bool bVal = false; - seq_MoveSequence(nSprite, nSeq, LionList[nLion].nFrame); - LionList[nLion].nFrame++; - if (LionList[nLion].nFrame >= SeqSize[nSeq]) - { - LionList[nLion].nFrame = 0; - bVal = true; - } + if (nAction != 7) { + Gravity(nSprite); + } - short nFlag = FrameFlag[SeqBase[nSeq] + LionList[nLion].nFrame]; - short nTarget = LionList[nLion].nTarget; + short nSeq = SeqOffsets[kSeqLion] + LionSeq[nAction].a; - int nMov = MoveCreatureWithCaution(nSprite); + pSprite->picnum = seq_GetSeqPicnum2(nSeq, LionList[nLion].nFrame); - switch (nAction) - { - default: - return; + seq_MoveSequence(nSprite, nSeq, LionList[nLion].nFrame); - case 0: - case 1: - { - if ((LionList[nLion].nIndex & 0x1F) == (totalmoves & 0x1F)) - { - if (nTarget < 0) - { - nTarget = FindPlayer(nSprite, 40); - if (nTarget >= 0) - { - D3PlayFX(StaticSound[kSound24], nSprite); - LionList[nLion].nAction = 2; - LionList[nLion].nFrame = 0; - - pSprite->xvel = bcos(pSprite->ang, -1); - pSprite->yvel = bsin(pSprite->ang, -1); - LionList[nLion].nTarget = nTarget; - return; - } - } - } + LionList[nLion].nFrame++; + if (LionList[nLion].nFrame >= SeqSize[nSeq]) + { + LionList[nLion].nFrame = 0; + bVal = true; + } - if (nAction && !easy()) - { - LionList[nLion].nCount--; - if (LionList[nLion].nCount <= 0) - { - if (RandomBit()) - { - pSprite->ang = RandomWord() & kAngleMask; - pSprite->xvel = bcos(pSprite->ang, -1); - pSprite->yvel = bsin(pSprite->ang, -1); - } - else - { - pSprite->xvel = 0; - pSprite->yvel = 0; - } - - LionList[nLion].nCount = 100; - } - } + short nFlag = FrameFlag[SeqBase[nSeq] + LionList[nLion].nFrame]; + short nTarget = LionList[nLion].nTarget; + + int nMov = MoveCreatureWithCaution(nSprite); + switch (nAction) + { + default: + return; + + case 0: + case 1: + { + if ((LionList[nLion].nIndex & 0x1F) == (totalmoves & 0x1F)) + { + if (nTarget < 0) + { + nTarget = FindPlayer(nSprite, 40); + if (nTarget >= 0) + { + D3PlayFX(StaticSound[kSound24], nSprite); + LionList[nLion].nAction = 2; + LionList[nLion].nFrame = 0; + + pSprite->xvel = bcos(pSprite->ang, -1); + pSprite->yvel = bsin(pSprite->ang, -1); + LionList[nLion].nTarget = nTarget; return; } + } + } - case 2: + if (nAction && !easy()) + { + LionList[nLion].nCount--; + if (LionList[nLion].nCount <= 0) + { + if (RandomBit()) { - if ((totalmoves & 0x1F) == (LionList[nLion].nIndex & 0x1F)) - { - PlotCourseToSprite(nSprite, nTarget); + pSprite->ang = RandomWord() & kAngleMask; + pSprite->xvel = bcos(pSprite->ang, -1); + pSprite->yvel = bsin(pSprite->ang, -1); + } + else + { + pSprite->xvel = 0; + pSprite->yvel = 0; + } - int nAng = pSprite->ang & 0xFFF8; - - if (pSprite->cstat & 0x8000) - { - pSprite->xvel = bcos(nAng, 1); - pSprite->yvel = bsin(nAng, 1); - } - else - { - pSprite->xvel = bcos(nAng, -1); - pSprite->yvel = bsin(nAng, -1); - } - } + LionList[nLion].nCount = 100; + } + } - if ((nMov & 0xC000) < 0x8000) - { - break; - } - else if ((nMov & 0xC000) == 0x8000) - { - // loc_378FA: - pSprite->ang = (pSprite->ang + 256) & kAngleMask; - pSprite->xvel = bcos(pSprite->ang, -1); - pSprite->yvel = bsin(pSprite->ang, -1); - break; - } - else if ((nMov & 0xC000) == 0xC000) - { - if ((nMov & 0x3FFF) == nTarget) - { - if (pSprite->cstat & 0x8000) - { - LionList[nLion].nAction = 9; - pSprite->cstat &= 0x7FFF; - pSprite->xvel = 0; - pSprite->yvel = 0; - } - else - { - int nAng = getangle(sprite[nTarget].x - pSprite->x, sprite[nTarget].y - pSprite->y); - - if (AngleDiff(pSprite->ang, nAng) < 64) - { - LionList[nLion].nAction = 3; - } - } - - LionList[nLion].nFrame = 0; - break; - } - else - { - // loc_378FA: - pSprite->ang = (pSprite->ang + 256) & kAngleMask; - pSprite->xvel = bcos(pSprite->ang, -1); - pSprite->yvel = bsin(pSprite->ang, -1); - break; - } - } + return; + } - break; - } + case 2: + { + if ((totalmoves & 0x1F) == (LionList[nLion].nIndex & 0x1F)) + { + PlotCourseToSprite(nSprite, nTarget); - case 3: - { - if (nTarget == -1) - { - LionList[nLion].nAction = 1; - LionList[nLion].nCount = 50; - } - else - { - if (PlotCourseToSprite(nSprite, nTarget) >= 768) - { - LionList[nLion].nAction = 2; - } - else if (nFlag & 0x80) - { - runlist_DamageEnemy(nTarget, nSprite, 10); - } - } + int nAng = pSprite->ang & 0xFFF8; - break; - } + if (pSprite->cstat & 0x8000) + { + pSprite->xvel = bcos(nAng, 1); + pSprite->yvel = bsin(nAng, 1); + } + else + { + pSprite->xvel = bcos(nAng, -1); + pSprite->yvel = bsin(nAng, -1); + } + } - case 4: + if ((nMov & 0xC000) < 0x8000) + { + break; + } + else if ((nMov & 0xC000) == 0x8000) + { + // loc_378FA: + pSprite->ang = (pSprite->ang + 256) & kAngleMask; + pSprite->xvel = bcos(pSprite->ang, -1); + pSprite->yvel = bsin(pSprite->ang, -1); + break; + } + else if ((nMov & 0xC000) == 0xC000) + { + if ((nMov & 0x3FFF) == nTarget) + { + if (pSprite->cstat & 0x8000) { - if (bVal) - { - LionList[nLion].nAction = 2; - LionList[nLion].nFrame = 0; - } + LionList[nLion].nAction = 9; + pSprite->cstat &= 0x7FFF; + pSprite->xvel = 0; + pSprite->yvel = 0; + } + else + { + int nAng = getangle(sprite[nTarget].x - pSprite->x, sprite[nTarget].y - pSprite->y); - if (nMov & 0x20000) + if (AngleDiff(pSprite->ang, nAng) < 64) { - pSprite->xvel >>= 1; - pSprite->yvel >>= 1; + LionList[nLion].nAction = 3; } - - return; } - case 5: // Jump away when damaged - { - LionList[nLion].nCount--; - if (LionList[nLion].nCount <= 0) - { - pSprite->zvel = -4000; - LionList[nLion].nCount = 0; + LionList[nLion].nFrame = 0; + break; + } + else + { + // loc_378FA: + pSprite->ang = (pSprite->ang + 256) & kAngleMask; + pSprite->xvel = bcos(pSprite->ang, -1); + pSprite->yvel = bsin(pSprite->ang, -1); + break; + } + } - int x = pSprite->x; - int y = pSprite->y; - int z = pSprite->z - (GetSpriteHeight(nSprite) >> 1); + break; + } - int nCheckDist = 0x7FFFFFFF; + case 3: + { + if (nTarget == -1) + { + LionList[nLion].nAction = 1; + LionList[nLion].nCount = 50; + } + else + { + if (PlotCourseToSprite(nSprite, nTarget) >= 768) + { + LionList[nLion].nAction = 2; + } + else if (nFlag & 0x80) + { + runlist_DamageEnemy(nTarget, nSprite, 10); + } + } - short nAngle = pSprite->ang; - short nScanAngle = (pSprite->ang - 512) & kAngleMask; + break; + } + + case 4: + { + if (bVal) + { + LionList[nLion].nAction = 2; + LionList[nLion].nFrame = 0; + } - for (int i = 0; i < 5; i++) - { - short hitwall; - int hitx, hity; - vec3_t startPos = { x, y, z }; - hitdata_t hitData; + if (nMov & 0x20000) + { + pSprite->xvel >>= 1; + pSprite->yvel >>= 1; + } - hitscan(&startPos, pSprite->sectnum, bcos(nScanAngle), bsin(nScanAngle), 0, &hitData, CLIPMASK1); + return; + } - hitx = hitData.pos.x; - hity = hitData.pos.y; - hitwall = hitData.wall; + case 5: // Jump away when damaged + { + LionList[nLion].nCount--; + if (LionList[nLion].nCount <= 0) + { + pSprite->zvel = -4000; + LionList[nLion].nCount = 0; - if (hitwall > -1) - { - int theX = abs(hitx - x); - int theY = abs(hity - y); + int x = pSprite->x; + int y = pSprite->y; + int z = pSprite->z - (GetSpriteHeight(nSprite) >> 1); - if ((theX + theY) < nCheckDist) - { - nCheckDist = theX; - nAngle = nScanAngle; - } - } + int nCheckDist = 0x7FFFFFFF; - nScanAngle += 256; - nScanAngle &= kAngleMask; - } + short nAngle = pSprite->ang; + short nScanAngle = (pSprite->ang - 512) & kAngleMask; - pSprite->ang = nAngle; + for (int i = 0; i < 5; i++) + { + short hitwall; + int hitx, hity; + vec3_t startPos = { x, y, z }; + hitdata_t hitData; - LionList[nLion].nAction = 6; - pSprite->xvel = bcos(pSprite->ang) - bcos(pSprite->ang, -3); - pSprite->yvel = bsin(pSprite->ang) - bsin(pSprite->ang, -3); - D3PlayFX(StaticSound[kSound24], nSprite); - } + hitscan(&startPos, pSprite->sectnum, bcos(nScanAngle), bsin(nScanAngle), 0, &hitData, CLIPMASK1); - return; - } + hitx = hitData.pos.x; + hity = hitData.pos.y; + hitwall = hitData.wall; - case 6: + if (hitwall > -1) { - if (nMov & 0x30000) - { - LionList[nLion].nAction = 2; - LionList[nLion].nFrame = 0; - return; - } + int theX = abs(hitx - x); + int theY = abs(hity - y); - if ((nMov & 0xC000) == 0x8000) + if ((theX + theY) < nCheckDist) { - LionList[nLion].nAction = 7; - pSprite->ang = (GetWallNormal(nMov & 0x3FFF) + 1024) & kAngleMask; - LionList[nLion].nCount = RandomSize(4); - return; + nCheckDist = theX; + nAngle = nScanAngle; } - else if ((nMov & 0xC000) == 0xC000) - { - if ((nMov & 0x3FFF) == nTarget) - { - int nAng = getangle(sprite[nTarget].x - pSprite->x, sprite[nTarget].y - pSprite->y); - if (AngleDiff(pSprite->ang, nAng) < 64) - { - LionList[nLion].nAction = 3; - LionList[nLion].nFrame = 0; - } - } - else - { - // loc_378FA: - pSprite->ang = (pSprite->ang + 256) & kAngleMask; - pSprite->xvel = bcos(pSprite->ang, -1); - pSprite->yvel = bsin(pSprite->ang, -1); - break; - } - } - - return; } - case 7: - { - LionList[nLion].nCount--; + nScanAngle += 256; + nScanAngle &= kAngleMask; + } - if (LionList[nLion].nCount <= 0) - { - LionList[nLion].nCount = 0; - if (nTarget > -1) - { - PlotCourseToSprite(nSprite, nTarget); - } - else - { - pSprite->ang = (RandomSize(9) + (pSprite->ang + 768)) & kAngleMask; - } - - pSprite->zvel = -1000; - - LionList[nLion].nAction = 6; - pSprite->xvel = bcos(pSprite->ang) - bcos(pSprite->ang, -3); - pSprite->yvel = bsin(pSprite->ang) - bsin(pSprite->ang, -3); - D3PlayFX(StaticSound[kSound24], nSprite); - } + pSprite->ang = nAngle; - return; - } + LionList[nLion].nAction = 6; + pSprite->xvel = bcos(pSprite->ang) - bcos(pSprite->ang, -3); + pSprite->yvel = bsin(pSprite->ang) - bsin(pSprite->ang, -3); + D3PlayFX(StaticSound[kSound24], nSprite); + } - case 8: - { - if (bVal) - { - LionList[nLion].nAction = 2; - LionList[nLion].nFrame = 0; - pSprite->cstat |= 0x8000; - } - return; - } + return; + } - case 9: - { - if (bVal) - { - LionList[nLion].nFrame = 0; - LionList[nLion].nAction = 2; - pSprite->cstat |= 0x101; - } - return; - } + case 6: + { + if (nMov & 0x30000) + { + LionList[nLion].nAction = 2; + LionList[nLion].nFrame = 0; + return; + } - case 10: - case 11: + if ((nMov & 0xC000) == 0x8000) + { + LionList[nLion].nAction = 7; + pSprite->ang = (GetWallNormal(nMov & 0x3FFF) + 1024) & kAngleMask; + LionList[nLion].nCount = RandomSize(4); + return; + } + else if ((nMov & 0xC000) == 0xC000) + { + if ((nMov & 0x3FFF) == nTarget) + { + int nAng = getangle(sprite[nTarget].x - pSprite->x, sprite[nTarget].y - pSprite->y); + if (AngleDiff(pSprite->ang, nAng) < 64) { - if (bVal) - { - runlist_SubRunRec(pSprite->owner); - runlist_SubRunRec(LionList[nLion].nRun); - pSprite->cstat = 0x8000; - } - return; + LionList[nLion].nAction = 3; + LionList[nLion].nFrame = 0; } } + else + { + // loc_378FA: + pSprite->ang = (pSprite->ang + 256) & kAngleMask; + pSprite->xvel = bcos(pSprite->ang, -1); + pSprite->yvel = bsin(pSprite->ang, -1); + break; + } + } + + return; + } + + case 7: + { + LionList[nLion].nCount--; - // loc_379AD: ? - if (nAction != 1 && nTarget != -1) + if (LionList[nLion].nCount <= 0) + { + LionList[nLion].nCount = 0; + if (nTarget > -1) { - if (!(sprite[nTarget].cstat & 0x101)) - { - LionList[nLion].nAction = 1; - LionList[nLion].nFrame = 0; - LionList[nLion].nCount = 100; - LionList[nLion].nTarget = -1; - pSprite->xvel = 0; - pSprite->yvel = 0; - } + PlotCourseToSprite(nSprite, nTarget); + } + else + { + pSprite->ang = (RandomSize(9) + (pSprite->ang + 768)) & kAngleMask; } - return; + pSprite->zvel = -1000; + + LionList[nLion].nAction = 6; + pSprite->xvel = bcos(pSprite->ang) - bcos(pSprite->ang, -3); + pSprite->yvel = bsin(pSprite->ang) - bsin(pSprite->ang, -3); + D3PlayFX(StaticSound[kSound24], nSprite); + } + + return; + } + + case 8: + { + if (bVal) + { + LionList[nLion].nAction = 2; + LionList[nLion].nFrame = 0; + pSprite->cstat |= 0x8000; + } + return; + } + + case 9: + { + if (bVal) + { + LionList[nLion].nFrame = 0; + LionList[nLion].nAction = 2; + pSprite->cstat |= 0x101; + } + return; + } + + case 10: + case 11: + { + if (bVal) + { + runlist_SubRunRec(pSprite->owner); + runlist_SubRunRec(LionList[nLion].nRun); + pSprite->cstat = 0x8000; + } + return; + } + } + + // loc_379AD: ? + if (nAction != 1 && nTarget != -1) + { + if (!(sprite[nTarget].cstat & 0x101)) + { + LionList[nLion].nAction = 1; + LionList[nLion].nFrame = 0; + LionList[nLion].nCount = 100; + LionList[nLion].nTarget = -1; + pSprite->xvel = 0; + pSprite->yvel = 0; } } } + + + +void FuncLion(int nObject, int nMessage, int nDamage, int nRun) +{ + AILion ai; + runlist_DispatchEvent(&ai, nObject, nMessage, nDamage, nRun); +} + END_PS_NS