3 #include <BLIB/Serialization/JSON.hpp>
21 std::string trainerName(
const std::string& n) {
return "tnr:" + n; }
23 std::string npcName(
const std::string& n) {
return "npc:" + n; }
29 , interactingEntity(
bl::ecs::InvalidEntity)
30 , currentConversation(owner)
31 , interactingTrainer(nullptr) {}
36 const bl::tmap::Position* pos =
37 owner.
engine().ecs().getComponent<bl::tmap::Position>(interactor);
38 if (!pos)
return false;
40 const bl::ecs::Entity interacted = owner.
position().
search(*pos, pos->direction, 1);
41 if (interacted != bl::ecs::InvalidEntity) {
42 BL_LOG_INFO <<
"Entity " << interactor <<
" interacted with entity: " << interacted;
45 BL_LOG_WARN <<
"Nonplayer entity " << interactor <<
" interacted with " << interacted;
48 const bl::ecs::Entity nonplayer =
49 interactor != owner.
player().
player() ? interactor : interacted;
53 setTalked(npcName(npc->
name()));
59 interactingEntity = nonplayer;
60 processConversationNode();
67 setTalked(trainerName(trainer->
name()));
72 interactingTrainer = trainer;
82 interactingEntity = nonplayer;
83 processConversationNode();
94 BL_LOG_INFO <<
"Player picked up: " <<
static_cast<unsigned int>(ic->
id()) <<
" ("
97 bl::event::Dispatcher::dispatch<event::ItemPickedUp>({ic->
id()});
98 owner.
engine().ecs().destroyEntity(interacted);
109 void Interaction::processConversationNode() {
110 if (interactingEntity == bl::ecs::InvalidEntity)
return;
111 if (currentConversation.
finished()) {
112 if (interactingTrainer) { startBattle(); }
118 const file::Conversation::Node& node = currentConversation.
currentNode();
119 switch (node.getType()) {
121 owner.
hud().
displayMessage(node.message(), std::bind(&Interaction::continuePressed,
this));
125 std::vector<std::string> choices;
126 choices.reserve(node.choices().size());
127 for (
const auto& pair : node.choices()) choices.push_back(pair.first);
130 std::bind(&Interaction::choiceMade,
this, std::placeholders::_1));
135 if (node.item().afterPrompt) {
138 std::bind(&Interaction::continuePressed,
this));
143 if (node.item().beforePrompt) {
147 std::bind(&Interaction::giveItemDecided,
this, std::placeholders::_1));
153 processConversationNode();
160 owner.
hud().
displayMessage(
"Received " + std::to_string(node.money()) +
" monies",
161 std::bind(&Interaction::continuePressed,
this));
166 "Fork over " + std::to_string(node.money()) +
" monies?",
168 std::bind(&Interaction::giveMoneyDecided,
this, std::placeholders::_1));
172 BL_LOG_ERROR <<
"Invalid conversation node type " << node.getType() <<
", terminating";
174 interactingEntity = bl::ecs::InvalidEntity;
179 void Interaction::continuePressed() {
181 processConversationNode();
184 void Interaction::failMessageFinished() {
186 processConversationNode();
189 void Interaction::choiceMade(
const std::string& c) {
191 processConversationNode();
194 void Interaction::giveItemDecided(
const std::string& c) {
198 processConversationNode();
201 owner.
hud().
displayMessage(
"A voice echos in your head: YOU DON'T HAVE THAT ITEM BRO",
202 std::bind(&Interaction::failMessageFinished,
this));
207 processConversationNode();
211 void Interaction::giveMoneyDecided(
const std::string& c) {
217 processConversationNode();
221 std::bind(&Interaction::failMessageFinished,
this));
226 processConversationNode();
230 void Interaction::faceEntity(bl::ecs::Entity rot, bl::ecs::Entity face) {
231 bl::tmap::Position* mpos = owner.
engine().ecs().getComponent<bl::tmap::Position>(rot);
232 const bl::tmap::Position* fpos = owner.
engine().ecs().getComponent<bl::tmap::Position>(face);
234 const bl::tmap::Direction dir = bl::tmap::Position::facePosition(*mpos, *fpos);
235 const event::EntityRotated event(rot, dir, mpos->direction);
236 mpos->direction = dir;
237 bl::event::Dispatcher::dispatch<event::EntityRotated>(event);
243 if (wit == talkedTo.end())
return false;
244 return wit->second.find(
"npc:" + name) != wit->second.end();
249 if (wit == talkedTo.end())
return false;
250 return wit->second.find(
"tnr:" + name) != wit->second.end();
268 processConversationNode();
271 interactingTrainer =
nullptr;
276 void Interaction::setTalked(
const std::string& name) {
278 if (wit == talkedTo.end()) {
281 wit->second.emplace(name);
284 void Interaction::startBattle() {
285 BL_LOG_INFO <<
"Starting trainer battle";
286 std::unique_ptr<battle::Battle> battle =
292 std::vector<pplmn::BattlePeoplemon> team;
293 team.reserve(interactingTrainer->
team().size());
294 for (
const auto& ppl : interactingTrainer->
team()) {
295 team.emplace_back(
const_cast<pplmn::OwnedPeoplemon*
>(&ppl));
297 battle->state.enemy().init(std::move(team),
298 std::make_unique<battle::AIController>(interactingTrainer->
name(),
299 interactingTrainer->
items()));
300 battle->setController(std::make_unique<battle::LocalBattleController>());
301 battle->state.enemy().getSubstate().trainer = interactingTrainer;
303 bl::event::Dispatcher::dispatch<event::BattleStarted>({std::move(battle)});
Core classes and functionality for both the editor and game.
void notifyNext()
Continues to the next node on player input.
bool finished() const
Returns whether or not the conversation is finished.
void notifyCheckFailed()
Jumps to the node for a check pass (ie take item/money fail etc)
void notifyCheckPassed()
Jumps to the node for a check pass (ie take item/money success etc)
void notifyChoiceMade(const std::string &choice)
Jumps to the node for the given choice if the current node is a Prompt.
const file::Conversation::Node & currentNode() const
Returns the current node.
void setConversation(const file::Conversation &conversation, bl::ecs::Entity entity, bool talked)
Sets the wrapper to point to the given underlying. The underlying must remain in scope during the lif...
static std::unique_ptr< Battle > create(bl::engine::Engine &engine, const std::string &location, system::Player &player, Type type)
Creates the battle struct and initializes the player battler.
Add this component to an entity to make it give an item when interacted with. On interact the owning ...
item::Id id() const
Returns the item id of this item entity.
Adding this to an entity will allow it to be interacted with and talked to.
const file::Conversation & conversation() const
The conversation of the NPC.
const std::string & name() const
The name of the NPC.
Adding this to an entity will make it a trainer that can battle.
const std::string & name() const
The name of the NPC.
bool defeated() const
Returns whether or not this trainer was defeated.
const file::Conversation & beforeBattleConversation() const
The conversation before battle is entered.
const std::vector< item::Id > & items() const
Returns the items the trainer has.
const file::Conversation & afterBattleConversation() const
The conversation used after battle if interacted again.
const std::vector< pplmn::OwnedPeoplemon > & team() const
Returns the team of peoplemon the trainer has.
void setDefeated()
Marks this trainer as defeated.
Fired when a battle finishes.
const battle::Battle::Type type
The type of battle that was completed.
const battle::Result result
The result of the battle.
Fired when the game is saving or loading. Allows systems to hook in their data.
file::GameSave & gameSave
Game save being initialized.
std::uint32_t & money()
Returns the money requested or given, undefined behavior if not a money node.
Item & item()
Returns the item to give or take. Undefined behavior if not an item node.
Type
Represents the different effects that nodes can have.
struct core::file::GameSave::InteractDataPointers interaction
std::unordered_set< std::string > * convFlags
std::unordered_map< std::string, std::unordered_set< std::string > > * talkedto
static const std::string & getName(item::Id item)
Returns the name of the given item.
const std::string & getLocationName(const bl::tmap::Position &pos) const
Returns the name of the town or route at the given position.
bool interact(bl::ecs::Entity interactor, const bl::tmap::Position &interactPos)
Lets entities interact with the map itself. This is called by the Interaction system.
const std::string & name() const
Returns the name of the map.
bool removeItem(item::Id item, unsigned int qty=1)
Removes the given item from the bag.
void addItem(item::Id item, unsigned int qty=1)
Adds the given item to the bag.
bool setEntityLocked(bl::ecs::Entity entity, bool locked, bool preserve=true)
Set the give entity to be locked or unlocked.
bool resetEntityLock(bl::ecs::Entity entity)
Resets the given entity's lock state to the last remembered value.
void displayMessage(const std::string &message, const Callback &cb=[](const std::string &) {})
Displays a message in the HUD textbox. Messages are queued in order that they arrive.
void promptUser(const std::string &prompt, const std::vector< std::string > &choices, const Callback &cb)
Asks the player a question through the HUD.
void init()
Subscribes to the game event bus.
Interaction(Systems &owner)
Construct a new Interaction system.
bool flagSet(const std::string &flag) const
Checks if the given conversation flag has been set.
bool npcTalkedTo(const std::string &name) const
Returns whether or not the given npc has been talked to.
bool interact(bl::ecs::Entity interactor)
Performs an interation on behalf of the given entity.
bool trainerTalkedto(const std::string &name) const
Returns whether or not the given trainer has been talked to.
void setFlag(const std::string &flag)
Sets the conversation flag.
player::State & state()
Returns the state of the player.
const bl::tmap::Position & position() const
Returns the current position of the player.
bl::ecs::Entity player() const
Returns the id of the player entity.
bl::ecs::Entity search(const bl::tmap::Position &start, bl::tmap::Direction dir, unsigned int range)
Searches for an entity from the starting position in the given direction for the given number of spac...
Owns all primary systems and a reference to the engine.
const bl::engine::Engine & engine() const
Const accessor for the Engine.
Player & player()
Returns the player system.
Position & position()
Returns a reference to the position system.
Controllable & controllable()
Returns the controllable entity system.
HUD & hud()
Returns the HUD.
World & world()
Modifiable accessor for the world system.
map::Map & activeMap()
Returns a reference to the active map.