feat: Implement contextual actions

Currently, only door unlocking is supported.
This commit is contained in:
Vsevolod Kremianskii 2020-11-15 13:57:36 +07:00
parent e51b219d7f
commit fad3f9054e
7 changed files with 108 additions and 9 deletions

View file

@ -25,6 +25,7 @@ enum class ActionType {
MoveToPoint = 0,
OpenDoor = 5,
CloseDoor = 6,
OpenLock = 13,
Follow = 35,
FollowLeader = 38,
QueueEmpty = 65534,

View file

@ -80,6 +80,9 @@ void ActionExecutor::executeActions(Object &object, float dt) {
case ActionType::OpenContainer:
executeOpenContainer(static_cast<Creature &>(object), *dynamic_cast<ObjectAction *>(action), dt);
break;
case ActionType::OpenLock:
executeOpenLock(static_cast<Creature &>(object), *dynamic_cast<ObjectAction *>(action), dt);
break;
default:
warn("ActionExecutor: action not implemented: " + to_string(static_cast<int>(type)));
action->isCompleted();
@ -255,6 +258,24 @@ void ActionExecutor::executeOpenContainer(Creature &actor, ObjectAction &action,
}
}
void ActionExecutor::executeOpenLock(Creature &actor, ObjectAction &action, float dt) {
Door *door = dynamic_cast<Door *>(action.object());
if (door) {
bool reached = navigateCreature(actor, door->position(), 1.0f, dt);
if (reached) {
door->setLocked(false);
door->open(&actor);
if (!door->blueprint().onOpen().empty()) {
runScript(door->blueprint().onOpen(), door->id(), actor.id(), -1);
}
action.complete();
}
} else {
warn("ActionExecutor: unsupported OpenLock object: " + to_string(action.object()->id()));
action.complete();
}
}
} // namespace game
} // namespace reone

View file

@ -59,6 +59,7 @@ private:
void executeOpenDoor(Object &actor, ObjectAction &action, float dt);
void executeCloseDoor(Object &actor, ObjectAction &action, float dt);
void executeOpenContainer(Creature &actor, ObjectAction &action, float dt);
void executeOpenLock(Creature &actor, ObjectAction &action, float dt);
// END Actions
};

View file

@ -148,6 +148,12 @@ void HUD::load() {
hideControl("TB_STEALTH");
}
bool HUD::handle(const SDL_Event &event) {
if (_select.handle(event)) return true;
return GUI::handle(event);
}
void HUD::update(float dt) {
GUI::update(dt);

View file

@ -35,6 +35,7 @@ public:
void load() override;
bool handle(const SDL_Event &event) override;
void update(float dt) override;
void render() const override;

View file

@ -43,6 +43,7 @@ namespace game {
static const int kOffsetToReticle = 8;
static const int kTitleBarWidth = 250;
static const int kTitleBarPadding = 6;
static const int kActionCount = 3;
static const int kActionBarMargin = 3;
static const int kActionBarPadding = 3;
static const int kActionWidth = 35;
@ -70,6 +71,52 @@ void SelectionOverlay::addTextureByAction(ContextualAction action, const string
_textureByAction.insert(make_pair(action, Textures::instance().get(resRef, TextureType::GUI)));
}
bool SelectionOverlay::handle(const SDL_Event &event) {
switch (event.type) {
case SDL_MOUSEMOTION:
return handleMouseMotion(event.motion);
case SDL_MOUSEBUTTONDOWN:
return handleMouseButtonDown(event.button);
default:
return false;
}
}
bool SelectionOverlay::handleMouseMotion(const SDL_MouseMotionEvent &event) {
_selectedActionIdx = -1;
if (!_hasSelected) return false;
for (int i = 0; i < kActionCount; ++i) {
float x, y;
getActionScreenCoords(i, x, y);
if (event.x >= x && event.y >= y && event.x < x + kActionWidth && event.y < y + kActionHeight) {
_selectedActionIdx = i;
return true;
}
}
return false;
}
bool SelectionOverlay::handleMouseButtonDown(const SDL_MouseButtonEvent &event) {
if (event.clicks > 1 || _selectedActionIdx == -1) return false;
shared_ptr<Area> area(_game->module()->area());
ObjectSelector &selector = area->objectSelector();
shared_ptr<SpatialObject> object(area->find(selector.selectedObjectId()));
switch (_actions[_selectedActionIdx]) {
case ContextualAction::Unlock: {
ActionQueue &actions = _game->party().leader()->actionQueue();
actions.add(make_unique<ObjectAction>(ActionType::OpenLock, object));
break;
}
}
return true;
}
void SelectionOverlay::update() {
shared_ptr<Module> module(_game->module());
shared_ptr<Area> area(module->area());
@ -177,10 +224,10 @@ void SelectionOverlay::drawTitleBar() const {
void SelectionOverlay::drawActionBar() const {
const GraphicsOptions &opts = _game->options().graphics;
float frameY = opts.height * (1.0f - _selectedScreenCoords.y) - _reticleHeight / 2 - kActionHeight - kOffsetToReticle - kActionBarMargin;
for (int i = -1; i < 2; ++i) {
float frameX = opts.width * _selectedScreenCoords.x + (static_cast<float>(i) - 0.5f) * kActionWidth + i * kActionBarMargin;
for (int i = 0; i < kActionCount; ++i) {
float frameX, frameY;
getActionScreenCoords(i, frameX, frameY);
glm::mat4 transform(1.0f);
transform = glm::translate(transform, glm::vec3(frameX, frameY, 0.0f));
@ -191,19 +238,24 @@ void SelectionOverlay::drawActionBar() const {
Shaders::instance().activate(ShaderProgram::GUIGUI, locals);
_friendlyScroll->bind(0);
shared_ptr<Texture> frameTexture;
if (i == _selectedActionIdx) {
frameTexture = _hilightedScroll;
} else {
frameTexture = _friendlyScroll;
}
frameTexture->bind(0);
Quad::getDefault().renderTriangles();
_friendlyScroll->unbind(0);
frameTexture->unbind(0);
int actionIdx = i + 1;
if (actionIdx < static_cast<int>(_actions.size())) {
ContextualAction action = _actions[actionIdx];
if (i < static_cast<int>(_actions.size())) {
ContextualAction action = _actions[i];
shared_ptr<Texture> texture(_textureByAction.find(action)->second);
if (texture) {
float y = opts.height * (1.0f - _selectedScreenCoords.y) - (_reticleHeight + kActionHeight + kActionWidth) / 2 - kOffsetToReticle - kActionBarMargin;
float y = opts.height * (1.0f - _selectedScreenCoords.y) - (_reticleHeight + kActionHeight + kActionWidth) / 2.0f - kOffsetToReticle - kActionBarMargin;
transform = glm::mat4(1.0f);
transform = glm::translate(transform, glm::vec3(frameX, y, 0.0f));
@ -224,6 +276,16 @@ void SelectionOverlay::drawActionBar() const {
}
}
bool SelectionOverlay::getActionScreenCoords(int index, float &x, float &y) const {
if (!_hasSelected) return false;
const GraphicsOptions &opts = _game->options().graphics;
x = opts.width * _selectedScreenCoords.x + (static_cast<float>(index - 1) - 0.5f) * kActionWidth + (index - 1) * kActionBarMargin;
y = opts.height * (1.0f - _selectedScreenCoords.y) - _reticleHeight / 2 - kActionHeight - kOffsetToReticle - kActionBarMargin;
return true;
}
} // namespace game
} // namespace reone

View file

@ -44,6 +44,7 @@ public:
void load();
bool handle(const SDL_Event &event);
void update();
void render() const;
@ -63,12 +64,18 @@ private:
glm::vec3 _selectedScreenCoords { 0.0f };
std::string _selectedTitle;
int _reticleHeight { 0 };
int _selectedActionIdx { -1 };
void addTextureByAction(ContextualAction action, const std::string &resRef);
bool handleMouseMotion(const SDL_MouseMotionEvent &event);
bool handleMouseButtonDown(const SDL_MouseButtonEvent &event);
void drawReticle(render::Texture &texture, const glm::vec3 &screenCoords) const;
void drawTitleBar() const;
void drawActionBar() const;
bool getActionScreenCoords(int index, float &x, float &y) const;
};
} // namespace game