2020-05-14 10:14:03 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 1996, 2003 - 3D Realms Entertainment
|
|
|
|
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
|
2020-06-28 07:03:31 +00:00
|
|
|
Copyright (C) 2020 - Christoph Oelckers
|
2020-05-14 10:14:03 +00:00
|
|
|
|
|
|
|
This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition
|
|
|
|
|
|
|
|
Duke Nukem 3D is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
Original Source: 1996 - Todd Replogle
|
|
|
|
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
|
|
|
|
|
|
|
|
EDuke enhancements integrated: 04/13/2003 - Matt Saettler
|
|
|
|
|
|
|
|
Note: EDuke source was in transition. Changes are in-progress in the
|
|
|
|
source as it is released.
|
|
|
|
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#include "ns.h"
|
|
|
|
#include "global.h"
|
2020-07-07 15:56:20 +00:00
|
|
|
#include "mapinfo.h"
|
2020-10-17 08:30:11 +00:00
|
|
|
#include "dukeactor.h"
|
2021-05-15 12:27:32 +00:00
|
|
|
#include "vm.h"
|
2020-05-14 10:14:03 +00:00
|
|
|
|
|
|
|
BEGIN_DUKE_NS
|
|
|
|
|
2020-07-15 16:10:31 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// callback for playercolor CVAR
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-08-23 18:48:48 +00:00
|
|
|
int playercolor2lookup(int color)
|
2020-07-15 16:10:31 +00:00
|
|
|
{
|
|
|
|
static int8_t player_pals[] = { 0, 9, 10, 11, 12, 13, 14, 15, 16, 21, 23, };
|
|
|
|
if (color >= 0 && color < 10) return player_pals[color];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlayerColorChanged(void)
|
|
|
|
{
|
|
|
|
if (ud.recstat != 0)
|
|
|
|
return;
|
|
|
|
|
2020-10-23 17:33:54 +00:00
|
|
|
auto& pp = ps[myconnectindex];
|
2020-07-15 16:10:31 +00:00
|
|
|
if (ud.multimode > 1)
|
|
|
|
{
|
|
|
|
//Net_SendClientInfo();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-23 17:33:54 +00:00
|
|
|
pp.palookup = ud.user_pals[myconnectindex] = playercolor2lookup(playercolor);
|
2020-07-15 16:10:31 +00:00
|
|
|
}
|
2021-12-31 17:47:00 +00:00
|
|
|
if (pp.GetActor()->isPlayer() && pp.GetActor()->spr.pal != 1)
|
2021-12-21 17:19:45 +00:00
|
|
|
pp.GetActor()->spr.pal = ud.user_pals[myconnectindex];
|
2020-07-15 16:10:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-16 21:55:21 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-03 14:17:37 +00:00
|
|
|
// why is this such a mess?
|
2020-05-16 21:55:21 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-02-07 10:04:19 +00:00
|
|
|
int setpal(player_struct* p)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2020-07-03 14:17:37 +00:00
|
|
|
int palette;
|
2020-05-16 21:55:21 +00:00
|
|
|
if (p->DrugMode) palette = DRUGPAL;
|
2020-07-03 14:17:37 +00:00
|
|
|
else if (p->heat_on) palette = SLIMEPAL;
|
2021-11-21 07:45:07 +00:00
|
|
|
else if (!p->insector()) palette = BASEPAL; // don't crash if out of range.
|
2022-01-21 13:02:59 +00:00
|
|
|
else if (gs.tileinfo[p->cursector->ceilingpicnum].flags & TFLAG_SLIME) palette = SLIMEPAL;
|
2021-11-21 07:56:39 +00:00
|
|
|
else if (p->cursector->lotag == ST_2_UNDERWATER) palette = WATERPAL;
|
2020-05-16 21:55:21 +00:00
|
|
|
else palette = BASEPAL;
|
2020-11-05 06:16:29 +00:00
|
|
|
return palette;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-02-07 10:04:19 +00:00
|
|
|
void quickkill(player_struct* p)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
|
|
|
SetPlayerPal(p, PalEntry(48, 48, 48, 48));
|
|
|
|
|
2020-10-23 17:50:18 +00:00
|
|
|
auto pa = p->GetActor();
|
2021-12-21 17:19:45 +00:00
|
|
|
pa->spr.extra = 0;
|
|
|
|
pa->spr.cstat |= CSTAT_SPRITE_INVISIBLE;
|
2020-10-23 17:50:18 +00:00
|
|
|
if (ud.god == 0) fi.guts(pa, TILE_JIBS6, 8, myconnectindex);
|
2020-05-16 21:55:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-09-20 10:01:05 +00:00
|
|
|
void forceplayerangle(int snum)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2020-09-20 10:01:05 +00:00
|
|
|
player_struct* p = &ps[snum];
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-10-11 06:46:56 +00:00
|
|
|
p->horizon.addadjustment(DAngle::fromDeg(-26.566));
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions |= SB_CENTERVIEW;
|
2022-09-13 16:11:40 +00:00
|
|
|
p->angle.rotscrnang = p->angle.look_ang = (DAngle22_5 - randomAngle(45)) / 2.;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-13 21:07:08 +00:00
|
|
|
void tracers(const DVector3& start, const DVector3& dest, int n)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2021-11-18 18:04:00 +00:00
|
|
|
sectortype* sect = nullptr;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-13 21:07:08 +00:00
|
|
|
auto direction = dest - start;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-13 21:07:08 +00:00
|
|
|
if (direction.XY().Sum() < 192.75)
|
2020-05-16 21:55:21 +00:00
|
|
|
return;
|
|
|
|
|
2022-09-13 21:07:08 +00:00
|
|
|
auto pos = start;
|
|
|
|
auto add = direction / (n + 1);
|
|
|
|
for (int i = n; i > 0; i--)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-13 21:07:08 +00:00
|
|
|
pos += add;
|
|
|
|
updatesector(pos, §);
|
2021-11-18 18:04:00 +00:00
|
|
|
if (sect)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2021-11-18 18:04:00 +00:00
|
|
|
if (sect->lotag == 2)
|
2022-10-07 16:57:09 +00:00
|
|
|
{
|
|
|
|
DVector2 scale(0.0625 + (krand() & 3) * REPEAT_SCALE, 0.0625 + (krand() & 3) * REPEAT_SCALE);
|
|
|
|
CreateActor(sect, pos, TILE_WATERBUBBLE, -32, scale, randomAngle(), 0., 0., ps[0].GetActor(), 5);
|
|
|
|
}
|
2020-05-16 21:55:21 +00:00
|
|
|
else
|
2022-10-07 16:57:09 +00:00
|
|
|
CreateActor(sect, pos, TILE_SMALLSMOKE, -32, DVector2(0.21875, 0.21875), nullAngle, 0., 0., ps[0].GetActor(), 5);
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-13 22:05:32 +00:00
|
|
|
double hits(DDukeActor* actor)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-13 22:08:56 +00:00
|
|
|
double zoff;
|
2021-12-06 11:24:22 +00:00
|
|
|
HitInfo hit{};
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-13 22:08:56 +00:00
|
|
|
if (actor->isPlayer()) zoff = gs.playerheight;
|
2020-05-16 21:55:21 +00:00
|
|
|
else zoff = 0;
|
|
|
|
|
2022-09-13 22:08:56 +00:00
|
|
|
auto pos = actor->spr.pos;
|
|
|
|
hitscan(pos.plusZ(-zoff), actor->sector(), DVector3(actor->spr.angle.ToVector() * 1024, 0), hit, CLIPMASK1);
|
|
|
|
return (hit.hitpos.XY() - actor->spr.pos.XY()).Length();
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-13 22:11:16 +00:00
|
|
|
double hitasprite(DDukeActor* actor, DDukeActor** hitsp)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-13 22:15:45 +00:00
|
|
|
double zoff;
|
2021-12-06 11:24:22 +00:00
|
|
|
HitInfo hit{};
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2020-10-23 17:33:54 +00:00
|
|
|
if (badguy(actor))
|
2022-09-13 22:15:45 +00:00
|
|
|
zoff = 42;
|
|
|
|
else if (actor->spr.picnum == TILE_APLAYER) zoff = gs.playerheight;
|
2020-05-16 21:55:21 +00:00
|
|
|
else zoff = 0;
|
|
|
|
|
2022-09-13 22:15:45 +00:00
|
|
|
auto pos = actor->spr.pos;
|
|
|
|
hitscan(pos.plusZ(-zoff), actor->sector(), DVector3(actor->spr.angle.ToVector() * 1024, 0), hit, CLIPMASK1);
|
2021-11-25 23:08:59 +00:00
|
|
|
if (hitsp) *hitsp = hit.actor();
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2021-12-18 14:11:21 +00:00
|
|
|
if (hit.hitWall != nullptr && (hit.hitWall->cstat & CSTAT_WALL_MASKED) && badguy(actor))
|
2022-09-13 22:11:16 +00:00
|
|
|
return INT_MAX;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-13 22:15:45 +00:00
|
|
|
return (hit.hitpos.XY() - actor->spr.pos.XY()).Length();
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-13 22:20:58 +00:00
|
|
|
double hitawall(player_struct* p, walltype** hitw)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2021-12-06 11:24:22 +00:00
|
|
|
HitInfo hit{};
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-11-24 02:20:17 +00:00
|
|
|
hitscan(p->GetActor()->getPosWithOffsetZ(), p->cursector, DVector3(p->angle.ang.ToVector() * 1024, 0), hit, CLIPMASK0);
|
2021-11-25 23:08:59 +00:00
|
|
|
if (hitw) *hitw = hit.hitWall;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-11-20 08:07:23 +00:00
|
|
|
return (hit.hitpos.XY() - p->GetActor()->spr.pos.XY()).Length();
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
DDukeActor* aim(DDukeActor* actor, int abase)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-14 16:08:23 +00:00
|
|
|
DAngle aang = DAngle90 * (AUTO_AIM_ANGLE / 512.);
|
|
|
|
|
2021-11-07 11:53:48 +00:00
|
|
|
bool gotshrinker, gotfreezer;
|
2021-12-27 14:33:10 +00:00
|
|
|
static const int aimstats[] = { STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR };
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
DAngle a = actor->spr.angle;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
|
|
|
// Autoaim from DukeGDX.
|
2021-12-31 17:47:00 +00:00
|
|
|
if (actor->isPlayer())
|
2020-07-26 07:06:08 +00:00
|
|
|
{
|
2022-09-01 14:42:23 +00:00
|
|
|
auto* plr = &ps[actor->PlayerIndex()];
|
2022-09-01 15:26:46 +00:00
|
|
|
int autoaim = Autoaim(actor->PlayerIndex());
|
2020-11-29 08:00:00 +00:00
|
|
|
if (!autoaim)
|
2020-07-26 07:06:08 +00:00
|
|
|
{
|
2021-12-27 14:33:10 +00:00
|
|
|
// Some fudging to avoid aim randomization when autoaim is off.
|
|
|
|
// This is a reimplementation of how it was solved in RedNukem.
|
|
|
|
if (plr->curr_weapon == PISTOL_WEAPON && !isWW2GI())
|
|
|
|
{
|
2022-10-11 04:10:30 +00:00
|
|
|
double vel = 1024, zvel = 0;
|
|
|
|
setFreeAimVelocity(vel, zvel, plr->horizon.sum(), 16.);
|
2021-12-27 14:33:10 +00:00
|
|
|
|
|
|
|
HitInfo hit{};
|
2022-11-24 02:20:17 +00:00
|
|
|
hitscan(plr->GetActor()->getPosWithOffsetZ().plusZ(4), actor->sector(), DVector3(actor->spr.angle.ToVector() * vel, zvel), hit, CLIPMASK1);
|
2021-12-27 14:33:10 +00:00
|
|
|
|
|
|
|
if (hit.actor() != nullptr)
|
|
|
|
{
|
|
|
|
if (isIn(hit.actor()->spr.statnum, { STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR }))
|
|
|
|
return hit.actor();
|
|
|
|
}
|
|
|
|
}
|
2020-07-26 07:06:08 +00:00
|
|
|
// The chickens in RRRA are homing and must always autoaim.
|
2021-12-27 14:33:10 +00:00
|
|
|
if (!isRRRA() || plr->curr_weapon != CHICKEN_WEAPON)
|
2020-11-01 19:57:02 +00:00
|
|
|
return nullptr;
|
2020-07-26 07:06:08 +00:00
|
|
|
}
|
2020-11-29 08:00:00 +00:00
|
|
|
else if (autoaim == 2)
|
2020-07-26 07:06:08 +00:00
|
|
|
{
|
|
|
|
int weap;
|
|
|
|
if (!isWW2GI())
|
|
|
|
{
|
2021-12-27 14:33:10 +00:00
|
|
|
weap = plr->curr_weapon;
|
2020-07-26 07:06:08 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-01 14:42:23 +00:00
|
|
|
weap = aplWeaponWorksLike(plr->curr_weapon, actor->PlayerIndex());
|
2020-07-26 07:06:08 +00:00
|
|
|
}
|
2022-09-14 23:05:42 +00:00
|
|
|
// The chickens in RRRA are homing and must always autoaim.
|
|
|
|
if (!isRRRA() || plr->curr_weapon != CHICKEN_WEAPON)
|
2020-07-26 07:06:08 +00:00
|
|
|
{
|
2022-09-14 23:05:42 +00:00
|
|
|
if (weap > CHAINGUN_WEAPON || weap == KNEE_WEAPON)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-07-26 07:06:08 +00:00
|
|
|
}
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2020-07-26 07:06:08 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-01 19:57:02 +00:00
|
|
|
DDukeActor* aimed = nullptr;
|
2022-09-01 14:42:23 +00:00
|
|
|
// if(actor->isPlayer() && ps[actor->PlayerIndex()].aim_mode) return -1;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
|
|
|
if (isRR())
|
|
|
|
{
|
2021-11-07 11:53:48 +00:00
|
|
|
gotshrinker = false;
|
|
|
|
gotfreezer = false;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
else if (isWW2GI())
|
|
|
|
{
|
2022-09-01 14:42:23 +00:00
|
|
|
gotshrinker = actor->isPlayer() && aplWeaponWorksLike(ps[actor->PlayerIndex()].curr_weapon, actor->PlayerIndex()) == SHRINKER_WEAPON;
|
|
|
|
gotfreezer = actor->isPlayer() && aplWeaponWorksLike(ps[actor->PlayerIndex()].curr_weapon, actor->PlayerIndex()) == FREEZE_WEAPON;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-01 14:42:23 +00:00
|
|
|
gotshrinker = actor->isPlayer() && ps[actor->PlayerIndex()].curr_weapon == SHRINKER_WEAPON;
|
|
|
|
gotfreezer = actor->isPlayer() && ps[actor->PlayerIndex()].curr_weapon == FREEZE_WEAPON;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
double smax = 0x7fffffff;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
auto dv1 = (a - aang).ToVector();
|
|
|
|
auto dv2 = (a + aang).ToVector();
|
|
|
|
auto dv3 = a.ToVector();
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
for (int k = 0; k < 4; k++)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2020-11-01 19:57:02 +00:00
|
|
|
if (aimed)
|
2020-05-16 21:55:21 +00:00
|
|
|
break;
|
2020-10-14 20:18:10 +00:00
|
|
|
|
2020-10-23 17:50:18 +00:00
|
|
|
DukeStatIterator it(aimstats[k]);
|
|
|
|
while (auto act = it.Next())
|
2020-10-14 20:18:10 +00:00
|
|
|
{
|
2022-10-07 21:33:37 +00:00
|
|
|
if (act->spr.scale.X > 0 && act->spr.extra >= 0 && (act->spr.cstat & (CSTAT_SPRITE_BLOCK_ALL | CSTAT_SPRITE_INVISIBLE)) == CSTAT_SPRITE_BLOCK_ALL)
|
2021-12-21 19:22:34 +00:00
|
|
|
if (badguy(act) || k < 2)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2021-12-31 17:47:00 +00:00
|
|
|
if (badguy(act) || act->isPlayer())
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2021-12-31 17:47:00 +00:00
|
|
|
if (act->isPlayer() &&
|
2020-05-16 21:55:21 +00:00
|
|
|
(isRR() && ud.ffire == 0) &&
|
|
|
|
ud.coop == 1 &&
|
2021-12-31 17:47:00 +00:00
|
|
|
actor->isPlayer() &&
|
2021-12-21 19:22:34 +00:00
|
|
|
actor != act)
|
2020-05-16 21:55:21 +00:00
|
|
|
continue;
|
|
|
|
|
2022-10-07 21:33:37 +00:00
|
|
|
if (gotshrinker && act->spr.scale.X < 0.46875 && !actorflag(act, SFLAG_SHRINKAUTOAIM)) continue;
|
2021-12-21 19:22:34 +00:00
|
|
|
if (gotfreezer && act->spr.pal == 1) continue;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
DVector2 vv = act->spr.pos.XY() - actor->spr.pos.XY();
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
if ((dv1.Y * vv.X) <= (dv1.X * vv.Y))
|
|
|
|
if ((dv2.Y * vv.X) >= (dv2.X * vv.Y))
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-14 16:08:23 +00:00
|
|
|
double sdist = dv3.dot(vv);
|
|
|
|
if (sdist > 32 && sdist < smax)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
2022-09-14 16:08:23 +00:00
|
|
|
int check;
|
2021-12-31 17:47:00 +00:00
|
|
|
if (actor->isPlayer())
|
2022-09-14 16:08:23 +00:00
|
|
|
{
|
2022-09-27 03:28:03 +00:00
|
|
|
double checkval = (act->spr.pos.Z - actor->spr.pos.Z) * 1.25 / sdist;
|
|
|
|
double horiz = ps[actor->PlayerIndex()].horizon.sum().Tan();
|
|
|
|
check = abs(checkval - horiz) < 0.78125;
|
2022-09-14 16:08:23 +00:00
|
|
|
}
|
|
|
|
else check = 1;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
int cans = cansee(act->spr.pos.plusZ(-32 + gs.actorinfo[act->spr.picnum].aimoffset), act->sector(), actor->spr.pos.plusZ(-32), actor->sector());
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2022-09-14 16:08:23 +00:00
|
|
|
if (check && cans)
|
2020-05-16 21:55:21 +00:00
|
|
|
{
|
|
|
|
smax = sdist;
|
2020-11-01 19:57:02 +00:00
|
|
|
aimed = act;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-14 20:18:10 +00:00
|
|
|
}
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
2020-11-01 19:57:02 +00:00
|
|
|
return aimed;
|
2020-05-16 21:55:21 +00:00
|
|
|
}
|
|
|
|
|
2020-05-17 21:44:53 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-10-23 17:50:18 +00:00
|
|
|
void dokneeattack(int snum, const std::initializer_list<int> & respawnlist)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
|
|
|
|
|
|
|
if (p->knee_incs > 0)
|
|
|
|
{
|
2022-06-05 23:19:55 +00:00
|
|
|
p->oknee_incs = p->knee_incs;
|
2020-05-17 21:44:53 +00:00
|
|
|
p->knee_incs++;
|
2022-11-24 02:20:17 +00:00
|
|
|
p->horizon.addadjustment(deltaangle(p->horizon.horiz, (p->GetActor()->getPosWithOffsetZ() - p->actorsqu->spr.pos).Pitch() * 1.1875));
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions |= SB_CENTERVIEW;
|
2020-05-17 21:44:53 +00:00
|
|
|
if (p->knee_incs > 15)
|
|
|
|
{
|
2022-06-05 23:19:55 +00:00
|
|
|
p->oknee_incs = p->knee_incs = 0;
|
2020-05-17 21:44:53 +00:00
|
|
|
p->holster_weapon = 0;
|
|
|
|
if (p->weapon_pos < 0)
|
|
|
|
p->weapon_pos = -p->weapon_pos;
|
2022-09-11 18:46:21 +00:00
|
|
|
if (p->actorsqu != nullptr && (p->GetActor()->spr.pos - p->actorsqu->spr.pos).Length() < 1400/16.)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-10-22 17:21:21 +00:00
|
|
|
fi.guts(p->actorsqu, TILE_JIBS6, 7, myconnectindex);
|
2020-10-23 17:50:18 +00:00
|
|
|
spawn(p->actorsqu, TILE_BLOODPOOL);
|
2020-07-25 07:32:54 +00:00
|
|
|
S_PlayActorSound(SQUISHED, p->actorsqu);
|
2021-12-21 17:19:45 +00:00
|
|
|
if (isIn(p->actorsqu->spr.picnum, respawnlist))
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2022-09-01 16:15:52 +00:00
|
|
|
if (p->actorsqu->spr.yint)
|
2022-11-20 10:58:19 +00:00
|
|
|
operaterespawns(p->actorsqu->spr.yint);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
2021-12-31 17:47:00 +00:00
|
|
|
if (p->actorsqu->isPlayer())
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2022-09-01 14:42:23 +00:00
|
|
|
quickkill(&ps[p->actorsqu->PlayerIndex()]);
|
|
|
|
ps[p->actorsqu->PlayerIndex()].frag_ps = snum;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2021-12-21 21:31:25 +00:00
|
|
|
else if (badguy(p->actorsqu))
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2022-11-20 18:25:23 +00:00
|
|
|
p->actorsqu->Destroy();
|
2020-05-17 21:44:53 +00:00
|
|
|
p->actors_killed++;
|
|
|
|
}
|
2022-11-20 18:25:23 +00:00
|
|
|
else p->actorsqu->Destroy();
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2020-10-17 08:30:11 +00:00
|
|
|
p->actorsqu = nullptr;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
int makepainsounds(int snum, int type)
|
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-10-23 17:50:18 +00:00
|
|
|
auto actor = p->GetActor();
|
2020-05-17 21:44:53 +00:00
|
|
|
int k = 0;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (rnd(32))
|
|
|
|
{
|
|
|
|
if (p->boot_amount > 0)
|
|
|
|
k = 1;
|
|
|
|
else
|
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
if (!S_CheckActorSoundPlaying(actor, DUKE_LONGTERM_PAIN))
|
|
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, actor);
|
2020-05-17 21:44:53 +00:00
|
|
|
SetPlayerPal(p, PalEntry(32, 64, 64, 64));
|
2021-12-21 19:22:34 +00:00
|
|
|
actor->spr.extra -= 1 + (krand() & 3);
|
2020-10-23 17:50:18 +00:00
|
|
|
if (!S_CheckActorSoundPlaying(actor, SHORT_CIRCUIT))
|
|
|
|
S_PlayActorSound(SHORT_CIRCUIT, actor);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (rnd(16))
|
|
|
|
{
|
|
|
|
if (p->boot_amount > 0)
|
|
|
|
k = 1;
|
|
|
|
else
|
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
if (!S_CheckActorSoundPlaying(actor, DUKE_LONGTERM_PAIN))
|
|
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, actor);
|
2020-05-17 21:44:53 +00:00
|
|
|
SetPlayerPal(p, PalEntry(32, 0, 8, 0));
|
2021-12-21 19:22:34 +00:00
|
|
|
actor->spr.extra -= 1 + (krand() & 3);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (rnd(32))
|
|
|
|
{
|
|
|
|
if (p->boot_amount > 0)
|
|
|
|
k = 1;
|
|
|
|
else
|
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
if (!S_CheckActorSoundPlaying(actor, DUKE_LONGTERM_PAIN))
|
|
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, actor);
|
2020-05-17 21:44:53 +00:00
|
|
|
SetPlayerPal(p, PalEntry(32, 8, 0, 0));
|
2021-12-21 19:22:34 +00:00
|
|
|
actor->spr.extra -= 1 + (krand() & 3);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if ((krand() & 3) == 1)
|
|
|
|
if (p->on_ground)
|
|
|
|
{
|
|
|
|
if (p->OnMotorcycle)
|
2021-12-21 19:22:34 +00:00
|
|
|
actor->spr.extra -= 2;
|
2020-05-17 21:44:53 +00:00
|
|
|
else
|
2021-12-21 19:22:34 +00:00
|
|
|
actor->spr.extra -= 4;
|
2020-10-23 17:50:18 +00:00
|
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, actor);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void footprints(int snum)
|
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-10-23 17:50:18 +00:00
|
|
|
auto actor = p->GetActor();
|
2020-05-17 21:44:53 +00:00
|
|
|
|
|
|
|
if (p->footprintcount > 0 && p->on_ground)
|
2022-01-04 11:43:58 +00:00
|
|
|
if (p->insector() && (p->cursector->floorstat & CSTAT_SECTOR_SLOPE) != 2)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
int j = -1;
|
2021-12-30 15:51:56 +00:00
|
|
|
DukeSectIterator it(actor->sector());
|
2020-10-23 17:50:18 +00:00
|
|
|
while (auto act = it.Next())
|
2020-10-14 19:16:54 +00:00
|
|
|
{
|
2021-12-21 17:19:45 +00:00
|
|
|
if (act->spr.picnum == TILE_FOOTPRINTS || act->spr.picnum == TILE_FOOTPRINTS2 || act->spr.picnum == TILE_FOOTPRINTS3 || act->spr.picnum == TILE_FOOTPRINTS4)
|
2022-11-21 02:29:33 +00:00
|
|
|
if (abs(act->spr.pos.X - p->GetActor()->spr.pos.X) < 24)
|
|
|
|
if (abs(act->spr.pos.Y - p->GetActor()->spr.pos.Y) < 24)
|
2020-10-23 17:50:18 +00:00
|
|
|
{
|
|
|
|
j = 1;
|
2020-05-17 21:44:53 +00:00
|
|
|
break;
|
2020-10-23 17:50:18 +00:00
|
|
|
}
|
2020-10-14 19:16:54 +00:00
|
|
|
}
|
2020-05-17 21:44:53 +00:00
|
|
|
if (j < 0)
|
|
|
|
{
|
|
|
|
p->footprintcount--;
|
2021-11-21 07:56:39 +00:00
|
|
|
if (p->cursector->lotag == 0 && p->cursector->hitag == 0)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
DDukeActor* fprint;
|
2020-05-17 21:44:53 +00:00
|
|
|
switch (krand() & 3)
|
|
|
|
{
|
2020-10-23 17:50:18 +00:00
|
|
|
case 0: fprint = spawn(actor, TILE_FOOTPRINTS); break;
|
|
|
|
case 1: fprint = spawn(actor, TILE_FOOTPRINTS2); break;
|
|
|
|
case 2: fprint = spawn(actor, TILE_FOOTPRINTS3); break;
|
|
|
|
default: fprint = spawn(actor, TILE_FOOTPRINTS4); break;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2021-11-19 11:32:12 +00:00
|
|
|
if (fprint)
|
|
|
|
{
|
2021-12-21 17:19:45 +00:00
|
|
|
fprint->spr.pal = p->footprintpal;
|
|
|
|
fprint->spr.shade = (int8_t)p->footprintshade;
|
2021-11-19 11:32:12 +00:00
|
|
|
}
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-10-21 17:14:41 +00:00
|
|
|
inline void backupplayer(player_struct* p)
|
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
p->backuppos();
|
2020-10-21 17:14:41 +00:00
|
|
|
p->angle.backup();
|
|
|
|
p->horizon.backup();
|
|
|
|
}
|
|
|
|
|
2022-09-14 19:25:27 +00:00
|
|
|
void playerisdead(int snum, int psectlotag, double floorz, double ceilingz)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-10-23 17:50:18 +00:00
|
|
|
auto actor = p->GetActor();
|
2020-05-17 21:44:53 +00:00
|
|
|
|
|
|
|
if (p->dead_flag == 0)
|
|
|
|
{
|
2021-12-21 19:22:34 +00:00
|
|
|
if (actor->spr.pal != 1)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
SetPlayerPal(p, PalEntry(63, 63, 0, 0));
|
2022-02-05 12:40:30 +00:00
|
|
|
actor->spr.pos.Z -= 16;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if (ud.recstat == 1 && ud.multimode < 2)
|
|
|
|
closedemowrite();
|
|
|
|
#endif
|
|
|
|
|
2021-12-21 19:22:34 +00:00
|
|
|
if (actor->spr.pal != 1)
|
2020-05-17 21:44:53 +00:00
|
|
|
p->dead_flag = (512 - ((krand() & 1) << 10) + (krand() & 255) - 512) & 2047;
|
|
|
|
|
|
|
|
p->jetpack_on = 0;
|
2020-10-21 08:48:38 +00:00
|
|
|
p->holoduke_on = nullptr;
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2020-10-23 17:50:18 +00:00
|
|
|
if (!isRR())S_StopSound(DUKE_JETPACK_IDLE, actor);
|
|
|
|
S_StopSound(-1, actor, CHAN_VOICE);
|
2020-05-17 21:44:53 +00:00
|
|
|
|
|
|
|
|
2021-12-21 19:22:34 +00:00
|
|
|
if (actor->spr.pal != 1 && (actor->spr.cstat & CSTAT_SPRITE_INVISIBLE) == 0) actor->spr.cstat = 0;
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2021-12-21 19:22:34 +00:00
|
|
|
if (ud.multimode > 1 && (actor->spr.pal != 1 || (actor->spr.cstat & CSTAT_SPRITE_INVISIBLE)))
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
if (p->frag_ps != snum)
|
|
|
|
{
|
|
|
|
ps[p->frag_ps].frag++;
|
2020-11-29 13:10:03 +00:00
|
|
|
ps[p->frag_ps].frags[snum]++;
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
auto pname = PlayerName(p->frag_ps);
|
2020-05-17 21:44:53 +00:00
|
|
|
if (snum == screenpeek)
|
|
|
|
{
|
2020-07-21 19:32:38 +00:00
|
|
|
Printf(PRINT_NOTIFY, "Killed by %s", pname);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-21 19:32:38 +00:00
|
|
|
Printf(PRINT_NOTIFY, "Killed %s", pname);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else p->fraggedself++;
|
2020-05-16 21:55:21 +00:00
|
|
|
|
2020-05-17 21:44:53 +00:00
|
|
|
p->frag_ps = snum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (psectlotag == ST_2_UNDERWATER)
|
|
|
|
{
|
|
|
|
if (p->on_warping_sector == 0)
|
|
|
|
{
|
2022-11-21 04:20:08 +00:00
|
|
|
if (abs(p->GetActor()->getOffsetZ() - floorz) > (gs.playerheight * 0.5))
|
2022-11-20 08:14:51 +00:00
|
|
|
p->GetActor()->spr.pos.Z += 348/ 256.;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-20 15:59:15 +00:00
|
|
|
actor->spr.pos.Z -= 2;
|
2022-09-11 17:28:45 +00:00
|
|
|
actor->vel.Z = -348 / 256.;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
2021-11-06 19:46:08 +00:00
|
|
|
Collision coll;
|
2022-11-21 04:20:08 +00:00
|
|
|
clipmove(p->GetActor()->spr.pos.XY(), p->GetActor()->getOffsetZ(), &p->cursector, DVector2( 0, 0), 10.25, 4., 4., CLIPMASK0, coll);
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
2020-07-29 22:24:27 +00:00
|
|
|
backupplayer(p);
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2022-10-11 02:37:20 +00:00
|
|
|
p->horizon.horizoff = p->horizon.horiz = nullAngle;
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2022-11-24 02:20:17 +00:00
|
|
|
updatesector(p->GetActor()->getPosWithOffsetZ(), &p->cursector);
|
2020-05-17 21:44:53 +00:00
|
|
|
|
2022-11-21 04:20:08 +00:00
|
|
|
pushmove(p->GetActor()->spr.pos.XY(), p->GetActor()->getOffsetZ(), &p->cursector, 8, 4, 20, CLIPMASK0);
|
2022-09-30 15:57:22 +00:00
|
|
|
|
2022-09-14 19:25:27 +00:00
|
|
|
if (floorz > ceilingz + 16 && actor->spr.pal != 1)
|
2022-11-21 04:20:08 +00:00
|
|
|
p->angle.rotscrnang = DAngle::fromBuild(p->dead_flag + ((floorz + p->GetActor()->getOffsetZ()) * 2));
|
2020-05-17 21:44:53 +00:00
|
|
|
|
|
|
|
p->on_warping_sector = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
int endoflevel(int snum)
|
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
|
|
|
|
|
|
|
// the fist puching the end-of-level thing...
|
2022-06-05 14:12:51 +00:00
|
|
|
p->ofist_incs = p->fist_incs;
|
2020-05-17 21:44:53 +00:00
|
|
|
p->fist_incs++;
|
|
|
|
if (p->fist_incs == 28)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (ud.recstat == 1) closedemowrite();
|
|
|
|
#endif
|
2020-07-25 07:32:54 +00:00
|
|
|
S_PlaySound(PIPEBOMB_EXPLODE);
|
2020-05-17 21:44:53 +00:00
|
|
|
SetPlayerPal(p, PalEntry(48, 64, 64, 64));
|
|
|
|
}
|
|
|
|
if (p->fist_incs > 42)
|
|
|
|
{
|
2020-07-07 15:56:20 +00:00
|
|
|
setnextmap(!!p->buttonpalette);
|
2020-05-17 21:44:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-05-18 22:26:07 +00:00
|
|
|
int timedexit(int snum)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
|
|
|
p->timebeforeexit--;
|
|
|
|
if (p->timebeforeexit == 26 * 5)
|
|
|
|
{
|
|
|
|
FX_StopAllSounds();
|
|
|
|
if (p->customexitsound >= 0)
|
|
|
|
{
|
2020-07-25 07:32:54 +00:00
|
|
|
S_PlaySound(p->customexitsound);
|
2020-05-17 21:44:53 +00:00
|
|
|
FTA(102, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (p->timebeforeexit == 1)
|
|
|
|
{
|
2020-07-07 15:56:20 +00:00
|
|
|
setnextmap(false);
|
2020-05-18 22:26:07 +00:00
|
|
|
return true;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2020-05-18 22:26:07 +00:00
|
|
|
return false;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 06:26:09 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-05-17 21:44:53 +00:00
|
|
|
void playerCrouch(int snum)
|
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
|
|
|
// crouching
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_CROUCH, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2022-11-20 08:14:51 +00:00
|
|
|
p->GetActor()->spr.pos.Z += 8 + 3;
|
2020-08-27 05:54:49 +00:00
|
|
|
p->crack_time = CRACK_TIME;
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-14 20:04:41 +00:00
|
|
|
void playerJump(int snum, double floorz, double ceilingz)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
|
|
|
if (p->jumping_toggle == 0 && p->jumping_counter == 0)
|
|
|
|
{
|
2022-09-14 20:04:41 +00:00
|
|
|
if ((floorz - ceilingz) > 56)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_JUMP, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
|
|
|
p->jumping_counter = 1;
|
|
|
|
p->jumping_toggle = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-17 01:00:43 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
void player_struct::apply_seasick(double factor)
|
2020-07-17 01:00:43 +00:00
|
|
|
{
|
2021-10-08 17:21:29 +00:00
|
|
|
if (isRRRA() && SeaSick && (dead_flag == 0 || (dead_flag && resurrected)))
|
2020-07-17 01:00:43 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
if (SeaSick < 250)
|
2020-07-17 01:00:43 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
if (SeaSick >= 180)
|
2022-08-27 11:48:57 +00:00
|
|
|
angle.rotscrnang += DAngle::fromDeg(24 * factor * BAngToDegree);
|
2020-11-29 08:00:00 +00:00
|
|
|
else if (SeaSick >= 130)
|
2022-08-27 11:48:57 +00:00
|
|
|
angle.rotscrnang -= DAngle::fromDeg(24 * factor * BAngToDegree);
|
2020-11-29 08:00:00 +00:00
|
|
|
else if (SeaSick >= 70)
|
2022-08-27 11:48:57 +00:00
|
|
|
angle.rotscrnang += DAngle::fromDeg(24 * factor * BAngToDegree);
|
2020-11-29 08:00:00 +00:00
|
|
|
else if (SeaSick >= 20)
|
2022-08-27 11:48:57 +00:00
|
|
|
angle.rotscrnang -= DAngle::fromDeg(24 * factor * BAngToDegree);
|
2020-07-17 01:00:43 +00:00
|
|
|
}
|
2020-11-29 08:00:00 +00:00
|
|
|
if (SeaSick < 250)
|
2022-08-27 11:48:57 +00:00
|
|
|
angle.look_ang = DAngle::fromDeg(((krand() & 255) - 128) * factor * BAngToDegree);
|
2020-08-05 12:57:47 +00:00
|
|
|
}
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
|
|
|
|
2020-07-17 01:00:43 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
void player_struct::backuppos(bool noclipping)
|
2020-07-29 22:24:27 +00:00
|
|
|
{
|
2020-07-29 22:49:01 +00:00
|
|
|
if (!noclipping)
|
2020-07-29 22:24:27 +00:00
|
|
|
{
|
2022-11-21 02:29:33 +00:00
|
|
|
GetActor()->backupvec2();
|
2020-07-29 22:24:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-11-21 02:29:33 +00:00
|
|
|
GetActor()->restorevec2();
|
2020-07-29 22:24:27 +00:00
|
|
|
}
|
|
|
|
|
2022-11-24 08:47:02 +00:00
|
|
|
GetActor()->backupz();
|
2022-11-20 08:07:23 +00:00
|
|
|
bobpos = GetActor()->spr.pos.XY();
|
2020-11-29 08:00:00 +00:00
|
|
|
opyoff = pyoff;
|
2020-07-29 22:24:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
void player_struct::backupweapon()
|
2020-08-03 03:28:16 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
oweapon_sway = weapon_sway;
|
|
|
|
oweapon_pos = weapon_pos;
|
|
|
|
okickback_pic = kickback_pic;
|
|
|
|
orandom_club_frame = random_club_frame;
|
|
|
|
ohard_landing = hard_landing;
|
2022-01-15 14:48:50 +00:00
|
|
|
ofistsign = fistsign;
|
2022-06-06 00:48:57 +00:00
|
|
|
otipincs = tipincs;
|
|
|
|
oknee_incs = knee_incs;
|
|
|
|
oaccess_incs = access_incs;
|
|
|
|
ofist_incs = fist_incs;
|
2022-06-06 01:24:38 +00:00
|
|
|
oloogcnt = loogcnt;
|
2020-08-03 03:28:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
void player_struct::checkhardlanding()
|
2020-08-05 07:53:22 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
if (hard_landing > 0)
|
2020-08-05 07:53:22 +00:00
|
|
|
{
|
2022-10-11 06:46:56 +00:00
|
|
|
horizon.addadjustment(maphoriz(hard_landing << 4));
|
2020-11-29 08:00:00 +00:00
|
|
|
hard_landing--;
|
2020-08-05 07:53:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-15 16:41:01 +00:00
|
|
|
void player_struct::playerweaponsway(double xvel)
|
2020-08-05 10:04:14 +00:00
|
|
|
{
|
|
|
|
if (cl_weaponsway)
|
|
|
|
{
|
2022-09-15 16:41:01 +00:00
|
|
|
if (xvel < 2 || on_ground == 0 || bobcounter == 1024)
|
2020-08-05 10:04:14 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
if ((weapon_sway & 2047) > (1024 + 96))
|
|
|
|
weapon_sway -= 96;
|
|
|
|
else if ((weapon_sway & 2047) < (1024 - 96))
|
|
|
|
weapon_sway += 96;
|
|
|
|
else oweapon_sway = weapon_sway = 1024;
|
2020-08-05 10:04:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
weapon_sway = bobcounter;
|
2020-08-05 10:04:14 +00:00
|
|
|
|
2020-11-29 08:00:00 +00:00
|
|
|
if ((bobcounter - oweapon_sway) > 256)
|
2020-08-05 10:04:14 +00:00
|
|
|
{
|
2020-11-29 08:00:00 +00:00
|
|
|
oweapon_sway = weapon_sway;
|
2020-08-05 10:04:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-05 07:53:22 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-08-29 11:32:14 +00:00
|
|
|
void checklook(int snum, ESyncBits actions)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-05-18 06:26:09 +00:00
|
|
|
auto p = &ps[snum];
|
2020-07-17 01:00:43 +00:00
|
|
|
|
2020-08-29 11:32:14 +00:00
|
|
|
if ((actions & SB_LOOK_LEFT) && !p->OnMotorcycle)
|
2020-05-17 21:44:53 +00:00
|
|
|
{
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_LOOKLEFT, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() != 0)
|
2020-07-16 15:59:25 +00:00
|
|
|
{
|
2020-09-21 07:00:07 +00:00
|
|
|
actions &= ~SB_LOOK_LEFT;
|
2020-07-16 15:59:25 +00:00
|
|
|
}
|
2020-07-17 01:00:43 +00:00
|
|
|
}
|
|
|
|
|
2020-08-29 11:32:14 +00:00
|
|
|
if ((actions & SB_LOOK_RIGHT) && !p->OnMotorcycle)
|
2020-07-17 01:00:43 +00:00
|
|
|
{
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_LOOKRIGHT, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() != 0)
|
2020-07-17 01:00:43 +00:00
|
|
|
{
|
2020-09-21 07:00:07 +00:00
|
|
|
actions &= ~SB_LOOK_RIGHT;
|
2020-07-17 01:00:43 +00:00
|
|
|
}
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2020-10-07 12:13:21 +00:00
|
|
|
p->angle.backup();
|
2020-05-17 21:44:53 +00:00
|
|
|
}
|
2020-05-18 06:26:09 +00:00
|
|
|
|
2020-07-17 01:00:43 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-05-18 06:26:09 +00:00
|
|
|
void playerCenterView(int snum)
|
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_RETURNTOCENTER, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions |= SB_CENTERVIEW;
|
2020-09-20 10:01:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions &= ~SB_CENTERVIEW;
|
2020-05-18 06:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 22:57:07 +00:00
|
|
|
void playerLookUp(int snum, ESyncBits actions)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_LOOKUP, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions |= SB_CENTERVIEW;
|
2020-09-20 10:01:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions &= ~SB_LOOK_UP;
|
2020-05-18 06:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 22:57:07 +00:00
|
|
|
void playerLookDown(int snum, ESyncBits actions)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_LOOKDOWN, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() == 0)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions |= SB_CENTERVIEW;
|
2020-09-20 10:01:05 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions &= ~SB_LOOK_DOWN;
|
2020-05-18 06:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 22:57:07 +00:00
|
|
|
void playerAimUp(int snum, ESyncBits actions)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2020-11-01 16:57:40 +00:00
|
|
|
OnEvent(EVENT_AIMUP, snum, p->GetActor(), -1);
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() != 0)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions &= ~SB_AIM_UP;
|
2020-05-18 06:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 22:57:07 +00:00
|
|
|
void playerAimDown(int snum, ESyncBits actions)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2020-11-01 17:23:09 +00:00
|
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
2021-01-30 22:42:44 +00:00
|
|
|
OnEvent(EVENT_AIMDOWN, snum, p->GetActor(), -1); // due to a typo in WW2GI's CON files this is the same as EVENT_AIMUP.
|
2021-12-05 16:36:57 +00:00
|
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum).value() != 0)
|
2020-05-18 06:26:09 +00:00
|
|
|
{
|
2020-09-24 14:09:31 +00:00
|
|
|
p->sync.actions &= ~SB_AIM_DOWN;
|
2020-05-18 06:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-05 09:24:32 +00:00
|
|
|
//---------------------------------------------------------------------------
|
2020-07-17 23:34:13 +00:00
|
|
|
//
|
|
|
|
// split out so that the weapon check can be done right.
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-01-02 00:04:03 +00:00
|
|
|
bool movementBlocked(player_struct *p)
|
2020-07-17 23:34:13 +00:00
|
|
|
{
|
|
|
|
auto blockingweapon = [=]()
|
|
|
|
{
|
|
|
|
if (isRR()) return false;
|
2021-12-05 12:43:31 +00:00
|
|
|
if (isWW2GI()) return aplWeaponWorksLike(p->curr_weapon, p->GetPlayerNum()) == TRIPBOMB_WEAPON;
|
2020-07-17 23:34:13 +00:00
|
|
|
else return p->curr_weapon == TRIPBOMB_WEAPON;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto weapondelay = [=]()
|
|
|
|
{
|
2021-12-05 12:43:31 +00:00
|
|
|
if (isWW2GI()) return aplWeaponFireDelay(p->curr_weapon, p->GetPlayerNum());
|
2020-07-17 23:34:13 +00:00
|
|
|
else return 4;
|
|
|
|
};
|
|
|
|
|
|
|
|
return (p->fist_incs ||
|
|
|
|
p->transporter_hold > 2 ||
|
|
|
|
p->hard_landing ||
|
|
|
|
p->access_incs > 0 ||
|
|
|
|
p->knee_incs > 0 ||
|
|
|
|
(blockingweapon() && p->kickback_pic > 1 && p->kickback_pic < weapondelay()));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-19 19:21:55 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-11-18 18:57:14 +00:00
|
|
|
int haskey(sectortype* sectp, int snum)
|
2020-05-19 19:21:55 +00:00
|
|
|
{
|
|
|
|
auto p = &ps[snum];
|
2022-01-05 07:05:15 +00:00
|
|
|
if (!sectp)
|
|
|
|
return 0;
|
2021-11-20 16:46:08 +00:00
|
|
|
if (!sectp->keyinfo)
|
2020-05-19 19:21:55 +00:00
|
|
|
return 1;
|
2021-11-20 16:46:08 +00:00
|
|
|
if (sectp->keyinfo > 6)
|
2020-05-19 19:21:55 +00:00
|
|
|
return 1;
|
2021-11-20 16:46:08 +00:00
|
|
|
int wk = sectp->keyinfo;
|
2020-05-19 19:21:55 +00:00
|
|
|
if (wk > 3)
|
|
|
|
wk -= 3;
|
|
|
|
|
|
|
|
if (p->keys[wk] == 1)
|
|
|
|
{
|
2021-11-20 16:46:08 +00:00
|
|
|
sectp->keyinfo = 0;
|
2020-05-19 19:21:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-20 23:03:38 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2022-01-20 07:31:08 +00:00
|
|
|
void shootbloodsplat(DDukeActor* actor, int p, const DVector3& pos, DAngle ang, int atwith, int BIGFORCE)
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2021-12-30 15:51:56 +00:00
|
|
|
auto sectp = actor->sector();
|
2022-09-13 18:54:34 +00:00
|
|
|
double zvel;
|
2021-12-06 11:24:22 +00:00
|
|
|
HitInfo hit{};
|
2020-10-20 23:03:38 +00:00
|
|
|
|
|
|
|
if (p >= 0)
|
2022-09-13 18:54:34 +00:00
|
|
|
ang += DAngle22_5 / 2 - randomAngle(22.5);
|
|
|
|
else ang += DAngle180 + DAngle22_5/2 - randomAngle(22.5);
|
|
|
|
|
|
|
|
zvel = 4 - krandf(8);
|
2020-10-20 23:03:38 +00:00
|
|
|
|
|
|
|
|
2022-09-13 18:54:34 +00:00
|
|
|
hitscan(pos, sectp, DVector3(ang.ToVector() * 1024, zvel * 64), hit, CLIPMASK1);
|
2020-10-20 23:03:38 +00:00
|
|
|
|
|
|
|
// oh my...
|
2022-09-13 18:54:34 +00:00
|
|
|
if ( (pos.XY() - hit.hitpos.XY()).Length() < 64 &&
|
2021-11-25 23:08:59 +00:00
|
|
|
(hit.hitWall != nullptr && hit.hitWall->overpicnum != BIGFORCE) &&
|
|
|
|
((hit.hitWall->twoSided() && hit.hitSector != nullptr &&
|
|
|
|
hit.hitWall->nextSector()->lotag == 0 &&
|
|
|
|
hit.hitSector->lotag == 0 &&
|
2022-08-28 09:34:54 +00:00
|
|
|
(hit.hitSector->floorz - hit.hitWall->nextSector()->floorz) > 16) ||
|
2021-11-25 23:08:59 +00:00
|
|
|
(!hit.hitWall->twoSided() && hit.hitSector->lotag == 0)))
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2021-12-18 14:11:21 +00:00
|
|
|
if ((hit.hitWall->cstat & CSTAT_WALL_MASKED) == 0)
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2021-11-25 23:08:59 +00:00
|
|
|
if (hit.hitWall->twoSided())
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2021-11-25 23:08:59 +00:00
|
|
|
DukeSectIterator it(hit.hitWall->nextSector());
|
2020-10-23 17:50:18 +00:00
|
|
|
while (auto act2 = it.Next())
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2021-12-21 17:19:45 +00:00
|
|
|
if (act2->spr.statnum == STAT_EFFECTOR && act2->spr.lotag == SE_13_EXPLOSIVE)
|
2020-10-20 23:03:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-25 23:08:59 +00:00
|
|
|
if (hit.hitWall->twoSided() &&
|
|
|
|
hit.hitWall->nextWall()->hitag != 0)
|
2020-10-20 23:03:38 +00:00
|
|
|
return;
|
|
|
|
|
2021-11-25 23:08:59 +00:00
|
|
|
if (hit.hitWall->hitag == 0)
|
2020-10-20 23:03:38 +00:00
|
|
|
{
|
2020-10-23 20:06:02 +00:00
|
|
|
auto spawned = spawn(actor, atwith);
|
2021-11-19 11:32:12 +00:00
|
|
|
if (spawned)
|
|
|
|
{
|
2022-09-13 17:56:17 +00:00
|
|
|
spawned->vel.X = -0.75;
|
2022-10-08 12:23:11 +00:00
|
|
|
spawned->spr.angle = hit.hitWall->delta().Angle() - DAngle90;
|
2022-08-23 20:47:38 +00:00
|
|
|
spawned->spr.pos = hit.hitpos;
|
2021-12-21 17:19:45 +00:00
|
|
|
spawned->spr.cstat |= randomXFlip();
|
2021-11-19 11:32:12 +00:00
|
|
|
ssp(spawned, CLIPMASK0);
|
2022-08-22 16:34:01 +00:00
|
|
|
SetActor(spawned, spawned->spr.pos);
|
2022-01-20 07:31:08 +00:00
|
|
|
if (actorflag(actor, SFLAG2_GREENBLOOD))
|
2021-12-21 17:19:45 +00:00
|
|
|
spawned->spr.pal = 6;
|
2021-11-19 11:32:12 +00:00
|
|
|
}
|
2020-10-20 23:03:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 10:14:03 +00:00
|
|
|
END_DUKE_NS
|