diff --git a/.gitignore b/.gitignore
index bee7a5a5..eb0f3c58 100644
--- a/.gitignore
+++ b/.gitignore
@@ -396,3 +396,4 @@ build/CMakeFiles/3.16.3/CompilerIdC/CMakeCCompilerId.c
build/CMakeFiles/3.16.3/CompilerIdCXX/CMakeCXXCompilerId.cpp
test.cpp
/Adventures in Lestoria/Adventures in Lestoria
+/Adventures in Lestoria/packkey.cpp
diff --git a/Adventures in Lestoria/Adventures in Lestoria.tiled-project b/Adventures in Lestoria/Adventures in Lestoria.tiled-project
index ec92d7ed..5738345f 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.tiled-project
+++ b/Adventures in Lestoria/Adventures in Lestoria.tiled-project
@@ -7,6 +7,8 @@
"folders": [
"."
],
+ "properties": [
+ ],
"propertyTypes": [
{
"color": "#ff3af8eb",
@@ -170,6 +172,26 @@
"layer"
]
},
+ {
+ "color": "#ff4f4f51",
+ "drawFill": true,
+ "id": 37,
+ "members": [
+ {
+ "name": "Scroll Direction",
+ "propertyType": "ScrollDirection",
+ "type": "string",
+ "value": "NORTH"
+ }
+ ],
+ "name": "Focus Area",
+ "type": "class",
+ "useAs": [
+ "property",
+ "object",
+ "project"
+ ]
+ },
{
"color": "#ffd9d929",
"drawFill": true,
@@ -420,6 +442,23 @@
"tile"
]
},
+ {
+ "id": 38,
+ "name": "ScrollDirection",
+ "storageType": "string",
+ "type": "enum",
+ "values": [
+ "NORTH",
+ "NORTHEAST",
+ "EAST",
+ "SOUTHEAST",
+ "SOUTH",
+ "SOUTHWEST",
+ "WEST",
+ "NORTHWEST"
+ ],
+ "valuesAsFlags": false
+ },
{
"color": "#ffe67300",
"drawFill": true,
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index e1ce0284..5d9bcfec 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -387,6 +387,10 @@
+
+
+
+
@@ -643,6 +647,10 @@
+
+
+
+
@@ -670,6 +678,7 @@
+
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
index 39994c4f..a456dcc7 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
@@ -465,6 +465,9 @@
Header Files
+
+ Header Files
+
@@ -812,6 +815,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp
index d6ace783..7ec81296 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.cpp
+++ b/Adventures in Lestoria/AdventuresInLestoria.cpp
@@ -76,11 +76,13 @@ All rights reserved.
#include "discord.h"
#endif
#include "GameSettings.h"
+#include "LoadingScreen.h"
INCLUDE_EMITTER_LIST
INCLUDE_ITEM_CATEGORIES
INCLUDE_BACKDROP_DATA
INCLUDE_MONSTER_DATA
+INCLUDE_PACK_KEY
bool _DEBUG_MAP_LOAD_INFO = false;
//360x240
@@ -226,8 +228,7 @@ AiL::AiL()
}
bool AiL::OnUserCreate(){
- std::string packKey="129jvgndsaf7dsa8932hj";
- gamepack.LoadPack("assets/"+"gamepack_file"_S,packKey);
+ gamepack.LoadPack("assets/"+"gamepack_file"_S,PACK_KEY);
GamePad::init();
@@ -278,7 +279,6 @@ bool AiL::OnUserCreate(){
Inventory::AddItem("Minor Health Potion"s,3);
Inventory::AddItem("Bandages"s,10);
- LoadLevel("starting_map"_S);
ChangePlayerClass(WARRIOR);
GameState::Initialize();
@@ -320,7 +320,7 @@ bool AiL::OnUserCreate(){
gameInitialized=true;
if(!gamepack.Loaded()&&"GENERATE_GAMEPACK"_B){
- gamepack.SavePack("assets/"+"gamepack_file"_S,packKey);
+ gamepack.SavePack("assets/"+"gamepack_file"_S,PACK_KEY);
std::cout<<"Game Pack has been generated!"<OnUserUpdate(this);
}
+ LoadingScreen::Update();
InputListener::Update();
Audio::Update();
RenderWorld(GetElapsedTime());
@@ -343,6 +344,7 @@ bool AiL::OnUserUpdate(float fElapsedTime){
RenderMenu();
GameState::STATE->DrawOverlay(this);
RenderFadeout();
+ LoadingScreen::Draw();
RenderVersionInfo();
#ifndef __EMSCRIPTEN__
if(Discord){
@@ -898,6 +900,7 @@ void AiL::RenderWorld(float fElapsedTime){
PopulateRenderLists();
auto RenderPlayer=[&](vf2d pos,vf2d scale){
+ if(player->IsInvisible())return;
vf2d playerScale=vf2d(player->GetSizeMult(),player->GetSizeMult());
int count=0;
for(vf2d&pos:player->ghostPositions){
@@ -1153,7 +1156,9 @@ void AiL::RenderWorld(float fElapsedTime){
if(view.IsRectVisible(group.GetRange().pos,group.GetRange().size)){
if(geom2d::overlaps(group.GetFadeRange(),player->pos)){
group.playerBehind=true;
- group.fadeFactor=std::min(group.fadeFactor+fElapsedTime,TileGroup::FADE_TIME);
+ if(GameState::STATE!=GameState::states[States::MAIN_MENU]){ //Don't fade out tile groups while we are on the main menu.
+ group.fadeFactor=std::min(group.fadeFactor+fElapsedTime,TileGroup::FADE_TIME);
+ }
} else {
group.playerBehind=false;
group.fadeFactor=std::max(group.fadeFactor-fElapsedTime,0.f);
@@ -1319,7 +1324,9 @@ void AiL::RenderWorld(float fElapsedTime){
if(view.IsRectVisible(group.GetRange().pos,group.GetRange().size)){
if(geom2d::overlaps(group.GetFadeRange(),player->pos)){
group.playerBehind=true;
- group.fadeFactor=std::min(group.fadeFactor+fElapsedTime,TileGroup::FADE_TIME);
+ if(GameState::STATE!=GameState::states[States::MAIN_MENU]){ //Don't fade out tile groups while we are on the main menu.
+ group.fadeFactor=std::min(group.fadeFactor+fElapsedTime,TileGroup::FADE_TIME);
+ }
} else {
group.playerBehind=false;
group.fadeFactor=std::max(group.fadeFactor-fElapsedTime,0.f);
@@ -1582,6 +1589,16 @@ void AiL::RenderCooldowns(){
const auto DrawCooldown=[&](vf2d pos,Ability&a,int loadoutSlot=-1/*Set to 0-2 to get an item slot rendered instead*/){
bool circle=loadoutSlot==-1;
if(a.name!="???"){
+
+ vf2d keyDisplaySize=vf2d{GetTextSize(a.input->GetDisplayName())}*vf2d{0.5f,0.5f};
+ InputType controlType=KEY;
+ if(Input::UsingGamepad())controlType=CONTROLLER;
+ vf2d drawOffset={};
+ if(loadoutSlot!=-1){
+ drawOffset.y+=2.f;
+ }
+ a.input->DrawInput(game,pos+vf2d{14,0.f}+drawOffset,"",255,controlType,{0.75f,0.75f});
+
if(a.cooldown>0.1){
vf2d iconScale={1,1};
if(loadoutSlot!=-1)iconScale={0.7f,0.7f};
@@ -1647,9 +1664,6 @@ void AiL::RenderCooldowns(){
vf2d manaCostSize=vf2d{GetTextSize(std::to_string(a.manaCost))}*vf2d{0.5f,0.75f};
DrawShadowStringDecal(pos+vf2d{20,4}-manaCostSize/2,std::to_string(a.manaCost),{192,192,255},manaCostShadowCol,{0.5f,0.75f});
}
-
- vf2d keyDisplaySize=vf2d{GetTextSize(a.input->GetDisplayName())}*vf2d{0.5f,0.5f};
- DrawShadowStringDecal(pos+vf2d{12,-2}-keyDisplaySize/2,a.input->GetDisplayName(),keyDisplayCol,BLACK,{0.5f,0.5f},std::numeric_limits::max(),1);
vf2d shortNameSize=vf2d{GetTextSize(a.shortName)}*vf2d{0.5f,0.75f};
DrawShadowStringDecal(pos+vf2d{13,24}-shortNameSize/2,a.shortName,shortNameCol,{255,255,255,230},{0.5f,0.75f});
@@ -1820,282 +1834,354 @@ void AiL::InitializeLevel(std::string mapFile,MapName map){
}
}
-void AiL::LoadLevel(MapName map){
- if(game->MAP_DATA.count(map)==0)ERR(std::format("WARNING! Could not load map {}! Does not exist! Refer to levels.txt for valid maps.",map));
- if(game->MAP_DATA[map].GetMapType()=="Hub"&&GameState::STATE!=GameState::states[States::GAME_HUB])ERR("WARNING! A hub level should only be initiated in the GAME_HUB game state!");
-
- #pragma region Reset Environmental Audio
- for(EnvironmentalAudio&audio:MAP_DATA[GetCurrentLevel()].environmentalAudioData){
- audio.Deactivate();
- }
- #pragma endregion
+void AiL::LoadLevel(MapName map,MusicChange changeMusic){
+ LoadingScreen::loading=true;
+ _PrepareLevel(map,changeMusic);
+}
- SPAWNER_LIST.clear();
- foregroundTileGroups.clear();
- upperForegroundTileGroups.clear();
- MONSTER_LIST.clear();
- ZONE_LIST.clear();
- ItemDrop::drops.clear();
- GameEvent::events.clear();
- worldColor=WHITE;
- worldColorFunc=[&](vi2d pos){return game->worldColor;};
+void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){
+ LoadingScreen::Reset();
+ previousLevel=currentLevel;
currentLevel=map;
- levelTime=0;
- bossName="";
- encounterDuration=0;
- totalDamageDealt=0;
- encounterStarted=false;
- totalBossEncounterMobs=0;
- Inventory::Clear("Monster Loot");
- Inventory::Clear("Stage Loot");
-
- GetPlayer()->hp=GetPlayer()->GetMaxHealth();
- GetPlayer()->mana=GetPlayer()->GetMaxMana();
- GetPlayer()->SetState(State::NORMAL);
- GetPlayer()->GetCastInfo()={};
- GetPlayer()->ResetAccumulatedXP();
-
- ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
+ #pragma region Reset all data (Loading phase 1)
+ LoadingScreen::AddPhase([&](){
+ if(game->MAP_DATA.count(GetCurrentLevel())==0)ERR(std::format("WARNING! Could not load map {}! Does not exist! Refer to levels.txt for valid maps.",map));
+ if(game->MAP_DATA[GetCurrentLevel()].GetMapType()=="Hub"&&GameState::STATE!=GameState::states[States::GAME_HUB])ERR("WARNING! A hub level should only be initiated in the GAME_HUB game state!");
+
+ #pragma region Reset Environmental Audio
+ for(EnvironmentalAudio&audio:MAP_DATA[previousLevel].environmentalAudioData){
+ audio.Deactivate();
+ }
+ #pragma endregion
+
+ SPAWNER_LIST.clear();
+ foregroundTileGroups.clear();
+ upperForegroundTileGroups.clear();
+ MONSTER_LIST.clear();
+ ZONE_LIST.clear();
+ ItemDrop::drops.clear();
+ GameEvent::events.clear();
+ worldColor=WHITE;
+ worldColorFunc=[&](vi2d pos){return game->worldColor;};
+ levelTime=0;
+ bossName="";
+ encounterDuration=0;
+ totalDamageDealt=0;
+ encounterStarted=false;
+ totalBossEncounterMobs=0;
+ Inventory::Clear("Monster Loot");
+ Inventory::Clear("Stage Loot");
+
+ GetPlayer()->hp=GetPlayer()->GetMaxHealth();
+ GetPlayer()->mana=GetPlayer()->GetMaxMana();
+ GetPlayer()->SetState(State::NORMAL);
+ GetPlayer()->GetCastInfo()={};
+ GetPlayer()->ResetAccumulatedXP();
+ GetPlayer()->SetIframes(0.f);
+ GetPlayer()->SetInvisible(false);
+
+ ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
+ return true;
+ });
+ #pragma endregion
- #pragma region Monster Spawn Data Setup
- for(auto&[key,value]:MAP_DATA[map].SpawnerData){
- SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key];
- std::vector>monster_list;
+ #pragma region Monster Spawn Data Setup (Loading phase 2)
+ LoadingScreen::AddPhase([&](){
+ for(auto&[key,value]:MAP_DATA[GetCurrentLevel()].SpawnerData){
+ SpawnerTag&spawnData=MAP_DATA[GetCurrentLevel()].SpawnerData[key];
+ std::vector>monster_list;
- vf2d spawnerRadius=vf2d{spawnData.ObjectData.GetFloat("width"),spawnData.ObjectData.GetFloat("height")}/2;
- for(XMLTag&monster:spawnData.monsters){
- std::string monsterName=monster.GetString("value");
- monster_list.push_back({monsterName,{monster.GetInteger("x")-spawnData.ObjectData.GetFloat("x"),monster.GetInteger("y")-spawnData.ObjectData.GetFloat("y")}});
+ vf2d spawnerRadius=vf2d{spawnData.ObjectData.GetFloat("width"),spawnData.ObjectData.GetFloat("height")}/2;
+ for(XMLTag&monster:spawnData.monsters){
+ std::string monsterName=monster.GetString("value");
+ monster_list.push_back({monsterName,{monster.GetInteger("x")-spawnData.ObjectData.GetFloat("x"),monster.GetInteger("y")-spawnData.ObjectData.GetFloat("y")}});
+ }
+ SPAWNER_LIST.push_back(MonsterSpawner{{spawnData.ObjectData.GetFloat("x"),spawnData.ObjectData.GetFloat("y")},spawnerRadius*2,monster_list,spawnData.upperLevel,spawnData.bossNameDisplay});
}
- SPAWNER_LIST.push_back(MonsterSpawner{{spawnData.ObjectData.GetFloat("x"),spawnData.ObjectData.GetFloat("y")},spawnerRadius*2,monster_list,spawnData.upperLevel,spawnData.bossNameDisplay});
- }
+ return true;
+ });
#pragma endregion
- #pragma region Identify Upper Foreground Tiles
- auto GetUpperZones=[&](){
- for(auto&zoneSet:MAP_DATA[map].ZoneData){
- if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
- return zoneSet.second;
+ #pragma region Identify Upper Foreground Tiles (Loading phase 3)
+ LoadingScreen::AddPhase([&](){
+ auto GetUpperZones=[&](){
+ for(auto&zoneSet:MAP_DATA[GetCurrentLevel()].ZoneData){
+ if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
+ return zoneSet.second;
+ }
}
- }
- return std::vector{};
- };
- for(ZoneData&zone:GetUpperZones()){
- int zoneX=zone.zone.pos.x/game->GetCurrentMapData().tilewidth; //snap to grid
- int zoneY=zone.zone.pos.y/game->GetCurrentMapData().tilewidth;
- int zoneW=zone.zone.right().start.x/game->GetCurrentMapData().tilewidth-zoneX;
- int zoneH=zone.zone.bottom().start.y/game->GetCurrentMapData().tilewidth-zoneY;
- for(int x=zoneX;x{};
+ };
+ for(ZoneData&zone:GetUpperZones()){
+ int zoneX=zone.zone.pos.x/game->GetCurrentMapData().tilewidth; //snap to grid
+ int zoneY=zone.zone.pos.y/game->GetCurrentMapData().tilewidth;
+ int zoneW=zone.zone.right().start.x/game->GetCurrentMapData().tilewidth-zoneX;
+ int zoneH=zone.zone.bottom().start.y/game->GetCurrentMapData().tilewidth-zoneY;
+ for(int x=zoneX;xforegroundTilesAdded,upperForegroundTilesAdded;
- for(int x=0;xtileset->Sprite()->width/tileSheet.tileset->tilewidth;
- int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/tileSheet.tileset->tileheight;
- int tileSheetIndex=tileID-(tileSheet.firstgid-1);
- int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
- int tileSheetX=realTileSheetIndex%tileSheetWidth;
- int tileSheetY=realTileSheetIndex/tileSheetWidth;
- int checkTileIndex=tileID;
- int checkTileID=tileSheetIndex;
- #pragma region TileGroupShenanigans
- auto SetupTileGroups=[&](std::functionIsForeground,TileRenderData tile,std::set&foregroundTilesIncluded,std::vector&groups){
- if(foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()&&IsForeground(tileSheet,tileSheetIndex)){
- std::queuetileGroupChecks;
- TileGroup group;
- foregroundTilesIncluded.insert({x,y});
- group.InsertTile(tile);
- if(x>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{-1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x-1,y});
- if(x0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,-1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y-1});
- if(ytileset->Sprite()->width/tileSheet.tileset->tilewidth;
- int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/tileSheet.tileset->tileheight;
- int tileSheetIndex=tileID-(tileSheet.firstgid-1);
- int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
- int tileSheetX=realTileSheetIndex%tileSheetWidth;
- int tileSheetY=realTileSheetIndex/tileSheetWidth;
- TileRenderData tile={tileSheet,vi2d{pos.x,pos.y}*game->GetCurrentMapData().tilewidth,vi2d{tileSheetX,tileSheetY}*game->GetCurrentMapData().tilewidth,realTileSheetIndex,layer2ID};
- if(IsForeground(tileSheet,tileSheetIndex)){
- foregroundTilesIncluded.insert({pos.x,pos.y});
- group.InsertTile(tile);
- hadForeground=true;
+ #pragma region Foreground and Upper Foreground Tile Fade Group Setup (Loading phase 4)
+ LoadingScreen::AddPhase([&](){
+ std::setforegroundTilesAdded,upperForegroundTilesAdded;
+ for(int x=0;xtileset->Sprite()->width/tileSheet.tileset->tilewidth;
+ int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/tileSheet.tileset->tileheight;
+ int tileSheetIndex=tileID-(tileSheet.firstgid-1);
+ int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
+ int tileSheetX=realTileSheetIndex%tileSheetWidth;
+ int tileSheetY=realTileSheetIndex/tileSheetWidth;
+ int checkTileIndex=tileID;
+ int checkTileID=tileSheetIndex;
+ #pragma region TileGroupShenanigans
+ auto SetupTileGroups=[&](std::functionIsForeground,TileRenderData tile,std::set&foregroundTilesIncluded,std::vector&groups){
+ if(foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()&&IsForeground(tileSheet,tileSheetIndex)){
+ std::queuetileGroupChecks;
+ TileGroup group;
+ foregroundTilesIncluded.insert({x,y});
+ group.InsertTile(tile);
+ if(x>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{-1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x-1,y});
+ if(x0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,-1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y-1});
+ if(ytileset->Sprite()->width/tileSheet.tileset->tilewidth;
+ int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/tileSheet.tileset->tileheight;
+ int tileSheetIndex=tileID-(tileSheet.firstgid-1);
+ int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
+ int tileSheetX=realTileSheetIndex%tileSheetWidth;
+ int tileSheetY=realTileSheetIndex/tileSheetWidth;
+ TileRenderData tile={tileSheet,vi2d{pos.x,pos.y}*game->GetCurrentMapData().tilewidth,vi2d{tileSheetX,tileSheetY}*game->GetCurrentMapData().tilewidth,realTileSheetIndex,layer2ID};
+ if(IsForeground(tileSheet,tileSheetIndex)){
+ foregroundTilesIncluded.insert({pos.x,pos.y});
+ group.InsertTile(tile);
+ hadForeground=true;
+ }
+ layer2ID++;
}
- layer2ID++;
- }
- return hadForeground;
- };
- IterateThroughOtherLayers({x,y});
- while(!tileGroupChecks.empty()){
- vi2d&pos=tileGroupChecks.front();
- if(IterateThroughOtherLayers(pos,true)){
- foregroundTilesIncluded.insert({pos.x,pos.y}); //Regardless of if we found a foreground tile or not, we need to add this to not get stuck in an infinite loop.
- vi2d targetPos=pos+vi2d{-1,0};
- if(pos.x>0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
- targetPos=pos+vi2d{1,0};
- if(pos.x0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
- targetPos=pos+vi2d{0,1};
- if(pos.y0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
+ targetPos=pos+vi2d{1,0};
+ if(pos.x0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
+ targetPos=pos+vi2d{0,1};
+ if(pos.yGetCurrentMapData().tilewidth,vi2d{tileSheetX,tileSheetY}*game->GetCurrentMapData().tilewidth,realTileSheetIndex,layerID};
- SetupTileGroups([&](TilesheetData sheet,int tileID){return IsForegroundTile(sheet,tileID);},tile,foregroundTilesAdded,foregroundTileGroups);
- SetupTileGroups([&](TilesheetData sheet,int tileID){return IsUpperForegroundTile(tileID);},tile,upperForegroundTilesAdded,upperForegroundTileGroups);
- #pragma endregion
+ };
+ TileRenderData tile={tileSheet,vi2d{x,y}*game->GetCurrentMapData().tilewidth,vi2d{tileSheetX,tileSheetY}*game->GetCurrentMapData().tilewidth,realTileSheetIndex,layerID};
+ SetupTileGroups([&](TilesheetData sheet,int tileID){return IsForegroundTile(sheet,tileID);},tile,foregroundTilesAdded,foregroundTileGroups);
+ SetupTileGroups([&](TilesheetData sheet,int tileID){return IsUpperForegroundTile(tileID);},tile,upperForegroundTilesAdded,upperForegroundTileGroups);
+ #pragma endregion
+ }
}
+ layerID++;
}
- layerID++;
}
}
- }
- for(TileGroup&group:foregroundTileGroups){
- std::sort(group.GetTiles().begin(),group.GetTiles().end(),[](TileRenderData&t1,TileRenderData&t2){return t1.layerID&group){
- std::multimapdata;
- using TileDataGroup=std::multimap; //See below.
- std::vectorsplitUpData; //This stores every tile group with tiles as a multi map.
- std::setiteratedTiles;
- for(TileGroup&group:group){
- for(TileRenderData&tile:group.GetTiles()){
- data.insert({tile.pos,tile});
+ #pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting (Loading phase 5)
+ LoadingScreen::AddPhase([&](){
+ auto SplitUp=[&](std::vector&group){
+ std::multimapdata;
+ using TileDataGroup=std::multimap; //See below.
+ std::vectorsplitUpData; //This stores every tile group with tiles as a multi map.
+ std::setiteratedTiles;
+ for(TileGroup&group:group){
+ for(TileRenderData&tile:group.GetTiles()){
+ data.insert({tile.pos,tile});
+ }
}
- }
- auto IsAdjacent=[](int tile1,int tile2,int tileSheetWidth){
- return abs(tile1-tile2)==1||abs(tile1-tile2)>=tileSheetWidth-1&&abs(tile1-tile2)<=tileSheetWidth+1;
- };
- for(auto&[key,tile]:data){
- if(iteratedTiles.count(key))continue;
- vi2d loc=key;
- auto loc_tiles=data.equal_range(loc);
- for(auto&it=loc_tiles.first;it!=loc_tiles.second;++it){ //For each tile that exists at this position...
- TileRenderData&tile=(*it).second;
- bool groupFound=false;
- for(TileDataGroup&group:splitUpData){ //See if this position can fit into any existing tile groups
- for(int y=-game->GetCurrentMapData().tileheight;y<=game->GetCurrentMapData().tileheight;y+=game->GetCurrentMapData().tileheight){
- for(int x=-game->GetCurrentMapData().tilewidth;x<=game->GetCurrentMapData().tilewidth;x+=game->GetCurrentMapData().tilewidth){
- if(x!=0||y!=0){ //Check every adjacent location for a possible adjacent tile.
- vi2d checkOffset=loc+vi2d{x,y};
- auto find_tiles=group.equal_range(checkOffset);//Each tile group consists of tiles that may be adjacent to us. Find all tiles that are adjacent to us in this tile group.
- for(auto&it=find_tiles.first;it!=find_tiles.second;++it){
- //These are all tiles that were found adjacent to the location we are checking for. See if they match a potential group.
- TileRenderData&foundTile=(*it).second;
- if(tile.tileSheet.tileset==foundTile.tileSheet.tileset){ //Let's first see if they are even in the same tileset.
- //Let's get how many tiles wide this tile sheet is.
- int tileWidth=tile.tileSheet.tileset->tilewidth;
- int tileSheetWidth=tile.tileSheet.tileset->tileset->Sprite()->width/tileWidth;
- if(IsAdjacent(tile.tileID,foundTile.tileID,tileSheetWidth)){
- group.insert({loc,tile});//We add this tile to the group! It is adjacent!
- groupFound=true;
- goto groupIterationDone;
+ auto IsAdjacent=[](int tile1,int tile2,int tileSheetWidth){
+ return abs(tile1-tile2)==1||abs(tile1-tile2)>=tileSheetWidth-1&&abs(tile1-tile2)<=tileSheetWidth+1;
+ };
+ for(auto&[key,tile]:data){
+ if(iteratedTiles.count(key))continue;
+ vi2d loc=key;
+ auto loc_tiles=data.equal_range(loc);
+ for(auto&it=loc_tiles.first;it!=loc_tiles.second;++it){ //For each tile that exists at this position...
+ TileRenderData&tile=(*it).second;
+ bool groupFound=false;
+ for(TileDataGroup&group:splitUpData){ //See if this position can fit into any existing tile groups
+ for(int y=-game->GetCurrentMapData().tileheight;y<=game->GetCurrentMapData().tileheight;y+=game->GetCurrentMapData().tileheight){
+ for(int x=-game->GetCurrentMapData().tilewidth;x<=game->GetCurrentMapData().tilewidth;x+=game->GetCurrentMapData().tilewidth){
+ if(x!=0||y!=0){ //Check every adjacent location for a possible adjacent tile.
+ vi2d checkOffset=loc+vi2d{x,y};
+ auto find_tiles=group.equal_range(checkOffset);//Each tile group consists of tiles that may be adjacent to us. Find all tiles that are adjacent to us in this tile group.
+ for(auto&it=find_tiles.first;it!=find_tiles.second;++it){
+ //These are all tiles that were found adjacent to the location we are checking for. See if they match a potential group.
+ TileRenderData&foundTile=(*it).second;
+ if(tile.tileSheet.tileset==foundTile.tileSheet.tileset){ //Let's first see if they are even in the same tileset.
+ //Let's get how many tiles wide this tile sheet is.
+ int tileWidth=tile.tileSheet.tileset->tilewidth;
+ int tileSheetWidth=tile.tileSheet.tileset->tileset->Sprite()->width/tileWidth;
+ if(IsAdjacent(tile.tileID,foundTile.tileID,tileSheetWidth)){
+ group.insert({loc,tile});//We add this tile to the group! It is adjacent!
+ groupFound=true;
+ goto groupIterationDone;
+ }
}
}
}
}
}
}
+ groupIterationDone:
+ if(!groupFound){
+ splitUpData.push_back({});
+ splitUpData.back().insert({loc,tile}); //Since we could not find a group to fit in, we had to start a brand new group.
+ }
}
- groupIterationDone:
- if(!groupFound){
- splitUpData.push_back({});
- splitUpData.back().insert({loc,tile}); //Since we could not find a group to fit in, we had to start a brand new group.
- }
+ iteratedTiles.insert(loc);
}
- iteratedTiles.insert(loc);
- }
- group.clear();
- for(auto&split:splitUpData){
- TileGroup newGroup;
- for(auto&[key,value]:split){
- newGroup.InsertTile(value);
+ group.clear();
+ for(auto&split:splitUpData){
+ TileGroup newGroup;
+ for(auto&[key,value]:split){
+ newGroup.InsertTile(value);
+ }
+ group.push_back(newGroup);
}
- group.push_back(newGroup);
- }
- };
- SplitUp(foregroundTileGroups);
- SplitUp(upperForegroundTileGroups);
+ };
+ SplitUp(foregroundTileGroups);
+ SplitUp(upperForegroundTileGroups);
+ return true;
+ });
#pragma endregion
- #pragma region Bridge Layer Setup
- bridgeLayerIndex=-1;
- for(int counter=0;LayerTag&layer:MAP_DATA[map].LayerData){
- if(IsBridgeLayer(layer)){
- bridgeLayerIndex=counter;
+ #pragma region Bridge Layer Setup (Loading Phase 6)
+ LoadingScreen::AddPhase([&](){
+ bridgeLayerIndex=-1;
+ for(int counter=0;LayerTag&layer:MAP_DATA[GetCurrentLevel()].LayerData){
+ if(IsBridgeLayer(layer)){
+ bridgeLayerIndex=counter;
+ }
+ counter++;
}
- counter++;
- }
+ return true;
+ });
#pragma endregion
- for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
- if(Unlock::IsUnlocked(data.unlockCondition)){
- MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
- MONSTER_LIST.back().iframe_timer=INFINITE;
- MONSTER_LIST.back().npcData=data;
- }
- }
+ #pragma region Setup NPCs (Loading Phase 7)
+ LoadingScreen::AddPhase([&](){
+ for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
+ if(Unlock::IsUnlocked(data.unlockCondition)){
+ MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
+ MONSTER_LIST.back().iframe_timer=INFINITE;
+ MONSTER_LIST.back().npcData=data;
+ }
+ }
+ return true;
+ });
+ #pragma endregion
- player->GetAbility1().cooldown=0.f;
- player->GetAbility2().cooldown=0.f;
- player->GetAbility3().cooldown=0.f;
- player->GetAbility4().cooldown=0.f;
- player->GetRightClickAbility().cooldown=0.f;
- player->useItem1.cooldown=0.f;
- player->useItem2.cooldown=0.f;
- player->useItem3.cooldown=0.f;
+ #pragma region Setup Player and Camera (Loading Phase 8)
+ LoadingScreen::AddPhase([&](){
+ player->GetAbility1().cooldown=0.f;
+ player->GetAbility2().cooldown=0.f;
+ player->GetAbility3().cooldown=0.f;
+ player->GetAbility4().cooldown=0.f;
+ player->GetRightClickAbility().cooldown=0.f;
+ player->useItem1.cooldown=0.f;
+ player->useItem2.cooldown=0.f;
+ player->useItem3.cooldown=0.f;
- player->upperLevel=false; //Assume player starts on lower level.
- player->ForceSetPos(MAP_DATA[map].MapData.playerSpawnLocation); //Normal set pos does one axis and then the other, so this will make sure that we actually end up at the right spot and ignore collision rules.
+ player->upperLevel=false; //Assume player starts on lower level.
+ player->ForceSetPos(MAP_DATA[GetCurrentLevel()].MapData.playerSpawnLocation); //Normal set pos does one axis and then the other, so this will make sure that we actually end up at the right spot and ignore collision rules.
- vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
- camera.MoveCamera(cameraStartPos);
+ vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
+ camera.MoveCamera(cameraStartPos);
+ return true;
+ });
+ #pragma endregion
- pathfinder.Initialize();
- Audio::SetAudioEvent("Default Volume");
- game->audioEngine.fullyLoaded=true; //We assume there's no audio to load, so we just set the audio as fully loaded by default.
- if(MAP_DATA[map].bgmSongName.length()>0){
- Audio::PlayBGM(MAP_DATA[map].bgmSongName);
- DisableFadeIn(true);
+ #pragma region Setup Pathfinding (Loading Phase 9)
+ LoadingScreen::AddPhase([&](){
+ pathfinder.Initialize();
+ return true;
+ });
+ #pragma endregion
+
+ if(changeMusic==PLAY_LEVEL_MUSIC){
+ #pragma region Audio Preparation (Loading Phase 10)
+ LoadingScreen::AddPhase([&](){
+ Audio::SetAudioEvent("Default Volume");
+ game->audioEngine.fullyLoaded=true; //We assume there's no audio to load, so we just set the audio as fully loaded by default.
+ if(MAP_DATA[GetCurrentLevel()].bgmSongName.length()>0){
+ Audio::PrepareBGM(MAP_DATA[GetCurrentLevel()].bgmSongName);
+ DisableFadeIn(true);
+ }
+ return true;
+ });
+ #pragma endregion
+
+ //Until the audio has stopped (by waiting for a set amount of time), we will respect the audio engine's wishes and not proceed.
+ LoadingScreen::DeferLoad([&](){return audioEngine.playBGMWaitTime==0.f;}); //This is the wait time for the audio engine to finish.
+
+ #pragma region Audio Channel Loading (Count based on Audio::GetPrepareBGMLoopIterations)
+ for(int i=0;i>&AiL::GetZoneData(MapName map){
- return MAP_DATA[map].ZoneData;
-}
-
void AiL::ChangePlayerClass(Class cl){
Ability itemAbility1=player->useItem1;
Ability itemAbility2=player->useItem2;
@@ -3100,7 +3182,7 @@ void AiL::RenderFadeout(){
}
bool AiL::GamePaused(){
- return fadeOutDuration>0||disableFadeIn||paused;
+ return fadeOutDuration>0||disableFadeIn||paused||LoadingScreen::loading;
}
void AiL::PauseGame(){
@@ -3338,12 +3420,22 @@ const bool AiL::GameInitialized()const {
rcode AiL::LoadResource(Renderable&renderable,std::string_view imgPath,bool filter,bool clamp){
rcode returnCode;
if(gamepack.Loaded()){
- returnCode=renderable.Load(std::string(imgPath),&gamepack);
+ returnCode=renderable.Load(std::string(imgPath),&gamepack,filter,clamp);
}else{
- returnCode=renderable.Load(std::string(imgPath));
+ returnCode=renderable.Load(std::string(imgPath),nullptr,filter,clamp);
if("GENERATE_GAMEPACK"_B){
gamepack.AddFile(std::string(imgPath));
}
}
return returnCode;
+}
+
+void AiL::UpdateMonsters(){
+ for(Monster&m:MONSTER_LIST){
+ m.Update(game->GetElapsedTime());
+ }
+ for(Monster&m:game->monstersToBeSpawned){
+ MONSTER_LIST.push_back(m);
+ }
+ game->monstersToBeSpawned.clear();
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h
index d19bea8d..019deb78 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.h
+++ b/Adventures in Lestoria/AdventuresInLestoria.h
@@ -72,6 +72,10 @@ class AiL : public olc::PixelGameEngine
std::unique_ptrplayer;
SplashScreen splash;
public:
+ enum MusicChange{
+ NO_MUSIC_CHANGE,
+ PLAY_LEVEL_MUSIC,
+ };
Pathfinding pathfinder;
static InputGroup KEY_BACK;
static InputGroup KEY_CONFIRM;
@@ -127,6 +131,7 @@ private:
float lastWorldShakeAdjust=0;
vf2d worldShakeVel={};
const float WORLD_SHAKE_ADJUST_MAX_TIME=0.4f;
+ MapName previousLevel="CAMPAIGN_1_1";
MapName currentLevel="CAMPAIGN_1_1";
std::vectorforegroundTileGroups;
std::vectorupperForegroundTileGroups;
@@ -169,6 +174,7 @@ private:
ResourcePack gamepack;
void ValidateGameStatus();
+ void _PrepareLevel(MapName map,MusicChange changeMusic);
#ifndef __EMSCRIPTEN__
::discord::Result SetupDiscord();
#endif
@@ -186,7 +192,7 @@ public:
geom2d::rectNO_COLLISION={{0.f,0.f,},{0.f,0.f}};
TileTransformedView view;
void InitializeLevel(std::string mapFile,MapName map);
- void LoadLevel(MapName map);
+ void LoadLevel(MapName map,MusicChange changeMusic=PLAY_LEVEL_MUSIC);
void HandleUserInput(float fElapsedTime);
void UpdateCamera(float fElapsedTime);
void UpdateEffects(float fElapsedTime);
@@ -225,7 +231,6 @@ public:
bool HasTileCollision(MapName map,vf2d pos,bool upperLevel=false);
const MapName&GetCurrentLevel()const;
bool IsBridgeLayer(LayerTag&layer);
- std::map>&GetZoneData(MapName map);
void PopulateRenderLists();
void ChangePlayerClass(Class cl);
std::string GetString(std::string key);
@@ -290,6 +295,7 @@ public:
void ResumeGame();
const bool GameInitialized()const;
rcode LoadResource(Renderable&renderable,std::string_view imgPath,bool filter=false,bool clamp=true);
+ void UpdateMonsters();
struct TileGroupData{
vi2d tilePos;
diff --git a/Adventures in Lestoria/Audio.cpp b/Adventures in Lestoria/Audio.cpp
index f6c18027..ef2b464a 100644
--- a/Adventures in Lestoria/Audio.cpp
+++ b/Adventures in Lestoria/Audio.cpp
@@ -39,6 +39,7 @@ All rights reserved.
#include "AdventuresInLestoria.h"
#include "DEFINES.h"
#include "util.h"
+#include "LoadingScreen.h"
INCLUDE_game
INCLUDE_DATA
@@ -121,12 +122,21 @@ const size_t Audio::LoadAndPlay(const std::string_view sound,const bool loop){
Engine().Play(soundID,loop);
return soundID;
};
-void Audio::PlayBGM(const std::string_view sound,const bool loop){
+void Audio::PrepareBGM(const std::string_view sound,const bool loop){
BGM&track=Self().bgm[std::string(sound)];
Self().fullyLoaded=false;
StopBGM(); //Stop any currently playing track.
Self().playParams={std::string(sound),loop};
Self().playBGMWaitTime=0.7f;
+
+ #pragma region Internal Loading Loop Setup
+ Self().trackLoadStarted=false;
+ Self().trackLoadComplete=false;
+ Self().channelPlayingStarted=false;
+ Self().channelPlayingComplete=false;
+ int currentLoopIndex=0;
+ #pragma endregion
+ Self().immediatelyLoadAudio=false;
};
void Audio::StopBGM(){
@@ -145,24 +155,39 @@ const bool Audio::BGMIsPlaying(){
return Self().currentBGM.length()>0;
}
-const Volume&Audio::BGM::GetVolume(const Event&eventName,const ChannelID&id)const{
- return eventVolumes.GetVolumes(eventName).at(id);
+const Volume&Audio::BGM::GetVolume(const Event&eventName,const int&index)const{
+ return eventVolumes.GetVolumes(eventName).at(index);
}
void Audio::BGM::Load(){
- if(Self().BGMIsPlaying()){
- if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
- BGM&bgm=Self().bgm[Self().GetTrackName()];
+ if(!Self().trackLoadStarted){
+ Self().trackLoadStarted=true;
if(Self().BGMIsPlaying()){
- bgm.Unload();
+ if(Self().GetTrackName()==songFileName){ //We are already playing the current track.
+ Self().trackLoadComplete=Self().channelPlayingComplete=Self().fullyLoaded=true;
+ return;
+ }else{
+ BGM&bgm=Self().bgm[Self().GetTrackName()];
+ if(Self().BGMIsPlaying()){
+ bgm.Unload();
+ }
+ }
}
- }
- Self().currentBGM=songFileName;
- BGM&newBgm=Self().bgm[songFileName];
- if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
- for(const ChannelName&channel:newBgm.GetChannels()){
+ Self().currentBGM=songFileName;
+ Self().currentLoopIndex=0;
+ BGM&newBgm=Self().bgm[songFileName];
+ if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
+ }else{
+ BGM&newBgm=Self().bgm[songFileName];
+ const ChannelName&channel=newBgm.GetChannels()[Self().currentLoopIndex];
ChannelID soundID=Engine().LoadSound("bgm_directory"_S+channel);
newBgm.channels.push_back(soundID);
+ #pragma region Handle threaded loop indexing
+ Self().currentLoopIndex++;
+ if(Self().currentLoopIndex>=newBgm.GetChannels().size()){
+ Self().trackLoadComplete=true;
+ }
+ #pragma endregion
}
}
@@ -258,27 +283,60 @@ const SongName&Audio::GetTrackName(){
return Self().currentBGM;
}
-void Audio::Update(){
- if(Self().playBGMWaitTime>0.f){
- Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
- if(Self().playBGMWaitTime==0.f){
- BGM&track=Self().bgm[Self().playParams.sound];
+void Audio::UpdateLoop(){
+ if(Self().playBGMWaitTime==0.f){
+ BGM&track=Self().bgm[Self().playParams.sound];
+ if(!Self().trackLoadComplete){
track.Load();
- Self().prevVolumes.clear();
- Self().targetVolumes.clear();
- Self().fadeToTargetVolumeTime=0.f;
- for(int channelListIndex=0;int trackID:track.GetChannelIDs()){
- float channelVol=track.GetVolume(Self().currentAudioEvent,channelListIndex);
+ }else
+ if(!Self().channelPlayingComplete){
+ if(!Self().channelPlayingStarted){
+ Self().prevVolumes.clear();
+ Self().targetVolumes.clear();
+ Self().fadeToTargetVolumeTime=0.f;
+ Self().currentLoopIndex=0;
+ Self().channelPlayingStarted=true;
+ }else{
+ int trackID=track.GetChannelIDs()[Self().currentLoopIndex];
+ float channelVol=track.GetVolume(Self().currentAudioEvent,Self().currentLoopIndex);
Self().prevVolumes.push_back(channelVol);
Self().targetVolumes.push_back(channelVol);
Engine().SetVolume(trackID,channelVol*GetBGMVolume());
- Engine().Play(trackID,Self().playParams.loop);
- channelListIndex++;
+ #pragma region Handle threaded loop indexing
+ Self().currentLoopIndex++;
+ if(Self().currentLoopIndex>=track.GetChannelIDs().size()){
+ Self().channelPlayingComplete=true;
+ Self().fullyLoaded=true;
+ }
+ #pragma endregion
}
- Self().fullyLoaded=true;
+ }else
+ if(!Self().fullyLoaded){
+ ERR("Invalid loading state or too many calls to initialize audio loop! The audio is still not fully loaded!");
}
}
+}
+void Audio::PlayBGM(const std::string_view sound,const bool loop){
+ PrepareBGM(sound,loop);
+ Self().immediatelyLoadAudio=true;
+}
+
+void Audio::Update(){
+ if(Self().fadeToTargetVolumeTime==0.f&&Self().playBGMWaitTime>0.f){
+ Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
+ if(Self().playBGMWaitTime==0.f&&Self().immediatelyLoadAudio){
+ while(!Self().BGMFullyLoaded()){
+ UpdateLoop(); //We immediately load the file. In a loading screen setting we would defer UpdateLoop() such that we have extra time to update the screen, UpdateLoop() is divided into many parts of the music loading process.
+ }
+
+ //Start playing the tracks.
+ Audio::BGM&track=Self().bgm[Self().GetTrackName()];
+ for(int trackID:track.GetChannelIDs()){
+ Self().Engine().Play(trackID,true);
+ }
+ }
+ }
if(Self().fadeToTargetVolumeTime>0.f){
Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime());
for(int counter=0;float&vol:Self().prevVolumes){
@@ -318,4 +376,9 @@ float&Audio::GetSFXVolume(){
float Audio::GetMuteMult(){
if(muted)return 0.f;
return 1.f;
+}
+
+int Audio::GetPrepareBGMLoopIterations(std::string_view sound){
+ BGM&newBgm=Self().bgm[std::string(sound)];
+ return newBgm.GetChannels().size()*2+2; //The channels list gets populated by calling newBgm.Load(), which then provides the list of channels that need to be loaded and played. This is why we multiply by 2. Each of the loading phases also consist of an initialization phase, so we add 2 as well.
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Audio.h b/Adventures in Lestoria/Audio.h
index d5f019e1..0f1b5d42 100644
--- a/Adventures in Lestoria/Audio.h
+++ b/Adventures in Lestoria/Audio.h
@@ -56,10 +56,13 @@ public:
static MiniAudio&Engine();
static void Initialize();
static void Update();
+ static void UpdateLoop();
static void Play(const std::string_view sound);
[[nodiscard]]
static const size_t LoadAndPlay(const std::string_view sound,const bool loop=true);
- //Play a BGM given a name found in bgm.txt configuration file.
+ //Prepares a BGM for loading. This means we call UpdateLoop() repeatedly until the loading of the music is complete. Names are found in bgm.txt configuration file.
+ static void PrepareBGM(const std::string_view sound,const bool loop=true);
+ //Play immediately a BGM given a name found in bgm.txt configuration file.
static void PlayBGM(const std::string_view sound,const bool loop=true);
static void StopBGM();
static const Event&GetAudioEvent();
@@ -72,7 +75,17 @@ public:
static float&GetBGMVolume();
static float&GetSFXVolume();
static float GetMuteMult();
+ //This will get a prepared BGM loop iteration count which is useful for loading stages.
+ static int GetPrepareBGMLoopIterations(std::string_view sound);
private:
+ bool trackLoadStarted=false;
+ bool trackLoadComplete=false;
+ bool channelPlayingStarted=false;
+ bool channelPlayingComplete=false;
+ int currentLoopIndex=0;
+ //Set to false by PrepareBGM(). If PlayBGM() is called instead, it will set the state of this variable to true, such that the loading is performed in Audio::Update()!
+ bool immediatelyLoadAudio=false;
+
struct BGMPlayParams{
std::string sound;
bool loop;
@@ -92,7 +105,7 @@ private:
const size_t GetChannelCount()const;
const std::vector&GetChannels()const;
const SongName&GetName()const;
- const Volume&GetVolume(const Event&eventName,const ChannelID&id)const;
+ const Volume&GetVolume(const Event&eventName,const int&index)const;
void SetName(std::string_view name);
void SetFileName(std::string_view name);
void AddChannel(const ChannelName&name);
diff --git a/Adventures in Lestoria/CharacterAbilityPreviewComponent.h b/Adventures in Lestoria/CharacterAbilityPreviewComponent.h
index 8a53b925..a9b4ae0f 100644
--- a/Adventures in Lestoria/CharacterAbilityPreviewComponent.h
+++ b/Adventures in Lestoria/CharacterAbilityPreviewComponent.h
@@ -69,11 +69,10 @@ protected:
vi2d descriptionPos=iconPos+vi2d{int(rect.size.y)-2,-1};
window.DrawShadowStringPropDecal(descriptionPos,ability->description,WHITE,BLACK,{0.8f,1.f},int(rect.size.x-(descriptionPos.x-rect.pos.x))-4);
+
+ InputType controlType=KEY;
+ if(Input::UsingGamepad())controlType=CONTROLLER;
- if(textWidth>boxWidth){
- window.DrawShadowStringPropDecal(textPos,ability->input->GetDisplayName(),WHITE,BLACK,{boxWidth/textWidth*0.5f,0.5});
- }else{
- window.DrawShadowStringPropDecal(textPos,ability->input->GetDisplayName(),WHITE,BLACK,{0.5,0.5});
- }
+ ability->input->DrawInput(&window,textPos+vf2d{boxWidth/2,7},"",255,controlType,{0.5f,0.5f});
}
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/CharacterRotatingDisplay.h b/Adventures in Lestoria/CharacterRotatingDisplay.h
index 65d8ddc9..8c5fffe6 100644
--- a/Adventures in Lestoria/CharacterRotatingDisplay.h
+++ b/Adventures in Lestoria/CharacterRotatingDisplay.h
@@ -50,7 +50,7 @@ protected:
float perspectiveFactor=6;
public:
inline CharacterRotatingDisplay(geom2d::rectrect,Decal*icon)
- :MenuComponent(rect,"",DO_NOTHING),icon(icon){}
+ :MenuComponent(rect,"",DO_NOTHING,ButtonAttr::UNSELECTABLE),icon(icon){}
inline void SetIcon(Decal*icon){
this->icon=icon;
}
diff --git a/Adventures in Lestoria/DEFINES.h b/Adventures in Lestoria/DEFINES.h
index 6dd69956..04df454b 100644
--- a/Adventures in Lestoria/DEFINES.h
+++ b/Adventures in Lestoria/DEFINES.h
@@ -59,6 +59,8 @@ using BackdropName=std::string;
#define INCLUDE_WINDOW_SIZE extern vi2d WINDOW_SIZE;
#define INCLUDE_ITEM_CONVERSIONS extern safemapITEM_CONVERSIONS;
+#define INCLUDE_PACK_KEY extern std::string PACK_KEY;
+
#define INCLUDE_BACKDROP_DATA extern std::mapBACKDROP_DATA;
diff --git a/Adventures in Lestoria/GameState.h b/Adventures in Lestoria/GameState.h
index f90762f3..c3023185 100644
--- a/Adventures in Lestoria/GameState.h
+++ b/Adventures in Lestoria/GameState.h
@@ -73,4 +73,5 @@ public:
virtual void GetAnyMousePress(int32_t mouseButton);
virtual void GetAnyMouseRelease(int32_t mouseButton);
static void ChangeState(States::State newState,float fadeOutDuration=0);
+ virtual void OnLevelLoad()=0;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/ItemDrop.cpp b/Adventures in Lestoria/ItemDrop.cpp
index c6fb63aa..64c73833 100644
--- a/Adventures in Lestoria/ItemDrop.cpp
+++ b/Adventures in Lestoria/ItemDrop.cpp
@@ -118,13 +118,13 @@ void ItemDrop::UpdateDrops(float fElapsedTime){
#pragma region Handle Upper/Lower Level Zone Intersecting
if(drop.speed.mag()>0){
- std::map>&zoneData=game->GetZoneData(game->GetCurrentLevel());
- for(ZoneData&upperLevelZone:zoneData["UpperZone"]){
+ const std::map>&zoneData=game->GetZones(game->GetCurrentLevel());
+ for(const ZoneData&upperLevelZone:zoneData.at("UpperZone")){
if(geom2d::overlaps(upperLevelZone.zone,drop.pos)){
drop.upperLevel=true;
}
}
- for(ZoneData&lowerLevelZone:zoneData["LowerZone"]){
+ for(const ZoneData&lowerLevelZone:zoneData.at("LowerZone")){
if(geom2d::overlaps(lowerLevelZone.zone,drop.pos)){
drop.upperLevel=false;
}
diff --git a/Adventures in Lestoria/Key.cpp b/Adventures in Lestoria/Key.cpp
index 9d0e79ee..0116d3f1 100644
--- a/Adventures in Lestoria/Key.cpp
+++ b/Adventures in Lestoria/Key.cpp
@@ -302,7 +302,7 @@ std::string InputGroup::GetDisplayName(){
return combinationDisplay;
}
-void InputGroup::DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha,InputType type)const{
+void InputGroup::DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha,InputType type,vf2d textScale)const{
std::optionalprimaryKey;
switch(type){
case CONTROLLER:primaryKey=GetPrimaryKey(CONTROLLER);break;
@@ -317,16 +317,16 @@ void InputGroup::DrawInput(const std::variantwidth+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=input.GetIcon(GameSettings::GetIconType()).Sprite()->width*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(input.GetIcon(GameSettings::GetIconType()).Sprite()->height));
buttonImgs.push_back(input.GetIcon(GameSettings::GetIconType()).Decal());
}else
if(input.HasIcon()){
- buttonImgSize.x+=input.GetIcon().Sprite()->width+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=input.GetIcon().Sprite()->width*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(input.GetIcon().Sprite()->height));
buttonImgs.push_back(input.GetIcon().Decal());
}else{
- buttonImgSize.x+=game->GetTextSizeProp(input.GetDisplayName()).x+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=game->GetTextSizeProp(input.GetDisplayName()).x*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(game->GetTextSizeProp(input.GetDisplayName()).y)+"Interface.InputHelperSpacing"_F);
buttonImgs.push_back(input.GetDisplayName());
}
@@ -336,16 +336,16 @@ void InputGroup::DrawInput(const std::variantwidth+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=primaryKey.value().GetIcon(GameSettings::GetIconType()).Sprite()->width*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(primaryKey.value().GetIcon(GameSettings::GetIconType()).Sprite()->height));
buttonImgs.push_back(primaryKey.value().GetIcon(GameSettings::GetIconType()).Decal());
}else
if(primaryKey.value().HasIcon()){
- buttonImgSize.x+=primaryKey.value().GetIcon().Sprite()->width+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=primaryKey.value().GetIcon().Sprite()->width*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(primaryKey.value().GetIcon().Sprite()->height));
buttonImgs.push_back(primaryKey.value().GetIcon().Decal());
}else{
- buttonImgSize.x+=game->GetTextSizeProp(primaryKey.value().GetDisplayName()).x+"Interface.InputHelperSpacing"_F;
+ buttonImgSize.x+=game->GetTextSizeProp(primaryKey.value().GetDisplayName()).x*textScale.x+"Interface.InputHelperSpacing"_F;
buttonImgSize.y=std::max(buttonImgSize.y,float(game->GetTextSizeProp(primaryKey.value().GetDisplayName()).y)+"Interface.InputHelperSpacing"_F);
buttonImgs.push_back(primaryKey.value().GetDisplayName());
}
@@ -359,19 +359,22 @@ void InputGroup::DrawInput(const std::variant(renderer)->DrawDecal(pos+offset-vf2d{0.f,2.f},img,{1.f,1.f},{255,255,255,alpha});
+ std::get(renderer)->DrawDecal(pos+offset-vf2d{0.f,2.f},img,textScale,{255,255,255,alpha});
#pragma endregion
if(std::holds_alternative(renderer)){
Render(AiL);
}else
if(std::holds_alternative(renderer)){
Render(TileTransformedView);
- }
- offset.x+=img->sprite->width+"Interface.InputHelperSpacing"_I;
+ }else
+ if(std::holds_alternative(renderer)){
+ Render(ViewPort);
+ }else ERR("Could not find proper renderer for rendering Inputs!");
+ offset.x+=img->sprite->width*textScale.x+"Interface.InputHelperSpacing"_I;
}else
if(std::holds_alternative(button)){
std::string label=std::get(button);
- vf2d textSize=game->GetTextSizeProp(label);
+ vf2d textSize=game->GetTextSizeProp(label)*textScale;
Pixel buttonBackCol="Interface.InputButtonBackCol"_Pixel;
Pixel buttonTextCol="Interface.InputButtonTextCol"_Pixel;
buttonBackCol.a=alpha;
@@ -382,7 +385,7 @@ void InputGroup::DrawInput(const std::variant(renderer)->FillRectDecal(pos+offset+vf2d{-2.f,0.f},vf2d{textSize.x+4,textSize.y},buttonBackCol); \
std::get(renderer)->FillRectDecal(pos+offset+vf2d{-1.f,-1.f},vf2d{textSize.x+2,textSize.y},buttonBackCol); \
std::get(renderer)->FillRectDecal(pos+offset+vf2d{-1.f,0.f},vf2d{textSize.x+2,textSize.y+1.f},buttonBackCol); \
- std::get(renderer)->DrawStringPropDecal(pos+offset+vf2d{0.f,0.f},label,buttonTextCol);
+ std::get(renderer)->DrawStringPropDecal(pos+offset+vf2d{0.f,0.f},label,buttonTextCol,textScale);
#pragma endregion
if(std::holds_alternative(renderer)){
@@ -390,15 +393,33 @@ void InputGroup::DrawInput(const std::variant(renderer)){
Render(TileTransformedView);
- }
+ }else
+ if(std::holds_alternative(renderer)){
+ Render(ViewPort);
+ }else ERR("Could not find proper renderer for rendering Inputs!");
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!");
}
+
+ #pragma region Render Display Text
+ #pragma region Render Macro
+ #define Render(rendererType) \
+ std::get(renderer)->DrawShadowStringPropDecal(pos+offset,displayText,{255,255,255,alpha},{0,0,0,alpha},textScale);
+ #pragma endregion
- game->view.DrawShadowStringPropDecal(pos+offset,displayText,{255,255,255,alpha},{0,0,0,alpha});
+ if(std::holds_alternative(renderer)){
+ Render(AiL);
+ }else
+ if(std::holds_alternative(renderer)){
+ Render(TileTransformedView);
+ }else
+ if(std::holds_alternative(renderer)){
+ Render(ViewPort);
+ }else ERR("Could not find proper renderer for rendering Inputs!");
+ #pragma endregion
}
-void InputGroup::DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha)const{
+void InputGroup::DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha)const{
InputType primaryType;
if(Input::UsingGamepad())primaryType=CONTROLLER;
else if(Menu::UsingMouseNavigation())primaryType=MOUSE;
diff --git a/Adventures in Lestoria/Key.h b/Adventures in Lestoria/Key.h
index 489c7333..6fbb6e79 100644
--- a/Adventures in Lestoria/Key.h
+++ b/Adventures in Lestoria/Key.h
@@ -44,6 +44,7 @@ All rights reserved.
#include "olcPGEX_TransformedView.h"
#include
#include "IconType.h"
+#include "olcPGEX_ViewPort.h"
class AiL;
@@ -119,8 +120,8 @@ public:
const float AnalogDAS(const float threshold=0.2f);
std::string GetDisplayName();
//Draws an input display with accompanying text centered at given position.
- void DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha)const;
- void DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha,const InputType type)const;
+ void DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha)const;
+ void DrawInput(const std::variantrenderer,const vf2d pos,const std::string_view displayText,const uint8_t alpha,const InputType type,vf2d textScale={1.f,1.f})const;
const std::optionalGetPrimaryKey(InputType type)const;
};
diff --git a/Adventures in Lestoria/LoadingScreen.cpp b/Adventures in Lestoria/LoadingScreen.cpp
new file mode 100644
index 00000000..1b3bae4a
--- /dev/null
+++ b/Adventures in Lestoria/LoadingScreen.cpp
@@ -0,0 +1,108 @@
+#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 © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+
+#include "AdventuresInLestoria.h"
+#include "LoadingScreen.h"
+#include "util.h"
+
+INCLUDE_game
+INCLUDE_WINDOW_SIZE
+INCLUDE_ANIMATION_DATA
+
+bool LoadingScreen::loading=false;
+int LoadingScreen::currentProgress=0;
+int LoadingScreen::totalProgress=0;
+std::queue>LoadingScreen::loadingPhases;
+bool LoadingScreen::showGhost=false;
+bool LoadingScreen::showLarge=false;
+
+void LoadingScreen::DeferLoad(std::functionwaitCondition){
+ AddPhase(waitCondition);
+}
+
+void LoadingScreen::Update(){
+ if(loading){
+ if(loadingPhases.size()>0){
+ std::function&loadFunc=loadingPhases.front();
+ if(loadFunc()){
+ currentProgress++;
+ loadingPhases.pop();
+ }
+ }else{
+ loading=false;
+ GameState::STATE->OnLevelLoad();
+ }
+ }
+}
+void LoadingScreen::Draw(){
+ if(loading){
+ game->FillRectDecal({0,0},WINDOW_SIZE,{VERY_DARK_GREEN.r,VERY_DARK_GREEN.g,VERY_DARK_GREEN.b,230});
+
+ game->FillRectDecal({22.f,WINDOW_SIZE.y-46.f},{(float(currentProgress)/totalProgress)*(WINDOW_SIZE.x-48.f)+4.f,28.f},VERY_DARK_GREEN/2);
+
+ game->FillRectDecal({24.f,WINDOW_SIZE.y-48.f},{(float(currentProgress)/totalProgress)*(WINDOW_SIZE.x-48.f),24.f},DARK_YELLOW);
+ game->DrawShadowStringPropDecal({24.f,WINDOW_SIZE.y-60.f},"Loading...",{170,210,0},BLACK,{1.f,1.5f});
+
+ vf2d playerScale=vf2d(game->GetPlayer()->GetSizeMult(),game->GetPlayer()->GetSizeMult());
+ float scale=1.f;
+ if(showLarge){
+ scale=2.f;
+ }
+ const std::vectorattackBuffs=game->GetPlayer()->GetStatBuffs({"Attack","Attack %"});
+ Pixel blendCol=attackBuffs.size()>0?Pixel{255,uint8_t(255*abs(sin(1.4*attackBuffs[0].duration))),uint8_t(255*abs(sin(1.4*attackBuffs[0].duration)))}:WHITE;
+ if(showGhost){
+ blendCol=BLACK;
+ }
+ game->GetPlayer()->GetWalkEAnimation();
+ Animate2D::FrameSequence&playerWalkE=ANIMATION_DATA[game->GetPlayer()->GetWalkEAnimation()];
+ game->DrawPartialRotatedDecal({(float(currentProgress)/totalProgress)*(WINDOW_SIZE.x-48.f),WINDOW_SIZE.y-36.f},playerWalkE.GetFrame(game->GetRuntime()).GetSourceImage()->Decal(),game->GetPlayer()->GetSpinAngle(),{12,12},playerWalkE.GetFrame(game->GetRuntime()).GetSourceRect().pos,playerWalkE.GetFrame(game->GetRuntime()).GetSourceRect().size,playerScale*scale,blendCol);
+ }
+}
+
+void LoadingScreen::Reset(){
+ currentProgress=0;
+ totalProgress=0;
+ showGhost=util::random()%6==0;
+ showLarge=util::random()%6==0;
+ while(loadingPhases.size()>0)ERR("WARNING! Previous loading phase was not properly cleared! This probably means some part of a previous load did not execute!");
+}
+
+void LoadingScreen::AddPhase(std::functionloadFunc){
+ loadingPhases.push(loadFunc);
+ totalProgress++;
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/LoadingScreen.h b/Adventures in Lestoria/LoadingScreen.h
new file mode 100644
index 00000000..7826243b
--- /dev/null
+++ b/Adventures in Lestoria/LoadingScreen.h
@@ -0,0 +1,57 @@
+#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 © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#pragma once
+
+#include
+#include "olcUTIL_Animate2D.h"
+
+class LoadingScreen{
+public:
+ static bool loading;
+ static int currentProgress;
+ static int totalProgress;
+ static float waitTime;
+ static bool showGhost;
+ static bool showLarge;
+ static std::queue>loadingPhases;
+ static void Update();
+ static void Draw();
+ static void DeferLoad(std::functionwaitCondition);
+ static void Reset();
+ static void AddPhase(std::functionloadFunc);
+};
\ No newline at end of file
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index c70db3d4..ce6214a3 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -455,13 +455,13 @@ bool Monster::SetPos(vf2d pos){
return resultX||resultY;
}
void Monster::Moved(){
- std::map>&zoneData=game->GetZoneData(game->GetCurrentLevel());
- for(ZoneData&upperLevelZone:zoneData["UpperZone"]){
+ const std::map>&zoneData=game->GetZones(game->GetCurrentLevel());
+ for(const ZoneData&upperLevelZone:zoneData.at("UpperZone")){
if(geom2d::overlaps(upperLevelZone.zone,pos)){
upperLevel=true;
}
}
- for(ZoneData&lowerLevelZone:zoneData["LowerZone"]){
+ for(const ZoneData&lowerLevelZone:zoneData.at("LowerZone")){
if(geom2d::overlaps(lowerLevelZone.zone,pos)){
upperLevel=false;
}
diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp
index f9b2fc0b..e650d126 100644
--- a/Adventures in Lestoria/Player.cpp
+++ b/Adventures in Lestoria/Player.cpp
@@ -783,13 +783,13 @@ void Player::Moved(){
spawner.SetTriggered(true);
}
}
- std::map>&zoneData=game->GetZoneData(game->GetCurrentLevel());
- for(ZoneData&upperLevelZone:zoneData["UpperZone"]){
+ const std::map>&zoneData=game->GetZones(game->GetCurrentLevel());
+ for(const ZoneData&upperLevelZone:zoneData.at("UpperZone")){
if(geom2d::overlaps(upperLevelZone.zone,pos)){
upperLevel=true;
}
}
- for(ZoneData&lowerLevelZone:zoneData["LowerZone"]){
+ for(const ZoneData&lowerLevelZone:zoneData.at("LowerZone")){
if(geom2d::overlaps(lowerLevelZone.zone,pos)){
upperLevel=false;
}
@@ -1349,4 +1349,13 @@ void Player::UpdateHealthAndMana(){
hp=std::min(hp,int(GetStat("Health")));
mana=std::min(mana,GetMaxMana());
}
+}
+
+void Player::SetInvisible(const bool invisibleState){
+ invisibility=invisibleState;
+}
+
+
+const bool Player::IsInvisible()const{
+ return invisibility;
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h
index 715d7ebd..6119601d 100644
--- a/Adventures in Lestoria/Player.h
+++ b/Adventures in Lestoria/Player.h
@@ -245,6 +245,8 @@ public:
void SetXP(const uint32_t xp);
void SetTotalXPEarned(const uint32_t totalXP);
void SetLevel(uint8_t newLevel);
+ void SetInvisible(const bool invisibleState);
+ const bool IsInvisible()const;
private:
int hp="Warrior.BaseHealth"_I;
int mana="Player.BaseMana"_I;
@@ -293,6 +295,7 @@ private:
uint32_t money="Player.Starting Money"_I;
EntityStats stats;
ItemAttribute&Get(std::string_view attr);
+ bool invisibility=false;
//Returns true if the move was valid and successful.
//If playerInvoked is true, this means the player was the one that instantiated this input, and it's not an extra movement done via collision.
//Set playerInvoked to false when you don't want a movement loop due to collisions.
diff --git a/Adventures in Lestoria/SoundEffect.cpp b/Adventures in Lestoria/SoundEffect.cpp
index a5e673c8..b003b535 100644
--- a/Adventures in Lestoria/SoundEffect.cpp
+++ b/Adventures in Lestoria/SoundEffect.cpp
@@ -49,23 +49,31 @@ INCLUDE_game
std::multimapSoundEffect::SOUND_EFFECTS;
const vf2d SoundEffect::CENTERED={-8419.f,-3289.f};
-SoundEffect::SoundEffect(const std::string_view filename,const float&vol,const float&minPitch,const float&maxPitch)
- :filename(filename),vol(vol),minPitch(minPitch),maxPitch(maxPitch){
+SoundEffect::SoundEffect(const std::string_view filename,const float&vol,const float&minPitch,const float&maxPitch,const bool combatSound)
+ :filename(filename),vol(vol),minPitch(minPitch),maxPitch(maxPitch),combatSound(combatSound){
if(vol<0.f||vol>1.f)ERR(std::format("WARNING! Volume must be between 0.0f ~ 1.0f! Provided value {}",vol));
}
void SoundEffect::Initialize(){
for(auto&[key,size]:DATA["Events"]["SFX"]){
int counter=0;
+ bool combatSound=false;
+ if(DATA["Events"]["SFX"][key].HasProperty("CombatSound")){
+ combatSound=DATA["Events"]["SFX"][key]["CombatSound"].GetBool();
+ }
while(DATA["Events"]["SFX"][key].HasProperty(std::format("File[{}]",counter))){
utils::datafile&data=DATA["Events"]["SFX"][key][std::format("File[{}]",counter)];
float minPitch=0.9f;
float maxPitch=1.1f;
if(data.GetValueCount()>=3){minPitch=data.GetInt(2)/100.f;}
if(data.GetValueCount()>=4){maxPitch=data.GetInt(3)/100.f;}
- SOUND_EFFECTS.insert({key,SoundEffect{data.GetString(0),data.GetInt(1)/100.f,minPitch,maxPitch}});
+ SOUND_EFFECTS.insert({key,SoundEffect{data.GetString(0),data.GetInt(1)/100.f,minPitch,maxPitch,combatSound}});
counter++;
}
+ auto itr=SOUND_EFFECTS.equal_range(key);
+ for(auto it=itr.first;it!=itr.second;++it){
+ it->second.combatSound=combatSound;
+ }
}
}
@@ -84,6 +92,8 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){
}
const SoundEffect&sfx=(*it).second;
+ if(GameState::STATE==GameState::states[States::MAIN_MENU])return; //Do not play combat sounds on the main menu.
+
float pitchDiff=sfx.maxPitch-sfx.minPitch;
float pitch=util::random(pitchDiff)+sfx.minPitch;
diff --git a/Adventures in Lestoria/SoundEffect.h b/Adventures in Lestoria/SoundEffect.h
index b1989216..8b6e8aab 100644
--- a/Adventures in Lestoria/SoundEffect.h
+++ b/Adventures in Lestoria/SoundEffect.h
@@ -45,7 +45,7 @@ using EventName=std::string;
class SoundEffect{
public:
- SoundEffect(const std::string_view filename,const float&vol,const float&minPitch=0.9f,const float&maxPitch=1.1f);
+ SoundEffect(const std::string_view filename,const float&vol,const float&minPitch=0.9f,const float&maxPitch=1.1f,const bool combatSound=false);
static void PlaySFX(const std::string_view eventName,const vf2d&pos);
static void Initialize();
static const vf2d CENTERED;
@@ -53,6 +53,7 @@ private:
static std::multimapSOUND_EFFECTS;
std::string filename;
float vol;
+ bool combatSound=false;
float minPitch=0.9f;
float maxPitch=1.1f;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_GameHub.cpp b/Adventures in Lestoria/State_GameHub.cpp
index 588fefb6..d86e6e92 100644
--- a/Adventures in Lestoria/State_GameHub.cpp
+++ b/Adventures in Lestoria/State_GameHub.cpp
@@ -59,6 +59,8 @@ void State_GameHub::OnStateChange(GameState*prevState){
game->GetPlayer()->SetState(State::NORMAL);
game->LoadLevel("HUB");
+}
+void State_GameHub::OnLevelLoad(){
game->UpdateDiscordStatus("Hub Area",game->GetPlayer()->GetClassName());
}
void State_GameHub::OnUserUpdate(AiL*game){
diff --git a/Adventures in Lestoria/State_GameHub.h b/Adventures in Lestoria/State_GameHub.h
index 3d70b97b..063d981f 100644
--- a/Adventures in Lestoria/State_GameHub.h
+++ b/Adventures in Lestoria/State_GameHub.h
@@ -45,4 +45,5 @@ class State_GameHub:public State_GameRun{
virtual void OnStateChange(GameState*prevState)override final;
virtual void OnUserUpdate(AiL*game)override final;
virtual void Draw(AiL*game)override final;
+ virtual void OnLevelLoad()override final;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_GameRun.cpp b/Adventures in Lestoria/State_GameRun.cpp
index aab678d7..04380daa 100644
--- a/Adventures in Lestoria/State_GameRun.cpp
+++ b/Adventures in Lestoria/State_GameRun.cpp
@@ -73,6 +73,7 @@ void State_GameRun::OnStateChange(GameState*prevState){
game->LoadLevel(State_OverworldMap::GetCurrentConnectionPoint().map);
}
+void State_GameRun::OnLevelLoad(){}
void State_GameRun::OnUserUpdate(AiL*game){
game->bossDisplayTimer=std::max(0.f,game->bossDisplayTimer-game->GetElapsedTime());
if(game->encounterStarted&&game->totalBossEncounterMobs>0){
@@ -84,13 +85,7 @@ void State_GameRun::OnUserUpdate(AiL*game){
game->UpdateEffects(game->GetElapsedTime());
GameEvent::UpdateEvents();
game->GetPlayer()->Update(game->GetElapsedTime());
- for(Monster&m:MONSTER_LIST){
- m.Update(game->GetElapsedTime());
- }
- for(Monster&m:game->monstersToBeSpawned){
- MONSTER_LIST.push_back(m);
- }
- game->monstersToBeSpawned.clear();
+ game->UpdateMonsters();
ItemDrop::UpdateDrops(game->GetElapsedTime());
game->UpdateBullets(game->GetElapsedTime());
diff --git a/Adventures in Lestoria/State_GameRun.h b/Adventures in Lestoria/State_GameRun.h
index 555eac3d..009408e9 100644
--- a/Adventures in Lestoria/State_GameRun.h
+++ b/Adventures in Lestoria/State_GameRun.h
@@ -46,6 +46,7 @@ protected:
virtual void OnStateChange(GameState*prevState)override;
virtual void OnUserUpdate(AiL*game)override;
virtual void Draw(AiL*game)override;
+ virtual void OnLevelLoad()override;
void FontTest();
void FontSpriteTest();
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_LevelComplete.cpp b/Adventures in Lestoria/State_LevelComplete.cpp
index e2bc7569..191423ad 100644
--- a/Adventures in Lestoria/State_LevelComplete.cpp
+++ b/Adventures in Lestoria/State_LevelComplete.cpp
@@ -76,6 +76,7 @@ void State_LevelComplete::OnStateChange(GameState*prevState){
game->GetPlayer()->SetState(State::NORMAL);
Menu::OpenMenu(LEVEL_COMPLETE);
};
+void State_LevelComplete::OnLevelLoad(){}
void State_LevelComplete::OnUserUpdate(AiL*game){
if(levelUpTimer>0.f){
levelUpTimer=std::max(0.f,levelUpTimer-game->GetElapsedTime());
diff --git a/Adventures in Lestoria/State_LevelComplete.h b/Adventures in Lestoria/State_LevelComplete.h
index 5fafaf73..0eb6bd21 100644
--- a/Adventures in Lestoria/State_LevelComplete.h
+++ b/Adventures in Lestoria/State_LevelComplete.h
@@ -48,4 +48,5 @@ class State_LevelComplete:public GameState{
virtual void OnUserUpdate(AiL*game)override final;
virtual void Draw(AiL*game)override final;
virtual void DrawOverlay(AiL*game)override final;
+ virtual void OnLevelLoad()override final;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_MainMenu.cpp b/Adventures in Lestoria/State_MainMenu.cpp
index b6d2e7ee..bc8bf673 100644
--- a/Adventures in Lestoria/State_MainMenu.cpp
+++ b/Adventures in Lestoria/State_MainMenu.cpp
@@ -40,6 +40,8 @@ All rights reserved.
#include "Menu.h"
#include "TitleScreen.h"
#include "Key.h"
+#include "ItemDrop.h"
+#include "util.h"
INCLUDE_game
@@ -47,13 +49,64 @@ void State_MainMenu::OnStateChange(GameState*prevState){
Audio::PlayBGM("title_screen");
TitleScreen::Reset();
game->UpdateDiscordStatus("Main Menu","");
+ game->LoadLevel("starting_map"_S,AiL::NO_MUSIC_CHANGE);
};
+void State_MainMenu::OnLevelLoad(){
+ game->GetPlayer()->SetIframes(999999.f);
+ game->GetPlayer()->SetInvisible(true);
+ SelectAndMoveToNewFocusArea();
+}
void State_MainMenu::OnUserUpdate(AiL*game){
+ game->GetPlayer()->ForceSetPos(game->GetPlayer()->GetPos()+cameraMoveDir*8*game->GetElapsedTime());
+ lastMoveTime+=game->GetElapsedTime();
+ if(lastMoveTime>8.f)SelectAndMoveToNewFocusArea();
TitleScreen::Update();
if(AiL::KEY_CONFIRM.Released()){
TitleScreen::Skip();
}
+
+ game->UpdateEffects(game->GetElapsedTime());
+ GameEvent::UpdateEvents();
+ game->UpdateMonsters();
+
+ ItemDrop::UpdateDrops(game->GetElapsedTime());
+ game->UpdateBullets(game->GetElapsedTime());
+ game->UpdateCamera(game->GetElapsedTime());
};
void State_MainMenu::Draw(AiL*game){
TitleScreen::Draw();
-};
\ No newline at end of file
+};
+
+const ZoneData&State_MainMenu::ChooseRandomFocusArea(){
+ //std::vector
+ if(game->GetZones().count("Focus Area")>0){
+ const std::vector&zones=game->GetZones().at("Focus Area");
+ newSelectedFocusAreaIndex=util::random()%zones.size();
+ return zones[newSelectedFocusAreaIndex];
+ }else ERR("WARNING! No focus areas included in the intro map!");
+
+ return game->GetZones().at("Focus Area")[0];
+}
+
+void State_MainMenu::SelectAndMoveToNewFocusArea(){
+ const ZoneData&newFocusArea=ChooseRandomFocusArea();
+ if(lastSelectedFocusAreaIndex==newSelectedFocusAreaIndex)return;
+ game->camera.MoveCamera(newFocusArea.zone.pos);
+ game->GetPlayer()->ForceSetPos(newFocusArea.zone.pos);
+ cameraMoveDir={};
+ for(const XMLTag&tag:newFocusArea.properties){
+ if(tag.data.at("name")=="Scroll Direction"){
+ std::string_view dir=tag.data.at("value");
+ if(dir=="NORTH"sv)cameraMoveDir={0.f,-1.f};else
+ if(dir=="NORTHEAST"sv)cameraMoveDir={1.f,-1.f};else
+ if(dir=="EAST"sv)cameraMoveDir={1.f,0.f};else
+ if(dir=="SOUTHEAST"sv)cameraMoveDir={1.f,1.f};else
+ if(dir=="SOUTH"sv)cameraMoveDir={0.f,1.f};else
+ if(dir=="SOUTHWEST"sv)cameraMoveDir={-1.f,1.f};else
+ if(dir=="WEST"sv)cameraMoveDir={-1.f,0.f};else
+ if(dir=="NORTHWEST"sv)cameraMoveDir={-1.f,-1.f};
+ }
+ }
+ lastMoveTime=0.f;
+ lastSelectedFocusAreaIndex=newSelectedFocusAreaIndex;
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_MainMenu.h b/Adventures in Lestoria/State_MainMenu.h
index 9d24b291..8bccbd4f 100644
--- a/Adventures in Lestoria/State_MainMenu.h
+++ b/Adventures in Lestoria/State_MainMenu.h
@@ -36,9 +36,18 @@ All rights reserved.
*/
#pragma endregion
#include "GameState.h"
+#include "TMXParser.h"
class State_MainMenu:public GameState{
virtual void OnStateChange(GameState*prevState)override final;
virtual void OnUserUpdate(AiL*game)override final;
virtual void Draw(AiL*game)override final;
+ virtual void OnLevelLoad()override final;
+
+ const ZoneData&ChooseRandomFocusArea();
+ vf2d cameraMoveDir;
+ float lastMoveTime=0.f;
+ size_t newSelectedFocusAreaIndex=0;
+ size_t lastSelectedFocusAreaIndex=0;
+ void SelectAndMoveToNewFocusArea();
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_OverworldMap.cpp b/Adventures in Lestoria/State_OverworldMap.cpp
index 72966bbd..e3780d6a 100644
--- a/Adventures in Lestoria/State_OverworldMap.cpp
+++ b/Adventures in Lestoria/State_OverworldMap.cpp
@@ -63,6 +63,8 @@ void State_OverworldMap::OnStateChange(GameState*prevState){
Component(MenuType::PAUSE,"Return to Camp Button")->SetGrayedOut(false);
SaveFile::SaveGame();
game->LoadLevel("WORLD_MAP");
+};
+void State_OverworldMap::OnLevelLoad(){
if(Menu::IsMenuOpen()){
Menu::CloseAllMenus();
}
@@ -82,7 +84,7 @@ void State_OverworldMap::OnStateChange(GameState*prevState){
}
Menu::OpenMenu(OVERWORLD_LEVEL_SELECT,false);
game->UpdateDiscordStatus("Overworld Map",game->GetPlayer()->GetClassName());
-};
+}
void State_OverworldMap::OnUserUpdate(AiL*game){
if(Menu::stack.size()>1)return;
diff --git a/Adventures in Lestoria/State_OverworldMap.h b/Adventures in Lestoria/State_OverworldMap.h
index 8cdc00fa..8f394a91 100644
--- a/Adventures in Lestoria/State_OverworldMap.h
+++ b/Adventures in Lestoria/State_OverworldMap.h
@@ -60,6 +60,7 @@ public:
virtual void OnUserUpdate(AiL*game)override final;
virtual void Draw(AiL*game)override final;
virtual void DrawOverlay(AiL*game)override final;
+ virtual void OnLevelLoad()override final;
static void StartLevel();
static void UpdateCurrentConnectionPoint(const ConnectionPoint&connection);
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/State_Story.cpp b/Adventures in Lestoria/State_Story.cpp
index 3708401a..de20d801 100644
--- a/Adventures in Lestoria/State_Story.cpp
+++ b/Adventures in Lestoria/State_Story.cpp
@@ -42,6 +42,7 @@ All rights reserved.
void State_Story::OnStateChange(GameState*prevState){
Menu::CloseAllMenus();
};
+void State_Story::OnLevelLoad(){}
void State_Story::OnUserUpdate(AiL*game){
VisualNovel::novel.Update();
};
diff --git a/Adventures in Lestoria/State_Story.h b/Adventures in Lestoria/State_Story.h
index 4da98385..b368922c 100644
--- a/Adventures in Lestoria/State_Story.h
+++ b/Adventures in Lestoria/State_Story.h
@@ -42,4 +42,5 @@ class State_Story:public GameState{
virtual void OnStateChange(GameState*prevState)override final;
virtual void OnUserUpdate(AiL*game)override final;
virtual void Draw(AiL*game)override final;
+ virtual void OnLevelLoad()override final;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/TMXParser.h b/Adventures in Lestoria/TMXParser.h
index 722668e6..efd65fe2 100644
--- a/Adventures in Lestoria/TMXParser.h
+++ b/Adventures in Lestoria/TMXParser.h
@@ -98,6 +98,7 @@ struct SpawnerTag{
struct ZoneData{
geom2d::rectzone;
bool isUpper=false;
+ std::vectorproperties;
};
struct NPCData{
@@ -478,7 +479,11 @@ class TMXParser{
}
} else
if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") {
- parsedMapInfo.MapData.playerSpawnLocation={newTag.GetInteger("x")-newTag.GetInteger("width")/2,newTag.GetInteger("y")-newTag.GetInteger("height")/2};
+ float width=1.f;
+ float height=1.f;
+ if(newTag.data.count("width")>0)width=newTag.GetFloat("width");
+ if(newTag.data.count("height")>0)height=newTag.GetFloat("height");
+ parsedMapInfo.MapData.playerSpawnLocation={int(newTag.GetFloat("x")-width/2),int(newTag.GetFloat("y")-height/2)};
} else
if (newTag.tag=="object"&&newTag.data["type"]=="NPC") {
if(inNPCTag)parsedMapInfo.npcs.push_back(NPCData{npcTag});
@@ -513,19 +518,19 @@ class TMXParser{
if(newTag.tag=="property"&¤tStagePlate!=nullptr){
currentStagePlate->properties[newTag.data["name"]]={newTag.data["name"],newTag.data["value"]};
}else
+ if(newTag.tag=="property"&&prevZoneData!=nullptr){
+ //This is a property for a zone that doesn't fit into the other categories, we add it to the previous zone data encountered.
+ prevZoneData->properties.push_back(newTag);
+ }else
if (newTag.tag=="object"&&newTag.data.find("type")!=newTag.data.end()){
//This is an object with a type that doesn't fit into other categories, we can add it to ZoneData.
- if(parsedMapInfo.ZoneData.find(newTag.data["type"])!=parsedMapInfo.ZoneData.end()){
- std::vector&zones=parsedMapInfo.ZoneData.at(newTag.data["type"]);
- zones.emplace_back(geom2d::rect{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}});
- prevZoneData=&zones.back();
- } else {
- if(newTag.data["width"].length()>0&&newTag.data["height"].length()>0){ //This ensures the zone is valid to begin with.
- std::vector&zones=parsedMapInfo.ZoneData[newTag.data["type"]];
- zones.emplace_back(geom2d::rect{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}});
- prevZoneData=&zones.back();
- }
- }
+ std::vector&zones=parsedMapInfo.ZoneData[newTag.data["type"]];
+ float width=1.f;
+ float height=1.f;
+ if(newTag.data.count("width")>0)width=newTag.GetFloat("width");
+ if(newTag.data.count("height")>0)height=newTag.GetFloat("height");
+ zones.emplace_back(geom2d::rect{{newTag.GetInteger("x"),newTag.GetInteger("y")},{int(width),int(height)}});
+ prevZoneData=&zones.back();
}else{
#ifdef _DEBUG
if(_DEBUG_MAP_LOAD_INFO)std::cout<<"Unsupported tag format! Ignoring."<<"\n";
diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt
index 0d9779e7..6aae2d89 100644
--- a/Adventures in Lestoria/TODO.txt
+++ b/Adventures in Lestoria/TODO.txt
@@ -1,27 +1,26 @@
-January 1st
-===========
+February 28th -> Begin Internal Game Playtesting
+March 6th -> Discord/Friend Playtesting
+March 30th -> Public Demo Release
+
+
- Foreground tile depth correction for tiles w/hitboxes
- Add Death screen (Zoom in on fatal blow, slow time down... Display some game over text... Allow retry or return to world map.)
- Track items used during a stage, on death, restore the loadout item quantities used.
-- Icon displays / Proper key displays above skill keys
-
+- Mosaic transition on level load
Add Bonus XP when completing a stage
-January 31st
-============
-
-- Loading Screen
-- Title Screen setpieces
-
-
- Hide mouse cursor during controller play. Reveal it again during mouse play.
- Auto aim causes retreat-type moves to aim away from the auto target, and prefer the direction the player's moving in.
- Condense stage track (loading times)
-- Credits/Licensing
\ No newline at end of file
+- Credits/Licensing
+
+- Basic tutorial on the first stage, Only allow the player to select "Change Loadout", explain how to setup items, can only start once a loadout item is set.
+
+- show inputs that can be used by the player to navigate, ability usage, and defensive. When player takes enough damage show how to use recovery items.
diff --git a/Adventures in Lestoria/Test.cpp b/Adventures in Lestoria/Test.cpp
index 81613bb5..db82c2be 100644
--- a/Adventures in Lestoria/Test.cpp
+++ b/Adventures in Lestoria/Test.cpp
@@ -54,8 +54,8 @@ void Test::is(std::string conditionStr,bool testResult){
void Test::RunMapTests(){
is("There are two LowerBridgeCollision zones in Campaign I-I",
- game->GetZoneData("CAMPAIGN_1_1").count("LowerBridgeCollision")
- &&game->GetZoneData("CAMPAIGN_1_1").at("LowerBridgeCollision").size()>=2);
+ game->GetZones("CAMPAIGN_1_1").count("LowerBridgeCollision")
+ &&game->GetZones("CAMPAIGN_1_1").at("LowerBridgeCollision").size()>=2);
for(auto&[key,value]:game->MAP_DATA){
is("A Map type has been selected for map "+key,
value.GetMapType()!=""&&value.GetMapType()!="Unspecified");
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index c3f8f4a1..47fb6cca 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 7515
+#define VERSION_BUILD 7609
#define stringify(a) stringify_(a)
#define stringify_(a) #a
diff --git a/Adventures in Lestoria/VisualNovel.cpp b/Adventures in Lestoria/VisualNovel.cpp
index 5b1a0f7e..02d81eb1 100644
--- a/Adventures in Lestoria/VisualNovel.cpp
+++ b/Adventures in Lestoria/VisualNovel.cpp
@@ -193,6 +193,9 @@ void VisualNovel::Update(){
locationDisplayTime=std::max(0.f,locationDisplayTime-game->GetElapsedTime());
transitionTime=std::max(0.f,transitionTime-game->GetElapsedTime());
textScrollTime=std::max(0.f,textScrollTime-game->GetElapsedTime());
+ if(backgroundScrollAmt<90.f){
+ backgroundScrollAmt=std::min(90.f,backgroundScrollAmt+backgroundScrollSpd*game->GetElapsedTime());
+ }
}
void VisualNovel::ExecuteNextCommand(){
if(commandIndexDrawDecal({0,0},GFX["story_background_image_location"_S+prevBackgroundFilename].Decal());
+ game->DrawDecal({0,-prevBackgroundScrollAmt},GFX["story_background_image_location"_S+prevBackgroundFilename].Decal());
}
- game->DrawDecal({0,0},GFX["story_background_image_location"_S+backgroundFilename].Decal(),{1,1},{255,255,255,uint8_t(255*alpha)});
+ game->DrawDecal({0,-backgroundScrollAmt},GFX["story_background_image_location"_S+backgroundFilename].Decal(),{1,1},{255,255,255,uint8_t(255*alpha)});
}else{
game->FillRectDecal({0,0},game->GetScreenSize());
}
@@ -289,6 +292,8 @@ void BackgroundCommand::Execute(VisualNovel&vn){
vn.prevBackgroundFilename=vn.backgroundFilename;
vn.backgroundFilename=backgroundFilename;
vn.transitionTime=2.0f;
+ vn.prevBackgroundScrollAmt=vn.backgroundScrollAmt;
+ vn.backgroundScrollAmt=0.f;
vn.ExecuteNextCommand();
}
BackgroundCommand::BackgroundCommand(std::string backgroundFilename)
@@ -323,6 +328,7 @@ SpeakerCommand::SpeakerCommand(std::string displayedName,std::string speaker)
CommandType::CommandType SpeakerCommand::GetType(){return CommandType::SPEAKER;}
void DialogCommand::Execute(VisualNovel&vn){
+ if(dialog.size()<=0)return;
vn.textScrollTime=VisualNovel::maxTextScrollTime;
bool mustDisplay=vn.activeText.length()==0;
Font*displayFont=&VisualNovel::font;
diff --git a/Adventures in Lestoria/VisualNovel.h b/Adventures in Lestoria/VisualNovel.h
index 89fb22eb..7c6525bd 100644
--- a/Adventures in Lestoria/VisualNovel.h
+++ b/Adventures in Lestoria/VisualNovel.h
@@ -73,7 +73,7 @@ public:
};
class DialogCommand final:public Command{
- std::string dialog;
+ std::string dialog="";
public:
void Execute(VisualNovel&vn)override;
DialogCommand(std::string dialog);
@@ -143,12 +143,15 @@ class VisualNovel{
std::string prevBackgroundFilename;
float transitionTime=0;
static constexpr float maxTransitionTime=2.0f;
+ const float backgroundScrollSpd=2.0f;
std::vectorcommands;
int commandIndex=0;
std::string locationDisplayText="";
float locationDisplayTime=0;
std::string prevTheme="";
float textScrollTime=0;
+ float backgroundScrollAmt=0;
+ float prevBackgroundScrollAmt=0;
static constexpr float maxTextScrollTime=1.0f;
public:
static Font font,narratorFont,locationFont;
diff --git a/Adventures in Lestoria/assets/Campaigns/Intro_Map.tmx b/Adventures in Lestoria/assets/Campaigns/Intro_Map.tmx
new file mode 100644
index 00000000..4f0977bd
--- /dev/null
+++ b/Adventures in Lestoria/assets/Campaigns/Intro_Map.tmx
@@ -0,0 +1,1628 @@
+
+
diff --git a/Adventures in Lestoria/assets/Campaigns/World_Map.tmx b/Adventures in Lestoria/assets/Campaigns/World_Map.tmx
index 48cc6299..3f6a4166 100644
--- a/Adventures in Lestoria/assets/Campaigns/World_Map.tmx
+++ b/Adventures in Lestoria/assets/Campaigns/World_Map.tmx
@@ -571,7 +571,7 @@
-
+