draw area borders black
[Tsunagari.git] / src / world.cpp
blob9f742651d7d4643cb456c3478961d80329b43dc2
1 /*********************************
2 ** Tsunagari Tile Engine **
3 ** world.cpp **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 #include <Gosu/Utility.hpp>
9 #include "area-tmx.h"
10 #include "common.h"
11 #include "log.h"
12 #include "python.h"
13 #include "resourcer.h"
14 #include "window.h"
15 #include "world.h"
16 #include "xml.h"
18 #define ASSERT(x) if (!(x)) return false
20 static World* globalWorld = NULL;
22 World* World::instance()
24 return globalWorld;
27 World::World()
28 : player(NULL)
30 globalWorld = this;
33 World::~World()
37 bool World::init()
39 if (!processDescriptor()) // Try to load in descriptor.
40 return false;
42 music.reset(new Music());
44 if (!player.init(playerentity))
45 return false;
46 player.setPhase("down");
48 if (onLoadScript.size()) {
49 pythonSetGlobal("player", (Entity*)&player);
50 Resourcer* rc = Resourcer::instance();
51 rc->runPythonScript(onLoadScript);
54 view = new Viewport(viewport);
55 view->trackEntity(&player);
57 AreaPtr area = getArea(entry.area);
58 if (!area)
59 return false;
60 focusArea(area, entry.coords);
61 return true;
64 void World::buttonDown(const Gosu::Button btn)
66 area->buttonDown(btn);
69 void World::buttonUp(const Gosu::Button btn)
71 area->buttonUp(btn);
74 void World::draw()
76 GameWindow& window = GameWindow::getWindow();
77 Gosu::Graphics& graphics = window.graphics();
79 // drawLetterbox(); // Superceeded by drawAreaBorders
80 drawAreaBorders();
81 graphics.pushTransform(getTransform());
82 area->draw();
83 graphics.popTransform();
86 bool World::needsRedraw() const
88 return area->needsRedraw();
91 void World::update(unsigned long dt)
93 // Prevent the Area from being deleted during this function call.
94 // Otherwise if it accesses its member variables and we've overwritten
95 // the memory, bad things happen.
96 boost::shared_ptr<Area> safe(area);
98 area->update(dt);
101 AreaPtr World::getArea(const std::string& filename, int flags)
103 if (conf.cacheEnabled && (flags & GETAREA_ALWAYS_CREATE) == false) {
104 AreaMap::iterator entry = areas.find(filename);
105 if (entry != areas.end())
106 return entry->second;
109 AreaPtr newArea(
110 new AreaTMX(view, &player, music.get(), filename)
113 if (!newArea->init())
114 newArea = AreaPtr();
115 if (conf.cacheEnabled)
116 areas[filename] = newArea;
117 return newArea;
120 AreaPtr World::getFocusedArea()
122 return area;
125 void World::focusArea(AreaPtr area, vicoord playerPos)
127 Log::info("World", area->getDescriptor() + ": focused");
128 this->area = area;
129 player.setArea(area.get());
130 player.setTileCoords(playerPos);
131 view->setArea(area.get());
132 area->focus();
135 std::string World::getAreaLoadScript()
137 return onAreaLoadScript;
140 bool World::processDescriptor()
142 XMLRef doc;
143 XMLNode root;
145 Resourcer* rc = Resourcer::instance();
146 ASSERT(doc = rc->getXMLDoc("world.conf", "world.dtd"));
147 ASSERT(root = doc->root()); // <world>
149 for (XMLNode child = root.childrenNode(); child; child = child.next()) {
150 if (child.is("info")) {
151 ASSERT(processInfo(child));
153 else if (child.is("init")) {
154 ASSERT(processInit(child));
156 else if (child.is("script")) {
157 ASSERT(processScript(child));
159 else if (child.is("input")) {
160 ASSERT(processInput(child));
164 return true;
167 bool World::processInfo(XMLNode node)
169 for (node = node.childrenNode(); node; node = node.next()) {
170 if (node.is("name")) {
171 name = node.content();
172 GameWindow::getWindow().setCaption(Gosu::widen(name));
173 } else if (node.is("author")) {
174 author = node.content();
175 } else if (node.is("version")) {
176 version = atof(node.content().c_str());
179 return true;
182 bool World::processInit(XMLNode node)
184 for (node = node.childrenNode(); node; node = node.next()) {
185 if (node.is("area")) {
186 entry.area = node.content();
188 else if (node.is("player")) {
189 playerentity = node.content();
191 else if (node.is("mode")) {
192 std::string str = node.content();
193 if (str == "turn")
194 conf.moveMode = TURN;
195 else if (str == "tile")
196 conf.moveMode = TILE;
197 else if (str == "notile")
198 conf.moveMode = NOTILE;
200 else if (node.is("coords")) {
201 if (!node.intAttr("x", &entry.coords.x) ||
202 !node.intAttr("y", &entry.coords.y) ||
203 !node.doubleAttr("z", &entry.coords.z))
204 return false;
206 else if (node.is("viewport")) {
207 if (!node.intAttr("width", &viewport.x) ||
208 !node.intAttr("height", &viewport.y))
209 return false;
212 return true;
215 bool World::processScript(XMLNode node)
217 for (node = node.childrenNode(); node; node = node.next()) {
218 if (node.is("onInit")) {
219 std::string filename = node.content();
220 if (rc->resourceExists(filename)) {
221 onLoadScript = filename;
223 else {
224 Log::err("world.conf",
225 std::string("script not found: ") + filename);
226 return false;
228 } else if (node.is("onAreaInit")) {
229 std::string filename = node.content();
230 if (rc->resourceExists(filename)) {
231 onAreaLoadScript = filename;
233 else {
234 Log::err("world.conf",
235 std::string("script not found: ") + filename);
236 return false;
240 return true;
243 bool World::processInput(XMLNode node)
245 for (node = node.childrenNode(); node; node = node.next()) {
246 if (node.is("persist")) {
247 if (!node.intAttr("init", &conf.persistInit) ||
248 !node.intAttr("cons", &conf.persistCons))
249 return false;
252 return true;
256 void World::drawLetterbox()
258 rvec2 sz = view->getPhysRes();
259 rvec2 lb = rvec2(0.0, 0.0);
260 lb -= view->getLetterboxOffset();
261 Gosu::Color black = Gosu::Color::BLACK;
263 drawRect(0, sz.x, 0, lb.y, black, 1000);
264 drawRect(0, sz.x, sz.y - lb.y, sz.y, black, 1000);
265 drawRect(0, lb.x, 0, sz.y, black, 1000);
266 drawRect(sz.x - lb.x, sz.x, 0, sz.y, black, 1000);
270 void World::drawAreaBorders()
272 Gosu::Color black = Gosu::Color::BLACK;
273 rvec2 sz = view->getPhysRes();
274 rvec2 scale = view->getScale();
275 rvec2 virtScroll = view->getMapOffset();
276 rvec2 padding = view->getLetterboxOffset();
278 rvec2 physScroll = virtScroll;
279 physScroll *= scale;
280 physScroll += padding;
281 physScroll *= -1;
283 bool loopX = area->loopsInX();
284 bool loopY = area->loopsInY();
286 if (!loopX && physScroll.x > 0) {
287 // Boxes on left-right.
288 drawRect(0, physScroll.x, 0, sz.y, black, 1000);
289 drawRect(sz.x - physScroll.x, sz.x, 0, sz.y, black, 1000);
291 if (!loopY && physScroll.y > 0) {
292 // Boxes on top-bottom.
293 drawRect(0, sz.x, 0, physScroll.y, black, 1000);
294 drawRect(0, sz.x, sz.y - physScroll.y, sz.y, black, 1000);
298 void World::drawRect(double x1, double x2, double y1, double y2,
299 Gosu::Color c, double z)
301 GameWindow& window = GameWindow::getWindow();
302 window.graphics().drawQuad(
303 x1, y1, c,
304 x2, y1, c,
305 x2, y2, c,
306 x1, y2, c,
311 Gosu::Transform World::getTransform()
313 rvec2 scale = view->getScale();
314 rvec2 scroll = view->getMapOffset();
315 rvec2 padding = view->getLetterboxOffset();
316 Gosu::Transform t = { {
317 scale.x, 0, 0, 0,
318 0, scale.y, 0, 0,
319 0, 0, 1, 0,
320 scale.x * -scroll.x - padding.x,
321 scale.y * -scroll.y - padding.y, 0, 1
322 } };
323 return t;