Implemented locking of accessories in the inventory and merchant window to prevent immediate selling of an item. Fixed a bug that prevented custom menu actions to be performed on the menu select button when a button was clicked. Release Build 7966. Patch Version 0.4.5.

mac-build
sigonasr2 9 months ago
parent 7ce1e37549
commit 2c81cf15f2
  1. 37
      Adventures in Lestoria/AccessoryRowItemDisplay.h
  2. 40
      Adventures in Lestoria/InventoryWindow.cpp
  3. 11
      Adventures in Lestoria/Item.cpp
  4. 4
      Adventures in Lestoria/Item.h
  5. 4
      Adventures in Lestoria/Menu.cpp
  6. 4
      Adventures in Lestoria/MenuComponent.cpp
  7. 3
      Adventures in Lestoria/MenuComponent.h
  8. 25
      Adventures in Lestoria/MerchantWindow.cpp
  9. 8
      Adventures in Lestoria/SaveFile.cpp
  10. 5
      Adventures in Lestoria/ScrollableWindowComponent.h
  11. 2
      Adventures in Lestoria/TODO.txt
  12. 4
      Adventures in Lestoria/Version.h
  13. 10
      Adventures in Lestoria/assets/config/audio/events.txt
  14. 2
      Adventures in Lestoria/assets/config/gfx/gfx.txt
  15. BIN
      Adventures in Lestoria/assets/gamepack.pak
  16. BIN
      Adventures in Lestoria/assets/lock.png
  17. BIN
      Adventures in Lestoria/assets/unlock.png
  18. BIN
      x64/Release/Adventures in Lestoria.exe

@ -37,12 +37,14 @@ All rights reserved.
#pragma endregion #pragma endregion
#pragma once #pragma once
#include "RowItemDisplay.h" #include "RowItemDisplay.h"
#include "SoundEffect.h"
#include "MenuIconButton.h"
INCLUDE_game INCLUDE_game
INCLUDE_GFX INCLUDE_GFX
class AccessoryRowItemDisplay:public RowItemDisplay{ class AccessoryRowItemDisplay:public RowItemDisplay{
std::weak_ptr<MenuComponent>lockButton; std::weak_ptr<MenuIconButton>lockButton;
public: public:
inline AccessoryRowItemDisplay(geom2d::rect<float>rect,const std::weak_ptr<Item>itemRef,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,ButtonAttr attributes=ButtonAttr::NONE) inline AccessoryRowItemDisplay(geom2d::rect<float>rect,const std::weak_ptr<Item>itemRef,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,ButtonAttr attributes=ButtonAttr::NONE)
:RowItemDisplay(rect,itemRef,onClick,itemNameLabelName,itemDescriptionLabelName,attributes){} :RowItemDisplay(rect,itemRef,onClick,itemNameLabelName,itemDescriptionLabelName,attributes){}
@ -54,9 +56,38 @@ public:
lockButton.reset(); lockButton.reset();
} }
} }
virtual inline void AfterCreate()override final{ inline void AfterCreate()override final{
lockButton=parentComponent.lock()->ADDSUB(std::format("{}_lock",name),MenuComponent)(geom2d::rect<float>{rect.pos,vf2d{16.f,8.f}},"Lock",[](MenuFuncData data){ lockButton=parentComponent.lock()->ADDSUB(std::format("{}_lock",name),MenuIconButton)(geom2d::rect<float>{rect.pos+vf2d{rect.size.x-10.f,rect.size.y-10.f},vf2d{10.f,10.f}},GFX["unlock.png"].Decal(),[](MenuFuncData data){
std::weak_ptr<AccessoryRowItemDisplay>accessoryParent=DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(data.component.lock()->GetSubcomponentParent());
accessoryParent.lock()->SetLocked(!accessoryParent.lock()->IsLocked());
if(accessoryParent.lock()->IsLocked()){
SoundEffect::PlaySFX("Lock Accessory",SoundEffect::CENTERED);
}else{
SoundEffect::PlaySFX("Unlock Accessory",SoundEffect::CENTERED);
}
std::weak_ptr<MenuIconButton>lockButton=DYNAMIC_POINTER_CAST<MenuIconButton>(data.component.lock());
return true; return true;
})END; })END;
} }
inline void Update(AiL*game)override final{
MenuComponent::Update(game);
if(itemRef.lock()->IsLocked()){
lockButton.lock()->SetIcon(GFX["lock.png"].Decal());
}else{
lockButton.lock()->SetIcon(GFX["unlock.png"].Decal());
}
}
inline const bool IsLocked()const{
return itemRef.lock()->IsLocked();
}
inline void SetLocked(const bool locked){
if(locked){
itemRef.lock()->Lock();
}else{
itemRef.lock()->Unlock();
}
}
inline const std::weak_ptr<MenuIconButton>GetLockButton()const{
return lockButton;
}
}; };

@ -46,6 +46,7 @@ All rights reserved.
#include "RowItemDisplay.h" #include "RowItemDisplay.h"
#include "PlayerMoneyLabel.h" #include "PlayerMoneyLabel.h"
#include "SoundEffect.h" #include "SoundEffect.h"
#include "AccessoryRowItemDisplay.h"
INCLUDE_game INCLUDE_game
INCLUDE_ITEM_CATEGORIES INCLUDE_ITEM_CATEGORIES
@ -202,7 +203,44 @@ void Menu::InitializeInventoryWindow(){
} }
}}}, }}},
{{game->KEY_SCROLL,Pressed},{"Navigate",[](MenuType type){}}}, {{game->KEY_SCROLL,Pressed},{"Navigate",[](MenuType type){}}},
{game->KEY_CONFIRM,{"Select",[](MenuType type){}}}, {game->KEY_CONFIRM,{[](MenuFuncData data){
if(!data.menu.GetSelection().expired()&&
!data.menu.GetSelection().lock()->parentComponent.expired()&&
data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){
if(DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){
return "Unlock";
}else{
return "Lock";
}
}
return "Select";
},[](MenuType type){
if(!Menu::menus[type]->GetSelection().expired()&&
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"
&&Menu::menus[type]->GetSelection().lock()->GetSubcomponentParent().expired()){
DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(Menu::menus[type]->GetSelection().lock())->GetLockButton().lock()->Click();
}
}}},
{game->KEY_SELECT,{[](MenuFuncData data){
if(!data.menu.GetSelection().expired()&&
!data.menu.GetSelection().lock()->parentComponent.expired()&&
data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){
if(DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){
return "Unlock";
}else{
return "Lock";
}
}
return "";
},[](MenuType type){
if(!Menu::menus[type]->GetSelection().expired()&&
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"
&&Menu::menus[type]->GetSelection().lock()->GetSubcomponentParent().expired()){
DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(Menu::menus[type]->GetSelection().lock())->GetLockButton().lock()->Click();
}
}}},
} }
,{ //Button Navigation Rules ,{ //Button Navigation Rules
{"Back Button",{ {"Back Button",{

@ -1262,4 +1262,15 @@ void Inventory::GivePlayerLoadoutItemsUsed(){
} }
} }
ResetLoadoutItemsUsed(); ResetLoadoutItemsUsed();
}
const bool Item::IsLocked()const{
return locked;
}
void Item::Lock(){
locked=true;
}
void Item::Unlock(){
locked=false;
} }

@ -174,6 +174,7 @@ private:
uint8_t enhancementLevel; uint8_t enhancementLevel;
ItemInfo*it; ItemInfo*it;
Stats randomizedStats; Stats randomizedStats;
bool locked=false;
void SetAmt(uint32_t newAmt); void SetAmt(uint32_t newAmt);
static ItemEnhancementFunctionPrimingData enhanceFunctionPrimed; static ItemEnhancementFunctionPrimingData enhanceFunctionPrimed;
@ -227,6 +228,9 @@ public:
static bool IsBlank(std::shared_ptr<Item>item); static bool IsBlank(std::shared_ptr<Item>item);
//Use ISBLANK macro instead!! This should not be called directly!! //Use ISBLANK macro instead!! This should not be called directly!!
static bool IsBlank(std::weak_ptr<Item>item); static bool IsBlank(std::weak_ptr<Item>item);
const bool IsLocked()const;
void Lock();
void Unlock();
friend const bool operator==(std::shared_ptr<Item>lhs,std::shared_ptr<Item>rhs){return lhs->it==rhs->it&&lhs->randomizedStats==rhs->randomizedStats;}; friend const bool operator==(std::shared_ptr<Item>lhs,std::shared_ptr<Item>rhs){return lhs->it==rhs->it&&lhs->randomizedStats==rhs->randomizedStats;};
friend const bool operator==(std::shared_ptr<Item>lhs,const IT&rhs){return lhs->ActualName()==const_cast<IT&>(rhs);}; friend const bool operator==(std::shared_ptr<Item>lhs,const IT&rhs){return lhs->ActualName()==const_cast<IT&>(rhs);};
friend const bool operator==(std::weak_ptr<Item>lhs,std::weak_ptr<Item>rhs){return !lhs.expired()&&!rhs.expired()&&lhs.lock()->it==rhs.lock()->it&&lhs.lock()->randomizedStats==rhs.lock()->randomizedStats;}; friend const bool operator==(std::weak_ptr<Item>lhs,std::weak_ptr<Item>rhs){return !lhs.expired()&&!rhs.expired()&&lhs.lock()->it==rhs.lock()->it&&lhs.lock()->randomizedStats==rhs.lock()->randomizedStats;};

@ -140,8 +140,10 @@ Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
void Menu::CheckClickAndPerformMenuSelect(AiL*game){ void Menu::CheckClickAndPerformMenuSelect(AiL*game){
if(game->KEY_CONFIRM.Released()&&!Menu::alreadyClicked&&(MOUSE_NAVIGATION||(!MOUSE_NAVIGATION&&!game->GetMouse(Mouse::LEFT).bReleased&&!game->GetMouse(Mouse::RIGHT).bReleased&&!game->GetMouse(Mouse::MIDDLE).bReleased))){ if(game->KEY_CONFIRM.Released()&&!Menu::alreadyClicked&&(MOUSE_NAVIGATION||(!MOUSE_NAVIGATION&&!game->GetMouse(Mouse::LEFT).bReleased&&!game->GetMouse(Mouse::RIGHT).bReleased&&!game->GetMouse(Mouse::MIDDLE).bReleased))){
if(!GetSelection().expired()){ //If we are on controller/gamepad it's possible we haven't highlighted a button yet, so don't click this button right away. if(!GetSelection().expired()){ //If we are on controller/gamepad it's possible we haven't highlighted a button yet, so don't click this button right away.
Menu*prevMenu=Menu::IsMenuOpen()?Menu::stack.back():nullptr;
MenuSelect(game); MenuSelect(game);
Menu::alreadyClicked=true; Menu*currentMenu=Menu::IsMenuOpen()?Menu::stack.back():nullptr;
if(prevMenu!=currentMenu)Menu::alreadyClicked=true; //The logic here is that only when we navigate between menus do we care about setting the already clicked flag to prevent further clicks going into the new screen. If we're still on the same menu, then we will proceed with regular inputs.
} }
} }
} }

@ -281,4 +281,8 @@ const bool MenuComponent::IsEnabledOutsideWindow()const{
} }
const bool MenuComponent::IsDisabledOutsideWindow()const{ const bool MenuComponent::IsDisabledOutsideWindow()const{
return disableOutsideWindow; return disableOutsideWindow;
}
const std::weak_ptr<MenuComponent>MenuComponent::GetSubcomponentParent()const{
return subcomponentParent;
} }

@ -98,6 +98,8 @@ private:
bool disableOutsideWindow=false; //If set to true, this component was automatically set to not be renderable outside the window. bool disableOutsideWindow=false; //If set to true, this component was automatically set to not be renderable outside the window.
bool disable=false; //If set to true, this component will not be rendered or updated. bool disable=false; //If set to true, this component will not be rendered or updated.
std::string label=""; std::string label="";
std::weak_ptr<MenuComponent>subcomponentParent; //For subcomponents, this value provides the actual component this subcomponent was spawned from.
protected: protected:
int depth=0; int depth=0;
float hoverEffect=0; float hoverEffect=0;
@ -168,4 +170,5 @@ public:
virtual void OnChapterUpdate(uint8_t newChapter); virtual void OnChapterUpdate(uint8_t newChapter);
virtual void Click(); virtual void Click();
virtual void SetLabel(std::string newLabel); virtual void SetLabel(std::string newLabel);
const std::weak_ptr<MenuComponent>GetSubcomponentParent()const;
}; };

@ -38,6 +38,7 @@ All rights reserved.
#include "Menu.h" #include "Menu.h"
#include "AdventuresInLestoria.h" #include "AdventuresInLestoria.h"
#include "AccessoryRowItemDisplay.h"
#include "RowInventoryScrollableWindowComponent.h" #include "RowInventoryScrollableWindowComponent.h"
#include "MenuItemItemButton.h" #include "MenuItemItemButton.h"
#include "MenuComponent.h" #include "MenuComponent.h"
@ -177,6 +178,10 @@ void Menu::InitializeMerchantWindow(){
auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect<float>{{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect<float>{{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label",
[](MenuFuncData data){ [](MenuFuncData data){
std::weak_ptr<RowItemDisplay>item=DYNAMIC_POINTER_CAST<RowItemDisplay>(data.component.lock()); std::weak_ptr<RowItemDisplay>item=DYNAMIC_POINTER_CAST<RowItemDisplay>(data.component.lock());
if(item.lock()->GetItem().lock()->IsLocked()){
SoundEffect::PlaySFX("Locked Item",SoundEffect::CENTERED);
return true;
}
if(item.lock()->GetItem().lock()->CanBeSold()){ if(item.lock()->GetItem().lock()->CanBeSold()){
Component<ItemMenuLabel>(SELL_ITEM,"Item Sell Header")->SetItem(item.lock()->GetItem()); Component<ItemMenuLabel>(SELL_ITEM,"Item Sell Header")->SetItem(item.lock()->GetItem());
Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue())); Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue()));
@ -330,6 +335,26 @@ void Menu::InitializeMerchantWindow(){
}}}, }}},
{{game->KEY_SCROLL,Pressed},{"Navigate",[](MenuType type){}}}, {{game->KEY_SCROLL,Pressed},{"Navigate",[](MenuType type){}}},
{game->KEY_CONFIRM,{"Select",[](MenuType type){}}}, {game->KEY_CONFIRM,{"Select",[](MenuType type){}}},
{game->KEY_SELECT,{[](MenuFuncData data){
/* //Too wordy, let's leave it out for now.
if(!data.menu.GetSelection().expired()&&
!data.menu.GetSelection().lock()->parentComponent.expired()&&
data.menu.GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"){
if(DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(data.menu.GetSelection().lock())->GetItem().lock()->IsLocked()){
return "Unlock";
}else{
return "Lock";
}
}*/
return "";
},[](MenuType type){
if(!Menu::menus[type]->GetSelection().expired()&&
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Inventory Display - Accessories"
&&Menu::menus[type]->GetSelection().lock()->GetSubcomponentParent().expired()){
DYNAMIC_POINTER_CAST<AccessoryRowItemDisplay>(Menu::menus[type]->GetSelection().lock())->GetLockButton().lock()->Click();
}
}}},
} }
,{ //Button Navigation Rules ,{ //Button Navigation Rules
{"Leave Button",{ {"Leave Button",{

@ -92,6 +92,7 @@ const void SaveFile::SaveGame(){
saveFile["Items"][std::format("Item[{}]",itemCount)]["Enhancement Level"].SetInt(item->EnhancementLevel()); saveFile["Items"][std::format("Item[{}]",itemCount)]["Enhancement Level"].SetInt(item->EnhancementLevel());
saveFile["Items"][std::format("Item[{}]",itemCount)]["Item Name"].SetString(item->ActualName()); saveFile["Items"][std::format("Item[{}]",itemCount)]["Item Name"].SetString(item->ActualName());
saveFile["Items"][std::format("Item[{}]",itemCount)]["Equip Slot"].SetInt(int(Inventory::GetSlotEquippedIn(item))); saveFile["Items"][std::format("Item[{}]",itemCount)]["Equip Slot"].SetInt(int(Inventory::GetSlotEquippedIn(item)));
saveFile["Items"][std::format("Item[{}]",itemCount)]["Locked"].SetBool(item->IsLocked());
uint8_t loadoutSlotNumber=255; uint8_t loadoutSlotNumber=255;
for(int i=0;i<game->loadout.size();i++){ for(int i=0;i<game->loadout.size();i++){
if(item==game->GetLoadoutItem(i)){loadoutSlotNumber=i;break;} if(item==game->GetLoadoutItem(i)){loadoutSlotNumber=i;break;}
@ -295,6 +296,13 @@ void SaveFile::LoadFile(){
if(slot!=EquipSlot::NONE){ //This should be equipped somewhere! if(slot!=EquipSlot::NONE){ //This should be equipped somewhere!
Inventory::EquipItem(newItem,slot); Inventory::EquipItem(newItem,slot);
} }
if(loadFile.GetProperty(std::format("Items.{}",key)).HasProperty("Locked")){
bool locked=loadFile.GetProperty(std::format("Items.{}",key))["Locked"].GetBool();
if(locked){
newItem.lock()->Lock();
}
}
} }
game->ChangePlayerClass(classutils::StringToClass(loadFile["Player"]["Class"].GetString())); game->ChangePlayerClass(classutils::StringToClass(loadFile["Player"]["Class"].GetString()));
game->GetPlayer()->SetLevel(loadFile["Player"]["Level"].GetInt()); game->GetPlayer()->SetLevel(loadFile["Player"]["Level"].GetInt());

@ -42,7 +42,7 @@ All rights reserved.
using A=Attribute; using A=Attribute;
#define ADDSUB(key,componentType) _AddSubcomponent<componentType>(key,std::make_shared<componentType> #define ADDSUB(key,componentType) _AddSubcomponent<componentType>(name,key,std::make_shared<componentType>
INCLUDE_game INCLUDE_game
@ -364,7 +364,7 @@ public:
} }
public: public:
template<class T> template<class T>
std::shared_ptr<T> _AddSubcomponent(std::string key,std::shared_ptr<T>button){ std::shared_ptr<T> _AddSubcomponent(std::string parentKey,std::string key,std::shared_ptr<T>button){
if(Menu::menus[parentMenu]->components.count(key)){ if(Menu::menus[parentMenu]->components.count(key)){
ERR("WARNING! Key "<<key<<" for menu"<<parentMenu<<" already exists! Key names must be unique!") ERR("WARNING! Key "<<key<<" for menu"<<parentMenu<<" already exists! Key names must be unique!")
} }
@ -377,6 +377,7 @@ public:
CalculateBounds(); CalculateBounds();
Menu::menus[parentMenu]->_AddComponent(key,button); Menu::menus[parentMenu]->_AddComponent(key,button);
button->subcomponentParent=Menu::menus[parentMenu]->components.at(parentKey);
return button; return button;
} }
template<class T> template<class T>

@ -8,8 +8,6 @@ Materials for initial craft seems to be wrong? need to recheck
do we need a minimap? (maybe with fog of war?) Maybe polling that once testing with more people. do we need a minimap? (maybe with fog of war?) Maybe polling that once testing with more people.
should gemstones dropp from boss stages aswell? (Maybe lower droprate?) should gemstones dropp from boss stages aswell? (Maybe lower droprate?)
feature to lock accesoires to protect them from selling would be nice
When opening craft/buy/sell menu, default to the appropriate button. When opening craft/buy/sell menu, default to the appropriate button.
Pressing back on the Select button of the equip menu causes you to exit the menu. Pressing back on the Select button of the equip menu causes you to exit the menu.
Funny text colors with text color override on blacksmith menu Funny text colors with text color override on blacksmith menu

@ -38,8 +38,8 @@ All rights reserved.
#pragma once #pragma once
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 4 #define VERSION_MINOR 4
#define VERSION_PATCH 4 #define VERSION_PATCH 5
#define VERSION_BUILD 7947 #define VERSION_BUILD 7966
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -79,6 +79,16 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = item_sell.ogg, 80% File[0] = item_sell.ogg, 80%
} }
Lock Accessory
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = button_click2.ogg, 40%
}
Unlock Accessory
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = button_click2.ogg, 60%, 50%, 60%
}
Locked Item Locked Item
{ {
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)

@ -79,6 +79,8 @@ Images
GFX_Ursule2 = monsters/Ursule Mother of Bears2.png GFX_Ursule2 = monsters/Ursule Mother of Bears2.png
GFX_Wisp = wisp.png GFX_Wisp = wisp.png
GFX_XPBar = xpbar.png GFX_XPBar = xpbar.png
GFX_Lock = lock.png
GFX_Unlock = unlock.png
# Ability Icons # Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Loading…
Cancel
Save