Initial commit
This commit is contained in:
424
engines/saga2/saga2.cpp
Normal file
424
engines/saga2/saga2.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "saga2/saga2.h"
|
||||
#include "saga2/fta.h"
|
||||
|
||||
#include "saga2/actor.h"
|
||||
#include "saga2/audio.h"
|
||||
#include "saga2/band.h"
|
||||
#include "saga2/beegee.h"
|
||||
#include "saga2/calendar.h"
|
||||
#include "saga2/console.h"
|
||||
#include "saga2/contain.h"
|
||||
#include "saga2/detection.h"
|
||||
#include "saga2/dispnode.h"
|
||||
#include "saga2/gdraw.h"
|
||||
#include "saga2/imagcach.h"
|
||||
#include "saga2/mouseimg.h"
|
||||
#include "saga2/motion.h"
|
||||
#include "saga2/music.h"
|
||||
#include "saga2/panel.h"
|
||||
#include "saga2/spelshow.h"
|
||||
#include "saga2/tilemode.h"
|
||||
#include "saga2/vpal.h"
|
||||
|
||||
namespace Saga2 {
|
||||
|
||||
void main_saga2();
|
||||
|
||||
Saga2Engine *g_vm;
|
||||
|
||||
Saga2Engine::Saga2Engine(OSystem *syst, const SAGA2GameDescription *desc)
|
||||
: Engine(syst), _gameDescription(desc) {
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
|
||||
// Don't forget to register your random source
|
||||
_rnd = new Common::RandomSource("saga2");
|
||||
|
||||
g_vm = this;
|
||||
|
||||
_console = nullptr;
|
||||
_renderer = nullptr;
|
||||
_audio = nullptr;
|
||||
_pal = nullptr;
|
||||
_act = nullptr;
|
||||
_calendar = nullptr;
|
||||
_tmm = nullptr;
|
||||
_cnm = nullptr;
|
||||
|
||||
_bandList = nullptr;
|
||||
_mouseInfo = nullptr;
|
||||
_smkDecoder = nullptr;
|
||||
_videoX = _videoY = 0;
|
||||
_loadedWeapons = 0;
|
||||
|
||||
_gameRunning = true;
|
||||
_autoAggression = true;
|
||||
_autoWeapon = true;
|
||||
_showNight = true;
|
||||
_speechText = true;
|
||||
_speechVoice = true;
|
||||
|
||||
_showPosition = false;
|
||||
_showStats = false;
|
||||
_showStatusMsg = false;
|
||||
_teleportOnClick = false;
|
||||
_teleportOnMap = false;
|
||||
|
||||
_indivControlsFlag = false;
|
||||
_userControlsSetup = false;
|
||||
_fadeDepth = 1;
|
||||
_currentMapNum = 0;
|
||||
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "res");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "dos/drivers"); // For Miles Sound files
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "drivers");
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "video"); // FTA2 movies
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "smack"); // Dino movies
|
||||
|
||||
_loadedWeapons = 0;
|
||||
|
||||
_imageCache = new CImageCache;
|
||||
_mTaskList = new MotionTaskList;
|
||||
_bandList = new BandList();
|
||||
_mainDisplayList = new DisplayNodeList;
|
||||
_activeSpells = new SpellDisplayList(kMaxActiveSpells);
|
||||
_pointer = new gMousePointer(_mainPort);
|
||||
_activeRegionList = new ActiveRegion[kPlayerActors];
|
||||
_toolBase = new gToolBase;
|
||||
_properties = new Properties;
|
||||
_aTaskList = new TileActivityTaskList;
|
||||
_grandMasterFTA = new Deejay;
|
||||
|
||||
_edpList = nullptr;
|
||||
_sdpList = nullptr;
|
||||
_tileImageBanks = nullptr;
|
||||
_stackList = nullptr;
|
||||
_taskList = nullptr;
|
||||
_frate = nullptr;
|
||||
_lrate = nullptr;
|
||||
}
|
||||
|
||||
Saga2Engine::~Saga2Engine() {
|
||||
debug("Saga2Engine::~Saga2Engine");
|
||||
|
||||
freeExeResources();
|
||||
|
||||
// Dispose your resources here
|
||||
delete _rnd;
|
||||
delete _renderer;
|
||||
delete _pal;
|
||||
delete _act;
|
||||
delete _calendar;
|
||||
delete _tmm;
|
||||
delete _cnm;
|
||||
|
||||
delete _imageCache;
|
||||
delete _mTaskList;
|
||||
delete _bandList;
|
||||
delete _mainDisplayList;
|
||||
delete _activeSpells;
|
||||
delete _pointer;
|
||||
delete[] _activeRegionList;
|
||||
delete _toolBase;
|
||||
delete _properties;
|
||||
delete _aTaskList;
|
||||
delete _grandMasterFTA;
|
||||
}
|
||||
|
||||
Common::Error Saga2Engine::run() {
|
||||
// Initialize graphics using following:
|
||||
initGraphics(640, 480);
|
||||
|
||||
_console = new Console(this);
|
||||
setDebugger(_console);
|
||||
|
||||
_renderer = new Renderer();
|
||||
|
||||
_pal = new PaletteManager;
|
||||
_act = new ActorManager;
|
||||
_calendar = new CalendarTime;
|
||||
_tmm = new TileModeManager;
|
||||
_cnm = new ContainerManager;
|
||||
|
||||
readConfig();
|
||||
|
||||
if (getGameId() == GID_FTA2)
|
||||
loadExeResources();
|
||||
// TODO: Load EXE resources for Dino
|
||||
|
||||
main_saga2();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool Saga2Engine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsSubtitleOptions);
|
||||
}
|
||||
|
||||
int Saga2Engine::getGameId() const {
|
||||
return _gameDescription->gameId;
|
||||
}
|
||||
|
||||
const ADGameFileDescription *Saga2Engine::getFilesDescriptions() const {
|
||||
return _gameDescription->desc.filesDescriptions;
|
||||
}
|
||||
|
||||
Common::Error Saga2Engine::loadGameStream(Common::SeekableReadStream *stream) {
|
||||
Common::Serializer s(stream, nullptr);
|
||||
syncGameStream(s);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error Saga2Engine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
||||
Common::Serializer s(nullptr, stream);
|
||||
syncGameStream(s);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::String Saga2Engine::getSavegameFile(int slot) {
|
||||
return getMetaEngine()->getSavegameFile(slot, _targetName.c_str());
|
||||
}
|
||||
|
||||
Common::Error Saga2Engine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
pauseTimer();
|
||||
|
||||
Common::OutSaveFile *outS = getSaveFileManager()->openForSaving(getSavegameFile(slot), false);
|
||||
if (!outS)
|
||||
return Common::kCreatingFileFailed;
|
||||
|
||||
saveGame(outS, desc);
|
||||
|
||||
outS->write("SCVM", 4);
|
||||
CHUNK_BEGIN;
|
||||
uint32 pos = outS->pos() + 4;
|
||||
|
||||
_renderer->saveBackBuffer(kBeforeTakingThumbnail);
|
||||
|
||||
if (_renderer->hasSavedBackBuffer(kBeforeOpeningMenu))
|
||||
_renderer->popSavedBackBuffer(kBeforeOpeningMenu);
|
||||
|
||||
getMetaEngine()->appendExtendedSaveToStream(out, g_vm->getTotalPlayTime() / 1000, desc, isAutosave, pos);
|
||||
|
||||
_renderer->popSavedBackBuffer(kBeforeTakingThumbnail);
|
||||
CHUNK_END;
|
||||
|
||||
outS->finalize();
|
||||
|
||||
delete outS;
|
||||
|
||||
resumeTimer();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error Saga2Engine::loadGameState(int slot) {
|
||||
loadGame(slot);
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void Saga2Engine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
|
||||
_speechText = true;
|
||||
|
||||
if (ConfMan.hasKey("subtitles"))
|
||||
_speechText = ConfMan.getBool("subtitles");
|
||||
|
||||
_speechVoice = true;
|
||||
|
||||
if (ConfMan.hasKey("speech_mute"))
|
||||
_speechVoice = !ConfMan.getBool("speech_mute");
|
||||
|
||||
if (_audio)
|
||||
_audio->_music->syncSoundSettings();
|
||||
}
|
||||
|
||||
void Saga2Engine::syncGameStream(Common::Serializer &s) {
|
||||
// Use methods of Serializer to save/load fields
|
||||
int dummy = 0;
|
||||
s.syncAsUint16LE(dummy);
|
||||
}
|
||||
|
||||
int32 clamp(int32 a, int32 val, int32 c) {
|
||||
if (val < a) return a;
|
||||
if (val > c) return c;
|
||||
return val;
|
||||
}
|
||||
|
||||
gFont Onyx10Font;
|
||||
gFont Plate18Font;
|
||||
gFont Helv11Font;
|
||||
gFont Amber13Font;
|
||||
gFont ThinFix8Font;
|
||||
gFont Script10Font;
|
||||
|
||||
uint32 loadingWindowWidth = 640;
|
||||
uint32 loadingWindowHeight = 480;
|
||||
|
||||
uint8 *loadingWindowPalette;
|
||||
uint8 *loadingWindowData;
|
||||
|
||||
uint8 *ColorMapRanges;
|
||||
|
||||
uint8 *closeBx1ImageData;
|
||||
uint8 *closeBx2ImageData;
|
||||
uint8 *usePtrImageData;
|
||||
uint8 *xPointerImageData;
|
||||
uint8 *arrowImageData;
|
||||
uint8 *grabPtrImageData;
|
||||
uint8 *attakPtrImageData;
|
||||
uint8 *centerActorIndicatorImageData;
|
||||
uint8 *pgUpImageData;
|
||||
uint8 *pgDownImageData;
|
||||
uint8 *pgLeftImageData;
|
||||
uint8 *pgRightImageData;
|
||||
uint8 *autoWalkImageData;
|
||||
uint8 *gaugeImageData;
|
||||
|
||||
static void loadFont(Common::File &file, gFont *font, uint32 offset) {
|
||||
file.seek(offset);
|
||||
|
||||
font->height = file.readUint16LE();
|
||||
font->baseLine = file.readUint16LE();
|
||||
font->rowMod = file.readUint16LE();
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
font->charXOffset[i] = file.readUint16LE();
|
||||
|
||||
file.read(font->charWidth, 256);
|
||||
file.read(font->charKern, 256);
|
||||
file.read(font->charSpace, 256);
|
||||
|
||||
uint size = font->height * font->rowMod;
|
||||
|
||||
font->fontdata = (byte *)malloc(size);
|
||||
file.read(font->fontdata, size);
|
||||
}
|
||||
|
||||
struct dataChunks {
|
||||
uint8 **ptr;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
} chunks[] = {
|
||||
{ (uint8 **)&Onyx10Font, 0x004F7258, 0 },
|
||||
{ (uint8 **)&Plate18Font, 0x004F7EE0, 0 },
|
||||
{ (uint8 **)&Helv11Font, 0x004F9F30, 0 },
|
||||
{ (uint8 **)&Amber13Font, 0x004FAC60, 0 },
|
||||
{ (uint8 **)&ThinFix8Font, 0x004FC210, 0 },
|
||||
{ (uint8 **)&Script10Font, 0x004FCD18, 0 },
|
||||
{ &loadingWindowPalette, 0x004A2600, 1024 },
|
||||
{ &loadingWindowData, 0x004A2A00, 307200 },
|
||||
{ &ColorMapRanges, 0x004EDC20, 1584 },
|
||||
{ &closeBx1ImageData, 0x004EE2B8, 144 },
|
||||
{ &closeBx2ImageData, 0x004EE348, 144 },
|
||||
{ &usePtrImageData, 0x004EE3D8, 232 },
|
||||
{ &xPointerImageData, 0x004EE4C0, 232 },
|
||||
{ &arrowImageData, 0x004EE5A8, 192 },
|
||||
{ &grabPtrImageData, 0x004EE668, 208 },
|
||||
{ &attakPtrImageData, 0x004EE738, 536 },
|
||||
{ ¢erActorIndicatorImageData,0x004EE950, 96 },
|
||||
{ &pgUpImageData, 0x004EE9B0, 256 },
|
||||
{ &pgDownImageData, 0x004EEAB0, 256 },
|
||||
{ &pgLeftImageData, 0x004EEBB0, 256 },
|
||||
{ &pgRightImageData, 0x004EECB0, 256 },
|
||||
{ &autoWalkImageData, 0x004EEDB0, 228 },
|
||||
{ &gaugeImageData, 0x004EF257, 241 },
|
||||
{ nullptr, 0, 0 }
|
||||
};
|
||||
|
||||
void Saga2Engine::loadExeResources() {
|
||||
Common::File exe;
|
||||
const uint32 offset = 0x4F6D90 - 0xF4990;
|
||||
|
||||
if (!(exe.open("win/fta2win.exe") || exe.open("fta2win.exe")))
|
||||
error("FTA2WIN.EXE file is missing");
|
||||
|
||||
if (exe.size() != 1093120)
|
||||
error("Incorrect FTA2WIN.EXE file size. Expected is 1093120");
|
||||
|
||||
for (int i = 0; chunks[i].ptr; i++) {
|
||||
if (chunks[i].size == 0) { // Font
|
||||
loadFont(exe, (gFont *)chunks[i].ptr, chunks[i].offset - offset);
|
||||
} else {
|
||||
*chunks[i].ptr = (uint8 *)malloc(chunks[i].size);
|
||||
exe.seek(chunks[i].offset - offset);
|
||||
exe.read(*chunks[i].ptr, chunks[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
initCursors();
|
||||
|
||||
exe.close();
|
||||
}
|
||||
|
||||
void Saga2Engine::freeExeResources() {
|
||||
for (int i = 0; chunks[i].ptr; i++)
|
||||
if (chunks[i].size == 0) // Font
|
||||
free(((gFont *)chunks[i].ptr)->fontdata);
|
||||
else
|
||||
free(*chunks[i].ptr);
|
||||
|
||||
freeCursors();
|
||||
}
|
||||
|
||||
void Saga2Engine::readConfig() {
|
||||
_autoWeapon = true;
|
||||
|
||||
if (ConfMan.hasKey("auto_weapon"))
|
||||
_autoWeapon = ConfMan.getBool("auto_weapon");
|
||||
|
||||
_autoAggression = true;
|
||||
|
||||
if (ConfMan.hasKey("auto_aggression"))
|
||||
_autoAggression = ConfMan.getBool("auto_aggression");
|
||||
|
||||
_showNight = true;
|
||||
|
||||
if (ConfMan.hasKey("show_night"))
|
||||
_showNight = ConfMan.getBool("show_night");
|
||||
|
||||
syncSoundSettings();
|
||||
}
|
||||
|
||||
void Saga2Engine::saveConfig() {
|
||||
ConfMan.flushToDisk();
|
||||
}
|
||||
|
||||
} // End of namespace Saga2
|
||||
Reference in New Issue
Block a user