player: change direction even if we can't move
[Tsunagari.git] / src / sprite.cpp
blob1b89835f3b6ac745a10d963cdba187fe4e125d7c
1 /******************************
2 ** Tsunagari Tile Engine **
3 ** sprite.cpp **
4 ** Copyright 2011 OmegaSDG **
5 ******************************/
7 #include <Gosu/Image.hpp>
8 #include <libxml/parser.h>
9 #include <libxml/tree.h>
11 #include "log.h"
12 #include "resourcer.h"
13 #include "sprite.h"
15 Sprite::Sprite(Resourcer* rc)
16 : rc(rc)
18 c.x = c.y = c.z = 0;
21 Sprite::~Sprite()
23 boost::unordered_map<std::string, Gosu::Image*>::iterator it;
24 for (it = imgs.begin(); it != imgs.end(); it++) {
25 Gosu::Image* img = (*it).second;
26 delete img;
30 bool Sprite::init(const std::string& descriptor)
32 this->descriptor = descriptor;
33 return processDescriptor() && loadPhases();
36 void Sprite::draw() const
38 img->draw((double)c.x, (double)c.y, (double)0);
41 bool Sprite::setPhase(const std::string& name)
43 bool changed = false;
44 boost::unordered_map<std::string, Gosu::Image*>::iterator phase;
45 phase = imgs.find(name);
46 if (phase != imgs.end()) {
47 Gosu::Image* newImg = (*phase).second;
48 changed = img != newImg;
49 img = newImg;
51 return changed;
54 coord_t Sprite::getCoordsByPixel()
56 return c;
59 coord_t Sprite::getCoordsByTile()
61 coord_t coords;
62 coords.x = c.x / img->width();
63 coords.y = c.y / img->height();
64 coords.z = c.z; // XXX: revisit when we have Z-buffers
65 return coords;
68 void Sprite::setCoordsByPixel(coord_t coords)
70 c = coords;
73 void Sprite::setCoordsByTile(coord_t coords)
75 // FIXME: use Area's tile width
76 c = coords;
77 c.x *= img->width();
78 c.y *= img->height();
79 // XXX: set c.z when we have Z-buffers
82 void Sprite::moveByPixel(coord_t dc)
84 c.x += dc.x;
85 c.y += dc.y;
86 c.z += dc.z;
89 void Sprite::moveByTile(coord_t dc)
91 // FIXME: use Area's tile width
92 c.x += dc.x * img->width();
93 c.y += dc.y * img->height();
94 // XXX: set c.z when we have Z-buffers
97 /**
98 * Try to load in descriptor.
100 bool Sprite::processDescriptor()
102 XMLDocRef doc = rc->getXMLDoc(descriptor, "dtd/sprite.dtd");
103 if (!doc)
104 return false;
105 const xmlNode* root = xmlDocGetRootElement(doc.get()); // <sprite>
106 if (!root)
107 return false;
108 xmlNode* node = root->xmlChildrenNode; // children of <sprite>
110 xmlChar* str;
111 for (; node != NULL; node = node->next) {
112 if (!xmlStrncmp(node->name, BAD_CAST("sheet"), 6)) {
113 str = xmlNodeGetContent(node);
114 xml.sheet = (char*)str;
116 str = xmlGetProp(node, BAD_CAST("tilesizex"));
117 xml.tilesize.x = atol((char*)str); // atol
119 str = xmlGetProp(node, BAD_CAST("tilesizey"));
120 xml.tilesize.y = atol((char*)str); // atol
122 else if (!xmlStrncmp(node->name, BAD_CAST("phases"), 7) &&
123 !processPhases(node))
124 return false;
126 return true;
129 bool Sprite::processPhases(xmlNode* phases)
131 for (xmlNode* phase = phases->xmlChildrenNode; phase != NULL;
132 phase = phase->next)
133 if (!xmlStrncmp(phase->name, BAD_CAST("phase"), 6))
134 if (!processPhase(phase))
135 return false;
136 return true;
139 bool Sprite::processPhase(xmlNode* phase)
141 /* Each phase requires a 'name'. Additionally,
142 * one of either 'pos' or 'speed' is needed.
143 * If speed is used, we have sub-elements. We
144 * can't have both pos and speed.
146 const std::string key = (char*)xmlGetProp(phase, BAD_CAST("name"));
148 const xmlChar* pos = xmlGetProp(phase, BAD_CAST("pos"));
149 const xmlChar* speed = xmlGetProp(phase, BAD_CAST("speed"));
151 if (pos && speed) {
152 Log::err(descriptor, "pos and speed attributes in "
153 "element phase are mutually exclusive");
154 return false;
156 if (!pos && !speed) {
157 Log::err(descriptor, "must have pos or speed attribute "
158 "in element phase");
159 return false;
162 if (pos) {
163 const unsigned value = (unsigned)atoi((const char*)pos); // atol
164 xml.phases[key] = value;
166 else { // speed
167 // TODO: Load animated sprites
168 // Load <member> subelements
171 return true;
174 bool Sprite::loadPhases()
176 Gosu::Bitmap src;
177 if (!rc->getBitmap(src, xml.sheet))
178 return false;
180 boost::unordered_map<std::string, unsigned>::iterator it;
181 for (it = xml.phases.begin(); it != xml.phases.end(); it++) {
182 const std::string& name = (*it).first;
183 unsigned idx = (*it).second;
184 Gosu::Image* image = loadImage(src, idx);
185 imgs[name] = img = image;
187 return true;
190 Gosu::Image* Sprite::loadImage(const Gosu::Bitmap& src, unsigned pos)
192 unsigned x = (unsigned)((xml.tilesize.x * pos) %
193 src.width());
194 unsigned y = (unsigned)((xml.tilesize.y * pos) /
195 src.width() * xml.tilesize.y); // ???
197 // FIXME: check for index out of bounds
199 return rc->bitmapSection(src, x, y, (unsigned)xml.tilesize.x,
200 (unsigned)xml.tilesize.y, true);