commit f44a6f36
Load monster information from data file
Changed files
| A | data/monsters/monsters.json |
| A | src/saland/GameMonsters.cpp |
| A | src/saland/GameMonsters.hpp |
| M | src/saland/GameRegion.cpp before |
| M | src/saland/GameRegion.hpp before |
diff --git a/data/monsters/monsters.json b/data/monsters/monsters.json
new file mode 100644
index 0000000..3880c02
--- /dev/null
+++ b/data/monsters/monsters.json
@@ -0,0 +1,30 @@
+{
+ "monsters": [
+ {
+ "race": "bat",
+ "radius": 16.0,
+ "health": 30.0,
+ "speed": 1.0,
+ "attack": {
+ "cooldownDuration": 1500.0,
+ "range": 40.0,
+ "damage": 5.0,
+ "animation": "slash",
+ "animationDuration": 300.0
+ }
+ },
+ {
+ "race": "bee",
+ "radius": 16.0,
+ "health": 30.0,
+ "speed": 1.0,
+ "attack": {
+ "cooldownDuration": 1500.0,
+ "range": 40.0,
+ "damage": 5.0,
+ "animation": "slash",
+ "animationDuration": 300.0
+ }
+ }
+ ]
+}
diff --git a/src/saland/GameMonsters.cpp b/src/saland/GameMonsters.cpp
new file mode 100644
index 0000000..1e68af8
--- /dev/null
+++ b/src/saland/GameMonsters.cpp
@@ -0,0 +1,122 @@
+/*
+===========================================================================
+ * Saland Adventures
+Copyright (C) 2014-2017 Poul Sander
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see http://www.gnu.org/licenses/
+
+Source information and contacts persons can be found at
+https://github.com/sago007/saland
+===========================================================================
+*/
+
+#include "GameMonsters.hpp"
+#include <unordered_map>
+#include "../sago/SagoMisc.hpp"
+#include "rapidjson/document.h"
+#include <iostream>
+
+static std::unordered_map<std::string, MonsterDef> all_monsters;
+
+static void LoadMonsterDefinitions() {
+ if (!all_monsters.empty()) {
+ return; // Already loaded
+ }
+
+ std::string filename = "monsters/monsters.json";
+ std::string content = sago::GetFileContent(filename.c_str());
+ rapidjson::Document document;
+ document.Parse(content.c_str());
+
+ if (!document.IsObject()) {
+ std::cerr << "Failed to parse: " << filename << "\n";
+ return;
+ }
+
+ for (auto& m : document.GetObject()) {
+ const std::string& header = m.name.GetString();
+ if (header == "monsters") {
+ const auto& monsters = m.value;
+ if (!monsters.IsArray()) {
+ std::cerr << "Failure reading " << filename << ": 'monsters' must be an array\n";
+ continue;
+ }
+
+ for (const auto& monster : monsters.GetArray()) {
+ if (!monster.IsObject()) {
+ continue;
+ }
+
+ MonsterDef def;
+ std::string race;
+ for (const auto& member : monster.GetObject()) {
+ std::string memberName = member.name.GetString();
+
+ if (memberName == "race") {
+ race = member.value.GetString();
+ def.race = race;
+ }
+ else if (memberName == "radius") {
+ def.radius = member.value.GetFloat();
+ }
+ else if (memberName == "health") {
+ def.health = member.value.GetFloat();
+ }
+ else if (memberName == "speed") {
+ def.speed = member.value.GetFloat();
+ }
+ else if (memberName == "attack" && member.value.IsObject()) {
+ for (const auto& attackMember : member.value.GetObject()) {
+ std::string attackName = attackMember.name.GetString();
+ if (attackName == "cooldownDuration") {
+ def.attack.cooldownDuration = attackMember.value.GetFloat();
+ }
+ else if (attackName == "range") {
+ def.attack.range = attackMember.value.GetFloat();
+ }
+ else if (attackName == "damage") {
+ def.attack.damage = attackMember.value.GetFloat();
+ }
+ else if (attackName == "animation") {
+ def.attack.animation = attackMember.value.GetString();
+ }
+ else if (attackName == "animationDuration") {
+ def.attack.animationDuration = attackMember.value.GetFloat();
+ }
+ }
+ }
+ }
+
+ if (!race.empty()) {
+ all_monsters[race] = def;
+ }
+ }
+ }
+ }
+}
+
+MonsterDef GetMonsterDefByRace(const std::string& race) {
+ LoadMonsterDefinitions();
+
+ auto it = all_monsters.find(race);
+ if (it != all_monsters.end()) {
+ return it->second;
+ }
+
+ // Return default if not found
+ std::cerr << "Warning: Monster race '" << race << "' not found in monsters.json\n";
+ MonsterDef def;
+ def.race = race;
+ return def;
+}
diff --git a/src/saland/GameMonsters.hpp b/src/saland/GameMonsters.hpp
new file mode 100644
index 0000000..c699027
--- /dev/null
+++ b/src/saland/GameMonsters.hpp
@@ -0,0 +1,31 @@
+/*
+===========================================================================
+ * Saland Adventures
+Copyright (C) 2014-2017 Poul Sander
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see http://www.gnu.org/licenses/
+
+Source information and contacts persons can be found at
+https://github.com/sago007/saland
+===========================================================================
+*/
+
+#ifndef GAMEMONSTERS_HPP
+#define GAMEMONSTERS_HPP
+
+#include "GameRegion.hpp"
+
+MonsterDef GetMonsterDefByRace(const std::string& race);
+
+#endif /* GAMEMONSTERS_HPP */
diff --git a/src/saland/GameRegion.cpp b/src/saland/GameRegion.cpp
index 5f4b9ce..6fec626 100644
--- a/src/saland/GameRegion.cpp
+++ b/src/saland/GameRegion.cpp
@@ -23,6 +23,7 @@ https://github.com/sago007/saland
#include "GameRegion.hpp"
#include "GameItems.hpp"
+#include "GameMonsters.hpp"
#include <cmath>
#include <random>
@@ -38,31 +39,31 @@ static std::string createFileName(int x, int y,const std::string& worldName) {
void GameRegion::SpawnMonster(const MonsterDef& def, float destX, float destY) {
- std::shared_ptr<Monster> bat = std::make_shared<Monster>();
- bat.get()->Radius = def.radius;
- bat.get()->race = def.race;
- bat.get()->X = destX;
- bat.get()->Y = destY;
- if (def.race == "bat") {
- bat.get()->health = 30;
- }
- placeables.push_back(bat);
-
- b2BodyDef batBodyDef;
- batBodyDef.type = b2_dynamicBody;
- batBodyDef.position.Set(0, 0);
- batBodyDef.linearDamping = 1.0f;
- bat->body = physicsBox->CreateBody(&batBodyDef);
+ std::shared_ptr<Monster> monster = std::make_shared<Monster>();
+ monster.get()->Radius = def.radius;
+ monster.get()->race = def.race;
+ monster.get()->X = destX;
+ monster.get()->Y = destY;
+ monster.get()->health = def.health;
+ monster.get()->speed = def.speed;
+ monster.get()->attack = def.attack;
+ placeables.push_back(monster);
+
+ b2BodyDef monsterBodyDef;
+ monsterBodyDef.type = b2_dynamicBody;
+ monsterBodyDef.position.Set(0, 0);
+ monsterBodyDef.linearDamping = 1.0f;
+ monster->body = physicsBox->CreateBody(&monsterBodyDef);
b2CircleShape circleShape;
circleShape.m_p.Set(0, 0); //position, relative to body position
circleShape.m_radius = def.radius/32.0f; //32 pixel = 1 unit
- b2FixtureDef batDef;
- batDef.shape = &circleShape;
- batDef.density = 10.0f;
- bat->body->CreateFixture(&batDef);
- bat->body->SetTransform(b2Vec2(bat.get()->X / 32.0f, bat.get()->Y / 32.0f),bat->body->GetAngle());
+ b2FixtureDef monsterFixtureDef;
+ monsterFixtureDef.shape = &circleShape;
+ monsterFixtureDef.density = 10.0f;
+ monster->body->CreateFixture(&monsterFixtureDef);
+ monster->body->SetTransform(b2Vec2(monster.get()->X / 32.0f, monster.get()->Y / 32.0f),monster->body->GetAngle());
}
static bool Intersect(const Placeable& p1, const Placeable& p2) {
@@ -371,13 +372,10 @@ void GameRegion::Init(int x, int y, const std::string& worldName, bool forceRese
SpawnPrefab(getPrefab("basic_house"), 32, 32);
- MonsterDef batDef;
- batDef.radius = 16.0f;
- batDef.race = "bat";
+ MonsterDef batDef = GetMonsterDefByRace("bat");
SpawnMonster(batDef, 200.0f, 200.0f);
SpawnMonster(batDef, 1200.0f, 1400.0f);
- MonsterDef beeDef = batDef;
- beeDef.race = "bee";
+ MonsterDef beeDef = GetMonsterDefByRace("bee");
SpawnMonster(beeDef, 220.0f, 220.0f);
}
diff --git a/src/saland/GameRegion.hpp b/src/saland/GameRegion.hpp
index 47ba584..0919617 100644
--- a/src/saland/GameRegion.hpp
+++ b/src/saland/GameRegion.hpp
@@ -35,6 +35,9 @@ https://github.com/sago007/saland
struct MonsterDef {
float radius = 1.0f;
std::string race = "";
+ float health = 30.0f;
+ float speed = 1.0f;
+ MonsterAttack attack;
};