raze/source/games/blood/src/callback.cpp

905 lines
25 KiB
C++
Raw Normal View History

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.
*/
//-------------------------------------------------------------------------
#include "ns.h" // Must come before everything else!
2019-09-19 22:42:45 +00:00
#include "build.h"
#include "blood.h"
2020-12-05 17:32:49 +00:00
#include "bloodactor.h"
2019-09-19 22:42:45 +00:00
BEGIN_BLD_NS
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxFlameLick(DBloodActor* actor, sectortype*) // 0
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int top, bottom;
GetActorExtents(actor, &top, &bottom);
for (int i = 0; i < 3; i++)
{
int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) / 2)) >> 3;
int nAngle = Random(2048);
int dx = MulScale(nDist, Cos(nAngle), 30);
int dy = MulScale(nDist, Sin(nAngle), 30);
int x = actor->spr.pos.X + dx;
int y = actor->spr.pos.Y + dy;
int z = bottom - Random(bottom - top);
auto pFX = gFX.fxSpawnActor(FX_32, actor->sector(), x, y, z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(-dx);
pFX->vel.Y = actor->vel.Y + Random2(-dy);
pFX->vel.Z = actor->vel.Z - Random(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
}
if (actor->xspr.burnTime > 0)
evPostActor(actor, 5, kCallbackFXFlameLick);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void Remove(DBloodActor* actor, sectortype*) // 1
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
evKillActor(actor, kCallbackFXFlareSpark);
if (actor->hasX())
seqKill(actor);
sfxKill3DSound(actor, 0, -1);
DeleteSprite(actor);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void FlareBurst(DBloodActor* actor, sectortype*) // 2
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int nAngle = getangle(actor->vel.X, actor->vel.Y);
2021-12-29 19:03:42 +00:00
int nRadius = 0x55555;
for (int i = 0; i < 8; i++)
{
auto spawnedactor = actSpawnSprite(actor, 5);
spawnedactor->spr.picnum = 2424;
spawnedactor->spr.shade = -128;
spawnedactor->spr.xrepeat = spawnedactor->spr.yrepeat = 32;
spawnedactor->spr.type = kMissileFlareAlt;
spawnedactor->spr.clipdist = 2;
spawnedactor->SetOwner(actor);
int nAngle2 = (i << 11) / 8;
int dx = 0;
int dy = mulscale30r(nRadius, Sin(nAngle2));
int dz = mulscale30r(nRadius, -Cos(nAngle2));
if (i & 1)
{
dy >>= 1;
dz >>= 1;
}
RotateVector(&dx, &dy, nAngle);
spawnedactor->vel.X += dx;
spawnedactor->vel.Y += dy;
spawnedactor->vel.Z += dz;
2021-12-29 19:03:42 +00:00
evPostActor(spawnedactor, 960, kCallbackRemove);
}
evPostActor(actor, 0, kCallbackRemove);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxFlareSpark(DBloodActor* actor, sectortype*) // 3
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x1aaaa);
pFX->vel.Y = actor->vel.Y + Random2(0x1aaaa);
pFX->vel.Z = actor->vel.Z - Random(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 4, kCallbackFXFlareSpark);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxFlareSparkLite(DBloodActor* actor, sectortype*) // 4
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x1aaaa);
pFX->vel.Y = actor->vel.Y + Random2(0x1aaaa);
pFX->vel.Z = actor->vel.Z - Random(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 12, kCallbackFXFlareSparkLite);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxZombieBloodSpurt(DBloodActor* actor, sectortype*) // 5
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
assert(actor->hasX());
int top, bottom;
GetActorExtents(actor, &top, &bottom);
auto pFX = gFX.fxSpawnActor(FX_27, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, top, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x11111);
pFX->vel.Y = actor->vel.Y + Random2(0x11111);
pFX->vel.Z = actor->vel.Z - 0x6aaaa;
2021-12-29 19:03:42 +00:00
}
if (actor->xspr.data1 > 0)
{
evPostActor(actor, 4, kCallbackFXZombieSpurt);
actor->xspr.data1 -= 4;
}
else if (actor->xspr.data2 > 0)
{
evPostActor(actor, 60, kCallbackFXZombieSpurt);
actor->xspr.data1 = 40;
actor->xspr.data2--;
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxBloodSpurt(DBloodActor* actor, sectortype*) // 6
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_27, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->spr.ang = 0;
pFX->vel.X = actor->vel.X >> 8;
pFX->vel.Y = actor->vel.Y >> 8;
pFX->vel.Z = actor->vel.Z >> 8;
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 6, kCallbackFXBloodSpurt);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxArcSpark(DBloodActor* actor, sectortype*) // 7
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_15, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x10000);
pFX->vel.Y = actor->vel.Y + Random2(0x10000);
pFX->vel.Z = actor->vel.Z - Random(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 3, kCallbackFXArcSpark);
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxDynPuff(DBloodActor* actor, sectortype*) // 8
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
if (actor->vel.Z)
2021-12-29 19:03:42 +00:00
{
int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) / 2)) >> 2;
int x = actor->spr.pos.X + MulScale(nDist, Cos(actor->spr.ang - 512), 30);
int y = actor->spr.pos.Y + MulScale(nDist, Sin(actor->spr.ang - 512), 30);
int z = actor->spr.pos.Z;
auto pFX = gFX.fxSpawnActor(FX_7, actor->sector(), x, y, z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X;
pFX->vel.Y = actor->vel.Y;
pFX->vel.Z = actor->vel.Z;
2021-12-29 19:03:42 +00:00
}
}
evPostActor(actor, 12, kCallbackFXDynPuff);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void Respawn(DBloodActor* actor, sectortype*) // 9
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
assert(actor->hasX());
if (actor->spr.statnum != kStatRespawn && actor->spr.statnum != kStatThing) {
viewSetSystemMessage("Sprite #%d is not on Respawn or Thing list\n", actor->GetIndex());
return;
}
else if (!(actor->spr.flags & kHitagRespawn)) {
viewSetSystemMessage("Sprite #%d does not have the respawn attribute\n", actor->GetIndex());
return;
}
switch (actor->xspr.respawnPending) {
case 1: {
int nTime = MulScale(actGetRespawnTime(actor), 0x4000, 16);
actor->xspr.respawnPending = 2;
evPostActor(actor, nTime, kCallbackRespawn);
break;
}
case 2: {
int nTime = MulScale(actGetRespawnTime(actor), 0x2000, 16);
actor->xspr.respawnPending = 3;
evPostActor(actor, nTime, kCallbackRespawn);
break;
}
case 3: {
assert(actor->spr.intowner != kStatRespawn);
assert(actor->spr.intowner >= 0 && actor->spr.intowner < kMaxStatus);
ChangeActorStat(actor, actor->spr.intowner);
2021-12-29 19:03:42 +00:00
actor->spr.type = actor->spr.inittype;
actor->SetOwner(nullptr);
actor->spr.flags &= ~kHitagRespawn;
actor->vel.X = actor->vel.Y = actor->vel.Z = 0;
2021-12-29 19:03:42 +00:00
actor->xspr.respawnPending = 0;
actor->xspr.burnTime = 0;
actor->xspr.isTriggered = 0;
if (actor->IsDudeActor())
{
int nType = actor->spr.type - kDudeBase;
actor->spr.pos = actor->basePoint;
actor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1 | CSTAT_SPRITE_BLOCK_ALL;
#ifdef NOONE_EXTENSIONS
if (!gModernMap || actor->xspr.sysData2 <= 0) actor->xspr.health = dudeInfo[actor->spr.type - kDudeBase].startHealth << 4;
else actor->xspr.health = ClipRange(actor->xspr.sysData2 << 4, 1, 65535);
switch (actor->spr.type) {
default:
actor->spr.clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID))
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, actor, -1);
break;
case kDudeModernCustom:
seqSpawn(genDudeSeqStartId(actor), actor, -1);
break;
}
// return dude to the patrol state
if (gModernMap && actor->xspr.dudeFlag4) {
actor->xspr.data3 = 0;
actor->SetTarget(nullptr);
}
#else
actor->spr.clipdist = getDudeInfo(nType + kDudeBase)->clipdist;
actor->xspr.health = getDudeInfo(nType + kDudeBase)->startHealth << 4;
if (getSequence(getDudeInfo(nType + kDudeBase)->seqStartID))
seqSpawn(getDudeInfo(nType + kDudeBase)->seqStartID, actor, -1);
#endif
aiInitSprite(actor);
actor->xspr.key = 0;
}
else if (actor->spr.type == kThingTNTBarrel) {
actor->spr.cstat |= CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN;
actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE;
}
gFX.fxSpawnActor(FX_29, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
sfxPlay3DSound(actor, 350, -1, 0);
break;
}
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void PlayerBubble(DBloodActor* actor, sectortype*) // 10
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
if (actor->IsPlayerActor())
{
PLAYER* pPlayer = &gPlayer[actor->spr.type - kDudePlayer1];
if (!pPlayer->bubbleTime)
return;
int top, bottom;
GetActorExtents(actor, &top, &bottom);
for (int i = 0; i < (pPlayer->bubbleTime >> 6); i++)
{
int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) / 2)) >> 2;
int nAngle = Random(2048);
int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 30);
int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 30);
int z = bottom - Random(bottom - top);
auto pFX = gFX.fxSpawnActor((FX_ID)(FX_23 + Random(3)), actor->sector(), x, y, z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x1aaaa);
pFX->vel.Y = actor->vel.Y + Random2(0x1aaaa);
pFX->vel.Z = actor->vel.Z + Random2(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
}
evPostActor(actor, 4, kCallbackPlayerBubble);
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void EnemyBubble(DBloodActor* actor, sectortype*) // 11
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int top, bottom;
GetActorExtents(actor, &top, &bottom);
for (int i = 0; i < (abs(actor->vel.Z) >> 18); i++)
2021-12-29 19:03:42 +00:00
{
int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) / 2)) >> 2;
int nAngle = Random(2048);
int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 30);
int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 30);
int z = bottom - Random(bottom - top);
auto pFX = gFX.fxSpawnActor((FX_ID)(FX_23 + Random(3)), actor->sector(), x, y, z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x1aaaa);
pFX->vel.Y = actor->vel.Y + Random2(0x1aaaa);
pFX->vel.Z = actor->vel.Z + Random2(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
}
evPostActor(actor, 4, kCallbackEnemeyBubble);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void CounterCheck(DBloodActor*, sectortype* pSector) // 12
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!pSector || pSector->type != kSectorCounter) return;
if (!pSector->hasX()) return;
XSECTOR* pXSector = &pSector->xs();
int nReq = pXSector->waitTimeA;
int nType = pXSector->data;
int nCount = 0;
if (!nType || !nReq) return;
BloodSectIterator it(pSector);
while (auto actor = it.Next())
{
if (actor->spr.type == nType) nCount++;
}
if (nCount < nReq) {
evPostSector(pSector, 5, kCallbackCounterCheck);
return;
}
else {
//pXSector->waitTimeA = 0; //do not reset necessary objects counter to zero
trTriggerSector(pSector, kCmdOn);
pXSector->locked = 1; //lock sector, so it can be opened again later
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void FinishHim(DBloodActor* actor, sectortype*) // 13
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
if (actor->IsPlayerActor() && playerSeqPlaying(&gPlayer[actor->spr.type - kDudePlayer1], 16) && actor == gMe->actor)
sndStartSample(3313, -1, 1, 0);
}
2021-11-24 00:05:17 +00:00
void fxBloodBits(DBloodActor* actor, sectortype*) // 14
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int ceilZ, floorZ;
Collision floorColl, ceilColl;
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->spr.clipdist, CLIPMASK0);
int top, bottom;
GetActorExtents(actor, &top, &bottom);
actor->spr.pos.Z += floorZ - bottom;
int nAngle = Random(2048);
int nDist = Random(16) << 4;
int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 28);
int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 28);
gFX.fxSpawnActor(FX_48, actor->sector(), x, y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (actor->spr.ang == 1024)
{
int nChannel = 28 + (actor->GetIndex() & 2); // this is a little stupid...
sfxPlay3DSound(actor, 385, nChannel, 1);
}
if (Chance(0x5000))
{
auto pFX = gFX.fxSpawnActor(FX_36, actor->sector(), x, y, floorZ - 64, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
pFX->spr.ang = nAngle;
}
gFX.remove(actor);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxTeslaAlt(DBloodActor* actor, sectortype*) // 15
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_49, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->vel.X = actor->vel.X + Random2(0x1aaaa);
pFX->vel.Y = actor->vel.Y + Random2(0x1aaaa);
pFX->vel.Z = actor->vel.Z - Random(0x1aaaa);
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 3, kCallbackFXTeslaAlt);
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static const int tommySleeveSnd[] = { 608, 609, 611 }; // unused?
static const int sawedOffSleeveSnd[] = { 610, 612 };
2021-11-24 00:05:17 +00:00
void fxBouncingSleeve(DBloodActor* actor, sectortype*) // 16
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int ceilZ, floorZ;
Collision floorColl, ceilColl;
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->spr.clipdist, CLIPMASK0);
int top, bottom; GetActorExtents(actor, &top, &bottom);
actor->spr.pos.Z += floorZ - bottom;
int zv = actor->vel.Z - actor->sector()->velFloor;
2021-12-29 19:03:42 +00:00
if (actor->vel.Z == 0) sleeveStopBouncing(actor);
2021-12-29 19:03:42 +00:00
else if (zv > 0) {
actFloorBounceVector((int*)&actor->vel.X, (int*)&actor->vel.Y, &zv, actor->sector(), 0x9000);
actor->vel.Z = zv;
if (actor->sector()->velFloor == 0 && abs(actor->vel.Z) < 0x20000) {
2021-12-29 19:03:42 +00:00
sleeveStopBouncing(actor);
return;
}
int nChannel = 28 + (actor->GetIndex() & 2);
// tommy sleeve
if (actor->spr.type >= FX_37 && actor->spr.type <= FX_39) {
2021-12-29 19:03:42 +00:00
Random(3);
sfxPlay3DSound(actor, 608 + Random(2), nChannel, 1);
// sawed-off sleeve
}
else {
sfxPlay3DSound(actor, sawedOffSleeveSnd[Random(2)], nChannel, 1);
}
}
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-12-29 19:03:42 +00:00
void sleeveStopBouncing(DBloodActor* actor)
2021-08-27 15:04:34 +00:00
{
actor->vel.X = actor->vel.Y = actor->vel.Z = 0;
2021-12-29 19:03:42 +00:00
if (actor->hasX()) seqKill(actor);
sfxKill3DSound(actor, -1, -1);
switch (actor->spr.type) {
case FX_37:
case FX_38:
case FX_39:
2021-12-29 19:03:42 +00:00
actor->spr.picnum = 2465;
break;
case FX_40:
case FX_41:
case FX_42:
2021-12-29 19:03:42 +00:00
actor->spr.picnum = 2464;
break;
}
actor->spr.type = FX_51;
2021-12-29 19:03:42 +00:00
actor->spr.xrepeat = actor->spr.yrepeat = 10;
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void returnFlagToBase(DBloodActor* actor, sectortype*) // 17
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto aOwner = actor->GetOwner();
if (aOwner)
{
switch (actor->spr.type)
{
case kItemFlagA:
trTriggerSprite(aOwner, kCmdOn, aOwner);
2021-12-29 19:03:42 +00:00
sndStartSample(8003, 255, 2, 0);
gBlueFlagDropped = false;
viewSetMessage("Blue Flag returned to base.");
break;
case kItemFlagB:
trTriggerSprite(aOwner, kCmdOn, aOwner);
2021-12-29 19:03:42 +00:00
sndStartSample(8002, 255, 2, 0);
gRedFlagDropped = false;
viewSetMessage("Red Flag returned to base.");
break;
}
}
evPostActor(actor, 0, kCallbackRemove);
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxPodBloodSpray(DBloodActor* actor, sectortype*) // 18
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
DBloodActor* pFX;
if (actor->spr.type == 53)
pFX = gFX.fxSpawnActor(FX_53, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
else
pFX = gFX.fxSpawnActor(FX_54, actor->sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
{
pFX->spr.ang = 0;
pFX->vel.X = actor->vel.X >> 8;
pFX->vel.Y = actor->vel.Y >> 8;
pFX->vel.Z = actor->vel.Z >> 8;
2021-12-29 19:03:42 +00:00
}
evPostActor(actor, 6, kCallbackFXPodBloodSpray);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void fxPodBloodSplat(DBloodActor* actor, sectortype*) // 19
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
int ceilZ, floorZ;
Collision floorColl, ceilColl;
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->spr.clipdist, CLIPMASK0);
int top, bottom;
GetActorExtents(actor, &top, &bottom);
actor->spr.pos.Z += floorZ - bottom;
int nAngle = Random(2048);
int nDist = Random(16) << 4;
int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 28);
int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 28);
if (actor->spr.ang == 1024 && actor->spr.type == 53)
2021-12-29 19:03:42 +00:00
{
int nChannel = 28 + (actor->GetIndex() & 2);
assert(nChannel < 32);
sfxPlay3DSound(actor, 385, nChannel, 1);
}
DBloodActor* pFX = NULL;
if (actor->spr.type == 53 || actor->spr.type == kThingPodGreenBall)
{
if (Chance(0x500) || actor->spr.type == kThingPodGreenBall)
pFX = gFX.fxSpawnActor(FX_55, actor->sector(), x, y, floorZ - 64, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
pFX->spr.ang = nAngle;
}
else
{
pFX = gFX.fxSpawnActor(FX_32, actor->sector(), x, y, floorZ - 64, 0);
2021-12-29 19:03:42 +00:00
if (pFX)
pFX->spr.ang = nAngle;
}
gFX.remove(actor);
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void LeechStateTimer(DBloodActor* actor, sectortype*) // 20
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
if (actor->spr.statnum == kStatThing && !(actor->spr.flags & 32)) {
switch (actor->spr.type) {
case kThingDroppedLifeLeech:
#ifdef NOONE_EXTENSIONS
case kModernThingEnemyLifeLeech:
#endif
actor->xspr.stateTimer = 0;
break;
}
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void sub_76A08(DBloodActor* actor, DBloodActor* actor2, PLAYER* pPlayer) // ???
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
int top, bottom;
GetActorExtents(actor, &top, &bottom);
actor->spr.pos.X = actor2->spr.pos.X;
actor->spr.pos.Y = actor2->spr.pos.Y;
actor->spr.pos.Z = actor2->sector()->floorz - (bottom - actor->spr.pos.Z);
2021-12-29 19:03:42 +00:00
actor->spr.ang = actor2->spr.ang;
ChangeActorSect(actor, actor2->sector());
2021-12-29 19:03:42 +00:00
sfxPlay3DSound(actor2, 201, -1, 0);
actor->vel.X = actor->vel.Y = actor->vel.Z = 0;
2021-12-29 19:03:42 +00:00
viewBackupSpriteLoc(actor);
if (pPlayer)
{
playerResetInertia(pPlayer);
pPlayer->zViewVel = pPlayer->zWeaponVel = 0;
}
2019-09-19 22:42:45 +00:00
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void DropVoodooCb(DBloodActor* actor, sectortype*) // unused
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
if (!actor) return;
auto Owner = actor->GetOwner();
if (Owner == nullptr)
{
evPostActor(actor, 0, kCallbackRemove);
return;
}
PLAYER* pPlayer;
if (Owner->IsPlayerActor())
pPlayer = &gPlayer[Owner->spr.type - kDudePlayer1];
else
pPlayer = nullptr;
if (!pPlayer)
{
evPostActor(actor, 0, kCallbackRemove);
return;
}
actor->spr.ang = getangle(Owner->spr.pos.X - actor->spr.pos.X, Owner->spr.pos.Y - actor->spr.pos.Y);
if (actor->hasX())
{
if (actor->xspr.data1 == 0)
{
evPostActor(actor, 0, kCallbackRemove);
return;
}
BloodStatIterator it(kStatDude);
while (auto actor2 = it.Next())
{
auto nextactor = it.Peek();
if (Owner == actor2)
continue;
if (actor2->hasX())
{
PLAYER* pPlayer2;
if (actor2->IsPlayerActor())
pPlayer2 = &gPlayer[actor2->spr.type - kDudePlayer1];
else
pPlayer2 = nullptr;
if (actor2->xspr.health > 0 && (pPlayer2 || actor2->xspr.key == 0))
{
if (pPlayer2)
{
if (gGameOptions.nGameType == 1)
continue;
if (gGameOptions.nGameType == 3 && pPlayer->teamId == pPlayer2->teamId)
continue;
int t = 0x8000 / ClipLow(gNetPlayers - 1, 1);
if (!powerupCheck(pPlayer2, kPwUpDeathMask))
t += ((3200 - pPlayer2->armor[2]) << 15) / 3200;
if (Chance(t) || nextactor == nullptr)
{
int nDmg = actDamageSprite(actor, actor2, kDamageSpirit, actor->xspr.data1 << 4);
actor->xspr.data1 = ClipLow(actor->xspr.data1 - nDmg, 0);
sub_76A08(actor2, actor, pPlayer2);
evPostActor(actor, 0, kCallbackRemove);
return;
}
}
else
{
int vd = 0x2666;
switch (actor2->spr.type)
{
case kDudeBoneEel:
case kDudeBat:
case kDudeRat:
case kDudeTinyCaleb:
case kDudeBeast:
vd = 0x147;
break;
case kDudeZombieAxeBuried:
case kDudePodGreen:
case kDudeTentacleGreen:
case kDudePodFire:
case kDudeTentacleFire:
case kDudePodMother:
case kDudeTentacleMother:
case kDudeCerberusTwoHead:
case kDudeCerberusOneHead:
case kDudeTchernobog:
case kDudeBurningInnocent:
case kDudeBurningCultist:
case kDudeBurningZombieAxe:
case kDudeBurningZombieButcher:
case kDudeCultistReserved:
case kDudeZombieAxeLaying:
case kDudeInnocent:
case kDudeBurningTinyCaleb:
case kDudeBurningBeast:
vd = 0;
break;
}
if (vd && (Chance(vd) || nextactor == nullptr))
{
sub_76A08(actor2, actor, NULL);
evPostActor(actor, 0, kCallbackRemove);
return;
}
}
}
}
}
actor->xspr.data1 = ClipLow(actor->xspr.data1 - 1, 0);
evPostActor(actor, 0, kCallbackRemove);
}
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void callbackCondition(DBloodActor* actor, sectortype*)
2021-09-01 19:54:23 +00:00
{
2021-12-29 19:03:42 +00:00
if (actor->xspr.isTriggered) return;
TRCONDITION const* pCond = &gCondition[actor->xspr.sysData1];
for (unsigned i = 0; i < pCond->length; i++) {
EVENT evn;
evn.target = pCond->obj[i].obj;
evn.cmd = pCond->obj[i].cmd;
evn.funcID = kCallbackCondition;
useCondition(actor, evn);
}
evPostActor(actor, actor->xspr.busyTime, kCallbackCondition);
return;
}
2021-12-29 19:03:42 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-24 00:05:17 +00:00
void(*gCallback[kCallbackMax])(DBloodActor*, sectortype*) =
2019-09-19 22:42:45 +00:00
{
2021-12-29 19:03:42 +00:00
fxFlameLick,
Remove,
FlareBurst,
fxFlareSpark,
fxFlareSparkLite,
fxZombieBloodSpurt,
fxBloodSpurt,
fxArcSpark,
fxDynPuff,
Respawn,
PlayerBubble,
EnemyBubble,
CounterCheck,
FinishHim,
fxBloodBits,
fxTeslaAlt,
fxBouncingSleeve,
returnFlagToBase,
fxPodBloodSpray,
fxPodBloodSplat,
LeechStateTimer,
DropVoodooCb, // unused
#ifdef NOONE_EXTENSIONS
callbackUniMissileBurst, // the code is in nnexts.cpp
callbackMakeMissileBlocking, // the code is in nnexts.cpp
callbackGenDudeUpdate, // the code is in nnexts.cpp
callbackCondition,
#endif
2019-09-19 22:42:45 +00:00
};
END_BLD_NS