Quapsel 12 months ago
commit bc70985eef
  1. 11
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 18
      Adventures in Lestoria/ClassSelectionWindow.cpp
  3. 47
      Adventures in Lestoria/Key.cpp
  4. 2
      Adventures in Lestoria/Key.h
  5. 5
      Adventures in Lestoria/Menu.cpp
  6. 1
      Adventures in Lestoria/Menu.h
  7. 4
      Adventures in Lestoria/Monster.cpp
  8. 4
      Adventures in Lestoria/Monster.h
  9. 32
      Adventures in Lestoria/NPC.cpp
  10. 25
      Adventures in Lestoria/RUN_STRATEGY.cpp
  11. 2
      Adventures in Lestoria/TMXParser.h
  12. 2
      Adventures in Lestoria/Version.h
  13. 8
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  14. 1
      Adventures in Lestoria/assets/maps/Tilesheet_No_Shadow24x24.tsx
  15. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1416,6 +1416,10 @@ void AiL::RenderWorld(float fElapsedTime){
}
}
for(Monster&m:MONSTER_LIST){
m.strategyDrawOverlay(this,m,MONSTER_DATA[m.GetName()].GetAIStrategy());
}
#ifdef _DEBUG
if(DEBUG_PATHFINDING){
std::vector<vf2d>pathing=game->pathfinder.Solve_AStar(player.get()->GetPos(),GetWorldMousePos(),8,player.get()->OnUpperLevel());
@ -2000,6 +2004,7 @@ void AiL::LoadLevel(MapName map){
for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
MONSTER_LIST.back().iframe_timer=INFINITE;
MONSTER_LIST.back().npcData=data;
}
player->GetAbility1().cooldown=0.f;
@ -2555,7 +2560,11 @@ void AiL::ReduceBossEncounterMobCount(){
void AiL::RenderMenu(){
if(!GamePaused()&&Menu::stack.size()>0){
Menu::stack.back()->Update(this);
if(Menu::alreadyClicked){ //Do not run a click event for this round.
Menu::alreadyClicked=false;
}else{
Menu::stack.back()->Update(this);
}
}
if(Menu::stack.size()>0){
for(Menu*menu:Menu::stack){

@ -78,12 +78,18 @@ void Menu::InitializeClassSelectionWindow(){
classSelectionWindow->ADD("Confirm",MenuComponent)(geom2d::rect<float>{{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));
if(SaveFile::IsOnline()){
SaveFile::SetSaveFileID(SaveFile::GetOnlineSaveFileCount());
SaveFile::UpdateSaveGameData([](){GameState::ChangeState(States::OVERWORLD_MAP);});
}else{
SaveFile::SetSaveFileOfflineID_TransitionToOverworldMap();
}
#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
->disabled=true;

@ -39,6 +39,7 @@ All rights reserved.
#include "DEFINES.h"
#include "AdventuresInLestoria.h"
#include "olcPGEX_Gamepad.h"
#include "Menu.h"
INCLUDE_game
INCLUDE_GFX
@ -240,6 +241,50 @@ std::string InputGroup::GetDisplayName(){
return combinationDisplay;
}
void InputGroup::DrawInput(const vf2d pos,const std::string_view displayText,const uint8_t alpha)const{
std::optional<Input>primaryKey;
if(Input::UsingGamepad())primaryKey=GetPrimaryKey(CONTROLLER);
else if(Menu::UsingMouseNavigation())primaryKey=GetPrimaryKey(MOUSE);
else primaryKey=GetPrimaryKey(KEY);
vf2d buttonImgSize{};
std::vector<std::variant<Decal*,std::string>>buttonImgs;
if(displayText.length()>0&&primaryKey.has_value()){
if(primaryKey.value().HasIcon()){
buttonImgSize+=primaryKey.value().GetIcon().Sprite()->Size()+vf2d{"Interface.InputHelperSpacing"_F,"Interface.InputHelperSpacing"_F};
buttonImgs.push_back(primaryKey.value().GetIcon().Decal());
}else{
buttonImgSize+=game->GetTextSizeProp(primaryKey.value().GetDisplayName())+vf2d{"Interface.InputHelperSpacing"_F,"Interface.InputHelperSpacing"_F};
buttonImgs.push_back(primaryKey.value().GetDisplayName());
}
}
vf2d descriptionTextSize=game->GetTextSizeProp(displayText);
vf2d offset=-((buttonImgSize+descriptionTextSize)/2.f);
if(buttonImgs.size()!=1)ERR("WARNING! Did not have two elements when rendering input button group display! THIS SHOULD NOT BE HAPPENING!")
for(auto&button:buttonImgs){
if(std::holds_alternative<Decal*>(button)){
Decal*img=std::get<Decal*>(button);
game->view.DrawDecal(pos+offset,img,{1.f,1.f},{255,255,255,alpha});
offset.x+=img->sprite->width+"Interface.InputHelperSpacing"_I;
}else
if(std::holds_alternative<std::string>(button)){
std::string label=std::get<std::string>(button);
vf2d textSize=game->GetTextSizeProp(label);
Pixel buttonBackCol="Interface.InputButtonBackCol"_Pixel;
Pixel buttonTextCol="Interface.InputButtonTextCol"_Pixel;
buttonBackCol.a=alpha;
buttonTextCol.a=alpha;
game->view.FillRectDecal(pos+offset+vf2d{-2.f,0.f},vf2d{textSize.x+4,textSize.y},buttonBackCol);
game->view.FillRectDecal(pos+offset+vf2d{-1.f,-1.f},vf2d{textSize.x+2,textSize.y},buttonBackCol);
game->view.FillRectDecal(pos+offset+vf2d{-1.f,0.f},vf2d{textSize.x+2,textSize.y+1.f},buttonBackCol);
game->view.DrawStringPropDecal(pos+offset+vf2d{0.f,0.f},label,buttonTextCol);
offset.x+=textSize.x+"Interface.InputHelperSpacing"_I;
}else [[unlikely]]ERR("WARNING! Hit a state where no data is inside of the button! THIS SHOULD NOT BE HAPPENING!");
game->view.DrawShadowStringPropDecal(pos+offset,displayText,{255,255,255,alpha},{0,0,0,alpha});
}
}
const bool Input::HasIcon()const{
return GenericKey::keyLiteral.at({type,key}).iconName.length()>0;
}
@ -247,6 +292,8 @@ const Renderable&Input::GetIcon()const{
return GFX.at(GenericKey::keyLiteral.at({type,key}).iconName);
}
#undef END
std::map<std::pair<InputType,int>,GenericKey::KeyInfo> GenericKey::keyLiteral={
{{KEY, NONE},{""}},
{{KEY, A},{"A"}},

@ -89,6 +89,8 @@ public:
const bool Released()const;
const float Analog()const;
std::string GetDisplayName();
//Draws an input display with accompanying text centered at given position.
void DrawInput(const vf2d pos,const std::string_view displayText,const uint8_t alpha)const;
const std::optional<Input>GetPrimaryKey(InputType type)const;
};

@ -61,6 +61,7 @@ std::vector<std::weak_ptr<MenuComponent>>Menu::chapterListeners;
const vf2d Menu::CENTERED = {-456,-456};
MenuType Menu::lastMenuTypeCreated;
std::string Menu::lastRegisteredComponent;
bool Menu::alreadyClicked=false;
INCLUDE_game
INCLUDE_GFX
@ -120,12 +121,13 @@ void Menu::CheckClickAndPerformMenuSelect(AiL*game){
if(game->KEY_CONFIRM.Released()&&(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.
MenuSelect(game);
Menu::alreadyClicked=true;
}
}
}
void Menu::HoverMenuSelect(AiL*game){
if(!game->IsFocused()||selection.expired()||selection.lock()->disabled||selection.lock()->grayedOut)return;
if(!game->IsFocused()||selection.expired()||selection.lock()->disabled||selection.lock()->grayedOut||Menu::alreadyClicked)return;
if(selection.lock()->draggable){
if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){
@ -283,6 +285,7 @@ void Menu::Draw(AiL*game){
};
void Menu::OpenMenu(MenuType menu,bool cover){
Menu::alreadyClicked=true;
menus[menu]->cover=cover;
if(menus[menu]->onOpenFunc){
Data returnData;

@ -119,6 +119,7 @@ class Menu:public IAttributable{
static vi2d lastActiveMousePos;
int componentCount=0;
float componentSelectionIndex=0.f;
static bool alreadyClicked;
std::unique_ptr<MenuComponent>draggingComponent;
ViewPort window;

@ -665,6 +665,10 @@ void Monster::SetStrategyDrawFunction(std::function<void(AiL*,Monster&,const std
strategyDraw=func;
}
void Monster::SetStrategyDrawOverlayFunction(std::function<void(AiL*,Monster&,const std::string&)>func){
strategyDrawOverlay=func;
}
std::map<ItemInfo*,uint16_t>Monster::SpawnDrops(){
std::map<ItemInfo*,uint16_t>drops;
for(MonsterDropData data:MONSTER_DATA.at(name).GetDropData()){

@ -46,6 +46,7 @@ All rights reserved.
#include "safemap.h"
#include "Pathfinding.h"
#include "GameEvent.h"
#include "TMXParser.h"
INCLUDE_ITEM_DATA
@ -181,7 +182,9 @@ public:
void SetSize(float newSize,bool immediate=true);
geom2d::circle<float>Hitbox();
void SetStrategyDrawFunction(std::function<void(AiL*,Monster&,const std::string&)>func);
void SetStrategyDrawOverlayFunction(std::function<void(AiL*,Monster&,const std::string&)>func);
std::function<void(AiL*,Monster&,const std::string&)>strategyDraw=[](AiL*pge,Monster&m,const std::string&strategy){};
std::function<void(AiL*,Monster&,const std::string&)>strategyDrawOverlay=[](AiL*pge,Monster&m,const std::string&strategy){};
const ItemAttributable&GetStats()const;
const EventName&GetHurtSound();
const EventName&GetDeathSound();
@ -239,6 +242,7 @@ private:
bool isBoss=false;
void OnDeath();
bool hasStrategyDeathFunction=false;
NPCData npcData;
std::function<bool(GameEvent&,Monster&,const std::string&)>strategyDeathFunc;
void SetStrategyDeathFunction(std::function<bool(GameEvent&,Monster&,const std::string&)>func);
ItemAttribute&Get(std::string_view attr);

@ -37,9 +37,39 @@ All rights reserved.
#pragma endregion
#include "Monster.h"
#include "AdventuresInLestoria.h"
#include "MonsterStrategyHelpers.h"
#include "util.h"
#include "Menu.h"
using A=Attribute;
void Monster::STRATEGY::NPC(Monster&m,float fElapsedTime,std::string strategy){
INCLUDE_game
void Monster::STRATEGY::NPC(Monster&m,float fElapsedTime,std::string strategy){
if(m.phase==0){ //Initialization.
if(m.npcData.function.length()>0){
m.SetStrategyDrawOverlayFunction([](AiL*game,Monster&m,const std::string&strategy){
game->KEY_CONFIRM.DrawInput(m.GetPos()+vf2d{ConfigFloatArr("Interaction Display Offset",0),ConfigFloatArr("Interaction Display Offset",1)},"Interact",uint8_t(util::lerp(0.f,255.f,m.F(A::TARGET_TIMER)/ConfigFloat("Interaction Display Ease in Timer"))));
});
}
m.phase=1;
}
float distFromPlayer=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).length();
if(distFromPlayer<ConfigFloat("Interaction Distance")/100.f*24.f){
m.F(A::TARGET_TIMER)=std::min(m.F(A::TARGET_TIMER)+fElapsedTime,ConfigFloat("Interaction Display Ease in Timer"));
if(game->KEY_CONFIRM.Released()&&Menu::stack.size()==0){
if(m.npcData.function=="Blacksmith"){
Menu::OpenMenu(MenuType::BLACKSMITH);
}else
if(m.npcData.function=="PotionCrafting"){
Menu::OpenMenu(MenuType::CRAFT_CONSUMABLE);
}else
if(m.npcData.function=="TravelingMerchant"){
Menu::OpenMenu(MenuType::MERCHANT);
}
}
}else{
m.F(A::TARGET_TIMER)=std::max(0.f,m.F(A::TARGET_TIMER)-fElapsedTime);
}
}

@ -58,35 +58,50 @@ void Monster::InitializeStrategies(){
}
int Monster::STRATEGY::_GetInt(Monster&m,std::string param,std::string strategy,int index){
if(DATA["Monsters"][m.name].HasProperty(param)){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return float(DATA["NPCs"][m.name].GetProperty(param).GetInt(index));
}else
if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
return DATA["Monsters"][m.name].GetProperty(param).GetInt(index);
} else {
return DATA["MonsterStrategy"][strategy].GetProperty(param).GetInt(index);
}
}
float Monster::STRATEGY::_GetFloat(Monster&m,std::string param,std::string strategy,int index){
if(DATA["Monsters"][m.name].HasProperty(param)){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return float(DATA["NPCs"][m.name].GetProperty(param).GetReal(index));
}else
if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
return float(DATA["Monsters"][m.name].GetProperty(param).GetReal(index));
} else {
return float(DATA["MonsterStrategy"][strategy].GetProperty(param).GetReal(index));
}
}
const std::string&Monster::STRATEGY::_GetString(Monster&m,std::string param,std::string strategy,int index){
if(DATA["Monsters"][m.name].HasProperty(param)){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return DATA["NPCs"][m.name].GetProperty(param).GetString(index);
}else
if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
return DATA["Monsters"][m.name].GetProperty(param).GetString(index);
} else {
return DATA["MonsterStrategy"][strategy].GetProperty(param).GetString(index);
}
}
datafile Monster::STRATEGY::_Get(Monster&m,std::string param,std::string strategy){
if(DATA["Monsters"][m.name].HasProperty(param)){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return DATA["NPCs"][m.name].GetProperty(param);
}else
if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
return DATA["Monsters"][m.name].GetProperty(param);
} else {
return DATA["MonsterStrategy"][strategy].GetProperty(param);
}
}
Pixel Monster::STRATEGY::_GetPixel(Monster&m,std::string param,std::string strategy,int index){
if(DATA["Monsters"][m.name].HasProperty(param)){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return DATA["NPCs"][m.name].GetProperty(param).GetPixel(index);
}else
if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
return DATA["Monsters"][m.name].GetProperty(param).GetPixel(index);
} else {
return DATA["MonsterStrategy"][strategy].GetProperty(param).GetPixel(index);

@ -101,6 +101,7 @@ struct NPCData{
std::string spawnFlag="";
uint32_t roamingRange=0;
vf2d spawnPos;
NPCData();
NPCData(XMLTag npcTag);
};
@ -296,6 +297,7 @@ class TMXParser{
const std::string_view Map::GetMapDisplayName()const{
return name;
}
NPCData::NPCData(){}
NPCData::NPCData(XMLTag npcTag){
const std::array<std::string,7>tags={"Function","NPC Name","Roaming Range","Spawn Flag","Spritesheet","x","y"};

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 6533
#define VERSION_BUILD 6563
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -491,5 +491,13 @@ MonsterStrategy
}
NPC
{
# How much to offset the text for the Interaction input display.
Interaction Display Offset = 0,-16
# Amount of time for the interaction display input to fade in/out.
Interaction Display Ease in Timer = 0.5s
# The maximum distance from the player that the NPC can be to interact with them.
Interaction Distance = 200
}
}

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.1" name="Tilesheet_No_Shadow24x24" class="Terrain" tilewidth="24" tileheight="24" tilecount="2912" columns="52">
<grid orientation="orthogonal" width="12" height="12"/>
<image source="commercial_assets/Tilesheet_No_Shadow24x24.png" width="1248" height="1344"/>
<tile id="0">
<objectgroup draworder="index" id="2">

Loading…
Cancel
Save