1 /*********************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 #include <Gosu/Utility.hpp>
13 #include "resourcer.h"
18 #define ASSERT(x) if (!(x)) return false
20 static World
* globalWorld
= NULL
;
22 World
* World::instance()
39 if (!processDescriptor()) // Try to load in descriptor.
42 music
.reset(new Music());
44 if (!player
.init(playerentity
))
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
);
60 focusArea(area
, entry
.coords
);
64 void World::buttonDown(const Gosu::Button btn
)
66 area
->buttonDown(btn
);
69 void World::buttonUp(const Gosu::Button btn
)
76 GameWindow
& window
= GameWindow::getWindow();
77 Gosu::Graphics
& graphics
= window
.graphics();
79 // drawLetterbox(); // Superceeded by drawAreaBorders
81 graphics
.pushTransform(getTransform());
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
);
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
;
110 new AreaTMX(view
, &player
, music
.get(), filename
)
113 if (!newArea
->init())
115 if (conf
.cacheEnabled
)
116 areas
[filename
] = newArea
;
120 AreaPtr
World::getFocusedArea()
125 void World::focusArea(AreaPtr area
, vicoord playerPos
)
127 Log::info("World", area
->getDescriptor() + ": focused");
129 player
.setArea(area
.get());
130 player
.setTileCoords(playerPos
);
131 view
->setArea(area
.get());
135 std::string
World::getAreaLoadScript()
137 return onAreaLoadScript
;
140 bool World::processDescriptor()
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
));
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());
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();
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
))
206 else if (node
.is("viewport")) {
207 if (!node
.intAttr("width", &viewport
.x
) ||
208 !node
.intAttr("height", &viewport
.y
))
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
;
224 Log::err("world.conf",
225 std::string("script not found: ") + filename
);
228 } else if (node
.is("onAreaInit")) {
229 std::string filename
= node
.content();
230 if (rc
->resourceExists(filename
)) {
231 onAreaLoadScript
= filename
;
234 Log::err("world.conf",
235 std::string("script not found: ") + filename
);
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
))
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
;
280 physScroll
+= padding
;
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(
311 Gosu::Transform
World::getTransform()
313 rvec2 scale
= view
->getScale();
314 rvec2 scroll
= view
->getMapOffset();
315 rvec2 padding
= view
->getLetterboxOffset();
316 Gosu::Transform t
= { {
320 scale
.x
* -scroll
.x
- padding
.x
,
321 scale
.y
* -scroll
.y
- padding
.y
, 0, 1