summaryrefslogtreecommitdiffstats
path: root/src/game-server/character.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/character.cpp')
-rw-r--r--src/game-server/character.cpp311
1 files changed, 146 insertions, 165 deletions
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 46ffa05..e24871c 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -27,6 +27,7 @@
#include "common/configuration.hpp"
#include "game-server/accountconnection.hpp"
+#include "game-server/attributemanager.hpp"
#include "game-server/buysell.hpp"
#include "game-server/eventlistener.hpp"
#include "game-server/inventory.hpp"
@@ -43,6 +44,7 @@
#include "serialize/characterdata.hpp"
#include "utils/logger.h"
+#include "utils/speedconv.hpp"
// These values should maybe be obtained from the config file
const float Character::EXPCURVE_EXPONENT = 3.0f;
@@ -67,18 +69,22 @@ Character::Character(MessageIn &msg):
mParty(0),
mTransaction(TRANS_NONE)
{
- Attribute attr = { 0, 0 };
- mAttributes.resize(CHAR_ATTR_NB, attr);
+ const AttributeScopes &attr = attributeManager->getAttributeInfoForType(ATTR_CHAR);
+ LOG_DEBUG("Character creation: initialisation of " << attr.size() << " attributes.");
+ for (AttributeScopes::const_iterator it1 = attr.begin(),
+ it1_end = attr.end();
+ it1 != it1_end;
+ ++it1)
+ mAttributes.insert(std::make_pair(it1->first,
+ Attribute(*it1->second)));
// Get character data.
mDatabaseID = msg.readLong();
setName(msg.readString());
deserializeCharacterData(*this, msg);
- for (int i = CHAR_ATTR_BEGIN; i < CHAR_ATTR_END; ++i)
- {
- modifiedAttribute(i);
- }
+ mOld = getPosition();
+ Inventory(this).initialise();
+ modifiedAllAttribute();
setSize(16);
- Inventory(this).initialize();
//give the character some specials for testing.
//TODO: get from quest vars and equipment
@@ -111,7 +117,7 @@ void Character::update()
}
if (numRechargeNeeded > 0)
{
- mRechargePerSpecial = getModifiedAttribute(CHAR_ATTR_INTELLIGENCE) / numRechargeNeeded;
+ mRechargePerSpecial = getModifiedAttribute(ATTR_INT) / numRechargeNeeded;
for (std::list<Special*>::iterator i = rechargeNeeded.begin(); i != rechargeNeeded.end(); i++)
{
(*i)->currentMana += mRechargePerSpecial;
@@ -145,36 +151,11 @@ void Character::perform()
return;
}
- // TODO: Check slot 2 too.
- int itemId = mPossessions.equipment[EQUIP_FIGHT1_SLOT];
- ItemClass *ic = ItemManager::getItem(itemId);
- int type = ic ? ic->getModifiers().getValue(MOD_WEAPON_TYPE) : 100;
-
- Damage damage;
- damage.base = getModifiedAttribute(BASE_ATTR_PHY_ATK_MIN);
- damage.delta = getModifiedAttribute(BASE_ATTR_PHY_ATK_DELTA) +
- getModifiedAttribute(type);
- damage.type = DAMAGE_PHYSICAL;
- damage.cth = getModifiedAttribute(BASE_ATTR_HIT) +
- getModifiedAttribute(type);
- damage.usedSkills.push_back(type);
-
- if (ic)
- {
- // weapon fighting
- const ItemModifiers &mods = ic->getModifiers();
- damage.element = mods.getValue(MOD_ELEMENT_TYPE);
- // todo: get attack range of weapon
- // (weapon equipping has to be fixed first)
- performAttack(mTarget, 64, damage);
- }
- else
- {
- // No-weapon fighting.
- damage.element = ELEMENT_NEUTRAL;
- performAttack(mTarget, 32, damage);
- }
-
+ std::list<AutoAttack> attacks;
+ mAutoAttacks.tick(&attacks);
+ if (attacks.empty()) return; // Install default attack?
+ else for (std::list<AutoAttack>::iterator it = attacks.begin(); it != attacks.end(); ++it)
+ performAttack(mTarget, it->getDamage());
}
void Character::died()
@@ -201,8 +182,9 @@ void Character::respawn()
{
// script-controlled respawning didn't work - fall back to
// hardcoded logic
- mAttributes[BASE_ATTR_HP].mod = -mAttributes[BASE_ATTR_HP].base + 1;
- modifiedAttribute(BASE_ATTR_HP); //warp back to spawn point
+ mAttributes[ATTR_HP].setBase(mAttributes[ATTR_MAX_HP].getModifiedAttribute());
+ modifiedAttribute(ATTR_HP);
+ //warp back to spawn point
int spawnMap = Configuration::getValue("respawnMap", 1);
int spawnX = Configuration::getValue("respawnX", 1024);
int spawnY = Configuration::getValue("respawnY", 1024);
@@ -334,8 +316,8 @@ void Character::sendStatus()
{
int attr = *i;
attribMsg.writeShort(attr);
- attribMsg.writeShort(getAttribute(attr));
- attribMsg.writeShort(getModifiedAttribute(attr));
+ attribMsg.writeLong(getAttribute(attr) * 256);
+ attribMsg.writeLong(getModifiedAttribute(attr) * 256);
}
if (attribMsg.getLength() > 2) gameHandler->sendTo(this, attribMsg);
mModifiedAttributes.clear();
@@ -361,95 +343,97 @@ void Character::sendStatus()
}
}
-int Character::getAttribute(int attr) const
-{
- if (attr <= CHAR_ATTR_END)
- {
- return Being::getAttribute(attr);
- }
- else
- {
- return Character::levelForExp(mExperience.find(attr)->second);
- }
-}
-
-int Character::getModifiedAttribute(int attr) const
-{
- if (attr <= CHAR_ATTR_END)
- {
- return Being::getModifiedAttribute(attr);
- }
- else
- {
- //TODO: Find a way to modify skills
- return Character::levelForExp(mExperience.find(attr)->second);
- }
-}
-
-void Character::modifiedAttribute(int attr)
-{
- if (attr >= CHAR_ATTR_BEGIN && attr < CHAR_ATTR_END)
- {
- for (int i = BASE_ATTR_BEGIN; i < BASE_ATTR_END; ++i)
+void Character::modifiedAllAttribute()
+{
+ for (AttributeMap::iterator it = mAttributes.begin(),
+ it_end = mAttributes.end();
+ it != it_end; ++it)
+ modifiedAttribute(it->first);
+}
+
+void Character::modifiedAttribute(unsigned int attr)
+{
+// Much of this is remnants from the previous attribute system (placeholder?)
+// This could be improved by defining what attributes are derived from others
+// in xml or otherwise, so only those that need to be recomputed are.
+ if (!mAttributes.count(attr)) return;
+ double newBase = getAttribute(attr);
+
+ switch (attr) {
+ case ATTR_STR:
+ modifiedAttribute(ATTR_INV_CAPACITY);
+ break;
+ case ATTR_AGI:
+ modifiedAttribute(ATTR_DODGE);
+ break;
+ case ATTR_VIT:
+ modifiedAttribute(ATTR_MAX_HP);
+ modifiedAttribute(ATTR_HP_REGEN);
+ modifiedAttribute(ATTR_DEFENSE);
+ break;
+ case ATTR_INT:
+ break;
+ case ATTR_DEX:
+ modifiedAttribute(ATTR_ACCURACY);
+ break;
+ case ATTR_WIL:
+ break;
+ case ATTR_ACCURACY:
+ newBase = getModifiedAttribute(ATTR_DEX); // Provisional
+ break;
+ case ATTR_DEFENSE:
+ newBase = 0.3 * getModifiedAttribute(ATTR_VIT);
+ break;
+ case ATTR_DODGE:
+ newBase = getModifiedAttribute(ATTR_AGI); // Provisional
+ break;
+ case ATTR_MAGIC_DODGE:
+ newBase = 1.0;
+ // TODO
+ break;
+ case ATTR_MAGIC_DEFENSE:
+ newBase = 0.0;
+ // TODO
+ break;
+ case ATTR_BONUS_ASPD:
+ newBase = 0.0;
+ // TODO
+ break;
+ case ATTR_HP_REGEN:
{
- int newValue = getAttribute(i);
-
- if (i == BASE_ATTR_HP_REGEN){
- newValue = (getModifiedAttribute(CHAR_ATTR_VITALITY) + 10)
- * (getModifiedAttribute(CHAR_ATTR_VITALITY) + 10)
- / (600 / TICKS_PER_HP_REGENERATION);
- // formula is in HP per minute. 600 game ticks = 1 minute.
- }
- else if (i == BASE_ATTR_HP){
- newValue = (getModifiedAttribute(CHAR_ATTR_VITALITY) + 10)
- * (mLevel + 10);
- }
- else if (i == BASE_ATTR_HIT) {
- newValue = getModifiedAttribute(CHAR_ATTR_DEXTERITY)
- /* + skill in class of currently equipped weapon */;
- }
- else if (i == BASE_ATTR_EVADE) {
- newValue = getModifiedAttribute(CHAR_ATTR_AGILITY);
- /* TODO: multiply with 10 / (10 * equip_weight)*/
- }
- else if (i == BASE_ATTR_PHY_RES) {
- newValue = getModifiedAttribute(CHAR_ATTR_VITALITY);
- /* equip defence is through equip modifiers */
- }
- else if (i == BASE_ATTR_PHY_ATK_MIN) {
- newValue = getModifiedAttribute(CHAR_ATTR_STRENGTH);
- /* weapon attack is applied through equip modifiers */
- }
- else if (i == BASE_ATTR_PHY_ATK_DELTA) {
- newValue = 0;
- /* + skill in class of currently equipped weapon ( is
- * applied during the damage calculation)
- * weapon attack bonus is applied through equip
- * modifiers.
- */
- }
- else if (i == BASE_ATTR_MAG_RES) {
- newValue = getModifiedAttribute(CHAR_ATTR_WILLPOWER);
- }
- else if (i == BASE_ATTR_MAG_ATK) {
- newValue = getModifiedAttribute(CHAR_ATTR_WILLPOWER);
- }
-
- if (newValue != getAttribute(i))
- {
- setAttribute(i, newValue);
- flagAttribute(i);
- }
+ double temp = getModifiedAttribute(ATTR_VIT) * 0.05;
+ newBase = (temp * TICKS_PER_HP_REGENERATION);
}
- }
+ break;
+ case ATTR_MAX_HP:
+ newBase = ((getModifiedAttribute(ATTR_VIT) + 3) * (getModifiedAttribute(ATTR_VIT) + 20)) * 0.125;
+ break;
+ case ATTR_MOVE_SPEED_TPS:
+ newBase = 3.0 + getModifiedAttribute(ATTR_AGI) * 0.08; // Provisional.
+ modifiedAttribute(ATTR_MOVE_SPEED_RAW);
+ break;
+ case ATTR_MOVE_SPEED_RAW:
+ newBase = utils::tpsToSpeed(getModifiedAttribute(ATTR_MOVE_SPEED_TPS));
+ break;
+ case ATTR_INV_CAPACITY:
+ newBase = 2000.0 + getModifiedAttribute(ATTR_STR) * 180.0; // Provisional
+ break;
+ default: break;
+ }
+
+ if (newBase != getAttribute(attr))
+ Being::setAttribute(attr, newBase, false);
flagAttribute(attr);
}
void Character::flagAttribute(int attr)
{
// Inform the client of this attribute modification.
+ accountHandler->updateAttributes(getDatabaseID(), attr,
+ getAttribute(attr),
+ getModifiedAttribute(attr));
mModifiedAttributes.insert(attr);
- if (attr == CHAR_ATTR_INTELLIGENCE)
+ if (attr == ATTR_INT)
{
mSpecialUpdateNeeded = true;
}
@@ -467,47 +451,44 @@ int Character::levelForExp(int exp)
void Character::receiveExperience(int skill, int experience, int optimalLevel)
{
- if (skill >= CHAR_ATTR_END)
+ // reduce experience when skill is over optimal level
+ int levelOverOptimum = levelForExp(getExperience(skill)) - optimalLevel;
+ if (optimalLevel && levelOverOptimum > 0)
{
- // reduce experience when skill is over optimal level
- int levelOverOptimum = getAttribute(skill) - optimalLevel;
- if (optimalLevel && levelOverOptimum > 0)
- {
- experience *= EXP_LEVEL_FLEXIBILITY / (levelOverOptimum + EXP_LEVEL_FLEXIBILITY);
- }
+ experience *= EXP_LEVEL_FLEXIBILITY / (levelOverOptimum + EXP_LEVEL_FLEXIBILITY);
+ }
- // add exp
- int oldExp = mExperience[skill];
- long int newExp = mExperience[skill] + experience;
- if (newExp < 0) newExp = 0; // avoid integer underflow/negative exp
+ // add exp
+ int oldExp = mExperience[skill];
+ long int newExp = mExperience[skill] + experience;
+ if (newExp < 0) newExp = 0; // avoid integer underflow/negative exp
- // Check the skill cap
- long int maxSkillCap = Configuration::getValue("maxSkillCap", INT_MAX);
- assert(maxSkillCap <= INT_MAX); // avoid interger overflow
- if (newExp > maxSkillCap)
+ // Check the skill cap
+ long int maxSkillCap = Configuration::getValue("maxSkillCap", INT_MAX);
+ assert(maxSkillCap <= INT_MAX); // avoid interger overflow
+ if (newExp > maxSkillCap)
+ {
+ newExp = maxSkillCap;
+ if (oldExp != maxSkillCap)
{
- newExp = maxSkillCap;
- if (oldExp != maxSkillCap)
- {
- LOG_INFO("Player hit the skill cap");
- // TODO: send a message to player leting them know they hit the cap
- }
+ LOG_INFO("Player hit the skill cap");
+ // TODO: send a message to player leting them know they hit the cap
}
- mExperience[skill] = newExp;
- mModifiedExperience.insert(skill);
+ }
+ mExperience[skill] = newExp;
+ mModifiedExperience.insert(skill);
- // inform account server
- if (newExp != oldExp)
- accountHandler->updateExperience(getDatabaseID(), skill, newExp);
+ // inform account server
+ if (newExp != oldExp)
+ accountHandler->updateExperience(getDatabaseID(), skill, newExp);
- // check for skill levelup
- if (Character::levelForExp(newExp) >= Character::levelForExp(oldExp))
- {
- modifiedAttribute(skill);
- }
-
- mRecalculateLevel = true;
+ // check for skill levelup
+ if (Character::levelForExp(newExp) >= Character::levelForExp(oldExp))
+ {
+ modifiedAttribute(skill);
}
+
+ mRecalculateLevel = true;
}
void Character::incrementKillCount(int monsterType)
@@ -543,7 +524,7 @@ void Character::recalculateLevel()
{
float expGot = getExpGot(a->first);
float expNeed = getExpNeeded(a->first);
- levels.push_back(getAttribute(a->first) + expGot / expNeed);
+ levels.push_back(levelForExp(a->first) + expGot / expNeed);
}
}
levels.sort();
@@ -577,13 +558,13 @@ void Character::recalculateLevel()
int Character::getExpNeeded(size_t skill) const
{
- int level = getAttribute(skill);
+ int level = levelForExp(getExperience(skill));
return Character::expForLevel(level + 1) - expForLevel(level);
}
int Character::getExpGot(size_t skill) const
{
- int level = getAttribute(skill);
+ int level = levelForExp(getExperience(skill));
return mExperience.at(skill) - Character::expForLevel(level);
}
@@ -606,11 +587,11 @@ void Character::levelup()
AttribmodResponseCode Character::useCharacterPoint(size_t attribute)
{
- if (attribute < CHAR_ATTR_BEGIN) return ATTRIBMOD_INVALID_ATTRIBUTE;
- if (attribute >= CHAR_ATTR_END) return ATTRIBMOD_INVALID_ATTRIBUTE;
+ if (!attributeManager->isAttributeDirectlyModifiable(attribute))
+ return ATTRIBMOD_INVALID_ATTRIBUTE;
if (!mCharacterPoints) return ATTRIBMOD_NO_POINTS_LEFT;
- mCharacterPoints--;
+ --mCharacterPoints;
setAttribute(attribute, getAttribute(attribute) + 1);
modifiedAttribute(attribute);
return ATTRIBMOD_OK;
@@ -618,13 +599,13 @@ AttribmodResponseCode Character::useCharacterPoint(size_t attribute)
AttribmodResponseCode Character::useCorrectionPoint(size_t attribute)
{
- if (attribute < CHAR_ATTR_BEGIN) return ATTRIBMOD_INVALID_ATTRIBUTE;
- if (attribute >= CHAR_ATTR_END) return ATTRIBMOD_INVALID_ATTRIBUTE;
+ if (!attributeManager->isAttributeDirectlyModifiable(attribute))
+ return ATTRIBMOD_INVALID_ATTRIBUTE;
if (!mCorrectionPoints) return ATTRIBMOD_NO_POINTS_LEFT;
if (getAttribute(attribute) <= 1) return ATTRIBMOD_DENIED;
- mCorrectionPoints--;
- mCharacterPoints++;
+ --mCorrectionPoints;
+ ++mCharacterPoints;
setAttribute(attribute, getAttribute(attribute) - 1);
modifiedAttribute(attribute);
return ATTRIBMOD_OK;