bool ThingTypeManager::loadDat(const std::string& file) { m_datLoaded = false; m_datSignature = 0; try { FileStreamPtr fin = g_resources.openFile(file); m_datSignature = fin->getU32(); int numThings[ThingLastCategory]; for(int category = 0; category < ThingLastCategory; ++category) { int count = fin->getU16() + 1; m_thingTypes[category].clear(); m_thingTypes[category].resize(count, m_nullThingType); } for(int category = 0; category < ThingLastCategory; ++category) { uint16 firstId = 1; if(category == ThingCategoryItem) firstId = 100; for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id) { ThingTypePtr type(new ThingType); type->unserialize(id, (ThingCategory)category, fin); m_thingTypes[category][id] = type; } } m_datLoaded = true; return true; } catch(stdext::exception& e) { g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what())); return false; } }
bool Map::loadOtcm(const std::string& fileName) { try { FileStreamPtr fin = g_resources.openFile(fileName); if(!fin) stdext::throw_exception("unable to open file"); stdext::timer loadTimer; fin->cache(); uint32 signature = fin->getU32(); if(signature != OTCM_SIGNATURE) stdext::throw_exception("invalid otcm file"); uint16 start = fin->getU16(); uint16 version = fin->getU16(); fin->getU32(); // flags switch(version) { case 1: { fin->getString(); // description uint32 datSignature = fin->getU32(); fin->getU16(); // protocol version fin->getString(); // world name if(datSignature != g_things.getDatSignature()) g_logger.warning("otcm map loaded was created with a different dat signature"); break; } default: stdext::throw_exception("otcm version not supported"); } fin->seek(start); while(true) { Position pos; pos.x = fin->getU16(); pos.y = fin->getU16(); pos.z = fin->getU8(); // end of file if(!pos.isValid()) break; const TilePtr& tile = g_map.createTile(pos); int stackPos = 0; while(true) { int id = fin->getU16(); // end of tile if(id == 0xFFFF) break; int countOrSubType = fin->getU8(); ItemPtr item = Item::create(id); item->setCountOrSubType(countOrSubType); if(item->isValid()) tile->addThing(item, stackPos++); } } fin->close(); g_logger.debug(stdext::format("Otcm load time: %.2f seconds", loadTimer.elapsed_seconds())); return true; } catch(stdext::exception& e) { g_logger.error(stdext::format("failed to load OTCM map: %s", e.what())); return false; } }
void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin) { m_null = false; m_id = clientId; m_category = category; int count = 0, attr = -1; bool done = false; for(int i = 0 ; i < ThingLastAttr;++i) { count++; attr = fin->getU8(); if(attr == ThingLastAttr) { done = true; break; } if(g_game.getClientVersion() >= 1000) { /* In 10.10+ all attributes from 16 and up were * incremented by 1 to make space for 16 as * "No Movement Animation" flag. */ if(attr == 16) attr = ThingAttrNoMoveAnimation; else if(attr > 16) attr -= 1; } else if(g_game.getClientVersion() >= 860) { /* Default attribute values follow * the format of 8.6-9.86. * Therefore no changes here. */ } else if(g_game.getClientVersion() >= 780) { /* In 7.80-8.54 all attributes from 8 and higher were * incremented by 1 to make space for 8 as * "Item Charges" flag. */ if(attr == 8) { m_attribs.set(ThingAttrChargeable, true); continue; } else if(attr > 8) attr -= 1; } else if(g_game.getClientVersion() >= 755) { /* In 7.55-7.72 attributes 23 is "Floor Change". */ if(attr == 23) attr = ThingAttrFloorChange; } else if(g_game.getClientVersion() >= 740) { /* In 7.4-7.5 attribute "Ground Border" did not exist * attributes 1-15 have to be adjusted. * Several other changes in the format. */ if(attr > 0 && attr <= 15) attr += 1; else if(attr == 16) attr = ThingAttrLight; else if(attr == 17) attr = ThingAttrFloorChange; else if(attr == 18) attr = ThingAttrFullGround; else if(attr == 19) attr = ThingAttrElevation; else if(attr == 20) attr = ThingAttrDisplacement; else if(attr == 22) attr = ThingAttrMinimapColor; else if(attr == 23) attr = ThingAttrRotateable; else if(attr == 24) attr = ThingAttrLyingCorpse; else if(attr == 25) attr = ThingAttrHangable; else if(attr == 26) attr = ThingAttrHookSouth; else if(attr == 27) attr = ThingAttrHookEast; else if(attr == 28) attr = ThingAttrAnimateAlways; /* "Multi Use" and "Force Use" are swapped */ if(attr == ThingAttrMultiUse) attr = ThingAttrForceUse; else if(attr == ThingAttrForceUse) attr = ThingAttrMultiUse; } switch(attr) { case ThingAttrDisplacement: { if(g_game.getClientVersion() >= 755) { m_displacement.x = fin->getU16(); m_displacement.y = fin->getU16(); } else { m_displacement.x = 8; m_displacement.y = 8; } m_attribs.set(attr, true); break; } case ThingAttrLight: { Light light; light.intensity = fin->getU16(); light.color = fin->getU16(); m_attribs.set(attr, light); break; } case ThingAttrMarket: { MarketData market; market.category = fin->getU16(); market.tradeAs = fin->getU16(); market.showAs = fin->getU16(); market.name = fin->getString(); market.restrictVocation = fin->getU16(); market.requiredLevel = fin->getU16(); m_attribs.set(attr, market); break; } case ThingAttrElevation: { m_elevation = fin->getU16(); m_attribs.set(attr, m_elevation); break; } case ThingAttrUsable: case ThingAttrGround: case ThingAttrWritable: case ThingAttrWritableOnce: case ThingAttrMinimapColor: case ThingAttrCloth: case ThingAttrLensHelp: m_attribs.set(attr, fin->getU16()); break; default: m_attribs.set(attr, true); break; }; } if(!done) stdext::throw_exception(stdext::format("corrupt data (id: %d, category: %d, count: %d, lastAttr: %d)", m_id, m_category, count, attr)); bool hasFrameGroups = (category == ThingCategoryCreature && g_game.getFeature(Otc::GameIdleAnimations)); uint8 groupCount = hasFrameGroups ? fin->getU8() : 1; for(int i = 0; i < groupCount; ++i) { uint8 frameGroupType = FrameGroupDefault; if(hasFrameGroups) frameGroupType = fin->getU8(); uint8 width = fin->getU8(); uint8 height = fin->getU8(); m_size = Size(width, height); if(width > 1 || height > 1) { m_realSize = fin->getU8(); m_exactSize = std::min<int>(m_realSize, std::max<int>(width * 32, height * 32)); } else m_exactSize = 32; m_layers = fin->getU8(); m_numPatternX = fin->getU8(); m_numPatternY = fin->getU8(); if(g_game.getClientVersion() >= 755) m_numPatternZ = fin->getU8(); else m_numPatternZ = 1; m_animationPhases = fin->getU8(); if(m_animationPhases > 1 && g_game.getFeature(Otc::GameEnhancedAnimations)) { m_animator = AnimatorPtr(new Animator); m_animator->unserialize(m_animationPhases, fin); } int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases; if(totalSprites > 4096) stdext::throw_exception("a thing type has more than 4096 sprites"); m_spritesIndex.resize(totalSprites); for(int i = 0; i < totalSprites; i++) m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16(); } m_textures.resize(m_animationPhases); m_texturesFramesRects.resize(m_animationPhases); m_texturesFramesOriginRects.resize(m_animationPhases); m_texturesFramesOffsets.resize(m_animationPhases); }
void ThingType::unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin) { m_null = false; m_id = clientId; m_category = category; bool done = false; for(int i = 0 ; i < ThingLastAttr;++i) { int attr = fin->getU8(); if(attr == ThingLastAttr) { done = true; break; } if(g_game.getFeature(Otc::GameChargeableItems)) { if(attr == ThingAttrWritable) { m_attribs.set(ThingAttrChargeable, true); continue; } else if(attr > ThingAttrWritable) attr -= 1; } if(g_game.getProtocolVersion() >= 1010) { /* In 10.10 all attributes from 16 and up were * incremented by 1 to make space for 16 as * "No Movement Animation" flag. */ if(attr == 16) attr = ThingAttrNoMoveAnimation; else if(attr > 16) attr -= 1; } switch(attr) { case ThingAttrDisplacement: { m_displacement.x = fin->getU16(); m_displacement.y = fin->getU16(); m_attribs.set(attr, true); break; } case ThingAttrLight: { Light light; light.intensity = fin->getU16(); light.color = fin->getU16(); m_attribs.set(attr, light); break; } case ThingAttrMarket: { MarketData market; market.category = fin->getU16(); market.tradeAs = fin->getU16(); market.showAs = fin->getU16(); market.name = fin->getString(); market.restrictVocation = fin->getU16(); market.requiredLevel = fin->getU16(); m_attribs.set(attr, market); break; } case ThingAttrElevation: { m_elevation = fin->getU16(); m_attribs.set(attr, m_elevation); break; } case ThingAttrGround: case ThingAttrWritable: case ThingAttrWritableOnce: case ThingAttrMinimapColor: case ThingAttrCloth: case ThingAttrLensHelp: m_attribs.set(attr, fin->getU16()); break; default: m_attribs.set(attr, true); break; }; } if(!done) stdext::throw_exception("corrupt data"); uint8 width = fin->getU8(); uint8 height = fin->getU8(); m_size = Size(width, height); m_exactSize = (width > 1 || height > 1) ? std::min((int)fin->getU8(), std::max(width * 32, height * 32)) : 32; m_layers = fin->getU8(); m_numPatternX = fin->getU8(); m_numPatternY = fin->getU8(); m_numPatternZ = fin->getU8(); m_animationPhases = fin->getU8(); int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases; // if(totalSprites == 0) // stdext::throw_exception("a thing type has no sprites"); if(totalSprites > 4096) stdext::throw_exception("a thing type has more than 4096 sprites"); m_spritesIndex.resize(totalSprites); for(int i = 0; i < totalSprites; i++) m_spritesIndex[i] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16(); m_textures.resize(m_animationPhases); m_texturesFramesRects.resize(m_animationPhases); m_texturesFramesOriginRects.resize(m_animationPhases); m_texturesFramesOffsets.resize(m_animationPhases); }