Add loading screen. Added flag for music change parameter when loading levels. Release Build 7558.

pull/35/head
sigonasr2 9 months ago
parent 76c1487871
commit 0861419582
  1. 524
      Adventures in Lestoria/AdventuresInLestoria.cpp
  2. 8
      Adventures in Lestoria/AdventuresInLestoria.h
  3. 33
      Adventures in Lestoria/Audio.cpp
  4. 2
      Adventures in Lestoria/Audio.h
  5. 1
      Adventures in Lestoria/GameState.h
  6. 56
      Adventures in Lestoria/LoadingScreen.cpp
  7. 12
      Adventures in Lestoria/LoadingScreen.h
  8. 2
      Adventures in Lestoria/State_GameHub.cpp
  9. 1
      Adventures in Lestoria/State_GameHub.h
  10. 1
      Adventures in Lestoria/State_GameRun.cpp
  11. 1
      Adventures in Lestoria/State_GameRun.h
  12. 1
      Adventures in Lestoria/State_LevelComplete.cpp
  13. 1
      Adventures in Lestoria/State_LevelComplete.h
  14. 1
      Adventures in Lestoria/State_MainMenu.cpp
  15. 1
      Adventures in Lestoria/State_MainMenu.h
  16. 4
      Adventures in Lestoria/State_OverworldMap.cpp
  17. 1
      Adventures in Lestoria/State_OverworldMap.h
  18. 1
      Adventures in Lestoria/State_Story.cpp
  19. 1
      Adventures in Lestoria/State_Story.h
  20. 2
      Adventures in Lestoria/Version.h
  21. BIN
      x64/Release/Adventures in Lestoria.exe

@ -279,7 +279,7 @@ bool AiL::OnUserCreate(){
Inventory::AddItem("Minor Health Potion"s,3);
Inventory::AddItem("Bandages"s,10);
LoadLevel("starting_map"_S);
LoadLevel("starting_map"_S,NO_MUSIC_CHANGE);
ChangePlayerClass(WARRIOR);
GameState::Initialize();
@ -1821,295 +1821,353 @@ void AiL::InitializeLevel(std::string mapFile,MapName map){
}
}
void AiL::LoadLevel(MapName map){
void AiL::LoadLevel(MapName map,MusicChange changeMusic){
LoadingScreen::loading=true;
#pragma region Reset all data (Loading phase 1)
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
_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();
#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();
ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
return true;
});
#pragma endregion
ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
#pragma region Monster Spawn Data Setup (Loading phase 2)
for(auto&[key,value]:MAP_DATA[map].SpawnerData){
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key];
std::vector<std::pair<std::string,vf2d>>monster_list;
LoadingScreen::AddPhase([&](){
for(auto&[key,value]:MAP_DATA[GetCurrentLevel()].SpawnerData){
SpawnerTag&spawnData=MAP_DATA[GetCurrentLevel()].SpawnerData[key];
std::vector<std::pair<std::string,vf2d>>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 (Loading phase 3)
auto GetUpperZones=[&](){
for(auto&zoneSet:MAP_DATA[map].ZoneData){
if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
return zoneSet.second;
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<ZoneData>{};
};
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<zoneX+zoneW;x++){
for(int y=zoneY;y<zoneY+zoneH;y++){
for(LayerTag&layer:MAP_DATA[map].LayerData){
int tile=layer.tiles[y][x]-1;
TilesheetData tileSheet=GetTileSheet(currentLevel,tile);
int tileSheetIndex=tile-(tileSheet.firstgid-1);
if(IsForegroundTile(tileSheet,tileSheetIndex)){
layer.tiles[y][x]+=1000000;
return std::vector<ZoneData>{};
};
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<zoneX+zoneW;x++){
for(int y=zoneY;y<zoneY+zoneH;y++){
for(LayerTag&layer:MAP_DATA[GetCurrentLevel()].LayerData){
int tile=layer.tiles[y][x]-1;
TilesheetData tileSheet=GetTileSheet(currentLevel,tile);
int tileSheetIndex=tile-(tileSheet.firstgid-1);
if(IsForegroundTile(tileSheet,tileSheetIndex)){
layer.tiles[y][x]+=1000000;
}
}
}
}
}
}
return true;
});
#pragma endregion
#pragma region Foreground and Upper Foreground Tile Fade Group Setup (Loading phase 4)
std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
for(int x=0;x<GetCurrentMapData().width;x++){
for(int y=0;y<GetCurrentMapData().height;y++){
int layerID=0;
for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){
if(Unlock::IsUnlocked(layer.unlockCondition)){
int tileID=layer.tiles[y][x]-1;
if(tileID!=-1){
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int tileSheetWidth=tileSheet.tileset->tileset->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::function<bool(TilesheetData,int)>IsForeground,TileRenderData tile,std::set<vi2d>&foregroundTilesIncluded,std::vector<TileGroup>&groups){
if(foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()&&IsForeground(tileSheet,tileSheetIndex)){
std::queue<vi2d>tileGroupChecks;
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(x<GetCurrentMapData().width-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x+1,y});
if(y>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,-1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y-1});
if(y<GetCurrentMapData().height-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y+1});
auto IterateThroughOtherLayers=[&](vi2d pos,bool loopAll=false){
int layer2ID=0;
bool hadForeground=false;
for(LayerTag&layer2:MAP_DATA[currentLevel].LayerData){
if(!loopAll&&&layer==&layer2){layer2ID++;continue;};
int tileID=layer2.tiles[pos.y][pos.x]-1;
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID%1000000);
int tileSheetWidth=tileSheet.tileset->tileset->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;
LoadingScreen::AddPhase([&](){
std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
for(int x=0;x<GetCurrentMapData().width;x++){
for(int y=0;y<GetCurrentMapData().height;y++){
int layerID=0;
for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){
if(Unlock::IsUnlocked(layer.unlockCondition)){
int tileID=layer.tiles[y][x]-1;
if(tileID!=-1){
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int tileSheetWidth=tileSheet.tileset->tileset->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::function<bool(TilesheetData,int)>IsForeground,TileRenderData tile,std::set<vi2d>&foregroundTilesIncluded,std::vector<TileGroup>&groups){
if(foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()&&IsForeground(tileSheet,tileSheetIndex)){
std::queue<vi2d>tileGroupChecks;
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(x<GetCurrentMapData().width-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x+1,y});
if(y>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,-1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y-1});
if(y<GetCurrentMapData().height-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y+1});
auto IterateThroughOtherLayers=[&](vi2d pos,bool loopAll=false){
int layer2ID=0;
bool hadForeground=false;
for(LayerTag&layer2:MAP_DATA[currentLevel].LayerData){
if(!loopAll&&&layer==&layer2){layer2ID++;continue;};
int tileID=layer2.tiles[pos.y][pos.x]-1;
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID%1000000);
int tileSheetWidth=tileSheet.tileset->tileset->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.x<GetCurrentMapData().width-1&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
targetPos=pos+vi2d{0,-1};
if(pos.y>0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
targetPos=pos+vi2d{0,1};
if(pos.y<GetCurrentMapData().height-1&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
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.x<GetCurrentMapData().width-1&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
targetPos=pos+vi2d{0,-1};
if(pos.y>0&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
targetPos=pos+vi2d{0,1};
if(pos.y<GetCurrentMapData().height-1&&foregroundTilesIncluded.find(targetPos)==foregroundTilesIncluded.end()){tileGroupChecks.push(targetPos);foregroundTilesIncluded.insert(targetPos);}
}
tileGroupChecks.pop();
}
tileGroupChecks.pop();
groups.push_back(group);
}
groups.push_back(group);
}
};
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
};
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<t2.layerID;});
}
for(TileGroup&group:upperForegroundTileGroups){
std::sort(group.GetTiles().begin(),group.GetTiles().end(),[](TileRenderData&t1,TileRenderData&t2){return t1.layerID<t2.layerID;});
}
for(TileGroup&group:foregroundTileGroups){
std::sort(group.GetTiles().begin(),group.GetTiles().end(),[](TileRenderData&t1,TileRenderData&t2){return t1.layerID<t2.layerID;});
}
for(TileGroup&group:upperForegroundTileGroups){
std::sort(group.GetTiles().begin(),group.GetTiles().end(),[](TileRenderData&t1,TileRenderData&t2){return t1.layerID<t2.layerID;});
}
return true;
});
#pragma endregion
#pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting (Loading phase 5)
auto SplitUp=[&](std::vector<TileGroup>&group){
std::multimap<vi2d,TileRenderData>data;
using TileDataGroup=std::multimap<vi2d,TileRenderData>; //See below.
std::vector<TileDataGroup>splitUpData; //This stores every tile group with tiles as a multi map.
std::set<vi2d>iteratedTiles;
for(TileGroup&group:group){
for(TileRenderData&tile:group.GetTiles()){
data.insert({tile.pos,tile});
LoadingScreen::AddPhase([&](){
auto SplitUp=[&](std::vector<TileGroup>&group){
std::multimap<vi2d,TileRenderData>data;
using TileDataGroup=std::multimap<vi2d,TileRenderData>; //See below.
std::vector<TileDataGroup>splitUpData; //This stores every tile group with tiles as a multi map.
std::set<vi2d>iteratedTiles;
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 (Loading Phase 6)
bridgeLayerIndex=-1;
for(int counter=0;LayerTag&layer:MAP_DATA[map].LayerData){
if(IsBridgeLayer(layer)){
bridgeLayerIndex=counter;
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
#pragma region Setup NPCs (Loading Phase 7)
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;
}
}
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
#pragma region Setup Player and Camera (Loading Phase 8)
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;
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
#pragma region Setup Pathfinding (Loading Phase 9)
pathfinder.Initialize();
LoadingScreen::AddPhase([&](){
pathfinder.Initialize();
return true;
});
#pragma endregion
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);
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<Audio::GetPrepareBGMLoopIterations(MAP_DATA[GetCurrentLevel()].bgmSongName);i++){
LoadingScreen::AddPhase([&](){
Audio::UpdateLoop();
return true;
});
}
#pragma endregion
LoadingScreen::AddPhase([&](){
Audio::BGM&track=audioEngine.bgm[audioEngine.GetTrackName()];
for(int trackID:track.GetChannelIDs()){
audioEngine.Engine().Play(trackID,true);
}
return true;
});
}
LoadingScreen::loading=false;
}
bool AiL::IsUpperForegroundTile(int tileID){
@ -3113,7 +3171,7 @@ void AiL::RenderFadeout(){
}
bool AiL::GamePaused(){
return fadeOutDuration>0||disableFadeIn||paused;
return fadeOutDuration>0||disableFadeIn||paused||LoadingScreen::loading;
}
void AiL::PauseGame(){
@ -3351,9 +3409,9 @@ 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));
}

@ -72,6 +72,10 @@ class AiL : public olc::PixelGameEngine
std::unique_ptr<Player>player;
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::vector<TileGroup>foregroundTileGroups;
std::vector<TileGroup>upperForegroundTileGroups;
@ -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::rect<float>NO_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);

@ -160,10 +160,14 @@ void Audio::BGM::Load(){
if(!Self().trackLoadStarted){
Self().trackLoadStarted=true;
if(Self().BGMIsPlaying()){
if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
BGM&bgm=Self().bgm[Self().GetTrackName()];
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;
@ -290,22 +294,22 @@ void Audio::UpdateLoop(){
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);
#pragma region Handle threaded loop indexing
Self().currentLoopIndex++;
if(Self().currentLoopIndex>=track.GetChannelIDs().size()){
Self().channelPlayingComplete=true;
Self().fullyLoaded=true;
}
#pragma endregion
}
}else{
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!");
}
}
}
@ -316,12 +320,18 @@ void Audio::PlayBGM(const std::string_view sound,const bool loop){
}
void Audio::Update(){
if(Self().playBGMWaitTime>0.f){
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){
@ -363,4 +373,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.
}

@ -75,6 +75,8 @@ 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;

@ -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;
};

@ -38,27 +38,71 @@ All rights reserved.
#include "AdventuresInLestoria.h"
#include "LoadingScreen.h"
#include "util.h"
INCLUDE_game
INCLUDE_WINDOW_SIZE
INCLUDE_ANIMATION_DATA
bool LoadingScreen::loading=false;
int LoadingScreen::totalProgress=0;
int LoadingScreen::currentProgress=0;
float LoadingScreen::waitTime=0.01f;
void LoadingScreen::DeferLoad(float waitTime){
int LoadingScreen::totalProgress=0;
std::queue<std::function<bool()>>LoadingScreen::loadingPhases;
bool LoadingScreen::showGhost=false;
bool LoadingScreen::showLarge=false;
void LoadingScreen::DeferLoad(std::function<bool()>waitCondition){
AddPhase(waitCondition);
}
void LoadingScreen::Update(){
if(loading){
if(loadingPhases.size()>0){
std::function<bool()>&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);
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,24.f},DARK_YELLOW);
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::vector<Buff>attackBuffs=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::function<bool()>loadFunc){
loadingPhases.push(loadFunc);
totalProgress++;
}

@ -37,13 +37,21 @@ All rights reserved.
#pragma endregion
#pragma once
#include <queue>
#include "olcUTIL_Animate2D.h"
class LoadingScreen{
public:
static bool loading;
static int totalProgress;
static int currentProgress;
static int totalProgress;
static float waitTime;
static bool showGhost;
static bool showLarge;
static std::queue<std::function<bool()>>loadingPhases;
static void Update();
static void Draw();
static void DeferLoad(float waitTime);
static void DeferLoad(std::function<bool()>waitCondition);
static void Reset();
static void AddPhase(std::function<bool()>loadFunc);
};

@ -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){

@ -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;
};

@ -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){

@ -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();
};

@ -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());

@ -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;
};

@ -48,6 +48,7 @@ void State_MainMenu::OnStateChange(GameState*prevState){
TitleScreen::Reset();
game->UpdateDiscordStatus("Main Menu","");
};
void State_MainMenu::OnLevelLoad(){}
void State_MainMenu::OnUserUpdate(AiL*game){
TitleScreen::Update();
if(AiL::KEY_CONFIRM.Released()){

@ -41,4 +41,5 @@ 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;
};

@ -63,6 +63,8 @@ void State_OverworldMap::OnStateChange(GameState*prevState){
Component<MenuComponent>(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;

@ -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);
};

@ -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();
};

@ -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;
};

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

Loading…
Cancel
Save