Implemented Merchant Selling Screen

pull/28/head
sigonasr2 11 months ago
parent 25dd39b60a
commit 6412f34dce
  1. 4
      Crawler/BuyItemWindow.cpp
  2. 8
      Crawler/Crawler.cpp
  3. 5
      Crawler/Crawler.vcxproj
  4. 4
      Crawler/Crawler.vcxproj.filters
  5. 2
      Crawler/InventoryConsumableWindow.cpp
  6. 16
      Crawler/InventoryScrollableWindowComponent.h
  7. 8
      Crawler/InventoryWindow.cpp
  8. 4
      Crawler/LevelCompleteWindow.cpp
  9. 2
      Crawler/Menu.cpp
  10. 14
      Crawler/MenuItemItemButton.h
  11. 4
      Crawler/MenuLabel.h
  12. 17
      Crawler/Merchant.cpp
  13. 34
      Crawler/MerchantWindow.cpp
  14. 21
      Crawler/RowInventoryScrollableWindowComponent.h
  15. 35
      Crawler/RowItemDisplay.h
  16. 24
      Crawler/RowMerchantInventoryScrollableWindowComponent.h
  17. 4
      Crawler/ScrollableWindowComponent.h
  18. 52
      Crawler/SellItemWindow.cpp
  19. 4
      Crawler/TODO.txt
  20. 2
      Crawler/Version.h
  21. 1
      Crawler/assets/config/gfx/gfx.txt
  22. 8
      Crawler/olcPGEX_ViewPort.h
  23. 8
      Crawler/olcPixelGameEngine.h

@ -43,10 +43,10 @@ using A=Attribute;
void Menu::InitializeBuyItemWindow(){
Menu*buyItemWindow=CreateMenu(BUY_ITEM,CENTERED,{192,72});
static auto GetQuantity = [&](){
static auto GetQuantity=[&](){
return std::stoi(Component<MenuLabel>(BUY_ITEM,"Amount to buy Amount Label")->GetLabel());
};
static auto UpdateMenu = [&](int32_t qty){
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));

@ -1244,7 +1244,7 @@ void Crawler::RenderHud(){
std::stringstream castTimeDisplay;
castTimeDisplay<<std::fixed<<std::setprecision(1)<<timer;
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2+90.f,ScreenHeight()-80.f}-vf2d{float(GetTextSizeProp(castTimeDisplay.str()).x),0},castTimeDisplay.str(),WHITE,BLACK);
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2.f-GetTextSizeProp(castText).x*2/2,ScreenHeight()-64.f},castText,WHITE,BLACK,{2,3},std::numeric_limits<float>::max(),0.75f);
DrawShadowStringPropDecal(vf2d{ScreenWidth()/2.f-GetTextSizeProp(castText).x*2/2,ScreenHeight()-64.f},castText,WHITE,BLACK,{2,3},std::numeric_limits<float>::max(),2.f);
};
if(GetPlayer()->GetCastInfo().castTimer>0){
@ -1258,8 +1258,8 @@ void Crawler::RenderHud(){
DrawDecal({2,20},GFX["mana.png"].Decal());
std::string text=player->GetHealth()>0?std::to_string(player->GetHealth()):"X";
std::string text_mana=std::to_string(player->GetMana());
DrawShadowStringPropDecal({20,3},text,WHITE,BLACK,{2,2},INFINITE,0.5f);
DrawShadowStringPropDecal({24,23},text_mana,{192,192,255},BLACK,{1.5f,1.5f},INFINITE,0.6f);
DrawShadowStringPropDecal({20,3},text,WHITE,BLACK,{2,2},INFINITE);
DrawShadowStringPropDecal({24,23},text_mana,{192,192,255},BLACK,{1.5f,1.5f},INFINITE);
if(player->notEnoughManaDisplay.second>0){
std::string displayText="Not enough mana for "+player->notEnoughManaDisplay.first+"!";
DrawShadowStringPropDecal(vf2d{float(ScreenWidth()/2),float(ScreenHeight()/4)}-GetTextSizeProp(displayText)/2,displayText,DARK_RED,VERY_DARK_RED);
@ -1362,7 +1362,7 @@ void Crawler::RenderCooldowns(){
DrawShadowStringDecal(pos+vf2d{12,-2}-keyDisplaySize/2,a.input->GetDisplayName(),keyDisplayCol,BLACK,{0.5f,0.5f},std::numeric_limits<float>::max(),1);
vf2d shortNameSize=vf2d{GetTextSize(a.shortName)}*vf2d{0.5f,0.75f};
DrawShadowStringDecal(pos+vf2d{13,24}-shortNameSize/2,a.shortName,shortNameCol,WHITE,{0.5f,0.75f});
DrawShadowStringDecal(pos+vf2d{13,24}-shortNameSize/2,a.shortName,shortNameCol,{255,255,255,230},{0.5f,0.75f});
}
};

@ -407,10 +407,7 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h" />
<ClInclude Include="safemap.h" />
<ClInclude Include="ScrollableWindowComponent.h" />
<ClInclude Include="InventoryScrollableWindowComponent.h" />

@ -375,10 +375,10 @@
<ClInclude Include="discord-files\types.h">
<Filter>Header Files\discord-files</Filter>
</ClInclude>
<ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h">
<ClInclude Include="PlayerMoneyLabel.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
<ClInclude Include="PlayerMoneyLabel.h">
<ClInclude Include="RowMerchantInventoryScrollableWindowComponent.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
</ItemGroup>

@ -55,7 +55,7 @@ void Menu::InitializeConsumableInventoryWindow(){
inventoryWindow->I(A::LOADOUT_SLOT)=0;
auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{0,15},{windowSize.x,96.f}},"Consumables","itemName","itemDescription",
auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{0,15},{windowSize.x,96.f}},"itemName","itemDescription",
[&](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component;
data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT));

@ -57,7 +57,6 @@ struct InventoryWindowOptions{
// Please ensure these are overwritten, otherwise you will get errors complaining about dynamic casts unable to convert classes successfully.
class InventoryScrollableWindowComponent:public ScrollableWindowComponent{
protected:
ITCategory inventoryType;
std::function<bool(MenuFuncData)>inventoryButtonClickAction;
std::function<bool(MenuFuncData)>inventoryButtonHoverAction;
std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction;
@ -67,11 +66,11 @@ protected:
std::string itemDescriptionLabelName;
bool inventoryButtonsActive=true;
public:
inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:InventoryScrollableWindowComponent(rect,invType,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,DO_NOTHING,DO_NOTHING,options,inventoryButtonsActive,attributes){
inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:InventoryScrollableWindowComponent(rect,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,DO_NOTHING,DO_NOTHING,options,inventoryButtonsActive,attributes){
}
inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,std::function<bool(MenuFuncData)>inventoryButtonHoverAction,std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(rect,attributes),inventoryButtonHoverAction(inventoryButtonHoverAction),inventoryButtonMouseOutAction(inventoryButtonMouseOutAction),inventoryType(invType),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),
inline InventoryScrollableWindowComponent(geom2d::rect<float>rect,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,std::function<bool(MenuFuncData)>inventoryButtonHoverAction,std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(rect,attributes),inventoryButtonHoverAction(inventoryButtonHoverAction),inventoryButtonMouseOutAction(inventoryButtonMouseOutAction),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),
options(options),inventoryButtonClickAction(inventoryButtonClickAction),inventoryButtonsActive(inventoryButtonsActive){}
virtual inline void Update(Crawler*game)override{
ScrollableWindowComponent::Update(game);
@ -128,7 +127,10 @@ protected:
AddButtonOnSlotUpdate(cat);
}else
if(components.size()>invSize){ //There are empty spots, so let's clean up.
RemoveEmptySlots();
RemoveAllComponents();
for(std::weak_ptr<Item> item:Inventory::get(cat)){
AddButtonOnSlotUpdate(cat);
}
}
}
@ -137,7 +139,7 @@ protected:
}
virtual inline void AddButtonOnSlotUpdate(ITCategory cat){
size_t invSize=Inventory::get(cat).size();
size_t invSize=components.size()+1;
int invWidth=int(rect.size.x/(float(options.size.x)+options.padding));
int x=int((invSize-1)%invWidth);
int y=int((invSize-1)/invWidth);

@ -88,7 +88,7 @@ void Menu::InitializeInventoryWindow(){
button->SetSelectionType(HIGHLIGHT);
button->S(A::CATEGORY_NAME)=category;
auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,inventoryWindow->size.y-44}},category,"Item Name Label","Item Description Label",DO_NOTHING,
auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,inventoryWindow->size.y-44}},"Item Name Label","Item Description Label",DO_NOTHING,
[](MenuFuncData data){
Component<MenuItemItemButton>(data.menu.GetType(),"Item Icon")->SetItem(dynamic_cast<RowItemDisplay*>(data.component)->GetItem());
Component<MenuItemItemButton>(data.menu.GetType(),"Item Icon")->UpdateIcon();
@ -131,4 +131,10 @@ void Menu::InitializeInventoryWindow(){
moneyDisplay->SetRightAlignment(true);
Player::AddMoneyListener(moneyDisplay);
#pragma endregion
inventoryWindow->ADD("Back Button",MenuComponent)({{inventoryWindow->size.x/2-48,28+inventoryWindow->size.y-44+6},{96,24}},"Back",MenuType::ENUM_END,
[](MenuFuncData data){
Menu::CloseMenu();
return true;
},{2,2})END;
}

@ -55,12 +55,12 @@ void Menu::InitializeLevelCompleteWindow(){
levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)({{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot","Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING)END;
auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING)END;
Menu::AddInventoryListener(monsterLootWindow,"Monster Loot");
levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)({{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END;
auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot","Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING)END;
auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING)END;
Menu::AddInventoryListener(stageLootWindow,"Stage Loot");
auto nextButtonAction=[](MenuFuncData data){

@ -177,6 +177,8 @@ void Menu::MenuSelect(Crawler*game){
}
void Menu::Update(Crawler*game){
if(selection.x<0||selection.x>=buttons[selection.y].size()){selection={-1,-1};}
if(draggingComponent==nullptr){
HoverMenuSelect(game);
}

@ -138,12 +138,14 @@ protected:
virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuIconButton::DrawDecal(window,focused);
if(valid&&!hideQty){
std::string quantityText="x"+std::to_string(itemRef.lock()->Amt());
vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=rect.pos+rect.size-textSize;
if(itemRef.lock()->Amt()!=INFINITE){
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale);
if(!ISBLANK(itemRef)){
std::string quantityText="x"+std::to_string(itemRef.lock()->Amt());
vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;
vf2d drawPos=rect.pos+rect.size-textSize;
if(itemRef.lock()->Amt()!=INFINITE){
window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale);
}
}
}
}

@ -83,9 +83,9 @@ protected:
}
if(shadow){
window.DrawShadowStringPropDecal(drawPos,label,WHITE,BLACK,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x);
window.DrawShadowStringPropDecal(drawPos,label,WHITE,BLACK,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x,1.0f);
}else{
window.DrawStringPropDecal(drawPos,label,WHITE,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x);
window.DrawStringPropDecal(drawPos,label,WHITE,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x,1.0f);
}
}
};

@ -73,8 +73,8 @@ Merchant&Merchant::AddMerchant(Chapter chapter){
void Merchant::AddItem(IT item,uint32_t amt,uint8_t enhancementLevel){
shopItems.push_back(std::make_shared<Item>(amt,item,enhancementLevel));
UpdateSortedItemsList();
if(&GetCurrentTravelingMerchant()==this){
UpdateSortedItemsList();
Menu::MerchantInventorySlotsUpdated(ITEM_DATA[item].Category());
}
}
@ -161,16 +161,27 @@ void Merchant::PurchaseItem(IT item,uint32_t amt){
purchaseFunctionPrimed.Validate(item,amt);
uint32_t totalCost=0U;
bool finiteItemPurchased=false;
for(std::shared_ptr<Item>it:shopItems){
if(it==item){
if(it->Amt()!=INFINITE){
it->SetAmt(it->Amt()-amt);
finiteItemPurchased=true;
}
totalCost=it->BuyValue()*amt;
break;
}
}
if(finiteItemPurchased){
size_t removeCount=std::erase_if(shopItems,[](std::shared_ptr<Item> it){return it->Amt()==0;});
if(removeCount>1)ERR("WARNING! Somehow we sold more than one item???")
if(removeCount){
UpdateSortedItemsList();
Menu::MerchantInventorySlotsUpdated(ITEM_DATA[item].Category());
}
}
Inventory::AddItem(item,amt);
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-totalCost);
@ -190,8 +201,8 @@ void Merchant::SellItem(IT item,uint32_t amt){
break;
}
}
if(!itemFound){
AddItem(item); //This may not be a feature we include in future versions of the game. For now let's allow it.
if(!itemFound&&ITEM_DATA[item].CanBePurchased()){
AddItem(item,amt); //This may not be a feature we include in future versions of the game. For now let's allow it.
}
totalCost=ITEM_DATA[item].GetSellValue()*amt;

@ -77,7 +77,7 @@ void Menu::InitializeMerchantWindow(){
buyTab->selectionType=SelectionType::HIGHLIGHT;
auto sellTab=merchantWindow->ADD("Sell Tab",MenuComponent)({{merchantWindow->size.x/2+2,0},{merchantWindow->size.x/2-4,24}},"Sell",[](MenuFuncData data){
Component<RowMerchantInventoryScrollableWindowComponent>(MERCHANT,"Merchant Inventory Display")->Enable(false);
Component<RowInventoryScrollableWindowComponent>(MERCHANT,"Merchant Inventory Display")->Enable(false);
Component<MenuComponent>(MERCHANT,"Buy Tab")->selected=false;
Component<MenuComponent>(MERCHANT,"Inventory Tabs Outline")->Enable(true);
for(auto&[category,items]:ITEM_CATEGORIES){
@ -119,6 +119,7 @@ void Menu::InitializeMerchantWindow(){
Component<MenuItemItemButton>(data.menu.GetType(),"Item Icon")->UpdateIcon();
return true;
},{.padding=1,.size={220-13,28}})END;
inventoryDisplay->SetPriceLabelType(PriceLabel::BUY_LABEL);
for(auto&[category,items]:ITEM_CATEGORIES){
Menu::AddMerchantInventoryListener(inventoryDisplay,category);
@ -148,22 +149,24 @@ void Menu::InitializeMerchantWindow(){
button->SetSelectionType(HIGHLIGHT);
button->S(A::CATEGORY_NAME)=category;
auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,merchantWindow->size.y-44}},category,"Item Name Label","Item Description Label",
auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label",
[](MenuFuncData data){
RowItemDisplay*item=dynamic_cast<RowItemDisplay*>(data.component);
Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->S(A::ITEM_NAME)=item->GetItem().lock()->ActualName();
Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue()));
Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1");
Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue()));
Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
bool canPurchase=merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1);
std::string colorCode="";
if(!canPurchase)colorCode="#FF0000";
Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->BuyValue()));
Component<MenuLabel>(SELL_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().lock()->DisplayName());
Component<MenuComponent>(SELL_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1));
Menu::OpenMenu(SELL_ITEM);
if(item->GetItem().lock()->CanBeSold()){
Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->S(A::ITEM_NAME)=item->GetItem().lock()->ActualName();
Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue()));
Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1");
Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue()));
Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
bool canPurchase=merchant.CanSellItem(item->GetItem().lock()->ActualName(),1);
std::string colorCode="";
if(!canPurchase)colorCode="#FF0000";
Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->SellValue()));
Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->SetLabel("Selling "+item->GetItem().lock()->DisplayName());
Component<MenuComponent>(SELL_ITEM,"Sell Button")->SetGrayedOut(!merchant.CanSellItem(item->GetItem().lock()->ActualName(),1));
Menu::OpenMenu(SELL_ITEM);
}
return true;
},
[](MenuFuncData data){
@ -176,6 +179,7 @@ void Menu::InitializeMerchantWindow(){
Component<MenuItemItemButton>(data.menu.GetType(),"Item Icon")->UpdateIcon();
return true;
},{.padding=1,.size={137,28}})END;
inventoryDisplay->SetPriceLabelType(PriceLabel::SELL_LABEL);
if(first){
merchantWindow->S(A::LAST_INVENTORY_TYPE_OPENED)=category;

@ -40,9 +40,11 @@ All rights reserved.
#include "RowItemDisplay.h"
class RowInventoryScrollableWindowComponent:public InventoryScrollableWindowComponent{
protected:
PriceLabel::PriceLabel priceLabel=PriceLabel::NONE;
public:
inline RowInventoryScrollableWindowComponent(geom2d::rect<float>rect,ITCategory invType,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,std::function<bool(MenuFuncData)>inventoryButtonHoverAction,std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:InventoryScrollableWindowComponent(rect,invType,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,options,inventoryButtonsActive,attributes){}
inline RowInventoryScrollableWindowComponent(geom2d::rect<float>rect,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,std::function<bool(MenuFuncData)>inventoryButtonHoverAction,std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:InventoryScrollableWindowComponent(rect,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,options,inventoryButtonsActive,attributes){}
virtual inline void SetCompactDescriptions(bool compact)override final{
if(compact)this->compact=COMPACT;
@ -57,8 +59,20 @@ public:
}
}
virtual inline void SetPriceLabelType(PriceLabel::PriceLabel labelType)final{
this->priceLabel=labelType;
for(MenuComponent*component:components){
RowItemDisplay*itemButton=dynamic_cast<RowItemDisplay*>(component);
if(itemButton){
itemButton->SetPriceLabelType(labelType);
}else{
ERR("WARNING! Attempting to cast a button that isn't a MenuItemButton!");
}
}
}
virtual inline void AddButtonOnSlotUpdate(ITCategory cat)override{
size_t invSize=Inventory::get(cat).size();
size_t invSize=components.size()+1;
int invWidth=int(rect.size.x/(float(options.size.x)+options.padding));
int x=int((invSize-1)%invWidth);
int y=int((invSize-1)/invWidth);
@ -69,6 +83,7 @@ public:
auto newItem=ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Inventory::GetInventorySlot(cat,itemIndex),inventoryButtonClickAction,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END;
newItem->SetCompactDescriptions(compact==COMPACT);
newItem->SetPriceLabelType(priceLabel);
newItem->SetHoverFunc(inventoryButtonHoverAction);
newItem->SetMouseOutFunc(inventoryButtonMouseOutAction);

@ -41,6 +41,15 @@ All rights reserved.
#include "MenuLabel.h"
INCLUDE_game
INCLUDE_GFX
namespace PriceLabel{
enum PriceLabel{
NONE,
BUY_LABEL,
SELL_LABEL,
};
}
class RowItemDisplay:public MenuComponent{
std::weak_ptr<Item>itemRef;
@ -48,6 +57,7 @@ class RowItemDisplay:public MenuComponent{
std::string itemDescriptionLabelName;
CompactText compact=NON_COMPACT;
bool showQuantity=true;
PriceLabel::PriceLabel priceLabel=PriceLabel::NONE;
public:
inline RowItemDisplay(geom2d::rect<float>rect,const std::weak_ptr<Item>itemRef,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,ButtonAttr attributes=ButtonAttr::NONE)
:MenuComponent(rect,"",onClick,attributes),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),itemRef(itemRef){
@ -71,6 +81,28 @@ public:
vf2d qtyTextSize=vf2d(game->GetTextSizeProp(quantityText))*qtyTextScale;
window.DrawShadowStringPropDecal(rect.pos+rect.size-vf2d{1,1}+vf2d{-qtyTextSize.x,-qtyTextSize.y},quantityText,WHITE,BLACK,{qtyTextScale,qtyTextScale});
}
if(priceLabel!=PriceLabel::NONE){
if(priceLabel==PriceLabel::SELL_LABEL){
std::string priceText=std::to_string(itemRef.lock()->SellValue());
if(itemRef.lock()->SellValue()==0)priceText="Cannot Sell";
vf2d priceTextSize=vf2d(game->GetTextSize(priceText));
if(itemRef.lock()->SellValue()!=0){
window.DrawShadowStringDecal(rect.pos+vf2d{rect.size.x-priceTextSize.x-15,3},priceText);
window.DrawDecal(rect.pos+vf2d{rect.size.x-14,1},GFX["currency_coin.png"].Decal(),{0.5f,0.5f});
}else{
vf2d priceTextSize=vf2d(game->GetTextSizeProp(priceText))*vf2d{0.5f,0.85f};
window.DrawShadowStringPropDecal(rect.pos+vf2d{rect.size.x-priceTextSize.x-1,3},priceText,WHITE,BLACK,{0.5f,0.85f});
}
}else{
std::string priceText=std::to_string(itemRef.lock()->BuyValue());
vf2d priceTextSize=vf2d(game->GetTextSize(priceText));
window.DrawShadowStringDecal(rect.pos+vf2d{rect.size.x-priceTextSize.x-15,3},priceText);
window.DrawDecal(rect.pos+vf2d{rect.size.x-14,1},GFX["currency_coin.png"].Decal(),{0.5f,0.5f});
}
}
if(Inventory::GetSlotEquippedIn(itemRef)!=EquipSlot::NONE){
window.DrawShadowStringDecal(rect.pos+vf2d{2,2}+iconSize-vf2d{8,8},"E",GREEN,VERY_DARK_GREEN);
@ -128,4 +160,7 @@ public:
virtual inline void OnHover()override{
UpdateLabel();
}
inline void SetPriceLabelType(PriceLabel::PriceLabel labelType){
this->priceLabel=labelType;
}
};

@ -41,7 +41,7 @@ All rights reserved.
class RowMerchantInventoryScrollableWindowComponent:public RowInventoryScrollableWindowComponent{
public:
inline RowMerchantInventoryScrollableWindowComponent(geom2d::rect<float>rect,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::function<bool(MenuFuncData)>inventoryButtonClickAction,std::function<bool(MenuFuncData)>inventoryButtonHoverAction,std::function<bool(MenuFuncData)>inventoryButtonMouseOutAction,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:RowInventoryScrollableWindowComponent(rect,"",itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,options,inventoryButtonsActive,attributes){}
:RowInventoryScrollableWindowComponent(rect,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,options,inventoryButtonsActive,attributes){}
virtual inline void OnInventorySlotsUpdate(ITCategory cat)override{
@ -51,13 +51,16 @@ public:
AddButtonOnSlotUpdate(cat);
}else
if(components.size()>merchantInv.size()){ //There are empty spots, so let's clean up.
RemoveEmptySlots();
RemoveAllComponents();
for(std::shared_ptr<Item> item:merchantInv){
AddButtonOnSlotUpdate(cat);
}
}
}
virtual inline void AddButtonOnSlotUpdate(ITCategory cat)override{
const std::vector<std::shared_ptr<Item>>&merchantInv=Merchant::GetCurrentTravelingMerchant().GetShopItems();
size_t invSize=merchantInv.size();
size_t invSize=components.size()+1;
int invWidth=int(rect.size.x/(float(options.size.x)+options.padding));
int x=int((invSize-1)%invWidth);
int y=int((invSize-1)/invWidth);
@ -66,21 +69,10 @@ public:
vf2d buttonSize=options.size;
vf2d totalSpacing={options.padding+buttonSize.x,options.padding+buttonSize.y};
auto newItem=ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],inventoryButtonClickAction,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END;
auto newItem=ADD("merchant_item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],inventoryButtonClickAction,itemNameLabelName,itemDescriptionLabelName,inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END;
newItem->SetCompactDescriptions(compact==COMPACT);
newItem->SetPriceLabelType(priceLabel);
newItem->SetHoverFunc(inventoryButtonHoverAction);
newItem->SetMouseOutFunc(inventoryButtonMouseOutAction);
//Since we are indexing into a vector reference which is inevitably going to get erased as we add more items,
//we must update all previous menu component references in case that memory has been overwritten!
for(int counter=0;MenuComponent*component:components){
RowItemDisplay*item=dynamic_cast<RowItemDisplay*>(component);
if(item!=nullptr){
item->SetItem(merchantInv[itemIndex]);
}else{
ERR("WARNING! Could not properly cast item to RowItemDisplay* type!");
}
counter++;
}
}
};

@ -236,6 +236,7 @@ public:
components.push_back(button);
button->renderInMain=false; //Now we are in control!
button->parentComponent=this;
button->disabled=disabled;
CalculateBounds();
@ -259,6 +260,9 @@ public:
}
virtual inline void Enable(bool enabled)override final{
disabled=!enabled;
for(MenuComponent*component:components){
component->Enable(enabled);
}
if(upButton){upButton->Enable(enabled);}
if(downButton){downButton->Enable(enabled);}
};

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

@ -1,6 +1,5 @@
January 1st
===========
Sell Item Merchant Screen
Blacksmith Item Crafting Screen
Randomized Item Stats
- Get Item may return multiples of the same item.
@ -9,9 +8,10 @@ Randomized Item Stats
The Hub / NPC Interactions
Save/Load Game
- Save Inventory Items/Equips
- Player Base Level/Stats
- Player Base Level/Stats/Accumulated Exp
- Unlock Progress
- World Map Location
- Chapter #
Audio Engine
- Audio Ambience Zones
- Menu Sound Effects

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

@ -43,6 +43,7 @@ Images
GFX_SqareSkillIcon = square_skill_overlay_icon.png
GFX_SqareSkillIconEmpty = square_skill_overlay_icon_empty.png
GFX_Money = money.png
GFX_CurrencyCoin = currency_coin.png
# Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png

@ -736,7 +736,7 @@ void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, std::string_view
pge->Clear(BLANK);
pge->DrawString({0,0},sText,WHITE,1U,width/scale.x);
newDecal->Update();
float adjustedShadowSizeFactor=shadowSizeFactor*4;
float adjustedShadowSizeFactor=shadowSizeFactor*4/std::max(scale.x,scale.y);
Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor*2,(imageSize.y/scale.x*4)+adjustedShadowSizeFactor*2));
garbageCollector[key+"_SHADOW"].decal=newShadowDecal;
pge->SetDrawTarget(newShadowDecal->sprite);
@ -760,7 +760,7 @@ void olc::ViewPort::DrawShadowStringDecal(const olc::vf2d& pos, std::string_view
}
return false;
});
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor}*scale,garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos,garbageCollector[key].decal,scale,col);
}
@ -784,7 +784,7 @@ void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_
pge->Clear(BLANK);
pge->DrawStringProp({0,0},sText,WHITE,1U,width/scale.x);
newDecal->Update();
float adjustedShadowSizeFactor=shadowSizeFactor*4;
float adjustedShadowSizeFactor=shadowSizeFactor*4/std::max(scale.x,scale.y);
Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor*2,(imageSize.y/scale.x*4)+adjustedShadowSizeFactor*2));
garbageCollector[key+"_SHADOW"].decal=newShadowDecal;
pge->SetDrawTarget(newShadowDecal->sprite);
@ -808,7 +808,7 @@ void olc::ViewPort::DrawShadowStringPropDecal(const olc::vf2d& pos, std::string_
}
return false;
});
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor}*scale,garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos,garbageCollector[key].decal,scale,col);
}

@ -3440,7 +3440,7 @@ namespace olc
Clear(BLANK);
DrawString({0,0},sText,WHITE,1U,width/scale.x);
newDecal->Update();
float adjustedShadowSizeFactor=shadowSizeFactor*4;
float adjustedShadowSizeFactor=shadowSizeFactor*4/std::max(scale.x,scale.y);
Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor*2,(imageSize.y/scale.x*4)+adjustedShadowSizeFactor*2));
garbageCollector[key+"_SHADOW"].decal=newShadowDecal;
SetDrawTarget(newShadowDecal->sprite);
@ -3464,7 +3464,7 @@ namespace olc
}
return false;
});
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor}*scale,garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos,garbageCollector[key].decal,scale,col);
}
@ -3564,7 +3564,7 @@ namespace olc
Clear(BLANK);
DrawStringProp({0,0},sText,WHITE,1U,width/scale.x);
newDecal->Update();
float adjustedShadowSizeFactor=shadowSizeFactor*4;
float adjustedShadowSizeFactor=shadowSizeFactor*4/std::max(scale.x,scale.y);
Decal*newShadowDecal=new Decal(new Sprite((imageSize.x/scale.x*4)+adjustedShadowSizeFactor*2,(imageSize.y/scale.x*4)+adjustedShadowSizeFactor*2));
garbageCollector[key+"_SHADOW"].decal=newShadowDecal;
SetDrawTarget(newShadowDecal->sprite);
@ -3588,7 +3588,7 @@ namespace olc
}
return false;
});
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor}*scale,garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos-vf2d{shadowSizeFactor,shadowSizeFactor},garbageCollector[key+"_SHADOW"].decal,scale/4,shadowCol);
DrawDecal(pos,garbageCollector[key].decal,scale,col);
}

Loading…
Cancel
Save