diff --git a/Adventures in Lestoria/Adventures in Lestoria.tiled-project b/Adventures in Lestoria/Adventures in Lestoria.tiled-project
index f6f7a2d8..535d01da 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.tiled-project
+++ b/Adventures in Lestoria/Adventures in Lestoria.tiled-project
@@ -168,7 +168,9 @@
"STORY_1_2",
"STORY_1_3",
"BOSS_1",
- "BLACKSMITH"
+ "BLACKSMITH",
+ "CAMPAIGN_1_B1",
+ "BOSS_1_B"
],
"valuesAsFlags": false
},
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index 77a0f5ae..15f6081a 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -369,6 +369,10 @@
+
+
+
+
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
index fa74026c..2ffdd5b5 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
@@ -444,6 +444,9 @@
Header Files\Interface
+
+ Header Files\Interface
+
diff --git a/Adventures in Lestoria/Checkbox.h b/Adventures in Lestoria/Checkbox.h
new file mode 100644
index 00000000..b4bb7806
--- /dev/null
+++ b/Adventures in Lestoria/Checkbox.h
@@ -0,0 +1,80 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+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"
+#include "AdventuresInLestoria.h"
+
+INCLUDE_game
+
+class Checkbox:public MenuComponent{
+protected:
+ bool checked=false;
+ ToggleFunc onToggle;
+
+ inline void Toggle(){
+ checked=!checked;
+ onToggle(ToggleFuncData{*Menu::menus[parentMenu],game,Menu::menus[parentMenu]->components[name],parentComponent,checked});
+ }
+public:
+ inline Checkbox(geom2d::rectrect,ToggleFunc onToggle,const bool checked=false)
+ :MenuComponent(rect,"",[](MenuFuncData data){
+ auto checkbox=Component(data.menu.GetType(),data.component.lock()->GetName());
+ checkbox->Toggle();
+ return true;
+ }),checked(checked),onToggle(onToggle){}
+
+ inline const bool IsChecked()const{
+ return checked;
+ }
+
+ inline void DrawDecal(ViewPort&window,bool focused)override{
+ geom2d::linecheckmarkLine1=geom2d::line({rect.left().start.x+rect.size.x*0.125f,rect.left().start.y+rect.size.y*0.5f},{rect.top().start.x+rect.size.x*0.375f,rect.top().start.y+rect.size.y*0.875f});
+ geom2d::linecheckmarkLine2=geom2d::line(checkmarkLine1.end,{rect.left().start.x+rect.size.x*0.875f,rect.top().start.y+rect.size.y*0.25f});
+
+ MenuComponent::DrawDecal(window,focused);
+ if(checked){
+ for(int y=-1;y<=1;y++){
+ for(int x=-1;x<=1;x++){
+ window.DrawLineDecal(vf2d{float(x),float(y)}/game->GetScreenPixelSize()+checkmarkLine1.start,vf2d{float(x),float(y)}/game->GetScreenPixelSize()+checkmarkLine1.end);
+ window.DrawLineDecal(vf2d{float(x),float(y)}/game->GetScreenPixelSize()+checkmarkLine2.start,vf2d{float(x),float(y)}/game->GetScreenPixelSize()+checkmarkLine2.end);
+ }
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/Adventures in Lestoria/ClassSelectionWindow.cpp b/Adventures in Lestoria/ClassSelectionWindow.cpp
index 3f5fbd7e..dd5b6137 100644
--- a/Adventures in Lestoria/ClassSelectionWindow.cpp
+++ b/Adventures in Lestoria/ClassSelectionWindow.cpp
@@ -44,6 +44,7 @@ All rights reserved.
#include "ClassInfo.h"
#include "SaveFileNameButton.h"
#include "TextEntryLabel.h"
+#include "Checkbox.h"
INCLUDE_game
using A=Attribute;
@@ -75,7 +76,12 @@ void Menu::InitializeClassSelectionWindow(){
classSelectionWindow->ADD("Confirm",MenuComponent)(geom2d::rect{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+29-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){
std::string selectedClass=data.component.lock()->S(A::CLASS_SELECTION);
data.game->ChangePlayerClass(classutils::StringToClass(selectedClass));
- GameState::ChangeState(States::OVERWORLD_MAP);
+ if(SaveFile::IsOnline()){
+ SaveFile::SetSaveFileID(SaveFile::GetOnlineSaveFileCount());
+ SaveFile::UpdateSaveGameData([](){GameState::ChangeState(States::OVERWORLD_MAP);});
+ }else{
+ SaveFile::SetSaveFileOfflineID_TransitionToOverworldMap();
+ }
return true;
})END
->disabled=true;
@@ -141,6 +147,20 @@ void Menu::InitializeClassSelectionWindow(){
toggleGroup.push_back(classSprite);
}
+ #ifdef __EMSCRIPTEN__
+ classSelectionWindow->ADD("Online Character Checkbox",Checkbox)(geom2d::rect{classSelectionWindow->pos+classSelectionWindow->size-vf2d{84,72},{12,12}},[](ToggleFuncData data){
+ SaveFile::SetOnlineMode(data.checked);
+ if(SaveFile::IsOnline()&&SaveFile::GetUserID().length()==0){
+ //Present the user with the user ID form.
+ game->TextEntryEnable(true);
+ Menu::OpenMenu(USER_ID);
+ }
+ return true;
+ },SaveFile::IsOnline())END;
+
+ classSelectionWindow->ADD("Online Character Text Label",MenuLabel)(geom2d::rect{classSelectionWindow->pos+classSelectionWindow->size-vf2d{69,70},{54,12}},"Online Character",0.75f,ComponentAttr::SHADOW)END;
+ #endif
+
for(std::weak_ptritem:toggleGroup){
item.lock()->SetToggleGroup(toggleGroup);
}
diff --git a/Adventures in Lestoria/LoadGameWindow.cpp b/Adventures in Lestoria/LoadGameWindow.cpp
index a5cea7c8..4bcf44b6 100644
--- a/Adventures in Lestoria/LoadGameWindow.cpp
+++ b/Adventures in Lestoria/LoadGameWindow.cpp
@@ -50,7 +50,6 @@ void Menu::InitializeLoadGameWindow(){
->Enable(false);
loadGameWindow->ADD("Go Back Button",MenuComponent)(geom2d::rect{{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END;
-
#pragma region ScrollWindow macro lambda
#define ScrollWindow(amount) \
[](MenuType type){ \
diff --git a/Adventures in Lestoria/MainMenuWindow.cpp b/Adventures in Lestoria/MainMenuWindow.cpp
index 0b63502b..8d264d6e 100644
--- a/Adventures in Lestoria/MainMenuWindow.cpp
+++ b/Adventures in Lestoria/MainMenuWindow.cpp
@@ -57,18 +57,7 @@ void Menu::InitializeMainMenuWindow(){
return true;
})END;
auto loadGameButton=mainMenuWindow->ADD("Load Game Button",MenuComponent)(geom2d::rect{{12,36},{72,24}},"Load Game",[](MenuFuncData data){
- #ifdef __EMSCRIPTEN__
- data.menu.S(A::NEXT_MENU)="Load Game";
- if(SaveFile::GetUserID().length()==0){
- game->TextEntryEnable(true);
- Menu::OpenMenu(USER_ID);
- }else{
- SaveFile::UpdateSaveGameData();
- }
- #else
- SaveFile::UpdateSaveGameData();
- Menu::OpenMenu(LOAD_GAME);
- #endif
+ SaveFile::UpdateSaveGameData([](){Menu::OpenMenu(LOAD_GAME);}); //This function also opens the menu in emscripten.
return true;
})END;
mainMenuWindow->ADD("Quit Game Button",MenuComponent)(geom2d::rect{{12,68},{72,24}},"Quit Game",[](MenuFuncData data){
diff --git a/Adventures in Lestoria/Menu.cpp b/Adventures in Lestoria/Menu.cpp
index a90a050f..25dc6d6f 100644
--- a/Adventures in Lestoria/Menu.cpp
+++ b/Adventures in Lestoria/Menu.cpp
@@ -639,6 +639,9 @@ void Menu::AddChapterListener(std::weak_ptrcomponent){
MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent)
:menu(menu),game(game),component(component),parentComponent(parentComponent){}
+ToggleFuncData::ToggleFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent,bool checked)
+ :MenuFuncData(menu,game,component,parentComponent),checked(checked){}
+
void Menu::SetupKeyboardNavigation(MenuDataFunc onOpen,MenuInputGroups inputGroups,ButtonNavigationGroups navigationGroups){
this->onOpenFunc=onOpen;
this->inputGroups=inputGroups;
diff --git a/Adventures in Lestoria/Menu.h b/Adventures in Lestoria/Menu.h
index f516bd4c..39968fab 100644
--- a/Adventures in Lestoria/Menu.h
+++ b/Adventures in Lestoria/Menu.h
@@ -61,7 +61,13 @@ struct MenuFuncData{
MenuFuncData(Menu&menu,AiL*const game,std::weak_ptr component,std::weak_ptrparentComponent={});
};
+struct ToggleFuncData:public MenuFuncData{
+ bool checked;
+ ToggleFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent,bool checked);
+};
+
using MenuFunc=std::function;
+using ToggleFunc=std::function;
//Add a component to a menu using this macro. Follow-up with END at the end of it.
#define ADD(key,componentType) _AddComponent(key,std::make_shared
#define END )
diff --git a/Adventures in Lestoria/SaveFile.cpp b/Adventures in Lestoria/SaveFile.cpp
index b39d4ad1..91668291 100644
--- a/Adventures in Lestoria/SaveFile.cpp
+++ b/Adventures in Lestoria/SaveFile.cpp
@@ -52,6 +52,7 @@ size_t SaveFile::saveFileID=0;
std::string SaveFile::saveFileName="";
std::string SaveFile::username="";
bool SaveFile::onlineMode=false;
+std::functionSaveFile::afterSaveGameDataUpdate;
const size_t SaveFile::GetSaveFileCount(){
std::filesystem::create_directories("save_file_path"_S);
@@ -301,7 +302,32 @@ const void SaveFile::SetSaveFileID(size_t saveFileID){
SaveFile::saveFileID=saveFileID;
}
-const void SaveFile::UpdateSaveGameData(){
+const void SaveFile::SetSaveFileOfflineID_TransitionToOverworldMap(){
+ #ifdef __EMSCRIPTEN__
+ emscripten_idb_async_load("/assets",("save_file_path"_S+"metadata.dat").c_str(),0,[](void*arg,void*data,int length){
+ std::string rawMetadata=(char*)data;
+ std::ofstream file("save_file_path"_S+"metadata.dat");
+ for(int i=0;iafterSaveGameDataUpdate){
+ SaveFile::afterSaveGameDataUpdate=afterSaveGameDataUpdate;
+
std::filesystem::create_directories("save_file_path"_S);
auto LoadMetadataFile=[](){
auto gameFilesList=Component(LOAD_GAME,"Game Files List");
@@ -346,7 +372,7 @@ const void SaveFile::UpdateSaveGameData(){
}
}
};
- auto LoadMetadataFromDB=[](){
+ auto LoadMetadataFromDB=[&](){
auto gameFilesList=Component(LOAD_GAME,"Game Files List");
gameFilesList->RemoveAllComponents();
#ifdef __EMSCRIPTEN__
@@ -376,17 +402,13 @@ const void SaveFile::UpdateSaveGameData(){
offsetY+=49;
}
}
- Menu::OpenMenu(LOAD_GAME);
+ SaveFile::afterSaveGameDataUpdate();
},[](void*arg){
std::cout<<"Failed to load metadata!"<afterSaveGameDataUpdate;
public:
static const std::string_view GetSaveFileName();
static const void SetSaveFileName(std::string_view saveFileName);
@@ -66,8 +67,10 @@ public:
static const void LoadGame();
static void LoadFile();
static const void SetSaveFileID(size_t saveFileID);
+ static const void SetSaveFileOfflineID_TransitionToOverworldMap();
//Called whenever the save game data is updated.
- static const void UpdateSaveGameData();
+ //WARNING! In Emscripten, this function also opens the Load Menu window!
+ static const void UpdateSaveGameData(std::functionafterSaveGameDataUpdate);
static const std::string CreateServerRequest(const SaveFileOperation::Operation operation,std::string_view data);
static const void Server_GetLoadInfo(std::functionrespCallbackFunc);
static const void Server_GetFile(std::functionrespCallbackFunc);
diff --git a/Adventures in Lestoria/SaveFileWindow.cpp b/Adventures in Lestoria/SaveFileWindow.cpp
index 316a046e..aa3ab439 100644
--- a/Adventures in Lestoria/SaveFileWindow.cpp
+++ b/Adventures in Lestoria/SaveFileWindow.cpp
@@ -49,11 +49,6 @@ void Menu::InitializeSaveFileWindow(){
saveFileWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{-8,68},{48,12}},"Cancel",[](MenuFuncData data){Menu::CloseMenu();game->TextEntryEnable(false);return true;})END;
saveFileWindow->ADD("Continue Button",MenuComponent)(geom2d::rect{{56,68},{48,12}},"Submit",MenuType::CLASS_SELECTION,[](MenuFuncData data){
SaveFile::SetSaveFileName(game->TextEntryGetString());
- if(SaveFile::IsOnline()){
- SaveFile::SetSaveFileID(SaveFile::GetOnlineSaveFileCount());
- }else{
- SaveFile::SetSaveFileID(SaveFile::GetSaveFileCount());
- }
game->TextEntryEnable(false);
return true;
})END
diff --git a/Adventures in Lestoria/UserIDMenu.cpp b/Adventures in Lestoria/UserIDMenu.cpp
index d95e37db..cb2404c3 100644
--- a/Adventures in Lestoria/UserIDMenu.cpp
+++ b/Adventures in Lestoria/UserIDMenu.cpp
@@ -40,6 +40,7 @@ All rights reserved.
#include "MenuLabel.h"
#include "TextEntryLabel.h"
#include "SaveFile.h"
+#include "Checkbox.h"
using A=Attribute;
@@ -51,21 +52,14 @@ void Menu::InitializeUserIDWindow(){
Component(USER_ID,"Submit Button")->SetGrayedOut(newLabel.length()==0);
},true,24U,1.f,ComponentAttr::BACKGROUND|ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
userIDWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{18,110},{48,12}},"Back",[](MenuFuncData data){
+ SaveFile::SetOnlineMode(false); //We declined the online saving, so don't allow it.
+ Component(CLASS_SELECTION,"Online Character Checkbox")->Click(); //Since the checkbox is currently checked, we have to click it to toggle it.
Menu::CloseMenu();
return true;
})END;
userIDWindow->ADD("Submit Button",MenuComponent)(geom2d::rect{{102,110},{48,12}},"Submit",[](MenuFuncData data){
SaveFile::SetUserID(Component(USER_ID,"User ID Input")->GetLabel());
- if(Menu::menus[MAIN_MENU]->S(A::NEXT_MENU)=="New Game"){
- Menu::CloseMenu();
- Component(MAIN_MENU,"New Game Button")->Click();
- }else
- if(Menu::menus[MAIN_MENU]->S(A::NEXT_MENU)=="Load Game"){
- Menu::CloseMenu();
- Component(MAIN_MENU,"Load Game Button")->Click();
- }else{
- ERR("WARNING! Unknown Next Menu set! Current Value:"<S(A::NEXT_MENU)));
- }
+ Menu::CloseMenu();
return true;
})END
->SetGrayedOut(true);
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index e0993a9c..fdacb33b 100644
--- a/Adventures in Lestoria/Version.h
+++ b/Adventures in Lestoria/Version.h
@@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 3
#define VERSION_PATCH 0
-#define VERSION_BUILD 6436
+#define VERSION_BUILD 6455
#define stringify(a) stringify_(a)
#define stringify_(a) #a
diff --git a/Adventures in Lestoria/assets/Campaigns/1_B1.tmx b/Adventures in Lestoria/assets/Campaigns/1_B1.tmx
index 33e6c146..375d2e18 100644
--- a/Adventures in Lestoria/assets/Campaigns/1_B1.tmx
+++ b/Adventures in Lestoria/assets/Campaigns/1_B1.tmx
@@ -1,5 +1,10 @@
-