1 /*********************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 #include <Gosu/Utility.hpp>
13 #include "resourcer.h"
19 #define ASSERT(x) if (!(x)) return false
21 static World
* globalWorld
= NULL
;
23 World
* World::instance()
32 pythonSetGlobal("World", this);
41 if (!processDescriptor()) // Try to load in descriptor.
44 music
.reset(new Music());
46 if (!player
.init(playerentity
))
48 player
.setPhase("down");
50 if (onLoadScript
.size()) {
51 pythonSetGlobal("Player", (Entity
*)&player
);
52 Resourcer
* rc
= Resourcer::instance();
53 rc
->runPythonScript(onLoadScript
);
56 view
= new Viewport(viewport
);
57 view
->trackEntity(&player
);
59 Area
* area
= getArea(entry
.area
);
62 focusArea(area
, entry
.coords
);
66 void World::buttonDown(const Gosu::Button btn
)
68 area
->buttonDown(btn
);
71 void World::buttonUp(const Gosu::Button btn
)
78 GameWindow
& window
= GameWindow::instance();
79 Gosu::Graphics
& graphics
= window
.graphics();
83 graphics
.pushTransform(getTransform());
85 graphics
.popTransform();
88 bool World::needsRedraw() const
90 return area
->needsRedraw();
93 void World::update(unsigned long dt
)
99 Area
* World::getArea(const std::string
& filename
)
101 AreaMap::iterator entry
= areas
.find(filename
);
102 if (entry
!= areas
.end())
103 return entry
->second
;
105 Area
* newArea
= new AreaTMX(view
, &player
, music
.get(), filename
);
107 if (!newArea
->init())
109 areas
[filename
] = newArea
;
113 Area
* World::getFocusedArea()
118 void World::focusArea(Area
* area
, int x
, int y
, double z
)
120 focusArea(area
, vicoord(x
, y
, z
));
123 void World::focusArea(Area
* area
, vicoord playerPos
)
125 // Log::info("World", area->getDescriptor() + ": focused");
127 player
.setArea(area
);
128 player
.setTileCoords(playerPos
);
133 std::string
World::getAreaLoadScript()
135 return onAreaLoadScript
;
138 bool World::processDescriptor()
143 Resourcer
* rc
= Resourcer::instance();
144 ASSERT(doc
= rc
->getXMLDoc("world.conf", "world.dtd"));
145 ASSERT(root
= doc
->root()); // <world>
147 for (XMLNode child
= root
.childrenNode(); child
; child
= child
.next()) {
148 if (child
.is("info")) {
149 ASSERT(processInfo(child
));
151 else if (child
.is("init")) {
152 ASSERT(processInit(child
));
154 else if (child
.is("script")) {
155 ASSERT(processScript(child
));
157 else if (child
.is("input")) {
158 ASSERT(processInput(child
));
165 bool World::processInfo(XMLNode node
)
167 for (node
= node
.childrenNode(); node
; node
= node
.next()) {
168 if (node
.is("name")) {
169 name
= node
.content();
170 GameWindow::instance().setCaption(Gosu::widen(name
));
171 } else if (node
.is("author")) {
172 author
= node
.content();
173 } else if (node
.is("version")) {
174 version
= atof(node
.content().c_str());
180 bool World::processInit(XMLNode node
)
182 for (node
= node
.childrenNode(); node
; node
= node
.next()) {
183 if (node
.is("area")) {
184 entry
.area
= node
.content();
186 else if (node
.is("player")) {
187 playerentity
= node
.content();
189 else if (node
.is("mode")) {
190 std::string str
= node
.content();
192 conf
.moveMode
= TURN
;
193 else if (str
== "tile")
194 conf
.moveMode
= TILE
;
195 else if (str
== "notile")
196 conf
.moveMode
= NOTILE
;
198 else if (node
.is("coords")) {
199 if (!node
.intAttr("x", &entry
.coords
.x
) ||
200 !node
.intAttr("y", &entry
.coords
.y
) ||
201 !node
.doubleAttr("z", &entry
.coords
.z
))
204 else if (node
.is("viewport")) {
205 if (!node
.intAttr("width", &viewport
.x
) ||
206 !node
.intAttr("height", &viewport
.y
))
213 bool World::processScript(XMLNode node
)
215 for (node
= node
.childrenNode(); node
; node
= node
.next()) {
216 if (node
.is("on_init")) {
217 std::string filename
= node
.content();
218 if (rc
->resourceExists(filename
)) {
219 onLoadScript
= filename
;
222 Log::err("world.conf",
223 std::string("script not found: ") + filename
);
226 } else if (node
.is("on_area_init")) {
227 std::string filename
= node
.content();
228 if (rc
->resourceExists(filename
)) {
229 onAreaLoadScript
= filename
;
232 Log::err("world.conf",
233 std::string("script not found: ") + filename
);
241 bool World::processInput(XMLNode node
)
243 for (node
= node
.childrenNode(); node
; node
= node
.next()) {
244 if (node
.is("persist")) {
245 if (!node
.intAttr("init", &conf
.persistInit
) ||
246 !node
.intAttr("cons", &conf
.persistCons
))
253 void World::drawLetterbox()
255 rvec2 sz
= view
->getPhysRes();
256 rvec2 lb
= rvec2(0.0, 0.0);
257 lb
-= view
->getLetterboxOffset();
258 Gosu::Color black
= Gosu::Color::BLACK
;
260 drawRect(0, sz
.x
, 0, lb
.y
, black
, 1000);
261 drawRect(0, sz
.x
, sz
.y
- lb
.y
, sz
.y
, black
, 1000);
262 drawRect(0, lb
.x
, 0, sz
.y
, black
, 1000);
263 drawRect(sz
.x
- lb
.x
, sz
.x
, 0, sz
.y
, black
, 1000);
266 void World::drawAreaBorders()
268 Gosu::Color black
= Gosu::Color::BLACK
;
269 rvec2 sz
= view
->getPhysRes();
270 rvec2 scale
= view
->getScale();
271 rvec2 virtScroll
= view
->getMapOffset();
272 rvec2 padding
= view
->getLetterboxOffset();
274 rvec2 physScroll
= virtScroll
;
276 physScroll
+= padding
;
279 bool loopX
= area
->loopsInX();
280 bool loopY
= area
->loopsInY();
282 if (!loopX
&& physScroll
.x
> 0) {
283 // Boxes on left-right.
284 drawRect(0, physScroll
.x
, 0, sz
.y
, black
, 500);
285 drawRect(sz
.x
- physScroll
.x
, sz
.x
, 0, sz
.y
, black
, 500);
287 if (!loopY
&& physScroll
.y
> 0) {
288 // Boxes on top-bottom.
289 drawRect(0, sz
.x
, 0, physScroll
.y
, black
, 500);
290 drawRect(0, sz
.x
, sz
.y
- physScroll
.y
, sz
.y
, black
, 500);
294 void World::drawRect(double x1
, double x2
, double y1
, double y2
,
295 Gosu::Color c
, double z
)
297 GameWindow
& window
= GameWindow::instance();
298 window
.graphics().drawQuad(
307 Gosu::Transform
World::getTransform()
309 rvec2 scale
= view
->getScale();
310 rvec2 scroll
= view
->getMapOffset();
311 rvec2 padding
= view
->getLetterboxOffset();
312 Gosu::Transform t
= { {
316 scale
.x
* -scroll
.x
- padding
.x
,
317 scale
.y
* -scroll
.y
- padding
.y
, 0, 1
324 using namespace boost::python
;
326 class_
<World
> ("World", no_init
)
327 .def("area", &World::getArea
,
328 return_value_policy
<reference_existing_object
>())
330 static_cast<void (World::*) (Area
*,int,int,double)>