summaryrefslogtreecommitdiff
path: root/src/resources
diff options
context:
space:
mode:
Diffstat (limited to 'src/resources')
-rw-r--r--src/resources/abilitydb.cpp4
-rw-r--r--src/resources/animation.cpp8
-rw-r--r--src/resources/attributes.cpp42
-rw-r--r--src/resources/beinginfo.cpp8
-rw-r--r--src/resources/chardb.cpp4
-rw-r--r--src/resources/dye.cpp12
-rw-r--r--src/resources/dye.h2
-rw-r--r--src/resources/emotedb.cpp16
-rw-r--r--src/resources/hairdb.cpp10
-rw-r--r--src/resources/image.cpp24
-rw-r--r--src/resources/imageset.cpp2
-rw-r--r--src/resources/imagewriter.cpp10
-rw-r--r--src/resources/itemdb.cpp42
-rw-r--r--src/resources/mapreader.cpp39
-rw-r--r--src/resources/monsterdb.cpp12
-rw-r--r--src/resources/music.cpp2
-rw-r--r--src/resources/npcdb.cpp4
-rw-r--r--src/resources/questdb.cpp232
-rw-r--r--src/resources/questdb.h139
-rw-r--r--src/resources/resource.cpp2
-rw-r--r--src/resources/resourcemanager.cpp18
-rw-r--r--src/resources/settingsmanager.cpp20
-rw-r--r--src/resources/settingsmanager.h4
-rw-r--r--src/resources/soundeffect.cpp2
-rw-r--r--src/resources/spritedef.cpp32
-rw-r--r--src/resources/theme.cpp75
-rw-r--r--src/resources/theme.h10
27 files changed, 584 insertions, 191 deletions
diff --git a/src/resources/abilitydb.cpp b/src/resources/abilitydb.cpp
index 311ee9eb..cb596ea8 100644
--- a/src/resources/abilitydb.cpp
+++ b/src/resources/abilitydb.cpp
@@ -41,7 +41,7 @@ static AbilityInfo::TargetMode targetModeFromString(const std::string& str)
if (str == "direction")
return AbilityInfo::TARGET_DIRECTION;
- logger->log("AbilityDB: Warning, unknown target mode \"%s\"", str.c_str() );
+ Log::info("AbilityDB: Warning, unknown target mode \"%s\"", str.c_str() );
return AbilityInfo::TARGET_BEING;
}
@@ -68,7 +68,7 @@ void AbilityDB::readAbilityNode(XML::Node node, const std::string &filename)
info->rechargeCurrent = 0;
if (mAbilityInfos.find(id) != mAbilityInfos.end())
- logger->log("AbilityDB: Duplicate ability ID %d in %s, ignoring", id, filename.c_str());
+ Log::info("AbilityDB: Duplicate ability ID %d in %s, ignoring", id, filename.c_str());
else
mAbilityInfos[id] = info;
}
diff --git a/src/resources/animation.cpp b/src/resources/animation.cpp
index 91c22236..c529400f 100644
--- a/src/resources/animation.cpp
+++ b/src/resources/animation.cpp
@@ -84,7 +84,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes)
if (index < 0)
{
- logger->log("No valid value for 'index'");
+ Log::info("No valid value for 'index'");
continue;
}
@@ -92,7 +92,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes)
if (!img)
{
- logger->log("No image at index %d", index);
+ Log::info("No image at index %d", index);
continue;
}
@@ -105,7 +105,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes)
if (start < 0 || end < 0)
{
- logger->log("No valid value for 'start' or 'end'");
+ Log::info("No valid value for 'start' or 'end'");
continue;
}
@@ -115,7 +115,7 @@ Animation Animation::fromXML(XML::Node node, const std::string &dyePalettes)
if (!img)
{
- logger->log("No image at index %d", start);
+ Log::info("No image at index %d", start);
continue;
}
diff --git a/src/resources/attributes.cpp b/src/resources/attributes.cpp
index 7ec6b516..5b1018ee 100644
--- a/src/resources/attributes.cpp
+++ b/src/resources/attributes.cpp
@@ -240,22 +240,22 @@ namespace Attributes {
int id = node.getProperty("id", 0);
if (!id)
{
- logger->log("Attributes: Invalid or missing stat ID in "
- DEFAULT_ATTRIBUTESDB_FILE "!");
+ Log::info("Attributes: Invalid or missing stat ID in "
+ DEFAULT_ATTRIBUTESDB_FILE "!");
return;
}
if (attributes.find(id) != attributes.end())
{
- logger->log("Attributes: Redefinition of stat ID %d", id);
+ Log::info("Attributes: Redefinition of stat ID %d", id);
}
std::string name = node.getProperty("name", "");
if (name.empty())
{
- logger->log("Attributes: Invalid or missing stat name in "
- DEFAULT_ATTRIBUTESDB_FILE "!");
+ Log::info("Attributes: Invalid or missing stat name in "
+ DEFAULT_ATTRIBUTESDB_FILE "!");
return;
}
@@ -280,10 +280,10 @@ namespace Attributes {
{
if (name.empty())
{
- logger->log("Attribute modifier in attribute %u:%s: "
- "Empty name definition "
- "on empty tag definition, skipping.",
- a.id, a.name.c_str());
+ Log::info("Attribute modifier in attribute %u:%s: "
+ "Empty name definition "
+ "on empty tag definition, skipping.",
+ a.id, a.name.c_str());
--count;
continue;
}
@@ -296,10 +296,10 @@ namespace Attributes {
{
if (name.empty())
{
- logger->log("Attribute modifier in attribute %u:%s: "
- "Empty name definition "
- "on empty effect definition, skipping.",
- a.id, a.name.c_str());
+ Log::info("Attribute modifier in attribute %u:%s: "
+ "Empty name definition "
+ "on empty effect definition, skipping.",
+ a.id, a.name.c_str());
--count;
continue;
}
@@ -308,7 +308,7 @@ namespace Attributes {
}
tags.insert(std::make_pair(tag, effect));
}
- logger->log("Found %d tags for attribute %d.", count, id);
+ Log::info("Found %d tags for attribute %d.", count, id);
}
/**
@@ -321,8 +321,8 @@ namespace Attributes {
DEFAULT_MIN_PTS);
attributeMaximum = node.getProperty("maximum",
DEFAULT_MAX_PTS);
- logger->log("Loaded points: start: %i, min: %i, max: %i.",
- creationPoints, attributeMinimum, attributeMaximum);
+ Log::info("Loaded points: start: %i, min: %i, max: %i.",
+ creationPoints, attributeMinimum, attributeMaximum);
}
/**
@@ -330,8 +330,8 @@ namespace Attributes {
*/
void checkStatus()
{
- logger->log("Found %d tags for %d attributes.", int(tags.size()),
- int(attributes.size()));
+ Log::info("Found %d tags for %d attributes.", int(tags.size()),
+ int(attributes.size()));
if (attributes.size() == 0)
{
@@ -346,9 +346,9 @@ namespace Attributes {
if (averageValue > attributeMaximum || averageValue < attributeMinimum
|| creationPoints < 1)
{
- logger->log("Attributes: Character's point values make "
- "the character's creation impossible. "
- "Switch back to defaults.");
+ Log::info("Attributes: Character's point values make "
+ "the character's creation impossible. "
+ "Switch back to defaults.");
creationPoints = DEFAULT_POINTS;
attributeMinimum = DEFAULT_MIN_PTS;
attributeMaximum = DEFAULT_MAX_PTS;
diff --git a/src/resources/beinginfo.cpp b/src/resources/beinginfo.cpp
index 20c24d4f..f2edf1d8 100644
--- a/src/resources/beinginfo.cpp
+++ b/src/resources/beinginfo.cpp
@@ -73,8 +73,8 @@ void BeingInfo::setTargetCursorSize(const std::string &size)
const auto cursorSize = targetCursorSizeFromString(size);
if (!cursorSize)
{
- logger->log("Unknown targetCursor value \"%s\" for %s",
- size.c_str(), name.c_str());
+ Log::info("Unknown targetCursor value \"%s\" for %s",
+ size.c_str(), name.c_str());
}
targetCursorSize = cursorSize.value_or(ActorSprite::TC_MEDIUM);
}
@@ -84,8 +84,8 @@ void BeingInfo::setHoverCursor(const std::string &cursorName)
const auto cursor = cursorFromString(cursorName);
if (!cursor)
{
- logger->log("Unknown hoverCursor value \"%s\" for %s",
- cursorName.c_str(), name.c_str());
+ Log::info("Unknown hoverCursor value \"%s\" for %s",
+ cursorName.c_str(), name.c_str());
}
hoverCursor = cursor.value_or(Cursor::Pointer);
}
diff --git a/src/resources/chardb.cpp b/src/resources/chardb.cpp
index 9001b6c2..97f86d3a 100644
--- a/src/resources/chardb.cpp
+++ b/src/resources/chardb.cpp
@@ -54,7 +54,7 @@ void CharDB::load()
if (!root || root.name() != "chars")
{
- logger->log("CharDB: Failed to parse charcreation.xml.");
+ Log::info("CharDB: Failed to parse charcreation.xml.");
return;
}
@@ -86,7 +86,7 @@ void CharDB::load()
void CharDB::unload()
{
- logger->log("Unloading chars database...");
+ Log::info("Unloading chars database...");
mLoaded = false;
}
diff --git a/src/resources/dye.cpp b/src/resources/dye.cpp
index 0ecc9fd6..136c9334 100644
--- a/src/resources/dye.cpp
+++ b/src/resources/dye.cpp
@@ -63,8 +63,8 @@ DyePalette::DyePalette(const std::string &description)
}
else
{
- logger->log("Error, invalid embedded palette: %s",
- description.c_str());
+ Log::info("Error, invalid embedded palette: %s",
+ description.c_str());
return;
}
@@ -82,7 +82,7 @@ DyePalette::DyePalette(const std::string &description)
++pos;
}
- logger->log("Error, invalid embedded palette: %s", description.c_str());
+ Log::info("Error, invalid embedded palette: %s", description.c_str());
}
void DyePalette::getColor(int intensity, int color[3]) const
@@ -195,7 +195,7 @@ Dye::Dye(const std::string &description)
if (next_pos <= pos + 3 || description[pos + 1] != ':')
{
- logger->log("Error, invalid dye: %s", description.c_str());
+ Log::info("Error, invalid dye: %s", description.c_str());
return;
}
@@ -211,7 +211,7 @@ Dye::Dye(const std::string &description)
case 'C': i = 5; break;
case 'W': i = 6; break;
default:
- logger->log("Error, invalid dye: %s", description.c_str());
+ Log::info("Error, invalid dye: %s", description.c_str());
return;
}
mDyePalettes[i] = new DyePalette(description.substr(pos + 2,
@@ -289,7 +289,7 @@ void Dye::instantiate(std::string &target, const std::string &palettes)
}
else
{
- logger->log("Error, invalid dye placeholder: %s", target.c_str());
+ Log::info("Error, invalid dye placeholder: %s", target.c_str());
return;
}
s << target[next_pos];
diff --git a/src/resources/dye.h b/src/resources/dye.h
index 0fe68f07..1730d2fd 100644
--- a/src/resources/dye.h
+++ b/src/resources/dye.h
@@ -35,7 +35,7 @@ class DyePalette
* The string is either a file name or a sequence of hexadecimal RGB
* values separated by ',' and starting with '#'.
*/
- DyePalette(const std::string &pallete);
+ DyePalette(const std::string &description);
/**
* Gets a pixel color depending on its intensity. First color is
diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp
index d29483d1..c0f5f777 100644
--- a/src/resources/emotedb.cpp
+++ b/src/resources/emotedb.cpp
@@ -51,7 +51,7 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename)
const int id = node.getProperty("id", -1);
if (id == -1)
{
- logger->log("Emote Database: Emote with missing ID in %s!", filename.c_str());
+ Log::info("Emote Database: Emote with missing ID in %s!", filename.c_str());
return;
}
@@ -63,8 +63,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename)
if (emote.effectId == -1)
{
- logger->log("Emote Database: Warning: Emote %s has no attached effect in %s!",
- emote.name.c_str(), filename.c_str());
+ Log::info("Emote Database: Warning: Emote %s has no attached effect in %s!",
+ emote.name.c_str(), filename.c_str());
return;
}
@@ -74,8 +74,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename)
if (imageName.empty() || width <= 0 || height <= 0)
{
- logger->log("Emote Database: Warning: Emote %s has bad imageset values in %s",
- emote.name.c_str(), filename.c_str());
+ Log::info("Emote Database: Warning: Emote %s has bad imageset values in %s",
+ emote.name.c_str(), filename.c_str());
return;
}
@@ -85,8 +85,8 @@ void EmoteDB::readEmoteNode(XML::Node node, const std::string &filename)
if (!emote.is || emote.is->size() == 0)
{
- logger->log("Emote Database: Error loading imageset for emote %s in %s",
- emote.name.c_str(), filename.c_str());
+ Log::info("Emote Database: Error loading imageset for emote %s in %s",
+ emote.name.c_str(), filename.c_str());
return;
}
@@ -119,7 +119,7 @@ const Emote &EmoteDB::get(int id)
if (i == mEmotes.end())
{
- logger->log("EmoteDB: Warning, unknown emote ID %d requested", id);
+ Log::info("EmoteDB: Warning, unknown emote ID %d requested", id);
return mUnknown;
}
diff --git a/src/resources/hairdb.cpp b/src/resources/hairdb.cpp
index 6b88a4df..312188d6 100644
--- a/src/resources/hairdb.cpp
+++ b/src/resources/hairdb.cpp
@@ -40,7 +40,7 @@ void HairDB::readHairColorNode(XML::Node node, const std::string &filename)
int id = node.getProperty("id", 0);
if (mHairColors.find(id) != mHairColors.end())
- logger->log("HairDb: Redefinition of color Id %d in %s", id, filename.c_str());
+ Log::info("HairDb: Redefinition of color Id %d in %s", id, filename.c_str());
mHairColors[id] = node.getProperty("value", COLOR_WHITE);
}
@@ -55,7 +55,7 @@ void HairDB::unload()
if (!mLoaded)
return;
- logger->log("Unloading hair style and color database...");
+ Log::info("Unloading hair style and color database...");
mHairColors.clear();
mHairStyles.clear();
@@ -71,7 +71,7 @@ void HairDB::addHairStyle(int id)
id = -id;
if (mHairStyles.find(id) != mHairStyles.end())
- logger->log("Warning: Redefinition of hairstyle id %i:", id);
+ Log::warn("Redefinition of hairstyle id %i:", id);
mHairStyles.insert(id);
}
@@ -81,13 +81,13 @@ const std::string &HairDB::getHairColor(int id) const
if (!mLoaded)
{
// no idea if this can happen, but that check existed before
- logger->log("WARNING: HairDB::getHairColor() called before settings were loaded!");
+ Log::warn("HairDB::getHairColor() called before settings were loaded!");
}
auto it = mHairColors.find(id);
if (it != mHairColors.end())
return it->second;
- logger->log("HairDb: Error, unknown color Id# %d", id);
+ Log::info("HairDb: Error, unknown color Id# %d", id);
return mHairColors.at(0);
}
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index b36aea01..11d5c275 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -54,8 +54,7 @@ Image::Image(SDL_Texture *texture, int width, int height):
if (!texture)
{
- logger->log(
- "Image::Image(SDL_Texture*, ...): Couldn't load invalid Surface!");
+ Log::info("Image::Image(SDL_Texture*, ...): Couldn't load invalid Surface!");
}
}
@@ -72,8 +71,7 @@ Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight)
if (glimage == 0)
{
- logger->log(
- "Image::Image(GLuint, ...): Couldn't load invalid Surface!");
+ Log::info("Image::Image(GLuint, ...): Couldn't load invalid Surface!");
}
}
#endif
@@ -101,7 +99,7 @@ Resource *Image::load(SDL_RWops *rw)
if (!tmpImage)
{
- logger->log("Error, image load failed: %s", IMG_GetError());
+ Log::info("Error, image load failed: %s", IMG_GetError());
return nullptr;
}
@@ -117,20 +115,20 @@ Resource *Image::load(SDL_RWops *rw, const Dye &dye)
if (!surf)
{
- logger->log("Error, image load failed: %s", IMG_GetError());
+ Log::info("Error, image load failed: %s", IMG_GetError());
return nullptr;
}
if (surf->format->format != SDL_PIXELFORMAT_RGBA32)
{
- logger->log("Warning: image format is %s, not SDL_PIXELFORMAT_RGBA32. Converting...",
- SDL_GetPixelFormatName(surf->format->format));
+ Log::warn("Image format is %s, not SDL_PIXELFORMAT_RGBA32. Converting...",
+ SDL_GetPixelFormatName(surf->format->format));
SDL_Surface *convertedSurf = SDL_ConvertSurfaceFormat(surf, SDL_PIXELFORMAT_RGBA32, 0);
SDL_FreeSurface(surf);
if (!convertedSurf)
{
- logger->log("Error, image convert failed: %s", SDL_GetError());
+ Log::info("Error, image convert failed: %s", SDL_GetError());
return nullptr;
}
surf = convertedSurf;
@@ -219,8 +217,8 @@ Image *Image::_GLload(SDL_Surface *image)
if (realWidth < width || realHeight < height)
{
- logger->log("Warning: image too large, cropping to %dx%d texture!",
- realWidth, realHeight);
+ Log::warn("Image too large, cropping to %dx%d texture!",
+ realWidth, realHeight);
}
// Determine 32-bit masks based on byte order
@@ -253,7 +251,7 @@ Image *Image::_GLload(SDL_Surface *image)
if (!image)
{
- logger->log("Error, image convert failed: out of memory");
+ Log::info("Error, image convert failed: out of memory");
return nullptr;
}
@@ -308,7 +306,7 @@ Image *Image::_GLload(SDL_Surface *image)
errmsg = "GL_OUT_OF_MEMORY";
break;
}
- logger->log("Error: Image GL import failed: %s", errmsg);
+ Log::error("Image GL import failed: %s", errmsg);
return nullptr;
}
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index 34cf1fd8..1f194b4f 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -50,7 +50,7 @@ Image *ImageSet::get(size_t i) const
{
if (i >= mImages.size())
{
- logger->log("Warning: No sprite %d in this image set", (int) i);
+ Log::warn("No sprite %d in this image set", (int) i);
return nullptr;
}
diff --git a/src/resources/imagewriter.cpp b/src/resources/imagewriter.cpp
index ddf1fbee..cf4c6803 100644
--- a/src/resources/imagewriter.cpp
+++ b/src/resources/imagewriter.cpp
@@ -42,7 +42,7 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename)
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr)
{
- logger->log("Had trouble creating png_structp");
+ Log::info("Had trouble creating png_structp");
return false;
}
@@ -50,21 +50,21 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename)
if (!info_ptr)
{
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
- logger->log("Could not create png_info");
+ Log::info("Could not create png_info");
return false;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
- logger->log("problem writing to %s", filename.c_str());
+ Log::info("problem writing to %s", filename.c_str());
return false;
}
FILE *fp = fopen(filename.c_str(), "wb");
if (!fp)
{
- logger->log("could not open file %s for writing", filename.c_str());
+ Log::info("could not open file %s for writing", filename.c_str());
return false;
}
@@ -83,7 +83,7 @@ bool ImageWriter::writePNG(SDL_Surface *surface, const std::string &filename)
row_pointers = new png_bytep[surface->h];
if (!row_pointers)
{
- logger->log("Had trouble converting surface to row pointers");
+ Log::info("Had trouble converting surface to row pointers");
fclose(fp);
return false;
}
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 05f6ad0b..1d217fc2 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -148,7 +148,7 @@ const ItemInfo &ItemDB::get(int id) const
auto i = mItemInfos.find(id);
if (i == mItemInfos.end())
{
- logger->log("ItemDB: Warning, unknown item ID# %d", id);
+ Log::info("ItemDB: Warning, unknown item ID# %d", id);
return *mUnknown;
}
@@ -164,8 +164,8 @@ const ItemInfo &ItemDB::get(const std::string &name) const
{
if (!name.empty())
{
- logger->log("ItemDB: Warning, unknown item name \"%s\"",
- name.c_str());
+ Log::info("ItemDB: Warning, unknown item name \"%s\"",
+ name.c_str());
}
return *mUnknown;
}
@@ -202,8 +202,8 @@ void ItemDB::loadSoundRef(ItemInfo &itemInfo, XML::Node node)
}
else
{
- logger->log("ItemDB: Ignoring unknown sound event '%s'",
- event.c_str());
+ Log::info("ItemDB: Ignoring unknown sound event '%s'",
+ event.c_str());
}
}
@@ -237,15 +237,15 @@ void ItemDB::loadReplacement(ItemInfo &info, XML::Node replaceNode)
if (sprite == SPRITE_UNKNOWN)
{
- logger->log("ItemDB: Invalid sprite name '%s' in replace tag",
- spriteString.data());
+ Log::info("ItemDB: Invalid sprite name '%s' in replace tag",
+ spriteString.data());
return;
}
if (direction == DIRECTION_UNKNOWN)
{
- logger->log("ItemDB: Invalid direction name '%s' in replace tag",
- directionString.data());
+ Log::info("ItemDB: Invalid direction name '%s' in replace tag",
+ directionString.data());
return;
}
@@ -266,7 +266,7 @@ void ItemDB::loadReplacement(ItemInfo &info, XML::Node replaceNode)
void ItemDB::unload()
{
- logger->log("Unloading item database...");
+ Log::info("Unloading item database...");
delete mUnknown;
mUnknown = nullptr;
@@ -283,12 +283,12 @@ void ItemDB::loadCommonRef(ItemInfo &itemInfo, XML::Node node, const std::string
if (!itemInfo.id)
{
- logger->log("ItemDB: Invalid or missing item Id in %s!", filename.c_str());
+ Log::info("ItemDB: Invalid or missing item Id in %s!", filename.c_str());
return;
}
else if (mItemInfos.find(itemInfo.id) != mItemInfos.end())
{
- logger->log("ItemDB: Redefinition of item Id %d in %s", itemInfo.id, filename.c_str());
+ Log::info("ItemDB: Redefinition of item Id %d in %s", itemInfo.id, filename.c_str());
}
itemInfo.mView = node.getProperty("view", 0);
@@ -346,8 +346,8 @@ void ItemDB::addItem(ItemInfo *itemInfo)
if (itr == mNamedItemInfos.end())
mNamedItemInfos[temp] = itemInfo;
else
- logger->log("ItemDB: Duplicate name (%s) for item id %d found.",
- temp.c_str(), itemInfo->id);
+ Log::info("ItemDB: Duplicate name (%s) for item id %d found.",
+ temp.c_str(), itemInfo->id);
}
}
@@ -359,7 +359,7 @@ static void checkParameter(int id, const T param, const T errorValue)
std::stringstream errMsg;
errMsg << "ItemDB: Missing " << param << " attribute for item id "
<< id << "!";
- logger->log("%s", errMsg.str().c_str());
+ Log::info("%s", errMsg.str().c_str());
}
}
@@ -368,7 +368,7 @@ void ItemDB::checkItemInfo(ItemInfo &itemInfo)
int id = itemInfo.id;
if (!itemInfo.attackAction.empty())
if (itemInfo.attackRange == 0)
- logger->log("ItemDB: Missing attack range from weapon %i!", id);
+ Log::info("ItemDB: Missing attack range from weapon %i!", id);
if (id >= 0)
{
@@ -504,7 +504,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename)
std::string trigger = itemChild.getProperty("trigger", std::string());
if (trigger.empty())
{
- logger->log("Found empty trigger effect label in %s, skipping.", filename.c_str());
+ Log::info("Found empty trigger effect label in %s, skipping.", filename.c_str());
continue;
}
@@ -514,8 +514,8 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename)
auto triggerLabel = triggerTable.find(trigger);
if (triggerLabel == triggerTable.end())
{
- logger->log("Warning: unknown trigger %s in item %d!",
- trigger.c_str(), itemInfo->id);
+ Log::warn("Unknown trigger %s in item %d!",
+ trigger.c_str(), itemInfo->id);
continue;
}
@@ -528,7 +528,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename)
int duration = effectChild.getProperty("duration", 0);
if (attribute.empty() || !value)
{
- logger->log("Warning: incomplete modifier definition in %s, skipping.", filename.c_str());
+ Log::warn("Incomplete modifier definition in %s, skipping.", filename.c_str());
continue;
}
auto it = extraStats.cbegin();
@@ -537,7 +537,7 @@ void ManaServItemDB::readItemNode(XML::Node node, const std::string &filename)
++it;
if (it == extraStats.end())
{
- logger->log("Warning: unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str());
+ Log::warn("Unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str());
continue;
}
effect.push_back(
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index b952cdcc..3ca5763c 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -77,7 +77,7 @@ static std::string resolveRelativePath(std::string base, std::string relative)
Map *MapReader::readMap(const std::string &filename)
{
- logger->log("Attempting to read map %s", filename.c_str());
+ Log::info("Attempting to read map %s", filename.c_str());
Map *map = nullptr;
XML::Document doc(filename);
@@ -89,7 +89,7 @@ Map *MapReader::readMap(const std::string &filename)
{
if (node.name() != "map")
{
- logger->log("Error: Not a map file (%s)!", filename.c_str());
+ Log::error("Not a map file (%s)!", filename.c_str());
}
else
{
@@ -98,7 +98,7 @@ Map *MapReader::readMap(const std::string &filename)
}
else
{
- logger->log("Error while parsing map file (%s)!", filename.c_str());
+ Log::info("Error while parsing map file (%s)!", filename.c_str());
}
if (map)
@@ -119,9 +119,9 @@ Map *MapReader::readMap(XML::Node node, const std::string &path)
if (tilew < 0 || tileh < 0)
{
- logger->log("MapReader: Warning: "
- "Unitialized tile width or height value for map: %s",
- path.c_str());
+ Log::info("MapReader: Warning: "
+ "Unitialized tile width or height value for map: %s",
+ path.c_str());
return nullptr;
}
@@ -174,15 +174,15 @@ Map *MapReader::readMap(XML::Node node, const std::string &path)
const int objW = objectNode.getProperty("width", 0);
const int objH = objectNode.getProperty("height", 0);
- logger->log("- Loading object name: %s type: %s at %d:%d",
- objName.c_str(), objType.c_str(),
- objX, objY);
+ Log::info("- Loading object name: %s type: %s at %d:%d",
+ objName.c_str(), objType.c_str(),
+ objX, objY);
if (objType == "PARTICLE_EFFECT")
{
if (objName.empty())
{
- logger->log(" Warning: No particle file given");
+ Log::info(" Warning: No particle file given");
continue;
}
@@ -203,7 +203,7 @@ Map *MapReader::readMap(XML::Node node, const std::string &path)
}
else
{
- logger->log(" Warning: Unknown object type");
+ Log::info(" Warning: Unknown object type");
}
}
}
@@ -293,7 +293,7 @@ static void readLayer(XML::Node node, Map *map)
map->addLayer(layer);
}
- logger->log("- Loading layer \"%s\"", name.c_str());
+ Log::info("- Loading layer \"%s\"", name.c_str());
int x = 0;
int y = 0;
@@ -333,8 +333,8 @@ static void readLayer(XML::Node node, Map *map)
if (!compression.empty() && compression != "gzip"
&& compression != "zlib")
{
- logger->log("Warning: only gzip or zlib layer "
- "compression supported!");
+ Log::warn("Only gzip or zlib layer "
+ "compression supported!");
return;
}
@@ -383,7 +383,7 @@ static void readLayer(XML::Node node, Map *map)
if (!inflated)
{
- logger->log("Error: Could not decompress layer!");
+ Log::error("Could not decompress layer!");
return;
}
}
@@ -415,7 +415,7 @@ static void readLayer(XML::Node node, Map *map)
const auto data = childNode.textContent();
if (data.empty())
{
- logger->log("Error: CSV layer data is empty!");
+ Log::error("CSV layer data is empty!");
continue;
}
@@ -432,7 +432,7 @@ static void readLayer(XML::Node node, Map *map)
if (errno == ERANGE)
{
- logger->log("Error: Range error in tile layer data!");
+ Log::error("Range error in tile layer data!");
break;
}
@@ -452,7 +452,7 @@ static void readLayer(XML::Node node, Map *map)
pos = strchr(end, ',');
if (!pos)
{
- logger->log("Error: CSV layer data too short!");
+ Log::error("CSV layer data too short!");
break;
}
++pos;
@@ -536,8 +536,7 @@ static Tileset *readTileset(XML::Node node, const std::string &path,
}
else
{
- logger->log("Warning: Failed to load tileset (%s)",
- source.c_str());
+ Log::warn("Failed to load tileset (%s)", source.c_str());
}
}
}
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index 4963f93f..7f092a0e 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -111,11 +111,11 @@ void MonsterDB::readMonsterNode(XML::Node node, const std::string &filename)
}
else
{
- logger->log("MonsterDB: Warning, sound effect %s for "
- "unknown event %s of monster %s in %s",
- soundFile.c_str(), event.c_str(),
- currentInfo->name.c_str(),
- filename.c_str());
+ Log::info("MonsterDB: Warning, sound effect %s for "
+ "unknown event %s of monster %s in %s",
+ soundFile.c_str(), event.c_str(),
+ currentInfo->name.c_str(),
+ filename.c_str());
}
}
else if (spriteNode.name() == "attack")
@@ -168,7 +168,7 @@ BeingInfo *MonsterDB::get(int id)
if (i == mMonsterInfos.end())
{
- logger->log("MonsterDB: Warning, unknown monster ID %d requested", id);
+ Log::info("MonsterDB: Warning, unknown monster ID %d requested", id);
return BeingInfo::Unknown;
}
diff --git a/src/resources/music.cpp b/src/resources/music.cpp
index 069af588..b73d89ce 100644
--- a/src/resources/music.cpp
+++ b/src/resources/music.cpp
@@ -40,7 +40,7 @@ Music *Music::load(SDL_RWops *rw)
return new Music(music);
}
- logger->log("Error, failed to load music: %s", Mix_GetError());
+ Log::info("Error, failed to load music: %s", Mix_GetError());
return nullptr;
}
diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp
index 6b1c3150..44292525 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -46,7 +46,7 @@ void NPCDB::readNPCNode(XML::Node node, const std::string &filename)
int id = node.getProperty("id", 0);
if (id == 0)
{
- logger->log("NPC Database: NPC with missing ID in %s", filename.c_str());
+ Log::info("NPC Database: NPC with missing ID in %s", filename.c_str());
return;
}
@@ -94,7 +94,7 @@ BeingInfo *NPCDB::get(int id)
if (i == mNPCInfos.end())
{
- logger->log("NPCDB: Warning, unknown NPC ID %d requested", id);
+ Log::info("NPCDB: Warning, unknown NPC ID %d requested", id);
return BeingInfo::Unknown;
}
diff --git a/src/resources/questdb.cpp b/src/resources/questdb.cpp
new file mode 100644
index 00000000..1424c20e
--- /dev/null
+++ b/src/resources/questdb.cpp
@@ -0,0 +1,232 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2025 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program 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 2 of the License, or
+ * any later version.
+ *
+ * This program 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 "resources/questdb.h"
+#include "log.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <utility>
+
+namespace QuestDB {
+
+// The quests are stored in a map using their variable ID as the key
+static std::unordered_map<int, Quest> quests;
+
+// Helper function to check if a container contains a value
+template<typename Container, typename Value>
+static bool contains(const Container &container, const Value &value)
+{
+ return std::find(container.begin(), container.end(), value) != container.end();
+}
+
+void init()
+{
+ unload();
+}
+
+void readQuestVarNode(XML::Node node, const std::string &filename)
+{
+ int varId = 0;
+ if (!node.attribute("id", varId))
+ return;
+
+ Quest &quest = quests[varId];
+
+ for (auto child : node.children())
+ {
+ if (child.name() == "effect")
+ {
+ QuestEffect &effect = quest.effects.emplace_back();
+ child.attribute("map", effect.map);
+ child.attribute("npc", effect.npcId);
+ child.attribute("effect", effect.statusEffectId);
+ child.attribute("value", effect.values);
+
+ if (effect.map.empty() || effect.npcId == 0 || effect.statusEffectId == 0 || effect.values.empty())
+ {
+ Log::warn("effect node for var %d is missing required attributes", varId);
+ }
+ }
+ else if (child.name() == "quest")
+ {
+ QuestState &state = quest.states.emplace_back();
+ child.attribute("name", state.name);
+ child.attribute("group", state.group);
+ child.attribute("incomplete", state.incomplete);
+ child.attribute("complete", state.complete);
+
+ if (state.incomplete.empty() && state.complete.empty())
+ {
+ Log::warn("quest node for var %d ('%s') has neither 'complete' nor 'incomplete' values",
+ varId, state.name.c_str());
+ continue;
+ }
+
+ for (auto questChild : child.children())
+ {
+ QuestRowType rowType;
+ std::string_view tag = questChild.name();
+ if (tag == "text")
+ rowType = QuestRowType::Text;
+ else if (tag == "name")
+ rowType = QuestRowType::Name;
+ else if (tag == "reward")
+ rowType = QuestRowType::Reward;
+ else if (tag == "questgiver" || tag == "giver")
+ rowType = QuestRowType::Giver;
+ else if (tag == "coordinates")
+ rowType = QuestRowType::Coordinates;
+ else if (tag == "npc")
+ rowType = QuestRowType::NPC;
+ else
+ {
+ Log::warn("unknown quest row type '%s' for var %d ('%s')",
+ tag.data(), varId, state.name.c_str());
+ continue;
+ }
+
+ QuestRow &row = state.rows.emplace_back(rowType);
+ row.text = questChild.textContent();
+
+ if (rowType == QuestRowType::Coordinates)
+ {
+ questChild.attribute("x", row.x);
+ questChild.attribute("y", row.y);
+ }
+ }
+ }
+ }
+}
+
+void unload()
+{
+ quests.clear();
+}
+
+bool hasQuests()
+{
+ return !quests.empty();
+}
+
+// In quests, the map name may include the file extension. This is discouraged
+// but supported for compatibility.
+static std::string_view baseName(const std::string &fileName)
+{
+ auto pos = fileName.find_last_of('.');
+ return pos == std::string::npos ? fileName : std::string_view(fileName.data(), pos);
+}
+
+QuestEffectMap getActiveEffects(const QuestVars &questVars,
+ const std::string &mapName)
+{
+ QuestEffectMap activeEffects;
+
+ for (auto &[var, quest] : std::as_const(quests))
+ {
+ auto value = questVars.get(var);
+
+ for (auto &effect : quest.effects)
+ {
+ if (baseName(effect.map) != mapName)
+ continue;
+ if (!contains(effect.values, value))
+ continue;
+
+ activeEffects.set(effect.npcId, effect.statusEffectId);
+ }
+ }
+
+ return activeEffects;
+}
+
+std::vector<QuestEntry> getQuestsEntries(const QuestVars &questVars,
+ bool skipCompleted)
+{
+ std::vector<QuestEntry> activeQuests;
+
+ for (auto &[varId, quest] : std::as_const(quests))
+ {
+ auto value = questVars.get(varId);
+
+ for (auto &state : quest.states)
+ {
+ bool matchesIncomplete = contains(state.incomplete, value);
+ bool matchesComplete = contains(state.complete, value);
+
+ if (skipCompleted && matchesComplete)
+ continue;
+
+ if (matchesIncomplete || matchesComplete)
+ {
+ QuestEntry &entry = activeQuests.emplace_back();
+ entry.varId = varId;
+ entry.completed = matchesComplete;
+ entry.state = &state;
+ }
+ }
+ }
+
+ return activeQuests;
+}
+
+static std::pair<int, int> countQuestEntries(const Quest &quest, int value)
+{
+ int totalEntries = 0;
+ int completedEntries = 0;
+
+ for (const auto &state : quest.states)
+ {
+ bool matchesIncomplete = contains(state.incomplete, value);
+ bool matchesComplete = contains(state.complete, value);
+
+ if (matchesIncomplete || matchesComplete)
+ {
+ totalEntries++;
+ if (matchesComplete)
+ completedEntries++;
+ }
+ }
+
+ return { totalEntries, completedEntries };
+}
+
+QuestChange questChange(int varId, int oldValue, int newValue)
+{
+ if (newValue == oldValue)
+ return QuestChange::None;
+
+ auto questIt = quests.find(varId);
+ if (questIt == quests.end())
+ return QuestChange::None;
+
+ const Quest &quest = questIt->second;
+
+ auto [oldQuestEntries, oldCompletedEntries] = countQuestEntries(quest, oldValue);
+ auto [newQuestEntries, newCompletedEntries] = countQuestEntries(quest, newValue);
+
+ if (newCompletedEntries > oldCompletedEntries)
+ return QuestChange::Completed;
+ if (newQuestEntries > oldQuestEntries)
+ return QuestChange::New;
+ return QuestChange::None;
+}
+
+} // namespace QuestDB
diff --git a/src/resources/questdb.h b/src/resources/questdb.h
new file mode 100644
index 00000000..43996b0b
--- /dev/null
+++ b/src/resources/questdb.h
@@ -0,0 +1,139 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2025 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * This program 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 2 of the License, or
+ * any later version.
+ *
+ * This program 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/>.
+ */
+
+#pragma once
+
+#include "utils/xml.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+/**
+ * A map that returns a default value for non-existent keys.
+ */
+template<typename Key, typename Value, Value def = Value()>
+class MapWithDefault
+{
+public:
+ void set(Key key, Value value)
+ {
+ mVars[key] = value;
+ }
+
+ Value get(Key key) const
+ {
+ auto it = mVars.find(key);
+ return it != mVars.end() ? it->second : def;
+ }
+
+ void clear()
+ {
+ mVars.clear();
+ }
+
+private:
+ std::map<Key, Value> mVars;
+};
+
+struct QuestEffect
+{
+ std::vector<int> values; // Quest variable values to which the effect applies
+ std::string map; // Map name the NPC is located on
+ int npcId = 0;
+ int statusEffectId = 0;
+};
+
+// Map of quest variables, from variable ID to value
+using QuestVars = MapWithDefault<int, int>;
+
+// Map of quest effects, from NPC ID to status effect ID
+using QuestEffectMap = MapWithDefault<int, int>;
+
+enum class QuestRowType
+{
+ Text,
+ Name,
+ Reward,
+ Giver,
+ Coordinates,
+ NPC
+};
+
+struct QuestRow
+{
+ QuestRow(QuestRowType type)
+ : type(type)
+ {}
+
+ QuestRowType type;
+ std::string text;
+ int x = 0;
+ int y = 0;
+};
+
+struct QuestState
+{
+ std::string name; // Name of the quest in this state
+ std::string group; // Group name of the quest in this state
+ std::vector<int> incomplete; // Quest variable values for this state (quest incomplete)
+ std::vector<int> complete; // Quest variable values for this state (quest complete)
+ std::vector<QuestRow> rows; // Rows of text in the Quests window for this state
+};
+
+struct Quest
+{
+ std::vector<QuestEffect> effects;
+ std::vector<QuestState> states;
+};
+
+struct QuestEntry
+{
+ int varId;
+ bool completed;
+ const QuestState *state;
+
+ const std::string &name() const { return state->name; }
+ const std::vector<QuestRow> &rows() const { return state->rows; }
+};
+
+enum class QuestChange
+{
+ None,
+ New,
+ Completed
+};
+
+namespace QuestDB
+{
+ void init();
+ void readQuestVarNode(XML::Node node, const std::string &filename);
+ void unload();
+
+ bool hasQuests();
+
+ QuestEffectMap getActiveEffects(const QuestVars &questVars,
+ const std::string &mapName);
+
+ std::vector<QuestEntry> getQuestsEntries(const QuestVars &questVars,
+ bool skipCompleted = false);
+
+ QuestChange questChange(int varId, int oldValue, int newValue);
+};
diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp
index cdff8060..17864cf5 100644
--- a/src/resources/resource.cpp
+++ b/src/resources/resource.cpp
@@ -31,7 +31,7 @@ void Resource::decRef(OrphanPolicy orphanPolicy)
{
// Reference may not already have reached zero
if (mRefCount == 0) {
- logger->log("Warning: mRefCount already zero for %s", mIdPath.c_str());
+ Log::warn("mRefCount already zero for %s", mIdPath.c_str());
assert(false);
}
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index e62407e3..2857c0df 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -45,7 +45,7 @@ ResourceManager *ResourceManager::instance = nullptr;
ResourceManager::ResourceManager()
{
- logger->log("Initializing resource manager...");
+ Log::info("Initializing resource manager...");
}
ResourceManager::~ResourceManager()
@@ -86,11 +86,11 @@ void ResourceManager::cleanUp(Resource *res)
{
if (res->mRefCount > 0)
{
- logger->log("ResourceManager::~ResourceManager() cleaning up %d "
- "reference%s to %s",
- res->mRefCount,
- (res->mRefCount == 1) ? "" : "s",
- res->mIdPath.c_str());
+ Log::info("ResourceManager::~ResourceManager() cleaning up %d "
+ "reference%s to %s",
+ res->mRefCount,
+ (res->mRefCount == 1) ? "" : "s",
+ res->mIdPath.c_str());
}
delete res;
@@ -118,7 +118,7 @@ void ResourceManager::cleanOrphans()
}
else
{
- logger->log("ResourceManager::release(%s)", res->mIdPath.c_str());
+ Log::info("ResourceManager::release(%s)", res->mIdPath.c_str());
iter = mOrphanedResources.erase(iter);
delete res; // delete only after removal from list, to avoid issues in recursion
}
@@ -129,12 +129,12 @@ void ResourceManager::cleanOrphans()
bool ResourceManager::addToSearchPath(const std::string &path, bool append)
{
- logger->log("Adding to PhysicsFS: %s", path.c_str());
if (!FS::addToSearchPath(path, append))
{
- logger->log("Error: %s", FS::getLastError());
+ Log::error("Couldn't add search path: %s (%s)", path.c_str(), FS::getLastError());
return false;
}
+ Log::info("Added search path: %s", path.c_str());
return true;
}
diff --git a/src/resources/settingsmanager.cpp b/src/resources/settingsmanager.cpp
index 9323d4d1..3dfb5eb4 100644
--- a/src/resources/settingsmanager.cpp
+++ b/src/resources/settingsmanager.cpp
@@ -27,6 +27,7 @@
#include "resources/monsterdb.h"
#include "resources/npcdb.h"
#include "resources/abilitydb.h"
+#include "resources/questdb.h"
#include "resources/statuseffectdb.h"
#include "net/net.h"
@@ -38,6 +39,9 @@
#include "log.h"
#include "units.h"
+#include <string>
+#include <set>
+
namespace SettingsManager
{
static std::string mSettingsFile;
@@ -53,6 +57,7 @@ namespace SettingsManager
hairDB.init();
itemDb->init();
MonsterDB::init();
+ QuestDB::init();
AbilityDB::init();
NPCDB::init();
EmoteDB::init();
@@ -96,6 +101,7 @@ namespace SettingsManager
NPCDB::unload();
AbilityDB::unload();
MonsterDB::unload();
+ QuestDB::unload();
if (itemDb)
itemDb->unload();
hairDB.unload();
@@ -107,7 +113,7 @@ namespace SettingsManager
*/
static bool loadFile(const std::string &filename)
{
- logger->log("Loading game settings from %s", filename.c_str());
+ Log::info("Loading game settings from %s", filename.c_str());
XML::Document doc(filename);
XML::Node node = doc.rootNode();
@@ -118,7 +124,7 @@ namespace SettingsManager
// FIXME: check root node's name when bjorn decides it's time
if (!node /*|| node.name() != "settings" */)
{
- logger->log("Settings Manager: %s is not a valid settings file!", filename.c_str());
+ Log::info("Settings Manager: %s is not a valid settings file!", filename.c_str());
return false;
}
@@ -156,7 +162,7 @@ namespace SettingsManager
// check if we're not entering a loop
if (mIncludedFiles.find(includeFile) != mIncludedFiles.end())
{
- logger->log("Warning: Circular include loop detecting while including %s from %s", includeFile.c_str(), filename.c_str());
+ Log::warn("Circular include loop detecting while including %s from %s", includeFile.c_str(), filename.c_str());
}
else
{
@@ -165,7 +171,7 @@ namespace SettingsManager
}
else
{
- logger->log("Warning: <include> element without 'file' or 'name' attribute in %s", filename.c_str());
+ Log::warn("<include> element without 'file' or 'name' attribute in %s", filename.c_str());
}
}
else if (childNode.name() == "option")
@@ -177,7 +183,7 @@ namespace SettingsManager
if (!name.empty())
paths.setValue(name, value);
else
- logger->log("Warning: option without a name found in %s", filename.c_str());
+ Log::warn("option without a name found in %s", filename.c_str());
}
else if (childNode.name() == "attribute")
{
@@ -221,6 +227,10 @@ namespace SettingsManager
{
NPCDB::readNPCNode(childNode, filename);
}
+ else if (childNode.name() == "var")
+ {
+ QuestDB::readQuestVarNode(childNode, filename);
+ }
else if (childNode.name() == "emote")
{
EmoteDB::readEmoteNode(childNode, filename);
diff --git a/src/resources/settingsmanager.h b/src/resources/settingsmanager.h
index 5b70f865..d9a6994c 100644
--- a/src/resources/settingsmanager.h
+++ b/src/resources/settingsmanager.h
@@ -20,10 +20,6 @@
#pragma once
-#include <string>
-#include <list>
-#include <set>
-
namespace SettingsManager
{
void load();
diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp
index 19d7a820..1b0492d7 100644
--- a/src/resources/soundeffect.cpp
+++ b/src/resources/soundeffect.cpp
@@ -36,7 +36,7 @@ SoundEffect *SoundEffect::load(SDL_RWops *rw)
return new SoundEffect(soundEffect);
}
- logger->log("Error, failed to load sound effect: %s", Mix_GetError());
+ Log::info("Error, failed to load sound effect: %s", Mix_GetError());
return nullptr;
}
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 85e5e566..0e7f12dd 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -44,7 +44,7 @@ Action *SpriteDef::getAction(const std::string &action) const
if (i == mActions.end())
{
- logger->log("Warning: no action \"%s\" defined!", action.c_str());
+ Log::warn("No action \"%s\" defined!", action.c_str());
return nullptr;
}
@@ -66,7 +66,7 @@ SpriteDef *SpriteDef::load(const std::string &animationFile, int variant)
if (!rootNode || rootNode.name() != "sprite")
{
- logger->log("Error, failed to parse %s", animationFile.c_str());
+ Log::info("Error, failed to parse %s", animationFile.c_str());
std::string errorFile = paths.getStringValue("sprites")
+ paths.getStringValue("spriteErrorFile");
@@ -157,7 +157,7 @@ void SpriteDef::loadImageSet(XML::Node node, const std::string &palettes)
auto imageSet = resman->getImageSet(imageSrc, width, height);
if (!imageSet)
{
- logger->error(strprintf("Couldn't load imageset (%s)!",
+ Log::critical(strprintf("Couldn't load imageset (%s)!",
imageSrc.c_str()));
}
@@ -174,16 +174,16 @@ void SpriteDef::loadAction(XML::Node node, int variant_offset)
auto si = mImageSets.find(imageSetName);
if (si == mImageSets.end())
{
- logger->log("Warning: imageset \"%s\" not defined in %s",
- imageSetName.c_str(), getIdPath().c_str());
+ Log::warn("imageset \"%s\" not defined in %s",
+ imageSetName.c_str(), getIdPath().c_str());
return;
}
ImageSet *imageSet = si->second;
if (actionName == SpriteAction::INVALID)
{
- logger->log("Warning: Unknown action \"%s\" defined in %s",
- actionName.c_str(), getIdPath().c_str());
+ Log::warn("Unknown action \"%s\" defined in %s",
+ actionName.c_str(), getIdPath().c_str());
return;
}
auto *action = new Action;
@@ -215,8 +215,8 @@ void SpriteDef::loadAnimation(XML::Node animationNode,
if (directionType == DIRECTION_INVALID)
{
- logger->log("Warning: Unknown direction \"%s\" used in %s",
- directionName.c_str(), getIdPath().c_str());
+ Log::warn("Unknown direction \"%s\" used in %s",
+ directionName.c_str(), getIdPath().c_str());
return;
}
@@ -239,7 +239,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode,
if (index < 0)
{
- logger->log("No valid value for 'index'");
+ Log::info("No valid value for 'index'");
continue;
}
@@ -247,7 +247,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode,
if (!img)
{
- logger->log("No image at index %d", index + variant_offset);
+ Log::info("No image at index %d", index + variant_offset);
continue;
}
@@ -260,7 +260,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode,
if (start < 0 || end < 0)
{
- logger->log("No valid value for 'start' or 'end'");
+ Log::info("No valid value for 'start' or 'end'");
continue;
}
@@ -270,7 +270,7 @@ void SpriteDef::loadAnimation(XML::Node animationNode,
if (!img)
{
- logger->log("No image at index %d", start + variant_offset);
+ Log::info("No image at index %d", start + variant_offset);
break;
}
@@ -295,8 +295,8 @@ void SpriteDef::includeSprite(XML::Node includeNode)
if (processedFiles.find(filename) != processedFiles.end())
{
- logger->log("Error, Tried to include %s which already is included.",
- filename.c_str());
+ Log::info("Error, Tried to include %s which already is included.",
+ filename.c_str());
return;
}
processedFiles.insert(filename);
@@ -306,7 +306,7 @@ void SpriteDef::includeSprite(XML::Node includeNode)
if (!rootNode || rootNode.name() != "sprite")
{
- logger->log("Error, no sprite root node in %s", filename.c_str());
+ Log::info("Error, no sprite root node in %s", filename.c_str());
return;
}
diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp
index 8e4a07be..0c332902 100644
--- a/src/resources/theme.cpp
+++ b/src/resources/theme.cpp
@@ -25,7 +25,6 @@
#include "configuration.h"
#include "log.h"
-#include "textrenderer.h"
#include "resources/dye.h"
#include "resources/image.h"
@@ -75,7 +74,7 @@ ThemeInfo::ThemeInfo(const std::string &path)
if (rootNode.attribute("name", name) && !name.empty())
this->doc = std::move(doc);
else
- logger->log("Error: Theme '%s' has no name!", path.c_str());
+ Log::error("Theme '%s' has no name!", path.c_str());
}
std::string ThemeInfo::getFullPath() const
@@ -228,15 +227,14 @@ void Skin::updateAlpha(float alpha)
Theme::Theme(const ThemeInfo &themeInfo)
: mThemePath(themeInfo.getFullPath())
- , mProgressColors(THEME_PROG_END)
{
listen(Event::ConfigChannel);
readTheme(themeInfo);
if (mPalettes.empty())
{
- logger->log("Error, theme did not define any palettes: %s",
- themeInfo.getPath().c_str());
+ Log::info("Error, theme did not define any palettes: %s",
+ themeInfo.getPath().c_str());
// Avoid crashing
mPalettes.emplace_back(THEME_COLORS_END);
@@ -377,9 +375,12 @@ void Theme::drawSkin(Graphics *graphics, SkinType type, const WidgetState &state
getSkin(type).draw(graphics, state);
}
-void Theme::drawProgressBar(Graphics *graphics, const gcn::Rectangle &area,
- const gcn::Color &color, float progress,
- const std::string &text) const
+void Theme::drawProgressBar(Graphics *graphics,
+ const gcn::Rectangle &area,
+ const gcn::Color &color,
+ float progress,
+ const std::string &text,
+ ProgressPalette progressType) const
{
gcn::Font *oldFont = graphics->getFont();
gcn::Color oldColor = graphics->getColor();
@@ -408,17 +409,21 @@ void Theme::drawProgressBar(Graphics *graphics, const gcn::Rectangle &area,
{
if (auto skinState = skin.getState(widgetState.flags))
{
- auto font = skinState->textFormat.bold ? boldFont : gui->getFont();
+ const TextFormat *textFormat = &skinState->textFormat;
+
+ if (progressType < THEME_PROG_END && mProgressTextFormats[progressType])
+ textFormat = &(*mProgressTextFormats[progressType]);
+
+ auto font = textFormat->bold ? boldFont : gui->getFont();
const int textX = area.x + area.width / 2;
const int textY = area.y + (area.height - font->getHeight()) / 2;
- TextRenderer::renderText(graphics,
- text,
- textX,
- textY,
- gcn::Graphics::CENTER,
- font,
- skinState->textFormat);
+ graphics->drawText(text,
+ textX,
+ textY,
+ gcn::Graphics::CENTER,
+ font,
+ *textFormat);
}
}
@@ -479,7 +484,7 @@ static bool check(bool value, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
- logger->vlog(msg, ap);
+ Log::vinfo(msg, ap);
va_end(ap);
}
return !value;
@@ -487,9 +492,9 @@ static bool check(bool value, const char *msg, ...)
bool Theme::readTheme(const ThemeInfo &themeInfo)
{
- logger->log("Loading %s theme from '%s'...",
- themeInfo.getName().c_str(),
- themeInfo.getPath().c_str());
+ Log::info("Loading %s theme from '%s'...",
+ themeInfo.getName().c_str(),
+ themeInfo.getPath().c_str());
XML::Node rootNode = themeInfo.getDocument().rootNode();
@@ -507,10 +512,10 @@ bool Theme::readTheme(const ThemeInfo &themeInfo)
else if (childNode.name() == "icon")
readIconNode(childNode);
else
- logger->log("Theme: Unknown node '%s'!", childNode.name().data());
+ Log::info("Theme: Unknown node '%s'!", childNode.name().data());
}
- logger->log("Finished loading theme.");
+ Log::info("Finished loading theme.");
for (auto &[_, skin] : mSkins)
skin.updateAlpha(mAlpha);
@@ -588,9 +593,8 @@ static void readSkinStateRectNode(XML::Node node, SkinState &state)
node.attribute("fill", rect.filled);
}
-static void readSkinStateTextNode(XML::Node node, SkinState &state)
+static void readTextNode(XML::Node node, TextFormat &textFormat)
{
- auto &textFormat = state.textFormat;
node.attribute("bold", textFormat.bold);
node.attribute("color", textFormat.color);
node.attribute("outlineColor", textFormat.outlineColor);
@@ -625,7 +629,7 @@ void Theme::readSkinStateNode(XML::Node node, Skin &skin) const
else if (childNode.name() == "rect")
readSkinStateRectNode(childNode, state);
else if (childNode.name() == "text")
- readSkinStateTextNode(childNode, state);
+ readTextNode(childNode, state.textFormat);
}
skin.addState(std::move(state));
@@ -689,7 +693,7 @@ void Theme::readSkinStateImgNode(XML::Node node, SkinState &state) const
border.right = right;
border.top = top;
border.bottom = bottom;
- border.image = image->getSubImage(x, y, width, height);
+ border.image.reset(image->getSubImage(x, y, width, height));
node.attribute("fill", border.fillMode);
}
@@ -705,7 +709,7 @@ inline void fromString(const char *str, gcn::Color &value)
if (strlen(str) < 7 || str[0] != '#')
{
error:
- logger->log("Error, invalid theme color palette: %s", str);
+ Log::info("Error, invalid theme color palette: %s", str);
value = gcn::Color(0, 0, 0);
return;
}
@@ -788,6 +792,7 @@ static int readColorId(const std::string &id)
"WHISPER_TAB",
"BACKGROUND",
"HIGHLIGHT",
+ "HIGHLIGHT_TEXT",
"TAB_FLASH",
"SHOP_WARNING",
"ITEM_EQUIPPED",
@@ -873,7 +878,7 @@ void Theme::readPaletteNode(XML::Node node)
{
int paletteId;
if (node.attribute("id", paletteId) && static_cast<size_t>(paletteId) != mPalettes.size())
- logger->log("Theme: Non-consecutive palette 'id' attribute with value %d!", paletteId);
+ Log::info("Theme: Non-consecutive palette 'id' attribute with value %d!", paletteId);
Palette &palette = mPalettes.emplace_back(THEME_COLORS_END);
@@ -882,7 +887,7 @@ void Theme::readPaletteNode(XML::Node node)
if (childNode.name() == "color")
readColorNode(childNode, palette);
else
- logger->log("Theme: Unknown node '%s'!", childNode.name().data());
+ Log::info("Theme: Unknown node '%s'!", childNode.name().data());
}
}
@@ -916,5 +921,15 @@ void Theme::readProgressBarNode(XML::Node node)
if (check(id >= 0, "Theme: 'progress' element has unknown 'id' attribute: '%s'!", idStr.c_str()))
return;
- mProgressColors[id] = std::make_unique<DyePalette>(node.getProperty("color", std::string()));
+ std::string color;
+ if (node.attribute("color", color))
+ mProgressColors[id] = std::make_unique<DyePalette>(color);
+
+ for (auto childNode : node.children())
+ {
+ if (childNode.name() == "text")
+ readTextNode(childNode, mProgressTextFormats[id].emplace());
+ else
+ Log::info("Theme: Unknown node '%s' in progressbar!", childNode.name().data());
+ }
}
diff --git a/src/resources/theme.h b/src/resources/theme.h
index bfd3b33a..fbcb263b 100644
--- a/src/resources/theme.h
+++ b/src/resources/theme.h
@@ -30,6 +30,7 @@
#include "resources/image.h"
#include "utils/xml.h"
+#include <array>
#include <map>
#include <memory>
#include <optional>
@@ -227,6 +228,7 @@ class Theme : public EventListener
WHISPER_TAB,
BACKGROUND,
HIGHLIGHT,
+ HIGHLIGHT_TEXT,
TAB_FLASH,
SHOP_WARNING,
ITEM_EQUIPPED,
@@ -283,7 +285,7 @@ class Theme : public EventListener
static const gcn::Color &getThemeColor(int type);
static gcn::Color getProgressColor(int type, float progress);
-
+
const Palette &getPalette(size_t index) const;
/**
@@ -305,7 +307,8 @@ class Theme : public EventListener
const gcn::Rectangle &area,
const gcn::Color &color,
float progress,
- const std::string &text = std::string()) const;
+ const std::string &text = std::string(),
+ ProgressPalette progressType = ProgressPalette::THEME_PROG_END) const;
const Skin &getSkin(SkinType skinType) const;
@@ -357,5 +360,6 @@ class Theme : public EventListener
float mAlpha = 1.0;
std::vector<Palette> mPalettes;
- std::vector<std::unique_ptr<DyePalette>> mProgressColors;
+ std::array<std::unique_ptr<DyePalette>, THEME_PROG_END> mProgressColors;
+ std::array<std::optional<TextFormat>, THEME_PROG_END> mProgressTextFormats;
};