[Scummvm-git-logs] scummvm master -> a259e6e2e6443c10080be10c7695cb9b44f90948
scemino
noreply at scummvm.org
Sun Apr 21 11:58:26 UTC 2024
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
30fc9cbb73 TWP: Fix invalid original savegame
a259e6e2e6 TWP: Implement missing sayLineAt function
Commit: 30fc9cbb73e4eed007daa6975e5e037386b5c006
https://github.com/scummvm/scummvm/commit/30fc9cbb73e4eed007daa6975e5e037386b5c006
Author: scemino (scemino74 at gmail.com)
Date: 2024-04-21T13:57:34+02:00
Commit Message:
TWP: Fix invalid original savegame
Changed paths:
engines/twp/twp.cpp
diff --git a/engines/twp/twp.cpp b/engines/twp/twp.cpp
index fc9e3f809b1..17612d4cfa8 100644
--- a/engines/twp/twp.cpp
+++ b/engines/twp/twp.cpp
@@ -1080,15 +1080,13 @@ Common::Error TwpEngine::saveGameState(int slot, const Common::String &desc, boo
if (!saveFile)
return Common::kWritingFailed;
- result = saveGameStream(saveFile, isAutosave);
- if (result.getCode() == Common::kNoError) {
- Common::OutSaveFile *thumbnail = _saveFileMan->openForSaving(Common::String::format("Savegame%d.png", slot), false);
- Graphics::Surface surface;
- capture(surface, 320, 180);
- Image::writePNG(*thumbnail, surface);
- thumbnail->finalize();
- delete thumbnail;
- }
+ _saveGameManager->saveGame(saveFile);
+ Common::OutSaveFile *thumbnail = _saveFileMan->openForSaving(Common::String::format("Savegame%d.png", slot), false);
+ Graphics::Surface surface;
+ capture(surface, 320, 180);
+ Image::writePNG(*thumbnail, surface);
+ thumbnail->finalize();
+ delete thumbnail;
saveFile->finalize();
delete saveFile;
Commit: a259e6e2e6443c10080be10c7695cb9b44f90948
https://github.com/scummvm/scummvm/commit/a259e6e2e6443c10080be10c7695cb9b44f90948
Author: scemino (scemino74 at gmail.com)
Date: 2024-04-21T13:57:34+02:00
Commit Message:
TWP: Implement missing sayLineAt function
Changed paths:
engines/twp/actorlib.cpp
engines/twp/motor.cpp
engines/twp/motor.h
engines/twp/twp.cpp
engines/twp/twp.h
diff --git a/engines/twp/actorlib.cpp b/engines/twp/actorlib.cpp
index c4d4c40d237..896030193b9 100644
--- a/engines/twp/actorlib.cpp
+++ b/engines/twp/actorlib.cpp
@@ -899,6 +899,7 @@ static SQInteger sayLineAt(HSQUIRRELVM v) {
SQInteger x, y;
Common::String text;
float duration = -1.0f;
+ Common::SharedPtr<Object> actor;
if (SQ_FAILED(sqget(v, 2, x)))
return sq_throwerror(v, "failed to get x");
if (SQ_FAILED(sqget(v, 3, y)))
@@ -909,23 +910,20 @@ static SQInteger sayLineAt(HSQUIRRELVM v) {
if (SQ_FAILED(sqget(v, 4, c)))
return sq_throwerror(v, "failed to get color");
color = Color::rgb(c);
- if (SQ_FAILED(sqget(v, 5, duration)))
- return sq_throwerror(v, "failed to get duration");
- if (SQ_FAILED(sqget(v, 6, text)))
- return sq_throwerror(v, "failed to get text");
} else {
- Common::SharedPtr<Object> actor = sqactor(v, 4);
+ actor = sqactor(v, 4);
if (!actor)
return sq_throwerror(v, "failed to get actor");
- Math::Vector2d pos = g_twp->roomToScreen(actor->_node->getAbsPos());
- x = pos.getX();
- y = pos.getY();
color = actor->_talkColor;
- if (SQ_FAILED(sqget(v, 6, text)))
- return sq_throwerror(v, "failed to get text");
}
- warning("TODO: saylineAt: (%lld,%lld) text=%s color=%s duration=%f", x, y, text.c_str(), color.toStr().c_str(), duration);
+ if (SQ_FAILED(sqget(v, 5, duration)))
+ return sq_throwerror(v, "failed to get duration");
+ if (SQ_FAILED(sqget(v, 6, text)))
+ return sq_throwerror(v, "failed to get text");
+
+ debugC(kDebugActScript, "saylineAt: (%lld,%lld) text=%s color=%s duration=%f", x, y, text.c_str(), color.toStr().c_str(), duration);
+ g_twp->sayLineAt(Math::Vector2d(x, y), color, actor, duration, text);
return 0;
}
diff --git a/engines/twp/motor.cpp b/engines/twp/motor.cpp
index 86e323f8579..a42fe08ce64 100644
--- a/engines/twp/motor.cpp
+++ b/engines/twp/motor.cpp
@@ -307,8 +307,71 @@ void WalkTo::onUpdate(float elapsed) {
}
}
-Talking::Talking(Common::SharedPtr<Object> obj, const Common::StringArray &texts, const Color &color) {
- _obj = obj;
+TalkingBase::TalkingBase(Common::SharedPtr<Object> actor, float duration)
+ : _actor(actor), _duration(duration) {
+}
+
+int TalkingBase::loadActorSpeech(const Common::String &name) {
+ if (ConfMan.getBool("speech_mute")) {
+ debugC(kDebugGame, "talking %s: speech_mute: true", _actor->_key.c_str());
+ return 0;
+ }
+
+ debugC(kDebugGame, "loadActorSpeech %s.ogg", name.c_str());
+ Common::String filename(name);
+ filename.toUppercase();
+ filename += ".ogg";
+ if (g_twp->_pack->assetExists(filename.c_str())) {
+ Common::SharedPtr<SoundDefinition> soundDefinition(new SoundDefinition(filename));
+ if (!soundDefinition) {
+ debugC(kDebugGame, "File %s.ogg not found", name.c_str());
+ } else {
+ g_twp->_audio->_soundDefs.push_back(soundDefinition);
+ int id = g_twp->_audio->play(soundDefinition, Audio::Mixer::SoundType::kSpeechSoundType, 0, 0, 1.f);
+ int duration = g_twp->_audio->getDuration(id);
+ debugC(kDebugGame, "talking %s audio id: %d, dur: %d", _actor->_key.c_str(), id, duration);
+ if (duration)
+ _duration = static_cast<float>(duration) / 1000.f;
+ return id;
+ }
+ }
+ return 0;
+}
+
+int TalkingBase::onTalkieId(int id) {
+ SQInteger result = 0;
+ sqcallfunc(result, "onTalkieID", _actor->_table, id);
+ if (result == 0)
+ result = id;
+ return result;
+}
+
+Common::String TalkingBase::talkieKey() {
+ Common::String result;
+ if (sqrawexists(_actor->_table, "_talkieKey") && SQ_FAILED(sqgetf(_actor->_table, "_talkieKey", result))) {
+ error("Failed to get talkie key");
+ }
+ if (sqrawexists(_actor->_table, "_key") && SQ_FAILED(sqgetf(_actor->_table, "_key", result))) {
+ error("Failed to get talkie key (2)");
+ }
+ return result;
+}
+
+void TalkingBase::setDuration(const Common::String &text) {
+ _elapsed = 0;
+ // let sayLineBaseTime = prefs(SayLineBaseTime);
+ float sayLineBaseTime = 1.5f;
+ // let sayLineCharTime = prefs(SayLineCharTime);
+ float sayLineCharTime = 0.025f;
+ // let sayLineMinTime = prefs(SayLineMinTime);
+ float sayLineMinTime = 0.2f;
+ // let sayLineSpeed = prefs(SayLineSpeed);
+ float sayLineSpeed = 0.5f;
+ float duration = (sayLineBaseTime + sayLineCharTime * static_cast<float>(text.size())) / (0.2f + sayLineSpeed);
+ _duration = MAX(duration, sayLineMinTime);
+}
+
+Talking::Talking(Common::SharedPtr<Object> obj, const Common::StringArray &texts, const Color &color) : TalkingBase(obj, 0.f) {
_color = color;
_texts.assign(texts.begin() + 1, texts.end());
say(texts[0]);
@@ -350,55 +413,28 @@ void Talking::onUpdate(float elapsed) {
return;
_elapsed += elapsed;
- if (_obj->_sound) {
- if (!g_twp->_audio->playing(_obj->_sound)) {
- debugC(kDebugGame, "talking %s audio stopped", _obj->_key.c_str());
- _obj->_sound = 0;
+ if (_actor->_sound) {
+ if (!g_twp->_audio->playing(_actor->_sound)) {
+ debugC(kDebugGame, "talking %s audio stopped", _actor->_key.c_str());
+ _actor->_sound = 0;
} else {
- float e = static_cast<float>(g_twp->_audio->getElapsed(_obj->_sound)) / 1000.f;
+ float e = static_cast<float>(g_twp->_audio->getElapsed(_actor->_sound)) / 1000.f;
char letter = _lip.letter(e);
- _obj->setHeadIndex(letterToIndex(letter));
+ _actor->setHeadIndex(letterToIndex(letter));
}
} else if (_elapsed < _duration) {
char letter = _lip.letter(_elapsed);
- _obj->setHeadIndex(letterToIndex(letter));
+ _actor->setHeadIndex(letterToIndex(letter));
} else if (!_texts.empty()) {
- debugC(kDebugGame, "talking %s: %s", _obj->_key.c_str(), _texts[0].c_str());
+ debugC(kDebugGame, "talking %s: %s", _actor->_key.c_str(), _texts[0].c_str());
say(_texts[0]);
_texts.remove_at(0);
} else {
- debugC(kDebugGame, "talking %s: ended", _obj->_key.c_str());
+ debugC(kDebugGame, "talking %s: ended", _actor->_key.c_str());
disable();
}
}
-int Talking::loadActorSpeech(const Common::String &name) {
- if (ConfMan.getBool("speech_mute")) {
- debugC(kDebugGame, "talking %s: speech_mute: true", _obj->_key.c_str());
- return 0;
- }
-
- debugC(kDebugGame, "loadActorSpeech %s.ogg", name.c_str());
- Common::String filename(name);
- filename.toUppercase();
- filename += ".ogg";
- if (g_twp->_pack->assetExists(filename.c_str())) {
- Common::SharedPtr<SoundDefinition> soundDefinition(new SoundDefinition(filename));
- if (!soundDefinition) {
- debugC(kDebugGame, "File %s.ogg not found", name.c_str());
- } else {
- g_twp->_audio->_soundDefs.push_back(soundDefinition);
- int id = g_twp->_audio->play(soundDefinition, Audio::Mixer::SoundType::kSpeechSoundType, 0, 0, 1.f);
- int duration = g_twp->_audio->getDuration(id);
- debugC(kDebugGame, "talking %s audio id: %d, dur: %d", _obj->_key.c_str(), id, duration);
- if (duration)
- _duration = static_cast<float>(duration) / 1000.f;
- return id;
- }
- }
- return 0;
-}
-
void Talking::say(const Common::String &text) {
if (text.empty())
return;
@@ -442,11 +478,11 @@ void Talking::say(const Common::String &text) {
debugC(kDebugGame, "Lip %s loaded", path.c_str());
}
- if (_obj->_sound) {
- g_twp->_audio->stop(_obj->_sound);
+ if (_actor->_sound) {
+ g_twp->_audio->stop(_actor->_sound);
}
- _obj->_sound = loadActorSpeech(name);
+ _actor->_sound = loadActorSpeech(name);
} else if (txt[0] == '^') {
txt = txt.substr(1);
}
@@ -460,9 +496,9 @@ void Talking::say(const Common::String &text) {
debugC(kDebugGame, "sayLine '%s'", txt.c_str());
- if (sqrawexists(_obj->_table, "sayingLine")) {
- const char *anim = _obj->_animName.empty() ? nullptr : _obj->_animName.c_str();
- sqcall(_obj->_table, "sayingLine", anim, txt);
+ if (sqrawexists(_actor->_table, "sayingLine")) {
+ const char *anim = _actor->_animName.empty() ? nullptr : _actor->_animName.c_str();
+ sqcall(_actor->_table, "sayingLine", anim, txt);
}
// modify state ?
@@ -473,34 +509,34 @@ void Talking::say(const Common::String &text) {
state = txt.substr(1, i - 1);
debugC(kDebugGame, "Set state from anim '%s'", state.c_str());
if (state != "notalk") {
- _obj->play(state);
+ _actor->play(state);
}
txt = txt.substr(i + 1);
}
}
- if (!_obj->_sound)
+ if (!_actor->_sound)
setDuration(txt);
- if (_obj->_sayNode) {
- _obj->_sayNode->remove();
+ if (_actor->_sayNode) {
+ _actor->_sayNode->remove();
}
if (ConfMan.getBool("subtitles")) {
Text text2("sayline", txt, thCenter, tvTop, SCREEN_WIDTH * 3.f / 4.f, _color);
- _obj->_sayNode = Common::SharedPtr<TextNode>(new TextNode());
- _obj->_sayNode->setText(text2);
- _obj->_sayNode->setColor(_color);
- _node = _obj->_sayNode;
- Math::Vector2d pos = g_twp->roomToScreen(_obj->_node->getAbsPos() + _obj->_talkOffset);
+ _actor->_sayNode = Common::SharedPtr<TextNode>(new TextNode());
+ _actor->_sayNode->setText(text2);
+ _actor->_sayNode->setColor(_color);
+ _node = _actor->_sayNode;
+ Math::Vector2d pos = g_twp->roomToScreen(_actor->_node->getAbsPos() + _actor->_talkOffset);
// clamp position to keep it on screen
pos.setX(CLIP(pos.getX(), 10.f + text2.getBounds().getX() / 2.f, SCREEN_WIDTH - text2.getBounds().getX() / 2.f));
pos.setY(CLIP(pos.getY(), 10.f + text2.getBounds().getY(), SCREEN_HEIGHT - text2.getBounds().getY()));
- _obj->_sayNode->setPos(pos);
- _obj->_sayNode->setAnchorNorm(Math::Vector2d(0.5f, 0.0f));
- g_twp->_screenScene->addChild(_obj->_sayNode.get());
+ _actor->_sayNode->setPos(pos);
+ _actor->_sayNode->setAnchorNorm(Math::Vector2d(0.5f, 0.0f));
+ g_twp->_screenScene->addChild(_actor->_sayNode.get());
}
_elapsed = 0.f;
@@ -508,48 +544,121 @@ void Talking::say(const Common::String &text) {
void Talking::disable() {
Motor::disable();
- if (_obj->_sound) {
- g_twp->_audio->stop(_obj->_sound);
+ if (_actor->_sound) {
+ g_twp->_audio->stop(_actor->_sound);
}
_texts.clear();
- _obj->setHeadIndex(1);
+ _actor->setHeadIndex(1);
if (_node)
_node->remove();
_elapsed = 0.f;
_duration = 0.f;
}
-int Talking::onTalkieId(int id) {
- SQInteger result = 0;
- sqcallfunc(result, "onTalkieID", _obj->_table, id);
- if (result == 0)
- result = id;
- return result;
+SayLineAt::SayLineAt(const Math::Vector2d &pos, const Color &color, Common::SharedPtr<Object> actor, float duration, const Common::String &text)
+ : TalkingBase(actor, duration), _pos(pos), _color(color), _text(text) {
+ say(text);
}
-void Talking::setDuration(const Common::String &text) {
- _elapsed = 0;
- // let sayLineBaseTime = prefs(SayLineBaseTime);
- float sayLineBaseTime = 1.5f;
- // let sayLineCharTime = prefs(SayLineCharTime);
- float sayLineCharTime = 0.025f;
- // let sayLineMinTime = prefs(SayLineMinTime);
- float sayLineMinTime = 0.2f;
- // let sayLineSpeed = prefs(SayLineSpeed);
- float sayLineSpeed = 0.5f;
- float duration = (sayLineBaseTime + sayLineCharTime * static_cast<float>(text.size())) / (0.2f + sayLineSpeed);
- _duration = MAX(duration, sayLineMinTime);
-}
+void SayLineAt::say(const Common::String &text) {
+ Common::String txt(text);
+ if (txt[0] == '$') {
+ HSQUIRRELVM v = g_twp->getVm();
+ SQInteger top = sq_gettop(v);
+ sq_pushroottable(v);
+ Common::String code(Common::String::format("return %s", text.substr(1, text.size() - 1).c_str()));
+ if (SQ_FAILED(sq_compilebuffer(v, code.c_str(), code.size(), "execCode", SQTrue))) {
+ error("Error executing code %s", code.c_str());
+ } else {
+ sq_push(v, -2);
+ // call
+ if (SQ_FAILED(sq_call(v, 1, SQTrue, SQTrue))) {
+ error("Error calling code %s", code.c_str());
+ } else {
+ if (SQ_FAILED(sqget(v, -1, txt))) {
+ error("Error getting call result %s", code.c_str());
+ }
+ sq_settop(v, top);
+ }
+ }
+ }
-Common::String Talking::talkieKey() {
- Common::String result;
- if (sqrawexists(_obj->_table, "_talkieKey") && SQ_FAILED(sqgetf(_obj->_table, "_talkieKey", result))) {
- error("Failed to get talkie key");
+ if (txt[0] == '@') {
+ int id = atoi(txt.c_str() + 1);
+ txt = g_twp->_textDb->getText(id);
+
+ if (_actor) {
+ id = onTalkieId(id);
+ Common::String key(talkieKey());
+ key.toUppercase();
+ Common::String name = Common::String::format("%s_%d", key.c_str(), id);
+ Common::String path(name + ".lip");
+
+ debugC(kDebugGame, "Load lip %s", path.c_str());
+ if (g_twp->_pack->assetExists(path.c_str())) {
+ GGPackEntryReader entry;
+ entry.open(*g_twp->_pack, path);
+ Lip lip;
+ lip.load(&entry);
+ debugC(kDebugGame, "Lip %s loaded", path.c_str());
+ }
+
+ if (_actor->_sound) {
+ g_twp->_audio->stop(_actor->_sound);
+ }
+
+ _actor->_sound = loadActorSpeech(name);
+ }
+ } else if (txt[0] == '^') {
+ txt = txt.substr(1);
}
- if (sqrawexists(_obj->_table, "_key") && SQ_FAILED(sqgetf(_obj->_table, "_key", result))) {
- error("Failed to get talkie key (2)");
+
+ // remove text in parentheses
+ if (txt[0] == '(') {
+ uint32 i = txt.find(')');
+ if (i != Common::String::npos)
+ txt = txt.substr(i + 1);
}
- return result;
+
+ if (_actor && !_actor->_sound)
+ setDuration(txt);
+
+ debugC(kDebugGame, "sayLine '%s'", txt.c_str());
+
+ // transform talking position to screen pos
+ Math::Vector2d talkingSize(320.f, 180.f);
+ Math::Vector2d pos(Math::Vector2d(SCREEN_WIDTH, SCREEN_HEIGHT) * _pos / talkingSize);
+
+ Text text2("sayline", txt, thCenter, tvTop, 0.f, _color);
+ _node = Common::SharedPtr<TextNode>(new TextNode());
+ _node->setText(text2);
+ _node->setPos(pos);
+ _node->setColor(_color);
+ _node->setAnchorNorm(Math::Vector2d(0.5f, 0.0f));
+ g_twp->_screenScene->addChild(_node.get());
+
+ _elapsed = 0.f;
+}
+
+void SayLineAt::onUpdate(float elapsed) {
+ if (!isEnabled())
+ return;
+
+ _elapsed += elapsed;
+ if (_actor && _actor->_sound) {
+ if (!g_twp->_audio->playing(_actor->_sound)) {
+ debugC(kDebugGame, "talking %s audio stopped", _actor->_key.c_str());
+ _actor->_sound = 0;
+ }
+ } else if (_elapsed >= _duration) {
+ debugC(kDebugGame, "talking %s: ended", _text.c_str());
+ disable();
+ }
+}
+
+void SayLineAt::disable() {
+ Motor::disable();
+ _node->remove();
}
Jiggle::Jiggle(Node *node, float amount) : _amount(amount), _node(node) {
diff --git a/engines/twp/motor.h b/engines/twp/motor.h
index 86594b9d2a1..93f1e2cd0f0 100644
--- a/engines/twp/motor.h
+++ b/engines/twp/motor.h
@@ -245,8 +245,28 @@ private:
};
class TextNode;
+
+class TalkingBase : public Motor {
+protected:
+ TalkingBase(Common::SharedPtr<Object> actor, float duration);
+
+public:
+ virtual ~TalkingBase() {}
+
+protected:
+ Common::String talkieKey();
+ int onTalkieId(int id);
+ int loadActorSpeech(const Common::String &name);
+ void setDuration(const Common::String &text);
+
+protected:
+ Common::SharedPtr<Object> _actor;
+ float _duration = 0.f;
+ float _elapsed = 0.f;
+};
+
// Creates a talking animation for a specified object.
-class Talking : public Motor {
+class Talking : public TalkingBase {
public:
Talking(Common::SharedPtr<Object> obj, const Common::StringArray &texts, const Color &color);
virtual ~Talking() {}
@@ -258,21 +278,32 @@ public:
private:
void say(const Common::String &text);
- int onTalkieId(int id);
- Common::String talkieKey();
- void setDuration(const Common::String &text);
- int loadActorSpeech(const Common::String &name);
private:
- Common::SharedPtr<Object> _obj;
Common::SharedPtr<TextNode> _node;
Lip _lip;
- float _elapsed = 0.f;
- float _duration = 0.f;
Color _color;
Common::StringArray _texts;
};
+class SayLineAt : public TalkingBase {
+public:
+ SayLineAt(const Math::Vector2d &pos, const Color &color, Common::SharedPtr<Object> actor, float duration, const Common::String &text);
+ virtual ~SayLineAt() {}
+
+ virtual void onUpdate(float elapsed) override;
+ virtual void disable() override;
+
+private:
+ void say(const Common::String &text);
+
+private:
+ const Math::Vector2d _pos;
+ Color _color;
+ Common::String _text;
+ Common::SharedPtr<TextNode> _node;
+};
+
class Jiggle : public Motor {
public:
Jiggle(Node *node, float amount);
diff --git a/engines/twp/twp.cpp b/engines/twp/twp.cpp
index 17612d4cfa8..a8b75b8c016 100644
--- a/engines/twp/twp.cpp
+++ b/engines/twp/twp.cpp
@@ -454,6 +454,8 @@ void TwpEngine::update(float elapsed) {
_audio->update(elapsed);
_noOverride->update(elapsed);
+ if (_talking)
+ _talking->update(elapsed);
// update mouse pos
Math::Vector2d scrPos = winToScreen(_cursor.pos);
@@ -1756,6 +1758,10 @@ void TwpEngine::updateTriggers() {
}
}
+void TwpEngine::sayLineAt(const Math::Vector2d &pos, const Color &color, Common::SharedPtr<Object> actor, float duration, const Common::String &text) {
+ _talking = Common::ScopedPtr<SayLineAt>(new SayLineAt(pos, color, actor, duration, text));
+}
+
void TwpEngine::stopTalking() {
if (!_room)
return;
@@ -1768,6 +1774,8 @@ void TwpEngine::stopTalking() {
}
bool TwpEngine::isSomeoneTalking() const {
+ if (_talking && _talking->isEnabled())
+ return true;
if (!_room)
return false;
for (auto it = _actors.begin(); it != _actors.end(); it++) {
diff --git a/engines/twp/twp.h b/engines/twp/twp.h
index 35635813e7f..834d1720cfc 100644
--- a/engines/twp/twp.h
+++ b/engines/twp/twp.h
@@ -58,6 +58,7 @@ class InputState;
struct Light;
class Lighting;
class LightingNode;
+class Motor;
class NoOverrideNode;
class Object;
class PathNode;
@@ -138,6 +139,7 @@ public:
void setActor(Common::SharedPtr<Object> actor, bool userSelected = false);
Common::SharedPtr<Object> objAt(const Math::Vector2d &pos);
void flashSelectableActor(int flash);
+ void sayLineAt(const Math::Vector2d &pos, const Color &color, Common::SharedPtr<Object> actor, float duration, const Common::String &text);
void stopTalking();
bool isSomeoneTalking() const;
void walkFast(bool state = true);
@@ -272,6 +274,7 @@ private:
unique_ptr<Shader> _sepiaShader;
int _speed = 1;
bool _control = false;
+ unique_ptr<Motor> _talking;
};
extern TwpEngine *g_twp;
More information about the Scummvm-git-logs
mailing list