#include #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/nbomb.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/objectives.h" #include "game/casing.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/stubs/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/stubs/game_015260.h" #include "game/stubs/game_015270.h" #include "game/explosions/reset.h" #include "game/smoke/reset.h" #include "game/stubs/game_0153f0.h" #include "game/stubs/game_015400.h" #include "game/stubs/game_015410.h" #include "game/shards.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/chr/chr.h" #include "game/prop.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/hudmsg.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_1531a0.h" #include "game/room.h" #include "game/game_165670.h" #include "game/core.h" #include "game/music.h" #include "game/texture.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[] = { SFX_HEARTBEAT, SFX_SLAYER_WHIR, SFX_SLAYER_BEEP, }; 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.lockscreen = 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(); hudmsgsInit(); 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(); objectivesReset(); func0f013ba0(); func0f011110(); func0f0108d0(); setupLoadFiles(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(); stub0f013540(); shardsInit(); 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(); casingsReset(); 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.lockscreen = 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.lockscreen) { gdl = bviewRenderMotionBlur(gdl, 0xffffffff, 255); g_Vars.lockscreen--; } 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, SFX_CAMSPY_SHUTTER, 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, SFX_DRUGSPY_FIREDART, 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, SFX_DRUGSPY_FIREEMPTY, 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 = bgRender(gdl); func0f028498(var80075d68 == 15 || var8005f020); gdl = propsRenderBulletTails(gdl); gdl = shardsRender(gdl); gdl = sparksRender(gdl); gdl = weatherRender(gdl); if (g_NbombsActive) { gdl = nbombsRender(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, SFX_INFIL_STATIC_LONG, &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, SFX_INFIL_STATIC_MEDIUM, 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, SFX_INFIL_STATIC_SHORT, 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() ? SFX_JO_BOOST_ACTIVATE : SFX_JO_BOOST_REVERT, 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 = mpRenderModalText(gdl); } if (g_Vars.currentplayer->dostartnewlife) { currentPlayerStartNewLife(); } } 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(); hudmsgsTick(); 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) { titleTickOld(); 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(); casingsTick(); shardsTick(); sparksTick(); func0f13eb44(); func0f149864(); if (g_WeatherActive) { weatherTick(); } if (g_NbombsActive) { nbombsTick(); } coreUpdateMiscSfx(); func0000fe88(); pakExecuteDebugOperations(); lightingTick(); func0f0b2904(); func0f0aefb8(); amTick(); menuTickAll(); scenarioTick(); 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); stub0f015270(); } chrsReset(); explosionsReset(); smokeReset(); stub0f015400(); stub0f015410(); shardsReset(); stub0f0153f0(); alarmReset(); func0f015010(); // props/setup related weatherReset(); objectivesAutocomplete(); stub0f015260(); func0f015470(); func0f0150a0(); musicReset(); 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; }