|
|
|
@ -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");
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
GetPlayer()->hp=GetPlayer()->GetMaxHealth();
|
|
|
|
|
GetPlayer()->mana=GetPlayer()->GetMaxMana();
|
|
|
|
|
GetPlayer()->SetState(State::NORMAL);
|
|
|
|
|
GetPlayer()->GetCastInfo()={};
|
|
|
|
|
GetPlayer()->ResetAccumulatedXP();
|
|
|
|
|
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);}
|
|
|
|
|
}
|
|
|
|
|
tileGroupChecks.pop();
|
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
group.clear();
|
|
|
|
|
for(auto&split:splitUpData){
|
|
|
|
|
TileGroup newGroup;
|
|
|
|
|
for(auto&[key,value]:split){
|
|
|
|
|
newGroup.InsertTile(value);
|
|
|
|
|
}
|
|
|
|
|
group.push_back(newGroup);
|
|
|
|
|
}
|
|
|
|
|
iteratedTiles.insert(loc);
|
|
|
|
|
}
|
|
|
|
|
group.clear();
|
|
|
|
|
for(auto&split:splitUpData){
|
|
|
|
|
TileGroup newGroup;
|
|
|
|
|
for(auto&[key,value]:split){
|
|
|
|
|
newGroup.InsertTile(value);
|
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|