From ad1e2260cfd811aa45afaa4dabfefe27c32c6378 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Mon, 1 Jan 2024 07:48:57 -0600 Subject: [PATCH] Saving and loading saves items in proper sorted order. Fixed bug with get inventory slot function. Connection point data is now static. --- .gitignore | 1 + Crawler/ConnectionPoint.h | 2 + Crawler/Crawler.cpp | 6 +- Crawler/Crawler.vcxproj | 8 + Crawler/Crawler.vcxproj.filters | 6 + Crawler/Item.cpp | 27 +-- Crawler/LoadFileButton.h | 64 +++++ Crawler/LoadGameWindow.cpp | 46 ++++ Crawler/MainMenuWindow.cpp | 12 +- Crawler/Menu.cpp | 1 + Crawler/Menu.h | 2 + Crawler/MenuComponent.cpp | 4 + Crawler/MenuComponent.h | 1 + Crawler/OverworldMenuWindow.cpp | 6 +- Crawler/SaveFile.cpp | 82 +++++-- Crawler/SaveFile.h | 2 + Crawler/ScrollableWindowComponent.h | 6 +- Crawler/State_OverworldMap.cpp | 17 +- Crawler/State_OverworldMap.h | 5 +- Crawler/TODO.txt | 10 + Crawler/Version.h | 2 +- Crawler/assets/saves/save.0000 | 354 ---------------------------- Crawler/olcPixelGameEngine.h | 5 + Crawler/olcUTIL_DataFile.h | 8 + 24 files changed, 271 insertions(+), 406 deletions(-) create mode 100644 Crawler/LoadFileButton.h create mode 100644 Crawler/LoadGameWindow.cpp delete mode 100644 Crawler/assets/saves/save.0000 diff --git a/.gitignore b/.gitignore index 0a633322..4e33477c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ memoryleak.txt [Dd]ebugPublic/ *.tlog/ Crawler/x64/ +Crawler/assets/saves/ [Rr]eleases/ x86/ [Ww][Ii][Nn]32/ diff --git a/Crawler/ConnectionPoint.h b/Crawler/ConnectionPoint.h index 5cda4da5..f24be593 100644 --- a/Crawler/ConnectionPoint.h +++ b/Crawler/ConnectionPoint.h @@ -39,6 +39,7 @@ All rights reserved. #include "olcUTIL_Geometry2D.h" struct ConnectionPoint{ + friend class State_OverworldMap; geom2d::rectrect; std::string type; std::string name; @@ -52,4 +53,5 @@ struct ConnectionPoint{ neighbors.fill(-1); } bool IsNeighbor(ConnectionPoint&testPoint); + static void UpdateCurrentConnectionPoint(const ConnectionPoint&connection); }; diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 2d1fa661..f23bf084 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -2540,7 +2540,7 @@ void Crawler::InitializePlayerLevelCap(){ } void Crawler::ResetGame(){ - GameState::ChangeState(States::OVERWORLD_MAP,0.5f); + GameState::ChangeState(States::MAIN_MENU,0.5f); for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){ Inventory::UnequipItem(EquipSlot(i)); } @@ -2551,9 +2551,11 @@ void Crawler::ResetGame(){ player->stats.Reset(); player->ResetAccumulatedXP(); player->totalXPEarned=0; + player->SetMoney(100U); Unlock::unlocks.clear(); Unlock::Initialize(); - DYNAMIC_CAST(GameState::STATE)->SetStageMarker("Stage I-I"); + State_OverworldMap::SetStageMarker("Stage I-I"); + State_OverworldMap::UpdateCurrentConnectionPoint(*State_OverworldMap::currentConnectionPoint); SetChapter(1); SaveFile::SetSaveFileName(""); } \ No newline at end of file diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj index 023a5249..0662f107 100644 --- a/Crawler/Crawler.vcxproj +++ b/Crawler/Crawler.vcxproj @@ -355,6 +355,10 @@ + + + + @@ -535,6 +539,10 @@ + + + + diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters index 7737272b..c7c8e8fa 100644 --- a/Crawler/Crawler.vcxproj.filters +++ b/Crawler/Crawler.vcxproj.filters @@ -396,6 +396,9 @@ Header Files + + Header Files\Interface + @@ -665,6 +668,9 @@ Source Files + + Source Files\Interface + diff --git a/Crawler/Item.cpp b/Crawler/Item.cpp index 273f9b86..9acaa0ef 100644 --- a/Crawler/Item.cpp +++ b/Crawler/Item.cpp @@ -488,7 +488,14 @@ bool Inventory::RemoveItem(std::weak_ptritemRef,ITCategory inventory,uint3 return true; }else{ if(itemRef.lock()->IsEquippable()){ //Since equipment doesn't stack, if we have more than one piece we have to still remove that piece. - size_t erased=std::erase_if(_inventory,[&](const std::pair>data){return data.second==itemRef;}); + bool found=false; + size_t erased=std::erase_if(_inventory,[&](const std::pair>data){ + if(!found&&data.second==itemRef){ + found=true; + return true; + } + return false; + }); if(erased!=1)ERR(std::format("Did not erase a single element, instead erased {} elements.",erased)); inv.erase(inv.begin()+count); //Clears it from the detected sorted inventory as well! Menu::InventorySlotsUpdated(inventory); @@ -664,11 +671,7 @@ const bool Item::IsBlank()const{ void Inventory::Clear(ITCategory itemCategory){ std::vector>itemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline. for(std::shared_ptr&item:itemList){ - size_t itemQuantity=GetItemCount(item->ActualName());//Normally we want to clear all the items that are actually in our inventory...But... - if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){//These do not affect the actual inventory, we just clear the lists. - itemQuantity=item->Amt(); - } - RemoveItem(item,itemCategory,uint32_t(itemQuantity)); + RemoveItem(item,itemCategory,item->Amt()); } } @@ -930,17 +933,7 @@ void Item::SetAmt(uint32_t newAmt){ } const std::weak_ptrInventory::GetInventorySlot(ITCategory itemCategory,size_t slot){ - auto GetFirstIndex = [](ITCategory itemCategory,size_t slot){ - auto firstIter=std::find_if(get(itemCategory).begin(),get(itemCategory).end(),[&](std::shared_ptritem){ - if(item->ActualName()==get(itemCategory).at(slot)->ActualName())return true; - return false; - }); - size_t firstIndex=firstIter-get(itemCategory).begin(); - if(firstIter==get(itemCategory).end())ERR(std::format("Invalid slot {} for category {} specified!",slot,itemCategory)); - return firstIndex; - }; - - return GetItem(get(itemCategory).at(slot)->ActualName())[slot-GetFirstIndex(itemCategory,slot)]; + return get(itemCategory).at(slot); } bool Item::IsBlank(std::shared_ptritem){ diff --git a/Crawler/LoadFileButton.h b/Crawler/LoadFileButton.h new file mode 100644 index 00000000..2e08842e --- /dev/null +++ b/Crawler/LoadFileButton.h @@ -0,0 +1,64 @@ +#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 +#pragma once + +#include "MenuComponent.h" + +class LoadFileButton:public MenuComponent{ + double playTime; + int chapter; + int level; + std::string className; + std::string saveFileName; + int saveFileID; +public: + inline LoadFileButton(geom2d::rectrect,const utils::datafile&metadata,const int saveFileID,MenuFunc onClick,ButtonAttr attributes) + :MenuComponent(rect,"",onClick,attributes),playTime(metadata.GetReal(0U)),chapter(metadata.GetInt(1U)),level(metadata.GetInt(2U)),className(metadata.GetString(3U)),saveFileName(metadata.GetString(4U)),saveFileID(saveFileID){ + showDefaultLabel=false; + } + + inline void DrawDecal(ViewPort&window,bool focused){ + MenuComponent::DrawDecal(window,focused); + + + } + + inline const int&getSaveFileID()const{ + return saveFileID; + } +}; \ No newline at end of file diff --git a/Crawler/LoadGameWindow.cpp b/Crawler/LoadGameWindow.cpp new file mode 100644 index 00000000..0548f0f7 --- /dev/null +++ b/Crawler/LoadGameWindow.cpp @@ -0,0 +1,46 @@ +#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 "ScrollableWindowComponent.h" + +void Menu::InitializeLoadGameWindow(){ + Menu*loadGameWindow=CreateMenu(LOAD_GAME,CENTERED,vi2d{96,96}); + + loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)({{-8,0},{112,104}})END; +} \ No newline at end of file diff --git a/Crawler/MainMenuWindow.cpp b/Crawler/MainMenuWindow.cpp index a26d9b5e..3353da89 100644 --- a/Crawler/MainMenuWindow.cpp +++ b/Crawler/MainMenuWindow.cpp @@ -39,6 +39,7 @@ All rights reserved. #include "DEFINES.h" #include "Menu.h" #include "MenuComponent.h" +#include "SaveFile.h" INCLUDE_game using A=Attribute; @@ -51,6 +52,13 @@ void Menu::InitializeMainMenuWindow(){ Menu::OpenMenu(SAVE_FILE_NAME); return true; })END; - mainMenuWindow->ADD("Load Game Button",MenuComponent)({{12,36},{72,24}},"Load Game",DO_NOTHING)END; - mainMenuWindow->ADD("Quit Game Button",MenuComponent)({{12,68},{72,24}},"Quit Game",DO_NOTHING)END; + mainMenuWindow->ADD("Load Game Button",MenuComponent)({{12,36},{72,24}},"Load Game",[](MenuFuncData data){ + SaveFile::UpdateSaveGameData(); + Menu::OpenMenu(LOAD_GAME); + return true; + })END; + mainMenuWindow->ADD("Quit Game Button",MenuComponent)({{12,68},{72,24}},"Quit Game",[](MenuFuncData data){ + game->EndGame(); + return true; + })END; } \ No newline at end of file diff --git a/Crawler/Menu.cpp b/Crawler/Menu.cpp index bb30542a..a1499dd2 100644 --- a/Crawler/Menu.cpp +++ b/Crawler/Menu.cpp @@ -112,6 +112,7 @@ void Menu::InitializeMenus(){ InitializeConsumableCraftingWindow(); InitializeConsumableCraftItemWindow(); InitializeSaveFileWindow(); + InitializeLoadGameWindow(); for(MenuType type=MenuType(int(MenuType::ENUM_START)+1);typerect,std::string label,MenuType menuDest,MenuFunc onClick,vf2d labelScaling,ButtonAttr attributes=ButtonAttr::NONE); virtual ~MenuComponent(); vf2d GetPos(); + const vf2d&GetSize()const; //We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed. //WARNING!!! This allocates a brand new component when successful!!! Be prepared to clear it! virtual MenuComponent*PickUpDraggableItem(); diff --git a/Crawler/OverworldMenuWindow.cpp b/Crawler/OverworldMenuWindow.cpp index 6386e026..208b54e6 100644 --- a/Crawler/OverworldMenuWindow.cpp +++ b/Crawler/OverworldMenuWindow.cpp @@ -56,5 +56,9 @@ void Menu::InitializeOverworldMenuWindow(){ })END; overworldMenuWindow->ADD("Inventory Button",MenuComponent)({{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END; overworldMenuWindow->ADD("Settings Button",MenuComponent)({{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END; - overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){game->EndGame();return true;})END; + overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){ + Menu::CloseAllMenus(); + game->ResetGame(); + return true; + })END; } \ No newline at end of file diff --git a/Crawler/SaveFile.cpp b/Crawler/SaveFile.cpp index 0eb7771f..062ea50b 100644 --- a/Crawler/SaveFile.cpp +++ b/Crawler/SaveFile.cpp @@ -43,6 +43,8 @@ All rights reserved. #include "State_OverworldMap.h" #include "SaveFile.h" #include "ClassInfo.h" +#include "ScrollableWindowComponent.h" +#include "LoadFileButton.h" INCLUDE_game @@ -62,18 +64,21 @@ const size_t SaveFile::GetSaveFileCount(){ const void SaveFile::SaveGame(){ utils::datafile saveFile; utils::datafile::INITIAL_SETUP_COMPLETE=false; - for(size_t itemCount=0;auto&[name,item]:Inventory::_inventory){ - saveFile["Items"][std::format("Item[{}]",itemCount)]["Amt"].SetInt(item->Amt()); - 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))); - for(const auto&[attr,val]:item->RandomStats()){ - saveFile["Items"][std::format("Item[{}]",itemCount)]["Attributes"][std::string(attr.ActualName())].SetReal(val); + for(size_t itemCount=0;auto&[cat,items]:Inventory::sortedInv){ + for(std::shared_ptr&item:items){ + saveFile["Items"][std::format("Item[{}]",itemCount)]["Amt"].SetInt(item->Amt()); + 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))); + for(const auto&[attr,val]:item->RandomStats()){ + saveFile["Items"][std::format("Item[{}]",itemCount)]["Attributes"][std::string(attr.ActualName())].SetReal(val); + } + itemCount++; } - itemCount++; } saveFile["Player"]["Class"].SetString(game->GetPlayer()->GetClassName()); saveFile["Player"]["Level"].SetInt(game->GetPlayer()->Level()); + saveFile["Player"]["Money"].SetInt(game->GetPlayer()->GetMoney()); saveFile["Player"]["Current EXP"].SetInt(game->GetPlayer()->CurrentXP()); saveFile["Player"]["Total EXP"].SetInt(game->GetPlayer()->TotalXP()); for(const auto&[attr,val]:game->GetPlayer()->GetBaseStats()){ @@ -85,39 +90,56 @@ const void SaveFile::SaveGame(){ saveFile["Overworld Map Location"].SetString(State_OverworldMap::GetCurrentConnectionPoint().name); saveFile["Chapter"].SetInt(game->GetCurrentChapter()); saveFile["Save Name"].SetString(std::string(GetSaveFileName())); - utils::datafile::INITIAL_SETUP_COMPLETE=true; + saveFile["Game Time"].SetReal(game->GetRuntime()); utils::datafile::Write(saveFile,"save_file_path"_S+std::format("save.{:04}",saveFileID)); + + utils::datafile metadata; + utils::datafile::Read(metadata,"save_file_path"_S+"metadata.dat"); + metadata.GetProperty(std::format("save{}",saveFileID)).SetReal(game->GetRuntime(),0U); + metadata.GetProperty(std::format("save{}",saveFileID)).SetInt(game->GetCurrentChapter(),1U); + metadata.GetProperty(std::format("save{}",saveFileID)).SetInt(game->GetPlayer()->Level(),2U); + metadata.GetProperty(std::format("save{}",saveFileID)).SetString(game->GetPlayer()->GetClassName(),3U); + metadata.GetProperty(std::format("save{}",saveFileID)).SetString(std::string(SaveFile::GetSaveFileName()),4U); + utils::datafile::Write(metadata,"save_file_path"_S+"metadata.dat"); + + utils::datafile::INITIAL_SETUP_COMPLETE=true; } const void SaveFile::LoadGame(){ utils::datafile loadFile; utils::datafile::Read(loadFile,"save_file_path"_S+std::format("save.{:04}",saveFileID)); game->ResetGame(); - for(auto&[key,size]:loadFile["Items"]){ - std::weak_ptrnewItem=Inventory::AddItem(loadFile["Items"][key]["Item Name"].GetString(),loadFile["Items"][key]["Amt"].GetInt()); - newItem.lock()->enhancementLevel=loadFile["Items"][key]["Enhancement Level"].GetInt(); - for(auto&[attr,size]:loadFile.GetProperty(std::format("{}.Attributes",key))){ - newItem.lock()->randomizedStats.A(attr)=loadFile.GetProperty(std::format("{}.Attributes.{}",key,attr)).GetReal(); + for(auto&[key,data]:loadFile["Items"].GetOrderedKeys()){ + std::weak_ptrnewItem=Inventory::AddItem(data["Item Name"].GetString(),data["Amt"].GetInt()); + newItem.lock()->enhancementLevel=data["Enhancement Level"].GetInt(); + if(loadFile.GetProperty(std::format("Items.{}",key)).HasProperty("Attributes")){ + for(auto&[attr,data]:loadFile.GetProperty(std::format("Items.{}.Attributes",key)).GetOrderedKeys()){ + newItem.lock()->randomizedStats.A(attr)=data.GetReal(); + } } - EquipSlot slot=EquipSlot(loadFile.GetProperty(std::format("{}.Equip Slot",key)).GetInt()); + EquipSlot slot=EquipSlot(loadFile.GetProperty(std::format("Items.{}.Equip Slot",key)).GetInt()); if(slot!=EquipSlot::NONE){ //This should be equipped somewhere! Inventory::EquipItem(newItem,slot); } } game->ChangePlayerClass(classutils::StringToClass(loadFile["Player"]["Class"].GetString())); game->GetPlayer()->level=loadFile["Player"]["Level"].GetInt(); + game->GetPlayer()->SetMoney(loadFile["Player"]["Money"].GetInt()); game->GetPlayer()->currentLevelXP=loadFile["Player"]["Current EXP"].GetInt(); game->GetPlayer()->totalXPEarned=loadFile["Player"]["Total EXP"].GetInt(); - for(const auto&[key,size]:loadFile["Player"]["Base Stats"]){ - game->GetPlayer()->SetBaseStat(key,loadFile["Player"]["Base Stats"][key].GetReal()); + for(auto&[key,data]:loadFile["Player"]["Base Stats"].GetOrderedKeys()){ + game->GetPlayer()->SetBaseStat(key,data.GetReal()); } - for(const auto&[key,size]:loadFile["Unlocks"]){ + for(const auto&[key,data]:loadFile["Unlocks"].GetOrderedKeys()){ Unlock::UnlockArea(key); } - DYNAMIC_CAST(GameState::STATE)->SetStageMarker(loadFile["Overworld Map Location"].GetString()); + State_OverworldMap::SetStageMarker(loadFile["Overworld Map Location"].GetString()); game->SetChapter(loadFile["Chapter"].GetInt()); SaveFile::SetSaveFileName(loadFile["Save Name"].GetString()); + game->SetRuntime(loadFile["Game Time"].GetReal()); game->GetPlayer()->RecalculateEquipStats(); + + GameState::ChangeState(States::OVERWORLD_MAP,0.5f); } const std::string_view SaveFile::GetSaveFileName(){ @@ -130,4 +152,24 @@ const void SaveFile::SetSaveFileName(std::string_view saveFileName){ const void SaveFile::SetSaveFileID(size_t saveFileID){ SaveFile::saveFileID=saveFileID; -} \ No newline at end of file +} + +const void SaveFile::UpdateSaveGameData(){ + auto gameFilesList=Component(LOAD_GAME,"Game Files List"); + gameFilesList->RemoveAllComponents(); + const size_t saveFileCount=GetSaveFileCount(); + utils::datafile metadata; + utils::datafile::Read(metadata,"save_file_path"_S+"metadata.dat"); + float offsetY=0; + for(size_t i=0;iADD(std::format("Load File Button - Save {}",i),LoadFileButton)({{0,offsetY},{gameFilesList->GetSize().x-13,48}},metadata[std::format("save{}",i)],i,[](MenuFuncData data){ + LoadFileButton*comp=DYNAMIC_CAST(data.component); + saveFileID=comp->getSaveFileID(); + SaveFile::LoadGame(); + return true; + },ButtonAttr::NONE)END; + offsetY+=49; + } + } +} \ No newline at end of file diff --git a/Crawler/SaveFile.h b/Crawler/SaveFile.h index cb83cfae..83f8676b 100644 --- a/Crawler/SaveFile.h +++ b/Crawler/SaveFile.h @@ -49,4 +49,6 @@ public: static const void SaveGame(); static const void LoadGame(); static const void SetSaveFileID(size_t saveFileID); + //Called whenever the save game data is updated. + static const void UpdateSaveGameData(); }; \ No newline at end of file diff --git a/Crawler/ScrollableWindowComponent.h b/Crawler/ScrollableWindowComponent.h index 43511964..972a961e 100644 --- a/Crawler/ScrollableWindowComponent.h +++ b/Crawler/ScrollableWindowComponent.h @@ -130,7 +130,7 @@ protected: if(mouseOverScrollbar||scrollBarSelected){ scrollBarHoverTime=std::min(scrollBarHoverTime+game->GetElapsedTime(),"ThemeGlobal.HighlightTime"_F); - if(game->GetMouse(0).bPressed){ + if(game->GetMouse(0).bPressed&&!geom2d::contains(rect,bounds)){ scrollBarSelected=true; } if(game->GetMouse(0).bReleased){ @@ -201,7 +201,9 @@ protected: for(MenuComponent*component:components){ component->_DrawDecal(subWindow,focused); } - DrawScrollbar(window,{},focused); + if(!geom2d::contains(rect,bounds)){ + DrawScrollbar(window,{},focused); + } } virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{ return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},game->GetMousePos())&& //Make sure the mouse is inside the parent window component first.... diff --git a/Crawler/State_OverworldMap.cpp b/Crawler/State_OverworldMap.cpp index b5506e4e..994f4358 100644 --- a/Crawler/State_OverworldMap.cpp +++ b/Crawler/State_OverworldMap.cpp @@ -52,6 +52,7 @@ INCLUDE_MONSTER_LIST INCLUDE_game std::vectorState_OverworldMap::connections; +ConnectionPoint*State_OverworldMap::currentConnectionPoint=nullptr; State_OverworldMap::State_OverworldMap(){ SetStageMarker("Stage I-I"); //Eventually we will load the game from a file and this will not be necessary. We just set it to this for now. @@ -111,7 +112,7 @@ void State_OverworldMap::OnUserUpdate(Crawler*game){ if(neighborInd==-1)continue; ConnectionPoint&neighbor=ConnectionPointFromIndex(neighborInd); if(Unlock::IsUnlocked(neighbor.unlockCondition)&&&cp==&neighbor){ - currentConnectionPoint=&neighbor; + UpdateCurrentConnectionPoint(neighbor); playerTargetPos=currentConnectionPoint->rect.pos+currentConnectionPoint->rect.size/2+vf2d{0,16}; float angleTo=util::angleTo(game->GetPlayer()->GetPos(),playerTargetPos); if(angleTo>=-3*PI/4&&angleTo<-PI/4){ @@ -125,10 +126,6 @@ void State_OverworldMap::OnUserUpdate(Crawler*game){ }else{ game->GetPlayer()->UpdateWalkingAnimation(LEFT); } - Component(OVERWORLD_LEVEL_SELECT,"Stage Label")->SetLabel(currentConnectionPoint->name); - Component(OVERWORLD_LEVEL_SELECT,"Spawns List")->UpdateSpawns(currentConnectionPoint->spawns); - Component(OVERWORLD_LEVEL_SELECT,"Enter Button")->Enable(currentConnectionPoint->levelDataExists); - Component(OVERWORLD_LEVEL_SELECT,"Change Loadout Button")->Enable(currentConnectionPoint->levelDataExists&&!(currentConnectionPoint->type=="STORY"||currentConnectionPoint->type=="SHOP")); break; } } @@ -177,4 +174,14 @@ void State_OverworldMap::StartLevel(){ game->LoadLevel(LEVEL_NAMES.at(State_OverworldMap::GetCurrentConnectionPoint().map)); GameState::ChangeState(States::GAME_RUN); } +} + + + +void State_OverworldMap::UpdateCurrentConnectionPoint(const ConnectionPoint&connection){ + currentConnectionPoint=const_cast(&connection); + Component(OVERWORLD_LEVEL_SELECT,"Stage Label")->SetLabel(currentConnectionPoint->name); + Component(OVERWORLD_LEVEL_SELECT,"Spawns List")->UpdateSpawns(currentConnectionPoint->spawns); + Component(OVERWORLD_LEVEL_SELECT,"Enter Button")->Enable(currentConnectionPoint->levelDataExists); + Component(OVERWORLD_LEVEL_SELECT,"Change Loadout Button")->Enable(currentConnectionPoint->levelDataExists&&!(currentConnectionPoint->type=="STORY"||currentConnectionPoint->type=="SHOP")); } \ No newline at end of file diff --git a/Crawler/State_OverworldMap.h b/Crawler/State_OverworldMap.h index 4f65deb8..cc4245d1 100644 --- a/Crawler/State_OverworldMap.h +++ b/Crawler/State_OverworldMap.h @@ -42,7 +42,7 @@ All rights reserved. class State_OverworldMap:public GameState{ friend class Crawler; - ConnectionPoint*currentConnectionPoint; + static ConnectionPoint*currentConnectionPoint; float currentTime=0; vf2d playerTargetPos; const float playerMoveSpd=48.0; @@ -50,10 +50,11 @@ public: State_OverworldMap(); static std::vectorconnections; static ConnectionPoint&GetCurrentConnectionPoint(); - void SetStageMarker(std::string connectionName); + static void SetStageMarker(std::string connectionName); static ConnectionPoint&ConnectionPointFromIndex(int ind); virtual void OnStateChange(GameState*prevState)override final; virtual void OnUserUpdate(Crawler*game)override final; virtual void Draw(Crawler*game)override final; static void StartLevel(); + static void UpdateCurrentConnectionPoint(const ConnectionPoint&connection); }; \ No newline at end of file diff --git a/Crawler/TODO.txt b/Crawler/TODO.txt index 87f882ab..ee79fc75 100644 --- a/Crawler/TODO.txt +++ b/Crawler/TODO.txt @@ -7,7 +7,15 @@ Save/Load Game - Unlock Progress - World Map Location - Chapter # + - Gold - Save File Name + - Game Play Time + + Load Game Screen: + Save File Name + Game Play Time + Chapter # + Level / Class - Start a New Game File - Load a Game (Load list displays save files in reverse chronological order based on last access) @@ -26,10 +34,12 @@ Audio Engine - Attack / Enemy Sound Effects - Music Loading/Looping Settings Menu + - Any settings should be saved to the save file! - Volume Controls - Key Configuration -Upon pressing a key, check if the key is bound to another option, if so, remove that bind from the list. Up to two keys may be binded per action. + -We have to save keybinds to the save file. January 31st diff --git a/Crawler/Version.h b/Crawler/Version.h index 23068dde..0552c6a6 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 5220 +#define VERSION_BUILD 5256 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/saves/save.0000 b/Crawler/assets/saves/save.0000 deleted file mode 100644 index 765cea2b..00000000 --- a/Crawler/assets/saves/save.0000 +++ /dev/null @@ -1,354 +0,0 @@ - -Items -{ - - Item[0] - { - Amt = 9 - Enhancement Level = 0 - Item Name = Bandages - Equip Slot = 0 - } - - - Item[1] - { - Amt = 22 - Enhancement Level = 0 - Item Name = Blue Slime Remains - Equip Slot = 0 - } - - - Item[2] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Bone Armor - Equip Slot = 0 - } - - - Item[3] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Bone Gloves - Equip Slot = 8 - } - - - Item[4] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Bone Pants - Equip Slot = 16 - } - - - Item[5] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Copper Armor - Equip Slot = 0 - } - - - Item[6] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Copper Helmet - Equip Slot = 0 - } - - - Item[7] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Copper Pants - Equip Slot = 0 - } - - - Item[8] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Copper Shoes - Equip Slot = 0 - } - - - Item[9] - { - Amt = 2 - Enhancement Level = 0 - Item Name = Elixir of Bear Strength - Equip Slot = 0 - } - - - Item[10] - { - Amt = 42 - Enhancement Level = 0 - Item Name = Green Slime Remains - Equip Slot = 0 - } - - - Item[11] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Laser Sword - Equip Slot = 0 - } - - - Item[12] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Leather Gloves - Equip Slot = 0 - } - - - Item[13] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Leather Helmet - Equip Slot = 0 - } - - - Item[14] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Leather Pants - Equip Slot = 0 - } - - - Item[15] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Leather Shoes - Equip Slot = 0 - } - - - Item[16] - { - Amt = 16 - Enhancement Level = 0 - Item Name = Minor Health Potion - Equip Slot = 0 - } - - - Item[17] - { - Amt = 4 - Enhancement Level = 0 - Item Name = Red Slime Remains - Equip Slot = 0 - } - - - Item[18] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Ring of the Slime King - Equip Slot = 128 - - Attributes - { - Attack = 4.000000 - Health = 17.000000 - Mana = 1.000000 - Move Spd % = 3.000000 - } - - } - - - Item[19] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Ring of the Slime King - Equip Slot = 0 - - Attributes - { - Attack = 3.000000 - Health = 8.000000 - Mana = 3.000000 - Move Spd % = 1.000000 - } - - } - - - Item[20] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Ring of the Slime King - Equip Slot = 0 - - Attributes - { - Attack = 3.000000 - Health = 6.000000 - Mana = 1.000000 - Move Spd % = 3.000000 - } - - } - - - Item[21] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Armor - Equip Slot = 0 - } - - - Item[22] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Armor - Equip Slot = 0 - } - - - Item[23] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Armor - Equip Slot = 0 - } - - - Item[24] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Gloves - Equip Slot = 0 - } - - - Item[25] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Gloves - Equip Slot = 0 - } - - - Item[26] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Gloves - Equip Slot = 0 - } - - - Item[27] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Gloves - Equip Slot = 0 - } - - - Item[28] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Helmet - Equip Slot = 0 - } - - - Item[29] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Shoes - Equip Slot = 0 - } - - - Item[30] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Shell Sword - Equip Slot = 0 - } - - - Item[31] - { - Amt = 1 - Enhancement Level = 0 - Item Name = Wooden Sword - Equip Slot = 0 - } - -} - - -Player -{ - Class = Wizard - Level = 1 - Current EXP = 44 - Total EXP = 44 - - Base Stats - { - Attack = 15.000000 - CDR = 0.000000 - Crit Dmg = 50.000000 - Crit Rate = 0.000000 - Defense = 0.000000 - HP6 Recovery % = 0.000000 - Health = 80.000000 - Health % = 0.000000 - Mana = 100.000000 - Move Spd % = 100.000000 - } - -} - - -Unlocks -{ - CAMPAIGN_1_1 = True - WORLD_MAP = True -} - -Overworld Map Location = Stage I-I -Chapter = 1 -Save Name = Test File diff --git a/Crawler/olcPixelGameEngine.h b/Crawler/olcPixelGameEngine.h index 4ab84317..9f010991 100644 --- a/Crawler/olcPixelGameEngine.h +++ b/Crawler/olcPixelGameEngine.h @@ -1038,6 +1038,7 @@ namespace olc // to specify the primary screen void SetDrawTarget(Sprite* target); double GetRuntime() const; + void SetRuntime(const double runTime); // Gets the current Frames Per Second uint32_t GetFPS() const; // Gets last update of elapsed time @@ -2195,6 +2196,10 @@ namespace olc double PixelGameEngine::GetRuntime() const { return dRunTime; } + void PixelGameEngine::SetRuntime(const double runTime){ + dRunTime=runTime; + } + uint32_t PixelGameEngine::GetFPS() const { return nLastFPS; } diff --git a/Crawler/olcUTIL_DataFile.h b/Crawler/olcUTIL_DataFile.h index 0ad8b8fd..e8ba2075 100644 --- a/Crawler/olcUTIL_DataFile.h +++ b/Crawler/olcUTIL_DataFile.h @@ -145,6 +145,10 @@ namespace olc::utils return m_mapObjects; } + inline std::vector>&GetOrderedKeys(){ + return m_vecObjects; + } + // Checks if a property exists - useful to avoid creating properties // via reading them, though non-essential inline bool HasProperty(const std::string& sName) @@ -281,6 +285,8 @@ namespace olc::utils inline static bool Read(datafile& n, const std::string& sFileName, const char sListSep = ',') { + bool previousSetupState=INITIAL_SETUP_COMPLETE; + INITIAL_SETUP_COMPLETE=false; // Open the file! std::ifstream file(sFileName); if (file.is_open()) @@ -435,11 +441,13 @@ namespace olc::utils // Close and exit! file.close(); + INITIAL_SETUP_COMPLETE=previousSetupState; return true; } // File not found, so fail ERR("WARNING! Could not open file "<