diff options
-rw-r--r-- | example/serverdata/scripts/special_actions.lua | 39 | ||||
-rw-r--r-- | gameserver.cbp | 5 | ||||
-rw-r--r-- | src/account-server/character.hpp | 22 | ||||
-rw-r--r-- | src/account-server/storage.cpp | 59 | ||||
-rw-r--r-- | src/game-server/character.cpp | 38 | ||||
-rw-r--r-- | src/game-server/character.hpp | 32 | ||||
-rw-r--r-- | src/game-server/main-game.cpp | 3 | ||||
-rw-r--r-- | src/game-server/statusmanager.cpp | 8 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 76 | ||||
-rw-r--r-- | src/scripting/luascript.cpp | 11 | ||||
-rw-r--r-- | src/scripting/luascript.hpp | 1 | ||||
-rw-r--r-- | src/scripting/script.cpp | 30 | ||||
-rw-r--r-- | src/scripting/script.hpp | 5 | ||||
-rw-r--r-- | src/serialize/characterdata.hpp | 16 | ||||
-rw-r--r-- | src/sql/mysql/createTables.sql | 15 | ||||
-rw-r--r-- | src/sql/mysql/updates/update_8_to_9.sql | 16 | ||||
-rw-r--r-- | src/sql/sqlite/createTables.sql | 14 | ||||
-rw-r--r-- | src/sql/sqlite/updates/update_8_to_9.sql | 16 |
18 files changed, 374 insertions, 32 deletions
diff --git a/example/serverdata/scripts/special_actions.lua b/example/serverdata/scripts/special_actions.lua new file mode 100644 index 00000000..135ad351 --- /dev/null +++ b/example/serverdata/scripts/special_actions.lua @@ -0,0 +1,39 @@ +------------------------------------------------------------- +-- Special action script file -- +-- -- +-- This file allows you to implement your special -- +-- action system. The system can for example implement -- +-- magic, physical attack or also such mundane things -- +-- as showing emoticons over the characters heads. -- +---------------------------------------------------------------------------------- +-- Copyright 2010 Manasource Development Team -- +-- -- +-- This file is part of Manasource. -- +-- -- +-- Manasource 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. -- +---------------------------------------------------------------------------------- + +local specialCost = {} +specialCost[1] = 50 +specialCost[2] = 250 +specialCost[3] = 1000 + +function use_special(ch, id) + -- perform whatever the special with the ID does + if id == 1 then + mana.being_say(ch, "Kaaame...Haaame... HAAAAAA!") + end + if id == 2 then + mana.being_say(ch, "HAA-DOKEN!") + end + if id == 3 then + mana.being_say(ch, "Sonic BOOM") + end +end + +function get_special_recharge_cost(id) + -- return the recharge cost for the special with the ID + return specialCost[id] +end diff --git a/gameserver.cbp b/gameserver.cbp index a55d9b44..6b5d41dd 100644 --- a/gameserver.cbp +++ b/gameserver.cbp @@ -65,8 +65,8 @@ <Unit filename="src\common\inventorydata.hpp" /> <Unit filename="src\common\permissionmanager.cpp" /> <Unit filename="src\common\permissionmanager.hpp" /> - <Unit filename="src\common\resourcemanager.cpp" /> - <Unit filename="src\common\resourcemanager.hpp" /> + <Unit filename="src\common\resourcemanager.cpp" /> + <Unit filename="src\common\resourcemanager.hpp" /> <Unit filename="src\common\transaction.hpp" /> <Unit filename="src\defines.h" /> <Unit filename="src\game-server\accountconnection.cpp" /> @@ -149,6 +149,7 @@ <Unit filename="src\scripting\luautil.hpp" /> <Unit filename="src\scripting\script.cpp" /> <Unit filename="src\scripting\script.hpp" /> + <Unit filename="src\serialize\characterdata.hpp" /> <Unit filename="src\utils\base64.cpp" /> <Unit filename="src\utils\base64.h" /> <Unit filename="src\utils\logger.cpp" /> diff --git a/src/account-server/character.hpp b/src/account-server/character.hpp index acb47044..d96413d4 100644 --- a/src/account-server/character.hpp +++ b/src/account-server/character.hpp @@ -32,6 +32,9 @@ class Account; class MessageIn; +/** placeholder type needed for include compatibility with game server*/ +typedef void Special; + class Character { public: @@ -155,6 +158,24 @@ class Character { mKillCount[monsterId] = kills; } /** + * Get / Set specials + */ + int getSpecialSize() const + { return mSpecials.size(); } + + const std::map<int, Special*>::const_iterator getSpecialBegin() const + { return mSpecials.begin(); } + + const std::map<int, Special*>::const_iterator getSpecialEnd() const + { return mSpecials.end(); } + + void clearSpecials() + { mSpecials.clear(); } + + void giveSpecial(int id) + { mSpecials[id] = NULL; } + + /** * Gets the Id of the map that the character is on. */ int getMapId() const { return mMapId; } @@ -212,6 +233,7 @@ class Character std::map<int, int> mExperience; //!< Skill Experience. std::map<int, int> mStatusEffects; //!< Status Effects std::map<int, int> mKillCount; //!< Kill Count + std::map<int, Special*> mSpecials; 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 4828e055..c104b4f7 100644 --- a/src/account-server/storage.cpp +++ b/src/account-server/storage.cpp @@ -40,7 +40,7 @@ static const char *DEFAULT_ITEM_FILE = "items.xml"; // defines the supported db version static const char *DB_VERSION_PARAMETER = "database_version"; -static const char *SUPPORTED_DB_VERSION = "8"; +static const char *SUPPORTED_DB_VERSION = "9"; /* * MySQL specificities: @@ -72,6 +72,7 @@ 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 *CHAR_SPECIALS_TBL_NAME = "mana_char_specials"; static const char *INVENTORIES_TBL_NAME = "mana_inventories"; static const char *ITEMS_TBL_NAME = "mana_items"; static const char *GUILDS_TBL_NAME = "mana_guilds"; @@ -433,11 +434,10 @@ Character *Storage::getCharacterBySQL(Account *owner) // 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()) + if (!killsInfo.isEmpty()) { const unsigned int nRows = killsInfo.rows(); for (unsigned int row = 0; row < nRows; row++) @@ -447,6 +447,20 @@ Character *Storage::getCharacterBySQL(Account *owner) toUint(killsInfo(row, 1))); // Kills } } + // load the special status + s.clear(); + s.str(""); + s << "select special_id FROM " << CHAR_SPECIALS_TBL_NAME + << " WHERE char_id = " << character->getDatabaseID(); + const dal::RecordSet &specialsInfo = mDb->execSql(s.str()); + if (!specialsInfo.isEmpty()) + { + const unsigned int nRows = specialsInfo.rows(); + for (unsigned int row = 0; row < nRows; row++) + { + character->giveSpecial(toUint(specialsInfo(row, 0))); + } + } } catch (const dal::DbSqlQueryExecFailure &e) { @@ -729,9 +743,44 @@ bool Storage::updateCharacter(Character *character, { mDb->rollbackTransaction(); } - LOG_ERROR("(DALStorage::updateCharacter #2) SQL query failure: " << e.what()); + LOG_ERROR("(DALStorage::updateCharacter #3) SQL query failure: " << e.what()); + return false; + } + /** + * Character's special actions + */ + try + { + // out with the old + std::ostringstream deleteSql(""); + std::ostringstream insertSql; + deleteSql << "DELETE FROM " << CHAR_SPECIALS_TBL_NAME + << " WHERE char_id='" << character->getDatabaseID() << "';"; + mDb->execSql(deleteSql.str()); + // in with the new + std::map<int, Special*>::const_iterator special_it; + for (special_it = character->getSpecialBegin(); + special_it != character->getSpecialEnd(); special_it++) + { + insertSql.str(""); + insertSql << "INSERT INTO " << CHAR_SPECIALS_TBL_NAME + << " (char_id, special_id) VALUES (" + << " '" << character->getDatabaseID() << "'," + << " '" << special_it->first << "');"; + mDb->execSql(insertSql.str()); + } + } + catch (const dal::DbSqlQueryExecFailure& e) + { + // TODO: throw an exception. + if (startTransaction) + { + mDb->rollbackTransaction(); + } + LOG_ERROR("(DALStorage::updateCharacter #4) SQL query failure: " << e.what()); return false; } + /** * Character's inventory */ @@ -752,7 +801,7 @@ bool Storage::updateCharacter(Character *character, { mDb->rollbackTransaction(); } - LOG_ERROR("(DALStorage::updateCharacter #3) SQL query failure: " << e.what()); + LOG_ERROR("(DALStorage::updateCharacter #5) SQL query failure: " << e.what()); return false; } diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index 258a7025..46ffa05e 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -232,14 +232,7 @@ void Character::useSpecial(int id) //tell script engine to cast the spell special->currentMana = 0; - Script *script = getMap()->getScript(); - if (script) { - script->prepare("cast"); - script->push(this); - script->push(id); - script->execute(); - } - + Script::perform_special_action(id, this); mSpecialUpdateNeeded = true; return; } @@ -661,14 +654,29 @@ void Character::giveSpecial(int id) { if (mSpecials.find(id) == mSpecials.end()) { - // TODO: get the needed mana from a SpecialDB - int neededMana; - if (id == 1) neededMana = 10; - if (id == 2) neededMana = 100; - if (id == 3) neededMana = 1000; - - Special *s = new Special(neededMana); + Special *s = new Special(); + Script::addDataToSpecial(id, s); mSpecials[id] = s; mSpecialUpdateNeeded = true; } } + +void Character::takeSpecial(int id) +{ + std::map<int, Special*>::iterator i = mSpecials.find(id); + if (i != mSpecials.end()) + { + delete i->second; + mSpecials.erase(i); + mSpecialUpdateNeeded = true; + } +} + +void Character::clearSpecials() +{ + for(std::map<int, Special*>::iterator i = mSpecials.begin(); i != mSpecials.end(); i++) + { + delete i->second; + } + mSpecials.clear(); +} diff --git a/src/game-server/character.hpp b/src/game-server/character.hpp index 7b74c08e..fdee3645 100644 --- a/src/game-server/character.hpp +++ b/src/game-server/character.hpp @@ -39,10 +39,9 @@ class Trade; struct Special { - Special(int needed) + Special() { currentMana = 0; - neededMana = needed; } int currentMana; int neededMana; @@ -95,6 +94,21 @@ class Character : public Being void giveSpecial(int id); /** + * Removes all specials from character + */ + void clearSpecials(); + + /** + * Checks if a character knows a special action + */ + bool hasSpecial(int id) { return mSpecials.find(id) != mSpecials.end(); } + + /** + * Removes an available special action + */ + void takeSpecial(int id); + + /** * Gets client computer. */ GameClient *getClient() const @@ -296,7 +310,7 @@ class Character : public Being { return mStatusEffects.end(); } /** - * used to serialized kill count + * used to serialize kill count */ int getKillCountSize() const { return mKillCount.size(); } @@ -311,6 +325,18 @@ class Character : public Being { mKillCount[monsterId] = kills; } /** + * used to serialize specials + */ + int getSpecialSize() const + { return mSpecials.size(); } + + const std::map<int, Special*>::const_iterator getSpecialBegin() const + { return mSpecials.begin(); } + + const std::map<int, Special*>::const_iterator getSpecialEnd() const + { return mSpecials.end(); } + + /** * Gets total accumulated exp for skill */ int getExperience(int skill) const diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp index d551035b..0901ce16 100644 --- a/src/game-server/main-game.cpp +++ b/src/game-server/main-game.cpp @@ -69,6 +69,7 @@ using utils::Logger; #define DEFAULT_STATUSDB_FILE "mana-status-effect.xml" #define DEFAULT_PERMISSION_FILE "permissions.xml" #define DEFAULT_GLOBAL_EVENT_SCRIPT_FILE "scripts/global_events.lua" +#define DEFAULT_SPECIAL_ACTIONS_SCRIPT_FILE "scripts/special_actions.lua" static int const WORLD_TICK_SKIP = 2; /** tolerance for lagging behind in world calculation) **/ @@ -186,6 +187,8 @@ void initialize() PermissionManager::initialize(DEFAULT_PERMISSION_FILE); // Initialize global event script LuaScript::load_global_event_script(DEFAULT_GLOBAL_EVENT_SCRIPT_FILE); + // Initialize special action script + LuaScript::load_special_actions_script(DEFAULT_SPECIAL_ACTIONS_SCRIPT_FILE); // --- Initialize the global handlers // FIXME: Make the global handlers global vars or part of a bigger diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp index 0e64df6b..702fd103 100644 --- a/src/game-server/statusmanager.cpp +++ b/src/game-server/statusmanager.cpp @@ -30,8 +30,8 @@ #include <set> #include <sstream> -typedef std::map< int, StatusEffect * > StatusEffects; -static StatusEffects statusEffects; +typedef std::map< int, StatusEffect * > StatusEffectsMap; +static StatusEffectsMap statusEffects; static std::string statusReferenceFile; void StatusManager::initialize(const std::string &file) @@ -108,7 +108,7 @@ void StatusManager::reload() void StatusManager::deinitialize() { - for (StatusEffects::iterator i = statusEffects.begin(), + for (StatusEffectsMap::iterator i = statusEffects.begin(), i_end = statusEffects.end(); i != i_end; ++i) { delete i->second; @@ -118,7 +118,7 @@ void StatusManager::deinitialize() StatusEffect *StatusManager::getStatus(int statusId) { - StatusEffects::const_iterator i = statusEffects.find(statusId); + StatusEffectsMap::const_iterator i = statusEffects.find(statusId); return i != statusEffects.end() ? i->second : NULL; } diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index ca916248..2d9562ed 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -1454,6 +1454,79 @@ static int chr_get_kill_count(lua_State *s) /** + * Enables a special for a character + * mana.chr_give_special (character, special) + */ +static int chr_give_special(lua_State *s) +{ + // cost_type is ignored until we have more than one cost type + Character *c = getCharacter(s, 1); + if (!c) + { + raiseScriptError(s, "chr_give_special called for nonexistent character."); + return 0; + } + if (!lua_isnumber(s, 2)) + { + raiseScriptError(s, "chr_give_special called with incorect parameters"); + return 0; + } + int special = lua_tointeger(s, 2); + + c->giveSpecial(special); + return 0; +} + +/** + * Checks if a character has a special and returns true or false + * mana.chr_has_special (character, special) + */ +static int chr_has_special(lua_State *s) +{ + Character *c = getCharacter(s, 1); + if (!c) + { + raiseScriptError(s, "chr_has_special called for nonexistent character."); + return 0; + } + if (!lua_isnumber(s, 2)) + { + raiseScriptError(s, "chr_has_special called with incorect parameters"); + return 0; + } + int special = lua_tointeger(s, 2); + + lua_pushboolean(s, c->hasSpecial(special)); + return 1; +} + +/** + * Removes a special from a character + * mana.chr_take_special (character, special) + */ +static int chr_take_special(lua_State *s) +{ + Character *c = getCharacter(s, 1); + if (!c) + { + raiseScriptError(s, "chr_take_special called for nonexistent character."); + return 0; + } + if (!lua_isnumber(s, 2)) + { + raiseScriptError(s, "chr_take_special called with incorect parameters"); + return 0; + } + int special = lua_tointeger(s, 2); + + lua_pushboolean(s, c->hasSpecial(special)); + c->takeSpecial(special); + return 1; +} + + + +/** * Returns the rights level of a character. * mana.chr_get_rights (being) */ @@ -1650,6 +1723,9 @@ LuaScript::LuaScript(): { "chr_set_hair_color", &chr_set_hair_color }, { "chr_get_hair_color", &chr_get_hair_color }, { "chr_get_kill_count", &chr_get_kill_count }, + { "chr_give_special", &chr_give_special }, + { "chr_has_special", &chr_has_special }, + { "chr_take_special", &chr_take_special }, { "exp_for_level", &exp_for_level }, { "monster_create", &monster_create }, { "monster_load_script", &monster_load_script }, diff --git a/src/scripting/luascript.cpp b/src/scripting/luascript.cpp index b48ec511..33145b56 100644 --- a/src/scripting/luascript.cpp +++ b/src/scripting/luascript.cpp @@ -167,3 +167,14 @@ bool LuaScript::load_global_event_script(const std::string &file) } return true; } + +bool LuaScript::load_special_actions_script(const std::string &file) +{ + Script::special_actions_script = new LuaScript(); + if (!Script::special_actions_script->loadFile(file)) + { + Script::special_actions_script = NULL; + return false; + } + return true; +} diff --git a/src/scripting/luascript.hpp b/src/scripting/luascript.hpp index 315c759f..94851ac7 100644 --- a/src/scripting/luascript.hpp +++ b/src/scripting/luascript.hpp @@ -71,6 +71,7 @@ class LuaScript: public Script * Loads the global event script file */ static bool load_global_event_script(const std::string &file); + static bool load_special_actions_script(const std::string &file); private: diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp index fe3c5d8d..359e94bd 100644 --- a/src/scripting/script.cpp +++ b/src/scripting/script.cpp @@ -33,6 +33,7 @@ typedef std::map< std::string, Script::Factory > Engines; static Engines *engines = NULL; Script *Script::global_event_script = NULL; +Script *Script::special_actions_script = NULL; Script::Script(): mMap(NULL), @@ -122,3 +123,32 @@ bool Script::execute_global_event_function(const std::string &function, Being* o } return isScriptHandled; } + + +void Script::addDataToSpecial(int id, Special* special) +{ + /* currently only gets the recharge cost. + TODO: get any other info in a similar way, but + first we have to agree on what other + info we actually want to provide. + */ + Script *script = Script::special_actions_script; + script->prepare("get_special_recharge_cost"); + script->push(id); + int scriptReturn = script->execute(); + special->neededMana = scriptReturn; + +} + +bool Script::perform_special_action(int specialId, Being* caster) +{ + Script *script = Script::special_actions_script; + if (script) + { + script->prepare("use_special"); + script->push(caster); + script->push(specialId); + script->execute(); + } + return true; +} diff --git a/src/scripting/script.hpp b/src/scripting/script.hpp index 96df0859..0e874151 100644 --- a/src/scripting/script.hpp +++ b/src/scripting/script.hpp @@ -23,6 +23,7 @@ #include <string> +#include "game-server/character.hpp" #include "game-server/eventlistener.hpp" class MapComposite; @@ -135,11 +136,13 @@ class Script * Runs a function from the global event script file */ static bool execute_global_event_function(const std::string &function, Being *obj); - + static void addDataToSpecial(int specialId, Special *special); + static bool perform_special_action(int specialId, Being *caster); protected: static Script* global_event_script; // the global event script + static Script* special_actions_script; // the special actions script std::string mScriptFile; private: diff --git a/src/serialize/characterdata.hpp b/src/serialize/characterdata.hpp index 44e2c29e..50acc8ea 100644 --- a/src/serialize/characterdata.hpp +++ b/src/serialize/characterdata.hpp @@ -81,6 +81,14 @@ void serializeCharacterData(const T &data, MessageOut &msg) msg.writeLong(kills_it->second); } + // character specials + std::map<int, Special*>::const_iterator special_it; + msg.writeShort(data.getSpecialSize()); + for (special_it = data.getSpecialBegin(); special_it != data.getSpecialEnd() ; special_it++) + { + msg.writeLong(special_it->first); + } + // inventory - must be last because size isn't transmitted const Possessions &poss = data.getPossessions(); msg.writeLong(poss.money); @@ -152,6 +160,14 @@ void deserializeCharacterData(T &data, MessageIn &msg) data.setKillCount(monsterId, kills); } + // character specials + int specialSize = msg.readShort(); + data.clearSpecials(); + for (int i = 0; i < specialSize; i++) + { + data.giveSpecial(msg.readLong()); + } + // inventory - must be last because size isn't transmitted Possessions &poss = data.getPossessions(); poss.money = msg.readLong(); diff --git a/src/sql/mysql/createTables.sql b/src/sql/mysql/createTables.sql index 1f9bce3c..a3b37ce0 100644 --- a/src/sql/mysql/createTables.sql +++ b/src/sql/mysql/createTables.sql @@ -103,6 +103,19 @@ CREATE TABLE IF NOT EXISTS `mana_char_kill_stats` ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- Create table 'mana_char_specials' + +CREATE TABLE mana_char_specials +( + `char_id` int(10) unsigned NOT NULL, + `special_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`char_id`, `special_id`), + FOREIGN KEY (`char_id`) + REFERENCES `mana_characters` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB +DEFAULT CHARSET=utf8; + -- -- table: `mana_items` @@ -383,7 +396,7 @@ AUTO_INCREMENT=0 ; INSERT INTO mana_world_states VALUES('accountserver_startup',NULL,NULL, NOW()); INSERT INTO mana_world_states VALUES('accountserver_version',NULL,NULL, NOW()); -INSERT INTO mana_world_states VALUES('database_version', NULL,'8', NOW()); +INSERT INTO mana_world_states VALUES('database_version', NULL,'9', NOW()); -- all known transaction codes diff --git a/src/sql/mysql/updates/update_8_to_9.sql b/src/sql/mysql/updates/update_8_to_9.sql new file mode 100644 index 00000000..499cd73e --- /dev/null +++ b/src/sql/mysql/updates/update_8_to_9.sql @@ -0,0 +1,16 @@ +-- Create table 'mana_char_specials' + +CREATE TABLE mana_char_specials +( + `char_id` int(10) unsigned NOT NULL, + `special_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`char_id`, `special_id`), + FOREIGN KEY (`char_id`) + REFERENCES `mana_characters` (`id`) + ON DELETE CASCADE +) ENGINE=InnoDB +DEFAULT CHARSET=utf8; + + +UPDATE mana_world_states SET value = '9' WHERE state_name = 'database_version'; + diff --git a/src/sql/sqlite/createTables.sql b/src/sql/sqlite/createTables.sql index f4b4b1d1..bc5eefba 100644 --- a/src/sql/sqlite/createTables.sql +++ b/src/sql/sqlite/createTables.sql @@ -110,6 +110,18 @@ CREATE INDEX mana_char_kill_stats_char on mana_char_status_effects ( char_id ); ----------------------------------------------------------------------------- +CREATE TABLE mana_char_specials +( + char_id INTEGER NOT NULL, + special_id INTEGER NOT NULL, + PRIMARY KEY (char_id, special_id), + FOREIGN KEY (char_id) REFERENCES mana_characters(id) +); + +CREATE INDEX mana_char_specials_char on mana_char_specials ( char_id ); + +----------------------------------------------------------------------------- + CREATE TABLE mana_items ( id INTEGER PRIMARY KEY, @@ -374,7 +386,7 @@ AS INSERT INTO mana_world_states VALUES('accountserver_startup',NULL,NULL, strftime('%s','now')); INSERT INTO mana_world_states VALUES('accountserver_version',NULL,NULL, strftime('%s','now')); -INSERT INTO mana_world_states VALUES('database_version', NULL,'8', strftime('%s','now')); +INSERT INTO mana_world_states VALUES('database_version', NULL,'9', strftime('%s','now')); -- all known transaction codes diff --git a/src/sql/sqlite/updates/update_8_to_9.sql b/src/sql/sqlite/updates/update_8_to_9.sql new file mode 100644 index 00000000..efc0d021 --- /dev/null +++ b/src/sql/sqlite/updates/update_8_to_9.sql @@ -0,0 +1,16 @@ +CREATE TABLE mana_char_specials +( + char_id INTEGER NOT NULL, + special_id INTEGER NOT NULL, + PRIMARY KEY (char_id, special_id), + FOREIGN KEY (char_id) REFERENCES mana_characters(id) +); + +CREATE INDEX mana_char_specials_char on mana_char_specials ( char_id ); + +-- update the database version, and set date of update +UPDATE mana_world_states + SET value = '9', + moddate = strftime('%s','now') + WHERE state_name = 'database_version'; + |