FEATURE: entity.exempt.exit
[Tsunagari.git] / src / tile.cpp
blobd6189a36d78f4de042ad2b02d209fd6eb3689ec2
1 /*********************************
2 ** Tsunagari Tile Engine **
3 ** tile.cpp **
4 ** Copyright 2011-2012 OmegaSDG **
5 *********************************/
7 #include <stdlib.h> // for exit(1) on fatal
9 #include <boost/foreach.hpp>
10 #include <boost/format.hpp>
12 #include "area.h"
13 #include "python.h"
14 #include "python-optional.h"
15 #include "string.h"
16 #include "tile.h"
17 #include "window.h"
19 static int ivec2_to_dir(ivec2 v)
21 switch (v.x) {
22 case -1:
23 return v.y == 0 ? EXIT_LEFT : -1;
24 case 0:
25 switch (v.y) {
26 case -1:
27 return EXIT_UP;
28 case 0:
29 return EXIT_NORMAL;
30 case 1:
31 return EXIT_DOWN;
32 default:
33 return -1;
35 break;
36 case 1:
37 return v.y == 0 ? EXIT_RIGHT : -1;
38 default:
39 return -1;
43 static Exit pythonNewExit(std::string area, int x, int y, double z)
45 return Exit(area, x, y, z);
50 * FLAGMANIP
52 FlagManip::FlagManip(unsigned* flags)
53 : flags(flags)
57 bool FlagManip::isNowalk() const
59 return (*flags & TILE_NOWALK) != 0;
62 bool FlagManip::isNowalkPlayer() const
64 return (*flags & TILE_NOWALK_PLAYER) != 0;
67 bool FlagManip::isNowalkNPC() const
69 return (*flags & TILE_NOWALK_NPC) != 0;
72 bool FlagManip::isNowalkExit() const
74 return (*flags & TILE_NOWALK_EXIT) != 0;
77 bool FlagManip::isNowalkAreaBound() const
79 return (*flags & TILE_NOWALK_AREA_BOUND) != 0;
82 void FlagManip::setNowalk(bool nowalk)
84 *flags &= ~TILE_NOWALK;
85 *flags |= TILE_NOWALK * nowalk;
88 void FlagManip::setNowalkPlayer(bool nowalk)
90 *flags &= ~TILE_NOWALK_PLAYER;
91 *flags |= TILE_NOWALK_PLAYER * nowalk;
94 void FlagManip::setNowalkNPC(bool nowalk)
96 *flags &= ~TILE_NOWALK_NPC;
97 *flags |= TILE_NOWALK_NPC * nowalk;
100 void FlagManip::setNowalkExit(bool nowalk)
102 *flags &= ~TILE_NOWALK_EXIT;
103 *flags |= TILE_NOWALK_EXIT * nowalk;
106 void FlagManip::setNowalkAreaBound(bool nowalk)
108 *flags &= ~TILE_NOWALK_AREA_BOUND;
109 *flags |= TILE_NOWALK_AREA_BOUND * nowalk;
113 Exit::Exit()
117 Exit::Exit(const std::string area, int x, int y, double z)
118 : area(area), coords(x, y, z)
124 * TILEBASE
126 TileBase::TileBase()
127 : parent(NULL), flags(0x0)
131 FlagManip TileBase::flagManip()
133 return FlagManip(&flags);
136 bool TileBase::hasFlag(unsigned flag) const
138 return flags & flag || (parent && parent->hasFlag(flag));
141 TileType* TileBase::getType() const
143 return (TileType*)parent;
146 void TileBase::setType(TileType* type)
148 parent = type;
151 void TileBase::runEnterScript(Entity* triggeredBy)
153 runScript(triggeredBy, enterScript);
154 if (parent)
155 parent->runEnterScript(triggeredBy);
158 void TileBase::runLeaveScript(Entity* triggeredBy)
160 runScript(triggeredBy, leaveScript);
161 if (parent)
162 parent->runLeaveScript(triggeredBy);
165 void TileBase::runUseScript(Entity* triggeredBy)
167 runScript(triggeredBy, useScript);
168 if (parent)
169 parent->runUseScript(triggeredBy);
172 void TileBase::runScript(Entity* triggeredBy, ScriptInst& script)
174 pythonSetGlobal("Entity", triggeredBy);
175 pythonSetGlobal("Tile", this);
176 script.invoke();
181 * TILE
183 Tile::Tile()
184 : entCnt(0)
188 Tile::Tile(Area* area, int x, int y, int z)
189 : TileBase(), area(area), x(x), y(y), z(z), entCnt(0)
191 memset(exits, 0, sizeof(exits));
192 memset(layermods, 0, sizeof(layermods));
195 Tile* Tile::offset(int x, int y)
197 return area->getTile(this->x + x, this->y + y, z);
200 double Tile::getZ()
202 vicoord vi = area->phys2virt_vi(icoord(x, y, z));
203 return vi.z;
206 Exit* Tile::getNormalExit() const
208 return exits[EXIT_NORMAL];
211 void Tile::setNormalExit(Exit exit)
213 Exit** norm = &exits[EXIT_NORMAL];
214 if (*norm)
215 delete *norm;
216 *norm = new Exit(exit);
219 Exit* Tile::exitAt(ivec2 dir) const
221 int idx = ivec2_to_dir(dir);
222 return idx == -1 ? NULL : exits[idx];
225 boost::optional<double> Tile::layermodAt(ivec2 dir) const
227 int idx = ivec2_to_dir(dir);
228 return idx == -1 ? boost::optional<double>() : layermods[idx];
233 * TILETYPE
235 TileType::TileType()
236 : TileBase()
240 TileType::TileType(ImageRef& img)
241 : TileBase()
243 anim.addFrame(img);
246 bool TileType::needsRedraw() const
248 const int millis = GameWindow::instance().time();
249 return anim.needsRedraw(millis);
253 * TILESET
255 TileSet::TileSet()
259 TileSet::TileSet(int width, int height)
260 : width(width), height(height)
264 void TileSet::add(TileType* type)
266 types.push_back(type);
269 void TileSet::set(int idx, TileType* type)
271 types[idx] = type;
274 TileType* TileSet::get(int x, int y)
276 size_t i = idx(x, y);
277 if (i > types.size()) {
278 Log::err("TileSet", boost::str(boost::format(
279 "get(%d, %d): out of bounds") % x % y));
280 return NULL;
282 return types[i];
285 int TileSet::getWidth() const
287 return height;
290 int TileSet::getHeight() const
292 return width;
295 size_t TileSet::idx(int x, int y) const
297 return y * width + x;
302 * PYTHON
304 void exportTile()
306 using namespace boost::python;
308 class_<FlagManip> ("FlagManipulator", no_init)
309 .add_property("nowalk",
310 &FlagManip::isNowalk, &FlagManip::setNowalk)
311 .add_property("nowalk_player",
312 &FlagManip::isNowalkPlayer, &FlagManip::setNowalkPlayer)
313 .add_property("nowalk_npc",
314 &FlagManip::isNowalkNPC, &FlagManip::setNowalkNPC)
315 .add_property("nowalk_exit",
316 &FlagManip::isNowalkExit, &FlagManip::setNowalkExit)
317 .add_property("nowalk_area_bound",
318 &FlagManip::isNowalkAreaBound,
319 &FlagManip::setNowalkAreaBound)
321 class_<TileBase> ("TileBase", no_init)
322 .add_property("flag", &TileBase::flagManip)
323 .add_property("type",
324 make_function(
325 static_cast<TileType* (TileBase::*) () const>
326 (&TileBase::getType),
327 return_value_policy<reference_existing_object>()),
328 &TileBase::setType)
329 .def_readwrite("on_enter", &TileBase::enterScript)
330 .def_readwrite("on_leave", &TileBase::leaveScript)
331 .def_readwrite("on_use", &TileBase::useScript)
332 .def("run_enter_script", &TileBase::runEnterScript)
333 .def("run_leave_script", &TileBase::runLeaveScript)
334 .def("run_use_script", &TileBase::runUseScript)
336 class_<Tile, bases<TileBase> > ("Tile", no_init)
337 .def_readonly("area", &Tile::area)
338 .def_readonly("x", &Tile::x)
339 .def_readonly("y", &Tile::y)
340 .add_property("z", &Tile::getZ)
341 .add_property("exit",
342 make_function(
343 static_cast<Exit* (Tile::*) () const>
344 (&Tile::getNormalExit),
345 return_value_policy<reference_existing_object>()),
346 &Tile::setNormalExit)
347 .def_readonly("nentities", &Tile::entCnt)
348 .def("offset", &Tile::offset,
349 return_value_policy<reference_existing_object>())
351 class_<TileType, bases<TileBase> > ("TileType", no_init)
353 class_<TileSet> ("TileSet", no_init)
354 .add_property("width", &TileSet::getWidth)
355 .add_property("height", &TileSet::getHeight)
356 .def("at", &TileSet::get,
357 return_value_policy<reference_existing_object>())
359 class_<Exit> ("Exit", no_init)
360 .def_readwrite("area", &Exit::area)
361 .def_readwrite("coords", &Exit::coords)
363 pythonAddFunction("new_exit", pythonNewExit);