Modified TMX Parser to read new map spawn format. Fix missing spawns. Added errors when spawns are missing from a monster.

pull/57/head
sigonasr2 8 months ago
parent d10127b721
commit a88b0b810b
  1. 1
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 3
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 18
      Adventures in Lestoria/AdventuresInLestoria.cpp
  4. 58
      Adventures in Lestoria/Monster.h
  5. 98
      Adventures in Lestoria/MonsterData.h
  6. 72
      Adventures in Lestoria/TMXParser.h
  7. 2
      Adventures in Lestoria/Version.h
  8. 30
      Adventures in Lestoria/assets/Campaigns/1_2.tmx
  9. 6
      Adventures in Lestoria/assets/Campaigns/1_8.tmx
  10. 6
      Adventures in Lestoria/assets/Campaigns/Intro_Map.tmx
  11. BIN
      x64/Release/Adventures in Lestoria.exe

@ -415,6 +415,7 @@
<SubType> <SubType>
</SubType> </SubType>
</ClInclude> </ClInclude>
<ClInclude Include="MonsterData.h" />
<ClInclude Include="olcPGEX_SplashScreen.h" /> <ClInclude Include="olcPGEX_SplashScreen.h" />
<ClInclude Include="PlayerMoneyLabel.h"> <ClInclude Include="PlayerMoneyLabel.h">
<SubType> <SubType>

@ -633,6 +633,9 @@
<ClInclude Include="Minimap.h"> <ClInclude Include="Minimap.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="MonsterData.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Player.cpp"> <ClCompile Include="Player.cpp">

@ -261,15 +261,6 @@ bool AiL::OnUserCreate(){
VisualNovel::Initialize(); VisualNovel::Initialize();
InitializeLevels();
//Initialize Camera.
camera=Camera2D{WINDOW_SIZE};
camera.SetMode(olc::utils::Camera2D::Mode::LazyFollow);
camera.SetTarget(player->GetPos());
camera.SetWorldBoundary({0,0},GetCurrentMap().MapData.MapSize*GetCurrentMap().MapData.TileSize);
camera.EnableWorldBoundary(false);
ItemAttribute::Initialize(); ItemAttribute::Initialize();
ItemInfo::InitializeItems(); ItemInfo::InitializeItems();
@ -290,6 +281,15 @@ bool AiL::OnUserCreate(){
MonsterData::InitializeMonsterData(); MonsterData::InitializeMonsterData();
MonsterData::InitializeNPCData(); MonsterData::InitializeNPCData();
InitializeLevels();
//Initialize Camera.
camera=Camera2D{WINDOW_SIZE};
camera.SetMode(olc::utils::Camera2D::Mode::LazyFollow);
camera.SetTarget(player->GetPos());
camera.SetWorldBoundary({0,0},GetCurrentMap().MapData.MapSize*GetCurrentMap().MapData.TileSize);
camera.EnableWorldBoundary(false);
sig::Animation::SetupPlayerAnimations(); sig::Animation::SetupPlayerAnimations();
view=TileTransformedView{GetScreenSize(),{1,1}}; view=TileTransformedView{GetScreenSize(),{1,1}};

@ -42,11 +42,11 @@ All rights reserved.
#include "olcUTIL_Animate2D.h" #include "olcUTIL_Animate2D.h"
#include "DEFINES.h" #include "DEFINES.h"
#include "Attributable.h" #include "Attributable.h"
#include "Item.h"
#include "safemap.h" #include "safemap.h"
#include "Pathfinding.h" #include "Pathfinding.h"
#include "GameEvent.h" #include "GameEvent.h"
#include "TMXParser.h" #include "TMXParser.h"
#include "MonsterData.h"
INCLUDE_ITEM_DATA INCLUDE_ITEM_DATA
@ -62,62 +62,6 @@ enum class MonsterAnimation{
DEATH DEATH
}; };
struct MonsterDropData{
ItemInfo*item;
float dropChance;
int minQty=1;
int maxQty=1;
MonsterDropData(std::string itemName,float dropChance,int minQty=1,int maxQty=1)
:item(&ITEM_DATA.at(itemName)),dropChance(dropChance),minQty(minQty),maxQty(maxQty){}
};
struct MonsterData{
private:
std::string name;
int hp;
int atk;
uint32_t xp;
float moveSpd;//1.0=100%
float size;
std::vector<std::string> animations;
std::string strategy;
int collisionDmg;
std::string jumpAnimation="WARRIOR_IDLE_S";
std::string shootAnimation="WARRIOR_IDLE_S";
std::string deathAnimation="WARRIOR_IDLE_S";
EventName hurtSound="";
EventName deathSound="";
EventName walkSound="";
std::vector<MonsterDropData> dropData;
bool isNPC=false;
public:
MonsterData();
MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vector<std::string>animations,std::vector<MonsterDropData>drops,float moveSpd=1.0f,float size=1.0f,std::string strategy="Run Towards",int collisionDmg=0);
int GetHealth();
int GetAttack();
const uint32_t GetXP()const;
float GetMoveSpdMult();
float GetSizeMult();
const std::string&GetAIStrategy()const;
int GetCollisionDmg();
std::string GetIdleAnimation();
std::string GetJumpAnimation();
std::string GetShootAnimation();
std::string GetDeathAnimation();
const EventName&GetHurtSound();
const EventName&GetDeathSound();
const EventName&GetWalkSound();
const bool IsNPC()const;
std::vector<std::string>GetAnimations(){
return animations;
}
const std::vector<MonsterDropData>&GetDropData();
std::string GetDisplayName();
static void InitializeMonsterData();
static void InitializeNPCData();
static std::map<std::string,Renderable*>imgs;
};
class GameEvent; class GameEvent;
class Monster:IAttributable{ class Monster:IAttributable{

@ -0,0 +1,98 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include "DEFINES.h"
#include "Item.h"
INCLUDE_ITEM_DATA
struct MonsterDropData{
ItemInfo*item;
float dropChance;
int minQty=1;
int maxQty=1;
MonsterDropData(std::string itemName,float dropChance,int minQty=1,int maxQty=1)
:item(&ITEM_DATA.at(itemName)),dropChance(dropChance),minQty(minQty),maxQty(maxQty){}
};
struct MonsterData{
private:
std::string name;
int hp;
int atk;
uint32_t xp;
float moveSpd;//1.0=100%
float size;
std::vector<std::string> animations;
std::string strategy;
int collisionDmg;
std::string jumpAnimation="WARRIOR_IDLE_S";
std::string shootAnimation="WARRIOR_IDLE_S";
std::string deathAnimation="WARRIOR_IDLE_S";
EventName hurtSound="";
EventName deathSound="";
EventName walkSound="";
std::vector<MonsterDropData> dropData;
bool isNPC=false;
public:
MonsterData();
MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vector<std::string>animations,std::vector<MonsterDropData>drops,float moveSpd=1.0f,float size=1.0f,std::string strategy="Run Towards",int collisionDmg=0);
int GetHealth();
int GetAttack();
const uint32_t GetXP()const;
float GetMoveSpdMult();
float GetSizeMult();
const std::string&GetAIStrategy()const;
int GetCollisionDmg();
std::string GetIdleAnimation();
std::string GetJumpAnimation();
std::string GetShootAnimation();
std::string GetDeathAnimation();
const EventName&GetHurtSound();
const EventName&GetDeathSound();
const EventName&GetWalkSound();
const bool IsNPC()const;
std::vector<std::string>GetAnimations(){
return animations;
}
const std::vector<MonsterDropData>&GetDropData();
std::string GetDisplayName();
static void InitializeMonsterData();
static void InitializeNPCData();
static std::map<std::string,Renderable*>imgs;
};

@ -45,7 +45,9 @@ All rights reserved.
#include "safemap.h" #include "safemap.h"
#include "ItemMapData.h" #include "ItemMapData.h"
#include "Class.h" #include "Class.h"
#include "MonsterData.h"
INCLUDE_MONSTER_DATA
using MapName=std::string; using MapName=std::string;
using namespace olc; using namespace olc;
@ -61,7 +63,7 @@ struct XMLTag{
float GetFloat(std::string dataTag); float GetFloat(std::string dataTag);
double GetDouble(std::string dataTag); double GetDouble(std::string dataTag);
bool GetBool(std::string dataTag); bool GetBool(std::string dataTag);
std::string GetString(std::string dataTag); std::string GetString(std::string dataTag)const;
}; };
struct ForegroundTileTag:public XMLTag{ struct ForegroundTileTag:public XMLTag{
@ -224,13 +226,13 @@ class TMXParser{
double XMLTag::GetDouble(std::string dataTag) { double XMLTag::GetDouble(std::string dataTag) {
return std::stod(data[dataTag]); return std::stod(data[dataTag]);
} }
std::string XMLTag::GetString(std::string dataTag) { std::string XMLTag::GetString(std::string dataTag)const{
return data[dataTag]; return data.at(dataTag);
} }
bool XMLTag::GetBool(std::string dataTag) { bool XMLTag::GetBool(std::string dataTag) {
if (data[dataTag]=="0"||data[dataTag]=="false") { if (data[dataTag]=="0"||data[dataTag]=="false") {
return false; return false;
} else { }else{
return true; return true;
} }
} }
@ -246,7 +248,7 @@ class TMXParser{
bool Property::GetBool() { bool Property::GetBool() {
if (value=="0") { if (value=="0") {
return false; return false;
} else { }else{
return true; return true;
} }
} }
@ -396,7 +398,7 @@ class TMXParser{
#if _DEBUG #if _DEBUG
if(_DEBUG_MAP_LOAD_INFO)LOG("Tag: "<<newTag.tag<<"\n"); if(_DEBUG_MAP_LOAD_INFO)LOG("Tag: "<<newTag.tag<<"\n");
#endif #endif
} else { }else{
std::string key = data.substr(0,data.find("=")); std::string key = data.substr(0,data.find("="));
std::string value = data.substr(data.find("=")+1,std::string::npos); std::string value = data.substr(data.find("=")+1,std::string::npos);
@ -416,6 +418,16 @@ class TMXParser{
XMLTag newTag=ReadNextTag(); XMLTag newTag=ReadNextTag();
auto ParseMonsterTemplateName=[](const XMLTag&monsterTag){
std::string monsterName=monsterTag.GetString("template").substr("../maps/Monsters/"s.length());
monsterName=monsterName.substr(0,monsterName.find(".tx"));
return monsterName;
};
if(newTag.tag!="property"&&newTag.tag!="properties"&&monsterPropertyTagCount==0){
ERR(std::format("WARNING! Monster {} at ({},{}) in Map {} does not have a spawn set!",ParseMonsterTemplateName(monsterTag),monsterTag.GetFloat("x"),monsterTag.GetFloat("y"),fileName));
}
if (newTag.tag=="object"&&newTag.data["type"]!="StagePlate"){ if (newTag.tag=="object"&&newTag.data["type"]!="StagePlate"){
currentStagePlate=nullptr; currentStagePlate=nullptr;
} }
@ -433,10 +445,10 @@ class TMXParser{
if(newTag.data.find("class")==newTag.data.end())ERR(std::format("WARNING! Map {} does not have a class set!",fileName)); if(newTag.data.find("class")==newTag.data.end())ERR(std::format("WARNING! Map {} does not have a class set!",fileName));
if(newTag.data["class"]!="Map")ERR(std::format("WARNING! Map {} is not set to the map class! Class is set to {} instead.",fileName,newTag.data["class"])); if(newTag.data["class"]!="Map")ERR(std::format("WARNING! Map {} is not set to the map class! Class is set to {} instead.",fileName,newTag.data["class"]));
parsedMapInfo.MapData={stoi(newTag.data["width"]),stoi(newTag.data["height"]),stoi(newTag.data["tilewidth"]),stoi(newTag.data["tileheight"])}; parsedMapInfo.MapData={stoi(newTag.data["width"]),stoi(newTag.data["height"]),stoi(newTag.data["tilewidth"]),stoi(newTag.data["tileheight"])};
} else }else
if (newTag.tag=="tileset"){ if (newTag.tag=="tileset"){
parsedMapInfo.TilesetData.push_back(newTag); parsedMapInfo.TilesetData.push_back(newTag);
} else }else
if (newTag.tag=="layer"){ if (newTag.tag=="layer"){
LayerTag l = {newTag}; LayerTag l = {newTag};
parsedMapInfo.LayerData.push_back(l); parsedMapInfo.LayerData.push_back(l);
@ -447,86 +459,84 @@ class TMXParser{
parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag}; parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag};
prevSpawner=newTag.GetInteger("id"); prevSpawner=newTag.GetInteger("id");
} }
} else }else
if(newTag.tag=="property"&&newTag.data["name"]=="Layer Unlock Condition"&&currentLayerTag!=nullptr){ if(newTag.tag=="property"&&newTag.data["name"]=="Layer Unlock Condition"&&currentLayerTag!=nullptr){
currentLayerTag->unlockCondition=newTag.data["value"]; currentLayerTag->unlockCondition=newTag.data["value"];
} else }else
if(newTag.tag=="property"&&newTag.data["name"]=="Upper?"&&prevZoneData!=nullptr){ if(newTag.tag=="property"&&newTag.data["name"]=="Upper?"&&prevZoneData!=nullptr){
prevZoneData->isUpper=newTag.GetBool("value"); prevZoneData->isUpper=newTag.GetBool("value");
}else }else
if (newTag.tag=="property"&&newTag.data["name"]=="Optimize"&&newTag.data["value"]=="true") { if (newTag.tag=="property"&&newTag.data["name"]=="Optimize"&&newTag.data["value"]=="true") {
parsedMapInfo.MapData.optimized=true; parsedMapInfo.MapData.optimized=true;
} else }else
if (newTag.tag=="property"&&newTag.data["name"]=="Boss Title Display") { if (newTag.tag=="property"&&newTag.data["name"]=="Boss Title Display") {
parsedMapInfo.SpawnerData[prevSpawner].bossNameDisplay=newTag.data["value"]; parsedMapInfo.SpawnerData[prevSpawner].bossNameDisplay=newTag.data["value"];
} else }else
if (newTag.tag=="property"&&newTag.data["name"]=="Level Type") { if (newTag.tag=="property"&&newTag.data["name"]=="Level Type") {
parsedMapInfo.mapType=newTag.data["value"]; parsedMapInfo.mapType=newTag.data["value"];
} else }else
if (newTag.tag=="property"&&newTag.data["name"]=="Background Music") { if (newTag.tag=="property"&&newTag.data["name"]=="Background Music") {
if(newTag.data["value"]!="None"){ //None is a default value that we ignore. if(newTag.data["value"]!="None"){ //None is a default value that we ignore.
parsedMapInfo.bgmSongName=newTag.data["value"]; parsedMapInfo.bgmSongName=newTag.data["value"];
} }
} else }else
if (newTag.tag=="property"&&newTag.data["name"].starts_with("Dev Completion Time")) { if (newTag.tag=="property"&&newTag.data["name"].starts_with("Dev Completion Time")) {
if(newTag.data.count("value")){ //None is a default value that we ignore. if(newTag.data.count("value")){ //None is a default value that we ignore.
size_t classStartPos="Dev Completion Time - "s.length(); size_t classStartPos="Dev Completion Time - "s.length();
std::string className=newTag.data["name"].substr(classStartPos,newTag.data["name"].find(' ',classStartPos)-classStartPos); std::string className=newTag.data["name"].substr(classStartPos,newTag.data["name"].find(' ',classStartPos)-classStartPos);
parsedMapInfo.devCompletionTrialTime[classutils::StringToClass(className)]=newTag.GetFloat("value"); parsedMapInfo.devCompletionTrialTime[classutils::StringToClass(className)]=newTag.GetFloat("value");
} }
} else }else
if (newTag.tag=="property"&&newTag.data["name"]=="Backdrop") { if (newTag.tag=="property"&&newTag.data["name"]=="Backdrop") {
if(newTag.data["value"]!="None"){ //None is a default value that we ignore. if(newTag.data["value"]!="None"){ //None is a default value that we ignore.
parsedMapInfo.backdrop=newTag.data["value"]; parsedMapInfo.backdrop=newTag.data["value"];
} }
} else }else
if (newTag.tag=="object"&&newTag.data["type"]=="AudioEnvironmentalSound") { if (newTag.tag=="object"&&newTag.data["type"]=="AudioEnvironmentalSound") {
parsedMapInfo.environmentalAudioData.emplace_back(); parsedMapInfo.environmentalAudioData.emplace_back();
prevAudioData=&parsedMapInfo.environmentalAudioData.back(); prevAudioData=&parsedMapInfo.environmentalAudioData.back();
prevAudioData->SetPos({newTag.GetFloat("x"),newTag.GetFloat("y")}); prevAudioData->SetPos({newTag.GetFloat("x"),newTag.GetFloat("y")});
} else }else
if (newTag.tag=="property"&&newTag.data["propertytype"]=="EnvironmentalSounds") { if (newTag.tag=="property"&&newTag.data["propertytype"]=="EnvironmentalSounds") {
if(newTag.data["value"]!="None"){ //None is a default value that we ignore. if(newTag.data["value"]!="None"){ //None is a default value that we ignore.
prevAudioData->SetAudioName(newTag.data["value"]); prevAudioData->SetAudioName(newTag.data["value"]);
} }
} else }else
if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") { if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") {
float width=1.f; float width=1.f;
float height=1.f; float height=1.f;
if(newTag.data.count("width")>0)width=newTag.GetFloat("width"); if(newTag.data.count("width")>0)width=newTag.GetFloat("width");
if(newTag.data.count("height")>0)height=newTag.GetFloat("height"); if(newTag.data.count("height")>0)height=newTag.GetFloat("height");
parsedMapInfo.MapData.playerSpawnLocation={int(newTag.GetFloat("x")-width/2),int(newTag.GetFloat("y")-height/2)}; parsedMapInfo.MapData.playerSpawnLocation={int(newTag.GetFloat("x")-width/2),int(newTag.GetFloat("y")-height/2)};
} else }else
if (newTag.tag=="object"&&newTag.data["type"]=="NPC") { if (newTag.tag=="object"&&newTag.data["type"]=="NPC") {
if(inNPCTag)parsedMapInfo.npcs.push_back(NPCData{npcTag}); if(inNPCTag)parsedMapInfo.npcs.push_back(NPCData{npcTag});
npcTag=newTag; npcTag=newTag;
inNPCTag=true; inNPCTag=true;
} else } else
if (newTag.tag=="object"&&newTag.data["type"]=="Monster") { if (newTag.tag=="object"&&newTag.data["template"].starts_with("../maps/Monsters")) {
monsterTag=newTag; monsterTag=newTag;
monsterPropertyTagCount=0; monsterPropertyTagCount=0;
} else }else
if (newTag.tag=="property"&&inNPCTag) { if (newTag.tag=="property"&&inNPCTag) {
npcTag.data[newTag.data["name"]]=newTag.data["value"]; npcTag.data[newTag.data["name"]]=newTag.data["value"];
} }else
if (newTag.tag=="property"&&monsterPropertyTagCount==0) { if (newTag.tag=="property"&&monsterPropertyTagCount==0) {
if(newTag.data["value"]=="None")ERR(std::format("WARNING! Invalid monster type provided: {} in map {}",newTag.data["value"],fileName)); std::string monsterName=ParseMonsterTemplateName(monsterTag);
monsterTag.data["value"]=newTag.data["value"]; if(!MONSTER_DATA.count(monsterName))ERR(std::format("WARNING! Could not find monster type {}",monsterName));
parsedMapInfo.spawns.insert(newTag.GetString("value")); parsedMapInfo.spawns.insert(monsterName);
monsterPropertyTagCount++;
} else
if (newTag.tag=="property"&&monsterPropertyTagCount==1) {
spawnerLinkTag=newTag; spawnerLinkTag=newTag;
monsterTag.data["value"]=monsterName;
monsterTag.data["spawnerLink"]=spawnerLinkTag.data["value"]; monsterTag.data["spawnerLink"]=spawnerLinkTag.data["value"];
accumulatedMonsterTags.push_back(monsterTag); accumulatedMonsterTags.push_back(monsterTag);
monsterPropertyTagCount=-1; monsterPropertyTagCount=-1;
} else }else
if (newTag.tag=="object"&&newTag.data["type"]=="StagePlate") { if (newTag.tag=="object"&&newTag.data["type"]=="StagePlate") {
if(newTag.GetInteger("id")!=0){ if(newTag.GetInteger("id")!=0){
stagePlates[newTag.GetInteger("id")]={newTag}; stagePlates[newTag.GetInteger("id")]={newTag};
currentStagePlate=&stagePlates.at(newTag.GetInteger("id")); currentStagePlate=&stagePlates.at(newTag.GetInteger("id"));
} }
} else }else
if(newTag.tag=="property"&&currentStagePlate!=nullptr){ if(newTag.tag=="property"&&currentStagePlate!=nullptr){
currentStagePlate->properties[newTag.data["name"]]={newTag.data["name"],newTag.data["value"]}; currentStagePlate->properties[newTag.data["name"]]={newTag.data["name"],newTag.data["value"]};
}else }else
@ -586,7 +596,7 @@ class TMXParser{
if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){ if(accumulator.length()>1&&accumulator.find('>')!=std::string::npos){
accumulator=""; //Restart because this tag has nothing in it! accumulator=""; //Restart because this tag has nothing in it!
} }
} else { }else{
//Start reading in data for this layer. //Start reading in data for this layer.
std::vector<int>rowData; std::vector<int>rowData;
while (data.find(",")!=std::string::npos) { while (data.find(",")!=std::string::npos) {

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 8926 #define VERSION_BUILD 8944
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -885,14 +885,34 @@
<object id="23" name="Spawn 4" type="SpawnGroup" x="1385.33" y="2518.67" width="406.667" height="340"> <object id="23" name="Spawn 4" type="SpawnGroup" x="1385.33" y="2518.67" width="406.667" height="340">
<ellipse/> <ellipse/>
</object> </object>
<object id="24" template="../maps/Monsters/Flower Turret.tx" type="Monster" x="1485.33" y="2676"/> <object id="24" template="../maps/Monsters/Flower Turret.tx" type="Monster" x="1485.33" y="2676">
<properties>
<property name="spawner" type="object" value="23"/>
</properties>
</object>
<object id="25" name="Spawn 5" type="SpawnGroup" x="1375.33" y="1923.33" width="486.667" height="476"> <object id="25" name="Spawn 5" type="SpawnGroup" x="1375.33" y="1923.33" width="486.667" height="476">
<ellipse/> <ellipse/>
</object> </object>
<object id="26" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1609.33" y="2589.33"/> <object id="26" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1609.33" y="2589.33">
<object id="27" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1542.67" y="2630.67"/> <properties>
<object id="28" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1669.33" y="2633.33"/> <property name="spawner" type="object" value="23"/>
<object id="29" template="../maps/Monsters/Red Slime.tx" type="Monster" x="1589.33" y="2708"/> </properties>
</object>
<object id="27" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1542.67" y="2630.67">
<properties>
<property name="spawner" type="object" value="23"/>
</properties>
</object>
<object id="28" template="../maps/Monsters/Blue Slime.tx" type="Monster" x="1669.33" y="2633.33">
<properties>
<property name="spawner" type="object" value="23"/>
</properties>
</object>
<object id="29" template="../maps/Monsters/Red Slime.tx" type="Monster" x="1589.33" y="2708">
<properties>
<property name="spawner" type="object" value="23"/>
</properties>
</object>
<object id="30" name="Spawn 6" type="SpawnGroup" x="1346" y="1522" width="508" height="210.667"> <object id="30" name="Spawn 6" type="SpawnGroup" x="1346" y="1522" width="508" height="210.667">
<ellipse/> <ellipse/>
</object> </object>

@ -675,7 +675,11 @@
<property name="spawner" type="object" value="2"/> <property name="spawner" type="object" value="2"/>
</properties> </properties>
</object> </object>
<object id="40" template="../maps/Monsters/Windhound.tx" type="Monster" x="1117.33" y="1394.67"/> <object id="40" template="../maps/Monsters/Windhound.tx" type="Monster" x="1117.33" y="1394.67">
<properties>
<property name="spawner" type="object" value="2"/>
</properties>
</object>
<object id="41" template="../maps/Monsters/Yellow Slime.tx" type="Monster" x="1140" y="938.667"> <object id="41" template="../maps/Monsters/Yellow Slime.tx" type="Monster" x="1140" y="938.667">
<properties> <properties>
<property name="spawner" type="object" value="3"/> <property name="spawner" type="object" value="3"/>

@ -1331,7 +1331,11 @@
<object id="24" name="Spawn 15" type="SpawnGroup" x="2638" y="1912" width="1072" height="664"> <object id="24" name="Spawn 15" type="SpawnGroup" x="2638" y="1912" width="1072" height="664">
<ellipse/> <ellipse/>
</object> </object>
<object id="26" template="../maps/Monsters/Bear.tx" type="Monster" x="3550" y="2263"/> <object id="26" template="../maps/Monsters/Bear.tx" type="Monster" x="3550" y="2263">
<properties>
<property name="spawner" type="object" value="16"/>
</properties>
</object>
<object id="27" name="Spawn 15" type="SpawnGroup" x="849" y="34" width="2028" height="808"> <object id="27" name="Spawn 15" type="SpawnGroup" x="849" y="34" width="2028" height="808">
<properties> <properties>
<property name="spawner" type="object" value="27"/> <property name="spawner" type="object" value="27"/>

Loading…
Cancel
Save