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.

This commit is contained in:
sigonasr2 2024-03-05 06:05:28 -06:00
parent 7ce1e37549
commit 2c81cf15f2
18 changed files with 148 additions and 11 deletions

View File

@ -37,12 +37,14 @@ All rights reserved.
#pragma endregion
#pragma once
#include "RowItemDisplay.h"
#include "SoundEffect.h"
#include "MenuIconButton.h"
INCLUDE_game
INCLUDE_GFX
class AccessoryRowItemDisplay:public RowItemDisplay{
std::weak_ptr<MenuComponent>lockButton;
std::weak_ptr<MenuIconButton>lockButton;
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)
:RowItemDisplay(rect,itemRef,onClick,itemNameLabelName,itemDescriptionLabelName,attributes){}
@ -54,9 +56,38 @@ public:
lockButton.reset();
}
}
virtual 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){
inline void AfterCreate()override final{
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;
})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;
}
};

View File

@ -46,6 +46,7 @@ All rights reserved.
#include "RowItemDisplay.h"
#include "PlayerMoneyLabel.h"
#include "SoundEffect.h"
#include "AccessoryRowItemDisplay.h"
INCLUDE_game
INCLUDE_ITEM_CATEGORIES
@ -202,7 +203,44 @@ void Menu::InitializeInventoryWindow(){
}
}}},
{{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
{"Back Button",{

View File

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

View File

@ -174,6 +174,7 @@ private:
uint8_t enhancementLevel;
ItemInfo*it;
Stats randomizedStats;
bool locked=false;
void SetAmt(uint32_t newAmt);
static ItemEnhancementFunctionPrimingData enhanceFunctionPrimed;
@ -227,6 +228,9 @@ public:
static bool IsBlank(std::shared_ptr<Item>item);
//Use ISBLANK macro instead!! This should not be called directly!!
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,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;};

View File

@ -140,8 +140,10 @@ Menu*Menu::CreateMenu(MenuType type,vf2d pos,vf2d size){
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(!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);
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.
}
}
}

View File

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

View File

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

View File

@ -38,6 +38,7 @@ All rights reserved.
#include "Menu.h"
#include "AdventuresInLestoria.h"
#include "AccessoryRowItemDisplay.h"
#include "RowInventoryScrollableWindowComponent.h"
#include "MenuItemItemButton.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",
[](MenuFuncData data){
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()){
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()));
@ -330,6 +335,26 @@ void Menu::InitializeMerchantWindow(){
}}},
{{game->KEY_SCROLL,Pressed},{"Navigate",[](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
{"Leave Button",{

View File

@ -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)]["Item Name"].SetString(item->ActualName());
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;
for(int i=0;i<game->loadout.size();i++){
if(item==game->GetLoadoutItem(i)){loadoutSlotNumber=i;break;}
@ -295,6 +296,13 @@ void SaveFile::LoadFile(){
if(slot!=EquipSlot::NONE){ //This should be equipped somewhere!
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->GetPlayer()->SetLevel(loadFile["Player"]["Level"].GetInt());

View File

@ -42,7 +42,7 @@ All rights reserved.
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
@ -364,7 +364,7 @@ public:
}
public:
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)){
ERR("WARNING! Key "<<key<<" for menu"<<parentMenu<<" already exists! Key names must be unique!")
}
@ -377,6 +377,7 @@ public:
CalculateBounds();
Menu::menus[parentMenu]->_AddComponent(key,button);
button->subcomponentParent=Menu::menus[parentMenu]->components.at(parentKey);
return button;
}
template<class T>

View File

@ -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.
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.
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

View File

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

View File

@ -79,6 +79,16 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
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
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)

View File

@ -79,6 +79,8 @@ Images
GFX_Ursule2 = monsters/Ursule Mother of Bears2.png
GFX_Wisp = wisp.png
GFX_XPBar = xpbar.png
GFX_Lock = lock.png
GFX_Unlock = unlock.png
# Ability Icons
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