2019-09-19 22:42:45 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
|
|
|
|
This file is part of NBlood.
|
|
|
|
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
2019-09-21 18:59:54 +00:00
|
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
|
2019-09-19 22:42:45 +00:00
|
|
|
#include "build.h"
|
|
|
|
#include "blood.h"
|
2020-12-05 17:32:49 +00:00
|
|
|
#include "bloodactor.h"
|
2019-09-19 22:42:45 +00:00
|
|
|
|
2019-09-22 06:39:22 +00:00
|
|
|
BEGIN_BLD_NS
|
|
|
|
|
2019-09-21 11:02:17 +00:00
|
|
|
|
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);
|
2022-01-30 17:09:26 +00:00
|
|
|
int x = actor->int_pos().X + dx;
|
|
|
|
int y = actor->int_pos().Y + dy;
|
2021-12-29 19:03:42 +00:00
|
|
|
int z = bottom - Random(bottom - top);
|
2021-12-30 15:51:56 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_32, actor->sector(), x, y, z, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(-dx);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(-dy);
|
2022-09-16 16:49:21 +00:00
|
|
|
pFX->vel.Z = actor->vel.Z - Random2F(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;
|
2022-09-01 18:49:35 +00:00
|
|
|
int nAngle = getangle(actor->int_vel().X, actor->int_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;
|
2022-09-09 16:24:22 +00:00
|
|
|
spawnedactor->set_const_clipdist(2);
|
2021-12-29 19:03:42 +00:00
|
|
|
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);
|
2022-09-01 19:02:20 +00:00
|
|
|
spawnedactor->add_int_bvel_x(dx);
|
2022-09-01 19:05:25 +00:00
|
|
|
spawnedactor->add_int_bvel_y(dy);
|
2022-09-01 19:08:05 +00:00
|
|
|
spawnedactor->add_int_bvel_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;
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x1aaaa);
|
2022-09-16 16:49:21 +00:00
|
|
|
pFX->vel.Z = actor->vel.Z - Random2F(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;
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x1aaaa);
|
2022-09-16 16:49:21 +00:00
|
|
|
pFX->vel.Z = actor->vel.Z - Random2F(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());
|
2022-08-22 16:31:03 +00:00
|
|
|
double top, bottom;
|
2021-12-29 19:03:42 +00:00
|
|
|
GetActorExtents(actor, &top, &bottom);
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_27, actor->sector(), DVector3(actor->spr.pos.XY(), top), 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x11111);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x11111);
|
2022-09-01 19:40:03 +00:00
|
|
|
pFX->set_int_bvel_z(actor->int_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;
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_27, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-09 16:37:55 +00:00
|
|
|
pFX->spr.angle = nullAngle;
|
2022-09-03 08:12:09 +00:00
|
|
|
pFX->vel = actor->vel * (1./256);
|
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
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-11-24 00:05:17 +00:00
|
|
|
void fxArcSpark(DBloodActor* actor, sectortype*) // 7
|
2019-10-11 21:59:39 +00:00
|
|
|
{
|
2021-12-29 19:03:42 +00:00
|
|
|
if (!actor) return;
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_15, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x10000);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x10000);
|
2022-09-16 16:49:21 +00:00
|
|
|
pFX->vel.Z = actor->vel.Z - Random2F(0x1aaaa);
|
2021-12-29 19:03:42 +00:00
|
|
|
}
|
|
|
|
evPostActor(actor, 3, kCallbackFXArcSpark);
|
2019-10-11 21:59:39 +00:00
|
|
|
}
|
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2019-10-11 21:59:39 +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;
|
2022-09-01 18:43:35 +00:00
|
|
|
if (actor->int_vel().Z)
|
2021-12-29 19:03:42 +00:00
|
|
|
{
|
|
|
|
int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) / 2)) >> 2;
|
2022-08-16 21:15:49 +00:00
|
|
|
int x = actor->int_pos().X + MulScale(nDist, Cos(actor->int_ang() - 512), 30);
|
|
|
|
int y = actor->int_pos().Y + MulScale(nDist, Sin(actor->int_ang() - 512), 30);
|
2022-01-30 17:09:26 +00:00
|
|
|
int z = actor->int_pos().Z;
|
2021-12-30 15:51:56 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_7, actor->sector(), x, y, z, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:11:05 +00:00
|
|
|
pFX->vel = actor->vel;
|
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: {
|
2022-05-23 22:30:41 +00:00
|
|
|
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;
|
2022-08-23 19:25:05 +00:00
|
|
|
actor->ZeroVelocity();
|
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;
|
2022-08-10 22:13:36 +00:00
|
|
|
actor->spr.pos = actor->basePoint;
|
2021-12-29 19:03:42 +00:00
|
|
|
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:
|
2022-09-09 16:32:42 +00:00
|
|
|
actor->set_native_clipdist(getDudeInfo(nType + kDudeBase)->clipdist);
|
2021-12-29 19:03:42 +00:00
|
|
|
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
|
2022-09-09 16:32:42 +00:00
|
|
|
actor->set_native_clipdist(getDudeInfo(nType + kDudeBase)->clipdist);
|
2021-12-29 19:03:42 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-08-22 16:31:03 +00:00
|
|
|
gFX.fxSpawnActor(FX_29, actor->sector(), actor->spr.pos, 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);
|
2022-01-30 17:09:26 +00:00
|
|
|
int x = actor->int_pos().X + MulScale(nDist, Cos(nAngle), 30);
|
|
|
|
int y = actor->int_pos().Y + MulScale(nDist, Sin(nAngle), 30);
|
2021-12-29 19:03:42 +00:00
|
|
|
int z = bottom - Random(bottom - top);
|
2021-12-30 15:51:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Z = actor->vel.Z + Random2F(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);
|
2022-09-01 18:43:35 +00:00
|
|
|
for (int i = 0; i < (abs(actor->int_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);
|
2022-01-30 17:09:26 +00:00
|
|
|
int x = actor->int_pos().X + MulScale(nDist, Cos(nAngle), 30);
|
|
|
|
int y = actor->int_pos().Y + MulScale(nDist, Sin(nAngle), 30);
|
2021-12-29 19:03:42 +00:00
|
|
|
int z = bottom - Random(bottom - top);
|
2021-12-30 15:51:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Z = actor->vel.Z + Random2F(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
|
|
|
}
|
|
|
|
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-11-24 00:05:17 +00:00
|
|
|
void FinishHim(DBloodActor* actor, sectortype*) // 13
|
2019-10-11 21:59:39 +00:00
|
|
|
{
|
2021-12-29 19:03:42 +00:00
|
|
|
if (!actor) return;
|
2022-09-10 13:15:58 +00:00
|
|
|
if (actor->IsPlayerActor() && playerSeqPlaying(&gPlayer[actor->spr.type - kDudePlayer1], 16) && actor == gPlayer[myconnectindex].actor)
|
2021-12-29 19:03:42 +00:00
|
|
|
sndStartSample(3313, -1, 1, 0);
|
2019-10-11 21:59:39 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2022-09-09 16:32:42 +00:00
|
|
|
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->native_clipdist(), CLIPMASK0);
|
2021-12-29 19:03:42 +00:00
|
|
|
int top, bottom;
|
|
|
|
GetActorExtents(actor, &top, &bottom);
|
2022-01-30 15:20:11 +00:00
|
|
|
actor->add_int_z(floorZ - bottom);
|
2021-12-29 19:03:42 +00:00
|
|
|
int nAngle = Random(2048);
|
|
|
|
int nDist = Random(16) << 4;
|
2022-01-30 17:09:26 +00:00
|
|
|
int x = actor->int_pos().X + MulScale(nDist, Cos(nAngle), 28);
|
|
|
|
int y = actor->int_pos().Y + MulScale(nDist, Sin(nAngle), 28);
|
|
|
|
gFX.fxSpawnActor(FX_48, actor->sector(), x, y, actor->int_pos().Z, 0);
|
2022-09-03 16:35:02 +00:00
|
|
|
if (actor->spr.angle == DAngle180)
|
2021-12-29 19:03:42 +00:00
|
|
|
{
|
|
|
|
int nChannel = 28 + (actor->GetIndex() & 2); // this is a little stupid...
|
|
|
|
sfxPlay3DSound(actor, 385, nChannel, 1);
|
|
|
|
}
|
|
|
|
if (Chance(0x5000))
|
|
|
|
{
|
2021-12-30 15:51:56 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_36, actor->sector(), x, y, floorZ - 64, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
2022-08-16 21:20:03 +00:00
|
|
|
pFX->set_int_ang(nAngle);
|
2021-12-29 19:03:42 +00:00
|
|
|
}
|
|
|
|
gFX.remove(actor);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-11-24 00:05:17 +00:00
|
|
|
void fxTeslaAlt(DBloodActor* actor, sectortype*) // 15
|
2019-10-11 21:59:39 +00:00
|
|
|
{
|
2021-12-29 19:03:42 +00:00
|
|
|
if (!actor) return;
|
2022-08-22 16:31:03 +00:00
|
|
|
auto pFX = gFX.fxSpawnActor(FX_49, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-03 08:09:28 +00:00
|
|
|
pFX->vel.X = actor->vel.X + Random2F(0x1aaaa);
|
|
|
|
pFX->vel.Y = actor->vel.Y + Random2F(0x1aaaa);
|
2022-09-16 16:49:21 +00:00
|
|
|
pFX->vel.Z = actor->vel.Z - Random2F(0x1aaaa);
|
2021-12-29 19:03:42 +00:00
|
|
|
}
|
|
|
|
evPostActor(actor, 3, kCallbackFXTeslaAlt);
|
2019-10-11 21:59:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static const int tommySleeveSnd[] = { 608, 609, 611 }; // unused?
|
|
|
|
static const int sawedOffSleeveSnd[] = { 610, 612 };
|
2019-10-11 21:59:39 +00:00
|
|
|
|
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;
|
|
|
|
|
2022-09-09 16:32:42 +00:00
|
|
|
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->native_clipdist(), CLIPMASK0);
|
2021-12-29 19:03:42 +00:00
|
|
|
int top, bottom; GetActorExtents(actor, &top, &bottom);
|
2022-01-30 15:20:11 +00:00
|
|
|
actor->add_int_z(floorZ - bottom);
|
2021-12-29 19:03:42 +00:00
|
|
|
|
2022-09-03 22:28:30 +00:00
|
|
|
double veldiff = actor->vel.Z - actor->sector()->velFloor;
|
2021-12-29 19:03:42 +00:00
|
|
|
|
2022-09-03 08:12:09 +00:00
|
|
|
if (actor->vel.Z == 0) sleeveStopBouncing(actor);
|
2022-09-03 22:28:30 +00:00
|
|
|
else if (veldiff > 0)
|
2022-09-02 21:56:03 +00:00
|
|
|
{
|
2022-09-03 22:28:30 +00:00
|
|
|
auto vec4 = actFloorBounceVector(actor, veldiff, actor->sector(), FixedToFloat(0x9000));
|
2022-09-03 07:45:23 +00:00
|
|
|
actor->vel = vec4.XYZ();
|
2022-09-02 21:56:03 +00:00
|
|
|
|
2022-09-03 22:28:30 +00:00
|
|
|
if (actor->sector()->velFloor == 0 && abs(actor->vel.Z) < 0x2) {
|
2021-12-29 19:03:42 +00:00
|
|
|
sleeveStopBouncing(actor);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nChannel = 28 + (actor->GetIndex() & 2);
|
|
|
|
|
|
|
|
// tommy sleeve
|
2022-05-05 23:14:58 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2019-10-11 21:59:39 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2019-10-11 21:59:39 +00:00
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
void sleeveStopBouncing(DBloodActor* actor)
|
2021-08-27 15:04:34 +00:00
|
|
|
{
|
2022-08-23 19:25:05 +00:00
|
|
|
actor->ZeroVelocity();
|
2021-12-29 19:03:42 +00:00
|
|
|
if (actor->hasX()) seqKill(actor);
|
|
|
|
sfxKill3DSound(actor, -1, -1);
|
|
|
|
|
|
|
|
switch (actor->spr.type) {
|
2022-05-05 23:14:58 +00:00
|
|
|
case FX_37:
|
|
|
|
case FX_38:
|
|
|
|
case FX_39:
|
2021-12-29 19:03:42 +00:00
|
|
|
actor->spr.picnum = 2465;
|
|
|
|
break;
|
2022-05-05 23:14:58 +00:00
|
|
|
case FX_40:
|
|
|
|
case FX_41:
|
|
|
|
case FX_42:
|
2021-12-29 19:03:42 +00:00
|
|
|
actor->spr.picnum = 2464;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-05 23:14:58 +00:00
|
|
|
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:
|
2022-08-10 21:45:29 +00:00
|
|
|
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:
|
2022-08-10 21:45:29 +00:00
|
|
|
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);
|
2019-10-11 21:59:39 +00:00
|
|
|
}
|
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-11-24 00:05:17 +00:00
|
|
|
void fxPodBloodSpray(DBloodActor* actor, sectortype*) // 18
|
2019-10-11 21:59:39 +00:00
|
|
|
{
|
2021-12-29 19:03:42 +00:00
|
|
|
if (!actor) return;
|
|
|
|
DBloodActor* pFX;
|
|
|
|
if (actor->spr.type == 53)
|
2022-08-22 16:31:03 +00:00
|
|
|
pFX = gFX.fxSpawnActor(FX_53, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
else
|
2022-08-22 16:31:03 +00:00
|
|
|
pFX = gFX.fxSpawnActor(FX_54, actor->sector(), actor->spr.pos, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
|
|
|
{
|
2022-09-09 16:37:55 +00:00
|
|
|
pFX->spr.angle = nullAngle;
|
2022-09-03 08:12:09 +00:00
|
|
|
pFX->vel = actor->vel * (1./256);
|
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;
|
|
|
|
|
2022-09-09 16:32:42 +00:00
|
|
|
GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, actor->native_clipdist(), CLIPMASK0);
|
2021-12-29 19:03:42 +00:00
|
|
|
int top, bottom;
|
|
|
|
GetActorExtents(actor, &top, &bottom);
|
2022-01-30 15:20:11 +00:00
|
|
|
actor->add_int_z(floorZ - bottom);
|
2021-12-29 19:03:42 +00:00
|
|
|
int nAngle = Random(2048);
|
|
|
|
int nDist = Random(16) << 4;
|
2022-01-30 17:09:26 +00:00
|
|
|
int x = actor->int_pos().X + MulScale(nDist, Cos(nAngle), 28);
|
|
|
|
int y = actor->int_pos().Y + MulScale(nDist, Sin(nAngle), 28);
|
2022-09-03 16:35:02 +00:00
|
|
|
if (actor->spr.angle == DAngle180 && 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)
|
2021-12-30 15:51:56 +00:00
|
|
|
pFX = gFX.fxSpawnActor(FX_55, actor->sector(), x, y, floorZ - 64, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
2022-08-16 21:20:03 +00:00
|
|
|
pFX->set_int_ang(nAngle);
|
2021-12-29 19:03:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-30 15:51:56 +00:00
|
|
|
pFX = gFX.fxSpawnActor(FX_32, actor->sector(), x, y, floorZ - 64, 0);
|
2021-12-29 19:03:42 +00:00
|
|
|
if (pFX)
|
2022-08-16 21:20:03 +00:00
|
|
|
pFX->set_int_ang(nAngle);
|
2021-12-29 19:03:42 +00:00
|
|
|
}
|
|
|
|
gFX.remove(actor);
|
2019-09-19 22:42:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-29 19:03:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2019-10-11 21:59:39 +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
|
|
|
{
|
2022-08-23 20:52:22 +00:00
|
|
|
double top, bottom;
|
2021-12-29 19:03:42 +00:00
|
|
|
GetActorExtents(actor, &top, &bottom);
|
2022-08-23 20:52:22 +00:00
|
|
|
actor->spr.pos = actor2->spr.pos.plusZ(-(bottom - actor->spr.pos.Z));
|
2022-08-28 03:15:31 +00:00
|
|
|
actor->spr.angle = actor2->spr.angle;
|
2021-12-30 15:51:56 +00:00
|
|
|
ChangeActorSect(actor, actor2->sector());
|
2021-12-29 19:03:42 +00:00
|
|
|
sfxPlay3DSound(actor2, 201, -1, 0);
|
2022-08-23 19:25:05 +00:00
|
|
|
actor->ZeroVelocity();
|
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;
|
|
|
|
}
|
2022-08-20 19:14:00 +00:00
|
|
|
actor->spr.angle = VecToAngle(Owner->spr.pos - actor->spr.pos);
|
2021-12-29 19:03:42 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-10-11 21:59:39 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2020-03-13 20:59:13 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
};
|
2019-09-22 06:39:22 +00:00
|
|
|
|
|
|
|
END_BLD_NS
|