mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 11:10:47 +00:00
b3639ae8e7
I have commented out the versions of these functions that perform bitmasks and shifts and replaced them with versions that cast to and from integral types, pending performance and compatibility research across platforms. git-svn-id: https://svn.eduke32.com/eduke32@5174 1a8010ca-5511-0410-912e-c29ae57300e0
5309 lines
169 KiB
C
5309 lines
169 KiB
C
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010 EDuke32 developers and contributors
|
|
|
|
This file is part of EDuke32.
|
|
|
|
EDuke32 is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
|
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "duke3d.h"
|
|
#include "common_game.h"
|
|
#include "osd.h"
|
|
#include "player.h"
|
|
#include "demo.h"
|
|
#include "enet/enet.h"
|
|
|
|
#ifdef __ANDROID__
|
|
#include "android.h"
|
|
#endif
|
|
|
|
int32_t lastvisinc;
|
|
hudweapon_t hudweap;
|
|
|
|
#ifdef SPLITSCREEN_MOD_HACKS
|
|
static int32_t g_snum;
|
|
#endif
|
|
|
|
extern int32_t g_levelTextTime, ticrandomseed;
|
|
|
|
int32_t g_numObituaries = 0;
|
|
int32_t g_numSelfObituaries = 0;
|
|
|
|
void P_UpdateScreenPal(DukePlayer_t *p)
|
|
{
|
|
int32_t intowater = 0;
|
|
const int32_t sect = p->cursectnum;
|
|
|
|
if (p->heat_on) p->palette = SLIMEPAL;
|
|
else if (sect < 0) p->palette = BASEPAL;
|
|
else if (sector[sect].ceilingpicnum >= FLOORSLIME && sector[sect].ceilingpicnum <= FLOORSLIME+2)
|
|
{
|
|
p->palette = SLIMEPAL;
|
|
intowater = 1;
|
|
}
|
|
else
|
|
{
|
|
if (sector[p->cursectnum].lotag == ST_2_UNDERWATER) p->palette = WATERPAL;
|
|
else p->palette = BASEPAL;
|
|
intowater = 1;
|
|
}
|
|
|
|
g_restorePalette = 1+intowater;
|
|
}
|
|
|
|
static void P_IncurDamage(DukePlayer_t *p)
|
|
{
|
|
int32_t damage;
|
|
|
|
if (VM_OnEvent(EVENT_INCURDAMAGE, p->i, P_Get(p->i)) != 0)
|
|
return;
|
|
|
|
sprite[p->i].extra -= p->extra_extra8>>8;
|
|
|
|
damage = sprite[p->i].extra - p->last_extra;
|
|
|
|
if (damage >= 0)
|
|
return;
|
|
|
|
p->extra_extra8 = 0;
|
|
|
|
if (p->inv_amount[GET_SHIELD] > 0)
|
|
{
|
|
int32_t shield_damage = damage * (20 + (krand()%30)) / 100;
|
|
damage -= shield_damage;
|
|
|
|
p->inv_amount[GET_SHIELD] += shield_damage;
|
|
|
|
if (p->inv_amount[GET_SHIELD] < 0)
|
|
{
|
|
damage += p->inv_amount[GET_SHIELD];
|
|
p->inv_amount[GET_SHIELD] = 0;
|
|
}
|
|
}
|
|
|
|
sprite[p->i].extra = p->last_extra + damage;
|
|
}
|
|
|
|
void P_QuickKill(DukePlayer_t *p)
|
|
{
|
|
P_PalFrom(p, 48, 48,48,48);
|
|
|
|
sprite[p->i].extra = 0;
|
|
sprite[p->i].cstat |= 32768;
|
|
|
|
if (ud.god == 0)
|
|
A_DoGuts(p->i,JIBS6,8);
|
|
}
|
|
|
|
static void A_DoWaterTracers(int32_t x1,int32_t y1,int32_t z1,int32_t x2,int32_t y2,int32_t z2,int32_t n)
|
|
{
|
|
int32_t i, xv, yv, zv;
|
|
int16_t sect = -1;
|
|
|
|
i = n+1;
|
|
xv = tabledivide32_noinline(x2-x1, i);
|
|
yv = tabledivide32_noinline(y2-y1, i);
|
|
zv = tabledivide32_noinline(z2-z1, i);
|
|
|
|
if ((klabs(x1-x2)+klabs(y1-y2)) < 3084)
|
|
return;
|
|
|
|
for (i=n; i>0; i--)
|
|
{
|
|
x1 += xv;
|
|
y1 += yv;
|
|
z1 += zv;
|
|
updatesector(x1,y1,§);
|
|
if (sect < 0)
|
|
break;
|
|
|
|
if (sector[sect].lotag == ST_2_UNDERWATER)
|
|
A_InsertSprite(sect,x1,y1,z1,WATERBUBBLE,-32,4+(krand()&3),4+(krand()&3),krand()&2047,0,0,g_player[0].ps->i,5);
|
|
else
|
|
A_InsertSprite(sect,x1,y1,z1,SMALLSMOKE,-32,14,14,0,0,0,g_player[0].ps->i,5);
|
|
}
|
|
}
|
|
|
|
static inline projectile_t * Proj_GetProjectile(int tile)
|
|
{
|
|
return ((unsigned)tile < MAXTILES && g_tile[tile].proj) ? g_tile[tile].proj : &DefaultProjectile;
|
|
}
|
|
|
|
static void A_HitscanProjTrail(const vec3_t *sv, const vec3_t *dv, int32_t ang, int32_t atwith)
|
|
{
|
|
int32_t n, j, i;
|
|
int16_t sect = -1;
|
|
vec3_t srcvect;
|
|
vec3_t destvect;
|
|
|
|
const projectile_t *const proj = Proj_GetProjectile(atwith);
|
|
|
|
Bmemcpy(&destvect, dv, sizeof(vec3_t));
|
|
|
|
srcvect.x = sv->x + tabledivide32_noinline(sintable[(348+ang+512)&2047], proj->offset);
|
|
srcvect.y = sv->y + tabledivide32_noinline(sintable[(ang+348)&2047], proj->offset);
|
|
srcvect.z = sv->z + 1024+(proj->toffset<<8);
|
|
|
|
n = ((FindDistance2D(srcvect.x-destvect.x,srcvect.y-destvect.y))>>8)+1;
|
|
|
|
destvect.x = tabledivide32_noinline((destvect.x-srcvect.x), n);
|
|
destvect.y = tabledivide32_noinline((destvect.y-srcvect.y), n);
|
|
destvect.z = tabledivide32_noinline((destvect.z-srcvect.z), n);
|
|
|
|
srcvect.x += destvect.x>>2;
|
|
srcvect.y += destvect.y>>2;
|
|
srcvect.z += (destvect.z>>2);
|
|
|
|
for (i=proj->tnum; i>0; i--)
|
|
{
|
|
srcvect.x += destvect.x;
|
|
srcvect.y += destvect.y;
|
|
srcvect.z += destvect.z;
|
|
updatesector(srcvect.x,srcvect.y,§);
|
|
if (sect < 0)
|
|
break;
|
|
getzsofslope(sect,srcvect.x,srcvect.y,&n,&j);
|
|
if (srcvect.z > j || srcvect.z < n)
|
|
break;
|
|
j = A_InsertSprite(sect,srcvect.x,srcvect.y,srcvect.z,proj->trail,-32,
|
|
proj->txrepeat,proj->tyrepeat,ang,0,0,g_player[0].ps->i,0);
|
|
changespritestat(j, STAT_ACTOR);
|
|
}
|
|
}
|
|
|
|
int32_t A_GetHitscanRange(int32_t i)
|
|
{
|
|
int32_t zoff = (PN == APLAYER) ? PHEIGHT : 0;
|
|
hitdata_t hit;
|
|
|
|
SZ -= zoff;
|
|
hitscan((const vec3_t *)&sprite[i],SECT,
|
|
sintable[(SA+512)&2047],
|
|
sintable[SA&2047],
|
|
0,&hit,CLIPMASK1);
|
|
SZ += zoff;
|
|
|
|
return (FindDistance2D(hit.pos.x-SX,hit.pos.y-SY));
|
|
}
|
|
|
|
static int32_t A_FindTargetSprite(const spritetype *s, int32_t aang, int32_t atwith)
|
|
{
|
|
int32_t gotshrinker,gotfreezer;
|
|
int32_t i, j, a, k, cans;
|
|
static const int32_t aimstats[] = {
|
|
STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR
|
|
};
|
|
int32_t dx1, dy1, dx2, dy2, dx3, dy3, smax, sdist;
|
|
int32_t xv, yv;
|
|
|
|
const int32_t snum = s->picnum == APLAYER ? P_GetP(s) : -1;
|
|
|
|
if (s->picnum == APLAYER)
|
|
{
|
|
if (!g_player[snum].ps->auto_aim)
|
|
return -1;
|
|
|
|
if (g_player[snum].ps->auto_aim == 2)
|
|
{
|
|
if (A_CheckSpriteTileFlags(atwith,SFLAG_PROJECTILE) && (Proj_GetProjectile(atwith)->workslike & PROJECTILE_RPG))
|
|
return -1;
|
|
|
|
switch (DYNAMICTILEMAP(atwith))
|
|
{
|
|
case TONGUE__STATIC:
|
|
case FREEZEBLAST__STATIC:
|
|
case SHRINKSPARK__STATIC:
|
|
case SHRINKER__STATIC:
|
|
case RPG__STATIC:
|
|
case FIRELASER__STATIC:
|
|
case SPIT__STATIC:
|
|
case COOLEXPLOSION1__STATIC:
|
|
return -1;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
a = s->ang;
|
|
|
|
j = -1;
|
|
|
|
gotshrinker = (s->picnum == APLAYER && PWEAPON(snum, g_player[snum].ps->curr_weapon, WorksLike) == SHRINKER_WEAPON);
|
|
gotfreezer = (s->picnum == APLAYER && PWEAPON(snum, g_player[snum].ps->curr_weapon, WorksLike) == FREEZE_WEAPON);
|
|
|
|
smax = INT32_MAX;
|
|
|
|
dx1 = sintable[(a+512-aang)&2047];
|
|
dy1 = sintable[(a-aang)&2047];
|
|
dx2 = sintable[(a+512+aang)&2047];
|
|
dy2 = sintable[(a+aang)&2047];
|
|
|
|
dx3 = sintable[(a+512)&2047];
|
|
dy3 = sintable[a&2047];
|
|
|
|
for (k=0; k<4; k++)
|
|
{
|
|
if (j >= 0)
|
|
break;
|
|
for (i=headspritestat[aimstats[k]]; i >= 0; i=nextspritestat[i])
|
|
if (sprite[i].xrepeat > 0 && sprite[i].extra >= 0 && (sprite[i].cstat&(257+32768)) == 257)
|
|
if (A_CheckEnemySprite(&sprite[i]) || k < 2)
|
|
{
|
|
if (A_CheckEnemySprite(&sprite[i]) || PN == APLAYER || PN == SHARK)
|
|
{
|
|
if (PN == APLAYER && s->picnum == APLAYER && s != &sprite[i] &&
|
|
// ud.ffire == 0 &&
|
|
(GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) || (GTFLAGS(GAMETYPE_TDM) &&
|
|
g_player[P_Get(i)].ps->team == g_player[snum].ps->team)))
|
|
continue;
|
|
|
|
if (gotshrinker && sprite[i].xrepeat < 30)
|
|
{
|
|
if (PN == SHARK)
|
|
{
|
|
if (sprite[i].xrepeat < 20) continue;
|
|
continue;
|
|
}
|
|
else if (!(PN >= GREENSLIME && PN <= GREENSLIME+7))
|
|
continue;
|
|
}
|
|
if (gotfreezer && sprite[i].pal == 1) continue;
|
|
}
|
|
|
|
xv = (SX-s->x);
|
|
yv = (SY-s->y);
|
|
|
|
if ((dy1*xv <= dx1*yv) && (dy2*xv >= dx2*yv))
|
|
{
|
|
sdist = mulscale(dx3,xv,14) + mulscale(dy3,yv,14);
|
|
|
|
if (sdist > 512 && sdist < smax)
|
|
{
|
|
if (s->picnum == APLAYER)
|
|
{
|
|
const DukePlayer_t *const ps = g_player[P_GetP(s)].ps;
|
|
a = (klabs(scale(SZ-s->z,10,sdist)-(ps->horiz+ps->horizoff-100)) < 100);
|
|
}
|
|
else a = 1;
|
|
|
|
if (PN == ORGANTIC || PN == ROTATEGUN)
|
|
cans = cansee(SX,SY,SZ,SECT,s->x,s->y,s->z-(32<<8),s->sectnum);
|
|
else cans = cansee(SX,SY,SZ-(32<<8),SECT,s->x,s->y,s->z-(32<<8),s->sectnum);
|
|
|
|
if (a && cans)
|
|
{
|
|
smax = sdist;
|
|
j = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
static void A_SetHitData(int32_t i, const hitdata_t *hit)
|
|
{
|
|
actor[i].t_data[6] = hit->wall;
|
|
actor[i].t_data[7] = hit->sect;
|
|
actor[i].t_data[8] = hit->sprite;
|
|
}
|
|
|
|
static int32_t CheckShootSwitchTile(int32_t pn)
|
|
{
|
|
return pn == DIPSWITCH || pn == DIPSWITCH+1 ||
|
|
pn == DIPSWITCH2 || pn == DIPSWITCH2+1 ||
|
|
pn == DIPSWITCH3 || pn == DIPSWITCH3+1 ||
|
|
pn == HANDSWITCH || pn == HANDSWITCH+1;
|
|
}
|
|
|
|
static int32_t safeldist(int32_t spritenum1, const spritetype *s2)
|
|
{
|
|
int32_t dst = ldist(&sprite[spritenum1], s2);
|
|
return dst ? dst : 1;
|
|
}
|
|
|
|
// flags:
|
|
// 1: do sprite center adjustment (cen-=(8<<8)) for GREENSLIME or ROTATEGUN
|
|
// 2: do auto getangle only if not RECON (if clear, do unconditionally)
|
|
static int32_t GetAutoAimAngle(int32_t i, int32_t p, int32_t atwith,
|
|
int32_t cen_add, int32_t flags,
|
|
const vec3_t *srcvect, int32_t vel,
|
|
int32_t *zvel, int16_t *sa)
|
|
{
|
|
int32_t j = -1;
|
|
|
|
Bassert((unsigned)p < MAXPLAYERS);
|
|
|
|
#ifdef LUNATIC
|
|
g_player[p].ps->autoaimang = g_player[p].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE;
|
|
#else
|
|
Gv_SetVar(g_iAimAngleVarID, g_player[p].ps->auto_aim == 3 ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE, i, p);
|
|
#endif
|
|
|
|
VM_OnEvent(EVENT_GETAUTOAIMANGLE, i, p);
|
|
|
|
{
|
|
#ifdef LUNATIC
|
|
int32_t aimang = g_player[p].ps->autoaimang;
|
|
#else
|
|
int32_t aimang = Gv_GetVar(g_iAimAngleVarID, i, p);
|
|
#endif
|
|
if (aimang > 0)
|
|
j = A_FindTargetSprite(&sprite[i], aimang, atwith);
|
|
}
|
|
|
|
if (j >= 0)
|
|
{
|
|
const spritetype *const spr = &sprite[j];
|
|
int32_t cen = 2*(spr->yrepeat*tilesiz[spr->picnum].y) + cen_add;
|
|
int32_t dst;
|
|
|
|
if (flags)
|
|
{
|
|
int32_t pn = spr->picnum;
|
|
if ((pn >= GREENSLIME && pn <= GREENSLIME+7) || spr->picnum==ROTATEGUN)
|
|
{
|
|
cen -= (8<<8);
|
|
}
|
|
}
|
|
|
|
dst = safeldist(g_player[p].ps->i, &sprite[j]);
|
|
*zvel = tabledivide32_noinline((spr->z - srcvect->z - cen)*vel, dst);
|
|
|
|
if (!(flags&2) || sprite[j].picnum != RECON)
|
|
*sa = getangle(spr->x-srcvect->x, spr->y-srcvect->y);
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
static void Proj_MaybeSpawn(int32_t k, int32_t atwith, const hitdata_t *hit)
|
|
{
|
|
// atwith < 0 is for hard-coded projectiles
|
|
projectile_t * const proj = Proj_GetProjectile(atwith);
|
|
int32_t spawntile = atwith < 0 ? -atwith : proj->spawns;
|
|
|
|
if (spawntile >= 0)
|
|
{
|
|
int32_t wh = A_Spawn(k, spawntile);
|
|
|
|
if (atwith >= 0)
|
|
{
|
|
if (proj->sxrepeat > 4)
|
|
sprite[wh].xrepeat = proj->sxrepeat;
|
|
if (proj->syrepeat > 4)
|
|
sprite[wh].yrepeat = proj->syrepeat;
|
|
}
|
|
|
|
A_SetHitData(wh, hit);
|
|
}
|
|
}
|
|
|
|
// <extra>: damage that this shotspark does
|
|
static int32_t Proj_InsertShotspark(const hitdata_t *hit, int32_t i, int32_t atwith,
|
|
int32_t xyrepeat, int32_t ang, int32_t extra)
|
|
{
|
|
int32_t k = A_InsertSprite(hit->sect, hit->pos.x, hit->pos.y, hit->pos.z,
|
|
SHOTSPARK1,-15, xyrepeat,xyrepeat, ang,0,0,i,4);
|
|
sprite[k].extra = extra;
|
|
// This is a hack to allow you to detect which weapon spawned a SHOTSPARK1:
|
|
sprite[k].yvel = atwith;
|
|
A_SetHitData(k, hit);
|
|
|
|
return k;
|
|
}
|
|
|
|
static int32_t Proj_GetExtra(int32_t atwith)
|
|
{
|
|
projectile_t * const proj = Proj_GetProjectile(atwith);
|
|
int32_t extra = proj->extra;
|
|
if (proj->extra_rand > 0)
|
|
extra += (krand() % proj->extra_rand);
|
|
return extra;
|
|
}
|
|
|
|
static void Proj_MaybeAddSpread(int32_t not_accurate_p, int32_t *zvel, int16_t *sa,
|
|
int32_t zRange, int32_t angRange)
|
|
{
|
|
if (not_accurate_p)
|
|
{
|
|
// Ranges <= 1 mean no spread at all. A range of 1 calls krand() though.
|
|
if (zRange > 0)
|
|
*zvel += zRange/2 - krand()%zRange;
|
|
if (angRange > 0)
|
|
*sa += angRange/2 - krand()%angRange;
|
|
}
|
|
}
|
|
|
|
|
|
static int32_t g_overrideShootZvel = 0; // a boolean
|
|
static int32_t g_shootZvel; // the actual zvel if the above is !=0
|
|
|
|
static int32_t A_GetShootZvel(int32_t defaultzvel)
|
|
{
|
|
return g_overrideShootZvel ? g_shootZvel : defaultzvel;
|
|
}
|
|
|
|
// Prepare hitscan weapon fired from player p.
|
|
static void P_PreFireHitscan(int32_t i, int32_t p, int32_t atwith,
|
|
vec3_t *srcvect, int32_t *zvel, int16_t *sa,
|
|
int32_t accurate_autoaim_p,
|
|
int32_t not_accurate_p)
|
|
{
|
|
int32_t angRange=32;
|
|
int32_t zRange=256;
|
|
|
|
int32_t j = GetAutoAimAngle(i, p, atwith, 5<<8, 0+1, srcvect, 256, zvel, sa);
|
|
DukePlayer_t *const ps = g_player[p].ps;
|
|
|
|
#ifdef LUNATIC
|
|
ps->angrange = angRange;
|
|
ps->zrange = zRange;
|
|
#else
|
|
Gv_SetVar(g_iAngRangeVarID,angRange, i,p);
|
|
Gv_SetVar(g_iZRangeVarID,zRange,i,p);
|
|
#endif
|
|
|
|
VM_OnEvent(EVENT_GETSHOTRANGE, i, p);
|
|
|
|
#ifdef LUNATIC
|
|
angRange = ps->angrange;
|
|
zRange = ps->zrange;
|
|
#else
|
|
angRange=Gv_GetVar(g_iAngRangeVarID,i,p);
|
|
zRange=Gv_GetVar(g_iZRangeVarID,i,p);
|
|
#endif
|
|
|
|
if (accurate_autoaim_p)
|
|
{
|
|
if (!ps->auto_aim)
|
|
{
|
|
hitdata_t hit;
|
|
|
|
*zvel = A_GetShootZvel((100-ps->horiz-ps->horizoff)<<5);
|
|
|
|
hitscan(srcvect, sprite[i].sectnum, sintable[(*sa+512)&2047], sintable[*sa&2047],
|
|
*zvel<<6,&hit,CLIPMASK1);
|
|
|
|
if (hit.sprite != -1)
|
|
{
|
|
const int32_t hitstatnumsbitmap =
|
|
((1<<STAT_ACTOR) | (1<<STAT_ZOMBIEACTOR) | (1<<STAT_PLAYER) | (1<<STAT_DUMMYPLAYER));
|
|
const int32_t st = sprite[hit.sprite].statnum;
|
|
|
|
if (st>=0 && st<=30 && (hitstatnumsbitmap&(1<<st)))
|
|
j = hit.sprite;
|
|
}
|
|
}
|
|
|
|
if (j == -1)
|
|
{
|
|
*zvel = (100-ps->horiz-ps->horizoff)<<5;
|
|
Proj_MaybeAddSpread(not_accurate_p, zvel, sa, zRange, angRange);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (j == -1) // no target
|
|
*zvel = (100-ps->horiz-ps->horizoff)<<5;
|
|
Proj_MaybeAddSpread(not_accurate_p, zvel, sa, zRange, angRange);
|
|
}
|
|
|
|
srcvect->z -= (2<<8);
|
|
}
|
|
|
|
// Hitscan weapon fired from actor (sprite s);
|
|
static void A_PreFireHitscan(const spritetype *s, vec3_t *srcvect, int32_t *zvel, int16_t *sa,
|
|
int32_t not_accurate_p)
|
|
{
|
|
const int32_t j = A_FindPlayer(s, NULL);
|
|
const DukePlayer_t *targetps = g_player[j].ps;
|
|
|
|
const int32_t d = safeldist(targetps->i, s);
|
|
*zvel = tabledivide32_noinline((targetps->pos.z-srcvect->z)<<8, d);
|
|
|
|
srcvect->z -= (4<<8);
|
|
|
|
if (s->picnum != BOSS1)
|
|
{
|
|
Proj_MaybeAddSpread(not_accurate_p, zvel, sa, 256, 64);
|
|
}
|
|
else
|
|
{
|
|
*sa = getangle(targetps->pos.x-srcvect->x, targetps->pos.y-srcvect->y);
|
|
|
|
Proj_MaybeAddSpread(not_accurate_p, zvel, sa, 256, 128);
|
|
}
|
|
}
|
|
|
|
static int32_t Proj_DoHitscan(int32_t i, int32_t cstatmask,
|
|
const vec3_t *srcvect, int32_t zvel, int16_t sa,
|
|
hitdata_t *hit)
|
|
{
|
|
spritetype *const s = &sprite[i];
|
|
|
|
s->cstat &= ~cstatmask;
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
|
|
hitscan(srcvect, s->sectnum,
|
|
sintable[(sa+512)&2047],
|
|
sintable[sa&2047],
|
|
zvel<<6, hit, CLIPMASK1);
|
|
|
|
s->cstat |= cstatmask;
|
|
|
|
return (hit->sect < 0);
|
|
}
|
|
|
|
static void Proj_DoRandDecalSize(int32_t spritenum, int32_t atwith)
|
|
{
|
|
const projectile_t *const proj = Proj_GetProjectile(atwith);
|
|
|
|
if (proj->workslike & PROJECTILE_RANDDECALSIZE)
|
|
{
|
|
int32_t wh = (krand()&proj->xrepeat);
|
|
if (wh < proj->yrepeat)
|
|
wh = proj->yrepeat;
|
|
sprite[spritenum].xrepeat = wh;
|
|
sprite[spritenum].yrepeat = wh;
|
|
}
|
|
else
|
|
{
|
|
sprite[spritenum].xrepeat = proj->xrepeat;
|
|
sprite[spritenum].yrepeat = proj->yrepeat;
|
|
}
|
|
}
|
|
|
|
static int32_t SectorContainsSE13(int32_t sectnum)
|
|
{
|
|
int32_t i;
|
|
if (sectnum >= 0)
|
|
for (SPRITES_OF_SECT(sectnum, i))
|
|
if (sprite[i].statnum == STAT_EFFECTOR && sprite[i].lotag == SE_13_EXPLOSIVE)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
// Maybe handle bit 2 (swap wall bottoms).
|
|
// (in that case walltype *hitwal may be stale)
|
|
static inline void HandleHitWall(hitdata_t *hit)
|
|
{
|
|
const walltype *const hitwal = &wall[hit->wall];
|
|
|
|
if ((hitwal->cstat&2) && redwallp(hitwal))
|
|
if (hit->pos.z >= sector[hitwal->nextsector].floorz)
|
|
hit->wall = hitwal->nextwall;
|
|
}
|
|
|
|
// Maybe damage a ceiling or floor as the consequence of projectile impact.
|
|
// Returns 1 if projectile hit a parallaxed ceiling.
|
|
// NOTE: Compare with Proj_MaybeDamageCF() in actors.c
|
|
static int32_t Proj_MaybeDamageCF2(int32_t zvel, int32_t hitsect)
|
|
{
|
|
if (zvel < 0)
|
|
{
|
|
Bassert(hitsect >= 0);
|
|
|
|
if (sector[hitsect].ceilingstat&1)
|
|
return 1;
|
|
|
|
Sect_DamageCeilingOrFloor(0, hitsect);
|
|
}
|
|
else if (zvel > 0)
|
|
{
|
|
Bassert(hitsect >= 0);
|
|
|
|
if (sector[hitsect].floorstat&1)
|
|
{
|
|
// Keep original Duke3D behavior: pass projectiles through
|
|
// parallaxed ceilings, but NOT through such floors.
|
|
return 0;
|
|
}
|
|
|
|
Sect_DamageCeilingOrFloor(1, hitsect);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Finish shooting hitscan weapon from player <p>. <k> is the inserted SHOTSPARK1.
|
|
// * <spawnatimpacttile> is passed to Proj_MaybeSpawn()
|
|
// * <decaltile> and <damagewalltile> are for wall impact
|
|
// * <damagewalltile> is passed to A_DamageWall()
|
|
// * <flags> is for decals upon wall impact:
|
|
// 1: handle random decal size (tile <atwith>)
|
|
// 2: set cstat to wall-aligned + random x/y flip
|
|
//
|
|
// TODO: maybe split into 3 cases (hit neither wall nor sprite, hit sprite, hit wall)?
|
|
static int32_t P_PostFireHitscan(int32_t p, int32_t k, hitdata_t *hit, int32_t i, int32_t atwith, int32_t zvel,
|
|
int32_t spawnatimpacttile, int32_t decaltile, int32_t damagewalltile,
|
|
int32_t flags)
|
|
{
|
|
if (hit->wall == -1 && hit->sprite == -1)
|
|
{
|
|
if (Proj_MaybeDamageCF2(zvel, hit->sect))
|
|
{
|
|
sprite[k].xrepeat = 0;
|
|
sprite[k].yrepeat = 0;
|
|
return -1;
|
|
}
|
|
|
|
Proj_MaybeSpawn(k, spawnatimpacttile, hit);
|
|
}
|
|
else if (hit->sprite >= 0)
|
|
{
|
|
A_DamageObject(hit->sprite, k);
|
|
|
|
if (sprite[hit->sprite].picnum == APLAYER &&
|
|
(ud.ffire == 1 || (!GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) && GTFLAGS(GAMETYPE_TDM) &&
|
|
g_player[P_Get(hit->sprite)].ps->team != g_player[P_Get(i)].ps->team)))
|
|
{
|
|
int32_t l = A_Spawn(k, JIBS6);
|
|
sprite[k].xrepeat = sprite[k].yrepeat = 0;
|
|
sprite[l].z += (4<<8);
|
|
sprite[l].xvel = 16;
|
|
sprite[l].xrepeat = sprite[l].yrepeat = 24;
|
|
sprite[l].ang += 64-(krand()&127);
|
|
}
|
|
else
|
|
{
|
|
Proj_MaybeSpawn(k, spawnatimpacttile, hit);
|
|
}
|
|
|
|
if (p >= 0 && CheckShootSwitchTile(sprite[hit->sprite].picnum))
|
|
{
|
|
P_ActivateSwitch(p, hit->sprite, 1);
|
|
return -1;
|
|
}
|
|
}
|
|
else if (hit->wall >= 0)
|
|
{
|
|
const walltype *const hitwal = &wall[hit->wall];
|
|
|
|
Proj_MaybeSpawn(k, spawnatimpacttile, hit);
|
|
|
|
if (CheckDoorTile(hitwal->picnum) == 1)
|
|
goto SKIPBULLETHOLE;
|
|
|
|
if (p >= 0 && CheckShootSwitchTile(hitwal->picnum))
|
|
{
|
|
P_ActivateSwitch(p, hit->wall, 0);
|
|
return -1;
|
|
}
|
|
|
|
if (hitwal->hitag != 0 || (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0))
|
|
goto SKIPBULLETHOLE;
|
|
|
|
if (hit->sect >= 0 && sector[hit->sect].lotag == 0)
|
|
if (hitwal->overpicnum != BIGFORCE && (hitwal->cstat&16) == 0)
|
|
if ((hitwal->nextsector >= 0 && sector[hitwal->nextsector].lotag == 0) ||
|
|
(hitwal->nextsector == -1 && sector[hit->sect].lotag == 0))
|
|
{
|
|
int32_t l;
|
|
|
|
if (SectorContainsSE13(hitwal->nextsector))
|
|
goto SKIPBULLETHOLE;
|
|
|
|
for (SPRITES_OF(STAT_MISC, l))
|
|
if (sprite[l].picnum == decaltile)
|
|
if (dist(&sprite[l],&sprite[k]) < (12+(krand()&7)))
|
|
goto SKIPBULLETHOLE;
|
|
|
|
if (decaltile >= 0)
|
|
{
|
|
l = A_Spawn(k, decaltile);
|
|
|
|
if (!A_CheckSpriteFlags(l, SFLAG_DECAL))
|
|
actor[l].flags |= SFLAG_DECAL;
|
|
|
|
sprite[l].xvel = -1;
|
|
sprite[l].ang = getangle(hitwal->x-wall[hitwal->point2].x,
|
|
hitwal->y-wall[hitwal->point2].y)+512;
|
|
if (flags&1)
|
|
Proj_DoRandDecalSize(l, atwith);
|
|
|
|
if (flags&2)
|
|
sprite[l].cstat = 16+(krand()&(8+4));
|
|
|
|
sprite[l].x -= sintable[(sprite[l].ang+2560)&2047]>>13;
|
|
sprite[l].y -= sintable[(sprite[l].ang+2048)&2047]>>13;
|
|
|
|
A_SetSprite(l, CLIPMASK0);
|
|
|
|
// BULLETHOLE already adds itself to the deletion queue in
|
|
// A_Spawn(). However, some other tiles do as well.
|
|
if (decaltile != BULLETHOLE)
|
|
A_AddToDeleteQueue(l);
|
|
}
|
|
}
|
|
|
|
SKIPBULLETHOLE:
|
|
HandleHitWall(hit);
|
|
|
|
A_DamageWall(k, hit->wall, &hit->pos, damagewalltile);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Finish shooting hitscan weapon from actor (sprite <i>).
|
|
static int32_t A_PostFireHitscan(const hitdata_t *hit, int32_t i, int32_t atwith, int32_t sa, int32_t extra,
|
|
int32_t spawnatimpacttile, int32_t damagewalltile)
|
|
{
|
|
int32_t k = Proj_InsertShotspark(hit, i, atwith, 24, sa, extra);
|
|
|
|
if (hit->sprite >= 0)
|
|
{
|
|
A_DamageObject(hit->sprite, k);
|
|
|
|
if (sprite[hit->sprite].picnum != APLAYER)
|
|
Proj_MaybeSpawn(k, spawnatimpacttile, hit);
|
|
else
|
|
sprite[k].xrepeat = sprite[k].yrepeat = 0;
|
|
}
|
|
else if (hit->wall >= 0)
|
|
A_DamageWall(k, hit->wall, &hit->pos, damagewalltile);
|
|
|
|
return k;
|
|
}
|
|
|
|
// Common "spawn blood?" predicate.
|
|
// minzdiff: minimal "step" height for blood to be spawned
|
|
static int32_t Proj_CheckBlood(const vec3_t *srcvect, const hitdata_t *hit,
|
|
int32_t projrange, int32_t minzdiff)
|
|
{
|
|
const walltype * hitwal;
|
|
|
|
if (hit->wall < 0 || hit->sect < 0)
|
|
return 0;
|
|
|
|
hitwal = &wall[hit->wall];
|
|
|
|
if (FindDistance2D(srcvect->x-hit->pos.x, srcvect->y-hit->pos.y) < projrange)
|
|
if (hitwal->overpicnum != BIGFORCE && (hitwal->cstat&16) == 0)
|
|
if (sector[hit->sect].lotag == 0)
|
|
if (hitwal->nextsector < 0 ||
|
|
(sector[hitwal->nextsector].lotag == 0 && sector[hit->sect].lotag == 0 &&
|
|
sector[hit->sect].floorz-sector[hitwal->nextsector].floorz > minzdiff))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void Proj_HandleKnee(hitdata_t *hit, int32_t i, int32_t p, int32_t atwith, int32_t sa,
|
|
const projectile_t *proj, int32_t inserttile,
|
|
int32_t addrandextra, int32_t spawnatimpacttile, int32_t soundnum)
|
|
{
|
|
const DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
|
|
|
|
int32_t j = A_InsertSprite(hit->sect,hit->pos.x,hit->pos.y,hit->pos.z,
|
|
inserttile,-15,0,0,sa,32,0,i,4);
|
|
|
|
if (proj != NULL)
|
|
{
|
|
// Custom projectiles.
|
|
SpriteProjectile[j].workslike = Proj_GetProjectile(sprite[j].picnum)->workslike;
|
|
sprite[j].extra = proj->extra;
|
|
}
|
|
|
|
if (addrandextra > 0)
|
|
sprite[j].extra += (krand()&addrandextra);
|
|
|
|
if (p >= 0)
|
|
{
|
|
if (spawnatimpacttile >= 0)
|
|
{
|
|
int32_t k = A_Spawn(j, spawnatimpacttile);
|
|
sprite[k].z -= (8<<8);
|
|
A_SetHitData(k, hit);
|
|
}
|
|
|
|
if (soundnum >= 0)
|
|
A_PlaySound(soundnum, j);
|
|
}
|
|
|
|
if (p >= 0 && ps->inv_amount[GET_STEROIDS] > 0 && ps->inv_amount[GET_STEROIDS] < 400)
|
|
sprite[j].extra += (ps->max_player_health>>2);
|
|
|
|
if (hit->sprite >= 0 && sprite[hit->sprite].picnum != ACCESSSWITCH && sprite[hit->sprite].picnum != ACCESSSWITCH2)
|
|
{
|
|
A_DamageObject(hit->sprite, j);
|
|
if (p >= 0)
|
|
P_ActivateSwitch(p, hit->sprite,1);
|
|
}
|
|
else if (hit->wall >= 0)
|
|
{
|
|
HandleHitWall(hit);
|
|
|
|
if (wall[hit->wall].picnum != ACCESSSWITCH && wall[hit->wall].picnum != ACCESSSWITCH2)
|
|
{
|
|
A_DamageWall(j, hit->wall, &hit->pos, atwith);
|
|
if (p >= 0)
|
|
P_ActivateSwitch(p, hit->wall,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MinibossScale(s) (((s)*sprite[i].yrepeat)/80)
|
|
|
|
static int32_t A_ShootCustom(const int32_t i, const int32_t atwith, int16_t sa, vec3_t * const srcvect)
|
|
{
|
|
/* Custom projectiles */
|
|
projectile_t *const proj = Proj_GetProjectile(atwith);
|
|
int32_t j, k = -1, l;
|
|
int32_t vel, zvel = 0;
|
|
hitdata_t hit;
|
|
spritetype *const s = &sprite[i];
|
|
const int16_t sect = s->sectnum;
|
|
const int32_t p = (s->picnum == APLAYER) ? P_GetP(s) : -1;
|
|
DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
|
|
|
|
#ifdef POLYMER
|
|
if (getrendermode() == REND_POLYMER && proj->flashcolor)
|
|
{
|
|
int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7);
|
|
|
|
s->x += x;
|
|
s->y += y;
|
|
G_AddGameLight(0, i, PHEIGHT, 8192, proj->flashcolor, PR_LIGHT_PRIO_MAX_GAME);
|
|
actor[i].lightcount = 2;
|
|
s->x -= x;
|
|
s->y -= y;
|
|
}
|
|
#endif // POLYMER
|
|
|
|
if (proj->offset == 0)
|
|
proj->offset = 1;
|
|
|
|
switch (proj->workslike & PROJECTILE_TYPE_MASK)
|
|
{
|
|
case PROJECTILE_HITSCAN:
|
|
if (!(proj->workslike & PROJECTILE_NOSETOWNERSHADE) && s->extra >= 0)
|
|
s->shade = proj->shade;
|
|
|
|
if (p >= 0)
|
|
P_PreFireHitscan(i, p, atwith, srcvect, &zvel, &sa,
|
|
proj->workslike & PROJECTILE_ACCURATE_AUTOAIM,
|
|
!(proj->workslike & PROJECTILE_ACCURATE));
|
|
else
|
|
A_PreFireHitscan(s, srcvect, &zvel, &sa,
|
|
!(proj->workslike & PROJECTILE_ACCURATE));
|
|
|
|
if (Proj_DoHitscan(i, (proj->cstat >= 0) ? proj->cstat : 256 + 1,
|
|
srcvect, zvel, sa, &hit))
|
|
return -1;
|
|
|
|
if (proj->range > 0 && klabs(srcvect->x - hit.pos.x) + klabs(srcvect->y - hit.pos.y) > proj->range)
|
|
return -1;
|
|
|
|
if (proj->trail >= 0)
|
|
A_HitscanProjTrail(srcvect, &hit.pos, sa, atwith);
|
|
|
|
if (proj->workslike & PROJECTILE_WATERBUBBLES)
|
|
{
|
|
if ((krand() & 15) == 0 && sector[hit.sect].lotag == ST_2_UNDERWATER)
|
|
A_DoWaterTracers(hit.pos.x, hit.pos.y, hit.pos.z,
|
|
srcvect->x, srcvect->y, srcvect->z, 8 - (ud.multimode >> 1));
|
|
}
|
|
|
|
if (p >= 0)
|
|
{
|
|
k = Proj_InsertShotspark(&hit, i, atwith, 10, sa, Proj_GetExtra(atwith));
|
|
|
|
if (P_PostFireHitscan(p, k, &hit, i, atwith, zvel,
|
|
atwith, proj->decal, atwith, 1 + 2) < 0)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
k = A_PostFireHitscan(&hit, i, atwith, sa, Proj_GetExtra(atwith),
|
|
atwith, atwith);
|
|
}
|
|
|
|
if ((krand() & 255) < 4 && proj->isound >= 0)
|
|
S_PlaySound3D(proj->isound, k, &hit.pos);
|
|
|
|
return -1;
|
|
|
|
case PROJECTILE_RPG:
|
|
if (!(proj->workslike & PROJECTILE_NOSETOWNERSHADE) && s->extra >= 0)
|
|
s->shade = proj->shade;
|
|
|
|
vel = proj->vel;
|
|
|
|
j = -1;
|
|
|
|
if (p >= 0)
|
|
{
|
|
// NOTE: j is a SPRITE_INDEX
|
|
j = GetAutoAimAngle(i, p, atwith, 8<<8, 0+2, srcvect, vel, &zvel, &sa);
|
|
|
|
if (j < 0)
|
|
zvel = (100-ps->horiz-ps->horizoff)*(proj->vel/8);
|
|
|
|
if (proj->sound >= 0)
|
|
A_PlaySound(proj->sound, i);
|
|
}
|
|
else
|
|
{
|
|
if (!(proj->workslike & PROJECTILE_NOAIM))
|
|
{
|
|
// NOTE: j is a player index
|
|
j = A_FindPlayer(s, NULL);
|
|
sa = getangle(g_player[j].ps->opos.x-srcvect->x, g_player[j].ps->opos.y-srcvect->y);
|
|
|
|
l = safeldist(g_player[j].ps->i, s);
|
|
zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect->z)*vel, l);
|
|
|
|
if (A_CheckEnemySprite(s) && (AC_MOVFLAGS(s, &actor[i]) & face_player_smart))
|
|
sa = s->ang + (krand() & 31) - 16;
|
|
}
|
|
}
|
|
|
|
if (numplayers > 1 && g_netClient) return -1;
|
|
|
|
// l may be a SPRITE_INDEX, see above
|
|
l = (p >= 0 && j >= 0) ? j : -1;
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
j = A_InsertSprite(sect,
|
|
srcvect->x + tabledivide32_noinline(sintable[(348 + sa + 512) & 2047], proj->offset),
|
|
srcvect->y + tabledivide32_noinline(sintable[(sa + 348) & 2047], proj->offset),
|
|
srcvect->z - (1 << 8), atwith, 0, 14, 14, sa, vel, zvel, i, 4);
|
|
|
|
sprite[j].xrepeat = proj->xrepeat;
|
|
sprite[j].yrepeat = proj->yrepeat;
|
|
|
|
if (proj->extra_rand > 0)
|
|
sprite[j].extra += (krand()&proj->extra_rand);
|
|
|
|
if (!(proj->workslike & PROJECTILE_BOUNCESOFFWALLS))
|
|
sprite[j].yvel = l; // NOT_BOUNCESOFFWALLS_YVEL
|
|
else
|
|
{
|
|
if (proj->bounces >= 1) sprite[j].yvel = proj->bounces;
|
|
else sprite[j].yvel = g_numFreezeBounces;
|
|
sprite[j].zvel -= (2 << 4);
|
|
}
|
|
|
|
if (proj->cstat >= 0) sprite[j].cstat = proj->cstat;
|
|
else sprite[j].cstat = 128;
|
|
|
|
if (proj->clipdist != 255) sprite[j].clipdist = proj->clipdist;
|
|
else sprite[j].clipdist = 40;
|
|
|
|
SpriteProjectile[j] = *Proj_GetProjectile(sprite[j].picnum);
|
|
|
|
return j;
|
|
|
|
case PROJECTILE_KNEE:
|
|
if (p >= 0)
|
|
{
|
|
zvel = (100 - ps->horiz - ps->horizoff) << 5;
|
|
srcvect->z += (6 << 8);
|
|
sa += 15;
|
|
}
|
|
else if (!(proj->workslike & PROJECTILE_NOAIM))
|
|
{
|
|
int32_t x;
|
|
j = g_player[A_FindPlayer(s, &x)].ps->i;
|
|
zvel = tabledivide32_noinline((sprite[j].z - srcvect->z) << 8, x + 1);
|
|
sa = getangle(sprite[j].x - srcvect->x, sprite[j].y - srcvect->y);
|
|
}
|
|
|
|
Proj_DoHitscan(i, 0, srcvect, zvel, sa, &hit);
|
|
|
|
if (hit.sect < 0) return -1;
|
|
|
|
if (proj->range == 0)
|
|
proj->range = 1024;
|
|
|
|
if (proj->range > 0 && klabs(srcvect->x - hit.pos.x) + klabs(srcvect->y - hit.pos.y) > proj->range)
|
|
return -1;
|
|
|
|
Proj_HandleKnee(&hit, i, p, atwith, sa,
|
|
proj, atwith,
|
|
proj->extra_rand,
|
|
proj->spawns, proj->sound);
|
|
|
|
return -1;
|
|
|
|
case PROJECTILE_BLOOD:
|
|
sa += 64 - (krand() & 127);
|
|
if (p < 0) sa += 1024;
|
|
zvel = 1024 - (krand() & 2047);
|
|
|
|
Proj_DoHitscan(i, 0, srcvect, zvel, sa, &hit);
|
|
|
|
if (proj->range == 0)
|
|
proj->range = 1024;
|
|
|
|
if (Proj_CheckBlood(srcvect, &hit, proj->range,
|
|
mulscale3(proj->yrepeat, tilesiz[proj->decal].y) << 8))
|
|
{
|
|
const walltype *const hitwal = &wall[hit.wall];
|
|
|
|
if (FindDistance2D(hitwal->x - wall[hitwal->point2].x, hitwal->y - wall[hitwal->point2].y) >
|
|
(mulscale3(proj->xrepeat + 8, tilesiz[proj->decal].x)))
|
|
{
|
|
if (SectorContainsSE13(hitwal->nextsector))
|
|
return -1;
|
|
|
|
if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0)
|
|
return -1;
|
|
|
|
if (hitwal->hitag == 0 && proj->decal >= 0)
|
|
{
|
|
k = A_Spawn(i, proj->decal);
|
|
|
|
if (!A_CheckSpriteFlags(k, SFLAG_DECAL))
|
|
actor[k].flags |= SFLAG_DECAL;
|
|
|
|
sprite[k].xvel = -1;
|
|
sprite[k].ang = getangle(hitwal->x - wall[hitwal->point2].x,
|
|
hitwal->y - wall[hitwal->point2].y) + 512;
|
|
Bmemcpy(&sprite[k], &hit.pos, sizeof(vec3_t));
|
|
|
|
Proj_DoRandDecalSize(k, atwith);
|
|
|
|
sprite[k].z += sprite[k].yrepeat << 8;
|
|
|
|
// sprite[k].cstat = 16+(krand()&12);
|
|
sprite[k].cstat = 16;
|
|
|
|
if (krand() & 1)
|
|
sprite[k].cstat |= 4;
|
|
|
|
if (krand() & 1)
|
|
sprite[k].cstat |= 8;
|
|
|
|
sprite[k].shade = sector[sprite[k].sectnum].floorshade;
|
|
|
|
sprite[k].x -= sintable[(sprite[k].ang + 2560) & 2047] >> 13;
|
|
sprite[k].y -= sintable[(sprite[k].ang + 2048) & 2047] >> 13;
|
|
|
|
A_SetSprite(k, CLIPMASK0);
|
|
A_AddToDeleteQueue(k);
|
|
changespritestat(k, 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int32_t A_ShootWithZvel(int32_t i, int32_t atwith, int32_t override_zvel)
|
|
{
|
|
int16_t sa;
|
|
vec3_t srcvect;
|
|
spritetype *const s = &sprite[i];
|
|
const int32_t p = (s->picnum == APLAYER) ? P_GetP(s) : -1;
|
|
DukePlayer_t *const ps = p >= 0 ? g_player[p].ps : NULL;
|
|
|
|
Bassert(atwith >= 0);
|
|
|
|
if (override_zvel != SHOOT_HARDCODED_ZVEL)
|
|
{
|
|
g_overrideShootZvel = 1;
|
|
g_shootZvel = override_zvel;
|
|
}
|
|
else
|
|
g_overrideShootZvel = 0;
|
|
|
|
if (s->picnum == APLAYER)
|
|
{
|
|
Bmemcpy(&srcvect,ps,sizeof(vec3_t));
|
|
srcvect.z += ps->pyoff+(4<<8);
|
|
sa = ps->ang;
|
|
|
|
ps->crack_time = 777;
|
|
}
|
|
else
|
|
{
|
|
sa = s->ang;
|
|
Bmemcpy(&srcvect,s,sizeof(vec3_t));
|
|
srcvect.z -= (((s->yrepeat*tilesiz[s->picnum].y)<<1)-(4<<8));
|
|
|
|
if (s->picnum != ROTATEGUN)
|
|
{
|
|
srcvect.z -= (7<<8);
|
|
|
|
if (A_CheckEnemySprite(s) && PN != COMMANDER)
|
|
{
|
|
srcvect.x += (sintable[(sa+1024+96)&2047]>>7);
|
|
srcvect.y += (sintable[(sa+512+96)&2047]>>7);
|
|
}
|
|
}
|
|
|
|
#ifdef POLYMER
|
|
switch (DYNAMICTILEMAP(atwith))
|
|
{
|
|
case FIRELASER__STATIC:
|
|
case SHOTGUN__STATIC:
|
|
case SHOTSPARK1__STATIC:
|
|
case CHAINGUN__STATIC:
|
|
case RPG__STATIC:
|
|
case MORTER__STATIC:
|
|
{
|
|
int32_t x = ((sintable[(s->ang+512)&2047])>>7), y = ((sintable[(s->ang)&2047])>>7);
|
|
s->x += x;
|
|
s->y += y;
|
|
G_AddGameLight(0, i, PHEIGHT, 8192, 255+(95<<8), PR_LIGHT_PRIO_MAX_GAME);
|
|
actor[i].lightcount = 2;
|
|
s->x -= x;
|
|
s->y -= y;
|
|
}
|
|
|
|
break;
|
|
}
|
|
#endif // POLYMER
|
|
}
|
|
|
|
if (A_CheckSpriteTileFlags(atwith, SFLAG_PROJECTILE))
|
|
return A_ShootCustom(i, atwith, sa, &srcvect);
|
|
else
|
|
{
|
|
int32_t j, k = -1, l;
|
|
int32_t vel, zvel = 0;
|
|
hitdata_t hit;
|
|
const int16_t sect = s->sectnum;
|
|
|
|
switch (DYNAMICTILEMAP(atwith))
|
|
{
|
|
case BLOODSPLAT1__STATIC:
|
|
case BLOODSPLAT2__STATIC:
|
|
case BLOODSPLAT3__STATIC:
|
|
case BLOODSPLAT4__STATIC:
|
|
sa += 64 - (krand()&127);
|
|
if (p < 0) sa += 1024;
|
|
zvel = 1024-(krand()&2047);
|
|
// fall-through
|
|
case KNEE__STATIC:
|
|
if (atwith == KNEE)
|
|
{
|
|
if (p >= 0)
|
|
{
|
|
zvel = (100-ps->horiz-ps->horizoff)<<5;
|
|
srcvect.z += (6<<8);
|
|
sa += 15;
|
|
}
|
|
else
|
|
{
|
|
int32_t x;
|
|
j = g_player[A_FindPlayer(s,&x)].ps->i;
|
|
zvel = tabledivide32_noinline((sprite[j].z-srcvect.z)<<8, x+1);
|
|
sa = getangle(sprite[j].x-srcvect.x,sprite[j].y-srcvect.y);
|
|
}
|
|
}
|
|
|
|
Proj_DoHitscan(i, 0, &srcvect, zvel, sa, &hit);
|
|
|
|
if (atwith >= BLOODSPLAT1 && atwith <= BLOODSPLAT4)
|
|
{
|
|
if (Proj_CheckBlood(&srcvect, &hit, 1024, 16<<8))
|
|
{
|
|
const walltype *const hitwal = &wall[hit.wall];
|
|
|
|
if (SectorContainsSE13(hitwal->nextsector))
|
|
return -1;
|
|
|
|
if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0)
|
|
return -1;
|
|
|
|
if (hitwal->hitag == 0)
|
|
{
|
|
k = A_Spawn(i,atwith);
|
|
sprite[k].xvel = -12;
|
|
sprite[k].ang = getangle(hitwal->x-wall[hitwal->point2].x,
|
|
hitwal->y-wall[hitwal->point2].y)+512;
|
|
Bmemcpy(&sprite[k], &hit.pos, sizeof(vec3_t));
|
|
|
|
sprite[k].cstat |= (krand()&4);
|
|
A_SetSprite(k,CLIPMASK0);
|
|
setsprite(k, (vec3_t *)&sprite[k]);
|
|
if (PN == OOZFILTER || PN == NEWBEAST)
|
|
sprite[k].pal = 6;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (hit.sect < 0) break;
|
|
|
|
if (klabs(srcvect.x-hit.pos.x)+klabs(srcvect.y-hit.pos.y) < 1024)
|
|
Proj_HandleKnee(&hit, i, p, atwith, sa,
|
|
NULL, KNEE, 7, SMALLSMOKE, KICK_HIT);
|
|
break;
|
|
|
|
case SHOTSPARK1__STATIC:
|
|
case SHOTGUN__STATIC:
|
|
case CHAINGUN__STATIC:
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
if (p >= 0)
|
|
P_PreFireHitscan(i, p, atwith, &srcvect, &zvel, &sa,
|
|
atwith == SHOTSPARK1__STATIC && !WW2GI && !NAM,
|
|
1);
|
|
else
|
|
A_PreFireHitscan(s, &srcvect, &zvel, &sa, 1);
|
|
|
|
if (Proj_DoHitscan(i, 256+1, &srcvect, zvel, sa, &hit))
|
|
return -1;
|
|
|
|
if ((krand()&15) == 0 && sector[hit.sect].lotag == ST_2_UNDERWATER)
|
|
A_DoWaterTracers(hit.pos.x,hit.pos.y,hit.pos.z,
|
|
srcvect.x,srcvect.y,srcvect.z,8-(ud.multimode>>1));
|
|
|
|
if (p >= 0)
|
|
{
|
|
k = Proj_InsertShotspark(&hit, i, atwith, 10, sa,
|
|
G_InitialActorStrength(atwith) + (krand()%6));
|
|
|
|
if (P_PostFireHitscan(p, k, &hit, i, atwith, zvel,
|
|
-SMALLSMOKE, BULLETHOLE, SHOTSPARK1, 0) < 0)
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
k = A_PostFireHitscan(&hit, i, atwith, sa, G_InitialActorStrength(atwith),
|
|
-SMALLSMOKE, SHOTSPARK1);
|
|
}
|
|
|
|
if ((krand()&255) < 4)
|
|
S_PlaySound3D(PISTOL_RICOCHET, k, &hit.pos);
|
|
|
|
return -1;
|
|
|
|
case GROWSPARK__STATIC:
|
|
if (p >= 0)
|
|
P_PreFireHitscan(i, p, atwith, &srcvect, &zvel, &sa, 1, 1);
|
|
else
|
|
A_PreFireHitscan(s, &srcvect, &zvel, &sa, 1);
|
|
|
|
if (Proj_DoHitscan(i, 256 + 1, &srcvect, zvel, sa, &hit))
|
|
return -1;
|
|
|
|
j = A_InsertSprite(hit.sect,hit.pos.x,hit.pos.y,hit.pos.z,GROWSPARK,-16,28,28,sa,0,0,i,1);
|
|
|
|
sprite[j].pal = 2;
|
|
sprite[j].cstat |= 130;
|
|
sprite[j].xrepeat = sprite[j].yrepeat = 1;
|
|
|
|
if (hit.wall == -1 && hit.sprite == -1 && hit.sect >= 0)
|
|
{
|
|
Proj_MaybeDamageCF2(zvel, hit.sect);
|
|
}
|
|
else if (hit.sprite >= 0) A_DamageObject(hit.sprite,j);
|
|
else if (hit.wall >= 0 && wall[hit.wall].picnum != ACCESSSWITCH && wall[hit.wall].picnum != ACCESSSWITCH2)
|
|
A_DamageWall(j,hit.wall,&hit.pos,atwith);
|
|
|
|
break;
|
|
|
|
case FIRELASER__STATIC:
|
|
case SPIT__STATIC:
|
|
case COOLEXPLOSION1__STATIC:
|
|
{
|
|
int32_t tsiz;
|
|
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
switch (atwith)
|
|
{
|
|
case SPIT__STATIC:
|
|
vel = 292;
|
|
break;
|
|
case COOLEXPLOSION1__STATIC:
|
|
if (s->picnum == BOSS2) vel = 644;
|
|
else vel = 348;
|
|
srcvect.z -= (4<<7);
|
|
break;
|
|
case FIRELASER__STATIC:
|
|
default:
|
|
vel = 840;
|
|
srcvect.z -= (4<<7);
|
|
break;
|
|
}
|
|
|
|
if (p >= 0)
|
|
{
|
|
j = GetAutoAimAngle(i, p, atwith, -(12<<8), 0, &srcvect, vel, &zvel, &sa);
|
|
|
|
if (j < 0)
|
|
zvel = (100-ps->horiz-ps->horizoff)*98;
|
|
}
|
|
else
|
|
{
|
|
j = A_FindPlayer(s, NULL);
|
|
// sa = getangle(g_player[j].ps->opos.x-sx,g_player[j].ps->opos.y-sy);
|
|
sa += 16-(krand()&31);
|
|
hit.pos.x = safeldist(g_player[j].ps->i, s);
|
|
zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect.z + (3<<8))*vel, hit.pos.x);
|
|
}
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
|
|
if (atwith == SPIT)
|
|
{
|
|
tsiz = 18;
|
|
srcvect.z -= (10<<8);
|
|
}
|
|
else if (p >= 0)
|
|
tsiz = 7;
|
|
else
|
|
{
|
|
if (atwith == FIRELASER)
|
|
{
|
|
if (p >= 0)
|
|
tsiz = 34;
|
|
else
|
|
tsiz = 18;
|
|
}
|
|
else
|
|
tsiz = 18;
|
|
}
|
|
|
|
j = A_InsertSprite(sect,srcvect.x,srcvect.y,srcvect.z,
|
|
atwith,-127,tsiz,tsiz,sa,vel,zvel,i,4);
|
|
sprite[j].extra += (krand()&7);
|
|
|
|
if (atwith == COOLEXPLOSION1)
|
|
{
|
|
sprite[j].shade = 0;
|
|
if (PN == BOSS2)
|
|
{
|
|
l = sprite[j].xvel;
|
|
sprite[j].xvel = MinibossScale(1024);
|
|
A_SetSprite(j,CLIPMASK0);
|
|
sprite[j].xvel = l;
|
|
sprite[j].ang += 128-(krand()&255);
|
|
}
|
|
}
|
|
|
|
sprite[j].cstat = 128;
|
|
sprite[j].clipdist = 4;
|
|
|
|
sa = s->ang+32-(krand()&63);
|
|
zvel += 512-(krand()&1023);
|
|
|
|
return j;
|
|
}
|
|
|
|
case FREEZEBLAST__STATIC:
|
|
srcvect.z += (3<<8);
|
|
case RPG__STATIC:
|
|
// XXX: "CODEDUP"
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
vel = 644;
|
|
|
|
j = -1;
|
|
|
|
if (p >= 0)
|
|
{
|
|
// NOTE: j is a SPRITE_INDEX
|
|
j = GetAutoAimAngle(i, p, atwith, 8<<8, 0+2, &srcvect, vel, &zvel, &sa);
|
|
|
|
if (j < 0)
|
|
zvel = (100-ps->horiz-ps->horizoff)*81;
|
|
|
|
if (atwith == RPG)
|
|
A_PlaySound(RPG_SHOOT,i);
|
|
}
|
|
else
|
|
{
|
|
// NOTE: j is a player index
|
|
j = A_FindPlayer(s, NULL);
|
|
sa = getangle(g_player[j].ps->opos.x-srcvect.x, g_player[j].ps->opos.y-srcvect.y);
|
|
if (PN == BOSS3)
|
|
srcvect.z -= MinibossScale(32<<8);
|
|
else if (PN == BOSS2)
|
|
{
|
|
vel += 128;
|
|
srcvect.z += MinibossScale(24<<8);
|
|
}
|
|
|
|
l = safeldist(g_player[j].ps->i, s);
|
|
zvel = tabledivide32_noinline((g_player[j].ps->opos.z - srcvect.z)*vel, l);
|
|
|
|
if (A_CheckEnemySprite(s) && (AC_MOVFLAGS(s, &actor[i]) & face_player_smart))
|
|
sa = s->ang+(krand()&31)-16;
|
|
}
|
|
|
|
if (numplayers > 1 && g_netClient)
|
|
return -1;
|
|
|
|
// l may be a SPRITE_INDEX, see above
|
|
l = (p >= 0 && j >= 0) ? j : -1;
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
j = A_InsertSprite(sect,
|
|
srcvect.x+(sintable[(348+sa+512)&2047]/448),
|
|
srcvect.y+(sintable[(sa+348)&2047]/448),
|
|
srcvect.z-(1<<8),atwith,0,14,14,sa,vel,zvel,i,4);
|
|
|
|
sprite[j].extra += (krand()&7);
|
|
if (atwith != FREEZEBLAST)
|
|
sprite[j].yvel = l; // RPG_YVEL
|
|
else
|
|
{
|
|
sprite[j].yvel = g_numFreezeBounces;
|
|
sprite[j].xrepeat >>= 1;
|
|
sprite[j].yrepeat >>= 1;
|
|
sprite[j].zvel -= (2<<4);
|
|
}
|
|
|
|
if (p == -1)
|
|
{
|
|
if (PN == BOSS3)
|
|
{
|
|
if (krand()&1)
|
|
{
|
|
sprite[j].x -= MinibossScale(sintable[sa&2047]>>6);
|
|
sprite[j].y -= MinibossScale(sintable[(sa+1024+512)&2047]>>6);
|
|
sprite[j].ang -= MinibossScale(8);
|
|
}
|
|
else
|
|
{
|
|
sprite[j].x += MinibossScale(sintable[sa&2047]>>6);
|
|
sprite[j].y += MinibossScale(sintable[(sa+1024+512)&2047]>>6);
|
|
sprite[j].ang += MinibossScale(4);
|
|
}
|
|
sprite[j].xrepeat = MinibossScale(42);
|
|
sprite[j].yrepeat = MinibossScale(42);
|
|
}
|
|
else if (PN == BOSS2)
|
|
{
|
|
sprite[j].x -= MinibossScale(sintable[sa&2047]/56);
|
|
sprite[j].y -= MinibossScale(sintable[(sa+1024+512)&2047]/56);
|
|
sprite[j].ang -= MinibossScale(8)+(krand()&255)-128;
|
|
sprite[j].xrepeat = 24;
|
|
sprite[j].yrepeat = 24;
|
|
}
|
|
else if (atwith != FREEZEBLAST)
|
|
{
|
|
sprite[j].xrepeat = 30;
|
|
sprite[j].yrepeat = 30;
|
|
sprite[j].extra >>= 2;
|
|
}
|
|
}
|
|
else if (PWEAPON(p, g_player[p].ps->curr_weapon, WorksLike) == DEVISTATOR_WEAPON)
|
|
{
|
|
sprite[j].extra >>= 2;
|
|
sprite[j].ang += 16-(krand()&31);
|
|
sprite[j].zvel += 256-(krand()&511);
|
|
|
|
if (g_player[p].ps->hbomb_hold_delay)
|
|
{
|
|
sprite[j].x -= sintable[sa&2047]/644;
|
|
sprite[j].y -= sintable[(sa+1024+512)&2047]/644;
|
|
}
|
|
else
|
|
{
|
|
sprite[j].x += sintable[sa&2047]>>8;
|
|
sprite[j].y += sintable[(sa+1024+512)&2047]>>8;
|
|
}
|
|
sprite[j].xrepeat >>= 1;
|
|
sprite[j].yrepeat >>= 1;
|
|
}
|
|
|
|
sprite[j].cstat = 128;
|
|
if (atwith == RPG)
|
|
sprite[j].clipdist = 4;
|
|
else
|
|
sprite[j].clipdist = 40;
|
|
|
|
return j;
|
|
|
|
case HANDHOLDINGLASER__STATIC:
|
|
{
|
|
const int32_t zoff = (p>=0) ? g_player[p].ps->pyoff : 0;
|
|
if (p >= 0)
|
|
zvel = (100-ps->horiz-ps->horizoff)*32;
|
|
else zvel = 0;
|
|
|
|
srcvect.z -= zoff;
|
|
Proj_DoHitscan(i, 0, &srcvect, zvel, sa, &hit);
|
|
srcvect.z += zoff;
|
|
|
|
j = 0;
|
|
if (hit.sprite >= 0) break;
|
|
|
|
if (hit.wall >= 0 && hit.sect >= 0)
|
|
if (((hit.pos.x-srcvect.x)*(hit.pos.x-srcvect.x)+(hit.pos.y-srcvect.y)*(hit.pos.y-srcvect.y)) < (290*290))
|
|
{
|
|
// ST_2_UNDERWATER
|
|
if (wall[hit.wall].nextsector >= 0)
|
|
{
|
|
if (sector[wall[hit.wall].nextsector].lotag <= 2 && sector[hit.sect].lotag <= 2)
|
|
j = 1;
|
|
}
|
|
else if (sector[hit.sect].lotag <= 2)
|
|
j = 1;
|
|
}
|
|
|
|
if (j == 1)
|
|
{
|
|
int32_t lTripBombControl = (p < 0) ? 0 :
|
|
#ifdef LUNATIC
|
|
g_player[p].ps->tripbombControl;
|
|
#else
|
|
Gv_GetVarByLabel("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, g_player[p].ps->i, p);
|
|
#endif
|
|
k = A_InsertSprite(hit.sect,hit.pos.x,hit.pos.y,hit.pos.z,TRIPBOMB,-16,4,5,sa,0,0,i,6);
|
|
if (lTripBombControl & TRIPBOMB_TIMER)
|
|
{
|
|
#ifdef LUNATIC
|
|
int32_t lLifetime = g_player[p].ps->tripbombLifetime;
|
|
int32_t lLifetimeVar = g_player[p].ps->tripbombLifetimeVar;
|
|
#else
|
|
int32_t lLifetime=Gv_GetVarByLabel("STICKYBOMB_LIFETIME", NAM_GRENADE_LIFETIME, g_player[p].ps->i, p);
|
|
int32_t lLifetimeVar=Gv_GetVarByLabel("STICKYBOMB_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, g_player[p].ps->i, p);
|
|
#endif
|
|
// set timer. blows up when at zero....
|
|
actor[k].t_data[7]=lLifetime
|
|
+ mulscale(krand(),lLifetimeVar, 14)
|
|
- lLifetimeVar;
|
|
// TIMER_CONTROL
|
|
actor[k].t_data[6]=1;
|
|
}
|
|
else
|
|
sprite[k].hitag = k;
|
|
|
|
A_PlaySound(LASERTRIP_ONWALL,k);
|
|
sprite[k].xvel = -20;
|
|
A_SetSprite(k,CLIPMASK0);
|
|
sprite[k].cstat = 16;
|
|
|
|
{
|
|
int32_t p2 = wall[hit.wall].point2;
|
|
int32_t a = getangle(wall[hit.wall].x-wall[p2].x, wall[hit.wall].y-wall[p2].y)-512;
|
|
actor[k].t_data[5] = sprite[k].ang = a;
|
|
}
|
|
}
|
|
return j?k:-1;
|
|
}
|
|
|
|
case BOUNCEMINE__STATIC:
|
|
case MORTER__STATIC:
|
|
{
|
|
int32_t x;
|
|
|
|
if (s->extra >= 0) s->shade = -96;
|
|
|
|
j = g_player[A_FindPlayer(s, NULL)].ps->i;
|
|
x = ldist(&sprite[j],s);
|
|
|
|
zvel = -x>>1;
|
|
|
|
if (zvel < -4096)
|
|
zvel = -2048;
|
|
vel = x>>4;
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
A_InsertSprite(sect,
|
|
srcvect.x+(sintable[(512+sa+512)&2047]>>8),
|
|
srcvect.y+(sintable[(sa+512)&2047]>>8),
|
|
srcvect.z+(6<<8),atwith,-64,32,32,sa,vel,zvel,i,1);
|
|
break;
|
|
}
|
|
|
|
case SHRINKER__STATIC:
|
|
if (s->extra >= 0) s->shade = -96;
|
|
if (p >= 0)
|
|
{
|
|
j = GetAutoAimAngle(i, p, atwith, 4<<8, 0, &srcvect, 768, &zvel, &sa);
|
|
|
|
if (j < 0)
|
|
zvel = (100-ps->horiz-ps->horizoff)*98;
|
|
}
|
|
else if (s->statnum != STAT_EFFECTOR)
|
|
{
|
|
j = A_FindPlayer(s, NULL);
|
|
l = safeldist(g_player[j].ps->i, s);
|
|
zvel = tabledivide32_noinline((g_player[j].ps->opos.z-srcvect.z)*512, l);
|
|
}
|
|
else zvel = 0;
|
|
|
|
zvel = A_GetShootZvel(zvel);
|
|
j = A_InsertSprite(sect,
|
|
srcvect.x+(sintable[(512+sa+512)&2047]>>12),
|
|
srcvect.y+(sintable[(sa+512)&2047]>>12),
|
|
srcvect.z+(2<<8),SHRINKSPARK,-16,28,28,sa,768,zvel,i,4);
|
|
|
|
sprite[j].cstat = 128;
|
|
sprite[j].clipdist = 32;
|
|
|
|
return j;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
//////////////////// HUD WEAPON / MISC. DISPLAY CODE ////////////////////
|
|
|
|
static void P_DisplaySpit(void)
|
|
{
|
|
DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
const int32_t loogcnt = ps->loogcnt;
|
|
|
|
if (loogcnt == 0)
|
|
return;
|
|
|
|
if (VM_OnEvent(EVENT_DISPLAYSPIT, ps->i, screenpeek) != 0)
|
|
return;
|
|
|
|
const int32_t y = loogcnt<<2;
|
|
|
|
for (int32_t i=0; i < ps->numloogs; i++)
|
|
{
|
|
int32_t a = klabs(sintable[((loogcnt+i)<<5)&2047])>>5;
|
|
int32_t z = 4096 + ((loogcnt+i)<<9);
|
|
int32_t x = (-g_player[screenpeek].sync->avel>>1) + (sintable[((loogcnt+i)<<6)&2047]>>10);
|
|
|
|
rotatesprite_fs(
|
|
(ps->loogiex[i]+x)<<16, (200+ps->loogiey[i]-y)<<16,
|
|
z-(i<<8), 256-a,
|
|
LOOGIE,0,0,2);
|
|
}
|
|
}
|
|
|
|
int32_t P_GetHudPal(const DukePlayer_t *p)
|
|
{
|
|
if (sprite[p->i].pal == 1)
|
|
return 1;
|
|
|
|
if (p->cursectnum >= 0)
|
|
{
|
|
int32_t dapal = sector[p->cursectnum].floorpal;
|
|
if (!g_noFloorPal[dapal])
|
|
return dapal;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t P_DisplayFist(int32_t gs)
|
|
{
|
|
int32_t looking_arc,fisti,fistpal;
|
|
int32_t fistzoom, fistz;
|
|
|
|
int32_t wx[2] = { windowx1, windowx2 };
|
|
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
fisti = ps->fist_incs;
|
|
if (fisti > 32) fisti = 32;
|
|
if (fisti <= 0) return 0;
|
|
|
|
switch (VM_OnEvent(EVENT_DISPLAYFIST, ps->i, screenpeek))
|
|
{
|
|
case 1:
|
|
return 1;
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
looking_arc = klabs(ps->look_ang)/9;
|
|
|
|
fistzoom = 65536 - (sintable[(512+(fisti<<6))&2047]<<2);
|
|
fistzoom = clamp(fistzoom, 40920, 90612);
|
|
|
|
fistz = 194 + (sintable[((6+fisti)<<7)&2047]>>9);
|
|
|
|
fistpal = P_GetHudPal(ps);
|
|
|
|
#ifdef SPLITSCREEN_MOD_HACKS
|
|
// XXX: this is outdated, doesn't handle above/below split.
|
|
if (g_fakeMultiMode==2)
|
|
wx[(g_snum==0)] = (wx[0]+wx[1])/2+1;
|
|
#endif
|
|
|
|
rotatesprite(
|
|
(-fisti+222+(g_player[screenpeek].sync->avel>>5))<<16,
|
|
(looking_arc+fistz)<<16,
|
|
fistzoom,0,FIST,gs,fistpal,2,
|
|
wx[0],windowy1,wx[1],windowy2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define DRAWEAP_CENTER 262144
|
|
#define weapsc(sc) scale(sc, ud.weaponscale, 100)
|
|
|
|
static int32_t g_dts_yadd;
|
|
|
|
static void G_DrawTileScaled(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p)
|
|
{
|
|
int32_t ang = 0;
|
|
int32_t xoff = 192;
|
|
|
|
int32_t wx[2] = { windowx1, windowx2 };
|
|
int32_t wy[2] = { windowy1, windowy2 };
|
|
int32_t yofs = 0;
|
|
|
|
switch (hudweap.cur)
|
|
{
|
|
case DEVISTATOR_WEAPON:
|
|
case TRIPBOMB_WEAPON:
|
|
xoff = 160;
|
|
break;
|
|
default:
|
|
if (orientation & DRAWEAP_CENTER)
|
|
{
|
|
xoff = 160;
|
|
orientation &= ~DRAWEAP_CENTER;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// bit 4 means "flip x" for G_DrawTileScaled
|
|
if (orientation&4)
|
|
ang = 1024;
|
|
|
|
#ifdef SPLITSCREEN_MOD_HACKS
|
|
if (g_fakeMultiMode==2)
|
|
{
|
|
const int32_t sidebyside = (ud.screen_size!=0);
|
|
|
|
// splitscreen HACK
|
|
orientation &= ~(1024|512|256);
|
|
if (sidebyside)
|
|
{
|
|
orientation &= ~8;
|
|
wx[(g_snum==0)] = (wx[0]+wx[1])/2 + 2;
|
|
}
|
|
else
|
|
{
|
|
orientation |= 8;
|
|
if (g_snum==0)
|
|
yofs = -(100<<16);
|
|
wy[(g_snum==0)] = (wy[0]+wy[1])/2 + 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_OPENGL
|
|
if (getrendermode() >= REND_POLYMOST && usemodels && md_tilehasmodel(tilenum,p) >= 0)
|
|
y += (224-weapsc(224));
|
|
#endif
|
|
rotatesprite(weapsc(x<<16) + ((xoff-weapsc(xoff))<<16),
|
|
weapsc((y<<16) + g_dts_yadd) + ((200-weapsc(200))<<16) + yofs,
|
|
weapsc(65536L),ang,tilenum,shade,p,(2|orientation),
|
|
wx[0],wy[0], wx[1],wy[1]);
|
|
}
|
|
|
|
static void G_DrawWeaponTile(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int32_t orientation, int32_t p,
|
|
uint8_t slot)
|
|
{
|
|
static int32_t shadef[2] = { 0, 0 }, palf[2] = { 0, 0 };
|
|
|
|
// sanity checking the slot value
|
|
if (slot > 1)
|
|
slot = 1;
|
|
|
|
// basic fading between player weapon shades
|
|
if (shadef[slot] != shade && (!p || palf[slot] == p))
|
|
{
|
|
shadef[slot] += (shade - shadef[slot]) >> 2;
|
|
|
|
if (!((shade - shadef[slot]) >> 2))
|
|
shadef[slot] = logapproach(shadef[slot], shade);
|
|
}
|
|
else
|
|
shadef[slot] = shade;
|
|
|
|
palf[slot] = p;
|
|
|
|
#ifdef USE_OPENGL
|
|
if (getrendermode() >= REND_POLYMOST)
|
|
if (tilenum >= CHAINGUN + 1 && tilenum <= CHAINGUN + 4)
|
|
if (!usemodels || md_tilehasmodel(tilenum, p) < 0)
|
|
{
|
|
// HACK: Draw the upper part of the chaingun two screen
|
|
// pixels (not texels; multiplied by weapon scale) lower
|
|
// first, preventing ugly horizontal seam.
|
|
g_dts_yadd = tabledivide32_noinline(65536 * 2 * 200, ydim);
|
|
G_DrawTileScaled(x, y, tilenum, shadef[slot], orientation, p);
|
|
g_dts_yadd = 0;
|
|
}
|
|
#endif
|
|
G_DrawTileScaled(x, y, tilenum, shadef[slot], orientation, p);
|
|
}
|
|
|
|
static inline void G_DrawWeaponTileWithID(int32_t id, int32_t x, int32_t y, int32_t tilenum, int32_t shade,
|
|
int32_t orientation, int32_t p, uint8_t slot)
|
|
{
|
|
int oldid = guniqhudid;
|
|
|
|
guniqhudid = id;
|
|
G_DrawWeaponTile(x, y, tilenum, shade, orientation, p, slot);
|
|
guniqhudid = oldid;
|
|
}
|
|
|
|
static int32_t P_DisplayKnee(int32_t gs)
|
|
{
|
|
static const int8_t knee_y[] = {0,-8,-16,-32,-64,-84,-108,-108,-108,-72,-32,-8};
|
|
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
if (ps->knee_incs == 0)
|
|
return 0;
|
|
|
|
switch (VM_OnEvent(EVENT_DISPLAYKNEE, ps->i, screenpeek))
|
|
{
|
|
case 1:
|
|
return 1;
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
if (ps->knee_incs >= ARRAY_SIZE(knee_y) || sprite[ps->i].extra <= 0)
|
|
return 0;
|
|
|
|
int32_t looking_arc, pal;
|
|
|
|
looking_arc = knee_y[ps->knee_incs] + klabs(ps->look_ang)/9;
|
|
|
|
looking_arc -= (ps->hard_landing<<3);
|
|
|
|
pal = P_GetHudPal(ps);
|
|
if (pal == 0)
|
|
pal = ps->palookup;
|
|
|
|
G_DrawTileScaled(105+(g_player[screenpeek].sync->avel>>5)-(ps->look_ang>>1)+(knee_y[ps->knee_incs]>>2),
|
|
looking_arc+280-((ps->horiz-ps->horizoff)>>4),KNEE,gs,4+DRAWEAP_CENTER,pal);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int32_t P_DisplayKnuckles(int32_t gs)
|
|
{
|
|
static const int8_t knuckle_frames[] = {0,1,2,2,3,3,3,2,2,1,0};
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
if (ps->knuckle_incs == 0)
|
|
return 0;
|
|
|
|
switch (VM_OnEvent(EVENT_DISPLAYKNUCKLES, ps->i, screenpeek))
|
|
{
|
|
case 1:
|
|
return 1;
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
if ((unsigned) (ps->knuckle_incs>>1) >= ARRAY_SIZE(knuckle_frames) || sprite[ps->i].extra <= 0)
|
|
return 0;
|
|
|
|
int32_t looking_arc, pal;
|
|
|
|
looking_arc = klabs(ps->look_ang)/9;
|
|
|
|
looking_arc -= (ps->hard_landing<<3);
|
|
|
|
pal = P_GetHudPal(ps);
|
|
|
|
G_DrawTileScaled(160+(g_player[screenpeek].sync->avel>>5)-(ps->look_ang>>1),
|
|
looking_arc+180-((ps->horiz-ps->horizoff)>>4),
|
|
CRACKKNUCKLES+knuckle_frames[ps->knuckle_incs>>1],gs,4+DRAWEAP_CENTER,pal);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#if !defined LUNATIC
|
|
// Set C-CON's WEAPON and WORKSLIKE gamevars.
|
|
void P_SetWeaponGamevars(int32_t snum, const DukePlayer_t *p)
|
|
{
|
|
Gv_SetVar(g_iWeaponVarID, p->curr_weapon, p->i, snum);
|
|
Gv_SetVar(g_iWorksLikeVarID,
|
|
((unsigned)p->curr_weapon < MAX_WEAPONS) ? PWEAPON(snum, p->curr_weapon, WorksLike) : -1,
|
|
p->i, snum);
|
|
}
|
|
#endif
|
|
|
|
static void P_FireWeapon(int32_t snum)
|
|
{
|
|
int32_t i;
|
|
DukePlayer_t *const p = g_player[snum].ps;
|
|
|
|
if (VM_OnEvent(EVENT_DOFIRE, p->i, snum) || p->weapon_pos != 0)
|
|
return;
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON)
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, FireSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, FireSound), p->i);
|
|
|
|
P_SetWeaponGamevars(snum, p);
|
|
// OSD_Printf("doing %d %d %d\n",PWEAPON(snum, p->curr_weapon, Shoots),p->curr_weapon,snum);
|
|
A_Shoot(p->i, PWEAPON(snum, p->curr_weapon, Shoots));
|
|
|
|
for (i = PWEAPON(snum, p->curr_weapon, ShotsPerBurst) - 1; i > 0; i--)
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_FIREEVERYOTHER)
|
|
{
|
|
// this makes the projectiles fire on a delay from player code
|
|
actor[p->i].t_data[7] = (PWEAPON(snum, p->curr_weapon, ShotsPerBurst)) << 1;
|
|
}
|
|
else
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_AMMOPERSHOT &&
|
|
PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON)
|
|
{
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
else
|
|
break;
|
|
}
|
|
|
|
A_Shoot(p->i, PWEAPON(snum, p->curr_weapon, Shoots));
|
|
}
|
|
}
|
|
|
|
if (!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_NOVISIBLE))
|
|
{
|
|
#ifdef POLYMER
|
|
spritetype *s = &sprite[p->i];
|
|
int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7);
|
|
|
|
s->x += x;
|
|
s->y += y;
|
|
G_AddGameLight(0, p->i, PHEIGHT, 8192, PWEAPON(snum, p->curr_weapon, FlashColor), PR_LIGHT_PRIO_MAX_GAME);
|
|
actor[p->i].lightcount = 2;
|
|
s->x -= x;
|
|
s->y -= y;
|
|
#endif // POLYMER
|
|
p->visibility = 0;
|
|
}
|
|
}
|
|
|
|
static void P_DoWeaponSpawn(int32_t snum)
|
|
{
|
|
int32_t j;
|
|
const DukePlayer_t *const p = g_player[snum].ps;
|
|
|
|
// NOTE: For the 'Spawn' member, 0 means 'none', too (originally so,
|
|
// i.e. legacy). The check for <0 was added to the check because mod
|
|
// authors (rightly) assumed that -1 is the no-op value.
|
|
if (PWEAPON(snum, p->curr_weapon, Spawn) <= 0) // <=0 : AMC TC beta/RC2 has WEAPONx_SPAWN -1
|
|
return;
|
|
|
|
j = A_Spawn(p->i, PWEAPON(snum, p->curr_weapon, Spawn));
|
|
|
|
if ((PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_SPAWNTYPE3))
|
|
{
|
|
// like chaingun shells
|
|
sprite[j].ang += 1024;
|
|
sprite[j].ang &= 2047;
|
|
sprite[j].xvel += 32;
|
|
sprite[j].z += (3<<8);
|
|
}
|
|
|
|
A_SetSprite(j,CLIPMASK0);
|
|
|
|
}
|
|
|
|
void P_DisplayScuba(void)
|
|
{
|
|
if (g_player[screenpeek].ps->scuba_on)
|
|
{
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
if (VM_OnEvent(EVENT_DISPLAYSCUBA, ps->i, screenpeek) != 0)
|
|
return;
|
|
|
|
int32_t p = P_GetHudPal(ps);
|
|
|
|
#ifdef SPLITSCREEN_MOD_HACKS
|
|
g_snum = screenpeek;
|
|
#endif
|
|
#ifdef USE_OPENGL
|
|
if (getrendermode() >= REND_POLYMOST)
|
|
G_DrawTileScaled(44, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+16+DRAWEAP_CENTER, p);
|
|
#endif
|
|
G_DrawTileScaled(43, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+16+DRAWEAP_CENTER, p);
|
|
G_DrawTileScaled(320-43, (200-tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2+4+16+DRAWEAP_CENTER, p);
|
|
}
|
|
}
|
|
|
|
static const int8_t access_tip_y [] ={
|
|
0, -8, -16, -32, -64, -84, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, -96, -72, -64, -32, -16,
|
|
/* EDuke32: */ 0, 16, 32, 48,
|
|
// At y coord 64, the hand is already not shown.
|
|
};
|
|
|
|
static int32_t P_DisplayTip(int32_t gs)
|
|
{
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
if (ps->tipincs == 0)
|
|
return 0;
|
|
|
|
switch (VM_OnEvent(EVENT_DISPLAYTIP, ps->i, screenpeek))
|
|
{
|
|
case 1:
|
|
return 1;
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
// Report that the tipping hand has been drawn so that the otherwise
|
|
// selected weapon is not drawn.
|
|
if ((unsigned)ps->tipincs >= ARRAY_SIZE(access_tip_y))
|
|
return 1;
|
|
|
|
int y, looking_arc, p = 0;
|
|
|
|
looking_arc = (klabs(ps->look_ang) / 9) - (ps->hard_landing << 3);
|
|
|
|
p = P_GetHudPal(ps);
|
|
|
|
y = access_tip_y[ps->tipincs] >> 1;
|
|
|
|
guniqhudid = 201;
|
|
|
|
G_DrawTileScaled(170 + (g_player[screenpeek].sync->avel >> 5) - (ps->look_ang >> 1),
|
|
y + looking_arc + 240 - ((ps->horiz - ps->horizoff) >> 4), TIP + ((26 - ps->tipincs) >> 4), gs,
|
|
DRAWEAP_CENTER, p);
|
|
|
|
guniqhudid = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int32_t P_DisplayAccess(int32_t gs)
|
|
{
|
|
const DukePlayer_t *const ps = g_player[screenpeek].ps;
|
|
|
|
if (ps->access_incs == 0)
|
|
return 0;
|
|
|
|
switch (VM_OnEvent(EVENT_DISPLAYACCESS, ps->i, screenpeek))
|
|
{
|
|
case 1:
|
|
return 1;
|
|
case -1:
|
|
return 0;
|
|
}
|
|
|
|
if ((unsigned)ps->access_incs >= ARRAY_SIZE(access_tip_y)-4 || sprite[ps->i].extra <= 0)
|
|
return 1;
|
|
|
|
int y, looking_arc, p = 0;
|
|
|
|
looking_arc = access_tip_y[ps->access_incs] + (klabs(ps->look_ang) / 9) - (ps->hard_landing << 3);
|
|
|
|
if (ps->access_spritenum >= 0)
|
|
p = sprite[ps->access_spritenum].pal;
|
|
|
|
y = access_tip_y[ps->access_incs] >> 2;
|
|
|
|
guniqhudid = 200;
|
|
|
|
if ((ps->access_incs - 3) > 0 && (ps->access_incs - 3) >> 3)
|
|
{
|
|
G_DrawTileScaled(170 + (g_player[screenpeek].sync->avel >> 5) - (ps->look_ang >> 1) + y,
|
|
looking_arc + 266 - ((ps->horiz - ps->horizoff) >> 4),
|
|
HANDHOLDINGLASER + (ps->access_incs >> 3), gs, DRAWEAP_CENTER, p);
|
|
}
|
|
else
|
|
{
|
|
G_DrawTileScaled(170 + (g_player[screenpeek].sync->avel >> 5) - (ps->look_ang >> 1) + y,
|
|
looking_arc + 266 - ((ps->horiz - ps->horizoff) >> 4), HANDHOLDINGACCESS, gs,
|
|
4 + DRAWEAP_CENTER, p);
|
|
}
|
|
|
|
guniqhudid = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int32_t fistsign;
|
|
|
|
void P_DisplayWeapon(void)
|
|
{
|
|
int32_t gun_pos, looking_arc, cw;
|
|
int32_t weapon_xoffset, i, j;
|
|
int32_t o = 0,pal = 0;
|
|
DukePlayer_t *const p = g_player[screenpeek].ps;
|
|
const uint8_t *const kb = &p->kickback_pic;
|
|
int32_t gs;
|
|
|
|
#ifdef SPLITSCREEN_MOD_HACKS
|
|
g_snum = screenpeek;
|
|
#endif
|
|
|
|
looking_arc = klabs(p->look_ang)/9;
|
|
|
|
gs = sprite[p->i].shade;
|
|
if (gs > 24) gs = 24;
|
|
|
|
if (p->newowner >= 0 || ud.camerasprite >= 0 || p->over_shoulder_on > 0 || (sprite[p->i].pal != 1 && sprite[p->i].extra <= 0))
|
|
return;
|
|
|
|
if (P_DisplayFist(gs) || P_DisplayKnuckles(gs) || P_DisplayTip(gs) || P_DisplayAccess(gs))
|
|
goto enddisplayweapon;
|
|
|
|
P_DisplayKnee(gs);
|
|
|
|
gun_pos = 80-(p->weapon_pos*p->weapon_pos);
|
|
|
|
weapon_xoffset = (160)-90;
|
|
|
|
if (ud.weaponsway)
|
|
{
|
|
weapon_xoffset -= (sintable[((p->weapon_sway>>1)+512)&2047]/(1024+512));
|
|
|
|
if (sprite[p->i].xrepeat < 32)
|
|
gun_pos -= klabs(sintable[(p->weapon_sway<<2)&2047]>>9);
|
|
else gun_pos -= klabs(sintable[(p->weapon_sway>>1)&2047]>>10);
|
|
}
|
|
else gun_pos -= 16;
|
|
|
|
weapon_xoffset -= 58 + p->weapon_ang;
|
|
gun_pos -= (p->hard_landing<<3);
|
|
|
|
cw = PWEAPON(screenpeek, (p->last_weapon >= 0) ? p->last_weapon : p->curr_weapon, WorksLike);
|
|
|
|
hudweap.gunposy=gun_pos;
|
|
hudweap.lookhoriz=looking_arc;
|
|
hudweap.cur=cw;
|
|
hudweap.gunposx=weapon_xoffset;
|
|
hudweap.shade=gs;
|
|
hudweap.count=*kb;
|
|
hudweap.lookhalfang=p->look_ang>>1;
|
|
|
|
if (VM_OnEvent(EVENT_DISPLAYWEAPON, p->i, screenpeek) == 0)
|
|
{
|
|
j = 14-p->quick_kick;
|
|
if ((j != 14 || p->last_quick_kick) && ud.drawweapon == 1)
|
|
{
|
|
pal = P_GetHudPal(p);
|
|
if (pal == 0)
|
|
pal = p->palookup;
|
|
|
|
guniqhudid = 100;
|
|
if (j < 6 || j > 12)
|
|
G_DrawTileScaled(weapon_xoffset+80-(p->look_ang>>1),
|
|
looking_arc+250-gun_pos,KNEE,gs,o|4|DRAWEAP_CENTER,pal);
|
|
else G_DrawTileScaled(weapon_xoffset+160-16-(p->look_ang>>1),
|
|
looking_arc+214-gun_pos,KNEE+1,gs,o|4|DRAWEAP_CENTER,pal);
|
|
guniqhudid = 0;
|
|
}
|
|
|
|
if (sprite[p->i].xrepeat < 40)
|
|
{
|
|
pal = P_GetHudPal(p);
|
|
|
|
if (p->jetpack_on == 0)
|
|
{
|
|
i = sprite[p->i].xvel;
|
|
looking_arc += 32-(i>>3);
|
|
fistsign += i>>3;
|
|
}
|
|
|
|
cw = weapon_xoffset;
|
|
weapon_xoffset += sintable[(fistsign)&2047]>>10;
|
|
G_DrawTileScaled(weapon_xoffset+250-(p->look_ang>>1),
|
|
looking_arc+258-(klabs(sintable[(fistsign)&2047]>>8)),
|
|
FIST,gs,o, pal);
|
|
weapon_xoffset = cw - (sintable[(fistsign)&2047]>>10);
|
|
G_DrawTileScaled(weapon_xoffset+40-(p->look_ang>>1),
|
|
looking_arc+200+(klabs(sintable[(fistsign)&2047]>>8)),
|
|
FIST,gs,o|4, pal);
|
|
}
|
|
else
|
|
{
|
|
switch (ud.drawweapon)
|
|
{
|
|
case 1:
|
|
break;
|
|
|
|
case 2:
|
|
if ((unsigned)hudweap.cur < MAX_WEAPONS && hudweap.cur != KNEE_WEAPON)
|
|
rotatesprite_win(160 << 16, (180 + (p->weapon_pos * p->weapon_pos)) << 16, scale(65536, ud.statusbarscale, 100), 0,
|
|
hudweap.cur == GROW_WEAPON ? GROWSPRITEICON : WeaponPickupSprites[hudweap.cur], 0,
|
|
0, 2);
|
|
default:
|
|
goto enddisplayweapon;
|
|
}
|
|
|
|
const int doanim = !(sprite[p->i].pal == 1 || ud.pause_on || g_player[myconnectindex].ps->gm&MODE_MENU);
|
|
const int hla = p->look_ang >> 1;
|
|
|
|
pal = P_GetHudPal(p);
|
|
|
|
switch (cw)
|
|
{
|
|
case KNEE_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek) || *kb == 0)
|
|
break;
|
|
|
|
if (pal == 0)
|
|
pal = p->palookup;
|
|
|
|
guniqhudid = cw;
|
|
if (*kb < 5 || *kb > 9)
|
|
G_DrawTileScaled(weapon_xoffset + 220 - hla, looking_arc + 250 - gun_pos, KNEE,
|
|
gs, o, pal);
|
|
else
|
|
G_DrawTileScaled(weapon_xoffset + 160 - hla, looking_arc + 214 - gun_pos, KNEE + 1,
|
|
gs, o, pal);
|
|
guniqhudid = 0;
|
|
break;
|
|
|
|
case TRIPBOMB_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
|
|
weapon_xoffset += 8;
|
|
gun_pos -= 10;
|
|
|
|
if ((*kb) > 6)
|
|
looking_arc += ((*kb) << 3);
|
|
else if ((*kb) < 4)
|
|
{
|
|
G_DrawWeaponTileWithID(cw << 2, weapon_xoffset + 142 - hla,
|
|
looking_arc + 234 - gun_pos, HANDHOLDINGLASER + 3, gs, o, pal, 0);
|
|
}
|
|
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 130 - hla, looking_arc + 249 - gun_pos,
|
|
HANDHOLDINGLASER + ((*kb) >> 2), gs, o, pal, 0);
|
|
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 152 - hla,
|
|
looking_arc + 249 - gun_pos, HANDHOLDINGLASER + ((*kb) >> 2), gs, o | 4,
|
|
pal, 0);
|
|
break;
|
|
|
|
case RPG_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON,g_player[screenpeek].ps->i,screenpeek))
|
|
break;
|
|
|
|
weapon_xoffset -= sintable[(768 + ((*kb) << 7)) & 2047] >> 11;
|
|
gun_pos += sintable[(768 + ((*kb) << 7)) & 2047] >> 11;
|
|
|
|
if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING))
|
|
o |= 512;
|
|
|
|
if (*kb > 0 && *kb < 8)
|
|
{
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 164, (looking_arc << 1) + 176 - gun_pos,
|
|
RPGGUN + ((*kb) >> 1), gs, o, pal, 0);
|
|
}
|
|
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 164, (looking_arc << 1) + 176 - gun_pos, RPGGUN, gs,
|
|
o, pal, 0);
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
|
|
weapon_xoffset -= 8;
|
|
|
|
switch (*kb)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 168 - hla, looking_arc + 201 - gun_pos,
|
|
SHOTGUN + 2, -128, o, pal, 0);
|
|
case 0:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 146 - hla, looking_arc + 202 - gun_pos,
|
|
SHOTGUN, gs, o, pal, 0);
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
gun_pos -= 40;
|
|
weapon_xoffset += 20;
|
|
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 178 - hla, looking_arc + 194 - gun_pos,
|
|
SHOTGUN + 1 + ((*(kb)-1) >> 1), -128, o, pal, 0);
|
|
case 5:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 158 - hla, looking_arc + 220 - gun_pos,
|
|
SHOTGUN + 3, gs, o, pal, 0);
|
|
break;
|
|
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
G_DrawWeaponTileWithID(cw, 32 + weapon_xoffset + 166 - hla, looking_arc + 210 - gun_pos,
|
|
SHOTGUN + 4, gs, o, pal, 0);
|
|
break;
|
|
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 24:
|
|
case 25:
|
|
case 26:
|
|
case 27:
|
|
G_DrawWeaponTileWithID(cw, 64 + weapon_xoffset + 170 - hla, looking_arc + 196 - gun_pos,
|
|
SHOTGUN + 5, gs, o, pal, 0);
|
|
break;
|
|
|
|
case 20:
|
|
case 21:
|
|
case 22:
|
|
case 23:
|
|
G_DrawWeaponTileWithID(cw, 64 + weapon_xoffset + 176 - hla, looking_arc + 196 - gun_pos,
|
|
SHOTGUN + 6, gs, o, pal, 0);
|
|
break;
|
|
|
|
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
G_DrawWeaponTileWithID(cw, 32 + weapon_xoffset + 156 - hla, looking_arc + 206 - gun_pos,
|
|
SHOTGUN + 4, gs, o, pal, 0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CHAINGUN_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
|
|
if (*kb > 0)
|
|
{
|
|
gun_pos -= sintable[(*kb)<<7]>>12;
|
|
|
|
if (doanim)
|
|
weapon_xoffset += 1-(rand()&3);
|
|
}
|
|
|
|
switch (*kb)
|
|
{
|
|
case 0:
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos,
|
|
CHAINGUN+1,gs,o,pal,0);
|
|
break;
|
|
|
|
default:
|
|
if (*kb > PWEAPON(screenpeek, CHAINGUN_WEAPON, FireDelay) && *kb < PWEAPON(screenpeek, CHAINGUN_WEAPON, TotalTime))
|
|
{
|
|
i = 0;
|
|
if (doanim) i = rand()&7;
|
|
G_DrawWeaponTileWithID(cw<<2, i+weapon_xoffset-4+140-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos,
|
|
CHAINGUN+5+((*kb-4)/5),gs,o,pal,0);
|
|
if (doanim) i = rand()&7;
|
|
G_DrawWeaponTileWithID(cw<<2, i+weapon_xoffset-4+184-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos,
|
|
CHAINGUN+5+((*kb-4)/5),gs,o,pal,0);
|
|
}
|
|
|
|
if (*kb < PWEAPON(screenpeek, CHAINGUN_WEAPON, TotalTime)-4)
|
|
{
|
|
i = 0;
|
|
if (doanim) i = rand()&7;
|
|
G_DrawWeaponTileWithID(cw<<2, i+weapon_xoffset-4+162-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos,
|
|
CHAINGUN+5+((*kb-2)/5),gs,o,pal,0);
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos,
|
|
CHAINGUN+1+((*kb)>>1),gs,o,pal,0);
|
|
}
|
|
else G_DrawWeaponTileWithID(cw, weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos,
|
|
CHAINGUN+1,gs,o,pal,0);
|
|
|
|
break;
|
|
}
|
|
|
|
G_DrawWeaponTileWithID(cw<<1, weapon_xoffset+168-(p->look_ang>>1),looking_arc+260-gun_pos,
|
|
CHAINGUN,gs,o,pal,0);
|
|
break;
|
|
|
|
case PISTOL_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON,g_player[screenpeek].ps->i,screenpeek))
|
|
break;
|
|
|
|
if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, TotalTime)+1)
|
|
{
|
|
static uint8_t kb_frames [] ={ 0, 1, 2 };
|
|
int32_t l = 195-12+weapon_xoffset;
|
|
|
|
if ((*kb) == PWEAPON(screenpeek, PISTOL_WEAPON, FireDelay))
|
|
l -= 3;
|
|
|
|
G_DrawWeaponTileWithID(cw, (l-(p->look_ang>>1)), (looking_arc+244-gun_pos), FIRSTGUN+kb_frames[*kb>2 ? 0 : *kb], gs, 2, pal, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING))
|
|
o |= 512;
|
|
|
|
if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload)-17)
|
|
G_DrawWeaponTileWithID(cw, 194-(p->look_ang>>1), looking_arc+230-gun_pos, FIRSTGUN+4, gs, o, pal, 0);
|
|
else if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload)-12)
|
|
{
|
|
G_DrawWeaponTileWithID(cw<<1, 244-((*kb)<<3)-(p->look_ang>>1), looking_arc+130-gun_pos+((*kb)<<4), FIRSTGUN+6, gs, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw, 224-(p->look_ang>>1), looking_arc+220-gun_pos, FIRSTGUN+5, gs, o, pal, 0);
|
|
}
|
|
else if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload)-7)
|
|
{
|
|
G_DrawWeaponTileWithID(cw<<1, 124+((*kb)<<1)-(p->look_ang>>1), looking_arc+430-gun_pos-((*kb)<<3), FIRSTGUN+6, gs, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw, 224-(p->look_ang>>1), looking_arc+220-gun_pos, FIRSTGUN+5, gs, o, pal, 0);
|
|
}
|
|
|
|
else if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload)-4)
|
|
{
|
|
G_DrawWeaponTileWithID(cw<<2, 184-(p->look_ang>>1), looking_arc+235-gun_pos, FIRSTGUN+8, gs, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw, 224-(p->look_ang>>1), looking_arc+210-gun_pos, FIRSTGUN+5, gs, o, pal, 0);
|
|
}
|
|
else if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload)-2)
|
|
{
|
|
G_DrawWeaponTileWithID(cw<<2, 164-(p->look_ang>>1), looking_arc+245-gun_pos, FIRSTGUN+8, gs, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw, 224-(p->look_ang>>1), looking_arc+220-gun_pos, FIRSTGUN+5, gs, o, pal, 0);
|
|
}
|
|
else if ((*kb) < PWEAPON(screenpeek, PISTOL_WEAPON, Reload))
|
|
G_DrawWeaponTileWithID(cw, 194-(p->look_ang>>1), looking_arc+235-gun_pos, FIRSTGUN+5, gs, o, pal, 0);
|
|
|
|
break;
|
|
|
|
case HANDBOMB_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
else
|
|
{
|
|
static uint8_t throw_frames [] ={ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
|
|
|
|
if (*kb >= PWEAPON(screenpeek, p->curr_weapon, TotalTime) || *kb >= ARRAY_SIZE(throw_frames))
|
|
break;
|
|
|
|
if (*kb)
|
|
{
|
|
if ((*kb) < 7)
|
|
gun_pos -= 10 * (*kb); // D
|
|
else if ((*kb) < 12)
|
|
gun_pos += 20 * ((*kb) - 10); // U
|
|
else if ((*kb) < 20)
|
|
gun_pos -= 9 * ((*kb) - 14); // D
|
|
|
|
gun_pos += 10;
|
|
}
|
|
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 190 - hla, looking_arc + 260 - gun_pos,
|
|
HANDTHROW + throw_frames[(*kb)], gs, o, pal, 0);
|
|
}
|
|
break;
|
|
|
|
case HANDREMOTE_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON,g_player[screenpeek].ps->i,screenpeek))
|
|
break;
|
|
else
|
|
{
|
|
static uint8_t remote_frames [] ={ 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, 0 };
|
|
|
|
if (*kb >= ARRAY_SIZE(remote_frames))
|
|
break;
|
|
|
|
weapon_xoffset = -48;
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 150 - hla, looking_arc + 258 - gun_pos,
|
|
HANDREMOTE + remote_frames[(*kb)], gs, o, pal, 0);
|
|
}
|
|
break;
|
|
|
|
case DEVISTATOR_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
|
|
if ((*kb) < (PWEAPON(screenpeek, DEVISTATOR_WEAPON, TotalTime) + 1) && (*kb) > 0)
|
|
{
|
|
static uint8_t cycloidy [] ={ 0, 4, 12, 24, 12, 4, 0 };
|
|
|
|
if (*kb >= ARRAY_SIZE(cycloidy))
|
|
break;
|
|
|
|
i = ksgn((*kb) >> 2);
|
|
|
|
if (p->hbomb_hold_delay)
|
|
{
|
|
G_DrawWeaponTileWithID(
|
|
cw, (cycloidy[*kb] >> 1) + weapon_xoffset + 268 - hla,
|
|
cycloidy[*kb] + looking_arc + 238 - gun_pos, DEVISTATOR + i, -32, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 30 - hla,
|
|
looking_arc + 240 - gun_pos, DEVISTATOR, gs, o | 4, pal, 0);
|
|
}
|
|
else
|
|
{
|
|
G_DrawWeaponTileWithID(cw<<1, -(cycloidy[*kb] >> 1) + weapon_xoffset + 30 - hla,
|
|
cycloidy[*kb] + looking_arc + 240 - gun_pos, DEVISTATOR + i, -32, o | 4,
|
|
pal, 0);
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 268 - hla, looking_arc + 238 - gun_pos,
|
|
DEVISTATOR, gs, o, pal, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 268 - hla, looking_arc + 238 - gun_pos,
|
|
DEVISTATOR, gs, o, pal, 0);
|
|
G_DrawWeaponTileWithID(cw<<1, weapon_xoffset + 30 - hla, looking_arc + 240 - gun_pos,
|
|
DEVISTATOR, gs, o | 4, pal, 0);
|
|
}
|
|
break;
|
|
|
|
case FREEZE_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON,g_player[screenpeek].ps->i,screenpeek))
|
|
break;
|
|
|
|
if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING))
|
|
o |= 512;
|
|
|
|
if ((*kb) < (PWEAPON(screenpeek, p->curr_weapon, TotalTime)+1) && (*kb) > 0)
|
|
{
|
|
static uint8_t cat_frames[] = { 0,0,1,1,2,2 };
|
|
|
|
if (*kb%6 >= ARRAY_SIZE(cat_frames))
|
|
break;
|
|
|
|
if (doanim)
|
|
{
|
|
weapon_xoffset += rand()&3;
|
|
looking_arc += rand()&3;
|
|
}
|
|
gun_pos -= 16;
|
|
G_DrawWeaponTileWithID(cw<<1, weapon_xoffset+210-(p->look_ang>>1),looking_arc+261-gun_pos,FREEZE+2,-32,o,pal,0);
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset+210-(p->look_ang>>1),looking_arc+235-gun_pos,FREEZE+3+cat_frames[*kb%6],-32,o,pal,0);
|
|
}
|
|
else
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset+210-(p->look_ang>>1),looking_arc+261-gun_pos,FREEZE,gs,o,pal,0);
|
|
break;
|
|
|
|
case GROW_WEAPON:
|
|
case SHRINKER_WEAPON:
|
|
if (VM_OnEvent(EVENT_DRAWWEAPON, g_player[screenpeek].ps->i, screenpeek))
|
|
break;
|
|
|
|
weapon_xoffset += 28;
|
|
looking_arc += 18;
|
|
|
|
if ((*kb) < PWEAPON(screenpeek, p->curr_weapon, TotalTime) && (*kb) > 0)
|
|
{
|
|
if (doanim)
|
|
{
|
|
weapon_xoffset += rand() & 3;
|
|
gun_pos += (rand() & 3);
|
|
}
|
|
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 184 - hla, looking_arc + 240 - gun_pos,
|
|
SHRINKER + 3 + ((*kb) & 3), -32, o, cw == GROW_WEAPON ? 2 : 0, 1);
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 188 - hla, looking_arc + 240 - gun_pos,
|
|
cw == GROW_WEAPON ? SHRINKER - 1 : SHRINKER + 1, gs, o, pal, 0);
|
|
}
|
|
else
|
|
{
|
|
G_DrawWeaponTileWithID(cw << 1, weapon_xoffset + 184 - hla, looking_arc + 240 - gun_pos,
|
|
SHRINKER + 2, 16 - (sintable[p->random_club_frame & 2047] >> 10), o,
|
|
cw == GROW_WEAPON ? 2 : 0, 1);
|
|
G_DrawWeaponTileWithID(cw, weapon_xoffset + 188 - hla, looking_arc + 240 - gun_pos,
|
|
cw == GROW_WEAPON ? SHRINKER - 2 : SHRINKER, gs, o, pal, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
enddisplayweapon:
|
|
P_DisplaySpit();
|
|
}
|
|
|
|
#define TURBOTURNTIME (TICRATE/8) // 7
|
|
#define NORMALTURN 15
|
|
#define PREAMBLETURN 5
|
|
#define NORMALKEYMOVE 40
|
|
#define MAXVEL ((NORMALKEYMOVE*2)+10)
|
|
#define MAXSVEL ((NORMALKEYMOVE*2)+10)
|
|
#define MAXANGVEL 255
|
|
#define MAXHORIZ 127
|
|
|
|
int32_t g_myAimMode = 0, g_myAimStat = 0, g_oldAimStat = 0;
|
|
int32_t mouseyaxismode = -1;
|
|
int32_t g_emuJumpTics = 0;
|
|
|
|
void P_GetInput(int32_t snum)
|
|
{
|
|
int32_t j;
|
|
static ControlInfo info[2];
|
|
static int32_t turnheldtime; //MED
|
|
static int32_t lastcontroltime; //MED
|
|
|
|
int32_t tics, running;
|
|
int32_t turnamount;
|
|
int32_t keymove;
|
|
DukePlayer_t *p = g_player[snum].ps;
|
|
static input_t in;
|
|
|
|
if ((p->gm & (MODE_MENU|MODE_TYPE)) || (ud.pause_on && !KB_KeyPressed(sc_Pause)))
|
|
{
|
|
if (!(p->gm&MODE_MENU))
|
|
CONTROL_GetInput(&info[0]);
|
|
|
|
Bmemset(&info[1], 0, sizeof(input_t));
|
|
Bmemset(&loc, 0, sizeof(input_t));
|
|
loc.bits = (((int32_t)g_gameQuit)<<SK_GAMEQUIT);
|
|
loc.extbits = (g_player[snum].pteam != g_player[snum].ps->team)<<6;
|
|
loc.extbits |= (1<<7);
|
|
|
|
return;
|
|
}
|
|
|
|
if (ud.mouseaiming)
|
|
g_myAimMode = BUTTON(gamefunc_Mouse_Aiming);
|
|
else
|
|
{
|
|
g_oldAimStat = g_myAimStat;
|
|
g_myAimStat = BUTTON(gamefunc_Mouse_Aiming);
|
|
if (g_myAimStat > g_oldAimStat)
|
|
{
|
|
g_myAimMode ^= 1;
|
|
P_DoQuote(QUOTE_MOUSE_AIMING_OFF+g_myAimMode,p);
|
|
}
|
|
}
|
|
|
|
j = (g_myAimMode) ? analog_lookingupanddown : ud.config.MouseAnalogueAxes[1];
|
|
|
|
if (j != mouseyaxismode)
|
|
{
|
|
CONTROL_MapAnalogAxis(1, j, controldevice_mouse);
|
|
mouseyaxismode = j;
|
|
}
|
|
|
|
CONTROL_GetInput(&info[0]);
|
|
|
|
if (ud.config.MouseDeadZone)
|
|
{
|
|
if (info[0].dpitch > 0)
|
|
{
|
|
if (info[0].dpitch > ud.config.MouseDeadZone)
|
|
info[0].dpitch -= ud.config.MouseDeadZone;
|
|
else info[0].dpitch = 0;
|
|
}
|
|
else if (info[0].dpitch < 0)
|
|
{
|
|
if (info[0].dpitch < -ud.config.MouseDeadZone)
|
|
info[0].dpitch += ud.config.MouseDeadZone;
|
|
else info[0].dpitch = 0;
|
|
}
|
|
if (info[0].dyaw > 0)
|
|
{
|
|
if (info[0].dyaw > ud.config.MouseDeadZone)
|
|
info[0].dyaw -= ud.config.MouseDeadZone;
|
|
else info[0].dyaw = 0;
|
|
}
|
|
else if (info[0].dyaw < 0)
|
|
{
|
|
if (info[0].dyaw < -ud.config.MouseDeadZone)
|
|
info[0].dyaw += ud.config.MouseDeadZone;
|
|
else info[0].dyaw = 0;
|
|
}
|
|
}
|
|
|
|
if (ud.config.MouseBias)
|
|
{
|
|
if (klabs(info[0].dyaw) > klabs(info[0].dpitch))
|
|
info[0].dpitch = tabledivide32_noinline(info[0].dpitch, ud.config.MouseBias);
|
|
else info[0].dyaw = tabledivide32_noinline(info[0].dyaw, ud.config.MouseBias);
|
|
}
|
|
|
|
tics = totalclock-lastcontroltime;
|
|
lastcontroltime = totalclock;
|
|
|
|
// JBF: Run key behaviour is selectable
|
|
running = (ud.runkey_mode) ? (BUTTON(gamefunc_Run) | ud.auto_run) : (ud.auto_run ^ BUTTON(gamefunc_Run));
|
|
|
|
in.svel = in.fvel = in.avel = in.horz = 0;
|
|
|
|
if (BUTTON(gamefunc_Strafe))
|
|
{
|
|
in.svel = -(info[0].dyaw+info[1].dyaw)/8;
|
|
info[1].dyaw = (info[1].dyaw+info[0].dyaw) % 8;
|
|
}
|
|
else
|
|
{
|
|
in.avel = (info[0].dyaw+info[1].dyaw)/32;
|
|
info[1].dyaw = (info[1].dyaw+info[0].dyaw) % 32;
|
|
}
|
|
|
|
if (ud.mouseflip)
|
|
in.horz = -(info[0].dpitch+info[1].dpitch)/(314-128);
|
|
else in.horz = (info[0].dpitch+info[1].dpitch)/(314-128);
|
|
|
|
info[1].dpitch = (info[1].dpitch+info[0].dpitch) % (314-128);
|
|
|
|
in.svel -= info[0].dx;
|
|
info[1].dz = info[0].dz % (1<<6);
|
|
in.fvel = -info[0].dz>>6;
|
|
|
|
// OSD_Printf("running: %d\n", running);
|
|
if (running)
|
|
{
|
|
turnamount = NORMALTURN<<1;
|
|
keymove = NORMALKEYMOVE<<1;
|
|
}
|
|
else
|
|
{
|
|
turnamount = NORMALTURN;
|
|
keymove = NORMALKEYMOVE;
|
|
}
|
|
|
|
if (BUTTON(gamefunc_Strafe))
|
|
{
|
|
if (BUTTON(gamefunc_Turn_Left) && !(g_player[snum].ps->movement_lock&4))
|
|
in.svel -= -keymove;
|
|
if (BUTTON(gamefunc_Turn_Right) && !(g_player[snum].ps->movement_lock&8))
|
|
in.svel -= keymove;
|
|
}
|
|
else
|
|
{
|
|
if (BUTTON(gamefunc_Turn_Left))
|
|
{
|
|
turnheldtime += tics;
|
|
in.avel -= (turnheldtime>=TURBOTURNTIME) ? (turnamount<<1) : (PREAMBLETURN<<1);
|
|
}
|
|
else if (BUTTON(gamefunc_Turn_Right))
|
|
{
|
|
turnheldtime += tics;
|
|
in.avel += (turnheldtime>=TURBOTURNTIME) ? (turnamount<<1) : (PREAMBLETURN<<1);
|
|
}
|
|
else
|
|
turnheldtime=0;
|
|
}
|
|
|
|
if (BUTTON(gamefunc_Strafe_Left) && !(g_player[snum].ps->movement_lock&4))
|
|
in.svel += keymove;
|
|
if (BUTTON(gamefunc_Strafe_Right) && !(g_player[snum].ps->movement_lock&8))
|
|
in.svel += -keymove;
|
|
if (BUTTON(gamefunc_Move_Forward) && !(g_player[snum].ps->movement_lock&1))
|
|
in.fvel += keymove;
|
|
if (BUTTON(gamefunc_Move_Backward) && !(g_player[snum].ps->movement_lock&2))
|
|
in.fvel += -keymove;
|
|
|
|
in.fvel = clamp(in.fvel, -MAXVEL, MAXVEL);
|
|
in.svel = clamp(in.svel, -MAXSVEL, MAXSVEL);
|
|
in.avel = clamp(in.avel, -MAXANGVEL, MAXANGVEL);
|
|
in.horz = clamp(in.horz, -MAXHORIZ, MAXHORIZ);
|
|
|
|
for (j = gamefunc_Weapon_10; j >= gamefunc_Weapon_1; j--)
|
|
{
|
|
if (BUTTON(j))
|
|
{
|
|
j -= (gamefunc_Weapon_1 - 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j == gamefunc_Weapon_1-1)
|
|
j = 0;
|
|
|
|
if (BUTTON(gamefunc_Previous_Weapon) || (BUTTON(gamefunc_Dpad_Select) && in.fvel < 0))
|
|
j = 11;
|
|
if (BUTTON(gamefunc_Next_Weapon) || (BUTTON(gamefunc_Dpad_Select) && in.fvel > 0))
|
|
j = 12;
|
|
|
|
if (BUTTON(gamefunc_Jump) && p->on_ground)
|
|
g_emuJumpTics = 4;
|
|
|
|
loc.bits = (g_emuJumpTics > 0 || BUTTON(gamefunc_Jump))<<SK_JUMP;
|
|
|
|
if (g_emuJumpTics > 0)
|
|
g_emuJumpTics--;
|
|
|
|
loc.bits |= BUTTON(gamefunc_Crouch)<<SK_CROUCH;
|
|
loc.bits |= BUTTON(gamefunc_Fire)<<SK_FIRE;
|
|
loc.bits |= (BUTTON(gamefunc_Aim_Up) || (BUTTON(gamefunc_Dpad_Aiming) && in.fvel > 0))<<SK_AIM_UP;
|
|
loc.bits |= (BUTTON(gamefunc_Aim_Down) || (BUTTON(gamefunc_Dpad_Aiming) && in.fvel < 0))<<SK_AIM_DOWN;
|
|
loc.bits |= ((ud.runkey_mode) ? (ud.auto_run | BUTTON(gamefunc_Run)) : (BUTTON(gamefunc_Run) ^ ud.auto_run))<<SK_RUN;
|
|
loc.bits |= BUTTON(gamefunc_Look_Left)<<SK_LOOK_LEFT;
|
|
loc.bits |= BUTTON(gamefunc_Look_Right)<<SK_LOOK_RIGHT;
|
|
loc.bits |= j<<SK_WEAPON_BITS;
|
|
loc.bits |= BUTTON(gamefunc_Steroids)<<SK_STEROIDS;
|
|
loc.bits |= BUTTON(gamefunc_Look_Up)<<SK_LOOK_UP;
|
|
loc.bits |= BUTTON(gamefunc_Look_Down)<<SK_LOOK_DOWN;
|
|
loc.bits |= BUTTON(gamefunc_NightVision)<<SK_NIGHTVISION;
|
|
loc.bits |= BUTTON(gamefunc_MedKit)<<SK_MEDKIT;
|
|
loc.bits |= BUTTON(gamefunc_Center_View)<<SK_CENTER_VIEW;
|
|
loc.bits |= BUTTON(gamefunc_Holster_Weapon)<<SK_HOLSTER;
|
|
loc.bits |= (BUTTON(gamefunc_Inventory_Left) || (BUTTON(gamefunc_Dpad_Select) && (in.svel > 0 || in.avel < 0))) <<SK_INV_LEFT;
|
|
loc.bits |= KB_KeyPressed(sc_Pause)<<SK_PAUSE;
|
|
loc.bits |= BUTTON(gamefunc_Quick_Kick)<<SK_QUICK_KICK;
|
|
loc.bits |= g_myAimMode<<SK_AIMMODE;
|
|
loc.bits |= BUTTON(gamefunc_Holo_Duke)<<SK_HOLODUKE;
|
|
loc.bits |= BUTTON(gamefunc_Jetpack)<<SK_JETPACK;
|
|
loc.bits |= (g_gameQuit<<SK_GAMEQUIT);
|
|
loc.bits |= (BUTTON(gamefunc_Inventory_Right) || (BUTTON(gamefunc_Dpad_Select) && (in.svel < 0 || in.avel > 0))) <<SK_INV_RIGHT;
|
|
loc.bits |= BUTTON(gamefunc_TurnAround)<<SK_TURNAROUND;
|
|
loc.bits |= BUTTON(gamefunc_Open)<<SK_OPEN;
|
|
loc.bits |= BUTTON(gamefunc_Inventory)<<SK_INVENTORY;
|
|
loc.bits |= ((uint32_t)KB_KeyPressed(sc_Escape))<<SK_ESCAPE;
|
|
|
|
if (BUTTON(gamefunc_Dpad_Select))
|
|
in.fvel = in.svel = in.avel = 0;
|
|
|
|
if (BUTTON(gamefunc_Dpad_Aiming))
|
|
in.fvel = 0;
|
|
|
|
if (PWEAPON(snum, g_player[snum].ps->curr_weapon, Flags) & WEAPON_SEMIAUTO && BUTTON(gamefunc_Fire))
|
|
CONTROL_ClearButton(gamefunc_Fire);
|
|
|
|
loc.extbits = (BUTTON(gamefunc_Move_Forward) || (in.fvel > 0));
|
|
loc.extbits |= (BUTTON(gamefunc_Move_Backward) || (in.fvel < 0))<<1;
|
|
loc.extbits |= (BUTTON(gamefunc_Strafe_Left) || (in.svel > 0))<<2;
|
|
loc.extbits |= (BUTTON(gamefunc_Strafe_Right) || (in.svel < 0))<<3;
|
|
|
|
if (VM_HaveEvent(EVENT_PROCESSINPUT) || VM_HaveEvent(EVENT_TURNLEFT))
|
|
loc.extbits |= BUTTON(gamefunc_Turn_Left)<<4;
|
|
|
|
if (VM_HaveEvent(EVENT_PROCESSINPUT) || VM_HaveEvent(EVENT_TURNRIGHT))
|
|
loc.extbits |= BUTTON(gamefunc_Turn_Right)<<5;
|
|
|
|
// used for changing team
|
|
loc.extbits |= (g_player[snum].pteam != g_player[snum].ps->team)<<6;
|
|
|
|
if (ud.scrollmode && ud.overhead_on)
|
|
{
|
|
ud.folfvel = in.fvel;
|
|
ud.folavel = in.avel;
|
|
loc.fvel = loc.svel = loc.avel = loc.horz = 0;
|
|
return;
|
|
}
|
|
|
|
loc.fvel =
|
|
mulscale9(in.fvel, sintable[(p->ang + 2560) & 2047]) + (mulscale9(in.svel, sintable[(p->ang + 2048) & 2047]));
|
|
loc.svel =
|
|
mulscale9(in.fvel, sintable[(p->ang + 2048) & 2047]) + (mulscale9(in.svel, sintable[(p->ang + 1536) & 2047]));
|
|
|
|
loc.avel = in.avel;
|
|
loc.horz = in.horz;
|
|
}
|
|
|
|
static int32_t P_DoCounters(int32_t snum)
|
|
{
|
|
DukePlayer_t *const p = g_player[snum].ps;
|
|
|
|
// j = g_player[snum].sync->avel;
|
|
// p->weapon_ang = -(j/5);
|
|
|
|
if (p->invdisptime > 0)
|
|
p->invdisptime--;
|
|
|
|
if (p->tipincs > 0)
|
|
p->tipincs--;
|
|
|
|
if (p->last_pissed_time > 0)
|
|
{
|
|
switch (--p->last_pissed_time)
|
|
{
|
|
case GAMETICSPERSEC*219:
|
|
{
|
|
A_PlaySound(FLUSH_TOILET,p->i);
|
|
if (snum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND))
|
|
A_PlaySound(DUKE_PISSRELIEF,p->i);
|
|
}
|
|
break;
|
|
case GAMETICSPERSEC*218:
|
|
{
|
|
p->holster_weapon = 0;
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p->crack_time > 0)
|
|
{
|
|
if (--p->crack_time == 0)
|
|
{
|
|
p->knuckle_incs = 1;
|
|
p->crack_time = 777;
|
|
}
|
|
}
|
|
|
|
if (p->inv_amount[GET_STEROIDS] > 0 && p->inv_amount[GET_STEROIDS] < 400)
|
|
{
|
|
if (--p->inv_amount[GET_STEROIDS] == 0)
|
|
P_SelectNextInvItem(p);
|
|
|
|
if (!(p->inv_amount[GET_STEROIDS]&7))
|
|
if (snum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND))
|
|
A_PlaySound(DUKE_HARTBEAT,p->i);
|
|
}
|
|
|
|
if (p->heat_on && p->inv_amount[GET_HEATS] > 0)
|
|
{
|
|
if (--p->inv_amount[GET_HEATS] == 0)
|
|
{
|
|
p->heat_on = 0;
|
|
P_SelectNextInvItem(p);
|
|
A_PlaySound(NITEVISION_ONOFF,p->i);
|
|
P_UpdateScreenPal(p);
|
|
}
|
|
}
|
|
|
|
if (p->holoduke_on >= 0)
|
|
{
|
|
if (--p->inv_amount[GET_HOLODUKE] <= 0)
|
|
{
|
|
A_PlaySound(TELEPORTER,p->i);
|
|
p->holoduke_on = -1;
|
|
P_SelectNextInvItem(p);
|
|
}
|
|
}
|
|
|
|
if (p->jetpack_on && p->inv_amount[GET_JETPACK] > 0)
|
|
{
|
|
if (--p->inv_amount[GET_JETPACK] <= 0)
|
|
{
|
|
p->jetpack_on = 0;
|
|
P_SelectNextInvItem(p);
|
|
A_PlaySound(DUKE_JETPACK_OFF,p->i);
|
|
S_StopEnvSound(DUKE_JETPACK_IDLE,p->i);
|
|
S_StopEnvSound(DUKE_JETPACK_ON,p->i);
|
|
}
|
|
}
|
|
|
|
if (p->quick_kick > 0 && sprite[p->i].pal != 1)
|
|
{
|
|
p->last_quick_kick = p->quick_kick+1;
|
|
|
|
if (--p->quick_kick == 8)
|
|
A_Shoot(p->i,KNEE);
|
|
}
|
|
else if (p->last_quick_kick > 0) p->last_quick_kick--;
|
|
|
|
if (p->access_incs && sprite[p->i].pal != 1)
|
|
{
|
|
p->access_incs++;
|
|
if (sprite[p->i].extra <= 0)
|
|
p->access_incs = 12;
|
|
|
|
if (p->access_incs == 12)
|
|
{
|
|
if (p->access_spritenum >= 0)
|
|
{
|
|
P_ActivateSwitch(snum,p->access_spritenum,1);
|
|
switch (sprite[p->access_spritenum].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 = -1;
|
|
}
|
|
else
|
|
{
|
|
P_ActivateSwitch(snum,p->access_wallnum,0);
|
|
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->weapon_pos = WEAPON_POS_RAISE;
|
|
p->kickback_pic = 0;
|
|
}
|
|
}
|
|
|
|
if (p->cursectnum >= 0 && p->scuba_on == 0 && sector[p->cursectnum].lotag == ST_2_UNDERWATER)
|
|
{
|
|
if (p->inv_amount[GET_SCUBA] > 0)
|
|
{
|
|
p->scuba_on = 1;
|
|
p->inven_icon = ICON_SCUBA;
|
|
P_DoQuote(QUOTE_SCUBA_ON,p);
|
|
}
|
|
else
|
|
{
|
|
if (p->airleft > 0)
|
|
p->airleft--;
|
|
else
|
|
{
|
|
p->extra_extra8 += 32;
|
|
if (p->last_extra < (p->max_player_health>>1) && (p->last_extra&3) == 0)
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
}
|
|
}
|
|
}
|
|
else if (p->inv_amount[GET_SCUBA] > 0 && p->scuba_on)
|
|
{
|
|
p->inv_amount[GET_SCUBA]--;
|
|
if (p->inv_amount[GET_SCUBA] == 0)
|
|
{
|
|
p->scuba_on = 0;
|
|
P_SelectNextInvItem(p);
|
|
}
|
|
}
|
|
|
|
if (p->knuckle_incs)
|
|
{
|
|
if (++p->knuckle_incs == 10)
|
|
{
|
|
if (totalclock > 1024)
|
|
if (snum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND))
|
|
{
|
|
|
|
if (rand()&1)
|
|
A_PlaySound(DUKE_CRACK,p->i);
|
|
else A_PlaySound(DUKE_CRACK2,p->i);
|
|
|
|
}
|
|
|
|
A_PlaySound(DUKE_CRACK_FIRST,p->i);
|
|
|
|
}
|
|
else if (p->knuckle_incs == 22 || TEST_SYNC_KEY(g_player[snum].sync->bits, SK_FIRE))
|
|
p->knuckle_incs=0;
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int16_t WeaponPickupSprites[MAX_WEAPONS] = { KNEE__STATIC, FIRSTGUNSPRITE__STATIC, SHOTGUNSPRITE__STATIC,
|
|
CHAINGUNSPRITE__STATIC, RPGSPRITE__STATIC, HEAVYHBOMB__STATIC, SHRINKERSPRITE__STATIC, DEVISTATORSPRITE__STATIC,
|
|
TRIPBOMBSPRITE__STATIC, FREEZESPRITE__STATIC, HEAVYHBOMB__STATIC, SHRINKERSPRITE__STATIC
|
|
};
|
|
// this is used for player deaths
|
|
void P_DropWeapon(int32_t snum)
|
|
{
|
|
const DukePlayer_t *const p = g_player[snum].ps;
|
|
int32_t cw = PWEAPON(snum, p->curr_weapon, WorksLike);
|
|
|
|
if ((unsigned)cw >= MAX_WEAPONS)
|
|
return;
|
|
|
|
if (krand()&1)
|
|
A_Spawn(p->i, WeaponPickupSprites[cw]);
|
|
else switch (cw)
|
|
{
|
|
case RPG_WEAPON:
|
|
case HANDBOMB_WEAPON:
|
|
A_Spawn(p->i, EXPLOSION2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void P_AddAmmo(int32_t weapon,DukePlayer_t *p,int32_t amount)
|
|
{
|
|
p->ammo_amount[weapon] += amount;
|
|
|
|
if (p->ammo_amount[weapon] > p->max_ammo_amount[weapon])
|
|
p->ammo_amount[weapon] = p->max_ammo_amount[weapon];
|
|
}
|
|
|
|
static void P_AddWeaponNoSwitch(DukePlayer_t *p, int32_t weapon)
|
|
{
|
|
int32_t snum = P_Get(p->i); // PASS_SNUM?
|
|
|
|
if ((p->gotweapon & (1<<weapon)) == 0)
|
|
{
|
|
p->gotweapon |= (1<<weapon);
|
|
|
|
if (weapon == SHRINKER_WEAPON)
|
|
p->gotweapon |= (1<<GROW_WEAPON);
|
|
}
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, SelectSound) > 0)
|
|
S_StopEnvSound(PWEAPON(snum, p->curr_weapon, SelectSound),p->i);
|
|
|
|
if (PWEAPON(snum, weapon, SelectSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, weapon, SelectSound),p->i);
|
|
}
|
|
|
|
static void P_ChangeWeapon(DukePlayer_t *p, int32_t weapon)
|
|
{
|
|
int32_t i = 0, snum = P_Get(p->i); // PASS_SNUM?
|
|
const int8_t curr_weapon = p->curr_weapon;
|
|
|
|
if (p->reloading)
|
|
return;
|
|
|
|
if (p->curr_weapon != weapon && VM_HaveEvent(EVENT_CHANGEWEAPON))
|
|
i = VM_OnEventWithReturn(EVENT_CHANGEWEAPON,p->i, snum, weapon);
|
|
|
|
if (i == -1)
|
|
return;
|
|
|
|
if (i != -2)
|
|
p->curr_weapon = weapon;
|
|
|
|
|
|
p->random_club_frame = 0;
|
|
|
|
if (p->weapon_pos == 0)
|
|
{
|
|
p->weapon_pos = -1;
|
|
p->last_weapon = curr_weapon;
|
|
}
|
|
else if ((unsigned)p->weapon_pos < WEAPON_POS_RAISE)
|
|
{
|
|
p->weapon_pos = -p->weapon_pos;
|
|
p->last_weapon = curr_weapon;
|
|
}
|
|
else if (p->last_weapon == weapon)
|
|
{
|
|
p->last_weapon = -1;
|
|
p->weapon_pos = -p->weapon_pos;
|
|
}
|
|
|
|
if (p->holster_weapon)
|
|
{
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
p->holster_weapon = 0;
|
|
p->last_weapon = -1;
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
if (curr_weapon != p->curr_weapon &&
|
|
// p->last_weapon != -1 &&
|
|
!(PWEAPON(snum, curr_weapon, WorksLike) == HANDREMOTE_WEAPON && PWEAPON(snum, p->curr_weapon, WorksLike) == HANDBOMB_WEAPON) &&
|
|
!(PWEAPON(snum, curr_weapon, WorksLike) == HANDBOMB_WEAPON && PWEAPON(snum, p->curr_weapon, WorksLike) == HANDREMOTE_WEAPON))
|
|
CONTROL_Android_SetLastWeapon(PWEAPON(snum, curr_weapon, WorksLike) == HANDREMOTE_WEAPON ? (int)HANDBOMB_WEAPON : curr_weapon);
|
|
#endif
|
|
|
|
p->kickback_pic = 0;
|
|
|
|
P_SetWeaponGamevars(snum, p);
|
|
}
|
|
|
|
void P_AddWeapon(DukePlayer_t *p, int32_t weapon, int32_t doswitch)
|
|
{
|
|
P_AddWeaponNoSwitch(p, weapon);
|
|
if (doswitch)
|
|
P_ChangeWeapon(p, weapon);
|
|
}
|
|
|
|
void P_SelectNextInvItem(DukePlayer_t *p)
|
|
{
|
|
if (p->inv_amount[GET_FIRSTAID] > 0)
|
|
p->inven_icon = ICON_FIRSTAID;
|
|
else if (p->inv_amount[GET_STEROIDS] > 0)
|
|
p->inven_icon = ICON_STEROIDS;
|
|
else if (p->inv_amount[GET_JETPACK] > 0)
|
|
p->inven_icon = ICON_JETPACK;
|
|
else if (p->inv_amount[GET_HOLODUKE] > 0)
|
|
p->inven_icon = ICON_HOLODUKE;
|
|
else if (p->inv_amount[GET_HEATS] > 0)
|
|
p->inven_icon = ICON_HEATS;
|
|
else if (p->inv_amount[GET_SCUBA] > 0)
|
|
p->inven_icon = ICON_SCUBA;
|
|
else if (p->inv_amount[GET_BOOTS] > 0)
|
|
p->inven_icon = ICON_BOOTS;
|
|
else p->inven_icon = ICON_NONE;
|
|
}
|
|
|
|
void P_CheckWeapon(DukePlayer_t *p)
|
|
{
|
|
int32_t i, snum, weapon;
|
|
|
|
if (p->reloading)
|
|
return;
|
|
|
|
if (p->wantweaponfire >= 0)
|
|
{
|
|
weapon = p->wantweaponfire;
|
|
p->wantweaponfire = -1;
|
|
|
|
if (weapon == p->curr_weapon)
|
|
return;
|
|
|
|
if ((p->gotweapon & (1<<weapon)) && p->ammo_amount[weapon] > 0)
|
|
{
|
|
P_AddWeapon(p, weapon, 1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
weapon = p->curr_weapon;
|
|
|
|
if ((p->gotweapon & (1<<weapon)) && (p->ammo_amount[weapon] > 0 || !(p->weaponswitch & 2)))
|
|
return;
|
|
|
|
snum = P_Get(p->i);
|
|
|
|
for (i=0; i<=FREEZE_WEAPON; i++)
|
|
{
|
|
weapon = g_player[snum].wchoice[i];
|
|
if (VOLUMEONE && weapon > SHRINKER_WEAPON)
|
|
continue;
|
|
|
|
if (weapon == KNEE_WEAPON)
|
|
weapon = FREEZE_WEAPON;
|
|
else weapon--;
|
|
|
|
if (weapon == KNEE_WEAPON || ((p->gotweapon & (1<<weapon)) && p->ammo_amount[weapon] > 0))
|
|
break;
|
|
}
|
|
|
|
if (i == HANDREMOTE_WEAPON)
|
|
weapon = KNEE_WEAPON;
|
|
|
|
// Found the weapon
|
|
|
|
P_ChangeWeapon(p, weapon);
|
|
}
|
|
|
|
#ifdef LUNATIC
|
|
void P_CheckWeaponI(int32_t snum)
|
|
{
|
|
P_CheckWeapon(g_player[snum].ps);
|
|
}
|
|
#endif
|
|
|
|
static void DoWallTouchDamage(const DukePlayer_t *p, int32_t obj)
|
|
{
|
|
vec3_t davect;
|
|
|
|
davect.x = p->pos.x + (sintable[(p->ang+512)&2047]>>9);
|
|
davect.y = p->pos.y + (sintable[p->ang&2047]>>9);
|
|
davect.z = p->pos.z;
|
|
|
|
A_DamageWall(p->i, obj, &davect, -1);
|
|
}
|
|
|
|
static void P_CheckTouchDamage(DukePlayer_t *p, int32_t obj)
|
|
{
|
|
if ((obj = VM_OnEventWithReturn(EVENT_CHECKTOUCHDAMAGE, p->i, P_Get(p->i), obj)) == -1)
|
|
return;
|
|
|
|
if ((obj&49152) == 49152)
|
|
{
|
|
obj &= MAXSPRITES-1;
|
|
|
|
if (sprite[obj].picnum == CACTUS)
|
|
{
|
|
if (p->hurt_delay < 8)
|
|
{
|
|
sprite[p->i].extra -= 5;
|
|
|
|
p->hurt_delay = 16;
|
|
P_PalFrom(p, 32, 32,0,0);
|
|
A_PlaySound(DUKE_LONGTERM_PAIN, p->i);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((obj&49152) != 32768)
|
|
return;
|
|
|
|
obj &= (MAXWALLS-1);
|
|
|
|
if (p->hurt_delay > 0)
|
|
{
|
|
p->hurt_delay--;
|
|
}
|
|
else if (wall[obj].cstat & FORCEFIELD_CSTAT)
|
|
{
|
|
int32_t switchpicnum = G_GetForcefieldPicnum(obj);
|
|
|
|
switch (DYNAMICTILEMAP(switchpicnum))
|
|
{
|
|
case W_FORCEFIELD__STATIC:
|
|
sprite[p->i].extra -= 5;
|
|
|
|
p->hurt_delay = 16;
|
|
P_PalFrom(p, 32, 32,0,0);
|
|
|
|
p->vel.x = -(sintable[(p->ang+512)&2047]<<8);
|
|
p->vel.y = -(sintable[(p->ang)&2047]<<8);
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
|
|
DoWallTouchDamage(p, obj);
|
|
break;
|
|
|
|
case BIGFORCE__STATIC:
|
|
p->hurt_delay = GAMETICSPERSEC;
|
|
DoWallTouchDamage(p, obj);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32_t P_CheckFloorDamage(DukePlayer_t *p, int32_t tex)
|
|
{
|
|
spritetype *s = &sprite[p->i];
|
|
|
|
if ((unsigned)(tex = VM_OnEventWithReturn(EVENT_CHECKFLOORDAMAGE, p->i, P_Get(p->i), tex)) >= MAXTILES)
|
|
return 0;
|
|
|
|
switch (DYNAMICTILEMAP(tex))
|
|
{
|
|
case HURTRAIL__STATIC:
|
|
if (rnd(32))
|
|
{
|
|
if (p->inv_amount[GET_BOOTS] > 0)
|
|
return 1;
|
|
else
|
|
{
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_LONGTERM_PAIN))
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
|
|
P_PalFrom(p, 32, 64,64,64);
|
|
|
|
s->extra -= 1+(krand()&3);
|
|
if (!A_CheckSoundPlaying(p->i,SHORT_CIRCUIT))
|
|
A_PlaySound(SHORT_CIRCUIT,p->i);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
case FLOORSLIME__STATIC:
|
|
if (rnd(16))
|
|
{
|
|
if (p->inv_amount[GET_BOOTS] > 0)
|
|
return 1;
|
|
else
|
|
{
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_LONGTERM_PAIN))
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
|
|
P_PalFrom(p, 32, 0,8,0);
|
|
s->extra -= 1+(krand()&3);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
case FLOORPLASMA__STATIC:
|
|
if (rnd(32))
|
|
{
|
|
if (p->inv_amount[GET_BOOTS] > 0)
|
|
return 1;
|
|
else
|
|
{
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_LONGTERM_PAIN))
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
|
|
P_PalFrom(p, 32, 8,0,0);
|
|
s->extra -= 1+(krand()&3);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int32_t P_FindOtherPlayer(int32_t p, int32_t *d)
|
|
{
|
|
int32_t j, closest_player = p;
|
|
int32_t x, closest = INT32_MAX;
|
|
|
|
for (TRAVERSE_CONNECT(j))
|
|
if (p != j && sprite[g_player[j].ps->i].extra > 0)
|
|
{
|
|
x = klabs(g_player[j].ps->opos.x-g_player[p].ps->pos.x) +
|
|
klabs(g_player[j].ps->opos.y-g_player[p].ps->pos.y) +
|
|
(klabs(g_player[j].ps->opos.z-g_player[p].ps->pos.z)>>4);
|
|
|
|
if (x < closest)
|
|
{
|
|
closest_player = j;
|
|
closest = x;
|
|
}
|
|
}
|
|
|
|
*d = closest;
|
|
return closest_player;
|
|
}
|
|
|
|
void P_FragPlayer(int32_t snum)
|
|
{
|
|
DukePlayer_t *p = g_player[snum].ps;
|
|
spritetype *s = &sprite[p->i];
|
|
|
|
if (g_netServer || g_netClient)
|
|
randomseed = ticrandomseed;
|
|
|
|
if (s->pal != 1)
|
|
{
|
|
P_PalFrom(p, 63, 63,0,0);
|
|
|
|
p->pos.z -= (16<<8);
|
|
s->z -= (16<<8);
|
|
|
|
p->dead_flag = (512-((krand()&1)<<10)+(krand()&255)-512)&2047;
|
|
if (p->dead_flag == 0)
|
|
p->dead_flag++;
|
|
#ifndef NETCODE_DISABLE
|
|
if (g_netServer)
|
|
{
|
|
packbuf[0] = PACKET_FRAG;
|
|
packbuf[1] = snum;
|
|
packbuf[2] = p->frag_ps;
|
|
packbuf[3] = actor[p->i].picnum;
|
|
B_BUF32(&packbuf[4], ticrandomseed);
|
|
packbuf[8] = myconnectindex;
|
|
|
|
enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 9, ENET_PACKET_FLAG_RELIABLE));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
p->jetpack_on = 0;
|
|
p->holoduke_on = -1;
|
|
|
|
S_StopEnvSound(DUKE_JETPACK_IDLE,p->i);
|
|
if (p->scream_voice > FX_Ok)
|
|
{
|
|
FX_StopSound(p->scream_voice);
|
|
S_Cleanup();
|
|
// S_TestSoundCallback(DUKE_SCREAM);
|
|
p->scream_voice = -1;
|
|
}
|
|
|
|
if (s->pal != 1 && (s->cstat&32768) == 0) s->cstat = 0;
|
|
|
|
if ((g_netServer || ud.multimode > 1) && (s->pal != 1 || (s->cstat&32768)))
|
|
{
|
|
if (p->frag_ps != snum)
|
|
{
|
|
if (GTFLAGS(GAMETYPE_TDM) && g_player[p->frag_ps].ps->team == g_player[snum].ps->team)
|
|
g_player[p->frag_ps].ps->fraggedself++;
|
|
else
|
|
{
|
|
g_player[p->frag_ps].ps->frag++;
|
|
g_player[p->frag_ps].frags[snum]++;
|
|
g_player[snum].frags[snum]++; // deaths
|
|
}
|
|
|
|
if (snum == screenpeek)
|
|
{
|
|
Bsprintf(ScriptQuotes[QUOTE_RESERVED],"Killed by %s",&g_player[p->frag_ps].user_name[0]);
|
|
P_DoQuote(QUOTE_RESERVED,p);
|
|
}
|
|
else
|
|
{
|
|
Bsprintf(ScriptQuotes[QUOTE_RESERVED2],"Killed %s",&g_player[snum].user_name[0]);
|
|
P_DoQuote(QUOTE_RESERVED2,g_player[p->frag_ps].ps);
|
|
}
|
|
|
|
if (ud.obituaries)
|
|
{
|
|
Bsprintf(tempbuf,ScriptQuotes[OBITQUOTEINDEX+(krand()%g_numObituaries)],
|
|
&g_player[p->frag_ps].user_name[0],
|
|
&g_player[snum].user_name[0]);
|
|
G_AddUserQuote(tempbuf);
|
|
}
|
|
else krand();
|
|
}
|
|
else
|
|
{
|
|
if (actor[p->i].picnum != APLAYERTOP)
|
|
{
|
|
p->fraggedself++;
|
|
if ((unsigned)p->wackedbyactor < MAXTILES && A_CheckEnemyTile(sprite[p->wackedbyactor].picnum))
|
|
Bsprintf(tempbuf,ScriptQuotes[OBITQUOTEINDEX+(krand()%g_numObituaries)],"A monster",&g_player[snum].user_name[0]);
|
|
else if (actor[p->i].picnum == NUKEBUTTON)
|
|
Bsprintf(tempbuf,"^02%s^02 tried to leave",&g_player[snum].user_name[0]);
|
|
else
|
|
{
|
|
// random suicide death string
|
|
Bsprintf(tempbuf,ScriptQuotes[SUICIDEQUOTEINDEX+(krand()%g_numSelfObituaries)],&g_player[snum].user_name[0]);
|
|
}
|
|
}
|
|
else Bsprintf(tempbuf,"^02%s^02 switched to team %d",&g_player[snum].user_name[0],p->team+1);
|
|
|
|
if (ud.obituaries)
|
|
G_AddUserQuote(tempbuf);
|
|
}
|
|
p->frag_ps = snum;
|
|
pus = NUMPAGES;
|
|
}
|
|
}
|
|
|
|
#ifdef LUNATIC
|
|
# define PIPEBOMB_CONTROL(snum) (g_player[snum].ps->pipebombControl)
|
|
#else
|
|
# define PIPEBOMB_CONTROL(snum) (Gv_GetVarByLabel("PIPEBOMB_CONTROL", PIPEBOMB_REMOTE, -1, snum))
|
|
#endif
|
|
|
|
static void P_ProcessWeapon(int32_t snum)
|
|
{
|
|
DukePlayer_t *const p = g_player[snum].ps;
|
|
uint8_t *const kb = &p->kickback_pic;
|
|
const int32_t shrunk = (sprite[p->i].yrepeat < 32);
|
|
uint32_t sb_snum = g_player[snum].sync->bits;
|
|
int32_t i, j, k;
|
|
|
|
switch (p->weapon_pos)
|
|
{
|
|
case WEAPON_POS_LOWER:
|
|
if (p->last_weapon >= 0)
|
|
{
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
p->last_weapon = -1;
|
|
}
|
|
else if (p->holster_weapon == 0)
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
break;
|
|
case 0:
|
|
break;
|
|
default:
|
|
p->weapon_pos--;
|
|
break;
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE))
|
|
{
|
|
P_SetWeaponGamevars(snum, p);
|
|
|
|
if (VM_OnEvent(EVENT_PRESSEDFIRE, p->i, snum) != 0)
|
|
sb_snum &= ~BIT(SK_FIRE);
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_HOLSTER)) // 'Holster Weapon
|
|
{
|
|
P_SetWeaponGamevars(snum, p);
|
|
|
|
if (VM_OnEvent(EVENT_HOLSTER, p->i, snum) == 0)
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, WorksLike) != KNEE_WEAPON)
|
|
{
|
|
if (p->holster_weapon == 0 && p->weapon_pos == 0)
|
|
{
|
|
p->holster_weapon = 1;
|
|
p->weapon_pos = -1;
|
|
P_DoQuote(QUOTE_WEAPON_LOWERED,p);
|
|
}
|
|
else if (p->holster_weapon == 1 && p->weapon_pos == WEAPON_POS_LOWER)
|
|
{
|
|
p->holster_weapon = 0;
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
P_DoQuote(QUOTE_WEAPON_RAISED,p);
|
|
}
|
|
}
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_HOLSTER_CLEARS_CLIP)
|
|
{
|
|
const int32_t cw=p->curr_weapon, clipcnt = PWEAPON(snum, cw, Clip);
|
|
|
|
if (p->ammo_amount[cw] > clipcnt && (p->ammo_amount[cw] % clipcnt) != 0)
|
|
{
|
|
p->ammo_amount[cw] -= p->ammo_amount[cw] % clipcnt;
|
|
(*kb) = PWEAPON(snum, cw, TotalTime);
|
|
sb_snum &= ~BIT(SK_FIRE); // not firing...
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_GLOWS)
|
|
{
|
|
p->random_club_frame += 64; // Glowing
|
|
|
|
if (p->kickback_pic == 0)
|
|
{
|
|
spritetype *s = &sprite[p->i];
|
|
int32_t x = ((sintable[(s->ang+512)&2047])>>7), y = ((sintable[(s->ang)&2047])>>7);
|
|
int32_t r = 1024+(sintable[p->random_club_frame&2047]>>3);
|
|
|
|
s->x += x;
|
|
s->y += y;
|
|
G_AddGameLight(0, p->i, PHEIGHT, max(r, 0), PWEAPON(snum, p->curr_weapon, FlashColor),PR_LIGHT_PRIO_HIGH_GAME);
|
|
actor[p->i].lightcount = 2;
|
|
s->x -= x;
|
|
s->y -= y;
|
|
}
|
|
|
|
}
|
|
|
|
// this is a hack for WEAPON_FIREEVERYOTHER
|
|
if (actor[p->i].t_data[7])
|
|
{
|
|
actor[p->i].t_data[7]--;
|
|
if (p->last_weapon == -1 && actor[p->i].t_data[7] != 0 && ((actor[p->i].t_data[7] & 1) == 0))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_AMMOPERSHOT)
|
|
{
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
else
|
|
{
|
|
actor[p->i].t_data[7] = 0;
|
|
P_CheckWeapon(p);
|
|
}
|
|
}
|
|
|
|
if (actor[p->i].t_data[7] != 0)
|
|
A_Shoot(p->i,PWEAPON(snum, p->curr_weapon, Shoots));
|
|
}
|
|
}
|
|
|
|
if (p->rapid_fire_hold == 1)
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE)) return;
|
|
p->rapid_fire_hold = 0;
|
|
}
|
|
|
|
if (shrunk || p->tipincs || p->access_incs)
|
|
sb_snum &= ~BIT(SK_FIRE);
|
|
else if (shrunk == 0 && (sb_snum&(1<<2)) && (*kb) == 0 && p->fist_incs == 0 &&
|
|
p->last_weapon == -1 && (p->weapon_pos == 0 || p->holster_weapon == 1))
|
|
{
|
|
p->crack_time = 777;
|
|
|
|
if (p->holster_weapon == 1)
|
|
{
|
|
if (p->last_pissed_time <= (GAMETICSPERSEC*218) && p->weapon_pos == WEAPON_POS_LOWER)
|
|
{
|
|
p->holster_weapon = 0;
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
P_DoQuote(QUOTE_WEAPON_RAISED,p);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
P_SetWeaponGamevars(snum, p);
|
|
|
|
if (VM_OnEvent(EVENT_FIRE, p->i, snum) == 0)
|
|
{
|
|
// this event is deprecated
|
|
VM_OnEvent(EVENT_FIREWEAPON, p->i, snum);
|
|
|
|
switch (PWEAPON(snum, p->curr_weapon, WorksLike))
|
|
{
|
|
case HANDBOMB_WEAPON:
|
|
p->hbomb_hold_delay = 0;
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
{
|
|
(*kb)=1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
break;
|
|
|
|
case HANDREMOTE_WEAPON:
|
|
p->hbomb_hold_delay = 0;
|
|
(*kb) = 1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
break;
|
|
|
|
case SHOTGUN_WEAPON:
|
|
if (p->ammo_amount[p->curr_weapon] > 0 && p->random_club_frame == 0)
|
|
{
|
|
(*kb)=1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
break;
|
|
|
|
case TRIPBOMB_WEAPON:
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
{
|
|
hitdata_t hit;
|
|
hitscan((const vec3_t *)p,
|
|
p->cursectnum, sintable[(p->ang+512)&2047],
|
|
sintable[p->ang&2047], (100-p->horiz-p->horizoff)*32,
|
|
&hit,CLIPMASK1);
|
|
|
|
if (hit.sect < 0 || hit.sprite >= 0)
|
|
break;
|
|
|
|
// ST_2_UNDERWATER
|
|
if (hit.wall >= 0 && sector[hit.sect].lotag > 2)
|
|
break;
|
|
|
|
if (hit.wall >= 0 && wall[hit.wall].overpicnum >= 0)
|
|
if (wall[hit.wall].overpicnum == BIGFORCE)
|
|
break;
|
|
|
|
j = headspritesect[hit.sect];
|
|
while (j >= 0)
|
|
{
|
|
if (sprite[j].picnum == TRIPBOMB &&
|
|
klabs(sprite[j].z-hit.pos.z) < (12<<8) &&
|
|
((sprite[j].x-hit.pos.x)*(sprite[j].x-hit.pos.x)+
|
|
(sprite[j].y-hit.pos.y)*(sprite[j].y-hit.pos.y)) < (290*290))
|
|
break;
|
|
j = nextspritesect[j];
|
|
}
|
|
|
|
// ST_2_UNDERWATER
|
|
if (j == -1 && hit.wall >= 0 && (wall[hit.wall].cstat&16) == 0)
|
|
if ((wall[hit.wall].nextsector >= 0 &&
|
|
sector[wall[hit.wall].nextsector].lotag <= 2) ||
|
|
(wall[hit.wall].nextsector == -1 && sector[hit.sect].lotag <= 2))
|
|
if (((hit.pos.x-p->pos.x)*(hit.pos.x-p->pos.x) +
|
|
(hit.pos.y-p->pos.y)*(hit.pos.y-p->pos.y)) < (290*290))
|
|
{
|
|
p->pos.z = p->opos.z;
|
|
p->vel.z = 0;
|
|
(*kb) = 1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
{
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PISTOL_WEAPON:
|
|
case CHAINGUN_WEAPON:
|
|
case SHRINKER_WEAPON:
|
|
case GROW_WEAPON:
|
|
case FREEZE_WEAPON:
|
|
case RPG_WEAPON:
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
{
|
|
(*kb) = 1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
break;
|
|
|
|
case DEVISTATOR_WEAPON:
|
|
if (p->ammo_amount[p->curr_weapon] > 0)
|
|
{
|
|
(*kb) = 1;
|
|
p->hbomb_hold_delay = !p->hbomb_hold_delay;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
break;
|
|
|
|
case KNEE_WEAPON:
|
|
if (p->quick_kick == 0)
|
|
{
|
|
(*kb) = 1;
|
|
if (PWEAPON(snum, p->curr_weapon, InitialSound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, InitialSound), p->i);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (*kb)
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, WorksLike) == HANDBOMB_WEAPON)
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, HoldDelay) && ((*kb) == PWEAPON(snum, p->curr_weapon, FireDelay)) && TEST_SYNC_KEY(sb_snum, SK_FIRE))
|
|
{
|
|
p->rapid_fire_hold = 1;
|
|
return;
|
|
}
|
|
|
|
if (++(*kb) == PWEAPON(snum, p->curr_weapon, HoldDelay))
|
|
{
|
|
p->ammo_amount[p->curr_weapon]--;
|
|
|
|
if (numplayers < 2 || g_netServer)
|
|
{
|
|
int32_t lPipeBombControl;
|
|
|
|
if (p->on_ground && TEST_SYNC_KEY(sb_snum, SK_CROUCH))
|
|
{
|
|
k = 15;
|
|
i = ((p->horiz+p->horizoff-100)*20);
|
|
}
|
|
else
|
|
{
|
|
k = 140;
|
|
i = -512-((p->horiz+p->horizoff-100)*20);
|
|
}
|
|
|
|
j = A_InsertSprite(p->cursectnum,
|
|
p->pos.x+(sintable[(p->ang+512)&2047]>>6),
|
|
p->pos.y+(sintable[p->ang&2047]>>6),
|
|
p->pos.z,PWEAPON(snum, p->curr_weapon, Shoots),-16,9,9,
|
|
p->ang,(k+(p->hbomb_hold_delay<<5)),i,p->i,1);
|
|
|
|
lPipeBombControl = PIPEBOMB_CONTROL(snum);
|
|
|
|
if (lPipeBombControl & PIPEBOMB_TIMER)
|
|
{
|
|
#ifdef LUNATIC
|
|
int32_t ltime = g_player[snum].ps->pipebombLifetime;
|
|
int32_t lv = g_player[snum].ps->pipebombLifetimeVar;
|
|
#else
|
|
int32_t ltime = Gv_GetVarByLabel("GRENADE_LIFETIME", NAM_GRENADE_LIFETIME, -1, snum);
|
|
int32_t lv=Gv_GetVarByLabel("GRENADE_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, -1, snum);
|
|
#endif
|
|
actor[j].t_data[7]= ltime
|
|
+ mulscale(krand(),lv, 14)
|
|
- lv;
|
|
// TIMER_CONTROL
|
|
actor[j].t_data[6]=1;
|
|
}
|
|
else actor[j].t_data[6]=2;
|
|
|
|
if (k == 15)
|
|
{
|
|
sprite[j].yvel = 3;
|
|
sprite[j].z += (8<<8);
|
|
}
|
|
|
|
if (A_GetHitscanRange(p->i) < 512)
|
|
{
|
|
sprite[j].ang += 1024;
|
|
sprite[j].zvel /= 3;
|
|
sprite[j].xvel /= 3;
|
|
}
|
|
}
|
|
|
|
p->hbomb_on = 1;
|
|
}
|
|
else if ((*kb) < PWEAPON(snum, p->curr_weapon, HoldDelay) && TEST_SYNC_KEY(sb_snum, SK_FIRE))
|
|
p->hbomb_hold_delay++;
|
|
else if ((*kb) > PWEAPON(snum, p->curr_weapon, TotalTime))
|
|
{
|
|
(*kb) = 0;
|
|
p->weapon_pos = WEAPON_POS_RAISE;
|
|
if (PIPEBOMB_CONTROL(snum) == PIPEBOMB_REMOTE)
|
|
{
|
|
p->curr_weapon = HANDREMOTE_WEAPON;
|
|
p->last_weapon = -1;
|
|
}
|
|
else P_CheckWeapon(p);
|
|
}
|
|
}
|
|
else if (PWEAPON(snum, p->curr_weapon, WorksLike) == HANDREMOTE_WEAPON)
|
|
{
|
|
if (++(*kb) == PWEAPON(snum, p->curr_weapon, FireDelay))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_BOMB_TRIGGER)
|
|
p->hbomb_on = 0;
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Shoots) != 0)
|
|
{
|
|
if (!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_NOVISIBLE))
|
|
{
|
|
lastvisinc = totalclock+32;
|
|
p->visibility = 0;
|
|
}
|
|
|
|
P_SetWeaponGamevars(snum, p);
|
|
A_Shoot(p->i, PWEAPON(snum, p->curr_weapon, Shoots));
|
|
}
|
|
}
|
|
|
|
if ((*kb) >= PWEAPON(snum, p->curr_weapon, TotalTime))
|
|
{
|
|
(*kb) = 0;
|
|
if ((p->ammo_amount[HANDBOMB_WEAPON] > 0) && PIPEBOMB_CONTROL(snum) == PIPEBOMB_REMOTE)
|
|
P_AddWeapon(p, HANDBOMB_WEAPON, 1);
|
|
else P_CheckWeapon(p);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the basic weapon...
|
|
(*kb)++;
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_CHECKATRELOAD)
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, WorksLike) == TRIPBOMB_WEAPON)
|
|
{
|
|
if ((*kb) >= PWEAPON(snum, p->curr_weapon, TotalTime))
|
|
{
|
|
(*kb) = 0;
|
|
P_CheckWeapon(p);
|
|
p->weapon_pos = WEAPON_POS_LOWER;
|
|
}
|
|
}
|
|
else if (*kb >= PWEAPON(snum, p->curr_weapon, Reload))
|
|
P_CheckWeapon(p);
|
|
}
|
|
else if (PWEAPON(snum, p->curr_weapon, WorksLike)!=KNEE_WEAPON && *kb >= PWEAPON(snum, p->curr_weapon, FireDelay))
|
|
P_CheckWeapon(p);
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_STANDSTILL
|
|
&& *kb < (PWEAPON(snum, p->curr_weapon, FireDelay)+1))
|
|
{
|
|
p->pos.z = p->opos.z;
|
|
p->vel.z = 0;
|
|
}
|
|
|
|
if (*kb == PWEAPON(snum, p->curr_weapon, Sound2Time))
|
|
if (PWEAPON(snum, p->curr_weapon, Sound2Sound) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, Sound2Sound),p->i);
|
|
|
|
if (*kb == PWEAPON(snum, p->curr_weapon, SpawnTime))
|
|
P_DoWeaponSpawn(snum);
|
|
|
|
if ((*kb) >= PWEAPON(snum, p->curr_weapon, TotalTime))
|
|
{
|
|
if (/*!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_CHECKATRELOAD) && */ p->reloading == 1 ||
|
|
(PWEAPON(snum, p->curr_weapon, Reload) > PWEAPON(snum, p->curr_weapon, TotalTime) && p->ammo_amount[p->curr_weapon] > 0
|
|
&& (PWEAPON(snum, p->curr_weapon, Clip)) && (((p->ammo_amount[p->curr_weapon]%(PWEAPON(snum, p->curr_weapon, Clip)))==0))))
|
|
{
|
|
int32_t i = PWEAPON(snum, p->curr_weapon, Reload) - PWEAPON(snum, p->curr_weapon, TotalTime);
|
|
|
|
p->reloading = 1;
|
|
|
|
if ((*kb) != (PWEAPON(snum, p->curr_weapon, TotalTime)))
|
|
{
|
|
if ((*kb) == (PWEAPON(snum, p->curr_weapon, TotalTime)+1))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, ReloadSound1) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, ReloadSound1),p->i);
|
|
}
|
|
else if (((*kb) == (PWEAPON(snum, p->curr_weapon, Reload) - (i/3)) &&
|
|
!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RELOAD_TIMING)) ||
|
|
((*kb) == (PWEAPON(snum, p->curr_weapon, Reload) - i+4) &&
|
|
(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RELOAD_TIMING)))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, ReloadSound2) > 0)
|
|
A_PlaySound(PWEAPON(snum, p->curr_weapon, ReloadSound2),p->i);
|
|
}
|
|
else if ((*kb) >= (PWEAPON(snum, p->curr_weapon, Reload)))
|
|
{
|
|
*kb=0;
|
|
p->reloading = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_AUTOMATIC &&
|
|
(PWEAPON(snum, p->curr_weapon, WorksLike)==KNEE_WEAPON?1:p->ammo_amount[p->curr_weapon] > 0))
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RANDOMRESTART)
|
|
*kb = 1+(krand()&3);
|
|
else *kb=1;
|
|
}
|
|
else *kb = 0;
|
|
}
|
|
else *kb = 0;
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RESET &&
|
|
((PWEAPON(snum, p->curr_weapon, WorksLike) == KNEE_WEAPON)?1:p->ammo_amount[p->curr_weapon] > 0))
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE)) *kb = 1;
|
|
else *kb = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (*kb >= PWEAPON(snum, p->curr_weapon, FireDelay) && (*kb) < PWEAPON(snum, p->curr_weapon, TotalTime)
|
|
&& ((PWEAPON(snum, p->curr_weapon, WorksLike) == KNEE_WEAPON)?1:p->ammo_amount[p->curr_weapon] > 0))
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_AUTOMATIC)
|
|
{
|
|
if (!(PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_SEMIAUTO))
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE) == 0 && PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RESET)
|
|
*kb = 0;
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_FIREEVERYTHIRD)
|
|
{
|
|
if (((*(kb))%3) == 0)
|
|
{
|
|
P_FireWeapon(snum);
|
|
P_DoWeaponSpawn(snum);
|
|
}
|
|
}
|
|
else if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_FIREEVERYOTHER)
|
|
{
|
|
P_FireWeapon(snum);
|
|
P_DoWeaponSpawn(snum);
|
|
}
|
|
else
|
|
{
|
|
if (*kb == PWEAPON(snum, p->curr_weapon, FireDelay))
|
|
{
|
|
P_FireWeapon(snum);
|
|
// P_DoWeaponSpawn(snum);
|
|
}
|
|
}
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_RESET &&
|
|
(*kb) > PWEAPON(snum, p->curr_weapon, TotalTime)-PWEAPON(snum, p->curr_weapon, HoldDelay) &&
|
|
((PWEAPON(snum, p->curr_weapon, WorksLike) == KNEE_WEAPON) || p->ammo_amount[p->curr_weapon] > 0))
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_FIRE)) *kb = 1;
|
|
else *kb = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (PWEAPON(snum, p->curr_weapon, Flags) & WEAPON_FIREEVERYOTHER)
|
|
{
|
|
P_FireWeapon(snum);
|
|
P_DoWeaponSpawn(snum);
|
|
}
|
|
else
|
|
{
|
|
if (*kb == PWEAPON(snum, p->curr_weapon, FireDelay))
|
|
{
|
|
P_FireWeapon(snum);
|
|
// P_DoWeaponSpawn(snum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (*kb == PWEAPON(snum, p->curr_weapon, FireDelay))
|
|
P_FireWeapon(snum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32_t P_DoFist(DukePlayer_t *p)
|
|
{
|
|
// the fist punching NUKEBUTTON
|
|
|
|
if (++p->fist_incs == 28)
|
|
{
|
|
if (ud.recstat == 1) G_CloseDemoWrite();
|
|
S_PlaySound(PIPEBOMB_EXPLODE);
|
|
|
|
P_PalFrom(p, 48, 64,64,64);
|
|
}
|
|
|
|
if (p->fist_incs > 42)
|
|
{
|
|
int32_t i;
|
|
|
|
for (TRAVERSE_CONNECT(i))
|
|
g_player[i].ps->gm = MODE_EOL;
|
|
|
|
if (p->buttonpalette && ud.from_bonus == 0)
|
|
{
|
|
ud.from_bonus = ud.level_number+1;
|
|
if (ud.secretlevel > 0 && ud.secretlevel <= MAXLEVELS)
|
|
ud.level_number = ud.secretlevel-1;
|
|
ud.m_level_number = ud.level_number;
|
|
}
|
|
else
|
|
{
|
|
if (ud.from_bonus)
|
|
{
|
|
ud.m_level_number = ud.level_number = ud.from_bonus;
|
|
ud.from_bonus = 0;
|
|
}
|
|
else
|
|
{
|
|
if (ud.level_number == ud.secretlevel && ud.from_bonus > 0)
|
|
ud.level_number = ud.from_bonus;
|
|
else ud.level_number++;
|
|
|
|
if (ud.level_number > MAXLEVELS-1)
|
|
ud.level_number = 0;
|
|
ud.m_level_number = ud.level_number;
|
|
}
|
|
}
|
|
|
|
p->fist_incs = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef YAX_ENABLE
|
|
static void getzsofslope_player(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
|
|
{
|
|
int32_t i, didceil=0, didflor=0;
|
|
|
|
if ((sector[sectnum].ceilingstat&512)==0)
|
|
{
|
|
i = yax_getneighborsect(dax, day, sectnum, YAX_CEILING);
|
|
if (i >= 0)
|
|
{
|
|
*ceilz = getceilzofslope(i, dax,day);
|
|
didceil = 1;
|
|
}
|
|
}
|
|
|
|
if ((sector[sectnum].floorstat&512)==0)
|
|
{
|
|
i = yax_getneighborsect(dax, day, sectnum, YAX_FLOOR);
|
|
if (i >= 0)
|
|
{
|
|
*florz = getflorzofslope(i, dax,day);
|
|
didflor = 1;
|
|
}
|
|
}
|
|
|
|
if (!didceil || !didflor)
|
|
{
|
|
int32_t cz, fz;
|
|
getzsofslope(sectnum, dax, day, &cz, &fz);
|
|
|
|
if (!didceil)
|
|
*ceilz = cz;
|
|
if (!didflor)
|
|
*florz = fz;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void P_UpdatePosWhenViewingCam(DukePlayer_t *p)
|
|
{
|
|
int32_t i = p->newowner;
|
|
|
|
Bmemcpy(&p->pos, &sprite[i], sizeof(vec3_t));
|
|
p->ang = SA;
|
|
p->vel.x = p->vel.y = sprite[p->i].xvel = 0;
|
|
p->look_ang = 0;
|
|
p->rotscrnang = 0;
|
|
}
|
|
|
|
void P_ProcessInput(int32_t snum)
|
|
{
|
|
DukePlayer_t *const p = g_player[snum].ps;
|
|
spritetype *const s = &sprite[p->i];
|
|
|
|
uint32_t sb_snum = g_player[snum].sync->bits;
|
|
|
|
int32_t j, i, k, doubvel = TICSPERFRAME, shrunk;
|
|
int32_t fz, cz, hz, lz, truefdist, x, y, psectlotag;
|
|
const uint8_t *const kb = &p->kickback_pic;
|
|
int16_t tempsect;
|
|
|
|
if (g_player[snum].playerquitflag == 0)
|
|
return;
|
|
|
|
p->player_par++;
|
|
|
|
VM_OnEvent(EVENT_PROCESSINPUT, p->i, snum);
|
|
|
|
if (p->cheat_phase > 0) sb_snum = 0;
|
|
|
|
if (p->cursectnum == -1)
|
|
{
|
|
if (s->extra > 0 && ud.noclip == 0)
|
|
{
|
|
P_QuickKill(p);
|
|
A_PlaySound(SQUISHED,p->i);
|
|
}
|
|
p->cursectnum = 0;
|
|
}
|
|
|
|
psectlotag = sector[p->cursectnum].lotag;
|
|
p->spritebridge = p->sbs = 0;
|
|
|
|
shrunk = (s->yrepeat < 32);
|
|
getzrange((vec3_t *)p,p->cursectnum,&cz,&hz,&fz,&lz,163L,CLIPMASK0);
|
|
|
|
#ifdef YAX_ENABLE
|
|
getzsofslope_player(p->cursectnum,p->pos.x,p->pos.y,&p->truecz,&p->truefz);
|
|
#else
|
|
getzsofslope(p->cursectnum,p->pos.x,p->pos.y,&p->truecz,&p->truefz);
|
|
#endif
|
|
j = p->truefz;
|
|
|
|
truefdist = klabs(p->pos.z-j);
|
|
|
|
if ((lz&49152) == 16384 && psectlotag == 1 && truefdist > PHEIGHT+(16<<8))
|
|
psectlotag = 0;
|
|
|
|
actor[p->i].floorz = fz;
|
|
actor[p->i].ceilingz = cz;
|
|
|
|
p->ohoriz = p->horiz;
|
|
p->ohorizoff = p->horizoff;
|
|
|
|
// calculates automatic view angle for playing without a mouse
|
|
if (p->aim_mode == 0 && p->on_ground && psectlotag != ST_2_UNDERWATER && (sector[p->cursectnum].floorstat&2))
|
|
{
|
|
x = p->pos.x+(sintable[(p->ang+512)&2047]>>5);
|
|
y = p->pos.y+(sintable[p->ang&2047]>>5);
|
|
tempsect = p->cursectnum;
|
|
updatesector(x,y,&tempsect);
|
|
if (tempsect >= 0)
|
|
{
|
|
k = getflorzofslope(p->cursectnum,x,y);
|
|
if (p->cursectnum == tempsect)
|
|
p->horizoff += mulscale16(j-k,160);
|
|
else if (klabs(getflorzofslope(tempsect,x,y)-k) <= (4<<8))
|
|
p->horizoff += mulscale16(j-k,160);
|
|
}
|
|
}
|
|
|
|
if (p->horizoff > 0) p->horizoff -= ((p->horizoff>>3)+1);
|
|
else if (p->horizoff < 0) p->horizoff += (((-p->horizoff)>>3)+1);
|
|
|
|
if (hz >= 0 && (hz&49152) == 49152)
|
|
{
|
|
hz &= (MAXSPRITES-1);
|
|
|
|
if (sprite[hz].statnum == STAT_ACTOR && sprite[hz].extra >= 0)
|
|
{
|
|
hz = 0;
|
|
cz = p->truecz;
|
|
}
|
|
}
|
|
|
|
if (lz >= 0 && (lz&49152) == 49152)
|
|
{
|
|
j = lz&(MAXSPRITES-1);
|
|
|
|
if ((sprite[j].cstat&33) == 33 || (sprite[j].cstat&17) == 17 ||
|
|
clipshape_idx_for_sprite(&sprite[j], -1) >= 0)
|
|
{
|
|
// EDuke32 extension: xvel of 1 makes a sprite be never regarded as a bridge.
|
|
if ((sprite[j].xvel&1) == 0)
|
|
{
|
|
psectlotag = 0;
|
|
p->footprintcount = 0;
|
|
p->spritebridge = 1;
|
|
p->sbs = j;
|
|
}
|
|
}
|
|
else if (A_CheckEnemySprite(&sprite[j]) && sprite[j].xrepeat > 24 && klabs(s->z-sprite[j].z) < (84<<8))
|
|
{
|
|
// TX: I think this is what makes the player slide off enemies... might
|
|
// be a good sprite flag to add later.
|
|
// Helix: there's also SLIDE_ABOVE_ENEMY.
|
|
j = getangle(sprite[j].x-p->pos.x,sprite[j].y-p->pos.y);
|
|
p->vel.x -= sintable[(j+512)&2047]<<4;
|
|
p->vel.y -= sintable[j&2047]<<4;
|
|
}
|
|
}
|
|
|
|
if (s->extra > 0)
|
|
P_IncurDamage(p);
|
|
else
|
|
{
|
|
s->extra = 0;
|
|
p->inv_amount[GET_SHIELD] = 0;
|
|
}
|
|
|
|
p->last_extra = s->extra;
|
|
|
|
if (p->loogcnt > 0) p->loogcnt--;
|
|
else p->loogcnt = 0;
|
|
|
|
if (p->fist_incs && P_DoFist(p)) return;
|
|
|
|
if (p->timebeforeexit > 1 && p->last_extra > 0)
|
|
{
|
|
if (--p->timebeforeexit == GAMETICSPERSEC*5)
|
|
{
|
|
FX_StopAllSounds();
|
|
S_ClearSoundLocks();
|
|
|
|
if (p->customexitsound >= 0)
|
|
{
|
|
S_PlaySound(p->customexitsound);
|
|
P_DoQuote(QUOTE_WEREGONNAFRYYOURASS,p);
|
|
}
|
|
}
|
|
else if (p->timebeforeexit == 1)
|
|
{
|
|
for (TRAVERSE_CONNECT(i))
|
|
g_player[i].ps->gm = MODE_EOL;
|
|
|
|
ud.m_level_number = ud.level_number++;
|
|
|
|
if (ud.from_bonus)
|
|
{
|
|
ud.m_level_number = ud.level_number = ud.from_bonus;
|
|
ud.from_bonus = 0;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (p->pals.f > 0)
|
|
{
|
|
#if !defined LUNATIC
|
|
p->pals.f--;
|
|
#else
|
|
if (p->palsfadespeed > 0)
|
|
{
|
|
// <palsfadespeed> is the tint fade speed is in
|
|
// decrements/P_ProcessInput() calls.
|
|
p->pals.f = max(p->pals.f - p->palsfadespeed, 0);
|
|
}
|
|
else
|
|
{
|
|
// <palsfadespeed> is a negated count of how many times we
|
|
// (P_ProcessInput()) should be called before decrementing the tint
|
|
// fading by one. <palsfadenext> is the live counter.
|
|
if (p->palsfadenext < 0)
|
|
p->palsfadenext++;
|
|
|
|
if (p->palsfadenext == 0)
|
|
{
|
|
p->palsfadenext = p->palsfadespeed;
|
|
p->pals.f--;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (p->fta > 0 && --p->fta == 0)
|
|
{
|
|
pub = pus = NUMPAGES;
|
|
p->ftq = 0;
|
|
}
|
|
|
|
if (g_levelTextTime > 0)
|
|
g_levelTextTime--;
|
|
|
|
if (s->extra <= 0)
|
|
{
|
|
if (ud.recstat == 1 && (!g_netServer && ud.multimode < 2))
|
|
G_CloseDemoWrite();
|
|
|
|
if ((numplayers < 2 || g_netServer) && p->dead_flag == 0)
|
|
P_FragPlayer(snum);
|
|
|
|
if (psectlotag == ST_2_UNDERWATER)
|
|
{
|
|
if (p->on_warping_sector == 0)
|
|
{
|
|
if (klabs(p->pos.z-fz) > (PHEIGHT>>1))
|
|
p->pos.z += 348;
|
|
}
|
|
else
|
|
{
|
|
s->z -= 512;
|
|
s->zvel = -348;
|
|
}
|
|
|
|
clipmove((vec3_t *)p,&p->cursectnum,
|
|
0,0,164L,(4L<<8),(4L<<8),CLIPMASK0);
|
|
// p->bobcounter += 32;
|
|
}
|
|
|
|
Bmemcpy(&p->opos, &p->pos, sizeof(vec3_t));
|
|
p->oang = p->ang;
|
|
p->opyoff = p->pyoff;
|
|
|
|
p->horiz = 100;
|
|
p->horizoff = 0;
|
|
|
|
updatesector(p->pos.x,p->pos.y,&p->cursectnum);
|
|
|
|
pushmove((vec3_t *)p,&p->cursectnum,128L,(4L<<8),(20L<<8),CLIPMASK0);
|
|
|
|
if (fz > cz+(16<<8) && s->pal != 1)
|
|
p->rotscrnang = (p->dead_flag + ((fz+p->pos.z)>>7))&2047;
|
|
|
|
p->on_warping_sector = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
if (p->transporter_hold > 0)
|
|
{
|
|
p->transporter_hold--;
|
|
if (p->transporter_hold == 0 && p->on_warping_sector)
|
|
p->transporter_hold = 2;
|
|
}
|
|
else if (p->transporter_hold < 0)
|
|
p->transporter_hold++;
|
|
|
|
if (p->newowner >= 0)
|
|
{
|
|
P_UpdatePosWhenViewingCam(p);
|
|
P_DoCounters(snum);
|
|
|
|
if (PWEAPON(snum, p->curr_weapon, WorksLike) == HANDREMOTE_WEAPON)
|
|
P_ProcessWeapon(snum);
|
|
|
|
return;
|
|
}
|
|
|
|
p->rotscrnang -= (p->rotscrnang>>1);
|
|
|
|
if (p->rotscrnang && !(p->rotscrnang>>1))
|
|
p->rotscrnang -= ksgn(p->rotscrnang);
|
|
|
|
p->look_ang -= (p->look_ang>>2);
|
|
|
|
if (p->look_ang && !(p->look_ang>>2))
|
|
p->look_ang -= ksgn(p->look_ang);
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_LOOK_LEFT))
|
|
{
|
|
// look_left
|
|
if (VM_OnEvent(EVENT_LOOKLEFT,p->i,snum) == 0)
|
|
{
|
|
p->look_ang -= 152;
|
|
p->rotscrnang += 24;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_LOOK_RIGHT))
|
|
{
|
|
// look_right
|
|
if (VM_OnEvent(EVENT_LOOKRIGHT,p->i,snum) == 0)
|
|
{
|
|
p->look_ang += 152;
|
|
p->rotscrnang -= 24;
|
|
}
|
|
}
|
|
|
|
if (p->on_crane >= 0)
|
|
goto HORIZONLY;
|
|
|
|
j = ksgn(g_player[snum].sync->avel);
|
|
|
|
if (s->xvel < 32 || p->on_ground == 0 || p->bobcounter == 1024)
|
|
{
|
|
if ((p->weapon_sway&2047) > (1024+96))
|
|
p->weapon_sway -= 96;
|
|
else if ((p->weapon_sway&2047) < (1024-96))
|
|
p->weapon_sway += 96;
|
|
else p->weapon_sway = 1024;
|
|
}
|
|
else p->weapon_sway = p->bobcounter;
|
|
|
|
// NOTE: This silently wraps if the difference is too great, e.g. used to do
|
|
// that when teleported by silent SE7s.
|
|
s->xvel = ksqrt(uhypsq(p->pos.x-p->bobpos.x, p->pos.y-p->bobpos.y));
|
|
|
|
if (p->on_ground)
|
|
p->bobcounter += sprite[p->i].xvel>>1;
|
|
|
|
if (ud.noclip == 0 && ((uint16_t)p->cursectnum >= MAXSECTORS || sector[p->cursectnum].floorpicnum == MIRROR))
|
|
{
|
|
p->pos.x = p->opos.x;
|
|
p->pos.y = p->opos.y;
|
|
}
|
|
else
|
|
{
|
|
p->opos.x = p->pos.x;
|
|
p->opos.y = p->pos.y;
|
|
}
|
|
|
|
p->bobpos.x = p->pos.x;
|
|
p->bobpos.y = p->pos.y;
|
|
|
|
p->opos.z = p->pos.z;
|
|
p->opyoff = p->pyoff;
|
|
p->oang = p->ang;
|
|
|
|
if (p->one_eighty_count < 0)
|
|
{
|
|
p->one_eighty_count += 128;
|
|
p->ang += 128;
|
|
}
|
|
|
|
// Shrinking code
|
|
|
|
i = 40;
|
|
|
|
if (psectlotag == ST_2_UNDERWATER)
|
|
{
|
|
// under water
|
|
p->jumping_counter = 0;
|
|
|
|
p->pycount += 32;
|
|
p->pycount &= 2047;
|
|
p->pyoff = sintable[p->pycount]>>7;
|
|
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_UNDERWATER))
|
|
A_PlaySound(DUKE_UNDERWATER,p->i);
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_JUMP))
|
|
{
|
|
if (VM_OnEvent(EVENT_SWIMUP,p->i,snum) == 0)
|
|
{
|
|
// jump
|
|
if (p->vel.z > 0) p->vel.z = 0;
|
|
p->vel.z -= 348;
|
|
if (p->vel.z < -(256*6)) p->vel.z = -(256*6);
|
|
}
|
|
}
|
|
else if (TEST_SYNC_KEY(sb_snum, SK_CROUCH))
|
|
{
|
|
if (VM_OnEvent(EVENT_SWIMDOWN,p->i,snum) == 0)
|
|
{
|
|
// crouch
|
|
if (p->vel.z < 0) p->vel.z = 0;
|
|
p->vel.z += 348;
|
|
if (p->vel.z > (256*6)) p->vel.z = (256*6);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// normal view
|
|
if (p->vel.z < 0)
|
|
{
|
|
p->vel.z += 256;
|
|
if (p->vel.z > 0)
|
|
p->vel.z = 0;
|
|
}
|
|
if (p->vel.z > 0)
|
|
{
|
|
p->vel.z -= 256;
|
|
if (p->vel.z < 0)
|
|
p->vel.z = 0;
|
|
}
|
|
}
|
|
|
|
if (p->vel.z > 2048)
|
|
p->vel.z >>= 1;
|
|
|
|
p->pos.z += p->vel.z;
|
|
|
|
if (p->pos.z > (fz-(15<<8)))
|
|
p->pos.z += ((fz-(15<<8))-p->pos.z)>>1;
|
|
|
|
if (p->pos.z < cz)
|
|
{
|
|
p->pos.z = cz;
|
|
p->vel.z = 0;
|
|
}
|
|
|
|
if (p->scuba_on && (krand()&255) < 8)
|
|
{
|
|
j = A_Spawn(p->i,WATERBUBBLE);
|
|
sprite[j].x +=
|
|
sintable[(p->ang+512+64-(g_globalRandom&128))&2047]>>6;
|
|
sprite[j].y +=
|
|
sintable[(p->ang+64-(g_globalRandom&128))&2047]>>6;
|
|
sprite[j].xrepeat = 3;
|
|
sprite[j].yrepeat = 2;
|
|
sprite[j].z = p->pos.z+(8<<8);
|
|
}
|
|
}
|
|
else if (p->jetpack_on)
|
|
{
|
|
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 < 11)
|
|
{
|
|
p->jetpack_on++;
|
|
p->pos.z -= (p->jetpack_on<<7); //Goin up
|
|
}
|
|
else if (p->jetpack_on == 11 && !A_CheckSoundPlaying(p->i,DUKE_JETPACK_IDLE))
|
|
A_PlaySound(DUKE_JETPACK_IDLE,p->i);
|
|
|
|
if (shrunk) j = 512;
|
|
else j = 2048;
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_JUMP)) //A (soar high)
|
|
{
|
|
// jump
|
|
if (VM_OnEvent(EVENT_SOARUP,p->i,snum) == 0)
|
|
{
|
|
p->pos.z -= j;
|
|
p->crack_time = 777;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_CROUCH)) //Z (soar low)
|
|
{
|
|
// crouch
|
|
if (VM_OnEvent(EVENT_SOARDOWN,p->i,snum) == 0)
|
|
{
|
|
p->pos.z += j;
|
|
p->crack_time = 777;
|
|
}
|
|
}
|
|
|
|
if (shrunk == 0 && (psectlotag == 0 || psectlotag == ST_2_UNDERWATER)) k = 32;
|
|
else k = 16;
|
|
|
|
if (psectlotag != ST_2_UNDERWATER && p->scuba_on == 1)
|
|
p->scuba_on = 0;
|
|
|
|
if (p->pos.z > (fz-(k<<8)))
|
|
p->pos.z += ((fz-(k<<8))-p->pos.z)>>1;
|
|
if (p->pos.z < (actor[p->i].ceilingz+(18<<8)))
|
|
p->pos.z = actor[p->i].ceilingz+(18<<8);
|
|
}
|
|
else if (psectlotag != ST_2_UNDERWATER)
|
|
{
|
|
p->airleft = 15 * GAMETICSPERSEC; // 13 seconds
|
|
|
|
if (p->scuba_on == 1)
|
|
p->scuba_on = 0;
|
|
|
|
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 < 0)
|
|
p->dummyplayersprite = A_Spawn(p->i,PLAYERONWATER);
|
|
sprite[p->dummyplayersprite].pal = sprite[p->i].pal;
|
|
sprite[p->dummyplayersprite].cstat |= 32768;
|
|
|
|
p->footprintcount = 6;
|
|
if (sector[p->cursectnum].floorpicnum == FLOORSLIME)
|
|
p->footprintpal = 8;
|
|
else p->footprintpal = 0;
|
|
p->footprintshade = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (p->footprintcount > 0 && p->on_ground)
|
|
if (p->cursectnum >= 0 && (sector[p->cursectnum].floorstat&2) != 2)
|
|
{
|
|
for (j=headspritesect[p->cursectnum]; j>=0; j=nextspritesect[j])
|
|
if (sprite[j].picnum == FOOTPRINTS || sprite[j].picnum == FOOTPRINTS2 ||
|
|
sprite[j].picnum == FOOTPRINTS3 || sprite[j].picnum == FOOTPRINTS4)
|
|
if (klabs(sprite[j].x-p->pos.x) < 384 && klabs(sprite[j].y-p->pos.y) < 384)
|
|
break;
|
|
|
|
if (j < 0)
|
|
{
|
|
if (p->cursectnum >= 0 && sector[p->cursectnum].lotag == 0 && sector[p->cursectnum].hitag == 0)
|
|
#ifdef YAX_ENABLE
|
|
if (yax_getbunch(p->cursectnum, YAX_FLOOR) < 0 || (sector[p->cursectnum].floorstat&512))
|
|
#endif
|
|
{
|
|
switch (krand()&3)
|
|
{
|
|
case 0:
|
|
j = A_Spawn(p->i,FOOTPRINTS);
|
|
break;
|
|
case 1:
|
|
j = A_Spawn(p->i,FOOTPRINTS2);
|
|
break;
|
|
case 2:
|
|
j = A_Spawn(p->i,FOOTPRINTS3);
|
|
break;
|
|
default:
|
|
j = A_Spawn(p->i,FOOTPRINTS4);
|
|
break;
|
|
}
|
|
sprite[j].pal = p->footprintpal;
|
|
sprite[j].shade = p->footprintshade;
|
|
p->footprintcount--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p->pos.z < (fz-(i<<8))) //falling
|
|
{
|
|
// not jumping or crouching
|
|
|
|
if (!TEST_SYNC_KEY(sb_snum, SK_JUMP) && !TEST_SYNC_KEY(sb_snum, SK_CROUCH) &&
|
|
p->on_ground && (sector[p->cursectnum].floorstat&2) && p->pos.z >= (fz-(i<<8)-(16<<8)))
|
|
p->pos.z = fz-(i<<8);
|
|
else
|
|
{
|
|
p->on_ground = 0;
|
|
p->vel.z += (g_spriteGravity+80); // (TICSPERFRAME<<6);
|
|
if (p->vel.z >= (4096+2048)) p->vel.z = (4096+2048);
|
|
if (p->vel.z > 2400 && p->falling_counter < 255)
|
|
{
|
|
p->falling_counter++;
|
|
if (p->falling_counter >= 38 && p->scream_voice <= FX_Ok)
|
|
{
|
|
int32_t voice = A_PlaySound(DUKE_SCREAM,p->i);
|
|
if (voice <= 127) // XXX: p->scream_voice is an int8_t
|
|
p->scream_voice = voice;
|
|
}
|
|
}
|
|
|
|
if ((p->pos.z+p->vel.z) >= (fz-(i<<8)) && p->cursectnum >= 0) // hit the ground
|
|
if (sector[p->cursectnum].lotag != ST_1_ABOVE_WATER)
|
|
{
|
|
if (p->falling_counter > 62)
|
|
P_QuickKill(p);
|
|
else if (p->falling_counter > 9)
|
|
{
|
|
// Falling damage.
|
|
s->extra -= p->falling_counter-(krand()&3);
|
|
|
|
if (s->extra <= 0)
|
|
{
|
|
A_PlaySound(SQUISHED,p->i);
|
|
|
|
// P_PalFrom(p, 63, 63,0,0);
|
|
}
|
|
else
|
|
{
|
|
A_PlaySound(DUKE_LAND,p->i);
|
|
A_PlaySound(DUKE_LAND_HURT,p->i);
|
|
}
|
|
|
|
P_PalFrom(p, 32, 16,0,0);
|
|
}
|
|
else if (p->vel.z > 2048)
|
|
A_PlaySound(DUKE_LAND,p->i);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p->falling_counter = 0;
|
|
|
|
if (p->scream_voice > FX_Ok)
|
|
{
|
|
FX_StopSound(p->scream_voice);
|
|
S_Cleanup();
|
|
p->scream_voice = -1;
|
|
}
|
|
|
|
if (psectlotag != ST_1_ABOVE_WATER && psectlotag != ST_2_UNDERWATER && p->on_ground == 0 && p->vel.z > (6144>>1))
|
|
p->hard_landing = p->vel.z>>10;
|
|
|
|
p->on_ground = 1;
|
|
|
|
if (i==40)
|
|
{
|
|
//Smooth on the ground
|
|
|
|
k = ((fz-(i<<8))-p->pos.z)>>1;
|
|
if (klabs(k) < 256) k = 0;
|
|
p->pos.z += k;
|
|
p->vel.z -= 768;
|
|
if (p->vel.z < 0) p->vel.z = 0;
|
|
}
|
|
else if (p->jumping_counter == 0)
|
|
{
|
|
p->pos.z += ((fz-(i<<7))-p->pos.z)>>1; //Smooth on the water
|
|
if (p->on_warping_sector == 0 && p->pos.z > fz-(16<<8))
|
|
{
|
|
p->pos.z = fz-(16<<8);
|
|
p->vel.z >>= 1;
|
|
}
|
|
}
|
|
|
|
p->on_warping_sector = 0;
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_CROUCH))
|
|
{
|
|
// crouching
|
|
if (VM_OnEvent(EVENT_CROUCH,p->i,snum) == 0)
|
|
{
|
|
p->pos.z += (2048+768);
|
|
p->crack_time = 777;
|
|
}
|
|
}
|
|
|
|
// jumping
|
|
if (!TEST_SYNC_KEY(sb_snum, SK_JUMP) && p->jumping_toggle == 1)
|
|
p->jumping_toggle = 0;
|
|
else if (TEST_SYNC_KEY(sb_snum, SK_JUMP) && p->jumping_toggle == 0)
|
|
{
|
|
if (p->jumping_counter == 0)
|
|
if ((fz-cz) > (56<<8))
|
|
{
|
|
if (VM_OnEvent(EVENT_JUMP,p->i,snum) == 0)
|
|
{
|
|
p->jumping_counter = 1;
|
|
p->jumping_toggle = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p->jumping_counter && !TEST_SYNC_KEY(sb_snum, SK_JUMP))
|
|
p->jumping_toggle = 0;
|
|
}
|
|
|
|
if (p->jumping_counter)
|
|
{
|
|
if (!TEST_SYNC_KEY(sb_snum, SK_JUMP) && p->jumping_toggle == 1)
|
|
p->jumping_toggle = 0;
|
|
|
|
if (p->jumping_counter < (1024+256))
|
|
{
|
|
if (psectlotag == ST_1_ABOVE_WATER && p->jumping_counter > 768)
|
|
{
|
|
p->jumping_counter = 0;
|
|
p->vel.z = -512;
|
|
}
|
|
else
|
|
{
|
|
p->vel.z -= (sintable[(2048-128+p->jumping_counter)&2047])/12;
|
|
p->jumping_counter += 180;
|
|
p->on_ground = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p->jumping_counter = 0;
|
|
p->vel.z = 0;
|
|
}
|
|
}
|
|
|
|
p->pos.z += p->vel.z;
|
|
|
|
if ((psectlotag != ST_2_UNDERWATER || cz != sector[p->cursectnum].ceilingz) && p->pos.z < (cz+(4<<8)))
|
|
{
|
|
p->jumping_counter = 0;
|
|
if (p->vel.z < 0)
|
|
p->vel.x = p->vel.y = 0;
|
|
p->vel.z = 128;
|
|
p->pos.z = cz+(4<<8);
|
|
}
|
|
}
|
|
|
|
if (p->fist_incs || p->transporter_hold > 2 || p->hard_landing || p->access_incs > 0 || p->knee_incs > 0 ||
|
|
(PWEAPON(snum, p->curr_weapon, WorksLike) == TRIPBOMB_WEAPON &&
|
|
*kb > 1 && *kb < PWEAPON(snum, p->curr_weapon, FireDelay)))
|
|
{
|
|
doubvel = 0;
|
|
p->vel.x = 0;
|
|
p->vel.y = 0;
|
|
}
|
|
else if (g_player[snum].sync->avel) //p->ang += syncangvel * constant
|
|
{
|
|
int32_t tempang = g_player[snum].sync->avel;
|
|
|
|
if (psectlotag == ST_2_UNDERWATER) p->angvel =(tempang-(tempang>>3))*ksgn(doubvel);
|
|
else p->angvel = tempang*ksgn(doubvel);
|
|
|
|
p->ang += p->angvel;
|
|
p->ang &= 2047;
|
|
p->crack_time = 777;
|
|
}
|
|
|
|
if (p->spritebridge == 0)
|
|
{
|
|
j = sector[s->sectnum].floorpicnum;
|
|
|
|
if (j == PURPLELAVA || sector[s->sectnum].ceilingpicnum == PURPLELAVA)
|
|
{
|
|
if (p->inv_amount[GET_BOOTS] > 0)
|
|
{
|
|
p->inv_amount[GET_BOOTS]--;
|
|
p->inven_icon = ICON_BOOTS;
|
|
if (p->inv_amount[GET_BOOTS] <= 0)
|
|
P_SelectNextInvItem(p);
|
|
}
|
|
else
|
|
{
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_LONGTERM_PAIN))
|
|
A_PlaySound(DUKE_LONGTERM_PAIN,p->i);
|
|
|
|
P_PalFrom(p, 32, 0,8,0);
|
|
s->extra--;
|
|
}
|
|
}
|
|
|
|
if (p->on_ground && truefdist <= PHEIGHT+(16<<8) && P_CheckFloorDamage(p, j))
|
|
{
|
|
P_DoQuote(QUOTE_BOOTS_ON, p);
|
|
p->inv_amount[GET_BOOTS] -= 2;
|
|
if (p->inv_amount[GET_BOOTS] <= 0)
|
|
{
|
|
p->inv_amount[GET_BOOTS] = 0;
|
|
P_SelectNextInvItem(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_player[snum].sync->extbits&(1))
|
|
VM_OnEvent(EVENT_MOVEFORWARD,p->i,snum);
|
|
|
|
if (g_player[snum].sync->extbits&(1<<1))
|
|
VM_OnEvent(EVENT_MOVEBACKWARD,p->i,snum);
|
|
|
|
if (g_player[snum].sync->extbits&(1<<2))
|
|
VM_OnEvent(EVENT_STRAFELEFT,p->i,snum);
|
|
|
|
if (g_player[snum].sync->extbits&(1<<3))
|
|
VM_OnEvent(EVENT_STRAFERIGHT,p->i,snum);
|
|
|
|
if (g_player[snum].sync->extbits&(1<<4) || g_player[snum].sync->avel < 0)
|
|
VM_OnEvent(EVENT_TURNLEFT,p->i,snum);
|
|
|
|
if (g_player[snum].sync->extbits&(1<<5) || g_player[snum].sync->avel > 0)
|
|
VM_OnEvent(EVENT_TURNRIGHT,p->i,snum);
|
|
|
|
if (p->vel.x || p->vel.y || g_player[snum].sync->fvel || g_player[snum].sync->svel)
|
|
{
|
|
p->crack_time = 777;
|
|
|
|
k = sintable[p->bobcounter&2047]>>12;
|
|
|
|
if ((truefdist < PHEIGHT+(8<<8)) && (k == 1 || k == 3))
|
|
{
|
|
if (p->walking_snd_toggle == 0 && p->on_ground)
|
|
{
|
|
switch (psectlotag)
|
|
{
|
|
case 0:
|
|
if (lz >= 0 && (lz&49152) == 49152)
|
|
j = sprite[lz&(MAXSPRITES-1)].picnum;
|
|
else j = sector[p->cursectnum].floorpicnum;
|
|
|
|
switch (DYNAMICTILEMAP(j))
|
|
{
|
|
case PANNEL1__STATIC:
|
|
case PANNEL2__STATIC:
|
|
A_PlaySound(DUKE_WALKINDUCTS,p->i);
|
|
p->walking_snd_toggle = 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ST_1_ABOVE_WATER:
|
|
if (!p->spritebridge)
|
|
{
|
|
if ((krand()&1) == 0)
|
|
A_PlaySound(DUKE_ONWATER,p->i);
|
|
p->walking_snd_toggle = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (p->walking_snd_toggle > 0)
|
|
p->walking_snd_toggle--;
|
|
|
|
if (p->jetpack_on == 0 && p->inv_amount[GET_STEROIDS] > 0 && p->inv_amount[GET_STEROIDS] < 400)
|
|
doubvel <<= 1;
|
|
|
|
p->vel.x += (((g_player[snum].sync->fvel) * doubvel) << 6);
|
|
p->vel.y += (((g_player[snum].sync->svel) * doubvel) << 6);
|
|
|
|
j = 0;
|
|
|
|
if (psectlotag == ST_2_UNDERWATER)
|
|
j = 0x1400;
|
|
else if (p->on_ground && (TEST_SYNC_KEY(sb_snum, SK_CROUCH) || (*kb > 10 && PWEAPON(snum, p->curr_weapon, WorksLike) == KNEE_WEAPON)))
|
|
j = 0x2000;
|
|
|
|
p->vel.x = mulscale16(p->vel.x, p->runspeed - j);
|
|
p->vel.y = mulscale16(p->vel.y, p->runspeed - j);
|
|
|
|
if (klabs(p->vel.x) < 2048 && klabs(p->vel.y) < 2048)
|
|
p->vel.x = p->vel.y = 0;
|
|
|
|
if (shrunk)
|
|
{
|
|
p->vel.x = mulscale16(p->vel.x,p->runspeed-(p->runspeed>>1)+(p->runspeed>>2));
|
|
p->vel.y = mulscale16(p->vel.y,p->runspeed-(p->runspeed>>1)+(p->runspeed>>2));
|
|
}
|
|
}
|
|
|
|
HORIZONLY:
|
|
if (psectlotag == ST_1_ABOVE_WATER || p->spritebridge == 1) i = p->autostep_sbw;
|
|
else i = p->autostep;
|
|
|
|
#ifdef EDUKE32_TOUCH_DEVICES
|
|
if (TEST_SYNC_KEY(sb_snum, SK_CROUCH))
|
|
i = p->autostep_sbw;
|
|
#endif
|
|
|
|
if (p->cursectnum >= 0 && sector[p->cursectnum].lotag == ST_2_UNDERWATER) k = 0;
|
|
else k = 1;
|
|
|
|
if (ud.noclip)
|
|
{
|
|
p->pos.x += p->vel.x>>14;
|
|
p->pos.y += p->vel.y>>14;
|
|
updatesector(p->pos.x,p->pos.y,&p->cursectnum);
|
|
changespritesect(p->i,p->cursectnum);
|
|
}
|
|
else
|
|
{
|
|
#ifdef YAX_ENABLE
|
|
int32_t sect = p->cursectnum;
|
|
int16_t cb, fb;
|
|
|
|
if (sect >= 0)
|
|
yax_getbunches(sect, &cb, &fb);
|
|
|
|
// This updatesectorz conflicts with Duke3D's way of teleporting through water,
|
|
// so make it a bit conditional... OTOH, this way we have an ugly z jump when
|
|
// changing from above water to underwater
|
|
if (sect >= 0 && !(sector[sect].lotag==ST_1_ABOVE_WATER && p->on_ground && fb>=0))
|
|
{
|
|
if ((fb>=0 && !(sector[sect].floorstat&512)) || (cb>=0 && !(sector[sect].ceilingstat&512)))
|
|
{
|
|
p->cursectnum += MAXSECTORS; // skip initial z check, restored by updatesectorz
|
|
updatesectorz(p->pos.x,p->pos.y,p->pos.z,&p->cursectnum);
|
|
}
|
|
}
|
|
#endif
|
|
if ((j = clipmove((vec3_t *)p, &p->cursectnum, p->vel.x + (p->fric.x << 9), p->vel.y + (p->fric.y << 9), 164L,
|
|
(4L << 8), i, CLIPMASK0)))
|
|
P_CheckTouchDamage(p, j);
|
|
|
|
p->fric.x = p->fric.y = 0;
|
|
}
|
|
|
|
// This makes the player view lower when shrunk. NOTE that it can get the
|
|
// view below the sector floor (and does, when on the ground).
|
|
if (p->jetpack_on == 0 && psectlotag != ST_2_UNDERWATER && psectlotag != ST_1_ABOVE_WATER && shrunk)
|
|
p->pos.z += 32<<8;
|
|
|
|
if (p->jetpack_on == 0)
|
|
{
|
|
if (s->xvel > 16)
|
|
{
|
|
if (psectlotag != ST_1_ABOVE_WATER && psectlotag != ST_2_UNDERWATER && p->on_ground)
|
|
{
|
|
p->pycount += 52;
|
|
p->pycount &= 2047;
|
|
p->pyoff =
|
|
klabs(s->xvel*sintable[p->pycount])/1596;
|
|
}
|
|
}
|
|
else if (psectlotag != ST_2_UNDERWATER && psectlotag != ST_1_ABOVE_WATER)
|
|
p->pyoff = 0;
|
|
}
|
|
|
|
// RBG***
|
|
|
|
p->pos.z += PHEIGHT;
|
|
setsprite(p->i,(vec3_t *)&p->pos.x);
|
|
p->pos.z -= PHEIGHT;
|
|
|
|
// ST_2_UNDERWATER
|
|
if (p->cursectnum >= 0 && psectlotag < 3)
|
|
{
|
|
const sectortype *sec = §or[p->cursectnum];
|
|
// p->cursectnum = s->sectnum;
|
|
|
|
if (!ud.noclip && sec->lotag == ST_31_TWO_WAY_TRAIN)
|
|
{
|
|
// TRAIN_SECTOR_TO_SE_INDEX
|
|
if ((unsigned)sec->hitag < MAXSPRITES && sprite[sec->hitag].xvel
|
|
&& actor[sec->hitag].t_data[0] == 0)
|
|
{
|
|
P_QuickKill(p);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p->cursectnum >= 0 && truefdist < PHEIGHT && p->on_ground &&
|
|
psectlotag != ST_1_ABOVE_WATER && shrunk == 0 && sector[p->cursectnum].lotag == ST_1_ABOVE_WATER)
|
|
if (!A_CheckSoundPlaying(p->i,DUKE_ONWATER))
|
|
A_PlaySound(DUKE_ONWATER,p->i);
|
|
|
|
if (p->cursectnum >=0 && p->cursectnum != s->sectnum)
|
|
changespritesect(p->i, p->cursectnum);
|
|
|
|
if (p->cursectnum >= 0 && ud.noclip == 0)
|
|
{
|
|
j = (pushmove((vec3_t *)p,&p->cursectnum,164L,(4L<<8),(4L<<8),CLIPMASK0) < 0 && A_GetFurthestAngle(p->i,8) < 512);
|
|
|
|
if (klabs(actor[p->i].floorz-actor[p->i].ceilingz) < (48<<8) || j)
|
|
{
|
|
if (!(sector[s->sectnum].lotag&0x8000) && (isanunderoperator(sector[s->sectnum].lotag) ||
|
|
isanearoperator(sector[s->sectnum].lotag)))
|
|
G_ActivateBySector(s->sectnum,p->i);
|
|
if (j)
|
|
{
|
|
P_QuickKill(p);
|
|
return;
|
|
}
|
|
}
|
|
else if (klabs(fz-cz) < (32<<8) && isanunderoperator(sector[p->cursectnum].lotag))
|
|
G_ActivateBySector(p->cursectnum,p->i);
|
|
}
|
|
|
|
i = 0;
|
|
if (TEST_SYNC_KEY(sb_snum, SK_CENTER_VIEW) || p->hard_landing)
|
|
if (VM_OnEvent(EVENT_RETURNTOCENTER,p->i,snum) == 0)
|
|
p->return_to_center = 9;
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_LOOK_UP))
|
|
{
|
|
if (VM_OnEvent(EVENT_LOOKUP,p->i,snum) == 0)
|
|
{
|
|
p->return_to_center = 9;
|
|
if (TEST_SYNC_KEY(sb_snum, SK_RUN)) p->horiz += 12;
|
|
p->horiz += 12;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_LOOK_DOWN))
|
|
{
|
|
if (VM_OnEvent(EVENT_LOOKDOWN,p->i,snum) == 0)
|
|
{
|
|
p->return_to_center = 9;
|
|
if (TEST_SYNC_KEY(sb_snum, SK_RUN)) p->horiz -= 12;
|
|
p->horiz -= 12;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_AIM_UP))
|
|
{
|
|
if (VM_OnEvent(EVENT_AIMUP,p->i,snum) == 0)
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_RUN)) p->horiz += 6;
|
|
p->horiz += 6;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (TEST_SYNC_KEY(sb_snum, SK_AIM_DOWN))
|
|
{
|
|
if (VM_OnEvent(EVENT_AIMDOWN,p->i,snum) == 0)
|
|
{
|
|
if (TEST_SYNC_KEY(sb_snum, SK_RUN)) p->horiz -= 6;
|
|
p->horiz -= 6;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (p->return_to_center > 0 && !TEST_SYNC_KEY(sb_snum, SK_LOOK_UP) && !TEST_SYNC_KEY(sb_snum, SK_LOOK_DOWN))
|
|
{
|
|
p->return_to_center--;
|
|
p->horiz += 33-(p->horiz/3);
|
|
i++;
|
|
}
|
|
|
|
if (p->hard_landing > 0)
|
|
{
|
|
p->hard_landing--;
|
|
p->horiz -= (p->hard_landing<<4);
|
|
}
|
|
|
|
if (i)
|
|
{
|
|
if (p->horiz > 95 && p->horiz < 105) p->horiz = 100;
|
|
if (p->horizoff > -5 && p->horizoff < 5) p->horizoff = 0;
|
|
}
|
|
|
|
p->horiz += g_player[snum].sync->horz;
|
|
|
|
if (p->horiz > HORIZ_MAX) p->horiz = HORIZ_MAX;
|
|
else if (p->horiz < HORIZ_MIN) p->horiz = HORIZ_MIN;
|
|
|
|
//Shooting code/changes
|
|
|
|
if (p->show_empty_weapon > 0)
|
|
{
|
|
p->show_empty_weapon--;
|
|
if (p->show_empty_weapon == 0 && (p->weaponswitch & 2) && p->ammo_amount[p->curr_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);
|
|
P_AddWeapon(p, p->last_full_weapon, 1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (p->knee_incs > 0)
|
|
{
|
|
p->horiz -= 48;
|
|
p->return_to_center = 9;
|
|
|
|
if (++p->knee_incs > 15)
|
|
{
|
|
p->knee_incs = 0;
|
|
p->holster_weapon = 0;
|
|
p->weapon_pos = klabs(p->weapon_pos);
|
|
|
|
if (p->actorsqu >= 0 && sprite[p->actorsqu].statnum != MAXSTATUS && dist(&sprite[p->i],&sprite[p->actorsqu]) < 1400)
|
|
{
|
|
A_DoGuts(p->actorsqu,JIBS6,7);
|
|
A_Spawn(p->actorsqu,BLOODPOOL);
|
|
A_PlaySound(SQUISHED,p->actorsqu);
|
|
|
|
switch (DYNAMICTILEMAP(sprite[p->actorsqu].picnum))
|
|
{
|
|
case FEM1__STATIC:
|
|
case FEM2__STATIC:
|
|
case FEM3__STATIC:
|
|
case FEM4__STATIC:
|
|
case FEM5__STATIC:
|
|
case FEM6__STATIC:
|
|
case FEM7__STATIC:
|
|
case FEM8__STATIC:
|
|
case FEM9__STATIC:
|
|
case FEM10__STATIC:
|
|
case PODFEM1__STATIC:
|
|
case NAKED1__STATIC:
|
|
case STATUE__STATIC:
|
|
if (sprite[p->actorsqu].yvel)
|
|
G_OperateRespawns(sprite[p->actorsqu].yvel);
|
|
A_DeleteSprite(p->actorsqu);
|
|
break;
|
|
case APLAYER__STATIC:
|
|
{
|
|
int32_t snum = P_Get(p->actorsqu);
|
|
P_QuickKill(g_player[snum].ps);
|
|
g_player[snum].ps->frag_ps = snum;
|
|
break;
|
|
}
|
|
default:
|
|
if (A_CheckEnemySprite(&sprite[p->actorsqu]))
|
|
p->actors_killed++;
|
|
A_DeleteSprite(p->actorsqu);
|
|
break;
|
|
}
|
|
}
|
|
p->actorsqu = -1;
|
|
}
|
|
else if (p->actorsqu >= 0)
|
|
p->ang += G_GetAngleDelta(p->ang,getangle(sprite[p->actorsqu].x-p->pos.x,sprite[p->actorsqu].y-p->pos.y))>>2;
|
|
}
|
|
|
|
if (P_DoCounters(snum))
|
|
return;
|
|
|
|
P_ProcessWeapon(snum);
|
|
}
|