Replace OpenLock with UseSkill(Security) action

This commit is contained in:
Vsevolod Kremianskii 2021-05-27 07:20:46 +07:00
parent b993989ae3
commit 9166d49f08
24 changed files with 279 additions and 117 deletions

View file

@ -439,6 +439,8 @@ set(GAME_HEADERS
src/engine/game/d20/feat.h
src/engine/game/d20/feats.h
src/engine/game/d20/savingthrows.h
src/engine/game/d20/skill.h
src/engine/game/d20/skills.h
src/engine/game/d20/spell.h
src/engine/game/d20/spells.h
src/engine/game/dialog.h
@ -542,6 +544,7 @@ set(GAME_SOURCES
src/engine/game/d20/class.cpp
src/engine/game/d20/classes.cpp
src/engine/game/d20/feats.cpp
src/engine/game/d20/skills.cpp
src/engine/game/d20/spells.cpp
src/engine/game/dialog.cpp
src/engine/game/footstepsounds.cpp

View file

@ -25,15 +25,15 @@ namespace game {
class UseSkillAction : public ObjectAction {
public:
UseSkillAction(std::shared_ptr<Object> object, Skill skill) :
UseSkillAction(std::shared_ptr<Object> object, SkillType skill) :
ObjectAction(ActionType::UseSkill, move(object)),
_skill(skill) {
}
Skill skill() const { return _skill; }
SkillType skill() const { return _skill; }
private:
Skill _skill;
SkillType _skill;
};
} // namespace game

View file

@ -26,6 +26,7 @@
#include "../scene/types.h"
#include "../script/execution.h"
#include "action/useskill.h"
#include "action/waitaction.h"
#include "enginetype/location.h"
#include "game.h"
@ -119,6 +120,13 @@ void ActionExecutor::executeActions(const shared_ptr<Object> &object, float dt)
case ActionType::MoveToLocation:
executeMoveToLocation(object, *static_pointer_cast<MoveToLocationAction>(action), dt);
break;
case ActionType::UseSkill: {
auto useAction = static_pointer_cast<UseSkillAction>(action);
if (useAction->skill() == SkillType::Security) {
executeOpenLock(object, *useAction, dt);
}
break;
}
default:
debug("ActionExecutor: action not implemented: " + to_string(static_cast<int>(type)), 2);
action->complete();

View file

@ -26,11 +26,11 @@ namespace game {
struct ContextAction {
ActionType type { ActionType::Invalid };
FeatType feat { FeatType::Invalid };
Skill skill { Skill::Invalid };
SkillType skill { SkillType::Invalid };
ContextAction(ActionType type) : type(type) {}
ContextAction(FeatType feat) : type(ActionType::UseFeat), feat(feat) {}
ContextAction(Skill skill) : type(ActionType::UseSkill), skill(skill) {}
ContextAction(SkillType skill) : type(ActionType::UseSkill), skill(skill) {}
};
} // namespace game

View file

@ -89,11 +89,11 @@ public:
// Skills
bool hasSkill(Skill skill) const;
bool hasSkill(SkillType skill) const;
int getSkillRank(Skill skill) const;
int getSkillRank(SkillType skill) const;
const std::map<Skill, int> &skillRanks() const { return _skillRanks; }
const std::map<SkillType, int> &skillRanks() const { return _skillRanks; }
int computerUse() const;
int demolitions() const;
int stealth() const;
@ -103,7 +103,7 @@ public:
int security() const;
int treatInjury() const;
void setSkillRank(Skill skill, int rank);
void setSkillRank(SkillType skill, int rank);
// END Skills
@ -128,7 +128,7 @@ public:
private:
std::vector<std::pair<CreatureClass *, int>> _classLevels;
std::map<Ability, int> _abilityScores;
std::map<Skill, int> _skillRanks;
std::map<SkillType, int> _skillRanks;
std::set<FeatType> _feats;
std::set<ForcePower> _spells;
};

View file

@ -25,47 +25,47 @@ namespace game {
static constexpr int kDefaultSkillRank = 0;
bool CreatureAttributes::hasSkill(Skill skill) const {
bool CreatureAttributes::hasSkill(SkillType skill) const {
return getSkillRank(skill) > 0;
}
int CreatureAttributes::getSkillRank(Skill skill) const {
int CreatureAttributes::getSkillRank(SkillType skill) const {
return getFromLookupOrElse(_skillRanks, skill, kDefaultSkillRank);
}
int CreatureAttributes::computerUse() const {
return getSkillRank(Skill::ComputerUse);
return getSkillRank(SkillType::ComputerUse);
}
int CreatureAttributes::demolitions() const {
return getSkillRank(Skill::Demolitions);
return getSkillRank(SkillType::Demolitions);
}
int CreatureAttributes::stealth() const {
return getSkillRank(Skill::Stealth);
return getSkillRank(SkillType::Stealth);
}
int CreatureAttributes::awareness() const {
return getSkillRank(Skill::Awareness);
return getSkillRank(SkillType::Awareness);
}
int CreatureAttributes::persuade() const {
return getSkillRank(Skill::Persuade);
return getSkillRank(SkillType::Persuade);
}
int CreatureAttributes::repair() const {
return getSkillRank(Skill::Repair);
return getSkillRank(SkillType::Repair);
}
int CreatureAttributes::security() const {
return getSkillRank(Skill::Security);
return getSkillRank(SkillType::Security);
}
int CreatureAttributes::treatInjury() const {
return getSkillRank(Skill::TreatInjury);
return getSkillRank(SkillType::TreatInjury);
}
void CreatureAttributes::setSkillRank(Skill skill, int rank) {
void CreatureAttributes::setSkillRank(SkillType skill, int rank) {
_skillRanks[skill] = rank;
}

View file

@ -74,7 +74,7 @@ void CreatureClass::loadClassSkills(const string &skillsTable) {
shared_ptr<TwoDA> skills(_resources->get2DA(kSkillsTwoDaResRef));
for (int row = 0; row < skills->getRowCount(); ++row) {
if (skills->getInt(row, skillsTable + "_class") == 1) {
_classSkills.insert(static_cast<Skill>(row));
_classSkills.insert(static_cast<SkillType>(row));
}
}
}
@ -100,7 +100,7 @@ void CreatureClass::loadAttackBonuses(const string &attackBonusTable) {
}
}
bool CreatureClass::isClassSkill(Skill skill) const {
bool CreatureClass::isClassSkill(SkillType skill) const {
return _classSkills.count(skill) > 0;
}

View file

@ -42,7 +42,7 @@ public:
void load(const resource::TwoDA &twoDa, int row);
bool isClassSkill(Skill skill) const;
bool isClassSkill(SkillType skill) const;
/**
* @return class saving throws at the specified creature level
@ -72,7 +72,7 @@ private:
int _hitdie { 0 };
CreatureAttributes _defaultAttributes;
int _skillPointBase { 0 };
std::unordered_set<Skill> _classSkills;
std::unordered_set<SkillType> _classSkills;
std::unordered_map<int, SavingThrows> _savingThrowsByLevel;
std::vector<int> _attackBonuses;

View file

@ -0,0 +1,37 @@
/*
* 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 <string>
#include "../../graphics/texture/texture.h"
namespace reone {
namespace game {
struct Skill {
std::string name;
std::string description;
std::shared_ptr<graphics::Texture> icon;
};
} // namespace game
} // namespace reone

View file

@ -0,0 +1,57 @@
/*
* 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/>.
*/
#include "skills.h"
#include "../../common/collectionutil.h"
using namespace std;
using namespace reone::graphics;
using namespace reone::resource;
namespace reone {
namespace game {
Skills::Skills(GraphicsServices &graphics, ResourceServices &resource) : _graphics(graphics), _resource(resource) {
}
void Skills::init() {
shared_ptr<TwoDA> skills(_resource.resources().get2DA("skills"));
if (!skills) return;
for (int row = 0; row < skills->getRowCount(); ++row) {
string name(_resource.strings().get(skills->getInt(row, "name", -1)));
string description(_resource.strings().get(skills->getInt(row, "description", -1)));
shared_ptr<Texture> icon(_graphics.textures().get(skills->getString(row, "icon"), TextureUsage::GUI));
auto skill = make_shared<Skill>();
skill->name = move(name);
skill->description = move(description);
skill->icon = move(icon);
_skills.insert(make_pair(static_cast<SkillType>(row), move(skill)));
}
}
shared_ptr<Skill> Skills::get(SkillType type) const {
return getFromLookupOrNull(_skills, type);
}
} // namespace game
} // namespace reone

View file

@ -0,0 +1,52 @@
/*
* 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 <unordered_map>
#include <boost/noncopyable.hpp>
#include "../../graphics/services.h"
#include "../../resource/services.h"
#include "../types.h"
#include "skill.h"
namespace reone {
namespace game {
class Skills : boost::noncopyable {
public:
Skills(graphics::GraphicsServices &graphics, resource::ResourceServices &resource);
void init();
std::shared_ptr<Skill> get(SkillType type) const;
private:
graphics::GraphicsServices &_graphics;
resource::ResourceServices &_resource;
std::unordered_map<SkillType, std::shared_ptr<Skill>> _skills;
};
} // namespace game
} // namespace reone

View file

@ -17,14 +17,8 @@
#include "spells.h"
#include <functional>
#include <string>
#include "../../common/collectionutil.h"
#include "../../common/guardutil.h"
#include "../../graphics/texture/textures.h"
#include "../../resource/resources.h"
#include "../../resource/strings.h"
using namespace std;

View file

@ -41,37 +41,37 @@ namespace reone {
namespace game {
static const unordered_map<string, Skill> g_skillByAlias {
{ "COM", Skill::ComputerUse },
{ "DEM", Skill::Demolitions },
{ "STE", Skill::Stealth },
{ "AWA", Skill::Awareness },
{ "PER", Skill::Persuade },
{ "REP", Skill::Repair },
{ "SEC", Skill::Security },
{ "TRE", Skill::TreatInjury }
static const unordered_map<string, SkillType> g_skillByAlias {
{ "COM", SkillType::ComputerUse },
{ "DEM", SkillType::Demolitions },
{ "STE", SkillType::Stealth },
{ "AWA", SkillType::Awareness },
{ "PER", SkillType::Persuade },
{ "REP", SkillType::Repair },
{ "SEC", SkillType::Security },
{ "TRE", SkillType::TreatInjury }
};
static const unordered_map<string, Skill> g_skillByLabelTag {
{ "COMPUTER_USE_LBL", Skill::ComputerUse },
{ "DEMOLITIONS_LBL", Skill::Demolitions },
{ "STEALTH_LBL", Skill::Stealth },
{ "AWARENESS_LBL", Skill::Awareness },
{ "PERSUADE_LBL", Skill::Persuade },
{ "REPAIR_LBL", Skill::Repair },
{ "SECURITY_LBL", Skill::Security },
{ "TREAT_INJURY_LBL", Skill::TreatInjury }
static const unordered_map<string, SkillType> g_skillByLabelTag {
{ "COMPUTER_USE_LBL", SkillType::ComputerUse },
{ "DEMOLITIONS_LBL", SkillType::Demolitions },
{ "STEALTH_LBL", SkillType::Stealth },
{ "AWARENESS_LBL", SkillType::Awareness },
{ "PERSUADE_LBL", SkillType::Persuade },
{ "REPAIR_LBL", SkillType::Repair },
{ "SECURITY_LBL", SkillType::Security },
{ "TREAT_INJURY_LBL", SkillType::TreatInjury }
};
static const unordered_map<Skill, int> g_descStrRefBySkill {
{ Skill::ComputerUse, 244 },
{ Skill::Demolitions, 246 },
{ Skill::Stealth, 248 },
{ Skill::Awareness, 250 },
{ Skill::Persuade, 252 },
{ Skill::Repair, 254 },
{ Skill::Security, 256 },
{ Skill::TreatInjury, 258 }
static const unordered_map<SkillType, int> g_descStrRefBySkill {
{ SkillType::ComputerUse, 244 },
{ SkillType::Demolitions, 246 },
{ SkillType::Stealth, 248 },
{ SkillType::Awareness, 250 },
{ SkillType::Persuade, 252 },
{ SkillType::Repair, 254 },
{ SkillType::Security, 256 },
{ SkillType::TreatInjury, 258 }
};
CharGenSkills::CharGenSkills(CharacterGeneration *charGen, Game *game) :
@ -119,14 +119,14 @@ void CharGenSkills::reset(bool newGame) {
if (newGame) {
_points *= 4;
_attributes.setSkillRank(Skill::ComputerUse, 0);
_attributes.setSkillRank(Skill::Demolitions, 0);
_attributes.setSkillRank(Skill::Stealth, 0);
_attributes.setSkillRank(Skill::Awareness, 0);
_attributes.setSkillRank(Skill::Persuade, 0);
_attributes.setSkillRank(Skill::Repair, 0);
_attributes.setSkillRank(Skill::Security, 0);
_attributes.setSkillRank(Skill::TreatInjury, 0);
_attributes.setSkillRank(SkillType::ComputerUse, 0);
_attributes.setSkillRank(SkillType::Demolitions, 0);
_attributes.setSkillRank(SkillType::Stealth, 0);
_attributes.setSkillRank(SkillType::Awareness, 0);
_attributes.setSkillRank(SkillType::Persuade, 0);
_attributes.setSkillRank(SkillType::Repair, 0);
_attributes.setSkillRank(SkillType::Security, 0);
_attributes.setSkillRank(SkillType::TreatInjury, 0);
} else {
_attributes = attributes;
}
@ -137,35 +137,35 @@ void CharGenSkills::reset(bool newGame) {
void CharGenSkills::refreshControls() {
setControlText("REMAINING_SELECTIONS_LBL", to_string(_points));
setControlText("COMPUTER_USE_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::ComputerUse)));
setControlText("DEMOLITIONS_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Demolitions)));
setControlText("STEALTH_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Stealth)));
setControlText("AWARENESS_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Awareness)));
setControlText("PERSUADE_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Persuade)));
setControlText("REPAIR_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Repair)));
setControlText("SECURITY_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::Security)));
setControlText("TREAT_INJURY_POINTS_BTN", to_string(_attributes.getSkillRank(Skill::TreatInjury)));
setControlText("COMPUTER_USE_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::ComputerUse)));
setControlText("DEMOLITIONS_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Demolitions)));
setControlText("STEALTH_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Stealth)));
setControlText("AWARENESS_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Awareness)));
setControlText("PERSUADE_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Persuade)));
setControlText("REPAIR_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Repair)));
setControlText("SECURITY_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::Security)));
setControlText("TREAT_INJURY_POINTS_BTN", to_string(_attributes.getSkillRank(SkillType::TreatInjury)));
setControlVisible("COM_MINUS_BTN", _attributes.getSkillRank(Skill::ComputerUse) > 0);
setControlVisible("DEM_MINUS_BTN", _attributes.getSkillRank(Skill::Demolitions) > 0);
setControlVisible("STE_MINUS_BTN", _attributes.getSkillRank(Skill::Stealth) > 0);
setControlVisible("AWA_MINUS_BTN", _attributes.getSkillRank(Skill::Awareness) > 0);
setControlVisible("PER_MINUS_BTN", _attributes.getSkillRank(Skill::Persuade) > 0);
setControlVisible("REP_MINUS_BTN", _attributes.getSkillRank(Skill::Repair) > 0);
setControlVisible("SEC_MINUS_BTN", _attributes.getSkillRank(Skill::Security) > 0);
setControlVisible("TRE_MINUS_BTN", _attributes.getSkillRank(Skill::TreatInjury) > 0);
setControlVisible("COM_MINUS_BTN", _attributes.getSkillRank(SkillType::ComputerUse) > 0);
setControlVisible("DEM_MINUS_BTN", _attributes.getSkillRank(SkillType::Demolitions) > 0);
setControlVisible("STE_MINUS_BTN", _attributes.getSkillRank(SkillType::Stealth) > 0);
setControlVisible("AWA_MINUS_BTN", _attributes.getSkillRank(SkillType::Awareness) > 0);
setControlVisible("PER_MINUS_BTN", _attributes.getSkillRank(SkillType::Persuade) > 0);
setControlVisible("REP_MINUS_BTN", _attributes.getSkillRank(SkillType::Repair) > 0);
setControlVisible("SEC_MINUS_BTN", _attributes.getSkillRank(SkillType::Security) > 0);
setControlVisible("TRE_MINUS_BTN", _attributes.getSkillRank(SkillType::TreatInjury) > 0);
setControlVisible("COM_PLUS_BTN", canIncreaseSkill(Skill::ComputerUse));
setControlVisible("DEM_PLUS_BTN", canIncreaseSkill(Skill::Demolitions));
setControlVisible("STE_PLUS_BTN", canIncreaseSkill(Skill::Stealth));
setControlVisible("AWA_PLUS_BTN", canIncreaseSkill(Skill::Awareness));
setControlVisible("PER_PLUS_BTN", canIncreaseSkill(Skill::Persuade));
setControlVisible("REP_PLUS_BTN", canIncreaseSkill(Skill::Repair));
setControlVisible("SEC_PLUS_BTN", canIncreaseSkill(Skill::Security));
setControlVisible("TRE_PLUS_BTN", canIncreaseSkill(Skill::TreatInjury));
setControlVisible("COM_PLUS_BTN", canIncreaseSkill(SkillType::ComputerUse));
setControlVisible("DEM_PLUS_BTN", canIncreaseSkill(SkillType::Demolitions));
setControlVisible("STE_PLUS_BTN", canIncreaseSkill(SkillType::Stealth));
setControlVisible("AWA_PLUS_BTN", canIncreaseSkill(SkillType::Awareness));
setControlVisible("PER_PLUS_BTN", canIncreaseSkill(SkillType::Persuade));
setControlVisible("REP_PLUS_BTN", canIncreaseSkill(SkillType::Repair));
setControlVisible("SEC_PLUS_BTN", canIncreaseSkill(SkillType::Security));
setControlVisible("TRE_PLUS_BTN", canIncreaseSkill(SkillType::TreatInjury));
}
bool CharGenSkills::canIncreaseSkill(Skill skill) const {
bool CharGenSkills::canIncreaseSkill(SkillType skill) const {
ClassType clazz = _charGen->character().attributes.getEffectiveClass();
shared_ptr<CreatureClass> creatureClass(_game->services().classes().get(clazz));
@ -175,7 +175,7 @@ bool CharGenSkills::canIncreaseSkill(Skill skill) const {
return _points >= pointCost && _attributes.getSkillRank(skill) < maxSkillRank;
}
static Skill getSkillByAlias(const string &alias) {
static SkillType getSkillByAlias(const string &alias) {
return g_skillByAlias.find(alias)->second;
}
@ -195,13 +195,13 @@ void CharGenSkills::onClick(const string &control) {
_charGen->openSteps();
} else if (boost::ends_with(control, "_MINUS_BTN")) {
Skill skill = getSkillByAlias(control.substr(0, 3));
SkillType skill = getSkillByAlias(control.substr(0, 3));
_attributes.setSkillRank(skill, _attributes.getSkillRank(skill) - 1);
_points += getPointCost(skill);
refreshControls();
} else if (boost::ends_with(control, "_PLUS_BTN")) {
Skill skill = getSkillByAlias(control.substr(0, 3));
SkillType skill = getSkillByAlias(control.substr(0, 3));
_points -= getPointCost(skill);
_attributes.setSkillRank(skill, _attributes.getSkillRank(skill) + 1);
refreshControls();
@ -216,7 +216,7 @@ void CharGenSkills::updateCharacter() {
_charGen->setCharacter(move(character));
}
int CharGenSkills::getPointCost(Skill skill) const {
int CharGenSkills::getPointCost(SkillType skill) const {
ClassType clazz = _charGen->character().attributes.getEffectiveClass();
shared_ptr<CreatureClass> creatureClass(_game->services().classes().get(clazz));
return creatureClass->isClassSkill(skill) ? 1 : 2;

View file

@ -46,9 +46,9 @@ private:
void refreshControls();
void updateCharacter();
bool canIncreaseSkill(Skill skill) const;
bool canIncreaseSkill(SkillType skill) const;
int getPointCost(Skill skill) const;
int getPointCost(SkillType skill) const;
};
} // namespace game

View file

@ -77,7 +77,7 @@ void AbilitiesMenu::load() {
void AbilitiesMenu::loadSkills() {
shared_ptr<TwoDA> skills(_game->services().resource().resources().get2DA("skills"));
for (int row = 0; row < skills->getRowCount(); ++row) {
auto skill = static_cast<Skill>(row);
auto skill = static_cast<SkillType>(row);
SkillInfo skillInfo;
skillInfo.skill = skill;
@ -141,7 +141,7 @@ void AbilitiesMenu::onClick(const string &control) {
void AbilitiesMenu::onListBoxItemClick(const string &control, const string &item) {
if (control == "LB_ABILITY") {
auto skill = static_cast<Skill>(stoi(item));
auto skill = static_cast<SkillType>(stoi(item));
auto maybeSkillInfo = _skills.find(skill);
if (maybeSkillInfo != _skills.end()) {
shared_ptr<Creature> partyLeader(_game->services().party().getLeader());

View file

@ -35,13 +35,13 @@ public:
private:
struct SkillInfo {
Skill skill;
SkillType skill;
std::string name;
std::string description;
std::shared_ptr<graphics::Texture> icon;
};
std::unordered_map<Skill, SkillInfo> _skills;
std::unordered_map<SkillType, SkillInfo> _skills;
void onClick(const std::string &control) override;
void onListBoxItemClick(const std::string &control, const std::string &item) override;

View file

@ -31,6 +31,7 @@
#include "../../resource/resources.h"
#include "../action/usefeat.h"
#include "../action/useskill.h"
#include "../d20/feats.h"
#include "../game.h"
#include "../objectconverter.h"
@ -58,7 +59,6 @@ static constexpr int kActionWidth = 35;
static constexpr int kActionHeight = 59;
static string g_attackIcon("i_attack");
static string g_securityIcon("isk_security");
SelectionOverlay::SelectionOverlay(Game *game) : _game(game) {
ensureNotNull(game, "game");
@ -122,15 +122,16 @@ bool SelectionOverlay::handleMouseButtonDown(const SDL_MouseButtonEvent &event)
const ActionSlot &slot = _actionSlots[_selectedActionSlot];
if (slot.indexSelected >= slot.actions.size()) return false;
switch (slot.actions[slot.indexSelected].type) {
const ContextAction &action = slot.actions[slot.indexSelected];
switch (action.type) {
case ActionType::AttackObject:
leader->addAction(make_unique<AttackAction>(selectedObject, leader->getAttackRange(), true));
break;
case ActionType::UseFeat:
leader->addAction(make_unique<UseFeatAction>(selectedObject, slot.actions[slot.indexSelected].feat));
leader->addAction(make_unique<UseFeatAction>(selectedObject, action.feat));
break;
case ActionType::OpenLock:
leader->addAction(make_unique<ObjectAction>(ActionType::OpenLock, selectedObject));
case ActionType::UseSkill:
leader->addAction(make_unique<UseSkillAction>(selectedObject, action.skill));
break;
default:
break;
@ -207,7 +208,7 @@ void SelectionOverlay::update() {
case ActionType::UseFeat:
_actionSlots[0].actions.push_back(action);
break;
case ActionType::OpenLock:
case ActionType::UseSkill:
_actionSlots[1].actions.push_back(action);
break;
default:
@ -375,9 +376,6 @@ void SelectionOverlay::drawActionIcon(int index) {
case ActionType::AttackObject:
texture = _game->services().graphics().textures().get(g_attackIcon, TextureUsage::GUI);
break;
case ActionType::OpenLock:
texture = _game->services().graphics().textures().get(g_securityIcon, TextureUsage::GUI);
break;
case ActionType::UseFeat: {
shared_ptr<Feat> feat(_game->services().feats().get(action.feat));
if (feat) {
@ -385,6 +383,13 @@ void SelectionOverlay::drawActionIcon(int index) {
}
break;
}
case ActionType::UseSkill: {
shared_ptr<Skill> skill(_game->services().skills().get(action.skill));
if (skill) {
texture = skill->icon;
}
break;
}
default:
break;
}

View file

@ -162,7 +162,7 @@ void Creature::loadAttributesFromUTC(const GffStruct &utc) {
vector<shared_ptr<GffStruct>> skillsUtc(utc.getList("SkillList"));
for (int i = 0; i < static_cast<int>(skillsUtc.size()); ++i) {
Skill skill = static_cast<Skill>(i);
SkillType skill = static_cast<SkillType>(i);
attributes.setSkillRank(skill, skillsUtc[i]->getInt("Rank"));
}

View file

@ -321,8 +321,8 @@ vector<ContextAction> Module::getContextActions(const shared_ptr<Object> &object
}
case ObjectType::Door: {
auto door = static_pointer_cast<Door>(object);
if (door->isLocked() && !door->isKeyRequired() && _game->services().party().getLeader()->attributes().hasSkill(Skill::Security)) {
actions.push_back(ContextAction(ActionType::OpenLock));
if (door->isLocked() && !door->isKeyRequired() && _game->services().party().getLeader()->attributes().hasSkill(SkillType::Security)) {
actions.push_back(ContextAction(SkillType::Security));
}
break;
}

View file

@ -485,7 +485,7 @@ Variable Routines::actionUseFeat(const VariablesList &args, ExecutionContext &ct
Variable Routines::actionUseSkill(const VariablesList &args, ExecutionContext &ctx) {
// TODO: pass all arguments to an action
auto skill = getEnum<Skill>(args, 0);
auto skill = getEnum<SkillType>(args, 0);
auto target = getObject(args, 1, ctx);
int subSkill = getInt(args, 2, 0);
auto itemUsed = getObject(args, 3, ctx);

View file

@ -205,7 +205,7 @@ Variable Routines::getHasFeat(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getHasSkill(const VariablesList &args, ExecutionContext &ctx) {
bool result = false;
auto creature = getCreatureOrCaller(args, 1, ctx);
auto skill = getEnum<Skill>(args, 0);
auto skill = getEnum<SkillType>(args, 0);
if (creature) {
result = creature->attributes().hasSkill(skill);
@ -311,7 +311,7 @@ Variable Routines::getLevelByPosition(const VariablesList &args, ExecutionContex
Variable Routines::getSkillRank(const VariablesList &args, ExecutionContext &ctx) {
int result = 0;
auto object = getCreatureOrCaller(args, 1, ctx);
auto skill = getEnum<Skill>(args, 0);
auto skill = getEnum<SkillType>(args, 0);
if (object) {
result = object->attributes().getSkillRank(skill);

View file

@ -70,6 +70,9 @@ void GameServices::init() {
_reputes = make_unique<Reputes>(&_resource.resources());
_reputes->init();
_skills = make_unique<Skills>(_graphics, _resource);
_skills->init();
_feats = make_unique<Feats>(&_graphics.textures(), &_resource.resources(), &_resource.strings());
_feats->init();

View file

@ -31,6 +31,7 @@
#include "cursors.h"
#include "d20/classes.h"
#include "d20/feats.h"
#include "d20/skills.h"
#include "d20/spells.h"
#include "footstepsounds.h"
#include "gui/sounds.h"
@ -80,6 +81,7 @@ public:
Routines &routines() { return *_routines; }
ScriptRunner &scriptRunner() { return *_scriptRunner; }
SoundSets &soundSets() { return *_soundSets; }
Skills &skills() { return *_skills; }
Spells &spells() { return *_spells; }
Surfaces &surfaces() { return *_surfaces; }
@ -104,6 +106,7 @@ private:
std::unique_ptr<Routines> _routines;
std::unique_ptr<ScriptRunner> _scriptRunner;
std::unique_ptr<SoundSets> _soundSets;
std::unique_ptr<Skills> _skills;
std::unique_ptr<Spells> _spells;
std::unique_ptr<Surfaces> _surfaces;
};

View file

@ -493,7 +493,7 @@ enum class Ability {
Charisma = 5
};
enum class Skill {
enum class SkillType {
Invalid = -1,
ComputerUse = 0,
Demolitions = 1,