Blood projectile scriptification.

This commit is contained in:
Christoph Oelckers 2023-10-05 16:50:06 +02:00
parent 93dde24ae1
commit cb443d443c
19 changed files with 625 additions and 217 deletions

View file

@ -100,3 +100,4 @@ xx(ExtraSound5)
xx(ExtraSound6)
xx(CloseAttackPercent)
xx(AttackPercent)
xx(BloodMissileBase)

View file

@ -1934,7 +1934,7 @@ bool actHealDude(DBloodActor* actor, int add, int threshold)
threshold <<= 4;
if (actor->xspr.health < (unsigned)threshold)
{
if (actor->IsPlayerActor()) sfxPlay3DSound(actor->spr.pos, 780, actor->sector());
if (actor->IsPlayerActor()) sfxPlay3DSectorSound(actor->spr.pos, 780, actor->sector());
actor->xspr.health = min<uint32_t>(actor->xspr.health + add, threshold);
return true;
}
@ -2620,7 +2620,7 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D
{
case -1:
GibSprite(actor, GIBTYPE_14, nullptr, nullptr);
sfxPlay3DSound(actor->spr.pos, 312, actor->sector());
sfxPlay3DSectorSound(actor->spr.pos, 312, actor->sector());
actPostSprite(actor, kStatFree);
break;
@ -2793,7 +2793,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
case kMissileArcGargoyle:
sfxKill3DSound(missileActor, -1, -1);
sfxPlay3DSound(missileActor->spr.pos, 306, missileActor->sector());
sfxPlay3DSectorSound(missileActor->spr.pos, 306, missileActor->sector());
GibSprite(missileActor, GIBTYPE_6, NULL, NULL);
if (hitCode == 3 && actorHit && (pThingInfo || pDudeInfo))
@ -2807,7 +2807,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
case kMissileLifeLeechAltNormal:
case kMissileLifeLeechAltSmall:
sfxKill3DSound(missileActor, -1, -1);
sfxPlay3DSound(missileActor->spr.pos, 306, missileActor->sector());
sfxPlay3DSectorSound(missileActor->spr.pos, 306, missileActor->sector());
if (hitCode == 3 && actorHit && (pThingInfo || pDudeInfo))
{
@ -2921,7 +2921,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
case kMissileEctoSkull:
sfxKill3DSound(missileActor, -1, -1);
sfxPlay3DSound(missileActor->spr.pos, 522, missileActor->sector());
sfxPlay3DSectorSound(missileActor->spr.pos, 522, missileActor->sector());
actPostSprite(missileActor, kStatDebris);
seqSpawn(20, missileActor, -1);
if (hitCode == 3 && actorHit && actorHit->hasX())
@ -2954,7 +2954,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
case kMissileTeslaRegular:
sfxKill3DSound(missileActor, -1, -1);
sfxPlay3DSound(missileActor->spr.pos, 518, missileActor->sector());
sfxPlay3DSectorSound(missileActor->spr.pos, 518, missileActor->sector());
GibSprite(missileActor, (hitCode == 2) ? GIBTYPE_23 : GIBTYPE_22, NULL, NULL);
evKillActor(missileActor);
seqKill(missileActor);
@ -3185,7 +3185,7 @@ static void checkHit(DBloodActor* actor)
break;
case kThingZombieHead:
sfxPlay3DSound(actor->spr.pos, 357, actor->sector());
sfxPlay3DSectorSound(actor->spr.pos, 357, actor->sector());
actKickObject(actor, actor2);
actDamageSprite(nullptr, actor2, kDamageFall, 80);
break;
@ -3263,7 +3263,7 @@ static void checkFloorHit(DBloodActor* actor)
pPlayer->kickPower = PlayClock + 60;
}
actKickObject(actor, actor2);
sfxPlay3DSound(actor->spr.pos, 357, actor->sector());
sfxPlay3DSectorSound(actor->spr.pos, 357, actor->sector());
sfxPlay3DSound(actor, 374, 0, 0);
break;
case kThingZombieHead:
@ -3273,7 +3273,7 @@ static void checkFloorHit(DBloodActor* actor)
pPlayer->kickPower = PlayClock + 60;
}
actKickObject(actor, actor2);
sfxPlay3DSound(actor->spr.pos, 357, actor->sector());
sfxPlay3DSectorSound(actor->spr.pos, 357, actor->sector());
actDamageSprite(nullptr, actor2, kDamageFall, 80);
break;
case kTrapSawCircular:
@ -4392,7 +4392,7 @@ void actActivateGibObject(DBloodActor* actor)
if (gib1 > 0) GibSprite(actor, (GIBTYPE)(gib1 - 1), nullptr, nullptr);
if (gib2 > 0) GibSprite(actor, (GIBTYPE)(gib2 - 1), nullptr, nullptr);
if (gib3 > 0 && actor->xspr.burnTime > 0) GibSprite(actor, (GIBTYPE)(gib3 - 1), nullptr, nullptr);
if (sound > 0) sfxPlay3DSound(actor->spr.pos, sound, actor->sector());
if (sound > 0) sfxPlay3DSectorSound(actor->spr.pos, sound, actor->sector());
if (dropmsg > 0) actDropObject(actor, dropmsg);
if (!(actor->spr.cstat & CSTAT_SPRITE_INVISIBLE) && !(actor->spr.flags & kHitagRespawn))
@ -5275,145 +5275,6 @@ DBloodActor* actFireThing(DBloodActor* actor, double xyoff, double zoff, double
//
//---------------------------------------------------------------------------
void actBuildMissile(DBloodActor* spawned, DBloodActor* actor)
{
switch (spawned->GetType())
{
case kMissileLifeLeechRegular:
evPostActor(spawned, 0, kCallbackFXFlameLick);
break;
case kMissileTeslaAlt:
evPostActor(spawned, 0, kCallbackFXTeslaAlt);
break;
case kMissilePukeGreen:
seqSpawn(29, spawned, -1);
break;
case kMissileButcherKnife:
spawned->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_WALL;
break;
case kMissileTeslaRegular:
sfxPlay3DSound(spawned, 251, 0, 0);
break;
case kMissileEctoSkull:
seqSpawn(2, spawned, -1);
sfxPlay3DSound(spawned, 493, 0, 0);
break;
case kMissileFireballNapalm:
seqSpawn(61, spawned, nNapalmClient);
sfxPlay3DSound(spawned, 441, 0, 0);
break;
case kMissileFireball:
seqSpawn(22, spawned, nFireballClient);
sfxPlay3DSound(spawned, 441, 0, 0);
break;
case kMissileFlameHound:
seqSpawn(27, spawned, -1);
spawned->vel += actor->vel * 0.5;
spawned->vel.X += Random2F(0x11111);
spawned->vel.Y += Random2F(0x11111);
spawned->vel.Z += Random2F(0x11111);
break;
case kMissileFireballCerberus:
seqSpawn(61, spawned, dword_2192E0);
sfxPlay3DSound(spawned, 441, 0, 0);
break;
case kMissileFireballTchernobog:
seqSpawn(23, spawned, dword_2192D8);
spawned->vel += actor->vel * 0.5;
spawned->vel.X += Random2F(0x11111);
spawned->vel.Y += Random2F(0x11111);
spawned->vel.Z += Random2F(0x11111);
break;
case kMissileFlameSpray:
if (Chance(0x8000)) seqSpawn(0, spawned, -1);
else seqSpawn(1, spawned, -1);
spawned->vel += actor->vel * 0.5;
spawned->vel.X += Random2F(0x11111);
spawned->vel.Y += Random2F(0x11111);
spawned->vel.Z += Random2F(0x11111);
break;
case kMissileFlareAlt:
evPostActor(spawned, 30, kCallbackFXFlareBurst);
evPostActor(spawned, 0, kCallbackFXFlareSpark);
sfxPlay3DSound(spawned, 422, 0, 0);
break;
case kMissileFlareRegular:
evPostActor(spawned, 0, kCallbackFXFlareSpark);
sfxPlay3DSound(spawned, 422, 0, 0);
break;
case kMissileLifeLeechAltSmall:
evPostActor(spawned, 0, kCallbackFXArcSpark);
break;
case kMissileArcGargoyle:
sfxPlay3DSound(spawned, 252, 0, 0);
break;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
DBloodActor* actFireMissile(DBloodActor* actor, double xyoff, double zoff, DVector3 dv, int nType)
{
assert(nType >= kMissileBase && nType < kMissileMax);
bool impact = false;
const MissileType* pMissileInfo = &missileInfo[nType - kMissileBase];
auto vect = actor->spr.pos.plusZ(zoff) + (actor->spr.Angles.Yaw + DAngle90).ToVector() * xyoff;
double clipdist = pMissileInfo->fClipDist() + actor->clipdist;
vect += actor->spr.Angles.Yaw.ToVector() * clipdist;
int hit = HitScan(actor, vect.Z, DVector3(vect.XY() - actor->spr.pos.XY(), 0), CLIPMASK0, clipdist * 4);
if (hit != -1)
{
if (hit == 3 || hit == 0)
{
impact = true;
vect.XY() = gHitInfo.hitpos.XY() - actor->spr.Angles.Yaw.ToVector() * 1;
}
else
{
vect.XY() = gHitInfo.hitpos.XY() - actor->spr.Angles.Yaw.ToVector() * pMissileInfo->fClipDist() * 2;
}
}
auto cls = GetSpawnType(nType);
auto spawned = actSpawnSprite(actor->sector(), vect, 5, 1, cls, nType);
spawned->spr.cstat2 |= CSTAT2_SPRITE_MAPPED;
spawned->spr.shade = pMissileInfo->shade;
spawned->spr.pal = 0;
spawned->clipdist = pMissileInfo->fClipDist();
spawned->spr.flags = 1;
spawned->spr.scale = DVector2(pMissileInfo->xrepeat * REPEAT_SCALE, pMissileInfo->yrepeat * REPEAT_SCALE);
spawned->spr.setspritetexture(pMissileInfo->textureID());
spawned->spr.Angles.Yaw = actor->spr.Angles.Yaw + mapangle(pMissileInfo->angleOfs);
spawned->vel = dv.Unit() * pMissileInfo->fVelocity();
spawned->SetOwner(actor);
spawned->spr.cstat |= CSTAT_SPRITE_BLOCK;
spawned->SetTarget(nullptr);
evPostActor(spawned, 600, kCallbackRemove);
actBuildMissile(spawned, actor);
if (impact)
{
actImpactMissile(spawned, hit);
return nullptr;
}
return spawned;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
bool actCheckRespawn(DBloodActor* actor)
{
if (actor->hasX())
@ -5702,7 +5563,7 @@ void actFireVector(DBloodActor* shooter, double offset, double zoffset, DVector3
#endif
if (pVectorData->surfHit[nSurf].fxSnd >= 0)
sfxPlay3DSound(pos, pVectorData->surfHit[nSurf].fxSnd, pSector);
sfxPlay3DSectorSound(pos, pVectorData->surfHit[nSurf].fxSnd, pSector);
}
//---------------------------------------------------------------------------

View file

@ -184,7 +184,6 @@ void actFireVector(DBloodActor* shooter, double offset, double zoffset, DVector3
void actPostSprite(DBloodActor* actor, int status);
void actPostProcess(void);
void MakeSplash(DBloodActor *actor);
void actBuildMissile(DBloodActor* spawned, DBloodActor* actor);
extern const int16_t DudeDifficulty[];

View file

@ -36,7 +36,7 @@ BEGIN_BLD_NS
//
//---------------------------------------------------------------------------
void fxFlameLick(DBloodActor* actor, sectortype*) // 0
void fxFlameLick(DBloodActor* actor) // 0
{
if (!actor) return;
double top, bottom;
@ -68,7 +68,7 @@ void fxFlameLick(DBloodActor* actor, sectortype*) // 0
//
//---------------------------------------------------------------------------
void Remove(DBloodActor* actor, sectortype*) // 1
void Remove(DBloodActor* actor) // 1
{
if (!actor) return;
evKillActor(actor, kCallbackFXFlareSpark);
@ -84,7 +84,7 @@ void Remove(DBloodActor* actor, sectortype*) // 1
//
//---------------------------------------------------------------------------
void FlareBurst(DBloodActor* actor, sectortype*) // 2
void FlareBurst(DBloodActor* actor) // 2
{
if (!actor) return;
auto nAngVec = actor->vel.XY().Angle().ToVector();
@ -112,7 +112,7 @@ void FlareBurst(DBloodActor* actor, sectortype*) // 2
//
//---------------------------------------------------------------------------
void fxFlareSpark(DBloodActor* actor, sectortype*) // 3
void fxFlareSpark(DBloodActor* actor) // 3
{
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos);
@ -131,7 +131,7 @@ void fxFlareSpark(DBloodActor* actor, sectortype*) // 3
//
//---------------------------------------------------------------------------
void fxFlareSparkLite(DBloodActor* actor, sectortype*) // 4
void fxFlareSparkLite(DBloodActor* actor) // 4
{
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_28, actor->sector(), actor->spr.pos);
@ -150,7 +150,7 @@ void fxFlareSparkLite(DBloodActor* actor, sectortype*) // 4
//
//---------------------------------------------------------------------------
void fxZombieBloodSpurt(DBloodActor* actor, sectortype*) // 5
void fxZombieBloodSpurt(DBloodActor* actor) // 5
{
if (!actor) return;
assert(actor->hasX());
@ -182,7 +182,7 @@ void fxZombieBloodSpurt(DBloodActor* actor, sectortype*) // 5
//
//---------------------------------------------------------------------------
void fxBloodSpurt(DBloodActor* actor, sectortype*) // 6
void fxBloodSpurt(DBloodActor* actor) // 6
{
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_27, actor->sector(), actor->spr.pos);
@ -200,7 +200,7 @@ void fxBloodSpurt(DBloodActor* actor, sectortype*) // 6
//
//---------------------------------------------------------------------------
void fxArcSpark(DBloodActor* actor, sectortype*) // 7
void fxArcSpark(DBloodActor* actor) // 7
{
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_15, actor->sector(), actor->spr.pos);
@ -219,7 +219,7 @@ void fxArcSpark(DBloodActor* actor, sectortype*) // 7
//
//---------------------------------------------------------------------------
void fxDynPuff(DBloodActor* actor, sectortype*) // 8
void fxDynPuff(DBloodActor* actor) // 8
{
if (!actor) return;
if (actor->vel.Z)
@ -242,7 +242,7 @@ void fxDynPuff(DBloodActor* actor, sectortype*) // 8
//
//---------------------------------------------------------------------------
void Respawn(DBloodActor* actor, sectortype*) // 9
void Respawn(DBloodActor* actor) // 9
{
if (!actor) return;
assert(actor->hasX());
@ -332,7 +332,7 @@ void Respawn(DBloodActor* actor, sectortype*) // 9
//
//---------------------------------------------------------------------------
void PlayerBubble(DBloodActor* actor, sectortype*) // 10
void PlayerBubble(DBloodActor* actor) // 10
{
if (!actor) return;
if (actor->IsPlayerActor())
@ -368,7 +368,7 @@ void PlayerBubble(DBloodActor* actor, sectortype*) // 10
//
//---------------------------------------------------------------------------
void EnemyBubble(DBloodActor* actor, sectortype*) // 11
void EnemyBubble(DBloodActor* actor) // 11
{
if (!actor) return;
double top, bottom;
@ -398,7 +398,7 @@ void EnemyBubble(DBloodActor* actor, sectortype*) // 11
//
//---------------------------------------------------------------------------
void CounterCheck(DBloodActor*, sectortype* pSector) // 12
void CounterCheck(sectortype* pSector) // 12
{
if (!pSector || pSector->type != kSectorCounter) return;
if (!pSector->hasX()) return;
@ -433,14 +433,14 @@ void CounterCheck(DBloodActor*, sectortype* pSector) // 12
//
//---------------------------------------------------------------------------
void FinishHim(DBloodActor* actor, sectortype*) // 13
void FinishHim(DBloodActor* actor) // 13
{
if (!actor) return;
if (actor->IsPlayerActor() && playerSeqPlaying(getPlayer(actor), 16) && actor == getPlayer(myconnectindex)->GetActor())
sndStartSample(3313, -1, 1, 0);
}
void fxBloodBits(DBloodActor* actor, sectortype*) // 14
void fxBloodBits(DBloodActor* actor) // 14
{
if (!actor) return;
double ceilZ, floorZ;
@ -474,7 +474,7 @@ void fxBloodBits(DBloodActor* actor, sectortype*) // 14
//
//---------------------------------------------------------------------------
void fxTeslaAlt(DBloodActor* actor, sectortype*) // 15
void fxTeslaAlt(DBloodActor* actor) // 15
{
if (!actor) return;
auto pFX = gFX.fxSpawnActor(FX_49, actor->sector(), actor->spr.pos);
@ -497,7 +497,7 @@ void fxTeslaAlt(DBloodActor* actor, sectortype*) // 15
static const int tommySleeveSnd[] = { 608, 609, 611 }; // unused?
static const int sawedOffSleeveSnd[] = { 610, 612 };
void fxBouncingSleeve(DBloodActor* actor, sectortype*) // 16
void fxBouncingSleeve(DBloodActor* actor) // 16
{
if (!actor) return;
double ceilZ, floorZ;
@ -576,7 +576,7 @@ void sleeveStopBouncing(DBloodActor* actor)
//
//---------------------------------------------------------------------------
void returnFlagToBase(DBloodActor* actor, sectortype*) // 17
void returnFlagToBase(DBloodActor* actor) // 17
{
if (!actor) return;
auto aOwner = actor->GetOwner();
@ -607,7 +607,7 @@ void returnFlagToBase(DBloodActor* actor, sectortype*) // 17
//
//---------------------------------------------------------------------------
void fxPodBloodSpray(DBloodActor* actor, sectortype*) // 18
void fxPodBloodSpray(DBloodActor* actor) // 18
{
if (!actor) return;
DBloodActor* pFX;
@ -629,7 +629,7 @@ void fxPodBloodSpray(DBloodActor* actor, sectortype*) // 18
//
//---------------------------------------------------------------------------
void fxPodBloodSplat(DBloodActor* actor, sectortype*) // 19
void fxPodBloodSplat(DBloodActor* actor) // 19
{
if (!actor) return;
double ceilZ, floorZ;
@ -673,7 +673,7 @@ void fxPodBloodSplat(DBloodActor* actor, sectortype*) // 19
//
//---------------------------------------------------------------------------
void LeechStateTimer(DBloodActor* actor, sectortype*) // 20
void LeechStateTimer(DBloodActor* actor) // 20
{
if (!actor) return;
if (actor->spr.statnum == kStatThing && !(actor->spr.flags & 32)) {
@ -717,7 +717,7 @@ void sub_76A08(DBloodActor* actor, DBloodActor* actor2, DBloodPlayer* pPlayer) /
//
//---------------------------------------------------------------------------
void DropVoodooCb(DBloodActor* actor, sectortype*) // unused
void DropVoodooCb(DBloodActor* actor) // unused
{
if (!actor) return;
auto Owner = actor->GetOwner();
@ -834,7 +834,7 @@ void DropVoodooCb(DBloodActor* actor, sectortype*) // unused
//
//---------------------------------------------------------------------------
void callbackCondition(DBloodActor* actor, sectortype*)
void callbackCondition(DBloodActor* actor)
{
if (actor->xspr.isTriggered) return;
@ -858,7 +858,7 @@ void callbackCondition(DBloodActor* actor, sectortype*)
//
//---------------------------------------------------------------------------
void(*gCallback[kCallbackMax])(DBloodActor*, sectortype*) =
void(*gCallback[kCallbackMax])(DBloodActor*) =
{
fxFlameLick,
Remove,
@ -872,7 +872,7 @@ void(*gCallback[kCallbackMax])(DBloodActor*, sectortype*) =
Respawn,
PlayerBubble,
EnemyBubble,
CounterCheck,
nullptr,
FinishHim,
fxBloodBits,
fxTeslaAlt,

View file

@ -58,6 +58,6 @@ enum CALLBACK_ID {
kCallbackMax,
};
extern void(*gCallback[kCallbackMax])(DBloodActor*, sectortype*);
extern void(*gCallback[kCallbackMax])(DBloodActor*);
END_BLD_NS

View file

@ -529,7 +529,7 @@ inline int ClipRange(int a, int b, int c)
return a;
}
inline uint8_t Chance(int a1)
inline int Chance(int a1)
{
return wrand() < (a1 >> 1);
}

View file

@ -552,9 +552,10 @@ void evProcess(unsigned int time)
if (event.cmd == kCmdCallback)
{
// Except for CounterCheck all other callbacks are for actors only.
assert(event.funcID < kCallbackMax);
if (event.target.isActor()) gCallback[event.funcID](event.target.actor(), nullptr);
else if (event.target.isSector()) gCallback[event.funcID](nullptr, event.target.sector());
if (event.target.isActor()) gCallback[event.funcID](event.target.actor());
else if (event.target.isSector() && event.funcID == kCallbackCounterCheck) CounterCheck(event.target.sector());
// no case for walls defined here.
}
else

View file

@ -227,7 +227,7 @@ void CFX::fxProcess(void)
remove(actor);
continue;
}
gCallback[pFXData->funcID](actor, nullptr);
gCallback[pFXData->funcID](actor);
continue;
}
if (pSector != actor->sector())
@ -252,7 +252,7 @@ void CFX::fxProcess(void)
remove(actor);
continue;
}
gCallback[pFXData->funcID](actor, nullptr);
gCallback[pFXData->funcID](actor);
continue;
}
}

View file

@ -498,7 +498,7 @@ void GibWall(walltype* pWall, GIBTYPE nGibType, DVector3* pVel)
center.Z = (ceilZ + floorZ) * 0.5;
GIBLIST* pGib = &gibList[nGibType];
sfxPlay3DSound(center, pGib->sound, pSector);
sfxPlay3DSectorSound(center, pGib->sound, pSector);
for (int i = 0; i < pGib->FXCount; i++)
{
GIBFX* pGibFX = &pGib->gibFX[i];

View file

@ -269,3 +269,9 @@ x(DIVEHUD, 2344)
x(DIVEDETAIL1, 2346)
x(DIVEDETAIL2, 2347)
x(ASBESTHUD, 2358)
x(ButcherKnife, 2138)
x(Fireball, 3056)
x(Teslaball, 2130)
x(EctoSkull, 870)
x(LeechBall, 2446)

View file

@ -3735,7 +3735,7 @@ void useSeqSpawnerGen(DBloodActor* sourceactor, int objType, sectortype* pSector
floorZ = min(floorZ, floorZ2);
cpos.Z = (ceilZ + floorZ) * 0.5;
sfxPlay3DSound(cpos, sourceactor->xspr.data4, pSector);
sfxPlay3DSectorSound(cpos, sourceactor->xspr.data4, pSector);
}
}
return;
@ -9170,7 +9170,7 @@ void levelEndLevelCustom(int nLevel)
//
//---------------------------------------------------------------------------
void callbackUniMissileBurst(DBloodActor* actor, sectortype*) // 22
void callbackUniMissileBurst(DBloodActor* actor) // 22
{
if (!actor) return;
if (actor->spr.statnum != kStatProjectile) return;
@ -9202,7 +9202,11 @@ void callbackUniMissileBurst(DBloodActor* actor, sectortype*) // 22
burstactor->spr.Angles.Yaw = actor->spr.Angles.Yaw + mapangle(missileInfo[actor->GetType() - kMissileBase].angleOfs);
burstactor->SetOwner(actor);
actBuildMissile(burstactor, actor);
IFVIRTUALPTRNAME(burstactor, NAME_BloodMissileBase, initMissile) // note: delete the name if this get scriptified.
{
VMValue p[] = { burstactor, actor };
VMCall(func, p, 2, nullptr, 0);
}
auto spAngVec = DAngle::fromBam(i << 29).ToVector().Rotated90CW() * nRadius;
if (i & 1) spAngVec *= 0.5;
@ -9219,13 +9223,13 @@ void callbackUniMissileBurst(DBloodActor* actor, sectortype*) // 22
//
//---------------------------------------------------------------------------
void callbackMakeMissileBlocking(DBloodActor* actor, sectortype*) // 23
void callbackMakeMissileBlocking(DBloodActor* actor) // 23
{
if (!actor || actor->spr.statnum != kStatProjectile) return;
actor->spr.cstat |= CSTAT_SPRITE_BLOCK;
}
void callbackGenDudeUpdate(DBloodActor* actor, sectortype*) // 24
void callbackGenDudeUpdate(DBloodActor* actor) // 24
{
if (actor)
genDudeUpdate(actor);

View file

@ -351,9 +351,9 @@ void playerQavScenePlay(DBloodPlayer* pPlayer);
void playerQavSceneDraw(DBloodPlayer* pPlayer, int shade, double xpos, double ypos, int palnum, DAngle angle);
void playerQavSceneReset(DBloodPlayer* pPlayer);
// ------------------------------------------------------------------------- //
void callbackUniMissileBurst(DBloodActor* actor, sectortype* nSprite);
void callbackMakeMissileBlocking(DBloodActor* actor, sectortype* nSprite);
void callbackGenDudeUpdate(DBloodActor* actor, sectortype* nSprite);
void callbackUniMissileBurst(DBloodActor* actor);
void callbackMakeMissileBlocking(DBloodActor* actor);
void callbackGenDudeUpdate(DBloodActor* actor);
// ------------------------------------------------------------------------- //
DBloodPlayer* getPlayerById(int id);
bool isGrown(DBloodActor* pSprite);

View file

@ -1243,7 +1243,7 @@ bool PickupItem(DBloodPlayer* pPlayer, DBloodActor* itemactor)
return 1;
}
sfxPlay3DSound(plActor->spr.pos, pickupSnd, plActor->sector());
sfxPlay3DSectorSound(plActor->spr.pos, pickupSnd, plActor->sector());
return 1;
}

View file

@ -155,7 +155,7 @@ FSoundID getSfx(FSoundID soundId, float& attenuation, int& relvol)
//
//---------------------------------------------------------------------------
void sfxPlay3DSound(const DVector3& pos, int soundId, sectortype* pSector)
void sfxPlay3DSectorSound(const DVector3& pos, int soundId, sectortype* pSector)
{
if (!SoundEnabled() || soundId < 0) return;
auto sid = soundEngine->FindSoundByResID(soundId);

View file

@ -28,7 +28,7 @@ void sndProcess(void);
void sndTerm(void);
void sndInit(void);
void sfxPlay3DSound(const DVector3& pos, int soundId, sectortype* pSector);
void sfxPlay3DSectorSound(const DVector3& pos, int soundId, sectortype* pSector);
void sfxPlay3DSound(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0);
void sfxPlay3DSoundVolume(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0, int pitch = 0, int volume = 0);
void sfxKill3DSound(DBloodActor* pSprite, int a2 = -1, int a3 = -1);

View file

@ -24,7 +24,7 @@ See the GNU General Public License for more details.
#include "blood.h"
BEGIN_BLD_NS
// ai callbacks
DEF_ANIMATOR(aiGenDudeMoveForward)
DEF_ANIMATOR(aiMoveDodge)
DEF_ANIMATOR(aiMoveForward)
@ -149,6 +149,7 @@ DEF_ANIMATOR(zombaThinkSearch)
DEF_ANIMATOR(zombfThinkChase)
DEF_ANIMATOR(zombfThinkGoto)
DEF_ANIMATOR(zombfThinkSearch)
// seq callbacks
DEF_ANIMATOR(FireballSeqCallback)
DEF_ANIMATOR(Fx33Callback)
DEF_ANIMATOR(NapalmSeqCallback)
@ -207,6 +208,29 @@ DEF_ANIMATOR(PlayerKneelsOver)
DEF_ANIMATOR(FireballTrapSeqCallback)
DEF_ANIMATOR(MGunFireSeqCallback)
DEF_ANIMATOR(MGunOpenSeqCallback)
// event callbacks
DEF_ANIMATOR(fxFlameLick) // 0
DEF_ANIMATOR(Remove) // 1
DEF_ANIMATOR(FlareBurst) // 2
DEF_ANIMATOR(fxFlareSpark) // 3
DEF_ANIMATOR(fxFlareSparkLite) // 4
DEF_ANIMATOR(fxZombieBloodSpurt) // 5
DEF_ANIMATOR(fxBloodSpurt) // 6
DEF_ANIMATOR(fxArcSpark) // 7
DEF_ANIMATOR(fxDynPuff) // 8
DEF_ANIMATOR(Respawn) // 9
DEF_ANIMATOR(PlayerBubble) // 10
DEF_ANIMATOR(EnemyBubble) // 11
DEF_ANIMATOR(FinishHim) // 13
DEF_ANIMATOR(fxBloodBits) // 14
DEF_ANIMATOR(fxTeslaAlt) // 15
DEF_ANIMATOR(fxBouncingSleeve) // 16
DEF_ANIMATOR(returnFlagToBase) // 17
DEF_ANIMATOR(fxPodBloodSpray) // 18
DEF_ANIMATOR(fxPodBloodSplat) // 19
DEF_ANIMATOR(LeechStateTimer) // 20
DEF_ANIMATOR(DropVoodooCb) // unused
DEFINE_FIELD_X(GAMEOPTIONS, GAMEOPTIONS, nGameType)
@ -226,6 +250,7 @@ DEFINE_FIELD_X(GAMEOPTIONS, GAMEOPTIONS, weaponsV10x)
DEFINE_FIELD_X(GAMEOPTIONS, GAMEOPTIONS, bFriendlyFire)
DEFINE_FIELD_X(GAMEOPTIONS, GAMEOPTIONS, bKeepKeysOnRespawn)
DEFINE_GLOBAL_UNSIZED(gGameOptions)
DEFINE_GLOBAL_UNSIZED(gHitInfo)
DEFINE_ACTION_FUNCTION(_Blood, OriginalLoadScreen)
@ -250,6 +275,21 @@ DEFINE_ACTION_FUNCTION(_Blood, PlayIntroMusic)
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(_Blood, Random2F, Random2F)
{
PARAM_PROLOGUE;
PARAM_INT(val);
PARAM_INT(scale);
ACTION_RETURN_FLOAT(Random2F(val));
}
DEFINE_ACTION_FUNCTION_NATIVE(_Blood, Chance, Chance)
{
PARAM_PROLOGUE;
PARAM_INT(val);
ACTION_RETURN_INT(Chance(val));
}
DEFINE_ACTION_FUNCTION(_Blood, sndStartSample)
{
PARAM_PROLOGUE;
@ -304,7 +344,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_BloodPlayer, powerupCheck, powerupCheck)
ACTION_RETURN_INT(powerupCheck(self, pwup));
}
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags)
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags2)
DEFINE_FIELD_X(XSECTOR, XSECTOR, marker0)
@ -480,6 +519,49 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, getActorExtents, bloodactor_getActorE
return min(numret, 2);
}
int bloodactor_HitScan(DBloodActor* self, double z, double x, double y, double zz, int clipmask, double clipdist)
{
return HitScan(self, z, DVector3(x, y, zz), clipmask, clipdist);
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, HitScan, bloodactor_HitScan)
{
PARAM_SELF_PROLOGUE(DBloodActor);
PARAM_FLOAT(z);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(zz);
PARAM_INT(clipmask);
PARAM_FLOAT(clipdist);
ACTION_RETURN_INT(bloodactor_HitScan(self, z, x, y, zz, clipmask, clipdist));
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, play3DSoundID, sfxPlay3DSound)
{
PARAM_SELF_PROLOGUE(DBloodActor);
PARAM_INT(sound);
PARAM_INT(chan);
PARAM_INT(flags);
sfxPlay3DSound(self, sound, chan, flags);
return 0;
}
DEFINE_ACTION_FUNCTION(DBloodActor, seqSpawnID) // will be changed later.
{
PARAM_SELF_PROLOGUE(DBloodActor);
PARAM_INT(seqid);
PARAM_INT(cbid);
seqSpawn(seqid, self, cbid);
return 0;
}
DEFINE_ACTION_FUNCTION_NATIVE(DBloodActor, impactMissile, actImpactMissile)
{
PARAM_SELF_PROLOGUE(DBloodActor);
PARAM_INT(hitcode);
actImpactMissile(self, hitcode);
return 0;
}
//---------------------------------------------------------------------------
//
//
@ -520,5 +602,25 @@ int actGetRespawnTime(DBloodActor* actor)
return -1;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
DBloodActor* actFireMissile(DBloodActor* actor, double xyoff, double zoff, DVector3 dv, int nType)
{
IFVM(BloodActor, fireMissile)
{
PClass* ty = GetSpawnType(nType);
DBloodActor* spawned;
VMReturn ret((void**)&spawned);
VMValue param[] = { actor, xyoff, zoff, dv.X, dv.Y, dv.Z, ty};
VMCall(func, param, 1, &ret, 1);
return spawned;
}
return nullptr;
}
END_BLD_NS

View file

@ -1,21 +1,308 @@
class BloodMissileButcherKnife : BloodActor {}
class BloodMissileFlareRegular : BloodActor {}
class BloodMissileTeslaAlt : BloodActor {}
class BloodMissileFlareAlt : BloodActor {}
class BloodMissileFlameSpray : BloodActor {}
class BloodMissileFireball : BloodActor {}
class BloodMissileTeslaRegular : BloodActor {}
class BloodMissileEctoSkull : BloodActor {}
class BloodMissileFlameHound : BloodActor {}
class BloodMissilePukeGreen : BloodActor {}
class BloodMissileUnused : BloodActor {}
class BloodMissileArcGargoyle : BloodActor {}
class BloodMissileFireballNapalm : BloodActor {}
class BloodMissileFireballCerberus : BloodActor {}
class BloodMissileFireballTchernobog : BloodActor {}
class BloodMissileLifeLeechRegular : BloodActor {}
class BloodMissileLifeLeechAltNormal : BloodActor {}
class BloodMissileLifeLeechAltSmall : BloodActor {}
class BloodMissileMax : BloodActor {}
class BloodMissileBase : BloodActor
{
meta double speed;
meta double defclipdist;
meta double angleofs;
meta int callbackID; // make this a function name later
meta int spawnsoundID;
meta Sound spawnsound;
meta double movementAdd;
meta double randomVel;
meta int seqID;
meta name seqName;
meta int seqCallbackID; // make this a function name later
property prefix: none;
property speed: speed;
property clipdist: defclipdist;
property angleofs: angleofs;
property callbackID: callbackID;
property spawnsound: spawnsound;
property spawnsoundID: spawnsoundID;
property movementAdd: movementAdd;
property randomVel: randomVel;
property seqID: seqID;
property seqName: seqName;
property seqCallbackID: seqCallbackID;
default
{
callbackID -1;
seqID -1;
spawnsoundID -1;
seqCallbackID -1;
}
virtual void initMissile(BloodActor spawner)
{
self.vel += self.movementAdd * spawner.vel;
if (self.randomVel > 0)
{
self.vel += (Blood.Random2F(self.randomVel), Blood.Random2F(self.randomVel), Blood.Random2F(self.randomVel) );
}
if (self.seqName != 'None')
{
// todo: the game cannot handle named seqs yet.
}
else if (self.seqID > -1)
{
self.seqSpawnID(self.seqID, self.seqCallbackID);
}
if (self.callbackID > -1)
{
self.evPostActorCallback(0, self.callbackID);
}
if (self.spawnsound != 0)
{
// todo: currently only IDs supported.
//self.play3DSound(self.spawnsound, 0, 0);
}
else if (self.spawnsoundID > -1)
{
self.play3DSoundID(self.spawnsoundID, 0, 0);
}
}
}
class BloodMissileButcherKnife : BloodMissileBase
{
default
{
pic "ButcherKnife";
speed 14.933319;
angleOfs 90.000000;
scale 0.625000, 0.625000;
shade -16;
clipdist 4.000000;
}
override void initMissile(BloodActor spawner)
{
super.initMissile(spawner);
self.cstat |= CSTAT_SPRITE_ALIGNMENT_WALL;
}
}
class BloodMissileFlareRegular : BloodMissileBase
{
default
{
pic "FLAREBURST";
speed 48.000000;
scale 0.500000, 0.500000;
shade -128;
clipdist 8.000000;
callbackID kCallbackFXFlareSpark;
spawnsoundID 422;
}
}
class BloodMissileTeslaAlt : BloodMissileBase
{
default
{
pic "Fireball";
speed 42.666656;
scale 0.500000, 0.500000;
shade -128;
clipdist 8.000000;
callbackID kCallbackFXTeslaAlt;
}
}
class BloodMissileFlareAlt : BloodMissileBase
{
default
{
pic "FLAREBURST";
speed 37.333328;
scale 0.500000, 0.500000;
shade -128;
clipdist 1.000000;
callbackID kCallbackFXFlareSpark;
spawnsoundID 422;
}
override void initMissile(BloodActor spawner)
{
super.initMissile(spawner);
self.evPostActorCallback(30, kCallbackFXFlareBurst);
}
}
class BloodMissileFlameSpray : BloodMissileBase
{
default
{
speed 17.066666;
scale 0.375000, 0.375000;
shade -128;
clipdist 4.000000;
movementAdd 0.5;
RandomVel 0x11111;
}
override void initMissile(BloodActor spawner)
{
super.InitMissile(spawner);
int index = Blood.Chance(0x8000)? 1 : 0;
self.seqSpawnID(index, -1);
}
}
class BloodMissileFireball : BloodMissileBase
{
default
{
speed 17.066666;
scale 0.500000, 0.500000;
shade -128;
clipdist 8.000000;
spawnsoundID 441;
seqID 22;
seqCallbackID nFireballClient;
}
}
class BloodMissileTeslaRegular : BloodMissileBase
{
default
{
pic "Teslaball";
speed 42.666656;
scale 0.500000, 0.500000;
shade -128;
clipdist 4.000000;
spawnsoundID 251;
}
}
class BloodMissileEctoSkull : BloodMissileBase
{
default
{
pic "EctoSkull";
speed 10.666656;
scale 0.500000, 0.500000;
shade -24;
clipdist 8.000000;
spawnsoundID 493;
}
}
class BloodMissileFlameHound : BloodMissileBase
{
default
{
speed 17.066666;
scale 0.375000, 0.375000;
shade -128;
clipdist 4.000000;
seqID 27;
movementAdd 0.5;
randomVel 0x11111;
}
}
class BloodMissilePukeGreen : BloodMissileBase
{
default
{
speed 12.799988;
scale 0.250000, 0.250000;
shade -16;
clipdist 4.000000;
seqID 29;
}
}
class BloodMissileUnused : BloodMissileBase
{
default
{
speed 12.799988;
scale 0.125000, 0.125000;
clipdist 4.000000;
}
}
class BloodMissileArcGargoyle : BloodMissileBase
{
default
{
pic "Fireball";
speed 32.000000;
scale 0.500000, 0.500000;
shade -128;
clipdist 4.000000;
spawnsoundID 252;
}
}
class BloodMissileFireballNapalm : BloodMissileBase
{
default
{
speed 37.333328;
scale 0.468750, 0.468750;
shade -128;
clipdist 6.000000;
spawnsoundID 441;
seqID 61;
seqCallbackID nNapalmClient;
}
}
class BloodMissileFireballCerberus : BloodMissileBase
{
default
{
speed 37.333328;
scale 0.468750, 0.468750;
shade -128;
clipdist 6.000000;
seqID 61;
seqCallbackID dword_2192E0;
}
}
class BloodMissileFireballTchernobog : BloodMissileBase
{
default
{
speed 21.333328;
scale 0.375000, 0.375000;
shade -128;
clipdist 4.000000;
seqID 23;
seqCallbackID dword_2192D8;
movementAdd 0.5;
RandomVel 0x11111;
}
}
class BloodMissileLifeLeechRegular : BloodMissileBase
{
default
{
pic "LeechBall";
speed 42.666656;
scale 0.500000, 0.500000;
shade -128;
clipdist 4.000000;
callbackID kCallbackFXFlameLick;
}
}
class BloodMissileLifeLeechAltNormal : BloodMissileBase
{
default
{
pic "Fireball";
speed 37.333328;
scale 0.250000, 0.250000;
shade -128;
clipdist 4.000000;
}
}
class BloodMissileLifeLeechAltSmall : BloodMissileBase
{
default
{
pic "Fireball";
speed 26.666656;
scale 0.500000, 0.500000;
shade -128;
clipdist 4.000000;
callbackID kCallbackFXArcSpark;
}
}

View file

@ -117,6 +117,7 @@ class BloodActor : CoreActor native
kStatFree = 1024,
};
// the callback ids are only temporary. This should work with direct function references.
enum CALLBACK_ID {
kCallbackNone = -1,
kCallbackFXFlameLick = 0,
@ -148,6 +149,70 @@ class BloodActor : CoreActor native
kCallbackCondition = 25,
}
enum SEQ_CALLBACK_ID
{
nFireballClient,
dword_2192D8,
nNapalmClient,
dword_2192E0,
nTreeToGibClient,
nDudeToGibClient1,
nDudeToGibClient2,
nBatBiteClient,
nSlashClient,
nStompClient,
nEelBiteClient,
nBurnClient,
nAttackClient,
nCerberusBiteClient,
nCerberusBurnClient,
nCerberusBurnClient2,
nTommyClient,
nTeslaClient,
nShotClient,
nThrowClient,
n68170Client,
n68230Client,
nSlashFClient,
nThrowFClient,
nThrowSClient,
nBlastSClient,
nGhostSlashClient,
nGhostThrowClient,
nGhostBlastClient,
nGillBiteClient,
nJumpClient,
nHoundBiteClient,
nHoundBurnClient,
nPodStartChaseClient,
nTentacleStartSearchClient,
dword_279B3C,
dword_279B40,
nRatBiteClient,
nSpidBiteClient,
nSpidJumpClient,
nSpidBirthClient,
dword_279B54,
dword_279B58,
dword_279B5C,
nGenDudeAttack1,
nGenDudePunch,
nGenDudeThrow1,
nGenDudeThrow2,
nHackClient,
nStandClient,
nZombfHackClient,
nZombfPukeClient,
nZombfThrowClient,
nPlayerSurviveClient,
nPlayerKneelClient,
nFireballTrapClient,
nMGunFireClient,
nMGunOpenClient,
};
// all callbacks, this is to allow using VM functions for all of them
native void aiGenDudeMoveForward();
native void aiMoveDodge();
native void aiMoveForward();
@ -330,7 +395,26 @@ native void PlayerKneelsOver();
native void FireballTrapSeqCallback();
native void MGunFireSeqCallback();
native void MGunOpenSeqCallback();
native void fxFlameLick(); // 0
native void FlareBurst(); // 2
native void fxFlareSpark(); // 3
native void fxFlareSparkLite(); // 4
native void fxZombieBloodSpurt(); // 5
native void fxBloodSpurt(); // 6
native void fxArcSpark(); // 7
native void fxDynPuff(); // 8
native void Respawn(); // 9
native void PlayerBubble(); // 10
native void EnemyBubble(); // 11
native void FinishHim(); // 13
native void fxBloodBits(); // 14
native void fxTeslaAlt(); // 15
native void fxBouncingSleeve(); // 16
native void returnFlagToBase(); // 17
native void fxPodBloodSpray(); // 18
native void fxPodBloodSplat(); // 19
native void LeechStateTimer(); // 20
native void DropVoodooCb(); // unused
native double dudeSlope;
native readonly bool hasx;
@ -343,7 +427,7 @@ native void MGunOpenSeqCallback();
// nnext stuff. For now not exported to scripting.
//SPRITEMASS spriteMass;
//GENDUDEEXTRA genDudeExtra;
//TObjPtr<DBloodActor*> prevmarker; // needed by the nnext marker code. This originally hijacked targetX in XSPRITE
//TObjPtr<BloodActor> prevmarker; // needed by the nnext marker code. This originally hijacked targetX in XSPRITE
//DVector3 basePoint;
//EventObject condition[2];
@ -357,6 +441,11 @@ native void MGunOpenSeqCallback();
native void addX();
native void evPostActorCallback(int delta, int callback);
native double, double getActorExtents();
native int HitScan(double z, vector3 xyz, int clipmask, double clipdist);
native void impactMissile(int hitcode);
native void play3DSoundID(int soundId, int a3 = -1, int a4 = 0);
native void seqSpawnID(int seqID, int seqCallbackID); // temporary. Callback will be turned into a function
virtual int getRespawnTime()
@ -425,5 +514,59 @@ native void MGunOpenSeqCallback();
return spawned;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
BloodActor fireMissile(double xyoff, double zoff, Vector3 dv, class<BloodMissileBase> type)
{
if (type == null || !(type is 'BloodMissileBase')) return null;
bool impact = false;
Vector3 spawnpos = self.pos + ((self.angle + 90.).ToVector() * xyoff, zoff);
double clipdist = GetDefaultByType(type).defclipdist + self.clipdist;
spawnpos.xy += self.angle.ToVector() * clipdist;
int hit = self.HitScan(spawnpos.Z, (spawnpos.XY - self.pos.XY, 0), CLIPMASK0, clipdist * 4);
if (hit != -1)
{
if (hit == 3 || hit == 0)
{
impact = true;
spawnpos.XY = gHitInfo.hitpos.XY - self.angle.ToVector() * 1;
}
else
{
spawnpos.XY = gHitInfo.hitpos.XY - self.angle.ToVector() * GetDefaultByType(type).defclipdist * 2;
}
}
let spawned = BloodMissileBase(self.spawnSprite(self.sector, spawnpos, kStatProjectile, true, type));
if (spawned == null) return null;
spawned.cstat2 |= CSTAT2_SPRITE_MAPPED;
spawned.shade = spawned.defshade;
spawned.pal = spawned.defpal;
spawned.clipdist = clipdist;
spawned.flags = 1;
spawned.Angle = self.angle + spawned.angleofs;
spawned.vel = dv.Unit() * spawned.speed;
spawned.ownerActor = self;
spawned.cstat |= CSTAT_SPRITE_BLOCK;
spawned.xspr.target = null;
spawned.evPostActorCallback(600, kCallbackRemove);
spawned.initMissile(self); // handle type specific init.
if (impact)
{
spawned.impactMissile(hit);
return nullptr;
}
return spawned;
}
}

View file

@ -89,6 +89,9 @@ struct Blood native
native static TextureID PowerupIcon(int pwup);
native static BloodPlayer GetViewPlayer();
native static double Random2F(int max, int scale = 16);
native static int Chance(int ch);
// These are just dummies to make the MP statusbar code compile.
static void GetPlayers(Array<BloodPlayer> players)
@ -125,6 +128,7 @@ struct GAMEOPTIONS native
extend struct _
{
native readonly @GAMEOPTIONS gGameOptions;
native HitInfo gHitInfo; // having this global sucks but there's too many side effects depending on it...
}
struct PACKINFO // not native!