aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute
diff options
context:
space:
mode:
Diffstat (limited to 'engines/wintermute')
-rw-r--r--engines/wintermute/ad/ad_actor.cpp52
-rw-r--r--engines/wintermute/ad/ad_entity.cpp79
-rw-r--r--engines/wintermute/ad/ad_entity.h10
-rw-r--r--engines/wintermute/ad/ad_game.cpp13
-rw-r--r--engines/wintermute/ad/ad_item.cpp34
-rw-r--r--engines/wintermute/ad/ad_response_box.cpp29
-rw-r--r--engines/wintermute/base/base_engine.h15
-rw-r--r--engines/wintermute/base/base_file_manager.cpp15
-rw-r--r--engines/wintermute/base/base_file_manager.h3
-rw-r--r--engines/wintermute/base/base_frame.cpp8
-rw-r--r--engines/wintermute/base/base_game.cpp310
-rw-r--r--engines/wintermute/base/base_keyboard_state.cpp605
-rw-r--r--engines/wintermute/base/base_keyboard_state.h12
-rw-r--r--engines/wintermute/base/base_persistence_manager.h1
-rw-r--r--engines/wintermute/base/base_sub_frame.cpp59
-rw-r--r--engines/wintermute/base/file/base_package.cpp2
-rw-r--r--engines/wintermute/base/file/base_package.h3
-rw-r--r--engines/wintermute/base/font/base_font_bitmap.cpp47
-rw-r--r--engines/wintermute/base/gfx/base_renderer.cpp29
-rw-r--r--engines/wintermute/base/gfx/base_renderer.h3
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp10
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.h1
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.h11
-rw-r--r--engines/wintermute/base/saveload.cpp32
-rw-r--r--engines/wintermute/base/saveload.h3
-rw-r--r--engines/wintermute/base/scriptables/script.cpp9
-rw-r--r--engines/wintermute/base/scriptables/script_ext_array.cpp34
-rw-r--r--engines/wintermute/configure.engine3
-rw-r--r--engines/wintermute/detection_tables.h274
-rw-r--r--engines/wintermute/wintermute.cpp15
30 files changed, 1274 insertions, 447 deletions
diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp
index 75e7c45d7e..a598581632 100644
--- a/engines/wintermute/ad/ad_actor.cpp
+++ b/engines/wintermute/ad/ad_actor.cpp
@@ -34,6 +34,7 @@
#include "engines/wintermute/ad/ad_waypoint_group.h"
#include "engines/wintermute/ad/ad_path.h"
#include "engines/wintermute/ad/ad_sentence.h"
+#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_region.h"
@@ -919,7 +920,7 @@ void AdActor::getNextStep() {
//////////////////////////////////////////////////////////////////////////
void AdActor::initLine(const BasePoint &startPt, const BasePoint &endPt) {
- _pFCount = MAX((abs(endPt.x - startPt.x)) , (abs(endPt.y - startPt.y)));
+ _pFCount = MAX((abs(endPt.x - startPt.x)), (abs(endPt.y - startPt.y)));
_pFStepX = (double)(endPt.x - startPt.x) / _pFCount;
_pFStepY = (double)(endPt.y - startPt.y) / _pFCount;
@@ -1022,6 +1023,55 @@ bool AdActor::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] StopWalking
+ // Used to stop Leah in one scene only at rabbit_run.script in action()
+ // Let's just call turnTo() for current direction to finalize movement
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "StopWalking") == 0) {
+ stack->correctParams(0);
+ turnTo(_dir);
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] SetSpeedWalkAnim
+ // Used to set Leah speed at leah.script in SetSpeed()
+ // Modifies walking animations interframe delays
+ // Takes integer parameter:
+ // 10 on state.ultra_super_mega_fast_walk cheat code
+ // 40 on "Fast" settings
+ // 70 on "Normal" settings
+ // 90 on "Slow" settings
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetSpeedWalkAnim") == 0) {
+ stack->correctParams(1);
+ int speedWalk = stack->pop()->getInt();
+ for (uint32 dir = 0; dir < NUM_DIRECTIONS; dir++) {
+ AdSpriteSet *anim = getAnimByName(_walkAnimName);
+ if (anim != nullptr) {
+ BaseSprite *item = anim->getSprite((TDirection)dir);
+ if (item != nullptr) {
+ for (uint32 i = 0; i < item->_frames.size(); i++) {
+ BaseFrame *frame = item->_frames[i];
+ if (frame != nullptr) {
+ frame->_delay = speedWalk;
+ }
+ }
+ }
+ }
+ }
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// MergeAnims
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp
index 7a4df6c114..ea7c46c5ac 100644
--- a/engines/wintermute/ad/ad_entity.cpp
+++ b/engines/wintermute/ad/ad_entity.cpp
@@ -34,6 +34,7 @@
#include "engines/wintermute/ad/ad_sentence.h"
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_parser.h"
@@ -67,6 +68,10 @@ AdEntity::AdEntity(BaseGame *inGame) : AdTalkHolder(inGame) {
_walkToX = _walkToY = 0;
_walkToDir = DI_NONE;
+#ifdef ENABLE_FOXTAIL
+ _hintX = _hintY = -1;
+#endif
+
_theora = nullptr;
}
@@ -98,6 +103,16 @@ const char *AdEntity::getItemName() const {
return _item;
}
+#ifdef ENABLE_FOXTAIL
+int32 AdEntity::getHintX() const {
+ return _hintX;
+}
+
+int32 AdEntity::getHintY() const {
+ return _hintY;
+}
+#endif
+
//////////////////////////////////////////////////////////////////////////
bool AdEntity::loadFile(const char *filename) {
char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename);
@@ -164,6 +179,10 @@ TOKEN_DEF(WALK_TO_X)
TOKEN_DEF(WALK_TO_Y)
TOKEN_DEF(WALK_TO_DIR)
TOKEN_DEF(SAVE_STATE)
+#ifdef ENABLE_FOXTAIL
+TOKEN_DEF(HINT_X)
+TOKEN_DEF(HINT_Y)
+#endif
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////////
bool AdEntity::loadBuffer(char *buffer, bool complete) {
@@ -210,6 +229,10 @@ bool AdEntity::loadBuffer(char *buffer, bool complete) {
TOKEN_TABLE(WALK_TO_Y)
TOKEN_TABLE(WALK_TO_DIR)
TOKEN_TABLE(SAVE_STATE)
+#ifdef ENABLE_FOXTAIL
+ TOKEN_TABLE(HINT_X)
+ TOKEN_TABLE(HINT_Y)
+#endif
TOKEN_TABLE_END
char *params;
@@ -487,6 +510,14 @@ bool AdEntity::loadBuffer(char *buffer, bool complete) {
i = DI_NONE;
}
_walkToDir = (TDirection)i;
+#ifdef ENABLE_FOXTAIL
+ case TOKEN_HINT_X:
+ parser.scanStr(params, "%d", &_hintX);
+ break;
+ case TOKEN_HINT_Y:
+ parser.scanStr(params, "%d", &_hintY);
+ break;
+#endif
}
break;
@@ -900,6 +931,24 @@ ScValue *AdEntity::scGetProperty(const Common::String &name) {
return _scValue;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] HintX
+ //////////////////////////////////////////////////////////////////////////
+ else if (name == "HintX") {
+ _scValue->setInt(_hintX);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] HintY
+ //////////////////////////////////////////////////////////////////////////
+ else if (name == "HintY") {
+ _scValue->setInt(_hintY);
+ return _scValue;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// WalkToDirection
//////////////////////////////////////////////////////////////////////////
@@ -951,6 +1000,24 @@ bool AdEntity::scSetProperty(const char *name, ScValue *value) {
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] HintX
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "HintX") == 0) {
+ _hintX = value->getInt();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HintY
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "HintY") == 0) {
+ _hintY = value->getInt();
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// WalkToDirection
//////////////////////////////////////////////////////////////////////////
@@ -1012,6 +1079,11 @@ bool AdEntity::saveAsText(BaseDynamicBuffer *buffer, int indent) {
buffer->putTextIndent(indent + 2, "WALK_TO_DIR=%d\n", (int)_walkToDir);
}
+#ifdef ENABLE_FOXTAIL
+ buffer->putTextIndent(indent + 2, "HINT_X=%d\n", _hintX);
+ buffer->putTextIndent(indent + 2, "HINT_Y=%d\n", _hintY);
+#endif
+
for (uint32 i = 0; i < _scripts.size(); i++) {
buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
}
@@ -1108,6 +1180,13 @@ bool AdEntity::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferPtr(TMEMBER_PTR(_theora));
+#ifdef ENABLE_FOXTAIL
+ if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_527, FOXTAIL_LATEST_VERSION)) {
+ persistMgr->transferSint32(TMEMBER(_hintX));
+ persistMgr->transferSint32(TMEMBER(_hintY));
+ }
+#endif
+
return STATUS_OK;
}
diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h
index 678608af36..5407093915 100644
--- a/engines/wintermute/ad/ad_entity.h
+++ b/engines/wintermute/ad/ad_entity.h
@@ -55,6 +55,11 @@ public:
TDirection getWalkToDir() const;
const char* getItemName() const;
+#ifdef ENABLE_FOXTAIL
+ int32 getHintX() const;
+ int32 getHintY() const;
+#endif
+
// scripting interface
virtual ScValue *scGetProperty(const Common::String &name) override;
virtual bool scSetProperty(const char *name, ScValue *value) override;
@@ -67,6 +72,11 @@ private:
TDirection _walkToDir;
char *_item;
TEntityType _subtype;
+
+#ifdef ENABLE_FOXTAIL
+ int32 _hintX;
+ int32 _hintY;
+#endif
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp
index dff0216c10..a6730feecd 100644
--- a/engines/wintermute/ad/ad_game.cpp
+++ b/engines/wintermute/ad/ad_game.cpp
@@ -873,6 +873,19 @@ bool AdGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] SetInventoryBoxHideSelected
+ // Used while changing cursor type at some included script
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetInventoryBoxHideSelected") == 0) {
+ stack->correctParams(1);
+ _inventoryBox->_hideSelected = stack->pop()->getBool(false);
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+#endif
else {
return BaseGame::scCallMethod(script, stack, thisStack, name);
diff --git a/engines/wintermute/ad/ad_item.cpp b/engines/wintermute/ad/ad_item.cpp
index b414fbdadf..cebc6980d9 100644
--- a/engines/wintermute/ad/ad_item.cpp
+++ b/engines/wintermute/ad/ad_item.cpp
@@ -535,6 +535,23 @@ bool AdItem::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] RemoveNormalCursor
+ // Used while changing cursor type at some included script
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "RemoveNormalCursor") == 0) {
+ stack->correctParams(0);
+
+ delete _cursorNormal;
+ _cursorNormal = nullptr;
+
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// GetNormalCursor
//////////////////////////////////////////////////////////////////////////
@@ -584,6 +601,23 @@ bool AdItem::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] RemoveHoverCursor
+ // Used while changing cursor type at some included script
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "RemoveHoverCursor") == 0) {
+ stack->correctParams(0);
+
+ delete _cursorHover;
+ _cursorHover = nullptr;
+
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// GetHoverCursor
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/ad/ad_response_box.cpp b/engines/wintermute/ad/ad_response_box.cpp
index fc8e778f37..bd4ae50eab 100644
--- a/engines/wintermute/ad/ad_response_box.cpp
+++ b/engines/wintermute/ad/ad_response_box.cpp
@@ -29,6 +29,7 @@
#include "engines/wintermute/ad/ad_game.h"
#include "engines/wintermute/ad/ad_response.h"
#include "engines/wintermute/ad/ad_response_box.h"
+#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_parser.h"
@@ -190,6 +191,18 @@ bool AdResponseBox::createButtons() {
btn->setWidth(width);
}
}
+
+#ifdef ENABLE_FOXTAIL
+ if (BaseEngine::instance().isFoxTail()) {
+ btn->addScript("interface/scripts/dialogue_button.script");
+ btn->setWidth(120);
+ if (_fontHover == nullptr) {
+ btn->setFontHover(btn->getFont());
+ btn->setFontPress(btn->getFontHover());
+ }
+ }
+#endif
+
btn->setName("response");
btn->correctSize();
@@ -500,6 +513,22 @@ bool AdResponseBox::display() {
// prepare response buttons
bool scrollNeeded = false;
for (i = _scrollOffset; i < _respButtons.size(); i++) {
+
+#ifdef ENABLE_FOXTAIL
+ // FoxTail's "HORIZONTAL=TRUE" display boxes are actual 2x3 display boxes
+ // Tests show that this hack was removed in FOXTAIL_1_2_362
+ if (_horizontal && BaseEngine::instance().isFoxTail(FOXTAIL_OLDEST_VERSION, FOXTAIL_1_2_304)) {
+ if (i >= _scrollOffset + 6) {
+ scrollNeeded = true;
+ break;
+ }
+ _respButtons[i]->setVisible(true);
+ _respButtons[i]->_posX = 55 + 120 * (i / 3);
+ _respButtons[i]->_posY = 100 + 10 * (i % 3);
+ continue;
+ }
+#endif
+
if ((_horizontal && xxx + _respButtons[i]->getWidth() > rect.right)
|| (!_horizontal && yyy + _respButtons[i]->getHeight() > rect.bottom)) {
diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h
index a8770f6168..14a14a3c19 100644
--- a/engines/wintermute/base/base_engine.h
+++ b/engines/wintermute/base/base_engine.h
@@ -84,7 +84,14 @@ enum WMETargetExecutable {
WME_1_9_2, // DEAD:CODE 2010
WME_1_9_3, // DEAD:CODE 2012, released as "1.10.1 beta"
WME_LITE,
- LATEST_VERSION
+ LATEST_VERSION,
+ FOXTAIL_OLDEST_VERSION,
+ FOXTAIL_1_2_227,
+ FOXTAIL_1_2_230,
+ FOXTAIL_1_2_304,
+ FOXTAIL_1_2_362,
+ FOXTAIL_1_2_527,
+ FOXTAIL_LATEST_VERSION
};
class BaseFileManager;
@@ -129,6 +136,12 @@ public:
WMETargetExecutable getTargetExecutable() const {
return _targetExecutable;
}
+ static bool isFoxTailCheck(WMETargetExecutable t, WMETargetExecutable v1=FOXTAIL_OLDEST_VERSION, WMETargetExecutable v2=FOXTAIL_LATEST_VERSION) {
+ return t >= v1 && t <= v2;
+ }
+ bool isFoxTail(WMETargetExecutable v1=FOXTAIL_OLDEST_VERSION, WMETargetExecutable v2=FOXTAIL_LATEST_VERSION) const {
+ return isFoxTailCheck(_targetExecutable, v1, v2);
+ }
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp
index dad8b43d65..6102c10725 100644
--- a/engines/wintermute/base/base_file_manager.cpp
+++ b/engines/wintermute/base/base_file_manager.cpp
@@ -300,7 +300,7 @@ bool BaseFileManager::registerPackages() {
}
}
debugC(kWintermuteDebugFileAccess, "Registering %s %s", fileIt->getPath().c_str(), fileIt->getName().c_str());
- registerPackage((*fileIt), "", searchSignature);
+ registerPackage((*fileIt), fileName, searchSignature);
}
}
@@ -311,7 +311,8 @@ bool BaseFileManager::registerPackages() {
bool BaseFileManager::registerPackage(Common::FSNode file, const Common::String &filename, bool searchSignature) {
PackageSet *pack = new PackageSet(file, filename, searchSignature);
- _packages.add(file.getName(), pack, pack->getPriority() , true);
+ _packages.add(filename, pack, pack->getPriority() , true);
+ _versions[filename] = pack->getVersion();
return STATUS_OK;
}
@@ -348,6 +349,16 @@ Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &f
return file;
}
+//////////////////////////////////////////////////////////////////////////
+uint32 BaseFileManager::getPackageVersion(const Common::String &filename) {
+ Common::HashMap<Common::String, uint32>::iterator it = _versions.find(filename);
+ if (it != _versions.end()) {
+ return it->_value;
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::hasFile(const Common::String &filename) {
if (scumm_strnicmp(filename.c_str(), "savegame:", 9) == 0) {
BasePersistenceManager pm(BaseEngine::instance().getGameTargetName());
diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h
index 85181f1f58..397e38cc3d 100644
--- a/engines/wintermute/base/base_file_manager.h
+++ b/engines/wintermute/base/base_file_manager.h
@@ -46,6 +46,7 @@ public:
Common::SeekableReadStream *openFile(const Common::String &filename, bool absPathWarning = true, bool keepTrackOf = true);
Common::WriteStream *openFileForWrite(const Common::String &filename);
byte *readWholeFile(const Common::String &filename, uint32 *size = nullptr, bool mustExist = true);
+ uint32 getPackageVersion(const Common::String &filename);
BaseFileManager(Common::Language lang, bool detectionMode = false);
virtual ~BaseFileManager();
@@ -72,6 +73,8 @@ private:
Common::Array<Common::SeekableReadStream *> _openFiles;
Common::Language _language;
Common::Archive *_resources;
+ Common::HashMap<Common::String, uint32> _versions;
+
// This class is intentionally not a subclass of Base, as it needs to be used by
// the detector too, without launching the entire engine:
};
diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp
index a821234ba0..6aa9785d84 100644
--- a/engines/wintermute/base/base_frame.cpp
+++ b/engines/wintermute/base/base_frame.cpp
@@ -174,7 +174,7 @@ bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
int r = 255, g = 255, b = 255;
int ar = 255, ag = 255, ab = 255, alpha = 255;
int hotspotX = 0, hotspotY = 0;
- bool custoTrans = false;
+ bool customTrans = false;
bool editorSelected = false;
bool is2DOnly = false;
bool is3DOnly = false;
@@ -196,7 +196,7 @@ bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
- custoTrans = true;
+ customTrans = true;
break;
case TOKEN_RECT:
@@ -310,7 +310,7 @@ bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
BaseSubFrame *sub = new BaseSubFrame(_gameRef);
if (surface_file != nullptr) {
- if (custoTrans) {
+ if (customTrans) {
sub->setSurface(surface_file, false, r, g, b, lifeTime, keepLoaded);
} else {
sub->setSurface(surface_file, true, 0, 0, 0, lifeTime, keepLoaded);
@@ -323,7 +323,7 @@ bool BaseFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
}
sub->_alpha = BYTETORGBA(ar, ag, ab, alpha);
- if (custoTrans) {
+ if (customTrans) {
sub->_transparent = BYTETORGBA(r, g, b, 0xFF);
}
}
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp
index a06511f3ea..f5caaa8d2e 100644
--- a/engines/wintermute/base/base_game.cpp
+++ b/engines/wintermute/base/base_game.cpp
@@ -48,6 +48,7 @@
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/saveload.h"
#include "engines/wintermute/base/save_thumb_helper.h"
+#include "engines/wintermute/base/scriptables/script_ext_array.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
@@ -1259,6 +1260,21 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] RegistryFlush
+ // Return value is never used
+ // Used at SaveGameSettings() and Game.RegistryFlush()
+ // Called after a series of RegWriteNumber calls
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "RegistryFlush") == 0) {
+ stack->correctParams(0);
+ ConfMan.flushToDisk();
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// RegWriteNumber
//////////////////////////////////////////////////////////////////////////
@@ -1362,13 +1378,54 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
else if (strcmp(name, "GetSaveSlotDescription") == 0) {
stack->correctParams(1);
int slot = stack->pop()->getInt();
- char desc[512];
- desc[0] = '\0';
- SaveLoad::getSaveSlotDescription(slot, desc);
- stack->pushString(desc);
+ Common::String desc = SaveLoad::getSaveSlotDescription(slot);
+ stack->pushString(desc.c_str());
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetSaveSlotDescriptionTimestamp
+ // Return struct with "Description" and "Timestamp" fields in 1.2.362-
+ // Return array with "Description" and "Timestamp" items in 1.2.527+
+ // Timestamps should be comparable types
+ // Used to sort saved games by timestamps at save.script & load.script
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetSaveSlotDescriptionTimestamp") == 0) {
+ stack->correctParams(1);
+ int slot = stack->pop()->getInt();
+
+ TimeDate time;
+ SaveLoad::getSaveSlotTimestamp(slot, &time);
+ stack->pushInt(time.tm_sec);
+ stack->pushInt(time.tm_min);
+ stack->pushInt(time.tm_hour);
+ stack->pushInt(time.tm_mday);
+ stack->pushInt(time.tm_mon + 1);
+ stack->pushInt(time.tm_year + 1900);
+ stack->pushInt(6);
+ BaseScriptable *date = makeSXDate(_gameRef, stack);
+ stack->pushNative(date, false);
+
+ Common::String desc = SaveLoad::getSaveSlotDescription(slot);
+ stack->pushString(desc.c_str());
+
+ BaseScriptable *obj;
+ if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_527, FOXTAIL_LATEST_VERSION)) {
+ stack->pushInt(2);
+ obj = makeSXArray(_gameRef, stack);
+ } else {
+ stack->pushInt(0);
+ obj = makeSXObject(_gameRef, stack);
+ obj->scSetProperty("Description", stack->pop());
+ obj->scSetProperty("Timestamp", stack->pop());
+ }
+ stack->pushNative(obj, false);
+
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// EmptySaveSlot
//////////////////////////////////////////////////////////////////////////
@@ -1941,6 +1998,96 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetScreenType
+ // Returns 0 on fullscreen and 1 on window
+ // Used to init and update controls at options.script and methods.script
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetScreenType") == 0) {
+ stack->correctParams(0);
+ int type = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
+ stack->pushInt(type);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetScreenMode
+ // Returns integer to be used as a pixelization mode multiplier
+ // (e.g. it returns 2 for 640x360, 3 for 960x540, etc...)
+ // Used to init and update controls at options.script and methods.script
+ // This implementation always return 2 to fake window size of 2*320 x 2*180
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetScreenMode") == 0) {
+ stack->correctParams(0);
+ stack->pushInt(2);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetDesktopDisplayMode
+ // Return struct with "w" and "h" fields in 1.2.362-
+ // Return array with "w" and "h" items in 1.2.527+
+ // Used to init and update controls at options.script and methods.script
+ // w,h of actual desktop size expected to calcucate maximum available size
+ // Available screen modes are calcucated as 2...N, N*320<w and N*180<h
+ // This implementation fakes available size as 2*320 x 2*180 only
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetDesktopDisplayMode") == 0) {
+ stack->correctParams(0);
+ stack->pushInt(2 * 180 + 1);
+ stack->pushInt(2 * 320 + 1);
+
+ BaseScriptable *obj;
+ if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_527, FOXTAIL_LATEST_VERSION)) {
+ stack->pushInt(2);
+ obj = makeSXArray(_gameRef, stack);
+ } else {
+ stack->pushInt(0);
+ obj = makeSXObject(_gameRef, stack);
+ obj->scSetProperty("w", stack->pop());
+ obj->scSetProperty("h", stack->pop());
+ }
+ stack->pushNative(obj, false);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] SetScreenTypeMode
+ // This implementation ignores mode, toggles screen type only
+ // Used to change screen type&mode at options.script and methods.script
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetScreenTypeMode") == 0) {
+ stack->correctParams(2);
+ int type = stack->pop()->getInt();
+ stack->pop()->getInt(); //mode is unused
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !type);
+ g_system->endGFXTransaction();
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] ChangeWindowGrab
+ // Used at game.script on "Keypress" event on F11
+ // Readme of FoxTail says: "F11 - free the mouse pointer from the window"
+ // This implementation does nothing
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "ChangeWindowGrab") == 0) {
+ stack->correctParams(0);
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// ShowStatusLine
//////////////////////////////////////////////////////////////////////////
@@ -2329,6 +2476,123 @@ ScValue *BaseGame::scGetProperty(const Common::String &name) {
return _scValue;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] SystemLanguage (RO)
+ // Returns Steam API language name string
+ //////////////////////////////////////////////////////////////////////////
+ else if (name == "SystemLanguage") {
+ switch (Common::parseLanguage(ConfMan.get("language"))) {
+ case Common::CZ_CZE:
+ _scValue->setString("czech");
+ break;
+ case Common::DA_DAN:
+ _scValue->setString("danish");
+ break;
+ case Common::DE_DEU:
+ _scValue->setString("german");
+ break;
+ case Common::ES_ESP:
+ _scValue->setString("spanish");
+ break;
+ case Common::FI_FIN:
+ _scValue->setString("finnish");
+ break;
+ case Common::FR_FRA:
+ _scValue->setString("french");
+ break;
+ case Common::GR_GRE:
+ _scValue->setString("greek");
+ break;
+ case Common::HU_HUN:
+ _scValue->setString("hungarian");
+ break;
+ case Common::IT_ITA:
+ _scValue->setString("italian");
+ break;
+ case Common::JA_JPN:
+ _scValue->setString("japanese");
+ break;
+ case Common::KO_KOR:
+ _scValue->setString("koreana");
+ break;
+ case Common::NB_NOR:
+ _scValue->setString("norwegian");
+ break;
+ case Common::NL_NLD:
+ _scValue->setString("dutch");
+ break;
+ case Common::PT_BRA:
+ _scValue->setString("brazilian");
+ break;
+ case Common::PT_POR:
+ _scValue->setString("portuguese");
+ break;
+ case Common::PL_POL:
+ _scValue->setString("polish");
+ break;
+ case Common::RU_RUS:
+ _scValue->setString("russian");
+ break;
+ case Common::SE_SWE:
+ _scValue->setString("swedish");
+ break;
+ case Common::UA_UKR:
+ _scValue->setString("ukrainian");
+ break;
+ case Common::ZH_CNA:
+ _scValue->setString("schinese");
+ break;
+ case Common::ZH_TWN:
+ _scValue->setString("tchinese");
+ break;
+ default:
+ _scValue->setString("english");
+ break;
+ }
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] BuildVersion (RO)
+ // Used to display full game version at options.script in UpdateControls()
+ // Returns FoxTail engine version number as a dotted string
+ //////////////////////////////////////////////////////////////////////////
+ else if (name == "BuildVersion") {
+ if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_227) {
+ _scValue->setString("1.2.227");
+ } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_230) {
+ _scValue->setString("1.2.230");
+ } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_304) {
+ _scValue->setString("1.2.304");
+ } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_362) {
+ _scValue->setString("1.2.362");
+ } else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_527) {
+ _scValue->setString("1.2.527");
+ } else {
+ _scValue->setString("UNKNOWN");
+ }
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GameVersion (RO)
+ // Used to display full game version at options.script in UpdateControls()
+ // Returns FoxTail version number as a string
+ //////////////////////////////////////////////////////////////////////////
+ else if (name == "GameVersion") {
+ uint32 gameVersion = 0;
+ BaseFileManager *fileManager = BaseEngine::instance().getFileManager();
+ if (fileManager) {
+ gameVersion = fileManager->getPackageVersion("data.dcp");
+ }
+ char tmp[16];
+ sprintf(tmp,"%u",gameVersion);
+ _scValue->setString(tmp);
+ return _scValue;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// Platform (RO)
//////////////////////////////////////////////////////////////////////////
@@ -2997,6 +3261,44 @@ bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack
stack->pushBool(val);
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] Split
+ // Returns array of words of a string, using another as a delimeter
+ // Used to split strings by 1 character delimeter in various scripts
+ // All the delimeters ever used in FoxTail are: " ", "@", "#", "$", "&"
+ // So, this implementation takes 1st char of delimeter string only
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Split") == 0) {
+ stack->correctParams(2);
+ const char *str = stack->pop()->getString();
+ const char sep = stack->pop()->getString()[0];
+ size_t size = strlen(str) + 1;
+
+ // There is no way to makeSXArray() with exactly 1 given element
+ // That's why we are creating empty Array and SXArray::push() later
+ stack->pushInt(0);
+ BaseScriptable *arr = makeSXArray(_gameRef, stack);
+
+ // Iterating string copy, replacing delimeter with '\0' and pushing matches
+ char *copy = new char[size];
+ strcpy(copy, str);
+ char *begin = copy;
+ for (char *it = copy; it < copy + size; it++) {
+ if (*it == sep || *it == '\0') {
+ *it = '\0';
+ stack->pushString(begin);
+ ((SXArray *)arr)->push(stack->pop());
+ begin = it + 1;
+ }
+ }
+
+ stack->pushNative(arr, false);
+
+ delete[] copy;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// failure
else {
diff --git a/engines/wintermute/base/base_keyboard_state.cpp b/engines/wintermute/base/base_keyboard_state.cpp
index 13b753a7d6..502577c656 100644
--- a/engines/wintermute/base/base_keyboard_state.cpp
+++ b/engines/wintermute/base/base_keyboard_state.cpp
@@ -39,8 +39,207 @@ namespace Wintermute {
IMPLEMENT_PERSISTENT(BaseKeyboardState, false)
+// Used in WME 1.x
+// See "MSDN: Virtual-Key Codes" for more details on original WME keycodes
+const keyCodeMapping wmeOriginalMapping[] = {
+ { Common::KEYCODE_BACKSPACE, 8 },
+ { Common::KEYCODE_TAB, 9 },
+ { Common::KEYCODE_RETURN, 13 },
+ { Common::KEYCODE_CAPSLOCK, 20 },
+ { Common::KEYCODE_ESCAPE, 27 },
+ { Common::KEYCODE_SPACE, 32 },
+
+ { Common::KEYCODE_PAUSE, 19 },
+ { Common::KEYCODE_PAGEUP, 33 },
+ { Common::KEYCODE_PAGEDOWN, 34 },
+ { Common::KEYCODE_END, 35 },
+ { Common::KEYCODE_HOME, 36 },
+ { Common::KEYCODE_LEFT, 37 },
+ { Common::KEYCODE_UP, 38 },
+ { Common::KEYCODE_RIGHT, 39 },
+ { Common::KEYCODE_DOWN, 40 },
+ { Common::KEYCODE_PRINT, 42 },
+ { Common::KEYCODE_INSERT, 45 },
+ { Common::KEYCODE_DELETE, 46 },
+ { Common::KEYCODE_SCROLLOCK, 145 },
+
+ { Common::KEYCODE_0, 48 },
+ { Common::KEYCODE_1, 49 },
+ { Common::KEYCODE_2, 50 },
+ { Common::KEYCODE_3, 51 },
+ { Common::KEYCODE_4, 52 },
+ { Common::KEYCODE_5, 53 },
+ { Common::KEYCODE_6, 54 },
+ { Common::KEYCODE_7, 55 },
+ { Common::KEYCODE_8, 56 },
+ { Common::KEYCODE_9, 57 },
+
+ { Common::KEYCODE_a, 65 },
+ { Common::KEYCODE_b, 66 },
+ { Common::KEYCODE_c, 67 },
+ { Common::KEYCODE_d, 68 },
+ { Common::KEYCODE_e, 69 },
+ { Common::KEYCODE_f, 70 },
+ { Common::KEYCODE_g, 71 },
+ { Common::KEYCODE_h, 72 },
+ { Common::KEYCODE_i, 73 },
+ { Common::KEYCODE_j, 74 },
+ { Common::KEYCODE_k, 75 },
+ { Common::KEYCODE_l, 76 },
+ { Common::KEYCODE_m, 77 },
+ { Common::KEYCODE_n, 78 },
+ { Common::KEYCODE_o, 79 },
+ { Common::KEYCODE_p, 80 },
+ { Common::KEYCODE_q, 81 },
+ { Common::KEYCODE_r, 82 },
+ { Common::KEYCODE_s, 83 },
+ { Common::KEYCODE_t, 84 },
+ { Common::KEYCODE_u, 85 },
+ { Common::KEYCODE_v, 86 },
+ { Common::KEYCODE_w, 87 },
+ { Common::KEYCODE_x, 88 },
+ { Common::KEYCODE_y, 89 },
+ { Common::KEYCODE_z, 90 },
+
+ { Common::KEYCODE_CLEAR, 12 },
+ { Common::KEYCODE_KP_ENTER, 13 },
+ { Common::KEYCODE_KP0, 96 },
+ { Common::KEYCODE_KP1, 97 },
+ { Common::KEYCODE_KP2, 98 },
+ { Common::KEYCODE_KP3, 99 },
+ { Common::KEYCODE_KP4, 100 },
+ { Common::KEYCODE_KP5, 101 },
+ { Common::KEYCODE_KP6, 102 },
+ { Common::KEYCODE_KP7, 103 },
+ { Common::KEYCODE_KP8, 104 },
+ { Common::KEYCODE_KP9, 105 },
+ { Common::KEYCODE_KP_MULTIPLY, 106 },
+ { Common::KEYCODE_KP_PLUS, 107 },
+ { Common::KEYCODE_KP_MINUS, 109 },
+ { Common::KEYCODE_KP_PERIOD, 110 },
+ { Common::KEYCODE_KP_DIVIDE, 111 },
+ { Common::KEYCODE_NUMLOCK, 144 },
+
+ { Common::KEYCODE_F1, 112 },
+ { Common::KEYCODE_F2, 113 },
+ { Common::KEYCODE_F3, 114 },
+ { Common::KEYCODE_F4, 115 },
+ { Common::KEYCODE_F5, 116 },
+ { Common::KEYCODE_F6, 117 },
+ { Common::KEYCODE_F7, 118 },
+ { Common::KEYCODE_F8, 119 },
+ { Common::KEYCODE_F9, 120 },
+ { Common::KEYCODE_F10, 121 },
+ { Common::KEYCODE_F11, 122 },
+ { Common::KEYCODE_F12, 123 },
+
+ { Common::KEYCODE_INVALID, 0 }
+};
+
+// Used in WME Lite & FoxTail
+// See "SDL_Keycode" for more details on new WME keycodes
+const keyCodeMapping wmeSdlMapping[] = {
+ { Common::KEYCODE_BACKSPACE, 8 },
+ { Common::KEYCODE_TAB, 9 },
+ { Common::KEYCODE_RETURN, 13 },
+ { Common::KEYCODE_ESCAPE, 27 },
+ { Common::KEYCODE_SPACE, 32 },
+ { Common::KEYCODE_CAPSLOCK, 1073741881 },
+
+ { Common::KEYCODE_DELETE, 127 },
+ { Common::KEYCODE_PRINT, 1073741894 },
+ { Common::KEYCODE_SCROLLOCK, 1073741895 },
+ { Common::KEYCODE_PAUSE, 1073741896 },
+ { Common::KEYCODE_INSERT, 1073741897 },
+ { Common::KEYCODE_HOME, 1073741898 },
+ { Common::KEYCODE_PAGEUP, 1073741899 },
+ { Common::KEYCODE_END, 1073741901 },
+ { Common::KEYCODE_PAGEDOWN, 1073741902 },
+ { Common::KEYCODE_RIGHT, 1073741903 },
+ { Common::KEYCODE_LEFT, 1073741904 },
+ { Common::KEYCODE_DOWN, 1073741905 },
+ { Common::KEYCODE_UP, 1073741906 },
+
+ { Common::KEYCODE_0, 48 },
+ { Common::KEYCODE_1, 49 },
+ { Common::KEYCODE_2, 50 },
+ { Common::KEYCODE_3, 51 },
+ { Common::KEYCODE_4, 52 },
+ { Common::KEYCODE_5, 53 },
+ { Common::KEYCODE_6, 54 },
+ { Common::KEYCODE_7, 55 },
+ { Common::KEYCODE_8, 56 },
+ { Common::KEYCODE_9, 57 },
+
+ { Common::KEYCODE_a, 97 },
+ { Common::KEYCODE_b, 98 },
+ { Common::KEYCODE_c, 99 },
+ { Common::KEYCODE_d, 100 },
+ { Common::KEYCODE_e, 101 },
+ { Common::KEYCODE_f, 102 },
+ { Common::KEYCODE_g, 103 },
+ { Common::KEYCODE_h, 104 },
+ { Common::KEYCODE_i, 105 },
+ { Common::KEYCODE_j, 106 },
+ { Common::KEYCODE_k, 107 },
+ { Common::KEYCODE_l, 108 },
+ { Common::KEYCODE_m, 109 },
+ { Common::KEYCODE_n, 110 },
+ { Common::KEYCODE_o, 111 },
+ { Common::KEYCODE_p, 112 },
+ { Common::KEYCODE_q, 113 },
+ { Common::KEYCODE_r, 114 },
+ { Common::KEYCODE_s, 115 },
+ { Common::KEYCODE_t, 116 },
+ { Common::KEYCODE_u, 117 },
+ { Common::KEYCODE_v, 118 },
+ { Common::KEYCODE_w, 119 },
+ { Common::KEYCODE_x, 120 },
+ { Common::KEYCODE_y, 121 },
+ { Common::KEYCODE_z, 122 },
+
+ { Common::KEYCODE_KP_ENTER, 13 },
+ { Common::KEYCODE_NUMLOCK, 1073741907 },
+ { Common::KEYCODE_KP_DIVIDE, 1073741908 },
+ { Common::KEYCODE_KP_MULTIPLY, 1073741909 },
+ { Common::KEYCODE_KP_MINUS, 1073741910 },
+ { Common::KEYCODE_KP_PLUS, 1073741911 },
+ { Common::KEYCODE_KP1, 1073741913 },
+ { Common::KEYCODE_KP2, 1073741914 },
+ { Common::KEYCODE_KP3, 1073741915 },
+ { Common::KEYCODE_KP4, 1073741916 },
+ { Common::KEYCODE_KP5, 1073741917 },
+ { Common::KEYCODE_KP6, 1073741918 },
+ { Common::KEYCODE_KP7, 1073741919 },
+ { Common::KEYCODE_KP8, 1073741920 },
+ { Common::KEYCODE_KP9, 1073741921 },
+ { Common::KEYCODE_KP0, 1073741922 },
+ { Common::KEYCODE_KP_PERIOD, 1073741923 },
+ { Common::KEYCODE_CLEAR, 1073741980 },
+
+ { Common::KEYCODE_F1, 1073741882 },
+ { Common::KEYCODE_F2, 1073741883 },
+ { Common::KEYCODE_F3, 1073741884 },
+ { Common::KEYCODE_F4, 1073741885 },
+ { Common::KEYCODE_F5, 1073741886 },
+ { Common::KEYCODE_F6, 1073741887 },
+ { Common::KEYCODE_F7, 1073741888 },
+ { Common::KEYCODE_F8, 1073741889 },
+ { Common::KEYCODE_F9, 1073741890 },
+ { Common::KEYCODE_F10, 1073741891 },
+ { Common::KEYCODE_F11, 1073741892 },
+ { Common::KEYCODE_F12, 1073741893 },
+
+ { Common::KEYCODE_INVALID, 0 }
+};
+
//////////////////////////////////////////////////////////////////////////
BaseKeyboardState::BaseKeyboardState(BaseGame *inGame) : BaseScriptable(inGame) {
+ init();
+}
+
+//////////////////////////////////////////////////////////////////////////
+void BaseKeyboardState::init() {
_currentPrintable = false;
_currentCharCode = 0;
_currentKeyData = 0;
@@ -53,6 +252,14 @@ BaseKeyboardState::BaseKeyboardState(BaseGame *inGame) : BaseScriptable(inGame)
for (int i = 0; i < KEYSTATES_ARRAY_SIZE; i++) {
_keyStates[i] = false;
}
+
+ if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
+ _mapping = wmeOriginalMapping;
+ _mappingSize = ARRAYSIZE(wmeOriginalMapping);
+ } else {
+ _mapping = wmeSdlMapping;
+ _mappingSize = ARRAYSIZE(wmeSdlMapping);
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -108,8 +315,18 @@ bool BaseKeyboardState::scCallMethod(ScScript *script, ScStack *stack, ScStack *
// For letters, single keycode is used for upper and lower case
// This mean that IsKeyDown(65) is true for both 'a' and Shift+'a'
- // See "MSDN: Virtual-Key Codes" for more details on original WME keycodes
- vKeyCode = vKeyToKeyCode(val->getInt());
+ vKeyCode = Common::KEYCODE_INVALID;
+ uint32 temp = (uint32)val->getInt();
+
+ for (uint32 i = 0; i < _mappingSize; i++) {
+ if (_mapping[i].engineKeycode == temp) {
+ vKeyCode = _mapping[i].commonKeycode;
+ }
+ }
+
+ if (vKeyCode == Common::KEYCODE_INVALID) {
+ warning("Unknown VKEY: %d", temp);
+ }
}
bool isDown = _keyStates[vKeyCode];
@@ -231,6 +448,11 @@ bool BaseKeyboardState::readKey(Common::Event *event) {
else if (code >= Common::KEYCODE_SPACE && code < Common::KEYCODE_DELETE) {
_currentCharCode = event->kbd.ascii;
_currentPrintable = true;
+#ifdef ENABLE_FOXTAIL
+ if (BaseEngine::instance().isFoxTail()) {
+ _currentCharCode = tolower(_currentCharCode);
+ }
+#endif
}
// use ASCII value for numpad '/', '*', '-', '+'
@@ -246,22 +468,28 @@ bool BaseKeyboardState::readKey(Common::Event *event) {
_currentPrintable = true;
}
- // use keyCodeToVKey mapping for all other events
- // in WME 1.x some of those keys are printable
- else if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
- _currentCharCode = keyCodeToVKey(event);
- _currentPrintable = code == Common::KEYCODE_BACKSPACE ||
- code == Common::KEYCODE_TAB ||
- code == Common::KEYCODE_RETURN ||
- code == Common::KEYCODE_KP_ENTER ||
- code == Common::KEYCODE_ESCAPE;
- }
-
- // use keyCodeToVKey mapping for all other events
- // in WME_LITE all of those key are not printable
+ // use _mapping for all other events
else {
- _currentCharCode = keyCodeToVKey(event);
- _currentPrintable = false;
+ _currentCharCode = 0;
+ for (uint32 i = 0; i < _mappingSize; i++) {
+ if (_mapping[i].commonKeycode == event->kbd.keycode) {
+ _currentCharCode = _mapping[i].engineKeycode;
+ }
+ }
+
+ if (!_currentCharCode && (event->kbd.flags & Common::KBD_NON_STICKY) == 0) {
+ warning("Key pressed (%d '%c') is not recognized, ASCII returned (%d '%c').", event->kbd.keycode, event->kbd.keycode, event->kbd.ascii, event->kbd.ascii);
+ }
+
+ if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
+ _currentPrintable = code == Common::KEYCODE_BACKSPACE ||
+ code == Common::KEYCODE_TAB ||
+ code == Common::KEYCODE_RETURN ||
+ code == Common::KEYCODE_KP_ENTER ||
+ code == Common::KEYCODE_ESCAPE;
+ } else {
+ _currentPrintable = false;
+ }
}
_currentControl = isControlDown();
@@ -285,10 +513,7 @@ bool BaseKeyboardState::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_currentShift));
if (!persistMgr->getIsSaving()) {
- _keyStates = new uint8[323]; // Hardcoded size for the common/keyboard.h enum
- for (int i = 0; i < 323; i++) {
- _keyStates[i] = false;
- }
+ init();
}
return STATUS_OK;
@@ -317,342 +542,4 @@ bool BaseKeyboardState::isCurrentPrintable() const {
return _currentPrintable;
}
-//////////////////////////////////////////////////////////////////////////
-enum VKeyCodes {
- kVkBack = 8, //printable
- kVkTab = 9, //printable
- kVkClear = 12,
- kVkReturn = 13, //printable
- kVkPause = 19,
- kVkCapital = 20,
- kVkEscape = 27, //printable
- kVkSpace = 32, //printable
-
- kVkPrior = 33,
- kVkNext = 34,
- kVkEnd = 35,
- kVkHome = 36,
- kVkLeft = 37,
- kVkUp = 38,
- kVkRight = 39,
- kVkDown = 40,
- kVkPrint = 42,
- kVkInsert = 45,
- kVkDelete = 46,
-
- kVkA = 65, //printable
- kVkB = 66, //printable
- kVkC = 67, //printable
- kVkD = 68, //printable
- kVkE = 69, //printable
- kVkF = 70, //printable
- kVkG = 71, //printable
- kVkH = 72, //printable
- kVkI = 73, //printable
- kVkJ = 74, //printable
- kVkK = 75, //printable
- kVkL = 76, //printable
- kVkM = 77, //printable
- kVkN = 78, //printable
- kVkO = 79, //printable
- kVkP = 80, //printable
- kVkQ = 81, //printable
- kVkR = 82, //printable
- kVkS = 83, //printable
- kVkT = 84, //printable
- kVkU = 85, //printable
- kVkV = 86, //printable
- kVkW = 87, //printable
- kVkX = 88, //printable
- kVkY = 89, //printable
- kVkZ = 90, //printable
-
- kVkNumpad0 = 96, //printable
- kVkNumpad1 = 97, //printable
- kVkNumpad2 = 98, //printable
- kVkNumpad3 = 99, //printable
- kVkNumpad4 = 100, //printable
- kVkNumpad5 = 101, //printable
- kVkNumpad6 = 102, //printable
- kVkNumpad7 = 103, //printable
- kVkNumpad8 = 104, //printable
- kVkNumpad9 = 105, //printable
- kVkMultiply = 106, //printable
- kVkAdd = 107, //printable
- kVkSeparator = 108, //printable
- kVkSubtract = 109, //printable
- kVkDecimal = 110, //printable
- kVkDivide = 111, //printable
-
- kVkF1 = 112,
- kVkF2 = 113,
- kVkF3 = 114,
- kVkF4 = 115,
- kVkF5 = 116,
- kVkF6 = 117,
- kVkF7 = 118,
- kVkF8 = 119,
- kVkF9 = 120,
- kVkF10 = 121,
- kVkF11 = 122,
- kVkF12 = 123,
-
- kVkNumLock = 144,
- kVkScroll = 145
-
- //TODO: shift, ctrl, menu, etc...
-};
-
-//////////////////////////////////////////////////////////////////////////
-uint32 BaseKeyboardState::keyCodeToVKey(Common::Event *event) {
- switch (event->kbd.keycode) {
- case Common::KEYCODE_BACKSPACE:
- return kVkBack;
- case Common::KEYCODE_TAB:
- return kVkTab;
- case Common::KEYCODE_CLEAR:
- case Common::KEYCODE_KP5:
- return kVkClear;
- case Common::KEYCODE_RETURN:
- case Common::KEYCODE_KP_ENTER:
- return kVkReturn;
- case Common::KEYCODE_PAUSE:
- return kVkPause;
- case Common::KEYCODE_CAPSLOCK:
- return kVkCapital;
- case Common::KEYCODE_ESCAPE:
- return kVkEscape;
- case Common::KEYCODE_KP9:
- case Common::KEYCODE_PAGEUP:
- return kVkPrior;
- case Common::KEYCODE_KP3:
- case Common::KEYCODE_PAGEDOWN:
- return kVkNext;
- case Common::KEYCODE_END:
- case Common::KEYCODE_KP1:
- return kVkEnd;
- case Common::KEYCODE_HOME:
- case Common::KEYCODE_KP7:
- return kVkHome;
- case Common::KEYCODE_LEFT:
- case Common::KEYCODE_KP4:
- return kVkLeft;
- case Common::KEYCODE_RIGHT:
- case Common::KEYCODE_KP6:
- return kVkRight;
- case Common::KEYCODE_UP:
- case Common::KEYCODE_KP8:
- return kVkUp;
- case Common::KEYCODE_DOWN:
- case Common::KEYCODE_KP2:
- return kVkDown;
- case Common::KEYCODE_PRINT:
- return kVkPrint;
- case Common::KEYCODE_INSERT:
- case Common::KEYCODE_KP0:
- return kVkInsert;
- case Common::KEYCODE_DELETE:
- case Common::KEYCODE_KP_PERIOD:
- return kVkDelete;
- case Common::KEYCODE_F1:
- return kVkF1;
- case Common::KEYCODE_F2:
- return kVkF2;
- case Common::KEYCODE_F3:
- return kVkF3;
- case Common::KEYCODE_F4:
- return kVkF4;
- case Common::KEYCODE_F5:
- return kVkF5;
- case Common::KEYCODE_F6:
- return kVkF6;
- case Common::KEYCODE_F7:
- return kVkF7;
- case Common::KEYCODE_F8:
- return kVkF8;
- case Common::KEYCODE_F9:
- return kVkF9;
- case Common::KEYCODE_F10:
- return kVkF10;
- case Common::KEYCODE_F11:
- return kVkF11;
- case Common::KEYCODE_F12:
- return kVkF12;
- case Common::KEYCODE_NUMLOCK:
- return kVkNumLock;
- case Common::KEYCODE_SCROLLOCK:
- return kVkScroll;
- default:
- // check if any non-sticky keys were used, otherwise key is unknown to us
- if ((event->kbd.flags & Common::KBD_NON_STICKY) == 0) {
- warning("Key pressed is not recognized, ASCII returned (%d '%c').", event->kbd.keycode, event->kbd.keycode);
- }
- // return ASCII if no match, since it could be used for typing
- return event->kbd.ascii;
- break;
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////////
-Common::KeyCode BaseKeyboardState::vKeyToKeyCode(uint32 vkey) {
- switch (vkey) {
- case kVkBack:
- return Common::KEYCODE_BACKSPACE;
- case kVkTab:
- return Common::KEYCODE_TAB;
- case kVkClear:
- return Common::KEYCODE_CLEAR;
- case kVkReturn:
- return Common::KEYCODE_RETURN;
- case kVkPause:
- return Common::KEYCODE_PAUSE;
- case kVkCapital:
- return Common::KEYCODE_CAPSLOCK;
- case kVkEscape:
- return Common::KEYCODE_ESCAPE;
- case kVkSpace:
- return Common::KEYCODE_SPACE;
- case kVkPrior:
- return Common::KEYCODE_PAGEUP;
- case kVkNext:
- return Common::KEYCODE_PAGEDOWN;
- case kVkHome:
- return Common::KEYCODE_HOME;
- case kVkEnd:
- return Common::KEYCODE_END;
- case kVkLeft:
- return Common::KEYCODE_LEFT;
- case kVkRight:
- return Common::KEYCODE_RIGHT;
- case kVkUp:
- return Common::KEYCODE_UP;
- case kVkDown:
- return Common::KEYCODE_DOWN;
- case kVkPrint:
- return Common::KEYCODE_PRINT;
- case kVkInsert:
- return Common::KEYCODE_INSERT;
- case kVkDelete:
- return Common::KEYCODE_DELETE;
- case kVkA:
- return Common::KEYCODE_a;
- case kVkB:
- return Common::KEYCODE_b;
- case kVkC:
- return Common::KEYCODE_c;
- case kVkD:
- return Common::KEYCODE_d;
- case kVkE:
- return Common::KEYCODE_e;
- case kVkF:
- return Common::KEYCODE_f;
- case kVkG:
- return Common::KEYCODE_g;
- case kVkH:
- return Common::KEYCODE_h;
- case kVkI:
- return Common::KEYCODE_i;
- case kVkJ:
- return Common::KEYCODE_j;
- case kVkK:
- return Common::KEYCODE_k;
- case kVkL:
- return Common::KEYCODE_l;
- case kVkM:
- return Common::KEYCODE_m;
- case kVkN:
- return Common::KEYCODE_n;
- case kVkO:
- return Common::KEYCODE_o;
- case kVkP:
- return Common::KEYCODE_p;
- case kVkQ:
- return Common::KEYCODE_q;
- case kVkR:
- return Common::KEYCODE_r;
- case kVkS:
- return Common::KEYCODE_s;
- case kVkT:
- return Common::KEYCODE_t;
- case kVkU:
- return Common::KEYCODE_u;
- case kVkV:
- return Common::KEYCODE_v;
- case kVkW:
- return Common::KEYCODE_w;
- case kVkX:
- return Common::KEYCODE_x;
- case kVkY:
- return Common::KEYCODE_y;
- case kVkZ:
- return Common::KEYCODE_z;
- case kVkNumpad0:
- return Common::KEYCODE_KP0;
- case kVkNumpad1:
- return Common::KEYCODE_KP1;
- case kVkNumpad2:
- return Common::KEYCODE_KP2;
- case kVkNumpad3:
- return Common::KEYCODE_KP3;
- case kVkNumpad4:
- return Common::KEYCODE_KP4;
- case kVkNumpad5:
- return Common::KEYCODE_KP5;
- case kVkNumpad6:
- return Common::KEYCODE_KP6;
- case kVkNumpad7:
- return Common::KEYCODE_KP7;
- case kVkNumpad8:
- return Common::KEYCODE_KP8;
- case kVkNumpad9:
- return Common::KEYCODE_KP9;
- case kVkMultiply:
- return Common::KEYCODE_KP_MULTIPLY;
- case kVkAdd:
- return Common::KEYCODE_KP_PLUS;
- case kVkSeparator:
- return Common::KEYCODE_KP_EQUALS;
- case kVkSubtract:
- return Common::KEYCODE_KP_MINUS;
- case kVkDecimal:
- return Common::KEYCODE_KP_PERIOD;
- case kVkDivide:
- return Common::KEYCODE_KP_DIVIDE;
- case kVkF1:
- return Common::KEYCODE_F1;
- case kVkF2:
- return Common::KEYCODE_F2;
- case kVkF3:
- return Common::KEYCODE_F3;
- case kVkF4:
- return Common::KEYCODE_F4;
- case kVkF5:
- return Common::KEYCODE_F5;
- case kVkF6:
- return Common::KEYCODE_F6;
- case kVkF7:
- return Common::KEYCODE_F7;
- case kVkF8:
- return Common::KEYCODE_F8;
- case kVkF9:
- return Common::KEYCODE_F9;
- case kVkF10:
- return Common::KEYCODE_F10;
- case kVkF11:
- return Common::KEYCODE_F11;
- case kVkF12:
- return Common::KEYCODE_F12;
- case kVkNumLock:
- return Common::KEYCODE_NUMLOCK;
- case kVkScroll:
- return Common::KEYCODE_SCROLLOCK;
- default:
- warning("Unknown VKEY: %d", vkey);
- return (Common::KeyCode)(vkey < KEYSTATES_ARRAY_SIZE ? vkey : 0);
- break;
- }
-
-}
-
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_keyboard_state.h b/engines/wintermute/base/base_keyboard_state.h
index 32680b34c1..b2f7f781ea 100644
--- a/engines/wintermute/base/base_keyboard_state.h
+++ b/engines/wintermute/base/base_keyboard_state.h
@@ -37,6 +37,11 @@
namespace Wintermute {
+struct keyCodeMapping {
+ Common::KeyCode commonKeycode;
+ uint32 engineKeycode;
+};
+
class BaseKeyboardState : public BaseScriptable {
public:
DECLARE_PERSISTENT(BaseKeyboardState, BaseScriptable)
@@ -58,6 +63,8 @@ public:
virtual const char *scToString();
private:
+ void init();
+
bool _currentPrintable;
uint32 _currentKeyData;
uint32 _currentCharCode;
@@ -67,8 +74,9 @@ private:
bool _currentControl;
uint8 *_keyStates;
- uint32 keyCodeToVKey(Common::Event *event); //TODO, add more mappings
- Common::KeyCode vKeyToKeyCode(uint32 vkey); //TODO, reimplement using ScummVM-backend
+
+ const keyCodeMapping *_mapping;
+ uint32 _mappingSize;
};
} // End of namespace Wintermute
diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h
index 760b45c907..e8ca663cb7 100644
--- a/engines/wintermute/base/base_persistence_manager.h
+++ b/engines/wintermute/base/base_persistence_manager.h
@@ -69,6 +69,7 @@ public:
uint32 _offset;
bool getIsSaving() { return _saving; }
+ TimeDate getSavedTimestamp() { return _savedTimestamp; }
uint32 _richBufferSize;
byte *_richBuffer;
diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp
index e8e62fb6bc..039e481fe3 100644
--- a/engines/wintermute/base/base_sub_frame.cpp
+++ b/engines/wintermute/base/base_sub_frame.cpp
@@ -119,7 +119,7 @@ bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
Rect32 rect;
int r = 255, g = 255, b = 255;
int ar = 255, ag = 255, ab = 255, alpha = 255;
- bool custoTrans = false;
+ bool customTrans = false;
rect.setEmpty();
char *surfaceFile = nullptr;
@@ -134,7 +134,7 @@ bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
- custoTrans = true;
+ customTrans = true;
break;
case TOKEN_RECT:
@@ -191,7 +191,7 @@ bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
}
if (surfaceFile != nullptr) {
- if (custoTrans) {
+ if (customTrans) {
setSurface(surfaceFile, false, r, g, b, lifeTime, keepLoaded);
} else {
setSurface(surfaceFile, true, 0, 0, 0, lifeTime, keepLoaded);
@@ -199,7 +199,7 @@ bool BaseSubFrame::loadBuffer(char *buffer, int lifeTime, bool keepLoaded) {
}
_alpha = BYTETORGBA(ar, ag, ab, alpha);
- if (custoTrans) {
+ if (customTrans) {
_transparent = BYTETORGBA(r, g, b, 0xFF);
}
@@ -434,6 +434,57 @@ bool BaseSubFrame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisS
return STATUS_OK;
}
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetHeight
+ // Used to find sprite center at methods.script in fix_offset()
+ // Return value is integer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetHeight") == 0) {
+ stack->correctParams(0);
+ if (_surface) {
+ stack->pushInt(_surface->getHeight());
+ } else {
+ stack->pushNULL();
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetWidth
+ // Used to find sprite center at methods.script in fix_offset()
+ // Return value is integer
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetWidth") == 0) {
+ stack->correctParams(0);
+ if (_surface) {
+ stack->pushInt(_surface->getWidth());
+ } else {
+ stack->pushNULL();
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] GetPixelAt
+ // Used for dynamic light at mixing.script in make_RGB() and make_HSV()
+ // Return value is passed to Game.GetRValue(), Game.GetGValue(), etc...
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetPixelAt") == 0) {
+ stack->correctParams(2);
+ int x = stack->pop()->getInt();
+ int y = stack->pop()->getInt();
+ byte r, g, b, a;
+ if (_surface && _surface->getPixel(x, y, &r, &g, &b, &a)) {
+ uint32 pixel = BYTETORGBA(r, g, b, a);
+ stack->pushInt(pixel);
+ } else {
+ stack->pushNULL();
+ }
+ return STATUS_OK;
+ }
+#endif
+
//////////////////////////////////////////////////////////////////////////
// SetImage
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/base/file/base_package.cpp b/engines/wintermute/base/file/base_package.cpp
index 2ed27e2c32..3d67d02774 100644
--- a/engines/wintermute/base/file/base_package.cpp
+++ b/engines/wintermute/base/file/base_package.cpp
@@ -142,6 +142,8 @@ PackageSet::PackageSet(Common::FSNode file, const Common::String &filename, bool
debugC(kWintermuteDebugFileAccess | kWintermuteDebugLog, " Warning: package file '%s' is outdated.", filename.c_str());
}
_priority = hdr._priority;
+ _version = hdr._gameVersion;
+
// new in v2
if (hdr._packageVersion == PACKAGE_VERSION) {
uint32 dirOffset;
diff --git a/engines/wintermute/base/file/base_package.h b/engines/wintermute/base/file/base_package.h
index 35976eb47b..578dc789fa 100644
--- a/engines/wintermute/base/file/base_package.h
+++ b/engines/wintermute/base/file/base_package.h
@@ -78,8 +78,11 @@ public:
virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
int getPriority() const { return _priority; }
+ uint32 getVersion() const { return _version; }
+
private:
byte _priority;
+ uint32 _version;
Common::Array<BasePackage *> _packages;
Common::HashMap<Common::String, Common::ArchiveMemberPtr> _files;
Common::HashMap<Common::String, Common::ArchiveMemberPtr>::iterator _filesIter;
diff --git a/engines/wintermute/base/font/base_font_bitmap.cpp b/engines/wintermute/base/font/base_font_bitmap.cpp
index c33b48d085..0c3c0ae97d 100644
--- a/engines/wintermute/base/font/base_font_bitmap.cpp
+++ b/engines/wintermute/base/font/base_font_bitmap.cpp
@@ -28,6 +28,7 @@
#include "engines/wintermute/base/font/base_font_bitmap.h"
#include "engines/wintermute/utils/string_util.h"
+#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/gfx/base_surface.h"
@@ -141,6 +142,9 @@ int BaseFontBitmap::textHeightDraw(const byte *text, int x, int y, int width, TT
bool done = false;
bool newLine = false;
bool longLine = false;
+#ifdef ENABLE_FOXTAIL
+ bool minimizeSpacing = BaseEngine::instance().isFoxTail();
+#endif
if (draw) {
_gameRef->_renderer->startSpriteBatch();
@@ -211,6 +215,11 @@ int BaseFontBitmap::textHeightDraw(const byte *text, int x, int y, int width, TT
startX += getCharWidth(str[i]);
}
y += _tileHeight;
+#ifdef ENABLE_FOXTAIL
+ if (minimizeSpacing) {
+ y -= 3;
+ }
+#endif
last_end = end;
if (longLine) {
end--;
@@ -264,7 +273,7 @@ void BaseFontBitmap::drawChar(byte c, int x, int y) {
}
}
if (!handled && _subframe) {
- _subframe->_surface->displayTrans(x, y, rect);
+ _subframe->_surface->displayTrans(x, y, rect, _subframe->_alpha);
}
}
@@ -308,6 +317,9 @@ TOKEN_DEF(EDITOR_PROPERTY)
TOKEN_DEF(SPRITE)
TOKEN_DEF(WIDTHS_FRAME)
TOKEN_DEF(PAINT_WHOLE_CELL)
+#ifdef ENABLE_FOXTAIL
+TOKEN_DEF(COLOR)
+#endif
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
bool BaseFontBitmap::loadBuffer(char *buffer) {
@@ -328,6 +340,9 @@ bool BaseFontBitmap::loadBuffer(char *buffer) {
TOKEN_TABLE(SPRITE)
TOKEN_TABLE(WIDTHS_FRAME)
TOKEN_TABLE(PAINT_WHOLE_CELL)
+#ifdef ENABLE_FOXTAIL
+ TOKEN_TABLE(COLOR)
+#endif
TOKEN_TABLE_END
char *params;
@@ -345,7 +360,11 @@ bool BaseFontBitmap::loadBuffer(char *buffer) {
int lastWidth = 0;
int i;
int r = 255, g = 255, b = 255;
- bool custoTrans = false;
+ bool customTrans = false;
+#ifdef ENABLE_FOXTAIL
+ int ar = 255, ag = 255, ab = 255;
+ bool customAlpha = false;
+#endif
char *surfaceFile = nullptr;
char *spriteFile = nullptr;
@@ -366,8 +385,15 @@ bool BaseFontBitmap::loadBuffer(char *buffer) {
case TOKEN_TRANSPARENT:
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
- custoTrans = true;
+ customTrans = true;
+ break;
+
+#ifdef ENABLE_FOXTAIL
+ case TOKEN_COLOR:
+ parser.scanStr(params, "%d,%d,%d", &ar, &ag, &ab);
+ customAlpha = true;
break;
+#endif
case TOKEN_WIDTHS:
parser.scanStr(params, "%D", widths, &num);
@@ -441,11 +467,16 @@ bool BaseFontBitmap::loadBuffer(char *buffer) {
if (surfaceFile != nullptr && !_sprite) {
_subframe = new BaseSubFrame(_gameRef);
- if (custoTrans) {
+ if (customTrans) {
_subframe->setSurface(surfaceFile, false, r, g, b);
} else {
_subframe->setSurface(surfaceFile);
}
+#ifdef ENABLE_FOXTAIL
+ if (customAlpha) {
+ _subframe->_alpha = BYTETORGBA(ar, ag, ab, 255);
+ }
+#endif
}
@@ -489,6 +520,14 @@ bool BaseFontBitmap::loadBuffer(char *buffer) {
}
}
+#ifdef ENABLE_FOXTAIL
+ if (BaseEngine::instance().isFoxTail()) {
+ for (i = lastWidth; i < NUM_CHARACTERS; i++) {
+ _widths[i]--;
+ }
+ }
+#endif
+
return STATUS_OK;
}
diff --git a/engines/wintermute/base/gfx/base_renderer.cpp b/engines/wintermute/base/gfx/base_renderer.cpp
index 0f33fc2c43..b60a4d4b38 100644
--- a/engines/wintermute/base/gfx/base_renderer.cpp
+++ b/engines/wintermute/base/gfx/base_renderer.cpp
@@ -32,6 +32,7 @@
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_region.h"
+#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_persistence_manager.h"
@@ -372,6 +373,26 @@ bool BaseRenderer::displayIndicator() {
if (!_indicatorDisplay || !_indicatorProgress) {
return STATUS_OK;
}
+
+#ifdef ENABLE_FOXTAIL
+ if (BaseEngine::instance().isFoxTail()) {
+ _hasDrawnSaveLoadImage = false;
+ fill(0, 0, 0);
+ displaySaveloadLines();
+ displaySaveloadImage();
+ forcedFlip();
+ return STATUS_OK;
+ }
+#endif
+
+ displaySaveloadImage();
+ displaySaveloadLines();
+ indicatorFlip();
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool BaseRenderer::displaySaveloadImage() {
if (_saveLoadImage && !_hasDrawnSaveLoadImage) {
Rect32 rc;
rc.setRect(0, 0, _saveLoadImage->getWidth(), _saveLoadImage->getHeight());
@@ -384,6 +405,11 @@ bool BaseRenderer::displayIndicator() {
_hasDrawnSaveLoadImage = true;
}
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool BaseRenderer::displaySaveloadLines() {
if ((!_indicatorDisplay && _indicatorWidth <= 0) || _indicatorHeight <= 0) {
return STATUS_OK;
}
@@ -395,9 +421,6 @@ bool BaseRenderer::displayIndicator() {
setup2D();
_indicatorWidthDrawn = curWidth;
- if (_indicatorWidthDrawn) {
- indicatorFlip();
- }
return STATUS_OK;
}
diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h
index 6b1a4f97f4..981171b78b 100644
--- a/engines/wintermute/base/gfx/base_renderer.h
+++ b/engines/wintermute/base/gfx/base_renderer.h
@@ -116,6 +116,7 @@ public:
* essentially, just copies the region defined by the _indicator-variables.
*/
virtual bool indicatorFlip() = 0;
+ virtual bool forcedFlip() = 0;
virtual void initLoop();
virtual bool setup2D(bool force = false);
virtual bool setupLines();
@@ -223,6 +224,8 @@ protected:
Rect32 _monitorRect;
private:
Common::Array<BaseActiveRect *> _rectList;
+ bool displaySaveloadImage();
+ bool displaySaveloadLines();
};
BaseRenderer *makeOSystemRenderer(BaseGame *inGame); // Implemented in BRenderSDL.cpp
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index 7692bc6c48..cfa43adb17 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -146,7 +146,15 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) {
}
bool BaseRenderOSystem::indicatorFlip() {
- g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_indicatorX, _indicatorY), _renderSurface->pitch, _indicatorX, _indicatorY, _indicatorWidthDrawn, _indicatorHeight);
+ if (_indicatorWidthDrawn > 0 && _indicatorHeight > 0) {
+ g_system->copyRectToScreen((byte *)_renderSurface->getBasePtr(_indicatorX, _indicatorY), _renderSurface->pitch, _indicatorX, _indicatorY, _indicatorWidthDrawn, _indicatorHeight);
+ g_system->updateScreen();
+ }
+ return STATUS_OK;
+}
+
+bool BaseRenderOSystem::forcedFlip() {
+ g_system->copyRectToScreen((byte *)_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h);
g_system->updateScreen();
return STATUS_OK;
}
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
index 47099046e9..11987e55e5 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h
@@ -69,6 +69,7 @@ public:
bool initRenderer(int width, int height, bool windowed) override;
bool flip() override;
virtual bool indicatorFlip();
+ virtual bool forcedFlip();
bool fill(byte r, byte g, byte b, Common::Rect *rect = nullptr) override;
Graphics::PixelFormat getPixelFormat() const override;
void fade(uint16 alpha) override;
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
index 9fbbe1d498..950cabf28c 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h
@@ -81,6 +81,17 @@ public:
}
return _height;
}
+ bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) override {
+ if (!_loaded) {
+ finishLoad();
+ }
+ if (_surface) {
+ uint32 pixel = getPixelAt(_surface, x, y);
+ _surface->format.colorToARGB(pixel, *a, *r, *g, *b);
+ return STATUS_OK;
+ }
+ return STATUS_FAILED;
+ }
Graphics::AlphaType getAlphaType() const { return _alphaType; }
private:
diff --git a/engines/wintermute/base/saveload.cpp b/engines/wintermute/base/saveload.cpp
index 6299cf6e01..1549eac7a8 100644
--- a/engines/wintermute/base/saveload.cpp
+++ b/engines/wintermute/base/saveload.cpp
@@ -159,31 +159,35 @@ void SaveLoad::afterLoadScript(void *script, void *data) {
}
Common::String SaveLoad::getSaveSlotFilename(int slot) {
+ Common::String filename;
BasePersistenceManager *pm = new BasePersistenceManager();
- Common::String filename = pm->getFilenameForSlot(slot);
- delete pm;
+ if (pm) {
+ filename = pm->getFilenameForSlot(slot);
+ delete pm;
+ }
debugC(kWintermuteDebugSaveGame, "getSaveSlotFileName(%d) = %s", slot, filename.c_str());
return filename;
}
-bool SaveLoad::getSaveSlotDescription(int slot, char *buffer) {
- buffer[0] = '\0';
-
+Common::String SaveLoad::getSaveSlotDescription(int slot) {
+ Common::String description;
Common::String filename = getSaveSlotFilename(slot);
BasePersistenceManager *pm = new BasePersistenceManager();
- if (!pm) {
- return false;
+ if ((pm->initLoad(filename))) {
+ description = pm->_savedDescription;
}
+ delete pm;
+ return description;
+}
- if (!(pm->initLoad(filename))) {
- delete pm;
- return false;
+void SaveLoad::getSaveSlotTimestamp(int slot, TimeDate *time) {
+ memset(time, 0, sizeof(TimeDate));
+ Common::String filename = getSaveSlotFilename(slot);
+ BasePersistenceManager *pm = new BasePersistenceManager();
+ if ((pm->initLoad(filename))) {
+ *time = pm->getSavedTimestamp();
}
-
- strcpy(buffer, pm->_savedDescription);
delete pm;
-
- return true;
}
bool SaveLoad::isSaveSlotUsed(int slot) {
diff --git a/engines/wintermute/base/saveload.h b/engines/wintermute/base/saveload.h
index 31f5841f41..295d19d543 100644
--- a/engines/wintermute/base/saveload.h
+++ b/engines/wintermute/base/saveload.h
@@ -37,7 +37,8 @@ class SaveLoad {
public:
static bool emptySaveSlot(int slot);
static bool isSaveSlotUsed(int slot);
- static bool getSaveSlotDescription(int slot, char *buffer);
+ static Common::String getSaveSlotDescription(int slot);
+ static void getSaveSlotTimestamp(int slot, TimeDate *time);
static Common::String getSaveSlotFilename(int slot);
static bool loadGame(const Common::String &filename, BaseGame *gameRef);
diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp
index c13310255d..856584fe72 100644
--- a/engines/wintermute/base/scriptables/script.cpp
+++ b/engines/wintermute/base/scriptables/script.cpp
@@ -29,6 +29,7 @@
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "common/memstream.h"
@@ -618,8 +619,14 @@ bool ScScript::executeInstruction() {
_state = SCRIPT_WAITING_SCRIPT;
_waitScript->copyParameters(_stack);
}
+#ifdef ENABLE_FOXTAIL
+ } else if (BaseEngine::instance().isFoxTail() && strcmp(methodName, "LoadItems") == 0 && strcmp(_threadEvent,"AfterLoad") == 0) {
+ _stack->correctParams(0);
+ _gameRef->LOG(0, "Method '%s' is called in unbreakable mode of '%s' event and was ignored", methodName, _threadEvent);
+ _stack->pushNULL();
+#endif
} else {
- // can call methods in unbreakable mode
+ // cannot call methods in unbreakable mode
_stack->correctParams(0);
runtimeError("Cannot call method '%s'. Ignored.", methodName);
_stack->pushNULL();
diff --git a/engines/wintermute/base/scriptables/script_ext_array.cpp b/engines/wintermute/base/scriptables/script_ext_array.cpp
index 7431029cbf..05effd991e 100644
--- a/engines/wintermute/base/scriptables/script_ext_array.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_array.cpp
@@ -118,8 +118,7 @@ bool SXArray::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
// Pop
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Pop") == 0) {
-
+ else if (strcmp(name, "Pop") == 0) {
stack->correctParams(0);
if (_length > 0) {
@@ -133,7 +132,36 @@ bool SXArray::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
}
return STATUS_OK;
- } else {
+ }
+
+#ifdef ENABLE_FOXTAIL
+ //////////////////////////////////////////////////////////////////////////
+ // [FoxTail] Delete
+ // Removes item from array by index, shifting other elements
+ // Used to shuffle arrays and delete found items in various scripts
+ // Return value is never used
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Delete") == 0) {
+ stack->correctParams(1);
+
+ int shiftPoint = stack->pop()->getInt(0);
+ char paramNameFrom[20];
+ char paramNameTo[20];
+
+ for (int i = shiftPoint; i < _length - 1 ; i++) {
+ sprintf(paramNameFrom, "%d", i + 1);
+ sprintf(paramNameTo, "%d", i);
+ _values->setProp(paramNameTo, _values->getProp(paramNameFrom), false);
+ }
+ _values->deleteProp(paramNameFrom);
+ _length--;
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+#endif
+
+ else {
return STATUS_FAILED;
}
}
diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine
index 68049684a3..c825845f50 100644
--- a/engines/wintermute/configure.engine
+++ b/engines/wintermute/configure.engine
@@ -1,3 +1,4 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine wintermute "Wintermute" yes "" "" "zlib 16bit highres jpeg png"
+add_engine wintermute "Wintermute" yes "foxtail" "" "zlib 16bit highres jpeg png"
+add_engine foxtail "FoxTail" yes
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 36280574ef..f9d8df081c 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -74,6 +74,7 @@ static const PlainGameDescriptor wintermuteGames[] = {
{"goldencalf", "The Golden Calf"},
{"hamlet", "Hamlet or the last game without MMORPG features, shaders and product placement"},
{"helga", "Helga Deep In Trouble"},
+ {"hor", "Hor"},
{"jamesperis", "James Peris: No License Nor Control"},
{"knossos", "K'NOSSOS"},
{"kulivocko", "Kulivocko"},
@@ -734,61 +735,242 @@ static const WMEGameDescription gameDescriptions[] = {
WME_WINENTRY("four", "",
WME_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1),
- // FoxTail (Steam, Feb 26th 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "651ae5b062073021edaca7e1de131eec", 59357572), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1291 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1291",
+ WME_ENTRY1s("data.dcp", "651ae5b062073021edaca7e1de131eec", 59357572), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 1th 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "03ed77b1ac8b94bbd0247324a41621ad", 59357623), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1291 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1291",
+ WME_ENTRY1s("data.dcp", "651ae5b062073021edaca7e1de131eec", 59357572), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 2th A 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "d7287c49210c7c9f9376327c6e224c7b", 59383312), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1291 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1291",
+ WME_ENTRY1s("data.dcp", "651ae5b062073021edaca7e1de131eec", 59357572), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 2th B 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "434c4f598582a569972acd4d700a44e5", 59383416), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1291 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1291",
+ WME_ENTRY1s("data.dcp", "651ae5b062073021edaca7e1de131eec", 59357572), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 3th A 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "5aa16c180998f1816a734c58a01ab8b1", 59383306), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1303 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1303",
+ WME_ENTRY1s("data.dcp", "03ed77b1ac8b94bbd0247324a41621ad", 59357623), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 3th B 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "363856606d19fb7e0e3a0a67737697fa", 59382887), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1303 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1303",
+ WME_ENTRY1s("data.dcp", "03ed77b1ac8b94bbd0247324a41621ad", 59357623), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 3th C 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "bbab16777c4bc979c5f773e12b804a63", 59151985), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1303 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1303",
+ WME_ENTRY1s("data.dcp", "03ed77b1ac8b94bbd0247324a41621ad", 59357623), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 3th D 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "22e5f634742956b6f4087459a9c8acf4", 59151985), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1303 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1303",
+ WME_ENTRY1s("data.dcp", "03ed77b1ac8b94bbd0247324a41621ad", 59357623), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 20th 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "32fd78f0b1509863f2e91bc7afc633ff", 59630008), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1313 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1313",
+ WME_ENTRY1s("data.dcp", "d7287c49210c7c9f9376327c6e224c7b", 59383312), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, May 30th 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "ca1b0379c8f0dffd3bf8b95e91379b2c", 70132635), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1313 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1313",
+ WME_ENTRY1s("data.dcp", "d7287c49210c7c9f9376327c6e224c7b", 59383312), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, May 31th 2018, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "2c4c744ff103f4fc6e770515e2da8b16", 70124937), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1313 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1313",
+ WME_ENTRY1s("data.dcp", "d7287c49210c7c9f9376327c6e224c7b", 59383312), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Jan 17th 2019, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1313 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1313",
+ WME_ENTRY1s("data.dcp", "d7287c49210c7c9f9376327c6e224c7b", 59383312), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Feb 22th 2019, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1315 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1315",
+ WME_ENTRY1s("data.dcp", "434c4f598582a569972acd4d700a44e5", 59383416), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
- // FoxTail (Steam, Mar 22th 2019, Windows/Linux/Mac)
- WME_WINENTRY("foxtail", "",
- WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::EN_ANY, ADGF_UNSTABLE, WME_LITE),
+ // FoxTail 1.2.230.1315 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1315",
+ WME_ENTRY1s("data.dcp", "434c4f598582a569972acd4d700a44e5", 59383416), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1315 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1315",
+ WME_ENTRY1s("data.dcp", "434c4f598582a569972acd4d700a44e5", 59383416), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1315 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1315",
+ WME_ENTRY1s("data.dcp", "434c4f598582a569972acd4d700a44e5", 59383416), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1316 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1316",
+ WME_ENTRY1s("data.dcp", "5aa16c180998f1816a734c58a01ab8b1", 59383306), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1316 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1316",
+ WME_ENTRY1s("data.dcp", "5aa16c180998f1816a734c58a01ab8b1", 59383306), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1316 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1316",
+ WME_ENTRY1s("data.dcp", "5aa16c180998f1816a734c58a01ab8b1", 59383306), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1316 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1316",
+ WME_ENTRY1s("data.dcp", "5aa16c180998f1816a734c58a01ab8b1", 59383306), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1318 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1318",
+ WME_ENTRY1s("data.dcp", "363856606d19fb7e0e3a0a67737697fa", 59382887), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1318 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1318",
+ WME_ENTRY1s("data.dcp", "363856606d19fb7e0e3a0a67737697fa", 59382887), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1318 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1318",
+ WME_ENTRY1s("data.dcp", "363856606d19fb7e0e3a0a67737697fa", 59382887), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1318 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1318",
+ WME_ENTRY1s("data.dcp", "363856606d19fb7e0e3a0a67737697fa", 59382887), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1321 (English)
+ WME_WINENTRY("foxtail", "1.2.230.1321",
+ WME_ENTRY1s("data.dcp", "bbab16777c4bc979c5f773e12b804a63", 59151985), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1321 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1321",
+ WME_ENTRY1s("data.dcp", "bbab16777c4bc979c5f773e12b804a63", 59151985), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1321 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1321",
+ WME_ENTRY1s("data.dcp", "bbab16777c4bc979c5f773e12b804a63", 59151985), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1321 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1321",
+ WME_ENTRY1s("data.dcp", "bbab16777c4bc979c5f773e12b804a63", 59151985), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1322 (English)
+ // not a mistake, data.dcp for 1.2.230.1321 and 1.2.230.1322 have same byte size
+ WME_WINENTRY("foxtail", "1.2.230.1322",
+ WME_ENTRY1s("data.dcp", "22e5f634742956b6f4087459a9c8acf4", 59151985), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1322 (German)
+ WME_WINENTRY("foxtail", "1.2.230.1322",
+ WME_ENTRY1s("data.dcp", "22e5f634742956b6f4087459a9c8acf4", 59151985), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1322 (Russian)
+ WME_WINENTRY("foxtail", "1.2.230.1322",
+ WME_ENTRY1s("data.dcp", "22e5f634742956b6f4087459a9c8acf4", 59151985), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.230.1322 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.230.1322",
+ WME_ENTRY1s("data.dcp", "22e5f634742956b6f4087459a9c8acf4", 59151985), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_230),
+
+ // FoxTail 1.2.304.1571 (English)
+ WME_WINENTRY("foxtail", "1.2.304.1571",
+ WME_ENTRY1s("data.dcp", "32fd78f0b1509863f2e91bc7afc633ff", 59630008), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_304),
+
+ // FoxTail 1.2.304.1571 (German)
+ WME_WINENTRY("foxtail", "1.2.304.1571",
+ WME_ENTRY1s("data.dcp", "32fd78f0b1509863f2e91bc7afc633ff", 59630008), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_304),
+
+ // FoxTail 1.2.304.1571 (Russian)
+ WME_WINENTRY("foxtail", "1.2.304.1571",
+ WME_ENTRY1s("data.dcp", "32fd78f0b1509863f2e91bc7afc633ff", 59630008), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_304),
+
+ // FoxTail 1.2.304.1571 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.304.1571",
+ WME_ENTRY1s("data.dcp", "32fd78f0b1509863f2e91bc7afc633ff", 59630008), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_304),
+
+ // FoxTail 1.2.362.2039 (English)
+ WME_WINENTRY("foxtail", "1.2.362.2039",
+ WME_ENTRY1s("data.dcp", "ca1b0379c8f0dffd3bf8b95e91379b2c", 70132635), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2039 (German)
+ WME_WINENTRY("foxtail", "1.2.362.2039",
+ WME_ENTRY1s("data.dcp", "ca1b0379c8f0dffd3bf8b95e91379b2c", 70132635), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2039 (Russian)
+ WME_WINENTRY("foxtail", "1.2.362.2039",
+ WME_ENTRY1s("data.dcp", "ca1b0379c8f0dffd3bf8b95e91379b2c", 70132635), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2039 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.362.2039",
+ WME_ENTRY1s("data.dcp", "ca1b0379c8f0dffd3bf8b95e91379b2c", 70132635), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2047 (English)
+ WME_WINENTRY("foxtail", "1.2.362.2047",
+ WME_ENTRY1s("data.dcp", "2c4c744ff103f4fc6e770515e2da8b16", 70124937), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2047 (German)
+ WME_WINENTRY("foxtail", "1.2.362.2047",
+ WME_ENTRY1s("data.dcp", "2c4c744ff103f4fc6e770515e2da8b16", 70124937), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2047 (Russian)
+ WME_WINENTRY("foxtail", "1.2.362.2047",
+ WME_ENTRY1s("data.dcp", "2c4c744ff103f4fc6e770515e2da8b16", 70124937), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.362.2047 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.362.2047",
+ WME_ENTRY1s("data.dcp", "2c4c744ff103f4fc6e770515e2da8b16", 70124937), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_362),
+
+ // FoxTail 1.2.527.3377 (English)
+ WME_WINENTRY("foxtail", "1.2.527.3377",
+ WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3377 (German)
+ WME_WINENTRY("foxtail", "1.2.527.3377",
+ WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3377 (Polish)
+ WME_WINENTRY("foxtail", "1.2.527.3377",
+ WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3377 (Russian)
+ WME_WINENTRY("foxtail", "1.2.527.3377",
+ WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3377 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.527.3377",
+ WME_ENTRY1s("data.dcp", "e0177c5752d067a3e473b86ad40d57c3", 109502449), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3389 (English)
+ WME_WINENTRY("foxtail", "1.2.527.3389",
+ WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3389 (German)
+ WME_WINENTRY("foxtail", "1.2.527.3389",
+ WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3389 (Polish)
+ WME_WINENTRY("foxtail", "1.2.527.3389",
+ WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3389 (Russian)
+ WME_WINENTRY("foxtail", "1.2.527.3389",
+ WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3389 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.527.3389",
+ WME_ENTRY1s("data.dcp", "a940ffa1b4347588d13e4a9756bb0bbd", 109503345), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3391 (English)
+ WME_WINENTRY("foxtail", "1.2.527.3391",
+ WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::EN_ANY, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3391 (German)
+ WME_WINENTRY("foxtail", "1.2.527.3391",
+ WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::DE_DEU, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3391 (Polish)
+ WME_WINENTRY("foxtail", "1.2.527.3391",
+ WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::PL_POL, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3391 (Russian)
+ WME_WINENTRY("foxtail", "1.2.527.3391",
+ WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::RU_RUS, ADGF_UNSTABLE, FOXTAIL_1_2_527),
+
+ // FoxTail 1.2.527.3391 (Ukranian)
+ WME_WINENTRY("foxtail", "1.2.527.3391",
+ WME_ENTRY1s("data.dcp", "e5d06fa058cd9d6f20d6206356e5854d", 109503303), Common::UA_UKR, ADGF_UNSTABLE, FOXTAIL_1_2_527),
// Framed (Beta)
WME_WINENTRY("framed", "Beta",
@@ -887,6 +1069,14 @@ static const WMEGameDescription gameDescriptions[] = {
WME_ENTRY2s("english.dcp", "b3a93e678f0ef97200f691cd1724643f", 135864,
"data.dcp", "45134ed93bc391edf148b79cdcbf2a09", 154266028), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, WME_1_9_3),
+ // Hor v1.0
+ WME_WINENTRY("hor", "1.0",
+ WME_ENTRY1s("data.dcp", "ae94007f25a21143c028c1b7807dd907", 15077486), Common::UNK_LANG, ADGF_UNSTABLE, WME_1_9_3),
+
+ // Hor v1.3
+ WME_WINENTRY("hor", "1.3",
+ WME_ENTRY1s("data.dcp", "37b0abeb8651b82b9e6327bd10a18185", 15077486), Common::UNK_LANG, ADGF_UNSTABLE, WME_1_9_3),
+
// James Peris: No License Nor Control (English)
WME_WINENTRY("jamesperis", "Version 1.5",
WME_ENTRY1s("data.dcp", "f5635080b65aaf75c3676ce0cd46460b", 225294032), Common::EN_ANY, ADGF_UNSTABLE, WME_1_9_1),
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 7ee28f0fe2..dec2025346 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -115,6 +115,10 @@ Common::Error WintermuteEngine::run() {
Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
if (_gameDescription->adDesc.flags & GF_LOWSPEC_ASSETS) {
initGraphics(320, 240, &format);
+#ifdef ENABLE_FOXTAIL
+ } else if (BaseEngine::isFoxTailCheck(_gameDescription->targetExecutable)) {
+ initGraphics(640, 360, &format);
+#endif
} else {
initGraphics(800, 600, &format);
}
@@ -158,6 +162,17 @@ int WintermuteEngine::init() {
}
#endif
+ // check dependencies for games with FoxTail subengine
+ #if not defined(ENABLE_FOXTAIL)
+ if (BaseEngine::isFoxTailCheck(_gameDescription->targetExecutable)) {
+ GUI::MessageDialog dialog(_("This game requires the FoxTail subengine, which is not compiled in."));
+ dialog.runModal();
+ delete _game;
+ _game = nullptr;
+ return false;
+ }
+ #endif
+
Common::ArchiveMemberList actors3d;
if (BaseEngine::instance().getFileManager()->listMatchingMembers(actors3d, "*.act3d")) {
GUI::MessageDialog dialog(