Peoplemon  0.1.0
Peoplemon 3 game source documentation
Trainers.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Audio/AudioSystem.hpp>
5 #include <Core/Properties.hpp>
6 #include <Core/Resources.hpp>
8 
9 namespace core
10 {
11 namespace system
12 {
13 namespace
14 {
15 constexpr float HoldTime = 0.75f;
16 constexpr float RevealRate = 60.f;
17 
18 std::string trainerKey(const component::Trainer& t) { return t.file() + ":" + t.name(); }
19 } // namespace
20 
22 : owner(o)
23 , trainerPool(o.engine().ecs().getAllComponents<component::Trainer>())
24 , state(State::Searching)
25 , walkingTrainer(bl::ecs::InvalidEntity) {}
26 
27 void Trainers::init(bl::engine::Engine& engine) {
28  exclaimTxtr = engine.renderer().texturePool().getOrLoadTexture(
30  engine.renderer().vulkanState().samplerCache.noFilterBorderClamped());
31  exclaim.create(engine, exclaimTxtr);
32  exclaim.getTransform().setDepth(-0.5f); // just above parent
33  engine.ecs().setEntityParentDestructionBehavior(
34  exclaim.entity(), bl::ecs::ParentDestructionBehavior::OrphanedByParent);
35 
36  exclaimSound = bl::audio::AudioSystem::getOrLoadSound(Properties::TrainerExclaimSound());
37 
38  bl::event::Dispatcher::subscribe(this);
39 }
40 
41 void Trainers::update(std::mutex&, float dt, float, float, float) {
42  const auto updateRect = [this](float h) {
43  exclaim.setTextureSource({0, 0.f, exclaimTxtr->size().x, h});
44  exclaim.scaleToSize({exclaimTxtr->size().x, h});
45  exclaim.getTransform().setPosition(exclaim.getTransform().getLocalPosition().x, -h - 12.f);
46  };
47 
48  switch (state) {
49  case State::PoppingUp:
50  height += dt * RevealRate;
51  if (height >= exclaimTxtr->size().y) {
52  updateRect(exclaimTxtr->size().y);
53  state = State::Holding;
54  height = 0.f;
55  }
56  else { updateRect(height); }
57  break;
58 
59  case State::Holding:
60  height += dt;
61  if (height >= HoldTime) {
62  height = exclaimTxtr->size().y;
63  state = State::Rising;
64  }
65  break;
66 
67  case State::Rising:
68  height -= dt * RevealRate;
69  if (height > 0.f) { updateRect(height); }
70  else {
71  updateRect(0);
72  state = State::Walking;
73  exclaim.removeFromScene();
74  }
75  break;
76 
77  case State::Walking:
78  if (!trainerMove->moving()) {
79  if (bl::tmap::Position::adjacent(*trainerPos, owner.player().position())) {
80  if (!owner.interaction().interact(walkingTrainer)) {
81  BL_LOG_ERROR << "Trainer " << walkingTrainer
82  << " was unable to interact with player, aborting";
83  cleanup();
84  }
85  else { state = State::Battling; }
86  }
87  else {
88  if (!owner.movement().moveEntity(walkingTrainer, trainerPos->direction, false)) {
89  BL_LOG_ERROR << "Trainer " << walkingTrainer
90  << " is unable to get to the player, aborting";
91  owner.controllable().setEntityLocked(owner.player().player(), false);
92  cleanup();
93  }
94  }
95  }
96  break;
97 
98  case State::Searching:
99  case State::Battling:
100  default:
101  break;
102  }
103 }
104 
105 bl::ecs::Entity Trainers::approachingTrainer() const { return walkingTrainer; }
106 
108  return defeated.find(trainerKey(t)) != defeated.end();
109 }
110 
112  t.setDefeated();
113  defeated.emplace(trainerKey(t));
114 }
115 
116 void Trainers::observe(const event::GameSaveInitializing& save) {
117  save.gameSave.trainers.defeated = &defeated;
118 }
119 
120 void Trainers::observe(const bl::ecs::event::ComponentAdded<component::Trainer>& tc) {
121  if (trainerDefeated(tc.component)) {
122  component::Trainer& t = const_cast<component::Trainer&>(tc.component);
123  t.setDefeated();
124  }
125 }
126 
127 void Trainers::observe(const event::BattleCompleted& b) {
128  if (b.type == battle::Battle::Type::Trainer && b.result.localPlayerWon) {
129  setDefeated(*trainerComponent);
130  }
131  cleanup();
132 }
133 
134 void Trainers::observe(const event::EntityRotated& rot) {
135  if (walkingTrainer == bl::ecs::InvalidEntity) {
136  component::Trainer* trainer = trainerPool.get(rot.entity);
137  if (trainer) { checkTrainer(rot.entity, *trainer); }
138  }
139 }
140 
141 void Trainers::observe(const event::EntityMoveFinished& moved) {
142  if (walkingTrainer != bl::ecs::InvalidEntity) return;
143 
144  if (moved.entity == owner.player().player()) {
145  trainerPool.forEach([this](bl::ecs::Entity ent, component::Trainer& trainer) {
146  checkTrainer(ent, trainer);
147  });
148  }
149  else {
150  component::Trainer* trainer = trainerPool.get(moved.entity);
151  if (trainer) { checkTrainer(moved.entity, *trainer); }
152  }
153 }
154 
155 void Trainers::checkTrainer(bl::ecs::Entity ent, component::Trainer& trainer) {
156  if (trainer.defeated()) return;
157  if (owner.flight().flying()) return;
158  // TODO - respect player/trainer locks?
159  const bl::tmap::Position* pos = owner.engine().ecs().getComponent<bl::tmap::Position>(ent);
160  if (!pos) {
161  BL_LOG_ERROR << "Encountered trainer " << ent << " with no position";
162  return;
163  }
164  component::Movable* move = owner.engine().ecs().getComponent<component::Movable>(ent);
165  if (!move) {
166  BL_LOG_ERROR << "Encountered trainer " << ent << " with no movable";
167  return;
168  }
169 
170  const bl::ecs::Entity see = owner.position().search(*pos, pos->direction, trainer.range());
171  if (see == owner.player().player()) {
172  BL_LOG_INFO << "Trainer " << ent << "(" << trainer.name() << " | " << trainer.file()
173  << ") sees player";
174  owner.ai().removeAi(ent);
175  walkingTrainer = ent;
176  trainerComponent = &trainer;
177  trainerPos = pos;
178  trainerMove = move;
179  owner.controllable().setEntityLocked(owner.player().player(), true);
180 
181  bl::audio::AudioSystem::playSound(exclaimSound);
182  state = State::PoppingUp;
183  height = 0.f;
184  exclaim.setTextureSource({0.f, 0.f, 0.f, 0.f});
185  static const float xoff =
186  static_cast<float>(Properties::PixelsPerTile()) * 0.5f - exclaimTxtr->size().x * 0.5f;
187  exclaim.setParent(ent);
188  exclaim.getTransform().setPosition(xoff, -static_cast<float>(Properties::PixelsPerTile()));
189  exclaim.addToScene(owner.world().activeMap().getScene(), bl::rc::UpdateSpeed::Dynamic);
190  }
191 }
192 
193 void Trainers::cleanup() {
194  state = State::Searching;
195  walkingTrainer = bl::ecs::InvalidEntity;
196  trainerComponent = nullptr;
197  trainerMove = nullptr;
198 }
199 
200 void Trainers::resetDefeated() { defeated.clear(); }
201 
202 } // namespace system
203 } // namespace core
Core classes and functionality for both the editor and game.
Collection of data classes that provide saving and loading of different game file formats.
Definition: GameSave.hpp:10
bool moving() const
Returns whether or not the entity is moving.
Definition: Movable.cpp:43
Adding this to an entity will make it a trainer that can battle.
Definition: Trainer.hpp:18
void setDefeated()
Marks this trainer as defeated.
Definition: Trainer.cpp:59
Fired when the game is saving or loading. Allows systems to hook in their data.
Definition: GameSave.hpp:22
file::GameSave & gameSave
Game save being initialized.
Definition: GameSave.hpp:24
struct core::file::GameSave::TrainerPointers trainers
std::unordered_set< std::string > * defeated
Definition: GameSave.hpp:73
bl::rc::SceneRef getScene()
Returns the scene for this map.
Definition: Map.hpp:280
static int PixelsPerTile()
Definition: Properties.cpp:279
static const std::string & TrainerExclaimSound()
Definition: Properties.cpp:690
static const std::string & TrainerExclaimImage()
Definition: Properties.cpp:684
void removeAi(bl::ecs::Entity ent)
Removes any ai behavior from the given entity. Does not affect path finding.
Definition: AI.cpp:178
bool setEntityLocked(bl::ecs::Entity entity, bool locked, bool preserve=true)
Set the give entity to be locked or unlocked.
bool flying() const
Returns whether or not the player is currently flying.
Definition: Flight.cpp:48
bool interact(bl::ecs::Entity interactor)
Performs an interation on behalf of the given entity.
Definition: Interaction.cpp:35
bool moveEntity(bl::ecs::Entity entity, bl::tmap::Direction direction, bool fast)
Moves an entity in the given direction using either its fast or slow speed.
Definition: Movement.cpp:27
const bl::tmap::Position & position() const
Returns the current position of the player.
Definition: Player.cpp:57
bl::ecs::Entity player() const
Returns the id of the player entity.
Definition: Player.cpp:55
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...
Definition: Position.cpp:39
Owns all primary systems and a reference to the engine.
Definition: Systems.hpp:47
const bl::engine::Engine & engine() const
Const accessor for the Engine.
Definition: Systems.cpp:35
AI & ai()
Returns the AI system.
Definition: Systems.cpp:65
Movement & movement()
Returns a reference to the movement system.
Definition: Systems.cpp:51
Player & player()
Returns the player system.
Definition: Systems.cpp:59
Flight & flight()
Returns the flight system.
Definition: Systems.cpp:83
Position & position()
Returns a reference to the position system.
Definition: Systems.cpp:47
Controllable & controllable()
Returns the controllable entity system.
Definition: Systems.cpp:63
World & world()
Modifiable accessor for the world system.
Definition: Systems.cpp:43
Interaction & interaction()
Returns the interaction system.
Definition: Systems.cpp:67
void resetDefeated()
Resets the list of defeated trainers.
Definition: Trainers.cpp:200
bl::ecs::Entity approachingTrainer() const
Returns the trainer currently approaching the player.
Definition: Trainers.cpp:105
bool trainerDefeated(const component::Trainer &trainer) const
Checks whether or not the given trainer has been defeated.
Definition: Trainers.cpp:107
void setDefeated(component::Trainer &trainer)
Sets the given trainer as having been defeated and updates the game save data.
Definition: Trainers.cpp:111
Trainers(Systems &owner)
Construct a new Trainers system.
Definition: Trainers.cpp:21
map::Map & activeMap()
Returns a reference to the active map.
Definition: World.cpp:84