mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-01 18:13:57 +00:00
* Add multiplayer extension * Fix animation system to work when host is outside ISLE world - Move TickHostSessions outside m_inIsleWorld gate so the host can coordinate animations from any world - Load animation catalog early in HandleCreate so the host can coordinate before entering the ISLE world - Use network-reported positions for remote player location detection instead of requiring spawned ROIs - Always erase sessions at launch — the host's job ends when the animation starts; clients play and complete independently - Replace BroadcastAnimComplete with locally-driven completion callbacks: host generates eventId at launch, clients cache completion JSON at start time, fire it when ScenePlayer finishes - Make StopAnimation only do local cleanup (stop playback, cancel own interest, reset coordinator) without destroying the session host, so other players' sessions survive world transitions - Broadcast state=0 in ResetAnimationState for full teardown paths (shutdown, reconnect, host migration) so clients aren't left with stale session state * Fix use-after-free crash in ScenePlayer when remote player disconnects mid-animation When a remote player's ROI is destroyed (disconnect, timeout, or respawn), notify all active ScenePlayer instances to null out dangling references before the ROI is freed. The animation engine already handles null ROI map entries gracefully, so playback continues for remaining participants. * Fix crash when performer's child ROIs are left dangling in ScenePlayer NotifyROIDestroyed now walks the parent chain to also invalidate child ROIs of the destroyed performer (head, limbs, etc.) that were placed into the roiMap by BuildROIMap. The ancestor walk happens once; all other fields are cleaned with simple pointer equality. * Allow spectator to play click animation during scene playback * Make PTATCAM track spectator ROI instead of camera in ScenePlayer * Only regenerate emscripten version files when git state changes Replace add_custom_target(ALL) with add_custom_command(OUTPUT) so the version script only runs when .git/HEAD or the current branch ref file changes, instead of on every build. * Fix ROI name collision causing dangling pointers in NPC locomotion roiMaps When ScenePlayer created cloned NPC ROIs for cooperative animations, it renamed them to match the original character name and added them to the ViewManager. This created a name collision: two ROIs with the same name. The original game's AppendROIToScene searches by name and stops at the first match, so if a locomotion BuildROIMap ran while the clone existed, it could capture pointers to the clone's child ROIs. When the clone was later destroyed (CleanupProps), those roiMap entries became dangling pointers, crashing in AnimateWithTransform at roi.h:151 (SetVisibility). Fix: use the alias mechanism (already supported by AnimUtils::BuildROIMap) instead of renaming clones. Also unify all ROI name generation behind a shared counter to prevent character manager key collisions.
1685 lines
48 KiB
C++
1685 lines
48 KiB
C++
#include "legogamestate.h"
|
|
|
|
#include "3dmanager/lego3dmanager.h"
|
|
#include "act2main_actions.h"
|
|
#include "act3_actions.h"
|
|
#include "ambulance.h"
|
|
#include "carrace.h"
|
|
#include "carrace_actions.h"
|
|
#include "carracer_actions.h"
|
|
#include "copter_actions.h"
|
|
#include "define.h"
|
|
#include "dunebuggy.h"
|
|
#include "dunecar_actions.h"
|
|
#include "elevbott_actions.h"
|
|
#include "extensions/multiplayer.h"
|
|
#include "garage_actions.h"
|
|
#include "helicopter.h"
|
|
#include "histbook_actions.h"
|
|
#include "hospital_actions.h"
|
|
#include "infocenter.h"
|
|
#include "infodoor_actions.h"
|
|
#include "infomain_actions.h"
|
|
#include "infoscor_actions.h"
|
|
#include "isle.h"
|
|
#include "isle_actions.h"
|
|
#include "islepathactor.h"
|
|
#include "jetrace_actions.h"
|
|
#include "jetracer_actions.h"
|
|
#include "jetski.h"
|
|
#include "jetski_actions.h"
|
|
#include "jetskirace.h"
|
|
#include "jukebox_actions.h"
|
|
#include "jukeboxw_actions.h"
|
|
#include "legoanimationmanager.h"
|
|
#include "legobuildingmanager.h"
|
|
#include "legocharactermanager.h"
|
|
#include "legomain.h"
|
|
#include "legonavcontroller.h"
|
|
#include "legoplantmanager.h"
|
|
#include "legostate.h"
|
|
#include "legoutils.h"
|
|
#include "legovideomanager.h"
|
|
#include "legoworld.h"
|
|
#include "misc.h"
|
|
#include "mxbackgroundaudiomanager.h"
|
|
#include "mxmisc.h"
|
|
#include "mxnotificationmanager.h"
|
|
#include "mxnotificationparam.h"
|
|
#include "mxobjectfactory.h"
|
|
#include "mxstring.h"
|
|
#include "mxutilities.h"
|
|
#include "mxvariabletable.h"
|
|
#include "pizza.h"
|
|
#include "police_actions.h"
|
|
#include "racecar.h"
|
|
#include "racecar_actions.h"
|
|
#include "regbook_actions.h"
|
|
#include "roi/legoroi.h"
|
|
#include "scripts.h"
|
|
#include "sndanim_actions.h"
|
|
#include "towtrack.h"
|
|
|
|
#include <SDL3/SDL_filesystem.h>
|
|
#include <SDL3/SDL_stdinc.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
using namespace Extensions;
|
|
|
|
DECOMP_SIZE_ASSERT(LegoGameState::Username, 0x0e)
|
|
DECOMP_SIZE_ASSERT(LegoGameState::ScoreItem, 0x2c)
|
|
DECOMP_SIZE_ASSERT(LegoGameState::History, 0x374)
|
|
DECOMP_SIZE_ASSERT(LegoGameState, 0x430)
|
|
DECOMP_SIZE_ASSERT(ColorStringStruct, 0x08)
|
|
DECOMP_SIZE_ASSERT(LegoBackgroundColor, 0x30)
|
|
DECOMP_SIZE_ASSERT(LegoFullScreenMovie, 0x24)
|
|
|
|
// GLOBAL: LEGO1 0x100f3e40
|
|
// STRING: LEGO1 0x100f3e3c
|
|
const char* g_fileExtensionGS = ".GS";
|
|
|
|
// GLOBAL: LEGO1 0x100f3e44
|
|
// STRING: LEGO1 0x100f3e30
|
|
const char* g_playersGSI = "Players.gsi";
|
|
|
|
// GLOBAL: LEGO1 0x100f3e48
|
|
// STRING: LEGO1 0x100f3e24
|
|
const char* g_historyGSI = "History.gsi";
|
|
|
|
// This is a pointer to the end of the global variable name table, which has
|
|
// the text "END_OF_VARIABLES" in it.
|
|
// TODO: make g_endOfVariables reference the actual end of the variable array.
|
|
// GLOBAL: LEGO1 0x100f3e50
|
|
// STRING: LEGO1 0x100f3e00
|
|
// GLOBAL: BETA10 0x101ed5dc
|
|
// STRING: BETA10 0x101ed768
|
|
const char* g_endOfVariables = "END_OF_VARIABLES";
|
|
|
|
// GLOBAL: LEGO1 0x100f3e58
|
|
ColorStringStruct g_colorSaveData[43] = {
|
|
{"c_dbbkfny0", "lego red"}, {"c_dbbkxly0", "lego white"}, // dunebuggy back fender, dunebuggy back axle
|
|
{"c_chbasey0", "lego black"}, {"c_chbacky0", "lego black"}, // copter base, copter back
|
|
{"c_chdishy0", "lego white"}, {"c_chhorny0", "lego black"}, // copter dish, copter horn
|
|
{"c_chljety1", "lego black"}, {"c_chrjety1", "lego black"}, // copter left jet, copter right jet
|
|
{"c_chmidly0", "lego black"}, {"c_chmotry0", "lego blue"}, // copter middle, copter motor
|
|
{"c_chsidly0", "lego black"}, {"c_chsidry0", "lego black"}, // copter side left, copter side right
|
|
{"c_chstuty0", "lego black"}, {"c_chtaily0", "lego black"}, // copter skids, copter tail
|
|
{"c_chwindy1", "lego black"}, {"c_dbfbrdy0", "lego red"}, // copter windshield, dunebuggy body
|
|
{"c_dbflagy0", "lego yellow"}, {"c_dbfrfny4", "lego red"}, // dunebuggy flag, dunebuggy front fender
|
|
{"c_dbfrxly0", "lego white"}, {"c_dbhndly0", "lego white"}, // dunebuggy front axle, dunebuggy handlebar
|
|
{"c_dbltbry0", "lego white"}, {"c_jsdashy0", "lego white"}, // dunebuggy rear lights, jetski dash
|
|
{"c_jsexhy0", "lego black"}, {"c_jsfrnty5", "lego black"}, // jetski exhaust, jetski front
|
|
{"c_jshndly0", "lego red"}, {"c_jslsidy0", "lego black"}, // jetski handlebar, jetski left side
|
|
{"c_jsrsidy0", "lego black"}, {"c_jsskiby0", "lego red"}, // jetski right side, jetski base
|
|
{"c_jswnshy5", "lego white"}, {"c_rcbacky6", "lego green"}, // jetski windshield, racecar back
|
|
{"c_rcedgey0", "lego green"}, {"c_rcfrmey0", "lego red"}, // racecar edge, racecar frame
|
|
{"c_rcfrnty6", "lego green"}, {"c_rcmotry0", "lego white"}, // racecar front, racecar motor
|
|
{"c_rcsidey0", "lego green"}, {"c_rcstery0", "lego white"}, // racecar side, racecar steering wheel
|
|
{"c_rcstrpy0", "lego yellow"}, {"c_rctailya", "lego white"}, // racecar stripe, racecar tail
|
|
{"c_rcwhl1y0", "lego white"}, {"c_rcwhl2y0", "lego white"}, // racecar wheels 1, racecar wheels 2
|
|
{"c_jsbasey0", "lego white"}, {"c_chblady0", "lego black"}, // jetski base, copter blades
|
|
{"c_chseaty0", "lego white"}, // copter seat
|
|
};
|
|
|
|
// NOTE: This offset = the end of the variables table, the last entry
|
|
// in that table is a special entry, the string "END_OF_VARIABLES"
|
|
extern const char* g_endOfVariables;
|
|
|
|
// GLOBAL: LEGO1 0x100f3fb0
|
|
// STRING: LEGO1 0x100f3a18
|
|
const char* g_delimiter = " \t";
|
|
|
|
// GLOBAL: LEGO1 0x100f3fb4
|
|
// STRING: LEGO1 0x100f3bf0
|
|
const char* g_set = "set";
|
|
|
|
// GLOBAL: LEGO1 0x100f3fb8
|
|
// STRING: LEGO1 0x100f0cdc
|
|
const char* g_reset = "reset";
|
|
|
|
// GLOBAL: LEGO1 0x100f3fbc
|
|
// STRING: LEGO1 0x100f3be8
|
|
const char* g_strEnable = "enable";
|
|
|
|
// GLOBAL: LEGO1 0x100f3fc0
|
|
// STRING: LEGO1 0x100f3bf4
|
|
const char* g_strDisable = "disable";
|
|
|
|
const InternationalCharacter LegoGameState::g_intCharacters[8] = {
|
|
{0xe4, "Aum_Bitmap", 29},
|
|
{0xf6, "Oum_Bitmap", 30},
|
|
{0xdf, "Beta_Bitmap", 31},
|
|
{0xfc, "Uum_Bitmap", 32},
|
|
{0xe5, "Ao_Bitmap", 29},
|
|
{0xe6, "Ae_Bitmap", 30},
|
|
{0xf8, "Oz_Bitmap", 31},
|
|
{0xf1, "Ene_Bitmap", 29}
|
|
};
|
|
|
|
// FUNCTION: LEGO1 0x10039550
|
|
LegoGameState::LegoGameState()
|
|
{
|
|
SetColors();
|
|
SetROIColorOverride();
|
|
|
|
m_stateCount = 0;
|
|
m_actorId = 0;
|
|
m_savePath = NULL;
|
|
m_stateArray = NULL;
|
|
m_jukeboxMusic = JukeboxScript::c_noneJukebox;
|
|
m_currentArea = e_undefined;
|
|
m_previousArea = e_undefined;
|
|
m_savedPreviousArea = e_undefined;
|
|
m_playerCount = 0;
|
|
m_isDirty = FALSE;
|
|
m_loadedAct = e_actNotFound;
|
|
SetCurrentAct(e_act1);
|
|
|
|
m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68");
|
|
VariableTable()->SetVariable(m_backgroundColor);
|
|
|
|
m_tempBackgroundColor = new LegoBackgroundColor("tempBackgroundColor", "set 56 54 68");
|
|
VariableTable()->SetVariable(m_tempBackgroundColor);
|
|
|
|
m_fullScreenMovie = new LegoFullScreenMovie("fsmovie", "disable");
|
|
VariableTable()->SetVariable(m_fullScreenMovie);
|
|
|
|
VariableTable()->SetVariable("lightposition", "2");
|
|
SerializeScoreHistory(LegoFile::c_read);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039720
|
|
LegoGameState::~LegoGameState()
|
|
{
|
|
LegoROI::SetColorOverride(NULL);
|
|
|
|
if (m_stateCount) {
|
|
for (MxS16 i = 0; i < m_stateCount; i++) {
|
|
LegoState* state = m_stateArray[i];
|
|
if (state) {
|
|
delete state;
|
|
}
|
|
}
|
|
|
|
delete[] m_stateArray;
|
|
}
|
|
|
|
delete[] m_savePath;
|
|
|
|
delete LegoOmni::GetInstance()->GetUserActor();
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039780
|
|
// FUNCTION: BETA10 0x10083d43
|
|
void LegoGameState::SetActor(MxU8 p_actorId)
|
|
{
|
|
if (p_actorId) {
|
|
m_actorId = p_actorId;
|
|
}
|
|
|
|
LegoPathActor* oldActor = UserActor();
|
|
SetUserActor(NULL);
|
|
|
|
IslePathActor* newActor = new IslePathActor();
|
|
const char* actorName = LegoActor::GetActorName(m_actorId);
|
|
LegoROI* roi = CharacterManager()->GetActorROI(actorName, FALSE);
|
|
MxDSAction action;
|
|
|
|
action.SetAtomId(*g_isleScript);
|
|
action.SetObjectId(100000);
|
|
newActor->Create(action);
|
|
newActor->SetActorId(p_actorId);
|
|
newActor->SetROI(roi, FALSE, FALSE);
|
|
|
|
if (oldActor) {
|
|
newActor->GetROI()->SetLocal2World(oldActor->GetROI()->GetLocal2World());
|
|
newActor->SetBoundary(oldActor->GetBoundary());
|
|
delete oldActor;
|
|
}
|
|
|
|
newActor->ClearFlag(LegoEntity::c_managerOwned);
|
|
SetUserActor(newActor);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039910
|
|
void LegoGameState::RemoveActor()
|
|
{
|
|
LegoPathActor* actor = UserActor();
|
|
SetUserActor(NULL);
|
|
delete actor;
|
|
m_actorId = 0;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039940
|
|
// FUNCTION: BETA10 0x10084069
|
|
void LegoGameState::ResetROI()
|
|
{
|
|
if (m_actorId) {
|
|
LegoPathActor* actor = UserActor();
|
|
|
|
if (actor) {
|
|
LegoROI* roi = actor->GetROI();
|
|
|
|
if (roi) {
|
|
VideoManager()->Get3DManager()->Remove(*roi);
|
|
VideoManager()->Get3DManager()->Add(*roi);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039980
|
|
// FUNCTION: BETA10 0x100840e4
|
|
MxResult LegoGameState::Save(MxULong p_slot)
|
|
{
|
|
InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState");
|
|
|
|
if (!infocenterState || !infocenterState->HasRegistered()) {
|
|
return SUCCESS;
|
|
}
|
|
|
|
MxResult result = FAILURE;
|
|
LegoFile storage;
|
|
MxVariableTable* variableTable = VariableTable();
|
|
MxS16 count = 0;
|
|
MxU32 i;
|
|
MxS32 j;
|
|
MxU16 area;
|
|
|
|
MxString savePath;
|
|
GetFileSavePath(&savePath, p_slot);
|
|
|
|
if (storage.Open(savePath.GetData(), LegoFile::c_write) == FAILURE) {
|
|
goto done;
|
|
}
|
|
|
|
storage.WriteS32(0x1000c);
|
|
storage.WriteS16(m_currentPlayerId);
|
|
storage.WriteU16(m_currentAct);
|
|
storage.WriteU8(m_actorId);
|
|
|
|
for (i = 0; i < sizeOfArray(g_colorSaveData); i++) {
|
|
if (WriteVariable(&storage, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (WriteVariable(&storage, variableTable, "backgroundcolor") == FAILURE) {
|
|
goto done;
|
|
}
|
|
if (WriteVariable(&storage, variableTable, "lightposition") == FAILURE) {
|
|
goto done;
|
|
}
|
|
|
|
WriteEndOfVariables(&storage);
|
|
CharacterManager()->Write(&storage);
|
|
PlantManager()->Write(&storage);
|
|
result = BuildingManager()->Write(&storage);
|
|
|
|
for (j = 0; j < m_stateCount; j++) {
|
|
if (m_stateArray[j]->IsSerializable()) {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
storage.WriteS16(count);
|
|
|
|
for (j = 0; j < m_stateCount; j++) {
|
|
if (m_stateArray[j]->IsSerializable()) {
|
|
m_stateArray[j]->Serialize(&storage);
|
|
}
|
|
}
|
|
|
|
area = m_savedPreviousArea;
|
|
storage.WriteU16(area);
|
|
SerializeScoreHistory(LegoFile::c_write);
|
|
m_isDirty = FALSE;
|
|
|
|
EmitGameEvent(e_saveSlotWritten, (void*) (intptr_t) p_slot);
|
|
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039bf0
|
|
MxResult LegoGameState::DeleteState()
|
|
{
|
|
MxS16 stateCount = m_stateCount;
|
|
LegoState** stateArray = m_stateArray;
|
|
|
|
m_stateCount = 0;
|
|
m_stateArray = NULL;
|
|
|
|
for (MxS32 count = 0; count < stateCount; count++) {
|
|
if (!stateArray[count]->Reset() && stateArray[count]->IsSerializable()) {
|
|
delete stateArray[count];
|
|
}
|
|
else {
|
|
RegisterState(stateArray[count]);
|
|
stateArray[count] = NULL;
|
|
}
|
|
}
|
|
|
|
delete[] stateArray;
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039c60
|
|
// FUNCTION: BETA10 0x10084329
|
|
MxResult LegoGameState::Load(MxULong p_slot)
|
|
{
|
|
Extension<MultiplayerExt>::Call(MP::HandleBeforeSaveLoad);
|
|
|
|
MxResult result = FAILURE;
|
|
LegoFile storage;
|
|
MxVariableTable* variableTable = VariableTable();
|
|
|
|
MxString savePath;
|
|
GetFileSavePath(&savePath, p_slot);
|
|
|
|
if (storage.Open(savePath.GetData(), LegoFile::c_read) == FAILURE) {
|
|
goto done;
|
|
}
|
|
|
|
MxS32 version;
|
|
MxU32 status;
|
|
MxS16 count, actArea;
|
|
const char* lightPosition;
|
|
|
|
storage.ReadS32(version);
|
|
|
|
assert(version == 0x1000c);
|
|
if (version != 0x1000c) {
|
|
OmniError("Saved game version mismatch", 0);
|
|
goto done;
|
|
}
|
|
|
|
storage.ReadS16(m_currentPlayerId);
|
|
storage.ReadS16(actArea);
|
|
|
|
SetCurrentAct((Act) actArea);
|
|
storage.ReadU8(m_actorId);
|
|
if (m_actorId) {
|
|
SetActor(m_actorId);
|
|
}
|
|
|
|
do {
|
|
status = ReadVariable(&storage, variableTable);
|
|
if (status == 1) {
|
|
goto done;
|
|
}
|
|
} while (status != 2);
|
|
|
|
m_backgroundColor->SetLightColor();
|
|
lightPosition = VariableTable()->GetVariable("lightposition");
|
|
|
|
if (lightPosition) {
|
|
SetLightPosition(atoi(lightPosition));
|
|
}
|
|
|
|
if (CharacterManager()->Read(&storage) == FAILURE) {
|
|
goto done;
|
|
}
|
|
if (PlantManager()->Read(&storage) == FAILURE) {
|
|
goto done;
|
|
}
|
|
if (BuildingManager()->Read(&storage) == FAILURE) {
|
|
goto done;
|
|
}
|
|
if (DeleteState() != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
char stateName[80];
|
|
storage.ReadS16(count);
|
|
|
|
if (count) {
|
|
for (MxS16 i = 0; i < count; i++) {
|
|
storage.ReadString(stateName);
|
|
|
|
LegoState* state = GetState(stateName);
|
|
if (!state) {
|
|
state = CreateState(stateName);
|
|
|
|
if (!state) {
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
state->Serialize(&storage);
|
|
}
|
|
}
|
|
|
|
storage.ReadS16(actArea);
|
|
|
|
if (m_currentAct == e_act1) {
|
|
m_savedPreviousArea = e_undefined;
|
|
}
|
|
else {
|
|
m_savedPreviousArea = (Area) actArea;
|
|
}
|
|
|
|
result = SUCCESS;
|
|
m_isDirty = FALSE;
|
|
|
|
Extension<MultiplayerExt>::Call(MP::HandleSaveLoaded);
|
|
|
|
done:
|
|
if (result != SUCCESS) {
|
|
OmniError("Game state loading was not successful!", 0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039f00
|
|
void LegoGameState::SetSavePath(char* p_savePath)
|
|
{
|
|
if (m_savePath != NULL) {
|
|
delete[] m_savePath;
|
|
}
|
|
|
|
if (p_savePath) {
|
|
m_savePath = new char[strlen(p_savePath) + 1];
|
|
strcpy(m_savePath, p_savePath);
|
|
}
|
|
else {
|
|
m_savePath = NULL;
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10039f70
|
|
// FUNCTION: BETA10 0x1008483b
|
|
MxResult LegoGameState::WriteVariable(LegoStorage* p_storage, MxVariableTable* p_from, const char* p_variableName)
|
|
{
|
|
MxResult result = FAILURE;
|
|
const char* variableValue = p_from->GetVariable(p_variableName);
|
|
|
|
if (variableValue) {
|
|
MxU8 length = strlen(p_variableName);
|
|
if (p_storage->Write(&length, sizeof(length)) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
if (p_storage->Write(p_variableName, length) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
length = strlen(variableValue);
|
|
if (p_storage->Write(&length, sizeof(length)) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
result = p_storage->Write(variableValue, length);
|
|
}
|
|
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a020
|
|
// FUNCTION: BETA10 0x10084928
|
|
MxResult LegoGameState::WriteEndOfVariables(LegoStorage* p_storage)
|
|
{
|
|
MxU8 len = strlen(g_endOfVariables);
|
|
|
|
if (p_storage->Write(&len, sizeof(len)) == SUCCESS) {
|
|
return p_storage->Write(g_endOfVariables, len);
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a080
|
|
// FUNCTION: BETA10 0x1008498b
|
|
MxS32 LegoGameState::ReadVariable(LegoStorage* p_storage, MxVariableTable* p_to)
|
|
{
|
|
MxS32 result = 1;
|
|
MxU8 len;
|
|
|
|
if (p_storage->Read(&len, sizeof(MxU8)) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
char varName[256];
|
|
assert(len < sizeof(varName));
|
|
|
|
if (p_storage->Read(varName, len) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
varName[len] = '\0';
|
|
if (strcmp(varName, g_endOfVariables) == 0) {
|
|
// 2 -> "This was the last entry, done reading."
|
|
result = 2;
|
|
goto done;
|
|
}
|
|
|
|
if (p_storage->Read(&len, sizeof(MxU8)) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
char value[256];
|
|
assert(len < sizeof(value));
|
|
|
|
if (p_storage->Read(value, len) != SUCCESS) {
|
|
goto done;
|
|
}
|
|
|
|
value[len] = '\0';
|
|
p_to->SetVariable(varName, value);
|
|
result = SUCCESS;
|
|
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a170
|
|
// FUNCTION: BETA10 0x10084b45
|
|
void LegoGameState::GetFileSavePath(MxString* p_outPath, MxS16 p_slotn)
|
|
{
|
|
char baseForSlot[2] = "0";
|
|
char path[1024] = "";
|
|
|
|
// Save path base
|
|
if (m_savePath != NULL) {
|
|
strcpy(path, m_savePath);
|
|
}
|
|
|
|
// Slot: "G0", "G1", ...
|
|
strcat(path, "\\G");
|
|
baseForSlot[0] += p_slotn;
|
|
strcat(path, baseForSlot);
|
|
|
|
// Extension: ".GS"
|
|
strcat(path, g_fileExtensionGS);
|
|
*p_outPath = MxString(path);
|
|
p_outPath->MapPathToFilesystem();
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a2e0
|
|
void LegoGameState::SerializePlayersInfo(MxS16 p_flags)
|
|
{
|
|
LegoFile storage;
|
|
MxString playersGSI = MxString(m_savePath);
|
|
|
|
playersGSI += "\\";
|
|
playersGSI += g_playersGSI;
|
|
|
|
if (storage.Open(playersGSI.GetData(), p_flags) == SUCCESS) {
|
|
if (storage.IsReadMode()) {
|
|
storage.ReadS16(m_playerCount);
|
|
}
|
|
else if (storage.IsWriteMode()) {
|
|
storage.WriteS16(m_playerCount);
|
|
}
|
|
|
|
for (MxS16 i = 0; i < m_playerCount; i++) {
|
|
m_players[i].Serialize(&storage);
|
|
}
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a3f0
|
|
MxResult LegoGameState::AddPlayer(Username& p_player)
|
|
{
|
|
MxString from, to;
|
|
|
|
if (m_playerCount == 9) {
|
|
GetFileSavePath(&from, 8);
|
|
SDL_RemovePath(from.GetData());
|
|
m_playerCount--;
|
|
}
|
|
|
|
for (MxS16 i = m_playerCount; i > 0; i--) {
|
|
m_players[i] = m_players[i - 1];
|
|
GetFileSavePath(&from, i - 1);
|
|
GetFileSavePath(&to, i);
|
|
SDL_RenamePath(from.GetData(), to.GetData());
|
|
}
|
|
|
|
m_playerCount++;
|
|
m_players[0].Set(p_player);
|
|
m_currentPlayerId = m_history.m_nextPlayerId;
|
|
m_history.m_nextPlayerId = m_currentPlayerId + 1;
|
|
m_history.WriteScoreHistory();
|
|
SetCurrentAct(e_act1);
|
|
|
|
return DeleteState();
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a540
|
|
// FUNCTION: BETA10 0x10084fc4
|
|
void LegoGameState::SwitchPlayer(MxS16 p_playerId)
|
|
{
|
|
if (p_playerId > 0) {
|
|
MxString from, temp, to;
|
|
|
|
GetFileSavePath(&from, p_playerId);
|
|
GetFileSavePath(&temp, 36);
|
|
|
|
Username selectedName(m_players[p_playerId]);
|
|
|
|
SDL_RenamePath(from.GetData(), temp.GetData());
|
|
|
|
for (MxS16 i = p_playerId; i > 0; i--) {
|
|
m_players[i] = m_players[i - 1];
|
|
GetFileSavePath(&from, i - 1);
|
|
GetFileSavePath(&to, i);
|
|
SDL_RenamePath(from.GetData(), to.GetData());
|
|
}
|
|
|
|
m_players[0] = selectedName;
|
|
GetFileSavePath(&from, 0);
|
|
SDL_RenamePath(temp.GetData(), from.GetData());
|
|
}
|
|
|
|
if (Load(0) != SUCCESS) {
|
|
Init();
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a6e0
|
|
MxS16 LegoGameState::FindPlayer(Username& p_player)
|
|
{
|
|
for (MxS16 i = 0; i < m_playerCount; i++) {
|
|
if (memcmp(&m_players[i], &p_player, sizeof(p_player)) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003a720
|
|
// FUNCTION: BETA10 0x10085211
|
|
void LegoGameState::StopArea(Area p_area)
|
|
{
|
|
if (p_area == e_previousArea) {
|
|
p_area = m_previousArea;
|
|
}
|
|
|
|
switch (p_area) {
|
|
case e_isle:
|
|
InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c__Isle, NULL);
|
|
InvokeAction(Extra::e_close, *g_isleScript, IsleScript::c__Isle, NULL);
|
|
InvokeAction(Extra::e_close, *g_sndAnimScript, SndanimScript::c_SoundAndAnim_Action, NULL);
|
|
break;
|
|
case e_infomain:
|
|
InvokeAction(Extra::e_stop, *g_infomainScript, InfomainScript::c__InfoMain, NULL);
|
|
InvokeAction(Extra::e_close, *g_infomainScript, InfomainScript::c__InfoMain, NULL);
|
|
break;
|
|
case e_infodoor:
|
|
InvokeAction(Extra::e_stop, *g_infodoorScript, InfodoorScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_infodoorScript, InfodoorScript::c__StartUp, NULL);
|
|
break;
|
|
case e_elevbott:
|
|
InvokeAction(Extra::e_stop, *g_elevbottScript, ElevbottScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_elevbottScript, ElevbottScript::c__StartUp, NULL);
|
|
break;
|
|
case e_elevride:
|
|
case e_elevride2:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Info_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Two_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Three_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter1_3_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter2_3_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_1_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_2_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter2_1_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter1_2_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_elevopen:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_seaview:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_observe:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Plane_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Sun_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Moon_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_SkyColor_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_LCab_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_RCab_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_GlobeRArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_GlobeLArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe1_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe2_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe3_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe4_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe5_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe6_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Draw1_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Draw2_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_Radio_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_elevdown:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_Elevator_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_regbook:
|
|
InvokeAction(Extra::e_stop, *g_regbookScript, RegbookScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_regbookScript, RegbookScript::c__StartUp, NULL);
|
|
break;
|
|
case e_infoscor:
|
|
InvokeAction(Extra::e_stop, *g_infoscorScript, InfoscorScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_infoscorScript, InfoscorScript::c__StartUp, NULL);
|
|
break;
|
|
case e_jetrace:
|
|
InvokeAction(Extra::e_stop, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL);
|
|
InvokeAction(Extra::e_close, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL);
|
|
InvokeAction(Extra::e_close, *g_jetracerScript, 0, NULL);
|
|
break;
|
|
case e_carrace:
|
|
InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c__CarRace_World, NULL);
|
|
InvokeAction(Extra::e_close, *g_carraceScript, CarraceScript::c__CarRace_World, NULL);
|
|
InvokeAction(Extra::e_close, *g_carracerScript, CarracerScript::c_nrt002pz_Anim, NULL);
|
|
break;
|
|
case e_garage:
|
|
Lego()->RemoveWorld(*g_garageScript, 0);
|
|
InvokeAction(Extra::e_stop, *g_garageScript, GarageScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_garageScript, GarageScript::c__StartUp, NULL);
|
|
break;
|
|
case e_garadoor:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_Door_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_hospital:
|
|
InvokeAction(Extra::e_stop, *g_hospitalScript, HospitalScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_hospitalScript, HospitalScript::c__StartUp, NULL);
|
|
break;
|
|
case e_police:
|
|
InvokeAction(Extra::e_stop, *g_policeScript, PoliceScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_policeScript, PoliceScript::c__StartUp, NULL);
|
|
break;
|
|
case e_polidoor:
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_Background_Bitmap, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_LeftArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_RightArrow_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_Door_Ctl, *g_isleScript, IsleScript::c__Isle);
|
|
break;
|
|
case e_copterbuild:
|
|
InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_HelicopterBuild_Movie, NULL);
|
|
InvokeAction(Extra::e_stop, *g_copterScript, CopterScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_copterScript, CopterScript::c__StartUp, NULL);
|
|
break;
|
|
case e_dunecarbuild:
|
|
InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_DuneCarBuild_Movie, NULL);
|
|
InvokeAction(Extra::e_stop, *g_dunecarScript, DunecarScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_dunecarScript, DunecarScript::c__StartUp, NULL);
|
|
break;
|
|
case e_jetskibuild:
|
|
InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_JetskiBuild_Movie, NULL);
|
|
InvokeAction(Extra::e_stop, *g_jetskiScript, JetskiScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_jetskiScript, JetskiScript::c__StartUp, NULL);
|
|
break;
|
|
case e_racecarbuild:
|
|
InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_RaceCarBuild_Movie, NULL);
|
|
InvokeAction(Extra::e_stop, *g_racecarScript, RacecarScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_racecarScript, RacecarScript::c__StartUp, NULL);
|
|
break;
|
|
case e_act2main:
|
|
if (m_currentArea != e_infomain) {
|
|
InvokeAction(Extra::e_stop, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL);
|
|
InvokeAction(Extra::e_close, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL);
|
|
}
|
|
break;
|
|
case e_act3script:
|
|
if (m_currentArea != e_infomain) {
|
|
InvokeAction(Extra::e_stop, *g_act3Script, Act3Script::c__Act3, NULL);
|
|
InvokeAction(Extra::e_close, *g_act3Script, Act3Script::c__Act3, NULL);
|
|
}
|
|
break;
|
|
case e_jukeboxw:
|
|
InvokeAction(Extra::e_stop, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL);
|
|
break;
|
|
case e_histbook:
|
|
InvokeAction(Extra::e_disable, *g_histbookScript, HistbookScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_stop, *g_histbookScript, HistbookScript::c__StartUp, NULL);
|
|
InvokeAction(Extra::e_close, *g_histbookScript, HistbookScript::c__StartUp, NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline void LoadIsle()
|
|
{
|
|
LegoWorld* world = FindWorld(*g_isleScript, IsleScript::c__Isle);
|
|
if (world != NULL) {
|
|
if (!world->NoDisabledObjects()) {
|
|
NotificationManager()->Send(world, MxNotificationParam(c_notificationType20, NULL));
|
|
}
|
|
}
|
|
else {
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_isleScript, IsleScript::c__Isle, NULL);
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003b060
|
|
// FUNCTION: BETA10 0x10085adf
|
|
void LegoGameState::SwitchArea(Area p_area)
|
|
{
|
|
m_previousArea = m_currentArea;
|
|
m_currentArea = p_area;
|
|
|
|
Disable(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d);
|
|
BackgroundAudioManager()->Stop();
|
|
AnimationManager()->Suspend();
|
|
VideoManager()->SetUnk0x554(FALSE);
|
|
|
|
switch (p_area) {
|
|
case e_isle:
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_isleScript, IsleScript::c__Isle, NULL);
|
|
break;
|
|
case e_infomain:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_infomainScript, InfomainScript::c__InfoMain, NULL);
|
|
break;
|
|
case e_infodoor:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_infodoorScript, InfodoorScript::c__StartUp, NULL);
|
|
break;
|
|
case e_infocenterExited:
|
|
case e_jetraceFinished:
|
|
case e_jetraceExterior:
|
|
case e_jetskibuildExited:
|
|
case e_carraceExterior:
|
|
case e_racecarbuildExited:
|
|
case e_carraceFinished:
|
|
case e_pizzeriaExterior:
|
|
case e_garageExterior:
|
|
case e_hospitalExterior:
|
|
case e_hospitalExited:
|
|
case e_policeExterior:
|
|
case e_bike:
|
|
case e_dunecar:
|
|
case e_motocycle:
|
|
case e_copter:
|
|
case e_skateboard:
|
|
case e_jetski:
|
|
case e_vehicleExited:
|
|
LoadIsle();
|
|
break;
|
|
case e_elevbott:
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_elevbottScript, ElevbottScript::c__StartUp, NULL);
|
|
break;
|
|
case e_elevride:
|
|
case e_elevride2:
|
|
LoadIsle();
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevRide, NULL);
|
|
break;
|
|
case e_elevopen:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevOpen, NULL);
|
|
break;
|
|
case e_seaview:
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_SeaView, NULL);
|
|
break;
|
|
case e_observe:
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_Observe, NULL);
|
|
break;
|
|
case e_elevdown:
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevDown, NULL);
|
|
break;
|
|
case e_regbook:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_regbookScript, RegbookScript::c__StartUp, NULL);
|
|
break;
|
|
case e_infoscor:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_infoscorScript, InfoscorScript::c__StartUp, NULL);
|
|
break;
|
|
case e_jetrace:
|
|
if (m_previousArea == e_infomain) {
|
|
m_currentArea = e_jetraceFinished;
|
|
LoadIsle();
|
|
}
|
|
else {
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL);
|
|
}
|
|
break;
|
|
case e_carrace:
|
|
if (m_previousArea == e_infomain) {
|
|
m_currentArea = e_carraceExterior;
|
|
LoadIsle();
|
|
}
|
|
else {
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_carraceScript, CarraceScript::c__CarRace_World, NULL);
|
|
}
|
|
break;
|
|
case e_garage:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_garageScript, GarageScript::c__StartUp, NULL);
|
|
break;
|
|
case e_garadoor:
|
|
LoadIsle();
|
|
VariableTable()->SetVariable("VISIBILITY", "Hide Gas");
|
|
UserActor()->ResetWorldTransform(FALSE);
|
|
NavController()->UpdateLocation(59); // LCAMZG1 in g_cameraLocations
|
|
VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f);
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_GaraDoor, NULL);
|
|
break;
|
|
case e_garageExited: {
|
|
Act1State* state = (Act1State*) GameState()->GetState("Act1State");
|
|
LoadIsle();
|
|
|
|
if (state->GetState() == Act1State::e_transitionToTowtrack) {
|
|
VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f);
|
|
}
|
|
else {
|
|
SetCameraControllerFromIsle();
|
|
UserActor()->ResetWorldTransform(TRUE);
|
|
AnimationManager()->Resume();
|
|
}
|
|
|
|
((IslePathActor*) UserActor())
|
|
->SpawnPlayer(
|
|
p_area,
|
|
TRUE,
|
|
IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3
|
|
);
|
|
break;
|
|
}
|
|
case e_hospital:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_hospitalScript, HospitalScript::c__StartUp, NULL);
|
|
break;
|
|
case e_policeExited:
|
|
LoadIsle();
|
|
SetCameraControllerFromIsle();
|
|
UserActor()->ResetWorldTransform(TRUE);
|
|
AnimationManager()->Resume();
|
|
((IslePathActor*) UserActor())
|
|
->SpawnPlayer(
|
|
p_area,
|
|
TRUE,
|
|
IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3
|
|
);
|
|
break;
|
|
case e_police:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_policeScript, PoliceScript::c__StartUp, NULL);
|
|
break;
|
|
case e_polidoor:
|
|
LoadIsle();
|
|
InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_PoliDoor, NULL);
|
|
break;
|
|
case e_copterbuild:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_copterScript, CopterScript::c__StartUp, NULL);
|
|
break;
|
|
case e_dunecarbuild:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_dunecarScript, DunecarScript::c__StartUp, NULL);
|
|
break;
|
|
case e_jetskibuild:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_jetskiScript, JetskiScript::c__StartUp, NULL);
|
|
break;
|
|
case e_racecarbuild:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_racecarScript, RacecarScript::c__StartUp, NULL);
|
|
break;
|
|
case e_act2main: {
|
|
LegoWorld* act2main = FindWorld(*g_act2mainScript, Act2mainScript::c__Act2Main);
|
|
|
|
if (act2main == NULL) {
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL);
|
|
}
|
|
else {
|
|
act2main->Enable(TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case e_act3script: {
|
|
LegoWorld* act3 = FindWorld(*g_act3Script, Act3Script::c__Act3);
|
|
|
|
if (act3 == NULL) {
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_act3Script, Act3Script::c__Act3, NULL);
|
|
}
|
|
else {
|
|
act3->Enable(TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case e_jukeboxw:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL);
|
|
break;
|
|
case e_jukeboxExterior:
|
|
LoadIsle();
|
|
break;
|
|
case e_histbook:
|
|
VideoManager()->SetUnk0x554(TRUE);
|
|
InvokeAction(Extra::ActionType::e_opendisk, *g_histbookScript, HistbookScript::c__StartUp, NULL);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003ba90
|
|
void LegoGameState::SetColors()
|
|
{
|
|
MxVariableTable* variableTable = VariableTable();
|
|
|
|
for (MxS32 i = 0; i < sizeOfArray(g_colorSaveData); i++) {
|
|
variableTable->SetVariable(g_colorSaveData[i].m_targetName, g_colorSaveData[i].m_colorName);
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bac0
|
|
void LegoGameState::SetROIColorOverride()
|
|
{
|
|
LegoROI::SetColorOverride(&ROIColorOverride);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bad0
|
|
MxBool ROIColorOverride(const char* p_input, char* p_output, MxU32 p_copyLen)
|
|
{
|
|
if (p_output != NULL && p_copyLen != 0 &&
|
|
(SDL_strncasecmp(p_input, "INDIR-F-", strlen("INDIR-F-")) == 0 ||
|
|
SDL_strncasecmp(p_input, "INDIR-G-", strlen("INDIR-F-")) == 0)) {
|
|
|
|
char buf[256];
|
|
sprintf(buf, "c_%s", &p_input[strlen("INDIR-F-")]);
|
|
|
|
const char* value = VariableTable()->GetVariable(buf);
|
|
if (value != NULL) {
|
|
strncpy(p_output, value, p_copyLen);
|
|
p_output[p_copyLen - 1] = '\0';
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bbb0
|
|
// FUNCTION: BETA10 0x10086280
|
|
LegoState* LegoGameState::GetState(const char* p_stateName)
|
|
{
|
|
for (MxS32 i = 0; i < m_stateCount; ++i) {
|
|
if (m_stateArray[i]->IsA(p_stateName)) {
|
|
return m_stateArray[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bc00
|
|
// FUNCTION: BETA10 0x100862fc
|
|
LegoState* LegoGameState::CreateState(const char* p_stateName)
|
|
{
|
|
// variable name verified by BETA10 0x10086341
|
|
LegoState* state = (LegoState*) ObjectFactory()->Create(p_stateName);
|
|
assert(state);
|
|
|
|
RegisterState(state);
|
|
|
|
return state;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bc30
|
|
// FUNCTION: BETA10 0x1008636e
|
|
void LegoGameState::RegisterState(LegoState* p_state)
|
|
{
|
|
MxS32 targetIndex;
|
|
for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex) {
|
|
if (m_stateArray[targetIndex]->IsA(p_state->ClassName())) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (targetIndex == m_stateCount) {
|
|
LegoState** newBuffer = new LegoState*[m_stateCount + 1];
|
|
|
|
if (m_stateCount != 0) {
|
|
memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*));
|
|
delete[] m_stateArray;
|
|
}
|
|
|
|
newBuffer[m_stateCount++] = p_state;
|
|
m_stateArray = newBuffer;
|
|
}
|
|
else {
|
|
delete m_stateArray[targetIndex];
|
|
m_stateArray[targetIndex] = p_state;
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bd00
|
|
void LegoGameState::Init()
|
|
{
|
|
m_backgroundColor->SetValue("set 56 54 68");
|
|
m_backgroundColor->SetLightColor();
|
|
m_tempBackgroundColor->SetValue("set 56 54 68");
|
|
VariableTable()->SetVariable("lightposition", "2");
|
|
SetLightPosition(2);
|
|
PlantManager()->Init();
|
|
BuildingManager()->Init();
|
|
CharacterManager()->Init();
|
|
AnimationManager()->Reset(TRUE);
|
|
SetColors();
|
|
RemoveActor();
|
|
DeleteState();
|
|
m_isDirty = FALSE;
|
|
FindLoadedAct();
|
|
SetCurrentAct(e_act1);
|
|
|
|
if (m_loadedAct == e_act1) {
|
|
Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle);
|
|
|
|
Helicopter* copter = (Helicopter*) isle->Find(*g_copterScript, CopterScript::c_Helicopter_Actor);
|
|
if (copter) {
|
|
isle->RemoveActor(copter);
|
|
isle->RemoveVehicle(copter);
|
|
delete copter;
|
|
}
|
|
|
|
DuneBuggy* dunebuggy = (DuneBuggy*) isle->Find(*g_dunecarScript, DunecarScript::c_DuneBugy_Actor);
|
|
if (dunebuggy) {
|
|
isle->RemoveActor(dunebuggy);
|
|
isle->RemoveVehicle(dunebuggy);
|
|
delete dunebuggy;
|
|
}
|
|
|
|
Jetski* jetski = (Jetski*) isle->Find(*g_jetskiScript, JetskiScript::c_Jetski_Actor);
|
|
if (jetski) {
|
|
isle->RemoveActor(jetski);
|
|
isle->RemoveVehicle(jetski);
|
|
delete jetski;
|
|
}
|
|
|
|
RaceCar* racecar = (RaceCar*) isle->Find(*g_racecarScript, RacecarScript::c_RaceCar_Actor);
|
|
if (racecar) {
|
|
isle->RemoveActor(racecar);
|
|
isle->RemoveVehicle(racecar);
|
|
delete racecar;
|
|
}
|
|
}
|
|
|
|
m_savedPreviousArea = e_undefined;
|
|
}
|
|
|
|
// FUNCTION: BETA10 0x10086510
|
|
LegoBackgroundColor::LegoBackgroundColor()
|
|
{
|
|
m_h = 0.0f;
|
|
m_s = 0.0f;
|
|
m_v = 0.0f;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003bfb0
|
|
// FUNCTION: BETA10 0x1008659d
|
|
LegoBackgroundColor::LegoBackgroundColor(const char* p_key, const char* p_value)
|
|
{
|
|
m_key = p_key;
|
|
m_key.ToUpperCase();
|
|
SetValue(p_value);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c070
|
|
// FUNCTION: BETA10 0x10086634
|
|
void LegoBackgroundColor::SetValue(const char* p_colorString)
|
|
{
|
|
m_value = p_colorString;
|
|
m_value.ToLowerCase();
|
|
|
|
LegoVideoManager* videomanager = VideoManager();
|
|
if (!videomanager || !p_colorString) {
|
|
return;
|
|
}
|
|
|
|
float convertedR, convertedG, convertedB;
|
|
char* colorStringCopy = strcpy(new char[strlen(p_colorString) + 1], p_colorString);
|
|
char* colorStringSplit = strtok(colorStringCopy, g_delimiter);
|
|
|
|
if (!strcmp(colorStringSplit, g_set)) {
|
|
colorStringSplit = strtok(0, g_delimiter);
|
|
if (colorStringSplit) {
|
|
m_h = (float) (atoi(colorStringSplit) * 0.01);
|
|
}
|
|
colorStringSplit = strtok(0, g_delimiter);
|
|
if (colorStringSplit) {
|
|
m_s = (float) (atoi(colorStringSplit) * 0.01);
|
|
}
|
|
colorStringSplit = strtok(0, g_delimiter);
|
|
if (colorStringSplit) {
|
|
m_v = (float) (atoi(colorStringSplit) * 0.01);
|
|
}
|
|
|
|
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
|
|
videomanager->SetSkyColor(convertedR, convertedG, convertedB);
|
|
}
|
|
else if (!strcmp(colorStringSplit, g_reset)) {
|
|
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
|
|
videomanager->SetSkyColor(convertedR, convertedG, convertedB);
|
|
}
|
|
|
|
delete[] colorStringCopy;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c230
|
|
// FUNCTION: BETA10 0x100867f9
|
|
void LegoBackgroundColor::ToggleDayNight(MxBool p_sun)
|
|
{
|
|
char buffer[30];
|
|
|
|
if (p_sun) {
|
|
m_s += 0.1;
|
|
if (m_s > 0.9) {
|
|
m_s = 1.0;
|
|
}
|
|
}
|
|
else {
|
|
m_s -= 0.1;
|
|
if (m_s < 0.1) {
|
|
m_s = 0.1;
|
|
}
|
|
}
|
|
|
|
sprintf(buffer, "set %d %d %d", (MxU32) (m_h * 100.0f), (MxU32) (m_s * 100.0f), (MxU32) (m_v * 100.0f));
|
|
m_value = buffer;
|
|
|
|
float convertedR, convertedG, convertedB;
|
|
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
|
|
VideoManager()->SetSkyColor(convertedR, convertedG, convertedB);
|
|
SetLightColor(convertedR, convertedG, convertedB);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c330
|
|
// FUNCTION: BETA10 0x100868de
|
|
void LegoBackgroundColor::ToggleSkyColor()
|
|
{
|
|
char buffer[30];
|
|
|
|
m_h += 0.05;
|
|
if (m_h > 1.0) {
|
|
m_h -= 1.0;
|
|
}
|
|
|
|
sprintf(buffer, "set %d %d %d", (MxU32) (m_h * 100.0f), (MxU32) (m_s * 100.0f), (MxU32) (m_v * 100.0f));
|
|
m_value = buffer;
|
|
|
|
float convertedR, convertedG, convertedB;
|
|
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
|
|
VideoManager()->SetSkyColor(convertedR, convertedG, convertedB);
|
|
SetLightColor(convertedR, convertedG, convertedB);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c400
|
|
// FUNCTION: BETA10 0x10086984
|
|
void LegoBackgroundColor::SetLightColor(float p_r, float p_g, float p_b)
|
|
{
|
|
if (!VideoManager()->GetVideoParam().Flags().GetLacksLightSupport()) {
|
|
// TODO: Computed constants based on what?
|
|
p_r *= 1. / 0.23;
|
|
p_g *= 1. / 0.63;
|
|
p_b *= 1. / 0.85;
|
|
|
|
if (p_r > 1.0) {
|
|
p_r = 1.0;
|
|
}
|
|
|
|
if (p_g > 1.0) {
|
|
p_g = 1.0;
|
|
}
|
|
|
|
if (p_b > 1.0) {
|
|
p_b = 1.0;
|
|
}
|
|
|
|
VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(FALSE, p_r, p_g, p_b);
|
|
VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(TRUE, p_r, p_g, p_b);
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c4b0
|
|
void LegoBackgroundColor::SetLightColor()
|
|
{
|
|
float convertedR, convertedG, convertedB;
|
|
ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB);
|
|
SetLightColor(convertedR, convertedG, convertedB);
|
|
}
|
|
|
|
// FUNCTION: BETA10 0x10086a87
|
|
LegoFullScreenMovie::LegoFullScreenMovie()
|
|
{
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c500
|
|
// FUNCTION: BETA10 0x10086af6
|
|
LegoFullScreenMovie::LegoFullScreenMovie(const char* p_key, const char* p_value)
|
|
{
|
|
m_key = p_key;
|
|
m_key.ToUpperCase();
|
|
SetValue(p_value);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c5c0
|
|
// FUNCTION: BETA10 0x10086b8d
|
|
void LegoFullScreenMovie::SetValue(const char* p_option)
|
|
{
|
|
m_value = p_option;
|
|
m_value.ToLowerCase();
|
|
|
|
LegoVideoManager* videomanager = VideoManager();
|
|
if (videomanager) {
|
|
if (!strcmp(m_value.GetData(), g_strEnable)) {
|
|
videomanager->EnableFullScreenMovie(TRUE);
|
|
}
|
|
else if (!strcmp(m_value.GetData(), g_strDisable)) {
|
|
videomanager->EnableFullScreenMovie(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c670
|
|
LegoGameState::Username::Username()
|
|
{
|
|
memset(m_letters, -1, sizeof(m_letters));
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c690
|
|
// FUNCTION: BETA10 0x10086c57
|
|
MxResult LegoGameState::Username::Serialize(LegoStorage* p_storage)
|
|
{
|
|
if (p_storage->IsReadMode()) {
|
|
for (MxS16 i = 0; i < (MxS16) sizeOfArray(m_letters); i++) {
|
|
p_storage->ReadS16(m_letters[i]);
|
|
}
|
|
}
|
|
else if (p_storage->IsWriteMode()) {
|
|
for (MxS16 i = 0; i < (MxS16) sizeOfArray(m_letters); i++) {
|
|
p_storage->WriteS16(m_letters[i]);
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c710
|
|
// FUNCTION: BETA10 0x10086d0c
|
|
LegoGameState::Username& LegoGameState::Username::operator=(const Username& p_other)
|
|
{
|
|
memcpy(m_letters, p_other.m_letters, sizeof(m_letters));
|
|
return *this;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c740
|
|
// FUNCTION: BETA10 0x10086d39
|
|
MxResult LegoGameState::ScoreItem::Serialize(LegoStorage* p_storage)
|
|
{
|
|
if (p_storage->IsReadMode()) {
|
|
p_storage->ReadS16(m_totalScore);
|
|
|
|
for (MxS32 i = 0; i < 5; i++) {
|
|
for (MxS32 j = 0; j < 5; j++) {
|
|
p_storage->ReadU8(m_scores[i][j]);
|
|
}
|
|
}
|
|
|
|
m_name.Serialize(p_storage);
|
|
p_storage->ReadS16(m_playerId);
|
|
}
|
|
else if (p_storage->IsWriteMode()) {
|
|
p_storage->WriteS16(m_totalScore);
|
|
|
|
for (MxS32 i = 0; i < 5; i++) {
|
|
for (MxS32 j = 0; j < 5; j++) {
|
|
p_storage->WriteU8(m_scores[i][j]);
|
|
}
|
|
}
|
|
|
|
m_name.Serialize(p_storage);
|
|
p_storage->WriteS16(m_playerId);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c830
|
|
// FUNCTION: BETA10 0x10086e87
|
|
LegoGameState::History::History()
|
|
{
|
|
m_count = 0;
|
|
m_nextPlayerId = 0;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003c870
|
|
// FUNCTION: BETA10 0x10086ec9
|
|
void LegoGameState::History::WriteScoreHistory()
|
|
{
|
|
MxS16 totalScore = 0;
|
|
MxU8 scores[5][5];
|
|
|
|
InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState");
|
|
|
|
if (!state->m_letters[0]) {
|
|
return;
|
|
}
|
|
|
|
JetskiRaceState* jetskiRaceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState");
|
|
CarRaceState* carRaceState = (CarRaceState*) GameState()->GetState("CarRaceState");
|
|
TowTrackMissionState* towTrackMissionState = (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState");
|
|
PizzaMissionState* pizzaMissionState = (PizzaMissionState*) GameState()->GetState("PizzaMissionState");
|
|
AmbulanceMissionState* ambulanceMissionState =
|
|
(AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState");
|
|
|
|
for (MxS32 actor = 1; actor <= 5; actor++) {
|
|
scores[0][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0;
|
|
totalScore += scores[0][actor - 1];
|
|
|
|
#ifdef BETA10
|
|
// likely a bug in BETA10
|
|
scores[1][actor - 1] = carRaceState ? carRaceState->GetState(actor)->GetHighScore() : 0;
|
|
#else
|
|
scores[1][actor - 1] = jetskiRaceState ? jetskiRaceState->GetState(actor)->GetHighScore() : 0;
|
|
#endif
|
|
totalScore += scores[1][actor - 1];
|
|
|
|
scores[2][actor - 1] = pizzaMissionState ? pizzaMissionState->GetHighScore(actor) : 0;
|
|
totalScore += scores[2][actor - 1];
|
|
|
|
scores[3][actor - 1] = towTrackMissionState ? towTrackMissionState->GetHighScore(actor) : 0;
|
|
totalScore += scores[3][actor - 1];
|
|
|
|
scores[4][actor - 1] = ambulanceMissionState ? ambulanceMissionState->GetHighScore(actor) : 0;
|
|
totalScore += scores[4][actor - 1];
|
|
}
|
|
|
|
MxS32 playerScoreHistoryIndex;
|
|
ScoreItem* p_scorehist =
|
|
FindPlayerInScoreHistory(GameState()->m_players, GameState()->m_currentPlayerId, playerScoreHistoryIndex);
|
|
|
|
#ifdef BETA10
|
|
if (!p_scorehist) {
|
|
MxS32 playerScoreRank;
|
|
// LINE: BETA10 0x100870ee
|
|
for (playerScoreRank = 0; playerScoreRank < m_count; playerScoreRank++) {
|
|
if (totalScore > m_scores[m_indices[playerScoreRank]].m_totalScore) {
|
|
break;
|
|
}
|
|
}
|
|
// LINE: BETA10 0x1008713f
|
|
if (playerScoreRank < m_count) {
|
|
if (m_count < 20) {
|
|
playerScoreHistoryIndex = m_count++;
|
|
}
|
|
else {
|
|
playerScoreHistoryIndex = m_indices[19];
|
|
}
|
|
|
|
MxS32 max = m_count - 1;
|
|
for (MxS32 j = max; playerScoreRank < j; j--) {
|
|
m_indices[j - 1] = m_indices[j - 2];
|
|
}
|
|
|
|
m_indices[playerScoreRank] = playerScoreHistoryIndex;
|
|
p_scorehist = &m_scores[playerScoreHistoryIndex];
|
|
}
|
|
else if (playerScoreRank < 20) {
|
|
m_indices[m_count] = m_count;
|
|
p_scorehist = &m_scores[m_count++];
|
|
}
|
|
}
|
|
else if (p_scorehist->m_totalScore != totalScore) {
|
|
assert(totalScore > p_scorehist->m_totalScore);
|
|
|
|
for (MxS32 i = playerScoreHistoryIndex; i > 0 && m_indices[i - 1] < m_indices[i]; i--) {
|
|
MxU8 tmp = m_indices[i - 1];
|
|
m_indices[i - 1] = m_indices[i];
|
|
m_indices[i] = tmp;
|
|
}
|
|
}
|
|
if (p_scorehist) {
|
|
p_scorehist->m_totalScore = totalScore;
|
|
memcpy(p_scorehist->m_scores[0], scores[0], sizeof(scores));
|
|
p_scorehist->m_name = GameState()->m_players[0];
|
|
p_scorehist->m_playerId = GameState()->m_currentPlayerId;
|
|
}
|
|
#else
|
|
if (p_scorehist != NULL) {
|
|
p_scorehist->m_totalScore = totalScore;
|
|
memcpy(p_scorehist->m_scores, scores, sizeof(p_scorehist->m_scores));
|
|
}
|
|
else {
|
|
if (m_count < (MxS16) sizeOfArray(m_scores)) {
|
|
m_scores[m_count].m_totalScore = totalScore;
|
|
memcpy(m_scores[m_count].m_scores, scores, sizeof(m_scores[m_count].m_scores));
|
|
m_scores[m_count].m_name = GameState()->m_players[0];
|
|
m_scores[m_count].m_playerId = GameState()->m_currentPlayerId;
|
|
m_count++;
|
|
}
|
|
else if (m_scores[19].m_totalScore <= totalScore) {
|
|
m_scores[19].m_totalScore = totalScore;
|
|
memcpy(m_scores[19].m_scores, scores, sizeof(m_scores[19].m_scores));
|
|
m_scores[19].m_name = GameState()->m_players[0];
|
|
m_scores[19].m_playerId = GameState()->m_currentPlayerId;
|
|
}
|
|
}
|
|
|
|
ScoreItem tmpItem;
|
|
|
|
for (MxS32 i = m_count - 1; i >= 0; i--) {
|
|
for (MxS32 j = 1; j <= i; j++) {
|
|
if (m_scores[j].m_totalScore > m_scores[j - 1].m_totalScore) {
|
|
tmpItem = m_scores[j - 1];
|
|
m_scores[j - 1] = m_scores[j];
|
|
m_scores[j] = tmpItem;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003cc90
|
|
// FUNCTION: BETA10 0x1008732a
|
|
LegoGameState::ScoreItem* LegoGameState::History::FindPlayerInScoreHistory(
|
|
LegoGameState::Username* p_player,
|
|
MxS16 p_playerId,
|
|
MxS32& p_playerScoreHistoryIndex
|
|
)
|
|
{
|
|
MxS32 i = 0;
|
|
for (; i < m_count; i++) {
|
|
if (!memcmp(p_player, &m_scores[i].m_name, sizeof(*p_player)) && m_scores[i].m_playerId == p_playerId) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
p_playerScoreHistoryIndex = i;
|
|
|
|
if (i >= m_count) {
|
|
return NULL;
|
|
}
|
|
|
|
return &m_scores[i];
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003ccf0
|
|
// FUNCTION: BETA10 0x100873e7
|
|
MxResult LegoGameState::History::Serialize(LegoStorage* p_storage)
|
|
{
|
|
if (p_storage->IsReadMode()) {
|
|
p_storage->ReadS16(m_nextPlayerId);
|
|
p_storage->ReadS16(m_count);
|
|
|
|
for (MxS16 i = 0; i < m_count; i++) {
|
|
MxS16 j;
|
|
p_storage->ReadS16(j);
|
|
m_scores[i].Serialize(p_storage);
|
|
}
|
|
}
|
|
else if (p_storage->IsWriteMode()) {
|
|
p_storage->WriteS16(m_nextPlayerId);
|
|
p_storage->WriteS16(m_count);
|
|
|
|
for (MxS16 i = 0; i < m_count; i++) {
|
|
p_storage->WriteS16(i);
|
|
m_scores[i].Serialize(p_storage);
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003cdd0
|
|
void LegoGameState::SerializeScoreHistory(MxS16 p_flags)
|
|
{
|
|
LegoFile storage;
|
|
MxString savePath(m_savePath);
|
|
savePath += "\\";
|
|
savePath += g_historyGSI;
|
|
|
|
if (p_flags == LegoFile::c_write) {
|
|
m_history.WriteScoreHistory();
|
|
}
|
|
|
|
if (storage.Open(savePath.GetData(), p_flags) == SUCCESS) {
|
|
m_history.Serialize(&storage);
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003cea0
|
|
// FUNCTION: BETA10 0x10017840
|
|
void LegoGameState::SetCurrentAct(Act p_currentAct)
|
|
{
|
|
m_currentAct = p_currentAct;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x1003ceb0
|
|
void LegoGameState::FindLoadedAct()
|
|
{
|
|
if (FindWorld(*g_isleScript, IsleScript::c__Isle)) {
|
|
m_loadedAct = e_act1;
|
|
}
|
|
else if (FindWorld(*g_act2mainScript, Act2mainScript::c__Act2Main)) {
|
|
m_loadedAct = e_act2;
|
|
}
|
|
else if (FindWorld(*g_act3Script, Act3Script::c__Act3)) {
|
|
m_loadedAct = e_act3;
|
|
}
|
|
else {
|
|
m_loadedAct = e_actNotFound;
|
|
}
|
|
}
|