/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef LASTEXPRESS_STATE_H #define LASTEXPRESS_STATE_H #include "lastexpress/shared.h" #include "common/rect.h" #include "common/serializer.h" #include "common/system.h" #include "common/textconsole.h" namespace LastExpress { class LastExpressEngine; class Inventory; class Objects; class SavePoints; class State { public: struct GameProgress : public Common::Serializable { uint32 field_0; JacketType jacket; bool eventCorpseMovedFromFloor; uint32 field_C; bool eventCorpseFound; uint32 field_14; ///< EntityIndex (used in Gendarmes) uint32 field_18; uint32 portrait; bool eventCorpseThrown; uint32 field_24; uint32 field_28; ChapterIndex chapter; uint32 field_30; bool eventMetAugust; bool isNightTime; uint32 field_3C; uint32 field_40; uint32 field_44; uint32 field_48; uint32 field_4C; bool isTrainRunning; uint32 field_54; uint32 field_58; uint32 field_5C; uint32 field_60; uint32 field_64; uint32 field_68; bool eventMertensAugustWaiting; bool eventMertensKronosInvitation; bool isEggOpen; uint32 field_78; // time? uint32 field_7C; uint32 field_80; uint32 field_84; uint32 field_88; uint32 field_8C; uint32 field_90; uint32 field_94; uint32 field_98; uint32 field_9C; uint32 field_A0; uint32 field_A4; uint32 field_A8; uint32 field_AC; uint32 field_B0; uint32 field_B4; uint32 field_B8; uint32 field_BC; uint32 field_C0; uint32 field_C4; uint32 field_C8; uint32 field_CC; bool eventMetBoutarel; bool eventMetHadija; bool eventMetYasmin; uint32 field_DC; uint32 field_E0; uint32 field_E4; uint32 field_E8; uint32 field_EC; uint32 field_F0; uint32 field_F4; uint32 field_F8; uint32 field_FC; uint32 field_100; uint32 field_104; uint32 field_108; uint32 field_10C; uint32 field_110; uint32 field_114; uint32 field_118; uint32 field_11C; uint32 field_120; uint32 field_124; uint32 field_128; uint32 field_12C; uint32 field_130; uint32 field_134; uint32 field_138; uint32 field_13C; uint32 field_140; uint32 field_144; uint32 field_148; uint32 field_14C; uint32 field_150; uint32 field_154; uint32 field_158; uint32 field_15C; uint32 field_160; uint32 field_164; uint32 field_168; uint32 field_16C; uint32 field_170; uint32 field_174; uint32 field_178; uint32 field_17C; uint32 field_180; uint32 field_184; uint32 field_188; uint32 field_18C; uint32 field_190; uint32 field_194; uint32 field_198; uint32 field_19C; uint32 field_1A0; uint32 field_1A4; uint32 field_1A8; uint32 field_1AC; uint32 field_1B0; uint32 field_1B4; uint32 field_1B8; uint32 field_1BC; uint32 field_1C0; uint32 field_1C4; uint32 field_1C8; uint32 field_1CC; uint32 field_1D0; uint32 field_1D4; uint32 field_1D8; uint32 field_1DC; uint32 field_1E0; uint32 field_1E4; uint32 field_1E8; uint32 field_1EC; uint32 field_1F0; uint32 field_1F4; uint32 field_1F8; uint32 field_1FC; GameProgress() { field_0 = 0; jacket = kJacketOriginal; eventCorpseMovedFromFloor = false; field_C = 0; eventCorpseFound = false; field_14 = 0; // 5 field_18 = 0; portrait = _defaultPortrait; eventCorpseThrown = false; field_24 = 0; field_28 = 0; // 10 chapter = kChapter1; field_30 = 0; eventMetAugust = false; isNightTime = false; field_3C = 0; // 15 field_40 = 0; field_44 = 0; field_48 = 0; field_4C = 0; isTrainRunning = false; // 20 field_54 = 0; field_58 = 0; field_5C = 0; field_60 = 0; field_64 = 0; // 25 field_68 = 0; eventMertensAugustWaiting = false; eventMertensKronosInvitation = false; isEggOpen = false; field_78 = 0; // 30 field_7C = 0; field_80 = 0; field_84 = 0; field_88 = 0; field_8C = 0; // 35 field_90 = 0; field_94 = 0; field_98 = 0; field_9C = 0; field_A0 = 0; // 40 field_A4 = 0; field_A8 = 0; field_AC = 0; field_B0 = 0; field_B4 = 0; // 45 field_B8 = 0; field_BC = 0; field_C0 = 0; field_C4 = 0; field_C8 = 0; // 50 field_CC = 0; eventMetBoutarel = false; eventMetHadija = false; eventMetYasmin = false; field_DC = 0; // 55 field_E0 = 0; field_E4 = 0; field_E8 = 0; field_EC = 0; field_F0 = 0; // 60 field_F4 = 0; field_F8 = 0; field_FC = 0; field_100 = 0; field_104 = 0; // 65 field_108 = 0; field_10C = 0; field_110 = 0; field_114 = 0; field_118 = 0; // 70 field_11C = 0; field_120 = 0; field_124 = 0; field_128 = 0; field_12C = 0; // 75 field_130 = 0; field_134 = 0; field_138 = 0; field_13C = 0; field_140 = 0; // 80 field_144 = 0; field_148 = 0; field_14C = 0; field_150 = 0; field_154 = 0; // 85 field_158 = 0; field_15C = 0; field_160 = 0; field_164 = 0; field_168 = 0; // 90 field_16C = 0; field_170 = 0; field_174 = 0; field_178 = 0; field_17C = 0; // 95 field_180 = 0; field_184 = 0; field_188 = 0; field_18C = 0; field_190 = 0; // 100 field_194 = 0; field_198 = 0; field_19C = 0; field_1A0 = 0; field_1A4 = 0; // 105 field_1A8 = 0; field_1AC = 0; field_1B0 = 0; field_1B4 = 0; field_1B8 = 0; // 110 field_1BC = 0; field_1C0 = 0; field_1C4 = 0; field_1C8 = 0; field_1CC = 0; // 115 field_1D0 = 0; field_1D4 = 0; field_1D8 = 0; field_1DC = 0; field_1E0 = 0; // 120 field_1E4 = 0; field_1E8 = 0; field_1EC = 0; field_1F0 = 0; field_1F4 = 0; // 125 field_1F8 = 0; field_1FC = 0; } /** * Query if if a progress value is equal to the specified value. * * Note: This is necessary because we store different types in the progress structure * and need to test a value based on an index in Action::getCursor() * * @param index Zero-based index of the progress structure entry * @param val The value. * * @return true if equal, false if not. */ bool isEqual(uint index, uint val) { return getOrSetValueName(index) == val; } uint32 getOrSetValueName(uint index, Common::String *name = NULL, const uint32* newValue = NULL) { #define EXPOSE_VALUE(idx, entryName, fieldType) \ case idx: { \ if (name) (*name) = "" #entryName; \ if (newValue) {entryName = (fieldType)*newValue;} \ return (uint32)entryName; \ } switch (index) { default: error("[GameProgress::getValueName] Invalid index value (was: %d, max:127)", index); break; EXPOSE_VALUE(0, field_0, uint32); EXPOSE_VALUE(1, jacket, JacketType); EXPOSE_VALUE(2, eventCorpseMovedFromFloor, bool); EXPOSE_VALUE(3, field_C, uint32); EXPOSE_VALUE(4, eventCorpseFound, bool); EXPOSE_VALUE(5, field_14, uint32); EXPOSE_VALUE(6, field_18, uint32); EXPOSE_VALUE(7, portrait, uint32); EXPOSE_VALUE(8, eventCorpseThrown, bool); EXPOSE_VALUE(9, field_24, uint32); EXPOSE_VALUE(10, field_28, uint32); EXPOSE_VALUE(11, chapter, ChapterIndex); EXPOSE_VALUE(12, field_30, uint32); EXPOSE_VALUE(13, eventMetAugust, bool); EXPOSE_VALUE(14, isNightTime, bool); EXPOSE_VALUE(15, field_3C, uint32); EXPOSE_VALUE(16, field_40, uint32); EXPOSE_VALUE(17, field_44, uint32); EXPOSE_VALUE(18, field_48, uint32); EXPOSE_VALUE(19, field_4C, uint32); EXPOSE_VALUE(20, isTrainRunning, bool); EXPOSE_VALUE(21, field_54, uint32); EXPOSE_VALUE(22, field_58, uint32); EXPOSE_VALUE(23, field_5C, uint32); EXPOSE_VALUE(24, field_60, uint32); EXPOSE_VALUE(25, field_64, uint32); EXPOSE_VALUE(26, field_68, uint32); EXPOSE_VALUE(27, eventMertensAugustWaiting, bool); EXPOSE_VALUE(28, eventMertensKronosInvitation, bool); EXPOSE_VALUE(29, isEggOpen, bool); EXPOSE_VALUE(30, field_78, uint32); EXPOSE_VALUE(31, field_7C, uint32); EXPOSE_VALUE(32, field_80, uint32); EXPOSE_VALUE(33, field_84, uint32); EXPOSE_VALUE(34, field_88, uint32); EXPOSE_VALUE(35, field_8C, uint32); EXPOSE_VALUE(36, field_90, uint32); EXPOSE_VALUE(37, field_94, uint32); EXPOSE_VALUE(38, field_98, uint32); EXPOSE_VALUE(39, field_9C, uint32); EXPOSE_VALUE(40, field_A0, uint32); EXPOSE_VALUE(41, field_A4, uint32); EXPOSE_VALUE(42, field_A8, uint32); EXPOSE_VALUE(43, field_AC, uint32); EXPOSE_VALUE(44, field_B0, uint32); EXPOSE_VALUE(45, field_B4, uint32); EXPOSE_VALUE(46, field_B8, uint32); EXPOSE_VALUE(47, field_BC, uint32); EXPOSE_VALUE(48, field_C0, uint32); EXPOSE_VALUE(49, field_C4, uint32); EXPOSE_VALUE(50, field_C8, uint32); EXPOSE_VALUE(51, field_CC, uint32); EXPOSE_VALUE(52, eventMetBoutarel, bool); EXPOSE_VALUE(53, eventMetHadija, bool); EXPOSE_VALUE(54, eventMetYasmin, bool); EXPOSE_VALUE(55, field_DC, uint32); EXPOSE_VALUE(56, field_E0, uint32); EXPOSE_VALUE(57, field_E4, uint32); EXPOSE_VALUE(58, field_E8, uint32); EXPOSE_VALUE(59, field_EC, uint32); EXPOSE_VALUE(60, field_F0, uint32); EXPOSE_VALUE(61, field_F4, uint32); EXPOSE_VALUE(62, field_F8, uint32); EXPOSE_VALUE(63, field_FC, uint32); EXPOSE_VALUE(64, field_100, uint32); EXPOSE_VALUE(65, field_104, uint32); EXPOSE_VALUE(66, field_108, uint32); EXPOSE_VALUE(67, field_10C, uint32); EXPOSE_VALUE(68, field_110, uint32); EXPOSE_VALUE(69, field_114, uint32); EXPOSE_VALUE(70, field_118, uint32); EXPOSE_VALUE(71, field_11C, uint32); EXPOSE_VALUE(72, field_120, uint32); EXPOSE_VALUE(73, field_124, uint32); EXPOSE_VALUE(74, field_128, uint32); EXPOSE_VALUE(75, field_12C, uint32); EXPOSE_VALUE(76, field_130, uint32); EXPOSE_VALUE(77, field_134, uint32); EXPOSE_VALUE(78, field_138, uint32); EXPOSE_VALUE(79, field_13C, uint32); EXPOSE_VALUE(80, field_140, uint32); EXPOSE_VALUE(81, field_144, uint32); EXPOSE_VALUE(82, field_148, uint32); EXPOSE_VALUE(83, field_14C, uint32); EXPOSE_VALUE(84, field_150, uint32); EXPOSE_VALUE(85, field_154, uint32); EXPOSE_VALUE(86, field_158, uint32); EXPOSE_VALUE(87, field_15C, uint32); EXPOSE_VALUE(88, field_160, uint32); EXPOSE_VALUE(89, field_164, uint32); EXPOSE_VALUE(90, field_168, uint32); EXPOSE_VALUE(91, field_16C, uint32); EXPOSE_VALUE(92, field_170, uint32); EXPOSE_VALUE(93, field_174, uint32); EXPOSE_VALUE(94, field_178, uint32); EXPOSE_VALUE(95, field_17C, uint32); EXPOSE_VALUE(96, field_180, uint32); EXPOSE_VALUE(97, field_184, uint32); EXPOSE_VALUE(98, field_188, uint32); EXPOSE_VALUE(99, field_18C, uint32); EXPOSE_VALUE(100, field_190, uint32); EXPOSE_VALUE(101, field_194, uint32); EXPOSE_VALUE(102, field_198, uint32); EXPOSE_VALUE(103, field_19C, uint32); EXPOSE_VALUE(104, field_1A0, uint32); EXPOSE_VALUE(105, field_1A4, uint32); EXPOSE_VALUE(106, field_1A8, uint32); EXPOSE_VALUE(107, field_1AC, uint32); EXPOSE_VALUE(108, field_1B0, uint32); EXPOSE_VALUE(109, field_1B4, uint32); EXPOSE_VALUE(110, field_1B8, uint32); EXPOSE_VALUE(111, field_1BC, uint32); EXPOSE_VALUE(112, field_1C0, uint32); EXPOSE_VALUE(113, field_1C4, uint32); EXPOSE_VALUE(114, field_1C8, uint32); EXPOSE_VALUE(115, field_1CC, uint32); EXPOSE_VALUE(116, field_1D0, uint32); EXPOSE_VALUE(117, field_1D4, uint32); EXPOSE_VALUE(118, field_1D8, uint32); EXPOSE_VALUE(119, field_1DC, uint32); EXPOSE_VALUE(120, field_1E0, uint32); EXPOSE_VALUE(121, field_1E4, uint32); EXPOSE_VALUE(122, field_1E8, uint32); EXPOSE_VALUE(123, field_1EC, uint32); EXPOSE_VALUE(124, field_1F0, uint32); EXPOSE_VALUE(125, field_1F4, uint32); EXPOSE_VALUE(126, field_1F8, uint32); EXPOSE_VALUE(127, field_1FC, uint32); } } Common::String toString() { Common::String ret = ""; for (uint i = 0; i < 128; i++) { Common::String name = ""; uint val = getOrSetValueName(i, &name, NULL); ret += Common::String::format("(%03d) %s = %d\n", i, name.c_str(), val); } return ret; } void saveLoadWithSerializer(Common::Serializer &s) { if (s.isLoading()) { for (uint i = 0; i < 128; i++) { uint32 val; s.syncAsUint32LE(val); getOrSetValueName(i, NULL, &val); } } else { for (uint i = 0; i < 128; i++) { uint32 val = getOrSetValueName(i); s.syncAsUint32LE(val); } } } }; struct GameState : public Common::Serializable { // Header uint32 brightness; uint32 volume; // Game data uint32 field_0; TimeValue time; uint32 timeDelta; uint32 timeTicks; bool sceneUseBackup; // byte SceneIndex scene; // uint32 SceneIndex sceneBackup; // uint32 SceneIndex sceneBackup2; // uin32 GameProgress progress; byte events[512]; GameState() { brightness = _defaultBrigthness; volume = _defaultVolume; //Game data field_0 = 0; time = kTimeCityParis; timeDelta = _defaultTimeDelta; timeTicks = 0; sceneUseBackup = false; scene = kSceneDefault; sceneBackup = kSceneNone; sceneBackup2 = kSceneNone; // Clear game events memset(events, 0, 512*sizeof(byte)); } /** * Convert this object into a string representation. * * @return A string representation of this object. */ Common::String toString() { Common::String ret = ""; uint8 hours = 0; uint8 minutes = 0; getHourMinutes(time, &hours, &minutes); ret += Common::String::format("Time: %d (%d:%d) - Time delta: %d - Ticks: %d\n", time, hours, minutes, timeDelta, timeTicks); ret += Common::String::format("Brightness: %d - Volume: %d - UseBackup: %d\n", brightness, volume, sceneUseBackup); ret += Common::String::format("Scene: %d - Scene backup: %d - Scene backup 2: %d\n", scene, sceneBackup, sceneBackup2); return ret; } void saveLoadWithSerializer(Common::Serializer &s) { s.syncAsUint32LE(time); s.syncAsUint32LE(timeDelta); s.syncAsUint32LE(timeTicks); s.syncAsUint32LE(scene); s.syncAsByte(sceneUseBackup); s.syncAsUint32LE(sceneBackup); s.syncAsUint32LE(sceneBackup2); } void syncEvents(Common::Serializer &s) { for (uint i = 0; i < ARRAYSIZE(events); i++) s.syncAsByte(events[i]); } }; struct Flags { bool flag_0; bool flag_3; bool flag_4; bool flag_5; bool frameInterval; bool isGameRunning; // Mouse flags bool mouseLeftClick; bool mouseRightClick; bool mouseLeftPressed; bool mouseRightPressed; bool flag_entities_0; bool flag_entities_1; bool shouldRedraw; bool shouldDrawEggOrHourGlass; int32 nis; Flags() { flag_0 = false; flag_3 = false; flag_4 = false; flag_5 = false; frameInterval = false; isGameRunning = false; mouseRightClick = false; mouseLeftClick = false; mouseLeftPressed = false; mouseRightPressed = false; flag_entities_0 = false; flag_entities_1 = false; shouldRedraw = false; shouldDrawEggOrHourGlass = false; nis = 0; } /** * Convert this object into a string representation. * * @return A string representation of this object. */ Common::String toString() { Common::String ret = ""; ret += Common::String::format("Unknown: 0:%02d - 3:%02d - 4:%02d - 5:%02d\n", flag_0, flag_3, flag_4, flag_5); ret += Common::String::format("FrameInterval: %02d - ShouldRedraw:%02d - ShouldDrawEggOrHourGlass:%02d\n", frameInterval, shouldRedraw, shouldDrawEggOrHourGlass); ret += Common::String::format("IsGameRunning: %02d\n", isGameRunning); ret += Common::String::format("Mouse: RightClick:%02d - LeftClick:%02d\n", mouseRightClick, mouseLeftClick); ret += Common::String::format("Entities: 0:%02d - 1:%02d\n", flag_entities_0, flag_entities_1); ret += Common::String::format("NIS: %d\n", nis); return ret; } }; State(LastExpressEngine *engine); ~State(); void reset(); // Accessors Inventory *getGameInventory() { return _inventory; } Objects *getGameObjects() { return _objects; } SavePoints *getGameSavePoints() { return _savepoints; } GameState *getGameState() { return _state; } Flags *getGameFlags() { return _flags; } // Time checks bool isNightTime() const; // Timer int getTimer() { return _timer; } void setTimer(int val) { _timer = val; } // Coordinates void setCoordinates(Common::Point coords) { _coords = coords; } const Common::Point getCoordinates() { return _coords; } // Helpers static uint32 getPowerOfTwo(uint32 x); static void getHourMinutes(uint32 time, uint8 *hours, uint8 *minutes); private: static const uint32 _defaultBrigthness = 3; static const uint32 _defaultVolume = 7; static const uint32 _defaultTimeDelta = 3; static const uint32 _defaultPortrait = 32; LastExpressEngine *_engine; // Timer int _timer; Flags *_flags; ///< Flags Inventory *_inventory; ///< Inventory Objects *_objects; ///< Objects SavePoints *_savepoints; ///< SavePoints GameState *_state; ///< State Common::Point _coords; ///< Current coordinates }; } // End of namespace LastExpress #endif // LASTEXPRESS_STATE_H