TWP: Add verb shake

This commit is contained in:
scemino 2024-04-25 22:23:26 +02:00
parent 986a18dcbd
commit 6a38a1fa62
5 changed files with 86 additions and 24 deletions

View File

@ -312,7 +312,7 @@ static SQInteger findScreenPosition(HSQUIRRELVM v) {
if (!actorSlot) if (!actorSlot)
return 0; return 0;
for (int i = 1; i < MAX_VERBS; i++) { for (int i = 1; i < MAX_VERBS; i++) {
Verb vb = actorSlot->verbs[i]; const Verb &vb = actorSlot->verbSlots[i]._verb;
if (vb.id.id == verb) { if (vb.id.id == verb) {
SpriteSheet *verbSheet = g_twp->_resManager->spriteSheet("VerbSheet"); SpriteSheet *verbSheet = g_twp->_resManager->spriteSheet("VerbSheet");
const SpriteSheetFrame *verbFrame = &verbSheet->getFrame(Common::String::format("%s_en", vb.image.c_str())); const SpriteSheetFrame *verbFrame = &verbSheet->getFrame(Common::String::format("%s_en", vb.image.c_str()));
@ -763,7 +763,7 @@ static SQInteger setVerb(HSQUIRRELVM v) {
debugC(kDebugGenScript, "setVerb %lld, %lld, %lld, %s", actorSlot, verbSlot, id, text.c_str()); debugC(kDebugGenScript, "setVerb %lld, %lld, %lld, %s", actorSlot, verbSlot, id, text.c_str());
VerbId verbId; VerbId verbId;
verbId.id = id; verbId.id = id;
g_twp->_hud->_actorSlots[actorSlot - 1].verbs[verbSlot] = Verb(verbId, image, fun, text, key, flags); g_twp->_hud->_actorSlots[actorSlot - 1].verbSlots[verbSlot]._verb = Verb(verbId, image, fun, text, key, flags);
return 0; return 0;
} }

View File

@ -21,11 +21,31 @@
#include "common/config-manager.h" #include "common/config-manager.h"
#include "twp/twp.h" #include "twp/twp.h"
#include "twp/motor.h"
#include "twp/hud.h" #include "twp/hud.h"
#include "twp/resmanager.h" #include "twp/resmanager.h"
namespace Twp { namespace Twp {
class ShakeVerb : public Motor {
public:
virtual ~ShakeVerb() {}
ShakeVerb(VerbSlot *slot, float amount) : _slot(slot), _amount(amount) {}
private:
virtual void onUpdate(float elapsed) override {
_shakeTime += 40.f * elapsed;
_elapsed += elapsed;
_slot->_shakeOffset = Math::Vector2d(_amount * cos(_shakeTime + 0.3f), _amount * sin(_shakeTime));
}
private:
VerbSlot *_slot = nullptr;
float _amount = 0.f;
float _shakeTime = 0.f;
float _elapsed = 0.f;
};
Verb::Verb() = default; Verb::Verb() = default;
Verb::Verb(VerbId verbId, const Common::String &img, const Common::String &f, const Common::String &t, const Common::String &k, int fl) Verb::Verb(VerbId verbId, const Common::String &img, const Common::String &f, const Common::String &t, const Common::String &k, int fl)
@ -175,22 +195,17 @@ void Hud::drawCore(const Math::Matrix4 &trsf) {
_shader._normalColor = slot->verbUiColors.verbHighlight; _shader._normalColor = slot->verbUiColors.verbHighlight;
_shader._highlightColor = slot->verbUiColors.verbHighlightTint; _shader._highlightColor = slot->verbUiColors.verbHighlightTint;
bool isOver = false;
for (int i = 1; i < MAX_VERBS; i++) { for (int i = 1; i < MAX_VERBS; i++) {
const Verb &verb = slot->verbs[i]; const VerbSlot &verbSlot = slot->verbSlots[i];
if (verb.image.size() > 0) { if (verbSlot._verb.image.size() > 0) {
const SpriteSheetFrame &verbFrame = verbSheet->getFrame(Common::String::format("%s%s_%s", verb.image.c_str(), verbSuffix.c_str(), lang.c_str())); const SpriteSheetFrame &verbFrame = verbSheet->getFrame(Common::String::format("%s%s_%s", verbSlot._verb.image.c_str(), verbSuffix.c_str(), lang.c_str()));
bool over = verbFrame.spriteSourceSize.contains(_mousePos.getX(), _mousePos.getY()); Color color = (verbSlot._over || (verbSlot._verb.id.id == _defaultVerbId)) ? verbHighlight : verbColor;
isOver |= over; Math::Matrix4 t(trsf);
Color color = (over || (verb.id.id == _defaultVerbId)) ? verbHighlight : verbColor; t.translate(Math::Vector3d(verbSlot._shakeOffset.getX(), verbSlot._shakeOffset.getY(), 0.f));
if (_mouseClick && over) { drawSprite(verbFrame, verbTexture, Color::withAlpha(color, getAlpha()), t);
selectVerb(verb);
}
drawSprite(verbFrame, verbTexture, Color::withAlpha(color, getAlpha()), trsf);
} }
} }
g_twp->getGfx().use(saveShader); g_twp->getGfx().use(saveShader);
_over = isOver;
} }
void Hud::update(float elapsed, const Math::Vector2d &pos, Common::SharedPtr<Object> hotspot, bool mouseClick) { void Hud::update(float elapsed, const Math::Vector2d &pos, Common::SharedPtr<Object> hotspot, bool mouseClick) {
@ -210,6 +225,42 @@ void Hud::update(float elapsed, const Math::Vector2d &pos, Common::SharedPtr<Obj
float alpha = MIN(_fadeTime, 2.0f) / 2.0f; float alpha = MIN(_fadeTime, 2.0f) / 2.0f;
setAlpha(alpha); setAlpha(alpha);
} }
ActorSlot *slot = actorSlot(_actor);
if (!slot)
return;
bool retroVerbs = ConfMan.getBool("retroVerbs");
Common::String lang = ConfMan.get("language");
Common::String verbSuffix = retroVerbs ? "_retro" : "";
SpriteSheet *verbSheet = g_twp->_resManager->spriteSheet("VerbSheet");
bool isOver = false;
for (int i = 1; i < MAX_VERBS; i++) {
VerbSlot &verbSlot = slot->verbSlots[i];
if (verbSlot._verb.image.size() > 0) {
const SpriteSheetFrame &verbFrame = verbSheet->getFrame(Common::String::format("%s%s_%s", verbSlot._verb.image.c_str(), verbSuffix.c_str(), lang.c_str()));
bool over = verbFrame.spriteSourceSize.contains(_mousePos.getX(), _mousePos.getY());
// shake choice when cursor is over
if ((verbSlot._shakeTime > 0.0f) && verbSlot._shake) {
verbSlot._shake->update(elapsed);
verbSlot._shakeTime -= elapsed;
if (verbSlot._shakeTime < 0.f) {
verbSlot._shakeTime = 0.f;
}
}
if (over && !verbSlot._over && verbSlot._shakeTime < 0.1f) {
verbSlot._shakeTime = 0.25f;
verbSlot._shake = Common::ScopedPtr<Motor>(new ShakeVerb(&verbSlot, 1.2f));
verbSlot._over = over;
}
verbSlot._over = over;
isOver |= over;
if (_mouseClick && over) {
selectVerb(verbSlot._verb);
}
}
}
_over = isOver;
} }
void Hud::setVisible(bool visible) { void Hud::setVisible(bool visible) {

View File

@ -60,10 +60,21 @@ struct Verb {
Verb(VerbId id, const Common::String &image, const Common::String &fun, const Common::String &text, const Common::String &key, int flags = 0); Verb(VerbId id, const Common::String &image, const Common::String &fun, const Common::String &text, const Common::String &key, int flags = 0);
}; };
struct VerbSlot {
Verb _verb;
float _shakeTime = 0.f;
Common::ScopedPtr<Motor> _shake;
Math::Vector2d _shakeOffset;
bool _over = false;
VerbSlot() {}
VerbSlot(Verb verb) : _verb(verb) {}
};
struct ActorSlot { struct ActorSlot {
public: public:
VerbUiColors verbUiColors; VerbUiColors verbUiColors;
Verb verbs[MAX_VERBS]; VerbSlot verbSlots[MAX_VERBS];
bool selectable = false; bool selectable = false;
Common::SharedPtr<Object> actor; Common::SharedPtr<Object> actor;
@ -71,9 +82,9 @@ public:
ActorSlot(); ActorSlot();
Verb *getVerb(int id) { Verb *getVerb(int id) {
for (auto &verb : verbs) { for (auto &verbSlot : verbSlots) {
if (verb.id.id == id) { if (verbSlot._verb.id.id == id) {
return &verb; return &verbSlot._verb;
} }
} }
return nullptr; return nullptr;

View File

@ -898,7 +898,7 @@ static SQInteger objectValidVerb(HSQUIRRELVM v) {
if (g_twp->_actor) { if (g_twp->_actor) {
ActorSlot *slot = g_twp->_hud->actorSlot(g_twp->_actor); ActorSlot *slot = g_twp->_hud->actorSlot(g_twp->_actor);
for (int i = 0; i < MAX_VERBS; i++) { for (int i = 0; i < MAX_VERBS; i++) {
Verb *vb = &slot->verbs[i]; const Verb *vb = &slot->verbSlots[i]._verb;
if (vb->id.id == verb) { if (vb->id.id == verb) {
if (sqrawexists(obj->_table, vb->fun)) { if (sqrawexists(obj->_table, vb->fun)) {
sqpush(v, true); sqpush(v, true);

View File

@ -259,7 +259,7 @@ void TwpEngine::clickedAt(const Math::Vector2d &scrPos) {
cancelSentence(_actor); cancelSentence(_actor);
if (_actor->_room == _room) if (_actor->_room == _room)
Object::walk(_actor, roomPos); Object::walk(_actor, roomPos);
_hud->selectVerb(_hud->actorSlot(_actor)->verbs[0]); _hud->selectVerb(_hud->actorSlot(_actor)->verbSlots[0]._verb);
_holdToMove = true; _holdToMove = true;
} }
@ -804,7 +804,7 @@ static void setVerbAction(int verbSlot) {
ActorSlot *slot = g_twp->_hud->actorSlot(g_twp->_actor); ActorSlot *slot = g_twp->_hud->actorSlot(g_twp->_actor);
if (!slot) if (!slot)
return; return;
g_twp->_hud->selectVerb(slot->verbs[verbSlot]); g_twp->_hud->selectVerb(slot->verbSlots[verbSlot]._verb);
} }
Common::Error TwpEngine::run() { Common::Error TwpEngine::run() {
@ -1377,7 +1377,7 @@ void TwpEngine::enterRoom(Common::SharedPtr<Room> room, Common::SharedPtr<Object
_room->setOverlay(Color(0.f, 0.f, 0.f, 0.f)); _room->setOverlay(Color(0.f, 0.f, 0.f, 0.f));
_camera->setBounds(Rectf::fromMinMax(Math::Vector2d(), _room->_roomSize)); _camera->setBounds(Rectf::fromMinMax(Math::Vector2d(), _room->_roomSize));
if (_actor && _hud->actorSlot(_actor)) if (_actor && _hud->actorSlot(_actor))
_hud->selectVerb(_hud->actorSlot(_actor)->verbs[0]); _hud->selectVerb(_hud->actorSlot(_actor)->verbSlots[0]._verb);
// move current actor to the new room // move current actor to the new room
Math::Vector2d camPos; Math::Vector2d camPos;
@ -1663,7 +1663,7 @@ void TwpEngine::resetVerb() {
_noun1 = nullptr; _noun1 = nullptr;
_noun2 = nullptr; _noun2 = nullptr;
_useFlag = UseFlag::ufNone; _useFlag = UseFlag::ufNone;
_hud->_verb = _hud->actorSlot(_actor)->verbs[0]; _hud->_verb = _hud->actorSlot(_actor)->verbSlots[0]._verb;
} }
bool TwpEngine::callVerb(Common::SharedPtr<Object> actor, VerbId verbId, Common::SharedPtr<Object> noun1, Common::SharedPtr<Object> noun2) { bool TwpEngine::callVerb(Common::SharedPtr<Object> actor, VerbId verbId, Common::SharedPtr<Object> noun1, Common::SharedPtr<Object> noun2) {
@ -1677,7 +1677,7 @@ bool TwpEngine::callVerb(Common::SharedPtr<Object> actor, VerbId verbId, Common:
Common::String noun2name = !noun2 ? "null" : noun2->_key; Common::String noun2name = !noun2 ? "null" : noun2->_key;
ActorSlot *slot = _hud->actorSlot(actor); ActorSlot *slot = _hud->actorSlot(actor);
Verb *verb = slot->getVerb(verbId.id); Verb *verb = slot->getVerb(verbId.id);
Common::String verbFuncName = verb ? verb->fun : slot->verbs[0].fun; Common::String verbFuncName = verb ? verb->fun : slot->verbSlots[0]._verb.fun;
debugC(kDebugGame, "callVerb(%s,%s,%s,%s)", name.c_str(), verbFuncName.c_str(), noun1name.c_str(), noun2name.c_str()); debugC(kDebugGame, "callVerb(%s,%s,%s,%s)", name.c_str(), verbFuncName.c_str(), noun1name.c_str(), noun2name.c_str());
// test if object became untouchable // test if object became untouchable