tibia-rme/source/materials.cpp

350 lines
11 KiB
C++
Raw Permalink Normal View History

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
2020-07-30 11:42:28 -03:00
// Remere's Map Editor is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Remere's Map Editor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "editor.h"
#include "items.h"
#include "monsters.h"
#include "gui.h"
#include "materials.h"
#include "brush.h"
#include "monster_brush.h"
#include "npc_brush.h"
#include "raw_brush.h"
Materials g_materials;
2023-10-09 19:12:16 -07:00
Materials::Materials() {
2015-12-06 11:42:37 -03:00
////
}
2023-10-09 19:12:16 -07:00
Materials::~Materials() {
clear();
}
2023-10-09 19:12:16 -07:00
void Materials::clear() {
for (TilesetContainer::iterator iter = tilesets.begin(); iter != tilesets.end(); ++iter) {
delete iter->second;
}
2023-10-09 19:12:16 -07:00
for (MaterialsExtensionList::iterator iter = extensions.begin(); iter != extensions.end(); ++iter) {
delete *iter;
}
tilesets.clear();
extensions.clear();
}
2023-10-09 19:12:16 -07:00
const MaterialsExtensionList &Materials::getExtensions() {
return extensions;
}
2023-10-09 19:12:16 -07:00
MaterialsExtensionList Materials::getExtensionsByVersion(uint16_t version_id) {
MaterialsExtensionList ret_list;
2023-10-09 19:12:16 -07:00
for (MaterialsExtensionList::iterator iter = extensions.begin(); iter != extensions.end(); ++iter) {
if ((*iter)->isForVersion(version_id)) {
ret_list.push_back(*iter);
}
}
return ret_list;
}
2023-10-09 19:12:16 -07:00
bool Materials::loadMaterials(const FileName &identifier, wxString &error, wxArrayString &warnings) {
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(identifier.GetFullPath().mb_str());
2023-10-09 19:12:16 -07:00
if (!result) {
2016-11-05 15:28:14 +01:00
warnings.push_back("Could not open " + identifier.GetFullName() + " (file not found or syntax error)");
return false;
}
pugi::xml_node node = doc.child("materials");
2023-10-09 19:12:16 -07:00
if (!node) {
2016-11-05 15:28:14 +01:00
warnings.push_back(identifier.GetFullName() + ": Invalid rootheader.");
return false;
}
unserializeMaterials(identifier, node, error, warnings);
return true;
}
2023-10-09 19:12:16 -07:00
bool Materials::loadExtensions(FileName directoryName, wxString &error, wxArrayString &warnings) {
directoryName.Mkdir(0755, wxPATH_MKDIR_FULL); // Create if it doesn't exist
wxDir ext_dir(directoryName.GetPath());
2023-10-09 19:12:16 -07:00
if (!ext_dir.IsOpened()) {
2016-11-05 15:28:14 +01:00
error = "Could not open extensions directory.";
return false;
}
wxString filename;
2023-10-09 19:12:16 -07:00
if (!ext_dir.GetFirst(&filename)) {
// No extensions found
return true;
}
StringVector clientVersions;
do {
FileName fn;
fn.SetPath(directoryName.GetPath());
fn.SetFullName(filename);
2023-10-09 19:12:16 -07:00
if (fn.GetExt() != "xml") {
continue;
}
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(fn.GetFullPath().mb_str());
2023-10-09 19:12:16 -07:00
if (!result) {
2016-11-05 15:28:14 +01:00
warnings.push_back("Could not open " + filename + " (file not found or syntax error)");
continue;
}
pugi::xml_node extensionNode = doc.child("materialsextension");
2023-10-09 19:12:16 -07:00
if (!extensionNode) {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Invalid rootheader.");
continue;
}
pugi::xml_attribute attribute;
2023-10-09 19:12:16 -07:00
if (!(attribute = extensionNode.attribute("name"))) {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Couldn't read extension name.");
continue;
}
2023-10-09 19:12:16 -07:00
const std::string &extensionName = attribute.as_string();
if (!(attribute = extensionNode.attribute("author"))) {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Couldn't read extension name.");
continue;
}
2023-10-09 19:12:16 -07:00
const std::string &extensionAuthor = attribute.as_string();
if (!(attribute = extensionNode.attribute("description"))) {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Couldn't read extension name.");
continue;
}
2023-10-09 19:12:16 -07:00
const std::string &extensionDescription = attribute.as_string();
if (extensionName.empty() || extensionAuthor.empty() || extensionDescription.empty()) {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Couldn't read extension attributes (name, author, description).");
continue;
}
std::string extensionUrl = extensionNode.attribute("url").as_string();
extensionUrl.erase(std::remove(extensionUrl.begin(), extensionUrl.end(), '\''));
std::string extensionAuthorLink = extensionNode.attribute("authorurl").as_string();
extensionAuthorLink.erase(std::remove(extensionAuthorLink.begin(), extensionAuthorLink.end(), '\''));
MaterialsExtension* materialExtension = newd MaterialsExtension(extensionName, extensionAuthor, extensionDescription);
materialExtension->url = extensionUrl;
materialExtension->author_url = extensionAuthorLink;
2023-10-09 19:12:16 -07:00
if ((attribute = extensionNode.attribute("client"))) {
clientVersions.clear();
2023-10-09 19:12:16 -07:00
const std::string &extensionClientString = attribute.as_string();
size_t lastPosition = 0;
size_t position = extensionClientString.find(';');
2023-10-09 19:12:16 -07:00
while (position != std::string::npos) {
clientVersions.push_back(extensionClientString.substr(lastPosition, position - lastPosition));
lastPosition = position + 1;
position = extensionClientString.find(';', lastPosition);
}
clientVersions.push_back(extensionClientString.substr(lastPosition));
2023-10-09 19:12:16 -07:00
for (const std::string &version : clientVersions) {
materialExtension->addVersion(version);
}
std::sort(materialExtension->version_list.begin(), materialExtension->version_list.end(), VersionComparisonPredicate);
2014-01-25 20:42:59 +01:00
auto duplicate = std::unique(materialExtension->version_list.begin(), materialExtension->version_list.end());
2023-10-09 19:12:16 -07:00
while (duplicate != materialExtension->version_list.end()) {
2014-01-25 20:42:59 +01:00
materialExtension->version_list.erase(duplicate);
duplicate = std::unique(materialExtension->version_list.begin(), materialExtension->version_list.end());
2014-01-25 20:42:59 +01:00
}
} else {
2016-11-05 15:28:14 +01:00
warnings.push_back(filename + ": Extension is not available for any version.");
}
extensions.push_back(materialExtension);
2023-10-09 19:12:16 -07:00
if (materialExtension->isForVersion(g_gui.GetCurrentVersionID())) {
unserializeMaterials(filename, extensionNode, error, warnings);
}
2023-10-09 19:12:16 -07:00
} while (ext_dir.GetNext(&filename));
return true;
}
2023-10-09 19:12:16 -07:00
bool Materials::unserializeMaterials(const FileName &filename, pugi::xml_node node, wxString &error, wxArrayString &warnings) {
wxString warning;
pugi::xml_attribute attribute;
2023-10-09 19:12:16 -07:00
for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) {
const std::string &childName = as_lower_str(childNode.name());
if (childName == "include") {
if (!(attribute = childNode.attribute("file"))) {
continue;
}
FileName includeName;
includeName.SetPath(filename.GetPath());
includeName.SetName(wxString(attribute.as_string(), wxConvUTF8));
wxString subError;
2023-10-09 19:12:16 -07:00
if (!loadMaterials(includeName, subError, warnings)) {
2016-11-05 15:28:14 +01:00
warnings.push_back("Error while loading file \"" + includeName.GetFullName() + "\": " + subError);
}
2023-10-09 19:12:16 -07:00
} else if (childName == "metaitem") {
g_items.loadMetaItem(childNode);
2023-10-09 19:12:16 -07:00
} else if (childName == "border") {
g_brushes.unserializeBorder(childNode, warnings);
2023-10-09 19:12:16 -07:00
if (warning.size()) {
2016-11-05 15:28:14 +01:00
warnings.push_back("materials.xml: " + warning);
}
2023-10-09 19:12:16 -07:00
} else if (childName == "brush") {
g_brushes.unserializeBrush(childNode, warnings);
2023-10-09 19:12:16 -07:00
if (warning.size()) {
2016-11-05 15:28:14 +01:00
warnings.push_back("materials.xml: " + warning);
}
2023-10-09 19:12:16 -07:00
} else if (childName == "tileset") {
unserializeTileset(childNode, warnings);
}
}
return true;
}
2023-10-09 19:12:16 -07:00
void Materials::createOtherTileset() {
Tileset* others;
2023-10-09 19:12:16 -07:00
if (tilesets["Others"] != nullptr) {
others = tilesets["Others"];
others->clear();
} else {
others = newd Tileset(g_brushes, "Others");
tilesets["Others"] = others;
}
// There should really be an iterator to do this
2023-10-09 19:12:16 -07:00
for (int32_t id = 0; id <= g_items.getMaxID(); ++id) {
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
ItemType* type = g_items.getRawItemType(id);
2023-10-09 19:12:16 -07:00
if (!type) {
continue;
}
2023-10-09 19:12:16 -07:00
if (!type->isMetaItem()) {
Brush* brush;
2023-10-09 19:12:16 -07:00
if (type->in_other_tileset) {
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
others->getCategory(TILESET_RAW)->brushlist.push_back(type->raw_brush);
continue;
2023-10-09 19:12:16 -07:00
} else if (!type->raw_brush) {
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
brush = type->raw_brush = newd RAWBrush(type->id);
type->has_raw = true;
g_brushes.addBrush(type->raw_brush);
2023-10-09 19:12:16 -07:00
} else if (!type->has_raw) {
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
brush = type->raw_brush;
2023-10-09 19:12:16 -07:00
} else {
continue;
2023-10-09 19:12:16 -07:00
}
brush->flagAsVisible();
feat: synchronizing commits with the official rme repository (#36) * Show indicators for pickupable and moveable items * Fix: drawing always refreshing ui * Fix crash on invalid friend for wallbrush * Option to remove empty spawns * Draws position indicator, some code cleanup * Teleport copy/paste improvements * Fix flood fill * Add function to get minimap/8bit color * Small code cleanup * Cleanup Position * Code cleanup and small optimizations * Code cleanup * Code cleanup and small optimizations (#406) * Cleanup and cast functions. * Avoid adding a new Unique ID if it already exists * Code cleanup and small optimizations * More changes and cleanup * Changes and cleanup * Some changes * Fix copy position. * Only show uid/aid alert if it really changed * Add actions history panel * Does not draw tooltips on minimap mode * Use constexpr * Replace items fix (#408) * Draw grid small optimization * Small change in selection box and Fix #409 * Fix some xpm * Ingame box improvements, add lights support. * Fix go to previous position (#410) * Fix depot crash (#411) * Fix XPMs * Export minimap as .otmm (otclient format) or .png (#413) * Fix glitch after drawing secondary map * fix * Update about_window.cpp * sonar * fix Minimap and progress bar * fix erro load items.xml * fix * fix doodad brush * fix: slightly more accurate house size estimation * feat: update items.otb and items.xml * fix: bad merge * Revert "feat: update items.otb and items.xml" This reverts commit 40f1edc70f17c423282d546a41541a8fe9b92dcc. --------- Co-authored-by: Nailson <Mignari@users.noreply.github.com> Co-authored-by: wtver <51377408+maattch@users.noreply.github.com> Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com> Co-authored-by: Luan Santos <github@luan.sh>
2023-10-09 23:02:37 -03:00
others->getCategory(TILESET_RAW)->brushlist.push_back(type->raw_brush);
type->in_other_tileset = true;
}
}
2023-10-09 19:12:16 -07:00
for (MonsterMap::iterator iter = g_monsters.begin(); iter != g_monsters.end(); ++iter) {
MonsterType* type = iter->second;
2023-10-09 19:12:16 -07:00
if (type->in_other_tileset) {
others->getCategory(TILESET_MONSTER)->brushlist.push_back(type->brush);
2023-10-09 19:12:16 -07:00
} else if (type->brush == nullptr) {
type->brush = newd MonsterBrush(type);
g_brushes.addBrush(type->brush);
type->brush->flagAsVisible();
type->in_other_tileset = true;
others->getCategory(TILESET_MONSTER)->brushlist.push_back(type->brush);
}
}
}
2023-10-09 19:12:16 -07:00
void Materials::createNpcTileset() {
Tileset* npcTileset;
2023-10-09 19:12:16 -07:00
if (tilesets["NPCs"] != nullptr) {
npcTileset = tilesets["NPCs"];
npcTileset->clear();
} else {
npcTileset = newd Tileset(g_brushes, "NPCs");
tilesets["NPCs"] = npcTileset;
}
2023-10-09 19:12:16 -07:00
for (NpcMap::iterator iter = g_npcs.begin(); iter != g_npcs.end(); ++iter) {
NpcType* type = iter->second;
2023-10-09 19:12:16 -07:00
if (type->in_other_tileset) {
npcTileset->getCategory(TILESET_NPC)->brushlist.push_back(type->brush);
2023-10-09 19:12:16 -07:00
} else if (type->brush == nullptr) {
type->brush = newd NpcBrush(type);
g_brushes.addBrush(type->brush);
type->brush->flagAsVisible();
type->in_other_tileset = true;
npcTileset->getCategory(TILESET_NPC)->brushlist.push_back(type->brush);
}
}
}
2023-10-09 19:12:16 -07:00
bool Materials::unserializeTileset(pugi::xml_node node, wxArrayString &warnings) {
pugi::xml_attribute attribute;
2023-10-09 19:12:16 -07:00
if (!(attribute = node.attribute("name"))) {
2016-11-05 15:28:14 +01:00
warnings.push_back("Couldn't read tileset name");
return false;
}
2023-10-09 19:12:16 -07:00
const std::string &name = attribute.as_string();
Tileset* tileset;
auto it = tilesets.find(name);
2023-10-09 19:12:16 -07:00
if (it != tilesets.end()) {
tileset = it->second;
} else {
tileset = newd Tileset(g_brushes, name);
tilesets.insert(std::make_pair(name, tileset));
}
2023-10-09 19:12:16 -07:00
for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) {
tileset->loadCategory(childNode, warnings);
}
return true;
}
2023-10-09 19:12:16 -07:00
bool Materials::isInTileset(Item* item, std::string tilesetName) const {
const ItemType &type = g_items.getItemType(item->getID());
return type.id != 0 && (isInTileset(type.brush, tilesetName) || isInTileset(type.doodad_brush, tilesetName) || isInTileset(type.raw_brush, tilesetName));
}
2023-10-09 19:12:16 -07:00
bool Materials::isInTileset(Brush* brush, std::string tilesetName) const {
if (!brush) {
return false;
2023-10-09 19:12:16 -07:00
}
TilesetContainer::const_iterator tilesetiter = tilesets.find(tilesetName);
2023-10-09 19:12:16 -07:00
if (tilesetiter == tilesets.end()) {
return false;
2023-10-09 19:12:16 -07:00
}
Tileset* tileset = tilesetiter->second;
return tileset->containsBrush(brush);
}