aboutsummaryrefslogtreecommitdiff
path: root/frontend/load_dungeon.cpp
blob: b19b5413f86b7b99e03e98890d631d43f4d23b80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <memory>
#include <filesystem>
#include <pugixml.hpp>
#include <map>

#include "backend/Location.h"
#include "backend/LocationFactory.h"
#include "backend/Exception.h"
#include "backend/Dungeon.h"

#include "load_dungeon.h"
#include "GameData.h"
#include "backend/Object.h"
#include "strings.h"

using namespace std;
using namespace pugi;

unique_ptr<Dungeon> load_dungeon(const string & filename) {
	unique_ptr<Dungeon> dungeon = make_unique<Dungeon>();

	xml_document doc;

	string canonical = filename;
	if (canonical.starts_with("~/"))
		canonical = getenv("HOME") + canonical.substr(1);
	try {
		canonical = filesystem::canonical(canonical);
	} catch (...) {
		throw Exception("kon bestand niet vinden (%s)", filename.c_str());
	}

	xml_parse_result result = doc.load_file(canonical.c_str(), parse_default, encoding_latin1);
	if (!result)
		throw Exception("kon XML-bestand niet lezen");

	xml_node locations = doc.child("locaties");
	if (!locations)
		throw Exception("XML-bestand mist een <locaties> tag");

	GameData & gamedata = GameData::get_instance();

	struct TempData {
		Location * location;
		unsigned edges[4];
	};
	map<unsigned, TempData> temp_map;

	for (xml_node & tag : locations) {
		Location * location = LocationFactory::create_location(
			tag.text().as_string(),
			tag.child("beschrijving").text().as_string()
		);

		vector<string> objects_hidden = str_split(tag.attribute("objectenverborgen").as_string(), ";");
		for (string & name : objects_hidden) {
			Object * object = gamedata.create_object(name);
			location->add_hidden_object(object);
		}
		vector<string> objects_visible = str_split(tag.attribute("objectenzichtbaar").as_string(), ";");
		for (string & name : objects_visible) {
			Object * object = gamedata.create_object(name);
			location->add_visible_object(object);
		}

		vector<string> enemies = str_split(tag.attribute("vijand").as_string(), ";");
		for (string & name : enemies) {
			Enemy * enemy = gamedata.create_enemy(name);
			location->add_enemy(enemy);
		}

		temp_map[tag.attribute("id").as_uint()] = {
			.location = location,
			.edges = {
				[Direction::NORTH] = tag.attribute("noord").as_uint(0),
				[Direction::EAST]  = tag.attribute("oost").as_uint(0),
				[Direction::SOUTH] = tag.attribute("zuid").as_uint(0),
				[Direction::WEST]  = tag.attribute("west").as_uint(0),
			},
		};
		dungeon->add_location(location);
	}

	// connect edges after creating all locations
	for (auto & [_, temp] : temp_map) {
		for (Direction direction : DIRECTIONS) {
			unsigned id = temp.edges[direction];
			if (temp.edges[direction] == 0) continue;
			if (!temp_map.contains(id)) continue;
			temp.location->set_exit(direction, temp_map[id].location);
		}
	}

	return dungeon;
}