summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBlue <bluesansdouze@gmail.com>2010-01-10 00:28:20 +0100
committerBlue <bluesansdouze@gmail.com>2010-01-10 00:28:20 +0100
commit4544e23b23fd722aeeeb99f37c7076e09cc037bb (patch)
tree4ac8bbb6a27439f9a1ff87dec1a61bd5f01d5452
parent9ad132534ada41efd7973f8ef52fe49bee769866 (diff)
parent5c5abafd2b0dcbcdeefad625b03732949c56056f (diff)
downloadmanaserv-4544e23b23fd722aeeeb99f37c7076e09cc037bb.tar.gz
manaserv-4544e23b23fd722aeeeb99f37c7076e09cc037bb.tar.xz
manaserv-4544e23b23fd722aeeeb99f37c7076e09cc037bb.zip
Merge branch 'master' of ssh://git@gitorious.org/mana/manaserv
-rw-r--r--src/account-server/character.hpp16
-rw-r--r--src/account-server/storage.cpp86
-rw-r--r--src/account-server/storage.hpp2
-rw-r--r--src/game-server/character.cpp25
-rw-r--r--src/game-server/character.hpp26
-rw-r--r--src/game-server/monster.cpp1
-rw-r--r--src/game-server/trigger.cpp3
-rw-r--r--src/scripting/lua.cpp29
-rw-r--r--src/serialize/characterdata.hpp33
-rw-r--r--src/sql/sqlite/createTables.sql13
-rw-r--r--src/sql/sqlite/updates/update_7_to_8.sql20
11 files changed, 250 insertions, 4 deletions
diff --git a/src/account-server/character.hpp b/src/account-server/character.hpp
index c99b2ff..0aa7c8e 100644
--- a/src/account-server/character.hpp
+++ b/src/account-server/character.hpp
@@ -140,6 +140,21 @@ class Character
{ return mStatusEffects.end(); }
/**
+ * Get / Set kill count
+ */
+ int getKillCountSize() const
+ { return mKillCount.size(); }
+
+ const std::map<int, int>::const_iterator getKillCountBegin() const
+ { return mKillCount.begin(); }
+
+ const std::map<int, int>::const_iterator getKillCountEnd() const
+ { return mKillCount.end(); }
+
+ void setKillCount(int monsterId, int kills)
+ { mKillCount[monsterId] = kills; }
+
+ /**
* Gets the Id of the map that the character is on.
*/
int getMapId() const { return mMapId; }
@@ -196,6 +211,7 @@ class Character
unsigned short mAttributes[CHAR_ATTR_NB]; //!< Attributes.
std::map<int, int> mExperience; //!< Skill Experience.
std::map<int, int> mStatusEffects; //!< Status Effects
+ std::map<int, int> mKillCount; //!< Kill Count
unsigned short mMapId; //!< Map the being is on.
unsigned char mGender; //!< Gender of the being.
unsigned char mHairStyle; //!< Hair style of the being.
diff --git a/src/account-server/storage.cpp b/src/account-server/storage.cpp
index e40e19d..c547977 100644
--- a/src/account-server/storage.cpp
+++ b/src/account-server/storage.cpp
@@ -41,7 +41,7 @@ static const char *DEFAULT_ITEM_FILE = "data/items.xml";
// defines the supported db version
static const char *DB_VERSION_PARAMETER = "database_version";
-static const char *SUPPORTED_DB_VERSION = "7";
+static const char *SUPPORTED_DB_VERSION = "8";
/*
* MySQL specificities:
@@ -72,6 +72,7 @@ static const char *ACCOUNTS_TBL_NAME = "mana_accounts";
static const char *CHARACTERS_TBL_NAME = "mana_characters";
static const char *CHAR_SKILLS_TBL_NAME = "mana_char_skills";
static const char *CHAR_STATUS_EFFECTS_TBL_NAME = "mana_char_status_effects";
+static const char *CHAR_KILL_COUNT_TBL_NAME = "mana_char_kill_stats";
static const char *INVENTORIES_TBL_NAME = "mana_inventories";
static const char *ITEMS_TBL_NAME = "mana_items";
static const char *GUILDS_TBL_NAME = "mana_guilds";
@@ -414,9 +415,9 @@ Character *Storage::getCharacterBySQL(Account *owner)
toUint(skillInfo(row, 1))); // experience
}
}
+ // Load the status effect
s.clear();
s.str("");
- // Load the status effect
s << "select status_id, status_time FROM " << CHAR_STATUS_EFFECTS_TBL_NAME
<< " WHERE char_id = " << character->getDatabaseID();
const dal::RecordSet &statusInfo = mDb->execSql(s.str());
@@ -430,6 +431,23 @@ Character *Storage::getCharacterBySQL(Account *owner)
toUint(statusInfo(row, 1))); // Time
}
}
+ // Load the kill stats
+ s.clear();
+ s.str("");
+ // Load the status effect
+ s << "select monster_id, kills FROM " << CHAR_KILL_COUNT_TBL_NAME
+ << " WHERE char_id = " << character->getDatabaseID();
+ const dal::RecordSet &killsInfo = mDb->execSql(s.str());
+ if (!statusInfo.isEmpty())
+ {
+ const unsigned int nRows = killsInfo.rows();
+ for (unsigned int row = 0; row < nRows; row++)
+ {
+ character->setKillCount(
+ toUint(killsInfo(row, 0)), // MonsterID
+ toUint(killsInfo(row, 1))); // Kills
+ }
+ }
}
catch (const dal::DbSqlQueryExecFailure &e)
{
@@ -693,7 +711,28 @@ bool Storage::updateCharacter(Character *character,
return false;
}
-
+ /**
+ * Character's kill count
+ */
+ try
+ {
+ std::map<int, int>::const_iterator kill_it;
+ for (kill_it = character->getKillCountBegin();
+ kill_it != character->getKillCountEnd(); kill_it++)
+ {
+ updateKillCount(character->getDatabaseID(), kill_it->first, kill_it->second);
+ }
+ }
+ catch (const dal::DbSqlQueryExecFailure& e)
+ {
+ // TODO: throw an exception.
+ if (startTransaction)
+ {
+ mDb->rollbackTransaction();
+ }
+ LOG_ERROR("(DALStorage::updateCharacter #2) SQL query failure: " << e.what());
+ return false;
+ }
/**
* Character's inventory
*/
@@ -1128,6 +1167,47 @@ void Storage::updateExperience(int charId, int skillId, int skillValue)
}
/**
+ * Write a modification message about character skills to the database.
+ * @param CharId ID of the character
+ * @param monsterId ID of the monster type
+ * @param kills new amount of kills
+ */
+void Storage::updateKillCount(int charId, int monsterId, int kills)
+{
+ LOG_INFO("Updating kill counts"); //<- DELME
+ try
+ {
+ // try to update the kill count
+ std::ostringstream sql;
+ sql << "UPDATE " << CHAR_KILL_COUNT_TBL_NAME
+ << " SET kills = " << kills
+ << " WHERE char_id = " << charId
+ << " AND monster_id = " << monsterId;
+ mDb->execSql(sql.str());
+
+ // check if the update has modified a row
+ if (mDb->getModifiedRows() > 0)
+ {
+ return;
+ }
+
+ sql.clear();
+ sql.str("");
+ sql << "INSERT INTO " << CHAR_KILL_COUNT_TBL_NAME << " "
+ << "(char_id, monster_id, kills) VALUES ( "
+ << charId << ", "
+ << monsterId << ", "
+ << kills << ")";
+ mDb->execSql(sql.str());
+ }
+ catch (const dal::DbSqlQueryExecFailure &e)
+ {
+ LOG_ERROR("DALStorage::updateKillCount: " << e.what());
+ throw;
+ }
+}
+
+/**
* Inserts a record about a status effect into the database
* @param charId ID of the character in the database
* @param statusId ID of the status effect
diff --git a/src/account-server/storage.hpp b/src/account-server/storage.hpp
index c376e94..bfc34c2 100644
--- a/src/account-server/storage.hpp
+++ b/src/account-server/storage.hpp
@@ -68,6 +68,8 @@ class Storage
void updateExperience(int charId, int skillId, int skillValue);
+ void updateKillCount(int charId, int monsterId, int kills);
+
void insertStatusEffect(int charId, int statusId, int time);
void banCharacter(int id, int duration);
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 95082d6..0775c75 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -506,6 +506,31 @@ void Character::receiveExperience(int skill, int experience, int optimalLevel)
}
}
+void Character::incrementKillCount(int monsterType)
+{
+ std::map<int, int>::iterator i = mKillCount.find(monsterType);
+ if (i == mKillCount.end())
+ {
+ // character has never murdered this species before
+ mKillCount[monsterType] = 1;
+ } else {
+ // character is a repeated offender
+ mKillCount[monsterType] ++;
+ };
+}
+
+int Character::getKillCount(int monsterType)
+{
+ std::map<int, int>::iterator i = mKillCount.find(monsterType);
+ if (i == mKillCount.end())
+ {
+ return 0;
+ } else {
+ return i->second;
+ };
+}
+
+
void Character::recalculateLevel()
{
std::list<float> levels;
diff --git a/src/game-server/character.hpp b/src/game-server/character.hpp
index 8b04e8c..05c36c2 100644
--- a/src/game-server/character.hpp
+++ b/src/game-server/character.hpp
@@ -291,6 +291,21 @@ class Character : public Being
{ return mStatusEffects.end(); }
/**
+ * used to serialized kill count
+ */
+ int getKillCountSize() const
+ { return mKillCount.size(); }
+
+ const std::map<int, int>::const_iterator getKillCountBegin() const
+ { return mKillCount.begin(); }
+
+ const std::map<int, int>::const_iterator getKillCountEnd() const
+ { return mKillCount.end(); }
+
+ void setKillCount(int monsterId, int kills)
+ { mKillCount[monsterId] = kills; }
+
+ /**
* Gets total accumulated exp for skill
*/
int getExperience(int skill) const
@@ -303,6 +318,16 @@ class Character : public Being
{ mExperience[skill] = 0; receiveExperience(skill, value, 0); }
/**
+ * Adds one kill of the monster type to the characters kill count
+ */
+ void incrementKillCount(int monsterType);
+
+ /**
+ * Gets the number of monsters the character killed of a given type
+ */
+ int getKillCount(int monsterType);
+
+ /**
* Shortcut to get being's health
*/
int getHealth() const
@@ -425,6 +450,7 @@ class Character : public Being
unsigned char mAccountLevel; /**< Account level of the user. */
int mParty; /**< Party id of the character */
TransactionType mTransaction; /**< Trade/buy/sell action the character is involved in. */
+ std::map<int, int> mKillCount; /**< how many monsters the character has slayn of each type */
protected:
/**
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index f30396c..e0ff43b 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -455,6 +455,7 @@ void Monster::died()
{
character->receiveExperience(*iSkill, expPerSkill, mSpecy->getOptimalLevel());
}
+ character->incrementKillCount(mSpecy->getType());
}
}
}
diff --git a/src/game-server/trigger.cpp b/src/game-server/trigger.cpp
index 522e0be..7db53cc 100644
--- a/src/game-server/trigger.cpp
+++ b/src/game-server/trigger.cpp
@@ -52,6 +52,9 @@ void TriggerArea::update()
std::set<Actor*> insideNow;
for (BeingIterator i(getMap()->getInsideRectangleIterator(mZone)); i; ++i)
{
+ //skip garbage
+ if (!(*i) || (*i)->getPublicID() == 0) continue;
+
if (mZone.contains((*i)->getPosition())) //<-- Why is this additional condition necessary? Shouldn't getInsideRectangleIterator already exclude those outside of the zone? --Crush
{
insideNow.insert(*i);
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 1c79ede..3b33a3d 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -1292,6 +1292,34 @@ static int chr_get_hair_color(lua_State *s)
}
/**
+ * Get the number of monsters the player killed of a type
+ * mana.chr_get_kill_count (character, monsterType)
+ */
+static int chr_get_kill_count(lua_State *s)
+{
+ Character *c = getCharacter(s, 1);
+ if (!c)
+ {
+ raiseScriptError(s, "chr_get_kill_count called for nonexistent character.");
+ return 0;
+ }
+
+ if (!lua_isnumber(s, 2))
+ {
+ raiseScriptError(s, "chr_get_kill_count called with incorect parameters");
+ return 0;
+ }
+
+ int id = lua_tointeger(s, 2);
+
+ int kills = c->getKillCount(id);
+
+ lua_pushinteger(s, kills);
+ return 1;
+}
+
+
+/**
* Returns the rights level of a character.
* mana.chr_get_rights (being)
*/
@@ -1463,6 +1491,7 @@ LuaScript::LuaScript():
{ "chr_get_hair_style", &chr_get_hair_style },
{ "chr_set_hair_color", &chr_set_hair_color },
{ "chr_get_hair_color", &chr_get_hair_color },
+ { "chr_get_kill_count", &chr_get_kill_count },
{ "exp_for_level", &exp_for_level },
{ "monster_create", &monster_create },
{ "monster_load_script", &monster_load_script },
diff --git a/src/serialize/characterdata.hpp b/src/serialize/characterdata.hpp
index c2b7f7b..1346f68 100644
--- a/src/serialize/characterdata.hpp
+++ b/src/serialize/characterdata.hpp
@@ -32,6 +32,7 @@
template< class T >
void serializeCharacterData(const T &data, MessageOut &msg)
{
+ // general character properties
msg.writeByte(data.getAccountLevel());
msg.writeByte(data.getGender());
msg.writeByte(data.getHairStyle());
@@ -40,11 +41,13 @@ void serializeCharacterData(const T &data, MessageOut &msg)
msg.writeShort(data.getCharacterPoints());
msg.writeShort(data.getCorrectionPoints());
+ // character attributes
for (int i = CHAR_ATTR_BEGIN; i < CHAR_ATTR_END; ++i)
{
msg.writeByte(data.getAttribute(i));
}
+ // character skills
msg.writeShort(data.getSkillSize());
std::map<int, int>::const_iterator skill_it;
@@ -54,6 +57,7 @@ void serializeCharacterData(const T &data, MessageOut &msg)
msg.writeLong(skill_it->second);
}
+ // status effects currently affecting the character
msg.writeShort(data.getStatusEffectSize());
std::map<int, int>::const_iterator status_it;
for (status_it = data.getStatusEffectBegin(); status_it != data.getStatusEffectEnd(); status_it++)
@@ -62,12 +66,22 @@ void serializeCharacterData(const T &data, MessageOut &msg)
msg.writeShort(status_it->second);
}
-
+ // location
msg.writeShort(data.getMapId());
const Point &pos = data.getPosition();
msg.writeShort(pos.x);
msg.writeShort(pos.y);
+ // kill count
+ msg.writeShort(data.getKillCountSize());
+ std::map<int, int>::const_iterator kills_it;
+ for (kills_it = data.getKillCountBegin(); kills_it != data.getKillCountEnd(); kills_it++)
+ {
+ msg.writeShort(kills_it->first);
+ msg.writeLong(kills_it->second);
+ }
+
+ // inventory - must be last because size isn't transmitted
const Possessions &poss = data.getPossessions();
msg.writeLong(poss.money);
for (int j = 0; j < EQUIPMENT_SLOTS; ++j)
@@ -80,11 +94,13 @@ void serializeCharacterData(const T &data, MessageOut &msg)
msg.writeShort(j->itemId);
msg.writeByte(j->amount);
}
+
}
template< class T >
void deserializeCharacterData(T &data, MessageIn &msg)
{
+ // general character properties
data.setAccountLevel(msg.readByte());
data.setGender(msg.readByte());
data.setHairStyle(msg.readByte());
@@ -93,11 +109,13 @@ void deserializeCharacterData(T &data, MessageIn &msg)
data.setCharacterPoints(msg.readShort());
data.setCorrectionPoints(msg.readShort());
+ // character attributes
for (int i = CHAR_ATTR_BEGIN; i < CHAR_ATTR_END; ++i)
{
data.setAttribute(i, msg.readByte());
}
+ // character skills
int skillSize = msg.readShort();
for (int i = 0; i < skillSize; ++i)
@@ -107,6 +125,7 @@ void deserializeCharacterData(T &data, MessageIn &msg)
data.setExperience(skill,level);
}
+ // status effects currently affecting the character
int statusSize = msg.readShort();
for (int i = 0; i < statusSize; i++)
@@ -116,6 +135,7 @@ void deserializeCharacterData(T &data, MessageIn &msg)
data.applyStatusEffect(status, time);
}
+ // location
data.setMapId(msg.readShort());
Point temporaryPoint;
@@ -123,6 +143,16 @@ void deserializeCharacterData(T &data, MessageIn &msg)
temporaryPoint.y = msg.readShort();
data.setPosition(temporaryPoint);
+ // kill count
+ int killSize = msg.readShort();
+ for (int i = 0; i < killSize; i++)
+ {
+ int monsterId = msg.readShort();
+ int kills = msg.readLong();
+ data.setKillCount(monsterId, kills);
+ }
+
+ // inventory - must be last because size isn't transmitted
Possessions &poss = data.getPossessions();
poss.money = msg.readLong();
for (int j = 0; j < EQUIPMENT_SLOTS; ++j)
@@ -137,6 +167,7 @@ void deserializeCharacterData(T &data, MessageIn &msg)
i.amount = msg.readByte();
poss.inventory.push_back(i);
}
+
}
#endif
diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql
index 26881fd..e3222da 100644
--- a/src/sql/sqlite/createTables.sql
+++ b/src/sql/sqlite/createTables.sql
@@ -97,6 +97,19 @@ CREATE INDEX mana_char_status_char on mana_char_status_effects ( char_id );
-----------------------------------------------------------------------------
+CREATE TABLE mana_char_kill_stats
+(
+ char_id INTEGER NOT NULL,
+ monster_id INTEGER NOT NULL,
+ kills INTEGER NOT NULL,
+ --
+ FOREIGN KEY (char_id) REFERENCES mana_characters(id)
+);
+
+CREATE INDEX mana_char_kill_stats_char on mana_char_status_effects ( char_id );
+
+-----------------------------------------------------------------------------
+
CREATE TABLE mana_items
(
id INTEGER PRIMARY KEY,
diff --git a/src/sql/sqlite/updates/update_7_to_8.sql b/src/sql/sqlite/updates/update_7_to_8.sql
new file mode 100644
index 0000000..35593c6
--- /dev/null
+++ b/src/sql/sqlite/updates/update_7_to_8.sql
@@ -0,0 +1,20 @@
+
+-- create table mana_char_kill_stats
+
+CREATE TABLE mana_char_kill_stats
+(
+ char_id INTEGER NOT NULL,
+ monster_id INTEGER NOT NULL,
+ kills INTEGER NOT NULL,
+ --
+ FOREIGN KEY (char_id) REFERENCES mana_characters(id)
+);
+
+CREATE INDEX mana_char_kill_stats_chars on mana_char_kill_stats ( char_id );
+
+-- update the database version, and set date of update
+UPDATE mana_world_states
+ SET value = '8',
+ moddate = strftime('%s','now')
+ WHERE state_name = 'database_version';
+