fix: more consistent trigger naming
[Tsunagari.git] / src / tile.cpp
blob32bbabe1ec07dff1cb55de99f77f6faa4184f7cf
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>
11 #include "area.h"
12 #include "python.h"
13 #include "python-optional.h"
14 #include "string.h"
15 #include "tile.h"
16 #include "window.h"
18 static int ivec2_to_dir(ivec2 v)
20 switch (v.x) {
21 case -1:
22 return v.y == 0 ? EXIT_LEFT : -1;
23 case 0:
24 switch (v.y) {
25 case -1:
26 return EXIT_UP;
27 case 0:
28 return EXIT_NORMAL;
29 case 1:
30 return EXIT_DOWN;
31 default:
32 return -1;
34 break;
35 case 1:
36 return v.y == 0 ? EXIT_RIGHT : -1;
37 default:
38 return -1;
42 static Exit pythonNewExit(std::string area, int x, int y, double z)
44 return Exit(area, x, y, z);
49 * FLAGMANIP
51 FlagManip::FlagManip(unsigned* flags)
52 : flags(flags)
56 bool FlagManip::isNowalk() const
58 return (*flags & TILE_NOWALK) != 0;
61 bool FlagManip::isNowalkPlayer() const
63 return (*flags & TILE_NOWALK_PLAYER) != 0;
66 bool FlagManip::isNowalkNPC() const
68 return (*flags & TILE_NOWALK_NPC) != 0;
71 void FlagManip::setNowalk(bool nowalk)
73 *flags = (*flags & ~TILE_NOWALK) | TILE_NOWALK * nowalk;
76 void FlagManip::setNowalkPlayer(bool nowalk)
78 *flags = (*flags & ~TILE_NOWALK_PLAYER) | TILE_NOWALK_PLAYER * nowalk;
81 void FlagManip::setNowalkNPC(bool nowalk)
83 *flags = (*flags & ~TILE_NOWALK_NPC) | TILE_NOWALK_NPC * nowalk;
87 Exit::Exit()
91 Exit::Exit(const std::string area, int x, int y, double z)
92 : area(area), coords(x, y, z)
98 * TILEBASE
100 TileBase::TileBase()
101 : parent(NULL), flags(0x0)
105 bool TileBase::hasFlag(unsigned flag) const
107 return flags & flag || (parent && parent->hasFlag(flag));
110 FlagManip TileBase::flagManip()
112 return FlagManip(&flags);
115 TileType* TileBase::getType() const
117 return (TileType*)parent;
120 void TileBase::setType(TileType* type)
122 parent = type;
125 void TileBase::onEnterScripts(Entity* triggeredBy)
127 runScripts(triggeredBy, onEnter);
128 if (parent)
129 parent->onEnterScripts(triggeredBy);
132 void TileBase::onLeaveScripts(Entity* triggeredBy)
134 runScripts(triggeredBy, onLeave);
135 if (parent)
136 parent->onLeaveScripts(triggeredBy);
139 void TileBase::onUseScripts(Entity* triggeredBy)
141 runScripts(triggeredBy, onUse);
142 if (parent)
143 parent->onUseScripts(triggeredBy);
146 void TileBase::runScripts(Entity* triggeredBy,
147 const std::vector<std::string>& events)
149 BOOST_FOREACH(const std::string& script, events) {
150 Resourcer* rc = Resourcer::instance();
151 pythonSetGlobal("Entity", triggeredBy);
152 pythonSetGlobal("Tile", this);
153 rc->runPythonScript(script);
159 * TILE
161 Tile::Tile()
165 Tile::Tile(Area* area, int x, int y, int z)
166 : TileBase(), area(area), x(x), y(y), z(z)
168 memset(exits, 0, sizeof(exits));
169 memset(layermods, 0, sizeof(layermods));
172 Tile& Tile::offset(int x, int y)
174 return area->getTile(this->x + x, this->y + y, z);
177 double Tile::getZ()
179 vicoord vi = area->phys2virt_vi(icoord(x, y, z));
180 return vi.z;
183 Exit* Tile::getNormalExit() const
185 return exits[EXIT_NORMAL];
188 void Tile::setNormalExit(Exit exit)
190 Exit** norm = &exits[EXIT_NORMAL];
191 if (*norm)
192 delete *norm;
193 *norm = new Exit(exit);
196 Exit* Tile::exitAt(ivec2 dir) const
198 int idx = ivec2_to_dir(dir);
199 return idx == -1 ? NULL : exits[idx];
202 boost::optional<double> Tile::layermodAt(ivec2 dir) const
204 int idx = ivec2_to_dir(dir);
205 return idx == -1 ? boost::optional<double>() : layermods[idx];
210 * TILETYPE
212 TileType::TileType()
213 : TileBase()
217 TileType::TileType(ImageRef& img)
218 : TileBase()
220 anim.addFrame(img);
223 bool TileType::needsRedraw() const
225 const int millis = GameWindow::instance().time();
226 return anim.needsRedraw(millis);
230 * TILESET
232 TileSet::TileSet()
236 TileSet::TileSet(int width, int height)
237 : width(width), height(height)
241 void TileSet::add(TileType* type)
243 types.push_back(type);
246 void TileSet::set(int idx, TileType* type)
248 types[idx] = type;
251 TileType& TileSet::get(int x, int y)
253 size_t i = idx(x, y);
254 if (i > types.size()) {
255 Log::fatal("TileSet", "index " + itostr((int)i) + " out of bounds");
256 exit(1);
258 return *types[i];
261 int TileSet::getWidth() const
263 return height;
266 int TileSet::getHeight() const
268 return width;
271 TileType& TileSet::pyGet(int x, int y)
273 size_t i = idx(x, y);
274 if (i > types.size()) {
275 PyErr_SetString(PyExc_IndexError,
276 "TileSet::at(): x, y index out of range");
277 boost::python::throw_error_already_set();
279 return *types[i];
282 size_t TileSet::idx(int x, int y) const
284 return y * width + x;
289 * PYTHON
291 void exportTile()
293 using namespace boost::python;
295 class_<FlagManip> ("FlagManipulator", no_init)
296 .add_property("nowalk",
297 &FlagManip::isNowalk, &FlagManip::setNowalk)
298 .add_property("nowalk_player",
299 &FlagManip::isNowalkPlayer, &FlagManip::setNowalkPlayer)
300 .add_property("nowalk_npc",
301 &FlagManip::isNowalkNPC, &FlagManip::setNowalkNPC)
303 class_<TileBase> ("TileBase", no_init)
304 .add_property("flag", &TileBase::flagManip)
305 .add_property("type",
306 make_function(
307 static_cast<TileType* (TileBase::*) () const>
308 (&TileBase::getType),
309 return_value_policy<reference_existing_object>()),
310 &TileBase::setType)
311 .def("run_enter_scripts", &TileBase::onEnterScripts)
312 .def("run_leave_scripts", &TileBase::onLeaveScripts)
313 .def("run_use_scripts", &TileBase::onUseScripts)
315 class_<Tile, bases<TileBase> > ("Tile", no_init)
316 .def_readonly("area", &Tile::area)
317 .def_readonly("x", &Tile::x)
318 .def_readonly("y", &Tile::y)
319 .add_property("z", &Tile::getZ)
320 .add_property("exit",
321 make_function(
322 static_cast<Exit* (Tile::*) () const>
323 (&Tile::getNormalExit),
324 return_value_policy<reference_existing_object>()),
325 &Tile::setNormalExit)
326 .def("offset", &Tile::offset,
327 return_value_policy<reference_existing_object>())
329 class_<TileType, bases<TileBase> > ("TileType", no_init)
331 class_<TileSet> ("TileSet", no_init)
332 .add_property("width", &TileSet::getWidth)
333 .add_property("height", &TileSet::getHeight)
334 .def("at", &TileSet::pyGet,
335 return_value_policy<reference_existing_object>())
337 class_<Exit> ("Exit", no_init)
338 .def_readwrite("area", &Exit::area)
339 .def_readwrite("coords", &Exit::coords)
341 pythonAddFunction("new_exit", pythonNewExit);