mirror of
https://github.com/DrBeef/Raze.git
synced 2025-01-24 01:40:58 +00:00
d8e331ef0f
Storing this in the player_struct is pointless and a relic from having to use real hardware palette switches. With this now just being a translation index being passed to the backend it can be cheaply retrieved right when used and nowhere else. Also making some changes to how RRRA's psychedelic cactus handles the projection. This fixes issues with occasionally passing a bad matrix.
3192 lines
73 KiB
C++
3192 lines
73 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 1996, 2003 - 3D Realms Entertainment
|
|
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
|
|
Copyright (C) 2020 - Christoph Oelckers
|
|
|
|
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"
|
|
#include "gamevar.h"
|
|
#include "names_d.h"
|
|
#include "dukeactor.h"
|
|
|
|
BEGIN_DUKE_NS
|
|
|
|
void fireweapon_ww(int snum);
|
|
void operateweapon_ww(int snum, ESyncBits actions, int psect);
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void incur_damage_d(struct player_struct* p)
|
|
{
|
|
int damage = 0L, shield_damage = 0L;
|
|
|
|
p->GetActor()->s.extra -= p->extra_extra8 >> 8;
|
|
|
|
damage = p->GetActor()->s.extra - p->last_extra;
|
|
|
|
if (damage < 0)
|
|
{
|
|
p->extra_extra8 = 0;
|
|
|
|
if (p->shield_amount > 0)
|
|
{
|
|
shield_damage = damage * (20 + (rand() % 30)) / 100;
|
|
damage -= shield_damage;
|
|
|
|
p->shield_amount += shield_damage;
|
|
|
|
if (p->shield_amount < 0)
|
|
{
|
|
damage += p->shield_amount;
|
|
p->shield_amount = 0;
|
|
}
|
|
}
|
|
|
|
p->GetActor()->s.extra = p->last_extra + damage;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootfireball(DDukeActor *actor, int p, int sx, int sy, int sz, int sa)
|
|
{
|
|
auto s = &actor->s;
|
|
int vel, zvel;
|
|
|
|
if (s->extra >= 0)
|
|
s->shade = -96;
|
|
|
|
sz -= (4 << 7);
|
|
if (s->picnum != BOSS5)
|
|
vel = 840;
|
|
else {
|
|
vel = 968;
|
|
sz += 6144;
|
|
}
|
|
|
|
if (p < 0)
|
|
{
|
|
sa += 16 - (krand() & 31);
|
|
int scratch;
|
|
int j = findplayer(actor, &scratch);
|
|
zvel = (((ps[j].oposz - sz + (3 << 8))) * vel) / ldist(ps[j].GetActor(), actor);
|
|
}
|
|
else
|
|
{
|
|
zvel = -mulscale16(ps[p].horizon.sum().asq16(), 98);
|
|
sx += sintable[(sa + 860) & 0x7FF] / 448;
|
|
sy += sintable[(sa + 348) & 0x7FF] / 448;
|
|
sz += (3 << 8);
|
|
}
|
|
|
|
int sizx = 18;
|
|
int sizy = 18;
|
|
if (p >= 0)
|
|
{
|
|
sizx = 7;
|
|
sizy = 7;
|
|
}
|
|
|
|
auto spawned = EGS(s->sectnum, sx, sy, sz, FIREBALL, -127, sizx, sizy, sa, vel, zvel, actor, (short)4);
|
|
auto spr = &spawned->s;
|
|
spr->extra += (krand() & 7);
|
|
if (s->picnum == BOSS5 || p >= 0)
|
|
{
|
|
spr->xrepeat = 40;
|
|
spr->yrepeat = 40;
|
|
}
|
|
spr->yvel = p;
|
|
spr->cstat = 128;
|
|
spr->clipdist = 4;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootflamethrowerflame(DDukeActor* actor, int p, int sx, int sy, int sz, int sa)
|
|
{
|
|
auto s = &actor->s;
|
|
int vel, zvel;
|
|
|
|
if (s->extra >= 0)
|
|
s->shade = -96;
|
|
vel = 400;
|
|
|
|
DDukeActor* spawned = nullptr;
|
|
if (p < 0)
|
|
{
|
|
int x;
|
|
int j = findplayer(actor, &x);
|
|
sa = getangle(ps[j].oposx - sx, ps[j].oposy - sy);
|
|
|
|
if (s->picnum == BOSS5)
|
|
{
|
|
vel = 528;
|
|
sz += 6144;
|
|
}
|
|
else if (s->picnum == BOSS3)
|
|
sz -= 8192;
|
|
|
|
int l = ldist(ps[j].GetActor(), actor);
|
|
if (l != 0)
|
|
zvel = ((ps[j].oposz - sz) * vel) / l;
|
|
|
|
if (badguy(actor) && (s->hitag & face_player_smart) != 0)
|
|
sa = (short)(s->ang + (krand() & 31) - 16);
|
|
|
|
if (sector[s->sectnum].lotag == 2 && (krand() % 5) == 0)
|
|
spawned = spawn(actor, WATERBUBBLE);
|
|
}
|
|
else
|
|
{
|
|
zvel = -mulscale16(ps[p].horizon.sum().asq16(), 81);
|
|
if (ps[p].GetActor()->s.xvel != 0)
|
|
vel = (int)((((512 - (1024
|
|
- abs(abs(getangle(sx - ps[p].oposx, sy - ps[p].oposy) - sa) - 1024)))
|
|
* 0.001953125f) * ps[p].GetActor()->s.xvel) + 400);
|
|
if (sector[s->sectnum].lotag == 2 && (krand() % 5) == 0)
|
|
spawned = spawn(actor, WATERBUBBLE);
|
|
}
|
|
|
|
if (spawned == nullptr)
|
|
{
|
|
spawned = spawn(actor, FLAMETHROWERFLAME);
|
|
spawned->s.xvel = (short)vel;
|
|
spawned->s.zvel = (short)zvel;
|
|
}
|
|
|
|
spawned->s.x = sx + sintable[(sa + 630) & 0x7FF] / 448;
|
|
spawned->s.y = sy + sintable[(sa + 112) & 0x7FF] / 448;
|
|
spawned->s.z = sz - 256;
|
|
spawned->s.sectnum = s->sectnum;
|
|
spawned->s.cstat = 0x80;
|
|
spawned->s.ang = sa;
|
|
spawned->s.xrepeat = 2;
|
|
spawned->s.yrepeat = 2;
|
|
spawned->s.clipdist = 40;
|
|
spawned->s.yvel = p;
|
|
spawned->SetOwner(actor);
|
|
|
|
if (p == -1)
|
|
{
|
|
if (s->picnum == BOSS5)
|
|
{
|
|
spawned->s.x -= sintable[sa & 2047] / 56;
|
|
spawned->s.y -= sintable[(sa + 1024 + 512) & 2047] / 56;
|
|
spawned->s.xrepeat = 10;
|
|
spawned->s.yrepeat = 10;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootknee(DDukeActor* actor, int p, int sx, int sy, int sz, int sa)
|
|
{
|
|
auto s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int zvel;
|
|
short hitsect, hitwall;
|
|
int hitx, hity, hitz;
|
|
DDukeActor* hitsprt;
|
|
|
|
if (p >= 0)
|
|
{
|
|
zvel = -ps[p].horizon.sum().asq16() >> 11;
|
|
sz += (6 << 8);
|
|
sa += 15;
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
auto pactor = ps[findplayer(actor, &x)].GetActor();
|
|
zvel = ((pactor->s.z - sz) << 8) / (x + 1);
|
|
sa = getangle(pactor->s.x - sx, pactor->s.y - sy);
|
|
}
|
|
|
|
hitscan(sx, sy, sz, sect,
|
|
sintable[(sa + 512) & 2047],
|
|
sintable[sa & 2047], zvel << 6,
|
|
&hitsect, &hitwall, &hitsprt, &hitx, &hity, &hitz, CLIPMASK1);
|
|
|
|
|
|
if (hitsect < 0) return;
|
|
|
|
if ((abs(sx - hitx) + abs(sy - hity)) < 1024)
|
|
{
|
|
if (hitwall >= 0 || hitsprt)
|
|
{
|
|
auto knee = EGS(hitsect, hitx, hity, hitz, KNEE, -15, 0, 0, sa, 32, 0, actor, 4);
|
|
knee->s.extra += (krand() & 7);
|
|
if (p >= 0)
|
|
{
|
|
auto k = spawn(knee, SMALLSMOKE);
|
|
k->s.z -= (8 << 8);
|
|
S_PlayActorSound(KICK_HIT, knee);
|
|
}
|
|
|
|
if (p >= 0 && ps[p].steroids_amount > 0 && ps[p].steroids_amount < 400)
|
|
knee->s.extra += (max_player_health >> 2);
|
|
|
|
if (hitsprt && hitsprt->s.picnum != ACCESSSWITCH && hitsprt->s.picnum != ACCESSSWITCH2)
|
|
{
|
|
fi.checkhitsprite(hitsprt, knee);
|
|
if (p >= 0) fi.checkhitswitch(p, -1, hitsprt);
|
|
}
|
|
|
|
else if (hitwall >= 0)
|
|
{
|
|
if (wall[hitwall].cstat & 2)
|
|
if (wall[hitwall].nextsector >= 0)
|
|
if (hitz >= (sector[wall[hitwall].nextsector].floorz))
|
|
hitwall = wall[hitwall].nextwall;
|
|
|
|
if (hitwall >= 0 && wall[hitwall].picnum != ACCESSSWITCH && wall[hitwall].picnum != ACCESSSWITCH2)
|
|
{
|
|
fi.checkhitwall(knee, hitwall, hitx, hity, hitz, KNEE);
|
|
if (p >= 0) fi.checkhitswitch(p, hitwall, nullptr);
|
|
}
|
|
}
|
|
}
|
|
else if (p >= 0 && zvel > 0 && sector[hitsect].lotag == 1)
|
|
{
|
|
auto splash = spawn(ps[p].GetActor(), WATERSPLASH2);
|
|
splash->s.x = hitx;
|
|
splash->s.y = hity;
|
|
splash->s.ang = ps[p].angle.ang.asbuild(); // Total tweek
|
|
splash->s.xvel = 32;
|
|
ssp(actor, CLIPMASK0);
|
|
splash->s.xvel = 0;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootweapon(DDukeActor *actor, int p, int sx, int sy, int sz, int sa, int atwith)
|
|
{
|
|
auto s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int zvel;
|
|
short hitsect, hitwall;
|
|
int hitx, hity, hitz;
|
|
DDukeActor* hitact;
|
|
|
|
if (s->extra >= 0) s->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);
|
|
DDukeActor* aimed = nullptr;
|
|
if (varval > 0)
|
|
{
|
|
aimed = aim(actor, varval);
|
|
}
|
|
|
|
if (aimed)
|
|
{
|
|
int dal = ((aimed->s.xrepeat * tilesiz[aimed->s.picnum].y) << 1) + (5 << 8);
|
|
switch (aimed->s.picnum)
|
|
{
|
|
case GREENSLIME:
|
|
case GREENSLIME + 1:
|
|
case GREENSLIME + 2:
|
|
case GREENSLIME + 3:
|
|
case GREENSLIME + 4:
|
|
case GREENSLIME + 5:
|
|
case GREENSLIME + 6:
|
|
case GREENSLIME + 7:
|
|
case ROTATEGUN:
|
|
dal -= (8 << 8);
|
|
break;
|
|
}
|
|
zvel = ((aimed->s.z - sz - dal) << 8) / ldist(ps[p].GetActor(), aimed);
|
|
sa = getangle(aimed->s.x - sx, aimed->s.y - sy);
|
|
}
|
|
|
|
if (isWW2GI())
|
|
{
|
|
int angRange = 32;
|
|
int zRange = 256;
|
|
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);
|
|
zRange = GetGameVarID(g_iZRangeVarID, actor, p);
|
|
|
|
sa += (angRange / 2) - (krand() & (angRange - 1));
|
|
if (aimed == nullptr)
|
|
{
|
|
// no target
|
|
zvel = -ps[p].horizon.sum().asq16() >> 11;
|
|
}
|
|
zvel += (zRange / 2) - (krand() & (zRange - 1));
|
|
}
|
|
else if (aimed == nullptr)
|
|
{
|
|
sa += 16 - (krand() & 31);
|
|
zvel = -ps[p].horizon.sum().asq16() >> 11;
|
|
zvel += 128 - (krand() & 255);
|
|
}
|
|
|
|
sz -= (2 << 8);
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
int j = findplayer(actor, &x);
|
|
sz -= (4 << 8);
|
|
zvel = ((ps[j].posz - sz) << 8) / (ldist(ps[j].GetActor(), actor));
|
|
if (s->picnum != BOSS1)
|
|
{
|
|
zvel += 128 - (krand() & 255);
|
|
sa += 32 - (krand() & 63);
|
|
}
|
|
else
|
|
{
|
|
zvel += 128 - (krand() & 255);
|
|
sa = getangle(ps[j].posx - sx, ps[j].posy - sy) + 64 - (krand() & 127);
|
|
}
|
|
}
|
|
|
|
s->cstat &= ~257;
|
|
hitscan(sx, sy, sz, sect,
|
|
sintable[(sa + 512) & 2047],
|
|
sintable[sa & 2047],
|
|
zvel << 6, &hitsect, &hitwall, &hitact, &hitx, &hity, &hitz, CLIPMASK1);
|
|
s->cstat |= 257;
|
|
|
|
|
|
if (hitsect < 0) return;
|
|
|
|
if ((krand() & 15) == 0 && sector[hitsect].lotag == 2)
|
|
tracers(hitx, hity, hitz, sx, sy, sz, 8 - (ud.multimode >> 1));
|
|
|
|
DDukeActor* spark;
|
|
if (p >= 0)
|
|
{
|
|
spark = EGS(hitsect, hitx, hity, hitz, SHOTSPARK1, -15, 10, 10, sa, 0, 0, actor, 4);
|
|
spark->s.extra = ScriptCode[actorinfo[atwith].scriptaddress];
|
|
spark->s.extra += (krand() % 6);
|
|
|
|
if (hitwall == -1 && hitact == nullptr)
|
|
{
|
|
if (zvel < 0)
|
|
{
|
|
if (sector[hitsect].ceilingstat & 1)
|
|
{
|
|
spark->s.xrepeat = 0;
|
|
spark->s.yrepeat = 0;
|
|
return;
|
|
}
|
|
else
|
|
fi.checkhitceiling(hitsect);
|
|
}
|
|
spawn(spark, SMALLSMOKE);
|
|
}
|
|
|
|
if (hitact)
|
|
{
|
|
fi.checkhitsprite(hitact, spark);
|
|
if (hitact->s.picnum == TILE_APLAYER && (ud.coop != 1 || ud.ffire == 1))
|
|
{
|
|
auto jib = spawn(spark, JIBS6);
|
|
spark->s.xrepeat = spark->s.yrepeat = 0;
|
|
jib->s.z += (4 << 8);
|
|
jib->s.xvel = 16;
|
|
jib->s.xrepeat = jib->s.yrepeat = 24;
|
|
jib->s.ang += 64 - (krand() & 127);
|
|
}
|
|
else spawn(spark, SMALLSMOKE);
|
|
|
|
if (p >= 0 && (
|
|
hitact->s.picnum == DIPSWITCH ||
|
|
hitact->s.picnum == DIPSWITCH + 1 ||
|
|
hitact->s.picnum == DIPSWITCH2 ||
|
|
hitact->s.picnum == DIPSWITCH2 + 1 ||
|
|
hitact->s.picnum == DIPSWITCH3 ||
|
|
hitact->s.picnum == DIPSWITCH3 + 1 ||
|
|
hitact->s.picnum == HANDSWITCH ||
|
|
hitact->s.picnum == HANDSWITCH + 1))
|
|
{
|
|
fi.checkhitswitch(p, -1, hitact);
|
|
return;
|
|
}
|
|
}
|
|
else if (hitwall >= 0)
|
|
{
|
|
spawn(spark, SMALLSMOKE);
|
|
|
|
if (fi.isadoorwall(wall[hitwall].picnum) == 1)
|
|
goto SKIPBULLETHOLE;
|
|
if (p >= 0 && (
|
|
wall[hitwall].picnum == DIPSWITCH ||
|
|
wall[hitwall].picnum == DIPSWITCH + 1 ||
|
|
wall[hitwall].picnum == DIPSWITCH2 ||
|
|
wall[hitwall].picnum == DIPSWITCH2 + 1 ||
|
|
wall[hitwall].picnum == DIPSWITCH3 ||
|
|
wall[hitwall].picnum == DIPSWITCH3 + 1 ||
|
|
wall[hitwall].picnum == HANDSWITCH ||
|
|
wall[hitwall].picnum == HANDSWITCH + 1))
|
|
{
|
|
fi.checkhitswitch(p, hitwall, nullptr);
|
|
return;
|
|
}
|
|
|
|
if (wall[hitwall].hitag != 0 || (wall[hitwall].nextwall >= 0 && wall[wall[hitwall].nextwall].hitag != 0))
|
|
goto SKIPBULLETHOLE;
|
|
|
|
if (hitsect >= 0 && sector[hitsect].lotag == 0)
|
|
if (wall[hitwall].overpicnum != BIGFORCE)
|
|
if ((wall[hitwall].nextsector >= 0 && sector[wall[hitwall].nextsector].lotag == 0) ||
|
|
(wall[hitwall].nextsector == -1 && sector[hitsect].lotag == 0))
|
|
if ((wall[hitwall].cstat & 16) == 0)
|
|
{
|
|
if (wall[hitwall].nextsector >= 0)
|
|
{
|
|
DukeSectIterator it(wall[hitwall].nextsector);
|
|
while (auto l = it.Next())
|
|
{
|
|
if (l->s.statnum == 3 && l->s.lotag == 13)
|
|
goto SKIPBULLETHOLE;
|
|
}
|
|
}
|
|
|
|
DukeStatIterator it(STAT_MISC);
|
|
while (auto l = it.Next())
|
|
{
|
|
if (l->s.picnum == BULLETHOLE)
|
|
if (dist(l, spark) < (12 + (krand() & 7)))
|
|
goto SKIPBULLETHOLE;
|
|
}
|
|
auto hole = spawn(spark, BULLETHOLE);
|
|
hole->s.xvel = -1;
|
|
hole->s.ang = getangle(wall[hitwall].x - wall[wall[hitwall].point2].x,
|
|
wall[hitwall].y - wall[wall[hitwall].point2].y) + 512;
|
|
ssp(hole, CLIPMASK0);
|
|
}
|
|
|
|
SKIPBULLETHOLE:
|
|
|
|
if (wall[hitwall].cstat & 2)
|
|
if (wall[hitwall].nextsector >= 0)
|
|
if (hitz >= (sector[wall[hitwall].nextsector].floorz))
|
|
hitwall = wall[hitwall].nextwall;
|
|
|
|
fi.checkhitwall(spark, hitwall, hitx, hity, hitz, SHOTSPARK1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
spark = EGS(hitsect, hitx, hity, hitz, SHOTSPARK1, -15, 24, 24, sa, 0, 0, actor, 4);
|
|
spark->s.extra = ScriptCode[actorinfo[atwith].scriptaddress];
|
|
|
|
if (hitact)
|
|
{
|
|
fi.checkhitsprite(hitact, spark);
|
|
if (hitact->s.picnum != TILE_APLAYER)
|
|
spawn(spark, SMALLSMOKE);
|
|
else spark->s.xrepeat = spark->s.yrepeat = 0;
|
|
}
|
|
else if (hitwall >= 0)
|
|
fi.checkhitwall(spark, hitwall, hitx, hity, hitz, SHOTSPARK1);
|
|
}
|
|
|
|
if ((krand() & 255) < 4)
|
|
{
|
|
vec3_t v{ hitx, hity, hitz };
|
|
S_PlaySound3D(PISTOL_RICOCHET, spark, &v);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootstuff(DDukeActor* actor, int p, int sx, int sy, int sz, int sa, int atwith)
|
|
{
|
|
spritetype* const s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int vel, zvel;
|
|
short l, scount;
|
|
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
scount = 1;
|
|
if (atwith == SPIT) vel = 292;
|
|
else
|
|
{
|
|
if (atwith == COOLEXPLOSION1)
|
|
{
|
|
if (s->picnum == BOSS2) vel = 644;
|
|
else vel = 348;
|
|
sz -= (4 << 7);
|
|
}
|
|
else
|
|
{
|
|
vel = 840;
|
|
sz -= (4 << 7);
|
|
}
|
|
}
|
|
|
|
if (p >= 0)
|
|
{
|
|
auto aimed = aim(actor, AUTO_AIM_ANGLE);
|
|
|
|
if (aimed)
|
|
{
|
|
int dal = ((aimed->s.xrepeat * tilesiz[aimed->s.picnum].y) << 1) - (12 << 8);
|
|
zvel = ((aimed->s.z - sz - dal) * vel) / ldist(ps[p].GetActor(), aimed);
|
|
sa = getangle(aimed->s.x - sx, aimed->s.y - sy);
|
|
}
|
|
else
|
|
zvel = -mulscale16(ps[p].horizon.sum().asq16(), 98);
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
int j = findplayer(actor, &x);
|
|
// sa = getangle(ps[j].oposx-sx,ps[j].oposy-sy);
|
|
sa += 16 - (krand() & 31);
|
|
zvel = (((ps[j].oposz - sz + (3 << 8))) * vel) / ldist(ps[p].GetActor(), actor);
|
|
}
|
|
|
|
int oldzvel = zvel;
|
|
int sizx, sizy;
|
|
|
|
if (atwith == SPIT) { sizx = 18; sizy = 18, sz -= (10 << 8); }
|
|
else
|
|
{
|
|
if (atwith == FIRELASER)
|
|
{
|
|
if (p >= 0)
|
|
{
|
|
|
|
sizx = 34;
|
|
sizy = 34;
|
|
}
|
|
else
|
|
{
|
|
sizx = 18;
|
|
sizy = 18;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sizx = 18;
|
|
sizy = 18;
|
|
}
|
|
}
|
|
|
|
if (p >= 0) sizx = 7, sizy = 7;
|
|
|
|
while (scount > 0)
|
|
{
|
|
auto spawned = EGS(sect, sx, sy, sz, atwith, -127, sizx, sizy, sa, vel, zvel, actor, 4);
|
|
spawned->s.extra += (krand() & 7);
|
|
|
|
if (atwith == COOLEXPLOSION1)
|
|
{
|
|
spawned->s.shade = 0;
|
|
if (s->picnum == BOSS2)
|
|
{
|
|
l = spawned->s.xvel;
|
|
spawned->s.xvel = 1024;
|
|
ssp(spawned, CLIPMASK0);
|
|
spawned->s.xvel = l;
|
|
spawned->s.ang += 128 - (krand() & 255);
|
|
}
|
|
}
|
|
|
|
spawned->s.cstat = 128;
|
|
spawned->s.clipdist = 4;
|
|
|
|
sa = s->ang + 32 - (krand() & 63);
|
|
zvel = oldzvel + 512 - (krand() & 1023);
|
|
|
|
scount--;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootrpg(DDukeActor *actor, int p, int sx, int sy, int sz, int sa, int atwith)
|
|
{
|
|
auto s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int vel, zvel;
|
|
short l, scount;
|
|
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
scount = 1;
|
|
vel = 644;
|
|
|
|
DDukeActor* aimed = nullptr;
|
|
|
|
if (p >= 0)
|
|
{
|
|
aimed = aim(actor, 48);
|
|
if (aimed)
|
|
{
|
|
int dal = ((aimed->s.xrepeat * tilesiz[aimed->s.picnum].y) << 1) + (8 << 8);
|
|
zvel = ((aimed->s.z - sz - dal) * vel) / ldist(ps[p].GetActor(), aimed);
|
|
if (aimed->s.picnum != RECON)
|
|
sa = getangle(aimed->s.x - sx, aimed->s.y - sy);
|
|
}
|
|
else zvel = -mulscale16(ps[p].horizon.sum().asq16(), 81);
|
|
if (atwith == RPG)
|
|
S_PlayActorSound(RPG_SHOOT, actor);
|
|
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
int j = findplayer(actor, &x);
|
|
sa = getangle(ps[j].oposx - sx, ps[j].oposy - sy);
|
|
if (s->picnum == BOSS3)
|
|
{
|
|
int zoffs = (32 << 8);
|
|
if (isWorldTour()) // Twentieth Anniversary World Tour
|
|
zoffs = (int)((actor->s.yrepeat / 80.0f) * zoffs);
|
|
sz -= zoffs;
|
|
}
|
|
else if (s->picnum == BOSS2)
|
|
{
|
|
vel += 128;
|
|
int zoffs = 24 << 8;
|
|
if (isWorldTour()) // Twentieth Anniversary World Tour
|
|
zoffs = (int)((actor->s.yrepeat / 80.0f) * zoffs);
|
|
sz += zoffs;
|
|
}
|
|
|
|
l = ldist(ps[j].GetActor(), actor);
|
|
zvel = ((ps[j].oposz - sz) * vel) / l;
|
|
|
|
if (badguy(actor) && (s->hitag & face_player_smart))
|
|
sa = s->ang + (krand() & 31) - 16;
|
|
}
|
|
if (p < 0) aimed = nullptr;
|
|
|
|
auto spawned = EGS(sect,
|
|
sx + (sintable[(348 + sa + 512) & 2047] / 448),
|
|
sy + (sintable[(sa + 348) & 2047] / 448),
|
|
sz - (1 << 8), atwith, 0, 14, 14, sa, vel, zvel, actor, 4);
|
|
|
|
auto spj = &spawned->s;
|
|
spj->extra += (krand() & 7);
|
|
if (atwith != FREEZEBLAST)
|
|
spawned->temp_actor = aimed;
|
|
else
|
|
{
|
|
spj->yvel = numfreezebounces;
|
|
spj->xrepeat >>= 1;
|
|
spj->yrepeat >>= 1;
|
|
spj->zvel -= (2 << 4);
|
|
}
|
|
|
|
if (p == -1)
|
|
{
|
|
if (s->picnum == BOSS3)
|
|
{
|
|
int xoffs = sintable[sa & 2047] >> 6;
|
|
int yoffs = sintable[(sa + 1024 + 512) & 2047] >> 6;
|
|
int aoffs = 4;
|
|
|
|
if ((krand() & 1) != 0)
|
|
{
|
|
xoffs = -xoffs;
|
|
yoffs = -yoffs;
|
|
aoffs = -8;
|
|
}
|
|
|
|
if (isWorldTour()) // Twentieth Anniversary World Tour
|
|
{
|
|
float siz = actor->s.yrepeat / 80.0f;
|
|
xoffs *= siz;
|
|
yoffs *= siz;
|
|
aoffs *= siz;
|
|
}
|
|
|
|
spj->x += xoffs;
|
|
spj->y += yoffs;
|
|
spj->ang += aoffs;
|
|
|
|
spj->xrepeat = 42;
|
|
spj->yrepeat = 42;
|
|
}
|
|
else if (s->picnum == BOSS2)
|
|
{
|
|
int xoffs = sintable[sa & 2047] / 56;
|
|
int yoffs = sintable[(sa + 1024 + 512) & 2047] / 56;
|
|
int aoffs = 8 + (krand() & 255) - 128;
|
|
|
|
if (isWorldTour()) { // Twentieth Anniversary World Tour
|
|
int siz = actor->s.yrepeat;
|
|
xoffs = Scale(xoffs, siz, 80);
|
|
yoffs = Scale(yoffs, siz, 80);
|
|
aoffs = Scale(aoffs, siz, 80);
|
|
}
|
|
|
|
spj->x -= xoffs;
|
|
spj->y -= yoffs;
|
|
spj->ang -= aoffs;
|
|
|
|
spj->x -= sintable[sa & 2047] / 56;
|
|
spj->y -= sintable[(sa + 1024 + 512) & 2047] / 56;
|
|
spj->ang -= 8 + (krand() & 255) - 128;
|
|
spj->xrepeat = 24;
|
|
spj->yrepeat = 24;
|
|
|
|
|
|
}
|
|
else if (atwith != FREEZEBLAST)
|
|
{
|
|
spj->xrepeat = 30;
|
|
spj->yrepeat = 30;
|
|
spj->extra >>= 2;
|
|
}
|
|
}
|
|
else if ((isWW2GI() && aplWeaponWorksLike[ps[p].curr_weapon][p] == DEVISTATOR_WEAPON) || (!isWW2GI() && ps[p].curr_weapon == DEVISTATOR_WEAPON))
|
|
{
|
|
spj->extra >>= 2;
|
|
spj->ang += 16 - (krand() & 31);
|
|
spj->zvel += 256 - (krand() & 511);
|
|
|
|
if (ps[p].hbomb_hold_delay)
|
|
{
|
|
spj->x -= sintable[sa & 2047] / 644;
|
|
spj->y -= sintable[(sa + 1024 + 512) & 2047] / 644;
|
|
}
|
|
else
|
|
{
|
|
spj->x += sintable[sa & 2047] >> 8;
|
|
spj->y += sintable[(sa + 1024 + 512) & 2047] >> 8;
|
|
}
|
|
spj->xrepeat >>= 1;
|
|
spj->yrepeat >>= 1;
|
|
}
|
|
|
|
spj->cstat = 128;
|
|
if (atwith == RPG)
|
|
spj->clipdist = 4;
|
|
else
|
|
spj->clipdist = 40;
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootlaser(DDukeActor* actor, int p, int sx, int sy, int sz, int sa)
|
|
{
|
|
spritetype* const s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int zvel;
|
|
short hitsect, hitwall, j;
|
|
int hitx, hity, hitz;
|
|
DDukeActor* hitsprt;
|
|
|
|
if (p >= 0)
|
|
zvel = -ps[p].horizon.sum().asq16() >> 11;
|
|
else zvel = 0;
|
|
|
|
hitscan(sx, sy, sz - ps[p].pyoff, sect,
|
|
sintable[(sa + 512) & 2047],
|
|
sintable[sa & 2047],
|
|
zvel << 6, &hitsect, &hitwall, &hitsprt, &hitx, &hity, &hitz, CLIPMASK1);
|
|
|
|
j = 0;
|
|
if (hitsprt) return;
|
|
|
|
if (hitwall >= 0 && hitsect >= 0)
|
|
if (((hitx - sx) * (hitx - sx) + (hity - sy) * (hity - sy)) < (290 * 290))
|
|
{
|
|
if (wall[hitwall].nextsector >= 0)
|
|
{
|
|
if (sector[wall[hitwall].nextsector].lotag <= 2 && sector[hitsect].lotag <= 2)
|
|
j = 1;
|
|
}
|
|
else if (sector[hitsect].lotag <= 2)
|
|
j = 1;
|
|
}
|
|
|
|
if (j == 1)
|
|
{
|
|
auto bomb = EGS(hitsect, hitx, hity, hitz, TRIPBOMB, -16, 4, 5, sa, 0, 0, actor, 6);
|
|
if (isWW2GI())
|
|
{
|
|
int lTripBombControl = GetGameVar("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, nullptr, -1);
|
|
if (lTripBombControl & TRIPBOMB_TIMER)
|
|
{
|
|
int lLifetime = GetGameVar("STICKYBOMB_LIFETIME", NAM_GRENADE_LIFETIME, nullptr, p);
|
|
int lLifetimeVar = GetGameVar("STICKYBOMB_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, nullptr, p);
|
|
// set timer. blows up when at zero....
|
|
bomb->s.extra = lLifetime
|
|
+ mulscale(krand(), lLifetimeVar, 14)
|
|
- lLifetimeVar;
|
|
}
|
|
}
|
|
|
|
// this originally used the sprite index as tag to link the laser segments.
|
|
// This value is never used again to reference an actor by index. Decouple this for robustness.
|
|
ud.bomb_tag = (ud.bomb_tag + 1) & 32767;
|
|
bomb->s.hitag = ud.bomb_tag;
|
|
S_PlayActorSound(LASERTRIP_ONWALL, bomb);
|
|
bomb->s.xvel = -20;
|
|
ssp(bomb, CLIPMASK0);
|
|
bomb->s.cstat = 16;
|
|
bomb->temp_data[5] = bomb->s.ang = getangle(wall[hitwall].x - wall[wall[hitwall].point2].x, wall[hitwall].y - wall[wall[hitwall].point2].y) - 512;
|
|
|
|
if (p >= 0)
|
|
ps[p].ammo_amount[TRIPBOMB_WEAPON]--;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void shootgrowspark(DDukeActor* actor, int p, int sx, int sy, int sz, int sa)
|
|
{
|
|
auto s = &actor->s;
|
|
int sect = s->sectnum;
|
|
int zvel;
|
|
short hitsect, hitwall, k;
|
|
int hitx, hity, hitz;
|
|
DDukeActor* hitsprt;
|
|
|
|
if (p >= 0)
|
|
{
|
|
auto aimed = aim(actor, AUTO_AIM_ANGLE);
|
|
if (aimed)
|
|
{
|
|
int dal = ((aimed->s.xrepeat * tilesiz[aimed->s.picnum].y) << 1) + (5 << 8);
|
|
switch (aimed->s.picnum)
|
|
{
|
|
case GREENSLIME:
|
|
case GREENSLIME + 1:
|
|
case GREENSLIME + 2:
|
|
case GREENSLIME + 3:
|
|
case GREENSLIME + 4:
|
|
case GREENSLIME + 5:
|
|
case GREENSLIME + 6:
|
|
case GREENSLIME + 7:
|
|
case ROTATEGUN:
|
|
dal -= (8 << 8);
|
|
break;
|
|
}
|
|
zvel = ((aimed->s.z - sz - dal) << 8) / (ldist(ps[p].GetActor(), aimed));
|
|
sa = getangle(aimed->s.x - sx, aimed->s.y - sy);
|
|
}
|
|
else
|
|
{
|
|
sa += 16 - (krand() & 31);
|
|
zvel = -ps[p].horizon.sum().asq16() >> 11;
|
|
zvel += 128 - (krand() & 255);
|
|
}
|
|
|
|
sz -= (2 << 8);
|
|
}
|
|
else
|
|
{
|
|
int x;
|
|
int j = findplayer(actor, &x);
|
|
sz -= (4 << 8);
|
|
zvel = ((ps[j].posz - sz) << 8) / (ldist(ps[p].GetActor(), actor));
|
|
zvel += 128 - (krand() & 255);
|
|
sa += 32 - (krand() & 63);
|
|
}
|
|
|
|
k = 0;
|
|
|
|
// RESHOOTGROW:
|
|
|
|
s->cstat &= ~257;
|
|
hitscan(sx, sy, sz, sect, sintable[(sa + 512) & 2047], sintable[sa & 2047],
|
|
zvel << 6, &hitsect, &hitwall, &hitsprt, &hitx, &hity, &hitz, CLIPMASK1);
|
|
|
|
s->cstat |= 257;
|
|
|
|
auto spark = EGS(sect, hitx, hity, hitz, GROWSPARK, -16, 28, 28, sa, 0, 0, actor, 1);
|
|
|
|
spark->s.pal = 2;
|
|
spark->s.cstat |= 130;
|
|
spark->s.xrepeat = spark->s.yrepeat = 1;
|
|
|
|
if (hitwall == -1 && hitsprt == nullptr && hitsect >= 0)
|
|
{
|
|
if (zvel < 0 && (sector[hitsect].ceilingstat & 1) == 0)
|
|
fi.checkhitceiling(hitsect);
|
|
}
|
|
else if (hitsprt != nullptr) fi.checkhitsprite(hitsprt, spark);
|
|
else if (hitwall >= 0 && wall[hitwall].picnum != ACCESSSWITCH && wall[hitwall].picnum != ACCESSSWITCH2)
|
|
{
|
|
fi.checkhitwall(spark, hitwall, hitx, hity, hitz, GROWSPARK);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void shoot_d(DDukeActor* actor, int atwith)
|
|
{
|
|
spritetype* const s = &actor->s;
|
|
|
|
short sect, l, j;
|
|
int sx, sy, sz, sa, p, vel, zvel, x, dal;
|
|
if (s->picnum == TILE_APLAYER)
|
|
{
|
|
p = s->yvel;
|
|
}
|
|
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) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
sect = s->sectnum;
|
|
zvel = 0;
|
|
|
|
if (s->picnum == TILE_APLAYER)
|
|
{
|
|
sx = ps[p].posx;
|
|
sy = ps[p].posy;
|
|
sz = ps[p].posz + ps[p].pyoff + (4 << 8);
|
|
sa = ps[p].angle.ang.asbuild();
|
|
|
|
ps[p].crack_time = CRACK_TIME;
|
|
|
|
}
|
|
else
|
|
{
|
|
sa = s->ang;
|
|
sx = s->x;
|
|
sy = s->y;
|
|
sz = s->z - ((s->yrepeat * tilesiz[s->picnum].y) << 1) + (4 << 8);
|
|
if (s->picnum != ROTATEGUN)
|
|
{
|
|
sz -= (7 << 8);
|
|
if (badguy(s) && s->picnum != COMMANDER)
|
|
{
|
|
sx += (sintable[(sa + 1024 + 96) & 2047] >> 7);
|
|
sy += (sintable[(sa + 512 + 96) & 2047] >> 7);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isWorldTour())
|
|
{ // Twentieth Anniversary World Tour
|
|
switch (atwith)
|
|
{
|
|
case FIREBALL:
|
|
shootfireball(actor, p, sx, sy, sz, sa);
|
|
return;
|
|
|
|
case FLAMETHROWERFLAME:
|
|
shootflamethrowerflame(actor, p, sx, sy, sz, sa);
|
|
return;
|
|
|
|
case FIREFLY: // BOSS5 shot
|
|
{
|
|
auto k = spawn(actor, atwith);
|
|
k->s.sectnum = sect;
|
|
k->s.x = sx;
|
|
k->s.y = sy;
|
|
k->s.z = sz;
|
|
k->s.ang = sa;
|
|
k->s.xvel = 500;
|
|
k->s.zvel = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (atwith)
|
|
{
|
|
case BLOODSPLAT1:
|
|
case BLOODSPLAT2:
|
|
case BLOODSPLAT3:
|
|
case BLOODSPLAT4:
|
|
shootbloodsplat(actor, p, sx, sy, sz, sa, atwith, BIGFORCE, OOZFILTER, NEWBEAST);
|
|
break;
|
|
|
|
case KNEE:
|
|
shootknee(actor, p, sx, sy, sz, sa);
|
|
break;
|
|
|
|
case SHOTSPARK1:
|
|
case SHOTGUN:
|
|
case CHAINGUN:
|
|
shootweapon(actor, p, sx, sy, sz, sa, atwith);
|
|
return;
|
|
|
|
case FIRELASER:
|
|
case SPIT:
|
|
case COOLEXPLOSION1:
|
|
shootstuff(actor, p, sx, sy, sz, sa, atwith);
|
|
return;
|
|
|
|
case FREEZEBLAST:
|
|
sz += (3 << 8);
|
|
case RPG:
|
|
|
|
shootrpg(actor, p, sx, sy, sz, sa, atwith);
|
|
break;
|
|
|
|
case HANDHOLDINGLASER:
|
|
shootlaser(actor, p, sx, sy, sz, sa);
|
|
return;
|
|
|
|
case BOUNCEMINE:
|
|
case MORTER:
|
|
{
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
auto j = ps[findplayer(actor, &x)].GetActor();
|
|
x = ldist(j, actor);
|
|
|
|
zvel = -x >> 1;
|
|
|
|
if (zvel < -4096)
|
|
zvel = -2048;
|
|
vel = x >> 4;
|
|
|
|
EGS(sect,
|
|
sx + (sintable[(512 + sa + 512) & 2047] >> 8),
|
|
sy + (sintable[(sa + 512) & 2047] >> 8),
|
|
sz + (6 << 8), atwith, -64, 32, 32, sa, vel, zvel, actor, 1);
|
|
break;
|
|
}
|
|
case GROWSPARK:
|
|
shootgrowspark(actor, p, sx, sy, sz, sa);
|
|
break;
|
|
|
|
case SHRINKER:
|
|
{
|
|
if (s->extra >= 0) s->shade = -96;
|
|
if (p >= 0)
|
|
{
|
|
auto aimed = isNamWW2GI() ? nullptr : aim(actor, AUTO_AIM_ANGLE);
|
|
if (aimed)
|
|
{
|
|
dal = ((aimed->s.xrepeat * tilesiz[aimed->s.picnum].y) << 1);
|
|
zvel = ((aimed->s.z - sz - dal - (4 << 8)) * 768) / (ldist(ps[p].GetActor(), aimed));
|
|
sa = getangle(aimed->s.x - sx, aimed->s.y - sy);
|
|
}
|
|
else zvel = -mulscale16(ps[p].horizon.sum().asq16(), 98);
|
|
}
|
|
else if (s->statnum != 3)
|
|
{
|
|
j = findplayer(actor, &x);
|
|
l = ldist(ps[j].GetActor(), actor);
|
|
zvel = ((ps[j].oposz - sz) * 512) / l;
|
|
}
|
|
else zvel = 0;
|
|
|
|
auto j = EGS(sect,
|
|
sx + (sintable[(512 + sa + 512) & 2047] >> 12),
|
|
sy + (sintable[(sa + 512) & 2047] >> 12),
|
|
sz + (2 << 8), SHRINKSPARK, -16, 28, 28, sa, 768, zvel, actor, 4);
|
|
|
|
j->s.cstat = 128;
|
|
j->s.clipdist = 32;
|
|
|
|
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void selectweapon_d(int snum, int weap) // playernum, weaponnum
|
|
{
|
|
int i, j, k;
|
|
auto p = &ps[snum];
|
|
if (p->last_pissed_time <= (26 * 218) && p->show_empty_weapon == 0 && p->kickback_pic == 0 && p->quick_kick == 0 && p->GetActor()->s.xrepeat > 32 && p->access_incs == 0 && p->knee_incs == 0)
|
|
{
|
|
if ((p->weapon_pos == 0 || (p->holster_weapon && p->weapon_pos == -9)))
|
|
{
|
|
if (weap == WeaponSel_Alt)
|
|
{
|
|
switch (p->curr_weapon)
|
|
{
|
|
case SHRINKER_WEAPON:
|
|
j = isPlutoPak() ? GROW_WEAPON : p->curr_weapon;
|
|
break;
|
|
case GROW_WEAPON:
|
|
j = SHRINKER_WEAPON;
|
|
break;
|
|
case FREEZE_WEAPON:
|
|
j = isWorldTour() ? FLAMETHROWER_WEAPON : p->curr_weapon;
|
|
break;
|
|
case FLAMETHROWER_WEAPON:
|
|
j = FREEZE_WEAPON;
|
|
break;
|
|
default:
|
|
j = p->curr_weapon;
|
|
break;
|
|
}
|
|
}
|
|
else if (weap == WeaponSel_Next || weap == WeaponSel_Prev)
|
|
{
|
|
k = p->curr_weapon;
|
|
j = (weap == WeaponSel_Prev ? -1 : 1); // JBF: prev (-1) or next (1) weapon choice
|
|
i = 0;
|
|
|
|
while ((k >= 0 && k < 10) || (isPlutoPak() && k == GROW_WEAPON && (p->subweapon & (1 << GROW_WEAPON)) != 0)
|
|
|| (isWorldTour() && k == FLAMETHROWER_WEAPON && (p->subweapon & (1 << FLAMETHROWER_WEAPON)) != 0))
|
|
{
|
|
if (k == FLAMETHROWER_WEAPON) //Twentieth Anniversary World Tour
|
|
{
|
|
if (j == -1) k = TRIPBOMB_WEAPON;
|
|
else k = PISTOL_WEAPON;
|
|
}
|
|
else if (k == GROW_WEAPON) // JBF: this is handling next/previous with the grower selected
|
|
{
|
|
if (j == (unsigned int)-1)
|
|
k = 5;
|
|
else k = 7;
|
|
|
|
}
|
|
else
|
|
{
|
|
k += j;
|
|
// JBF 20040116: so we don't select grower with v1.3d
|
|
if (isPlutoPak() && k == SHRINKER_WEAPON && (p->subweapon & (1 << GROW_WEAPON))) // JBF: activates grower
|
|
k = GROW_WEAPON; // if enabled
|
|
if (isWorldTour() && k == FREEZE_WEAPON && (p->subweapon & (1 << FLAMETHROWER_WEAPON)) != 0)
|
|
k = FLAMETHROWER_WEAPON;
|
|
}
|
|
|
|
if (k == -1) k = 9;
|
|
else if (k == 10) k = 0;
|
|
|
|
if (p->gotweapon[k] && p->ammo_amount[k] > 0)
|
|
{
|
|
if (isPlutoPak()) // JBF 20040116: so we don't select grower with v1.3d
|
|
if (k == SHRINKER_WEAPON && (p->subweapon & (1 << GROW_WEAPON)))
|
|
k = GROW_WEAPON;
|
|
if (isWorldTour() && k == FREEZE_WEAPON && (p->subweapon & (1 << FLAMETHROWER_WEAPON)) != 0)
|
|
k = FLAMETHROWER_WEAPON;
|
|
|
|
j = k;
|
|
break;
|
|
}
|
|
else if (isPlutoPak() && k == GROW_WEAPON && p->ammo_amount[GROW_WEAPON] == 0 && p->gotweapon[SHRINKER_WEAPON] && p->ammo_amount[SHRINKER_WEAPON] > 0) // JBF 20040116: added isPlutoPak() so we don't select grower with v1.3d
|
|
{
|
|
j = SHRINKER_WEAPON;
|
|
p->subweapon &= ~(1 << GROW_WEAPON);
|
|
break;
|
|
}
|
|
else if (isPlutoPak() && k == SHRINKER_WEAPON && p->ammo_amount[SHRINKER_WEAPON] == 0 && p->gotweapon[SHRINKER_WEAPON] && p->ammo_amount[GROW_WEAPON] > 0) // JBF 20040116: added isPlutoPak() so we don't select grower with v1.3d
|
|
{
|
|
j = GROW_WEAPON;
|
|
p->subweapon |= (1 << GROW_WEAPON);
|
|
break;
|
|
}
|
|
//Twentieth Anniversary World Tour
|
|
else if (isWorldTour() && k == FLAMETHROWER_WEAPON && p->ammo_amount[FLAMETHROWER_WEAPON] == 0 && p->gotweapon[FREEZE_WEAPON] && p->ammo_amount[FREEZE_WEAPON] > 0)
|
|
{
|
|
j = FREEZE_WEAPON;
|
|
p->subweapon &= ~(1 << FLAMETHROWER_WEAPON);
|
|
break;
|
|
}
|
|
else if (isWorldTour() && k == FREEZE_WEAPON && p->ammo_amount[FREEZE_WEAPON] == 0 && p->gotweapon[FLAMETHROWER_WEAPON] && p->ammo_amount[FLAMETHROWER_WEAPON] > 0)
|
|
{
|
|
j = FLAMETHROWER_WEAPON;
|
|
p->subweapon |= (1 << FLAMETHROWER_WEAPON);
|
|
break;
|
|
}
|
|
|
|
i++; // absolutely no weapons, so use foot
|
|
if (i == 10)
|
|
{
|
|
fi.addweapon(p, KNEE_WEAPON);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else j = weap - 1;
|
|
|
|
k = -1;
|
|
|
|
if (j == HANDBOMB_WEAPON && p->ammo_amount[HANDBOMB_WEAPON] == 0)
|
|
{
|
|
DukeStatIterator it(STAT_ACTOR);
|
|
while (auto act = it.Next())
|
|
{
|
|
if (act->s.picnum == HEAVYHBOMB && act->GetOwner() == p->GetActor())
|
|
{
|
|
p->gotweapon.Set(HANDBOMB_WEAPON);
|
|
j = HANDREMOTE_WEAPON;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Twentieth Anniversary World Tour
|
|
if (j == FREEZE_WEAPON && isWorldTour())
|
|
{
|
|
if (p->curr_weapon != FLAMETHROWER_WEAPON && p->curr_weapon != FREEZE_WEAPON)
|
|
{
|
|
if (p->ammo_amount[FLAMETHROWER_WEAPON] > 0)
|
|
{
|
|
if ((p->subweapon & (1 << FLAMETHROWER_WEAPON)) == (1 << FLAMETHROWER_WEAPON))
|
|
j = FLAMETHROWER_WEAPON;
|
|
else if (p->ammo_amount[FREEZE_WEAPON] == 0)
|
|
{
|
|
j = FLAMETHROWER_WEAPON;
|
|
p->subweapon |= (1 << FLAMETHROWER_WEAPON);
|
|
}
|
|
}
|
|
else if (p->ammo_amount[FREEZE_WEAPON] > 0)
|
|
p->subweapon &= ~(1 << FLAMETHROWER_WEAPON);
|
|
}
|
|
else if (p->curr_weapon == FREEZE_WEAPON)
|
|
{
|
|
p->subweapon |= (1 << FLAMETHROWER_WEAPON);
|
|
j = FLAMETHROWER_WEAPON;
|
|
}
|
|
else
|
|
p->subweapon &= ~(1 << FLAMETHROWER_WEAPON);
|
|
}
|
|
|
|
if (j == SHRINKER_WEAPON && isPlutoPak()) // JBF 20040116: so we don't select the grower with v1.3d
|
|
{
|
|
if (p->curr_weapon != GROW_WEAPON && p->curr_weapon != SHRINKER_WEAPON)
|
|
{
|
|
if (p->ammo_amount[GROW_WEAPON] > 0)
|
|
{
|
|
if ((p->subweapon & (1 << GROW_WEAPON)) == (1 << GROW_WEAPON))
|
|
j = GROW_WEAPON;
|
|
else if (p->ammo_amount[SHRINKER_WEAPON] == 0)
|
|
{
|
|
j = GROW_WEAPON;
|
|
p->subweapon |= (1 << GROW_WEAPON);
|
|
}
|
|
}
|
|
else if (p->ammo_amount[SHRINKER_WEAPON] > 0)
|
|
p->subweapon &= ~(1 << GROW_WEAPON);
|
|
}
|
|
else if (p->curr_weapon == SHRINKER_WEAPON)
|
|
{
|
|
p->subweapon |= (1 << GROW_WEAPON);
|
|
j = GROW_WEAPON;
|
|
}
|
|
else
|
|
p->subweapon &= ~(1 << GROW_WEAPON);
|
|
}
|
|
|
|
if (p->holster_weapon)
|
|
{
|
|
PlayerSetInput(snum, SB_HOLSTER);
|
|
p->oweapon_pos = p->weapon_pos = -9;
|
|
}
|
|
else if (j >= MIN_WEAPON && p->gotweapon[j] && (unsigned int)p->curr_weapon != j) switch (j)
|
|
{
|
|
case KNEE_WEAPON:
|
|
fi.addweapon(p, KNEE_WEAPON);
|
|
break;
|
|
case PISTOL_WEAPON:
|
|
case SHOTGUN_WEAPON:
|
|
case CHAINGUN_WEAPON:
|
|
case RPG_WEAPON:
|
|
case DEVISTATOR_WEAPON:
|
|
case FREEZE_WEAPON:
|
|
case FLAMETHROWER_WEAPON:
|
|
case GROW_WEAPON:
|
|
case SHRINKER_WEAPON:
|
|
|
|
if (p->ammo_amount[j] == 0 && p->show_empty_weapon == 0)
|
|
{
|
|
p->show_empty_weapon = 32;
|
|
p->last_full_weapon = p->curr_weapon;
|
|
}
|
|
|
|
fi.addweapon(p, j);
|
|
break;
|
|
case HANDREMOTE_WEAPON:
|
|
if (k >= 0) // Found in list of [1]'s
|
|
{
|
|
p->curr_weapon = HANDREMOTE_WEAPON;
|
|
p->last_weapon = -1;
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
}
|
|
break;
|
|
case HANDBOMB_WEAPON:
|
|
if (p->ammo_amount[HANDBOMB_WEAPON] > 0 && p->gotweapon[HANDBOMB_WEAPON])
|
|
fi.addweapon(p, HANDBOMB_WEAPON);
|
|
break;
|
|
case TRIPBOMB_WEAPON:
|
|
if (p->ammo_amount[TRIPBOMB_WEAPON] > 0 && p->gotweapon[TRIPBOMB_WEAPON])
|
|
fi.addweapon(p, TRIPBOMB_WEAPON);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int doincrements_d(struct player_struct* p)
|
|
{
|
|
int snum;
|
|
|
|
auto pact = p->GetActor();
|
|
snum = pact->s.yvel;
|
|
|
|
p->player_par++;
|
|
|
|
if (p->invdisptime > 0)
|
|
p->invdisptime--;
|
|
|
|
if (p->tipincs > 0) p->tipincs--;
|
|
|
|
if (p->last_pissed_time > 0)
|
|
{
|
|
p->last_pissed_time--;
|
|
|
|
if (p->last_pissed_time == (26 * 219))
|
|
{
|
|
S_PlayActorSound(FLUSH_TOILET, pact);
|
|
if (snum == screenpeek || ud.coop == 1)
|
|
S_PlayActorSound(DUKE_PISSRELIEF, pact);
|
|
}
|
|
|
|
if (p->last_pissed_time == (26 * 218))
|
|
{
|
|
p->holster_weapon = 0;
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
}
|
|
}
|
|
|
|
if (p->crack_time > 0)
|
|
{
|
|
p->crack_time--;
|
|
if (p->crack_time == 0)
|
|
{
|
|
p->knuckle_incs = 1;
|
|
p->crack_time = CRACK_TIME;
|
|
}
|
|
}
|
|
|
|
if (p->steroids_amount > 0 && p->steroids_amount < 400)
|
|
{
|
|
p->steroids_amount--;
|
|
if (p->steroids_amount == 0)
|
|
checkavailinven(p);
|
|
if (!(p->steroids_amount & 7))
|
|
if (snum == screenpeek || ud.coop == 1)
|
|
S_PlayActorSound(DUKE_HARTBEAT, pact);
|
|
}
|
|
|
|
if (p->heat_on && p->heat_amount > 0)
|
|
{
|
|
p->heat_amount--;
|
|
if (p->heat_amount == 0)
|
|
{
|
|
p->heat_on = 0;
|
|
checkavailinven(p);
|
|
S_PlayActorSound(NITEVISION_ONOFF, pact);
|
|
}
|
|
}
|
|
|
|
if (p->holoduke_on != nullptr)
|
|
{
|
|
p->holoduke_amount--;
|
|
if (p->holoduke_amount <= 0)
|
|
{
|
|
S_PlayActorSound(TELEPORTER, pact);
|
|
p->holoduke_on = nullptr;
|
|
checkavailinven(p);
|
|
}
|
|
}
|
|
|
|
if (p->jetpack_on && p->jetpack_amount > 0)
|
|
{
|
|
p->jetpack_amount--;
|
|
if (p->jetpack_amount <= 0)
|
|
{
|
|
p->jetpack_on = 0;
|
|
checkavailinven(p);
|
|
S_PlayActorSound(DUKE_JETPACK_OFF, pact);
|
|
S_StopSound(DUKE_JETPACK_IDLE, pact);
|
|
S_StopSound(DUKE_JETPACK_ON, pact);
|
|
}
|
|
}
|
|
|
|
if (p->quick_kick > 0 && p->GetActor()->s.pal != 1)
|
|
{
|
|
p->last_quick_kick = p->quick_kick + 1;
|
|
p->quick_kick--;
|
|
if (p->quick_kick == 8)
|
|
fi.shoot(p->GetActor(), KNEE);
|
|
}
|
|
else if (p->last_quick_kick > 0)
|
|
p->last_quick_kick--;
|
|
|
|
if (p->access_incs && p->GetActor()->s.pal != 1)
|
|
{
|
|
p->access_incs++;
|
|
if (p->GetActor()->s.extra <= 0)
|
|
p->access_incs = 12;
|
|
if (p->access_incs == 12)
|
|
{
|
|
if (p->access_spritenum != nullptr)
|
|
{
|
|
fi.checkhitswitch(snum, -1, p->access_spritenum);
|
|
switch (p->access_spritenum->s.pal)
|
|
{
|
|
case 0:p->got_access &= (0xffff - 0x1); break;
|
|
case 21:p->got_access &= (0xffff - 0x2); break;
|
|
case 23:p->got_access &= (0xffff - 0x4); break;
|
|
}
|
|
p->access_spritenum = nullptr;
|
|
}
|
|
else
|
|
{
|
|
fi.checkhitswitch(snum, p->access_wallnum, nullptr);
|
|
switch (wall[p->access_wallnum].pal)
|
|
{
|
|
case 0:p->got_access &= (0xffff - 0x1); break;
|
|
case 21:p->got_access &= (0xffff - 0x2); break;
|
|
case 23:p->got_access &= (0xffff - 0x4); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p->access_incs > 20)
|
|
{
|
|
p->access_incs = 0;
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
}
|
|
|
|
if (p->scuba_on == 0 && sector[p->cursectnum].lotag == 2)
|
|
{
|
|
if (p->scuba_amount > 0)
|
|
{
|
|
p->scuba_on = 1;
|
|
p->inven_icon = 6;
|
|
FTA(76, p);
|
|
}
|
|
else
|
|
{
|
|
if (p->airleft > 0)
|
|
p->airleft--;
|
|
else
|
|
{
|
|
p->extra_extra8 += 32;
|
|
if (p->last_extra < (max_player_health >> 1) && (p->last_extra & 3) == 0)
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, pact);
|
|
}
|
|
}
|
|
}
|
|
else if (p->scuba_amount > 0 && p->scuba_on)
|
|
{
|
|
p->scuba_amount--;
|
|
if (p->scuba_amount == 0)
|
|
{
|
|
p->scuba_on = 0;
|
|
checkavailinven(p);
|
|
}
|
|
}
|
|
|
|
if (p->knuckle_incs)
|
|
{
|
|
p->knuckle_incs++;
|
|
if (p->knuckle_incs == 10 && !isWW2GI())
|
|
{
|
|
if (ud.levelclock > 1024)
|
|
if (snum == screenpeek || ud.coop == 1)
|
|
{
|
|
if (rand() & 1)
|
|
S_PlayActorSound(DUKE_CRACK, pact);
|
|
else S_PlayActorSound(DUKE_CRACK2, pact);
|
|
}
|
|
S_PlayActorSound(DUKE_CRACK_FIRST, pact);
|
|
}
|
|
else if (p->knuckle_incs == 22 || PlayerInput(snum, SB_FIRE))
|
|
p->knuckle_incs = 0;
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void checkweapons_d(struct player_struct* p)
|
|
{
|
|
static const short weapon_sprites[MAX_WEAPONS] = { KNEE, FIRSTGUNSPRITE, SHOTGUNSPRITE,
|
|
CHAINGUNSPRITE, RPGSPRITE, HEAVYHBOMB, SHRINKERSPRITE, DEVISTATORSPRITE,
|
|
TRIPBOMBSPRITE, FREEZESPRITE, HEAVYHBOMB, SHRINKERSPRITE };
|
|
|
|
int cw;
|
|
|
|
if (isWW2GI())
|
|
{
|
|
int snum = p->GetActor()->s.yvel;
|
|
cw = aplWeaponWorksLike[p->curr_weapon][snum];
|
|
}
|
|
else
|
|
cw = p->curr_weapon;
|
|
|
|
|
|
if (cw < 1 || cw >= MAX_WEAPONS) return;
|
|
|
|
if (cw)
|
|
{
|
|
if (krand() & 1)
|
|
spawn(p->GetActor(), weapon_sprites[cw]);
|
|
else switch (cw)
|
|
{
|
|
case RPG_WEAPON:
|
|
case HANDBOMB_WEAPON:
|
|
spawn(p->GetActor(), EXPLOSION2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void operateJetpack(int snum, ESyncBits actions, int psectlotag, int fz, int cz, int shrunk)
|
|
{
|
|
int j;
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
p->on_ground = 0;
|
|
p->jumping_counter = 0;
|
|
p->hard_landing = 0;
|
|
p->falling_counter = 0;
|
|
|
|
p->pycount += 32;
|
|
p->pycount &= 2047;
|
|
p->pyoff = sintable[p->pycount] >> 7;
|
|
|
|
if (p->jetpack_on && S_CheckActorSoundPlaying(pact, DUKE_SCREAM))
|
|
{
|
|
S_StopSound(DUKE_SCREAM, pact);
|
|
}
|
|
|
|
if (p->jetpack_on < 11)
|
|
{
|
|
p->jetpack_on++;
|
|
p->posz -= (p->jetpack_on << 7); //Goin up
|
|
}
|
|
else if (p->jetpack_on == 11 && !S_CheckActorSoundPlaying(pact, DUKE_JETPACK_IDLE))
|
|
S_PlayActorSound(DUKE_JETPACK_IDLE, pact);
|
|
|
|
if (shrunk) j = 512;
|
|
else j = 2048;
|
|
|
|
if (actions & SB_JUMP) //A (soar high)
|
|
{
|
|
// jump
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
|
OnEvent(EVENT_SOARUP, snum, p->GetActor(), -1);
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum) == 0)
|
|
{
|
|
p->posz -= j;
|
|
p->crack_time = CRACK_TIME;
|
|
}
|
|
}
|
|
|
|
if (actions & SB_CROUCH) //Z (soar low)
|
|
{
|
|
// crouch
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
|
OnEvent(EVENT_SOARDOWN, snum, p->GetActor(), -1);
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum) == 0)
|
|
{
|
|
p->posz += j;
|
|
p->crack_time = CRACK_TIME;
|
|
}
|
|
}
|
|
|
|
int k;
|
|
if (shrunk == 0 && (psectlotag == 0 || psectlotag == 2)) k = 32;
|
|
else k = 16;
|
|
|
|
if (psectlotag != 2 && p->scuba_on == 1)
|
|
p->scuba_on = 0;
|
|
|
|
if (p->posz > (fz - (k << 8)))
|
|
p->posz += ((fz - (k << 8)) - p->posz) >> 1;
|
|
if (p->posz < (pact->ceilingz + (18 << 8)))
|
|
p->posz = pact->ceilingz + (18 << 8);
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void movement(int snum, ESyncBits actions, int psect, int fz, int cz, int shrunk, int truefdist, int psectlotag)
|
|
{
|
|
int j;
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
|
|
if (p->airleft != 15 * 26)
|
|
p->airleft = 15 * 26; //Aprox twenty seconds.
|
|
|
|
if (p->scuba_on == 1)
|
|
p->scuba_on = 0;
|
|
|
|
int i = 40;
|
|
if (psectlotag == ST_1_ABOVE_WATER && p->spritebridge == 0)
|
|
{
|
|
if (shrunk == 0)
|
|
{
|
|
i = 34;
|
|
p->pycount += 32;
|
|
p->pycount &= 2047;
|
|
p->pyoff = sintable[p->pycount] >> 6;
|
|
}
|
|
else i = 12;
|
|
|
|
if (shrunk == 0 && truefdist <= PHEIGHT)
|
|
{
|
|
if (p->on_ground == 1)
|
|
{
|
|
if (p->dummyplayersprite == nullptr)
|
|
p->dummyplayersprite = spawn(pact, PLAYERONWATER);
|
|
|
|
p->footprintcount = 6;
|
|
if (sector[p->cursectnum].floorpicnum == FLOORSLIME)
|
|
p->footprintpal = 8;
|
|
else p->footprintpal = 0;
|
|
p->footprintshade = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
footprints(snum);
|
|
}
|
|
|
|
if (p->posz < (fz - (i << 8))) //falling
|
|
{
|
|
|
|
// not jumping or crouching
|
|
if ((actions & (SB_JUMP|SB_CROUCH)) == 0 && p->on_ground && (sector[psect].floorstat & 2) && p->posz >= (fz - (i << 8) - (16 << 8)))
|
|
p->posz = fz - (i << 8);
|
|
else
|
|
{
|
|
p->on_ground = 0;
|
|
p->poszv += (gc + 80); // (TICSPERFRAME<<6);
|
|
if (p->poszv >= (4096 + 2048)) p->poszv = (4096 + 2048);
|
|
if (p->poszv > 2400 && p->falling_counter < 255)
|
|
{
|
|
p->falling_counter++;
|
|
if (p->falling_counter == 38 && !S_CheckActorSoundPlaying(pact, DUKE_SCREAM))
|
|
S_PlayActorSound(DUKE_SCREAM, pact);
|
|
}
|
|
|
|
if ((p->posz + p->poszv) >= (fz - (i << 8))) // hit the ground
|
|
{
|
|
S_StopSound(DUKE_SCREAM, pact);
|
|
if (sector[p->cursectnum].lotag != 1)
|
|
{
|
|
if (p->falling_counter > 62) quickkill(p);
|
|
|
|
else if (p->falling_counter > 9)
|
|
{
|
|
j = p->falling_counter;
|
|
pact->s.extra -= j - (krand() & 3);
|
|
if (pact->s.extra <= 0)
|
|
{
|
|
S_PlayActorSound(SQUISHED, pact);
|
|
SetPlayerPal(p, PalEntry(63, 63, 0, 0));
|
|
}
|
|
else
|
|
{
|
|
S_PlayActorSound(DUKE_LAND, pact);
|
|
S_PlayActorSound(DUKE_LAND_HURT, pact);
|
|
}
|
|
|
|
SetPlayerPal(p, PalEntry(32, 16, 0, 0));
|
|
}
|
|
else if (p->poszv > 2048) S_PlayActorSound(DUKE_LAND, pact);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
p->falling_counter = 0;
|
|
S_StopSound(-1, pact, CHAN_VOICE);
|
|
|
|
if (psectlotag != ST_1_ABOVE_WATER && psectlotag != ST_2_UNDERWATER && p->on_ground == 0 && p->poszv > (6144 >> 1))
|
|
p->hard_landing = p->poszv >> 10;
|
|
|
|
p->on_ground = 1;
|
|
|
|
if (i == 40)
|
|
{
|
|
//Smooth on the ground
|
|
|
|
int k = ((fz - (i << 8)) - p->posz) >> 1;
|
|
if (abs(k) < 256) k = 0;
|
|
p->posz += k;
|
|
p->poszv -= 768;
|
|
if (p->poszv < 0) p->poszv = 0;
|
|
}
|
|
else if (p->jumping_counter == 0)
|
|
{
|
|
p->posz += ((fz - (i << 7)) - p->posz) >> 1; //Smooth on the water
|
|
if (p->on_warping_sector == 0 && p->posz > fz - (16 << 8))
|
|
{
|
|
p->posz = fz - (16 << 8);
|
|
p->poszv >>= 1;
|
|
}
|
|
}
|
|
|
|
p->on_warping_sector = 0;
|
|
|
|
if (actions & SB_CROUCH)
|
|
{
|
|
playerCrouch(snum);
|
|
}
|
|
|
|
// jumping
|
|
if ((actions & SB_JUMP) == 0 && p->jumping_toggle == 1)
|
|
p->jumping_toggle = 0;
|
|
|
|
else if ((actions & SB_JUMP))
|
|
{
|
|
playerJump(snum, fz, cz);
|
|
}
|
|
|
|
if (p->jumping_counter && (actions & SB_JUMP) == 0)
|
|
p->jumping_toggle = 0;
|
|
}
|
|
|
|
if (p->jumping_counter)
|
|
{
|
|
if ((actions & SB_JUMP) == 0 && p->jumping_toggle == 1)
|
|
p->jumping_toggle = 0;
|
|
|
|
if (p->jumping_counter < (1024 + 256))
|
|
{
|
|
if (psectlotag == 1 && p->jumping_counter > 768)
|
|
{
|
|
p->jumping_counter = 0;
|
|
p->poszv = -512;
|
|
}
|
|
else
|
|
{
|
|
p->poszv -= (sintable[(2048 - 128 + p->jumping_counter) & 2047]) / 12;
|
|
p->jumping_counter += 180;
|
|
p->on_ground = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p->jumping_counter = 0;
|
|
p->poszv = 0;
|
|
}
|
|
}
|
|
|
|
p->posz += p->poszv;
|
|
|
|
if (p->posz < (cz + (4 << 8)))
|
|
{
|
|
p->jumping_counter = 0;
|
|
if (p->poszv < 0)
|
|
p->posxv = p->posyv = 0;
|
|
p->poszv = 128;
|
|
p->posz = cz + (4 << 8);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void underwater(int snum, ESyncBits actions, int psect, int fz, int cz)
|
|
{
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
int psectlotag = sector[psect].lotag;
|
|
|
|
// under water
|
|
p->jumping_counter = 0;
|
|
|
|
p->pycount += 32;
|
|
p->pycount &= 2047;
|
|
p->pyoff = sintable[p->pycount] >> 7;
|
|
|
|
if (!S_CheckActorSoundPlaying(pact, DUKE_UNDERWATER))
|
|
S_PlayActorSound(DUKE_UNDERWATER, pact);
|
|
|
|
if (actions & SB_JUMP)
|
|
{
|
|
// jump
|
|
if (p->poszv > 0) p->poszv = 0;
|
|
p->poszv -= 348;
|
|
if (p->poszv < -(256 * 6)) p->poszv = -(256 * 6);
|
|
}
|
|
else if (actions & SB_CROUCH)
|
|
{
|
|
// crouch
|
|
if (p->poszv < 0) p->poszv = 0;
|
|
p->poszv += 348;
|
|
if (p->poszv > (256 * 6)) p->poszv = (256 * 6);
|
|
}
|
|
else
|
|
{
|
|
// normal view
|
|
if (p->poszv < 0)
|
|
{
|
|
p->poszv += 256;
|
|
if (p->poszv > 0)
|
|
p->poszv = 0;
|
|
}
|
|
if (p->poszv > 0)
|
|
{
|
|
p->poszv -= 256;
|
|
if (p->poszv < 0)
|
|
p->poszv = 0;
|
|
}
|
|
}
|
|
|
|
if (p->poszv > 2048)
|
|
p->poszv >>= 1;
|
|
|
|
p->posz += p->poszv;
|
|
|
|
if (p->posz > (fz - (15 << 8)))
|
|
p->posz += ((fz - (15 << 8)) - p->posz) >> 1;
|
|
|
|
if (p->posz < (cz + (4 << 8)))
|
|
{
|
|
p->posz = cz + (4 << 8);
|
|
p->poszv = 0;
|
|
}
|
|
|
|
if (p->scuba_on && (krand() & 255) < 8)
|
|
{
|
|
auto j = spawn(pact, WATERBUBBLE);
|
|
j->s.x +=
|
|
sintable[(p->angle.ang.asbuild() + 512 + 64 - (global_random & 128)) & 2047] >> 6;
|
|
j->s.y +=
|
|
sintable[(p->angle.ang.asbuild() + 64 - (global_random & 128)) & 2047] >> 6;
|
|
j->s.xrepeat = 3;
|
|
j->s.yrepeat = 2;
|
|
j->s.z = p->posz + (8 << 8);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int operateTripbomb(int snum)
|
|
{
|
|
auto p = &ps[snum];
|
|
|
|
int sx, sy, sz;
|
|
short sect, hw;
|
|
DDukeActor* hitsprt;
|
|
|
|
hitscan(p->posx, p->posy, p->posz,
|
|
p->cursectnum, sintable[(p->angle.ang.asbuild() + 512) & 2047],
|
|
sintable[p->angle.ang.asbuild() & 2047], -p->horizon.sum().asq16() >> 11,
|
|
§, &hw, &hitsprt, &sx, &sy, &sz, CLIPMASK1);
|
|
|
|
if (sect < 0 || hitsprt)
|
|
return 0;
|
|
|
|
if (hw >= 0 && sector[sect].lotag > 2)
|
|
return 0;
|
|
|
|
if (hw >= 0 && wall[hw].overpicnum >= 0)
|
|
if (wall[hw].overpicnum == BIGFORCE)
|
|
return 0;
|
|
|
|
DDukeActor* j;
|
|
DukeSectIterator it(sect);
|
|
while (j = it.Next())
|
|
{
|
|
auto sj = &j->s;
|
|
if (sj->picnum == TRIPBOMB &&
|
|
abs(sj->z - sz) < (12 << 8) && ((sj->x - sx) * (sj->x - sx) + (sj->y - sy) * (sj->y - sy)) < (290 * 290))
|
|
return 0;
|
|
}
|
|
|
|
if (j == nullptr && hw >= 0 && (wall[hw].cstat & 16) == 0)
|
|
if ((wall[hw].nextsector >= 0 && sector[wall[hw].nextsector].lotag <= 2) || (wall[hw].nextsector == -1 && sector[sect].lotag <= 2))
|
|
if (((sx - p->posx) * (sx - p->posx) + (sy - p->posy) * (sy - p->posy)) < (290 * 290))
|
|
{
|
|
p->posz = p->oposz;
|
|
p->poszv = 0;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void fireweapon(int snum)
|
|
{
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
|
|
p->crack_time = CRACK_TIME;
|
|
|
|
if (p->holster_weapon == 1)
|
|
{
|
|
if (p->last_pissed_time <= (26 * 218) && p->weapon_pos == -9)
|
|
{
|
|
p->holster_weapon = 0;
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
FTA(74, p);
|
|
}
|
|
}
|
|
else switch (p->curr_weapon)
|
|
{
|
|
case HANDBOMB_WEAPON:
|
|
p->hbomb_hold_delay = 0;
|
|
if (p->ammo_amount[HANDBOMB_WEAPON] > 0)
|
|
p->kickback_pic = 1;
|
|
break;
|
|
case HANDREMOTE_WEAPON:
|
|
p->hbomb_hold_delay = 0;
|
|
p->kickback_pic = 1;
|
|
break;
|
|
|
|
case PISTOL_WEAPON:
|
|
if (p->ammo_amount[PISTOL_WEAPON] > 0)
|
|
{
|
|
p->ammo_amount[PISTOL_WEAPON]--;
|
|
p->kickback_pic = 1;
|
|
}
|
|
break;
|
|
|
|
|
|
case CHAINGUN_WEAPON:
|
|
if (p->ammo_amount[CHAINGUN_WEAPON] > 0) // && p->random_club_frame == 0)
|
|
p->kickback_pic = 1;
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
if (p->ammo_amount[SHOTGUN_WEAPON] > 0 && p->random_club_frame == 0)
|
|
p->kickback_pic = 1;
|
|
break;
|
|
case TRIPBOMB_WEAPON:
|
|
if (p->ammo_amount[TRIPBOMB_WEAPON] > 0)
|
|
{
|
|
if (operateTripbomb(snum))
|
|
p->kickback_pic = 1;
|
|
}
|
|
break;
|
|
|
|
case SHRINKER_WEAPON:
|
|
case GROW_WEAPON:
|
|
if (p->curr_weapon == GROW_WEAPON)
|
|
{
|
|
if (p->ammo_amount[GROW_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
S_PlayActorSound(EXPANDERSHOOT, pact);
|
|
}
|
|
}
|
|
else if (p->ammo_amount[SHRINKER_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
S_PlayActorSound(SHRINKER_FIRE, pact);
|
|
}
|
|
break;
|
|
|
|
case FREEZE_WEAPON:
|
|
if (p->ammo_amount[FREEZE_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
S_PlayActorSound(CAT_FIRE, pact);
|
|
}
|
|
break;
|
|
case DEVISTATOR_WEAPON:
|
|
if (p->ammo_amount[DEVISTATOR_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
p->hbomb_hold_delay = !p->hbomb_hold_delay;
|
|
S_PlayActorSound(CAT_FIRE, pact);
|
|
}
|
|
break;
|
|
|
|
case RPG_WEAPON:
|
|
if (p->ammo_amount[RPG_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
}
|
|
break;
|
|
|
|
case FLAMETHROWER_WEAPON: // Twentieth Anniversary World Tour
|
|
if (isWorldTour() && p->ammo_amount[FLAMETHROWER_WEAPON] > 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
if (sector[p->cursectnum].lotag != 2)
|
|
S_PlayActorSound(FLAMETHROWER_INTRO, pact);
|
|
}
|
|
break;
|
|
|
|
case KNEE_WEAPON:
|
|
if (p->quick_kick == 0)
|
|
{
|
|
p->kickback_pic = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void operateweapon(int snum, ESyncBits actions, int psect)
|
|
{
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
int i, k;
|
|
|
|
// already firing...
|
|
|
|
switch (p->curr_weapon)
|
|
{
|
|
case HANDBOMB_WEAPON: // grenade in NAM
|
|
if (p->kickback_pic == 6 && (actions & SB_FIRE))
|
|
{
|
|
p->rapid_fire_hold = 1;
|
|
break;
|
|
}
|
|
p->kickback_pic++;
|
|
if (p->kickback_pic == 12)
|
|
{
|
|
p->ammo_amount[HANDBOMB_WEAPON]--;
|
|
|
|
if (p->on_ground && (actions & SB_CROUCH))
|
|
{
|
|
k = 15;
|
|
i = mulscale16(p->horizon.sum().asq16(), 20);
|
|
}
|
|
else
|
|
{
|
|
k = 140;
|
|
i = -512 - mulscale16(p->horizon.sum().asq16(), 20);
|
|
}
|
|
|
|
auto spawned = EGS(p->cursectnum,
|
|
p->posx + (sintable[(p->angle.ang.asbuild() + 512) & 2047] >> 6),
|
|
p->posy + (sintable[p->angle.ang.asbuild() & 2047] >> 6),
|
|
p->posz, HEAVYHBOMB, -16, 9, 9,
|
|
p->angle.ang.asbuild(), (k + (p->hbomb_hold_delay << 5)), i, pact, 1);
|
|
|
|
if (isNam())
|
|
{
|
|
spawned->s.extra = mulscale(krand(), NAM_GRENADE_LIFETIME_VAR, 14);
|
|
}
|
|
|
|
if (k == 15)
|
|
{
|
|
spawned->s.yvel = 3;
|
|
spawned->s.z += (8 << 8);
|
|
}
|
|
|
|
k = hits(pact);
|
|
if (k < 512)
|
|
{
|
|
spawned->s.ang += 1024;
|
|
spawned->s.zvel /= 3;
|
|
spawned->s.xvel /= 3;
|
|
}
|
|
|
|
p->hbomb_on = 1;
|
|
|
|
}
|
|
else if (p->kickback_pic < 12 && (actions & SB_FIRE))
|
|
p->hbomb_hold_delay++;
|
|
else if (p->kickback_pic > 19)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
// don't change to remote when in NAM: grenades are timed
|
|
if (isNam()) checkavailweapon(p);
|
|
else
|
|
{
|
|
p->curr_weapon = HANDREMOTE_WEAPON;
|
|
p->last_weapon = -1;
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case HANDREMOTE_WEAPON: // knife in NAM
|
|
|
|
p->kickback_pic++;
|
|
|
|
if (p->kickback_pic == 2)
|
|
{
|
|
p->hbomb_on = 0;
|
|
}
|
|
|
|
if (p->kickback_pic == 10)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
int weapon = isNam() ? TRIPBOMB_WEAPON : HANDBOMB_WEAPON;
|
|
|
|
if (p->ammo_amount[weapon] > 0)
|
|
fi.addweapon(p, weapon);
|
|
else
|
|
checkavailweapon(p);
|
|
}
|
|
break;
|
|
|
|
case PISTOL_WEAPON: // m-16 in NAM
|
|
if (p->kickback_pic == 1)
|
|
{
|
|
fi.shoot(pact, SHOTSPARK1);
|
|
S_PlayActorSound(PISTOL_FIRE, pact);
|
|
lastvisinc = ud.levelclock + 32;
|
|
p->visibility = 0;
|
|
}
|
|
|
|
else if (p->kickback_pic == 2)
|
|
spawn(pact, SHELL);
|
|
|
|
p->kickback_pic++;
|
|
|
|
if (p->kickback_pic >= 5)
|
|
{
|
|
if (p->ammo_amount[PISTOL_WEAPON] <= 0 || (p->ammo_amount[PISTOL_WEAPON] % (isNam() ? 20 : 12)))
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
checkavailweapon(p);
|
|
}
|
|
else
|
|
{
|
|
switch (p->kickback_pic)
|
|
{
|
|
case 5:
|
|
S_PlayActorSound(EJECT_CLIP, pact);
|
|
break;
|
|
//#ifdef NAM
|
|
// case WEAPON2_RELOAD_TIME - 15:
|
|
//#else
|
|
case 8:
|
|
//#endif
|
|
S_PlayActorSound(INSERT_CLIP, pact);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3 second re-load time
|
|
if (p->kickback_pic == (isNam() ? 50 : 27))
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
checkavailweapon(p);
|
|
}
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
|
|
p->kickback_pic++;
|
|
|
|
if (p->kickback_pic == 4)
|
|
{
|
|
for(int i = 0; i < 7; i++)
|
|
fi.shoot(pact, SHOTGUN);
|
|
p->ammo_amount[SHOTGUN_WEAPON]--;
|
|
|
|
S_PlayActorSound(SHOTGUN_FIRE, pact);
|
|
|
|
lastvisinc = ud.levelclock + 32;
|
|
p->visibility = 0;
|
|
|
|
}
|
|
|
|
switch(p->kickback_pic)
|
|
{
|
|
case 13:
|
|
checkavailweapon(p);
|
|
break;
|
|
case 15:
|
|
S_PlayActorSound(SHOTGUN_COCK, pact);
|
|
break;
|
|
case 17:
|
|
case 20:
|
|
p->kickback_pic++;
|
|
break;
|
|
case 24:
|
|
{
|
|
auto j = spawn(pact, SHOTGUNSHELL);
|
|
j->s.ang += 1024;
|
|
ssp(j, CLIPMASK0);
|
|
j->s.ang += 1024;
|
|
p->kickback_pic++;
|
|
break;
|
|
}
|
|
case 31:
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case CHAINGUN_WEAPON: // m-60 in NAM
|
|
|
|
p->kickback_pic++;
|
|
|
|
if (p->kickback_pic <= 12)
|
|
{
|
|
if (((p->kickback_pic) % 3) == 0)
|
|
{
|
|
p->ammo_amount[CHAINGUN_WEAPON]--;
|
|
|
|
if ((p->kickback_pic % 3) == 0)
|
|
{
|
|
auto j = spawn(pact, SHELL);
|
|
|
|
j->s.ang += 1024;
|
|
j->s.ang &= 2047;
|
|
j->s.xvel += 32;
|
|
j->s.z += (3 << 8);
|
|
ssp(j, CLIPMASK0);
|
|
}
|
|
|
|
S_PlayActorSound(CHAINGUN_FIRE, pact);
|
|
fi.shoot(pact, CHAINGUN);
|
|
lastvisinc = ud.levelclock + 32;
|
|
p->visibility = 0;
|
|
checkavailweapon(p);
|
|
|
|
if ((actions & SB_FIRE) == 0)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (p->kickback_pic > 10)
|
|
{
|
|
if (actions & SB_FIRE) p->okickback_pic = p->kickback_pic = 1;
|
|
else p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case GROW_WEAPON: // m-14 with scope (sniper rifle)
|
|
|
|
bool check;
|
|
if (isNam())
|
|
{
|
|
p->kickback_pic++;
|
|
check = (p->kickback_pic == 3);
|
|
}
|
|
else
|
|
{
|
|
check = (p->kickback_pic > 3);
|
|
}
|
|
if (check)
|
|
{
|
|
// fire now, but don't reload right away...
|
|
if (isNam())
|
|
{
|
|
p->kickback_pic++;
|
|
if (p->ammo_amount[p->curr_weapon] <= 1)
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
else
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
fi.shoot(pact, GROWSPARK);
|
|
|
|
//#ifdef NAM
|
|
//#else
|
|
if (!(aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_NOVISIBLE))
|
|
{
|
|
// make them visible if not set...
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
}
|
|
checkavailweapon(p);
|
|
//#endif
|
|
}
|
|
else if (!isNam()) p->kickback_pic++;
|
|
if (isNam() && p->kickback_pic > aplWeaponReload[p->curr_weapon][snum]) // 30)
|
|
{
|
|
// reload now...
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
if (!(aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_NOVISIBLE))
|
|
{
|
|
// make them visible if not set...
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
}
|
|
checkavailweapon(p);
|
|
}
|
|
break;
|
|
|
|
case SHRINKER_WEAPON: // m-79 in NAM (Grenade launcher)
|
|
if ((!isNam() && p->kickback_pic > 10) || (isNam() && p->kickback_pic == 10))
|
|
{
|
|
if (isNam()) p->kickback_pic++; // fire now, but wait for reload...
|
|
else p->okickback_pic = p->kickback_pic = 0;
|
|
|
|
p->ammo_amount[SHRINKER_WEAPON]--;
|
|
fi.shoot(pact, SHRINKER);
|
|
|
|
if (!isNam())
|
|
{
|
|
p->visibility = 0;
|
|
//flashColor = 176 + (252 << 8) + (120 << 16);
|
|
lastvisinc = ud.levelclock + 32;
|
|
checkavailweapon(p);
|
|
}
|
|
}
|
|
else if (isNam() && p->kickback_pic > 30)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
checkavailweapon(p);
|
|
}
|
|
else p->kickback_pic++;
|
|
break;
|
|
|
|
case DEVISTATOR_WEAPON:
|
|
if (p->kickback_pic)
|
|
{
|
|
p->kickback_pic++;
|
|
|
|
if (isNam())
|
|
{
|
|
if ((p->kickback_pic >= 2) &&
|
|
p->kickback_pic < 5 &&
|
|
(p->kickback_pic & 1))
|
|
{
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
fi.shoot(pact, RPG);
|
|
p->ammo_amount[DEVISTATOR_WEAPON]--;
|
|
checkavailweapon(p);
|
|
}
|
|
if (p->kickback_pic > 5) p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
else if (p->kickback_pic & 1)
|
|
{
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
fi.shoot(pact, RPG);
|
|
p->ammo_amount[DEVISTATOR_WEAPON]--;
|
|
checkavailweapon(p);
|
|
if (p->ammo_amount[DEVISTATOR_WEAPON] <= 0) p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
if (p->kickback_pic > 5) p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
break;
|
|
case FREEZE_WEAPON:
|
|
// flame thrower in NAM
|
|
|
|
if (p->kickback_pic < 4)
|
|
{
|
|
p->kickback_pic++;
|
|
if (p->kickback_pic == 3)
|
|
{
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
|
|
p->visibility = 0;
|
|
lastvisinc = ud.levelclock + 32;
|
|
fi.shoot(pact, FREEZEBLAST);
|
|
checkavailweapon(p);
|
|
}
|
|
if (pact->s.xrepeat < 32)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0; break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (actions & SB_FIRE)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 1;
|
|
S_PlayActorSound(CAT_FIRE, pact);
|
|
}
|
|
else p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
break;
|
|
|
|
case FLAMETHROWER_WEAPON:
|
|
if (!isWorldTour()) // Twentieth Anniversary World Tour
|
|
break;
|
|
p->kickback_pic++;
|
|
if (p->kickback_pic == 2)
|
|
{
|
|
if (sector[p->cursectnum].lotag != 2)
|
|
{
|
|
p->ammo_amount[FLAMETHROWER_WEAPON]--;
|
|
if (snum == screenpeek)
|
|
g_visibility = 0;
|
|
fi.shoot(pact, FIREBALL);
|
|
}
|
|
checkavailweapon(p);
|
|
}
|
|
else if (p->kickback_pic == 16)
|
|
{
|
|
if ((actions & SB_FIRE) != 0)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 1;
|
|
S_PlayActorSound(FLAMETHROWER_INTRO, pact);
|
|
}
|
|
else
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
break;
|
|
|
|
case TRIPBOMB_WEAPON: // Claymore in NAM
|
|
if (p->kickback_pic < 4)
|
|
{
|
|
p->posz = p->oposz;
|
|
p->poszv = 0;
|
|
if (p->kickback_pic == 3)
|
|
fi.shoot(pact, HANDHOLDINGLASER);
|
|
}
|
|
if (p->kickback_pic == 16)
|
|
{
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
checkavailweapon(p);
|
|
p->oweapon_pos = p->weapon_pos = -9;
|
|
}
|
|
else p->kickback_pic++;
|
|
break;
|
|
case KNEE_WEAPON:
|
|
p->kickback_pic++;
|
|
|
|
if (p->kickback_pic == 7) fi.shoot(pact, KNEE);
|
|
else if (p->kickback_pic == 14)
|
|
{
|
|
if (actions & SB_FIRE)
|
|
p->okickback_pic = p->kickback_pic = 1 + (krand() & 3);
|
|
else p->okickback_pic = p->kickback_pic = 0;
|
|
}
|
|
|
|
if (p->wantweaponfire >= 0)
|
|
checkavailweapon(p);
|
|
break;
|
|
|
|
case RPG_WEAPON: // m-72 in NAM (LAW)
|
|
p->kickback_pic++;
|
|
if (p->kickback_pic == 4)
|
|
{
|
|
p->ammo_amount[RPG_WEAPON]--;
|
|
lastvisinc = ud.levelclock + 32;
|
|
p->visibility = 0;
|
|
fi.shoot(pact, RPG);
|
|
checkavailweapon(p);
|
|
}
|
|
else if (p->kickback_pic == (cl_dukefixrpgrecoil ? 13 : 20))
|
|
p->okickback_pic = p->kickback_pic = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// this function exists because gotos suck. :P
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void processweapon(int snum, ESyncBits actions, int psect)
|
|
{
|
|
auto p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
auto s = &pact->s;
|
|
int shrunk = (s->yrepeat < 32);
|
|
|
|
// Set maximum for pistol slightly higher if playing with `cl_showmagamount 1`.
|
|
if (!cl_showmagamt)
|
|
{
|
|
if (p->ammo_amount[PISTOL_WEAPON] > PISTOL_MAXDEFAULT)
|
|
p->ammo_amount[PISTOL_WEAPON] = PISTOL_MAXDEFAULT;
|
|
|
|
if (max_ammo_amount[PISTOL_WEAPON] != PISTOL_MAXDEFAULT)
|
|
max_ammo_amount[PISTOL_WEAPON] = PISTOL_MAXDEFAULT;
|
|
}
|
|
else
|
|
{
|
|
short pistolAddition = 4;
|
|
short pistolNewMaximum = PISTOL_MAXDEFAULT + pistolAddition;
|
|
|
|
if (p->ammo_amount[PISTOL_WEAPON] == PISTOL_MAXDEFAULT && max_ammo_amount[PISTOL_WEAPON] == PISTOL_MAXDEFAULT)
|
|
p->ammo_amount[PISTOL_WEAPON] += pistolAddition;
|
|
|
|
if (max_ammo_amount[PISTOL_WEAPON] != pistolNewMaximum)
|
|
max_ammo_amount[PISTOL_WEAPON] = pistolNewMaximum;
|
|
}
|
|
|
|
if (isNamWW2GI() && (actions & SB_HOLSTER)) // 'Holster Weapon
|
|
{
|
|
if (isWW2GI())
|
|
{
|
|
SetGameVarID(g_iReturnVarID, 0, p->GetActor(), snum);
|
|
SetGameVarID(g_iWeaponVarID, p->curr_weapon, p->GetActor(), snum);
|
|
SetGameVarID(g_iWorksLikeVarID, aplWeaponWorksLike[p->curr_weapon][snum], p->GetActor(), snum);
|
|
OnEvent(EVENT_HOLSTER, snum, p->GetActor(), -1);
|
|
if (GetGameVarID(g_iReturnVarID, p->GetActor(), snum) == 0)
|
|
{
|
|
// now it uses the game definitions...
|
|
if (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_HOLSTER_CLEARS_CLIP)
|
|
{
|
|
if (p->ammo_amount[p->curr_weapon] > aplWeaponClip[p->curr_weapon][snum]
|
|
&& (p->ammo_amount[p->curr_weapon] % aplWeaponClip[p->curr_weapon][snum]) != 0)
|
|
{
|
|
// throw away the remaining clip
|
|
p->ammo_amount[p->curr_weapon] -=
|
|
p->ammo_amount[p->curr_weapon] % aplWeaponClip[p->curr_weapon][snum];
|
|
// p->kickback_pic = aplWeaponFireDelay[p->curr_weapon][snum]+1; // animate, but don't shoot...
|
|
p->kickback_pic = aplWeaponTotalTime[p->curr_weapon][snum] + 1; // animate, but don't shoot...
|
|
actions &= ~SB_FIRE; // not firing...
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (p->curr_weapon == PISTOL_WEAPON)
|
|
{
|
|
if (p->ammo_amount[PISTOL_WEAPON] > 20)
|
|
{
|
|
// throw away the remaining clip
|
|
p->ammo_amount[PISTOL_WEAPON] -= p->ammo_amount[PISTOL_WEAPON] % 20;
|
|
p->kickback_pic = 3; // animate, but don't shoot...
|
|
actions &= ~SB_FIRE; // not firing...
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (isWW2GI() && (aplWeaponFlags[p->curr_weapon][snum] & WEAPON_FLAG_GLOWS))
|
|
p->random_club_frame += 64; // Glowing
|
|
|
|
if (!isWW2GI() && (p->curr_weapon == SHRINKER_WEAPON || p->curr_weapon == GROW_WEAPON))
|
|
p->random_club_frame += 64; // Glowing
|
|
|
|
if (p->rapid_fire_hold == 1)
|
|
{
|
|
if (actions & SB_FIRE) return;
|
|
p->rapid_fire_hold = 0;
|
|
}
|
|
|
|
if (shrunk || p->tipincs || p->access_incs)
|
|
actions &= ~SB_FIRE;
|
|
else if (shrunk == 0 && (actions & SB_FIRE) && p->kickback_pic == 0 && p->fist_incs == 0 &&
|
|
p->last_weapon == -1 && (p->weapon_pos == 0 || p->holster_weapon == 1))
|
|
{
|
|
if (!isWW2GI()) fireweapon(snum);
|
|
else fireweapon_ww(snum);
|
|
}
|
|
else if (p->kickback_pic)
|
|
{
|
|
if (!isWW2GI()) operateweapon(snum, actions, psect);
|
|
else operateweapon_ww(snum, actions, psect);
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void processinput_d(int snum)
|
|
{
|
|
int j, k, doubvel, fz, cz, truefdist;
|
|
Collision chz, clz;
|
|
bool shrunk;
|
|
ESyncBits actions;
|
|
short psect, psectlotag;
|
|
struct player_struct* p;
|
|
spritetype* s;
|
|
|
|
p = &ps[snum];
|
|
auto pact = p->GetActor();
|
|
s = &pact->s;
|
|
|
|
p->horizon.resetadjustment();
|
|
p->angle.resetadjustment();
|
|
|
|
actions = PlayerInputBits(snum, SB_ALL);
|
|
|
|
auto sb_fvel = PlayerInputForwardVel(snum);
|
|
auto sb_svel = PlayerInputSideVel(snum);
|
|
auto sb_avel = PlayerInputAngVel(snum);
|
|
|
|
psect = p->cursectnum;
|
|
if (psect == -1)
|
|
{
|
|
if (s->extra > 0 && ud.clipping == 0)
|
|
{
|
|
quickkill(p);
|
|
S_PlayActorSound(SQUISHED, pact);
|
|
}
|
|
psect = 0;
|
|
}
|
|
|
|
psectlotag = sector[psect].lotag;
|
|
p->spritebridge = 0;
|
|
|
|
shrunk = (s->yrepeat < 32);
|
|
getzrange_ex(p->posx, p->posy, p->posz, psect, &cz, chz, &fz, clz, 163L, CLIPMASK0);
|
|
|
|
j = getflorzofslope(psect, p->posx, p->posy);
|
|
|
|
p->truefz = j;
|
|
p->truecz = getceilzofslope(psect, p->posx, p->posy);
|
|
|
|
truefdist = abs(p->posz - j);
|
|
if (clz.type == kHitSector && psectlotag == 1 && truefdist > PHEIGHT + (16 << 8))
|
|
psectlotag = 0;
|
|
|
|
pact->floorz = fz;
|
|
pact->ceilingz = cz;
|
|
|
|
if (cl_syncinput)
|
|
{
|
|
p->horizon.backup();
|
|
calcviewpitch(p, 1);
|
|
}
|
|
|
|
if (chz.type == kHitSprite)
|
|
{
|
|
if (chz.actor->s.statnum == 1 && chz.actor->s.extra >= 0)
|
|
{
|
|
chz.type = kHitNone;
|
|
chz.actor = nullptr;
|
|
cz = p->truecz;
|
|
}
|
|
}
|
|
|
|
if (clz.type == kHitSprite)
|
|
{
|
|
if ((clz.actor->s.cstat & 33) == 33)
|
|
{
|
|
psectlotag = 0;
|
|
p->footprintcount = 0;
|
|
p->spritebridge = 1;
|
|
}
|
|
else if (badguy(clz.actor) && clz.actor->s.xrepeat > 24 && abs(s->z - clz.actor->s.z) < (84 << 8))
|
|
{
|
|
j = getangle(clz.actor->s.x - p->posx, clz.actor->s.y - p->posy);
|
|
p->posxv -= sintable[(j + 512) & 2047] << 4;
|
|
p->posyv -= sintable[j & 2047] << 4;
|
|
}
|
|
}
|
|
|
|
|
|
if (s->extra > 0) fi.incur_damage(p);
|
|
else
|
|
{
|
|
s->extra = 0;
|
|
p->shield_amount = 0;
|
|
}
|
|
|
|
p->last_extra = s->extra;
|
|
|
|
if (p->loogcnt > 0) p->loogcnt--;
|
|
else p->loogcnt = 0;
|
|
|
|
if (p->fist_incs)
|
|
{
|
|
if (endoflevel(snum)) return;
|
|
}
|
|
|
|
if (p->timebeforeexit > 1 && p->last_extra > 0)
|
|
{
|
|
if (timedexit(snum))
|
|
return;
|
|
}
|
|
|
|
if (s->extra <= 0 && !ud.god)
|
|
{
|
|
playerisdead(snum, psectlotag, fz, cz);
|
|
return;
|
|
}
|
|
|
|
if (p->transporter_hold > 0)
|
|
{
|
|
p->transporter_hold--;
|
|
if (p->transporter_hold == 0 && p->on_warping_sector)
|
|
p->transporter_hold = 2;
|
|
}
|
|
if (p->transporter_hold < 0)
|
|
p->transporter_hold++;
|
|
|
|
if (p->newOwner != nullptr)
|
|
{
|
|
p->posxv = p->posyv = s->xvel = 0;
|
|
|
|
fi.doincrements(p);
|
|
|
|
if (isWW2GI() && aplWeaponWorksLike[p->curr_weapon][snum] == HANDREMOTE_WEAPON) processweapon(snum, actions, psect);
|
|
if (!isWW2GI() && p->curr_weapon == HANDREMOTE_WEAPON) processweapon(snum, actions, psect);
|
|
return;
|
|
}
|
|
|
|
doubvel = TICSPERFRAME;
|
|
|
|
checklook(snum,actions);
|
|
int ii = 40;
|
|
|
|
if (p->on_crane != nullptr)
|
|
goto HORIZONLY;
|
|
|
|
playerweaponsway(p, s);
|
|
|
|
s->xvel = clamp(ksqrt((p->posx - p->bobposx) * (p->posx - p->bobposx) + (p->posy - p->bobposy) * (p->posy - p->bobposy)), 0, 512);
|
|
if (p->on_ground) p->bobcounter += p->GetActor()->s.xvel >> 1;
|
|
|
|
backuppos(p, ud.clipping == 0 && (sector[p->cursectnum].floorpicnum == MIRROR || p->cursectnum < 0 || p->cursectnum >= MAXSECTORS));
|
|
|
|
// Shrinking code
|
|
|
|
if (psectlotag == ST_2_UNDERWATER)
|
|
{
|
|
underwater(snum, actions, psect, fz, cz);
|
|
}
|
|
|
|
else if (p->jetpack_on)
|
|
{
|
|
operateJetpack(snum, actions, psectlotag, fz, cz, shrunk);
|
|
}
|
|
else if (psectlotag != ST_2_UNDERWATER)
|
|
{
|
|
movement(snum, actions, psect, fz, cz, shrunk, truefdist, psectlotag);
|
|
}
|
|
|
|
p->psectlotag = psectlotag;
|
|
|
|
//Do the quick lefts and rights
|
|
|
|
if (movementBlocked(snum))
|
|
{
|
|
doubvel = 0;
|
|
p->posxv = 0;
|
|
p->posyv = 0;
|
|
}
|
|
else if (cl_syncinput)
|
|
{
|
|
//p->ang += syncangvel * constant
|
|
//ENGINE calculates angvel for you
|
|
// may still be needed later for demo recording
|
|
|
|
processavel(p, &sb_avel);
|
|
applylook(&p->angle, sb_avel, &p->sync.actions, 1, p->crouch_toggle || actions & SB_CROUCH);
|
|
}
|
|
|
|
if (p->spritebridge == 0)
|
|
{
|
|
j = sector[s->sectnum].floorpicnum;
|
|
|
|
if (j == PURPLELAVA || sector[s->sectnum].ceilingpicnum == PURPLELAVA)
|
|
{
|
|
if (p->boot_amount > 0)
|
|
{
|
|
p->boot_amount--;
|
|
p->inven_icon = 7;
|
|
if (p->boot_amount <= 0)
|
|
checkavailinven(p);
|
|
}
|
|
else
|
|
{
|
|
if (!S_CheckActorSoundPlaying(pact, DUKE_LONGTERM_PAIN))
|
|
S_PlayActorSound(DUKE_LONGTERM_PAIN, pact);
|
|
SetPlayerPal(p, PalEntry(32, 0, 8, 0));
|
|
s->extra--;
|
|
}
|
|
}
|
|
|
|
k = 0;
|
|
|
|
if (p->on_ground && truefdist <= PHEIGHT + (16 << 8))
|
|
{
|
|
int whichsound = j == HURTRAIL ? 0 : j == FLOORSLIME ? 1 : j == FLOORPLASMA ? 2 : -1;
|
|
if (j >= 0) k = makepainsounds(snum, whichsound);
|
|
}
|
|
|
|
if (k)
|
|
{
|
|
FTA(75, p);
|
|
p->boot_amount -= 2;
|
|
if (p->boot_amount <= 0)
|
|
checkavailinven(p);
|
|
}
|
|
}
|
|
|
|
if (p->posxv || p->posyv || sb_fvel || sb_svel)
|
|
{
|
|
p->crack_time = CRACK_TIME;
|
|
|
|
k = sintable[p->bobcounter & 2047] >> 12;
|
|
|
|
if (truefdist < PHEIGHT + (8 << 8) && (k == 1 || k == 3))
|
|
{
|
|
if (p->spritebridge == 0 && p->walking_snd_toggle == 0 && p->on_ground)
|
|
{
|
|
switch (psectlotag)
|
|
{
|
|
case 0:
|
|
|
|
if (clz.type == kHitSprite)
|
|
j = clz.actor->s.picnum;
|
|
else
|
|
j = sector[psect].floorpicnum;
|
|
|
|
switch (j)
|
|
{
|
|
case PANNEL1:
|
|
case PANNEL2:
|
|
S_PlayActorSound(DUKE_WALKINDUCTS, pact);
|
|
p->walking_snd_toggle = 1;
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
if ((krand() & 1) == 0)
|
|
S_PlayActorSound(DUKE_ONWATER, pact);
|
|
p->walking_snd_toggle = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (p->walking_snd_toggle > 0)
|
|
p->walking_snd_toggle--;
|
|
|
|
if (p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400)
|
|
doubvel <<= 1;
|
|
|
|
p->posxv += ((sb_fvel * doubvel) << 6);
|
|
p->posyv += ((sb_svel * doubvel) << 6);
|
|
|
|
bool check;
|
|
|
|
if (!isWW2GI()) check = ((p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && p->on_ground) || (p->on_ground && (actions & SB_CROUCH)));
|
|
else check = ((aplWeaponWorksLike[p->curr_weapon][snum] == KNEE_WEAPON && p->kickback_pic > 10 && p->on_ground) || (p->on_ground && (actions & SB_CROUCH)));
|
|
if (check)
|
|
{
|
|
p->posxv = mulscale(p->posxv, dukefriction - 0x2000, 16);
|
|
p->posyv = mulscale(p->posyv, dukefriction - 0x2000, 16);
|
|
}
|
|
else
|
|
{
|
|
if (psectlotag == 2)
|
|
{
|
|
p->posxv = mulscale(p->posxv, dukefriction - 0x1400, 16);
|
|
p->posyv = mulscale(p->posyv, dukefriction - 0x1400, 16);
|
|
}
|
|
else
|
|
{
|
|
p->posxv = mulscale(p->posxv, dukefriction, 16);
|
|
p->posyv = mulscale(p->posyv, dukefriction, 16);
|
|
}
|
|
}
|
|
|
|
if (abs(p->posxv) < 2048 && abs(p->posyv) < 2048)
|
|
p->posxv = p->posyv = 0;
|
|
|
|
if (shrunk)
|
|
{
|
|
p->posxv =
|
|
mulscale16(p->posxv, dukefriction - (dukefriction >> 1) + (dukefriction >> 2));
|
|
p->posyv =
|
|
mulscale16(p->posyv, dukefriction - (dukefriction >> 1) + (dukefriction >> 2));
|
|
}
|
|
}
|
|
|
|
HORIZONLY:
|
|
|
|
if (psectlotag == 1 || p->spritebridge == 1) ii = (4L << 8);
|
|
else ii = (20L << 8);
|
|
|
|
if (sector[p->cursectnum].lotag == 2) k = 0;
|
|
else k = 1;
|
|
|
|
Collision clip{};
|
|
if (ud.clipping)
|
|
{
|
|
p->posx += p->posxv >> 14;
|
|
p->posy += p->posyv >> 14;
|
|
updatesector(p->posx, p->posy, &p->cursectnum);
|
|
changespritesect(pact, p->cursectnum);
|
|
}
|
|
else
|
|
clipmove_ex(&p->posx, &p->posy,
|
|
&p->posz, &p->cursectnum,
|
|
p->posxv, p->posyv, 164L, (4L << 8), ii, CLIPMASK0, clip);
|
|
|
|
if (p->jetpack_on == 0 && psectlotag != 2 && psectlotag != 1 && shrunk)
|
|
p->posz += 32 << 8;
|
|
|
|
if (clip.type != kHitNone)
|
|
checkplayerhurt_d(p, clip);
|
|
|
|
if (p->jetpack_on == 0)
|
|
{
|
|
if (s->xvel > 16)
|
|
{
|
|
if (psectlotag != 1 && psectlotag != 2 && p->on_ground)
|
|
{
|
|
p->pycount += 52;
|
|
p->pycount &= 2047;
|
|
p->pyoff =
|
|
abs(s->xvel * sintable[p->pycount]) / 1596;
|
|
}
|
|
}
|
|
else if (psectlotag != 2 && psectlotag != 1)
|
|
p->pyoff = 0;
|
|
}
|
|
|
|
// RBG***
|
|
setsprite(pact, p->posx, p->posy, p->posz + PHEIGHT);
|
|
|
|
if (psectlotag < 3)
|
|
{
|
|
psect = s->sectnum;
|
|
if (ud.clipping == 0 && sector[psect].lotag == 31)
|
|
{
|
|
auto secact = ScriptIndexToActor(sector[psect].hitag);
|
|
if (secact && secact->s.xvel && secact->temp_data[0] == 0)
|
|
{
|
|
quickkill(p);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (truefdist < PHEIGHT && p->on_ground && psectlotag != 1 && shrunk == 0 && sector[p->cursectnum].lotag == 1)
|
|
if (!S_CheckActorSoundPlaying(pact, DUKE_ONWATER))
|
|
S_PlayActorSound(DUKE_ONWATER, pact);
|
|
|
|
if (p->cursectnum != s->sectnum)
|
|
changespritesect(pact, p->cursectnum);
|
|
|
|
if (ud.clipping == 0)
|
|
j = (pushmove(&p->posx, &p->posy, &p->posz, &p->cursectnum, 164L, (4L << 8), (4L << 8), CLIPMASK0) < 0 && furthestangle(p->GetActor(), 8) < 512);
|
|
else j = 0;
|
|
|
|
if (ud.clipping == 0)
|
|
{
|
|
if (abs(pact->floorz - pact->ceilingz) < (48 << 8) || j)
|
|
{
|
|
if (!(sector[s->sectnum].lotag & 0x8000) && (isanunderoperator(sector[s->sectnum].lotag) ||
|
|
isanearoperator(sector[s->sectnum].lotag)))
|
|
fi.activatebysector(s->sectnum, pact);
|
|
if (j)
|
|
{
|
|
quickkill(p);
|
|
return;
|
|
}
|
|
}
|
|
else if (abs(fz - cz) < (32 << 8) && isanunderoperator(sector[psect].lotag))
|
|
fi.activatebysector(psect, pact);
|
|
}
|
|
|
|
// center_view
|
|
if (actions & SB_CENTERVIEW || p->hard_landing)
|
|
{
|
|
playerCenterView(snum);
|
|
}
|
|
else if (actions & SB_LOOK_UP)
|
|
{
|
|
playerLookUp(snum, actions);
|
|
}
|
|
else if (actions & SB_LOOK_DOWN)
|
|
{
|
|
playerLookDown(snum, actions);
|
|
}
|
|
else if (actions & SB_AIM_UP)
|
|
{
|
|
playerAimUp(snum, actions);
|
|
}
|
|
else if (actions & SB_AIM_DOWN)
|
|
{ // aim_down
|
|
playerAimDown(snum, actions);
|
|
}
|
|
|
|
if (cl_syncinput)
|
|
{
|
|
sethorizon(&p->horizon.horiz, PlayerHorizon(snum), &p->sync.actions, 1);
|
|
}
|
|
|
|
checkhardlanding(p);
|
|
|
|
//Shooting code/changes
|
|
|
|
if (p->show_empty_weapon > 0)
|
|
{
|
|
p->show_empty_weapon--;
|
|
if (p->show_empty_weapon == 0)
|
|
{
|
|
if (p->last_full_weapon == GROW_WEAPON)
|
|
p->subweapon |= (1 << GROW_WEAPON);
|
|
else if (p->last_full_weapon == SHRINKER_WEAPON)
|
|
p->subweapon &= ~(1 << GROW_WEAPON);
|
|
fi.addweapon(p, p->last_full_weapon);
|
|
return;
|
|
}
|
|
}
|
|
|
|
dokneeattack(snum, { FEM1, FEM2, FEM3, FEM4, FEM5, FEM6, FEM7, FEM8, FEM9, FEM10, PODFEM1, NAKED1, STATUE });
|
|
|
|
if (fi.doincrements(p)) return;
|
|
|
|
if (p->weapon_pos != 0)
|
|
{
|
|
if (p->weapon_pos == -9)
|
|
{
|
|
if (p->last_weapon >= 0)
|
|
{
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
// if(p->curr_weapon == KNEE_WEAPON) p->kickback_pic = 1;
|
|
p->last_weapon = -1;
|
|
}
|
|
else if (p->holster_weapon == 0)
|
|
p->oweapon_pos = p->weapon_pos = 10;
|
|
}
|
|
else p->weapon_pos--;
|
|
}
|
|
|
|
// HACKS
|
|
processweapon(snum, actions, psect);
|
|
}
|
|
|
|
void processmove_d(int snum, ESyncBits actions, int psect, int fz, int cz, int shrunk, int truefdist)
|
|
{
|
|
int psectlotag = sector[psect].lotag;
|
|
auto p = &ps[snum];
|
|
if (psectlotag == 2)
|
|
{
|
|
underwater(snum, actions, psect, fz, cz);
|
|
}
|
|
|
|
else if (p->jetpack_on)
|
|
{
|
|
operateJetpack(snum, actions, psectlotag, fz, cz, shrunk);
|
|
}
|
|
else if (psectlotag != 2)
|
|
{
|
|
movement(snum, actions, psect, fz, cz, shrunk, truefdist, psectlotag);
|
|
}
|
|
}
|
|
END_DUKE_NS
|