Implemented reading spawn zones on maps. Monsters now spawn according to spawn zones.

pull/28/head
sigonasr2 1 year ago
parent 9a2af45245
commit 57d7f3344b
  1. 2
      Crawler/Class.cpp
  2. 14
      Crawler/Crawler.cpp
  3. 2
      Crawler/Player.cpp
  4. 144
      Crawler/TMXParser.h
  5. 2
      Crawler/Version.h
  6. 56
      Crawler/assets/Campaigns/1_1.tmx

@ -102,7 +102,7 @@ bool Warrior::AutoAttack(){
bool Warrior::Ability1(){ bool Warrior::Ability1(){
ACCESS_PLAYER ACCESS_PLAYER
game->AddEffect(Effect(p.pos,0.1,AnimationState::BATTLECRY_EFFECT,1,0.3)); game->AddEffect(Effect(p.pos,0.1,AnimationState::BATTLECRY_EFFECT,p.upperLevel,1,0.3));
p.AddBuff(BuffType::ATTACK_UP,10,0.1); p.AddBuff(BuffType::ATTACK_UP,10,0.1);
p.AddBuff(BuffType::DAMAGE_REDUCTION,10,0.1); p.AddBuff(BuffType::DAMAGE_REDUCTION,10,0.1);
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){

@ -1034,16 +1034,18 @@ void Crawler::LoadLevel(MapName map){
foregroundTileGroups.clear(); foregroundTileGroups.clear();
currentLevel=map; currentLevel=map;
WORLD_SIZE={MAP_DATA[map].MapData.width,MAP_DATA[map].MapData.height}; WORLD_SIZE={MAP_DATA[map].MapData.width,MAP_DATA[map].MapData.height};
for(SpawnerTag&spawner:MAP_DATA[map].SpawnerData){ for(auto key:MAP_DATA[map].SpawnerData){
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key.first];
std::vector<std::pair<MonsterName,vf2d>>monster_list; std::vector<std::pair<MonsterName,vf2d>>monster_list;
vf2d spawnerRadius=vf2d{spawner.ObjectData.GetFloat("width"),spawner.ObjectData.GetFloat("height")}/2;
for(XMLTag&property:spawner.properties){ vf2d spawnerRadius=vf2d{spawnData.ObjectData.GetFloat("width"),spawnData.ObjectData.GetFloat("height")}/2;
int monsterTypeID=property.GetInteger("value")-1; for(XMLTag&monster:spawnData.monsters){
int monsterTypeID=monster.GetInteger("value")-1;
if(monsterTypeID>=0&&monsterTypeID<MonsterName::END){ if(monsterTypeID>=0&&monsterTypeID<MonsterName::END){
monster_list.push_back({MonsterName(monsterTypeID),{rand()%int(spawnerRadius.x)-spawnerRadius.x/2,rand()%int(spawnerRadius.y)-spawnerRadius.y/2}}); monster_list.push_back({MonsterName(monsterTypeID),{monster.GetInteger("x")-spawnData.ObjectData.GetFloat("x"),monster.GetInteger("y")-spawnData.ObjectData.GetFloat("y")}});
} }
} }
SPAWNER_LIST.push_back(MonsterSpawner{{spawner.ObjectData.GetFloat("x")+spawnerRadius.x,spawner.ObjectData.GetFloat("y")+spawnerRadius.y},spawnerRadius,monster_list}); SPAWNER_LIST.push_back(MonsterSpawner{{spawnData.ObjectData.GetFloat("x"),spawnData.ObjectData.GetFloat("y")},spawnerRadius*2,monster_list});
} }
for(int x=0;x<WORLD_SIZE.x;x++){ for(int x=0;x<WORLD_SIZE.x;x++){
for(int y=0;y<WORLD_SIZE.y;y++){ for(int y=0;y<WORLD_SIZE.y;y++){

@ -392,7 +392,7 @@ Key Player::GetFacingDirection(){
void Player::Moved(){ void Player::Moved(){
for(MonsterSpawner&spawner:SPAWNER_LIST){ for(MonsterSpawner&spawner:SPAWNER_LIST){
if(!spawner.SpawnTriggered()&&geom2d::contains(geom2d::ellipse<float>{spawner.GetPos(),spawner.GetRange()},pos)){ if(!spawner.SpawnTriggered()&&geom2d::contains(geom2d::rect<float>{spawner.GetPos(),spawner.GetRange()},pos)){
spawner.SetTriggered(true); spawner.SetTriggered(true);
} }
} }

@ -31,7 +31,7 @@ struct LayerTag{
struct SpawnerTag{ struct SpawnerTag{
XMLTag ObjectData; XMLTag ObjectData;
std::vector<XMLTag>properties; std::vector<XMLTag>monsters;
std::string str(); std::string str();
friend std::ostream& operator << (std::ostream& os, SpawnerTag& rhs); friend std::ostream& operator << (std::ostream& os, SpawnerTag& rhs);
}; };
@ -40,10 +40,10 @@ struct Map{
MapTag MapData; MapTag MapData;
std::vector<XMLTag> TilesetData; std::vector<XMLTag> TilesetData;
std::vector<LayerTag> LayerData; std::vector<LayerTag> LayerData;
std::vector<SpawnerTag> SpawnerData; 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<geom2d::rect<int>>> ZoneData; std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
std::string FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles); std::string FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles);
std::string FormatSpawnerData(std::ostream& os, std::vector<SpawnerTag>tiles); std::string FormatSpawnerData(std::ostream& os, std::map<int,SpawnerTag>tiles);
friend std::ostream& operator << (std::ostream& os, Map& rhs); friend std::ostream& operator << (std::ostream& os, Map& rhs);
friend std::ostream& operator << (std::ostream& os, std::vector<XMLTag>& rhs); friend std::ostream& operator << (std::ostream& os, std::vector<XMLTag>& rhs);
}; };
@ -56,6 +56,10 @@ class TMXParser{
bool buildingSpawner=false; bool buildingSpawner=false;
SpawnerTag obj; SpawnerTag obj;
void ParseTag(std::string tag); void ParseTag(std::string tag);
int monsterPropertyTagCount=-1;
XMLTag monsterTag;
XMLTag spawnerLinkTag;
std::vector<XMLTag>accumulatedMonsterTags;
public: public:
TMXParser(std::string file); TMXParser(std::string file);
}; };
@ -108,8 +112,8 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
} }
std::string SpawnerTag::str() { std::string SpawnerTag::str() {
std::string displayStr=ObjectData.tag+"\n"+ObjectData.FormatTagData(ObjectData.data); std::string displayStr=ObjectData.tag+"\n"+ObjectData.FormatTagData(ObjectData.data);
for(XMLTag tag:properties){ for(XMLTag&monster:monsters){
displayStr+=" ("+tag.FormatTagData(tag.data)+" )\n"; displayStr+=" ("+monster.FormatTagData(monster.data)+" )\n";
} }
return displayStr; return displayStr;
} }
@ -124,10 +128,10 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
} }
return displayStr; return displayStr;
} }
std::string Map::FormatSpawnerData(std::ostream& os, std::vector<SpawnerTag>tiles) { std::string Map::FormatSpawnerData(std::ostream& os, std::map<int,SpawnerTag>tiles) {
std::string displayStr; std::string displayStr;
for (int i=0;i<SpawnerData.size();i++) { for (auto key:SpawnerData) {
displayStr+=SpawnerData[i].str(); displayStr+=SpawnerData[key.first].str();
} }
return displayStr; return displayStr;
} }
@ -150,51 +154,58 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
return parsedMapInfo; return parsedMapInfo;
} }
void TMXParser::ParseTag(std::string tag) { void TMXParser::ParseTag(std::string tag) {
XMLTag newTag;
//First character is a '<' so we discard it.
tag.erase(0,1); tag.erase(tag.length()-1,1); //Erase the first and last characters in the tag. Now parse by spaces. auto ReadNextTag=[&](){
std::stringstream s(tag); //Turn it into a string stream to now parse into individual whitespaces. XMLTag newTag;
std::string data; //First character is a '<' so we discard it.
while (s.good()) { tag.erase(0,1); tag.erase(tag.length()-1,1); //Erase the first and last characters in the tag. Now parse by spaces.
int quotationMarkCount=0; std::stringstream s(tag); //Turn it into a string stream to now parse into individual whitespaces.
bool pastEquals=false; std::string data;
data=""; while (s.good()) {
bool valid=false; int quotationMarkCount=0;
while(s.good()){ bool pastEquals=false;
int character=s.get(); data="";
if(character=='"'){ bool valid=false;
quotationMarkCount++; while(s.good()){
} int character=s.get();
if(character==' '&&quotationMarkCount%2==0){ if(character=='"'){
valid=true; quotationMarkCount++;
break; }
} if(character==' '&&quotationMarkCount%2==0){
data+=character; valid=true;
if(pastEquals&&quotationMarkCount%2==0){ break;
valid=true; }
break; data+=character;
} if(pastEquals&&quotationMarkCount%2==0){
if(character=='='&&quotationMarkCount%2==0){ valid=true;
pastEquals=true; break;
}
if(character=='='&&quotationMarkCount%2==0){
pastEquals=true;
}
} }
} if(valid&&data.length()>0){
if(valid&&data.length()>0){ if (newTag.tag.length()==0) { //Tag's empty, so first line is the tag.
if (newTag.tag.length()==0) { //Tag's empty, so first line is the tag. newTag.tag=data;
newTag.tag=data; std::cout<<"Tag: "<<newTag.tag<<"\n";
std::cout<<"Tag: "<<newTag.tag<<"\n"; } 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);
//Strip Quotation marks. //Strip Quotation marks.
value = value.substr(1,std::string::npos); value = value.substr(1,std::string::npos);
value = value.substr(0,value.length()-1); value = value.substr(0,value.length()-1);
newTag.data[key]=value; newTag.data[key]=value;
std::cout<<" "<<key<<":"<<newTag.data[key]<<"\n"; std::cout<<" "<<key<<":"<<newTag.data[key]<<"\n";
}
} }
} }
} return newTag;
};
XMLTag newTag=ReadNextTag();
if (newTag.tag=="map") { if (newTag.tag=="map") {
parsedMapInfo.MapData={stoi(newTag.data["width"]),stoi(newTag.data["height"])}; parsedMapInfo.MapData={stoi(newTag.data["width"]),stoi(newTag.data["height"])};
@ -207,12 +218,7 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
parsedMapInfo.LayerData.push_back(l); parsedMapInfo.LayerData.push_back(l);
}else }else
if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") { if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") {
if(buildingSpawner){ parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag};
parsedMapInfo.SpawnerData.push_back(obj);
}
buildingSpawner=true;
obj={newTag};
goto spawnerResetSkip;
} else } else
if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") { if (newTag.tag=="object"&&newTag.data["type"]=="PlayerSpawnLocation") {
parsedMapInfo.MapData.playerSpawnLocation={newTag.GetInteger("x")-newTag.GetInteger("width")/2,newTag.GetInteger("y")-newTag.GetInteger("height")/2}; parsedMapInfo.MapData.playerSpawnLocation={newTag.GetInteger("x")-newTag.GetInteger("width")/2,newTag.GetInteger("y")-newTag.GetInteger("height")/2};
@ -232,19 +238,25 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
parsedMapInfo.ZoneData[newTag.data["type"]]=zones; parsedMapInfo.ZoneData[newTag.data["type"]]=zones;
} }
}else }else
if (newTag.tag=="property"&&buildingSpawner) { if (newTag.tag=="object"&&newTag.data["type"]=="Monster") {
if(newTag.data["propertytype"]=="MonsterName"){ //XMLTag monsterTag=ReadNextTag();
obj.properties.push_back(newTag); //XMLTag spawnerLinkTag=ReadNextTag();
} //newTag.data["value"]=monsterTag.GetInteger("value"); //Value now contains which monster name this spawn represents.
goto spawnerResetSkip; monsterTag=newTag;
monsterPropertyTagCount=0;
} else
if (newTag.tag=="property"&&monsterPropertyTagCount==0) {
monsterTag.data["value"]=newTag.data["value"];
monsterPropertyTagCount++;
} else
if (newTag.tag=="property"&&monsterPropertyTagCount==1) {
spawnerLinkTag=newTag;
monsterTag.data["spawnerLink"]=spawnerLinkTag.data["value"];
accumulatedMonsterTags.push_back(monsterTag);
monsterPropertyTagCount=-1;
} else { } else {
std::cout<<"Unsupported tag format! Ignoring."<<"\n"; std::cout<<"Unsupported tag format! Ignoring."<<"\n";
} }
if(buildingSpawner){
parsedMapInfo.SpawnerData.push_back(obj);
}
buildingSpawner=false;
spawnerResetSkip:
std::cout<<"\n"<<"=============\n"; std::cout<<"\n"<<"=============\n";
} }
TMXParser::TMXParser(std::string file){ TMXParser::TMXParser(std::string file){
@ -289,8 +301,8 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
} }
} }
if(buildingSpawner){ for(XMLTag&monster:accumulatedMonsterTags){
parsedMapInfo.SpawnerData.push_back(obj); parsedMapInfo.SpawnerData[monster.GetInteger("spawnerLink")].monsters.push_back(monster);
} }
std::cout<<"Parsed Map Data:\n"<<parsedMapInfo<<"\n"; std::cout<<"Parsed Map Data:\n"<<parsedMapInfo<<"\n";

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 528 #define VERSION_BUILD 547
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="192" height="203" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="45"> <map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="192" height="203" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="59">
<tileset firstgid="1" source="../maps/grass_tiles_24x24.tsx"/> <tileset firstgid="1" source="../maps/grass_tiles_24x24.tsx"/>
<tileset firstgid="784" source="../maps/grass_tiles_modded.tsx"/> <tileset firstgid="784" source="../maps/grass_tiles_modded.tsx"/>
<layer id="5" name="Collision Layer" width="192" height="203"> <layer id="5" name="Collision Layer" width="192" height="203">
@ -1044,7 +1044,6 @@
<object id="8" name="Spawn Group 2" type="SpawnGroup" x="1461.33" y="3090.67" width="521.333" height="534.667"> <object id="8" name="Spawn Group 2" type="SpawnGroup" x="1461.33" y="3090.67" width="521.333" height="534.667">
<ellipse/> <ellipse/>
</object> </object>
<object id="10" name="Spawn Group 3" type="SpawnGroup" x="2261.33" y="3040" width="242.667" height="592"/>
<object id="12" name="Spawn Group 4" type="SpawnGroup" x="3029.33" y="2946.67" width="513.333" height="509.333"> <object id="12" name="Spawn Group 4" type="SpawnGroup" x="3029.33" y="2946.67" width="513.333" height="509.333">
<ellipse/> <ellipse/>
</object> </object>
@ -1054,9 +1053,6 @@
<object id="14" name="Spawn Group 6" type="SpawnGroup" x="3182.67" y="1885.33" width="625.333" height="249.333"> <object id="14" name="Spawn Group 6" type="SpawnGroup" x="3182.67" y="1885.33" width="625.333" height="249.333">
<ellipse/> <ellipse/>
</object> </object>
<object id="15" x="3352" y="2328">
<ellipse/>
</object>
<object id="16" name="Spawn Group 7" type="SpawnGroup" x="3109.33" y="1048" width="729.333" height="225.333"> <object id="16" name="Spawn Group 7" type="SpawnGroup" x="3109.33" y="1048" width="729.333" height="225.333">
<ellipse/> <ellipse/>
</object> </object>
@ -1133,6 +1129,56 @@
<point/> <point/>
</object> </object>
<object id="44" name="Player Spawn" type="PlayerSpawnLocation" x="456" y="3288" width="24" height="24"/> <object id="44" name="Player Spawn" type="PlayerSpawnLocation" x="456" y="3288" width="24" height="24"/>
<object id="45" name="Blue Slime" type="Monster" x="1560" y="3270">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="52" name="Blue Slime" type="Monster" x="1578" y="3402">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="53" name="Blue Slime" type="Monster" x="2292" y="3204">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="58"/>
</properties>
<point/>
</object>
<object id="54" name="Blue Slime" type="Monster" x="1746" y="3174">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="55" name="Blue Slime" type="Monster" x="1860" y="3336">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="56" name="Blue Slime" type="Monster" x="1776" y="3420">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="57" name="Blue Slime" type="Monster" x="1704" y="3240">
<properties>
<property name="Type" type="int" propertytype="MonsterName" value="2"/>
<property name="spawner" type="object" value="8"/>
</properties>
<point/>
</object>
<object id="58" name="Spawn Group 3" type="SpawnGroup" x="2220" y="3018" width="242.667" height="592"/>
</objectgroup> </objectgroup>
<objectgroup id="7" name="Transition Layerxzs"> <objectgroup id="7" name="Transition Layerxzs">
<object id="40" type="LowerZone" x="1596" y="1134" width="372" height="684"/> <object id="40" type="LowerZone" x="1596" y="1134" width="372" height="684"/>

Loading…
Cancel
Save