Combine Object and ActionQueue

This commit is contained in:
Vsevolod Kremianskii 2021-05-18 12:14:31 +07:00
parent 6c47a9de8e
commit e27a77b1e9
15 changed files with 134 additions and 258 deletions

View file

@ -403,8 +403,6 @@ set(GAME_HEADERS
src/engine/game/action/playanimation.h
src/engine/game/action/startconversation.h
src/engine/game/action/waitaction.h
src/engine/game/actionexecutor.h
src/engine/game/actionqueue.h
src/engine/game/animationutil.h
src/engine/game/camera/animatedcamera.h
src/engine/game/camera/camera.h
@ -501,7 +499,6 @@ set(GAME_HEADERS
set(GAME_SOURCES
src/engine/game/actionexecutor.cpp
src/engine/game/actionqueue.cpp
src/engine/game/animationutil.cpp
src/engine/game/camera/animatedcamera.cpp
src/engine/game/camera/camera.cpp
@ -585,6 +582,7 @@ set(GAME_SOURCES
src/engine/game/object/item_blueprint.cpp
src/engine/game/object/module.cpp
src/engine/game/object/object.cpp
src/engine/game/object/object_actions.cpp
src/engine/game/object/objectfactory.cpp
src/engine/game/object/placeable.cpp
src/engine/game/object/placeable_blueprint.cpp

View file

@ -55,9 +55,7 @@ ActionExecutor::ActionExecutor(Game *game) : _game(game) {
}
void ActionExecutor::executeActions(const shared_ptr<Object> &object, float dt) {
ActionQueue &actionQueue = object->actionQueue();
shared_ptr<Action> action(actionQueue.getCurrentAction());
shared_ptr<Action> action(object->getCurrentAction());
if (!action) return;
ActionType type = action->type();

View file

@ -1,64 +0,0 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <memory>
#include <queue>
#include "../common/timer.h"
#include "action/action.h"
namespace reone {
namespace game {
class ActionQueue {
public:
void clear();
void add(std::unique_ptr<Action> action);
void addToTop(std::unique_ptr<Action> action);
void delay(std::unique_ptr<Action> action, float seconds);
void update(float dt);
bool isEmpty() const;
bool containsUserActions() const;
int getSize() const;
std::shared_ptr<Action> getCurrentAction() const;
const std::deque<std::shared_ptr<Action>> &actions() const { return _actions; }
private:
struct DelayedAction {
std::unique_ptr<Action> action;
Timer timer;
};
std::deque<std::shared_ptr<Action>> _actions;
std::vector<DelayedAction> _delayed;
void removeCompletedActions();
void updateDelayedActions(float dt);
};
} // namespace game
} // namespace reone

View file

@ -288,7 +288,7 @@ void HUD::hideCombatHud() {
}
void HUD::refreshActionQueueItems() const {
auto &actions = _game->party().getLeader()->actionQueue().actions();
auto &actions = _game->party().getLeader()->actions();
for (int i = 0; i < 4; ++i) {
bool attack = i < static_cast<int>(actions.size()) && actions[i]->type() == ActionType::AttackObject;
@ -317,9 +317,9 @@ void HUD::onClick(const string &control) {
} else if (control == "BTN_OPT") {
_game->openInGameMenu(InGameMenu::Tab::Options);
} else if (control == "BTN_CLEARALL") {
_game->party().getLeader()->actionQueue().clear();
_game->party().getLeader()->clearAllActions();
} else if (control == "BTN_CLEARONE" || control == "BTN_CLEARONE2") {
for (auto &action : _game->party().getLeader()->actionQueue().actions()) {
for (auto &action : _game->party().getLeader()->actions()) {
if (action->type() == ActionType::AttackObject) {
action->complete();
break;

View file

@ -118,15 +118,14 @@ bool SelectionOverlay::handleMouseButtonDown(const SDL_MouseButtonEvent &event)
switch (_actions[_selectedActionIdx]) {
case ContextualAction::Unlock: {
ActionQueue &actions = _game->party().getLeader()->actionQueue();
actions.add(make_unique<ObjectAction>(ActionType::OpenLock, selectedObject));
shared_ptr<Creature> partyLeader(_game->party().getLeader());
partyLeader->addAction(make_unique<ObjectAction>(ActionType::OpenLock, selectedObject));
break;
}
case ContextualAction::Attack: {
shared_ptr<Creature> partyLeader(_game->party().getLeader());
ActionQueue &actions = partyLeader->actionQueue();
actions.add(make_unique<AttackAction>(static_pointer_cast<Creature>(selectedObject), partyLeader->getAttackRange(), true));
partyLeader->addAction(make_unique<AttackAction>(static_pointer_cast<Creature>(selectedObject), partyLeader->getAttackRange(), true));
break;
}

View file

@ -552,11 +552,9 @@ void Creature::deactivateCombat(float delay) {
shared_ptr<SpatialObject> Creature::getAttemptedAttackTarget() const {
shared_ptr<SpatialObject> result;
if (!_actionQueue.isEmpty()) {
auto attackAction = dynamic_pointer_cast<AttackAction>(_actionQueue.actions().front());
if (attackAction) {
result = attackAction->target();
}
auto attackAction = dynamic_pointer_cast<AttackAction>(getCurrentAction());
if (attackAction) {
result = attackAction->target();
}
return move(result);

View file

@ -216,21 +216,20 @@ void Module::onCreatureClick(const shared_ptr<Creature> &creature) {
debug(boost::format("Module: click: creature '%s', faction %d") % creature->tag() % static_cast<int>(creature->faction()));
shared_ptr<Creature> partyLeader(_game->party().getLeader());
ActionQueue &actions = partyLeader->actionQueue();
if (creature->isDead()) {
if (!creature->items().empty()) {
actions.clear();
actions.add(make_unique<ObjectAction>(ActionType::OpenContainer, creature));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<ObjectAction>(ActionType::OpenContainer, creature));
}
} else {
bool isEnemy = Reputes::instance().getIsEnemy(*partyLeader, *creature);
if (isEnemy) {
actions.clear();
actions.add(make_unique<AttackAction>(creature));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<AttackAction>(creature));
} else if (!creature->conversation().empty()) {
actions.clear();
actions.add(make_unique<StartConversationAction>(creature, creature->conversation()));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<StartConversationAction>(creature, creature->conversation()));
}
}
}
@ -242,22 +241,20 @@ void Module::onDoorClick(const shared_ptr<Door> &door) {
}
if (!door->isOpen()) {
shared_ptr<Creature> partyLeader(_game->party().getLeader());
ActionQueue &actions = partyLeader->actionQueue();
actions.clear();
actions.add(make_unique<ObjectAction>(ActionType::OpenDoor, door));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<ObjectAction>(ActionType::OpenDoor, door));
}
}
void Module::onPlaceableClick(const shared_ptr<Placeable> &placeable) {
shared_ptr<Creature> partyLeader(_game->party().getLeader());
ActionQueue &actions = partyLeader->actionQueue();
if (placeable->hasInventory()) {
actions.clear();
actions.add(make_unique<ObjectAction>(ActionType::OpenContainer, placeable));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<ObjectAction>(ActionType::OpenContainer, placeable));
} else if (!placeable->conversation().empty()) {
actions.clear();
actions.add(make_unique<StartConversationAction>(placeable, placeable->conversation()));
partyLeader->clearAllActions();
partyLeader->addAction(make_unique<StartConversationAction>(placeable, placeable->conversation()));
} else {
placeable->runOnUsed(move(partyLeader));
}

View file

@ -18,12 +18,9 @@
#include "object.h"
#include "../../common/collectionutil.h"
#include "../../script/types.h"
using namespace std;
using namespace reone::script;
namespace reone {
namespace game {
@ -32,31 +29,7 @@ Object::Object(uint32_t id, ObjectType type) : _id(id), _type(type) {
}
void Object::update(float dt) {
_actionQueue.update(dt);
}
void Object::clearAllActions() {
_actionQueue.clear();
}
void Object::setTag(string tag) {
_tag = move(tag);
}
void Object::setMinOneHP(bool minOneHP) {
_minOneHP = minOneHP;
}
void Object::setMaxHitPoints(int maxHitPoints) {
_maxHitPoints = maxHitPoints;
}
void Object::setPlotFlag(bool plot) {
_plot = plot;
}
void Object::setCommandable(bool value) {
_commandable = value;
updateActions(dt);
}
bool Object::getLocalBoolean(int index) const {

View file

@ -17,13 +17,17 @@
#pragma once
#include <deque>
#include <map>
#include <string>
#include <unordered_map>
#include <vector>
#include <boost/noncopyable.hpp>
#include "../actionqueue.h"
#include "../../common/timer.h"
#include "../action/action.h"
#include "../types.h"
namespace reone {
@ -47,12 +51,11 @@ public:
const std::string &blueprintResRef() const { return _blueprintResRef; }
const std::string &name() const { return _name; }
const std::string &conversation() const { return _conversation; }
ActionQueue &actionQueue() { return _actionQueue; }
bool plotFlag() const { return _plot; }
void setTag(std::string tag);
void setPlotFlag(bool plot);
void setCommandable(bool value);
void setTag(std::string tag) { _tag = std::move(tag); }
void setPlotFlag(bool plot) { _plot = plot; }
void setCommandable(bool commandable) { _commandable = commandable; }
// Hit Points
@ -65,11 +68,25 @@ public:
// Current hit points, not counting any bonuses.
int currentHitPoints() const { return _currentHitPoints; }
void setMinOneHP(bool minOneHP);
void setMaxHitPoints(int maxHitPoints);
void setMinOneHP(bool minOneHP) { _minOneHP = minOneHP; }
void setMaxHitPoints(int maxHitPoints) { _maxHitPoints = maxHitPoints; }
// END Hit Points
// Actions
void addAction(std::unique_ptr<Action> action);
void addActionOnTop(std::unique_ptr<Action> action);
void delayAction(std::unique_ptr<Action> action, float seconds);
bool hasUserActionsPending() const;
std::shared_ptr<Action> getCurrentAction() const;
const std::deque<std::shared_ptr<Action>> &actions() const { return _actions; }
// END Actions
// Local variables
bool getLocalBoolean(int index) const;
@ -88,13 +105,17 @@ public:
// END Scripts
protected:
struct DelayedAction {
std::unique_ptr<Action> action;
Timer timer;
};
uint32_t _id { 0 };
std::string _tag;
ObjectType _type { ObjectType::Invalid };
std::string _blueprintResRef;
std::string _name;
std::string _conversation;
ActionQueue _actionQueue;
bool _minOneHP { false };
int _hitPoints { 0 };
int _maxHitPoints { 0 };
@ -105,6 +126,13 @@ protected:
bool _autoRemoveKey { false };
bool _interruptable { false };
// Actions
std::deque<std::shared_ptr<Action>> _actions;
std::vector<DelayedAction> _delayed;
// END Actions
// Local variables
std::map<int, bool> _localBooleans;
@ -121,6 +149,15 @@ protected:
// END Scripts
Object(uint32_t id, ObjectType type);
// Actions
void updateActions(float dt);
void removeCompletedActions();
void updateDelayedActions(float dt);
// END Actions
};
} // namespace game

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "actionqueue.h"
#include "object.h"
#include <algorithm>
@ -25,33 +25,33 @@ namespace reone {
namespace game {
void ActionQueue::clear() {
void Object::clearAllActions() {
while (!_actions.empty()) {
_actions.pop_front();
}
}
void ActionQueue::add(unique_ptr<Action> action) {
void Object::addAction(unique_ptr<Action> action) {
_actions.push_back(move(action));
}
void ActionQueue::addToTop(unique_ptr<Action> action) {
void Object::addActionOnTop(unique_ptr<Action> action) {
_actions.push_front(move(action));
}
void ActionQueue::delay(unique_ptr<Action> action, float seconds) {
void Object::delayAction(unique_ptr<Action> action, float seconds) {
DelayedAction delayed;
delayed.action = move(action);
delayed.timer.reset(seconds);
_delayed.push_back(move(delayed));
}
void ActionQueue::update(float dt) {
void Object::updateActions(float dt) {
removeCompletedActions();
updateDelayedActions(dt);
}
void ActionQueue::removeCompletedActions() {
void Object::removeCompletedActions() {
while (true) {
shared_ptr<Action> action(getCurrentAction());
if (!action || !action->isCompleted()) return;
@ -60,7 +60,7 @@ void ActionQueue::removeCompletedActions() {
}
}
void ActionQueue::updateDelayedActions(float dt) {
void Object::updateDelayedActions(float dt) {
for (auto &delayed : _delayed) {
if (delayed.timer.advance(dt)) {
_actions.push_back(move(delayed.action));
@ -74,23 +74,14 @@ void ActionQueue::updateDelayedActions(float dt) {
_delayed.erase(delayedToRemove, _delayed.end());
}
bool ActionQueue::isEmpty() const {
return _actions.empty();
}
bool ActionQueue::containsUserActions() const {
bool Object::hasUserActionsPending() const {
for (auto &action : _actions) {
if (action->isUserAction()) return true;
}
return false;
}
int ActionQueue::getSize() const {
return static_cast<int>(_actions.size());
}
shared_ptr<Action> ActionQueue::getCurrentAction() const {
shared_ptr<Action> Object::getCurrentAction() const {
return _actions.empty() ? nullptr : _actions.front();
}

View file

@ -125,7 +125,7 @@ void Party::onLeaderChanged() {
_members[0].creature->playSound(entry, false);
for (auto &member : _members) {
member.creature->actionQueue().clear();
member.creature->clearAllActions();
}
_game->module()->area()->onPartyLeaderMoved(true);

View file

@ -156,18 +156,14 @@ void Player::update(float dt) {
movement = false;
}
ActionQueue &actions = partyLeader->actionQueue();
if (movement) {
actions.clear();
partyLeader->clearAllActions();
glm::vec2 dir(glm::normalize(glm::vec2(-glm::sin(facing), glm::cos(facing))));
if (_area->moveCreature(partyLeader, dir, true, dt)) {
partyLeader->setMovementType(Creature::MovementType::Run);
partyLeader->setAppliedForce(glm::vec3(dir, 0.0f));
}
} else if (actions.isEmpty()) {
} else if (partyLeader->actions().empty()) {
partyLeader->setMovementType(Creature::MovementType::None);
partyLeader->setAppliedForce(glm::vec3(0.0f));
}

View file

@ -46,7 +46,7 @@ Variable Routines::delayCommand(const VariablesList &args, ExecutionContext &ctx
auto action = getAction(args, 1);
auto objectAction = make_unique<CommandAction>(move(action));
getCaller(ctx)->actionQueue().delay(move(objectAction), seconds);
getCaller(ctx)->delayAction(move(objectAction), seconds);
return Variable();
}
@ -57,7 +57,7 @@ Variable Routines::assignCommand(const VariablesList &args, ExecutionContext &ct
if (subject) {
auto objectAction = make_unique<CommandAction>(move(action));
subject->actionQueue().add(move(objectAction));
subject->addAction(move(objectAction));
} else {
debug("Script: assignCommand: subject is invalid", 1, DebugChannels::script);
}
@ -69,7 +69,7 @@ Variable Routines::actionDoCommand(const VariablesList &args, ExecutionContext &
auto action = getAction(args, 0);
auto commandAction = make_unique<CommandAction>(move(action));
getCaller(ctx)->actionQueue().add(move(commandAction));
getCaller(ctx)->addAction(move(commandAction));
return Variable();
}
@ -81,7 +81,7 @@ Variable Routines::actionMoveToObject(const VariablesList &args, ExecutionContex
if (moveTo) {
auto action = make_unique<MoveToObjectAction>(move(moveTo), run, range);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionMoveToObject: moveTo is invalid", 1, DebugChannels::script);
}
@ -101,7 +101,7 @@ Variable Routines::actionStartConversation(const VariablesList &args, ExecutionC
dialogResRef = caller->conversation();
}
auto action = make_unique<StartConversationAction>(move(objectToConverse), move(dialogResRef), ignoreStartRange);
caller->actionQueue().add(move(action));
caller->addAction(move(action));
} else {
debug("Script: actionStartConversation: objectToConverse is invalid", 1, DebugChannels::script);
}
@ -111,13 +111,13 @@ Variable Routines::actionStartConversation(const VariablesList &args, ExecutionC
Variable Routines::actionPauseConversation(const VariablesList &args, ExecutionContext &ctx) {
auto action = make_unique<Action>(ActionType::PauseConversation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionResumeConversation(const VariablesList &args, ExecutionContext &ctx) {
auto action = make_unique<Action>(ActionType::ResumeConversation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -125,7 +125,7 @@ Variable Routines::actionOpenDoor(const VariablesList &args, ExecutionContext &c
auto door = getObject(args, 0, ctx);
if (door) {
auto action = make_unique<ObjectAction>(ActionType::OpenDoor, door);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionOpenDoor: door is invalid", 1, DebugChannels::script);
}
@ -136,7 +136,7 @@ Variable Routines::actionCloseDoor(const VariablesList &args, ExecutionContext &
auto door = getObject(args, 0, ctx);
if (door) {
auto action = make_unique<ObjectAction>(ActionType::CloseDoor, door);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionCloseDoor: door is invalid", 1, DebugChannels::script);
}
@ -155,7 +155,7 @@ Variable Routines::actionJumpToObject(const VariablesList &args, ExecutionContex
if (jumpTo) {
auto action = make_unique<ObjectAction>(ActionType::JumpToObject, move(jumpTo));
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionJumpToObject: jumpTo is invalid", 1, DebugChannels::script);
}
@ -167,7 +167,7 @@ Variable Routines::actionJumpToLocation(const VariablesList &args, ExecutionCont
auto location = getLocationEngineType(args, 0);
if (location) {
auto action = make_unique<LocationAction>(ActionType::JumpToLocation, move(location));
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionJumpToLocation: location is invalid", 1, DebugChannels::script);
}
@ -183,7 +183,7 @@ Variable Routines::actionForceMoveToObject(const VariablesList &args, ExecutionC
if (moveTo) {
auto action = make_unique<MoveToObjectAction>(move(moveTo), run, range);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionForceMoveToObject: moveTo is invalid", 1, DebugChannels::script);
}
@ -199,7 +199,7 @@ Variable Routines::actionForceMoveToLocation(const VariablesList &args, Executio
if (destination) {
auto action = make_unique<MoveToLocationAction>(move(destination));
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionForceMoveToLocation: destination is invalid", 1, DebugChannels::script);
}
@ -214,7 +214,7 @@ Variable Routines::jumpToObject(const VariablesList &args, ExecutionContext &ctx
if (jumpTo) {
auto action = make_unique<ObjectAction>(ActionType::JumpToObject, move(jumpTo));
getCaller(ctx)->actionQueue().addToTop(move(action));
getCaller(ctx)->addActionOnTop(move(action));
} else {
debug("Script: jumpToObject: jumpTo is invalid", 1, DebugChannels::script);
}
@ -226,7 +226,7 @@ Variable Routines::jumpToLocation(const VariablesList &args, ExecutionContext &c
auto destination = getLocationEngineType(args, 0);
if (destination) {
auto action = make_unique<LocationAction>(ActionType::JumpToLocation, move(destination));
getCaller(ctx)->actionQueue().addToTop(move(action));
getCaller(ctx)->addActionOnTop(move(action));
} else {
debug("Script: jumpToLocation: destination is invalid", 1, DebugChannels::script);
}
@ -235,7 +235,7 @@ Variable Routines::jumpToLocation(const VariablesList &args, ExecutionContext &c
Variable Routines::actionRandomWalk(const VariablesList &args, ExecutionContext &ctx) {
auto action = make_unique<Action>(ActionType::RandomWalk);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -245,7 +245,7 @@ Variable Routines::actionMoveToLocation(const VariablesList &args, ExecutionCont
if (destination) {
auto action = make_unique<MoveToLocationAction>(move(destination), run);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionMoveToLocation: destination is invalid", 1, DebugChannels::script);
}
@ -261,7 +261,7 @@ Variable Routines::actionMoveAwayFromObject(const VariablesList &args, Execution
if (fleeFrom) {
auto action = make_unique<Action>(ActionType::MoveAwayFromObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionMoveAwayFromObject: fleeFrom is invalid", 1, DebugChannels::script);
}
@ -277,7 +277,7 @@ Variable Routines::actionEquipItem(const VariablesList &args, ExecutionContext &
if (item) {
auto action = make_unique<Action>(ActionType::EquipItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionEquipItem: item is invalid", 1, DebugChannels::script);
}
@ -292,7 +292,7 @@ Variable Routines::actionUnequipItem(const VariablesList &args, ExecutionContext
if (item) {
auto action = make_unique<Action>(ActionType::UnequipItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionUnequipItem: item is invalid", 1, DebugChannels::script);
}
@ -305,7 +305,7 @@ Variable Routines::actionPickUpItem(const VariablesList &args, ExecutionContext
auto item = getItem(args, 0, ctx);
if (item) {
auto action = make_unique<Action>(ActionType::PickUpItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionPickUpItem: item is invalid", 1, DebugChannels::script);
}
@ -317,7 +317,7 @@ Variable Routines::actionPutDownItem(const VariablesList &args, ExecutionContext
auto item = getItem(args, 0, ctx);
if (item) {
auto action = make_unique<Action>(ActionType::DropItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionPutDownItem: item is invalid", 1, DebugChannels::script);
}
@ -332,7 +332,7 @@ Variable Routines::actionAttack(const VariablesList &args, ExecutionContext &ctx
if (caller && attackee) {
auto action = make_unique<AttackAction>(attackee, caller->getAttackRange());
caller->actionQueue().add(move(action));
caller->addAction(move(action));
} else if (!caller) {
debug("Script: actionAttack: caller is invalid", 1, DebugChannels::script);
} else if (!attackee) {
@ -348,7 +348,7 @@ Variable Routines::actionSpeakString(const VariablesList &args, ExecutionContext
auto talkVolume = getEnum(args, 1, TalkVolume::Talk);
auto action = make_unique<Action>(ActionType::SpeakString);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -359,7 +359,7 @@ Variable Routines::actionPlayAnimation(const VariablesList &args, ExecutionConte
float duration = getFloat(args, 2, 0.0f);
auto action = make_unique<PlayAnimationAction>(animation, speed, duration);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -375,7 +375,7 @@ Variable Routines::actionCastSpellAtObject(const VariablesList &args, ExecutionC
bool instantSpell = getBool(args, 6, false);
auto action = make_unique<Action>(ActionType::CastSpellAtObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -387,7 +387,7 @@ Variable Routines::actionGiveItem(const VariablesList &args, ExecutionContext &c
if (item && giveTo) {
auto action = make_unique<Action>(ActionType::GiveItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else if (!item) {
debug("Script: actionGiveItem: item is invalid", 1, DebugChannels::script);
} else if (!giveTo) {
@ -404,7 +404,7 @@ Variable Routines::actionTakeItem(const VariablesList &args, ExecutionContext &c
if (item && takeFrom) {
auto action = make_unique<Action>(ActionType::TakeItem);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else if (!item) {
debug("Script: actionTakeItem: item is invalid", 1, DebugChannels::script);
} else if (!takeFrom) {
@ -421,7 +421,7 @@ Variable Routines::actionForceFollowObject(const VariablesList &args, ExecutionC
if (follow) {
auto action = make_unique<Action>(ActionType::ForceFollowObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionForceFollowObject: follow is invalid", 1, DebugChannels::script);
}
@ -433,7 +433,7 @@ Variable Routines::actionWait(const VariablesList &args, ExecutionContext &ctx)
float seconds = getFloat(args, 0);
auto action = make_unique<WaitAction>(seconds);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -449,7 +449,7 @@ Variable Routines::actionCastSpellAtLocation(const VariablesList &args, Executio
if (targetLocation) {
auto action = make_unique<Action>(ActionType::CastSpellAtLocation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionCastSpellAtLocation: targetLocation is invalid", 1, DebugChannels::script);
}
@ -463,7 +463,7 @@ Variable Routines::actionSpeakStringByStrRef(const VariablesList &args, Executio
auto talkVolume = getEnum(args, 1, TalkVolume::Talk);
auto action = make_unique<Action>(ActionType::SpeakStringByStrRef);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -475,7 +475,7 @@ Variable Routines::actionUseFeat(const VariablesList &args, ExecutionContext &ct
if (target) {
auto action = make_unique<Action>(ActionType::UseFeat);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionUseFeat: target is invalid", 1, DebugChannels::script);
}
@ -492,7 +492,7 @@ Variable Routines::actionUseSkill(const VariablesList &args, ExecutionContext &c
if (target) {
auto action = make_unique<Action>(ActionType::UseSkill);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionUseSkill: target is invalid", 1, DebugChannels::script);
}
@ -507,7 +507,7 @@ Variable Routines::actionUseTalentOnObject(const VariablesList &args, ExecutionC
if (target) {
auto action = make_unique<Action>(ActionType::UseTalentOnObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionUseTalentOnObject: target is invalid", 1, DebugChannels::script);
}
@ -522,7 +522,7 @@ Variable Routines::actionUseTalentAtLocation(const VariablesList &args, Executio
if (targetLocation) {
auto action = make_unique<Action>(ActionType::UseTalentAtLocation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
} else {
debug("Script: actionUseTalentAtLocation: targetLocation is invalid", 1, DebugChannels::script);
}
@ -533,70 +533,70 @@ Variable Routines::actionUseTalentAtLocation(const VariablesList &args, Executio
Variable Routines::actionInteractObject(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::InteractObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionMoveAwayFromLocation(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::MoveAwayFromLocation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionSurrenderToEnemies(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::SurrenderToEnemies);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionEquipMostDamagingMelee(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::EquipMostDamagingMelee);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionEquipMostDamagingRanged(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::EquipMostDamagingRanged);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionEquipMostEffectiveArmor(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::EquipMostEffectiveArmor);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionUnlockObject(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::UnlockObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionLockObject(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::LockObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionCastFakeSpellAtObject(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::CastFakeSpellAtObject);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionCastFakeSpellAtLocation(const VariablesList &args, ExecutionContext &ctx) {
// TODO: extract and pass all arguments to an action
auto action = make_unique<Action>(ActionType::CastFakeSpellAtLocation);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -605,14 +605,14 @@ Variable Routines::actionBarkString(const VariablesList &args, ExecutionContext
int strRef = getInt(args, 0);
auto action = make_unique<Action>(ActionType::BarkString);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionFollowLeader(const VariablesList &args, ExecutionContext &ctx) {
auto action = make_unique<Action>(ActionType::FollowLeader);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
@ -621,20 +621,20 @@ Variable Routines::actionFollowOwner(const VariablesList &args, ExecutionContext
float range = getFloat(args, 0, 2.5f);
auto action = make_unique<Action>(ActionType::FollowOwner);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::actionSwitchWeapons(const VariablesList &args, ExecutionContext &ctx) {
auto action = make_unique<Action>(ActionType::SwitchWeapons);
getCaller(ctx)->actionQueue().add(move(action));
getCaller(ctx)->addAction(move(action));
return Variable();
}
Variable Routines::getCurrentAction(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObjectOrCaller(args, 0, ctx);
shared_ptr<Action> action(object->actionQueue().getCurrentAction());
shared_ptr<Action> action(object->getCurrentAction());
return Variable::ofInt(static_cast<int>(action ? action->type() : ActionType::QueueEmpty));
}

View file

@ -171,7 +171,7 @@ Variable Routines::getUserActionsPending(const VariablesList &args, ExecutionCon
auto caller = getCallerAsCreature(ctx);
if (caller) {
result = caller->actionQueue().containsUserActions();
result = caller->hasUserActionsPending();
} else {
debug("Script: getUserActionsPending: caller is invalid", 1, DebugChannels::script);
}

View file

@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE actionqueue
#include <boost/test/included/unit_test.hpp>
#include "../engine/game/actionqueue.h"
using namespace std;
using namespace reone::game;
BOOST_AUTO_TEST_CASE(test_action_completion) {
ActionQueue actionQueue;
actionQueue.add(make_unique<Action>(ActionType::PauseConversation));
actionQueue.add(make_unique<Action>(ActionType::ResumeConversation));
shared_ptr<Action> currentAction(actionQueue.getCurrentAction());
BOOST_TEST((currentAction && currentAction->type() == ActionType::PauseConversation));
currentAction->complete();
actionQueue.update(0.0f);
currentAction = actionQueue.getCurrentAction();
BOOST_TEST((currentAction && currentAction->type() == ActionType::ResumeConversation));
currentAction->complete();
actionQueue.update(0.0f);
currentAction = actionQueue.getCurrentAction();
BOOST_TEST(!currentAction);
}