perfect_dark/src/game/core.c

2368 lines
59 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/activemenu/activemenu.h"
#include "game/activemenu/tick.h"
#include "game/bondmove.h"
#include "game/camdraw.h"
#include "game/cheats.h"
#include "game/chr/chraction.h"
#include "game/data/data_000000.h"
#include "game/data/data_0083d0.h"
#include "game/data/data_00e460.h"
#include "game/data/data_0160b0.h"
#include "game/data/data_01a3a0.h"
#include "game/data/data_020df0.h"
#include "game/data/data_02a0e0.h"
#include "game/data/data_02da90.h"
#include "game/debug.h"
#include "game/dlights.h"
#include "game/game_005fd0.h"
#include "game/game_006bd0.h"
#include "game/game_00b480.h"
#include "game/game_00b820.h"
#include "game/game_00c240.h"
#include "game/game_00c490.h"
#include "game/game_0108d0.h"
#include "game/game_0109d0.h"
#include "game/game_010b20.h"
#include "game/game_011110.h"
#include "game/inventory/init.h"
#include "game/game_0125a0.h"
#include "game/explosions/init.h"
#include "game/smoke/init.h"
#include "game/sparks/init.h"
#include "game/weather/init.h"
#include "game/game_013540.h"
#include "game/game_013550.h"
#include "game/game_013cf0.h"
#include "game/game_0147a0.h"
#include "game/game_0147d0.h"
#include "game/game_014f10.h"
#include "game/game_015010.h"
#include "game/game_0150a0.h"
#include "game/game_0151f0.h"
#include "game/game_015260.h"
#include "game/game_015270.h"
#include "game/explosions/free.h"
#include "game/smoke/free.h"
#include "game/game_0153f0.h"
#include "game/game_015400.h"
#include "game/game_015410.h"
#include "game/game_015420.h"
#include "game/game_015470.h"
#include "game/title.h"
#include "game/game_01b0a0.h"
#include "game/game_01bea0.h"
#include "game/weather/tick.h"
#include "game/game_01d860.h"
#include "game/game_01d990.h"
#include "game/game_01d9f0.h"
#include "game/game_01de30.h"
#include "game/chr/chr.h"
#include "game/game_0601b0.h"
#include "game/game_095320.h"
#include "game/game_097ba0.h"
#include "game/game_0abe70.h"
#include "game/game_0b0fd0.h"
#include "game/game_0b28d0.h"
#include "game/game_0b63b0.h"
#include "game/game_0b69d0.h"
#include "game/game_0d4690.h"
#include "game/game_0dcdb0.h"
#include "game/game_0f09f0.h"
#include "game/game_107fb0.h"
#include "game/game_10c9c0.h"
#include "game/game_11f000.h"
#include "game/game_127910.h"
#include "game/game_129210.h"
#include "game/explosions/explosions.h"
#include "game/sparks/sparks.h"
#include "game/weather/weather.h"
#include "game/sky.h"
#include "game/credits.h"
#include "game/game_13c510.h"
#include "game/bondview.h"
#include "game/game_150820.h"
#include "game/game_1531a0.h"
#include "game/game_157db0.h"
#include "game/game_165670.h"
#include "game/core.h"
#include "game/music.h"
#include "game/game_16e810.h"
#include "game/game_176080.h"
#include "game/mplayer/setup.h"
#include "game/mplayer/scenarios.h"
#include "game/game_19aa80.h"
#include "game/training/training.h"
#include "game/lang.h"
#include "game/mplayer/mplayer.h"
#include "game/pak/pak.h"
#include "game/propobj.h"
#include "game/sparks/tick.h"
#include "game/splat.h"
#include "game/utils.h"
#include "game/wallhit.h"
#include "gvars/gvars.h"
#include "lib/args.h"
#include "lib/controller.h"
#include "lib/lib_06440.h"
#include "lib/lib_09660.h"
#include "lib/main.h"
#include "lib/lib_0e9d0.h"
#include "lib/lib_11420.h"
#include "lib/rng.h"
#include "lib/lib_16110.h"
#include "lib/lib_233c0.h"
#include "lib/lib_317f0.h"
#include "types.h"
const char var7f1b7730[] = "fr: %d\n";
const char var7f1b7738[] = "cutsceneframe: %d\n";
const char var7f1b774c[] = "pos:%s%s %.2f %.2f %.2f\n";
const char var7f1b7768[] = "";
const char var7f1b776c[] = "";
u32 var80084010 = 0;
bool var80084014 = false;
f32 var80084018 = 1;
u32 var8008401c = 0x00000001;
s32 g_Difficulty = DIFF_A;
s32 g_StageTimeElapsed60 = 0;
s32 g_MpTimeLimit60 = SECSTOTIME60(60 * 10); // 10 minutes
s32 g_MpScoreLimit = 10;
s32 g_MpTeamScoreLimit = 20;
struct audiohandle *g_MiscAudioHandle = NULL;
s32 g_NumReasonsToEndMpMatch = 0;
f32 g_StageTimeElapsed1f = 0;
bool var80084040 = true;
u32 g_MiscSfxSounds[] = {0x05c8, 0x8068, 0x01c8};
s32 var80084050 = 0;
s16 g_FadeNumFrames = 0;
f32 g_FadeFrac = -1;
u32 g_FadePrevColour = 0;
u32 g_FadeColour = 0;
s16 g_FadeDelay = 0;
u32 getVar80084040(void)
{
return var80084040;
}
void setVar80084040(u32 value)
{
var80084040 = value;
}
void func0f167af8(void)
{
g_Vars.unk000320 = 0;
g_Vars.unk0004d8 = -1;
}
void coreStopAllMiscSfx(void)
{
s32 i;
for (i = 0; i != ARRAYCOUNT(g_MiscSfxAudioHandles); i++) {
g_MiscSfxAudioHandles[i] = NULL;
g_MiscSfxActiveTypes[i] = -1;
}
}
s32 coreGetMiscSfxIndex(u32 type)
{
s32 i;
for (i = 0; i != ARRAYCOUNT(g_MiscSfxActiveTypes); i++) {
if (g_MiscSfxActiveTypes[i] == type) {
return i;
}
}
return -1;
}
void coreSetMiscSfxState(u32 type, bool play)
{
if (play) {
if (coreGetMiscSfxIndex(type) == -1) {
s32 index = coreGetMiscSfxIndex(-1);
if (index != -1 && g_MiscSfxAudioHandles[index] == NULL) {
audioStart(var80095200, g_MiscSfxSounds[type], &g_MiscSfxAudioHandles[index], -1, -1, -1, -1, -1);
g_MiscSfxActiveTypes[index] = type;
}
}
} else {
u32 stack;
s32 index = coreGetMiscSfxIndex(type);
if (index != -1) {
audioStop(g_MiscSfxAudioHandles[index]);
g_MiscSfxActiveTypes[index] = -1;
}
}
}
void coreUpdateMiscSfx(void)
{
s32 i;
if (g_Vars.lvupdate240 == 0) {
for (i = 0; i != ARRAYCOUNT(g_MiscSfxActiveTypes); i++) {
coreSetMiscSfxState(i, false);
}
} else {
bool usingboost = g_Vars.speedpillon
&& coreGetSlowMotionType() == SLOWMOTION_OFF
&& g_Vars.in_cutscene == false;
bool usingrocket;
coreSetMiscSfxState(MISCSFX_BOOSTHEARTBEAT, usingboost);
usingrocket = false;
for (i = 0; i < PLAYERCOUNT(); i++) {
if (g_Vars.players[i]->visionmode == VISIONMODE_SLAYERROCKET) {
usingrocket = true;
}
}
coreSetMiscSfxState(MISCSFX_SLAYERROCKETHUM, usingrocket);
coreSetMiscSfxState(MISCSFX_SLAYERROCKETBEEP, usingrocket);
}
if (g_Vars.lvupdate240 == 0 && g_MiscAudioHandle && audioIsPlaying(g_MiscAudioHandle)) {
audioStop(g_MiscAudioHandle);
}
}
void coreLoadStage(s32 stagenum)
{
coreCancelFade();
var80084014 = false;
var80084010 = 0;
func00013900();
g_Vars.unk0004d8 = 10;
g_Vars.unk0004d1 = 0;
g_Vars.paksconnected = 0;
g_Vars.stagenum = stagenum;
cheatsActivate();
var80084040 = true;
g_Vars.lvframenum = 0;
var80084050 = 0;
g_Vars.lvframe60 = 0;
g_Vars.lvupdate240 = 4;
g_Vars.lvupdate240f = 1;
g_Vars.lvupdate240frealprev = 1.0f;
g_Vars.lvupdate240freal = g_Vars.lvupdate240frealprev;
g_StageTimeElapsed60 = 0;
g_StageTimeElapsed1f = 0;
g_Vars.speedpilltime = 0;
g_Vars.speedpillchange = 0;
g_Vars.speedpillwant = 0;
g_Vars.speedpillon = false;
g_Vars.restartlevel = false;
g_Vars.unk000478 = 0;
g_Vars.unk000488 = 0;
g_Vars.antiheadnum = -1;
g_Vars.antibodynum = -1;
g_Vars.dontplaynrg = false;
g_Vars.in_cutscene = 0;
g_Vars.unk0004d3 = 0;
g_Vars.unk0004d6 = 0;
g_Vars.unk0004d7 = 0;
g_MiscAudioHandle = NULL;
func0f16d324();
func0f011124(true);
func0f013b80();
texturesLoadConfigs();
fontsLoadForCurrentStage();
hudmsgSystemInit();
if (stagenum == STAGE_TEST_OLD) {
func0f00b480();
}
if (stagenum == STAGE_TITLE) {
func0f00b480();
} else if (stagenum == STAGE_BOOTPAKMENU) {
// empty
} else if (stagenum == STAGE_CREDITS) {
// empty
} else if (stagenum == STAGE_4MBMENU) {
// empty
} else {
s32 i;
s32 j;
stageLoadTiles();
func0f15b534(g_Vars.stagenum);
func0f15b908(g_Vars.stagenum);
func0f0147a0(g_Vars.stagenum);
if (g_Vars.normmplayerisrunning) {
musicSetStageAndStartMusic(stagenum);
} else {
musicSetStage(stagenum);
}
if (g_Vars.normmplayerisrunning) {
mpApplyLimits();
}
if (g_Vars.mplayerisrunning == false) {
g_Vars.playerstats[0].mpindex = 4;
g_MpPlayers[4].base.unk45 = 0;
g_MpPlayers[4].base.unk46 = 1;
}
for (i = 0; i != ARRAYCOUNT(g_Vars.playerstats); i++) {
g_Vars.playerstats[i].damagescale = 1;
g_Vars.playerstats[i].drawplayercount = 0;
g_Vars.playerstats[i].distance = 0;
g_Vars.playerstats[i].backshotcount = 0;
g_Vars.playerstats[i].armourcount = 0;
g_Vars.playerstats[i].fastest2kills = S32_MAX;
g_Vars.playerstats[i].slowest2kills = 0;
g_Vars.playerstats[i].maxkills = 0;
g_Vars.playerstats[i].maxsimulkills = 0;
g_Vars.playerstats[i].longestlife = 0;
g_Vars.playerstats[i].shortestlife = S32_MAX;
g_Vars.playerstats[i].tokenheldtime = 0;
g_Vars.playerstats[i].damreceived = 0;
g_Vars.playerstats[i].damtransmitted = 0;
for (j = 0; j != ARRAYCOUNT(g_Vars.playerstats[i].kills); j++) {
g_Vars.playerstats[i].kills[j] = 0;
}
}
}
mpSetDefaultNamesIfEmpty();
func0002373c();
setupResetObjectives();
func0f013ba0();
func0f011110();
func0f0108d0();
func0f00eb64(stagenum);
mpPrepareScenario();
gvarsInitProps();
setupInit();
func0f00b510();
stageChooseActiveHeads(stagenum);
setupParseObjects(stagenum);
tagsAllocatePtrs();
explosionsInit();
smokeInit();
sparksInit();
weatherInit();
coreStopAllMiscSfx();
switch (g_Vars.stagenum) {
case STAGE_ESCAPE:
case STAGE_EXTRACTION:
case STAGE_INFILTRATION:
case STAGE_DEFECTION:
case STAGE_ATTACKSHIP:
case STAGE_TEST_OLD:
skyInit();
break;
}
func0f0099a4();
func0f0147d0();
func0f0147f8();
func0f013540();
func0f0139f0();
frUnloadData();
if (g_Vars.stagenum == STAGE_TITLE) {
// empty
} else if (stagenum == STAGE_BOOTPAKMENU) {
setCurrentPlayerNum(0);
menuInit();
} else if (stagenum == STAGE_4MBMENU) {
setCurrentPlayerNum(0);
menuInit();
} else if (stagenum == STAGE_CREDITS) {
creditsInit();
} else {
s32 i;
func0f1777f8();
func0f010b20();
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
g_Vars.currentplayer->usedowntime = 0;
g_Vars.currentplayer->invdowntime = g_Vars.currentplayer->usedowntime;
menuInit();
amInit();
invInitGunsHeld();
func0f010bb0();
currentPlayerResetToDefault();
currentPlayerInit();
currentPlayerSpawn();
currentPlayerInitAnimation();
if (g_Vars.normmplayerisrunning && (g_MpSetup.options & MPOPTION_TEAMSENABLED)) {
currentPlayerCalculateAiBuddyNums();
}
}
acousticReset();
func0f0b65f8();
func0f001bdc();
setCurrentPlayerNum(0);
}
if (g_Vars.lvmpbotlevel) {
mpCalculateTeamIsOnlyAi();
}
func0f11a2e4();
func0000eadc();
if (stagenum == STAGE_BOOTPAKMENU) {
pakPushPakMenuDialog();
}
if (stagenum == STAGE_4MBMENU) {
func0f10cb2c();
}
if (IS8MB()) {
func0f14a3c4();
}
func0f011124(false);
var80084018 = 1;
bbufResetIndexes();
coreSetPaused(0);
#if PIRACYCHECKS
{
u32 checksum = 0;
s32 *i = (s32 *)&coreGetSlowMotionType;
s32 *end = (s32 *)&coreTick;
while (i < end) {
checksum += *i;
i++;
}
if (checksum != CHECKSUM_PLACEHOLDER) {
u32 address = 0;
u32 buffer[4];
buffer[0] = 0xbb8b80bd;
buffer[1] = 0xffffffff;
buffer[2] = 0x020f0100;
buffer[3] = 0xcd31100b;
osEepromLongWrite(&var80099e78, address, (u8 *)&buffer, 0x10);
var800a2380[4].unk2be = 0;
}
}
#endif
}
void coreConfigureFade(u32 color, s16 num_frames)
{
g_FadeNumFrames = num_frames;
g_FadePrevColour = g_FadeColour;
if (g_FadeNumFrames == 0) {
g_FadeColour = color;
g_FadeFrac = -1;
return;
}
g_FadeFrac = 0;
g_FadeColour = color;
g_FadeDelay = 2;
}
Gfx *coreRenderFade(Gfx *gdl)
{
u32 colour = g_FadeColour;
u32 inset = 0;
if (g_Vars.stagenum == STAGE_TEST_OLD) {
inset = 61;
}
if (g_FadeFrac >= 0) {
if (g_FadeDelay > 0) {
g_FadeDelay--;
} else {
g_FadeFrac += g_Vars.diffframe60f / g_FadeNumFrames;
if (g_FadeFrac >= 1) {
g_FadeFrac = -1;
}
}
}
if (g_FadeFrac < 0) {
if ((g_FadeColour & 0xff) == 0) {
return gdl;
}
} else {
colour = colourBlend(g_FadeColour, g_FadePrevColour, g_FadeFrac * 255);
}
if ((colour & 0xff) == 0) {
return gdl;
}
gDPPipeSync(gdl++);
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gDPSetPrimColorViaWord(gdl++, 0, 0, colour);
gDPFillRectangle(gdl++,
viGetViewLeft(),
viGetViewTop() + inset,
viGetViewLeft() + viGetViewWidth() + 1,
viGetViewTop() + viGetViewHeight() - inset + 2);
return func0f153838(gdl);
}
bool coreIsFadeActive(void)
{
return g_FadeFrac >= 0;
}
void coreCancelFade(void)
{
g_FadeNumFrames = 0;
g_FadeFrac = -1;
g_FadePrevColour = 0;
g_FadeColour = 0;
g_FadeDelay = 0;
}
bool coreCheckCmpFollowThreat(struct threat *threat, s32 index)
{
f32 sp76;
f32 sp72;
f32 sp68;
f32 sp64;
struct prop *prop = threat->prop;
struct chrdata *chr;
if (threat->prop && prop->chr) {
switch (threat->prop->type) {
case PROPTYPE_PLAYER:
if (propGetPlayerNum(prop) == g_Vars.currentplayernum) {
return false;
}
// fall through
case PROPTYPE_CHR:
chr = threat->prop->chr;
if (chrIsDead(threat->prop->chr)) {
if (index >= 0) {
// Existing threat
if (g_Vars.currentplayer->targetset[index] < 129) {
g_Vars.currentplayer->targetset[index] = 129;
}
if (g_Vars.currentplayer->targetset[index] >= 175) {
threat->prop = NULL;
return false;
}
} else {
// Attempting to add a new threat, but chr is dead
threat->prop = NULL;
return false;
}
}
if ((threat->prop->flags & PROPFLAG_02)
&& (chr->chrflags & CHRCFLAG_NOAUTOAIM) == 0) {
struct model *model = chr->model;
sp72 = -1;
sp76 = -1;
sp64 = -2;
sp68 = -2;
if (modelSetRedBox(model, &sp64, &sp72, &sp68, &sp76)) {
break;
}
return false;
}
return false;
case PROPTYPE_OBJ:
case PROPTYPE_WEAPON:
if (threat->prop->flags & PROPFLAG_02) {
struct defaultobj *obj = threat->prop->obj;
struct model *model = obj->model;
sp72 = -1;
sp76 = -1;
sp64 = -2;
sp68 = -2;
if (modelSetRedBox(model, &sp64, &sp72, &sp68, &sp76)) {
break;
}
return false;
}
return false;
case PROPTYPE_DOOR:
case PROPTYPE_EYESPY:
case PROPTYPE_EXPLOSION:
case PROPTYPE_SMOKE:
default:
return false;
}
threat->unk04 = sp72 - 2;
threat->unk08 = sp64 + 2;
threat->unk06 = sp76 - 2;
threat->unk0a = sp68 + 2;
}
return true;
}
void coreFindThreatsForProp(struct prop *prop, bool inchild, struct coord *playerpos, bool *activeslots, f32 *distances)
{
bool condition = true;
struct defaultobj *obj;
bool pass;
f32 sp88;
f32 sp84;
f32 sp80;
f32 sp76;
s32 i;
struct model *model;
struct weaponobj *weapon;
if (!inchild && prop->z < 0) {
condition = false;
}
if (prop->obj
&& (prop->flags & PROPFLAG_02)
&& (prop->type == PROPTYPE_OBJ || prop->type == PROPTYPE_WEAPON)
&& condition) {
pass = false;
obj = prop->obj;
model = prop->obj->model;
if (obj
&& obj->type == OBJTYPE_AUTOGUN
&& (obj->flags2 & (OBJFLAG2_80000000 | OBJFLAG2_AICANNOTUSE)) == 0) {
pass = true;
}
if (obj && obj->modelnum == MODEL_SK_SHUTTLE) {
pass = true;
}
weapon = (struct weaponobj *)prop->obj;
if (weapon && prop->obj->type == OBJTYPE_WEAPON) {
switch (weapon->weaponnum) {
case WEAPON_GRENADE:
case WEAPON_NBOMB:
case WEAPON_TIMEDMINE:
case WEAPON_PROXIMITYMINE:
case WEAPON_REMOTEMINE:
pass = true;
break;
case WEAPON_DRAGON:
if (weapon->thrown == 1U) {
pass = true;
}
break;
}
}
if (obj->modelnum == MODEL_TARGET && frIsTargetOneHitExplodable(prop)) {
pass = true;
}
if (pass) {
for (i = 0; i != 4; i++) {
if (g_Vars.currentplayer->cmpfollowprops[i].prop == prop) {
pass = false;
}
}
}
if (pass) {
sp84 = -1;
sp88 = -1;
sp76 = -2;
sp80 = -2;
if (!modelSetRedBox(model, &sp76, &sp84, &sp80, &sp88)) {
pass = false;
}
}
if (pass) {
f32 furtherestdist = 0;
s32 index = -1;
f32 sqdist =
(prop->pos.f[0] - playerpos->f[0]) * (prop->pos.f[0] - playerpos->f[0]) +
(prop->pos.f[1] - playerpos->f[1]) * (prop->pos.f[1] - playerpos->f[1]) +
(prop->pos.f[2] - playerpos->f[2]) * (prop->pos.f[2] - playerpos->f[2]);
for (i = 0; i < 4; i++) {
if (!activeslots[i]) {
index = i;
}
}
if (index == -1) {
// No slots available - consider replacing the furtherest
for (i = 0; i != 4; i++) {
if (distances[i] > furtherestdist) {
furtherestdist = distances[i];
index = i;
}
}
if (sqdist >= furtherestdist) {
index = -1;
}
}
if (index >= 0) {
g_Vars.currentplayer->cmpfollowprops[index].prop = prop;
g_Vars.currentplayer->cmpfollowprops[index].unk04 = sp84 - 2;
g_Vars.currentplayer->cmpfollowprops[index].unk08 = sp76 + 2;
g_Vars.currentplayer->cmpfollowprops[index].unk06 = sp88 - 2;
g_Vars.currentplayer->cmpfollowprops[index].unk0a = sp80 + 2;
g_Vars.currentplayer->targetset[index] = 0;
activeslots[index] = true;
distances[index] = sqdist;
}
}
}
if (prop->child) {
coreFindThreatsForProp(prop->child, true, playerpos, activeslots, distances);
}
if (inchild && prop->next) {
coreFindThreatsForProp(prop->next, inchild, playerpos, activeslots, distances);
}
}
void func0f168f24(struct prop *prop, bool inchild, struct coord *playerpos, s32 *activeslots, f32 *distances)
{
s32 i;
f32 sp128;
f32 sp124;
f32 sp120;
f32 sp116;
struct model *model;
for (i = 0; i != 4; i++) {
if (g_Vars.currentplayer->cmpfollowprops[i].prop == prop
&& (prop->flags & PROPFLAG_02)) {
model = NULL;
if (prop->type == PROPTYPE_OBJ
|| prop->type == PROPTYPE_WEAPON
|| prop->type == PROPTYPE_DOOR) {
model = g_Vars.currentplayer->cmpfollowprops[i].prop->obj->model;
} else {
if (prop->type == PROPTYPE_CHR
|| (prop->type == PROPTYPE_PLAYER
&& propGetPlayerNum(prop) != g_Vars.currentplayernum)) {
model = g_Vars.currentplayer->cmpfollowprops[i].prop->chr->model;
}
}
if (model) {
sp124 = -1;
sp128 = -1;
sp116 = -2;
sp120 = -2;
if (modelSetRedBox(model, &sp116, &sp124, &sp120, &sp128)) {
activeslots[i] = true;
g_Vars.currentplayer->cmpfollowprops[i].unk04 = sp124 - 2;
g_Vars.currentplayer->cmpfollowprops[i].unk08 = sp116 + 2;
g_Vars.currentplayer->cmpfollowprops[i].unk06 = sp128 - 2;
g_Vars.currentplayer->cmpfollowprops[i].unk0a = sp120 + 2;
distances[i] =
(prop->pos.f[0] - playerpos->f[0]) * (prop->pos.f[0] - playerpos->f[0]) +
(prop->pos.f[1] - playerpos->f[1]) * (prop->pos.f[1] - playerpos->f[1]) +
(prop->pos.f[2] - playerpos->f[2]) * (prop->pos.f[2] - playerpos->f[2]);
}
}
}
}
if (prop->child) {
func0f168f24(prop->child, true, playerpos, activeslots, distances);
}
if (inchild && prop->next) {
func0f168f24(prop->next, inchild, playerpos, activeslots, distances);
}
}
void coreFindThreats(void)
{
s32 i;
struct prop *prop;
f32 distances[] = {0, 0, 0, 0};
s32 activeslots[] = {false, false, false, false};
struct prop **propptr = g_Vars.unk00034c - 1;
struct coord campos;
campos.x = g_Vars.currentplayer->cam_pos.x;
campos.y = g_Vars.currentplayer->cam_pos.y;
campos.z = g_Vars.currentplayer->cam_pos.z;
while (propptr >= g_Vars.tangibleprops) {
prop = *propptr;
if (prop) {
func0f168f24(prop, false, &campos, activeslots, distances);
}
propptr--;
}
for (i = 0; i != ARRAYCOUNT(activeslots); i++) {
if (!activeslots[i]) {
g_Vars.currentplayer->cmpfollowprops[i].prop = NULL;
g_Vars.currentplayer->cmpfollowprops[i].unk04 = -1;
g_Vars.currentplayer->cmpfollowprops[i].unk08 = -2;
}
}
propptr = g_Vars.unk00034c - 1;
while (propptr >= g_Vars.tangibleprops) {
prop = *propptr;
if (prop) {
coreFindThreatsForProp(prop, false, &campos, activeslots, distances);
}
propptr--;
}
}
/**
* Renders a complete frame for all players, and also does some other game logic
* that really doesn't belong here.
*
* This function is pretty big, so here's an overview of its structure:
*
* if (stage == STAGE_TITLE) {
* // title screen rendering
* } else if (stage == STAGE_BOOTPAKMENU) {
* // boot pak menu rendering
* } else if (stage == STAGE_4MBMENU) {
* // 4MB menu rendering
* } else if (stage == STAGE_CREDITS) {
* // credits rendering
* } else {
* for (i = 0; i < numplayers; i++) {
* // rendering and logic per player
* }
* }
* // logic for auto-playing cutscene advancement
*
* The player loop takes up the majority of the function. In addition to
* rendering the scene and HUD, it also handles the following logic:
* - decreasing dizziness
* - detecting if the prop being looked at is still valid
* - pressing Z when using eyespy
* - opening doors and reloading
* - random static in the Infiltration intro cutscene
* - combat boost activation and reverting
*/
Gfx *coreRender(Gfx *gdl)
{
gSPSegment(gdl++, 0x00, 0x00000000);
func0f0d5a7c();
if (g_Vars.stagenum == STAGE_TITLE
|| (g_Vars.stagenum == STAGE_TEST_OLD && titleIsKeepingMode())) {
gSPDisplayList(gdl++, &var800613a0);
if (debug0f11ee28()) {
gSPDisplayList(gdl++, &var80061360);
} else {
gSPDisplayList(gdl++, &var80061380);
}
gdl = func0000b280(gdl);
gdl = func0000b1d0(gdl);
gDPSetScissorFrac(gdl++, 0,
viGetViewLeft() * 4.0f, viGetViewTop() * 4.0f,
(viGetViewLeft() + viGetViewWidth()) * 4.0f,
(viGetViewTop() + viGetViewHeight()) * 4.0f);
gdl = titleRender(gdl);
gdl = coreRenderFade(gdl);
} else if (g_Vars.stagenum == STAGE_BOOTPAKMENU) {
gSPClipRatio(gdl++, FRUSTRATIO_2);
gSPDisplayList(gdl++, &var800613a0);
gSPDisplayList(gdl++, &var80061380);
setCurrentPlayerNum(0);
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewx, g_Vars.currentplayer->viewy);
func00016748(1);
gdl = func0000b1d0(gdl);
gdl = func0000b330(gdl);
gdl = func0f15cb74(gdl);
gdl = func0f0fbc30(gdl);
} else if (g_Vars.stagenum == STAGE_4MBMENU) {
gSPClipRatio(gdl++, FRUSTRATIO_2);
gSPDisplayList(gdl++, &var800613a0);
gSPDisplayList(gdl++, &var80061380);
setCurrentPlayerNum(0);
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewx, g_Vars.currentplayer->viewy);
func00016748(1);
gdl = func0000b1d0(gdl);
gdl = func0f15cb74(gdl);
gdl = func0f0fbc30(gdl);
if (g_Vars.currentplayer->pausemode != PAUSEMODE_UNPAUSED) {
currentPlayerTickPauseMenu();
}
} else if (g_Vars.stagenum == STAGE_CREDITS) {
gSPClipRatio(gdl++, FRUSTRATIO_2);
gSPDisplayList(gdl++, &var800613a0);
gSPDisplayList(gdl++, &var80061380);
setCurrentPlayerNum(0);
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewx, g_Vars.currentplayer->viewy);
func00016748(1);
gdl = func0000b1a8(gdl);
gdl = func0000b1d0(gdl);
gdl = func0000b330(gdl);
gdl = creditsRender(gdl);
} else {
// Normal stages
s32 i;
s32 playercount;
Gfx *savedgdl;
bool forcesingleplayer = (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0)
&& func0f0bc4c0();
struct player *player;
struct chrdata *chr;
playercount = forcesingleplayer ? 1 : PLAYERCOUNT();
gSPClipRatio(gdl++, FRUSTRATIO_2);
for (i = 0; i < playercount; i++) {
bool islastplayer;
u32 bluramount = 0;
savedgdl = gdl;
if (forcesingleplayer) {
setCurrentPlayerNum(0);
g_Vars.currentplayerindex = 0;
islastplayer = true;
} else {
s32 nextplayernum = i + 1;
setCurrentPlayerNum(getPlayerByOrderNum(i));
islastplayer = playercount == nextplayernum;
}
// Calculate bluramount - this will be used later
if (g_Vars.tickmode != TICKMODE_CUTSCENE) {
player = g_Vars.currentplayer;
chr = player->prop->chr;
if (chr->blurdrugamount > 0
&& !g_Vars.currentplayer->invincible
&& !g_Vars.currentplayer->training) {
bluramount = (chr->blurdrugamount * 130) / 5000 + 100;
if (bluramount > 230) {
bluramount = 230;
}
if (chr->blurdrugamount > 5000) {
chr->blurdrugamount = 5000;
}
chr->blurdrugamount -= g_Vars.lvupdate240_60 * (chr->blurnumtimesdied + 1);
if (chr->blurdrugamount < 1) {
chr->blurdrugamount = 0;
chr->blurnumtimesdied = 0;
}
}
}
bviewSetBlur(bluramount);
gSPDisplayList(gdl++, &var800613a0);
if (debug0f11ee28()) {
gSPDisplayList(gdl++, &var80061360);
} else {
gSPDisplayList(gdl++, &var80061380);
}
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewx, g_Vars.currentplayer->viewy);
func00016748(g_Vars.currentplayerstats->scale_bg2gfx);
func0f1657f8();
func0f176298();
gdl = func0000b280(gdl);
gdl = func0000b1d0(gdl);
gdl = func0f15cb74(gdl);
func0f13c510();
if ((g_Vars.stagenum != STAGE_CITRAINING || (var80087260 <= 0 && g_MenuData.root != MENUROOT_MPSETUP))
&& g_Vars.lvframenum <= 5
&& !g_Vars.normmplayerisrunning
&& g_Vars.tickmode != TICKMODE_CUTSCENE) {
if (var80084050 < 6) {
g_Vars.unk000320 = 1;
}
var80084050++;
} else if (g_Vars.currentplayer->unk1583_06
&& var80075d60 == 2
&& g_Vars.currentplayer->cameramode != CAMERAMODE_THIRDPERSON
&& g_Vars.currentplayer->cameramode != CAMERAMODE_EYESPY
&& var8009dfc0 == 0) {
g_Vars.currentplayer->unk1583_06 = func0f09eae4();
}
if (g_Vars.unk000320) {
gdl = bviewRenderMotionBlur(gdl, 0xffffffff, 255);
g_Vars.unk000320--;
} else if (var8009dfc0) {
gdl = func0000b330(gdl);
gdl = func0f15cb74(gdl);
func00016748(1);
if (g_Vars.currentplayer->unk1c50_01) {
gdl = func0f0fbc30(gdl);
}
} else {
if (var80075d60 == 2) {
gdl = currentPlayerUpdateShootRot(gdl);
}
gdl = func0000b330(gdl);
gdl = func0f11f984(gdl);
func0f15ca00();
func0f004314();
func0f06302c(islastplayer);
scenarioCallback14(NULL);
func0f0601b0();
func0f064ce8();
handsTickAttack();
// Calculate lookingatprop
if (PLAYERCOUNT() == 1
|| g_Vars.coopplayernum >= 0
|| g_Vars.antiplayernum >= 0
|| (weaponHasFlag(handGetWeaponNum(HAND_RIGHT), WEAPONFLAG_AIMTRACK) && bmoveIsInSightAimMode())) {
g_Vars.currentplayer->lookingatprop.prop = func0f061d54(HAND_RIGHT, 0, 0);
if (g_Vars.currentplayer->lookingatprop.prop) {
if (g_Vars.currentplayer->lookingatprop.prop->type == PROPTYPE_CHR
|| g_Vars.currentplayer->lookingatprop.prop->type == PROPTYPE_PLAYER) {
chr = g_Vars.currentplayer->lookingatprop.prop->chr;
if (chr->hidden & CHRHFLAG_CLOAKED) {
if (g_Vars.currentplayer->isdead
|| g_InCutscene
|| !EYESPYINACTIVE()
|| (g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit & DEVICE_IRSCANNER) == false) {
g_Vars.currentplayer->lookingatprop.prop = NULL;
}
}
} else if (g_Vars.currentplayer->lookingatprop.prop->type == PROPTYPE_OBJ
|| g_Vars.currentplayer->lookingatprop.prop->type == PROPTYPE_WEAPON
|| g_Vars.currentplayer->lookingatprop.prop->type == PROPTYPE_DOOR) {
struct defaultobj *obj = g_Vars.currentplayer->lookingatprop.prop->obj;
if ((obj->flags3 & OBJFLAG3_00008000) == 0) {
if (g_Vars.stagenum != STAGE_CITRAINING
|| (obj->modelnum != MODEL_TARGET
&& obj->modelnum != MODEL_CIHUB
&& obj->modelnum != MODEL_COMHUB)) {
g_Vars.currentplayer->lookingatprop.prop = NULL;
}
}
} else {
g_Vars.currentplayer->lookingatprop.prop = NULL;
}
}
} else {
g_Vars.currentplayer->lookingatprop.prop = NULL;
}
if (handHasFunctionFlags(g_Vars.currentplayer->hands, FUNCFLAG_00080000)) {
coreFindThreats();
} else if (weaponHasFlag(handGetWeaponNum(HAND_RIGHT), WEAPONFLAG_AIMTRACK)) {
s32 j;
if (frIsInTraining()
&& g_Vars.currentplayer->lookingatprop.prop
&& bmoveIsInSightAimMode()) {
func0f1a0924(g_Vars.currentplayer->lookingatprop.prop);
} else if (coreCheckCmpFollowThreat(&g_Vars.currentplayer->lookingatprop, -1) == 0) {
g_Vars.currentplayer->lookingatprop.prop = NULL;
}
for (j = 0; j < ARRAYCOUNT(g_Vars.currentplayer->cmpfollowprops); j++) {
if (!coreCheckCmpFollowThreat(&g_Vars.currentplayer->cmpfollowprops[j], j)) {
g_Vars.currentplayer->cmpfollowprops[j].unk04 = -1;
g_Vars.currentplayer->cmpfollowprops[j].unk08 = -2;
}
}
}
// Handle eyespy Z presses
if (g_Vars.currentplayer->eyespy
&& (g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit & DEVICE_EYESPY)
&& g_Vars.currentplayer->eyespy->camerabuttonheld) {
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
objectiveCheckHolograph(400);
audioStart(var80095200, 0x4ff, 0, -1, -1, -1, -1, -1);
} else if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_DRUGSPY) {
if (g_Vars.currentplayer->eyespydarts) {
// Fire dart
struct coord direction;
audioStart(var80095200, 0x8057, 0, -1, -1, -1, -1, -1);
g_Vars.currentplayer->eyespydarts--;
direction.x = g_Vars.currentplayer->eyespy->look.x;
direction.y = g_Vars.currentplayer->eyespy->look.y;
direction.z = g_Vars.currentplayer->eyespy->look.z;
projectileCreate(g_Vars.currentplayer->eyespy->prop, 0,
&g_Vars.currentplayer->eyespy->prop->pos, &direction, WEAPON_TRANQUILIZER, NULL);
} else {
// No dart ammo
audioStart(var80095200, 0x8052, 0, -1, -1, -1, -1, -1);
}
} else { // EYESPYMODE_BOMBSPY
struct coord spd4 = {0, 0, 0};
s8 spd0[] = {30, 0, 0, 0};
explosionCreateSimple(g_Vars.currentplayer->eyespy->prop,
&g_Vars.currentplayer->eyespy->prop->pos,
g_Vars.currentplayer->eyespy->prop->rooms,
EXPLOSIONTYPE_23, 0);
func0f0319a8(g_Vars.currentplayer->eyespy->prop->chr, &spd4, 0, 0, spd0, 0, 0);
}
}
// Handle opening doors and reloading
if (g_Vars.currentplayer->bondactivateorreload) {
if (currentPlayerInteract(false)) {
currentPlayerReloadHandIfPossible(HAND_RIGHT);
currentPlayerReloadHandIfPossible(HAND_LEFT);
}
} else if (g_Vars.currentplayer->eyespy
&& g_Vars.currentplayer->eyespy->active
&& g_Vars.currentplayer->eyespy->opendoor) {
currentPlayerInteract(true);
}
func0f0641f4();
gdl = func0f15cae0(gdl);
func0f028498(var80075d68 == 15 || var8005f020);
gdl = propsRenderBulletTails(gdl);
gdl = func0f1526e4(gdl);
gdl = func0f130044(gdl);
gdl = weatherRender(gdl);
if (var80061640) {
gdl = func0f00a168(gdl);
}
if (var80075d60 == 2) {
gdl = func0f0c07c8(gdl);
} else {
gdl = func0f0aeed8(gdl);
if (g_Vars.currentplayer->visionmode != VISIONMODE_XRAY) {
gdl = func0f15b114(gdl);
}
}
if (var80075d78 <= 0) {
static struct audiohandle *g_CutsceneStaticAudioHandle = NULL;
static s32 g_CutsceneStaticTimer = 100;
static u8 g_CutsceneStaticActive = false;
bool cutscenehasstatic = false;
u32 alpha;
if (g_Vars.tickmode == TICKMODE_CUTSCENE) {
// This chunk of code is unreachable
// (STAGE_TEST_OLD is not used)
if (g_Vars.stagenum == STAGE_TEST_OLD) {
f32 frac = 0;
u32 colour;
s32 endframe = animGetNumFrames(g_CameraAnimNum) - 1;
colour = 0;
if (g_CameraAnimCurFrame < STAGE_TITLE) {
frac = 1.0f - (f32)g_CameraAnimCurFrame / 90.0f;
}
if (g_CameraAnimNum != 0x46c) {
if (g_CameraAnimCurFrame > endframe - 90) {
frac = (g_CameraAnimCurFrame - endframe + 90) / 90.0f;
}
} else {
if (g_CameraAnimCurFrame > endframe - 30) {
colour = 0xffffff00;
frac = (g_CameraAnimCurFrame - endframe + 30) / 30.0f;
}
}
if (frac > 0) {
alpha = 255 * frac;
gDPPipeSync(gdl++);
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
gDPSetPrimColorViaWord(gdl++, 0, 0, colour | alpha);
gDPFillRectangle(gdl++,
viGetViewLeft(),
viGetViewTop(),
viGetViewLeft() + viGetViewWidth(),
viGetViewTop() + viGetViewHeight());
gdl = func0f153838(gdl);
}
}
// Handle visual effects in cutscenes
switch (g_CameraAnimNum) {
case 0x1e5:
// Horizon scanner in Air Base intro
if (g_CameraAnimCurFrame > 839 && g_CameraAnimCurFrame < 1411) {
gdl = bviewRenderHorizonScanner(gdl);
}
break;
case 0x181:
case 0x183:
case 0x188:
{
// Show static randomly in Infiltration intro
s32 cutscenestatic = 0;
cutscenehasstatic = true;
if (g_CutsceneStaticAudioHandle == NULL) {
audioStart(var80095200, 0x59f, &g_CutsceneStaticAudioHandle, -1, -1, -1, -1, -1);
}
g_CutsceneStaticTimer -= g_Vars.diffframe60;
if (g_CutsceneStaticTimer < 0) {
g_CutsceneStaticTimer = random() % 200 + 40;
g_CutsceneStaticActive = false;
}
gdl = bviewRenderFilmLens(gdl, 0xffffffff, 0xffffffff);
if (g_CutsceneStaticTimer < 15) {
if (g_CutsceneStaticActive == false) {
g_CutsceneStaticActive = true;
audioStart(var80095200, 0x59e, NULL, -1, -1, -1, -1, -1);
}
cutscenestatic = 225 - g_CutsceneStaticTimer * 10;
}
// Consider a single frame of static, separate
// to the main static above
if (random() % 60 == 1) {
cutscenestatic = 255;
audioStart(var80095200, 0x59d, NULL, -1, -1, -1, -1, -1);
}
if (cutscenestatic) {
gdl = bviewRenderStatic(gdl, 0xffffffff, cutscenestatic);
}
}
break;
}
}
if (g_CutsceneStaticAudioHandle && !cutscenehasstatic) {
audioStop(g_CutsceneStaticAudioHandle);
}
// Slayer rocket shows static when flying out of bounds
if (g_Vars.currentplayer->visionmode == VISIONMODE_SLAYERROCKET
&& g_Vars.tickmode != TICKMODE_CUTSCENE) {
gdl = bviewRenderSlayerRocketLens(gdl, 0xffffffff, 0xffffffff);
if (g_Vars.currentplayer->badrockettime > 0) {
u32 slayerstatic = g_Vars.currentplayer->badrockettime * 255 / 90;
if (slayerstatic > 255) {
slayerstatic = 255;
}
gdl = bviewRenderStatic(gdl, 0x4fffffff, slayerstatic);
}
}
if (g_Vars.currentplayer->visionmode == VISIONMODE_3) {
gdl = bviewRenderStatic(gdl, 0x4fffffff, 255);
g_Vars.currentplayer->visionmode = VISIONMODE_NORMAL;
}
if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY
&& g_Vars.tickmode != TICKMODE_CUTSCENE) {
s32 xraything = 99;
if (g_Vars.currentplayer->erasertime < 200) {
xraything = 249 - (g_Vars.currentplayer->erasertime * 3 >> 2);
}
gdl = bviewRenderZoomBlur(gdl, 0xffffffff, xraything, 1.05f, 1.05f);
}
// Handle combat boosts
if ((g_Vars.speedpillchange > 0 && g_Vars.speedpillchange < 30)
|| (g_Vars.speedpillwant && !g_Vars.speedpillon)
|| (!g_Vars.speedpillwant && g_Vars.speedpillon)) {
if (g_Vars.speedpillchange == 30 && !g_Vars.speedpillwant) {
audioStart(var80095200, coreGetSlowMotionType() ? 0x5c9 : 0x2ad, 0, -1, -1, -1, -1, -1);
}
if (g_Vars.speedpillchange < 15) {
gdl = bviewRenderZoomBlur(gdl, 0xffffffff,
g_Vars.speedpillchange * 180 / 15,
(f32)g_Vars.speedpillchange * 0.02000000141561f + 1.1f,
(f32)g_Vars.speedpillchange * 0.02000000141561f + 1.1f);
gdl = fadeDraw(gdl, 0xff, 0xff, 0xff,
g_Vars.speedpillchange * 0.0066666668280959f);
} else {
gdl = bviewRenderZoomBlur(gdl, 0xffffffff,
(30 - g_Vars.speedpillchange) * 180 / 15,
(f32)(30 - g_Vars.speedpillchange) * 0.02000000141561f + 1.1f,
(f32)(30 - g_Vars.speedpillchange) * 0.02000000141561f + 1.1f);
gdl = fadeDraw(gdl, 0xff, 0xff, 0xff,
(30.0f - g_Vars.speedpillchange) * 0.0066666668280959f);
}
if (g_Vars.currentplayernum == 0) {
if (g_Vars.speedpillwant) {
g_Vars.speedpillchange++;
} else {
g_Vars.speedpillchange--;
}
}
if (g_Vars.speedpillchange > 30) {
g_Vars.speedpillchange = 30;
} else if (g_Vars.speedpillchange < 0) {
g_Vars.speedpillchange = 0;
}
}
if (g_Vars.speedpillchange > 15) {
g_Vars.speedpillon = true;
} else {
g_Vars.speedpillon = false;
}
if (bluramount) {
// empty
}
if (bluramount) {
bviewClearBlur();
gdl = bviewRenderMotionBlur(gdl, 0xffffffff, bluramount);
}
// Handle blur effect in cutscenes (Extraction intro?)
if (g_Vars.tickmode == TICKMODE_CUTSCENE) {
f32 cutsceneblurfrac = cutsceneGetBlurFrac();
if (cutsceneblurfrac > 0) {
u32 bluramount = cutsceneblurfrac * 255;
gdl = bviewRenderMotionBlur(gdl, 0xffffff00, bluramount);
}
}
if (debugGetMotionBlur() == 1) {
gdl = bviewRenderMotionBlur(gdl, 0xffffff00, 128);
} else if (debugGetMotionBlur() == 2) {
gdl = bviewRenderMotionBlur(gdl, 0xffffff00, 192);
} else if (debugGetMotionBlur() == 3) {
gdl = bviewRenderMotionBlur(gdl, 0xffffff00, 230);
}
if (bluramount) {
// empty
}
// Render white when teleporting
if (g_Vars.currentplayer->teleportstate > TELEPORTSTATE_INACTIVE) {
alpha = 0;
if (g_Vars.currentplayer->teleportstate == TELEPORTSTATE_WHITE) {
alpha = 255;
}
if (g_Vars.currentplayer->teleportstate == TELEPORTSTATE_EXITING
&& g_Vars.currentplayer->teleporttime < 16) {
alpha = -g_Vars.currentplayer->teleporttime * 16 + 240;
}
if (g_Vars.currentplayer->teleportstate == TELEPORTSTATE_ENTERING) {
if (g_Vars.currentplayer->teleporttime > 32) {
alpha = g_Vars.currentplayer->teleporttime * 16 - 512;
}
if (g_Vars.currentplayer->teleporttime == 48) {
alpha = 255;
}
}
if (alpha) {
gdl = func0f153628(gdl);
gdl = func0f153a34(gdl,
viGetViewLeft(), viGetViewTop(),
viGetViewLeft() + viGetViewWidth(),
viGetViewTop() + viGetViewHeight(), 0xffffff00 | alpha);
gdl = func0f153780(gdl);
}
}
}
gdl = func0f185774(gdl);
gdl = coreRenderFade(gdl);
if (g_FrIsValidWeapon) {
gdl = frRenderHud(gdl);
}
if (debug0f11ee88() == 0
&& debug0f11ee90() == 0
&& debug0f11eea8() == 0
&& debug0f11ef80() == 0
&& debug0f11ef78() == 0) {
debug0f11ee40();
}
gdl = func0f1274d8(gdl);
gdl = amRender(gdl);
func00016748(1);
if (g_Vars.currentplayer->unk1c50_01) {
gdl = func0f0fbc30(gdl);
}
func00016748(g_Vars.currentplayerstats->scale_bg2gfx);
if (g_Vars.mplayerisrunning) {
gdl = func0f18973c(gdl);
}
if (g_Vars.currentplayer->dostartnewlife) {
func0f0b72dc();
}
}
func0f13c54c();
if ((g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0)
&& func0f0bc4c0()
&& g_Vars.currentplayernum != 0) {
gdl = savedgdl;
}
} // end of player loop
} // end of stage if-statements
if (g_Vars.unk0004d3) {
if (g_Vars.unk0004d6) {
g_Vars.unk0004d3 = 0;
g_Vars.unk0004d6 = 0;
if (g_Vars.unk0004d7) {
g_Vars.unk0004d4 = -1;
g_Vars.unk0004d5 = 0;
}
if (g_Vars.unk0004d4 < 0 && g_Vars.unk0004d5 <= 0) {
mainSetStageNum(STAGE_TITLE);
}
}
}
// Advance the cutscenes when autoplaying
if (g_Vars.unk0004d3 == 0 && g_Vars.unk0004d4 >= 0 && g_Vars.unk0004d5 > 0) {
hudmsgRemoveAll();
g_Vars.unk0004d2 = g_Cutscenes[g_Vars.unk0004d4].scene;
g_MissionConfig.iscoop = false;
g_Vars.mplayerisrunning = false;
g_Vars.normmplayerisrunning = false;
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = -1;
g_MissionConfig.isanti = false;
setNumPlayers(1);
titleSetNextMode(TITLEMODE_SKIP);
g_MissionConfig.difficulty = DIFF_A;
coreSetDifficulty(DIFF_A);
g_MissionConfig.stageindex = g_Cutscenes[g_Vars.unk0004d4].mission;
g_MissionConfig.stagenum = g_Cutscenes[g_Vars.unk0004d4].stage;
titleSetNextStage(g_Cutscenes[g_Vars.unk0004d4].stage);
mainSetStageNum(g_Cutscenes[g_Vars.unk0004d4].stage);
g_Vars.unk0004d5--;
if (g_Vars.unk0004d5 > 0) {
g_Vars.unk0004d4++;
} else {
g_Vars.unk0004d4 = -1;
}
}
gDPSetScissor(gdl++, G_SC_NON_INTERLACE, 0, 0, viGetX(), viGetY());
return gdl;
}
u32 g_CutsceneTime240_60 = 0;
u32 var800840a8 = 0x00000000;
u32 var800840ac = 0x00000000;
u32 var800840b0 = 0x00000000;
u32 var800840b4 = 0x00000000;
u32 var800840b8 = 0x00000000;
u32 var800840bc = 0x00000000;
void coreUpdateSoloHandicaps(void)
{
if (g_Vars.antiplayernum >= 0) {
if (g_Difficulty == DIFF_A) {
g_CameraWaitMultiplier = 2;
var8006994c = 2;
var80069950 = 0.5f;
var80069954 = 0.5f;
var80069958 = 2;
var80062ca0 = 0.5f;
var80062ca4 = 0.35f;
var80062ca8 = 4;
var8007e4a8 = 0.25f;
var80069880 = 1.5f;
g_AmmoMultiplier = 3;
var80062cac = 0.2f;
} else if (g_Difficulty == DIFF_SA) {
g_CameraWaitMultiplier = 2;
var8006994c = 1.5f;
var80069950 = 0.5f;
var80069954 = 0.5f;
var80069958 = 1.5f;
var80062ca0 = 0.6f;
var80062ca4 = 0.5f;
var80062ca8 = 3;
var8007e4a8 = 0.25f;
var80069880 = 1.1f;
g_AmmoMultiplier = 2.5f;
var80062cac = 0.5f;
} else {
g_CameraWaitMultiplier = 2;
var8006994c = 1;
var80069950 = 0.5f;
var80069954 = 0.5f;
var80069958 = 1;
var80062ca0 = 0.7f;
var80062ca4 = 0.65f;
var80062ca8 = 2;
var8007e4a8 = 0.25f;
var80069880 = 0.75f;
g_AmmoMultiplier = 2;
var80062cac = 1;
}
} else if (g_Vars.coopplayernum >= 0) {
if (g_Difficulty == DIFF_A) {
g_CameraWaitMultiplier = 2;
var8006994c = 2;
var80069950 = 0.5f;
var80069954 = 0.5f;
var80069958 = 2;
var80062ca0 = 0.6f;
var80062ca4 = 0.5f;
var80062ca8 = 2;
var8007e4a8 = 0.25f;
var80069880 = 1.5f;
g_AmmoMultiplier = 2;
var80062cac = 0.2f;
} else if (g_Difficulty == DIFF_SA) {
g_CameraWaitMultiplier = 1;
var8006994c = 1;
var80069950 = 0.75f;
var80069954 = 1;
var80069958 = 1;
var80062ca0 = 0.75f;
var80062ca4 = 1;
var80062ca8 = 1;
var8007e4a8 = 1;
var80069880 = g_LanguageId ? 1.1f : 0.75f;
g_AmmoMultiplier = 1.5f;
var80062cac = 0.5f;
} else {
g_CameraWaitMultiplier = 1;
var8006994c = 1;
var80069950 = 1;
var80069954 = 1.5f;
var80069958 = 1;
var80062ca0 = 1.5f;
var80062ca4 = 1.5f;
var80062ca8 = 1;
var8007e4a8 = 1.5f;
var80069880 = g_LanguageId ? 0.75f : 0.2f;
g_AmmoMultiplier = 1;
var80062cac = 1;
}
} else {
if (g_Difficulty == DIFF_A) {
f32 totalhealth;
f32 frac = 1;
if (g_Vars.coopplayernum < 0 && g_Vars.antiplayernum < 0) {
totalhealth = currentPlayerGetHealthFrac() + currentPlayerGetShieldFrac();
if (totalhealth <= 0.125f) {
frac = 0.5f;
} else {
frac = 1;
if (totalhealth <= 0.6f) {
frac = (totalhealth - 0.125f) * 0.5f / 0.47500002384186f + 0.5f;
}
}
}
g_CameraWaitMultiplier = 2;
var8006994c = 2;
var80069950 = 0.5f * frac;
var80069954 = 0.5f * frac;
var80069958 = 2;
var80062ca0 = 0.6f;
var80062ca4 = 0.5f * frac;
var80062ca8 = 2;
var8007e4a8 = 0.25f * frac;
var80069880 = 1.5f;
g_AmmoMultiplier = 2;
var80062cac = 0.2f;
} else if (g_Difficulty == DIFF_SA) {
g_CameraWaitMultiplier = 1;
var8006994c = 1;
var80069950 = 0.75f;
var80069954 = 0.75f;
var80069958 = 1;
var80062ca0 = 0.8f;
var80062ca4 = 0.6f;
var80062ca8 = 1;
var8007e4a8 = 0.75f;
var80069880 = g_LanguageId ? 1.1f : 0.75f;
g_AmmoMultiplier = 1.5f;
var80062cac = 0.5f;
} else if (g_Difficulty == DIFF_PA) {
g_CameraWaitMultiplier = 1;
var8006994c = 1;
var80069950 = 1;
var80069954 = 1;
var80069958 = 1;
var80062ca0 = 1.175f;
var80062ca4 = 1;
var80062ca8 = 1;
var8007e4a8 = 1;
var80069880 = g_LanguageId ? 0.75f : 0.2f;
g_AmmoMultiplier = 1;
var80062cac = 1;
} else if (g_Difficulty == DIFF_PD) {
g_CameraWaitMultiplier = 1;
var8006994c = 1;
var80069950 = 1;
var80069954 = 1;
var80069958 = 1;
var80062ca0 = 1.1f;
var80062ca4 = 1;
var80062ca8 = 1;
var8007e4a8 = 1;
var80069880 = 1;
g_AmmoMultiplier = 1;
var80062cac = 1;
}
}
}
s32 sub54321(s32 value)
{
return value - 54321;
}
void coreUpdateCutsceneTime(void)
{
if (g_Vars.in_cutscene) {
g_CutsceneTime240_60 += g_Vars.lvupdate240_60;
return;
}
g_CutsceneTime240_60 = 0;
}
GLOBAL_ASM(
glabel coreGetSlowMotionType
/* f16b854: 27bdffd0 */ addiu $sp,$sp,-48
/* f16b858: afbf0014 */ sw $ra,0x14($sp)
/* f16b85c: 3c04b000 */ lui $a0,0xb000
/* f16b860: 0fc5ae00 */ jal sub54321
/* f16b864: 3484de8d */ ori $a0,$a0,0xde8d
/* f16b868: 3c041741 */ lui $a0,0x1741
/* f16b86c: afa2002c */ sw $v0,0x2c($sp)
/* f16b870: 0fc5ae00 */ jal sub54321
/* f16b874: 3484d42a */ ori $a0,$a0,0xd42a
/* f16b878: afa20024 */ sw $v0,0x24($sp)
/* f16b87c: 8fa4002c */ lw $a0,0x2c($sp)
/* f16b880: 0c013994 */ jal osPiReadIo
/* f16b884: 27a50028 */ addiu $a1,$sp,0x28
/* f16b888: 8fae0028 */ lw $t6,0x28($sp)
/* f16b88c: 8faf0024 */ lw $t7,0x24($sp)
/* f16b890: 3c058006 */ lui $a1,%hi(var80059fe0)
/* f16b894: 24a29fe0 */ addiu $v0,$a1,%lo(var80059fe0)
/* f16b898: 11cf000d */ beq $t6,$t7,.L0f16b8d0
/* f16b89c: 3c09800a */ lui $t1,%hi(g_Vars+0x318)
/* f16b8a0: 3c188006 */ lui $t8,%hi(var80059fe0+0x1)
/* f16b8a4: 24431000 */ addiu $v1,$v0,0x1000
/* f16b8a8: 27189fe1 */ addiu $t8,$t8,%lo(var80059fe0+0x1)
/* f16b8ac: 0078082b */ sltu $at,$v1,$t8
/* f16b8b0: 14200007 */ bnez $at,.L0f16b8d0
/* f16b8b4: 00000000 */ nop
.L0f16b8b8:
/* f16b8b8: 8c590000 */ lw $t9,0x0($v0)
/* f16b8bc: 24420004 */ addiu $v0,$v0,0x4
/* f16b8c0: 0043082b */ sltu $at,$v0,$v1
/* f16b8c4: 27280008 */ addiu $t0,$t9,0x8
/* f16b8c8: 1420fffb */ bnez $at,.L0f16b8b8
/* f16b8cc: ac48fffc */ sw $t0,-0x4($v0)
.L0f16b8d0:
/* f16b8d0: 8d29a2d8 */ lw $t1,%lo(g_Vars+0x318)($t1)
/* f16b8d4: 3c02800b */ lui $v0,%hi(g_MpSetup+0xc)
/* f16b8d8: 1120000b */ beqz $t1,.L0f16b908
/* f16b8dc: 00000000 */ nop
/* f16b8e0: 8c42cb94 */ lw $v0,%lo(g_MpSetup+0xc)($v0)
/* f16b8e4: 304a0040 */ andi $t2,$v0,0x40
/* f16b8e8: 11400003 */ beqz $t2,.L0f16b8f8
/* f16b8ec: 304b0080 */ andi $t3,$v0,0x80
/* f16b8f0: 1000001a */ b .L0f16b95c
/* f16b8f4: 24020001 */ addiu $v0,$zero,0x1
.L0f16b8f8:
/* f16b8f8: 51600018 */ beqzl $t3,.L0f16b95c
/* f16b8fc: 00001025 */ or $v0,$zero,$zero
/* f16b900: 10000016 */ b .L0f16b95c
/* f16b904: 24020002 */ addiu $v0,$zero,0x2
.L0f16b908:
/* f16b908: 0fc41b99 */ jal cheatIsActive
/* f16b90c: 24040006 */ addiu $a0,$zero,0x6
/* f16b910: 10400003 */ beqz $v0,.L0f16b920
/* f16b914: 00000000 */ nop
/* f16b918: 10000010 */ b .L0f16b95c
/* f16b91c: 24020001 */ addiu $v0,$zero,0x1
.L0f16b920:
/* f16b920: 0fc47b9c */ jal debugGetSlowMotion
/* f16b924: 00000000 */ nop
/* f16b928: 24010001 */ addiu $at,$zero,0x1
/* f16b92c: 14410003 */ bne $v0,$at,.L0f16b93c
/* f16b930: 00000000 */ nop
/* f16b934: 10000009 */ b .L0f16b95c
/* f16b938: 24020001 */ addiu $v0,$zero,0x1
.L0f16b93c:
/* f16b93c: 0fc47b9c */ jal debugGetSlowMotion
/* f16b940: 00000000 */ nop
/* f16b944: 24010002 */ addiu $at,$zero,0x2
/* f16b948: 54410004 */ bnel $v0,$at,.L0f16b95c
/* f16b94c: 00001025 */ or $v0,$zero,$zero
/* f16b950: 10000002 */ b .L0f16b95c
/* f16b954: 24020002 */ addiu $v0,$zero,0x2
/* f16b958: 00001025 */ or $v0,$zero,$zero
.L0f16b95c:
/* f16b95c: 8fbf0014 */ lw $ra,0x14($sp)
/* f16b960: 27bd0030 */ addiu $sp,$sp,0x30
/* f16b964: 03e00008 */ jr $ra
/* f16b968: 00000000 */ nop
);
// Can't match the antipiracy part
//u32 coreGetSlowMotionType(void)
//{
//#if PIRACYCHECKS
// u32 addr = sub54321(0xb000de8d);
// u32 actual;
// u32 expected = sub54321(0x1741d42a);
// osPiReadIo(addr, &actual);
//
// if (actual != expected) {
// extern u32 _rspMicrocodeStart;
// extern u32 _rspMicrocodeStartPlusOne;
// u32 *ptr = &_rspMicrocodeStart;
// u32 *end = &ptr[1024];
//
// if (!(end < &_rspMicrocodeStartPlusOne)) {
// do {
// *ptr += 8;
// ptr++;
// } while (ptr < end);
// }
// }
//#endif
//
// if (g_Vars.normmplayerisrunning) {
// if (g_MpSetup.options & MPOPTION_SLOWMOTION_ON) {
// return SLOWMOTION_ON;
// }
// if (g_MpSetup.options & MPOPTION_SLOWMOTION_SMART) {
// return SLOWMOTION_SMART;
// }
// } else {
// if (cheatIsActive(CHEAT_SLOMO)) {
// return SLOWMOTION_ON;
// }
// if (debugGetSlowMotion() == SLOWMOTION_ON) {
// return SLOWMOTION_ON;
// }
// if (debugGetSlowMotion() == SLOWMOTION_SMART) {
// return SLOWMOTION_SMART;
// }
// }
//
// return SLOWMOTION_OFF;
//}
void coreTick(void)
{
s32 j;
s32 i;
coreCheckPauseStateChanged();
if (g_Vars.unk0004e4) {
func0f11c54c();
}
if (g_Vars.unk0004d8 > 0) {
g_Vars.unk0004d8--;
} else if (g_Vars.unk0004d8 == 0) {
func00013938();
if (g_Vars.stagenum == STAGE_TITLE
|| g_Vars.stagenum == STAGE_BOOTPAKMENU
|| g_Vars.stagenum == STAGE_CREDITS
|| g_Vars.stagenum == STAGE_4MBMENU) {
g_Vars.unk0004d1 = 0;
} else {
g_Vars.unk0004d1 = 31;
func0f11df38();
}
g_Vars.unk0004d8 = -1;
}
if (IS4MB()) {
func0f19ab40();
}
for (j = 0; j < PLAYERCOUNT(); j++) {
g_Vars.players[j]->hands[HAND_LEFT].unk0cec = 0;
g_Vars.players[j]->hands[HAND_RIGHT].unk0cec = 0;
}
if (coreIsPaused()) {
g_Vars.lvupdate240 = 0;
} else if (mpIsPaused()) {
g_Vars.lvupdate240 = 0;
for (j = 0; j < PLAYERCOUNT(); j++) {
g_Vars.players[j]->joybutinhibit = 0xefffefff;
}
} else {
s32 slowmo = coreGetSlowMotionType();
g_Vars.lvupdate240 = g_Vars.diffframe240;
if (slowmo == SLOWMOTION_ON) {
if (g_Vars.speedpillon == false || g_Vars.in_cutscene) {
if (g_Vars.lvupdate240 > 4) {
g_Vars.lvupdate240 = 4;
}
}
} else if (slowmo == SLOWMOTION_SMART) {
// Smart slow motion - activates if an enemy chr is nearby
if (g_Vars.speedpillon == false || g_Vars.in_cutscene) {
if (g_Vars.mplayerisrunning) {
bool foundnearbychr = false;
s32 playernum;
// Check if another player is in a nearby room
for (playernum = 0; playernum < PLAYERCOUNT() && !foundnearbychr; playernum++) {
if (g_Vars.players[playernum]->isdead == false) {
s16 *rooms = g_Vars.players[playernum]->prop->rooms;
s32 r;
for (r = 0; rooms[r] != -1 && !foundnearbychr; r++) {
s32 otherplayernum;
for (otherplayernum = 0; otherplayernum < PLAYERCOUNT(); otherplayernum++) {
if (playernum != otherplayernum
&& g_Vars.players[otherplayernum]->isdead == false
&& roomIsVisibleByPlayer(rooms[r], otherplayernum)) {
foundnearbychr = true;
}
}
}
}
}
if (foundnearbychr) {
if (g_Vars.lvupdate240 > 4) {
g_Vars.lvupdate240 = 4;
}
} else {
if (g_Vars.lvupdate240 > 8) {
g_Vars.lvupdate240 = 8;
}
}
} else {
if (g_Vars.lvupdate240 > 4) {
g_Vars.lvupdate240 = 4;
}
}
}
} else {
// Slow motion settings are off
if (g_Vars.speedpillon && g_Vars.in_cutscene == false) {
if (g_Vars.lvupdate240 > 4) {
g_Vars.lvupdate240 = 4;
}
}
}
}
g_Vars.lvupdate240_60 = g_Vars.lvupdate240 + g_Vars.lvupdate240_60error;
g_Vars.lvupdate240_60error = g_Vars.lvupdate240_60 & 3;
g_Vars.lvupdate240_60 >>= 2;
if (g_Vars.lvupdate240 > 0) {
g_Vars.lvframenum++;
}
g_Vars.lvupdate240f = g_Vars.lvupdate240 * 0.25f;
g_Vars.lvframe60 += g_Vars.lvupdate240_60;
g_Vars.lvframe240 += g_Vars.lvupdate240;
g_Vars.lvupdate240frealprev = g_Vars.lvupdate240freal;
g_Vars.lvupdate240freal = g_Vars.lvupdate240f;
speedpillTick();
func0f0df364();
if ((contGetButtonsPressedThisFrame(0, 0xffff) != 0
|| contGetStickX(0) > 10
|| contGetStickX(0) < -10
|| contGetStickY(0) > 10
|| contGetStickY(0) < -10
|| contGetButtonsPressedThisFrame(1, 0xffff) != 0
|| contGetStickX(1) > 10
|| contGetStickX(1) < -10
|| contGetStickY(1) > 10
|| contGetStickY(1) < -10
|| contGetButtonsPressedThisFrame(2, 0xffff) != 0
|| contGetStickX(2) > 10
|| contGetStickX(2) < -10
|| contGetStickY(2) > 10
|| contGetStickY(2) < -10
|| contGetButtonsPressedThisFrame(3, 0xffff) != 0
|| contGetStickX(3) > 10
|| contGetStickX(3) < -10
|| contGetStickY(3) > 10
|| contGetStickY(3) < -10) && var800624a4) {
if (g_Vars.stagenum != STAGE_TITLE) {
titleSetNextMode(TITLEMODE_SKIP);
mainSetStageNum(STAGE_TITLE);
}
var800624a4 = 0;
}
if (g_Vars.stagenum < STAGE_TITLE && !var800624a4 && !g_Vars.in_cutscene) {
if (contGetButtons(0, 0xffff) == 0
&& contGetStickX(0) < 10
&& contGetStickX(0) > -10
&& contGetStickY(0) < 10
&& contGetStickY(0) > -10
&& contGetButtons(1, 0xffff) == 0
&& contGetStickX(1) < 10
&& contGetStickX(1) > -10
&& contGetStickY(1) < 10
&& contGetStickY(1) > -10
&& contGetButtons(2, 0xffff) == 0
&& contGetStickX(2) < 10
&& contGetStickX(2) > -10
&& contGetStickY(2) < 10
&& contGetStickY(2) > -10
&& contGetButtons(3, 0xffff) == 0
&& contGetStickX(3) < 10
&& contGetStickX(3) > -10
&& contGetStickY(3) < 10
&& contGetStickY(3) > -10) {
var800624b0 += g_Vars.diffframe60;
} else {
var800624b0 = 0;
}
} else {
var800624b0 = 0;
}
g_NumReasonsToEndMpMatch = 0;
// Handle MP match ending
if (g_Vars.normmplayerisrunning && g_Vars.stagenum < STAGE_TITLE) {
if (g_MpTimeLimit60 > 0) {
s32 elapsed = g_StageTimeElapsed60;
s32 nexttime = g_Vars.lvupdate240_60 + g_StageTimeElapsed60;
s32 warntime = g_MpTimeLimit60 - 3600;
// Show HUD message at one minute remaining
if (elapsed < warntime && nexttime >= warntime) {
s32 i;
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
hudmsgCreateViaPreset(langGet(L_MISC(68)), 0); // "One minute left."
}
}
if (elapsed < g_MpTimeLimit60 && nexttime >= g_MpTimeLimit60) {
// Match is ending due to time limit reached
mainEndStage();
}
// Sound alarm at 10 seconds remaining
if (nexttime >= g_MpTimeLimit60 - 600
&& g_MiscAudioHandle == NULL
&& !coreIsPaused()
&& nexttime < g_MpTimeLimit60) {
func00010718(&g_MiscAudioHandle, 0, 0x7fff, 0x40, 163, 1, 1, -1, 1);
}
}
if (g_Vars.lvupdate240 != 0) {
s32 numdying = 0;
for (i = 0; i < PLAYERCOUNT(); i++) {
if (g_Vars.players[i]->isdead) {
if (g_Vars.players[i]->redbloodfinished == false
|| g_Vars.players[i]->deathanimfinished == false
|| g_Vars.players[i]->colourfadetimemax60 >= 0) {
numdying++;
}
}
}
for (i = 0; i < g_MpNumPlayers; i++) {
if (g_MpPlayerChrs[i]->actiontype == ACT_DIE) {
numdying++;
}
}
if (g_MpScoreLimit > 0) {
struct mpteaminfo info[12];
s32 count = mpGetPlayerRankings(info);
for (i = 0; i < count; i++) {
if (info[i].score >= g_MpScoreLimit) {
g_NumReasonsToEndMpMatch++;
}
}
}
if (g_MpTeamScoreLimit > 0) {
struct mpteaminfo info[12];
s32 count = mpGetTeamRankings(info);
for (i = 0; i < count; i++) {
if (info[i].score >= g_MpTeamScoreLimit) {
g_NumReasonsToEndMpMatch++;
}
}
}
if (g_NumReasonsToEndMpMatch > 0 && numdying == 0) {
mainEndStage();
}
}
}
g_StageTimeElapsed60 += g_Vars.lvupdate240_60;
g_StageTimeElapsed1f = g_StageTimeElapsed60 / 60.0f;
viSetUseZBuf(true);
if (g_Vars.stagenum == STAGE_TEST_OLD) {
func0f01ae30();
func00011d84();
}
if (g_Vars.stagenum == STAGE_TITLE) {
titleTick();
func0f01d860();
func00011d84();
} else if (g_Vars.stagenum == STAGE_BOOTPAKMENU) {
setCurrentPlayerNum(0);
menuTickAll();
func00011d84();
func0f01d860();
pakExecuteDebugOperations();
} else if (g_Vars.stagenum == STAGE_4MBMENU) {
menuTickAll();
func00011d84();
func0f01d860();
pakExecuteDebugOperations();
} else if (g_Vars.stagenum == STAGE_CREDITS) {
func00011d84();
func0f01d860();
} else {
coreUpdateCutsceneTime();
func0f12939c();
coreUpdateSoloHandicaps();
func0f01d8c0();
func0f01d990();
func0f01dd6c();
func0f01de30();
sparksTick();
func0f13eb44();
func0f149864();
if (g_WeatherEnabled) {
weatherTick();
}
if (var80061640) {
func0f009eac();
}
coreUpdateMiscSfx();
func0000fe88();
pakExecuteDebugOperations();
func0f0033b0();
func0f0b2904();
func0f0aefb8();
amTick();
menuTickAll();
scenarioCallback10();
if (var8005d9d0 == 0) {
func0f01e250();
}
func00011d84();
func0f01d860();
func0f063dcc();
if (mainGetStageNum() == STAGE_CITRAINING) {
struct trainingdata *trainingdata = dtGetData();
if ((g_Vars.currentplayer->prop->rooms[0] < CIROOM_HOLOSTART || g_Vars.currentplayer->prop->rooms[0] > CIROOM_HOLOEND)
&& g_Vars.currentplayer->prop->rooms[0] != CIROOM_FIRINGRANGE
&& (trainingdata == NULL || trainingdata->intraining == false)) {
chrUnsetStageFlag(NULL, STAGEFLAG_CI_IN_TRAINING);
}
frTick();
if (g_Vars.lvupdate240 != 0) {
dtTick();
htTick();
}
}
}
}
void coreRecordDistanceMoved(void)
{
f32 xdiff;
f32 zdiff;
if (var80075d64 == 2) {
if (var80075d68 == 2) {
func0f0bd904(true);
} else {
func0f0bd904(false);
}
}
xdiff = g_Vars.currentplayer->prop->pos.x - g_Vars.currentplayer->bondprevpos.x;
zdiff = g_Vars.currentplayer->prop->pos.z - g_Vars.currentplayer->bondprevpos.z;
g_Vars.currentplayerstats->distance += sqrtf(xdiff * xdiff + zdiff * zdiff);
}
void coreUnloadStage(void)
{
func0f11dcb0(1);
if (g_MiscAudioHandle && audioIsPlaying(g_MiscAudioHandle)) {
audioStop(g_MiscAudioHandle);
}
if (g_Vars.stagenum < NUM_STAGES) {
s32 bank = langGetLangBankIndexFromStagenum(g_Vars.stagenum);
langClearBank(bank);
func0f015270();
}
func0f014f10();
explosionsFree();
smokeFree();
func0f015400();
func0f015410();
func0f015420();
func0f0153f0();
func0f014fe0();
func0f015010();
weatherFree();
func0f0151f0();
func0f015260();
func0f015470();
func0f0150a0();
func0f16d9fc();
hudmsgsReset();
if (g_Vars.stagenum < NUM_STAGES) {
func0f15c850();
}
func00033dd8();
if (g_FileState == FILESTATE_CHANGINGAGENT) {
menuPlaySound(MENUSOUND_EXPLOSION);
g_FileState = FILESTATE_UNSELECTED;
}
func0f01bea0();
}
void coreCheckPauseStateChanged(void)
{
u32 paused = mpIsPaused();
if (paused != var80084010) {
if (paused) {
func0f11deb8();
} else {
func0f11df38();
}
}
var80084010 = paused;
}
void coreSetPaused(bool paused)
{
if (paused) {
func0f11deb8();
func0000fe20();
} else {
func0000fe50();
func0f11df38();
}
var80084014 = paused;
}
bool coreIsPaused(void)
{
return var80084014;
}
s32 coreGetDifficulty(void)
{
return g_Difficulty;
}
void coreSetDifficulty(s32 difficulty)
{
if (difficulty < DIFF_A || difficulty > DIFF_PD) {
difficulty = DIFF_A;
}
g_Difficulty = difficulty;
}
void coreSetMpTimeLimit60(u32 limit)
{
g_MpTimeLimit60 = limit;
}
void coreSetMpScoreLimit(u32 limit)
{
g_MpScoreLimit = limit;
}
void coreSetMpTeamScoreLimit(u32 limit)
{
g_MpTeamScoreLimit = limit;
}
f32 coreGetStageTimeInSeconds(void)
{
return g_StageTimeElapsed1f;
}
u32 coreGetStageTime60(void)
{
return g_StageTimeElapsed60;
}
u32 func0f16ce04(u32 arg0)
{
return arg0;
}