Traveling Merchant Purchase Window and systems implemented.

pull/28/head
sigonasr2 11 months ago
parent 71fe49162d
commit eae8239501
  1. 42
      Crawler/BuyItemWindow.cpp
  2. 2
      Crawler/Crawler.cpp
  3. 10
      Crawler/Crawler.vcxproj
  4. 24
      Crawler/Crawler.vcxproj.filters
  5. 7
      Crawler/InventoryWindow.cpp
  6. 6
      Crawler/Menu.cpp
  7. 12
      Crawler/MenuComponent.cpp
  8. 3
      Crawler/MenuComponent.h
  9. 3
      Crawler/MenuItemButton.h
  10. 3
      Crawler/MenuItemItemButton.h
  11. 7
      Crawler/MenuLabel.h
  12. 25
      Crawler/MerchantWindow.cpp
  13. 1
      Crawler/MonsterAttribute.h
  14. 9
      Crawler/Player.cpp
  15. 3
      Crawler/Player.h
  16. 62
      Crawler/PlayerMoneyLabel.h
  17. 2
      Crawler/RowItemDisplay.h
  18. 2
      Crawler/Version.h
  19. 14
      Crawler/assets/config/shops/Chapter 1 Merchants.txt

@ -39,10 +39,52 @@ All rights reserved.
#include "Menu.h" #include "Menu.h"
#include "MenuLabel.h" #include "MenuLabel.h"
using A=Attribute;
void Menu::InitializeBuyItemWindow(){ void Menu::InitializeBuyItemWindow(){
Menu*buyItemWindow=CreateMenu(BUY_ITEM,CENTERED,{192,72}); Menu*buyItemWindow=CreateMenu(BUY_ITEM,CENTERED,{192,72});
static auto GetQuantity = [&](){
return std::stoi(Component<MenuLabel>(BUY_ITEM,"Amount to buy Amount Label")->GetLabel());
};
static auto UpdateMenu = [&](int32_t qty){
qty=std::clamp(qty,1,99);
int pricePerItem=std::stoi(Component<MenuLabel>(BUY_ITEM,"Price per item Amount Label")->GetLabel());
Component<MenuLabel>(BUY_ITEM,"Amount to buy Amount Label")->SetLabel(std::to_string(qty));
Component<MenuLabel>(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(qty*pricePerItem));
Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
const std::string&item=Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->GetString(A::ITEM_NAME);
Component<MenuComponent>(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item,GetQuantity()));
};
buyItemWindow->ADD("Item Purchase Header",MenuLabel)({{2,2},{188,12}},"Buying ",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; buyItemWindow->ADD("Item Purchase Header",MenuLabel)({{2,2},{188,12}},"Buying ",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END;
buyItemWindow->ADD("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
buyItemWindow->ADD("Amount to Buy Label",MenuLabel)({{4,34},{188,12}},"Amount to Buy",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
buyItemWindow->ADD("Price Label",MenuLabel)({{4,50},{188,12}},"Total Cost",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
buyItemWindow->ADD("Price per item Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END;
buyItemWindow->ADD("Amount to buy Amount Label",MenuLabel)({{buyItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END;
buyItemWindow->ADD("Increase buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){
UpdateMenu(GetQuantity()+1);
return true;
})END;
buyItemWindow->ADD("Decrease buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){
UpdateMenu(GetQuantity()-1);
return true;
})END;
buyItemWindow->ADD("Total Price Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END;
buyItemWindow->ADD("Purchase Button",MenuComponent)({{buyItemWindow->size.x/2+18,70},{64,12}},"Purchase",[&](MenuFuncData data){
Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
const std::string&item=Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->GetString(A::ITEM_NAME);
merchant.PurchaseItem(item,GetQuantity());
Menu::CloseMenu();
return true;
})END;
buyItemWindow->ADD("Cancel Button",MenuComponent)({{buyItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){
Menu::CloseMenu();
return true;
})END;
} }

@ -1739,6 +1739,7 @@ void Crawler::ChangePlayerClass(Class cl){
Ability itemAbility2=player->useItem2; Ability itemAbility2=player->useItem2;
Ability itemAbility3=player->useItem3; Ability itemAbility3=player->useItem3;
uint32_t oldMoney=player->money; uint32_t oldMoney=player->money;
std::set<MenuComponent*>moneyListeners=Player::moneyListeners;
switch(cl){ switch(cl){
case WARRIOR:{ case WARRIOR:{
player.reset(NEW Warrior(player.get())); player.reset(NEW Warrior(player.get()));
@ -1771,6 +1772,7 @@ void Crawler::ChangePlayerClass(Class cl){
GetPlayer()->SetItem2UseFunc(itemAbility2); GetPlayer()->SetItem2UseFunc(itemAbility2);
GetPlayer()->SetItem3UseFunc(itemAbility3); GetPlayer()->SetItem3UseFunc(itemAbility3);
camera.SetTarget(player->GetPos()); camera.SetTarget(player->GetPos());
Player::moneyListeners=moneyListeners;
} }
void Crawler::InitializeClasses(){ void Crawler::InitializeClasses(){

@ -342,6 +342,10 @@
</SubType> </SubType>
</ClInclude> </ClInclude>
<ClInclude Include="GameState.h" /> <ClInclude Include="GameState.h" />
<ClInclude Include="PlayerMoneyLabel.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="Item.h" /> <ClInclude Include="Item.h" />
<ClInclude Include="ItemDrop.h"> <ClInclude Include="ItemDrop.h">
<SubType> <SubType>
@ -568,6 +572,12 @@
<Text Include="assets\config\Monsters.txt" /> <Text Include="assets\config\Monsters.txt" />
<Text Include="assets\config\MonsterStrategies.txt" /> <Text Include="assets\config\MonsterStrategies.txt" />
<Text Include="assets\config\Player.txt" /> <Text Include="assets\config\Player.txt" />
<Text Include="assets\config\shops\Chapter 1 Merchants.txt" />
<Text Include="assets\config\shops\Chapter 2 Merchants.txt" />
<Text Include="assets\config\shops\Chapter 3 Merchants.txt" />
<Text Include="assets\config\shops\Chapter 4 Merchants.txt" />
<Text Include="assets\config\shops\Chapter 5 Merchants.txt" />
<Text Include="assets\config\shops\Chapter 6 Merchants.txt" />
<Text Include="assets\config\story\Chapter 1.txt" /> <Text Include="assets\config\story\Chapter 1.txt" />
<Text Include="Crawler_Story_Chapter_1 (2).txt" /> <Text Include="Crawler_Story_Chapter_1 (2).txt" />
<Text Include="Crawler_System_Overview.txt" /> <Text Include="Crawler_System_Overview.txt" />

@ -79,6 +79,9 @@
<Filter Include="Source Files\discord-files"> <Filter Include="Source Files\discord-files">
<UniqueIdentifier>{8911e0bb-703c-4a2b-b3dd-259192956733}</UniqueIdentifier> <UniqueIdentifier>{8911e0bb-703c-4a2b-b3dd-259192956733}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Configurations\Item Merchants">
<UniqueIdentifier>{8423ea80-23c9-48cb-a506-6b3bdfa8000e}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="olcPixelGameEngine.h"> <ClInclude Include="olcPixelGameEngine.h">
@ -372,6 +375,9 @@
<ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h"> <ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h">
<Filter>Header Files\Interface</Filter> <Filter>Header Files\Interface</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="PlayerMoneyLabel.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Player.cpp"> <ClCompile Include="Player.cpp">
@ -698,6 +704,24 @@
<Text Include="assets\config\items\ItemSets.txt"> <Text Include="assets\config\items\ItemSets.txt">
<Filter>Configurations\Items</Filter> <Filter>Configurations\Items</Filter>
</Text> </Text>
<Text Include="assets\config\shops\Chapter 1 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
<Text Include="assets\config\shops\Chapter 2 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
<Text Include="assets\config\shops\Chapter 3 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
<Text Include="assets\config\shops\Chapter 4 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
<Text Include="assets\config\shops\Chapter 5 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
<Text Include="assets\config\shops\Chapter 6 Merchants.txt">
<Filter>Configurations\Item Merchants</Filter>
</Text>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="assets\heart.ico"> <Image Include="assets\heart.ico">

@ -44,6 +44,7 @@ All rights reserved.
#include "MenuItemButton.h" #include "MenuItemButton.h"
#include "MenuItemItemButton.h" #include "MenuItemItemButton.h"
#include "RowItemDisplay.h" #include "RowItemDisplay.h"
#include "PlayerMoneyLabel.h"
INCLUDE_game INCLUDE_game
INCLUDE_ITEM_CATEGORIES INCLUDE_ITEM_CATEGORIES
@ -123,9 +124,13 @@ void Menu::InitializeInventoryWindow(){
inventoryWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END; inventoryWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END;
#pragma endregion #pragma endregion
#pragma region Money Display
vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+inventoryWindow->size.y-44+8}; vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+inventoryWindow->size.y-44+8};
auto moneyIcon=inventoryWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; auto moneyIcon=inventoryWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END;
std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); std::string moneyText=std::to_string(game->GetPlayer()->GetMoney());
vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2;
inventoryWindow->ADD("Money Label",MenuLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,0},moneyTextSize},moneyText,2,SHADOW|LEFT_ALIGN)END; auto moneyDisplay=inventoryWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,0},moneyTextSize},2,SHADOW|LEFT_ALIGN)END;
moneyDisplay->SetRightAlignment(true);
Player::AddMoneyListener(moneyDisplay);
#pragma endregion
} }

@ -158,7 +158,7 @@ void Menu::HoverMenuSelect(Crawler*game){
} }
void Menu::MenuSelect(Crawler*game){ void Menu::MenuSelect(Crawler*game){
if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; if(selection==vi2d{-1,-1}||(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut))return;
bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x],(ScrollableWindowComponent*)buttons[selection.y][selection.x]->parentComponent}); bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x],(ScrollableWindowComponent*)buttons[selection.y][selection.x]->parentComponent});
if(buttonStillValid){ if(buttonStillValid){
if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){ if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
@ -200,7 +200,7 @@ void Menu::Update(Crawler*game){
for(auto&[key,value]:buttons){ for(auto&[key,value]:buttons){
int index=0; int index=0;
for(auto&button:value){ for(auto&button:value){
if(!button->disabled){ if(!button->disabled&&!button->grayedOut){
if(button->GetHoverState(game)){ if(button->GetHoverState(game)){
button->hovered=true; button->hovered=true;
itemHovered=true; itemHovered=true;
@ -449,7 +449,7 @@ void Menu::KeyboardButtonNavigation(Crawler*game,vf2d menuPos){
} }
} }
if(prevSelection!=selection){ if(prevSelection!=selection){
if(selection!=vi2d{-1,-1}&&buttons[selection.y][selection.x]->disabled){ if(selection!=vi2d{-1,-1}&&(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut)){
bool handled=false; bool handled=false;
if(!UsingMouseNavigation()){ if(!UsingMouseNavigation()){
//Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead. //Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead.

@ -102,7 +102,11 @@ void MenuComponent::OnEquipStatsUpdate(){}
void MenuComponent::DrawDecal(ViewPort&window,bool focused){ void MenuComponent::DrawDecal(ViewPort&window,bool focused){
if(background){ if(background){
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F)); Pixel backCol=PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F);
if(grayedOut){
backCol=DARK_GREY;
}
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,backCol);
} }
if(selected&&selectionType==HIGHLIGHT){ if(selected&&selectionType==HIGHLIGHT){
window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),util::lerp(0.75f,1.0f,hoverEffect/"ThemeGlobal.HighlightTime"_F))); window.FillRectDecal(rect.pos+V(A::DRAW_OFFSET),rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),util::lerp(0.75f,1.0f,hoverEffect/"ThemeGlobal.HighlightTime"_F)));
@ -241,3 +245,9 @@ void MenuComponent::SetMouseOutFunc(std::function<bool(MenuFuncData)>func){
runHoverFunctions=true; runHoverFunctions=true;
onMouseOut=func; onMouseOut=func;
}; };
void MenuComponent::SetGrayedOut(bool grayedOut){
this->grayedOut=grayedOut;
}
void MenuComponent::OnPlayerMoneyUpdate(uint32_t newMoney){}

@ -108,6 +108,7 @@ protected:
bool renderInMain=true; //If set to false, this component is the responsibility of some other windowing system and won't be rendered or updated via the main window loop. bool renderInMain=true; //If set to false, this component is the responsibility of some other windowing system and won't be rendered or updated via the main window loop.
bool valid=true; //If set to false, this would cause the component to be removed. bool valid=true; //If set to false, this would cause the component to be removed.
bool fitToLabel=false; //Will shrink text horizontally to fit the size of the label if the display text is too large. bool fitToLabel=false; //Will shrink text horizontally to fit the size of the label if the display text is too large.
bool grayedOut=false; //If turned on, a button will appear grayed out and unresponsive.
vf2d labelScaling={1,1}; vf2d labelScaling={1,1};
virtual void Update(Crawler*game); virtual void Update(Crawler*game);
virtual void DrawDecal(ViewPort&window,bool focused); virtual void DrawDecal(ViewPort&window,bool focused);
@ -146,4 +147,6 @@ public:
virtual void Cleanup(); virtual void Cleanup();
virtual void SetHoverFunc(std::function<bool(MenuFuncData)>func); virtual void SetHoverFunc(std::function<bool(MenuFuncData)>func);
virtual void SetMouseOutFunc(std::function<bool(MenuFuncData)>func); virtual void SetMouseOutFunc(std::function<bool(MenuFuncData)>func);
void SetGrayedOut(bool grayedOut);
virtual void OnPlayerMoneyUpdate(uint32_t newMoney);
}; };

@ -140,10 +140,11 @@ protected:
vf2d quantityTextScale=rect.size/48.f; vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=rect.pos+rect.size-textSize; vf2d drawPos=rect.pos+rect.size-textSize;
geom2d::rect<float>boundingBox={drawPos,textSize}; if(itemQuantity!=INFINITE){
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x); window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x);
} }
} }
}
inline MenuComponent*PickUpDraggableItem()override final{ inline MenuComponent*PickUpDraggableItem()override final{
if(valid){ if(valid){
MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName);

@ -139,8 +139,9 @@ protected:
vf2d quantityTextScale=rect.size/48.f; vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=rect.pos+rect.size-textSize; vf2d drawPos=rect.pos+rect.size-textSize;
geom2d::rect<float>boundingBox={drawPos,textSize}; if(itemRef.get().Amt()!=INFINITE){
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x); window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale,quantityTextScale.x);
} }
} }
}
}; };

@ -45,9 +45,8 @@ All rights reserved.
INCLUDE_game INCLUDE_game
class MenuLabel:public MenuComponent{ class MenuLabel:public MenuComponent{
private:
float scale=1;
protected: protected:
float scale=1;
bool shadow=false; bool shadow=false;
bool centered=true; bool centered=true;
public: public:
@ -62,10 +61,10 @@ public:
label=text; label=text;
} }
protected: protected:
virtual void inline Update(Crawler*game)override{ inline virtual void Update(Crawler*game)override{
MenuComponent::Update(game); MenuComponent::Update(game);
} }
virtual void inline DrawDecal(ViewPort&window,bool focused)override{ inline virtual void DrawDecal(ViewPort&window,bool focused)override{
MenuComponent::DrawDecal(window,focused); MenuComponent::DrawDecal(window,focused);
std::string adjustedText=label; std::string adjustedText=label;
if(!fitToLabel){ if(!fitToLabel){

@ -41,13 +41,15 @@ All rights reserved.
#include "RowMerchantInventoryScrollableWindowComponent.h" #include "RowMerchantInventoryScrollableWindowComponent.h"
#include "MenuItemItemButton.h" #include "MenuItemItemButton.h"
#include "MenuComponent.h" #include "MenuComponent.h"
#include "PlayerMoneyLabel.h"
INCLUDE_game INCLUDE_game
INCLUDE_ITEM_CATEGORIES INCLUDE_ITEM_CATEGORIES
INCLUDE_DATA INCLUDE_DATA
INCLUDE_GFX
void Menu::InitializeMerchantWindow(){ void Menu::InitializeMerchantWindow(){
Menu*merchantWindow=CreateMenu(MERCHANT,CENTERED,game->GetScreenSize()-vi2d{24,24}); Menu*merchantWindow=CreateMenu(MERCHANT,CENTERED,game->GetScreenSize()-vi2d{52,52});
static std::string lastInventoryTypeOpened=""; static std::string lastInventoryTypeOpened="";
@ -63,7 +65,12 @@ void Menu::InitializeMerchantWindow(){
[](MenuFuncData data){ [](MenuFuncData data){
RowItemDisplay*item=dynamic_cast<RowItemDisplay*>(data.component); RowItemDisplay*item=dynamic_cast<RowItemDisplay*>(data.component);
Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item->GetItem().ActualName(); Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item->GetItem().ActualName();
Component<MenuLabel>(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().BuyValue()));
Component<MenuLabel>(BUY_ITEM,"Amount to buy Amount Label")->SetLabel("1");
Component<MenuLabel>(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().BuyValue()));
Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().DisplayName()); Component<MenuLabel>(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().DisplayName());
Component<MenuComponent>(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item->GetItem().DisplayName(),1));
Menu::OpenMenu(BUY_ITEM); Menu::OpenMenu(BUY_ITEM);
return true; return true;
}, },
@ -89,4 +96,20 @@ void Menu::InitializeMerchantWindow(){
merchantWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; merchantWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
merchantWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; merchantWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
#pragma endregion #pragma endregion
#pragma region Money Display
vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+merchantWindow->size.y-44+8};
auto moneyIcon=merchantWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END;
std::string moneyText=std::to_string(game->GetPlayer()->GetMoney());
vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2;
auto moneyDisplay=merchantWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,0},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
moneyDisplay->SetRightAlignment(true);
Player::AddMoneyListener(moneyDisplay);
#pragma endregion
merchantWindow->ADD("Leave Button",MenuComponent)({{merchantWindow->size.x/2-48,28+merchantWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END,
[](MenuFuncData data){
Menu::CloseMenu();
return true;
},{2,2})END;
} }

@ -73,4 +73,5 @@ enum class Attribute{
CATEGORY_NAME, CATEGORY_NAME,
DRAW_OFFSET, DRAW_OFFSET,
ITEM_NAME, ITEM_NAME,
ITEM_QUANTITY,
}; };

@ -72,6 +72,8 @@ InputGroup Player::KEY_ITEM3;
ItemAttributable PlayerStats::equipStats; ItemAttributable PlayerStats::equipStats;
ItemAttributable PlayerStats::baseStats; ItemAttributable PlayerStats::baseStats;
std::set<MenuComponent*>Player::moneyListeners;
Player::Player() Player::Player()
:lastReleasedMovementKey(DOWN),facingDirection(DOWN),state(State::NORMAL){ :lastReleasedMovementKey(DOWN),facingDirection(DOWN),state(State::NORMAL){
Initialize(); Initialize();
@ -915,4 +917,11 @@ uint32_t Player::GetMoney()const{
}; };
void Player::SetMoney(uint32_t newMoney){ void Player::SetMoney(uint32_t newMoney){
money=newMoney; money=newMoney;
for(auto&component:moneyListeners){
component->OnPlayerMoneyUpdate(newMoney);
}
}; };
void Player::AddMoneyListener(MenuComponent*component){
if(moneyListeners.count(component))ERR("WARNING! Trying to add a second copy of component "<<std::quoted(component->GetName()));
moneyListeners.insert(component);
}

@ -52,6 +52,7 @@ All rights reserved.
#undef GetClassName #undef GetClassName
struct DamageNumber; struct DamageNumber;
class MenuComponent;
struct CastInfo{ struct CastInfo{
std::string name; std::string name;
@ -252,7 +253,9 @@ public:
void SetItem3UseFunc(Ability a); void SetItem3UseFunc(Ability a);
static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3; static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3;
static std::set<MenuComponent*>moneyListeners;
static void AddMoneyListener(MenuComponent*component);
uint32_t GetMoney()const; uint32_t GetMoney()const;
void SetMoney(uint32_t newMoney); void SetMoney(uint32_t newMoney);
}; };

@ -0,0 +1,62 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2022 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "MenuLabel.h"
#include "Crawler.h"
INCLUDE_game
class PlayerMoneyLabel:public MenuLabel{
bool rightAligned=false;
float anchorPointX=0;
public:
inline PlayerMoneyLabel(geom2d::rect<float>rect,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,std::to_string(game->GetPlayer()->GetMoney()),scale,attributes){}
inline virtual void OnPlayerMoneyUpdate(uint32_t newMoney)final{
SetLabel(std::to_string(newMoney));
std::string moneyText=std::to_string(newMoney);
vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*scale;
rect.pos.x=anchorPointX-moneyTextSize.x;
}
inline void SetRightAlignment(bool rightAligned){
this->rightAligned=rightAligned;
anchorPointX=rect.pos.x+rect.size.x;
}
};

@ -65,7 +65,7 @@ public:
window.DrawShadowStringPropDecal(rect.pos+vf2d{4,4}+vf2d{iconSize.x,iconSize.y/2-4},itemName,WHITE,BLACK,scaledSize); window.DrawShadowStringPropDecal(rect.pos+vf2d{4,4}+vf2d{iconSize.x,iconSize.y/2-4},itemName,WHITE,BLACK,scaledSize);
if(showQuantity){ if(showQuantity&&itemRef.get().Amt()!=INFINITE){
std::string quantityText=std::format("x{}",itemRef.get().Amt()); std::string quantityText=std::format("x{}",itemRef.get().Amt());
float qtyTextScale=0.75f; float qtyTextScale=0.75f;
vf2d qtyTextSize=vf2d(game->GetTextSizeProp(quantityText))*qtyTextScale; vf2d qtyTextSize=vf2d(game->GetTextSizeProp(quantityText))*qtyTextScale;

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 1 #define VERSION_PATCH 1
#define VERSION_BUILD 4220 #define VERSION_BUILD 4251
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -6,28 +6,28 @@ Merchant
{ {
DisplayName = Merchant DisplayName = Merchant
# Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply. # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Health Potion,5 Item[1] = Minor Health Potion
Item[2] = Minor Mana Potion,5 Item[2] = Minor Mana Potion
} }
Chapter1_B Chapter1_B
{ {
DisplayName = Merchant DisplayName = Merchant
# Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply. # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Health Potion,5 Item[1] = Minor Health Potion
} }
Chapter1_C Chapter1_C
{ {
DisplayName = Merchant DisplayName = Merchant
# Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply. # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Mana Potion,5 Item[1] = Minor Mana Potion
} }
Chapter1_D Chapter1_D
{ {
DisplayName = Merchant DisplayName = Merchant
# Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply. # Specify items this merchant sells. Add an optional quantity as a second argument. Not specifying a second argument will give the shop infinite supply.
Item[1] = Minor Health Potion,5 Item[1] = Minor Health Potion
Item[2] = Minor Mana Potion,5 Item[2] = Minor Mana Potion
Item[3] = Bandages,5 Item[3] = Bandages
} }
} }
} }
Loading…
Cancel
Save