diff --git a/Adventures in Lestoria/Adventures in Lestoria.tiled-project b/Adventures in Lestoria/Adventures in Lestoria.tiled-project index 69a2a224..6e14e954 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.tiled-project +++ b/Adventures in Lestoria/Adventures in Lestoria.tiled-project @@ -52,6 +52,19 @@ ], "valuesAsFlags": false }, + { + "color": "#ffa45f5f", + "drawFill": true, + "id": 36, + "members": [ + ], + "name": "BossArena", + "type": "class", + "useAs": [ + "property", + "object" + ] + }, { "color": "#ff290aa4", "drawFill": true, diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index 32aaa5a0..a9af986d 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -806,14 +806,14 @@ void AiL::PopulateRenderLists(){ } } - for(ZoneData&zone:MAP_DATA[GetCurrentLevel()].ZoneData["EndZone"]){ + for(const ZoneData&zone:GetZones().at("EndZone")){ if(zone.isUpper){ upperEndZones.push_back(zone); }else{ endZones.push_back(zone); } } - + std::sort(monstersBeforeUpper.begin(),monstersBeforeUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().yGetPos().y;}); std::sort(monstersBeforeLower.begin(),monstersBeforeLower.end(),[](Monster*m1,Monster*m2){return m1->GetPos().yGetPos().y;}); std::sort(monstersAfterUpper.begin(),monstersAfterUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().yGetPos().y;}); @@ -1744,6 +1744,7 @@ void AiL::LoadLevel(MapName map){ foregroundTileGroups.clear(); upperForegroundTileGroups.clear(); MONSTER_LIST.clear(); + ZONE_LIST.clear(); GameEvent::events.clear(); worldColor=WHITE; worldColorFunc=[&](vi2d pos){return game->worldColor;}; @@ -1756,12 +1757,15 @@ void AiL::LoadLevel(MapName map){ 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 Environmental Audio for(EnvironmentalAudio&audio:MAP_DATA[map].environmentalAudioData){ audio.Deactivate(); @@ -2338,6 +2342,12 @@ void AiL::InitializeLevels(){ InitializeLevel("map_path"_S+DATA["Levels"][key]["Map File"].GetString(),key); } + std::setcpNames; + for(ConnectionPoint&cp:State_OverworldMap::connections){ + if(cpNames.count(cp.name)>0)ERR(std::format("WARNING! More than one connection point has the same name: {} THIS IS NOT ALLOWED!",cp.name)); + cpNames.insert(cp.name); + } + for(ConnectionPoint&cp:State_OverworldMap::connections){ if(cp.levelDataExists)continue; if(VisualNovel::storyLevelData.count(cp.map)){ //Visual novel story data for story levels. @@ -2960,4 +2970,26 @@ void AiL::SetWorldColor(Pixel worldCol){ const Pixel&AiL::GetWorldColor()const{ return worldColor; +} + +const std::map>&AiL::GetZones(const std::string_view mapName)const{ + if(GetCurrentMapDisplayName()==mapName)return GetZones(); + return MAP_DATA.at(std::string(mapName)).ZoneData; +} + +const std::map>&AiL::GetZones()const{ + return ZONE_LIST; +} + +void AiL::AddZone(const std::string_view zoneName,const ZoneData&zone){ + if(ZONE_LIST.count(std::string(zoneName))==0)ERR(std::format("WARNING! Trying to add non-existent Zone Key {} to zone list of map {}. THIS IS NOT ALLOWED!",zoneName,std::string(GetCurrentMapName()))); + ZONE_LIST[std::string(zoneName)].push_back(zone); +} + +const std::string_view AiL::GetCurrentMapDisplayName()const{ + return GetCurrentMap().GetMapDisplayName(); +} + +const uint8_t AiL::BossEncounterMobCount()const{ + return totalBossEncounterMobs; } \ No newline at end of file diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index 225353c2..a162da2c 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -142,6 +142,7 @@ private: DynamicCounter manaCounter; Pixel worldColor=WHITE; std::functionworldColorFunc=[](vi2d pos){return WHITE;}; + std::map>ZONE_LIST; void ValidateGameStatus(); #ifndef __EMSCRIPTEN__ @@ -223,11 +224,13 @@ public: void DisplayBossEncounterInfo(); void BossDamageDealt(int damage); void ReduceBossEncounterMobCount(); + const uint8_t BossEncounterMobCount()const; void InitializeGraphics(); void RenderVersionInfo(); const Map&GetCurrentMap()const; const MapTag&GetCurrentMapData()const; const MapName&GetCurrentMapName()const; + const std::string_view GetCurrentMapDisplayName()const; int GetCurrentChapter(); void SetChapter(int chapter); const std::weak_ptrGetLoadoutItem(int slot); @@ -248,6 +251,11 @@ public: void SetWorldColorFunc(std::functionfunc); void SetWorldColor(Pixel worldCol); const Pixel&GetWorldColor()const; + //Returns the zones in the current stage + const std::map>&GetZones()const; + //Returns the zones of any given stage + const std::map>&GetZones(const std::string_view mapName)const; + void AddZone(const std::string_view zoneName,const ZoneData&zone); struct TileGroupData{ vi2d tilePos; diff --git a/Adventures in Lestoria/EnvironmentalAudio.cpp b/Adventures in Lestoria/EnvironmentalAudio.cpp index 9edad25e..8e7f460c 100644 --- a/Adventures in Lestoria/EnvironmentalAudio.cpp +++ b/Adventures in Lestoria/EnvironmentalAudio.cpp @@ -79,7 +79,7 @@ void EnvironmentalAudio::Deactivate(){ activated=false; } void EnvironmentalAudio::UpdateEnvironmentalAudio(){ - for(const EnvironmentalAudio&aud:game->GetCurrentMap().environmentalAudioData){ + for(const EnvironmentalAudio&aud:game->GetCurrentMap().GetEnvironmentalAudio()){ EnvironmentalAudio&audio=const_cast(aud); audio.Update(); } diff --git a/Adventures in Lestoria/Item.cpp b/Adventures in Lestoria/Item.cpp index b2358da5..902e6835 100644 --- a/Adventures in Lestoria/Item.cpp +++ b/Adventures in Lestoria/Item.cpp @@ -409,6 +409,7 @@ std::weak_ptrInventory::AddItem(IT it,uint32_t amt,bool monsterDrop){ std::shared_ptrnewItem=(*_inventory.insert({it,std::make_shared(1,it)})).second; newItem->RandomizeStats(); InsertIntoSortedInv(newItem); + InsertIntoStageInventoryCategory(newItem,monsterDrop); itemPtr=newItem; } goto SkipAddingStackableItem; @@ -418,6 +419,7 @@ std::weak_ptrInventory::AddItem(IT it,uint32_t amt,bool monsterDrop){ if(!_inventory.count(it)){ std::shared_ptrnewItem=(*_inventory.insert({it,std::make_shared(amt,it)})).second; InsertIntoSortedInv(newItem); + InsertIntoStageInventoryCategory(newItem,monsterDrop); itemPtr=newItem; }else{ auto inventory=_inventory.equal_range(it); @@ -429,7 +431,6 @@ std::weak_ptrInventory::AddItem(IT it,uint32_t amt,bool monsterDrop){ } SkipAddingStackableItem: - InsertIntoStageInventoryCategory(it,amt,monsterDrop); return itemPtr; } @@ -499,8 +500,12 @@ bool Inventory::RemoveItem(std::weak_ptritemRef,ITCategory inventory,uint3 //There are two places to manipulate items in (Both the sorted inventory and the actual inventory) if(!itemAmt)return false; + std::string itemName=itemRef.lock()->DisplayName(); + if (amt>=itemAmt){ + size_t invSize=inv.size(); inv.erase(inv.begin()+count); //Clears it from the detected sorted inventory as well! + if(invSize-1!=inv.size())ERR(std::format("WARNING! Did not properly erase {} from sorted inventory {}",itemName,inventory)); if(!eraseFromLootWindow){ //We must clear out the item AFTER we've updated context-sensitive inventories because they may be borrowing a ref from this structure!!! _inventory.erase(itemRef.lock()->ActualName()); } @@ -511,6 +516,7 @@ bool Inventory::RemoveItem(std::weak_ptritemRef,ITCategory inventory,uint3 }else{ if(itemRef.lock()->IsEquippable()){ //Since equipment doesn't stack, if we have more than one piece we have to still remove that piece. bool found=false; + size_t erased=std::erase_if(_inventory,[&](const std::pair>data){ if(!found&&data.second==itemRef){ found=true; @@ -519,7 +525,9 @@ bool Inventory::RemoveItem(std::weak_ptritemRef,ITCategory inventory,uint3 return false; }); if(erased!=1)ERR(std::format("Did not erase a single element, instead erased {} elements.",erased)); + size_t invSize=inv.size(); inv.erase(inv.begin()+count); //Clears it from the detected sorted inventory as well! + if(invSize-1!=inv.size())ERR(std::format("WARNING! Did not properly erase {} from sorted inventory {}",itemName,inventory)); Menu::InventorySlotsUpdated(inventory); return true; }else{ @@ -545,17 +553,22 @@ void Inventory::InsertIntoSortedInv(std::shared_ptritemRef){ Menu::InventorySlotsUpdated(itemRef->Category()); } -void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop){ +void Inventory::InsertIntoStageInventoryCategory(std::shared_ptritemRef,const bool monsterDrop){ std::string stageInventoryCategory="Stage Loot"; if(monsterDrop){ stageInventoryCategory="Monster Loot"; } + std::vector>&inv=sortedInv.at(stageInventoryCategory); - std::vector>::iterator it=std::find(inv.begin(),inv.end(),std::make_shared(amt,item)); //Uses operator== to compare if this item does exist in a stage/monster loot inventory already. We just make an in-place shared pointer of an item to compare with. - if(it!=inv.end()){ - (*it)->amt+=amt; + if(itemRef->IsEquippable()){ //We cannot stack items! They are always individual. + inv.push_back(itemRef); }else{ - inv.push_back(std::make_shared(amt,item)); + std::vector>::iterator it=std::find(inv.begin(),inv.end(),itemRef); //Uses operator== to compare if this item does exist in a stage/monster loot inventory already. We just make an in-place shared pointer of an item to compare with. + if(it!=inv.end()){ + (*it)->amt+=itemRef->Amt(); + }else{ + inv.push_back(itemRef); + } } Menu::InventorySlotsUpdated(stageInventoryCategory); } @@ -692,8 +705,15 @@ const bool Item::IsBlank()const{ void Inventory::Clear(ITCategory itemCategory){ std::vector>itemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline. - for(std::shared_ptr&item:itemList){ - RemoveItem(item,itemCategory,item->Amt()); + if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){ + while(sortedInv[itemCategory].size()>0){ + RemoveItem(sortedInv[itemCategory].front(),itemCategory,sortedInv[itemCategory].front()->Amt()); + } + }else + { + for(std::shared_ptr&item:itemList){ + RemoveItem(item,itemCategory,item->Amt()); + } } } @@ -1101,8 +1121,7 @@ void Item::RandomizeStats(){ randomizedStats=it->RandomizeStats(); }; -const Stats ItemInfo::GetMinStats()const{ - return minStats; +const Stats ItemInfo::GetMinStats()const{return minStats; } const Stats ItemInfo::GetMaxStats()const{ return maxStats; @@ -1129,4 +1148,12 @@ const EventName&ItemInfo::UseSound()const{ } const EventName&Item::UseSound()const{ return it->UseSound(); +} + +const std::vector>Inventory::GetInventory(){ + std::vector>itemList; + for(size_t itemCount=0;auto&[itemName,item]:Inventory::_inventory){ + itemList.push_back(item); + } + return itemList; } \ No newline at end of file diff --git a/Adventures in Lestoria/Item.h b/Adventures in Lestoria/Item.h index ada7d557..c0f3d478 100644 --- a/Adventures in Lestoria/Item.h +++ b/Adventures in Lestoria/Item.h @@ -247,6 +247,8 @@ public: static EquipSlot GetSlotEquippedIn(const std::weak_ptrit); static std::weak_ptrGetEquip(EquipSlot slot); static const std::mapGetEquippedItemSets(); + //Gets all items currently on inventory (Ignores Stage Loot and Monster Loot Inventories) + static const std::vector>GetInventory(); static bool SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2); //Makes sure this is a valid category. Will error out if it doesn't exist! Use for ERROR HANDLING! @@ -256,7 +258,7 @@ public: } private: static void InsertIntoSortedInv(std::shared_ptritemRef); - static void InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop); + static void InsertIntoStageInventoryCategory(std::shared_ptritemRef,const bool monsterDrop); static bool ExecuteAction(IT item); static std::multimap>_inventory; static std::map>equipment; diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index d59b8d1d..af48e851 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -669,6 +669,17 @@ void Monster::OnDeath(){ animation.ChangeState(internal_animState,GetDeathAnimationName()); if(isBoss){ game->ReduceBossEncounterMobCount(); + if(game->BossEncounterMobCount()==0){ + ZoneData exitRing{geom2d::rect{vi2d{GetPos()-vf2d{"boss_spawn_ring_radius"_F,"boss_spawn_ring_radius"_F}},vi2d{"boss_spawn_ring_radius"_I*2,"boss_spawn_ring_radius"_I*2}},OnUpperLevel()}; + + const geom2d::rectarenaBounds=game->GetZones().at("BossArena")[0].zone; + geom2d::rectclampedArena{vi2d(arenaBounds.pos+"boss_spawn_ring_radius"_I),vi2d(arenaBounds.size-"boss_spawn_ring_radius"_I*2)}; + + exitRing.zone.pos.x=std::clamp(exitRing.zone.pos.x,clampedArena.pos.x,clampedArena.pos.x+clampedArena.size.x); + exitRing.zone.pos.y=std::clamp(exitRing.zone.pos.y,clampedArena.pos.y,clampedArena.pos.y+clampedArena.size.y); + + game->AddZone("EndZone",exitRing); //Create a 144x144 ring around the dead boss. + } } if(hasStrategyDeathFunction){ diff --git a/Adventures in Lestoria/Pathfinding.cpp b/Adventures in Lestoria/Pathfinding.cpp index 48c607c5..2d5e99dc 100644 --- a/Adventures in Lestoria/Pathfinding.cpp +++ b/Adventures in Lestoria/Pathfinding.cpp @@ -50,7 +50,7 @@ void Pathfinding::Initialize(){ for (int y = 0; y < game->GetCurrentMapData().height*24; y+=gridSpacing.y) { bool tileIsEmpty=true; - for(const LayerTag&layer:game->GetCurrentMap().LayerData){ + for(const LayerTag&layer:game->GetCurrentMap().GetLayers()){ int tileID=layer.tiles[y/24][x/24]-1; if(tileID!=-1){ tileIsEmpty=false; diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index 6e301684..f9932623 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -965,11 +965,11 @@ float Player::GetEndZoneStandTime(){ void Player::CheckEndZoneCollision(){ auto HasZoneData=[&](){ - return game->MAP_DATA[game->GetCurrentLevel()].ZoneData.count("EndZone"); + return game->GetZones().count("EndZone"); }; if(IsOutOfCombat()&&HasZoneData()){ - for(ZoneData&zone:game->MAP_DATA[game->GetCurrentLevel()].ZoneData.at("EndZone")){ + for(const ZoneData&zone:game->GetZones().at("EndZone")){ if(zone.isUpper==upperLevel&&geom2d::overlaps(GetPos(),zone.zone)){ endZoneStandTime+=game->GetElapsedTime(); if(endZoneStandTime>="Player.End Zone Wait Time"_F){ diff --git a/Adventures in Lestoria/SaveFile.cpp b/Adventures in Lestoria/SaveFile.cpp index 91668291..cb965f56 100644 --- a/Adventures in Lestoria/SaveFile.cpp +++ b/Adventures in Lestoria/SaveFile.cpp @@ -80,22 +80,20 @@ const void SaveFile::SaveGame(){ std::filesystem::create_directories("save_file_path"_S); utils::datafile saveFile; utils::datafile::INITIAL_SETUP_COMPLETE=false; - for(size_t itemCount=0;auto&[cat,items]:Inventory::sortedInv){ - for(std::shared_ptr&item:items){ - saveFile["Items"][std::format("Item[{}]",itemCount)]["Amt"].SetInt(item->Amt()); - saveFile["Items"][std::format("Item[{}]",itemCount)]["Enhancement Level"].SetInt(item->EnhancementLevel()); - saveFile["Items"][std::format("Item[{}]",itemCount)]["Item Name"].SetString(item->ActualName()); - saveFile["Items"][std::format("Item[{}]",itemCount)]["Equip Slot"].SetInt(int(Inventory::GetSlotEquippedIn(item))); - uint8_t loadoutSlotNumber=255; - for(int i=0;iloadout.size();i++){ - if(item==game->GetLoadoutItem(i)){loadoutSlotNumber=i;break;} - } - saveFile["Items"][std::format("Item[{}]",itemCount)]["LoadoutSlot"].SetInt(loadoutSlotNumber); - for(const auto&[attr,val]:item->RandomStats()){ - saveFile["Items"][std::format("Item[{}]",itemCount)]["Attributes"][std::string(attr.ActualName())].SetReal(val); - } - itemCount++; + for(size_t itemCount=0;auto&item:Inventory::GetInventory()){ + saveFile["Items"][std::format("Item[{}]",itemCount)]["Amt"].SetInt(item->Amt()); + saveFile["Items"][std::format("Item[{}]",itemCount)]["Enhancement Level"].SetInt(item->EnhancementLevel()); + saveFile["Items"][std::format("Item[{}]",itemCount)]["Item Name"].SetString(item->ActualName()); + saveFile["Items"][std::format("Item[{}]",itemCount)]["Equip Slot"].SetInt(int(Inventory::GetSlotEquippedIn(item))); + uint8_t loadoutSlotNumber=255; + for(int i=0;iloadout.size();i++){ + if(item==game->GetLoadoutItem(i)){loadoutSlotNumber=i;break;} + } + saveFile["Items"][std::format("Item[{}]",itemCount)]["LoadoutSlot"].SetInt(loadoutSlotNumber); + for(const auto&[attr,val]:item->RandomStats()){ + saveFile["Items"][std::format("Item[{}]",itemCount)]["Attributes"][std::string(attr.ActualName())].SetReal(val); } + itemCount++; } saveFile["Player"]["Class"].SetString(game->GetPlayer()->GetClassName()); saveFile["Player"]["Level"].SetInt(game->GetPlayer()->Level()); diff --git a/Adventures in Lestoria/State_LevelComplete.cpp b/Adventures in Lestoria/State_LevelComplete.cpp index 42fd595f..78894562 100644 --- a/Adventures in Lestoria/State_LevelComplete.cpp +++ b/Adventures in Lestoria/State_LevelComplete.cpp @@ -51,7 +51,7 @@ void State_LevelComplete::OnStateChange(GameState*prevState){ } Component(MenuType::LEVEL_COMPLETE,"Level EXP Gain Outline")->SetLabel(std::format("+{} Exp",game->GetPlayer()->GetAccumulatedXP())); game->GetPlayer()->AddXP(game->GetPlayer()->GetAccumulatedXP()); - for(const ItemMapData&data:game->GetCurrentMap().stageLoot){ + for(const ItemMapData&data:game->GetCurrentMap().GetStageLoot()){ uint8_t amountDiff=data.maxAmt-data.minAmt; uint8_t randomAmt=data.maxAmt; if(amountDiff>0){ //This check avoids division by zero. diff --git a/Adventures in Lestoria/TMXParser.h b/Adventures in Lestoria/TMXParser.h index 1ce12ab7..c6bc046a 100644 --- a/Adventures in Lestoria/TMXParser.h +++ b/Adventures in Lestoria/TMXParser.h @@ -95,6 +95,9 @@ struct ZoneData{ }; struct Map{ + friend class AiL; + friend class TMXParser; +private: MapTag MapData; std::string name; Renderable*optimizedTile=nullptr; @@ -108,7 +111,15 @@ struct Map{ std::setspawns; std::map SpawnerData; //Spawn groups have IDs, mobs associate which spawner they are tied to via this ID. std::map> ZoneData; + const std::map>&GetZones()const; +public: + const MapTag&GetMapData()const; + const std::string_view GetMapType()const; + const std::vector&GetStageLoot()const; + const std::vector&GetLayers()const; + const std::vector&GetEnvironmentalAudio()const; const MapName&GetMapName()const; + const std::string_view GetMapDisplayName()const; std::string FormatLayerData(std::ostream& os, std::vectortiles); std::string FormatSpawnerData(std::ostream& os, std::maptiles); friend std::ostream& operator << (std::ostream& os, Map& rhs); @@ -248,9 +259,30 @@ class TMXParser{ } return displayStr; } + const std::string_view Map::GetMapType()const{ + return mapType; + } const MapName&Map::GetMapName()const{ return name; } + const MapTag&Map::GetMapData()const{ + return MapData; + } + const std::vector&Map::GetEnvironmentalAudio()const{ + return environmentalAudioData; + } + const std::map>&Map::GetZones()const{ + return ZoneData; + } + const std::vector&Map::GetStageLoot()const{ + return stageLoot; + } + const std::vector&Map::GetLayers()const{ + return LayerData; + } + const std::string_view Map::GetMapDisplayName()const{ + return name; + } std::ostream& operator <<(std::ostream& os, std::vector& rhs) { for(XMLTag&tag:rhs){ os << @@ -440,6 +472,12 @@ class TMXParser{ std::string accumulator=""; + //Initialize these so that they are valid entries for zones. + parsedMapInfo.ZoneData["LowerZone"]; + parsedMapInfo.ZoneData["UpperZone"]; + parsedMapInfo.ZoneData["EndZone"]; + parsedMapInfo.ZoneData["BossArena"]; + while (f.good()&&!infiniteMap) { std::string data; f>>data; diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index cee1e94f..b4fdd5e1 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -25,6 +25,8 @@ Settings Menu - Implement escape menu during gameplay. - If you leave a stage, the stage complete window still shows up, showing only the loot you obtained that session. +- No equip sounds for weapons? + January 31st ============ diff --git a/Adventures in Lestoria/Test.cpp b/Adventures in Lestoria/Test.cpp index 26f85727..a3517fff 100644 --- a/Adventures in Lestoria/Test.cpp +++ b/Adventures in Lestoria/Test.cpp @@ -54,14 +54,14 @@ void Test::is(std::string conditionStr,bool testResult){ void Test::RunMapTests(){ is("There are two LowerBridgeCollision zones in Campaign I-I", - game->MAP_DATA.at("CAMPAIGN_1_1").ZoneData.count("LowerBridgeCollision") - &&game->MAP_DATA.at("CAMPAIGN_1_1").ZoneData.at("LowerBridgeCollision").size()>=2); + game->GetZoneData("CAMPAIGN_1_1").count("LowerBridgeCollision") + &&game->GetZoneData("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.mapType!=""&&value.mapType!="Unspecified"); - if(value.mapType=="Dungeon"){ + value.GetMapType()!=""&&value.GetMapType()!="Unspecified"); + if(value.GetMapType()=="Dungeon"){ is("There is an EndZone in Dungeon "+key, - value.ZoneData.count("EndZone")); + game->GetZones(key).count("EndZone")); } } } \ No newline at end of file diff --git a/Adventures in Lestoria/Ursule.cpp b/Adventures in Lestoria/Ursule.cpp index cb471ad6..abf52f38 100644 --- a/Adventures in Lestoria/Ursule.cpp +++ b/Adventures in Lestoria/Ursule.cpp @@ -127,7 +127,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy break; } } - vf2d mapCenter=game->GetCurrentMap().MapData.MapSize*vf2d{float(game->GetCurrentMap().MapData.tilewidth),float(game->GetCurrentMap().MapData.tileheight)}/2.0f; + vf2d mapCenter=game->GetCurrentMap().GetMapData().MapSize*vf2d{float(game->GetCurrentMap().GetMapData().tilewidth),float(game->GetCurrentMap().GetMapData().tileheight)}/2.0f; float distToCenter=geom2d::line(m.GetPos(),mapCenter).length(); if(distToCenter>4.0f){ m.targetAcquireTimer=20.f; @@ -204,7 +204,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy vi2d wispSize={ConfigIntArr("Phase 2.Wisp Size",0),ConfigIntArr("Phase 2.Wisp Size",1)}; float rowWidth=ConfigString(std::format("Wisp Pattern {}.Row[0]",wispPattern)).length()*wispSize.x; // Width of a wisp set in pixels. - float mapWidth=game->GetCurrentMap().MapData.MapSize.x*float(game->GetCurrentMap().MapData.tilewidth); + float mapWidth=game->GetCurrentMap().GetMapData().MapSize.x*float(game->GetCurrentMap().GetMapData().tilewidth); int rowCount=Config(std::format("Wisp Pattern {}",wispPattern)).GetKeys().size(); for(float x=0;xGetCurrentMap().MapData.MapSize*vf2d{float(game->GetCurrentMap().MapData.tilewidth),float(game->GetCurrentMap().MapData.tileheight)}/2.0f; + vf2d mapCenter=game->GetCurrentMap().GetMapData().MapSize*vf2d{float(game->GetCurrentMap().GetMapData().tilewidth),float(game->GetCurrentMap().GetMapData().tileheight)}/2.0f; float distToCenter=geom2d::line(m.GetPos(),mapCenter).length(); if(distToCenter>4.0f){ m.targetAcquireTimer=20.f; @@ -317,8 +317,8 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy m.AddBuff(COLLISION_KNOCKBACK_STRENGTH,10.f,ConfigFloat("Phase 3.Charge Attack Knockback Strength")); m.target=geom2d::line(m.GetPos(),game->GetPlayer()->GetPos()).upoint(2.0f); //It's possible the charge forces the bear outside the map, so it will attempt to run forever on the clamped edges. - m.target.x=std::clamp(m.target.x,0.f,float(game->GetCurrentMap().MapData.width*game->GetCurrentMap().MapData.tilewidth)); - m.target.y=std::clamp(m.target.y,0.f,float(game->GetCurrentMap().MapData.height*game->GetCurrentMap().MapData.tileheight)); + m.target.x=std::clamp(m.target.x,0.f,float(game->GetCurrentMap().GetMapData().width*game->GetCurrentMap().GetMapData().tilewidth)); + m.target.y=std::clamp(m.target.y,0.f,float(game->GetCurrentMap().GetMapData().height*game->GetCurrentMap().GetMapData().tileheight)); m.F(A::TARGET_TIMER)=ConfigFloat("Phase 3.Charge Max Run Time"); m.F(A::CHARGE_COOLDOWN)=ConfigFloat("Phase 3.Charge Attack Cooldown"); m.PerformOtherAnimation(3); @@ -408,7 +408,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy vi2d wispSize={ConfigIntArr("Phase 4.Wisp Size",0),ConfigIntArr("Phase 4.Wisp Size",1)}; float rowWidth=ConfigString(std::format("Wisp Pattern {}.Row[0]",wispPattern)).length()*wispSize.x; // Width of a wisp set in pixels. - float mapWidth=game->GetCurrentMap().MapData.MapSize.x*float(game->GetCurrentMap().MapData.tilewidth); + float mapWidth=game->GetCurrentMap().GetMapData().MapSize.x*float(game->GetCurrentMap().GetMapData().tilewidth); int rowCount=Config(std::format("Wisp Pattern {}",wispPattern)).GetKeys().size(); for(float x=0;x - + @@ -275,5 +275,6 @@ + diff --git a/Adventures in Lestoria/assets/Campaigns/Boss_1_v2.tmx b/Adventures in Lestoria/assets/Campaigns/Boss_1_v2.tmx index 216b65eb..f4c4551b 100644 --- a/Adventures in Lestoria/assets/Campaigns/Boss_1_v2.tmx +++ b/Adventures in Lestoria/assets/Campaigns/Boss_1_v2.tmx @@ -1,5 +1,5 @@ - + @@ -275,5 +275,7 @@ + + diff --git a/Adventures in Lestoria/assets/Campaigns/World_Map.tmx b/Adventures in Lestoria/assets/Campaigns/World_Map.tmx index c5695898..012158c3 100644 --- a/Adventures in Lestoria/assets/Campaigns/World_Map.tmx +++ b/Adventures in Lestoria/assets/Campaigns/World_Map.tmx @@ -669,7 +669,7 @@ - + @@ -679,7 +679,7 @@ - + diff --git a/Adventures in Lestoria/assets/config/Monsters.txt b/Adventures in Lestoria/assets/config/Monsters.txt index 2d6c8efa..06ba9070 100644 --- a/Adventures in Lestoria/assets/config/Monsters.txt +++ b/Adventures in Lestoria/assets/config/Monsters.txt @@ -381,7 +381,7 @@ Monsters DROP[2] = Bear Claw,30%,1,1 Hurt Sound = Monster Hurt - Death Sound = Slime Dead + Death Sound = Ursule Dead Walk Sound = Slime Walk #Additional custom animations go down below. Start with ANIMATION[0] Order is: diff --git a/Adventures in Lestoria/assets/config/audio/bgm.txt b/Adventures in Lestoria/assets/config/audio/bgm.txt index 162d8c34..e2800e3d 100644 --- a/Adventures in Lestoria/assets/config/audio/bgm.txt +++ b/Adventures in Lestoria/assets/config/audio/bgm.txt @@ -95,19 +95,20 @@ BGM { Track Name = Foresty Loop 1 - channel[0]=loop2/foresty1_1_loop1_bass.ogg - channel[1]=loop2/foresty1_1_loop1_drums.ogg - channel[2]=loop2/foresty1_1_loop1_piano 1.ogg - channel[3]=loop2/foresty1_1_loop1_piano 2.ogg - channel[4]=loop2/foresty1_1_loop1_staccato.ogg - channel[5]=loop2/foresty1_1_loop1_strings.ogg + channel[0]=loop1/foresty1_1_loop1_bass.ogg + channel[1]=loop1/foresty1_1_loop1_drums.ogg + channel[2]=loop1/foresty1_1_loop1_flute.ogg + channel[3]=loop1/foresty1_1_loop1_piano 1.ogg + channel[4]=loop1/foresty1_1_loop1_piano 2.ogg + channel[5]=loop1/foresty1_1_loop1_strings.ogg + channel[6]=loop1/foresty1_1_loop1_xtra perc.ogg # Transition time between one phase to the next. Fade Time = 2.0 Events { - Default Volume = 0%,70%,0%,70%,70%,0% + Default Volume = 0%,70%,0%,0%,70%,70%,0% } } } \ No newline at end of file diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt index 36f68ddb..745d7231 100644 --- a/Adventures in Lestoria/assets/config/audio/events.txt +++ b/Adventures in Lestoria/assets/config/audio/events.txt @@ -144,6 +144,11 @@ Events File[1] = slime_walk2.ogg, 10% File[2] = slime_walk3.ogg, 10% } + Ursule Dead + { + # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) + File[0] = ursule_dead.ogg, 100% + } Ursule Phase Transition { # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) diff --git a/Adventures in Lestoria/assets/config/configuration.txt b/Adventures in Lestoria/assets/config/configuration.txt index 2a307717..57792eb1 100644 --- a/Adventures in Lestoria/assets/config/configuration.txt +++ b/Adventures in Lestoria/assets/config/configuration.txt @@ -154,4 +154,7 @@ water_reflection_scale_factor = 0.05 # The message displayed to the user about ID creation. user_id_message = In order to save progress online, we ask that you provide a unique username to identify your save data with. -user_id_message2 = When loading a file, you will need this unique ID. \ No newline at end of file +user_id_message2 = When loading a file, you will need this unique ID. + +# How large the exit ring is for a boss when it's killed. +boss_spawn_ring_radius = 116 \ No newline at end of file diff --git a/Adventures in Lestoria/assets/sounds/fireplace.wav b/Adventures in Lestoria/assets/sounds/fireplace.wav deleted file mode 100644 index 2f7e915c..00000000 Binary files a/Adventures in Lestoria/assets/sounds/fireplace.wav and /dev/null differ diff --git a/Adventures in Lestoria/assets/sounds/ursule_dead.ogg b/Adventures in Lestoria/assets/sounds/ursule_dead.ogg new file mode 100644 index 00000000..ed39783b Binary files /dev/null and b/Adventures in Lestoria/assets/sounds/ursule_dead.ogg differ