1 /*********************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
11 #include <boost/foreach.hpp>
12 #include <boost/shared_ptr.hpp>
13 #include <Gosu/Graphics.hpp>
14 #include <Gosu/Image.hpp>
15 #include <Gosu/Math.hpp>
16 #include <Gosu/Timing.hpp>
23 #include "resourcer.h"
28 #define ASSERT(x) if (!(x)) return false
30 /* NOTE: In the TMX map format used by Tiled, tileset tiles start counting
31 their Y-positions from 0, while layer tiles start counting from 1. I
32 can't imagine why the author did this, but we have to take it into
37 static T
wrap(T min
, T value
, T max
)
44 Area::Area(Viewport
* view
,
47 const std::string
& descriptor
)
51 colorOverlay(0, 0, 0, 0),
54 loopX(false), loopY(false),
57 descriptor(descriptor
)
78 music
->setIntro(musicIntro
);
79 music
->setLoop(musicLoop
);
81 if (onFocusScripts
.size()) {
82 BOOST_FOREACH(const std::string
& script
, onFocusScripts
) {
83 pythonSetGlobal("Area", this);
84 Resourcer
* rc
= Resourcer::instance();
85 rc
->runPythonScript(script
);
90 void Area::buttonDown(const Gosu::Button btn
)
92 if (btn
== Gosu::kbRight
)
93 player
->startMovement(ivec2(1, 0));
94 else if (btn
== Gosu::kbLeft
)
95 player
->startMovement(ivec2(-1, 0));
96 else if (btn
== Gosu::kbUp
)
97 player
->startMovement(ivec2(0, -1));
98 else if (btn
== Gosu::kbDown
)
99 player
->startMovement(ivec2(0, 1));
100 else if (btn
== Gosu::kbSpace
)
104 void Area::buttonUp(const Gosu::Button btn
)
106 if (btn
== Gosu::kbRight
)
107 player
->stopMovement(ivec2(1, 0));
108 else if (btn
== Gosu::kbLeft
)
109 player
->stopMovement(ivec2(-1, 0));
110 else if (btn
== Gosu::kbUp
)
111 player
->stopMovement(ivec2(0, -1));
112 else if (btn
== Gosu::kbDown
)
113 player
->stopMovement(ivec2(0, 1));
118 updateTileAnimations();
125 bool Area::needsRedraw() const
129 if (player
->needsRedraw())
132 // Do any on-screen tile types need to update their animations?
133 const icube tiles
= visibleTiles();
134 for (int z
= tiles
.z1
; z
< tiles
.z2
; z
++) {
135 for (int y
= tiles
.y1
; y
< tiles
.y2
; y
++) {
136 for (int x
= tiles
.x1
; x
< tiles
.x2
; x
++) {
137 const Tile
& tile
= getTile(x
, y
, z
);
138 const TileType
* type
= tile
.getType();
139 if (type
&& type
->needsRedraw())
147 void Area::requestRedraw()
152 void Area::update(unsigned long dt
)
154 pythonSetGlobal("Area", this);
157 if (onUpdateScripts
.size()) {
158 BOOST_FOREACH(const std::string
& script
, onUpdateScripts
) {
159 pythonSetGlobal("Area", this);
160 Resourcer
* rc
= Resourcer::instance();
161 rc
->runPythonScript(script
);
169 AreaPtr
Area::reset()
171 World
* world
= World::instance();
172 AreaPtr newSelf
= world
->getArea(descriptor
, GETAREA_ALWAYS_CREATE
);
173 if (world
->getFocusedArea().get() == this) {
174 vicoord c
= player
->getTileCoords_vi();
175 world
->focusArea(newSelf
, c
);
180 void Area::setColorOverlay(int r
, int g
, int b
, int a
)
182 using namespace Gosu
;
184 if (0 <= r
&& r
< 256 &&
188 Color::Channel ac
= (Color::Channel
)a
;
189 Color::Channel rc
= (Color::Channel
)r
;
190 Color::Channel gc
= (Color::Channel
)g
;
191 Color::Channel bc
= (Color::Channel
)b
;
192 colorOverlay
= Color(ac
, rc
, gc
, bc
);
196 PyErr_Format(PyExc_ValueError
,
197 "Area::color_overlay() arguments must be "
198 "between 0 and 255");
204 const Tile
& Area::getTile(int x
, int y
, int z
) const
207 x
= wrap(0, x
, dim
.x
);
209 y
= wrap(0, y
, dim
.y
);
213 const Tile
& Area::getTile(int x
, int y
, double z
) const
215 return getTile(x
, y
, depthIndex(z
));
218 const Tile
& Area::getTile(icoord phys
) const
220 return getTile(phys
.x
, phys
.y
, phys
.z
);
223 const Tile
& Area::getTile(vicoord virt
) const
225 return getTile(virt2phys(virt
));
228 Tile
& Area::getTile(int x
, int y
, int z
)
231 x
= wrap(0, x
, dim
.x
);
233 y
= wrap(0, y
, dim
.y
);
237 Tile
& Area::getTile(int x
, int y
, double z
)
239 return getTile(x
, y
, depthIndex(z
));
242 Tile
& Area::getTile(icoord phys
)
244 return getTile(phys
.x
, phys
.y
, phys
.z
);
247 Tile
& Area::getTile(vicoord virt
)
249 return getTile(virt2phys(virt
));
252 TileType
& Area::getTileType(int idx
)
254 return tileTypes
[idx
];
259 ivec3
Area::getDimensions() const
264 ivec2
Area::getTileDimensions() const
269 icube
Area::visibleTileBounds() const
271 rvec2 screen
= view
->getVirtRes();
272 rvec2 off
= view
->getMapOffset();
274 int x1
= (int)floor(off
.x
/ tileDim
.x
);
275 int y1
= (int)floor(off
.y
/ tileDim
.y
);
276 int x2
= (int)ceil((screen
.x
+ off
.x
) / tileDim
.x
);
277 int y2
= (int)ceil((screen
.y
+ off
.y
) / tileDim
.y
);
279 return icube(x1
, y1
, 0, x2
, y2
, dim
.z
);
282 icube
Area::visibleTiles() const
284 icube cube
= visibleTileBounds();
286 cube
.x1
= std::max(cube
.x1
, 0);
287 cube
.x2
= std::min(cube
.x2
, dim
.x
);
290 cube
.y1
= std::max(cube
.y1
, 0);
291 cube
.y2
= std::min(cube
.y2
, dim
.y
);
296 bool Area::inBounds(int x
, int y
, int z
) const
298 return ((loopX
|| (0 <= x
&& x
< dim
.x
)) &&
299 (loopY
|| (0 <= y
&& y
< dim
.y
)) &&
300 0 <= z
&& z
< dim
.z
);
303 bool Area::inBounds(int x
, int y
, double z
) const
305 return inBounds(x
, y
, depthIndex(z
));
308 bool Area::inBounds(icoord phys
) const
310 return inBounds(phys
.x
, phys
.y
, phys
.z
);
313 bool Area::inBounds(vicoord virt
) const
315 return inBounds(virt2phys(virt
));
320 bool Area::loopsInX() const
325 bool Area::loopsInY() const
330 const std::string
Area::getDescriptor() const
337 vicoord
Area::phys2virt_vi(icoord phys
) const
339 return vicoord(phys
.x
, phys
.y
, indexDepth(phys
.z
));
342 rcoord
Area::phys2virt_r(icoord phys
) const
345 (double)phys
.x
* tileDim
.x
,
346 (double)phys
.y
* tileDim
.y
,
351 icoord
Area::virt2phys(vicoord virt
) const
353 return icoord(virt
.x
, virt
.y
, depthIndex(virt
.z
));
356 icoord
Area::virt2phys(rcoord virt
) const
359 (int)(virt
.x
/ tileDim
.x
),
360 (int)(virt
.y
/ tileDim
.y
),
365 rcoord
Area::virt2virt(vicoord virt
) const
368 (double)virt
.x
* tileDim
.x
,
369 (double)virt
.y
* tileDim
.y
,
374 vicoord
Area::virt2virt(rcoord virt
) const
377 (int)virt
.x
/ tileDim
.x
,
378 (int)virt
.y
/ tileDim
.y
,
384 int Area::depthIndex(double depth
) const
386 return depth2idx
.find(depth
)->second
;
389 double Area::indexDepth(int idx
) const
391 return idx2depth
[idx
];
396 void Area::runOnLoads()
398 Resourcer
* rc
= Resourcer::instance();
399 World
* world
= World::instance();
400 std::string onAreaLoadScript
= world
->getAreaLoadScript();
401 if (onAreaLoadScript
.size()) {
402 pythonSetGlobal("Area", this);
403 rc
->runPythonScript(onAreaLoadScript
);
405 BOOST_FOREACH(const std::string
& script
, onLoadScripts
) {
406 pythonSetGlobal("Area", this);
407 rc
->runPythonScript(script
);
411 void Area::updateTileAnimations()
413 const int millis
= GameWindow::instance().time();
414 BOOST_FOREACH(TileType
& type
, tileTypes
)
415 type
.anim
.updateFrame(millis
);
418 void Area::drawTiles() const
420 const icube tiles
= visibleTiles();
421 for (int z
= tiles
.z1
; z
< tiles
.z2
; z
++) {
422 double depth
= idx2depth
[z
];
423 for (int y
= tiles
.y1
; y
< tiles
.y2
; y
++) {
424 for (int x
= tiles
.x1
; x
< tiles
.x2
; x
++) {
425 const Tile
& tile
= getTile(x
, y
, z
);
426 drawTile(tile
, x
, y
, depth
);
432 void Area::drawTile(const Tile
& tile
, int x
, int y
, double depth
) const
434 const TileType
* type
= (TileType
*)tile
.parent
;
436 const Gosu::Image
* img
= type
->anim
.frame();
438 img
->draw((double)x
*img
->width(),
439 (double)y
*img
->height(), depth
);
443 void Area::drawEntities()
448 void Area::drawColorOverlay()
450 if (colorOverlay
.alpha() != 0) {
451 GameWindow
& window
= GameWindow::instance();
452 Gosu::Color c
= colorOverlay
;
453 int x
= window
.width();
454 int y
= window
.height();
455 window
.graphics().drawQuad(
465 boost::python::tuple
Area::pyGetDimensions()
467 using namespace boost::python
;
470 BOOST_FOREACH(double dep
, idx2depth
)
472 return make_tuple(dim
.x
, dim
.y
, zs
);
477 using namespace boost::python
;
479 class_
<Area
>("Area", no_init
)
480 .add_property("descriptor", &Area::getDescriptor
)
481 .add_property("dimensions", &Area::pyGetDimensions
)
482 .def("redraw", &Area::requestRedraw
)
484 static_cast<Tile
& (Area::*) (int, int, double)>
486 return_value_policy
<reference_existing_object
>())
488 static_cast<bool (Area::*) (int, int, double) const>
490 .def("get_tile_type", &Area::getTileType
,
491 return_value_policy
<reference_existing_object
>())
492 .def("reset", &Area::reset
)
493 .def("color_overlay", &Area::setColorOverlay
)