mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-15 00:42:08 +00:00
- scriptified and consolidated the hitscan attacks.
This commit is contained in:
parent
1f5cd93564
commit
3af08ecbac
7 changed files with 356 additions and 540 deletions
|
@ -106,7 +106,6 @@ void playerLookUp(int snum, ESyncBits actions);
|
|||
void playerLookDown(int snum, ESyncBits actions);
|
||||
void playerAimUp(int snum, ESyncBits actions);
|
||||
void playerAimDown(int snum, ESyncBits actions);
|
||||
void tracers(const DVector3& start, const DVector3& dest, int n);
|
||||
DDukeActor* aim(DDukeActor* s, int aang, bool force = true);
|
||||
DDukeActor* aim_(DDukeActor* actor, DDukeActor* weapon);
|
||||
void checkweapons(player_struct* const p);
|
||||
|
|
|
@ -129,40 +129,6 @@ void forceplayerangle(player_struct* p)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void tracers(const DVector3& start, const DVector3& dest, int n)
|
||||
{
|
||||
sectortype* sect = nullptr;
|
||||
|
||||
auto direction = dest - start;
|
||||
|
||||
if (direction.XY().Sum() < 192.75)
|
||||
return;
|
||||
|
||||
auto pos = start;
|
||||
auto add = direction / (n + 1);
|
||||
for (int i = n; i > 0; i--)
|
||||
{
|
||||
pos += add;
|
||||
updatesector(pos, §);
|
||||
if (sect)
|
||||
{
|
||||
if (sect->lotag == 2)
|
||||
{
|
||||
DVector2 scale(0.0625 + (krand() & 3) * REPEAT_SCALE, 0.0625 + (krand() & 3) * REPEAT_SCALE);
|
||||
CreateActor(sect, pos, PClass::FindActor(NAME_DukeWaterBubble), -32, scale, randomAngle(), 0., 0., ps[0].GetActor(), 5);
|
||||
}
|
||||
else
|
||||
CreateActor(sect, pos, PClass::FindActor(NAME_DukeSmallSmoke), -32, DVector2(0.21875, 0.21875), nullAngle, 0., 0., ps[0].GetActor(), 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
double hits(DDukeActor* actor)
|
||||
{
|
||||
double zoff;
|
||||
|
|
|
@ -81,234 +81,6 @@ void incur_damage_d(player_struct* p)
|
|||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void shootweapon(DDukeActor *actor, int p, DVector3 pos, DAngle ang, int atwith)
|
||||
{
|
||||
auto sectp = actor->sector();
|
||||
double vel = 1024, zvel = 0;
|
||||
HitInfo hit{};
|
||||
|
||||
if (actor->spr.extra >= 0) actor->spr.shade = -96;
|
||||
|
||||
if (p >= 0)
|
||||
{
|
||||
SetGameVarID(g_iAimAngleVarID, AUTO_AIM_ANGLE, actor, p);
|
||||
OnEvent(EVENT_GETAUTOAIMANGLE, p, ps[p].GetActor(), -1);
|
||||
int varval = GetGameVarID(g_iAimAngleVarID, actor, p).value();
|
||||
DDukeActor* aimed = nullptr;
|
||||
if (varval > 0)
|
||||
{
|
||||
aimed = aim(actor, varval);
|
||||
}
|
||||
|
||||
if (aimed)
|
||||
{
|
||||
auto tex = TexMan.GetGameTexture(aimed->spr.spritetexture());
|
||||
double dal = ((aimed->spr.scale.X * tex->GetDisplayHeight()) * 0.5) + 5;
|
||||
switch (aimed->spr.picnum)
|
||||
{
|
||||
case DTILE_GREENSLIME:
|
||||
case DTILE_ROTATEGUN:
|
||||
dal -= 8;
|
||||
break;
|
||||
}
|
||||
double dist = (ps[p].GetActor()->spr.pos.XY() - aimed->spr.pos.XY()).Length();
|
||||
zvel = ((aimed->spr.pos.Z - pos.Z - dal) * 16) / dist;
|
||||
ang = (aimed->spr.pos - pos).Angle();
|
||||
}
|
||||
|
||||
if (isWW2GI())
|
||||
{
|
||||
int angRange = 32;
|
||||
double zRange = 1;
|
||||
SetGameVarID(g_iAngRangeVarID, 32, actor, p);
|
||||
SetGameVarID(g_iZRangeVarID, 256, actor, p);
|
||||
OnEvent(EVENT_GETSHOTRANGE, p, ps[p].GetActor(), -1);
|
||||
angRange = GetGameVarID(g_iAngRangeVarID, actor, p).value();
|
||||
zRange = GetGameVarID(g_iZRangeVarID, actor, p).value() / 256.;
|
||||
|
||||
ang += DAngle::fromBuild((angRange / 2) - (krand() & (angRange - 1)));
|
||||
if (aimed == nullptr)
|
||||
{
|
||||
// no target
|
||||
setFreeAimVelocity(vel, zvel, ps[p].Angles.getPitchWithView(), 16.);
|
||||
}
|
||||
zvel += (zRange / 2) - krandf(zRange);
|
||||
}
|
||||
else if (aimed == nullptr || atwith != DTILE_SHOTSPARK1)
|
||||
{
|
||||
ang += DAngle22_5 / 8 - randomAngle(22.5 / 4);
|
||||
if (aimed == nullptr) setFreeAimVelocity(vel, zvel, ps[p].Angles.getPitchWithView(), 16.);
|
||||
zvel += 0.5 - krandf(1);
|
||||
}
|
||||
|
||||
pos.Z -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x;
|
||||
int j = findplayer(actor, &x);
|
||||
pos.Z -= 4;
|
||||
double dist = (ps[j].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Length();
|
||||
zvel = ((ps[j].GetActor()->getOffsetZ() - pos.Z) * 16) / dist;
|
||||
zvel += 0.5 - krandf(1);
|
||||
if (actor->spr.picnum != DTILE_BOSS1)
|
||||
{
|
||||
ang += DAngle22_5 / 8 - randomAngle(22.5 / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ang = (ps[j].GetActor()->spr.pos.XY() - pos.XY()).Angle() + DAngle22_5 / 2 - randomAngle(22.5);
|
||||
}
|
||||
}
|
||||
|
||||
actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
|
||||
hitscan(pos, sectp, DVector3(ang.ToVector() * vel, zvel * 64), hit, CLIPMASK1);
|
||||
actor->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
|
||||
|
||||
|
||||
if (hit.hitSector == nullptr) return;
|
||||
|
||||
if ((krand() & 15) == 0 && hit.hitSector->lotag == 2)
|
||||
tracers(hit.hitpos, pos, 8 - (ud.multimode >> 1));
|
||||
|
||||
DDukeActor* spark;
|
||||
if (p >= 0)
|
||||
{
|
||||
spark = CreateActor(hit.hitSector, hit.hitpos, DTILE_SHOTSPARK1, -15, DVector2(0.15625, 0.15625), ang, 0., 0., actor, 4);
|
||||
if (!spark) return;
|
||||
|
||||
spark->spr.extra = ScriptCode[gs.actorinfo[atwith].scriptaddress];
|
||||
spark->spr.extra += (krand() % 6);
|
||||
|
||||
if (hit.hitWall == nullptr && hit.actor() == nullptr)
|
||||
{
|
||||
if (zvel < 0)
|
||||
{
|
||||
if (hit.hitSector->ceilingstat & CSTAT_SECTOR_SKY)
|
||||
{
|
||||
spark->spr.scale = DVector2(0, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
checkhitceiling(hit.hitSector);
|
||||
}
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
}
|
||||
|
||||
if (hit.actor())
|
||||
{
|
||||
checkhitsprite(hit.actor(), spark);
|
||||
if (hit.actor()->isPlayer() && (ud.coop != 1 || ud.ffire == 1))
|
||||
{
|
||||
spark->spr.scale = DVector2(0, 0);
|
||||
auto jib = spawn(spark, DTILE_JIBS6);
|
||||
if (jib)
|
||||
{
|
||||
jib->spr.pos.Z += 4;
|
||||
jib->vel.X = 1;
|
||||
jib->spr.scale = DVector2(0.375, 0.375);
|
||||
jib->spr.Angles.Yaw += DAngle22_5 / 2 - randomAngle(22.5);
|
||||
}
|
||||
}
|
||||
else spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
|
||||
if (p >= 0 && isshootableswitch(hit.actor()->spr.spritetexture()))
|
||||
{
|
||||
checkhitswitch(p, nullptr, hit.actor());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (hit.hitWall)
|
||||
{
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
|
||||
if (isadoorwall(hit.hitWall->walltexture) == 1)
|
||||
goto SKIPBULLETHOLE;
|
||||
if (isablockdoor(hit.hitWall->walltexture) == 1)
|
||||
goto SKIPBULLETHOLE;
|
||||
if (p >= 0 && isshootableswitch(hit.hitWall->walltexture))
|
||||
{
|
||||
checkhitswitch(p, hit.hitWall, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hit.hitWall->hitag != 0 || (hit.hitWall->twoSided() && hit.hitWall->nextWall()->hitag != 0))
|
||||
goto SKIPBULLETHOLE;
|
||||
|
||||
if (hit.hitSector && hit.hitSector->lotag == 0)
|
||||
if (!(tileflags(hit.hitWall->overtexture) & TFLAG_FORCEFIELD))
|
||||
if ((hit.hitWall->twoSided() && hit.hitWall->nextSector()->lotag == 0) ||
|
||||
(!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 l = it.Next())
|
||||
{
|
||||
if (l->spr.statnum == STAT_EFFECTOR && l->spr.lotag == SE_13_EXPLOSIVE)
|
||||
goto SKIPBULLETHOLE;
|
||||
}
|
||||
}
|
||||
|
||||
DukeStatIterator it(STAT_MISC);
|
||||
while (auto l = it.Next())
|
||||
{
|
||||
if (l->spr.picnum == DTILE_BULLETHOLE)
|
||||
if ((l->spr.pos - spark->spr.pos).Length() < 0.75 + krandf(0.5))
|
||||
goto SKIPBULLETHOLE;
|
||||
}
|
||||
auto hole = spawn(spark, DTILE_BULLETHOLE);
|
||||
if (hole)
|
||||
{
|
||||
hole->vel.X = -1 / 16.;
|
||||
hole->spr.Angles.Yaw = hit.hitWall->delta().Angle() - DAngle90;
|
||||
ssp(hole, CLIPMASK0);
|
||||
hole->spr.cstat2 |= CSTAT2_SPRITE_DECAL;
|
||||
}
|
||||
}
|
||||
|
||||
SKIPBULLETHOLE:
|
||||
|
||||
if (hit.hitWall->cstat & CSTAT_WALL_BOTTOM_SWAP)
|
||||
if (hit.hitWall->twoSided())
|
||||
if (hit.hitpos.Z >= hit.hitWall->nextSector()->floorz)
|
||||
hit.hitWall = hit.hitWall->nextWall();
|
||||
|
||||
checkhitwall(spark, hit.hitWall, hit.hitpos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spark = CreateActor(hit.hitSector, hit.hitpos, DTILE_SHOTSPARK1, -15, DVector2(0.375, 0.375), ang, 0., 0., actor, 4);
|
||||
if (spark)
|
||||
{
|
||||
spark->spr.extra = ScriptCode[gs.actorinfo[atwith].scriptaddress];
|
||||
|
||||
if (hit.actor())
|
||||
{
|
||||
checkhitsprite(hit.actor(), spark);
|
||||
if (!hit.actor()->isPlayer())
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
else spark->spr.scale = DVector2(0, 0);
|
||||
}
|
||||
else if (hit.hitWall)
|
||||
checkhitwall(spark, hit.hitWall, hit.hitpos);
|
||||
}
|
||||
}
|
||||
|
||||
if ((krand() & 255) < 4)
|
||||
{
|
||||
S_PlaySound3D(PISTOL_RICOCHET, spark, hit.hitpos);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
@ -617,12 +389,6 @@ void shoot_d(DDukeActor* actor, int atwith, PClass *cls)
|
|||
|
||||
switch (atwith)
|
||||
{
|
||||
case DTILE_SHOTSPARK1:
|
||||
case DTILE_SHOTGUN:
|
||||
case DTILE_CHAINGUN:
|
||||
shootweapon(actor, p, spos, sang, atwith);
|
||||
return;
|
||||
|
||||
case DTILE_FIRELASER:
|
||||
case DTILE_SPIT:
|
||||
case DTILE_COOLEXPLOSION1:
|
||||
|
|
|
@ -83,235 +83,6 @@ void incur_damage_r(player_struct* p)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void shootweapon(DDukeActor* actor, int p, DVector3 pos, DAngle ang, int atwith)
|
||||
{
|
||||
auto sectp = actor->sector();
|
||||
double vel = 1024., zvel = 0;
|
||||
HitInfo hit{};
|
||||
|
||||
if (actor->spr.extra >= 0) actor->spr.shade = -96;
|
||||
|
||||
if (p >= 0)
|
||||
{
|
||||
auto aimed = aim(actor, AUTO_AIM_ANGLE);
|
||||
if (aimed)
|
||||
{
|
||||
auto tex = TexMan.GetGameTexture(aimed->spr.spritetexture());
|
||||
double dal = ((aimed->spr.scale.X * tex->GetDisplayHeight()) * 0.5) + 5;
|
||||
double dist = (ps[p].GetActor()->spr.pos.XY() - aimed->spr.pos.XY()).Length();
|
||||
zvel = ((aimed->spr.pos.Z - pos.Z - dal) * 16) / dist;
|
||||
ang = (aimed->spr.pos - pos).Angle();
|
||||
}
|
||||
|
||||
if (atwith == RTILE_SHOTSPARK1)
|
||||
{
|
||||
if (aimed == nullptr)
|
||||
{
|
||||
ang += DAngle22_5 / 8 - randomAngle(22.5 / 4);
|
||||
setFreeAimVelocity(vel, zvel, ps[p].Angles.getPitchWithView(), 16.);
|
||||
zvel += 0.5 - krandf(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (atwith == RTILE_SHOTGUN)
|
||||
ang += DAngle22_5 / 2 - randomAngle(22.5);
|
||||
else
|
||||
ang += DAngle22_5 / 8 - randomAngle(22.5 / 4);
|
||||
if (aimed == nullptr) setFreeAimVelocity(vel, zvel, ps[p].Angles.getPitchWithView(), 16.);
|
||||
zvel += 0.5 - krandf(1);
|
||||
}
|
||||
pos.Z -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x;
|
||||
int j = findplayer(actor, &x);
|
||||
pos.Z -= 4;
|
||||
double dist = (ps[j].GetActor()->spr.pos.XY() - actor->spr.pos.XY()).Length();
|
||||
zvel = ((ps[j].GetActor()->getOffsetZ() - pos.Z) * 16) / dist;
|
||||
zvel += 0.5 - krandf(1);
|
||||
ang += DAngle22_5 / 4 - randomAngle(22.5 / 2);
|
||||
}
|
||||
|
||||
actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
|
||||
hitscan(pos, sectp, DVector3(ang.ToVector() * vel, zvel * 64), hit, CLIPMASK1);
|
||||
|
||||
if (isRRRA() && hit.hitSector != nullptr && (((hit.hitSector->lotag == ST_160_FLOOR_TELEPORT && zvel > 0) || (hit.hitSector->lotag == ST_161_CEILING_TELEPORT && zvel < 0))
|
||||
&& hit.actor() == nullptr && hit.hitWall == nullptr))
|
||||
{
|
||||
DukeStatIterator its(STAT_EFFECTOR);
|
||||
while (auto effector = its.Next())
|
||||
{
|
||||
auto Owner = effector->GetOwner();
|
||||
if (effector->sector() == hit.hitSector && iseffector(effector) && Owner && effector->spr.lotag == SE_7_TELEPORT)
|
||||
{
|
||||
DVector3 npos;
|
||||
npos.XY() = hit.hitpos.XY() + (Owner->spr.pos.XY() - effector->spr.pos.XY());
|
||||
if (hit.hitSector->lotag == ST_161_CEILING_TELEPORT)
|
||||
{
|
||||
npos.Z = Owner->sector()->floorz;
|
||||
}
|
||||
else
|
||||
{
|
||||
npos.Z = Owner->sector()->ceilingz;
|
||||
}
|
||||
hitscan(npos, Owner->sector(), DVector3(ang.ToVector() * 1024, zvel * 0.25), hit, CLIPMASK1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actor->spr.cstat |= CSTAT_SPRITE_BLOCK_ALL;
|
||||
|
||||
if (hit.hitSector == nullptr) return;
|
||||
|
||||
if (atwith == RTILE_SHOTGUN)
|
||||
if (hit.hitSector->lotag == 1)
|
||||
if (krand() & 1)
|
||||
return;
|
||||
|
||||
if ((krand() & 15) == 0 && hit.hitSector->lotag == 2)
|
||||
tracers(hit.hitpos, pos, 8 - (ud.multimode >> 1));
|
||||
|
||||
DDukeActor* spark;
|
||||
if (p >= 0)
|
||||
{
|
||||
spark = CreateActor(hit.hitSector, hit.hitpos, RTILE_SHOTSPARK1, -15, DVector2(0.15625, 0.15625), ang, 0., 0., actor, 4);
|
||||
if (!spark) return;
|
||||
spark->spr.extra = ScriptCode[gs.actorinfo[atwith].scriptaddress];
|
||||
spark->spr.extra += (krand() % 6);
|
||||
|
||||
if (hit.hitWall == nullptr && hit.actor() == nullptr)
|
||||
{
|
||||
if (zvel < 0)
|
||||
{
|
||||
if (hit.hitSector->ceilingstat & CSTAT_SECTOR_SKY)
|
||||
{
|
||||
spark->spr.scale = DVector2(0, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
checkhitceiling(hit.hitSector);
|
||||
}
|
||||
if (hit.hitSector->lotag != 1)
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
}
|
||||
|
||||
if (hit.actor())
|
||||
{
|
||||
if (hit.actor()->spr.picnum == RTILE_TORNADO)
|
||||
return;
|
||||
checkhitsprite(hit.actor(), spark);
|
||||
if (hit.actor()->isPlayer() && (ud.coop != 1 || ud.ffire == 1))
|
||||
{
|
||||
auto jib = spawn(spark, RTILE_JIBS6);
|
||||
spark->spr.scale = DVector2(0, 0);
|
||||
if (jib)
|
||||
{
|
||||
jib->spr.pos.Z += 4;
|
||||
jib->vel.X = 1;
|
||||
jib->spr.scale = DVector2(0.375, 0.375);
|
||||
jib->spr.Angles.Yaw += DAngle22_5 / 2 - randomAngle(22.5);
|
||||
}
|
||||
}
|
||||
else spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
|
||||
if (p >= 0 && isshootableswitch(hit.actor()->spr.spritetexture()))
|
||||
{
|
||||
checkhitswitch(p, nullptr, hit.actor());
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (hit.hitWall != nullptr)
|
||||
{
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
|
||||
if (isadoorwall(hit.hitWall->walltexture) == 1)
|
||||
goto SKIPBULLETHOLE;
|
||||
if (isablockdoor(hit.hitWall->walltexture) == 1)
|
||||
goto SKIPBULLETHOLE;
|
||||
if (p >= 0 && isshootableswitch(hit.hitWall->walltexture))
|
||||
{
|
||||
checkhitswitch(p, hit.hitWall, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hit.hitWall->hitag != 0 || (hit.hitWall->twoSided() && hit.hitWall->nextWall()->hitag != 0))
|
||||
goto SKIPBULLETHOLE;
|
||||
|
||||
if (hit.hitSector != nullptr && hit.hitSector->lotag == 0)
|
||||
if (!(tileflags(hit.hitWall->overtexture) & TFLAG_FORCEFIELD))
|
||||
if ((hit.hitWall->twoSided() && hit.hitWall->nextSector()->lotag == 0) ||
|
||||
(!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 l = it.Next())
|
||||
{
|
||||
if (l->spr.statnum == STAT_EFFECTOR && l->spr.lotag == SE_13_EXPLOSIVE)
|
||||
goto SKIPBULLETHOLE;
|
||||
}
|
||||
}
|
||||
|
||||
DukeStatIterator it(STAT_MISC);
|
||||
while (auto l = it.Next())
|
||||
{
|
||||
if (l->spr.picnum == RTILE_BULLETHOLE)
|
||||
if ((l->spr.pos - spark->spr.pos).Length() < 0.75 + krandf(0.5))
|
||||
goto SKIPBULLETHOLE;
|
||||
}
|
||||
auto hole = spawn(spark, RTILE_BULLETHOLE);
|
||||
if (hole)
|
||||
{
|
||||
hole->vel.X = -1 / 16;
|
||||
hole->spr.Angles.Yaw = hit.hitWall->delta().Angle() - DAngle90;
|
||||
ssp(hole, CLIPMASK0);
|
||||
hole->spr.cstat2 |= CSTAT2_SPRITE_DECAL;
|
||||
}
|
||||
}
|
||||
|
||||
SKIPBULLETHOLE:
|
||||
|
||||
if (hit.hitWall->cstat & CSTAT_WALL_BOTTOM_SWAP)
|
||||
if (hit.hitWall->twoSided())
|
||||
if (hit.hitpos.Z >= hit.hitWall->nextSector()->floorz)
|
||||
hit.hitWall = hit.hitWall->nextWall();
|
||||
|
||||
checkhitwall(spark, hit.hitWall, hit.hitpos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spark = CreateActor(hit.hitSector, hit.hitpos, RTILE_SHOTSPARK1, -15, DVector2(0.375, 0.375), ang, 0., 0., actor, 4);
|
||||
if (!spark) return;
|
||||
spark->spr.extra = ScriptCode[gs.actorinfo[atwith].scriptaddress];
|
||||
|
||||
if (hit.actor())
|
||||
{
|
||||
checkhitsprite(hit.actor(), spark);
|
||||
if (!hit.actor()->isPlayer())
|
||||
spawn(spark, PClass::FindActor(NAME_DukeSmallSmoke));
|
||||
else spark->spr.scale = DVector2(0, 0);
|
||||
}
|
||||
else if (hit.hitWall != nullptr)
|
||||
checkhitwall(spark, hit.hitWall, hit.hitpos);
|
||||
}
|
||||
|
||||
if ((krand() & 255) < 10)
|
||||
{
|
||||
S_PlaySound3D(PISTOL_RICOCHET, spark, hit.hitpos);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void shootstuff(DDukeActor* actor, int p, DVector3 pos, DAngle ang, int atwith)
|
||||
{
|
||||
auto sect = actor->sector();
|
||||
|
@ -655,12 +426,6 @@ void shoot_r(DDukeActor* actor, int atwith, PClass* cls)
|
|||
|
||||
switch (atwith)
|
||||
{
|
||||
case RTILE_SHOTSPARK1:
|
||||
case RTILE_SHOTGUN:
|
||||
case RTILE_CHAINGUN:
|
||||
shootweapon(actor, p, spos, sang, atwith);
|
||||
return;
|
||||
|
||||
case RTILE_OWHIP:
|
||||
case RTILE_UWHIP:
|
||||
shootwhip(actor, p, spos, sang, atwith);
|
||||
|
|
|
@ -159,6 +159,7 @@ version "4.10"
|
|||
|
||||
|
||||
#include "zscript/games/duke/actors/dukeweapons/melee.zs"
|
||||
#include "zscript/games/duke/actors/dukeweapons/hitscan.zs"
|
||||
#include "zscript/games/duke/actors/dukeweapons/shrinker.zs"
|
||||
#include "zscript/games/duke/actors/dukeweapons/grower.zs"
|
||||
#include "zscript/games/duke/actors/dukeweapons/tripbomb.zs"
|
||||
|
|
|
@ -11,47 +11,11 @@ class DukeRadiusExplosion : DukeActor
|
|||
}
|
||||
}
|
||||
|
||||
class DukeShotgunShot : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "SHOTGUN";
|
||||
}
|
||||
}
|
||||
|
||||
class RedneckShotgunShot : DukeShotgunShot
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
class DukeChaingunShot : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "CHAINGUN";
|
||||
}
|
||||
}
|
||||
|
||||
class RedneckChaingunShot : DukeChaingunShot
|
||||
{
|
||||
}
|
||||
|
||||
class DukeSectorEffector : DukeActor
|
||||
{
|
||||
//This never gets ticked, the handler goes directly to the native implementations.
|
||||
}
|
||||
|
||||
class DukeShotSpark : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "SHOTSPARK1";
|
||||
+FORCERUNCON;
|
||||
+LIGHTDAMAGE;
|
||||
statnum STAT_MISC;
|
||||
}
|
||||
}
|
||||
|
||||
class RedneckMotoHit : DukeActor
|
||||
{
|
||||
default
|
||||
|
|
355
wadsrc/static/zscript/games/duke/actors/dukeweapons/hitscan.zs
Normal file
355
wadsrc/static/zscript/games/duke/actors/dukeweapons/hitscan.zs
Normal file
|
@ -0,0 +1,355 @@
|
|||
|
||||
extend class DukeActor
|
||||
{
|
||||
static void tracers(Vector3 start, Vector3 dest, int n)
|
||||
{
|
||||
sectortype sect = nullptr;
|
||||
|
||||
let direction = dest - start;
|
||||
|
||||
if (direction.XY.Sum() < 192.75)
|
||||
return;
|
||||
|
||||
let pos = start;
|
||||
let add = direction / (n + 1);
|
||||
for (int i = n; i > 0; i--)
|
||||
{
|
||||
pos += add;
|
||||
sect = Raze.updatesector(pos.XY, sect);
|
||||
if (sect)
|
||||
{
|
||||
if (sect.lotag == ST_2_UNDERWATER)
|
||||
{
|
||||
Vector2 scale = (0.0625 + random(0, 3) * REPEAT_SCALE, 0.0625 + random(0, 3) * REPEAT_SCALE);
|
||||
dlevel.SpawnActor(sect, pos, "DukeWaterBubble", -32, scale, frandom(0, 360), 0., 0., Duke.GetLocalPlayer().actor, STAT_MISC);
|
||||
}
|
||||
else
|
||||
dlevel.SpawnActor(sect, pos, "DukeSmallSmoke", -32, (0.21875, 0.21875), 0, 0., 0., Duke.GetLocalPlayer().actor, STAT_MISC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool HitscanAttack(DukeActor actor, DukePlayer p, Vector3 pos, double ang, double hspread, double vspread, double enemyspread, bool forcespread, bool waterhalfhitchance = false, class<DukeActor> sparktype = "DukeShotSpark") const
|
||||
{
|
||||
let sectp = actor.sector;
|
||||
double vel = 1024, zvel = 0;
|
||||
HitInfo hit;
|
||||
|
||||
if (actor.extra >= 0) actor.shade = -96;
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
let aimed = actor.aim(self);
|
||||
if (aimed)
|
||||
{
|
||||
double dal = ((aimed.scale.X * aimed.spriteHeight()) * 0.5) + aimed.sparkoffset;
|
||||
double dist = (p.actor.pos.XY - aimed.pos.XY).Length();
|
||||
zvel = ((aimed.pos.Z - pos.Z - dal) * 16) / dist;
|
||||
ang = (aimed.pos - pos).Angle();
|
||||
}
|
||||
|
||||
if (aimed == nullptr || forcespread)
|
||||
{
|
||||
ang += hspread / 2 - frandom(0, hspread);
|
||||
if (aimed == nullptr) [vel, zvel] = Raze.setFreeAimVelocity(vel, zvel, p.getPitchWithView(), 16);
|
||||
zvel += vspread / 8 - frandom(0, vspread / 4);
|
||||
}
|
||||
pos.Z -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
let j = actor.findplayer();
|
||||
pos.Z -= 4;
|
||||
double dist = (j.actor.pos.XY - actor.pos.XY).Length();
|
||||
zvel = ((j.actor.pos.Z + j.actor.viewzoffset - pos.Z) * 16) / dist;
|
||||
zvel += frandom(-0.5, 0.5);
|
||||
if (!actor.bALTHITSCANDIRECTION)
|
||||
{
|
||||
ang += enemyspread / 2 - frandom(0, enemyspread);
|
||||
}
|
||||
else
|
||||
{
|
||||
// one of those lousy hacks in Duke.
|
||||
ang = (j.actor.pos.XY - pos.XY).Angle() + enemyspread / 4 - frandom(0, enemyspread / 2);
|
||||
}
|
||||
}
|
||||
|
||||
actor.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
|
||||
Raze.hitscan(pos, sectp, (ang.ToVector() * vel, zvel * 64), hit, CLIPMASK1);
|
||||
|
||||
if (Raze.isRRRA() && hit.hitSector != nullptr && ((hit.hitSector.lotag == ST_160_FLOOR_TELEPORT && zvel > 0) || (hit.hitSector.lotag == ST_161_CEILING_TELEPORT && zvel < 0))
|
||||
&& hit.hitActor == nullptr && hit.hitWall == nullptr)
|
||||
{
|
||||
DukeStatIterator its;
|
||||
for (let effector = its.First(STAT_EFFECTOR); effector; effector = its.Next())
|
||||
{
|
||||
if (effector.sector == hit.hitSector && effector.GetClassName() == 'DukeSectorEffector' && effector.ownerActor && effector.lotag == SE_7_TELEPORT)
|
||||
{
|
||||
let owner = effector.ownerActor;
|
||||
Vector3 npos;
|
||||
npos.XY = hit.hitpos.XY + (owner.pos.XY - effector.pos.XY);
|
||||
if (hit.hitSector.lotag == ST_161_CEILING_TELEPORT)
|
||||
{
|
||||
npos.Z = owner.sector.floorz;
|
||||
}
|
||||
else
|
||||
{
|
||||
npos.Z = owner.sector.ceilingz;
|
||||
}
|
||||
Raze.hitscan(npos, owner.sector, (ang.ToVector() * 1024, zvel * 0.25), hit, CLIPMASK1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actor.cstat |= CSTAT_SPRITE_BLOCK_ALL;
|
||||
|
||||
if (hit.hitSector == nullptr) return true;
|
||||
|
||||
// RR shotgun only
|
||||
if (waterhalfhitchance && hit.hitSector.lotag == ST_1_ABOVE_WATER && random(0, 1))
|
||||
return true;
|
||||
|
||||
if (random(0, 15) == 0 && hit.hitSector.lotag == ST_2_UNDERWATER)
|
||||
tracers(hit.hitpos, pos, 8 - (ud.multimode >> 1));
|
||||
|
||||
DukeActor spark = null;
|
||||
if (p != null)
|
||||
{
|
||||
spark = dlevel.SpawnActor(hit.hitSector, hit.hitpos, sparktype, -15, (0.15625, 0.15625), ang, 0., 0., actor, STAT_PROJECTILE);
|
||||
if (!spark) return true;
|
||||
|
||||
spark.extra = self.strength + random(0, 5);
|
||||
|
||||
if (hit.hitWall == nullptr && hit.hitActor == nullptr)
|
||||
{
|
||||
if (zvel < 0)
|
||||
{
|
||||
if (hit.hitSector.ceilingstat & CSTAT_SECTOR_SKY)
|
||||
{
|
||||
spark.scale = (0, 0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
dlevel.checkhitceiling(hit.hitSector, spark);
|
||||
}
|
||||
if (zvel < 0 || hit.hitSector.lotag != ST_1_ABOVE_WATER)
|
||||
spark.spawn("DukeSmallSmoke");
|
||||
}
|
||||
|
||||
let hitActor = DukeActor(hit.hitActor);
|
||||
if (hitActor)
|
||||
{
|
||||
if (hitActor.bNOHITSCANHIT)
|
||||
return true;
|
||||
hitActor.OnHit(spark);
|
||||
if (hitActor.isPlayer() && (ud.coop != 1 || ud.ffire == 1))
|
||||
{
|
||||
let jib = spark.spawn("DukeJibs6");
|
||||
spark.scale = (0, 0);
|
||||
if (jib)
|
||||
{
|
||||
jib.pos.Z += 4;
|
||||
jib.vel.X = 1;
|
||||
jib.scale = (0.375, 0.375);
|
||||
jib.Angle += frandom(-11.25, 11.25);
|
||||
}
|
||||
}
|
||||
else spark.spawn("DukeSmallSmoke");
|
||||
|
||||
if (p != null && Duke.isshootableswitch(hitActor.spritetexture()))
|
||||
{
|
||||
p.checkhitswitch(nullptr, hitActor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (hit.hitWall)
|
||||
{
|
||||
spark.spawn("DukeSmallSmoke");
|
||||
|
||||
if (!(Raze.tileflags(hit.hitWall.walltexture) & (Duke.TFLAG_DOORWALL | Duke.TFLAG_BLOCKDOOR)))
|
||||
{
|
||||
if (p != null && Duke.isshootableswitch(hit.hitWall.walltexture))
|
||||
{
|
||||
p.checkhitswitch(hit.hitWall, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(hit.hitWall.hitag != 0 || (hit.hitWall.twoSided() && hit.hitWall.nextWallp().hitag != 0)))
|
||||
{
|
||||
|
||||
if (hit.hitSector && hit.hitSector.lotag == 0 && !(Raze.tileflags(hit.hitWall.overtexture) & Duke.TFLAG_FORCEFIELD))
|
||||
{
|
||||
if ((hit.hitWall.twoSided() && hit.hitWall.nextSectorp().lotag == 0) || (!hit.hitWall.twoSided() && hit.hitSector.lotag == 0))
|
||||
{
|
||||
if ((hit.hitWall.cstat & CSTAT_WALL_MASKED) == 0)
|
||||
{
|
||||
bool ok = true;
|
||||
if (hit.hitWall.twoSided())
|
||||
{
|
||||
DukeSectIterator it;
|
||||
for (let l = it.First(hit.hitWall.nextSectorp()); l; l = it.Next())
|
||||
{
|
||||
if (l.statnum == STAT_EFFECTOR && l.lotag == SE_13_EXPLOSIVE)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
DukeStatIterator it;
|
||||
for (let l = it.First(STAT_MISC); l; l = it.Next())
|
||||
{
|
||||
if (l is 'DukeBulletHole' && (l.pos - spark.pos).Length() < frandom(0.75, 1.25))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
let hole = spark.spawn("DukeBulletHole");
|
||||
if (hole)
|
||||
{
|
||||
hole.vel.X = -1 / 16.;
|
||||
hole.Angle = hit.hitWall.delta().Angle() - 90;
|
||||
hole.DoMove(CLIPMASK0);
|
||||
hole.cstat2 |= CSTAT2_SPRITE_DECAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hit.hitWall.cstat & CSTAT_WALL_BOTTOM_SWAP)
|
||||
if (hit.hitWall.twoSided())
|
||||
if (hit.hitpos.Z >= hit.hitWall.nextSectorp().floorz)
|
||||
hit.hitWall = hit.hitWall.nextWallp();
|
||||
|
||||
dlevel.checkhitwall(hit.hitWall, spark, hit.hitpos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spark = dlevel.SpawnActor(hit.hitSector, hit.hitpos, sparktype, -15, (0.375, 0.375), ang, 0., 0., actor, STAT_PROJECTILE);
|
||||
if (spark)
|
||||
{
|
||||
spark.extra = self.strength;
|
||||
let hitActor = DukeActor(hit.hitActor);
|
||||
|
||||
if (hitActor)
|
||||
{
|
||||
hitActor.OnHit(spark);
|
||||
if (!hitActor.isPlayer())
|
||||
spark.spawn("DukeSmallSmoke");
|
||||
else spark.scale = (0, 0);
|
||||
}
|
||||
else if (hit.hitWall)
|
||||
dlevel.checkhitwall(hit.hitWall, spark, hit.hitpos);
|
||||
}
|
||||
}
|
||||
|
||||
if (spark && random(0, 255) < 4)
|
||||
{
|
||||
spark.PlayActorSound("PISTOL_RICOCHET");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class DukeShotSpark : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "SHOTSPARK1";
|
||||
+FORCERUNCON;
|
||||
+LIGHTDAMAGE;
|
||||
statnum STAT_MISC;
|
||||
}
|
||||
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 5.625, 4, 5.625, false);
|
||||
}
|
||||
}
|
||||
|
||||
class DukeShotgunShot : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "SHOTGUN";
|
||||
}
|
||||
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 5.625, 4, 5.625, true);
|
||||
}
|
||||
}
|
||||
|
||||
class DukeChaingunShot : DukeActor
|
||||
{
|
||||
default
|
||||
{
|
||||
pic "CHAINGUN";
|
||||
}
|
||||
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 5.625, 4, 5.625, true);
|
||||
}
|
||||
}
|
||||
|
||||
// RR' damage properties are a bit different.
|
||||
class RedneckShotSpark : DukeShotSpark
|
||||
{
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 5.625, 4, 11.25, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RedneckShotgunShot : DukeShotgunShot
|
||||
{
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 22.5, 4, 11.25, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RedneckChaingunShot : DukeChaingunShot
|
||||
{
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 5.625, 4, 11.25, true);
|
||||
}
|
||||
}
|
||||
|
||||
// WW2GI uses different spread settings for its pistol
|
||||
class WW2GIShotSpark : DukeShotSpark
|
||||
{
|
||||
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang)
|
||||
{
|
||||
return HitscanAttack(actor, p, pos, ang, 0.3515625, 0.25, 5.625, true);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue