3 #include <BLIB/Interfaces/Utilities.hpp>
15 using ExitCb = std::function<void()>;
16 using ItemCb = std::function<void(menu::BagItemButton*)>;
18 constexpr
float SlideTime = 0.5f;
20 int lastPosPerTab[4] = {0, 0, 0, 0};
25 const char* tabTitles[4] = {
"Regular Items",
"Peopleballs",
"TM's",
"Key Items"};
26 constexpr
float MenuX = 365.f;
27 constexpr
float MenuY = 30.f;
28 constexpr
float MenuWidth = 319.f;
29 constexpr
float MenuHeight = 385.f;
31 void populateMenu(bl::menu::Menu& menu,
const std::vector<core::player::Bag::Item>& items,
32 const ExitCb& ecb,
const ItemCb& icb,
const ItemCb& dcb,
int ti) {
34 exit->getSignal(bl::menu::Item::Activated).willAlwaysCall(ecb);
35 exit->getSignal(bl::menu::Item::Selected).willAlwaysCall(std::bind(dcb, exit.get()));
36 menu.setRootItem(exit);
37 menu.setMoveFailSound(bl::audio::AudioSystem::InvalidHandle);
39 menu::BagItemButton* b = exit.get();
40 menu::BagItemButton* selectMe = exit.get();
41 int i = items.size() - 1;
42 for (
auto rit = items.rbegin(); rit != items.rend(); ++rit) {
44 nb->getSignal(bl::menu::Item::Activated).willAlwaysCall(std::bind(icb, nb.get()));
45 menu.addItem(nb, b, bl::menu::Item::Top);
47 nb->getSignal(bl::menu::Item::Selected).willAlwaysCall([nbp, i, ti, dcb]() {
48 lastPosPerTab[ti] = i;
53 if (lastPosPerTab[ti] == i) { selectMe = nb.get(); }
56 if (b != exit.get()) { menu.attachExisting(exit.get(), b, bl::menu::Item::Top); }
57 menu.setSelectedItem(selectMe);
74 int outNow,
int* chosenPpl,
bool* up) {
75 return bl::engine::State::Ptr(
new BagMenu(s, c, i, outNow, chosenPpl, up));
80 :
State(s,
bl::engine::StateMask::Menu)
84 , itemPeoplemon(chosenPpl ? chosenPpl : &selectedPeoplemon)
86 , state(MenuState::Browsing)
87 , activeMenu(®ularMenu)
89 actionMenu.create(s.
engine(),
90 s.
engine().renderer().getObserver(),
91 bl::menu::ArrowSelector::create(10.f, sf::Color::Black));
92 actionMenu.setDepth(bl::cam::OverlayCamera::MinDepth);
94 s.
engine(), s.
engine().renderer().getObserver(), bl::menu::NoSelector::create());
96 s.
engine(), s.
engine().renderer().getObserver(), bl::menu::NoSelector::create());
97 keyMenu.create(s.
engine(), s.
engine().renderer().getObserver(), bl::menu::NoSelector::create());
98 tmMenu.create(s.
engine(), s.
engine().renderer().getObserver(), bl::menu::NoSelector::create());
100 bgndTxtr = s.
engine().renderer().texturePool().getOrLoadTexture(
102 background.create(s.
engine(), bgndTxtr);
105 bl::menu::Item::Ptr use =
107 bl::menu::Item::Ptr give =
109 bl::menu::Item::Ptr drop =
111 bl::menu::Item::Ptr back =
114 use->getSignal(bl::menu::Item::Activated)
115 .willAlwaysCall(std::bind(&BagMenu::useItem,
this));
116 give->getSignal(bl::menu::Item::Activated)
117 .willAlwaysCall(std::bind(&BagMenu::giveItem,
this));
118 drop->getSignal(bl::menu::Item::Activated)
119 .willAlwaysCall(std::bind(&BagMenu::dropItem,
this));
120 back->getSignal(bl::menu::Item::Activated)
121 .willAlwaysCall(std::bind(&BagMenu::resetAction,
this));
123 actionMenu.setRootItem(use);
124 actionMenu.addItem(drop, use.get(), bl::menu::Item::Bottom);
125 actionMenu.addItem(back, drop.get(), bl::menu::Item::Right);
126 actionMenu.addItem(give, back.get(), bl::menu::Item::Top);
127 actionMenu.attachExisting(give.get(), use.get(), bl::menu::Item::Right);
130 bl::menu::Item::Ptr use =
132 bl::menu::Item::Ptr back =
135 use->getSignal(bl::menu::Item::Activated)
136 .willAlwaysCall(std::bind(&BagMenu::useItem,
this));
137 back->getSignal(bl::menu::Item::Activated)
138 .willAlwaysCall(std::bind(&BagMenu::resetAction,
this));
140 actionMenu.setRootItem(use);
141 actionMenu.addItem(back, use.get(), bl::menu::Item::Bottom);
143 actionMenu.setPadding({16.f, 4.f});
144 actionMenu.configureBackground(sf::Color::White, sf::Color::Black, 3.f, {14.f, 2.f, 2.f, 2.f});
145 actionMenu.setPosition({252.f, 82.f});
148 pocketLabel.getTransform().setPosition(72.f, 342.f);
149 pocketLabel.setParent(background);
152 description.getTransform().setPosition(98.f, 473.f);
153 description.wordWrap(607.f);
154 description.setParent(background);
156 menuTabs[0] = ®ularMenu;
157 menuTabs[1] = &ballMenu;
158 menuTabs[2] = &tmMenu;
159 menuTabs[3] = &keyMenu;
161 for (
int i = 0; i < 4; ++i) {
162 menuTabs[i]->configureBackground(
163 sf::Color::Transparent, sf::Color::Transparent, 0.f, {0.f, 0.f, 0.f, 0.f});
164 menuTabs[i]->setPosition({MenuX, MenuY});
165 menuTabs[i]->setMaximumSize({-1.f, MenuHeight});
166 menuTabs[i]->setScissor(sf::IntRect(MenuX, MenuY, MenuWidth, MenuHeight));
173 bl::menu::Menu* toDrive =
nullptr;
175 if (state == MenuState::ChoosingGive) {
176 if (*itemPeoplemon >= 0) {
180 removeAndUpdateItem(1);
181 toDrive = activeMenu;
183 else { toDrive = &actionMenu; }
184 state = MenuState::Browsing;
186 else if (state == MenuState::ChoosingItemPeoplemon) {
187 if (*itemPeoplemon >= 0) {
190 if (result) *result = selectedItem->
getItem().
id;
191 state = MenuState::ImmediatelyPop;
195 removeAndUpdateItem(0);
196 state = MenuState::Browsing;
198 toDrive = activeMenu;
201 toDrive = &actionMenu;
202 state = MenuState::Browsing;
208 std::vector<core::player::Bag::Item> items;
209 for (
int i = 0; i < 4; ++i) {
211 populateMenu(*menuTabs[i],
213 std::bind(&BagMenu::exitSelected,
this),
214 std::bind(&BagMenu::itemSelected,
this, std::placeholders::_1),
215 std::bind(&BagMenu::itemHighlighted,
this, std::placeholders::_1),
219 state = MenuState::Browsing;
221 activeMenu = lastTab >= 0 ? menuTabs[lastTab] : ®ularMenu;
222 toDrive = activeMenu;
223 pocketLabel.getSection().setString(tabTitles[lastTab >= 0 ? lastTab : 0]);
224 if (lastTab < 0) lastTab = 0;
227 auto overlay = engine.renderer().getObserver().pushScene<bl::rc::Overlay>();
228 background.addToScene(overlay, bl::rc::UpdateSpeed::Static);
229 pocketLabel.addToScene(overlay, bl::rc::UpdateSpeed::Static);
230 description.addToScene(overlay, bl::rc::UpdateSpeed::Static);
231 actionMenu.addToOverlay(background.entity());
232 actionMenu.setHidden(
true);
233 for (
unsigned int i = 0; i < std::size(menuTabs); ++i) {
234 menuTabs[i]->addToOverlay(background.entity());
235 menuTabs[i]->setHidden(menuTabs[i] != activeMenu);
238 engine.inputSystem().getActor().addListener(*
this);
239 inputDriver.drive(toDrive);
243 engine.renderer().getObserver().popScene();
244 engine.inputSystem().getActor().removeListener(*
this);
249 case MenuState::Sliding: {
250 slideOff += slideVel * dt;
252 const float m = slideVel > 0.f ? -1.f : 1.f;
253 const float x = MenuX + slideOff;
254 const float wf = MenuWidth * m + x;
255 activeMenu->setPosition({wf, MenuY});
256 slideOut->setPosition({x, MenuY});
258 if (std::abs(slideOff) >= activeMenu->getBounds().width) {
259 state = MenuState::Browsing;
260 activeMenu->setPosition({MenuX, MenuY});
261 inputDriver.drive(activeMenu);
262 slideOut->setHidden(
true);
266 case MenuState::ImmediatelyPop:
270 case MenuState::ShowingMessage:
271 case MenuState::Browsing:
277 bool BagMenu::observe(
const bl::input::Actor&,
unsigned int ctrl, bl::input::DispatchType,
279 inputDriver.sendControl(ctrl, fromEvent);
281 if (state == MenuState::Browsing && fromEvent) {
296 lastTab = lastTab > 0 ? lastTab - 1 : 3;
297 activeMenu = menuTabs[lastTab];
298 activeMenu->setHidden(
false);
299 pocketLabel.getSection().setString(tabTitles[lastTab]);
301 dynamic_cast<const menu::BagItemButton*
>(activeMenu->getSelectedItem()));
306 lastTab = lastTab < 3 ? lastTab + 1 : 0;
307 activeMenu = menuTabs[lastTab];
308 activeMenu->setHidden(
false);
309 pocketLabel.getSection().setString(tabTitles[lastTab]);
311 dynamic_cast<const menu::BagItemButton*
>(activeMenu->getSelectedItem()));
323 void BagMenu::itemSelected(
const menu::BagItemButton* but) {
324 selectedItem =
const_cast<menu::BagItemButton*
>(but);
326 actionMenu.setHidden(
false);
327 inputDriver.drive(&actionMenu);
330 void BagMenu::exitSelected() {
systems.
engine().popState(); }
332 void BagMenu::useItem() {
335 state = MenuState::ShowingMessage;
337 std::bind(&BagMenu::messageDone,
this));
343 if (needPickPeoplemon(selectedItem->
getItem().
id, type)) {
344 state = MenuState::ChoosingItemPeoplemon;
355 if (result) *result = selectedItem->
getItem().
id;
356 state = MenuState::ImmediatelyPop;
361 state = MenuState::ShowingMessage;
366 "Use your Penny to use the Transportation Crystal?",
368 std::bind(&BagMenu::keyItemConfirmUse,
this, std::placeholders::_1));
372 std::bind(&BagMenu::messageDone,
this));
378 if (unpause !=
nullptr) { *unpause =
true; }
379 state = MenuState::ImmediatelyPop;
383 "It's not very dark here. Better save the batteries for later.",
384 std::bind(&BagMenu::messageDone,
this));
389 "This will make all trainers hostile again! Are you sure you want to do "
390 "this? This cannot be undone except through violence.",
392 std::bind(&BagMenu::keyItemConfirmUse,
this, std::placeholders::_1));
396 "Blow yourself up and respawn at the last PC Center you visited?",
398 std::bind(&BagMenu::keyItemConfirmUse,
this, std::placeholders::_1));
402 "The Professor's voice rings in your head: \"Not now I'm working!\"");
404 std::bind(&BagMenu::messageDone,
this));
416 std::bind(&BagMenu::messageDone,
this));
420 std::bind(&BagMenu::messageDone,
this));
422 state = MenuState::ShowingMessage;
426 "thing is completely useless! "
427 "What are you expecting to happen bro?\"",
428 std::bind(&BagMenu::messageDone,
this));
429 state = MenuState::ShowingMessage;
433 "The Professor's voice echoes in your head: \"You can't use that here bro\"",
434 std::bind(&BagMenu::messageDone,
this));
435 state = MenuState::ShowingMessage;
442 void BagMenu::giveItem() {
443 state = MenuState::ChoosingGive;
448 void BagMenu::dropItem() {
449 state = MenuState::ShowingMessage;
451 "s should be dropped?",
454 std::bind(&BagMenu::doDrop,
this, std::placeholders::_1));
457 void BagMenu::doDrop(
int qty) {
458 removeAndUpdateItem(qty);
462 void BagMenu::resetAction() {
464 inputDriver.drive(activeMenu);
465 actionMenu.setHidden(
true);
468 void BagMenu::itemHighlighted(
const menu::BagItemButton* but) {
469 const auto i = but->getItem().id;
472 description.getSection().setString(d);
474 else { description.getSection().setString(
"Close the bag"); }
477 void BagMenu::beginSlide(
bool l) {
478 slideOut = activeMenu;
480 slideVel = activeMenu->getBounds().width / SlideTime;
481 if (l) slideVel = -slideVel;
482 inputDriver.drive(
nullptr);
483 state = MenuState::Sliding;
486 void BagMenu::messageDone() {
487 state = MenuState::Browsing;
491 void BagMenu::removeAndUpdateItem(
int qty) {
495 if (it.
qty <= 0) { activeMenu->removeItem(selectedItem); }
496 else { selectedItem->
update(it); }
499 void BagMenu::keyItemConfirmUse(
const std::string& c) {
505 if (unpause !=
nullptr) { *unpause =
true; }
506 state = MenuState::ImmediatelyPop;
511 std::bind(&BagMenu::messageDone,
this));
512 state = MenuState::ShowingMessage;
516 bl::event::Dispatcher::dispatch<core::event::SwitchMapTriggered>(
518 if (unpause !=
nullptr) { *unpause =
true; }
519 state = MenuState::ImmediatelyPop;
523 std::bind(&BagMenu::messageDone,
this));
524 state = MenuState::ShowingMessage;
Type
The type classification of an item. This is used to determine when an item may be used and how to use...
Category
Represents a category that an item can belong to. Used for bag sorting.
Id
Represents an item in its simplist form.
@ EvolveStone
The item is used to evolve peoplemon.
@ Useless
Items who's only use is to be sold.
@ KeyItem
The item is a key item.
@ TargetPeoplemon
The item is used on a peoplemon.
@ PlayerModifier
The item modifiers player state (ie repel)
@ Key
Key items. Covers ids [101, 200].
@ TM
TM's. Covers ids [201, 499].
@ Regular
Regular items. Covers ids [1, 100].
Parent namespace for all functionality unique to the game.
Context
Represents how the menu should be opened.
static std::string getUseLine(Id item, const pplmn::OwnedPeoplemon &ppl)
Returns the text to display when the item is used on the given peoplemon.
static const std::string & getDescription(item::Id item)
Returns the description of the given item.
static void useOnPlayer(Id item, player::State &state)
Uses the given item on the player.
static const std::string & getName(item::Id item)
Returns the name of the given item.
static bool canUseInBattle(Id item)
Returns whether or not the item can be used in battle.
static Type getType(Id item)
Returns the type of the given item.
static bool hasEffectOnPlayer(Id item, const player::State &state)
Returns whether or not the given item will affect the player.
bool lightsAreOn() const
Returns whether lights are being shown or not based on how dark it is.
LightingSystem & lightingSystem()
Returns a reference to the lighting system in this map.
void getByCategory(item::Category category, std::vector< Item > &result) const
Returns the set of owned items in the given category.
bool removeItem(item::Id item, unsigned int qty=1)
Removes the given item from the bag.
unsigned int itemCount(item::Id item) const
Returns the number of the given item owned.
bool hasItem(item::Id item) const
Returns true if at least one of the given items is owned.
Simple struct representing a set of items in the bag.
item::Id id
The item in the bag.
unsigned int qty
How many of the item are in the bag.
std::vector< pplmn::OwnedPeoplemon > peoplemon
static const sf::VulkanFont & MenuFont()
static bl::audio::AudioSystem::Handle MenuBackSound()
static const std::string & MenuImagePath()
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 getQty(const std::string &prompt, int minQty, int maxQty, const QtyCallback &cb)
Gets a number from the player.
void promptUser(const std::string &prompt, const std::vector< std::string > &choices, const Callback &cb)
Asks the player a question through the HUD.
void showLantern()
Creates a light for the player's lantern. Keeps it updated as well.
player::State & state()
Returns the state of the player.
void whiteout()
Heals all Peoplemon and respawns at the last PC center.
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.
Trainers & trainers()
Returns the trainer system.
HUD & hud()
Returns the HUD.
World & world()
Modifiable accessor for the world system.
void resetDefeated()
Resets the list of defeated trainers.
map::Map & activeMap()
Returns a reference to the active map.
void update(const core::player::Bag::Item &item)
Updates the text labels from the given item.
const core::player::Bag::Item & getItem() const
Returns the item this button is representing.
std::shared_ptr< BagItemButton > Ptr
Pointer to the menu item.
static Ptr create(const core::player::Bag::Item &item)
Creates a new item button.
State for displaying the player's inventory and selecting items.
static bl::engine::State::Ptr create(core::system::Systems &systems, Context ctx, core::item::Id *result=nullptr, int outNow=-1, int *chosenPeoplemon=nullptr, bool *unpause=nullptr)
Creates a new BagMenu.
virtual void activate(bl::engine::Engine &) override
Populates the menu with the player's inventory.
virtual const char * name() const override
Returns "BagMenu".
virtual void update(bl::engine::Engine &, float dt, float) override
Updates the menu.
virtual void deactivate(bl::engine::Engine &) override
Unsubscribes from event and input buses.
static bl::engine::State::Ptr create(core::system::Systems &systems, Context ctx, int outNow=-1, int *chosen=nullptr, core::item::Id item=core::item::Id::None)
Creates a new PeoplemonMenu state.
Parent to all game states. Provides some commonly required data like core game systems.
core::system::Systems & systems