ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

state.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/myst3/state.h"
00024 #include "engines/myst3/database.h"
00025 #include "engines/myst3/gfx.h"
00026 
00027 #include "common/debug-channels.h"
00028 #include "common/ptr.h"
00029 #include "common/savefile.h"
00030 
00031 #include "graphics/surface.h"
00032 
00033 namespace Myst3 {
00034 
00035 GameState::StateData::StateData() {
00036     version = GameState::kSaveVersion;
00037     gameRunning = true;
00038     tickCount = 0;
00039     nextSecondsUpdate = 0;
00040     secondsPlayed = 0;
00041     dword_4C2C44 = 0;
00042     dword_4C2C48 = 0;
00043     dword_4C2C4C = 0;
00044     dword_4C2C50 = 0;
00045     dword_4C2C54 = 0;
00046     dword_4C2C58 = 0;
00047     dword_4C2C5C = 0;
00048     dword_4C2C60 = 0;
00049     currentNodeType = 0;
00050     lookatPitch = 0;
00051     lookatHeading = 0;
00052     lookatFOV = 0;
00053     pitchOffset = 0;
00054     headingOffset = 0;
00055     limitCubeCamera = 0;
00056     minPitch = 0;
00057     maxPitch = 0;
00058     minHeading = 0;
00059     maxHeading = 0;
00060     dword_4C2C90 = 0;
00061 
00062     for (uint i = 0; i < 2048; i++)
00063         vars[i] = 0;
00064 
00065     vars[0] = 0;
00066     vars[1] = 1;
00067 
00068     inventoryCount = 0;
00069 
00070     for (uint i = 0; i < 7; i++)
00071         inventoryList[i] = 0;
00072 
00073     for (uint i = 0; i < 64; i++)
00074         zipDestinations[i] = 0;
00075 
00076     saveDay = 0;
00077     saveMonth = 0;
00078     saveYear = 0;
00079     saveHour = 0;
00080     saveMinute = 0;
00081     isAutosave = false;
00082 }
00083 
00084 GameState::GameState(const Common::Platform platform, Database *database):
00085         _platform(platform),
00086         _db(database) {
00087 
00088 #define VAR(var, x, unk) _varDescriptions.setVal(#x, VarDescription(var, #x, unk));
00089 
00090     VAR(14, CursorTransparency, false)
00091 
00092     VAR(47, ProjectorAngleX, false)
00093     VAR(48, ProjectorAngleY, false)
00094     VAR(49, ProjectorAngleZoom, false)
00095     VAR(50, ProjectorAngleBlur, false)
00096     VAR(51, DraggedWeight, false)
00097 
00098     VAR(57, DragEnded, false)
00099     VAR(58, DragLeverSpeed, false)
00100     VAR(59, DragPositionFound, false)
00101     VAR(60, DragLeverPositionChanged, false)
00102 
00103     VAR(61, LocationAge, false)
00104     VAR(62, LocationRoom, false)
00105     VAR(63, LocationNode, false)
00106     VAR(64, BookSavedAge, false)
00107     VAR(65, BookSavedRoom, false)
00108     VAR(66, BookSavedNode, false)
00109     VAR(67, MenuSavedAge, false)
00110     VAR(68, MenuSavedRoom, false)
00111     VAR(69, MenuSavedNode, false)
00112 
00113     VAR(70, SecondsCountdown, false)
00114     VAR(71, TickCountdown, false)
00115 
00116     // Counters, unused by the game scripts
00117     VAR(76, CounterUnk76, false)
00118     VAR(77, CounterUnk77, false)
00119     VAR(78, CounterUnk78, false)
00120 
00121     VAR(79, SweepEnabled, false)
00122     VAR(80, SweepValue, false)
00123     VAR(81, SweepStep, false)
00124     VAR(82, SweepMin, false)
00125     VAR(83, SweepMax, false)
00126 
00127     VAR(84, InputMousePressed, false)
00128     VAR(88, InputEscapePressed, false)
00129     VAR(89, InputTildePressed, false)
00130     VAR(90, InputSpacePressed, false)
00131 
00132     VAR(92, HotspotActiveRect, false)
00133 
00134     VAR(93, WaterEffectRunning, false)
00135     VAR(94, WaterEffectActive, false)
00136     VAR(95, WaterEffectSpeed, false)
00137     VAR(96, WaterEffectAttenuation, false)
00138     VAR(97, WaterEffectFrequency, false)
00139     VAR(98, WaterEffectAmpl, false)
00140     VAR(99, WaterEffectMaxStep, false)
00141     VAR(100, WaterEffectAmplOffset, false)
00142 
00143     VAR(101, LavaEffectActive, false)
00144     VAR(102, LavaEffectSpeed, false)
00145     VAR(103, LavaEffectAmpl, false)
00146     VAR(104, LavaEffectStepSize, false)
00147 
00148     VAR(105, MagnetEffectActive, false)
00149     VAR(106, MagnetEffectSpeed, false)
00150     VAR(107, MagnetEffectUnk1, false)
00151     VAR(108, MagnetEffectUnk2, false)
00152     VAR(109, MagnetEffectSound, false)
00153     VAR(110, MagnetEffectNode, false)
00154     VAR(111, MagnetEffectUnk3, false)
00155 
00156     VAR(112, ShakeEffectAmpl, false)
00157     VAR(113, ShakeEffectTickPeriod, false)
00158     VAR(114, RotationEffectSpeed, false)
00159     VAR(115, SunspotIntensity, false)
00160     VAR(116, SunspotColor, false)
00161     VAR(117, SunspotRadius, false)
00162 
00163     VAR(119, AmbiantFadeOutDelay, false)
00164     VAR(120, AmbiantPreviousFadeOutDelay, false)
00165     VAR(121, AmbientOverrideFadeOutDelay, false)
00166     VAR(122, SoundScriptsSuspended, false)
00167 
00168     VAR(124, SoundNextMultipleSounds, false)
00169     VAR(125, SoundNextIsChoosen, false)
00170     VAR(126, SoundNextId, false)
00171     VAR(127, SoundNextIsLast, false)
00172     VAR(128, SoundScriptsTimer, false)
00173     VAR(129, SoundScriptsPaused, false)
00174     VAR(130, SoundScriptFadeOutDelay, false)
00175 
00176     VAR(131, CursorLocked, false)
00177     VAR(132, CursorHidden, false)
00178 
00179     VAR(136, CameraPitch, false)
00180     VAR(137, CameraHeading, false)
00181     VAR(140, CameraMinPitch, false)
00182     VAR(141, CameraMaxPitch, false)
00183 
00184     VAR(142, MovieStartFrame, false)
00185     VAR(143, MovieEndFrame, false)
00186     VAR(144, MovieVolume1, false)
00187     VAR(145, MovieVolume2, false)
00188     VAR(146, MovieOverrideSubtitles, false)
00189 
00190     VAR(149, MovieConditionBit, false)
00191     VAR(150, MoviePreloadToMemory, false)
00192     VAR(151, MovieScriptDriven, false)
00193     VAR(152, MovieNextFrameSetVar, false)
00194     VAR(153, MovieNextFrameGetVar, false)
00195     VAR(154, MovieStartFrameVar, false)
00196     VAR(155, MovieEndFrameVar, false)
00197     VAR(156, MovieForce2d, false)
00198     VAR(157, MovieVolumeVar, false)
00199     VAR(158, MovieSoundHeading, false)
00200     VAR(159, MoviePanningStrenght, false)
00201     VAR(160, MovieSynchronized, false)
00202 
00203     // We ignore this, and never skip frames
00204     VAR(161, MovieNoFrameSkip, false)
00205 
00206     // Only play the audio track. This is used in TOHO 3 only.
00207     // Looks like it works fine without any specific implementation
00208     VAR(162, MovieAudioOnly, false)
00209 
00210     VAR(163, MovieOverrideCondition, false)
00211     VAR(164, MovieUVar, false)
00212     VAR(165, MovieVVar, false)
00213     VAR(166, MovieOverridePosition, false)
00214     VAR(167, MovieOverridePosU, false)
00215     VAR(168, MovieOverridePosV, false)
00216     VAR(169, MovieScale, false)
00217     VAR(170, MovieAdditiveBlending, false)
00218     VAR(171, MovieTransparency, false)
00219     VAR(172, MovieTransparencyVar, false)
00220     VAR(173, MoviePlayingVar, false)
00221     VAR(174, MovieStartSoundId, false)
00222     VAR(175, MovieStartSoundVolume, false)
00223     VAR(176, MovieStartSoundHeading, false)
00224     VAR(177, MovieStartSoundAttenuation, false)
00225 
00226     VAR(178, MovieUseBackground, false)
00227     VAR(179, CameraSkipAnimation, false)
00228     VAR(180, MovieAmbiantScriptStartFrame, false)
00229     VAR(181, MovieAmbiantScript, false)
00230     VAR(182, MovieScriptStartFrame, false)
00231     VAR(183, MovieScript, false)
00232 
00233     VAR(185, CameraMoveSpeed, false)
00234 
00235     // We always allow missing SpotItem data
00236     VAR(186, SpotItemAllowMissing, false)
00237 
00238     VAR(187, TransitionSound, false)
00239     VAR(188, TransitionSoundVolume, false)
00240     VAR(189, LocationNextNode, false)
00241     VAR(190, LocationNextRoom, false)
00242     VAR(191, LocationNextAge, false)
00243 
00244     VAR(195, BallPosition, false)
00245     VAR(196, BallFrame, false)
00246     VAR(197, BallLeverLeft, false)
00247     VAR(198, BallLeverRight, false)
00248 
00249     VAR(228, BallDoorOpen, false)
00250 
00251     VAR(243, ProjectorX, false)
00252     VAR(244, ProjectorY, false)
00253     VAR(245, ProjectorZoom, false)
00254     VAR(246, ProjectorBlur, false)
00255     VAR(247, ProjectorAngleXOffset, false)
00256     VAR(248, ProjectorAngleYOffset, false)
00257     VAR(249, ProjectorAngleZoomOffset, false)
00258     VAR(250, ProjectorAngleBlurOffset, false)
00259 
00260     VAR(277, JournalAtrusState, false)
00261     VAR(279, JournalSaavedroState, false)
00262     VAR(280, JournalSaavedroClosed, false)
00263     VAR(281, JournalSaavedroOpen, false)
00264     VAR(282, JournalSaavedroLastPage, false)
00265     VAR(283, JournalSaavedroChapter, false)
00266     VAR(284, JournalSaavedroPageInChapter, false)
00267 
00268     VAR(329, TeslaAllAligned, false)
00269     VAR(330, TeslaTopAligned, false)
00270     VAR(331, TeslaMiddleAligned, false)
00271     VAR(332, TeslaBottomAligned, false)
00272     VAR(333, TeslaMovieStart, false)
00273 
00274     // Amateria ambient sound / movie counters (XXXX 1001 and XXXX 1002)
00275     VAR(406, AmateriaSecondsCounter, false)
00276     VAR(407, AmateriaTicksCounter, false)
00277 
00278     VAR(444, ResonanceRingsSolved, false)
00279 
00280     VAR(460, PinballRemainingPegs, false)
00281 
00282     VAR(475, OuterShieldUp, false)
00283     VAR(476, InnerShieldUp, false)
00284     VAR(479, SaavedroStatus, false)
00285 
00286     VAR(480, BookStateTomahna, false)
00287     VAR(481, BookStateReleeshahn, false)
00288 
00289     VAR(489, SymbolCode2Solved, false)
00290     VAR(495, SymbolCode1AllSolved, false)
00291     VAR(496, SymbolCode1CurrentSolved, false)
00292     VAR(497, SymbolCode1TopSolved, false)
00293     VAR(502, SymbolCode1LeftSolved, false)
00294     VAR(507, SymbolCode1RightSolved, false)
00295 
00296     VAR(540, SoundVoltaicUnk540, false)
00297     VAR(587, SoundEdannaUnk587, false)
00298     VAR(627, SoundAmateriaUnk627, false)
00299     VAR(930, SoundAmateriaUnk930, false)
00300     VAR(1031, SoundEdannaUnk1031, false)
00301     VAR(1146, SoundVoltaicUnk1146, false)
00302 
00303     VAR(1322, ZipModeEnabled, false)
00304     VAR(1323, SubtitlesEnabled, false)
00305     VAR(1324, WaterEffects, false)
00306     VAR(1325, TransitionSpeed, false)
00307     VAR(1326, MouseSpeed, false)
00308     VAR(1327, DialogResult, false)
00309 
00310     VAR(1395, HotspotIgnoreClick, false)
00311     VAR(1396, HotspotHovered, false)
00312     VAR(1397, SpotSubtitle, false)
00313 
00314     // Override node from which effect masks are loaded
00315     // This is only used in LEIS x75, but is useless
00316     // since all the affected nodes have the same effect masks
00317     VAR(1398, EffectsOverrideMaskNode, false)
00318 
00319     VAR(1399, DragLeverLimited, false)
00320     VAR(1400, DragLeverLimitMin, false)
00321     VAR(1401, DragLeverLimitMax, false)
00322 
00323     // Mouse unk
00324     VAR(6, Unk6, true)
00325 
00326     // Backup var for opcodes 245, 246 => find usage
00327     VAR(13, Unk13, true)
00328 
00329     // ???
00330     VAR(147, MovieUnk147, true)
00331     VAR(148, MovieUnk148, true)
00332 
00333     if (_platform != Common::kPlatformXbox) {
00334         VAR(1337, MenuEscapePressed, false)
00335         VAR(1338, MenuNextAction, false)
00336         VAR(1339, MenuLoadBack, false)
00337         VAR(1340, MenuSaveBack, false)
00338         VAR(1341, MenuSaveAction, false)
00339         VAR(1342, MenuOptionsBack, false)
00340 
00341         VAR(1350, MenuSaveLoadPageLeft, false)
00342         VAR(1351, MenuSaveLoadPageRight, false)
00343         VAR(1352, MenuSaveLoadSelectedItem, false)
00344         VAR(1353, MenuSaveLoadCurrentPage, false)
00345 
00346         // Menu stuff does not look like it's too useful
00347         VAR(1361, Unk1361, true)
00348         VAR(1362, Unk1362, true)
00349         VAR(1363, Unk1363, true)
00350 
00351         VAR(1374, OverallVolume, false)
00352         VAR(1377, MusicVolume, false)
00353         VAR(1380, MusicFrequency, false)
00354         VAR(1393, LanguageAudio, false)
00355         VAR(1394, LanguageText, false)
00356 
00357         VAR(1406, ShieldEffectActive, false)
00358 
00359     } else {
00360         shiftVariables(927, 1);
00361         shiftVariables(1031, 2);
00362         shiftVariables(1395, -22);
00363 
00364         VAR(1340, MenuSavesAvailable, false)
00365         VAR(1341, MenuNextAction, false)
00366         VAR(1342, MenuLoadBack, false)
00367         VAR(1343, MenuSaveBack, false)
00368         VAR(1344, MenuSaveAction, false)
00369         VAR(1345, MenuOptionsBack, false)
00370         VAR(1346, MenuSelectedSave, false)
00371 
00372         VAR(1384, MovieOptional, false)
00373         VAR(1386, VibrationEnabled, false)
00374 
00375         VAR(1430, GamePadActionPressed, false)
00376         VAR(1431, GamePadDownPressed, false)
00377         VAR(1432, GamePadUpPressed, false)
00378         VAR(1433, GamePadLeftPressed, false)
00379         VAR(1434, GamePadRightPressed, false)
00380         VAR(1435, GamePadCancelPressed, false)
00381 
00382         VAR(1437, DragWithDirectionKeys, false)
00383         VAR(1438, MenuAttractCountDown, false)
00384         VAR(1439, ShieldEffectActive, false)
00385 
00386         VAR(1445, StateCanSave, false)
00387     }
00388 
00389 #undef VAR
00390 
00391     newGame();
00392 }
00393 
00394 GameState::~GameState() {
00395 }
00396 
00397 void GameState::syncFloat(Common::Serializer &s, float &val,
00398         Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
00399     static const float precision = 10000.0;
00400 
00401     if (s.isLoading()) {
00402         int32 saved = 0;
00403         s.syncAsSint32LE(saved, minVersion, maxVersion);
00404         val = saved / precision;
00405     } else {
00406         int32 toSave = static_cast<int32>(val * precision);
00407         s.syncAsSint32LE(toSave, minVersion, maxVersion);
00408     }
00409 }
00410 
00411 Common::Error GameState::StateData::syncWithSaveGame(Common::Serializer &s) {
00412     if (!s.syncVersion(kSaveVersion))
00413         return Common::Error(Common::kUnknownError, Common::String::format("This savegame (v%d) is too recent (max %d) please get a newer version of ResidualVM", s.getVersion(), kSaveVersion));
00414 
00415     s.syncAsUint32LE(gameRunning);
00416     s.syncAsUint32LE(tickCount);
00417     s.syncAsUint32LE(nextSecondsUpdate);
00418     s.syncAsUint32LE(secondsPlayed);
00419     s.syncAsUint32LE(dword_4C2C44);
00420     s.syncAsUint32LE(dword_4C2C48);
00421     s.syncAsUint32LE(dword_4C2C4C);
00422     s.syncAsUint32LE(dword_4C2C50);
00423     s.syncAsUint32LE(dword_4C2C54);
00424     s.syncAsUint32LE(dword_4C2C58);
00425     s.syncAsUint32LE(dword_4C2C5C);
00426     s.syncAsUint32LE(dword_4C2C60);
00427     s.syncAsUint32LE(currentNodeType);
00428 
00429     // The original engine (v148) saved the raw IEE754 data,
00430     // we save decimal data as fixed point instead to be achieve portability
00431     if (s.getVersion() < 149) {
00432         s.syncBytes((byte*) &lookatPitch, sizeof(float));
00433         s.syncBytes((byte*) &lookatHeading, sizeof(float));
00434         s.syncBytes((byte*) &lookatFOV, sizeof(float));
00435         s.syncBytes((byte*) &pitchOffset, sizeof(float));
00436         s.syncBytes((byte*) &headingOffset, sizeof(float));
00437     } else {
00438         syncFloat(s, lookatPitch);
00439         syncFloat(s, lookatHeading);
00440         syncFloat(s, lookatFOV);
00441         syncFloat(s, pitchOffset);
00442         syncFloat(s, headingOffset);
00443     }
00444 
00445     s.syncAsUint32LE(limitCubeCamera);
00446 
00447     if (s.getVersion() < 149) {
00448         s.syncBytes((byte*) &minPitch, sizeof(float));
00449         s.syncBytes((byte*) &maxPitch, sizeof(float));
00450         s.syncBytes((byte*) &minHeading, sizeof(float));
00451         s.syncBytes((byte*) &maxHeading, sizeof(float));
00452     } else {
00453         syncFloat(s, minPitch);
00454         syncFloat(s, maxPitch);
00455         syncFloat(s, minHeading);
00456         syncFloat(s, maxHeading);
00457     }
00458 
00459     s.syncAsUint32LE(dword_4C2C90);
00460 
00461     for (uint i = 0; i < 2048; i++)
00462         s.syncAsSint32LE(vars[i]);
00463 
00464     s.syncAsUint32LE(inventoryCount);
00465 
00466     for (uint i = 0; i < 7; i++)
00467         s.syncAsUint32LE(inventoryList[i]);
00468 
00469     for (uint i = 0; i < 64; i++)
00470         s.syncAsUint32LE(zipDestinations[i]);
00471 
00472     s.syncAsByte(saveDay, 149);
00473     s.syncAsByte(saveMonth, 149);
00474     s.syncAsUint16LE(saveYear, 149);
00475     s.syncAsByte(saveHour, 149);
00476     s.syncAsByte(saveMinute, 149);
00477     s.syncString(saveDescription, 149);
00478     s.syncAsUint32LE(isAutosave, 150);
00479 
00480     return Common::kNoError;
00481 }
00482 
00483 const Graphics::PixelFormat GameState::getThumbnailSavePixelFormat() {
00484 #ifdef SCUMM_BIG_ENDIAN
00485     return Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0);
00486 #else
00487     return Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24);
00488 #endif
00489 }
00490 
00491 Graphics::Surface *GameState::readThumbnail(Common::ReadStream *inStream) {
00492     Graphics::Surface *thumbnail = new Graphics::Surface();
00493     thumbnail->create(kThumbnailWidth, kThumbnailHeight, getThumbnailSavePixelFormat());
00494 
00495     inStream->read((byte *)thumbnail->getPixels(), kThumbnailWidth * kThumbnailHeight * 4);
00496 
00497     thumbnail->convertToInPlace(Texture::getRGBAPixelFormat());
00498 
00499     return thumbnail;
00500 }
00501 
00502 void GameState::writeThumbnail(Common::WriteStream *outStream, const Graphics::Surface *thumbnail) {
00503     assert(thumbnail->format == Texture::getRGBAPixelFormat());
00504     assert(thumbnail && thumbnail->w == kThumbnailWidth && thumbnail->h == kThumbnailHeight);
00505 
00506     Graphics::Surface *converted = thumbnail->convertTo(getThumbnailSavePixelFormat());
00507 
00508     outStream->write((byte *)converted->getPixels(), kThumbnailWidth * kThumbnailHeight * 4);
00509 
00510     converted->free();
00511     delete converted;
00512 }
00513 
00514 Graphics::Surface *GameState::resizeThumbnail(Graphics::Surface *big, uint width, uint height) {
00515     assert(big->format.bytesPerPixel == 4);
00516     Graphics::Surface *small = new Graphics::Surface();
00517     small->create(width, height, big->format);
00518 
00519     uint32 *dst = (uint32 *)small->getPixels();
00520     for (uint i = 0; i < small->h; i++) {
00521         for (uint j = 0; j < small->w; j++) {
00522             uint32 srcX = big->w * j / small->w;
00523             uint32 srcY = big->h * i / small->h;
00524             uint32 *src = (uint32 *)big->getBasePtr(srcX, srcY);
00525 
00526             // Copy RGBA pixel
00527             *dst++ = *src;
00528         }
00529     }
00530 
00531     return small;
00532 }
00533 
00534 void GameState::newGame() {
00535     _data = StateData();
00536     _lastTickStartTime = g_system->getMillis();
00537 }
00538 
00539 Common::Error GameState::load(Common::InSaveFile *saveFile) {
00540     Common::Serializer s = Common::Serializer(saveFile, 0);
00541     Common::Error loadError = _data.syncWithSaveGame(s);
00542 
00543     _data.gameRunning = true;
00544 
00545     if (loadError.getCode() != Common::kNoError) {
00546         return loadError;
00547     }
00548 
00549     return Common::kNoError;
00550 }
00551 
00552 Common::Error GameState::save(Common::OutSaveFile *saveFile, const Common::String &description, const Graphics::Surface *thumbnail, bool isAutosave) {
00553     Common::Serializer s = Common::Serializer(0, saveFile);
00554 
00555     // Update save creation info
00556     TimeDate t;
00557     g_system->getTimeAndDate(t);
00558     _data.saveYear = t.tm_year + 1900;
00559     _data.saveMonth = t.tm_mon + 1;
00560     _data.saveDay = t.tm_mday;
00561     _data.saveHour = t.tm_hour;
00562     _data.saveMinute = t.tm_min;
00563     _data.saveDescription = description;
00564     _data.isAutosave = isAutosave;
00565 
00566     _data.gameRunning = false;
00567 
00568     Common::Error saveError = _data.syncWithSaveGame(s);
00569     if (saveError.getCode() != Common::kNoError) {
00570         return saveError;
00571     }
00572 
00573     writeThumbnail(saveFile, thumbnail);
00574 
00575     _data.gameRunning = true;
00576 
00577     return Common::kNoError;
00578 }
00579 
00580 Common::String GameState::formatSaveTime() {
00581     if (_data.saveYear == 0)
00582         return "";
00583 
00584     // TODO: Check the Xbox NTSC version, maybe it uses that strange MM/DD/YYYY format
00585     return Common::String::format("%02d/%02d/%02d %02d:%02d",
00586             _data.saveDay, _data.saveMonth, _data.saveYear,
00587             _data.saveHour, _data.saveMinute);
00588 }
00589 
00590 Common::Array<uint16> GameState::getInventory() {
00591     Common::Array<uint16> items;
00592 
00593     for (uint i = 0; i < _data.inventoryCount; i++)
00594         items.push_back(_data.inventoryList[i]);
00595 
00596     return items;
00597 }
00598 
00599 void GameState::updateInventory(const Common::Array<uint16> &items) {
00600     for (uint i = 0; i < 7; i++)
00601         _data.inventoryList[i] = 0;
00602 
00603     for (uint i = 0; i < items.size(); i++)
00604         _data.inventoryList[i] = items[i];
00605 
00606     _data.inventoryCount = items.size();
00607 }
00608 
00609 void GameState::checkRange(uint16 var) {
00610     if (var < 1 || var > 2047)
00611         error("Variable out of range %d", var);
00612 }
00613 
00614 const GameState::VarDescription GameState::findDescription(uint16 var) {
00615     for (VarMap::const_iterator it = _varDescriptions.begin(); it != _varDescriptions.end(); it++) {
00616         if (it->_value.var == var) {
00617             return it->_value;
00618         }
00619     }
00620 
00621     return VarDescription();
00622 }
00623 
00624 void GameState::shiftVariables(uint16 base, int32 value) {
00625     for (VarMap::iterator it = _varDescriptions.begin(); it != _varDescriptions.end(); it++) {
00626         if (it->_value.var >= base) {
00627             it->_value.var += value;
00628         }
00629     }
00630 }
00631 
00632 int32 GameState::getVar(uint16 var) {
00633     checkRange(var);
00634 
00635     return _data.vars[var];
00636 }
00637 
00638 void GameState::setVar(uint16 var, int32 value) {
00639     checkRange(var);
00640 
00641     if (DebugMan.isDebugChannelEnabled(kDebugVariable)) {
00642         const VarDescription &d = findDescription(var);
00643 
00644         if (d.name && d.unknown) {
00645             warning("A script is writing to the unimplemented engine-mapped var %d (%s)", var, d.name);
00646         }
00647     }
00648 
00649     _data.vars[var] = value;
00650 }
00651 
00652 bool GameState::evaluate(int16 condition) {
00653     uint16 unsignedCond = abs(condition);
00654     uint16 var = unsignedCond & 2047;
00655     int32 varValue = getVar(var);
00656     int32 targetValue = (unsignedCond >> 11) - 1;
00657 
00658     if (targetValue >= 0) {
00659         if (condition >= 0)
00660             return varValue == targetValue;
00661         else
00662             return varValue != targetValue;
00663     } else {
00664         if (condition >= 0)
00665             return varValue != 0;
00666         else
00667             return varValue == 0;
00668     }
00669 }
00670 
00671 int32 GameState::valueOrVarValue(int16 value) {
00672     if (value < 0)
00673         return getVar(-value);
00674 
00675     return value;
00676 }
00677 
00678 int32 GameState::engineGet(const Common::String &varName) {
00679     if (!_varDescriptions.contains(varName))
00680         error("The engine is trying to access an undescribed var (%s)", varName.c_str());
00681 
00682     const VarDescription &d = _varDescriptions.getVal(varName);
00683 
00684     return _data.vars[d.var];
00685 }
00686 
00687 void GameState::engineSet(const Common::String &varName, int32 value) {
00688     if (!_varDescriptions.contains(varName))
00689         error("The engine is trying to access an undescribed var (%s)", varName.c_str());
00690 
00691     const VarDescription &d = _varDescriptions.getVal(varName);
00692 
00693     _data.vars[d.var] = value;
00694 }
00695 
00696 const Common::String GameState::describeVar(uint16 var) {
00697     const VarDescription &d = findDescription(var);
00698 
00699     if (d.name) {
00700         return Common::String::format("v%s", d.name);
00701     } else {
00702         return Common::String::format("v%d", var);
00703     }
00704 }
00705 
00706 const Common::String GameState::describeCondition(int16 condition) {
00707     uint16 unsignedCond = abs(condition);
00708     uint16 var = unsignedCond & 2047;
00709     int16 value = (unsignedCond >> 11) - 1;
00710 
00711     return Common::String::format("c[%s %s %d]",
00712             describeVar(var).c_str(),
00713             (condition >= 0 && value >= 0) || (condition < 0 && value < 0) ? "==" : "!=",
00714             value >= 0 ? value : 0);
00715 }
00716 
00717 void GameState::limitCubeCamera(float minPitch, float maxPitch, float minHeading, float maxHeading) {
00718     _data.limitCubeCamera = true;
00719     _data.minPitch = minPitch;
00720     _data.maxPitch = maxPitch;
00721     _data.minHeading = minHeading;
00722     _data.maxHeading = maxHeading;
00723 }
00724 
00725 void GameState::updateFrameCounters() {
00726     if (!_data.gameRunning)
00727         return;
00728 
00729     uint32 currentTime = g_system->getMillis();
00730     int32 timeToNextTick = _lastTickStartTime + kTickDuration - currentTime;
00731 
00732     if (timeToNextTick <= 0) {
00733         _data.tickCount++;
00734         updateTickCounters();
00735         _lastTickStartTime = currentTime + timeToNextTick;
00736     }
00737 
00738     if (currentTime > _data.nextSecondsUpdate || ABS<int32>(_data.nextSecondsUpdate - currentTime) > 2000) {
00739         _data.secondsPlayed++;
00740         _data.nextSecondsUpdate = currentTime + 1000;
00741 
00742         int32 secondsCountdown = getSecondsCountdown();
00743         if (secondsCountdown > 0)
00744             setSecondsCountdown(--secondsCountdown);
00745 
00746         if (getAmateriaSecondsCounter() > 0)
00747             setAmateriaSecondsCounter(getAmateriaSecondsCounter() - 1);
00748 
00749         if (getSoundScriptsTimer() > 0)
00750             setSoundScriptsTimer(getSoundScriptsTimer() - 1);
00751 
00752         if (hasVarMenuAttractCountDown() && getMenuAttractCountDown() > 0)
00753             setMenuAttractCountDown(getMenuAttractCountDown() - 1);
00754     }
00755 }
00756 
00757 void GameState::updateTickCounters() {
00758     int32 tickCountdown = getTickCountdown();
00759     if (tickCountdown > 0)
00760             setTickCountdown(--tickCountdown);
00761 
00762     if (getAmateriaTicksCounter() > 0)
00763             setAmateriaTicksCounter(getAmateriaTicksCounter() - 1);
00764 
00765     if (getSweepEnabled()) {
00766             if (getSweepValue() + getSweepStep() > getSweepMax()) {
00767                 setSweepValue(getSweepMax());
00768 
00769                 if (getSweepStep() > 0) {
00770                     setSweepStep(-getSweepStep());
00771                 }
00772             } else if (getSweepValue() + getSweepStep() < getSweepMin()) {
00773                 setSweepValue(getSweepMin());
00774 
00775                 if (getSweepStep() < 0) {
00776                     setSweepStep(-getSweepStep());
00777                 }
00778             } else {
00779                 setSweepValue(getSweepValue() + getSweepStep());
00780             }
00781         }
00782 }
00783 
00784 uint GameState::getTickCount() const {
00785     return _data.tickCount;
00786 }
00787 
00788 void GameState::pauseEngine(bool pause) {
00789     if (!pause) {
00790         _lastTickStartTime = g_system->getMillis();
00791     }
00792 }
00793 
00794 bool GameState::isZipDestinationAvailable(uint16 node, uint16 room, uint32 age) {
00795     int32 zipBitIndex = _db->getNodeZipBitIndex(node, room, age);
00796 
00797     int32 arrayIndex = zipBitIndex / 32;
00798     assert(arrayIndex < 64);
00799 
00800     return (_data.zipDestinations[arrayIndex] & (1 << (zipBitIndex % 32))) != 0;
00801 }
00802 
00803 void GameState::markNodeAsVisited(uint16 node, uint16 room, uint32 age) {
00804     int32 zipBitIndex = _db->getNodeZipBitIndex(node, room, age);
00805 
00806     int32 arrayIndex = zipBitIndex / 32;
00807     assert(arrayIndex < 64);
00808 
00809     _data.zipDestinations[arrayIndex] |= 1 << (zipBitIndex % 32);
00810 }
00811 
00812 Common::String Saves::buildName(const char *name, Common::Platform platform) {
00813     const char *format;
00814 
00815     if (platform == Common::kPlatformXbox) {
00816         format = "%s.m3x";
00817     } else {
00818         format = "%s.m3s";
00819     }
00820 
00821     return Common::String::format(format, name);
00822 }
00823 
00824 struct AutosaveFirstComparator {
00825     bool operator()(const Common::String &x, const Common::String &y) const {
00826         if (x.hasPrefixIgnoreCase("autosave.")) {
00827             return true;
00828         }
00829 
00830         if (y.hasPrefixIgnoreCase("autosave.")) {
00831             return false;
00832         }
00833 
00834         return x < y;
00835     }
00836 };
00837 
00838 Common::StringArray Saves::list(Common::SaveFileManager *saveFileManager, Common::Platform platform) {
00839     Common::String searchPattern = Saves::buildName("*", platform);
00840     Common::StringArray filenames = saveFileManager->listSavefiles(searchPattern);
00841 
00842     // The saves are sorted alphabetically
00843     Common::sort(filenames.begin(), filenames.end(), AutosaveFirstComparator());
00844 
00845     // The MetaEngine save system expects the Autosave to be in slot 0
00846     // if we don't have an autosave (yet), insert a fake one.
00847     if (!filenames.empty() && !filenames[0].hasPrefixIgnoreCase("autosave.")) {
00848         filenames.insert_at(0, buildName("Autosave", platform));
00849     }
00850 
00851     return filenames;
00852 }
00853 } // End of namespace Myst3


Generated on Sat May 30 2020 05:00:51 for ResidualVM by doxygen 1.7.1
curved edge   curved edge