3 #include <BLIB/Util/Random.hpp>
14 const sf::Vector2f QtyPosition{293.f, 399.f};
15 constexpr
float DingTime = 0.6f;
18 const std::string catTexts[3] = {
"Regular Items",
"Peopleballs",
"TM's"};
21 using menu::StoreItemRow;
29 return bl::engine::State::Ptr(
new StoreMenu(systems, data));
33 :
State(systems,
bl::engine::StateMask::Menu)
34 , menuState(MenuState::GetAction)
35 , qtyEntry(systems.engine()) {
36 bgndTxtr =
systems.
engine().renderer().texturePool().getOrLoadTexture(
40 dingSound = bl::audio::AudioSystem::getOrLoadSound(
43 if (data.
items.empty()) {
45 <<
"Received no item list, selling all regular items and Peopleballs at normal price";
55 items.reserve(data.
items.size());
56 for (
const auto& item : data.
items) { items.emplace_back(item.first, item.second); }
61 bl::menu::ArrowSelector::create(14.f, sf::Color::Black));
64 bl::menu::ArrowSelector::create(8.f, sf::Color::Black));
65 for (
auto& sellMenu : sellMenus) {
68 bl::menu::ArrowSelector::create(8.f, sf::Color::Black));
72 boxText.wordWrap(260.f);
73 boxText.getTransform().setPosition(28.f, 408.f);
74 boxText.setParent(background);
76 moneyText.getTransform().setPosition(605.f, 15.f);
77 moneyText.setParent(background);
79 actionText.getTransform().setPosition(378.f, 67.f);
80 actionText.setParent(background);
82 catText.setParent(background);
84 leftArrow.create(
systems.
engine(), {0.f, 13.f}, {15.f, 0.f}, {15.f, 26.f});
85 rightArrow.create(
systems.
engine(), {0.f, 0.f}, {0.f, 26.f}, {15.f, 13.f});
86 leftArrow.setFillColor(sf::Color::Black);
87 rightArrow.setFillColor(sf::Color::Black);
88 rightArrow.getTransform().setPosition(730.f, 73.f);
89 leftArrow.setParent(background);
90 rightArrow.setParent(background);
92 bl::menu::TextItem::Ptr buyItem =
94 bl::menu::TextItem::Ptr sellItem =
96 bl::menu::TextItem::Ptr closeItem =
98 buyItem->getSignal(bl::menu::Item::Activated)
99 .willAlwaysCall(std::bind(&StoreMenu::enterState,
this, MenuState::BuyMenu));
100 sellItem->getSignal(bl::menu::Item::Activated)
101 .willAlwaysCall(std::bind(&StoreMenu::enterState,
this, MenuState::SellMenu));
102 closeItem->getSignal(bl::menu::Item::Activated)
103 .willAlwaysCall(std::bind(&StoreMenu::close,
this));
104 actionMenu.setRootItem(buyItem);
105 actionMenu.addItem(sellItem, buyItem.get(), bl::menu::Item::Bottom);
106 actionMenu.addItem(closeItem, sellItem.get(), bl::menu::Item::Bottom);
107 actionMenu.setSelectedItem(buyItem.get());
108 actionMenu.configureBackground(sf::Color::White, sf::Color::Black, 2.f, {18.f, 2.f, 4.f, 4.f});
109 actionMenu.setPosition({20.f, 230.f});
111 buyMenu.setPosition({378.f, 140.f});
112 buyMenu.setMaximumSize({500.f, 420.f});
113 for (
int i = 0; i < 3; ++i) {
114 sellMenus[i].setPosition({378.f, 140.f});
115 sellMenus[i].setMaximumSize({500.f, 420.f});
119 for (
const auto& p : data.
sellPrices) { sellPrices.emplace(p.first, p.second); }
126 BL_LOG_ERROR <<
"Nothing is for sale asshole";
132 auto overlay = engine.renderer().getObserver().pushScene<bl::rc::Overlay>();
133 background.addToScene(overlay, bl::rc::UpdateSpeed::Static);
134 actionMenu.addToOverlay(background.entity());
135 buyMenu.addToOverlay(background.entity());
136 for (
auto& sellMenu : sellMenus) { sellMenu.addToOverlay(background.entity()); }
137 actionText.addToScene(overlay, bl::rc::UpdateSpeed::Static);
138 boxText.addToScene(overlay, bl::rc::UpdateSpeed::Static);
139 moneyText.addToScene(overlay, bl::rc::UpdateSpeed::Static);
140 catText.addToScene(overlay, bl::rc::UpdateSpeed::Static);
141 leftArrow.addToScene(overlay, bl::rc::UpdateSpeed::Static);
142 rightArrow.addToScene(overlay, bl::rc::UpdateSpeed::Static);
145 bl::menu::Item::Ptr root = makeItemRow(items.front().item, items.front().price, 0);
146 buyMenu.setRootItem(root);
147 bl::menu::Item* prev = root.get();
148 for (
unsigned int i = 1; i < items.size(); ++i) {
149 bl::menu::Item::Ptr row = makeItemRow(items[i].item, items[i].price, i);
150 buyMenu.addItem(row, prev, bl::menu::Item::Bottom);
153 buyMenu.addItem(makeCloseItem(), prev, bl::menu::Item::Bottom);
155 std::vector<core::player::Bag::Item> playerItems;
156 for (
int i = 0; i < 3; ++i) {
158 if (!playerItems.empty()) {
159 bl::menu::Item::Ptr root =
160 makeSellItemRow(playerItems.front().id, playerItems.front().qty);
161 sellMenus[i].setRootItem(root);
163 for (
unsigned int j = 1; j < playerItems.size(); ++j) {
164 bl::menu::Item::Ptr row = makeSellItemRow(playerItems[j].
id, playerItems[j].qty);
165 sellMenus[i].addItem(row, prev, bl::menu::Item::Bottom);
168 sellMenus[i].addItem(makeCloseItem(), prev, bl::menu::Item::Bottom);
170 else { sellMenus[i].setRootItem(makeCloseItem()); }
177 enterState(MenuState::GetAction);
179 renderMenu = &buyMenu;
180 systems.
engine().inputSystem().getActor().addListener(*
this);
185 if (bl::util::Random::get<int>(0, 100) <= 5) {
187 int cheapestPrice = std::numeric_limits<int>::max();
188 for (
const auto item : items) {
189 if (item.price < cheapestPrice) {
190 cheapestPrice = item.price;
191 cheapest = item.item;
198 enterState(MenuState::ImpulseBuyMessage);
199 setBoxText(ppl.name() +
" made an Impulse Buy and purchased a " +
209 engine.renderer().getObserver().popScene();
210 systems.
engine().inputSystem().getActor().removeListener(*
this);
211 bl::event::Dispatcher::dispatch<core::event::StoreClosed>({});
218 case MenuState::BuyDing:
219 case MenuState::SellDing:
220 case MenuState::TooPoorDing:
221 if (dingTime >= DingTime) {
222 enterState(menuState == MenuState::SellDing ? MenuState::SellMenu : MenuState::BuyMenu);
225 case MenuState::ImpulseBuyMessage:
226 if (dingTime >= DingTime * 2.3f) { enterState(MenuState::GetAction); }
233 void StoreMenu::enterState(MenuState newState) {
234 menuState = newState;
237 buyMenu.setHidden(
true);
238 for (
auto& sellMenu : sellMenus) { sellMenu.setHidden(
true); }
240 catText.setHidden(
true);
241 rightArrow.setHidden(
true);
242 leftArrow.setHidden(
true);
244 const auto unhideSellItems = [
this]() {
245 catText.setHidden(
false);
246 rightArrow.setHidden(
false);
247 leftArrow.setHidden(
false);
251 case MenuState::GetAction:
252 setBoxText(
"Would you like to buy or sell?");
255 case MenuState::BuyMenu:
256 renderMenu = &buyMenu;
257 setBoxText(
"What would you like to buy?");
258 actionText.getSection().setFillColor(sf::Color(20, 60, 240));
259 actionText.getSection().setString(
"Buying");
262 case MenuState::SellMenu:
263 renderMenu = &sellMenus[curCat];
264 setBoxText(
"What can I take off your hands?");
265 actionText.getSection().setFillColor(sf::Color(240, 60, 20));
266 actionText.getSection().setString(
"Selling");
270 case MenuState::BuyQty:
273 setBoxText(
"How many would you like to buy?");
276 case MenuState::SellQty:
279 setBoxText(
"How many would you like to sell?");
283 case MenuState::TooPoorDing:
284 setBoxText(
"You're too poor!");
287 case MenuState::SellDing:
288 case MenuState::BuyDing:
289 case MenuState::ImpulseBuyMessage:
290 bl::audio::AudioSystem::playOrRestartSound(dingSound);
293 if (newState == MenuState::SellDing) { unhideSellItems(); }
300 renderMenu->setHidden(
false);
303 void StoreMenu::setBoxText(
const std::string& t) { boxText.getSection().setString(t); }
305 void StoreMenu::setMoneyText() {
311 bool StoreMenu::observe(
const bl::input::Actor&,
unsigned int control, bl::input::DispatchType,
312 bool eventTriggered) {
314 if (!eventTriggered)
return true;
317 case MenuState::GetAction:
320 case MenuState::BuyMenu:
321 case MenuState::SellMenu:
322 enterState(MenuState::GetAction);
324 case MenuState::SellQty:
325 enterState(MenuState::SellMenu);
327 case MenuState::BuyQty:
328 enterState(MenuState::BuyMenu);
336 bl::menu::Menu* sendTo =
nullptr;
338 case MenuState::GetAction:
339 sendTo = &actionMenu;
341 case MenuState::BuyMenu:
344 case MenuState::SellMenu:
353 sendTo = &sellMenus[curCat];
357 case MenuState::BuyQty:
358 case MenuState::SellQty:
361 qtyEntry.
up(1, eventTriggered);
364 qtyEntry.
up(10, eventTriggered);
367 qtyEntry.
down(1, eventTriggered);
370 qtyEntry.
down(10, eventTriggered);
373 if (menuState == MenuState::BuyQty) {
374 const int qty = qtyEntry.
curQty();
378 enterState(MenuState::BuyDing);
380 else { enterState(MenuState::BuyMenu); }
383 const int qty = qtyEntry.
curQty();
389 if (newQty > 0) { sellingItem->
updateQty(newQty); }
390 else { sellMenus[curCat].removeItem(sellingItem); }
391 enterState(MenuState::SellDing);
393 else { enterState(MenuState::SellMenu); }
403 if (sendTo !=
nullptr && dingTime >= DingTime) {
404 inputDriver.drive(sendTo);
405 inputDriver.sendControl(control, eventTriggered);
411 bl::menu::Item::Ptr StoreMenu::makeItemRow(
core::item::Id item,
int price,
unsigned int i) {
413 row->getSignal(bl::menu::Item::Activated)
414 .willAlwaysCall(std::bind(&StoreMenu::selectBuyItem,
this, i));
418 bl::menu::Item::Ptr StoreMenu::makeSellItemRow(
core::item::Id item,
int qty) {
420 row->getSignal(bl::menu::Item::Activated)
421 .willAlwaysCall(std::bind(&StoreMenu::selectSellItem,
this, row.get()));
425 bl::menu::Item::Ptr StoreMenu::makeCloseItem() {
426 bl::menu::TextItem::Ptr ci =
428 ci->getSignal(bl::menu::Item::Activated).willAlwaysCall(std::bind(&StoreMenu::closeMenu,
this));
432 void StoreMenu::selectBuyItem(
unsigned int i) {
435 MenuState::TooPoorDing);
438 void StoreMenu::closeMenu() { enterState(MenuState::GetAction); }
440 void StoreMenu::selectSellItem(StoreItemRow* row) {
442 enterState(MenuState::SellQty);
445 void StoreMenu::catRight() {
446 if (dingTime >= DingTime) {
448 curCat = (curCat + 1) % 3;
454 void StoreMenu::catLeft() {
455 if (dingTime >= DingTime) {
457 curCat = curCat > 0 ? curCat - 1 : 2;
463 void StoreMenu::catSync() {
464 catText.getSection().setString(catTexts[curCat]);
465 catText.getTransform().setPosition(745.f - catText.getGlobalSize().x -
466 rightArrow.getGlobalSize().x - 9.f,
467 actionText.getTransform().getGlobalPosition().y);
468 leftArrow.getTransform().setPosition(catText.getTransform().getGlobalPosition().x -
469 leftArrow.getGlobalSize().x - 3.f,
470 rightArrow.getTransform().getGlobalPosition().y);
471 renderMenu = &sellMenus[curCat];
475 const auto it = sellPrices.find(item);
Category
Represents a category that an item can belong to. Used for bag sorting.
Id
Represents an item in its simplist form.
@ TM
TM's. Covers ids [201, 499].
@ Regular
Regular items. Covers ids [1, 100].
Parent namespace for all functionality unique to the game.
Event that is fired by the Core module to signal to the game to open a store.
const std::vector< std::pair< item::Id, int > > & items
const std::vector< std::pair< item::Id, int > > & sellPrices
static Category getCategory(Id item)
Returns the category of the given item.
static const std::string & getName(item::Id item)
Returns the name of the given item.
static const std::vector< Id > & validIds()
Returns the list of valid item ids.
static int getValue(item::Id item)
Returns the value of the given item.
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.
void addItem(item::Id item, unsigned int qty=1)
Adds the given item to the bag.
unsigned int itemCount(item::Id item) const
Returns the number of the given item owned.
std::vector< pplmn::OwnedPeoplemon > peoplemon
static const sf::VulkanFont & MenuFont()
static const std::string & SoundPath()
static bl::audio::AudioSystem::Handle MenuMoveSound()
static const std::string & MenuImagePath()
void configure(int minQty, int maxQty, int qty)
Configures the entry with the given parameters and adds to the overlay.
void setPosition(const sf::Vector2f &position)
Sets the position of the selector.
void up(int q, bool ignoreDebounce)
Increments the qty up.
void down(int q, bool ignoreDebounce)
Decrements the qty down.
sf::Vector2f getSize() const
Returns the size of the entry in pixels.
void hide()
Removes the quantity entry from the overlay.
int curQty() const
Returns the currently selected qty.
player::State & state()
Returns the state of the player.
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.
void updateQty(int qty)
Updates the text for how many items can be sold.
core::item::Id getItem() const
Returns the item that this row represents.
static Ptr create(int qty, core::item::Id item, int price)
Creates a new menu item in sell mode.
std::shared_ptr< StoreItemRow > Ptr
Pointer to the menu item.
Parent to all game states. Provides some commonly required data like core game systems.
core::system::Systems & systems
State that renders and implements a store menu to buy and sell items.
virtual void activate(bl::engine::Engine &engine) override
Subscribes to event buses.
virtual void deactivate(bl::engine::Engine &engine) override
Unsubscribes from event buses.
virtual void update(bl::engine::Engine &engine, float dt, float) override
Updates the store menu.
virtual const char * name() const override
Returns "StoreMenu".