00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "resources/spritedef.h"
00023
00024 #include "resources/action.h"
00025 #include "resources/animation.h"
00026 #include "resources/dye.h"
00027 #include "resources/image.h"
00028 #include "resources/imageset.h"
00029 #include "resources/resourcemanager.h"
00030
00031 #include "log.h"
00032
00033 #include "utils/xml.h"
00034
00035 #include <set>
00036
00037 Action *SpriteDef::getAction(SpriteAction action) const
00038 {
00039 Actions::const_iterator i = mActions.find(action);
00040
00041 if (i == mActions.end())
00042 {
00043 logger->log("Warning: no action \"%u\" defined!", action);
00044 return NULL;
00045 }
00046
00047 return i->second;
00048 }
00049
00050 SpriteDef *SpriteDef::load(const std::string &animationFile, int variant)
00051 {
00052 std::string::size_type pos = animationFile.find('|');
00053 std::string palettes;
00054 if (pos != std::string::npos)
00055 palettes = animationFile.substr(pos + 1);
00056
00057 XML::Document doc(animationFile.substr(0, pos));
00058 xmlNodePtr rootNode = doc.rootNode();
00059
00060 if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite"))
00061 {
00062 logger->log("Error, failed to parse %s", animationFile.c_str());
00063
00064 if (animationFile != "graphics/sprites/error.xml") {
00065 return load("graphics/sprites/error.xml", 0);
00066 } else {
00067 return NULL;
00068 }
00069 }
00070
00071 SpriteDef *def = new SpriteDef;
00072 def->loadSprite(rootNode, variant, palettes);
00073 def->substituteActions();
00074 return def;
00075 }
00076
00077 void SpriteDef::substituteActions()
00078 {
00079 substituteAction(ACTION_STAND, ACTION_DEFAULT);
00080 substituteAction(ACTION_WALK, ACTION_STAND);
00081 substituteAction(ACTION_WALK, ACTION_RUN);
00082 substituteAction(ACTION_ATTACK, ACTION_STAND);
00083 substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK);
00084 substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING);
00085 substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB);
00086 substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING);
00087 substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING);
00088 substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC);
00089 substituteAction(ACTION_SIT, ACTION_STAND);
00090 substituteAction(ACTION_SLEEP, ACTION_SIT);
00091 substituteAction(ACTION_HURT, ACTION_STAND);
00092 substituteAction(ACTION_DEAD, ACTION_HURT);
00093 }
00094
00095 void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant,
00096 const std::string &palettes)
00097 {
00098
00099 const int variantCount = XML::getProperty(spriteNode, "variants", 0);
00100 int variant_offset = 0;
00101
00102 if (variantCount > 0 && variant < variantCount)
00103 {
00104 variant_offset =
00105 variant * XML::getProperty(spriteNode, "variant_offset", 0);
00106 }
00107
00108 for_each_xml_child_node(node, spriteNode)
00109 {
00110 if (xmlStrEqual(node->name, BAD_CAST "imageset"))
00111 {
00112 loadImageSet(node, palettes);
00113 }
00114 else if (xmlStrEqual(node->name, BAD_CAST "action"))
00115 {
00116 loadAction(node, variant_offset);
00117 }
00118 else if (xmlStrEqual(node->name, BAD_CAST "include"))
00119 {
00120 includeSprite(node);
00121 }
00122 }
00123 }
00124
00125 void SpriteDef::loadImageSet(xmlNodePtr node, const std::string &palettes)
00126 {
00127 const std::string name = XML::getProperty(node, "name", "");
00128
00129
00130
00131 if (mImageSets.find(name) != mImageSets.end())
00132 return;
00133
00134 const int width = XML::getProperty(node, "width", 0);
00135 const int height = XML::getProperty(node, "height", 0);
00136 std::string imageSrc = XML::getProperty(node, "src", "");
00137 Dye::instantiate(imageSrc, palettes);
00138
00139 ResourceManager *resman = ResourceManager::getInstance();
00140 ImageSet *imageSet = resman->getImageSet(imageSrc, width, height);
00141
00142 if (!imageSet)
00143 {
00144 logger->error("Couldn't load imageset!");
00145 }
00146
00147 mImageSets[name] = imageSet;
00148 }
00149
00150 void SpriteDef::loadAction(xmlNodePtr node, int variant_offset)
00151 {
00152 const std::string actionName = XML::getProperty(node, "name", "");
00153 const std::string imageSetName = XML::getProperty(node, "imageset", "");
00154
00155 ImageSetIterator si = mImageSets.find(imageSetName);
00156 if (si == mImageSets.end())
00157 {
00158 logger->log("Warning: imageset \"%s\" not defined in %s",
00159 imageSetName.c_str(), getIdPath().c_str());
00160 return;
00161 }
00162 ImageSet *imageSet = si->second;
00163
00164 SpriteAction actionType = makeSpriteAction(actionName);
00165 if (actionType == ACTION_INVALID)
00166 {
00167 logger->log("Warning: Unknown action \"%s\" defined in %s",
00168 actionName.c_str(), getIdPath().c_str());
00169 return;
00170 }
00171 Action *action = new Action;
00172 mActions[actionType] = action;
00173
00174
00175 if (mActions.empty())
00176 {
00177 mActions[ACTION_DEFAULT] = action;
00178 }
00179
00180
00181 for_each_xml_child_node(animationNode, node)
00182 {
00183 if (xmlStrEqual(animationNode->name, BAD_CAST "animation"))
00184 {
00185 loadAnimation(animationNode, action, imageSet, variant_offset);
00186 }
00187 }
00188 }
00189
00190 void SpriteDef::loadAnimation(xmlNodePtr animationNode,
00191 Action *action, ImageSet *imageSet,
00192 int variant_offset)
00193 {
00194 const std::string directionName =
00195 XML::getProperty(animationNode, "direction", "");
00196 const SpriteDirection directionType = makeSpriteDirection(directionName);
00197
00198 if (directionType == DIRECTION_INVALID)
00199 {
00200 logger->log("Warning: Unknown direction \"%s\" used in %s",
00201 directionName.c_str(), getIdPath().c_str());
00202 return;
00203 }
00204
00205 Animation *animation = new Animation;
00206 action->setAnimation(directionType, animation);
00207
00208
00209 for_each_xml_child_node(frameNode, animationNode)
00210 {
00211 const int delay = XML::getProperty(frameNode, "delay", 0);
00212 int offsetX = XML::getProperty(frameNode, "offsetX", 0);
00213 int offsetY = XML::getProperty(frameNode, "offsetY", 0);
00214 offsetY -= imageSet->getHeight() - 32;
00215 offsetX -= imageSet->getWidth() / 2 - 16;
00216
00217 if (xmlStrEqual(frameNode->name, BAD_CAST "frame"))
00218 {
00219 const int index = XML::getProperty(frameNode, "index", -1);
00220
00221 if (index < 0)
00222 {
00223 logger->log("No valid value for 'index'");
00224 continue;
00225 }
00226
00227 Image *img = imageSet->get(index + variant_offset);
00228
00229 if (!img)
00230 {
00231 logger->log("No image at index %d", index + variant_offset);
00232 continue;
00233 }
00234
00235 animation->addFrame(img, delay, offsetX, offsetY);
00236 }
00237 else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence"))
00238 {
00239 int start = XML::getProperty(frameNode, "start", -1);
00240 const int end = XML::getProperty(frameNode, "end", -1);
00241
00242 if (start < 0 || end < 0)
00243 {
00244 logger->log("No valid value for 'start' or 'end'");
00245 continue;
00246 }
00247
00248 while (end >= start)
00249 {
00250 Image *img = imageSet->get(start + variant_offset);
00251
00252 if (!img)
00253 {
00254 logger->log("No image at index %d", start + variant_offset);
00255 continue;
00256 }
00257
00258 animation->addFrame(img, delay, offsetX, offsetY);
00259 start++;
00260 }
00261 }
00262 else if (xmlStrEqual(frameNode->name, BAD_CAST "end"))
00263 {
00264 animation->addTerminator();
00265 }
00266 }
00267 }
00268
00269 void SpriteDef::includeSprite(xmlNodePtr includeNode)
00270 {
00271
00272
00273 const std::string filename = XML::getProperty(includeNode, "file", "");
00274
00275 if (filename.empty())
00276 return;
00277
00278 XML::Document doc("graphics/sprites/" + filename);
00279 xmlNodePtr rootNode = doc.rootNode();
00280
00281 if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "sprite"))
00282 {
00283 logger->log("Error, no sprite root node in %s", filename.c_str());
00284 return;
00285 }
00286
00287 loadSprite(rootNode, 0);
00288 }
00289
00290 void SpriteDef::substituteAction(SpriteAction complete, SpriteAction with)
00291 {
00292 if (mActions.find(complete) == mActions.end())
00293 {
00294 Actions::iterator i = mActions.find(with);
00295 if (i != mActions.end()) {
00296 mActions[complete] = i->second;
00297 }
00298 }
00299 }
00300
00301 SpriteDef::~SpriteDef()
00302 {
00303
00304 std::set< Action * > actions;
00305 for (Actions::const_iterator i = mActions.begin(),
00306 i_end = mActions.end(); i != i_end; ++i)
00307 {
00308 actions.insert(i->second);
00309 }
00310
00311 for (std::set< Action * >::const_iterator i = actions.begin(),
00312 i_end = actions.end(); i != i_end; ++i)
00313 {
00314 delete *i;
00315 }
00316
00317 for (ImageSetIterator i = mImageSets.begin();
00318 i != mImageSets.end(); ++i)
00319 {
00320 i->second->decRef();
00321 }
00322 }
00323
00324 SpriteAction SpriteDef::makeSpriteAction(const std::string &action)
00325 {
00326 if (action.empty() || action == "default") {
00327 return ACTION_DEFAULT;
00328 }
00329 if (action == "stand") {
00330 return ACTION_STAND;
00331 }
00332 else if (action == "walk") {
00333 return ACTION_WALK;
00334 }
00335 else if (action == "run") {
00336 return ACTION_RUN;
00337 }
00338 else if (action == "attack") {
00339 return ACTION_ATTACK;
00340 }
00341 else if (action == "attack_swing") {
00342 return ACTION_ATTACK_SWING;
00343 }
00344 else if (action == "attack_stab") {
00345 return ACTION_ATTACK_STAB;
00346 }
00347 else if (action == "attack_bow") {
00348 return ACTION_ATTACK_BOW;
00349 }
00350 else if (action == "attack_throw") {
00351 return ACTION_ATTACK_THROW;
00352 }
00353 else if (action == "special0") {
00354 return ACTION_SPECIAL_0;
00355 }
00356 else if (action == "special1") {
00357 return ACTION_SPECIAL_1;
00358 }
00359 else if (action == "special2") {
00360 return ACTION_SPECIAL_2;
00361 }
00362 else if (action == "special3") {
00363 return ACTION_SPECIAL_3;
00364 }
00365 else if (action == "special4") {
00366 return ACTION_SPECIAL_4;
00367 }
00368 else if (action == "special5") {
00369 return ACTION_SPECIAL_5;
00370 }
00371 else if (action == "special6") {
00372 return ACTION_SPECIAL_6;
00373 }
00374 else if (action == "special7") {
00375 return ACTION_SPECIAL_7;
00376 }
00377 else if (action == "special8") {
00378 return ACTION_SPECIAL_8;
00379 }
00380 else if (action == "special9") {
00381 return ACTION_SPECIAL_9;
00382 }
00383 else if (action == "cast_magic") {
00384 return ACTION_CAST_MAGIC;
00385 }
00386 else if (action == "use_item") {
00387 return ACTION_USE_ITEM;
00388 }
00389 else if (action == "sit") {
00390 return ACTION_SIT;
00391 }
00392 else if (action == "sleep") {
00393 return ACTION_SLEEP;
00394 }
00395 else if (action == "hurt") {
00396 return ACTION_HURT;
00397 }
00398 else if (action == "dead") {
00399 return ACTION_DEAD;
00400 }
00401 else {
00402 return ACTION_INVALID;
00403 }
00404 }
00405
00406 SpriteDirection SpriteDef::makeSpriteDirection(const std::string &direction)
00407 {
00408 if (direction.empty() || direction == "default") {
00409 return DIRECTION_DEFAULT;
00410 }
00411 else if (direction == "up") {
00412 return DIRECTION_UP;
00413 }
00414 else if (direction == "left") {
00415 return DIRECTION_LEFT;
00416 }
00417 else if (direction == "right") {
00418 return DIRECTION_RIGHT;
00419 }
00420 else if (direction == "down") {
00421 return DIRECTION_DOWN;
00422 }
00423 else {
00424 return DIRECTION_INVALID;
00425 }
00426 }