Refactored Map Data access so that other locations in code no longer had write abilities to the map data. Changed permanent exit zone spawning to a temporary. Fix equipment items being duplicated due to sorted inventory not being in sync with actual inventory.
This commit is contained in:
parent
7162b151e4
commit
5c83a41a86
@ -52,6 +52,19 @@
|
||||
],
|
||||
"valuesAsFlags": false
|
||||
},
|
||||
{
|
||||
"color": "#ffa45f5f",
|
||||
"drawFill": true,
|
||||
"id": 36,
|
||||
"members": [
|
||||
],
|
||||
"name": "BossArena",
|
||||
"type": "class",
|
||||
"useAs": [
|
||||
"property",
|
||||
"object"
|
||||
]
|
||||
},
|
||||
{
|
||||
"color": "#ff290aa4",
|
||||
"drawFill": true,
|
||||
|
@ -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().y<m2->GetPos().y;});
|
||||
std::sort(monstersBeforeLower.begin(),monstersBeforeLower.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
|
||||
std::sort(monstersAfterUpper.begin(),monstersAfterUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().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::set<std::string>cpNames;
|
||||
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<std::string,std::vector<::ZoneData>>&AiL::GetZones(const std::string_view mapName)const{
|
||||
if(GetCurrentMapDisplayName()==mapName)return GetZones();
|
||||
return MAP_DATA.at(std::string(mapName)).ZoneData;
|
||||
}
|
||||
|
||||
const std::map<std::string,std::vector<::ZoneData>>&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;
|
||||
}
|
@ -142,6 +142,7 @@ private:
|
||||
DynamicCounter manaCounter;
|
||||
Pixel worldColor=WHITE;
|
||||
std::function<Pixel(vi2d)>worldColorFunc=[](vi2d pos){return WHITE;};
|
||||
std::map<std::string,std::vector<::ZoneData>>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_ptr<Item>GetLoadoutItem(int slot);
|
||||
@ -248,6 +251,11 @@ public:
|
||||
void SetWorldColorFunc(std::function<Pixel(vi2d)>func);
|
||||
void SetWorldColor(Pixel worldCol);
|
||||
const Pixel&GetWorldColor()const;
|
||||
//Returns the zones in the current stage
|
||||
const std::map<std::string,std::vector<::ZoneData>>&GetZones()const;
|
||||
//Returns the zones of any given stage
|
||||
const std::map<std::string,std::vector<::ZoneData>>&GetZones(const std::string_view mapName)const;
|
||||
void AddZone(const std::string_view zoneName,const ZoneData&zone);
|
||||
|
||||
struct TileGroupData{
|
||||
vi2d tilePos;
|
||||
|
@ -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<EnvironmentalAudio&>(aud);
|
||||
audio.Update();
|
||||
}
|
||||
|
@ -409,6 +409,7 @@ std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
|
||||
std::shared_ptr<Item>newItem=(*_inventory.insert({it,std::make_shared<Item>(1,it)})).second;
|
||||
newItem->RandomizeStats();
|
||||
InsertIntoSortedInv(newItem);
|
||||
InsertIntoStageInventoryCategory(newItem,monsterDrop);
|
||||
itemPtr=newItem;
|
||||
}
|
||||
goto SkipAddingStackableItem;
|
||||
@ -418,6 +419,7 @@ std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
|
||||
if(!_inventory.count(it)){
|
||||
std::shared_ptr<Item>newItem=(*_inventory.insert({it,std::make_shared<Item>(amt,it)})).second;
|
||||
InsertIntoSortedInv(newItem);
|
||||
InsertIntoStageInventoryCategory(newItem,monsterDrop);
|
||||
itemPtr=newItem;
|
||||
}else{
|
||||
auto inventory=_inventory.equal_range(it);
|
||||
@ -429,7 +431,6 @@ std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
|
||||
}
|
||||
|
||||
SkipAddingStackableItem:
|
||||
InsertIntoStageInventoryCategory(it,amt,monsterDrop);
|
||||
return itemPtr;
|
||||
}
|
||||
|
||||
@ -499,8 +500,12 @@ bool Inventory::RemoveItem(std::weak_ptr<Item>itemRef,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_ptr<Item>itemRef,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<const IT,std::shared_ptr<Item>>data){
|
||||
if(!found&&data.second==itemRef){
|
||||
found=true;
|
||||
@ -519,7 +525,9 @@ bool Inventory::RemoveItem(std::weak_ptr<Item>itemRef,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_ptr<Item>itemRef){
|
||||
Menu::InventorySlotsUpdated(itemRef->Category());
|
||||
}
|
||||
|
||||
void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop){
|
||||
void Inventory::InsertIntoStageInventoryCategory(std::shared_ptr<Item>itemRef,const bool monsterDrop){
|
||||
std::string stageInventoryCategory="Stage Loot";
|
||||
if(monsterDrop){
|
||||
stageInventoryCategory="Monster Loot";
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Item>>&inv=sortedInv.at(stageInventoryCategory);
|
||||
std::vector<std::shared_ptr<Item>>::iterator it=std::find(inv.begin(),inv.end(),std::make_shared<Item>(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<Item>(amt,item));
|
||||
std::vector<std::shared_ptr<Item>>::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<std::shared_ptr<Item>>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>&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>&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<std::shared_ptr<Item>>Inventory::GetInventory(){
|
||||
std::vector<std::shared_ptr<Item>>itemList;
|
||||
for(size_t itemCount=0;auto&[itemName,item]:Inventory::_inventory){
|
||||
itemList.push_back(item);
|
||||
}
|
||||
return itemList;
|
||||
}
|
@ -247,6 +247,8 @@ public:
|
||||
static EquipSlot GetSlotEquippedIn(const std::weak_ptr<Item>it);
|
||||
static std::weak_ptr<Item>GetEquip(EquipSlot slot);
|
||||
static const std::map<ItemSet,int>GetEquippedItemSets();
|
||||
//Gets all items currently on inventory (Ignores Stage Loot and Monster Loot Inventories)
|
||||
static const std::vector<std::shared_ptr<Item>>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_ptr<Item>itemRef);
|
||||
static void InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop);
|
||||
static void InsertIntoStageInventoryCategory(std::shared_ptr<Item>itemRef,const bool monsterDrop);
|
||||
static bool ExecuteAction(IT item);
|
||||
static std::multimap<IT,std::shared_ptr<Item>>_inventory;
|
||||
static std::map<EquipSlot,std::weak_ptr<Item>>equipment;
|
||||
|
@ -669,6 +669,17 @@ void Monster::OnDeath(){
|
||||
animation.ChangeState(internal_animState,GetDeathAnimationName());
|
||||
if(isBoss){
|
||||
game->ReduceBossEncounterMobCount();
|
||||
if(game->BossEncounterMobCount()==0){
|
||||
ZoneData exitRing{geom2d::rect<int>{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::rect<int>arenaBounds=game->GetZones().at("BossArena")[0].zone;
|
||||
geom2d::rect<int>clampedArena{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){
|
||||
|
@ -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;
|
||||
|
@ -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){
|
||||
|
@ -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>&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;i<game->loadout.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;i<game->loadout.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());
|
||||
|
@ -51,7 +51,7 @@ void State_LevelComplete::OnStateChange(GameState*prevState){
|
||||
}
|
||||
Component<MenuLabel>(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.
|
||||
|
@ -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::set<std::string>spawns;
|
||||
std::map<int,SpawnerTag> SpawnerData; //Spawn groups have IDs, mobs associate which spawner they are tied to via this ID.
|
||||
std::map<std::string,std::vector<::ZoneData>> ZoneData;
|
||||
const std::map<std::string,std::vector<::ZoneData>>&GetZones()const;
|
||||
public:
|
||||
const MapTag&GetMapData()const;
|
||||
const std::string_view GetMapType()const;
|
||||
const std::vector<ItemMapData>&GetStageLoot()const;
|
||||
const std::vector<LayerTag>&GetLayers()const;
|
||||
const std::vector<EnvironmentalAudio>&GetEnvironmentalAudio()const;
|
||||
const MapName&GetMapName()const;
|
||||
const std::string_view GetMapDisplayName()const;
|
||||
std::string FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles);
|
||||
std::string FormatSpawnerData(std::ostream& os, std::map<int,SpawnerTag>tiles);
|
||||
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<EnvironmentalAudio>&Map::GetEnvironmentalAudio()const{
|
||||
return environmentalAudioData;
|
||||
}
|
||||
const std::map<std::string,std::vector<::ZoneData>>&Map::GetZones()const{
|
||||
return ZoneData;
|
||||
}
|
||||
const std::vector<ItemMapData>&Map::GetStageLoot()const{
|
||||
return stageLoot;
|
||||
}
|
||||
const std::vector<LayerTag>&Map::GetLayers()const{
|
||||
return LayerData;
|
||||
}
|
||||
const std::string_view Map::GetMapDisplayName()const{
|
||||
return name;
|
||||
}
|
||||
std::ostream& operator <<(std::ostream& os, std::vector<XMLTag>& 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;
|
||||
|
@ -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
|
||||
============
|
||||
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
@ -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<float>(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;x<mapWidth;x+=wispSize.x){
|
||||
for(int y=0;y<rowCount;y++){
|
||||
@ -287,7 +287,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<float>(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<float>(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<mapWidth;x+=wispSize.x){
|
||||
for(int y=0;y<rowCount;y++){
|
||||
|
@ -39,7 +39,7 @@ All rights reserved.
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 6459
|
||||
#define VERSION_BUILD 6503
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" class="Map" orientation="orthogonal" renderorder="right-down" width="72" height="80" tilewidth="24" tileheight="24" infinite="0" nextlayerid="5" nextobjectid="6">
|
||||
<map version="1.10" tiledversion="1.10.1" class="Map" orientation="orthogonal" renderorder="right-down" width="72" height="80" tilewidth="24" tileheight="24" infinite="0" nextlayerid="5" nextobjectid="7">
|
||||
<properties>
|
||||
<property name="Backdrop" propertytype="Backdrop" value="forest"/>
|
||||
<property name="Background Music" propertytype="BGM" value="foresty_boss"/>
|
||||
@ -275,5 +275,6 @@
|
||||
</properties>
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="Boss Arena" type="BossArena" x="196" y="285" width="1339" height="1395"/>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.1" class="Map" orientation="orthogonal" renderorder="right-down" width="72" height="80" tilewidth="24" tileheight="24" infinite="0" nextlayerid="5" nextobjectid="6">
|
||||
<map version="1.10" tiledversion="1.10.1" class="Map" orientation="orthogonal" renderorder="right-down" width="72" height="80" tilewidth="24" tileheight="24" infinite="0" nextlayerid="5" nextobjectid="9">
|
||||
<properties>
|
||||
<property name="Backdrop" propertytype="Backdrop" value="forest"/>
|
||||
<property name="Background Music" propertytype="BGM" value="foresty_boss"/>
|
||||
@ -275,5 +275,7 @@
|
||||
</properties>
|
||||
<point/>
|
||||
</object>
|
||||
<object id="6" name="Boss Arena" type="BossArena" x="196" y="285" width="1339" height="1395"/>
|
||||
<object id="7" x="29" y="444"/>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
@ -669,7 +669,7 @@
|
||||
<property name="Unlock Condition" propertytype="Level" value="BOSS_1"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="17" name="Stage VI" type="StagePlate" x="156.25" y="475.75" width="44" height="16">
|
||||
<object id="17" name="Stage B-I" type="StagePlate" x="156.25" y="475.75" width="44" height="16">
|
||||
<properties>
|
||||
<property name="Connection 2 - East" type="object" value="18"/>
|
||||
<property name="Connection 3 - South" type="object" value="0"/>
|
||||
@ -679,7 +679,7 @@
|
||||
<property name="Unlock Condition" propertytype="Level" value="CAMPAIGN_1_5"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="18" name="Boss I" type="StagePlate" x="192" y="516" width="32" height="24">
|
||||
<object id="18" name="Boss B-I" type="StagePlate" x="192" y="516" width="32" height="24">
|
||||
<properties>
|
||||
<property name="Connection 1 - North" type="object" value="0"/>
|
||||
<property name="Map" propertytype="Level" value="BOSS_1_B"/>
|
||||
|
@ -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:
|
||||
|
@ -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%
|
||||
}
|
||||
}
|
||||
}
|
@ -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%)
|
||||
|
@ -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.
|
||||
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
|
Binary file not shown.
BIN
Adventures in Lestoria/assets/sounds/ursule_dead.ogg
Normal file
BIN
Adventures in Lestoria/assets/sounds/ursule_dead.ogg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user