summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-01-28 20:56:41 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-01-28 20:57:58 +0100
commit264be2108c51837fa92085f6c839e66aebbcfc9e (patch)
treee1f535d4cda5f399e5e622f6154690a0a4e08c4b
parentd86a1df562e00a6e930683534b9d001f45a951ff (diff)
downloadmana-client-264be2108c51837fa92085f6c839e66aebbcfc9e.tar.gz
mana-client-264be2108c51837fa92085f6c839e66aebbcfc9e.tar.bz2
mana-client-264be2108c51837fa92085f6c839e66aebbcfc9e.tar.xz
mana-client-264be2108c51837fa92085f6c839e66aebbcfc9e.zip
Added support for map/layer mask
A custom "Mask" property on a layer or a "foregroundXmask" property on a map can now be used in combination with the SMSG_MAP_MASK to dynamically disable certain map layers from the server. Feature previously seen on ManaPlus and implemented for Mana client for compatibility. Also added a ResourceRef class for automating the Resource reference counting. Closes #44
-rw-r--r--src/map.cpp72
-rw-r--r--src/map.h7
-rw-r--r--src/net/tmwa/network.cpp9
-rw-r--r--src/net/tmwa/network.h1
-rw-r--r--src/net/tmwa/playerhandler.cpp10
-rw-r--r--src/net/tmwa/protocol.h2
-rw-r--r--src/properties.h21
-rw-r--r--src/resources/ambientlayer.cpp16
-rw-r--r--src/resources/ambientlayer.h27
-rw-r--r--src/resources/mapreader.cpp20
-rw-r--r--src/resources/resource.h68
11 files changed, 188 insertions, 65 deletions
diff --git a/src/map.cpp b/src/map.cpp
index 76ddc56a..1ba62fcd 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -255,61 +255,46 @@ void Map::initializeAmbientLayers()
{
ResourceManager *resman = ResourceManager::getInstance();
+ auto addAmbientLayer = [=](const std::string &name, std::list<AmbientLayer*> &list)
+ {
+ if (Image *img = resman->getImage(getProperty(name + "image")))
+ {
+ auto ambientLayer = new AmbientLayer(img);
+ ambientLayer->mParallax = getFloatProperty(name + "parallax");
+ ambientLayer->mSpeedX = getFloatProperty(name + "scrollX");
+ ambientLayer->mSpeedY = getFloatProperty(name + "scrollY");
+ ambientLayer->mMask = getIntProperty(name + "mask", 1);
+
+ list.push_back(ambientLayer);
+
+ // The AmbientLayer takes control over the image.
+ img->decRef();
+ }
+ };
+
// search for "foreground*" or "overlay*" (old term) in map properties
for (int i = 0; /* terminated by a break */; i++)
{
- std::string name;
if (hasProperty("foreground" + toString(i) + "image"))
{
- name = "foreground" + toString(i);
+ addAmbientLayer("foreground" + toString(i), mForegrounds);
}
else if (hasProperty("overlay" + toString(i) + "image"))
{
- name = "overlay" + toString(i);
+ addAmbientLayer("overlay" + toString(i), mForegrounds);
}
else
{
break; // the FOR loop
}
-
- Image *img = resman->getImage(getProperty(name + "image"));
- const float speedX = getFloatProperty(name + "scrollX");
- const float speedY = getFloatProperty(name + "scrollY");
- const float parallax = getFloatProperty(name + "parallax");
- const bool keepRatio = getBoolProperty(name + "keepratio");
-
- if (img)
- {
- mForegrounds.push_back(
- new AmbientLayer(img, parallax, speedX, speedY, keepRatio));
-
- // The AmbientLayer takes control over the image.
- img->decRef();
- }
}
-
// search for "background*" in map properties
for (int i = 0;
hasProperty("background" + toString(i) + "image");
i++)
{
- const std::string name = "background" + toString(i);
-
- Image *img = resman->getImage(getProperty(name + "image"));
- const float speedX = getFloatProperty(name + "scrollX");
- const float speedY = getFloatProperty(name + "scrollY");
- const float parallax = getFloatProperty(name + "parallax");
- const bool keepRatio = getBoolProperty(name + "keepratio");
-
- if (img)
- {
- mBackgrounds.push_back(
- new AmbientLayer(img, parallax, speedX, speedY, keepRatio));
-
- // The AmbientLayer takes control over the image.
- img->decRef();
- }
+ addAmbientLayer("background" + toString(i), mBackgrounds);
}
}
@@ -387,6 +372,9 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY)
{
for (; layeri != mLayers.end() && !overFringe; ++layeri)
{
+ if (((*layeri)->getMask() & mMask) == 0)
+ continue;
+
if ((*layeri)->isFringeLayer() && (mDebugFlags & DEBUG_SPECIAL2))
overFringe = true;
@@ -503,10 +491,16 @@ void Map::updateAmbientLayers(float scrollX, float scrollY)
std::list<AmbientLayer*>::iterator i;
for (i = mBackgrounds.begin(); i != mBackgrounds.end(); i++)
{
+ if (((*i)->mMask & mMask) == 0)
+ continue;
+
(*i)->update(timePassed, dx, dy);
}
for (i = mForegrounds.begin(); i != mForegrounds.end(); i++)
{
+ if (((*i)->mMask & mMask) == 0)
+ continue;
+
(*i)->update(timePassed, dx, dy);
}
mLastScrollX = scrollX;
@@ -541,6 +535,9 @@ void Map::drawAmbientLayers(Graphics *graphics, LayerType type,
for (auto i = layers->begin();
i != layers->end(); i++)
{
+ if (((*i)->mMask & mMask) == 0)
+ continue;
+
(*i)->draw(graphics, graphics->getWidth(), graphics->getHeight());
// Detail 1: only one overlay, higher: all overlays
@@ -1041,3 +1038,8 @@ TileAnimation *Map::getAnimationForGid(int gid) const
auto i = mTileAnimations.find(gid);
return (i == mTileAnimations.end()) ? NULL : i->second;
}
+
+void Map::setMask(int mask)
+{
+ mMask = mask;
+}
diff --git a/src/map.h b/src/map.h
index 2900b4d1..410ae16e 100644
--- a/src/map.h
+++ b/src/map.h
@@ -131,9 +131,13 @@ class MapLayer
int getTileDrawWidth(int x1, int y1, int endX, int &width) const;
+ void setMask(int mask) { mMask = mask; }
+ int getMask() const { return mMask; }
+
private:
int mX, mY;
int mWidth, mHeight;
+ int mMask = 1;
bool mIsFringeLayer; /**< Whether the actors are drawn. */
Image **mTiles;
Map *mMap; /** The mother map pointer */
@@ -335,6 +339,8 @@ class Map : public Properties
*/
TileAnimation *getAnimationForGid(int gid) const;
+ void setMask(int mask);
+
protected:
friend class Actor;
@@ -415,6 +421,7 @@ class Map : public Properties
std::map<int, TileAnimation*> mTileAnimations;
+ int mMask = 1;
};
#endif
diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp
index c1ba615f..d0a5dc62 100644
--- a/src/net/tmwa/network.cpp
+++ b/src/net/tmwa/network.cpp
@@ -40,7 +40,7 @@
// indicator for a variable-length packet
const uint16_t VAR = 1;
-uint16_t packet_lengths[0x220] = {
+uint16_t packet_lengths[] = {
10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -82,9 +82,12 @@ uint16_t packet_lengths[0x220] = {
VAR,VAR, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56,VAR, 4, 5, 10,
// #0x0200
26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 10, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,VAR, 16, 0, 8,VAR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ VAR,122,VAR,VAR,VAR,VAR, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
+static const int packet_lengths_size
+ = static_cast<int>(sizeof(packet_lengths) / sizeof(uint16_t));
const unsigned int BUFFER_SIZE = 65536;
namespace TmwAthena {
@@ -287,7 +290,7 @@ bool Network::messageReady()
// TODO don't hard-code this single case
if (msgId == SMSG_SERVER_VERSION_RESPONSE)
len = 10;
- else if (msgId < 0x220)
+ else if (msgId < packet_lengths_size)
len = packet_lengths[msgId];
if (len == VAR)
diff --git a/src/net/tmwa/network.h b/src/net/tmwa/network.h
index 97c7970f..4df44b75 100644
--- a/src/net/tmwa/network.h
+++ b/src/net/tmwa/network.h
@@ -41,6 +41,7 @@
* the protocol accordingly.
*/
#define CLIENT_PROTOCOL_VERSION 1
+// 10 -> 11: SMSG_MAP_MASK DONE
namespace TmwAthena {
diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp
index 6ef669e4..5c57b8aa 100644
--- a/src/net/tmwa/playerhandler.cpp
+++ b/src/net/tmwa/playerhandler.cpp
@@ -152,6 +152,7 @@ PlayerHandler::PlayerHandler()
SMSG_PLAYER_STAT_UPDATE_5,
SMSG_PLAYER_STAT_UPDATE_6,
SMSG_PLAYER_ARROW_MESSAGE,
+ SMSG_MAP_MASK,
0
};
handledMessages = _messages;
@@ -512,6 +513,15 @@ void PlayerHandler::handleMessage(MessageIn &msg)
}
}
break;
+
+ case SMSG_MAP_MASK:
+ {
+ const int mask = msg.readInt32();
+ msg.readInt32(); // unused
+ if (Map *map = Game::instance()->getCurrentMap())
+ map->setMask(mask);
+ }
+ break;
}
}
diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h
index 768d6061..e9ea84e8 100644
--- a/src/net/tmwa/protocol.h
+++ b/src/net/tmwa/protocol.h
@@ -213,6 +213,8 @@ static const int STORAGE_OFFSET = 1;
#define SMSG_MVP 0x010c
+#define SMSG_MAP_MASK 0x0226
+
/**********************************
* Packets from client to server *
**********************************/
diff --git a/src/properties.h b/src/properties.h
index 40be8d7f..84b6d184 100644
--- a/src/properties.h
+++ b/src/properties.h
@@ -71,6 +71,27 @@ class Properties
}
/**
+ * Gets a map property as an int.
+ *
+ * @param name The name of the property.
+ * @param def Default value, 0 by default.
+ * @return the value of the given property or the given default when it
+ * doesn't exist.
+ */
+ float getIntProperty(const std::string &name, int def = 0) const
+ {
+ auto i = mProperties.find(name);
+ int ret = def;
+ if (i != mProperties.end())
+ {
+ std::stringstream ss;
+ ss.str(i->second);
+ ss >> ret;
+ }
+ return ret;
+ }
+
+ /**
* Gets a map property as a boolean.
*
* @param name The name of the property.
diff --git a/src/resources/ambientlayer.cpp b/src/resources/ambientlayer.cpp
index 301927f8..b71378cb 100644
--- a/src/resources/ambientlayer.cpp
+++ b/src/resources/ambientlayer.cpp
@@ -25,20 +25,12 @@
#include "resources/image.h"
#include "resources/resourcemanager.h"
-AmbientLayer::AmbientLayer(Image *img, float parallax,
- float speedX, float speedY, bool keepRatio):
- mImage(img), mParallax(parallax),
- mPosX(0), mPosY(0),
- mSpeedX(speedX), mSpeedY(speedY),
- mKeepRatio(keepRatio)
-{
- mImage->incRef();
-}
+AmbientLayer::AmbientLayer(Image *img)
+ : mImage(img)
+{}
AmbientLayer::~AmbientLayer()
-{
- mImage->decRef();
-}
+{}
void AmbientLayer::update(int timePassed, float dx, float dy)
{
diff --git a/src/resources/ambientlayer.h b/src/resources/ambientlayer.h
index 9ccf5194..def2090b 100644
--- a/src/resources/ambientlayer.h
+++ b/src/resources/ambientlayer.h
@@ -21,6 +21,8 @@
#ifndef RESOURCES_AMBIENTOVERLAY_H
#define RESOURCES_AMBIENTOVERLAY_H
+#include "resource.h"
+
class Graphics;
class Image;
@@ -31,29 +33,24 @@ class AmbientLayer
* Constructor.
*
* @param img the image this overlay displays
- * @param parallax scroll factor based on camera position
- * @param speedX scrolling speed in x-direction
- * @param speedY scrolling speed in y-direction
- * @param keepRatio rescale the image to keep
- * the same ratio than in 800x600 resolution mode.
*/
- AmbientLayer(Image *img, float parallax,
- float speedX, float speedY, bool keepRatio = false);
-
+ AmbientLayer(Image *img);
~AmbientLayer();
void update(int timePassed, float dx, float dy);
void draw(Graphics *graphics, int x, int y);
+ float mParallax = 0; /**< Scroll factor based on camera position. */
+ float mSpeedX = 0; /**< Scrolling speed in X direction. */
+ float mSpeedY = 0; /**< Scrolling speed in Y direction. */
+ int mMask = 1;
+ bool mKeepRatio = false; /**< Keep overlay ratio on every resolution like in 800x600 */
+
private:
- Image *mImage;
- float mParallax;
- float mPosX; /**< Current layer X position. */
- float mPosY; /**< Current layer Y position. */
- float mSpeedX; /**< Scrolling speed in X direction. */
- float mSpeedY; /**< Scrolling speed in Y direction. */
- bool mKeepRatio; /**< Keep overlay ratio on every resolution */
+ ResourceRef<Image> mImage;
+ float mPosX = 0; /**< Current layer X position. */
+ float mPosY = 0; /**< Current layer Y position. */
};
#endif
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index af41da12..aba9f85d 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -276,6 +276,26 @@ void MapReader::readLayer(xmlNodePtr node, Map *map)
// Load the tile data
for_each_xml_child_node(childNode, node)
{
+ if (xmlStrEqual(childNode->name, BAD_CAST "properties"))
+ {
+ for_each_xml_child_node(prop, childNode)
+ {
+ if (!xmlStrEqual(prop->name, BAD_CAST "property"))
+ continue;
+
+ const std::string pname = XML::getProperty(prop, "name", "");
+ const std::string value = XML::getProperty(prop, "value", "");
+
+ // TODO: Consider supporting "Hidden", "Version" and "NotVersion"
+
+ if (pname == "Mask")
+ {
+ layer->setMask(atoi(value.c_str()));
+ }
+ }
+ continue;
+ }
+
if (!xmlStrEqual(childNode->name, BAD_CAST "data"))
continue;
diff --git a/src/resources/resource.h b/src/resources/resource.h
index af688eb0..988b78a5 100644
--- a/src/resources/resource.h
+++ b/src/resources/resource.h
@@ -69,4 +69,72 @@ class Resource
unsigned mRefCount; /**< Reference count. */
};
+/**
+ * Automatically counting Resource reference.
+ */
+template<typename RESOURCE>
+class ResourceRef
+{
+public:
+ // Allow implicit construction from RESOURCE *
+ ResourceRef(RESOURCE *resource = nullptr)
+ : mResource(resource)
+ {
+ if (mResource)
+ mResource->incRef();
+ }
+
+ // Copy constructor
+ ResourceRef(const ResourceRef &other)
+ : mResource(other.mResource)
+ {
+ if (mResource)
+ mResource->incRef();
+ }
+
+ // Move constructor
+ ResourceRef(ResourceRef &&other)
+ : mResource(other.mResource)
+ {
+ other.mResource = nullptr;
+ }
+
+ // Destructor
+ ~ResourceRef()
+ {
+ if (mResource)
+ mResource->decRef();
+ }
+
+ // Assignment operator
+ ResourceRef &operator=(const ResourceRef &other)
+ {
+ if (this != &other)
+ {
+ if (mResource)
+ mResource->decRef();
+
+ mResource = other.mResource;
+
+ if (mResource)
+ mResource->incRef();
+ }
+ return *this;
+ }
+
+ // Allow dereferencing
+ RESOURCE *operator->() const
+ { return mResource; }
+
+ RESOURCE *get() const
+ { return mResource; }
+
+ // Allow implicit conversion to RESOURCE *
+ operator RESOURCE *() const
+ { return mResource; }
+
+private:
+ RESOURCE *mResource;
+};
+
#endif