GRIM: Merge branch 'remastered'

This commit is contained in:
Paweł Kołodziejski 2020-10-07 18:26:49 +02:00
commit 6e619ca714
36 changed files with 1917 additions and 38 deletions

View File

@ -77,7 +77,8 @@ enum ADGameFlags {
ADGF_DROPLANGUAGE = (1 << 27), ///< don't add language to gameid
ADGF_DROPPLATFORM = (1 << 28), ///< don't add platform to gameid
ADGF_CD = (1 << 29), ///< add "-cd" to gameid
ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid
ADGF_DEMO = (1 << 30), ///< add "-demo" to gameid
ADGF_REMASTERED = (1 << 31) ///< remastered
};
struct ADGameDescription {

View File

@ -1172,6 +1172,9 @@ void Actor::sayLine(const char *msgId, bool background, float x, float y) {
Common::String soundName = id;
if (g_grim->getGameType() == GType_GRIM) {
if (g_grim->getGameFlags() & ADGF_REMASTERED) {
soundName = g_grim->getLanguagePrefix() + "_" + soundName;
}
soundName += ".wav";
} else if (g_grim->getGameType() == GType_MONKEY4 && g_grim->getGamePlatform() == Common::kPlatformPS2) {
soundName += ".scx";

View File

@ -324,6 +324,19 @@ static const GrimGameDescription gameDescriptions[] = {
},
GType_GRIM
},
{
// Grim Fandango Remastered
{
"grim",
"Remastered",
AD_ENTRY1s("VOX0001.LAB", "0ff872fb353707fbdb9579038d4cf31c", 382736476),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_REMASTERED,
GUIO1(GAMEOPTION_LOAD_DATAUSR)
},
GType_GRIM
},
#ifdef ENABLE_MONKEY4
{
// Escape from Monkey Island English

View File

@ -22,6 +22,9 @@
#include "common/endian.h"
#include "graphics/fonts/ttf.h"
#include "graphics/font.h"
#include "engines/grim/debug.h"
#include "engines/grim/grim.h"
#include "engines/grim/savegame.h"
@ -82,6 +85,8 @@ void Font::load(const Common::String &filename, Common::SeekableReadStream *data
g_driver->createFont(this);
}
uint16 Font::getCharIndex(unsigned char c) const {
uint16 c2 = uint16(c);
@ -160,6 +165,12 @@ void Font::restoreState(SaveGame *state) {
delete stream;
}
void FontTTF::loadTTF(const Common::String &filename, Common::SeekableReadStream *data, int size) {
_font = Graphics::loadTTFFont(*data, size);
//f->
}
// Hardcoded default font for FPS, GUI, etc
const uint8 Font::emerFont[][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

View File

@ -25,6 +25,8 @@
#include "engines/grim/pool.h"
#include "graphics/font.h"
namespace Common {
class SeekableReadStream;
}
@ -42,23 +44,24 @@ public:
void load(const Common::String &filename, Common::SeekableReadStream *data);
const Common::String &getFilename() const { return _filename; }
int32 getKernedHeight() const { return _kernedHeight; }
int32 getBaseOffsetY() const { return _baseOffsetY; }
int32 getCharBitmapWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
int32 getCharBitmapHeight(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
int32 getCharKernedWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].kernedWidth; }
int32 getCharStartingCol(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingCol; }
int32 getCharStartingLine(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingLine; }
int32 getCharOffset(unsigned char c) const { return _charHeaders[getCharIndex(c)].offset; }
virtual int32 getKernedHeight() const { return _kernedHeight; }
virtual int32 getBaseOffsetY() const { return _baseOffsetY; }
virtual int32 getCharBitmapWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapWidth; }
virtual int32 getCharBitmapHeight(unsigned char c) const { return _charHeaders[getCharIndex(c)].bitmapHeight; }
virtual int32 getCharKernedWidth(unsigned char c) const { return _charHeaders[getCharIndex(c)].kernedWidth; }
virtual int32 getCharStartingCol(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingCol; }
virtual int32 getCharStartingLine(unsigned char c) const { return _charHeaders[getCharIndex(c)].startingLine; }
virtual int32 getCharOffset(unsigned char c) const { return _charHeaders[getCharIndex(c)].offset; }
const byte *getCharData(unsigned char c) const { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
const byte *getFontData() const { return _fontData; }
uint32 getDataSize() const { return _dataSize; }
int getKernedStringLength(const Common::String &text) const;
int getBitmapStringLength(const Common::String &text) const;
int getStringHeight(const Common::String &text) const;
virtual int getKernedStringLength(const Common::String &text) const;
virtual int getBitmapStringLength(const Common::String &text) const;
virtual int getStringHeight(const Common::String &text) const;
const void *getUserData() const { return _userData; }
void setUserData(void *data) { _userData = data; }
@ -90,6 +93,20 @@ private:
void *_userData;
};
class FontTTF : public Font
{
public:
void loadTTF(const Common::String &filename, Common::SeekableReadStream *data, int size);
int32 getKernedHeight() const override { return _font->getFontHeight(); }
int32 getBaseOffsetY() const override { return 0; }
int32 getCharKernedWidth(unsigned char c) const override { return _font->getCharWidth(c); }
int getKernedStringLength(const Common::String &text) const override { return _font->getStringWidth(text); }
Graphics::Font *_font;
};
} // end of namespace Grim
#endif

View File

@ -56,6 +56,7 @@ class Mesh;
class MeshFace;
class Sprite;
class Texture;
class Overlay;
/**
* The Color-formats used for bitmaps in Grim Fandango/Escape From Monkey Island
@ -143,6 +144,8 @@ public:
virtual void drawSprite(const Sprite *sprite) = 0;
virtual void drawMesh(const Mesh *mesh);
virtual void drawOverlay(const Overlay *overlay) { };
virtual void enableLights() = 0;
virtual void disableLights() = 0;
virtual void setupLight(Light *light, int lightId) = 0;
@ -278,7 +281,10 @@ protected:
Texture _specialtyTextures[_numSpecialtyTextures];
static const int _gameHeight = 480;
static const int _gameWidth = 640;
static const int _globalHeight = 1080;
static const int _globalWidth = 1920;
float _scaleW, _scaleH;
float _globalScaleW, _globalScaleH;
int _screenWidth, _screenHeight;
Shadow *_currentShadowArray;
unsigned char _shadowColorR;

View File

@ -49,6 +49,7 @@
#include "engines/grim/model.h"
#include "engines/grim/set.h"
#include "engines/grim/emi/modelemi.h"
#include "engines/grim/remastered/overlay.h"
#include "engines/grim/registry.h"
@ -135,6 +136,9 @@ void GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) {
_scaleW = _screenWidth / (float)_gameWidth;
_scaleH = _screenHeight / (float)_gameHeight;
_globalScaleW = _screenWidth / (float)_globalWidth;
_globalScaleH = _screenHeight / (float)_globalHeight;
_useDepthShader = false;
_useDimShader = false;
@ -924,6 +928,55 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
glPopMatrix();
}
void GfxOpenGL::drawOverlay(const Overlay *overlay) {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GEQUAL, 0.5f);
glDisable(GL_DEPTH_TEST);
float height = overlay->getHeight() * _globalScaleH;
float width = overlay->getWidth() * _globalScaleW;
float x = overlay->_x * _globalScaleW;
float y = overlay->_y * _globalScaleH;
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(x, y);
glTexCoord2f(1.0f, 0.0f);
glVertex2f((x + width), y);
glTexCoord2f(1.0f, 1.0f);
glVertex2f((x + width), (y + height));
glTexCoord2f(0.0f, 1.0f);
glVertex2f(x, (y + height));
glEnd();
glEnable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glDepthMask(GL_TRUE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glPopMatrix();
}
void GfxOpenGL::translateViewpointStart() {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
@ -1374,7 +1427,43 @@ void GfxOpenGL::destroyFont(Font *font) {
}
}
struct TextObjectUserData {
GLuint *_texids;
};
void GfxOpenGL::createTextObject(TextObject *text) {
//error("Could not get font userdata");
const Font *font = text->getFont();
const FontTTF *f = static_cast<const FontTTF *>(font);
Graphics::Font *gf = f->_font;
int numLines = text->getNumLines();
GLuint *texids = new GLuint[numLines];
glGenTextures(numLines, texids);
// Not at all correct for line-wrapping, but atleast we get all the lines now.
for (int i = 0; i < numLines; i++) {
Graphics::Surface surface;
int width = gf->getStringWidth(text->getLines()[i]);
int height = width;
surface.create(height, width, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
gf->drawString(&surface, text->getLines()[i], 0, 0, width, 0xFFFFFFFF);
byte *bitmap = (byte *)surface.getPixels();
glBindTexture(GL_TEXTURE_2D, texids[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
surface.free();
}
TextObjectUserData *ud = new TextObjectUserData;
ud->_texids = texids;
text->setUserData(ud);
}
void GfxOpenGL::drawTextObject(const TextObject *text) {
@ -1401,8 +1490,60 @@ void GfxOpenGL::drawTextObject(const TextObject *text) {
glColor3ub(color.getRed(), color.getGreen(), color.getBlue());
const FontUserData *userData = (const FontUserData *)font->getUserData();
if (!userData)
error("Could not get font userdata");
if (!userData) {
const FontTTF *f = static_cast<const FontTTF *>(font);
Graphics::Font *gf = f->_font;
const TextObjectUserData *ud = (const TextObjectUserData *)text->getUserData();
int numLines = text->getNumLines();
for (int i = 0; i < numLines; ++i) {
float width = gf->getStringWidth(text->getLines()[i]);
float height = width;
float x = text->getLineX(i);
float y = text->getLineY(i);
if (text->getCoords() == 2 || text->getCoords() == 1) {
x *= _globalScaleW;
y *= _globalScaleH;
width *= _globalScaleW;
height *= _globalScaleH;
} else if (text->getCoords() == 0) {
x *= _scaleW;
y *= _scaleH;
width *= _scaleW;
height *= _scaleH;
}
glBindTexture(GL_TEXTURE_2D, ud->_texids[i]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(x, y);
glTexCoord2f(1.0f, 0.0f);
glVertex2f((x + width), y);
glTexCoord2f(1.0f, 1.0f);
glVertex2f((x + width), (y + height));
glTexCoord2f(0.0f, 1.0f);
glVertex2f(x, (y + height));
glEnd();
}
glColor3f(1, 1, 1);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDepthMask(GL_TRUE);
return;
}
float sizeW = userData->size * _scaleW;
float sizeH = userData->size * _scaleH;
GLuint texture = userData->texture;
@ -1448,6 +1589,9 @@ void GfxOpenGL::drawTextObject(const TextObject *text) {
}
void GfxOpenGL::destroyTextObject(TextObject *text) {
TextObjectUserData *ud = (TextObjectUserData *)text->getUserData();
glDeleteTextures(text->getNumLines(), ud->_texids);
delete ud;
}
void GfxOpenGL::createTexture(Texture *texture, const uint8 *data, const CMap *cmap, bool clamp) {
@ -1575,6 +1719,14 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
int width = frame->w;
byte *bitmap = (byte *)frame->getPixels();
double scaleW = _scaleW;
double scaleH = _scaleH;
// Remastered hack, don't scale full-screen videos for now.
if (height == 1080) {
_scaleW = 1.0f;
_scaleH = 1.0f;
}
GLenum format;
GLenum dataType;
int bytesPerPixel = frame->format.bytesPerPixel;
@ -1646,9 +1798,18 @@ void GfxOpenGL::prepareMovieFrame(Graphics::Surface *frame) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
_smushWidth = (int)(width * _scaleW);
_smushHeight = (int)(height * _scaleH);
_scaleW = scaleW;
_scaleH = scaleH;
}
void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
double scaleW = _scaleW;
double scaleH = _scaleH;
// Remastered hack, don't scale full-screen videos for now.
if (_smushHeight == 1080) {
_scaleW = 1.0f;
_scaleH = 1.0f;
}
// prepare view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@ -1695,6 +1856,9 @@ void GfxOpenGL::drawMovieFrame(int offsetX, int offsetY) {
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
_scaleW = scaleW;
_scaleH = scaleH;
}
void GfxOpenGL::releaseMovieFrame() {

View File

@ -90,6 +90,8 @@ public:
void drawModelFace(const Mesh *mesh, const MeshFace *face) override;
void drawSprite(const Sprite *sprite) override;
void drawOverlay(const Overlay *overlay) override;
void enableLights() override;
void disableLights() override;
void setupLight(Light *light, int lightId) override;

View File

@ -76,6 +76,9 @@
#include "engines/grim/sound.h"
#include "engines/grim/stuffit.h"
#include "engines/grim/debugger.h"
#include "engines/grim/remastered/overlay.h"
#include "engines/grim/remastered/lua_remastered.h"
#include "engines/grim/remastered/commentary.h"
#include "engines/grim/imuse/imuse.h"
#include "engines/grim/emi/sound/emisound.h"
@ -89,7 +92,7 @@ GfxBase *g_driver = nullptr;
int g_imuseState = -1;
GrimEngine::GrimEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, Common::Platform platform, Common::Language language) :
Engine(syst), _currSet(nullptr), _selectedActor(nullptr), _pauseStartTime(0) {
Engine(syst), _currSet(nullptr), _selectedActor(nullptr), _pauseStartTime(0), _language(0) {
g_grim = this;
setDebugger(new Debugger());
@ -183,6 +186,22 @@ GrimEngine::GrimEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, C
SearchMan.addSubDirectoryMatching(gameDataDir, "widescreen");
Debug::registerDebugChannels();
//Remastered:
if (getGameFlags() & ADGF_REMASTERED) {
for (int i = 0; i < kNumCutscenes; i++) {
_cutsceneEnabled[i] = false;
}
for (int i = 0; i < kNumConcepts; i++) {
_conceptEnabled[i] = false;
}
_saveMeta1 = "";
_saveMeta2 = 0;
_saveMeta3 = "";
}
_commentary = nullptr;
}
GrimEngine::~GrimEngine() {
@ -214,6 +233,9 @@ GrimEngine::~GrimEngine() {
g_driver = nullptr;
delete _iris;
// Remastered:
delete _commentary;
ConfMan.flushToDisk();
DebugMan.clearAllDebugChannels();
@ -233,7 +255,11 @@ void GrimEngine::clearPools() {
}
LuaBase *GrimEngine::createLua() {
return new Lua_V1();
if (getGameFlags() == ADGF_REMASTERED) {
return new Lua_Remastered();
} else {
return new Lua_V1();
}
}
GfxBase *GrimEngine::createRenderer(int screenW, int screenH, bool fullscreen) {
@ -311,7 +337,7 @@ Common::Error GrimEngine::run() {
}
ConfMan.registerDefault("check_gamedata", true);
if (ConfMan.getBool("check_gamedata")) {
if (ConfMan.getBool("check_gamedata") && getGameFlags() != ADGF_REMASTERED) {
MD5CheckDialog d;
if (!d.runModal()) {
Common::U32String confirmString = Common::U32String::format(_(
@ -343,6 +369,10 @@ Common::Error GrimEngine::run() {
if (getGameType() == GType_GRIM) {
g_imuse = new Imuse(20, demo);
g_emiSound = nullptr;
if (g_grim->getGameFlags() & ADGF_REMASTERED) {
// This must happen here, since we need the resource loader set up.
_commentary = new Commentary();
}
} else if (getGameType() == GType_MONKEY4) {
g_emiSound = new EMISound(20);
g_imuse = nullptr;
@ -350,7 +380,7 @@ Common::Error GrimEngine::run() {
g_sound = new SoundPlayer();
bool fullscreen = ConfMan.getBool("fullscreen");
g_driver = createRenderer(640, 480, fullscreen);
g_driver->setupScreen(640, 480, fullscreen);
if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) {
// Play EMI Mac Aspyr logo
@ -874,6 +904,10 @@ void GrimEngine::drawNormalMode() {
p->draw();
}
foreach (Overlay *p, Overlay::getPool()) {
p->draw();
}
_currSet->setupCamera();
g_driver->set3DMode();
@ -1054,11 +1088,34 @@ void GrimEngine::mainLoop() {
handleJoyAxis(event.joystick.axis, event.joystick.position);
if (type == Common::EVENT_JOYBUTTON_DOWN || type == Common::EVENT_JOYBUTTON_UP)
handleJoyButton(type, event.joystick.button);
if (type == Common::EVENT_LBUTTONUP) {
_cursorX = event.mouse.x;
_cursorY = event.mouse.y;
Common::KeyState k;
k.keycode = (Common::KeyCode)KEYCODE_MOUSE_B1;
handleControls(Common::EVENT_KEYUP, k);
}
if (type == Common::EVENT_LBUTTONDOWN) {
_cursorX = event.mouse.x;
_cursorY = event.mouse.y;
Common::KeyState k;
k.keycode = (Common::KeyCode)KEYCODE_MOUSE_B1;
handleControls(Common::EVENT_KEYDOWN, k);
}
if (type == Common::EVENT_MOUSEMOVE) {
_cursorX = event.mouse.x;
_cursorY = event.mouse.y;
handleMouseAxis(0, _cursorX);
handleMouseAxis(1, _cursorY);
}
if (type == Common::EVENT_SCREEN_CHANGED) {
handleUserPaint();
}
}
if (_mode != PauseMode) {
// Draw the display scene before doing the luaUpdate.
// This give a large performance boost as OpenGL stores commands
@ -1243,6 +1300,17 @@ void GrimEngine::restoreGRIM() {
_savedState->endSection();
}
void GrimEngine::storeSaveGameMetadata(SaveGame *state) {
if (!g_grim->getGameFlags() & ADGF_REMASTERED) {
return;
}
state->beginSection('META');
state->writeString(_saveMeta1);
state->writeLEUint32(_saveMeta2);
state->writeString(_saveMeta3);
state->endSection();
}
void GrimEngine::storeSaveGameImage(SaveGame *state) {
const Graphics::PixelFormat image_format = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
int width = 250, height = 188;
@ -1286,6 +1354,7 @@ void GrimEngine::savegameSave() {
GUI::displayErrorDialog(_("Error: the game could not be saved."));
return;
}
storeSaveGameMetadata(_savedState);
storeSaveGameImage(_savedState);
@ -1599,4 +1668,49 @@ void GrimEngine::debugLua(const Common::String &str) {
lua_dostring(str.c_str());
}
Common::String GrimEngine::getLanguagePrefix() const {
switch (getLanguage()) {
case 0:
return Common::String("en");
case 1:
return Common::String("de");
case 2:
return Common::String("es");
case 3:
return Common::String("fr");
case 4:
return Common::String("it");
case 5:
return Common::String("pt");
default:
error("Unknown language id %d", getLanguage());
}
}
bool GrimEngine::isConceptEnabled(uint32 number) const {
assert (number < kNumConcepts);
return _conceptEnabled[number];
}
void GrimEngine::enableConcept(uint32 number) {
assert (number < kNumConcepts);
_conceptEnabled[number] = true;
}
bool GrimEngine::isCutsceneEnabled(uint32 number) const {
assert (number < kNumCutscenes);
return _cutsceneEnabled[number];
}
void GrimEngine::enableCutscene(uint32 number) {
assert (number < kNumCutscenes);
_cutsceneEnabled[number] = true;
}
void GrimEngine::setSaveMetaData(const char *meta1, int meta2, const char *meta3) {
_saveMeta1 = meta1;
_saveMeta2 = meta2;
_saveMeta3 = meta3;
}
} // end of namespace Grim

View File

@ -47,6 +47,7 @@ class Set;
class TextObject;
class PrimitiveObject;
class LuaBase;
class Commentary;
class GfxBase;
struct ControlDescriptor {
@ -159,6 +160,21 @@ public:
void setMovieSubtitle(TextObject *to);
void setMovieSetup();
int getLanguage() const { return _language; }
void setLanguage(int langId) { _language = langId; }
Common::String getLanguagePrefix() const;
bool isConceptEnabled(uint32 number) const;
void enableConcept(uint32 number);
bool isCutsceneEnabled(uint32 number) const;
void enableCutscene(uint32 number);
Commentary *getCommentary() { return _commentary; }
// TODO: Refactor.
void setSaveMetaData(const char*, int, const char*);
void saveGame(const Common::String &file);
void loadGame(const Common::String &file);
@ -183,6 +199,7 @@ protected:
void handleControls(Common::EventType type, const Common::KeyState &key);
void handleChars(Common::EventType type, const Common::KeyState &key);
void handleJoyAxis(byte axis, int16 position);
void handleMouseAxis(byte axis, int16 position);
void handleJoyButton(Common::EventType type, byte button);
void handleExit();
void handlePause();
@ -204,6 +221,7 @@ protected:
void savegameRestore();
void restoreGRIM();
virtual void storeSaveGameMetadata(SaveGame *state);
virtual void storeSaveGameImage(SaveGame *savedState);
bool _savegameLoadRequest;
@ -252,6 +270,23 @@ protected:
Common::Platform _gamePlatform;
Common::Language _gameLanguage;
uint32 _pauseStartTime;
// Remastered;
uint32 _language;
static const uint32 kNumConcepts = 98;
static const uint32 kNumCutscenes = 40;
bool _cutsceneEnabled[kNumCutscenes]; // TODO, could probably use a different data structure
bool _conceptEnabled[kNumConcepts];
Common::String _saveMeta1;
int _saveMeta2;
Common::String _saveMeta3;
Commentary *_commentary;
public:
int _cursorX;
int _cursorY;
};
extern GrimEngine *g_grim;

View File

@ -211,6 +211,8 @@ const ControlDescriptor controls[] = {
{ "KEY_MOUSE_B2", KEYCODE_MOUSE_B2 },
{ "KEY_MOUSE_B3", KEYCODE_MOUSE_B3 },
{ "KEY_MOUSE_B4", KEYCODE_MOUSE_B4 },
{ "KEY_MOUSE_LONG", KEYCODE_MOUSE_B4 }, // TODO: Actually map this
{ "KEY_MOUSE_PING", KEYCODE_MOUSE_B4 }, // TODO: Actually map this
{ "AXIS_JOY1_X", KEYCODE_AXIS_JOY1_X },
{ "AXIS_JOY1_Y", KEYCODE_AXIS_JOY1_Y },
{ "AXIS_JOY1_Z", KEYCODE_AXIS_JOY1_Z },
@ -347,6 +349,19 @@ void GrimEngine::handleJoyAxis(byte axis, int16 position) {
}
}
void GrimEngine::handleMouseAxis(byte axis, int16 position) {
int keycode = KEYCODE_AXIS_MOUSE_X;
if (!_controlsEnabled[keycode])
return;
LuaObjects objects;
objects.add(keycode);
objects.add(position);
if (!LuaBase::instance()->callback("axisHandler", objects)) {
error("handleJoyAxis: invalid joystick handler");
}
}
void GrimEngine::handleJoyButton(Common::EventType operation, byte button) {
if (button > NUM_JOY_BUTTONS)
return;

View File

@ -23,6 +23,7 @@
#include "common/file.h"
#include "common/str.h"
#include "common/endian.h"
#include "common/tokenizer.h"
#include "engines/grim/localize.h"
#include "engines/grim/grim.h"
@ -32,6 +33,7 @@ namespace Grim {
Localizer *g_localizer = nullptr;
Localizer::Localizer() {
// To avoid too wide lines further below, we just name these here.
bool isAnyDemo = g_grim->getGameFlags() & ADGF_DEMO;
@ -42,6 +44,7 @@ Localizer::Localizer() {
bool isSpanish = g_grim->getGameLanguage() == Common::ES_ESP;
bool isTranslatedGrimDemo = (isGerman || isFrench || isItalian || isSpanish) && isGrimDemo;
bool isPS2 = g_grim->getGamePlatform() == Common::kPlatformPS2;
bool isRemastered = g_grim->getGameFlags() & ADGF_REMASTERED; // TODO: Add handling of this from g_grim.
if (isGrimDemo && !isTranslatedGrimDemo)
return;
@ -50,7 +53,9 @@ Localizer::Localizer() {
if (g_grim->getGameType() == GType_MONKEY4) {
filename = "script.tab";
} else {
if (isTranslatedGrimDemo) {
if (isRemastered) {
filename = Common::String("grim.") + g_grim->getLanguagePrefix() + Common::String(".tab"); // TODO: Detect based on language.
} else if (isTranslatedGrimDemo) {
filename = "language.tab";
} else {
filename = "grim.tab";
@ -71,6 +76,11 @@ Localizer::Localizer() {
data[filesize] = '\0';
delete f;
if (isRemastered) {
parseRemasteredData(Common::String(data));
return;
}
// Explicitly white-list german demo, as it has a .tab-file
if ((isTranslatedGrimDemo) || (!isAnyDemo && !isPS2)) {
if (filesize < 4)
@ -142,6 +152,22 @@ Localizer::Localizer() {
delete[] data;
}
void Localizer::parseRemasteredData(const Common::String &data) {
// This is probably cleaner implemented using a read line-by-line, but for now this works.
Common::StringTokenizer tokens(data, "\t\n");
while (!tokens.empty()) {
Common::String key = tokens.nextToken();
// Not sure if this is right, but it is necessary to get by the second line
key.trim();
// Handle comments
if (!(key.size() > 0 && !(key[0] == '#'))) {
continue;
}
Common::String string = tokens.nextToken();
_entries[key] = string;
}
}
Common::String Localizer::localize(const char *str) const {
assert(str);

View File

@ -33,6 +33,7 @@ public:
Common::String localize(const char *str) const;
private:
void parseRemasteredData(const Common::String &data);
Common::StringMap _entries;
};

View File

@ -232,6 +232,8 @@ void LuaBase::registerLua() {
refTextObjectBackground = lua_ref(true);
lua_pushstring("layer");
refTextObjectLayer = lua_ref(true);
lua_pushstring("coords");
refTextObjectCoords = lua_ref(true);
}
void LuaBase::forceDemo() {
@ -627,6 +629,18 @@ void LuaBase::setTextObjectParams(TextObjectCommon *textObject, lua_Object table
}
}
// FIXME: remove check once the major save version is updated
// currently it is needed for backward compatibility of old savegames
if (lua_getref(refTextObjectCoords) == LUA_NOOBJECT)
return;
lua_pushobject(tableObj);
lua_pushobject(lua_getref(refTextObjectCoords));
keyObj = lua_gettable();
if (keyObj) {
if (lua_isnumber(keyObj)) {
textObject->setCoords(lua_getnumber(keyObj));
}
}
}
void LuaBase::typeOverride() {

View File

@ -185,6 +185,7 @@ private:
int refTextObjectBackground;
int refTextObjectPan;
int refTextObjectLayer;
int refTextObjectCoords;
static LuaBase *s_instance;

View File

@ -243,14 +243,14 @@ int32 luaD_call(StkId base, int32 nResults) {
// when in year 4 bi.exit() calls bi.book.act:free(). But bi.book.act is nil,
// hence it enters this branch and the error blocks the game.
// Now we try instead to survive and go on with the function.
lua_Task *t = lua_state->task;
/*lua_Task *t = lua_state->task;
lua_state->task = t->next;
lua_state->some_task = tmpTask;
luaM_free(t);
warning("Lua: call expression not a function");
return 1;
// lua_error("call expression not a function");
return 1;*/
lua_error("call expression not a function");
}
luaD_callTM(im, (lua_state->stack.top - lua_state->stack.stack) - (base - 1), nResults);
continue;

View File

@ -361,7 +361,6 @@ void Lua_V1::ChangePrimitive() {
if (lua_isnumber(height))
/*y = (int)*/lua_getnumber(height);
// TODO pmodify->setSize(x, y);
assert(0);
}
}

View File

@ -22,6 +22,7 @@
#include "common/endian.h"
#include "image/tga.h"
#include "image/png.h"
#include "graphics/surface.h"
#include "engines/grim/grim.h"
@ -46,7 +47,43 @@ MaterialData::MaterialData(const Common::String &filename, Common::SeekableReadS
}
}
void loadPNG(Common::SeekableReadStream *data, Texture *t) {
Image::PNGDecoder *pngDecoder = new Image::PNGDecoder();
pngDecoder->loadStream(*data);
Graphics::Surface *pngSurface =pngDecoder->getSurface()->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), pngDecoder->getPalette());
t->_width = pngSurface->w;
t->_height = pngSurface->h;
t->_texture = nullptr;
int bpp = pngSurface->format.bytesPerPixel;
assert(bpp == 4); // Assure we have 32 bpp
t->_colorFormat = BM_RGBA;
t->_bpp = 4;
t->_hasAlpha = true;
// Allocate room for the texture.
t->_data = new uint8[t->_width * t->_height * (bpp)];
// Copy the texture data, as the decoder owns the current copy.
memcpy(t->_data, pngSurface->getPixels(), t->_width * t->_height * (bpp));
pngSurface->free();
delete pngSurface;
delete pngDecoder;
}
void MaterialData::initGrim(Common::SeekableReadStream *data) {
if (_fname.hasSuffix(".png")) {
_numImages = 1;
_textures = new Texture*[1];
_textures[0] = new Texture();
loadPNG(data, _textures[0]);
return;
}
uint32 tag = data->readUint32BE();
if (tag != MKTAG('M','A','T',' '))
error("Invalid header for texture %s. Expected 'MAT ', got '%c%c%c%c'", _fname.c_str(),
@ -201,7 +238,8 @@ MaterialData *MaterialData::getMaterialData(const Common::String &filename, Comm
++m->_refCount;
return m;
}
if (m->_fname == filename && m->_cmap->getFilename() == cmap->getFilename()) {
// We need to allow null cmaps for remastered overlays
if (m->_fname == filename && (!(m->_cmap || cmap) || m->_cmap->getFilename() == cmap->getFilename())) {
++m->_refCount;
return m;
}

View File

@ -83,6 +83,10 @@ MODULE_OBJS := \
movie/movie.o \
movie/quicktime.o \
movie/smush.o \
remastered/commentary.o \
remastered/hotspot.o \
remastered/lua_remastered.o \
remastered/overlay.o \
update/packfile.o \
update/mscab.o \
update/lang_filter.o \

View File

@ -23,6 +23,8 @@
#include "engines/grim/movie/codecs/smush_decoder.h"
#include "engines/grim/movie/smush.h"
#include "video/theora_decoder.h"
#include "engines/grim/resource.h"
#include "engines/grim/grim.h"
@ -32,25 +34,49 @@ MoviePlayer *CreateSmushPlayer(bool demo) {
return new SmushPlayer(demo);
}
SmushPlayer::~SmushPlayer() {
delete _theoraDecoder;
}
SmushPlayer::SmushPlayer(bool demo) : MoviePlayer(), _demo(demo) {
_smushDecoder = new SmushDecoder();
_videoDecoder = _smushDecoder;
_theoraDecoder = new Video::TheoraDecoder();
//_smushDecoder->setDemo(_demo);
}
bool SmushPlayer::loadFile(const Common::String &filename) {
warning("Play video %s\n", filename.c_str());
bool success = false;
_videoDecoder = _smushDecoder;
if (!_demo)
return _videoDecoder->loadStream(g_resourceloader->openNewStreamFile(filename.c_str()));
success = _videoDecoder->loadStream(g_resourceloader->openNewStreamFile(filename.c_str()));
else
return _videoDecoder->loadFile(filename);
success = _videoDecoder->loadFile(filename);
if (!success) {
Common::String theoraFilename = "MoviesHD/" + filename;
theoraFilename.erase(theoraFilename.size() - 4);
theoraFilename += ".ogv";
warning("Trying to open %s", theoraFilename.c_str());
success = _theoraDecoder->loadFile(theoraFilename);
_videoDecoder = _theoraDecoder;
_currentVideoIsTheora = true;
} else {
_videoDecoder = _smushDecoder;
_currentVideoIsTheora = false;
}
return success;
}
void SmushPlayer::init() {
if (_demo) {
_x = _smushDecoder->getX();
_y = _smushDecoder->getY();
} else {
_smushDecoder->setLooping(_videoLooping);
if (!_currentVideoIsTheora) {
if (_demo) {
_x = _smushDecoder->getX();
_y = _smushDecoder->getY();
} else {
_smushDecoder->setLooping(_videoLooping);
}
}
MoviePlayer::init();
}
@ -65,21 +91,23 @@ void SmushPlayer::handleFrame() {
deinit();
return;
} else {
_smushDecoder->rewind(); // This doesnt handle if looping fails.
_smushDecoder->start();
if (!_currentVideoIsTheora) {
_smushDecoder->rewind(); // This doesnt handle if looping fails.
_smushDecoder->start();
}
}
}
}
void SmushPlayer::postHandleFrame() {
if (_demo) {
if (_demo && !_currentVideoIsTheora) {
_x = _smushDecoder->getX();
_y = _smushDecoder->getY();
}
}
void SmushPlayer::restore(SaveGame *state) {
if (isPlaying()) {
if (isPlaying() && !_currentVideoIsTheora) {
_smushDecoder->seek((uint32)_movieTime);
_smushDecoder->start();
timerCallback(this);

View File

@ -25,6 +25,10 @@
#include "engines/grim/movie/movie.h"
namespace Video {
class TheoraDecoder;
}
namespace Grim {
class SmushDecoder;
@ -32,7 +36,7 @@ class SmushDecoder;
class SmushPlayer : public MoviePlayer {
public:
SmushPlayer(bool demo);
virtual ~SmushPlayer();
void restore(SaveGame *state) override;
private:
@ -41,7 +45,9 @@ private:
void postHandleFrame() override;
void init() override;
bool _demo;
bool _currentVideoIsTheora;
SmushDecoder *_smushDecoder;
Video::TheoraDecoder *_theoraDecoder; // HACK for now, move to other class later?
};
} // end of namespace Grim

View File

@ -119,6 +119,17 @@ Registry::Registry() :
//_joystick.setString(ConfMan.get("joystick"));
_joystick.setString("false");
_transcript.setString(ConfMan.get("transcript"));
// Remastered
_widescreen.setInt(ConfMan.getInt("widescreen"));
_directorsCommentary.setInt(ConfMan.getInt("directors_commentary"));
_directorsCommentaryVolume.setInt(convertVolumeFromMixer(ConfMan.getInt("directors_commentary_volume")));
_language.setInt(ConfMan.getInt("grim_language")); // Avoid overlap with confman
_resolutionScaling.setInt(ConfMan.getInt("resolution_scaling"));
_mouseSpeed.setInt(ConfMan.getInt("mouse_speed"));
_advancedLighting.setInt(ConfMan.getInt("advanced_lighting"));
_renderingMode.setInt(ConfMan.getInt("rendering_mode"));
_fullScreen.setInt(ConfMan.getInt("grim_fullscreen")); // TODO: Should probably map against normal fullscreen, but this may have issues with alt-enter, so leaving it like this for now.
}
Registry::Value &Registry::value(const Common::String &key) {
@ -154,6 +165,27 @@ Registry::Value &Registry::value(const Common::String &key) {
return _spewOnError;
} else if (scumm_stricmp("Transcript", key.c_str()) == 0) {
return _transcript;
} else if (scumm_stricmp("DirectorsCommentary", key.c_str()) == 0) {
return _directorsCommentary;
} else if (scumm_stricmp("Widescreen", key.c_str()) == 0) {
return _widescreen;
} else if (scumm_stricmp("Language", key.c_str()) == 0) {
return _language;
} else if (scumm_stricmp("ResolutionScaling", key.c_str()) == 0) {
return _resolutionScaling;
} else if (scumm_stricmp("MouseSpeed", key.c_str()) == 0) {
return _mouseSpeed;
} else if (scumm_stricmp("AdvancedLighting", key.c_str()) == 0) {
return _advancedLighting;
} else if (scumm_stricmp("DirectorsCommentaryVolume", key.c_str()) == 0) {
return _directorsCommentaryVolume;
} else if (scumm_stricmp("RenderingMode", key.c_str()) == 0) {
return _renderingMode;
} else if (scumm_stricmp("Fullscreen", key.c_str()) == 0) {
return _fullScreen;
} else {
warning("write unknown regisry value %s", key.c_str());
return _musicVolume;
}
assert(0);
@ -193,6 +225,27 @@ const Registry::Value &Registry::value(const Common::String &key) const {
return _spewOnError;
} else if (scumm_stricmp("Transcript", key.c_str()) == 0) {
return _transcript;
} else if (scumm_stricmp("DirectorsCommentary", key.c_str()) == 0) {
return _directorsCommentary;
} else if (scumm_stricmp("Widescreen", key.c_str()) == 0) {
return _widescreen;
} else if (scumm_stricmp("Language", key.c_str()) == 0) {
return _language;
} else if (scumm_stricmp("ResolutionScaling", key.c_str()) == 0) {
return _resolutionScaling;
} else if (scumm_stricmp("MouseSpeed", key.c_str()) == 0) {
return _mouseSpeed;
} else if (scumm_stricmp("AdvancedLighting", key.c_str()) == 0) {
return _advancedLighting;
} else if (scumm_stricmp("DirectorsCommentaryVolume", key.c_str()) == 0) {
return _directorsCommentaryVolume;
} else if (scumm_stricmp("RenderingMode", key.c_str()) == 0) {
return _renderingMode;
} else if (scumm_stricmp("Fullscreen", key.c_str()) == 0) {
return _fullScreen;
} else {
warning("unknown regisry value %s", key.c_str());
return _musicVolume;
}
assert(0);
@ -253,6 +306,16 @@ void Registry::save() {
ConfMan.set("voice_effects", _voiceEffects.getString());
ConfMan.set("transcript", _transcript.getString());
// Remastered (TODO: These are handled as string for now)
ConfMan.setInt("widescreen", _widescreen.getInt());
ConfMan.setInt("directors_commentary", _directorsCommentary.getInt());
ConfMan.setInt("grim_language", _language.getInt());
ConfMan.setInt("resolution_scaling", _resolutionScaling.getInt());
ConfMan.setInt("mouse_speed", _mouseSpeed.getInt());
ConfMan.setInt("advanced_lighting", _advancedLighting.getInt());
ConfMan.setInt("directors_commentary_volume", convertVolumeToMixer(_directorsCommentaryVolume.getInt()));
ConfMan.setInt("rendering_mode", _renderingMode.getInt());
ConfMan.setInt("grim_fullscreen", _fullScreen.getInt());
_dirty = false;
}

View File

@ -94,6 +94,17 @@ private:
Value _spewOnError;
Value _transcript;
Value _dummy;
// Remastered (TODO: Fix the type-handling), TODO: Disable for original
Value _directorsCommentary;
Value _widescreen;
Value _language;
Value _resolutionScaling;
Value _mouseSpeed;
Value _advancedLighting;
Value _directorsCommentaryVolume;
Value _renderingMode;
Value _fullScreen;
bool _dirty;

View File

@ -0,0 +1,172 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "engines/grim/remastered/commentary.h"
#include "engines/grim/resource.h"
#include "engines/grim/textsplit.h"
#include "engines/grim/localize.h"
#include "common/textconsole.h"
namespace Grim {
struct CommentLine {
int _id;
Common::String _line;
int _start;
int _end;
};
class Comment {
Common::String _name;
Common::String _filename;
Common::Array<CommentLine> _lines;
bool _hasHeard; //TODO: Should be saved
public:
Comment(const Common::String &name, const Common::String &filename);
Common::String getName() const;
void addLine(int id, const Common::String &text, int start, int end);
void play();
bool hasHeard() const { return _hasHeard; }
};
Comment::Comment(const Common::String &name, const Common::String &filename) : _name(name), _filename(filename), _hasHeard(false) {
}
void Comment::addLine(int id, const Common::String &text, int start, int end) {
CommentLine line;
line._id = id;
line._line = text;
line._start = start;
line._end = end;
_lines.push_back(line);
}
Common::String Comment::getName() const {
return _name;
}
void Comment::play() {
for (int i = 0; i < _lines.size(); i++) {
Common::String text = g_localizer->localize(_lines[i]._line.c_str());
warning("Line: %d Start: %d End: %d Id: %d Text: %s", i, _lines[i]._start, _lines[i]._end, _lines[i]._id, text.c_str());
}
_hasHeard = true;
}
Commentary::Commentary() : _currentCommentary(nullptr) {
loadCommentary();
}
Commentary::~Commentary() {
Common::HashMap<Common::String, Comment*>::iterator it = _comments.begin();
for (; it != _comments.end(); ++it) {
delete it->_value;
}
_comments.clear();
}
void Commentary::loadCommentary() {
Common::String defFilename = "commentary_def.txt";
Common::SeekableReadStream *f = g_resourceloader->openNewStreamFile(defFilename);
if (!f) {
error("Commentary::loadCommentary: Unable to find commentary definition (%s)", defFilename.c_str());
return;
}
TextSplitter ts(defFilename, f);
while (!ts.isEof()) {
// Skip comments
while (ts.checkString("#")) {
ts.nextLine();
}
// Skip blank lines and trim input
Common::String currentLine = ts.getCurrentLine();
currentLine.trim();
while (currentLine.size() == 0) {
currentLine = ts.nextLine();
currentLine.trim();
}
Common::String name = currentLine;
name.trim();
Common::String filename = ts.nextLine();
ts.nextLine();
filename.trim();
Comment *c = new Comment(name, filename);
int numLines = 0;
ts.scanString("\t%d", 1, &numLines);
char str[20] = {0};
for (int i = 0; i < numLines; i++) {
int id = 0;
int start = 0;
int end = 0;
ts.scanString("%d\t%s\t%d\t%d", 4, &id, str, &start, &end);
c->addLine(id, str, start, end);
}
_comments.setVal(name, c);
}
}
Comment *Commentary::findCommentary(const Common::String &name) {
Common::String lowerName = name;
lowerName.toLowercase();
if (!_comments.contains(lowerName)) {
return nullptr;
} else {
return _comments.getVal(lowerName);
}
}
void Commentary::playCurrentCommentary() {
if (_currentCommentary != nullptr) {
warning("Commentary::playCurrentCommentary, current is %s", _currentCommentary->getName().c_str());
_currentCommentary->play();
} else {
warning("Commentary::playCurrentCommentary, no current commentary");
}
}
void Commentary::setCurrentCommentary(const Common::String &name) {
warning("Commentary::setCurrentCommentary(%s)", name.c_str());
_currentCommentary = findCommentary(name);
if (_currentCommentary == nullptr) {
warning("Commentary::setCurrentCommentary(%s) could not find commentary", name.c_str());
}
}
bool Commentary::hasHeardCommentary(const Common::String &name) const {
Common::String lowerName = name;
lowerName.toLowercase();
if (!_comments.contains(lowerName)) {
warning("Commentary::hasHeardCommentary(%s) could not find commentary", name.c_str());
return false;
} else {
return _comments.getVal(lowerName)->hasHeard();
}
}
} // end of namespace Grim

View File

@ -0,0 +1,48 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRIM_COMMENTARY
#define GRIM_COMMENTARY
#include "common/str.h"
#include "common/hash-str.h"
namespace Grim {
class Comment;
class Commentary {
// TODO: Case sensitivity
Common::HashMap<Common::String, Comment*> _comments;
Comment *_currentCommentary;
Comment *findCommentary(const Common::String &name);
void loadCommentary();
public:
Commentary();
~Commentary();
void playCurrentCommentary();
void setCurrentCommentary(const Common::String &name);
bool hasHeardCommentary(const Common::String &name) const;
};
} // end of namespace Grim
#endif

View File

@ -0,0 +1,40 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "engines/grim/remastered/hotspot.h"
namespace Grim {
Hotspot::Hotspot(const Common::String &name, int x, int y, int width, int height) :
_name(name), _x(x), _y(y), _width(width), _height(height), _rect(Math::Vector2d(_x, _y), Math::Vector2d(_x + _width, _y + _height)) {
}
Hotspot::~Hotspot() {
}
}

View File

@ -0,0 +1,54 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRIM_HOTSPOT_H
#define GRIM_HOTSPOT_H
#include "common/endian.h"
#include "engines/grim/pool.h"
#include "math/rect2d.h"
namespace Grim {
class Hotspot : public PoolObject<Hotspot> {
public:
Hotspot(const Common::String &name, int x, int y, int width, int height);
~Hotspot();
static int32 getStaticTag() { return MKTAG('H','O','T','S'); }
//private:
Common::String _name;
int _x;
int _y;
int _width;
int _height;
Math::Rect2d _rect;
};
}
#endif

View File

@ -0,0 +1,699 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/endian.h"
#include "common/foreach.h"
#include "common/savefile.h"
#include "common/config-manager.h"
#include "engines/grim/remastered/lua_remastered.h"
#include "engines/grim/remastered/overlay.h"
#include "engines/grim/remastered/hotspot.h"
#include "engines/grim/grim.h"
#include "engines/grim/font.h"
#include "engines/grim/resource.h"
#include "engines/grim/registry.h"
#include "engines/grim/localize.h"
#include "engines/grim/lua/lauxlib.h"
#include "engines/grim/lua/luadebug.h"
namespace Grim {
void Lua_Remastered::WidescreenCorrectionFactor() {
warning("Stub function: WidescreenCorrectionFactor, returns 1");
lua_pushnumber(1);
}
void Lua_Remastered::GetFontDimensions() {
// Taken from Lua_v2 and modified
lua_Object fontObj = lua_getparam(1);
if (!lua_isuserdata(fontObj) || lua_tag(fontObj) != Font::getStaticTag())
return;
Font *font = Font::getPool().getObject(lua_getuserdata(fontObj));
if (font) {
int32 h = font->getKernedHeight();
int32 w = font->getCharKernedWidth('w');
lua_pushnumber(w);
lua_pushnumber(h);
} else {
warning("Lua_Remastered::GetFontDimensions for invalid font: returns 0,0");
lua_pushnumber(0.f);
lua_pushnumber(0.f);
}
}
void Lua_Remastered::GetTextObjectDimensions() {
lua_Object textObj = lua_getparam(1);
lua_Object coordsObj = lua_getparam(2);
if (lua_isnumber(coordsObj)) {
int val = lua_getnumber(coordsObj);
warning("Stub function: GetTextObjectDimensions(%d)", val);
}
if (lua_isuserdata(textObj) && lua_tag(textObj) == MKTAG('T', 'E', 'X', 'T')) {
TextObject *textObject = gettextobject(textObj);
lua_pushnumber(textObject->getWidth()); // REMASTERED HACK
lua_pushnumber(textObject->getBitmapHeight()); // REMASTERED HACK
// If the line is rjustified getX does us no good
lua_pushnumber(textObject->getLineX(0));
lua_pushnumber(textObject->getY());
}
}
void Lua_Remastered::OverlayDimensions() {
lua_Object overlayObj = lua_getparam(1);
if (!lua_isuserdata(overlayObj) || lua_tag(overlayObj) != Overlay::getStaticTag())
return;
Overlay *overlay = Overlay::getPool().getObject(lua_getuserdata(overlayObj));
lua_pushnumber(overlay->getWidth());
lua_pushnumber(overlay->getHeight());
}
void Lua_Remastered::OverlayGetScreenSize() {
warning("Stub function: OverlayGetScreenSize, returns 1920, 1080");
lua_pushnumber(1920);
lua_pushnumber(1080);
}
void Lua_Remastered::OverlayCreate() {
warning("Stub function: OverlayCreate not done");
lua_Object param1 = lua_getparam(1);
lua_Object param2 = lua_getparam(2);
lua_Object param3 = lua_getparam(3);
lua_Object param4 = lua_getparam(4);
if (!lua_isstring(param1) || !lua_isnumber(param2) || !lua_isnumber(param3) || !lua_istable(param4)) {
return;
}
const char *overlayName = lua_getstring(param1);
float x = lua_getnumber(param2);
float y = lua_getnumber(param3);
lua_pushobject(param4);
lua_pushstring("layer");
lua_Object table = lua_gettable();
float layer = lua_getnumber(table);
Overlay *overlay = g_resourceloader->loadOverlay(overlayName);
if (overlay) {
overlay->setPos(x, y);
overlay->setLayer(layer);
lua_pushusertag(overlay->getId(), overlay->getTag());
} else {
lua_pushnil();
}
}
void Lua_Remastered::OverlayDestroy() {
lua_Object actorObj = lua_getparam(1);
if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != Overlay::getStaticTag())
return;
Overlay *overlay = Overlay::getPool().getObject(lua_getuserdata(actorObj));
delete overlay;
}
void Lua_Remastered::OverlayFade() {
lua_Object overlayObj = lua_getparam(1);
lua_Object fadeObj = lua_getparam(2);
if (!lua_isuserdata(overlayObj) || lua_tag(overlayObj) != Overlay::getStaticTag())
return;
assert(lua_isnumber(fadeObj));
int fadeType = lua_getnumber(fadeObj);
warning("Stub function: OverlayFade(%d)", fadeType);
Overlay *overlay = Overlay::getPool().getObject(lua_getuserdata(overlayObj));
if (fadeType == 3) {
delete overlay;
}
}
void Lua_Remastered::OverlayMove() {
lua_Object overlayObj = lua_getparam(1);
lua_Object param2 = lua_getparam(2);
lua_Object param3 = lua_getparam(3);
if (!lua_isuserdata(overlayObj) || lua_tag(overlayObj) != Overlay::getStaticTag())
return;
Overlay *overlay = Overlay::getPool().getObject(lua_getuserdata(overlayObj));
float x = lua_getnumber(param2);
float y = lua_getnumber(param3);
overlay->setPos(x, y);
}
void Lua_Remastered::QueryActiveHotspots() {
lua_Object param = lua_getparam(1);
assert(lua_isnumber(param));
warning("Stub function: QueryActiveHotspots(%d)", lua_getnumber(param));
// TODO: Handle coord scaling better
float scaleX = 1920.0f/1600;
float scaleY = 1080.0f/900;
Math::Vector2d pos(g_grim->_cursorX*scaleX, g_grim->_cursorY*scaleY);
lua_Object result = lua_createtable();
int count = 0;
foreach (Hotspot *h, Hotspot::getPool()) {
if (!h->_rect.containsPoint(pos)) {
continue;
}
lua_Object inner = lua_createtable();
lua_pushobject(inner);
lua_pushstring("type");
lua_pushstring("normal");
lua_settable();
lua_pushobject(inner);
lua_pushstring("cursor");
lua_pushnumber(0);
lua_settable();
lua_pushobject(inner);
lua_pushstring("id");
lua_pushstring(h->_name.c_str());
lua_settable();
lua_pushobject(inner);
lua_pushstring("obj");
lua_pushusertag(h->getId(), h->getTag());
lua_settable();
lua_pushobject(result);
lua_pushnumber(count++);
lua_pushobject(inner);
lua_settable();
}
lua_pushobject(result);
}
void Lua_Remastered::GetLanguage() {
warning("Stub function: GetLanguage, just guesswork");
lua_pushnumber(g_grim->getLanguage());
}
void Lua_Remastered::SaveRegistryToDisk() {
warning("Guesswork: SaveRegistryToDisk");
g_registry->save();
ConfMan.flushToDisk(); // Since we can't consistently exit yet, we force a write for now
}
void Lua_Remastered::GetCursorPosition() {
lua_pushnumber(g_grim->_cursorX);
lua_pushnumber(g_grim->_cursorX);
}
void Lua_Remastered::SetCursor() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: SetCursor(%d)", lua_getnumber(param1));
}
void Lua_Remastered::GetPlatform() {
warning("Stub function: GetPlatform, returns 1 (windows)");
lua_pushnumber(1);
}
void Lua_Remastered::GetRemappedKeyName() {
lua_Object param1 = lua_getparam(1);
const char *str = "";
if (lua_isstring(param1)) {
str = lua_getstring(param1);
}
warning("Stub function: GetRemappedKeyName(%s), returns TODO", str);
lua_pushstring("TODO");
}
void Lua_Remastered::GetRemappedKeyHint() {
lua_Object param1 = lua_getparam(1);
warning("Stub function: GetRemappedKeyHint(%s), returns key_empty.png", lua_getstring(param1));
lua_pushstring("key_empty.png");
}
void Lua_Remastered::ImSetCommentaryVol() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: ImSetCommentaryVol(%f)", lua_getnumber(param1));
}
void Lua_Remastered::ImGetCommentaryVol() {
warning("Stub function: ImGetCommentaryVol() returns 0");
lua_pushnumber(0);
}
void Lua_Remastered::SetLanguage() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: SetLanguage(%f)", lua_getnumber(param1));
g_grim->setLanguage(lua_getnumber(param1));
delete g_localizer;
g_localizer = new Localizer();
}
void Lua_Remastered::SetMouseSpeedScale() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: SetMouseSpeedScale(%f)", lua_getnumber(param1));
}
// Commentary
void Lua_Remastered::EnableCommentary() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: EnableCommentary(%f)", lua_getnumber(param1));
}
void Lua_Remastered::SetCommentary() {
lua_Object param1 = lua_getparam(1);
assert(lua_isstring(param1));
warning("Stub function: SetCommentary(%s)", lua_getstring(param1));
g_grim->getCommentary()->setCurrentCommentary(lua_getstring(param1));
}
void Lua_Remastered::PlayCurrentCommentary() {
warning("Stub function: PlayCurrentCommentary");
g_grim->getCommentary()->playCurrentCommentary();
}
void Lua_Remastered::HasHeardCommentary() {
lua_Object param1 = lua_getparam(1);
assert(lua_isstring(param1));
bool hasHeard = g_grim->getCommentary()->hasHeardCommentary(lua_getstring(param1));
warning("Remastered function: HasHeardCommentary(%s) returns %d", lua_getstring(param1), hasHeard);
if (hasHeard) {
lua_pushnumber(1);
} else {
lua_pushnil();
}
}
void Lua_Remastered::SetResolutionScaling() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: SetResolutionScaling(%f)", lua_getnumber(param1));
}
void Lua_Remastered::IsConceptUnlocked() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Remastered function: IsConceptUnlocked(%f) returns %d", lua_getnumber(param1), g_grim->isConceptEnabled(lua_getnumber(param1)));
if (g_grim->isConceptEnabled(lua_getnumber(param1))) {
lua_pushnumber(1);
} else {
lua_pushnil();
}
}
void Lua_Remastered::UnlockConcept() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Remastered function: UnlockConcept(%f)", lua_getnumber(param1));
g_grim->enableConcept(lua_getnumber(param1));
}
void Lua_Remastered::UnlockCutscene() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Remastered function: UnlockCutscene(%f)", lua_getnumber(param1));
g_grim->enableCutscene(lua_getnumber(param1));
}
void Lua_Remastered::IsCutsceneUnlocked() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Remastered function: IsCutsceneUnlocked(%f) returns %d", lua_getnumber(param1), g_grim->isCutsceneEnabled(lua_getnumber(param1)));
if (g_grim->isCutsceneEnabled(lua_getnumber(param1))) {
lua_pushnumber(1);
} else {
lua_pushnil();
}
}
void Lua_Remastered::GetGameRenderMode() {
warning("Stub function: GetGameRenderMode() - not all modes possible yet");
lua_pushnumber(g_grim->getMode());
}
void Lua_Remastered::SetGameRenderMode() {
lua_Object param1 = lua_getparam(1);
if (lua_isnil(param1)) {
warning("SetGameRenderMode(nil) - Should it be possible to call this with nil?");
return;
}
assert(lua_isnumber(param1));
warning("Stub function: SetGameRenderMode(%f)", lua_getnumber(param1));
g_grim->setMode((GrimEngine::EngineMode)(int)lua_getnumber(param1));
}
void Lua_Remastered::AddHotspot() {
lua_Object param1 = lua_getparam(1);
lua_Object param2 = lua_getparam(2);
lua_Object param3 = lua_getparam(3);
lua_Object param4 = lua_getparam(4);
lua_Object param5 = lua_getparam(5);
lua_Object param6 = lua_getparam(6);
lua_Object param7 = lua_getparam(7);
lua_Object param8 = lua_getparam(8);
lua_Object param9 = lua_getparam(9);
lua_Object param10 = lua_getparam(10);
lua_Object param11 = lua_getparam(11);
assert(lua_isstring(param1));
assert(lua_isnumber(param2));
assert(lua_isnumber(param3));
assert(lua_isnumber(param4));
assert(lua_isnumber(param5));
assert(lua_isnumber(param6));
assert(lua_isnumber(param7));
// assert(lua_isnumber(param8));
assert(lua_isnumber(param11));
const char *p9str = "nil";
const char *p10str = "nil";
if (lua_isstring(param9)) {
p9str = lua_getstring(param9);
} else if (!lua_isnil(param9)) {
assert(lua_isnil(param9));
}
if (lua_isstring(param10)) {
p10str = lua_getstring(param10);
} else if (!lua_isnil(param10)) {
assert(lua_isnil(param10));
}
warning("Stub function: AddHotspot(%s, %f, %f, %f, %f, %f, %f, %f, %s, %s, %f)", lua_getstring(param1), lua_getnumber(param2), lua_getnumber(param3), lua_getnumber(param4), lua_getnumber(param5), lua_getnumber(param6), lua_getnumber(param7), lua_getnumber(param8), p9str, p10str, lua_getnumber(param11));
Hotspot *hotspot = new Hotspot(lua_getstring(param1), lua_getnumber(param2), lua_getnumber(param3), lua_getnumber(param4), lua_getnumber(param5));
lua_pushusertag(hotspot->getId(), hotspot->getTag());
}
void Lua_Remastered::RemoveHotspot() {
lua_Object hotspotObj = lua_getparam(1);
Hotspot *hotspot = Hotspot::getPool().getObject(lua_getuserdata(hotspotObj));
delete hotspot;
}
void Lua_Remastered::GlobalSaveResolved() {
warning("Stub function: GlobalSaveResolved() returns 1");
lua_pushnumber(1);
}
void Lua_Remastered::FindSaveGames() {
warning("Stub function: FindSaveGames()");
Common::SaveFileManager *saveMan = g_grim->getSaveFileManager();
Common::StringArray saveFiles = saveMan->listSavefiles("grim_r???.sav");
if (saveFiles.empty()) {
lua_pushnil();
return;
}
lua_Object result = lua_createtable();
Common::StringArray::iterator it = saveFiles.begin();
for (int i = 0; it != saveFiles.end(); ++it) {
const char *filename = (*it).c_str();
warning("Savefile: %s", filename);
SaveGame *savedState = SaveGame::openForLoading(filename);
if (!savedState || !savedState->isCompatible()) {
if (!savedState) {
error("Savegame %s is invalid", filename);
} else {
error("Savegame %s is incompatible with this ResidualVM build. Save version: %d.%d; current version: %d.%d",
filename, savedState->saveMajorVersion(), savedState->saveMinorVersion(),
SaveGame::SAVEGAME_MAJOR_VERSION, SaveGame::SAVEGAME_MINOR_VERSION);
}
delete savedState;
return;
}
int slot = atoi((*it).c_str() + 6);
Common::String str1;
Common::String str2;
int x;
int32 dataSize = savedState->beginSection('META');
char str[200] = {};
int32 strSize = 0;
strSize = savedState->readLESint32();
savedState->read(str, strSize);
str1 = str;
x = savedState->readLESint32();
strSize = savedState->readLESint32();
savedState->read(str, strSize);
str2 = str;
savedState->endSection();
delete savedState;
lua_pushobject(result);
lua_pushnumber(i++);
str2 = g_localizer->localize(str2.c_str());
lua_Object keyVal = lua_createtable();
// The key-value-mapping:
{
lua_pushobject(keyVal);
lua_pushstring("slot");
lua_pushnumber(slot);
lua_settable();
lua_pushobject(keyVal);
lua_pushstring("title");
lua_pushstring(str2.c_str());
lua_settable();
lua_pushobject(keyVal);
lua_pushstring("timeDateString");
lua_pushstring("Unknown");
lua_settable();
lua_pushobject(keyVal);
lua_pushstring("mural_info");
lua_pushstring(str1.c_str());
lua_settable();
lua_pushobject(keyVal);
lua_pushstring("setIndex");
lua_pushnumber(x);
lua_settable();
}
lua_pushobject(keyVal);
lua_settable();
}
lua_pushobject(result);
}
void Lua_Remastered::Load() {
lua_Object fileName = lua_getparam(1);
// lua_Object param2 = lua_getparam(2);
if (lua_isnil(fileName)) {
g_grim->loadGame("");
} else if (lua_isnumber(fileName)) {
int slot = lua_getnumber(fileName);
Common::String saveGameFilename = Common::String::format("grim_r%03d.sav", slot);
g_grim->loadGame(saveGameFilename.c_str());
} else if (lua_isstring(fileName)) { // Check for number before this
g_grim->loadGame(lua_getstring(fileName));
} else {
warning("Load() fileName is wrong");
return;
}
}
void Lua_Remastered::Save() {
lua_Object param1 = lua_getparam(1);
lua_Object param2 = lua_getparam(2);
lua_Object param3 = lua_getparam(3);
lua_Object param4 = lua_getparam(4);
assert(lua_isnumber(param1));
assert(lua_isstring(param2));
assert(lua_isnumber(param3));
assert(lua_isstring(param4));
int slot = lua_getnumber(param1);
const char *p2Str = lua_getstring(param2);
int p3Num = lua_getnumber(param3);
const char *p4Str = lua_getstring(param4);
warning("REMASTERED save: %d, %s, %d, %s", slot, p2Str, p3Num, p4Str);
Common::String saveGameFilename = Common::String::format("grim_r%03d.sav", slot);
g_grim->setSaveMetaData(p2Str, p3Num, p4Str);
g_grim->saveGame(saveGameFilename.c_str());
}
void Lua_Remastered::ShowCursor() {
lua_Object param1 = lua_getparam(1);
assert(lua_isnumber(param1));
warning("Stub function: ShowCursor(%f)", lua_getnumber(param1));
}
void Lua_Remastered::ReadRegistryIntValue() {
lua_Object param1 = lua_getparam(1);
assert(lua_isstring(param1));
warning("Stub function: ReadRegistryIntValue(%s) returns nil", lua_getstring(param1));
lua_pushnil();
}
// Stub function for builtin functions not yet implemented
static void stubWarning(const char *funcName) {
warning("Stub function: %s", funcName);
}
static void stubError(const char *funcName) {
error("Stub function: %s", funcName);
}
#define STUB_FUNC(name) void name() { stubWarning(#name); }
#define STUB_FUNC2(name) void name() { stubError(#name); }
STUB_FUNC(Lua_Remastered::PreloadCursors)
STUB_FUNC(Lua_Remastered::GetFindSaveGameStatus)
STUB_FUNC(Lua_Remastered::InitiateFindSaveGames)
STUB_FUNC(Lua_Remastered::AreAchievementsInstalled)
STUB_FUNC(Lua_Remastered::UnlockAchievement)
STUB_FUNC(Lua_Remastered::SetAdvancedLighting)
STUB_FUNC(Lua_Remastered::IsPlayingCommentary)
STUB_FUNC(Lua_Remastered::ClearCommentary)
STUB_FUNC(Lua_Remastered::LoadRemappedKeys)
STUB_FUNC(Lua_Remastered::StopCommentaryImmediately)
STUB_FUNC(Lua_Remastered::DestroyAllUIButtonsImmediately)
STUB_FUNC(Lua_Remastered::UpdateUIButtons)
STUB_FUNC(Lua_Remastered::OverlayClearCache)
STUB_FUNC(Lua_Remastered::LinkHotspot)
STUB_FUNC(Lua_Remastered::UpdateHotspot)
STUB_FUNC(Lua_Remastered::HideMouseCursor)
STUB_FUNC(Lua_Remastered::UpdateMouseCursor)
STUB_FUNC(Lua_Remastered::SetActorHKHackMode)
STUB_FUNC(Lua_Remastered::CacheCurrentWalkVector)
STUB_FUNC(Lua_Remastered::SetKeyMappingMode)
STUB_FUNC(Lua_Remastered::ResetKeyMappingToDefault)
STUB_FUNC(Lua_Remastered::SaveRemappedKeys)
STUB_FUNC(Lua_Remastered::New)
STUB_FUNC(Lua_Remastered::RemoveBorders)
STUB_FUNC(Lua_Remastered::GetSaveStatus)
STUB_FUNC(Lua_Remastered::StartCheckOfCrossSaveStatus)
STUB_FUNC(Lua_Remastered::GetCrossSaveStatus)
STUB_FUNC(Lua_Remastered::GetFloorWalkPos)
STUB_FUNC(Lua_Remastered::CursorMovieEnabled)
struct luaL_reg remasteredMainOpcodes[] = {
{ "GetPlatform", LUA_OPCODE(Lua_Remastered, GetPlatform) },
{ "GetLanguage", LUA_OPCODE(Lua_Remastered, GetLanguage) },
{ "PreloadCursors", LUA_OPCODE(Lua_Remastered, PreloadCursors) },
{ "AreAchievementsInstalled", LUA_OPCODE(Lua_Remastered, AreAchievementsInstalled) },
{ "UnlockAchievement", LUA_OPCODE(Lua_Remastered, UnlockAchievement) },
{ "ImGetCommentaryVol", LUA_OPCODE(Lua_Remastered, ImGetCommentaryVol) },
{ "ImSetCommentaryVol", LUA_OPCODE(Lua_Remastered, ImSetCommentaryVol) },
{ "SetMouseSpeedScale", LUA_OPCODE(Lua_Remastered, SetMouseSpeedScale) },
{ "SetResolutionScaling", LUA_OPCODE(Lua_Remastered, SetResolutionScaling) },
{ "SetAdvancedLighting", LUA_OPCODE(Lua_Remastered, SetAdvancedLighting) },
{ "SetLanguage", LUA_OPCODE(Lua_Remastered, SetLanguage) },
{ "PlayCurrentCommentary", LUA_OPCODE(Lua_Remastered, PlayCurrentCommentary) },
{ "IsPlayingCommentary", LUA_OPCODE(Lua_Remastered, IsPlayingCommentary) },
{ "EnableCommentary", LUA_OPCODE(Lua_Remastered, EnableCommentary) },
{ "ClearCommentary", LUA_OPCODE(Lua_Remastered, ClearCommentary) },
{ "HasHeardCommentary", LUA_OPCODE(Lua_Remastered, HasHeardCommentary) },
{ "SetCommentary", LUA_OPCODE(Lua_Remastered, SetCommentary) },
{ "LoadRemappedKeys", LUA_OPCODE(Lua_Remastered, LoadRemappedKeys) },
{ "GlobalSaveResolved", LUA_OPCODE(Lua_Remastered, GlobalSaveResolved) },
{ "StopCommentaryImmediately", LUA_OPCODE(Lua_Remastered, StopCommentaryImmediately) },
{ "ReadRegistryIntValue", LUA_OPCODE(Lua_Remastered, ReadRegistryIntValue) },
{ "DestroyAllUIButtonsImmediately", LUA_OPCODE(Lua_Remastered, DestroyAllUIButtonsImmediately) },
{ "UpdateUIButtons", LUA_OPCODE(Lua_Remastered, UpdateUIButtons) },
{ "GetGameRenderMode", LUA_OPCODE(Lua_Remastered, GetGameRenderMode) },
{ "SetGameRenderMode", LUA_OPCODE(Lua_Remastered, SetGameRenderMode) },
{ "WidescreenCorrectionFactor", LUA_OPCODE(Lua_Remastered, WidescreenCorrectionFactor) },
{ "OverlayCreate", LUA_OPCODE(Lua_Remastered, OverlayCreate) },
{ "OverlayClearCache", LUA_OPCODE(Lua_Remastered, OverlayClearCache) },
{ "OverlayDimensions", LUA_OPCODE(Lua_Remastered, OverlayDimensions) },
{ "OverlayDestroy", LUA_OPCODE(Lua_Remastered, OverlayDestroy) },
{ "OverlayFade", LUA_OPCODE(Lua_Remastered, OverlayFade) },
{ "OverlayGetScreenSize", LUA_OPCODE(Lua_Remastered, OverlayGetScreenSize) },
{ "OverlayMove", LUA_OPCODE(Lua_Remastered, OverlayMove) },
{ "AddHotspot", LUA_OPCODE(Lua_Remastered, AddHotspot) },
{ "LinkHotspot", LUA_OPCODE(Lua_Remastered, LinkHotspot) },
{ "RemoveHotspot", LUA_OPCODE(Lua_Remastered, RemoveHotspot) },
{ "UpdateHotspot", LUA_OPCODE(Lua_Remastered, UpdateHotspot) },
{ "QueryActiveHotspots", LUA_OPCODE(Lua_Remastered, QueryActiveHotspots) },
{ "HideMouseCursor", LUA_OPCODE(Lua_Remastered, HideMouseCursor) },
{ "ShowCursor", LUA_OPCODE(Lua_Remastered, ShowCursor) },
{ "UpdateMouseCursor", LUA_OPCODE(Lua_Remastered, UpdateMouseCursor) },
{ "GetCursorPosition", LUA_OPCODE(Lua_Remastered, GetCursorPosition) },
{ "SetCursor", LUA_OPCODE(Lua_Remastered, SetCursor) },
{ "UnlockCutscene", LUA_OPCODE(Lua_Remastered, UnlockCutscene) },
{ "IsCutsceneUnlocked", LUA_OPCODE(Lua_Remastered, IsCutsceneUnlocked) },
{ "SetActorHKHackMode", LUA_OPCODE(Lua_Remastered, SetActorHKHackMode) },
{ "CacheCurrentWalkVector", LUA_OPCODE(Lua_Remastered, CacheCurrentWalkVector) },
{ "UnlockConcept", LUA_OPCODE(Lua_Remastered, UnlockConcept) },
{ "IsConceptUnlocked", LUA_OPCODE(Lua_Remastered, IsConceptUnlocked) },
{ "GetRemappedKeyHint", LUA_OPCODE(Lua_Remastered, GetRemappedKeyHint) },
{ "SetKeyMappingMode", LUA_OPCODE(Lua_Remastered, SetKeyMappingMode) },
{ "ResetKeyMappingToDefault", LUA_OPCODE(Lua_Remastered, ResetKeyMappingToDefault) },
{ "SaveRemappedKeys", LUA_OPCODE(Lua_Remastered, SaveRemappedKeys) },
{ "SaveRegistryToDisk", LUA_OPCODE(Lua_Remastered, SaveRegistryToDisk) },
{ "InitiateFindSaveGames", LUA_OPCODE(Lua_Remastered, InitiateFindSaveGames) },
{ "GetFindSaveGameStatus", LUA_OPCODE(Lua_Remastered, GetFindSaveGameStatus) },
{ "FindSaveGames", LUA_OPCODE(Lua_Remastered, FindSaveGames) },
{ "GetRemappedKeyName", LUA_OPCODE(Lua_Remastered, GetRemappedKeyName) },
{ "New", LUA_OPCODE(Lua_Remastered, New) },
{ "RemoveBorders", LUA_OPCODE(Lua_Remastered, RemoveBorders) },
{ "GetSaveStatus", LUA_OPCODE(Lua_Remastered, GetSaveStatus) },
{ "StartCheckOfCrossSaveStatus", LUA_OPCODE(Lua_Remastered, StartCheckOfCrossSaveStatus) },
{ "GetCrossSaveStatus", LUA_OPCODE(Lua_Remastered, GetCrossSaveStatus) },
{ "GetFloorWalkPos", LUA_OPCODE(Lua_Remastered, GetFloorWalkPos) },
{ "CursorMovieEnabled", LUA_OPCODE(Lua_Remastered, CursorMovieEnabled) },
};
void Lua_Remastered::registerOpcodes() {
Lua_V1::registerOpcodes();
// Register main opcodes functions
luaL_openlib(remasteredMainOpcodes, ARRAYSIZE(remasteredMainOpcodes));
}
} // end of namespace Grim

View File

@ -0,0 +1,114 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRIM_LUA_REMASTERED
#define GRIM_LUA_REMASTERED
#include "engines/grim/lua_v1.h"
#include "engines/grim/remastered/commentary.h"
namespace Grim {
class Lua_Remastered : public Lua_V1 {
public:
typedef Lua_Remastered LuaClass;
void registerOpcodes() override;
protected:
// Overrides from Lua_V1
DECLARE_LUA_OPCODE(GetFontDimensions);
DECLARE_LUA_OPCODE(GetTextObjectDimensions);
DECLARE_LUA_OPCODE(Load);
DECLARE_LUA_OPCODE(Save);
// Remastered
DECLARE_LUA_OPCODE(GetPlatform);
DECLARE_LUA_OPCODE(GetLanguage);
DECLARE_LUA_OPCODE(PreloadCursors);
DECLARE_LUA_OPCODE(ReadRegistryIntValue);
DECLARE_LUA_OPCODE(WidescreenCorrectionFactor);
DECLARE_LUA_OPCODE(InitiateFindSaveGames);
DECLARE_LUA_OPCODE(FindSaveGames);
DECLARE_LUA_OPCODE(GetFindSaveGameStatus);
DECLARE_LUA_OPCODE(AreAchievementsInstalled);
DECLARE_LUA_OPCODE(UnlockAchievement);
DECLARE_LUA_OPCODE(ImGetCommentaryVol);
DECLARE_LUA_OPCODE(ImSetCommentaryVol);
DECLARE_LUA_OPCODE(SetMouseSpeedScale);
DECLARE_LUA_OPCODE(SetResolutionScaling);
DECLARE_LUA_OPCODE(SetAdvancedLighting);
DECLARE_LUA_OPCODE(SetLanguage);
DECLARE_LUA_OPCODE(PlayCurrentCommentary);
DECLARE_LUA_OPCODE(IsPlayingCommentary);
DECLARE_LUA_OPCODE(EnableCommentary);
DECLARE_LUA_OPCODE(ClearCommentary);
DECLARE_LUA_OPCODE(HasHeardCommentary);
DECLARE_LUA_OPCODE(SetCommentary);
DECLARE_LUA_OPCODE(LoadRemappedKeys);
DECLARE_LUA_OPCODE(GlobalSaveResolved);
DECLARE_LUA_OPCODE(StopCommentaryImmediately);
DECLARE_LUA_OPCODE(DestroyAllUIButtonsImmediately);
DECLARE_LUA_OPCODE(UpdateUIButtons);
DECLARE_LUA_OPCODE(OverlayClearCache);
DECLARE_LUA_OPCODE(GetGameRenderMode);
DECLARE_LUA_OPCODE(SetGameRenderMode);
DECLARE_LUA_OPCODE(OverlayMove);
DECLARE_LUA_OPCODE(OverlayCreate);
DECLARE_LUA_OPCODE(OverlayDestroy);
DECLARE_LUA_OPCODE(OverlayFade);
DECLARE_LUA_OPCODE(OverlayGetScreenSize);
DECLARE_LUA_OPCODE(OverlayDimensions);
DECLARE_LUA_OPCODE(AddHotspot);
DECLARE_LUA_OPCODE(LinkHotspot);
DECLARE_LUA_OPCODE(RemoveHotspot);
DECLARE_LUA_OPCODE(UpdateHotspot);
DECLARE_LUA_OPCODE(QueryActiveHotspots);
DECLARE_LUA_OPCODE(HideMouseCursor);
DECLARE_LUA_OPCODE(SetCursor);
DECLARE_LUA_OPCODE(ShowCursor);
DECLARE_LUA_OPCODE(UpdateMouseCursor);
DECLARE_LUA_OPCODE(GetCursorPosition);
DECLARE_LUA_OPCODE(UnlockCutscene);
DECLARE_LUA_OPCODE(IsCutsceneUnlocked);
DECLARE_LUA_OPCODE(SetActorHKHackMode);
DECLARE_LUA_OPCODE(CacheCurrentWalkVector);
DECLARE_LUA_OPCODE(UnlockConcept);
DECLARE_LUA_OPCODE(IsConceptUnlocked);
DECLARE_LUA_OPCODE(SaveRegistryToDisk);
DECLARE_LUA_OPCODE(GetRemappedKeyName);
DECLARE_LUA_OPCODE(GetRemappedKeyHint);
DECLARE_LUA_OPCODE(SetKeyMappingMode);
DECLARE_LUA_OPCODE(ResetKeyMappingToDefault);
DECLARE_LUA_OPCODE(SaveRemappedKeys);
DECLARE_LUA_OPCODE(New);
DECLARE_LUA_OPCODE(RemoveBorders);
DECLARE_LUA_OPCODE(GetSaveStatus);
DECLARE_LUA_OPCODE(StartCheckOfCrossSaveStatus);
DECLARE_LUA_OPCODE(GetCrossSaveStatus);
DECLARE_LUA_OPCODE(GetFloorWalkPos);
DECLARE_LUA_OPCODE(CursorMovieEnabled);
};
} // end of namespace Grim
#endif

View File

@ -0,0 +1,55 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "image/png.h"
#include "graphics/surface.h"
#include "engines/grim/remastered/overlay.h"
#include "engines/grim/resource.h"
#include "engines/grim/material.h"
#include "engines/grim/gfx_base.h"
namespace Grim {
Overlay::Overlay(const Common::String &filename, Common::SeekableReadStream *data) :
_x(0), _y(0) {
_material = g_resourceloader->loadMaterial(filename, NULL, true);
}
Overlay::~Overlay() {
}
void Overlay::draw() {
_material->select();
g_driver->drawOverlay(this);
}
int Overlay::getWidth() const {
return _material->getData()->_textures[0]->_width;
}
int Overlay::getHeight() const {
return _material->getData()->_textures[0]->_height;
}
}

View File

@ -0,0 +1,59 @@
/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef GRIM_OVERLAY_H
#define GRIM_OVERLAY_H
#include "common/endian.h"
#include "engines/grim/pool.h"
namespace Grim {
class Material;
class Overlay : public PoolObject<Overlay> {
public:
Overlay(const Common::String &filename, Common::SeekableReadStream *data);
~Overlay();
void draw();
void setPos(float x, float y) { _x = x; _y = y; }
void setLayer(int layer) { _layer = layer; }
int getWidth() const;
int getHeight() const;
static int32 getStaticTag() { return MKTAG('O','V','E','R'); }
//private:
Material *_material;
float _x;
float _y;
int _layer;
};
}
#endif

View File

@ -41,6 +41,7 @@
#include "engines/grim/emi/costumeemi.h"
#include "engines/grim/emi/modelemi.h"
#include "engines/grim/emi/skeleton.h"
#include "engines/grim/remastered/overlay.h"
#include "engines/grim/patchr.h"
#include "engines/grim/md5check.h"
#include "engines/grim/update/update.h"
@ -79,7 +80,7 @@ ResourceLoader::ResourceLoader() {
Common::ArchiveMemberList files, updFiles;
//Load the update from the executable, if needed
const char *updateFilename = g_grim->getUpdateFilename();
const char *updateFilename = NULL;//g_grim->getUpdateFilename();
if (updateFilename) {
Common::File *updStream = new Common::File();
if (updStream && updStream->open(updateFilename)) {
@ -133,6 +134,10 @@ ResourceLoader::ResourceLoader() {
SearchMan.listMatchingMembers(files, "local.lab");
SearchMan.listMatchingMembers(files, "credits.lab");
if (g_grim->getGameFlags() & ADGF_REMASTERED) {
SearchMan.listMatchingMembers(files, "commentary.lab");
SearchMan.listMatchingMembers(files, "images.lab");
}
//Sort the archives in order to ensure that they are loaded with the correct order
Common::sort(files.begin(), files.end(), LabListComperator());
@ -360,6 +365,27 @@ Costume *ResourceLoader::loadCostume(const Common::String &filename, Actor *owne
Font *ResourceLoader::loadFont(const Common::String &filename) {
Common::SeekableReadStream *stream;
Common::String name = "FontsHD/" + filename + ".txt";
stream = openNewStreamFile(name, true);
if (stream) {
Common::String line = stream->readLine();
Common::String font;
Common::String size;
for (int i = 0; i < line.size(); ++i) {
if (line[i] == ' ') {
font = "FontsHD/" + Common::String(line.c_str(), i);
size = Common::String(line.c_str() + i + 1, line.size() - i - 2);
}
}
int s = atoi(size.c_str());
delete stream;
stream = openNewStreamFile(font.c_str(), true);
FontTTF *result = new FontTTF();
result->loadTTF(font, stream, s);
return result;
}
stream = openNewStreamFile(filename.c_str(), true);
if (!stream)
error("Could not find font file %s", filename.c_str());
@ -515,6 +541,22 @@ AnimationEmi *ResourceLoader::loadAnimationEmi(const Common::String &filename) {
return result;
}
Overlay *ResourceLoader::loadOverlay(const Common::String &filename) {
Common::String fname = fixFilename(filename);
Common::SeekableReadStream *stream;
stream = openNewStreamFile(fname.c_str(), true);
if (!stream) {
warning("Could not find overlay %s", filename.c_str());
return nullptr;
}
Overlay *result = new Overlay(filename, stream);
delete stream;
return result;
}
void ResourceLoader::uncache(const char *filename) const {
Common::String fname = filename;
fname.toLowercase();

View File

@ -46,6 +46,7 @@ class Sprite;
class EMICostume;
class Lab;
class Actor;
class Overlay;
typedef ObjectPtr<Material> MaterialPtr;
typedef ObjectPtr<Model> ModelPtr;
@ -71,6 +72,7 @@ public:
Skeleton *loadSkeleton(const Common::String &fname);
Sprite *loadSprite(const Common::String &fname, EMICostume *costume);
AnimationEmi *loadAnimationEmi(const Common::String &filename);
Overlay *loadOverlay(const Common::String &filename);
Common::SeekableReadStream *openNewStreamFile(Common::String fname, bool cache = false) const;
ModelPtr getModel(const Common::String &fname, CMap *c);

View File

@ -172,6 +172,20 @@ void Sector::load(TextSplitter &ts) {
float length = _normal.getMagnitude();
if (length > 0)
_normal /= length;
// Remastered
if (!ts.checkString("numtris")) {
return;
}
int _numTris;
ts.scanString(" numtris %d", 1, &_numTris);
//_vertices = new Math::Vector3d[_numVertices + 1];
int a,b,c;
if (_numTris > 0) {
ts.scanString(" triangles: %f %f %f", 3, &a, &b, &c);
for (i = 1; i < _numTris; i++)
ts.scanString(" %f %f %f", 3, &a, &b, &c);
}
}
void Sector::loadBinary(Common::SeekableReadStream *data) {

View File

@ -33,7 +33,7 @@ namespace Grim {
TextObjectCommon::TextObjectCommon() :
_x(0), _y(0), _fgColor(0), _justify(0), _width(0), _height(0),
_font(nullptr), _duration(0), _layer(0) {
_font(nullptr), _duration(0), _layer(0), _coords(0) {
if (g_grim)
g_grim->invalidateTextObjectsSortOrder();
}
@ -264,6 +264,10 @@ void TextObject::setupText() {
_lines = new Common::String[_numberLines];
// Reset the max width so it can be recalculated
_maxLineWidth = 0;
for (int j = 0; j < _numberLines; j++) {
int nextLinePos, cutLen;
const char *breakPos = strchr(message.c_str(), '\n');

View File

@ -62,6 +62,9 @@ public:
void setLayer(int layer);
int getLayer() const { return _layer; }
void setCoords(int coords) { _coords = coords; }
int getCoords() const { return _coords; }
protected:
TextObjectCommon();
@ -71,6 +74,7 @@ protected:
int _justify;
int _duration;
int _layer;
int _coords;
Color _fgColor;
};