summaryrefslogtreecommitdiffstats
path: root/src/game-server/attribute.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/attribute.cpp')
-rw-r--r--src/game-server/attribute.cpp333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/game-server/attribute.cpp b/src/game-server/attribute.cpp
new file mode 100644
index 0000000..37ac07b
--- /dev/null
+++ b/src/game-server/attribute.cpp
@@ -0,0 +1,333 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2004-2010 The Mana World Development Team
+ *
+ * This file is part of The Mana Server.
+ *
+ * The Mana Server 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.
+ *
+ * The Mana Server 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 The Mana Server. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "attribute.hpp"
+#include "game-server/being.hpp"
+#include "utils/logger.h"
+#include <cassert>
+
+AttributeModifiersEffect::AttributeModifiersEffect(AT_TY sType, AME_TY eType)
+ : mMod(eType == AME_MULT ? 1 : 0), mSType(sType), mEType(eType)
+{
+ assert(eType == AME_MULT || eType == AME_ADD);
+ assert(sType == TY_ST || sType == TY_NST || sType == TY_NSTB);
+ LOG_DEBUG("Layer created with eType " << eType << " and sType " << sType << ".");
+}
+
+AttributeModifiersEffect::~AttributeModifiersEffect()
+{
+ // ?
+ /*mStates.clear();*/
+ LOG_WARN("DELETION of attribute effect!");
+}
+
+bool AttributeModifiersEffect::add(unsigned short duration, double value, double prevLayerValue, int level)
+{
+ LOG_DEBUG("Adding modifier with value " << value <<
+ " with a previous layer value of " << prevLayerValue << ". "
+ "Current mod at this layer: " << mMod << ".");
+ bool ret = false;
+ mStates.push_back(new AttributeModifierState(duration, value, level));
+ switch (mSType) {
+ case TY_ST:
+ switch (mEType) {
+ case AME_ADD:
+ if (value)
+ {
+ ret = true;
+ mMod += value;
+ mCacheVal = prevLayerValue + mMod;
+ }
+ break;
+ case AME_MULT:
+ if (value != 1)
+ {
+ ret = true;
+ mMod *= value;
+ mCacheVal = prevLayerValue * mMod;
+ }
+ break;
+ default:
+ LOG_FATAL("Attribute modifiers effect: unhandled type '"
+ << mEType << "' as a stackable!");
+ assert(0);
+ break;
+ }
+ break;
+ case TY_NST:
+ switch (mEType) {
+ case AME_ADD:
+ if (value > mMod)
+ {
+ ret = true;
+ mMod = value;
+ if (mMod > prevLayerValue)
+ mCacheVal = mMod;
+ }
+ break;
+ default:
+ LOG_FATAL("Attribute modifiers effect: unhandled type '"
+ << mEType << "' as a non-stackable!");
+ assert(0);
+ }
+ // A multiplicative type would also be nonsensical
+ break;
+ case TY_NSTB:
+ switch (mEType) {
+ case AME_ADD:
+ case AME_MULT:
+ if (value > mMod)
+ {
+ ret = true;
+ mMod = value;
+ mCacheVal = mEType == AME_ADD ? prevLayerValue + mMod
+ : prevLayerValue * mMod;
+ }
+ break;
+ default:
+ LOG_FATAL("Attribute modifiers effect: unhandled type '"
+ << mEType << "' as a non-stackable bonus!");
+ assert(0);
+ }
+ break;
+ default:
+ LOG_FATAL("Attribute modifiers effect: unknown modifier type '"
+ << mSType << "'!");
+ assert(0);
+ }
+ return ret;
+}
+
+bool durationCompare(const AttributeModifierState *lhs,
+ const AttributeModifierState *rhs)
+{ return lhs->mDuration < rhs->mDuration; }
+
+bool AttributeModifiersEffect::remove(double value, unsigned int id, bool fullCheck) {
+ /* We need to find and check this entry exists, and erase the entry
+ from the list too. */
+ if (!fullCheck)
+ mStates.sort(durationCompare); /* Search only through those with a duration of 0. */
+ bool ret = false;
+ for (std::list< AttributeModifierState * >::iterator it = mStates.begin();
+ it != mStates.end() && (fullCheck || !(*it)->mDuration);
+ ++it)
+ {
+ /* Check for a match */
+ if ((*it)->mValue != value || (*it)->mId != id)
+ continue;
+ if (mSType == TY_ST)
+ updateMod();
+ delete *it;
+ mStates.erase(it);
+ if (!id)
+ return true;
+ else ret = true;
+ }
+ if (ret && mSType != TY_ST)
+ updateMod();
+ return ret;
+}
+
+void AttributeModifiersEffect::updateMod(double value)
+{
+ if (mSType == TY_ST)
+ {
+ if (mEType == AME_ADD)
+ mMod -= value;
+ else if (mEType == AME_MULT)
+ mMod /= value;
+ else LOG_ERROR("Attribute modifiers effect: unhandled type '"
+ << mEType << "' as a stackable in cache update!");
+ }
+ else if (mSType == TY_NST || mSType == TY_NSTB)
+ {
+ if (mMod == value)
+ {
+ mMod = 0;
+ for (std::list< AttributeModifierState * >::const_iterator
+ it2 = mStates.begin(),
+ it2_end = mStates.end();
+ it2 != it2_end;
+ ++it2)
+ if ((*it2)->mValue > mMod)
+ mMod = (*it2)->mValue;
+ }
+ else LOG_ERROR("Attribute modifiers effect: unhandled type '"
+ << mEType << "' as a non-stackable in cache update!");
+ }
+ else LOG_ERROR("Attribute modifiers effect: unknown modifier type '"
+ << mSType << "' in cache update!");
+}
+
+bool AttributeModifiersEffect::recalculateModifiedValue(double newPrevLayerValue)
+ {
+ double oldValue = mCacheVal;
+ switch (mEType)
+ case AME_ADD: {
+ switch (mSType) {
+ case TY_ST:
+ case TY_NSTB:
+ mCacheVal = newPrevLayerValue + mMod;
+ break;
+ case TY_NST:
+ mCacheVal = newPrevLayerValue < mMod ? mMod : newPrevLayerValue;
+ break;
+ default:
+ LOG_FATAL("Unknown stack type '" << mEType << "'!");
+ assert(0);
+ } break;
+ case AME_MULT:
+ mCacheVal = mSType == TY_ST ? newPrevLayerValue * mMod : newPrevLayerValue * mMod;
+ break;
+ default:
+ LOG_FATAL("Unknown effect type '" << mEType << "'!");
+ assert(0);
+ }
+ return oldValue != mCacheVal;
+}
+
+bool Attribute::add(unsigned short duration, double value, unsigned int layer, int level)
+{
+ assert(mMods.size() > layer);
+ LOG_DEBUG("Adding modifier to attribute with duration " << duration <<
+ ", value " << value << ", at layer " << layer << " with id "
+ << level);
+ if (mMods.at(layer)->add(duration, value,
+ (layer ? mMods.at(layer - 1)->getCachedModifiedValue()
+ : mBase)
+ , level))
+ {
+ while (++layer < mMods.size())
+ {
+ if (!mMods.at(layer)->recalculateModifiedValue(
+ mMods.at(layer - 1)->getCachedModifiedValue()))
+ {
+ LOG_DEBUG("Modifier added, but modified value not changed.");
+ return false;
+ }
+ }
+ LOG_DEBUG("Modifier added. Base value: " << mBase << ", new modified "
+ "value: " << getModifiedAttribute() << ".");
+ return true;
+ }
+ LOG_DEBUG("Failed to add modifier!");
+ return false;
+}
+
+bool Attribute::remove(double value, unsigned int layer, int lvl, bool fullcheck)
+{
+ assert(mMods.size() > layer);
+ if (mMods.at(layer)->remove(value, lvl, fullcheck))
+ {
+ while (++layer < mMods.size())
+ if (!mMods.at(layer)->recalculateModifiedValue(
+ mMods.at(layer - 1)->getCachedModifiedValue()))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+bool AttributeModifiersEffect::tick()
+{
+ bool ret = false;
+ std::list<AttributeModifierState *>::iterator it = mStates.begin();
+ while (it != mStates.end())
+ {
+ if ((*it)->tick())
+ {
+ double value = (*it)->mValue;
+ LOG_DEBUG("Modifier of value " << value << " expiring!");
+ delete *it;
+ mStates.erase(it++);
+ updateMod(value);
+ ret = true;
+ }
+ ++it;
+ }
+ return ret;
+}
+
+Attribute::Attribute(const std::vector<struct AttributeInfoType> &type)
+{
+ LOG_DEBUG("Construction of new attribute with '" << type.size() << "' layers.");
+ for (unsigned int i = 0; i < type.size(); ++i)
+ {
+ LOG_DEBUG("Adding layer with stack type " << type[i].sType << " and effect type " << type[i].eType << ".");
+ mMods.push_back(new AttributeModifiersEffect(type[i].sType,
+ type[i].eType));
+ LOG_DEBUG("Layer added.");
+ }
+}
+
+Attribute::~Attribute()
+{
+ for (std::vector<AttributeModifiersEffect *>::iterator it = mMods.begin(),
+ it_end = mMods.end(); it != it_end; ++it)
+ {
+ // ?
+ //delete *it;
+ }
+}
+
+bool Attribute::tick()
+{
+ bool ret = false;
+ double prev = mBase;
+ for (std::vector<AttributeModifiersEffect *>::iterator it = mMods.begin(),
+ it_end = mMods.end(); it != it_end; ++it)
+ {
+ if ((*it)->tick())
+ {
+ LOG_DEBUG("Attribute layer " << mMods.begin() - it
+ << " has expiring modifiers.");
+ ret = true;
+ }
+ if (ret)
+ if (!(*it)->recalculateModifiedValue(prev)) ret = false;
+ prev = (*it)->getCachedModifiedValue();
+ }
+ return ret;
+}
+
+void Attribute::clearMods()
+{
+ for (std::vector<AttributeModifiersEffect *>::iterator it = mMods.begin(),
+ it_end = mMods.end(); it != it_end; ++it)
+ (*it)->clearMods(mBase);
+}
+
+void Attribute::setBase(double base) {
+ LOG_DEBUG("Setting base attribute from " << mBase << " to " << base << ".");
+ double prev = mBase = base;
+ std::vector<AttributeModifiersEffect *>::iterator it = mMods.begin();
+ while (it != mMods.end())
+ if ((*it)->recalculateModifiedValue(prev))
+ prev = (*it++)->getCachedModifiedValue();
+ else
+ break;
+}
+
+void AttributeModifiersEffect::clearMods(double baseValue)
+{
+ mStates.clear();
+ mCacheVal = baseValue;
+ mMod = mEType == AME_ADD ? 0 : 1;
+}