From a7572bca0abb08f33e1c65d516ccd224b82aad90 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 3 Dec 2020 18:00:07 +0100 Subject: [PATCH] - actImpactMissile. --- source/games/blood/src/actor.cpp | 682 +++++++++++++--------------- source/games/blood/src/actor.h | 3 +- source/games/blood/src/aibeast.cpp | 16 +- source/games/blood/src/bloodactor.h | 11 + source/games/blood/src/eventq.cpp | 16 + source/games/blood/src/eventq.h | 4 + source/games/blood/src/gameutil.cpp | 6 + source/games/blood/src/gameutil.h | 1 + source/games/blood/src/triggers.cpp | 4 + source/games/blood/src/triggers.h | 1 + source/games/blood/src/weapon.cpp | 7 +- 11 files changed, 376 insertions(+), 375 deletions(-) diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 63f2db9dbb9..77d4a019d37 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -2742,7 +2742,7 @@ static void actNapalmMove(DBloodActor* actor) if (pXSprite->data4 > 1) { - GibSprite(pSprite, GIBTYPE_5, NULL, NULL); + GibSprite(pSprite, GIBTYPE_5, nullptr, nullptr); int spawnparam[2]; spawnparam[0] = pXSprite->data4 >> 1; spawnparam[1] = pXSprite->data4 - spawnparam[0]; @@ -2880,7 +2880,7 @@ static DBloodActor* actDropFlag(DBloodActor* actor, int nType) auto act2 = actDropItem(actor, nType); if (act2 && gGameOptions.nGameType == 3) { - evPost(act2->s().index, 3, 1800, kCallbackReturnFlag); + evPost(act2, 1800, kCallbackReturnFlag); } return act2; } @@ -2949,7 +2949,7 @@ static bool actKillModernDude(DBloodActor* actor, DAMAGE_TYPE damageType) auto pXSprite = &actor->x(); GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); removeDudeStuff(pSprite); - if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) + if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == nullptr) { if (pExtra->weaponType == kGenDudeWeaponKamikaze && Chance(0x4000) && damageType != DAMAGE_TYPE_5 && damageType != DAMAGE_TYPE_4) { @@ -3280,7 +3280,7 @@ static void zombieAxeNormalDeath(DBloodActor* actor, int nSeq) else if (nSeq == 1 && Chance(0x4000)) { seqSpawn(dudeInfo[nType].seqStartID + 7, actor, nDudeToGibClient1); - evPost(pSprite->index, 3, 0, kCallbackFXZombieSpurt); + evPost(actor, 0, kCallbackFXZombieSpurt); sfxPlay3DSound(pSprite, 362, -1, 0); actor->x().data1 = 35; actor->x().data2 = 5; @@ -3308,7 +3308,7 @@ static void burningCultistDeath(DBloodActor* actor, int nSeq) if (Chance(0x8000)) { for (int i = 0; i < 3; i++) - GibSprite(pSprite, GIBTYPE_7, NULL, NULL); + GibSprite(pSprite, GIBTYPE_7, nullptr, nullptr); seqSpawn(dudeInfo[nType].seqStartID + 16 - Random(1), actor, nDudeToGibClient1); } else @@ -3454,7 +3454,7 @@ void actKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damag gPlayer[p].setFragger(nullptr); } if (pSprite->type != kDudeCultistBeast) - trTriggerSprite(pSprite->index, pXSprite, kCmdOff); + trTriggerSprite(actor, kCmdOff); pSprite->flags |= 7; checkAddFrag(killerActor, actor); @@ -3735,7 +3735,7 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D #ifdef NOONE_EXTENSIONS case kModernThingEnemyLifeLeech: #endif - GibSprite(pSprite, GIBTYPE_14, NULL, NULL); + GibSprite(pSprite, GIBTYPE_14, nullptr, nullptr); pXSprite->data1 = pXSprite->data2 = pXSprite->data3 = pXSprite->DudeLockout = 0; pXSprite->stateTimer = pXSprite->data4 = pXSprite->isTriggered = 0; @@ -3751,7 +3751,7 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D break; } - trTriggerSprite(pSprite->index, pXSprite, kCmdOff); + trTriggerSprite(actor, kCmdOff); switch (pSprite->type) { @@ -3772,7 +3772,7 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D case kThingFluorescent: seqSpawn(12, 3, pSprite->extra, -1); - GibSprite(pSprite, GIBTYPE_6, NULL, NULL); + GibSprite(pSprite, GIBTYPE_6, nullptr, nullptr); break; case kThingSpiderWeb: @@ -3781,14 +3781,14 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D case kThingMetalGrate: seqSpawn(21, 3, pSprite->extra, -1); - GibSprite(pSprite, GIBTYPE_4, NULL, NULL); + GibSprite(pSprite, GIBTYPE_4, nullptr, nullptr); break; case kThingFlammableTree: switch (pXSprite->data1) { case -1: - GibSprite(pSprite, GIBTYPE_14, NULL, NULL); + GibSprite(pSprite, GIBTYPE_14, nullptr, nullptr); sfxPlay3DSound(pSprite->x, pSprite->y, pSprite->z, 312, pSprite->sectnum); actPostSprite(actor, kStatFree); break; @@ -3828,7 +3828,7 @@ int actDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE damageT if (source == nullptr) source = actor; - PLAYER* pSourcePlayer = NULL; + PLAYER* pSourcePlayer = nullptr; if (source->IsPlayerActor()) pSourcePlayer = &gPlayer[source->s().type - kDudePlayer1]; if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pSourcePlayer, pSprite)) return 0; @@ -3847,362 +3847,320 @@ int actDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE damageT //--------------------------------------------------------------------------- // -// +// this was condensed to the parts actually in use. // //--------------------------------------------------------------------------- -void actHitcodeToData(int a1, HITINFO *pHitInfo, int *a3, spritetype **a4, XSPRITE **a5, int *a6, walltype **a7, XWALL **a8, int *a9, sectortype **a10, XSECTOR **a11) +void actHitcodeToData(int a1, HITINFO* pHitInfo, DBloodActor** pActor, walltype** a7) { - assert(pHitInfo != NULL); - int nSprite = -1; - spritetype *pSprite = NULL; - XSPRITE *pXSprite = NULL; - int nWall = -1; - walltype *pWall = NULL; - XWALL *pXWall = NULL; - int nSector = -1; - sectortype *pSector = NULL; - XSECTOR *pXSector = NULL; - switch (a1) - { - case 3: - case 5: - nSprite = pHitInfo->hitsprite; - assert(nSprite >= 0 && nSprite < kMaxSprites); - pSprite = &sprite[nSprite]; - if (pSprite->extra > 0) - pXSprite = &xsprite[pSprite->extra]; - break; - case 0: - case 4: - nWall = pHitInfo->hitwall; - assert(nWall >= 0 && nWall < kMaxWalls); - pWall = &wall[nWall]; - if (pWall->extra > 0) - pXWall = &xwall[pWall->extra]; - break; - case 1: - case 2: - case 6: - nSector = pHitInfo->hitsect; - assert(nSector >= 0 && nSector < kMaxSectors); - pSector = §or[nSector]; - if (pSector->extra > 0) - pXSector = &xsector[pSector->extra]; - break; - } - if (a3) - *a3 = nSprite; - if (a4) - *a4 = pSprite; - if (a5) - *a5 = pXSprite; - if (a6) - *a6 = nWall; - if (a7) - *a7 = pWall; - if (a8) - *a8 = pXWall; - if (a9) - *a9 = nSector; - if (a10) - *a10 = pSector; - if (a11) - *a11 = pXSector; + assert(pHitInfo != nullptr); + int nSprite = -1; + int nWall = -1; + walltype* pWall = nullptr; + switch (a1) + { + case 3: + case 5: + nSprite = pHitInfo->hitsprite; + break; + case 0: + case 4: + nWall = pHitInfo->hitwall; + if (nWall >= 0 && nWall < kMaxWalls) pWall = &wall[nWall]; + break; + default: + break; + } + if (pActor) *pActor = nSprite == -1 ? nullptr : &bloodActors[nSprite]; + if (a7) *a7 = pWall; } -void actImpactMissile(spritetype *pMissile, int hitCode) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static void actImpactMissile(DBloodActor* missileActor, int hitCode) { - int nXMissile = pMissile->extra; - assert(nXMissile > 0 && nXMissile < kMaxXSprites); - XSPRITE *pXMissile = &xsprite[pMissile->extra]; - - int nSpriteHit = -1; int nWallHit = -1; int nSectorHit = -1; - spritetype *pSpriteHit = NULL; XSPRITE *pXSpriteHit = NULL; - walltype *pWallHit = NULL; XWALL *pXWallHit = NULL; - sectortype *pSectorHit = NULL; XSECTOR *pXSectorHit = NULL; - - actHitcodeToData(hitCode, &gHitInfo, &nSpriteHit, &pSpriteHit, &pXSpriteHit, &nWallHit, &pWallHit, &pXWallHit, &nSectorHit, &pSectorHit, &pXSectorHit); - const THINGINFO *pThingInfo = NULL; DUDEINFO *pDudeInfo = NULL; - - if (hitCode == 3 && pSpriteHit) { - switch (pSpriteHit->statnum) { - case kStatThing: - pThingInfo = &thingInfo[pSpriteHit->type - kThingBase]; - break; - case kStatDude: - pDudeInfo = getDudeInfo(pSpriteHit->type); - break; - } - } - switch (pMissile->type) { - case kMissileLifeLeechRegular: - if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) { - int nOwner = pMissile->owner; - DAMAGE_TYPE rand1 = (DAMAGE_TYPE)Random(7); - int rand2 = (7 + Random(7)) << 4; - int nDamage = actDamageSprite(nOwner, pSpriteHit, rand1, rand2); - if ((pThingInfo && pThingInfo->dmgControl[DAMAGE_TYPE_1] != 0) || (pDudeInfo && pDudeInfo->damageVal[DAMAGE_TYPE_1] != 0)) - actBurnSprite(pMissile->owner, pXSpriteHit, 360); - - // by NoOne: make Life Leech heal user, just like it was in 1.0x versions - if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus() && pDudeInfo != NULL) { - spritetype* pSource = &sprite[nOwner]; - XSPRITE* pXSource = (pSource->extra >= 0) ? &xsprite[pSource->extra] : NULL; - - if (IsDudeSprite(pSource) && pXSource != NULL && pXSource->health != 0) - - actHealDude(pXSource, nDamage >> 2, getDudeInfo(pSource->type)->startHealth); - } - } - - if (pMissile->extra > 0) { - actPostSprite(pMissile->index, kStatDecoration); - if (pMissile->ang == 1024) sfxPlay3DSound(pMissile, 307, -1, 0); - pMissile->type = kSpriteDecoration; - seqSpawn(9, 3, pMissile->extra, -1); - } else { - actPostSprite(pMissile->index, kStatFree); - } + auto pMissile = &missileActor->s(); + XSPRITE* pXMissile = &missileActor->x(); + auto missileOwner = missileActor->GetOwner(); - break; - case kMissileTeslaAlt: - teslaHit(pMissile, hitCode); - switch (hitCode) { - case 0: - case 4: - if (pWallHit) { - spritetype* pFX = gFX.fxSpawn(FX_52, pMissile->sectnum, pMissile->x, pMissile->y, pMissile->z, 0); - if (pFX) pFX->ang = (GetWallAngle(nWallHit) + 512) & 2047; - } - break; - } - GibSprite(pMissile, GIBTYPE_24, NULL, NULL); - actPostSprite(pMissile->index, kStatFree); - break; - case kMissilePukeGreen: - seqKill(3, nXMissile); - if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) - { - int nOwner = pMissile->owner; - int nDamage = (15+Random(7))<<4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); - } - actPostSprite(pMissile->index, kStatFree); - break; - case kMissileArcGargoyle: - sfxKill3DSound(pMissile, -1, -1); - sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum); - GibSprite(pMissile, GIBTYPE_6, NULL, NULL); - if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) - { - int nOwner = pMissile->owner; - int nDamage = (25+Random(20))<<4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_5, nDamage); - } - actPostSprite(pMissile->index, kStatFree); - break; - case kMissileLifeLeechAltNormal: - case kMissileLifeLeechAltSmall: - sfxKill3DSound(pMissile, -1, -1); - sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum); - if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) { - int nOwner = pMissile->owner; - int nDmgMul = (pMissile->type == kMissileLifeLeechAltSmall) ? 6 : 3; - int nDamage = (nDmgMul+Random(nDmgMul))<<4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_5, nDamage); - } - actPostSprite(pMissile->index, kStatFree); - break; - case kMissileFireball: - case kMissileFireballNapam: - if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) - { - if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && pXSpriteHit->burnTime == 0) - evPost(nSpriteHit, 3, 0, kCallbackFXFlameLick); - int nOwner = pMissile->owner; - int nDamage = (50+Random(50))<<4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); - } - actExplodeSprite(pMissile); - break; - case kMissileFlareAlt: - sfxKill3DSound(pMissile, -1, -1); - actExplodeSprite(pMissile); - break; - case kMissileFlareRegular: - sfxKill3DSound(pMissile, -1, -1); - if ((hitCode == 3 && pSpriteHit) && (pThingInfo || pDudeInfo)) { - int nOwner = pMissile->owner; - if ((pThingInfo && pThingInfo->dmgControl[DAMAGE_TYPE_1] != 0) || (pDudeInfo && pDudeInfo->damageVal[DAMAGE_TYPE_1] != 0)) { - if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && pXSpriteHit->burnTime == 0) - evPost(nSpriteHit, 3, 0, kCallbackFXFlameLick); - - actBurnSprite(pMissile->owner, pXSpriteHit, 480); - actRadiusDamage(&bloodActors[nOwner], pMissile->x, pMissile->y, pMissile->z, pMissile->sectnum, 16, 20, 10, DAMAGE_TYPE_2, 6, 480); + DBloodActor* actorHit = nullptr; + walltype* pWallHit = nullptr; - // by NoOne: allow additional bullet damage for Flare Gun - if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) { - int nDamage = (20 + Random(10)) << 4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); - } - } else { - int nDamage = (20+Random(10))<<4; - actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); - } - - if (surfType[pSpriteHit->picnum] == kSurfFlesh) { - pMissile->picnum = 2123; - pXMissile->target = nSpriteHit; - pXMissile->targetZ = pMissile->z-pSpriteHit->z; - pXMissile->goalAng = getangle(pMissile->x-pSpriteHit->x, pMissile->y-pSpriteHit->y)-pSpriteHit->ang; - pXMissile->state = 1; - actPostSprite(pMissile->index, kStatFlare); - pMissile->cstat &= ~257; - break; - } - } - GibSprite(pMissile, GIBTYPE_17, NULL, NULL); - actPostSprite(pMissile->index, kStatFree); - break; - case kMissileFlameSpray: - case kMissileFlameHound: - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - if (pObject->extra > 0) - { - XSPRITE *pXObject = &xsprite[pObject->extra]; - if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0) - evPost(nObject, 3, 0, kCallbackFXFlameLick); - int nOwner = pMissile->owner; - actBurnSprite(pMissile->owner, pXObject, (4+gGameOptions.nDifficulty)<<2); - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_1, 8); - } - } - break; - case kMissileFireballCerberus: - actExplodeSprite(pMissile); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - if (pObject->extra > 0) - { - XSPRITE *pXObject = &xsprite[pObject->extra]; - if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0) - evPost(nObject, 3, 0, kCallbackFXFlameLick); - int nOwner = pMissile->owner; - actBurnSprite(pMissile->owner, pXObject, (4+gGameOptions.nDifficulty)<<2); - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_1, 8); - int nDamage = (25+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_2, nDamage); - } - } - actExplodeSprite(pMissile); - break; - case kMissileFireballTchernobog: - actExplodeSprite(pMissile); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - if (pObject->extra > 0) - { - XSPRITE *pXObject = &xsprite[pObject->extra]; - if ((pObject->statnum == kStatThing || pObject->statnum == kStatDude) && pXObject->burnTime == 0) - evPost(nObject, 3, 0, kCallbackFXFlameLick); - int nOwner = pMissile->owner; - actBurnSprite(pMissile->owner, pXObject, 32); - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_5, 12); - int nDamage = (25+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_2, nDamage); - } - } - actExplodeSprite(pMissile); - break; - case kMissileEctoSkull: - sfxKill3DSound(pMissile, -1, -1); - sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 522, pMissile->sectnum); - actPostSprite(pMissile->index, kStatDebris); - seqSpawn(20, 3, pMissile->extra, -1); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - if (pObject->statnum == kStatDude) - { - int nOwner = pMissile->owner; - int nDamage = (25+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_5, nDamage); - } - } - break; - case kMissileButcherKnife: - actPostSprite(pMissile->index, kStatDebris); - pMissile->cstat &= ~16; - pMissile->type = kSpriteDecoration; - seqSpawn(20, 3, pMissile->extra, -1); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - if (pObject->statnum == kStatDude) - { - int nOwner = pMissile->owner; - int nDamage = (10+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_5, nDamage); - spritetype *pOwner = &sprite[nOwner]; - XSPRITE *pXOwner = &xsprite[pOwner->extra]; - int nType = pOwner->type-kDudeBase; - if (pXOwner->health > 0) - actHealDude(pXOwner, 10, getDudeInfo(nType+kDudeBase)->startHealth); - } - } - break; - case kMissileTeslaRegular: - sfxKill3DSound(pMissile, -1, -1); - sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 518, pMissile->sectnum); - GibSprite(pMissile, (hitCode == 2) ? GIBTYPE_23 : GIBTYPE_22, NULL, NULL); - evKill(pMissile->index, 3); - seqKill(3, nXMissile); - actPostSprite(pMissile->index, kStatFree); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - int nOwner = pMissile->owner; - int nDamage = (15+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_6, nDamage); - } - break; - default: - seqKill(3, nXMissile); - actPostSprite(pMissile->index, kStatFree); - if (hitCode == 3) - { - int nObject = gHitInfo.hitsprite; - assert(nObject >= 0 && nObject < kMaxSprites); - spritetype *pObject = &sprite[nObject]; - int nOwner = pMissile->owner; - int nDamage = (10+Random(10))<<4; - actDamageSprite(nOwner, pObject, DAMAGE_TYPE_0, nDamage); - } - break; - } - - #ifdef NOONE_EXTENSIONS - if (gModernMap && pXSpriteHit && pXSpriteHit->state != pXSpriteHit->restState && pXSpriteHit->Impact) - trTriggerSprite(nSpriteHit, pXSpriteHit, kCmdSpriteImpact); - #endif - pMissile->cstat &= ~257; + actHitcodeToData(hitCode, &gHitInfo, &actorHit, &pWallHit); + spritetype* pSpriteHit = actorHit ? &actorHit->s() : nullptr; + XSPRITE* pXSpriteHit = actorHit && actorHit->hasX() ? &actorHit->x() : nullptr; + + const THINGINFO* pThingInfo = nullptr; + DUDEINFO* pDudeInfo = nullptr; + + if (hitCode == 3 && pSpriteHit) + { + switch (pSpriteHit->statnum) + { + case kStatThing: + pThingInfo = &thingInfo[pSpriteHit->type - kThingBase]; + break; + case kStatDude: + pDudeInfo = getDudeInfo(pSpriteHit->type); + break; + } + } + switch (pMissile->type) + { + case kMissileLifeLeechRegular: + if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) + { + DAMAGE_TYPE rand1 = (DAMAGE_TYPE)Random(7); + int rand2 = (7 + Random(7)) << 4; + int nDamage = actDamageSprite(missileOwner, actorHit, rand1, rand2); + + if ((pThingInfo && pThingInfo->dmgControl[DAMAGE_TYPE_1] != 0) || (pDudeInfo && pDudeInfo->damageVal[DAMAGE_TYPE_1] != 0)) + actBurnSprite(missileActor->GetOwner(), actorHit, 360); + + // by NoOne: make Life Leech heal user, just like it was in 1.0x versions + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus() && pDudeInfo != nullptr) + { + if (missileOwner->IsDudeActor() && missileOwner->hasX() && missileOwner->x().health != 0) + actHealDude(missileOwner, nDamage >> 2, getDudeInfo(missileOwner->s().type)->startHealth); + } + } + + if (pMissile->extra > 0) + { + actPostSprite(missileActor, kStatDecoration); + if (pMissile->ang == 1024) sfxPlay3DSound(pMissile, 307, -1, 0); + pMissile->type = kSpriteDecoration; + seqSpawn(9, missileActor, -1); + } + else + { + actPostSprite(pMissile->index, kStatFree); + } + + break; + case kMissileTeslaAlt: + teslaHit(pMissile, hitCode); + switch (hitCode) + { + case 0: + case 4: + if (pWallHit) + { + spritetype* pFX = gFX.fxSpawn(FX_52, pMissile->sectnum, pMissile->x, pMissile->y, pMissile->z, 0); + if (pFX) pFX->ang = (GetWallAngle(pWallHit) + 512) & 2047; + } + break; + } + GibSprite(pMissile, GIBTYPE_24, NULL, NULL); + actPostSprite(missileActor, kStatFree); + break; + + case kMissilePukeGreen: + seqKill(missileActor); + if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) + { + int nOwner = pMissile->owner; + int nDamage = (15 + Random(7)) << 4; + actDamageSprite(nOwner, pSpriteHit, DAMAGE_TYPE_2, nDamage); + } + actPostSprite(missileActor, kStatFree); + break; + + case kMissileArcGargoyle: + sfxKill3DSound(pMissile, -1, -1); + sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum); + GibSprite(pMissile, GIBTYPE_6, NULL, NULL); + + if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) + { + int nDamage = (25 + Random(20)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_5, nDamage); + } + actPostSprite(missileActor, kStatFree); + break; + + case kMissileLifeLeechAltNormal: + case kMissileLifeLeechAltSmall: + sfxKill3DSound(pMissile, -1, -1); + sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 306, pMissile->sectnum); + + if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) + { + int nDmgMul = (pMissile->type == kMissileLifeLeechAltSmall) ? 6 : 3; + int nDamage = (nDmgMul + Random(nDmgMul)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_5, nDamage); + } + actPostSprite(missileActor, kStatFree); + break; + + case kMissileFireball: + case kMissileFireballNapam: + if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo)) + { + if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && actorHit->x().burnTime == 0) + evPost(actorHit, 0, kCallbackFXFlameLick); + + int nDamage = (50 + Random(50)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_2, nDamage); + } + actExplodeSprite(pMissile); + break; + + case kMissileFlareAlt: + sfxKill3DSound(pMissile, -1, -1); + actExplodeSprite(pMissile); + break; + + case kMissileFlareRegular: + sfxKill3DSound(pMissile, -1, -1); + if ((hitCode == 3 && pSpriteHit) && (pThingInfo || pDudeInfo)) + { + if ((pThingInfo && pThingInfo->dmgControl[DAMAGE_TYPE_1] != 0) || (pDudeInfo && pDudeInfo->damageVal[DAMAGE_TYPE_1] != 0)) + { + if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && actorHit->x().burnTime == 0) + evPost(actorHit, 0, kCallbackFXFlameLick); + + actBurnSprite(missileOwner, actorHit, 480); + actRadiusDamage(missileOwner, pMissile->x, pMissile->y, pMissile->z, pMissile->sectnum, 16, 20, 10, DAMAGE_TYPE_2, 6, 480); + + // by NoOne: allow additional bullet damage for Flare Gun + if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus()) + { + int nDamage = (20 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_2, nDamage); + } + } + else + { + int nDamage = (20 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_2, nDamage); + } + + if (surfType[pSpriteHit->picnum] == kSurfFlesh) + { + pMissile->picnum = 2123; + missileActor->SetTarget(actorHit); + pXMissile->targetZ = pMissile->z - pSpriteHit->z; + pXMissile->goalAng = getangle(pMissile->x - pSpriteHit->x, pMissile->y - pSpriteHit->y) - pSpriteHit->ang; + pXMissile->state = 1; + actPostSprite(pMissile->index, kStatFlare); + pMissile->cstat &= ~257; + break; + } + } + GibSprite(pMissile, GIBTYPE_17, NULL, NULL); + actPostSprite(missileActor, kStatFree); + break; + + case kMissileFlameSpray: + case kMissileFlameHound: + if (hitCode == 3 && actorHit && actorHit->hasX()) + { + if ((pSpriteHit->statnum == kStatThing || pSpriteHit->statnum == kStatDude) && pXSpriteHit->burnTime == 0) + evPost(actorHit, 0, kCallbackFXFlameLick); + + actBurnSprite(missileOwner, actorHit, (4 + gGameOptions.nDifficulty) << 2); + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_1, 8); + } + break; + + case kMissileFireballCerberus: + actExplodeSprite(pMissile); + if (hitCode == 3 && actorHit && actorHit->hasX()) + { + if ((pSpriteHit->statnum == kStatThing || pSpriteHit->statnum == kStatDude) && pXSpriteHit->burnTime == 0) + evPost(actorHit, 0, kCallbackFXFlameLick); + + actBurnSprite(missileOwner, actorHit, (4 + gGameOptions.nDifficulty) << 2); + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_1, 8); + int nDamage = (25 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_2, nDamage); + } + actExplodeSprite(pMissile); + break; + + case kMissileFireballTchernobog: + actExplodeSprite(pMissile); + if (hitCode == 3 && actorHit && actorHit->hasX()) + { + if ((pSpriteHit->statnum == kStatThing || pSpriteHit->statnum == kStatDude) && pXSpriteHit->burnTime == 0) + evPost(actorHit, 0, kCallbackFXFlameLick); + + actBurnSprite(missileOwner, actorHit, 32); + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_5, 12); + int nDamage = (25 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_2, nDamage); + } + actExplodeSprite(pMissile); + break; + + case kMissileEctoSkull: + sfxKill3DSound(pMissile, -1, -1); + sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 522, pMissile->sectnum); + actPostSprite(pMissile->index, kStatDebris); + seqSpawn(20, 3, pMissile->extra, -1); + if (hitCode == 3 && actorHit && actorHit->hasX()) + { + if (pSpriteHit->statnum == kStatDude) + { + int nDamage = (25 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_5, nDamage); + } + } + break; + + case kMissileButcherKnife: + actPostSprite(missileActor, kStatDebris); + pMissile->cstat &= ~16; + pMissile->type = kSpriteDecoration; + seqSpawn(20, 3, pMissile->extra, -1); + if (hitCode == 3 && actorHit && actorHit->hasX()) + { + if (pSpriteHit->statnum == kStatDude) + { + int nDamage = (10 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_5, nDamage); + int nType = missileOwner->s().type - kDudeBase; + if (missileOwner->x().health > 0) + actHealDude(missileOwner, 10, getDudeInfo(nType + kDudeBase)->startHealth); + } + } + break; + + case kMissileTeslaRegular: + sfxKill3DSound(pMissile, -1, -1); + sfxPlay3DSound(pMissile->x, pMissile->y, pMissile->z, 518, pMissile->sectnum); + GibSprite(pMissile, (hitCode == 2) ? GIBTYPE_23 : GIBTYPE_22, NULL, NULL); + evKill(missileActor); + seqKill(missileActor); + actPostSprite(missileActor, kStatFree); + if (hitCode == 3 && actorHit) + { + int nDamage = (15 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_6, nDamage); + } + break; + + default: + seqKill(missileActor); + actPostSprite(missileActor, kStatFree); + if (hitCode == 3 && actorHit) + { + int nDamage = (10 + Random(10)) << 4; + actDamageSprite(missileOwner, actorHit, DAMAGE_TYPE_0, nDamage); + } + break; + } + +#ifdef NOONE_EXTENSIONS + if (gModernMap && pXSpriteHit && pXSpriteHit->state != pXSpriteHit->restState && pXSpriteHit->Impact) + trTriggerSprite(actorHit, kCmdSpriteImpact); +#endif + pMissile->cstat &= ~257; } void actKickObject(spritetype *pSprite1, spritetype *pSprite2) @@ -4825,7 +4783,7 @@ void MoveDude(spritetype *pSprite) { HITINFO hitInfo = gHitInfo; gHitInfo.hitsprite = nSprite; - actImpactMissile(pHitSprite, 3); + actImpactMissile(&bloodActors[nHitSprite], 3); gHitInfo = hitInfo; } #ifdef NOONE_EXTENSIONS @@ -5893,7 +5851,7 @@ void actProcessSprites(void) viewBackupSpriteLoc(nSprite, pSprite); int hit = MoveMissile(pSprite); if (hit >= 0) - actImpactMissile(pSprite, hit); + actImpactMissile(&bloodActors[pSprite->index], hit); } it.Reset(kStatExplosion); while ((nSprite = it.NextIndex()) >= 0) @@ -6597,7 +6555,7 @@ spritetype* actFireMissile(spritetype *pSprite, int a2, int a3, int a4, int a5, if (v4) { - actImpactMissile(pMissile, hit); + actImpactMissile(&bloodActors[pMissile->index], hit); pMissile = NULL; } return pMissile; diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index 34fa07c5a63..266616f9749 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -221,8 +221,7 @@ void actKillDude(DBloodActor* a1, DBloodActor* pSprite, DAMAGE_TYPE a3, int a4); void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4); int actDamageSprite(int nSource, spritetype *pSprite, DAMAGE_TYPE a3, int a4); int actDamageSprite(DBloodActor* pSource, DBloodActor* pTarget, DAMAGE_TYPE damageType, int damage); -void actHitcodeToData(int a1, HITINFO *pHitInfo, int *a3, spritetype **a4, XSPRITE **a5, int *a6, walltype **a7, XWALL **a8, int *a9, sectortype **a10, XSECTOR **a11); -void actImpactMissile(spritetype *pMissile, int hitCode); +void actHitcodeToData(int a1, HITINFO *pHitInfo, DBloodActor **actor, walltype **a7 = nullptr); void actKickObject(spritetype *pSprite1, spritetype *pSprite2); void actTouchFloor(spritetype *pSprite, int nSector); void ProcessTouchObjects(spritetype *pSprite, int nXSprite); diff --git a/source/games/blood/src/aibeast.cpp b/source/games/blood/src/aibeast.cpp index c9aae1c1fdf..ef27268f7cc 100644 --- a/source/games/blood/src/aibeast.cpp +++ b/source/games/blood/src/aibeast.cpp @@ -80,12 +80,12 @@ void SlashSeqCallback(int, DBloodActor* actor) sfxPlay3DSound(pSprite, 9012+Random(2), -1, 0); } -void StompSeqCallback(int, DBloodActor* actor) +void StompSeqCallback(int, DBloodActor* actor1) { uint8_t vb8[(kMaxSectors+7)>>3]; - XSPRITE* pXSprite = &actor->x(); + XSPRITE* pXSprite = &actor1->x(); int nSprite = pXSprite->reference; - spritetype *pSprite = &actor->s(); + spritetype *pSprite = &actor1->s(); int dx = CosScale16(pSprite->ang); int dy = SinScale16(pSprite->ang); int x = pSprite->x; @@ -97,12 +97,12 @@ void StompSeqCallback(int, DBloodActor* actor) int v10 = 25+30*gGameOptions.nDifficulty; GetClosestSpriteSectors(nSector, x, y, vc, vb8); char v4 = 0; - int v34 = -1; int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0); - actHitcodeToData(hit, &gHitInfo, &v34, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (hit == 3 && v34 >= 0) + DBloodActor* actor2 = nullptr; + actHitcodeToData(hit, &gHitInfo, &actor2); + if (hit == 3 && actor2) { - if (sprite[v34].statnum == kStatDude) + if (actor2->s().statnum == kStatDude) v4 = 0; } vc <<= 4; @@ -178,7 +178,7 @@ static void MorphToBeast(DBloodActor* actor) { auto pXSprite = &actor->x(); auto pSprite = &actor->s(); - actHealDude(pXSprite, dudeInfo[51].startHealth, dudeInfo[51].startHealth); + actHealDude(actor, dudeInfo[51].startHealth, dudeInfo[51].startHealth); pSprite->type = kDudeBeast; } diff --git a/source/games/blood/src/bloodactor.h b/source/games/blood/src/bloodactor.h index d98d4951ed4..45926018bf6 100644 --- a/source/games/blood/src/bloodactor.h +++ b/source/games/blood/src/bloodactor.h @@ -50,6 +50,17 @@ class DBloodActor return base() + s().owner; } + void SetTarget(DBloodActor* own) + { + x().target = own ? own->s().index : -1; + } + + DBloodActor* GetTarget() + { + if (x().target == -1 || x().target == kMaxSprites - 1) return nullptr; + return base() + x().target; + } + void SetSpecialOwner() // nnext hackery { s().owner = kMaxSprites - 1; diff --git a/source/games/blood/src/eventq.cpp b/source/games/blood/src/eventq.cpp index 77fbf3a0a6a..407a18f003b 100644 --- a/source/games/blood/src/eventq.cpp +++ b/source/games/blood/src/eventq.cpp @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "blood.h" #include "secrets.h" #include "serializer.h" +#include "bloodactor.h" BEGIN_BLD_NS @@ -525,6 +526,16 @@ void evPost(int nIndex, int nType, unsigned int nDelta, CALLBACK_ID callback) } +void evPost(DBloodActor* actor, unsigned int nDelta, COMMAND_ID command) +{ + evPost(actor->s().index, 3, nDelta, command); +} + +void evPost(DBloodActor* actor, unsigned int nDelta, CALLBACK_ID callback) +{ + evPost(actor->s().index, 3, nDelta, callback); +} + //--------------------------------------------------------------------------- // // @@ -549,6 +560,11 @@ void evKill(int index, int type, CALLBACK_ID cb) } } +void evKill(DBloodActor* actor) +{ + evKill(actor->s().index, 3); +} + //--------------------------------------------------------------------------- // // diff --git a/source/games/blood/src/eventq.h b/source/games/blood/src/eventq.h index b5f281bd4fe..2ecb4522de5 100644 --- a/source/games/blood/src/eventq.h +++ b/source/games/blood/src/eventq.h @@ -158,8 +158,12 @@ void evInit(void); void evSend(int nIndex, int nType, int rxId, COMMAND_ID command); void evPost(int nIndex, int nType, unsigned int nDelta, COMMAND_ID command); void evPost(int nIndex, int nType, unsigned int nDelta, CALLBACK_ID callback); +void evPost(DBloodActor*, unsigned int nDelta, COMMAND_ID command); +void evPost(DBloodActor*, unsigned int nDelta, CALLBACK_ID callback); + void evProcess(unsigned int nTime); void evKill(int a1, int a2); void evKill(int a1, int a2, CALLBACK_ID a3); +void evKill(DBloodActor*); END_BLD_NS diff --git a/source/games/blood/src/gameutil.cpp b/source/games/blood/src/gameutil.cpp index 2b65b74d05b..a531f49bf27 100644 --- a/source/games/blood/src/gameutil.cpp +++ b/source/games/blood/src/gameutil.cpp @@ -321,6 +321,12 @@ int GetWallAngle(int nWall) return getangle(wall[nWall2].x - wall[nWall].x, wall[nWall2].y - wall[nWall].y); } +int GetWallAngle(walltype* pWall) +{ + int nWall2 = pWall->point2; + return getangle(wall[nWall2].x - pWall->x, wall[nWall2].y - pWall->y); +} + void GetWallNormal(int nWall, int *pX, int *pY) { assert(nWall >= 0 && nWall < kMaxWalls); diff --git a/source/games/blood/src/gameutil.h b/source/games/blood/src/gameutil.h index a16119d4de6..31a99b255ae 100644 --- a/source/games/blood/src/gameutil.h +++ b/source/games/blood/src/gameutil.h @@ -72,6 +72,7 @@ bool CheckProximity(spritetype *pSprite, int nX, int nY, int nZ, int nSector, in bool CheckProximityPoint(int nX1, int nY1, int nZ1, int nX2, int nY2, int nZ2, int nDist); bool CheckProximityWall(int nWall, int x, int y, int nDist); int GetWallAngle(int nWall); +int GetWallAngle(walltype* pWall); void GetWallNormal(int nWall, int *pX, int *pY); bool IntersectRay(int wx, int wy, int wdx, int wdy, int x1, int y1, int z1, int x2, int y2, int z2, int *ix, int *iy, int *iz); int HitScan(spritetype *pSprite, int z, int dx, int dy, int dz, unsigned int nMask, int a8); diff --git a/source/games/blood/src/triggers.cpp b/source/games/blood/src/triggers.cpp index 06ac6fc6ad6..533be2d258d 100644 --- a/source/games/blood/src/triggers.cpp +++ b/source/games/blood/src/triggers.cpp @@ -1802,6 +1802,10 @@ void trTriggerSprite(unsigned int nSprite, XSPRITE *pXSprite, int command) { } } +void trTriggerSprite(DBloodActor* actor, int command) { + trTriggerSprite(actor->s().index, &actor->x(), command); +} + void trMessageSector(unsigned int nSector, EVENT event) { assert(nSector < (unsigned int)numsectors); diff --git a/source/games/blood/src/triggers.h b/source/games/blood/src/triggers.h index 17336e2ef7c..68e05cb6a62 100644 --- a/source/games/blood/src/triggers.h +++ b/source/games/blood/src/triggers.h @@ -35,6 +35,7 @@ void trMessageSector(unsigned int nSector, EVENT event); void trTriggerWall(unsigned int nWall, XWALL *pXWall, int command); void trMessageWall(unsigned int nWall, EVENT event); void trTriggerSprite(unsigned int nSprite, XSPRITE *pXSprite, int command); +void trTriggerSprite(DBloodActor* actor, int command); void trMessageSprite(unsigned int nSprite, EVENT event); void trProcessBusy(void); void trInit(void); diff --git a/source/games/blood/src/weapon.cpp b/source/games/blood/src/weapon.cpp index 8c94b6dd6b6..b939692d1dd 100644 --- a/source/games/blood/src/weapon.cpp +++ b/source/games/blood/src/weapon.cpp @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "build.h" #include "blood.h" +#include "bloodactor.h" BEGIN_BLD_NS @@ -2591,9 +2592,9 @@ void teslaHit(spritetype *pMissile, int a2) int nOwner = pMissile->owner; GetClosestSpriteSectors(nSector, x, y, nDist, va4); bool v4 = true; - int v24 = -1; - actHitcodeToData(a2, &gHitInfo, &v24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (a2 == 3 && v24 >= 0 && sprite[v24].statnum == kStatDude) + DBloodActor* actor = nullptr; + actHitcodeToData(a2, &gHitInfo, &actor); + if (a2 == 3 && actor && actor->s().statnum == kStatDude) v4 = false; int nSprite; StatIterator it(kStatDude);