- virtualized the 'shoot' interface and scriptified the bloodsplats to test it.

This calls virtual functions on the actor defaults now to allow writing specific shoot functions for subclasses.
This commit is contained in:
Christoph Oelckers 2022-11-29 13:06:42 +01:00
parent 8a921c98bd
commit 15fb7dab35
29 changed files with 309 additions and 286 deletions

View file

@ -95,6 +95,26 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Raze, cansee, Raze_cansee)
ACTION_RETURN_BOOL(Raze_cansee(x, y, z, s, xe, ye, ze, se));
}
int Raze_hitscan(double x, double y, double z, sectortype* sec, double xe, double ye, double ze, HitInfoBase* hit, unsigned cliptype, double maxrange)
{
return hitscan(DVector3(x, y, z), sec, DVector3(xe, ye, ze), *hit, cliptype, maxrange);
}
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, hitscan, Raze_hitscan)
{
PARAM_PROLOGUE;
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_POINTER(s, sectortype);
PARAM_FLOAT(xe);
PARAM_FLOAT(ye);
PARAM_FLOAT(ze);
PARAM_POINTER(se, HitInfoBase);
PARAM_UINT(clip);
PARAM_FLOAT(maxrange);
ACTION_RETURN_INT(Raze_hitscan(x, y, z, s, xe, ye, ze, se, clip, maxrange));
}
DEFINE_ACTION_FUNCTION_NATIVE(_Raze, SoundEnabled, SoundEnabled)

View file

@ -808,26 +808,6 @@ void reactor(DDukeActor* const actor, int REACTOR, int REACTOR2, int REACTORBURN
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void bloodsplats(DDukeActor *actor)
{
if (actor->temp_data[0] < 14 * 26)
{
auto offset = krandf(1);
auto lerp = 1. - (double(actor->temp_data[0]) / (14 * 26));
auto zadj = (1. / 16.) * lerp;
auto sadj = (1. / 12.) * lerp * REPEAT_SCALE;
actor->spr.pos.Z += zadj + offset * zadj;
actor->spr.scale.Y += sadj + offset * sadj;
actor->temp_data[0]++;
}
}
//---------------------------------------------------------------------------
//
//
@ -1406,7 +1386,7 @@ void handle_se14(DDukeActor* actor, bool checkstat, int RPG, int JIBS6)
{
auto saved_angle = actor->spr.Angles.Yaw;
actor->spr.Angles.Yaw = (actor->spr.pos.XY() - ps[p].GetActor()->spr.pos.XY()).Angle();
fi.shoot(actor, RPG);
fi.shoot(actor, RPG, nullptr);
actor->spr.Angles.Yaw = saved_angle;
}
}
@ -1892,7 +1872,7 @@ void handle_se05(DDukeActor* actor, int FIRELASER)
{
auto ang = actor->spr.Angles.Yaw;
actor->spr.Angles.Yaw = (actor->spr.pos.XY() - ps[p].GetActor()->spr.pos.XY()).Angle();
fi.shoot(actor, FIRELASER);
fi.shoot(actor, FIRELASER, nullptr);
actor->spr.Angles.Yaw = ang;
}

View file

@ -2426,14 +2426,6 @@ void moveexplosions_d(void) // STATNUM 5
else act->spr.shade = 127;
continue;
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
bloodsplats(act);
continue;
case NUKEBUTTON:
case NUKEBUTTON + 1:
case NUKEBUTTON + 2:
@ -2824,7 +2816,7 @@ void moveeffectors_d(void) //STATNUM 3
if (act->temp_data[0])
{
if (act->temp_data[0] == 1)
fi.shoot(act, sc->extra);
fi.shoot(act, sc->extra, nullptr);
else if (act->temp_data[0] == 26 * 5)
act->temp_data[0] = 0;
act->temp_data[0]++;

View file

@ -2171,14 +2171,6 @@ void moveexplosions_r(void) // STATNUM 5
else act->spr.shade = 127;
continue;
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
bloodsplats(act);
continue;
case MUD:
act->temp_data[0]++;
@ -2559,7 +2551,7 @@ void moveeffectors_r(void) //STATNUM 3
if (act->temp_data[0])
{
if (act->temp_data[0] == 1)
fi.shoot(act, sc->extra);
fi.shoot(act, sc->extra, nullptr);
else if (act->temp_data[0] == 26 * 5)
act->temp_data[0] = 0;
act->temp_data[0]++;

View file

@ -89,16 +89,6 @@ void animatesprites_d(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
t->picnum = h->spr.picnum + k;
break;
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
if (t->pal == 6)
{
t->shade = -127;
continue;
}
[[fallthrough]];
case BULLETHOLE:
t->shade = 16;
continue;

View file

@ -73,16 +73,6 @@ void animatesprites_r(tspriteArray& tsprites, const DVector2& viewVec, DAngle vi
else t->cstat &= ~CSTAT_SPRITE_XFLIP;
t->picnum = h->spr.picnum + k;
break;
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
if (t->pal == 6)
{
t->shade = -127;
continue;
}
[[fallthrough]];
case BULLETHOLE:
t->shade = 16;
continue;

View file

@ -392,8 +392,8 @@ enum
TFLAG_DOORWALL = 1 << 5,
TFLAG_BLOCKDOOR = 1 << 6,
TFLAG_OUTERSPACE = 1 << 7,
TFLAG_NOCIRCLEREFLECT = 32,
TFLAG_NOBLOODSPLAT = 1 << 8,
TFLAG_NOCIRCLEREFLECT = 1 << 9,
};
enum

View file

@ -74,8 +74,8 @@ void move_d(DDukeActor* i, int g_p, int g_x);
void move_r(DDukeActor* i, int g_p, int g_x);
void incur_damage_d(player_struct* p);
void incur_damage_r(player_struct* p);
void shoot_d(DDukeActor* i, int atwith);
void shoot_r(DDukeActor* i, int atwith);
void shoot_d(DDukeActor* i, int atwith, PClass* cls);
void shoot_r(DDukeActor* i, int atwith, PClass* cls);
void selectweapon_d(int snum, int j);
void selectweapon_r(int snum, int j);
int doincrements_d(player_struct* p);

View file

@ -99,7 +99,7 @@ struct Dispatcher
// player
void (*incur_damage)(player_struct* p);
void (*shoot)(DDukeActor*, int);
void (*shoot)(DDukeActor*, int, PClass* cls);
void (*selectweapon)(int snum, int j);
int (*doincrements)(player_struct* p);
void (*checkweapons)(player_struct* p);
@ -125,6 +125,7 @@ bool CallOnUse(DDukeActor* actor, player_struct* user);
void CallOnMotoSmash(DDukeActor* actor, player_struct* hitter);
void CallOnRespawn(DDukeActor* actor, int low);
bool CallAnimate(DDukeActor* actor, tspritetype* hitter);
bool CallShootThis(DDukeActor* clsdef, DDukeActor* actor, int pn, const DVector3& spos, DAngle sang);
void CallStaticSetup(DDukeActor* actor);

View file

@ -44,7 +44,6 @@ bool respawnmarker(DDukeActor* i, int yellow, int green);
void forcesphere(DDukeActor* i, int forcesphere);
void recon(DDukeActor* i, int explosion, int firelaser, int attacksnd, int painsnd, int roamsnd, int shift, int (*getspawn)(DDukeActor* i));
void reactor(DDukeActor* i, int REACTOR, int REACTOR2, int REACTORBURNT, int REACTOR2BURNT, int REACTORSPARK, int REACTOR2SPARK);
void bloodsplats(DDukeActor* actor);
void forcesphereexplode(DDukeActor* i);
void watersplash2(DDukeActor* i);
void frameeffect1(DDukeActor* i);
@ -123,7 +122,6 @@ void quickkill(player_struct* p);
int setpal(player_struct* p);
int madenoise(int playerNum);
int haskey(sectortype* sect, int snum);
void shootbloodsplat(DDukeActor* i, int p, const DVector3& pos, DAngle ang, int atwith, int BIGFORCE);
void breakwall(int newpn, DDukeActor* spr, walltype* dawallnum);
int callsound(sectortype* sectnum,DDukeActor* snum, bool endstate = false);

View file

@ -507,4 +507,16 @@ void CallStaticSetup(DDukeActor* actor)
}
}
bool CallShootThis(DDukeActor* clsdef, DDukeActor* actor, int pn, const DVector3& spos, DAngle sang)
{
int rv = 0;
VMReturn ret(&rv);
IFVIRTUALPTR(clsdef, DDukeActor, ShootThis)
{
VMValue val[] = {clsdef, actor, pn >= 0? &ps[pn] : nullptr, spos.X, spos.Y, spos.Z, sang.Degrees()};
VMCall(func, val, 7, &ret, 1);
}
return rv;
}
END_DUKE_NS

View file

@ -1755,7 +1755,7 @@ int ParseState::parse(void)
break;
case concmd_shoot:
insptr++;
fi.shoot(g_ac, (short)*insptr);
fi.shoot(g_ac, (short)*insptr, nullptr);
insptr++;
break;
case concmd_ifsoundid:

View file

@ -993,69 +993,5 @@ int haskey(sectortype* sectp, int snum)
return 0;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void shootbloodsplat(DDukeActor* actor, int p, const DVector3& pos, DAngle ang, int atwith, int BIGFORCE)
{
auto sectp = actor->sector();
double zvel;
HitInfo hit{};
if (p >= 0)
ang += DAngle22_5 / 2 - randomAngle(22.5);
else ang += DAngle180 + DAngle22_5/2 - randomAngle(22.5);
zvel = 4 - krandf(8);
hitscan(pos, sectp, DVector3(ang.ToVector() * 1024, zvel * 64), hit, CLIPMASK1);
// oh my...
if ( (pos.XY() - hit.hitpos.XY()).Length() < 64 &&
(hit.hitWall != nullptr && hit.hitWall->overpicnum != BIGFORCE) &&
((hit.hitWall->twoSided() && hit.hitSector != nullptr &&
hit.hitWall->nextSector()->lotag == 0 &&
hit.hitSector->lotag == 0 &&
(hit.hitSector->floorz - hit.hitWall->nextSector()->floorz) > 16) ||
(!hit.hitWall->twoSided() && hit.hitSector->lotag == 0)))
{
if ((hit.hitWall->cstat & CSTAT_WALL_MASKED) == 0)
{
if (hit.hitWall->twoSided())
{
DukeSectIterator it(hit.hitWall->nextSector());
while (auto act2 = it.Next())
{
if (act2->spr.statnum == STAT_EFFECTOR && act2->spr.lotag == SE_13_EXPLOSIVE)
return;
}
}
if (hit.hitWall->twoSided() &&
hit.hitWall->nextWall()->hitag != 0)
return;
if (hit.hitWall->hitag == 0)
{
auto spawned = spawn(actor, atwith);
if (spawned)
{
spawned->vel.X = -0.75;
spawned->spr.Angles.Yaw = hit.hitWall->delta().Angle() - DAngle90;
spawned->spr.pos = hit.hitpos;
spawned->spr.cstat |= randomXFlip();
ssp(spawned, CLIPMASK0);
SetActor(spawned, spawned->spr.pos);
if (actorflag(actor, SFLAG2_GREENBLOOD))
spawned->spr.pal = 6;
}
}
}
}
}
END_DUKE_NS

View file

@ -1044,7 +1044,7 @@ static void shootshrinker(DDukeActor* actor, int p, const DVector3& pos, DAngle
//
//---------------------------------------------------------------------------
void shoot_d(DDukeActor* actor, int atwith)
void shoot_d(DDukeActor* actor, int atwith, PClass *cls)
{
int p;
DVector3 spos;
@ -1052,35 +1052,17 @@ void shoot_d(DDukeActor* actor, int atwith)
auto const sect = actor->sector();
sang = actor->spr.Angles.Yaw;
if (actor->isPlayer())
{
p = actor->PlayerIndex();
spos = actor->getPosWithOffsetZ().plusZ(ps[p].pyoff + 4);
ps[p].crack_time = CRACK_TIME;
}
else
{
p = -1;
}
SetGameVarID(g_iAtWithVarID, atwith, actor, p);
SetGameVarID(g_iReturnVarID, 0, actor, p);
OnEvent(EVENT_SHOOT, p, ps[p].GetActor(), -1);
if (GetGameVarID(g_iReturnVarID, actor, p).safeValue() != 0)
{
return;
}
if (actor->isPlayer())
{
spos = ps[p].GetActor()->getPosWithOffsetZ().plusZ(ps[p].pyoff + 4);
sang = ps[p].GetActor()->spr.Angles.Yaw;
ps[p].crack_time = CRACK_TIME;
}
else
{
sang = actor->spr.Angles.Yaw;
spos = actor->spr.pos.plusZ(-(actor->spr.scale.Y * tileHeight(actor->spr.picnum) * 0.5) + 4);
if (actor->spr.picnum != ROTATEGUN)
@ -1094,6 +1076,16 @@ void shoot_d(DDukeActor* actor, int atwith)
}
}
if (cls == nullptr)
{
auto info = spawnMap.CheckKey(atwith);
if (info)
{
cls = static_cast<PClassActor*>(info->Class(atwith));
}
}
if (cls && cls->IsDescendantOf(RUNTIME_CLASS(DDukeActor)) && CallShootThis(static_cast<DDukeActor*>(GetDefaultByType(cls)), actor, p, spos, sang)) return;
if (isWorldTour())
{ // Twentieth Anniversary World Tour
switch (atwith)
@ -1124,13 +1116,6 @@ void shoot_d(DDukeActor* actor, int atwith)
switch (atwith)
{
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
shootbloodsplat(actor, p, spos, sang, atwith, BIGFORCE);
break;
case KNEE:
shootknee(actor, p, spos, sang);
break;
@ -1528,7 +1513,7 @@ int doincrements_d(player_struct* p)
p->last_quick_kick = p->quick_kick + 1;
p->quick_kick--;
if (p->quick_kick == 8)
fi.shoot(p->GetActor(), KNEE);
fi.shoot(p->GetActor(), KNEE, nullptr);
}
else if (p->last_quick_kick > 0)
p->last_quick_kick--;
@ -2277,7 +2262,7 @@ static void operateweapon(int snum, ESyncBits actions)
case PISTOL_WEAPON: // m-16 in NAM
if (p->kickback_pic == 1)
{
fi.shoot(pact, SHOTSPARK1);
fi.shoot(pact, SHOTSPARK1, nullptr);
S_PlayActorSound(PISTOL_FIRE, pact);
lastvisinc = PlayClock + 32;
p->visibility = 0;
@ -2328,7 +2313,7 @@ static void operateweapon(int snum, ESyncBits actions)
if (p->kickback_pic == 4)
{
for(int ii = 0; ii < 7; ii++)
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN, nullptr);
p->ammo_amount[SHOTGUN_WEAPON]--;
S_PlayActorSound(SHOTGUN_FIRE, pact);
@ -2397,7 +2382,7 @@ static void operateweapon(int snum, ESyncBits actions)
}
S_PlayActorSound(CHAINGUN_FIRE, pact);
fi.shoot(pact, CHAINGUN);
fi.shoot(pact, CHAINGUN, nullptr);
lastvisinc = PlayClock + 32;
p->visibility = 0;
checkavailweapon(p);
@ -2441,7 +2426,7 @@ static void operateweapon(int snum, ESyncBits actions)
else
p->okickback_pic = p->kickback_pic = 0;
p->ammo_amount[p->curr_weapon]--;
fi.shoot(pact, GROWSPARK);
fi.shoot(pact, GROWSPARK, nullptr);
//#ifdef NAM
//#else
@ -2476,7 +2461,7 @@ static void operateweapon(int snum, ESyncBits actions)
else p->okickback_pic = p->kickback_pic = 0;
p->ammo_amount[SHRINKER_WEAPON]--;
fi.shoot(pact, SHRINKER);
fi.shoot(pact, SHRINKER, nullptr);
if (!isNam())
{
@ -2509,7 +2494,7 @@ static void operateweapon(int snum, ESyncBits actions)
{
p->visibility = 0;
lastvisinc = PlayClock + 32;
fi.shoot(pact, RPG);
fi.shoot(pact, RPG, nullptr);
p->ammo_amount[DEVISTATOR_WEAPON]--;
checkavailweapon(p);
}
@ -2519,7 +2504,7 @@ static void operateweapon(int snum, ESyncBits actions)
{
p->visibility = 0;
lastvisinc = PlayClock + 32;
fi.shoot(pact, RPG);
fi.shoot(pact, RPG, nullptr);
p->ammo_amount[DEVISTATOR_WEAPON]--;
checkavailweapon(p);
if (p->ammo_amount[DEVISTATOR_WEAPON] <= 0) p->okickback_pic = p->kickback_pic = 0;
@ -2539,7 +2524,7 @@ static void operateweapon(int snum, ESyncBits actions)
p->visibility = 0;
lastvisinc = PlayClock + 32;
fi.shoot(pact, FREEZEBLAST);
fi.shoot(pact, FREEZEBLAST, nullptr);
checkavailweapon(p);
}
if (pact->spr.scale.X < 0.5)
@ -2567,7 +2552,7 @@ static void operateweapon(int snum, ESyncBits actions)
if (p->cursector->lotag != 2)
{
p->ammo_amount[FLAMETHROWER_WEAPON]--;
fi.shoot(pact, FIREBALL);
fi.shoot(pact, FIREBALL, nullptr);
}
checkavailweapon(p);
}
@ -2589,7 +2574,7 @@ static void operateweapon(int snum, ESyncBits actions)
p->GetActor()->restorez();
p->vel.Z = 0;
if (p->kickback_pic == 3)
fi.shoot(pact, HANDHOLDINGLASER);
fi.shoot(pact, HANDHOLDINGLASER, nullptr);
}
if (p->kickback_pic == 16)
{
@ -2602,7 +2587,7 @@ static void operateweapon(int snum, ESyncBits actions)
case KNEE_WEAPON:
p->kickback_pic++;
if (p->kickback_pic == 7) fi.shoot(pact, KNEE);
if (p->kickback_pic == 7) fi.shoot(pact, KNEE, nullptr);
else if (p->kickback_pic == 14)
{
if (actions & SB_FIRE)
@ -2621,7 +2606,7 @@ static void operateweapon(int snum, ESyncBits actions)
p->ammo_amount[RPG_WEAPON]--;
lastvisinc = PlayClock + 32;
p->visibility = 0;
fi.shoot(pact, RPG);
fi.shoot(pact, RPG, nullptr);
checkavailweapon(p);
}
else if (p->kickback_pic == 20)

View file

@ -810,7 +810,7 @@ static void shootmortar(DDukeActor* actor, int p, const DVector3& pos, DAngle an
//
//---------------------------------------------------------------------------
void shoot_r(DDukeActor* actor, int atwith)
void shoot_r(DDukeActor* actor, int atwith, PClass* cls)
{
int p;
DVector3 spos;
@ -818,18 +818,17 @@ void shoot_r(DDukeActor* actor, int atwith)
auto const sect = actor->sector();
sang = actor->spr.Angles.Yaw;
if (actor->isPlayer())
{
p = actor->PlayerIndex();
spos = ps[p].GetActor()->getPosWithOffsetZ().plusZ(ps[p].pyoff + 4);
sang = ps[p].GetActor()->spr.Angles.Yaw;
spos = actor->getPosWithOffsetZ().plusZ(ps[p].pyoff + 4);
if (isRRRA()) ps[p].crack_time = CRACK_TIME;
}
else
{
p = -1;
sang = actor->spr.Angles.Yaw;
spos = actor->spr.pos.plusZ(-(actor->spr.scale.Y * tileHeight(actor->spr.picnum) * 0.5) - 3);
if (badguy(actor))
@ -839,23 +838,18 @@ void shoot_r(DDukeActor* actor, int atwith)
}
}
SetGameVarID(g_iAtWithVarID, atwith, actor, p);
SetGameVarID(g_iReturnVarID, 0, actor, p);
OnEvent(EVENT_SHOOT, p, ps[p].GetActor(), -1);
if (GetGameVarID(g_iReturnVarID, actor, p).safeValue() != 0)
if (cls == nullptr)
{
return;
auto info = spawnMap.CheckKey(atwith);
if (info)
{
cls = static_cast<PClassActor*>(info->Class(atwith));
}
}
if (cls && cls->IsDescendantOf(RUNTIME_CLASS(DDukeActor)) && CallShootThis(static_cast<DDukeActor*>(GetDefaultByType(cls)), actor, p, spos, sang)) return;
switch (atwith)
{
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
shootbloodsplat(actor, p, spos, sang, atwith, BIGFORCE);
return;
case SLINGBLADE:
if (!isRRRA()) break;
[[fallthrough]];
@ -2726,7 +2720,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
case PISTOL_WEAPON:
if (p->kickback_pic == 1)
{
fi.shoot(pact, SHOTSPARK1);
fi.shoot(pact, SHOTSPARK1, nullptr);
S_PlayActorSound(PISTOL_FIRE, pact);
p->noise_radius = 512;
madenoise(snum);
@ -2791,16 +2785,16 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
if (p->kickback_pic == 4)
{
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
p->ammo_amount[SHOTGUN_WEAPON]--;
@ -2817,16 +2811,16 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
{
if (p->shotgun_state[1])
{
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
fi.shoot(pact, SHOTGUN, nullptr);
p->ammo_amount[SHOTGUN_WEAPON]--;
@ -2917,7 +2911,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
}
S_PlayActorSound(CHAINGUN_FIRE, pact);
fi.shoot(pact, CHAINGUN);
fi.shoot(pact, CHAINGUN, nullptr);
p->noise_radius = 512;
madenoise(snum);
lastvisinc = PlayClock + 32;
@ -2949,7 +2943,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
if (p->kickback_pic > 3)
{
p->okickback_pic = p->kickback_pic = 0;
fi.shoot(pact, GROWSPARK);
fi.shoot(pact, GROWSPARK, nullptr);
p->noise_radius = 64;
madenoise(snum);
checkavailweapon(p);
@ -2962,7 +2956,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
if (p->kickback_pic == 1)
{
p->ammo_amount[THROWSAW_WEAPON]--;
fi.shoot(pact, SHRINKSPARK);
fi.shoot(pact, SHRINKSPARK, nullptr);
checkavailweapon(p);
}
p->kickback_pic++;
@ -2977,7 +2971,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
p->visibility = 0;
lastvisinc = PlayClock + 32;
S_PlayActorSound(CHAINGUN_FIRE, pact);
fi.shoot(pact, SHOTSPARK1);
fi.shoot(pact, SHOTSPARK1, nullptr);
p->noise_radius = 1024;
madenoise(snum);
p->ammo_amount[TIT_WEAPON]--;
@ -3004,7 +2998,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
p->visibility = 0;
lastvisinc = PlayClock + 32;
S_PlayActorSound(CHAINGUN_FIRE, pact);
fi.shoot(pact, CHAINGUN);
fi.shoot(pact, CHAINGUN, nullptr);
p->noise_radius = 1024;
madenoise(snum);
p->ammo_amount[MOTORCYCLE_WEAPON]--;
@ -3031,7 +3025,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
{
p->MotoSpeed -= 20;
p->ammo_amount[BOAT_WEAPON]--;
fi.shoot(pact, BOATGRENADE);
fi.shoot(pact, BOATGRENADE, nullptr);
}
p->kickback_pic++;
if (p->kickback_pic > 20)
@ -3048,7 +3042,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
case ALIENBLASTER_WEAPON:
p->kickback_pic++;
if (p->kickback_pic >= 7 && p->kickback_pic <= 11)
fi.shoot(pact, FIRELASER);
fi.shoot(pact, FIRELASER, nullptr);
if (p->kickback_pic == 5)
{
@ -3106,7 +3100,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
{
p->ammo_amount[BOWLING_WEAPON]--;
S_PlayActorSound(354, pact);
fi.shoot(pact, BOWLINGBALL);
fi.shoot(pact, BOWLINGBALL, nullptr);
p->noise_radius = 64;
madenoise(snum);
}
@ -3129,7 +3123,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
S_PlayActorSound(426, pact);
if (p->kickback_pic == 12)
{
fi.shoot(pact, KNEE);
fi.shoot(pact, KNEE, nullptr);
p->noise_radius = 64;
madenoise(snum);
}
@ -3147,7 +3141,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
S_PlayActorSound(252, pact);
if (p->kickback_pic == 8)
{
fi.shoot(pact, SLINGBLADE);
fi.shoot(pact, SLINGBLADE, nullptr);
p->noise_radius = 64;
madenoise(snum);
}
@ -3167,7 +3161,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
p->ammo_amount[DYNAMITE_WEAPON]--;
lastvisinc = PlayClock + 32;
p->visibility = 0;
fi.shoot(pact, RPG);
fi.shoot(pact, RPG, nullptr);
p->noise_radius = 2048;
madenoise(snum);
checkavailweapon(p);
@ -3185,7 +3179,7 @@ static void operateweapon(int snum, ESyncBits actions, sectortype* psectp)
p->ammo_amount[CHICKEN_WEAPON]--;
lastvisinc = PlayClock + 32;
p->visibility = 0;
fi.shoot(pact, RPG2);
fi.shoot(pact, RPG2, nullptr);
p->noise_radius = 2048;
madenoise(snum);
checkavailweapon(p);

View file

@ -65,10 +65,10 @@ void DoFire(player_struct* p, int snum)
SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum);
SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike(p->curr_weapon, snum), p->GetActor(), snum);
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum));
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum), nullptr);
for (i = 1; i < aplWeaponShotsPerBurst(p->curr_weapon, snum); i++)
{
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum));
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum), nullptr);
if (aplWeaponFlags(p->curr_weapon, snum) & WEAPON_FLAG_AMMOPERSHOT)
{
p->ammo_amount[p->curr_weapon]--;
@ -405,7 +405,7 @@ void operateweapon_ww(int snum, ESyncBits actions)
}
SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum);
SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike(p->curr_weapon, snum), p->GetActor(), snum);
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum));
fi.shoot(p->GetActor(), aplWeaponShoots(p->curr_weapon, snum), nullptr);
}
}

View file

@ -969,10 +969,10 @@ void checkhitdefault_d(DDukeActor* targ, DDukeActor* proj)
if (Owner && Owner->isPlayer() && targ->spr.picnum != ROTATEGUN && targ->spr.picnum != DRONE)
if (ps[Owner->PlayerIndex()].curr_weapon == SHOTGUN_WEAPON)
{
fi.shoot(targ, BLOODSPLAT3);
fi.shoot(targ, BLOODSPLAT1);
fi.shoot(targ, BLOODSPLAT2);
fi.shoot(targ, BLOODSPLAT4);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat3"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat1"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat2"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat4"));
}
if (!actorflag(targ, SFLAG2_NODAMAGEPUSH) && !bossguy(targ)) // RR does not have this.
@ -1172,7 +1172,7 @@ void checkhitsprite_d(DDukeActor* targ, DDukeActor* proj)
case FETUSBROKE:
for (j = 0; j < 48; j++)
{
fi.shoot(targ, BLOODSPLAT1);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat1"));
targ->spr.Angles.Yaw += DAngle1 * 58.5; // Was 333, which really makes no sense.
}
S_PlayActorSound(GLASS_HEAVYBREAK, targ);
@ -1254,21 +1254,21 @@ void checkhitsprite_d(DDukeActor* targ, DDukeActor* proj)
targ->spr.extra -= proj->spr.extra;
if (targ->spr.extra > 0) break;
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT1);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat1"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT2);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat2"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT3);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat3"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT4);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat4"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT1);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat1"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT2);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat2"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT3);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat3"));
targ->spr.Angles.Yaw = randomAngle();
fi.shoot(targ, BLOODSPLAT4);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat4"));
spawnguts(targ, PClass::FindActor("DukeJibs1"), 1);
spawnguts(targ, PClass::FindActor("DukeJibs2"), 2);
spawnguts(targ, PClass::FindActor("DukeJibs3"), 3);

View file

@ -1333,10 +1333,10 @@ void checkhitdefault_r(DDukeActor* targ, DDukeActor* proj)
if (Owner && Owner->isPlayer() && targ->spr.picnum != DRONE)
if (ps[Owner->PlayerIndex()].curr_weapon == SHOTGUN_WEAPON)
{
fi.shoot(targ, BLOODSPLAT3);
fi.shoot(targ, BLOODSPLAT1);
fi.shoot(targ, BLOODSPLAT2);
fi.shoot(targ, BLOODSPLAT4);
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat3"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat1"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat2"));
fi.shoot(targ, -1, PClass::FindActor("DukeBloodSplat4"));
}
if (targ->spr.statnum == STAT_ZOMBIEACTOR)

View file

@ -251,20 +251,6 @@ DDukeActor* spawninit_d(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
ChangeActorStat(act, STAT_MISC);
break;
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
act->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_WALL;
act->spr.scale.X = (0.109375 + (krand() & 7) * REPEAT_SCALE);
act->spr.scale.Y = (0.109375 + (krand() & 7) * REPEAT_SCALE);
act->spr.pos.Z -= 16;
if (actj && actj->spr.pal == 6)
act->spr.pal = 6;
insertspriteq(act);
ChangeActorStat(act, STAT_MISC);
break;
case SPACEMARINE:
act->spr.extra = 20;
act->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;

View file

@ -194,20 +194,6 @@ DDukeActor* spawninit_r(DDukeActor* actj, DDukeActor* act, TArray<DDukeActor*>*
act->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_FLOOR;
[[fallthrough]];
case BLOODSPLAT1:
case BLOODSPLAT2:
case BLOODSPLAT3:
case BLOODSPLAT4:
act->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_WALL;
act->spr.scale.X = (0.109375 + (krand() & 7) * REPEAT_SCALE);
act->spr.scale.Y = (0.109375 + (krand() & 7) * REPEAT_SCALE);
act->spr.pos.Z -= 16;
if (actj && actj->spr.pal == 6)
act->spr.pal = 6;
insertspriteq(act);
ChangeActorStat(act, STAT_MISC);
break;
case HYDRENT:
case SATELITE:
case FUELPOD:

View file

@ -619,12 +619,11 @@ void DukeActor_shoot(DDukeActor* act, int intname)
{
auto cls = PClass::FindActor(FName(ENamedName(intname)));
assert(cls);
picnum = GetDefaultByType(cls)->spr.picnum;
fi.shoot(act, picnum); // for now this crutch must suffice.
fi.shoot(act, -1, cls);
}
else
{
fi.shoot(act, picnum);
fi.shoot(act, picnum, nullptr);
}
}
@ -1138,16 +1137,17 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DukeLevel, floorflags, duke_floorflags)
ACTION_RETURN_INT(duke_floorflags(sect));
}
int duke_wallflags(walltype* wal)
int duke_wallflags(walltype* wal, int which)
{
return tileflags(wal->picnum);
return tileflags(which? wal->overpicnum : wal->picnum);
}
DEFINE_ACTION_FUNCTION_NATIVE(_DukeLevel, wallflags, duke_wallflags)
{
PARAM_PROLOGUE;
PARAM_POINTER(sect, walltype);
ACTION_RETURN_INT(duke_wallflags(sect));
PARAM_INT(which);
ACTION_RETURN_INT(duke_wallflags(sect, which));
}
int duke_ismirror(walltype* wal)

View file

@ -9,3 +9,5 @@ define TFLAG_SLIME 16
define TFLAG_DOORWALL 32
define TFLAG_BLOCKDOOR 64
define TFLAG_OUTERSPACE 128
define TFLAG_NOBLOODSPLAT 256
define TFLAG_NOCIRCLEREFLECT 512

View file

@ -51,6 +51,10 @@ spawnclasses
1960 = DukeRecon
2300 = DukeOoz
2309 = DukeOoz2
2296 = DukeBloodSplat1
2297 = DukeBloodSplat2
2298 = DukeBloodSplat3
2299 = DukeBloodSplat4
1272 = DukeTrash
634 = DukeBolt1
@ -233,3 +237,7 @@ tileflag TFLAG_OUTERSPACE {
MOONSKY1
BIGORBIT1
}
tileflag TFLAG_NOBLOODSPLAT {
BIGFORCE
}

View file

@ -52,6 +52,10 @@ spawnclasses
1344 = DukeRat
1759 = DukeForceSphere
1529 = DukeOoz
1525 = DukeBloodSplat1
1526 = DukeBloodSplat2
1527 = DukeBloodSplat3
1528 = DukeBloodSplat4
285 = RedneckChickenSpawner1
286 = RedneckChickenSpawner2

View file

@ -57,6 +57,7 @@ version "4.10"
#include "zscript/games/duke/actors/soundcontroller.zs"
#include "zscript/games/duke/actors/respawncontroller.zs"
#include "zscript/games/duke/actors/respawnmarker.zs"
#include "zscript/games/duke/actors/bloodsplats.zs"
#include "zscript/games/duke/actors/rat.zs"
#include "zscript/games/duke/actors/jibs.zs"

View file

@ -0,0 +1,129 @@
class DukeBloodSplat1 : DukeActor
{
default
{
statnum STAT_MISC;
Pic "BLOODSPLAT1";
}
override void Initialize()
{
self.cstat |= CSTAT_SPRITE_ALIGNMENT_WALL;
self.scale.X = 0.109375 + random(0, 7) * REPEAT_SCALE;
self.scale.Y = 0.109375 + random(0, 7) * REPEAT_SCALE;
self.pos.Z -= 16;
if (self.ownerActor && self.ownerActor.pal == 6)
self.pal = 6;
self.insertspriteq();
}
override void Tick()
{
if (self.temp_data[0] < 14 * 26)
{
let offset = frandom(0, 1);
let lerp = 1. - (double(self.temp_data[0]) / (14 * 26));
let zadj = (1. / 16.) * lerp;
let sadj = (1. / 12.) * lerp * REPEAT_SCALE;
self.pos.Z += zadj + offset * zadj;
self.scale.Y += sadj + offset * sadj;
self.temp_data[0]++;
}
}
override bool Animate(tspritetype t)
{
if (t.pal == 6)
t.shade = -127;
else
t.shade = 16;
return true;
}
override bool shootthis(DukeActor shooter, DukePlayer p, Vector3 pos, double ang) const
{
let sectp = shooter.sector;
double zvel;
HitInfo hit;
if (p != null) ang += frandom(-11.25, 11.25);
else ang += 180 + frandom(-11.25, 11.25);
zvel = 4 - frandom(0, 8);
Raze.hitscan(pos, sectp, (ang.ToVector() * 1024, zvel * 64), hit, 1);
let wal = hit.hitWall;
if ( (pos.XY - hit.hitpos.XY).Length() >= 64)
return true;
if (wal == null)
return true;
if (wal.hitag != 0)
return true;
if (dlevel.wallflags(wal, 1) & Duke.TFLAG_NOBLOODSPLAT)
return true;
if ((wal.cstat & CSTAT_WALL_MASKED) != 0)
return true;
if (hit.hitSector.lotag != 0)
return true;
if (wal.twoSided())
{
if (wal.nextSectorp().lotag != 0 || (hit.hitSector.floorz - wal.nextSectorp().floorz) <= 16)
return true;
if (hit.hitSector.lotag != 0)
return true;
if (wal.nextWallp().hitag != 0)
return true;
DukeSectIterator it;
for(let act2 = it.First(wal.nextSectorp()); act2; act2 = it.Next())
{
if (act2.statnum == STAT_EFFECTOR && act2.lotag == SE_13_EXPLOSIVE)
{
return true;
}
}
}
let spawned = shooter.spawn(self.getclassname());
if (spawned)
{
spawned.vel.X = -0.75;
spawned.Angle = wal.delta().Angle() - 90;
spawned.pos = hit.hitpos;
spawned.cstat |= randomXFlip();
spawned.DoMove(CLIPMASK0);
spawned.SetPosition(spawned.pos);
spawned.cstat2 |= CSTAT2_SPRITE_DECAL;
if (shooter.actorflag2(SFLAG2_GREENBLOOD))
spawned.pal = 6;
}
return true;
}
}
class DukeBloodSplat2 : DukeBloodSplat1
{
default
{
Pic "BLOODSPLAT2";
}
}
class DukeBloodSplat3 : DukeBloodSplat1
{
default
{
Pic "BLOODSPLAT3";
}
}
class DukeBloodSplat4 : DukeBloodSplat1
{
default
{
Pic "BLOODSPLAT4";
}
}

View file

@ -189,6 +189,10 @@ class DukeActor : CoreActor native
virtual void onRespawn(int tag) { }
virtual bool animate(tspritetype tspr) { return false; }
virtual void RunState() {} // this is the CON function.
virtual bool shootthis(DukeActor actor, DukePlayer p, Vector3 pos, double ang) const // this gets called on the defaults.
{
return false;
}
native void RandomScrap();
native void hitradius(int r, int hp1, int hp2, int hp3, int hp4);
@ -231,7 +235,7 @@ struct DukeLevel
native static void operatemasterswitches(int lotag);
native static void operateactivators(int lotag, DukePlayer p);
native static int floorflags(sectortype s);
native static int wallflags(walltype s);
native static int wallflags(walltype s, int which);
native static void AddCycler(sectortype sector, int lotag, int shade, int shade2, int hitag, int state);
native static void addtorch(sectortype sector, int shade, int lotag);
native static void addlightning(sectortype sector, int shade);

View file

@ -70,12 +70,16 @@ struct Duke native
enum ETextureFlags
{
TFLAG_WALLSWITCH = 1,
TFLAG_ADULT = 2,
TFLAG_ELECTRIC = 4,
TFLAG_CLEARINVENTORY = 8, // really dumb Duke stuff...
TFLAG_SLIME = 16,
TFLAG_NOCIRCLEREFLECT = 32,
TFLAG_WALLSWITCH = 1 << 0,
TFLAG_ADULT = 1 << 1,
TFLAG_ELECTRIC = 1 << 2,
TFLAG_CLEARINVENTORY = 1 << 3, // really dumb Duke stuff...
TFLAG_SLIME = 1 << 4,
TFLAG_DOORWALL = 1 << 5,
TFLAG_BLOCKDOOR = 1 << 6,
TFLAG_OUTERSPACE = 1 << 7,
TFLAG_NOBLOODSPLAT = 1 << 8,
TFLAG_NOCIRCLEREFLECT = 1 << 9,
};
enum ESoundFlags

View file

@ -150,8 +150,16 @@ struct CollisionData
native void setWall(walltype w);
native void setActor(CoreActor a);
native void setVoid();
}
struct HitInfo
{
Vector3 hitpos;
sectortype hitSector;
walltype hitWall;
CoreActor hitActor;
}
struct Raze
{
const kAngleMask = 0x7FF;
@ -173,6 +181,7 @@ struct Raze
native static sectortype updatesector(Vector2 pos, sectortype lastsect, double maxdist = 96);
native static sectortype, Vector3 clipmove(Vector3 pos, sectortype sect, Vector2 move, double walldist, double ceildist, double flordist, uint cliptype, CollisionData coll, int clipmoveboxtracenum = 3);
native static bool cansee(Vector3 start, sectortype startsec, Vector3 end, sectortype endsec);
native static int hitscan(Vector3 start, sectortype startsect, Vector3 vect, HitInfo hitinfo, uint cliptype, double maxrange = -1);
// game check shortcuts