The open source repository for the action RPG game in development by Sig Productions titled 'Adventures in Lestoria'!
https://forums.lestoria.net
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
12 KiB
341 lines
12 KiB
#pragma region License
|
|
/*
|
|
License (OLC-3)
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.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 © 2024 The FreeType
|
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
|
All rights reserved.
|
|
*/
|
|
#pragma endregion
|
|
#include "AdventuresInLestoria.h"
|
|
#include "DEFINES.h"
|
|
#include "Menu.h"
|
|
#include "MenuLabel.h"
|
|
#include "MenuAnimatedIconToggleButton.h"
|
|
#include "GameState.h"
|
|
#include "ClassInfo.h"
|
|
#include "SaveFileNameButton.h"
|
|
#include "TextEntryLabel.h"
|
|
#include "Checkbox.h"
|
|
#ifndef __EMSCRIPTEN__
|
|
#include <isteamutils.h>
|
|
#endif
|
|
|
|
INCLUDE_game
|
|
using A=Attribute;
|
|
|
|
void Menu::InitializeClassSelectionWindow(){
|
|
vf2d windowSize=game->GetScreenSize()-vi2d{24,8};
|
|
|
|
Menu*classSelectionWindow=CreateMenu(CLASS_SELECTION,CENTERED,windowSize);
|
|
|
|
classSelectionWindow->S(A::CLASS_SELECTION)="Warrior"; //Default selected class.
|
|
|
|
vf2d outlineSize=classSelectionWindow->size-vf2d{8,29};
|
|
|
|
classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)(geom2d::rect<float>{{4,12},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
|
|
|
|
auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)(geom2d::rect<float>{{4,4},outlineSize+vf2d{0,25}},"",1,ComponentAttr::OUTLINE)END;
|
|
|
|
classSelectionWindow->ADD("Character Name Label",MenuLabel)(geom2d::rect<float>{{windowSize.x/2-144.f,60.f},{96.f,24.f}},"Name:",2.0f,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
|
|
|
|
classSelectionWindow->ADD("Character Name Box",SaveFileNameButton)(geom2d::rect<float>{{windowSize.x/2-48.f,60.f},{192.f,24}},[&](MenuFuncData data){
|
|
Component<TextEntryLabel>(SAVE_FILE_NAME,"Save File Name Text Entry")->SetInput(std::string(SaveFile::GetSaveFileName()));
|
|
game->TextEntryEnable(true);
|
|
Menu::OpenMenu(SAVE_FILE_NAME);
|
|
vf2d textboxWindowPos=data.component.lock()->rect.pos*game->GetPixelSize();
|
|
vf2d textboxWindowSize=data.component.lock()->rect.size*game->GetPixelSize();
|
|
|
|
if(SteamUtils()){
|
|
SteamUtils()->ShowGamepadTextInput(k_EGamepadTextInputModeNormal,k_EGamepadTextInputLineModeSingleLine,"Character Name:",16U,std::string(SaveFile::GetSaveFileName()).c_str());
|
|
}
|
|
return true;
|
|
},vf2d{2.f,2.f})END;
|
|
|
|
vf2d navigationButtonSize={24*2.5f,16};
|
|
|
|
classSelectionWindow->ADD("Back",MenuComponent)(geom2d::rect<float>{{6,outlineSize.y+29-navigationButtonSize.y-14},navigationButtonSize},"Back",[](MenuFuncData){Menu::CloseMenu();return true;})END;
|
|
|
|
classSelectionWindow->ADD("Confirm",MenuComponent)(geom2d::rect<float>{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+29-navigationButtonSize.y-14},navigationButtonSize},"Confirm",[](MenuFuncData data){
|
|
std::string selectedClass=data.component.lock()->S(A::CLASS_SELECTION);
|
|
|
|
//Player starting items.
|
|
Inventory::AddItem("Minor Health Potion"s,3);
|
|
Inventory::AddItem("Bandages"s,10);
|
|
|
|
data.game->ChangePlayerClass(classutils::StringToClass(selectedClass));
|
|
#ifdef __EMSCRIPTEN__
|
|
if(SaveFile::IsOnline()){
|
|
SaveFile::SetSaveFileID(SaveFile::GetOnlineSaveFileCount());
|
|
SaveFile::UpdateSaveGameData([](){GameState::ChangeState(States::OVERWORLD_MAP);});
|
|
}else{
|
|
SaveFile::SetSaveFileOfflineID_TransitionToOverworldMap();
|
|
}
|
|
#else
|
|
SaveFile::SetSaveFileID(SaveFile::GetSaveFileCount());
|
|
SaveFile::SaveGame();
|
|
GameState::ChangeState(States::OVERWORLD_MAP);
|
|
#endif
|
|
return true;
|
|
})END
|
|
->Disable();
|
|
|
|
vf2d buttonPadding={2,2};
|
|
vf2d buttonSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/9-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
|
|
|
|
float buttonTotalWidth=(buttonSize.x+buttonPadding.x)*3;
|
|
|
|
vf2d buttonStartPos=outline->GetPos()+vf2d{outlineSize.x/2,outlineSize.y/3}-vf2d{buttonTotalWidth/2,0}+vf2d{0,24};
|
|
|
|
std::array<std::string,6>classNames={
|
|
Warrior::name,
|
|
Ranger::name,
|
|
Wizard::name,
|
|
Thief::name,
|
|
Trapper::name,
|
|
Witch::name,
|
|
};
|
|
std::array<std::string,6>classAnimationNames={
|
|
Warrior::walk_s,
|
|
Ranger::walk_s,
|
|
Wizard::walk_s,
|
|
Thief::walk_s,
|
|
Trapper::walk_s,
|
|
Witch::walk_s,
|
|
};
|
|
|
|
std::vector<std::weak_ptr<IToggleable>>toggleGroup;
|
|
|
|
for(int i=0;i<6;i++){
|
|
std::string className=classNames[i];
|
|
std::string classAnimationName=classAnimationNames[i];
|
|
vf2d offsetPos={
|
|
buttonStartPos.x+(buttonSize.x+buttonPadding.x)*float(i%3),
|
|
buttonStartPos.y+(buttonSize.y+buttonPadding.y+2*outlineSize.y/9)*float(i/3)+2*outlineSize.y/9,
|
|
};
|
|
vf2d backgroundOffsetPos={
|
|
buttonStartPos.x+(buttonSize.x+buttonPadding.x)*float(i%3),
|
|
buttonStartPos.y+(buttonSize.y+buttonPadding.y+2*outlineSize.y/9)*float(i/3),
|
|
};
|
|
vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug.
|
|
|
|
|
|
auto classLabel=classSelectionWindow->ADD(className+" Background",MenuLabel)(geom2d::rect<float>{backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
|
|
auto classButton=classSelectionWindow->ADD(className+" Button",MenuComponent)(geom2d::rect<float>{offsetPos,buttonSize},"Info",
|
|
[](MenuFuncData data){
|
|
data.menu.S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION);
|
|
delete Menu::menus[CLASS_INFO];
|
|
Menu::InitializeClassInfoWindow();
|
|
Menu::OpenMenu(CLASS_INFO);
|
|
return true;
|
|
})END;
|
|
classButton->S(A::CLASS_SELECTION)=className;
|
|
|
|
classSelectionWindow->ADD(className+" Label",MenuLabel)(geom2d::rect<float>{backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END;
|
|
auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)(geom2d::rect<float>{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){
|
|
data.menu.components["Confirm"]->Enable();
|
|
data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION);
|
|
return true;
|
|
})END;
|
|
|
|
if(i>=3){
|
|
classLabel->SetGrayedOut(true);
|
|
classButton->SetGrayedOut(true);
|
|
classSprite->SetGrayedOut(true);
|
|
}
|
|
|
|
classSprite->S(A::CLASS_SELECTION)=className;
|
|
|
|
toggleGroup.push_back(classSprite);
|
|
}
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
classSelectionWindow->ADD("Online Character Checkbox",Checkbox)(geom2d::rect<float>{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<float>{classSelectionWindow->pos+classSelectionWindow->size-vf2d{69,70},{54,12}},"Online Character",0.75f,ComponentAttr::SHADOW)END;
|
|
#endif
|
|
|
|
for(std::weak_ptr<IToggleable>item:toggleGroup){
|
|
item.lock()->SetToggleGroup(toggleGroup);
|
|
}
|
|
|
|
|
|
classSelectionWindow->SetupKeyboardNavigation(
|
|
[](MenuType type,Data&returnData){ //On Open
|
|
returnData=Warrior::name+" Button";
|
|
},
|
|
{ //Button Key
|
|
{game->KEY_BACK,{"Back",[](MenuType type){
|
|
Component<MenuComponent>(type,"Back")->Click();
|
|
}}},
|
|
{game->KEY_START,{[](MenuFuncData data){
|
|
if(Component<MenuComponent>(data.menu.GetType(),"Confirm")->IsEnabled()){
|
|
return "Confirm";
|
|
}else{
|
|
return "";
|
|
}
|
|
},[](MenuType type){
|
|
Component<MenuComponent>(type,"Confirm")->Click();
|
|
}}},
|
|
{game->KEY_FACEUP,{"Change Player Name",[](MenuType type){
|
|
Component<SaveFileNameButton>(type,"Character Name Box")->Click();
|
|
}}},
|
|
#ifdef __EMSCRIPTEN__
|
|
{game->KEY_FACELEFT,{"Toggle Online Character",[](MenuType type){
|
|
Component<Checkbox>(type,"Online Character Checkbox")->Click();
|
|
}}},
|
|
#endif
|
|
}
|
|
,{ //Button Navigation Rules
|
|
{Warrior::name+" Button",{
|
|
.up=Warrior::name+" Icon",
|
|
.down=Thief::name+" Icon",
|
|
.left="Back",
|
|
.right=Ranger::name+" Button",
|
|
}},
|
|
{Warrior::name+" Icon",{
|
|
.up="Character Name Box",
|
|
.down=Warrior::name+" Button",
|
|
.left="Back",
|
|
.right=Ranger::name+" Icon",
|
|
}},
|
|
{Ranger::name+" Button",{
|
|
.up=Ranger::name+" Icon",
|
|
.down=Trapper::name+" Icon",
|
|
.left=Warrior::name+" Button",
|
|
.right=Wizard::name+" Button",
|
|
}},
|
|
{Ranger::name+" Icon",{
|
|
.up="Character Name Box",
|
|
.down=Ranger::name+" Button",
|
|
.left=Warrior::name+" Icon",
|
|
.right=Wizard::name+" Icon",
|
|
}},
|
|
{Wizard::name+" Button",{
|
|
.up=Wizard::name+" Icon",
|
|
.down=Witch::name+" Icon",
|
|
.left=Ranger::name+" Button",
|
|
#ifdef __EMSCRIPTEN__
|
|
.right="Online Character Checkbox",
|
|
#else
|
|
.right="Confirm",
|
|
#endif
|
|
}},
|
|
{Wizard::name+" Icon",{
|
|
.up="Character Name Box",
|
|
.down=Wizard::name+" Button",
|
|
.left=Ranger::name+" Icon",
|
|
#ifdef __EMSCRIPTEN__
|
|
.right="Online Character Checkbox",
|
|
#else
|
|
.right="Confirm",
|
|
#endif
|
|
}},
|
|
{Thief::name+" Button",{
|
|
.up=Thief::name+" Icon",
|
|
.down="Character Name Box",
|
|
.left="Back",
|
|
.right=Trapper::name+" Button",
|
|
}},
|
|
{Thief::name+" Icon",{
|
|
.up=Warrior::name+" Button",
|
|
.down=Thief::name+" Button",
|
|
.left="Back",
|
|
.right=Trapper::name+" Icon",
|
|
}},
|
|
{Trapper::name+" Button",{
|
|
.up=Trapper::name+" Icon",
|
|
.down="Character Name Box",
|
|
.left=Thief::name+" Button",
|
|
.right=Witch::name+" Button",
|
|
}},
|
|
{Trapper::name+" Icon",{
|
|
.up=Ranger::name+" Button",
|
|
.down=Trapper::name+" Button",
|
|
.left=Thief::name+" Icon",
|
|
.right=Witch::name+" Icon",
|
|
}},
|
|
{Witch::name+" Button",{
|
|
.up=Witch::name+" Icon",
|
|
.down="Character Name Box",
|
|
.left=Trapper::name+" Button",
|
|
#ifdef __EMSCRIPTEN__
|
|
.right="Online Character Checkbox",
|
|
#else
|
|
.right="Confirm",
|
|
#endif
|
|
}},
|
|
{Witch::name+" Icon",{
|
|
.up=Wizard::name+" Button",
|
|
.down=Witch::name+" Button",
|
|
.left=Trapper::name+" Icon",
|
|
#ifdef __EMSCRIPTEN__
|
|
.right="Online Character Checkbox",
|
|
#else
|
|
.right="Confirm",
|
|
#endif
|
|
}},
|
|
{"Character Name Box",{
|
|
.up=Witch::name+" Button",
|
|
.down=Wizard::name+" Icon",
|
|
}},
|
|
{"Confirm",{
|
|
#ifdef __EMSCRIPTEN__
|
|
.up="Online Character Checkbox",
|
|
#else
|
|
.up=Wizard::name+" Button",
|
|
#endif
|
|
.down=Wizard::name+" Button",
|
|
.left=Wizard::name+" Button",
|
|
.right="Back",
|
|
}},
|
|
{"Online Character Checkbox",{
|
|
.up="Confirm",
|
|
.down="Confirm",
|
|
.left=Wizard::name+" Button",
|
|
.right=Warrior::name+" Button",
|
|
}},
|
|
{"Back",{
|
|
.up=Warrior::name+" Button",
|
|
.down=Warrior::name+" Button",
|
|
.left="Confirm",
|
|
.right=Warrior::name+" Button",
|
|
}},
|
|
});
|
|
} |