Files
perfect-dark/src/game/bondwalk.c
T
2022-07-20 21:20:17 +10:00

1783 lines
52 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/bondmove.h"
#include "game/bondwalk.h"
#include "game/cheats.h"
#include "game/chraction.h"
#include "game/debug.h"
#include "game/game_006900.h"
#include "game/chr.h"
#include "game/prop.h"
#include "game/propsnd.h"
#include "game/objectives.h"
#include "game/bondgun.h"
#include "game/player.h"
#include "game/inv.h"
#include "game/bondhead.h"
#include "game/playermgr.h"
#include "game/propobj.h"
#include "bss.h"
#include "lib/snd.h"
#include "lib/rng.h"
#include "lib/mtx.h"
#include "lib/anim.h"
#include "lib/collision.h"
#include "data.h"
#include "types.h"
void bwalkInit(void)
{
u32 prevmode = g_Vars.currentplayer->bondmovemode;
s32 i;
g_Vars.currentplayer->bondmovemode = MOVEMODE_WALK;
g_Vars.currentplayer->bondonground = 0;
g_Vars.currentplayer->tank = NULL;
g_Vars.currentplayer->unk1af0 = NULL;
g_Vars.currentplayer->bondonturret = false;
g_Vars.currentplayer->swaypos = 0;
g_Vars.currentplayer->swayoffset = 0;
g_Vars.currentplayer->swaytarget = 0;
g_Vars.currentplayer->swayoffset0 = 0;
g_Vars.currentplayer->swayoffset2 = 0;
g_Vars.currentplayer->bdeltapos.x = 0;
g_Vars.currentplayer->bdeltapos.y = -0.0001f;
g_Vars.currentplayer->bdeltapos.z = 0;
g_Vars.currentplayer->isfalling = false;
g_Vars.currentplayer->fallstart = 0;
g_Vars.currentplayer->gunextraaimx = 0;
g_Vars.currentplayer->gunextraaimy = 0;
g_Vars.currentplayer->bondforcespeed.x = 0;
g_Vars.currentplayer->bondforcespeed.y = 0;
g_Vars.currentplayer->bondforcespeed.z = 0;
if (prevmode != MOVEMODE_WALK && prevmode != MOVEMODE_CUTSCENE) {
g_Vars.currentplayer->sumcrouch = 0;
g_Vars.currentplayer->crouchheight = 0;
g_Vars.currentplayer->crouchtime240 = 0;
g_Vars.currentplayer->crouchfall = 0;
g_Vars.currentplayer->crouchpos = CROUCHPOS_STAND;
g_Vars.currentplayer->autocrouchpos = CROUCHPOS_STAND;
g_Vars.currentplayer->crouchspeed = 0;
g_Vars.currentplayer->crouchoffset = 0;
#if VERSION < VERSION_NTSC_1_0
bwalkUpdateCrouchOffsetReal();
#endif
g_Vars.currentplayer->guncloseroffset = 0;
}
#if VERSION >= VERSION_NTSC_1_0
bwalkUpdateCrouchOffsetReal();
#endif
if (prevmode != MOVEMODE_GRAB && prevmode != MOVEMODE_WALK) {
for (i = 0; i != 3; i++) {
g_Vars.currentplayer->bondshotspeed.f[i] = 0;
}
g_Vars.currentplayer->speedsideways = 0;
g_Vars.currentplayer->speedstrafe = 0;
g_Vars.currentplayer->speedgo = 0;
g_Vars.currentplayer->speedboost = 1;
g_Vars.currentplayer->speedmaxtime60 = 0;
g_Vars.currentplayer->speedforwards = 0;
g_Vars.currentplayer->speedtheta = 0;
g_Vars.currentplayer->speedthetacontrol = 0;
}
if (g_Vars.currentplayer->walkinitmove) {
struct coord delta;
mtx00016b58(&g_Vars.currentplayer->walkinitmtx,
0, 0, 0,
-g_Vars.currentplayer->bond2.unk1c.x, -g_Vars.currentplayer->bond2.unk1c.y, -g_Vars.currentplayer->bond2.unk1c.z,
g_Vars.currentplayer->bond2.unk28.x, g_Vars.currentplayer->bond2.unk28.y, g_Vars.currentplayer->bond2.unk28.z);
g_Vars.currentplayer->walkinitt = 0;
g_Vars.currentplayer->walkinitt2 = 0;
g_Vars.currentplayer->walkinitstart.x = g_Vars.currentplayer->prop->pos.x;
g_Vars.currentplayer->walkinitstart.y = g_Vars.currentplayer->prop->pos.y;
g_Vars.currentplayer->walkinitstart.z = g_Vars.currentplayer->prop->pos.z;
delta.x = g_Vars.currentplayer->walkinitpos.x - g_Vars.currentplayer->prop->pos.x;
delta.y = 0;
delta.z = g_Vars.currentplayer->walkinitpos.z - g_Vars.currentplayer->prop->pos.z;
propSetPerimEnabled(g_Vars.currentplayer->hoverbike, false);
bwalkCalculateNewPositionWithPush(&delta, 0, true, 0, CDTYPE_ALL);
propSetPerimEnabled(g_Vars.currentplayer->hoverbike, true);
} else if (prevmode != MOVEMODE_GRAB && prevmode != MOVEMODE_WALK) {
g_Vars.currentplayer->moveinitspeed.x = 0;
g_Vars.currentplayer->moveinitspeed.y = 0;
g_Vars.currentplayer->moveinitspeed.z = 0;
}
}
void bwalkSetSwayTarget(s32 value)
{
g_Vars.currentplayer->swaytarget = value * 75.0f;
}
void bwalkAdjustCrouchPos(s32 value)
{
g_Vars.currentplayer->crouchpos += value;
if (g_Vars.currentplayer->crouchpos < CROUCHPOS_SQUAT) {
g_Vars.currentplayer->crouchpos = CROUCHPOS_SQUAT;
} else if (g_Vars.currentplayer->crouchpos > CROUCHPOS_STAND) {
g_Vars.currentplayer->crouchpos = CROUCHPOS_STAND;
}
}
void bwalk0f0c3b38(struct coord *reltarget, struct defaultobj *obj)
{
struct coord posunk;
struct coord vector;
struct coord tween;
struct coord globalthinga;
struct coord globalthingb;
struct coord abstarget;
abstarget.x = reltarget->x + g_Vars.currentplayer->prop->pos.x;
abstarget.y = g_Vars.currentplayer->prop->pos.y;
abstarget.z = reltarget->z + g_Vars.currentplayer->prop->pos.z;
#if VERSION >= VERSION_NTSC_1_0
cd00024e4c(&globalthinga, &globalthingb, 223, "bondwalk.c");
#else
cd00024e4c(&globalthinga, &globalthingb, 221, "bondwalk.c");
#endif
vector.x = globalthingb.z - globalthinga.z;
vector.y = 0;
vector.z = globalthinga.x - globalthingb.x;
if (vector.f[0] != 0 || vector.f[2] != 0) {
guNormalize(&vector.x, &vector.y, &vector.z);
} else {
vector.z = 1;
}
func0f02e3dc(&globalthinga, &globalthingb, &abstarget, &vector, &posunk);
tween.x = (abstarget.x - g_Vars.currentplayer->prop->pos.x) / g_Vars.lvupdate240freal;
tween.y = 0;
tween.z = (abstarget.z - g_Vars.currentplayer->prop->pos.z) / g_Vars.lvupdate240freal;
func0f082e84(obj, &posunk, &vector, &tween, false);
}
/**
* Attempt to move the current player up vertically by the given amount.
*
* Collision checks are done for the new location, and if successful the
* player's positional values are updated.
*
* The function is called with amount = 0 when attempting to stand up from a
* crouch, after increasing the player's bbox to the standing size.
*/
s32 bwalkTryMoveUpwards(f32 amount)
{
bool result;
struct coord newpos;
s16 rooms[8];
u32 stack;
u32 types;
f32 ymax;
f32 ymin;
f32 radius;
if (g_Vars.currentplayer->floorflags & GEOFLAG_0100) {
g_Vars.enableslopes = false;
} else {
g_Vars.enableslopes = true;
}
newpos.x = g_Vars.currentplayer->prop->pos.x;
newpos.y = g_Vars.currentplayer->prop->pos.y + amount;
newpos.z = g_Vars.currentplayer->prop->pos.z;
types = g_Vars.bondcollisions ? CDTYPE_ALL : CDTYPE_BG;
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
func0f065e74(&g_Vars.currentplayer->prop->pos, g_Vars.currentplayer->prop->rooms, &newpos, rooms);
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &newpos, rooms);
propSetPerimEnabled(g_Vars.currentplayer->prop, false);
ymin -= 0.1f;
result = cdTestVolume(&newpos, radius, rooms, types, 1,
ymax - g_Vars.currentplayer->prop->pos.y,
ymin - g_Vars.currentplayer->prop->pos.y);
propSetPerimEnabled(g_Vars.currentplayer->prop, true);
if (result == CDRESULT_NOCOLLISION) {
g_Vars.currentplayer->prop->pos.y = newpos.y;
propDeregisterRooms(g_Vars.currentplayer->prop);
roomsCopy(rooms, g_Vars.currentplayer->prop->rooms);
}
g_Vars.enableslopes = true;
return result;
}
bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply, f32 extrawidth, s32 checktypes)
{
s32 result = CDRESULT_NOCOLLISION;
f32 halfradius;
struct coord dstpos;
s16 dstrooms[8];
bool copyrooms = false;
s16 sp64[22];
s32 types;
f32 ymax;
f32 ymin;
f32 radius;
f32 xdiff;
f32 zdiff;
s32 i;
if (g_Vars.currentplayer->floorflags & GEOFLAG_0100) {
g_Vars.enableslopes = false;
} else {
g_Vars.enableslopes = true;
}
dstpos.x = g_Vars.currentplayer->prop->pos.x;
dstpos.y = g_Vars.currentplayer->prop->pos.y;
dstpos.z = g_Vars.currentplayer->prop->pos.z;
if (vel->x || vel->y || vel->z) {
if (g_Vars.currentplayer->tank) {
propSetPerimEnabled(g_Vars.currentplayer->tank, false);
}
propSetPerimEnabled(g_Vars.currentplayer->prop, false);
dstpos.x += vel->x;
dstpos.y += vel->y;
dstpos.z += vel->z;
types = g_Vars.bondcollisions ? checktypes : CDTYPE_BG;
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
radius += extrawidth;
func0f065dfc(&g_Vars.currentplayer->prop->pos, g_Vars.currentplayer->prop->rooms,
&dstpos, dstrooms, sp64, 20);
#if VERSION < VERSION_NTSC_1_0
for (i = 0; dstrooms[i] != -1; i++) {
if (dstrooms[i] == g_Vars.currentplayer->floorroom) {
dstrooms[0] = g_Vars.currentplayer->floorroom;
dstrooms[1] = -1;
break;
}
}
#endif
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &dstpos, dstrooms);
copyrooms = true;
// Check if the player is moving at least half their radius along the
// X or Z axis in a single frame. If less, only do a collision check for
// the dst position. If more, do a halfway check too?
xdiff = dstpos.x - g_Vars.currentplayer->prop->pos.x;
zdiff = dstpos.z - g_Vars.currentplayer->prop->pos.z;
halfradius = radius * 0.5f;
if (xdiff > halfradius || zdiff > halfradius || xdiff < -halfradius || zdiff < -halfradius) {
result = cdTestAToB3(&g_Vars.currentplayer->prop->pos,
g_Vars.currentplayer->prop->rooms,
&dstpos, dstrooms, radius, types, 1,
ymax - g_Vars.currentplayer->prop->pos.y,
ymin - g_Vars.currentplayer->prop->pos.y);
if (result == CDRESULT_NOCOLLISION) {
result = cdTestAToB1(&g_Vars.currentplayer->prop->pos,
&dstpos, radius, dstrooms, types, 1,
ymax - g_Vars.currentplayer->prop->pos.y,
ymin - g_Vars.currentplayer->prop->pos.y);
}
} else {
result = cdTestAToB1(&g_Vars.currentplayer->prop->pos,
&dstpos, radius, sp64, types, 1,
ymax - g_Vars.currentplayer->prop->pos.y,
ymin - g_Vars.currentplayer->prop->pos.y);
}
propSetPerimEnabled(g_Vars.currentplayer->prop, true);
if (g_Vars.currentplayer->tank) {
propSetPerimEnabled(g_Vars.currentplayer->tank, true);
}
}
if (result == CDRESULT_NOCOLLISION && apply) {
f32 angle = g_Vars.currentplayer->vv_theta + (rotateamount * 360) / M_BADTAU;
while (angle < 0) {
angle += 360;
}
while (angle >= 360) {
angle -= 360;
}
g_Vars.currentplayer->vv_theta = angle;
g_Vars.currentplayer->prop->pos.x = dstpos.x;
g_Vars.currentplayer->prop->pos.y = dstpos.y;
g_Vars.currentplayer->prop->pos.z = dstpos.z;
if (copyrooms) {
propDeregisterRooms(g_Vars.currentplayer->prop);
roomsCopy(dstrooms, g_Vars.currentplayer->prop->rooms);
}
}
g_Vars.enableslopes = true;
return result;
}
bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bool apply, f32 extrawidth, s32 types)
{
s32 result = bwalkCalculateNewPosition(delta, rotateamount, apply, extrawidth, types);
if (result != CDRESULT_NOCOLLISION) {
struct prop *obstacle = cdGetObstacle();
if (obstacle && g_Vars.lvupdate240 > 0) {
if (obstacle->type == PROPTYPE_DOOR) {
struct doorobj *door = obstacle->door;
struct coord sp90;
struct coord sp84;
struct coord sp78;
if (door->doorflags & DOORFLAG_DAMAGEONCONTACT) {
if (!g_Vars.currentplayer->isdead) {
#if VERSION >= VERSION_NTSC_1_0
cd00024e4c(&sp84, &sp78, 465, "bondwalk.c");
#else
cd00024e4c(&sp84, &sp78, 460, "bondwalk.c");
#endif
sp90.x = sp78.f[2] - sp84.f[2];
sp90.y = 0;
sp90.z = sp84.f[0] - sp78.f[0];
if (sp90.f[0] || sp90.f[2]) {
guNormalize(&sp90.x, &sp90.y, &sp90.z);
} else {
sp90.z = 1;
}
chrDamageByLaser(g_Vars.currentplayer->prop->chr, 0.4f, &sp90, 0, g_Vars.currentplayer->prop);
// Laser zap sound
sndStart(var80095200, SFX_PICKUP_LASER, 0, -1, -1, -1, -1, -1);
}
}
} else if (obstacle->type == PROPTYPE_CHR) {
struct chrdata *chr = obstacle->chr;
struct coord newpos;
s16 newrooms[8];
f32 movingdist;
f32 xdist;
f32 zdist;
f32 disttochr;
bool canpush = false;
if (g_Vars.normmplayerisrunning) {
if (chrCompareTeams(g_Vars.currentplayer->prop->chr, chr, COMPARE_FRIENDS)) {
// AI bot on same team
canpush = true;
}
} else if (chr->chrflags & CHRCFLAG_PUSHABLE) {
if (g_Vars.antiplayernum < 0
|| g_Vars.currentplayer != g_Vars.anti
|| (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) {
canpush = true;
}
}
if (canpush) {
movingdist = sqrtf(delta->f[0] * delta->f[0] + delta->f[2] * delta->f[2]) / LVUPDATE240FREAL();
xdist = obstacle->pos.x - g_Vars.currentplayer->prop->pos.x;
zdist = obstacle->pos.z - g_Vars.currentplayer->prop->pos.z;
if (xdist || zdist) {
disttochr = sqrtf(xdist * xdist + zdist * zdist);
if (disttochr > 0) {
disttochr = movingdist / disttochr;
xdist *= disttochr;
zdist *= disttochr;
chr->pushspeed[0] = 0.5f * xdist;
chr->pushspeed[1] = 0.5f * zdist;
newpos.x = obstacle->pos.x + chr->pushspeed[0] * LVUPDATE240FREAL();
newpos.y = obstacle->pos.y;
newpos.z = obstacle->pos.z + chr->pushspeed[1] * LVUPDATE240FREAL();
chrCalculatePushPos(chr, &newpos, newrooms, false);
obstacle->pos.x = newpos.x;
obstacle->pos.y = newpos.y;
obstacle->pos.z = newpos.z;
propDeregisterRooms(obstacle);
roomsCopy(newrooms, obstacle->rooms);
chr0f0220ac(chr);
modelSetRootPosition(chr->model, &newpos);
result = bwalkCalculateNewPosition(delta, rotateamount, apply, extrawidth, types);
}
}
}
} else if (obstacle->type == PROPTYPE_PLAYER) {
// empty
} else if (obstacle->type == PROPTYPE_OBJ) {
struct defaultobj *obj = obstacle->obj;
bool dothething;
if ((obj->hidden & OBJHFLAG_MOUNTED) == 0 && (obj->hidden & OBJHFLAG_GRABBED) == 0) {
if (g_Vars.currentplayer->unk1af0 == 0 && obj->type == OBJTYPE_TANK) {
g_Vars.currentplayer->tank = obstacle;
} else if (obj->flags3 & OBJFLAG3_PUSHABLE) {
g_Vars.currentplayer->speedmaxtime60 = 0;
dothething = true;
if ((obj->hidden & OBJHFLAG_PROJECTILE) &&
(obj->projectile->flags & PROJECTILEFLAG_00001000)) {
dothething = false;
}
if (dothething) {
bwalk0f0c3b38(delta, obj);
if (obj->hidden & OBJHFLAG_PROJECTILE && (obj->projectile->flags & PROJECTILEFLAG_SLIDING)) {
bool somevalue;
bool embedded = false;
somevalue = projectileTick(obj, &embedded);
if (obj->hidden & OBJHFLAG_PROJECTILE) {
obj->projectile->flags |= PROJECTILEFLAG_00001000;
if (somevalue) {
obj->projectile->flags |= PROJECTILEFLAG_00002000;
} else {
obj->projectile->flags &= ~PROJECTILEFLAG_00002000;
}
}
if (somevalue) {
result = bwalkCalculateNewPosition(delta, rotateamount, apply, extrawidth, types);
}
}
}
}
}
}
}
}
return result;
}
s32 bwalk0f0c4764(struct coord *delta, struct coord *arg1, struct coord *arg2, s32 types)
{
s32 result = bwalkCalculateNewPositionWithPush(delta, 0, true, 0, types);
if (result == CDRESULT_COLLISION) {
#if VERSION >= VERSION_NTSC_1_0
cd00024e4c(arg1, arg2, 607, "bondwalk.c");
#else
cd00024e4c(arg1, arg2, 602, "bondwalk.c");
#endif
}
return result;
}
s32 bwalk0f0c47d0(struct coord *a, struct coord *b, struct coord *c,
struct coord *d, struct coord *e, s32 types)
{
struct coord quarter;
bool result;
if (cd00024ea4()) {
f32 mult = cd00024e98();
quarter.x = a->x * mult * 0.25f;
quarter.y = a->y * mult * 0.25f;
quarter.z = a->z * mult * 0.25f;
result = bwalkCalculateNewPositionWithPush(&quarter, 0, true, 0, types);
if (result == CDRESULT_NOCOLLISION) {
return CDRESULT_NOCOLLISION;
}
if (result == CDRESULT_COLLISION) {
#if VERSION >= VERSION_NTSC_1_0
cd00024e4c(d, e, 635, "bondwalk.c");
#else
cd00024e4c(d, e, 630, "bondwalk.c");
#endif
if (b->x != d->x
|| b->y != d->y
|| b->z != d->z
|| c->x != e->x
|| c->y != e->y
|| c->z != e->z) {
return CDRESULT_COLLISION;
}
}
}
return CDRESULT_ERROR;
}
s32 bwalk0f0c494c(struct coord *a, struct coord *b, struct coord *c, s32 types)
{
if (b->f[0] != c->f[0] || b->f[2] != c->f[2]) {
f32 tmp;
struct coord sp38;
struct coord sp2c;
sp38.x = c->x - b->x;
sp38.y = 0;
sp38.z = c->z - b->z;
tmp = sqrtf(sp38.f[0] * sp38.f[0] + sp38.f[2] * sp38.f[2]);
sp38.x *= 1.0f / tmp;
sp38.z *= 1.0f / tmp;
tmp = a->f[0] * sp38.f[0] + a->f[2] * sp38.f[2];
sp2c.x = sp38.x * tmp;
sp2c.y = 0;
sp2c.z = sp38.z * tmp;
return bwalkCalculateNewPositionWithPush(&sp2c, 0, true, 0, types);
}
return -1;
}
s32 bwalk0f0c4a5c(struct coord *arg0, struct coord *arg1, struct coord *arg2, s32 types)
{
struct coord sp34;
struct coord sp28;
f32 ymax;
f32 ymin;
f32 tmp;
f32 radius;
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
sp34.x = arg1->x - (g_Vars.currentplayer->prop->pos.x + arg0->f[0]);
sp34.z = arg1->z - (g_Vars.currentplayer->prop->pos.z + arg0->f[2]);
if (sp34.f[0] * sp34.f[0] + sp34.f[2] * sp34.f[2] <= radius * radius) {
if (arg1->f[0] != g_Vars.currentplayer->prop->pos.f[0] || arg1->f[2] != g_Vars.currentplayer->prop->pos.f[2]) {
sp34.x = -(arg1->z - g_Vars.currentplayer->prop->pos.z);
sp34.y = 0;
sp34.z = arg1->x - g_Vars.currentplayer->prop->pos.x;
tmp = sqrtf(sp34.f[0] * sp34.f[0] + sp34.f[2] * sp34.f[2]);
sp34.x = sp34.f[0] * (1.0f / tmp);
sp34.z = sp34.f[2] * (1.0f / tmp);
tmp = arg0->f[0] * sp34.f[0] + arg0->f[2] * sp34.f[2];
sp34.x = sp34.x * tmp;
sp34.z = sp34.z * tmp;
sp28.x = sp34.x;
sp28.y = 0;
sp28.z = sp34.z;
if (bwalkCalculateNewPositionWithPush(&sp28, 0, true, 0, types) == CDRESULT_NOCOLLISION) {
return true;
}
}
} else {
sp34.x = arg2->x - (g_Vars.currentplayer->prop->pos.x + arg0->f[0]);
sp34.z = arg2->z - (g_Vars.currentplayer->prop->pos.z + arg0->f[2]);
if (sp34.f[0] * sp34.f[0] + sp34.f[2] * sp34.f[2] <= radius * radius) {
if (arg2->f[0] != g_Vars.currentplayer->prop->pos.f[0] || arg2->f[2] != g_Vars.currentplayer->prop->pos.f[2]) {
sp34.x = -(arg2->z - g_Vars.currentplayer->prop->pos.z);
sp34.y = 0;
sp34.z = arg2->x - g_Vars.currentplayer->prop->pos.x;
tmp = sqrtf(sp34.f[0] * sp34.f[0] + sp34.f[2] * sp34.f[2]);
sp34.x = sp34.f[0] * (1.0f / tmp);
sp34.z = sp34.f[2] * (1.0f / tmp);
tmp = arg0->f[0] * sp34.f[0] + arg0->f[2] * sp34.f[2];
sp34.x = sp34.x * tmp;
sp34.z = sp34.z * tmp;
sp28.x = sp34.x;
sp28.y = 0;
sp28.z = sp34.z;
if (bwalkCalculateNewPositionWithPush(&sp28, 0, true, 0, types) == CDRESULT_NOCOLLISION) {
return true;
}
}
}
}
return false;
}
void bwalk0f0c4d98(void)
{
// empty
}
void bwalkUpdateSpeedSideways(f32 targetspeed, f32 accelspeed, s32 mult)
{
if (g_Vars.normmplayerisrunning) {
targetspeed = (g_PlayerConfigsArray[g_Vars.currentplayerstats->mpindex].base.unk1c + 25.0f) / 100 * targetspeed;
}
if (g_Vars.currentplayer->speedstrafe > targetspeed) {
g_Vars.currentplayer->speedstrafe -= PALUPF(accelspeed * mult);
if (g_Vars.currentplayer->speedstrafe < targetspeed) {
g_Vars.currentplayer->speedstrafe = targetspeed;
}
} else if (g_Vars.currentplayer->speedstrafe < targetspeed) {
g_Vars.currentplayer->speedstrafe += PALUPF(accelspeed * mult);
if (g_Vars.currentplayer->speedstrafe > targetspeed) {
g_Vars.currentplayer->speedstrafe = targetspeed;
}
}
g_Vars.currentplayer->speedsideways = g_Vars.currentplayer->speedstrafe;
}
void bwalkUpdateSpeedForwards(f32 targetspeed, f32 accelspeed)
{
if (g_Vars.normmplayerisrunning) {
targetspeed = (g_PlayerConfigsArray[g_Vars.currentplayerstats->mpindex].base.unk1c + 25.0f) / 100 * targetspeed;
}
if (g_Vars.currentplayer->speedgo < targetspeed) {
g_Vars.currentplayer->speedgo += accelspeed * g_Vars.lvupdate240freal;
if (g_Vars.currentplayer->speedgo > targetspeed) {
g_Vars.currentplayer->speedgo = targetspeed;
}
} else if (g_Vars.currentplayer->speedgo > targetspeed) {
g_Vars.currentplayer->speedgo -= accelspeed * g_Vars.lvupdate240freal;
if (g_Vars.currentplayer->speedgo < targetspeed) {
g_Vars.currentplayer->speedgo = targetspeed;
}
}
g_Vars.currentplayer->speedforwards = g_Vars.currentplayer->speedgo;
}
void bwalkUpdateVertical(void)
{
s32 i;
f32 newfallspeed;
f32 radius;
f32 ymax;
f32 ymin;
f32 ground;
bool onladder;
bool onladder2 = false;
s16 rooms[8];
struct coord testpos;
struct coord newpos;
s16 newrooms[8];
s32 newinlift;
struct prop *lift = NULL;
f32 sumground;
f32 moveamount;
#if VERSION >= VERSION_NTSC_1_0
f32 limit;
f32 amount;
struct prop *prop;
#endif
f32 newmanground;
f32 fallspeed;
f32 eyeheight;
f32 multiplier;
#if VERSION >= VERSION_NTSC_1_0
struct defaultobj *obj;
#endif
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
#if VERSION >= VERSION_NTSC_1_0
// Maybe reset counter-op's radius - not sure why
// Maybe it gets set to 0 when they die?
if (g_Vars.antiplayernum >= 0
&& g_Vars.currentplayer == g_Vars.anti
&& g_Vars.currentplayer->bond2.radius != 30
&& cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, 1, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) {
g_Vars.currentplayer->prop->chr->radius = 30;
g_Vars.currentplayer->bond2.radius = 30;
radius = 30;
}
#endif
// Determine if player is on a ladder
// If this comes up false, a second check is done... maybe checking if the
// player is touching a ladder from a room which shares the same coordinate
// space?
onladder = cd00029ffc(&g_Vars.currentplayer->prop->pos,
radius * 1.2f, ymax - g_Vars.currentplayer->prop->pos.y,
g_Vars.currentplayer->vv_manground - g_Vars.currentplayer->prop->pos.y + 1,
g_Vars.currentplayer->prop->rooms, 0x8040, &g_Vars.currentplayer->laddernormal);
if (!onladder) {
testpos.x = g_Vars.currentplayer->prop->pos.x;
testpos.y = g_Vars.currentplayer->prop->pos.y - 10;
testpos.z = g_Vars.currentplayer->prop->pos.z;
roomsCopy(g_Vars.currentplayer->prop->rooms, rooms);
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &testpos, rooms);
onladder2 = cd00029ffc(&g_Vars.currentplayer->prop->pos,
radius * 1.1f, ymax - g_Vars.currentplayer->prop->pos.y,
g_Vars.currentplayer->vv_manground - g_Vars.currentplayer->prop->pos.y - 10,
rooms, 0x8040, &g_Vars.currentplayer->laddernormal);
}
testpos.x = g_Vars.currentplayer->prop->pos.x;
testpos.y = g_Vars.currentplayer->prop->pos.y;
testpos.z = g_Vars.currentplayer->prop->pos.z;
if (g_Vars.currentplayer->inlift) {
testpos.y -= g_Vars.currentplayer->crouchheight + g_Vars.currentplayer->crouchoffsetrealsmall;
}
roomsCopy(g_Vars.currentplayer->prop->rooms, rooms);
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &testpos, rooms);
ground = cdFindGroundY(&testpos, g_Vars.currentplayer->bond2.radius, rooms,
&g_Vars.currentplayer->floorcol, &g_Vars.currentplayer->floortype,
&g_Vars.currentplayer->floorflags, &g_Vars.currentplayer->floorroom,
&newinlift, &lift);
ground += g_Vars.currentplayer->bondonground;
if (ground < -30000) {
ground = -30000;
}
#if PIRACYCHECKS
if (g_Vars.currentplayer->inlift && newinlift == false) {
// Exiting a lift
piracyRestore();
}
#endif
if (g_Vars.currentplayer->inlift && newinlift && g_Vars.currentplayer->onladder == false) {
// Remaining in a lift
moveamount = ground - g_Vars.currentplayer->vv_ground;
#if VERSION >= VERSION_NTSC_1_0
if (moveamount != 0)
#endif
{
// The lift is moving
if (g_Vars.currentplayer->isfalling == false && lift == g_Vars.currentplayer->lift) {
if (g_Vars.currentplayer->liftground - g_Vars.currentplayer->vv_manground < 1.0f
&& g_Vars.currentplayer->liftground - g_Vars.currentplayer->vv_manground > -1.0f) {
// It's actually moving, and not a floating point precision issue
g_Vars.currentplayer->vv_ground += moveamount;
if (moveamount > 0
|| lift == NULL
|| lift->obj == NULL
|| (lift->obj->flags & OBJFLAG_CHOPPER_INACTIVE) == 0
|| bwalkTryMoveUpwards(moveamount) == CDRESULT_NOCOLLISION) {
// Going up
g_Vars.currentplayer->vv_manground += moveamount;
g_Vars.currentplayer->sumground = g_Vars.currentplayer->vv_manground / (PAL ? 0.054400026798248f : 0.045499980449677f);
}
}
}
if (g_Vars.currentplayer->walkinitmove) {
g_Vars.currentplayer->walkinitstart.y += moveamount;
}
}
} else {
lift = NULL;
}
g_Vars.currentplayer->inlift = newinlift;
if (newinlift) {
g_Vars.currentplayer->liftground = ground;
}
g_Vars.currentplayer->lift = lift;
// Ladders
if (g_Vars.currentplayer->onladder) {
if (g_Vars.currentplayer->ladderupdown >= 0 ||
(ground <= g_Vars.currentplayer->vv_manground &&
ground <= g_Vars.currentplayer->vv_manground + g_Vars.currentplayer->ladderupdown)) {
// Still on ladder
if (bwalkTryMoveUpwards(g_Vars.currentplayer->ladderupdown) == CDRESULT_NOCOLLISION) {
g_Vars.currentplayer->vv_manground += g_Vars.currentplayer->ladderupdown;
}
} else {
if (bwalkTryMoveUpwards(ground - g_Vars.currentplayer->vv_manground) == CDRESULT_NOCOLLISION) {
g_Vars.currentplayer->vv_manground = ground;
onladder = false;
}
}
}
g_Vars.currentplayer->onladder = onladder;
if (g_Vars.currentplayer->onladder) {
g_Vars.currentplayer->vv_ground = g_Vars.currentplayer->vv_manground;
} else if (onladder2 == false) {
g_Vars.currentplayer->vv_ground = ground;
}
// Standing on flat ground, or going up stairs, ledges or ramps
// In other words, not falling
if (g_Vars.currentplayer->bdeltapos.y >= 0.0f
|| g_Vars.currentplayer->vv_ground > g_Vars.currentplayer->vv_manground) {
g_Vars.currentplayer->sumground = g_Vars.currentplayer->vv_manground / (PAL ? 0.054400026798248f : 0.045499980449677f);
for (i = 0; i < g_Vars.lvupdate240; i++) {
g_Vars.currentplayer->sumground =
g_Vars.currentplayer->sumground * (PAL ? 0.94559997320175f : 0.9545f) + g_Vars.currentplayer->vv_ground;
}
if (g_Vars.currentplayer->vv_manground < g_Vars.currentplayer->vv_ground) {
// Feet are lower than the ground
sumground = g_Vars.currentplayer->sumground * (PAL ? 0.054400026798248f : 0.045499980449677f);
if (sumground < g_Vars.currentplayer->vv_ground - 50) {
sumground = g_Vars.currentplayer->vv_ground - 50;
}
if (bwalkTryMoveUpwards(sumground - g_Vars.currentplayer->vv_manground) == CDRESULT_NOCOLLISION) {
g_Vars.currentplayer->vv_manground = sumground;
}
#if VERSION >= VERSION_NTSC_1_0
else {
// Not enough room above. If on a hoverbike, blow it up
prop = cdGetObstacle();
if (prop
&& g_Vars.currentplayer->prop->pos.y < prop->pos.y
&& prop->type == PROPTYPE_OBJ) {
obj = prop->obj;
if (obj->modelnum == MODEL_HOVBIKE) {
amount = (obj->maxdamage - obj->damage + 1) / 250.0f;
obj->flags &= ~OBJFLAG_INVINCIBLE;
objDamage(obj, amount, &obj->prop->pos, WEAPON_REMOTEMINE, -1);
}
}
}
#endif
}
// Kill player if standing on tile with GEOFLAG_DIE
if ((g_Vars.currentplayer->floorflags & GEOFLAG_DIE)
&& g_Vars.currentplayer->vv_manground - 20.0f < g_Vars.currentplayer->vv_ground
&& g_Vars.currentplayer->onladder == false
&& onladder2 == false) {
playerDie(true);
}
}
if (g_Vars.currentplayer->vv_manground > g_Vars.currentplayer->vv_ground) {
// Not standing on ground - probably falling, or on an object of some sort
fallspeed = g_Vars.currentplayer->bdeltapos.y;
newmanground = g_Vars.currentplayer->vv_manground;
if (debugIsTurboModeEnabled()
&& g_Vars.currentplayer->bondforcespeed.x == 0
&& g_Vars.currentplayer->bondforcespeed.z == 0) {
multiplier = 0.277777777f * 5;
} else {
multiplier = 0.277777777f;
}
newfallspeed = fallspeed - g_Vars.lvupdate240freal * multiplier;
newmanground += g_Vars.lvupdate240freal * (fallspeed + newfallspeed) * 0.5f;
fallspeed = newfallspeed;
if (newmanground < g_Vars.currentplayer->vv_ground) {
newfallspeed = g_Vars.currentplayer->vv_manground - g_Vars.currentplayer->vv_ground;
newmanground = g_Vars.currentplayer->vv_ground;
fallspeed = sqrtf(g_Vars.currentplayer->bdeltapos.y *
g_Vars.currentplayer->bdeltapos.y +
(((newfallspeed + newfallspeed) * 0.277777777f) / 60.0f) * 60.0f);
fallspeed = -fallspeed;
}
if (bwalkTryMoveUpwards(newmanground - g_Vars.currentplayer->vv_manground) == CDRESULT_NOCOLLISION) {
// Falling
g_Vars.currentplayer->vv_manground = newmanground;
g_Vars.currentplayer->bdeltapos.y = fallspeed;
if (g_Vars.currentplayer->isfalling == false) {
// Just started falling
g_Vars.currentplayer->isfalling = true;
g_Vars.currentplayer->fallstart = g_Vars.lvframe60;
} else {
if (g_Vars.lvframe60 - g_Vars.currentplayer->fallstart > TICKS(240)) {
// Have been falling for 4 seconds
playerDie(true);
}
}
} else {
// Not falling
#if VERSION >= VERSION_NTSC_1_0
if (g_Vars.normmplayerisrunning == false
&& g_Vars.currentplayer->vv_ground < g_Vars.currentplayer->vv_manground - 30) {
// Not falling - but still at least 30 units off the ground.
// Must be something in the way...
prop = cdGetObstacle();
if (prop) {
if (prop->type == PROPTYPE_CHR) {
// Landed on top of a chr
if (prop->chr->inlift) {
chrYeetFromPos(prop->chr, &g_Vars.currentplayer->prop->pos, 0);
}
} else if (prop->type == PROPTYPE_PLAYER) {
// Landed on top of a player
u32 prevplayernum = g_Vars.currentplayernum;
setCurrentPlayerNum(playermgrGetPlayerNumByProp(prop));
if (g_Vars.currentplayer->inlift) {
playerDieByShooter(prevplayernum, true);
}
setCurrentPlayerNum(prevplayernum);
}
}
}
#endif
g_Vars.currentplayer->bdeltapos.y = VERSION >= VERSION_NTSC_1_0 ? 0.0f : 0;
if (g_Vars.currentplayer->isfalling) {
g_Vars.currentplayer->isfalling = false;
}
if (g_Vars.currentplayer->vv_manground <= -30000) {
playerDie(true);
}
}
} else {
// Not falling
if (g_Vars.currentplayer->isfalling) {
g_Vars.currentplayer->isfalling = false;
}
if (g_Vars.currentplayer->vv_manground <= -30000) {
playerDie(true);
}
}
if (g_Vars.currentplayer->bdeltapos.y < 0 &&
g_Vars.currentplayer->vv_manground <= g_Vars.currentplayer->vv_ground) {
// Landing after a fall
if (g_Vars.currentplayer->isfalling) {
g_Vars.currentplayer->isfalling = false;
}
// I suspect these crouch fields are related to the recovery during
// landing. Eg. The faster the fall speed, the longer Jo will take to
// stand back to full height again.
if (g_Vars.currentplayer->bdeltapos.y < -13.333333f) {
g_Vars.currentplayer->crouchtime240 = TICKS(60);
g_Vars.currentplayer->crouchfall = -90;
} else if (g_Vars.currentplayer->bdeltapos.y < -5.0f) {
g_Vars.currentplayer->crouchtime240 = TICKS(60);
g_Vars.currentplayer->crouchfall =
(-5.0f - g_Vars.currentplayer->bdeltapos.y) * -90.0f / 8.333333f;
}
if (g_Vars.currentplayer->bdeltapos.y < -6.0f) {
// Play footstep sounds
s32 sound;
struct chrdata *chr = g_Vars.currentplayer->prop->chr;
chr->floortype = g_Vars.currentplayer->floortype;
chr->footstep = 1;
sound = footstepChooseSound(chr, true);
if (sound != -1) {
if (sound != -1) {
propsnd0f0939f8(NULL, g_Vars.currentplayer->prop, sound,
-1, -1, 0x8400, 0, 0, 0, -1, NULL, -1, -1, -1, -1);
}
chr->footstep = 2;
sound = footstepChooseSound(chr, true);
if (sound != -1) {
propsnd0f0939f8(NULL, g_Vars.currentplayer->prop, sound,
-1, -1, 0x8400, 0, 0, 0, -1, NULL, -1, -1, -1, -1);
}
}
if (g_Vars.mplayerisrunning == false
&& (chr->headnum == HEAD_DARK_COMBAT || chr->headnum == HEAD_DARK_FROCK)
&& g_Vars.lvframe60 - g_Vars.currentplayer->fallstart > TICKS(40)) {
// Play Jo landing grunt
s32 sounds[] = {
SFX_JO_LANDING_046F,
SFX_JO_LANDING_05B6,
SFX_JO_LANDING_05B7
};
propsnd0f0939f8(NULL, g_Vars.currentplayer->prop, sounds[random() % 3],
-1, -1, 0x8400, 0, 0, 0, -1, NULL, -1, -1, -1, -1);
}
}
g_Vars.currentplayer->bdeltapos.y = 0;
}
// Decrease crouchtime240 for this tick.
// If reached 0 and crouchfall is negative, start increasing
// crouchfall over the next several ticks until it reaches 0.
for (i = 0; i < g_Vars.lvupdate240; i++) {
if (g_Vars.currentplayer->crouchtime240 > 0) {
g_Vars.currentplayer->sumcrouch =
g_Vars.currentplayer->sumcrouch * (PAL ? 0.93540000915527f : 0.9456f) + g_Vars.currentplayer->crouchfall;
g_Vars.currentplayer->crouchtime240--;
} else {
if (g_Vars.currentplayer->crouchfall < 0) {
g_Vars.currentplayer->crouchfall -= (PAL ? -1.3636363744736f : -1.125f);
if (g_Vars.currentplayer->crouchfall >= 0) {
g_Vars.currentplayer->crouchfall = 0;
}
}
g_Vars.currentplayer->sumcrouch =
g_Vars.currentplayer->sumcrouch * (PAL ? 0.93540000915527f : 0.9456f) + g_Vars.currentplayer->crouchfall;
}
}
{
g_Vars.currentplayer->crouchheight = g_Vars.currentplayer->sumcrouch * (PAL ? 0.064599990844727f : 0.054400026798248f);
g_Vars.currentplayer->vv_height =
(g_Vars.currentplayer->headpos.y / g_Vars.currentplayer->standheight)
* g_Vars.currentplayer->vv_eyeheight;
eyeheight = g_Vars.currentplayer->vv_height +
g_Vars.currentplayer->crouchoffsetrealsmall +
g_Vars.currentplayer->crouchheight *
g_Vars.currentplayer->vv_eyeheight * 0.0062893079593778f;
if (eyeheight < 30) {
eyeheight = 30;
}
newpos.x = g_Vars.currentplayer->prop->pos.x;
newpos.y = g_Vars.currentplayer->vv_manground + eyeheight;
newpos.z = g_Vars.currentplayer->prop->pos.z;
}
#if VERSION >= VERSION_NTSC_1_0
if (newpos.y < g_Vars.currentplayer->vv_ground + 10) {
newpos.y = g_Vars.currentplayer->vv_ground + 10;
}
#endif
if (newpos.x != g_Vars.currentplayer->prop->pos.x
|| newpos.y != g_Vars.currentplayer->prop->pos.y
|| newpos.z != g_Vars.currentplayer->prop->pos.z) {
func0f065e74(&g_Vars.currentplayer->prop->pos, g_Vars.currentplayer->prop->rooms, &newpos, newrooms);
g_Vars.currentplayer->prop->pos.x = newpos.x;
g_Vars.currentplayer->prop->pos.y = newpos.y;
g_Vars.currentplayer->prop->pos.z = newpos.z;
propDeregisterRooms(g_Vars.currentplayer->prop);
roomsCopy(newrooms, g_Vars.currentplayer->prop->rooms);
}
}
void bwalkApplyCrouchSpeed(void)
{
if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) {
g_Vars.currentplayer->speedforwards *= 0.5f;
g_Vars.currentplayer->speedsideways *= 0.5f;
} else if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) {
g_Vars.currentplayer->speedforwards *= 0.35f;
g_Vars.currentplayer->speedsideways *= 0.35f;
}
}
void bwalkUpdateCrouchOffsetReal(void)
{
if (g_Vars.currentplayer->vv_eyeheight + -90.0f * g_Vars.currentplayer->vv_eyeheight * (1.0f / 159.0f) < 69.0f) {
g_Vars.currentplayer->crouchoffsetreal = g_Vars.currentplayer->crouchoffset * ((69.0f - g_Vars.currentplayer->vv_eyeheight) / -90.0f);
} else {
g_Vars.currentplayer->crouchoffsetreal = g_Vars.currentplayer->crouchoffset * g_Vars.currentplayer->vv_eyeheight * (1.0f / 159.0f);
}
if (cheatIsActive(CHEAT_SMALLJO)) {
g_Vars.currentplayer->crouchoffsetsmall = 69.0f - g_Vars.currentplayer->vv_eyeheight;
g_Vars.currentplayer->crouchoffsetrealsmall = 69.0f - g_Vars.currentplayer->vv_eyeheight;
} else {
g_Vars.currentplayer->crouchoffsetsmall = g_Vars.currentplayer->crouchoffset;
g_Vars.currentplayer->crouchoffsetrealsmall = g_Vars.currentplayer->crouchoffsetreal;
}
}
void bwalkUpdateCrouchOffset(void)
{
f32 targetoffset = 0;
if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) {
targetoffset = -90;
} else if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) {
targetoffset = -45;
} else if (bmoveGetCrouchPos() == CROUCHPOS_STAND) {
// empty
}
if (targetoffset != g_Vars.currentplayer->crouchoffset) {
f32 prevcrouchoffset = g_Vars.currentplayer->crouchoffset;
f32 prevcrouchoffsetreal = g_Vars.currentplayer->crouchoffsetreal;
f32 prevcrouchoffsetsmall = g_Vars.currentplayer->crouchoffsetsmall;
f32 prevcrouchoffsetrealsmall = g_Vars.currentplayer->crouchoffsetrealsmall;
// f32 *frac, f32 maxfrac, f32 *fracspeed, f32 accel, f32 decel, f32 maxspeed
applySpeed(&g_Vars.currentplayer->crouchoffset, targetoffset,
&g_Vars.currentplayer->crouchspeed, PALUPF(0.5f), PALUPF(0.5f), PALUPF(5.0f));
bwalkUpdateCrouchOffsetReal();
if (bwalkTryMoveUpwards(0) == CDRESULT_COLLISION) {
// Crouch adjustment is blocked by ceiling
g_Vars.currentplayer->crouchoffset = prevcrouchoffset;
g_Vars.currentplayer->crouchoffsetreal = prevcrouchoffsetreal;
g_Vars.currentplayer->crouchoffsetsmall = prevcrouchoffsetsmall;
g_Vars.currentplayer->crouchoffsetrealsmall = prevcrouchoffsetrealsmall;
g_Vars.currentplayer->crouchspeed = 0;
bwalkAdjustCrouchPos(-1);
}
}
if (targetoffset == g_Vars.currentplayer->crouchoffset) {
g_Vars.currentplayer->crouchspeed = 0;
}
g_Vars.currentplayer->guncloseroffset = g_Vars.currentplayer->crouchoffset / -90;
}
void bwalkUpdateTheta(void)
{
f32 mult;
f32 rotateamount;
struct coord delta = {0, 0, 0};
// Turn speed is calculated from the chr's height
mult = 159.0f / g_Vars.currentplayer->vv_eyeheight;
rotateamount = g_Vars.currentplayer->speedtheta * mult
* g_Vars.lvupdate240freal * 0.0174505133f * 3.5f;
bwalkCalculateNewPositionWithPush(&delta, rotateamount, true, 0, CDTYPE_ALL);
}
void bwalk0f0c63bc(struct coord *arg0, u32 arg1, s32 types)
{
struct coord sp100;
struct coord sp88;
g_Vars.currentplayer->bondonturret = false;
g_Vars.currentplayer->autocrouchpos = CROUCHPOS_STAND;
bwalk0f0c4d98();
if (bwalk0f0c4764(arg0, &sp100, &sp88, types) == CDRESULT_COLLISION) {
struct coord sp76;
struct coord sp64;
s32 result = bwalk0f0c47d0(arg0, &sp100, &sp88, &sp76, &sp64, types);
if (result >= CDRESULT_NOCOLLISION || result <= CDRESULT_ERROR) {
if (result >= CDRESULT_NOCOLLISION) {
bwalk0f0c4d98();
}
if (arg1
&& bwalk0f0c494c(arg0, &sp100, &sp88, types) <= CDRESULT_COLLISION
&& bwalk0f0c4a5c(arg0, &sp100, &sp88, types) <= CDRESULT_COLLISION) {
// empty
}
} else if (result == CDRESULT_COLLISION) {
struct coord sp48;
struct coord sp36;
if (bwalk0f0c47d0(arg0, &sp76, &sp64, &sp48, &sp36, types) >= CDRESULT_NOCOLLISION) {
bwalk0f0c4d98();
}
if (arg1
&& bwalk0f0c494c(arg0, &sp76, &sp64, types) <= CDRESULT_COLLISION
&& bwalk0f0c494c(arg0, &sp100, &sp88, types) <= CDRESULT_COLLISION
&& bwalk0f0c4a5c(arg0, &sp76, &sp64, types) <= CDRESULT_COLLISION) {
bwalk0f0c4a5c(arg0, &sp100, &sp88, types);
}
}
}
bwalk0f0c4d98();
}
void bwalkUpdatePrevPos(void)
{
g_Vars.currentplayer->bondprevpos.x = g_Vars.currentplayer->prop->pos.x;
g_Vars.currentplayer->bondprevpos.y = g_Vars.currentplayer->prop->pos.y;
g_Vars.currentplayer->bondprevpos.z = g_Vars.currentplayer->prop->pos.z;
roomsCopy(g_Vars.currentplayer->prop->rooms, g_Vars.currentplayer->bondprevrooms);
}
void bwalkHandleActivate(void)
{
if (g_Vars.currentplayer->walkinitmove) {
g_Vars.currentplayer->bondactivateorreload = 0;
}
}
void bwalkApplyMoveData(struct movedata *data)
{
if (g_Vars.currentplayer->walkinitmove == false) {
// Sideways
if (data->digitalstepleft) {
bwalkUpdateSpeedSideways(-1, 0.2f, data->digitalstepleft);
} else if (data->digitalstepright) {
bwalkUpdateSpeedSideways(1, 0.2f, data->digitalstepright);
} else if (data->unk14 == false) {
bwalkUpdateSpeedSideways(0, 0.2f, g_Vars.lvupdate240_60);
}
if (data->unk14) {
bwalkUpdateSpeedSideways(data->analogstrafe * 0.014285714365542f, 0.2f, g_Vars.lvupdate240_60);
}
// Forward/back
if (data->digitalstepforward) {
bwalkUpdateSpeedForwards(1, 1);
g_Vars.currentplayer->speedmaxtime60 += g_Vars.lvupdate240_60;
} else if (data->digitalstepback) {
bwalkUpdateSpeedForwards(-1, 1);
} else if (data->canlookahead == false) {
bwalkUpdateSpeedForwards(0, 1);
}
if (data->canlookahead) {
bwalkUpdateSpeedForwards(data->analogwalk * 0.014285714365542f, 1);
if (data->analogwalk > 60) {
g_Vars.currentplayer->speedmaxtime60 += g_Vars.lvupdate240_60;
} else {
g_Vars.currentplayer->speedmaxtime60 = 0;
}
}
// Force speeds to range -1 to 1
if (g_Vars.currentplayer->speedforwards > 1) {
g_Vars.currentplayer->speedforwards = 1;
}
if (g_Vars.currentplayer->speedforwards < -1) {
g_Vars.currentplayer->speedforwards = -1;
}
if (g_Vars.currentplayer->speedsideways > 1) {
g_Vars.currentplayer->speedsideways = 1;
}
if (g_Vars.currentplayer->speedsideways < -1) {
g_Vars.currentplayer->speedsideways = -1;
}
g_Vars.currentplayer->speedforwards *= 1.08f;
g_Vars.currentplayer->speedforwards *= g_Vars.currentplayer->speedboost;
if ((data->canlookahead == false && data->digitalstepforward == false) ||
bmoveGetCrouchPos() != CROUCHPOS_STAND) {
g_Vars.currentplayer->speedmaxtime60 = 0;
}
if (data->rleanleft) {
bwalkSetSwayTarget(-1);
} else if (data->rleanright) {
bwalkSetSwayTarget(1);
} else {
bwalkSetSwayTarget(0);
}
while (data->crouchdown-- > 0) {
bwalkAdjustCrouchPos(-1);
}
while (data->crouchup-- > 0) {
bwalkAdjustCrouchPos(1);
}
g_Vars.currentplayer->eyesshut = data->eyesshut;
}
}
void bwalkUpdateSpeedTheta(void)
{
if (bmoveGetCrouchPos() == CROUCHPOS_SQUAT) {
g_Vars.currentplayer->speedtheta *= 0.5f;
} else if (bmoveGetCrouchPos() == CROUCHPOS_DUCK) {
g_Vars.currentplayer->speedtheta *= 0.75f;
}
}
void bwalk0f0c69b8(void)
{
s32 i;
f32 spe0;
f32 spdc;
f32 spd8;
struct coord spcc = {0, 0, 0};
f32 spc8;
f32 spc4;
f32 spc0;
f32 tmp1;
f32 tmp2;
f32 spb4;
f32 spb0;
f32 dist;
f32 spa8;
f32 mult;
f32 f0;
f32 lvupdate240f;
s32 lvupdate240;
s32 cdresult;
struct escalatorobj *esc;
f32 sp8c;
f32 sp88;
f32 speedforwards;
f32 speedsideways;
f32 speedtheta;
f32 maxspeed;
f32 sp74;
f32 radius;
f32 ymax;
f32 ymin;
f32 xdiff;
f32 zdiff;
f32 xdelta;
f32 zdelta;
f32 sp54;
f32 sp50;
f32 sp4c;
f32 sp48;
f32 sp44;
f32 sp40;
f32 sp3c;
f32 breathing;
spc0 = g_Vars.currentplayer->vv_eyeheight - 159;
if (invHasBriefcase() && ((g_MpSetup.scenario == MPSCENARIO_HOLDTHEBRIEFCASE || g_MpSetup.scenario == MPSCENARIO_CAPTURETHECASE))) {
spc0 = -63.600006f;
}
spc0 = spc0 / 353.33331298828f + 1.0f;
if (g_Vars.normmplayerisrunning && (g_MpSetup.options & MPOPTION_FASTMOVEMENT)) {
spc0 *= 1.25f;
}
#if VERSION >= VERSION_NTSC_1_0
if (cheatIsActive(CHEAT_SMALLJO)) {
spc0 *= 0.4f;
}
#endif
if (g_Vars.currentplayer->walkinitmove) {
g_Vars.currentplayer->walkinitt += g_Vars.lvupdate240freal * (1.0f / 60.0f);
if (g_Vars.currentplayer->walkinitt >= 1.0f) {
g_Vars.currentplayer->walkinitt = 1.0f;
g_Vars.currentplayer->walkinitmove = false;
}
g_Vars.currentplayer->walkinitt2 = 1.0f - (cosf(g_Vars.currentplayer->walkinitt * M_BADPI) + 1.0f) * 0.5f;
bmoveUpdateHead(0.0f, 0.0f, 0.0f, &g_Vars.currentplayer->walkinitmtx, 1.0f - g_Vars.currentplayer->walkinitt2);
g_Vars.currentplayer->gunspeed = 0.0f;
bmoveUpdateMoveInitSpeed(&spcc);
bwalkCalculateNewPositionWithPush(&spcc, 0.0f, true, 0.0f, CDTYPE_ALL);
} else {
bwalkApplyCrouchSpeed();
bwalkUpdateCrouchOffset();
bmove0f0cba88(&spc8, &spc4,
&g_Vars.currentplayer->bondshotspeed,
g_Vars.currentplayer->vv_sintheta, g_Vars.currentplayer->vv_costheta);
tmp1 = -g_Vars.currentplayer->swaytarget * g_Vars.currentplayer->bond2.unk00.f[2];
tmp2 = g_Vars.currentplayer->swaytarget * g_Vars.currentplayer->bond2.unk00.f[0];
tmp1 *= spc0;
tmp2 *= spc0;
spa8 = 0.0f;
if (g_Vars.currentplayer->crouchoffset < -45.0f) {
tmp1 *= 0.35f;
tmp2 *= 0.35f;
} else if (g_Vars.currentplayer->crouchoffset < 0.0f) {
tmp1 *= 0.5f;
tmp2 *= 0.5f;
}
spb4 = tmp1 - g_Vars.currentplayer->swayoffset0;
spb0 = tmp2 - g_Vars.currentplayer->swayoffset2;
dist = sqrtf(spb4 * spb4 + spb0 * spb0);
if (g_Vars.lvupdate240freal > PALUPF(4)) {
lvupdate240f = PALUPF(4);
lvupdate240 = 4;
} else {
lvupdate240f = g_Vars.lvupdate240freal;
lvupdate240 = g_Vars.lvupdate240_60;
}
for (i = 0; i < lvupdate240; i++) {
spa8 += (dist - spa8) * PALUPF(0.1f);
}
spa8 += 3.75f * lvupdate240f;
if (g_Vars.currentplayer->crouchoffset < -45.0f) {
spa8 *= 0.35f;
} else if (g_Vars.currentplayer->crouchoffset < 0.0f) {
spa8 *= 0.5f;
}
if (spa8 < dist) {
spa8 /= dist;
spb4 *= spa8;
spb0 *= spa8;
}
speedsideways = (g_Vars.currentplayer->speedsideways + spc4) * 0.8f;
speedforwards = g_Vars.currentplayer->speedforwards + spc8;
speedtheta = g_Vars.currentplayer->speedtheta * 0.8f;
if (speedsideways < 0.0f) {
speedsideways = -speedsideways;
}
if (speedforwards < 0.0f) {
speedforwards = -speedforwards;
}
if (speedtheta < 0.0f) {
speedtheta = -speedtheta;
}
maxspeed = speedforwards;
if (speedsideways > maxspeed) {
maxspeed = speedsideways;
}
if (speedtheta > maxspeed) {
maxspeed = speedtheta;
}
if (dist >= 0.1f && maxspeed < 0.8f) {
maxspeed = 0.8f;
}
if (maxspeed >= 0.75f) {
g_Vars.currentplayer->bondbreathing += (maxspeed - 0.75f) * g_Vars.lvupdate240freal / 900;
} else {
g_Vars.currentplayer->bondbreathing -= (0.75f - maxspeed) * g_Vars.lvupdate240freal / 2700;
}
if (g_Vars.currentplayer->bondbreathing < 0.0f) {
g_Vars.currentplayer->bondbreathing = 0.0f;
} else if (g_Vars.currentplayer->bondbreathing > 1.0f) {
g_Vars.currentplayer->bondbreathing = 1.0f;
}
mult = var80075c00[1].unk0c * 0.5f * g_Vars.lvupdate240freal;
spe0 = (g_Vars.currentplayer->speedsideways * spc0 + spc4) * mult;
#if VERSION >= VERSION_NTSC_1_0
if (cheatIsActive(CHEAT_SMALLJO)) {
spe0 /= 0.4f;
}
#endif
bmove0f0cc654(maxspeed, g_Vars.currentplayer->speedforwards * spc0 + spc8, spe0);
g_Vars.currentplayer->gunspeed = maxspeed;
spdc = g_Vars.currentplayer->headpos.x;
spd8 = g_Vars.currentplayer->headpos.z;
#if VERSION >= VERSION_NTSC_1_0
if (cheatIsActive(CHEAT_SMALLJO)) {
spdc *= 0.4f;
}
#endif
spcc.f[0] += (spd8 * g_Vars.currentplayer->bond2.unk00.f[0] - spdc * g_Vars.currentplayer->bond2.unk00.f[2]) * g_Vars.lvupdate240freal;
spcc.f[2] += (spd8 * g_Vars.currentplayer->bond2.unk00.f[2] + spdc * g_Vars.currentplayer->bond2.unk00.f[0]) * g_Vars.lvupdate240freal;
spcc.f[0] += spb4;
spcc.f[2] += spb0;
bmoveUpdateMoveInitSpeed(&spcc);
if (debugIsTurboModeEnabled()) {
spcc.f[0] += (g_Vars.currentplayer->bond2.unk00.f[0] * g_Vars.currentplayer->speedforwards - g_Vars.currentplayer->bond2.unk00.f[2] * g_Vars.currentplayer->speedsideways) * g_Vars.lvupdate240freal * 10.0f;
spcc.f[2] += (g_Vars.currentplayer->bond2.unk00.f[2] * g_Vars.currentplayer->speedforwards + g_Vars.currentplayer->bond2.unk00.f[0] * g_Vars.currentplayer->speedsideways) * g_Vars.lvupdate240freal * 10.0f;
}
if (g_Vars.currentplayer->bondforcespeed.f[0] != 0.0f || g_Vars.currentplayer->bondforcespeed.f[2] != 0.0f) {
spcc.f[0] += g_Vars.currentplayer->bondforcespeed.f[0] * g_Vars.lvupdate240freal;
spcc.f[2] += g_Vars.currentplayer->bondforcespeed.f[2] * g_Vars.lvupdate240freal;
}
if (g_Vars.currentplayer->onladder) {
guNormalize(&g_Vars.currentplayer->laddernormal.x, &g_Vars.currentplayer->laddernormal.y, &g_Vars.currentplayer->laddernormal.z);
sp74 = -(spcc.f[0] * g_Vars.currentplayer->laddernormal.f[0] + spcc.f[2] * g_Vars.currentplayer->laddernormal.f[2]);
if (-4.0f * g_Vars.lvupdate240freal < sp74) {
if (sp74 < 0.0f) {
spcc.f[0] += sp74 * g_Vars.currentplayer->laddernormal.f[0];
spcc.f[2] += sp74 * g_Vars.currentplayer->laddernormal.f[2];
g_Vars.currentplayer->ladderupdown = sp74 * 0.3f;
} else {
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
cdresult = cd0002a13c(&g_Vars.currentplayer->prop->pos,
radius * 1.1f, ymax - g_Vars.currentplayer->prop->pos.y,
(g_Vars.currentplayer->vv_manground - g_Vars.currentplayer->prop->pos.y) + 1.0f,
g_Vars.currentplayer->prop->rooms, 0x8040);
if (cdresult == CDRESULT_COLLISION) {
g_Vars.currentplayer->ladderupdown = 0.0f;
} else {
spcc.f[0] += sp74 * g_Vars.currentplayer->laddernormal.f[0];
spcc.f[2] += sp74 * g_Vars.currentplayer->laddernormal.f[2];
g_Vars.currentplayer->ladderupdown = sp74 * 0.3f;
}
}
spcc.x *= 0.3f;
spcc.z *= 0.3f;
} else {
g_Vars.currentplayer->ladderupdown = 0.0f;
}
}
if (g_Vars.currentplayer->lift) {
esc = (struct escalatorobj *) g_Vars.currentplayer->lift->obj;
if (esc->base.type == OBJTYPE_ESCASTEP) {
spcc.x += esc->base.prop->pos.x - esc->prevpos.x;
spcc.z += esc->base.prop->pos.z - esc->prevpos.z;
}
}
sp8c = g_Vars.currentplayer->prop->pos.x;
sp88 = g_Vars.currentplayer->prop->pos.z;
bwalk0f0c63bc(&spcc, g_Vars.currentplayer->swaytarget == 0.0f, CDTYPE_ALL);
xdelta = g_Vars.currentplayer->prop->pos.x - g_Vars.currentplayer->bondprevpos.x;
zdelta = g_Vars.currentplayer->prop->pos.z - g_Vars.currentplayer->bondprevpos.z;
sp54 = -xdelta * g_Vars.currentplayer->bond2.unk00.f[2] + zdelta * g_Vars.currentplayer->bond2.unk00.f[0];
sp50 = xdelta * g_Vars.currentplayer->bond2.unk00.f[0] + zdelta * g_Vars.currentplayer->bond2.unk00.f[2];
sp4c = -spcc.f[0] * g_Vars.currentplayer->bond2.unk00.f[2] + spcc.f[2] * g_Vars.currentplayer->bond2.unk00.f[0];
sp48 = spcc.f[0] * g_Vars.currentplayer->bond2.unk00.f[0] + spcc.f[2] * g_Vars.currentplayer->bond2.unk00.f[2];
if (xdelta >= 0.0f) {
if (g_Vars.currentplayer->bondshotspeed.f[0] > 0.0f) {
if (spcc.f[0] >= 0.0f && xdelta < spcc.f[0]) {
g_Vars.currentplayer->bondshotspeed.f[0] *= xdelta / spcc.f[0];
}
} else {
if (spcc.f[0] < 0.0f) {
g_Vars.currentplayer->bondshotspeed.f[0] = 0.0f;
}
}
} else {
if (g_Vars.currentplayer->bondshotspeed.f[0] < 0.0f) {
if (spcc.f[0] <= 0.0f && spcc.f[0] < xdelta) {
g_Vars.currentplayer->bondshotspeed.f[0] *= xdelta / spcc.f[0];
}
} else {
if (spcc.f[0] > 0.0f) {
g_Vars.currentplayer->bondshotspeed.f[0] = 0.0f;
}
}
}
if (zdelta >= 0.0f) {
if (g_Vars.currentplayer->bondshotspeed.f[2] > 0.0f) {
if (spcc.f[2] >= 0.0f && zdelta < spcc.f[2]) {
g_Vars.currentplayer->bondshotspeed.f[2] *= zdelta / spcc.f[2];
}
} else {
if (spcc.f[2] < 0.0f) {
g_Vars.currentplayer->bondshotspeed.f[2] = 0.0f;
}
}
} else {
if (g_Vars.currentplayer->bondshotspeed.f[2] < 0.0f) {
if (spcc.f[2] <= 0.0f && spcc.f[2] < zdelta) {
g_Vars.currentplayer->bondshotspeed.f[2] *= zdelta / spcc.f[2];
}
} else {
if (spcc.f[2] > 0.0f) {
g_Vars.currentplayer->bondshotspeed.f[2] = 0.0f;
}
}
}
if (sp4c != 0.0f && g_Vars.currentplayer->speedstrafe * sp4c > 0.0f) {
sp54 /= sp4c;
if (sp54 <= 0.0f) {
g_Vars.currentplayer->speedstrafe = 0.0f;
} else if (sp54 < 1.0f) {
g_Vars.currentplayer->speedstrafe *= sp54;
}
}
if (sp48 != 0.0f) {
if (g_Vars.currentplayer->speedgo * sp48 > 0.0f) {
sp50 /= sp48;
if (sp50 <= 0.0f) {
g_Vars.currentplayer->speedgo = 0.0f;
} else if (sp50 < 1.0f) {
g_Vars.currentplayer->speedgo *= sp50;
}
}
}
xdiff = g_Vars.currentplayer->prop->pos.x - sp8c;
zdiff = g_Vars.currentplayer->prop->pos.z - sp88;
f0 = spcc.f[0] * spcc.f[0] + spcc.f[2] * spcc.f[2];
if (f0 != 0.0f) {
f0 = (xdiff * xdiff + zdiff * zdiff) / f0;
}
f0 = sqrtf(f0);
g_Vars.currentplayer->swayoffset0 += f0 * spb4;
g_Vars.currentplayer->swayoffset2 += f0 * spb0;
}
sp44 = g_Vars.currentplayer->speedtheta;
sp40 = g_Vars.currentplayer->speedverta / 0.7f + g_Vars.currentplayer->crouchspeed / PALUPF(5.0f);
sp3c = g_Vars.currentplayer->gunspeed;
breathing = bheadGetBreathingValue();
if (sp40 > 1.0f) {
sp40 = 1.0f;
} else if (sp40 < -1.0f) {
sp40 = -1.0f;
}
if (g_Vars.currentplayer->headanim == 1) {
breathing *= 1.2f;
}
bgun0f09d8dc(breathing, sp3c, sp40, sp44, 0.0f);
bgunSetAdjustPos(g_Vars.currentplayer->vv_verta360 * 0.017450513318181f);
}
void bwalkTick(void)
{
bwalkUpdatePrevPos();
bwalkUpdateTheta();
bmoveUpdateVerta();
bwalk0f0c69b8();
bwalkUpdateVertical();
#if VERSION >= VERSION_NTSC_1_0
{
s32 i;
for (i = 0; g_Vars.currentplayer->prop->rooms[i] != -1; i++) {
if (g_Vars.currentplayer->floorroom == g_Vars.currentplayer->prop->rooms[i]) {
propDeregisterRooms(g_Vars.currentplayer->prop);
g_Vars.currentplayer->prop->rooms[0] = g_Vars.currentplayer->floorroom;
g_Vars.currentplayer->prop->rooms[1] = -1;
break;
}
}
}
#endif
bmoveUpdateRooms(g_Vars.currentplayer);
objectiveCheckRoomEntered(g_Vars.currentplayer->prop->rooms[0]);
if (g_Vars.currentplayer->walkinitmove) {
struct coord coord;
coord.x = (g_Vars.currentplayer->walkinitstart.x - g_Vars.currentplayer->walkinitpos.x)
* (1.0f - g_Vars.currentplayer->walkinitt2) + g_Vars.currentplayer->prop->pos.x;
coord.y = (g_Vars.currentplayer->walkinitstart.y - g_Vars.currentplayer->prop->pos.y)
* (1.0f - g_Vars.currentplayer->walkinitt2) + g_Vars.currentplayer->prop->pos.y;
coord.z = (g_Vars.currentplayer->walkinitstart.z - g_Vars.currentplayer->walkinitpos.z)
* (1.0f - g_Vars.currentplayer->walkinitt2) + g_Vars.currentplayer->prop->pos.z;
bmove0f0cc19c(&coord);
} else {
bmove0f0cc19c(&g_Vars.currentplayer->prop->pos);
}
playerUpdatePerimInfo();
doorsCheckAutomatic();
}