From 9fef977a3a8474ab3c70cce5733dbba12ecc35dd Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Fri, 29 Dec 2023 02:43:59 -0600 Subject: [PATCH] Add in consumable crafting. Allow specifying a quantity for item crafts. Add Flower Petals to Flower Turret drop table. --- Crawler/ConsumableCraftItemWindow.cpp | 101 +++++++++++++++++++ Crawler/ConsumableCraftingWindow.cpp | 17 ++-- Crawler/Crawler.cpp | 2 +- Crawler/Crawler.vcxproj | 4 + Crawler/Crawler.vcxproj.filters | 3 + Crawler/FunctionPriming.h | 4 +- Crawler/Item.cpp | 52 +++++++--- Crawler/Item.h | 4 +- Crawler/Menu.cpp | 1 + Crawler/Menu.h | 2 + Crawler/MenuLabel.h | 8 ++ Crawler/RequiredMaterialsList.h | 24 +++-- Crawler/Version.h | 2 +- Crawler/assets/config/Monsters.txt | 1 + Crawler/assets/config/items/ItemDatabase.txt | 6 +- Crawler/loc.sh | 3 + 16 files changed, 190 insertions(+), 44 deletions(-) create mode 100644 Crawler/ConsumableCraftItemWindow.cpp diff --git a/Crawler/ConsumableCraftItemWindow.cpp b/Crawler/ConsumableCraftItemWindow.cpp new file mode 100644 index 00000000..addfa138 --- /dev/null +++ b/Crawler/ConsumableCraftItemWindow.cpp @@ -0,0 +1,101 @@ +#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 "Menu.h" +#include "EnhancementStatsLabel.h" +#include "RequiredMaterialsList.h" +#include "Item.h" + +INCLUDE_ITEM_DATA +using A=Attribute; + +void Menu::InitializeConsumableCraftItemWindow(){ + Menu*consumableCraftItemWindow=CreateMenu(CONSUMABLE_CRAFT_ITEM,CENTERED,{240,96}); + + consumableCraftItemWindow->ADD("Item Name Header",MenuLabel)({{2,-4},{consumableCraftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + + static auto GetQuantity=[&](){ + return std::stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); + }; + + static auto UpdateMenu=[&](std::string_view label){ + uint8_t qty=std::stoi(std::string(label)); + + const std::string&item=Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->GetString(A::ITEM_NAME); + bool canCraft=Item(qty,item).CanEnhanceItem(qty); + + std::string colorCode=""; + if(!canCraft)colorCode="#FF0000"; + Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->SetQuantity(qty); + Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!canCraft); + }; + + consumableCraftItemWindow->ADD("Amount to Craft Label",MenuLabel)({{4,34},{188,12}},"Craft Amount",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftItemWindow->ADD("Amount to Craft Amount Label",MenuLabel)({{consumableCraftItemWindow->size.x/2+48,34},{32,12}},"1" + ,UpdateMenu,1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; + + consumableCraftItemWindow->ADD("Increase Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + uint8_t qty=std::clamp(GetQuantity()+1,1,99); + Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); + return true; + })END; + consumableCraftItemWindow->ADD("Decrease Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + uint8_t qty=std::clamp(GetQuantity()-1,1,99); + Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); + return true; + })END; + + consumableCraftItemWindow->ADD("Materials Requirement Outline",MenuComponent)({{2,86-18},{consumableCraftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + consumableCraftItemWindow->ADD("Required Materials Label",MenuLabel)({{4,80-18},{consumableCraftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; + + consumableCraftItemWindow->ADD("Required Materials List",RequiredMaterialsList)({{4,88-18},{consumableCraftItemWindow->size.x-8,22}},Item::BLANK)END; + + consumableCraftItemWindow->ADD("Back Button",MenuComponent)({{36,116-18},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + consumableCraftItemWindow->ADD("Craft Button",MenuComponent)({{consumableCraftItemWindow->size.x-84,116-18},{48,12}},"Craft",[](MenuFuncData data){ + const std::weak_ptritem=Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->GetItem(); + uint8_t qty=stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); + + for(uint8_t i=0;iCanEnhanceItem(qty)){ + item.lock()->EnhanceItem(qty); + } + } + data.component->SetGrayedOut(!item.lock()->CanEnhanceItem(qty)); + return true; + })END; +} \ No newline at end of file diff --git a/Crawler/ConsumableCraftingWindow.cpp b/Crawler/ConsumableCraftingWindow.cpp index 7527fd70..d20d8880 100644 --- a/Crawler/ConsumableCraftingWindow.cpp +++ b/Crawler/ConsumableCraftingWindow.cpp @@ -57,17 +57,12 @@ void Menu::InitializeConsumableCraftingWindow(){ [](MenuFuncData data){ RowItemDisplay*comp=DYNAMIC_CAST(data.component); const std::weak_ptritem=comp->GetItem(); - - std::string label=""; - if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){ - label=std::format("Level {} ->#00AA00 {}",item.lock()->EnhancementLevel(),item.lock()->EnhancementLevel()+1); - } - Component(CRAFT_ITEM,"Enhancement Level Header")->SetLabel(label); - Component(CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName())); - Component(CRAFT_ITEM,"Enhancement Stats Label")->SetItem(item); - Component(CRAFT_ITEM,"Required Materials List")->SetItem(item); - Component(CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem()); - Menu::OpenMenu(CRAFT_ITEM); + Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->GetString(A::ITEM_NAME)=item.lock()->ActualName(); + Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel("1"); + Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName())); + Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->SetItem(item); + Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem()); + Menu::OpenMenu(CONSUMABLE_CRAFT_ITEM); return true; }, [](MenuFuncData data){ diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index f469dff7..409d63c7 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -192,7 +192,7 @@ bool Crawler::OnUserCreate(){ Inventory::AddItem("Minor Health Potion",16); Inventory::AddItem("Bandages",10); - Inventory::AddItem("Green Slime Remains",1); + Inventory::AddItem("Green Slime Remains",40); Inventory::AddItem("Blue Slime Remains",22); Inventory::AddItem("Copper Armor"); Inventory::AddItem("Copper Pants"); diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj index aa06174c..2de000eb 100644 --- a/Crawler/Crawler.vcxproj +++ b/Crawler/Crawler.vcxproj @@ -472,6 +472,10 @@ + + + + diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters index 10cf9119..a0790faa 100644 --- a/Crawler/Crawler.vcxproj.filters +++ b/Crawler/Crawler.vcxproj.filters @@ -647,6 +647,9 @@ Source Files\Interface + + Source Files\Interface + diff --git a/Crawler/FunctionPriming.h b/Crawler/FunctionPriming.h index 5d0b41b6..1c90ecba 100644 --- a/Crawler/FunctionPriming.h +++ b/Crawler/FunctionPriming.h @@ -69,11 +69,13 @@ struct MerchantFunctionPrimingData:public FunctionPrimingData{ struct ItemEnhancementFunctionPrimingData:public FunctionPrimingData{ IT item=""; uint8_t enhancementLevel=0; + uint8_t qty=0; inline ItemEnhancementFunctionPrimingData(std::string dependentFunction) :FunctionPrimingData(dependentFunction){} - virtual inline void Validate(IT item,uint8_t enhancementLevel){ + virtual inline void Validate(IT item,uint8_t enhancementLevel,uint8_t qty){ if(!primed)ERR(std::format("WARNING! {} should be called before running this function! Priming Requirement!",dependentFunction)); if(this->item!=item)ERR(std::format("WARNING! Primed items are not matching! {}!={}",this->item,item)); + if(this->qty!=qty)ERR(std::format("WARNING! Primed items do not have the same quantity! {}!={}",this->qty,qty)); if(this->enhancementLevel!=enhancementLevel)ERR(std::format("WARNING! Primed enhancement levels are not matching! {}!={}",this->enhancementLevel,enhancementLevel)); primed=false; } diff --git a/Crawler/Item.cpp b/Crawler/Item.cpp index 417ebc3b..7fd9ca9d 100644 --- a/Crawler/Item.cpp +++ b/Crawler/Item.cpp @@ -247,6 +247,8 @@ void ItemInfo::InitializeItems(){ ReadItems(DATA["ItemDatabase"]); ReadItems(DATA["Equipment"]); + + std::sort(craftableConsumables.begin(),craftableConsumables.end(),[](std::shared_ptr&item1,std::shared_ptr&item2){return item1.get()->GetEnhancementInfo().AvailableChapter()GetEnhancementInfo().AvailableChapter();}); ITEM_DATA.SetInitialized(); ITEM_CATEGORIES.SetInitialized(); @@ -557,10 +559,13 @@ const std::string Item::Description(CompactText compact)const{ Inventory::GetItemCount(name)); } description+="\n"; - description+=std::format("{}Crafting Cost: {} {}", - game->GetPlayer()->GetMoney()0){ + description+=std::format("{}Crafting Cost: {} {}", + game->GetPlayer()->GetMoney()Item::ItemSet()const{ const uint8_t Item::EnhancementLevel()const{ return enhancementLevel; }; -void Item::EnhanceItem(){ - enhanceFunctionPrimed.Validate(ActualName(),EnhancementLevel()); - - if(enhancementLevel+1>"Item.Item Max Enhancement Level"_I)ERR("WARNING! Attempted to enhance "<"Item.Item Max Enhancement Level"_I)ERR("WARNING! Attempted to enhance "<GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost()); + }else{ //This is a craftable, so we have to give the player the item they crafted. + Inventory::AddItem(ActualName()); + + const CraftingRequirement&consumedResources=GetEnhancementInfo()[1].craftingRequirement; - for(const auto&[name,amt]:consumedResources.GetItems()){ - Inventory::RemoveItem(name,amt); + for(const auto&[name,amt]:consumedResources.GetItems()){ + Inventory::RemoveItem(name,amt); + } + game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost()); + } } - game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost()); }; const std::vector>&ItemSet::GetSetBonusBreakpoints()const{ @@ -917,7 +935,8 @@ void EnhancementInfo::SetCraftingRequirements(const int enhanceLevel,const std:: EnhancementLevelInfo::EnhancementLevelInfo(const Stats&stats,const CraftingRequirement&craftingRequirement) :stats(stats),craftingRequirement(craftingRequirement){} -const bool Item::CanEnhanceItem()const{ +const bool Item::CanEnhanceItem(uint8_t qty)const{ + if(qty==0)ERR("WARNING! Must specify at least 1 for the quantity!") if(ISBLANK(std::make_shared(*this)))return false; if(!GetEnhancementInfo().CanBeEnhanced())return false; if(GetEnhancementInfo().AvailableChapter()GetCurrentChapter())return false; @@ -925,15 +944,16 @@ const bool Item::CanEnhanceItem()const{ if(GetEnhancementInfo().size()>2){ //If the item has exactly 2 enhancement levels, then it's an item that can only simply be crafted. Therefore, don't do the max enhancement level check. if(EnhancementLevel()>="Item.Item Max Enhancement Level"_I)return false; } - if(game->GetPlayer()->GetMoney()GetPlayer()->GetMoney()BLANK; const std::optionalItemSet()const; const bool IsEquippable()const; diff --git a/Crawler/Menu.cpp b/Crawler/Menu.cpp index f424c0b9..4f47dbee 100644 --- a/Crawler/Menu.cpp +++ b/Crawler/Menu.cpp @@ -110,6 +110,7 @@ void Menu::InitializeMenus(){ InitializeBlacksmithCraftingWindow(); InitializeCraftItemWindow(); InitializeConsumableCraftingWindow(); + InitializeConsumableCraftItemWindow(); for(MenuType type=MenuType(int(MenuType::ENUM_START)+1);typeonLabelChangeFunc; public: + inline MenuLabel(geom2d::rectrect,std::string label,std::functiononLabelChangeFunc,float scale=1,ComponentAttr attributes=ComponentAttr::NONE) + :MenuLabel(rect,label,scale,attributes){ + runOnLabelChangeFunc=true; + this->onLabelChangeFunc=onLabelChangeFunc; + } inline MenuLabel(geom2d::rectrect,std::string label,float scale=1,ComponentAttr attributes=ComponentAttr::NONE) :MenuComponent(rect,label,MenuFunc{},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD),scale(scale),centered(!(attributes&ComponentAttr::LEFT_ALIGN)),shadow(attributes&ComponentAttr::SHADOW),proportional(!(attributes&ComponentAttr::FIXED_WIDTH_FONT)){ border=attributes&ComponentAttr::OUTLINE; @@ -60,6 +67,7 @@ public: } inline virtual void SetLabel(std::string text){ label=text; + if(runOnLabelChangeFunc)onLabelChangeFunc(text); } protected: inline virtual void Update(Crawler*game)override{ diff --git a/Crawler/RequiredMaterialsList.h b/Crawler/RequiredMaterialsList.h index e0958ed9..4ca86958 100644 --- a/Crawler/RequiredMaterialsList.h +++ b/Crawler/RequiredMaterialsList.h @@ -42,6 +42,7 @@ All rights reserved. class RequiredMaterialsList:public MenuLabel{ std::weak_ptritemRef; + uint8_t qty=1; public: inline RequiredMaterialsList(geom2d::rectrect,const std::weak_ptritemRef,ComponentAttr attributes=ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN) :MenuLabel(rect,"",1.f,attributes),itemRef(itemRef){} @@ -51,6 +52,9 @@ public: inline const std::weak_ptrGetItem()const{ return itemRef; } + inline void SetQuantity(uint8_t quantity){ + this->qty=quantity; + } protected: inline virtual void DrawDecal(ViewPort&window,bool focused)override final{ MenuComponent::DrawDecal(window,focused); @@ -70,23 +74,25 @@ protected: int index=0; for(const auto&[name,amt]:itemRef.lock()->GetEnhancementInfo()[itemRef.lock()->EnhancementLevel()+1].craftingRequirement.GetItems()){ Pixel textCol=WHITE; - if(Inventory::GetItemCount(name)GetTextSizeProp(labelText).x; - window.DrawShadowStringDecal(drawPos,std::format("{:>3}",amt),textCol,BLACK); + window.DrawShadowStringDecal(drawPos,std::format("{:>3}",amt*qty),textCol,BLACK); window.DrawShadowStringPropDecal(drawPos+vf2d{26,0},labelText,textCol,BLACK,{std::min(1.f,(drawWidth-26-2)/labelWidth),1.f}); index++; } Pixel textCol=WHITE; uint32_t goldAmt=itemRef.lock()->GetEnhancementInfo()[itemRef.lock()->EnhancementLevel()+1].craftingRequirement.GetCost(); - if(game->GetPlayer()->GetMoney()3}",goldAmt); - std::string labelText=std::format("{}","Item.Currency Name"_S); - float goldAmtWidth=game->GetTextSize(goldAmtText).x; - window.DrawShadowStringDecal(drawPos,goldAmtText,textCol,BLACK); - window.DrawShadowStringPropDecal(drawPos+vf2d{goldAmtWidth+2,0},labelText,textCol,BLACK); + if(goldAmt>0){ + if(game->GetPlayer()->GetMoney()3}",goldAmt*qty); + std::string labelText=std::format("{}","Item.Currency Name"_S); + float goldAmtWidth=game->GetTextSize(goldAmtText).x; + window.DrawShadowStringDecal(drawPos,goldAmtText,textCol,BLACK); + window.DrawShadowStringPropDecal(drawPos+vf2d{goldAmtWidth+2,0},labelText,textCol,BLACK); + } index++; } } diff --git a/Crawler/Version.h b/Crawler/Version.h index edc7eab8..5eaf4523 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5056 +#define VERSION_BUILD 5077 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/config/Monsters.txt b/Crawler/assets/config/Monsters.txt index 2bd9e346..08a37b29 100644 --- a/Crawler/assets/config/Monsters.txt +++ b/Crawler/assets/config/Monsters.txt @@ -150,6 +150,7 @@ Monsters # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DROP[0] = Bandages,30%,1,1 DROP[1] = Berries,5%,1,1 + DROP[2] = Flower Petals,10%,1,1 #Additional custom animations go down below. Start with ANIMATION[0] #ANIMATION[0] = MY_NEW_ANIMATION diff --git a/Crawler/assets/config/items/ItemDatabase.txt b/Crawler/assets/config/items/ItemDatabase.txt index 4047ace7..828f40cb 100644 --- a/Crawler/assets/config/items/ItemDatabase.txt +++ b/Crawler/assets/config/items/ItemDatabase.txt @@ -29,7 +29,7 @@ ItemDatabase Item[0] = Green Slime Remains,3 Item[1] = Blue Slime Remains,1 - Gold = 0 + Gold = 10 } } Minor Mana Potion @@ -45,7 +45,7 @@ ItemDatabase Crafting { # When this crafting recipe is available. - AvailableChapter = 1 + AvailableChapter = 2 Item[0] = Red Slime Remains,1 Item[1] = Yellow Slime Remains,1 @@ -86,7 +86,7 @@ ItemDatabase Crafting { # When this crafting recipe is available. - AvailableChapter = 2 + AvailableChapter = 1 Item[0] = Bear Claw,1 Item[1] = Bear Blood,1 diff --git a/Crawler/loc.sh b/Crawler/loc.sh index 1af1ec79..592158eb 100755 --- a/Crawler/loc.sh +++ b/Crawler/loc.sh @@ -1,3 +1,6 @@ +ALLTOTAL=$(wc -l $(find *.cpp *.h)|grep "total"|awk '{print $1}') + TOTAL=$(wc -l $(find *.cpp *.h -not -name "miniaudio.h" -not -name "olc*.h")|grep "total"|awk '{print $1}') FILECOUNT=$(find *.cpp *.h -not -name "miniaudio.h" -not -name "olc*.h"|wc -l) +echo "ALL: $[ALLTOTAL]" echo "$[TOTAL-FILECOUNT*37] (License lines Excluded)"