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


Generated on Sat May 18 2019 05:01:20 for ResidualVM by doxygen 1.7.1
curved edge   curved edge