summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.LICENSE-HEADER20
-rw-r--r--README14
-rw-r--r--docs/manaserv.xml.example5
-rw-r--r--example/serverdata/scripts/maps/desert.lua19
-rw-r--r--src/account-server/main-account.cpp19
-rw-r--r--src/chat-server/chathandler.cpp8
-rw-r--r--src/game-server/accountconnection.cpp15
-rw-r--r--src/game-server/being.cpp12
-rw-r--r--src/game-server/main-game.cpp19
-rw-r--r--src/game-server/map.cpp10
-rw-r--r--src/game-server/map.h63
-rw-r--r--src/game-server/mapcomposite.cpp207
-rw-r--r--src/game-server/mapcomposite.h27
-rw-r--r--src/game-server/mapmanager.cpp21
-rw-r--r--src/game-server/mapmanager.h3
-rw-r--r--src/game-server/mapreader.cpp276
-rw-r--r--src/game-server/mapreader.h13
-rw-r--r--src/scripting/lua.cpp150
-rw-r--r--src/scripting/luautil.cpp5
-rw-r--r--src/scripting/luautil.h5
-rw-r--r--src/utils/logger.cpp17
-rw-r--r--src/utils/logger.h4
22 files changed, 540 insertions, 392 deletions
diff --git a/.LICENSE-HEADER b/.LICENSE-HEADER
new file mode 100644
index 0000000..8411df1
--- /dev/null
+++ b/.LICENSE-HEADER
@@ -0,0 +1,20 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2004-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Developers
+ *
+ * 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/>.
+ */
diff --git a/README b/README
index 5b316b7..798bce8 100644
--- a/README
+++ b/README
@@ -6,10 +6,16 @@ COMPILATION
Before trying to compile, make sure all the dependencies are installed. For
each dependency the Ubuntu package name is listed as well as the website.
- * libxml2 (libxml2-dev) - http://xmlsoft.org/
- * Lua (liblua5.1-0-dev) - http://lua.org/
- * PhysFS (libphysfs-dev) - http://icculus.org/physfs/
- * SQLite 3 (libsqlite3-dev) - http://sqlite.org/
+ * libxml2 (libxml2-dev) - http://xmlsoft.org/
+ * Lua (liblua5.1-0-dev) - http://lua.org/
+ * PhysFS (libphysfs-dev) - http://icculus.org/physfs/
+ * SQLite 3 (libsqlite3-dev) - http://sqlite.org/
+
+Optional dependencies:
+
+ * MySQL (libmysqlclient-dev) - http://dev.mysql.com/
+ (replaces the SQLite 3 depency)
+
1) cmake .
2) make
diff --git a/docs/manaserv.xml.example b/docs/manaserv.xml.example
index e810aba..75b7743 100644
--- a/docs/manaserv.xml.example
+++ b/docs/manaserv.xml.example
@@ -101,6 +101,11 @@
Change the log file each day.
-->
<option name="log_perDay" value="false"/>
+
+ <!--
+ Set whether both servers will log also on the standard output.
+ -->
+ <option name="log_toStandardOutput" value="true"/>
<!-- end of logs configuration ****************************************** -->
diff --git a/example/serverdata/scripts/maps/desert.lua b/example/serverdata/scripts/maps/desert.lua
index 601274f..8977b54 100644
--- a/example/serverdata/scripts/maps/desert.lua
+++ b/example/serverdata/scripts/maps/desert.lua
@@ -92,17 +92,22 @@ function Tamer(npc, ch, list)
mana.being_say(npc, "I will now spawn a monster for your training session.")
-- Remove monsters in the area
- for i, b in ipairs(mana.get_beings_in_rectangle(
- mana.posX(npc) - 3 * TILESIZE, mana.posY(npc) - 3 * TILESIZE,
- 6 * TILESIZE, 6 * TILESIZE)) do
+ for i, b in ipairs(mana.get_beings_in_rectangle(mana.posX(npc) - 3 * TILESIZE,
+ mana.posY(npc) - 3 * TILESIZE,
+ 6 * TILESIZE, 6 * TILESIZE)) do
if mana.being_type(b) == TYPE_MONSTER then
mana.monster_remove(b)
end
end
local m1 = mana.monster_create("Maggot", mana.posX(ch), mana.posY(ch))
- schedule_in(0.5, function()
- mana.being_say(m1, "Roaaarrrr!!!")
- mana.monster_change_anger(m1, ch, 100)
- end)
+ mana.monster_change_anger(m1, ch, 100)
+
+ -- (The following is not safe, since the being might have been removed by
+ -- the time this function gets executed (especially with the above code))
+ --
+ --schedule_in(0.5, function()
+ -- mana.being_say(m1, "Roaaarrrr!!!")
+ -- mana.monster_change_anger(m1, ch, 100)
+ -- end)
end
diff --git a/src/account-server/main-account.cpp b/src/account-server/main-account.cpp
index 6d46ec4..0adf128 100644
--- a/src/account-server/main-account.cpp
+++ b/src/account-server/main-account.cpp
@@ -141,14 +141,7 @@ static void initialize()
// Initialize PhysicsFS
PHYSFS_init("");
- // Initialize the logger.
- Logger::setLogFile(logFile, true);
-
- // Write the messages to both the screen and the log file.
- Logger::setTeeMode(
- Configuration::getBoolValue("log_accountToStandardOutput",
- true));
- LOG_INFO("Using log file: " << logFile);
+ Logger::initialize(logFile);
// Indicate in which file the statistics are put.
statisticsFile = Configuration::getValue("log_statisticsFile",
@@ -156,16 +149,6 @@ static void initialize()
LOG_INFO("Using statistics file: " << statisticsFile);
- // Set up the options related to log rotation.
- Logger::enableLogRotation(Configuration::getBoolValue("log_enableRotation",
- false));
-
- Logger::setMaxLogfileSize(Configuration::getValue("log_maxFileSize",
- 1024));
-
- Logger::setSwitchLogEachDay(Configuration::getBoolValue("log_perDay",
- false));
-
ResourceManager::initialize();
// Open database
diff --git a/src/chat-server/chathandler.cpp b/src/chat-server/chathandler.cpp
index 3f11d71..e7ef11d 100644
--- a/src/chat-server/chathandler.cpp
+++ b/src/chat-server/chathandler.cpp
@@ -350,14 +350,6 @@ void ChatHandler::handlePrivMsgMessage(ChatClient &client, MessageIn &msg)
// We seek the player to whom the message is told and send it to her/him.
sayToPlayer(client, user, text);
-
- // log transaction
- Transaction trans;
- trans.mCharacterId = client.characterId;
- trans.mAction = TRANS_MSG_PRIVATE;
- trans.mMessage = "User said " + text;
- trans.mMessage.append(" to " + user);
- storage->addTransaction(trans);
}
void ChatHandler::handleWhoMessage(ChatClient &client)
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index 874bf3e..36f30f3 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -160,7 +160,7 @@ void AccountConnection::processMessage(MessageIn &msg)
case AGMSG_ACTIVE_MAP:
{
int mapId = msg.readInt16();
- if (MapManager::raiseActive(mapId))
+ if (MapManager::activateMap(mapId))
{
// Set map variables
MapComposite *m = MapManager::getMap(mapId);
@@ -288,7 +288,8 @@ void AccountConnection::playerReconnectAccount(int id,
send(msg);
}
-void AccountConnection::requestCharacterVar(Character *ch, const std::string &name)
+void AccountConnection::requestCharacterVar(Character *ch,
+ const std::string &name)
{
MessageOut msg(GAMSG_GET_VAR_CHR);
msg.writeInt32(ch->getDatabaseID());
@@ -296,8 +297,9 @@ void AccountConnection::requestCharacterVar(Character *ch, const std::string &na
send(msg);
}
-void AccountConnection::updateCharacterVar(Character *ch, const std::string &name,
- const std::string &value)
+void AccountConnection::updateCharacterVar(Character *ch,
+ const std::string &name,
+ const std::string &value)
{
MessageOut msg(GAMSG_SET_VAR_CHR);
msg.writeInt32(ch->getDatabaseID());
@@ -306,8 +308,9 @@ void AccountConnection::updateCharacterVar(Character *ch, const std::string &nam
send(msg);
}
-void AccountConnection::updateMapVar(MapComposite *map, const std::string &name,
- const std::string &value)
+void AccountConnection::updateMapVar(MapComposite *map,
+ const std::string &name,
+ const std::string &value)
{
MessageOut msg(GAMSG_SET_VAR_MAP);
msg.writeInt32(map->getID());
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
index 4058a4a..fd9f8fe 100644
--- a/src/game-server/being.cpp
+++ b/src/game-server/being.cpp
@@ -192,11 +192,11 @@ void Being::setDestination(const Point &dst)
Path Being::findPath()
{
- mOld = getPosition();
Map *map = getMap()->getMap();
int tileWidth = map->getTileWidth();
int tileHeight = map->getTileHeight();
- int startX = mOld.x / tileWidth, startY = mOld.y / tileHeight;
+ int startX = getPosition().x / tileWidth;
+ int startY = getPosition().y / tileHeight;
int destX = mDst.x / tileWidth, destY = mDst.y / tileHeight;
return map->findPath(startX, startY, destX, destY, getWalkMask());
@@ -307,8 +307,10 @@ void Being::move()
Map *map = getMap()->getMap();
int tileWidth = map->getTileWidth();
int tileHeight = map->getTileHeight();
- int tileSX = mOld.x / tileWidth, tileSY = mOld.y / tileHeight;
- int tileDX = mDst.x / tileWidth, tileDY = mDst.y / tileHeight;
+ int tileSX = getPosition().x / tileWidth;
+ int tileSY = getPosition().y / tileHeight;
+ int tileDX = mDst.x / tileWidth;
+ int tileDY = mDst.y / tileHeight;
if (tileSX == tileDX && tileSY == tileDY)
{
@@ -316,7 +318,7 @@ void Being::move()
setAction(STAND);
// Moving while staying on the same tile is free
// We only update the direction in that case.
- updateDirection(mOld, mDst);
+ updateDirection(getPosition(), mDst);
setPosition(mDst);
mMoveTime = 0;
return;
diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp
index 9d96a6a..a9a6652 100644
--- a/src/game-server/main-game.cpp
+++ b/src/game-server/main-game.cpp
@@ -164,24 +164,7 @@ static void initializeServer()
// Initialize PhysicsFS
PHYSFS_init("");
- // Initialize the logger.
- Logger::setLogFile(logFile, true);
-
- // Write the messages to both the screen and the log file.
- Logger::setTeeMode(Configuration::getBoolValue("log_gameToStandardOutput",
- true));
-
- LOG_INFO("Using log file: " << logFile);
-
- // Set up the options related to log rotation.
- Logger::enableLogRotation(Configuration::getBoolValue("log_enableRotation",
- false));
-
- Logger::setMaxLogfileSize(Configuration::getValue("log_maxFileSize",
- 1024));
-
- Logger::setSwitchLogEachDay(Configuration::getBoolValue("log_perDay",
- false));
+ Logger::initialize(logFile);
// --- Initialize the managers
// Initialize the slang's and double quotes filter.
diff --git a/src/game-server/map.cpp b/src/game-server/map.cpp
index b824aaa..e372f03 100644
--- a/src/game-server/map.cpp
+++ b/src/game-server/map.cpp
@@ -96,7 +96,6 @@ class Location
int Fcost; /**< Estimation of total path cost */
};
-
Map::Map(int width, int height, int tileWidth, int tileHeight):
mWidth(width), mHeight(height),
mTileWidth(tileWidth), mTileHeight(tileHeight),
@@ -104,6 +103,15 @@ Map::Map(int width, int height, int tileWidth, int tileHeight):
{
}
+Map::~Map()
+{
+ for (std::vector<MapObject*>::iterator it = mMapObjects.begin();
+ it != mMapObjects.end(); ++it)
+ {
+ delete *it;
+ }
+}
+
void Map::setSize(int width, int height)
{
mWidth = width;
diff --git a/src/game-server/map.h b/src/game-server/map.h
index 7c58d00..eca3686 100644
--- a/src/game-server/map.h
+++ b/src/game-server/map.h
@@ -26,11 +26,12 @@
#include <string>
#include <vector>
+#include "utils/logger.h"
#include "utils/point.h"
+#include "utils/string.h"
typedef std::list<Point> Path;
typedef Path::iterator PathIterator;
-
enum BlockType
{
BLOCKTYPE_NONE = -1,
@@ -59,6 +60,49 @@ class MetaTile
char blockmask; /**< walkability bitfield */
};
+class MapObject
+{
+ public:
+ MapObject(const Rectangle &bounds,
+ const std::string &name,
+ const std::string &type)
+ : mBounds(bounds),
+ mName(name),
+ mType(type)
+ { }
+
+ void addProperty(const std::string &key, const std::string &value)
+ {
+ if (mProperties.contains(key))
+ LOG_WARN("Duplicate property " << key <<
+ " of object " << mName);
+ else
+ mProperties.insert(key, value);
+ }
+
+ std::string getProperty(const std::string &key) const
+ { return mProperties.find(key); }
+
+ const std::string &getName() const
+ { return mName; }
+
+ const std::string &getType() const
+ { return mType; }
+
+ const Rectangle &getBounds() const
+ { return mBounds; }
+
+ int getX() const { return mBounds.x; }
+ int getY() const { return mBounds.y; }
+
+ private:
+ Rectangle mBounds;
+ std::string mName;
+ std::string mType;
+ utils::NameMap<std::string> mProperties;
+};
+
+
/**
* A tile map.
*/
@@ -71,6 +115,8 @@ class Map
Map(int width, int height,
int tileWidth, int tileHeight);
+ ~Map();
+
/**
* Sets the size of the map. This will destroy any existing map data.
*/
@@ -129,9 +175,21 @@ class Map
/**
* Sets a map property
*/
- void setProperty(const std::string& key, const std::string& val)
+ void setProperty(const std::string &key, const std::string &val)
{ mProperties[key] = val; }
+ /**
+ * Adds an object.
+ */
+ void addObject(MapObject *object)
+ { mMapObjects.push_back(object); }
+
+ /**
+ * Returns the objects of the map.
+ */
+ const std::vector<MapObject*> &getObjects() const
+ { return mMapObjects; }
+
/**
* Find a path from one location to the next.
*/
@@ -154,6 +212,7 @@ class Map
std::map<std::string, std::string> mProperties;
std::vector<MetaTile> mMetaTiles;
+ std::vector<MapObject*> mMapObjects;
};
#endif
diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp
index d3475f7..ecd3956 100644
--- a/src/game-server/mapcomposite.cpp
+++ b/src/game-server/mapcomposite.cpp
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2006-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -21,11 +22,17 @@
#include <algorithm>
#include <cassert>
-#include "common/configuration.h"
#include "accountconnection.h"
-#include "game-server/map.h"
-#include "game-server/mapcomposite.h"
+#include "common/configuration.h"
+#include "common/resourcemanager.h"
#include "game-server/character.h"
+#include "game-server/mapcomposite.h"
+#include "game-server/map.h"
+#include "game-server/mapmanager.h"
+#include "game-server/mapreader.h"
+#include "game-server/monstermanager.h"
+#include "game-server/spawnarea.h"
+#include "game-server/trigger.h"
#include "scripting/script.h"
#include "utils/logger.h"
#include "utils/point.h"
@@ -261,6 +268,11 @@ void ActorIterator::operator++()
}
}
+
+/******************************************************************************
+ * ObjectBucket
+ *****************************************************************************/
+
ObjectBucket::ObjectBucket()
: free(256), next_object(0)
{
@@ -326,6 +338,11 @@ void ObjectBucket::deallocate(int i)
++free;
}
+
+/******************************************************************************
+ * MapContent
+ *****************************************************************************/
+
MapContent::MapContent(Map *map)
: last_bucket(0), zones(NULL)
{
@@ -433,6 +450,11 @@ MapZone& MapContent::getZone(const Point &pos) const
return zones[(pos.x / zoneDiam) + (pos.y / zoneDiam) * mapWidth];
}
+
+/******************************************************************************
+ * MapComposite
+ *****************************************************************************/
+
MapComposite::MapComposite(int id, const std::string &name):
mMap(NULL),
mContent(NULL),
@@ -449,6 +471,39 @@ MapComposite::~MapComposite()
delete mScript;
}
+bool MapComposite::activate()
+{
+ assert(!isActive());
+
+ std::string file = "maps/" + mName + ".tmx";
+ if (!ResourceManager::exists(file))
+ file += ".gz";
+
+ mMap = MapReader::readMap(file);
+ if (!mMap)
+ return false;
+
+ initializeContent();
+
+ std::string sPvP = mMap->getProperty("pvp");
+ if (sPvP.empty())
+ sPvP = Configuration::getValue("game_defaultPvp", std::string());
+
+ if (sPvP == "free")
+ mPvPRules = PVP_FREE;
+ else
+ mPvPRules = PVP_NONE;
+
+ if (Script *s = getScript())
+ {
+ s->setMap(this);
+ s->prepare("initialize");
+ s->execute();
+ }
+
+ return true;
+}
+
ZoneIterator MapComposite::getAroundPointIterator(const Point &p, int radius) const
{
MapRegion r;
@@ -544,22 +599,6 @@ void MapComposite::remove(Thing *ptr)
}
}
-void MapComposite::setMap(Map *m)
-{
- assert(!mMap && m);
- mMap = m;
- mContent = new MapContent(m);
-
- std::string sPvP = m->getProperty("pvp");
- if (sPvP.empty())
- sPvP = Configuration::getValue("game_defaultPvp", std::string());
-
- if (sPvP == "free")
- mPvPRules = PVP_FREE;
- else
- mPvPRules = PVP_NONE;
-}
-
void MapComposite::update()
{
for (int i = 0; i < mContent->mapHeight * mContent->mapWidth; ++i)
@@ -596,12 +635,11 @@ const std::vector< Thing * > &MapComposite::getEverything() const
}
-std::string MapComposite::getVariable(const std::string &key)
+std::string MapComposite::getVariable(const std::string &key) const
{
- std::map<std::string, std::string>::iterator iValue =
- mScriptVariables.find(key);
- if (iValue != mScriptVariables.end())
- return iValue->second;
+ std::map<std::string, std::string>::const_iterator i = mScriptVariables.find(key);
+ if (i != mScriptVariables.end())
+ return i->second;
else
return std::string();
}
@@ -609,9 +647,8 @@ std::string MapComposite::getVariable(const std::string &key)
void MapComposite::setVariable(const std::string &key, const std::string &value)
{
// check if the value actually changed
- std::map<std::string, std::string>::iterator iOldValue =
- mScriptVariables.find(key);
- if (iOldValue == mScriptVariables.end() || iOldValue->second != value)
+ std::map<std::string, std::string>::iterator i = mScriptVariables.find(key);
+ if (i == mScriptVariables.end() || i->second != value)
{
// changed value or unknown variable
mScriptVariables[key] = value;
@@ -619,3 +656,119 @@ void MapComposite::setVariable(const std::string &key, const std::string &value)
accountHandler->updateMapVar(this, key, value);
}
}
+
+/**
+ * Initializes the map content. This creates the warps, spawn areas, npcs and
+ * other scripts.
+ */
+void MapComposite::initializeContent()
+{
+ mContent = new MapContent(mMap);
+
+ const std::vector<MapObject*> &objects = mMap->getObjects();
+
+ for (size_t i = 0; i < objects.size(); ++i)
+ {
+ const MapObject *object = objects.at(i);
+ const std::string &type = object->getType();
+
+ if (utils::compareStrI(type, "WARP") == 0)
+ {
+ std::string destMapName = object->getProperty("DEST_MAP");
+ int destX = utils::stringToInt(object->getProperty("DEST_X"));
+ int destY = utils::stringToInt(object->getProperty("DEST_Y"));
+
+ if (!destMapName.empty() && destX && destY)
+ {
+ if (MapComposite *destMap = MapManager::getMap(destMapName))
+ {
+ WarpAction *action = new WarpAction(destMap, destX, destY);
+ insert(new TriggerArea(this, object->getBounds(),
+ action, false));
+ }
+ }
+ else
+ {
+ LOG_WARN("Unrecognized warp format");
+ }
+ }
+ else if (utils::compareStrI(type, "SPAWN") == 0)
+ {
+ MonsterClass *monster = 0;
+ int maxBeings = utils::stringToInt(object->getProperty("MAX_BEINGS"));
+ int spawnRate = utils::stringToInt(object->getProperty("SPAWN_RATE"));
+ std::string monsterName = object->getProperty("MONSTER_ID");
+ int monsterId = utils::stringToInt(monsterName);
+
+ if (monsterId)
+ {
+ monster = monsterManager->getMonster(monsterId);
+ if (!monster)
+ {
+ LOG_WARN("Couldn't find monster ID " << monsterId <<
+ " for spawn area");
+ }
+ }
+ else
+ {
+ monster = monsterManager->getMonsterByName(monsterName);
+ if (!monster)
+ {
+ LOG_WARN("Couldn't find monster " << monsterName <<
+ " for spawn area");
+ }
+ }
+
+ if (monster && maxBeings && spawnRate)
+ {
+ insert(new SpawnArea(this, monster, object->getBounds(),
+ maxBeings, spawnRate));
+ }
+ }
+ else if (utils::compareStrI(type, "NPC") == 0)
+ {
+ if (!mScript)
+ {
+ mScript = Script::create("lua");
+ }
+
+ int npcId = utils::stringToInt(object->getProperty("NPC_ID"));
+ std::string scriptText = object->getProperty("SCRIPT");
+
+ if (npcId && !scriptText.empty())
+ {
+ mScript->loadNPC(object->getName(), npcId,
+ object->getX(), object->getY(),
+ scriptText.c_str());
+ }
+ else
+ {
+ LOG_WARN("Unrecognized format for npc");
+ }
+ }
+ else if (utils::compareStrI(type, "SCRIPT") == 0)
+ {
+ if (!mScript)
+ {
+ mScript = Script::create("lua");
+ }
+
+ std::string scriptFilename = object->getProperty("FILENAME");
+ std::string scriptText = object->getProperty("TEXT");
+
+ if (!scriptFilename.empty())
+ {
+ mScript->loadFile(scriptFilename);
+ }
+ else if (!scriptText.empty())
+ {
+ std::string name = "'" + object->getName() + "'' in " + mName;
+ mScript->load(scriptText.c_str(), name.c_str());
+ }
+ else
+ {
+ LOG_WARN("Unrecognized format for script");
+ }
+ }
+ }
+}
diff --git a/src/game-server/mapcomposite.h b/src/game-server/mapcomposite.h
index f34ad24..988b0ed 100644
--- a/src/game-server/mapcomposite.h
+++ b/src/game-server/mapcomposite.h
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2006-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -233,10 +234,13 @@ class MapComposite
~MapComposite();
/**
- * Sets the underlying pathfinding map.
- * Can be done only once.
+ * Loads the map and initializes the map content. Should only be called
+ * once!
+ *
+ * @return <code>true</code> when succesful, <code>false</code> when
+ * an error occurred.
*/
- void setMap(Map *);
+ bool activate();
/**
* Gets the underlying pathfinding map.
@@ -245,13 +249,8 @@ class MapComposite
{ return mMap; }
/**
- * Sets the associated script.
- */
- void setScript(Script *s)
- { mScript = s; }
-
- /**
- * Gets the associated script.
+ * Gets the associated script. Returns 0 when no scripts or inline
+ * NPCs are used on this map!
*/
Script *getScript() const
{ return mScript; }
@@ -329,13 +328,13 @@ class MapComposite
/**
* Gets the cached value of a map-bound script variable
*/
- std::string getVariable(const std::string &key);
+ std::string getVariable(const std::string &key) const;
/**
* Changes a script variable and notifies the database server
* about the change
*/
- void setVariable (const std::string &key, const std::string &value);
+ void setVariable(const std::string &key, const std::string &value);
/**
* Changes a script variable without notifying the database server
@@ -348,13 +347,15 @@ class MapComposite
private:
MapComposite(const MapComposite &);
+ void initializeContent();
+
Map *mMap; /**< Actual map. */
MapContent *mContent; /**< Entities on the map. */
Script *mScript; /**< Script associated to this map. */
std::string mName; /**< Name of the map. */
unsigned short mID; /**< ID of the map. */
/** Cached persistent variables */
- std::map< std::string, std::string > mScriptVariables;
+ std::map<std::string, std::string> mScriptVariables;
PvPRules mPvPRules;
};
diff --git a/src/game-server/mapmanager.cpp b/src/game-server/mapmanager.cpp
index 094af92..4d7b25b 100644
--- a/src/game-server/mapmanager.cpp
+++ b/src/game-server/mapmanager.cpp
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2004-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -23,7 +24,6 @@
#include "common/resourcemanager.h"
#include "game-server/map.h"
#include "game-server/mapcomposite.h"
-#include "game-server/mapreader.h"
#include "utils/logger.h"
#include "utils/xml.h"
@@ -127,30 +127,25 @@ MapComposite *MapManager::getMap(const std::string &mapName)
return NULL;
}
-bool MapManager::raiseActive(int mapId)
+bool MapManager::activateMap(int mapId)
{
Maps::iterator i = maps.find(mapId);
assert(i != maps.end());
MapComposite *composite = i->second;
+
if (composite->isActive())
- {
return true;
- }
- std::string file = "maps/" + composite->getName() + ".tmx";
- if (!ResourceManager::exists(file))
- {
- file += ".gz";
- }
- if (MapReader::readMap(file, composite))
+ if (composite->activate())
{
- LOG_INFO("Activated map \"" << file << "\" (id " << mapId << ")");
+ LOG_INFO("Activated map \"" << composite->getName()
+ << "\" (id " << mapId << ")");
return true;
}
else
{
- LOG_WARN("Couldn't activate invalid map \"" << file << "\" (id " <<
- mapId << ")");
+ LOG_WARN("Couldn't activate invalid map \"" << composite->getName()
+ << "\" (id " << mapId << ")");
return false;
}
}
diff --git a/src/game-server/mapmanager.h b/src/game-server/mapmanager.h
index d21bd41..6b51881 100644
--- a/src/game-server/mapmanager.h
+++ b/src/game-server/mapmanager.h
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2004-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -62,7 +63,7 @@ namespace MapManager
* Sets the activity status of the map.
* @return true if the activation was successful.
*/
- bool raiseActive(int mapId);
+ bool activateMap(int mapId);
}
#endif // MAPMANAGER_H
diff --git a/src/game-server/mapreader.cpp b/src/game-server/mapreader.cpp
index 8438c82..87101a6 100644
--- a/src/game-server/mapreader.cpp
+++ b/src/game-server/mapreader.cpp
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2004-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -20,13 +21,8 @@
#include "game-server/mapreader.h"
+#include "common/defines.h"
#include "game-server/map.h"
-#include "game-server/mapcomposite.h"
-#include "game-server/mapmanager.h"
-#include "game-server/monstermanager.h"
-#include "game-server/spawnarea.h"
-#include "game-server/trigger.h"
-#include "scripting/script.h"
#include "utils/base64.h"
#include "utils/logger.h"
#include "utils/xml.h"
@@ -37,7 +33,7 @@
static std::vector< int > tilesetFirstGids;
-bool MapReader::readMap(const std::string &filename, MapComposite *composite)
+Map *MapReader::readMap(const std::string &filename)
{
XML::Document doc(filename);
xmlNodePtr rootNode = doc.rootNode();
@@ -49,39 +45,16 @@ bool MapReader::readMap(const std::string &filename, MapComposite *composite)
return false;
}
- std::vector<Thing *> things;
- Map *map = readMap(rootNode, filename, composite, things);
-
- if (map)
- {
- composite->setMap(map);
-
- for (std::vector< Thing * >::const_iterator i = things.begin(),
- i_end = things.end(); i != i_end; ++i)
- {
- composite->insert(*i);
- }
-
- if (Script *s = composite->getScript())
- {
- s->setMap(composite);
- s->prepare("initialize");
- s->execute();
- }
- }
- return true;
+ return readMap(rootNode);
}
-Map* MapReader::readMap(xmlNodePtr node, const std::string &path,
- MapComposite *composite, std::vector<Thing *> &things)
+Map *MapReader::readMap(xmlNodePtr node)
{
- // Take the filename off the path
- std::string pathDir = path.substr(0, path.rfind("/") + 1);
int w = XML::getProperty(node, "width", 0);
int h = XML::getProperty(node, "height", 0);
- int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_LENGTH);
- int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_LENGTH);
- Map* map = new Map(w, h, tilew, tileh);
+ int tileW = XML::getProperty(node, "tilewidth", DEFAULT_TILE_LENGTH);
+ int tileH = XML::getProperty(node, "tileheight", DEFAULT_TILE_LENGTH);
+ Map *map = new Map(w, h, tileW, tileH);
for (node = node->xmlChildrenNode; node != NULL; node = node->next)
{
@@ -141,236 +114,29 @@ Map* MapReader::readMap(xmlNodePtr node, const std::string &path,
int objH = XML::getProperty(objectNode, "height", 0);
Rectangle rect = { objX, objY, objW, objH };
+ MapObject *newObject = new MapObject(rect, objName, objType);
- if (utils::compareStrI(objType, "WARP") == 0)
- {
- std::string destMapName = std::string();
- int destX = -1;
- int destY = -1;
-
- for_each_xml_child_node(propertiesNode, objectNode)
- {
- if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties"))
- {
- continue;
- }
-
- for_each_xml_child_node(propertyNode, propertiesNode)
- {
- if (xmlStrEqual(propertyNode->name,
- BAD_CAST "property"))
- {
- std::string value = XML::getProperty(
- propertyNode, "name", std::string());
- value = utils::toUpper(value);
- if (utils::compareStrI(value, "DEST_MAP") == 0)
- {
- destMapName = getObjectProperty(propertyNode,
- std::string());
- }
- else if (utils::compareStrI(value, "DEST_X") == 0)
- {
- destX = getObjectProperty(propertyNode, -1);
- }
- else if (utils::compareStrI(value, "DEST_Y") == 0)
- {
- destY = getObjectProperty(propertyNode, -1);
- }
- }
- }
- }
-
- if (!destMapName.empty() && destX != -1 && destY != -1)
- {
- MapComposite *destMap = MapManager::getMap(destMapName);
- if (destMap)
- {
- things.push_back(new TriggerArea(
- composite, rect,
- new WarpAction(destMap, destX, destY),
- false));
- }
- }
- else
- {
- LOG_WARN("Unrecognized warp format");
- }
- }
- else if (utils::compareStrI(objType, "SPAWN") == 0)
- {
- MonsterClass *monster = 0;
- int maxBeings = 10; // Default value
- int spawnRate = 10; // Default value
-
- for_each_xml_child_node(propertiesNode, objectNode)
- {
- if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties"))
- {
- continue;
- }
-
- for_each_xml_child_node(propertyNode, propertiesNode)
- {
- if (xmlStrEqual(propertyNode->name, BAD_CAST "property"))
- {
- std::string value = XML::getProperty(
- propertyNode,
- "name",
- std::string());
- value = utils::toUpper(value);
- if (utils::compareStrI(value, "MONSTER_ID") == 0)
- {
- std::string monsterName =
- getObjectProperty(propertyNode,
- std::string());
- int monsterId = utils::stringToInt(monsterName);
- if (monsterId)
- {
- monster = monsterManager->getMonster(
- monsterId);
- if (!monster)
- {
- LOG_WARN("Couldn't find monster ID "
- << monsterId <<
- " for spawn area");
- }
- }
- else
- {
- monster = monsterManager->
- getMonsterByName(monsterName);
- if (!monster)
- {
- LOG_WARN("Couldn't find monster "
- << monsterName <<
- " for spawn area");
- }
- }
- }
- else if (utils::compareStrI(value,
- "MAX_BEINGS") == 0)
- {
- maxBeings = getObjectProperty(propertyNode,
- maxBeings);
- }
- else if (utils::compareStrI(value,
- "SPAWN_RATE") == 0)
- {
- spawnRate = getObjectProperty(propertyNode,
- spawnRate);
- }
- }
- }
- }
-
- if (monster)
- {
- things.push_back(new SpawnArea(composite, monster, rect,
- maxBeings, spawnRate));
- }
- }
- else if (utils::compareStrI(objType, "NPC") == 0)
+ for_each_xml_child_node(propertiesNode, objectNode)
{
- Script *s = composite->getScript();
- if (!s)
+ if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties"))
{
- // Create a Lua context.
- s = Script::create("lua");
- composite->setScript(s);
+ continue;
}
-
- int npcId = -1;
- std::string scriptText;
-
- for_each_xml_child_node(propertiesNode, objectNode)
+
+ for_each_xml_child_node(propertyNode, propertiesNode)
{
- if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties"))
- {
- continue;
- }
-
- for_each_xml_child_node(propertyNode, propertiesNode)
+ if (xmlStrEqual(propertyNode->name, BAD_CAST "property"))
{
- if (xmlStrEqual(propertyNode->name, BAD_CAST "property"))
- {
- std::string value = XML::getProperty(propertyNode, "name", std::string());
- value = utils::toUpper(value);
- if (utils::compareStrI(value, "NPC_ID") == 0)
- {
- npcId = getObjectProperty(propertyNode, npcId);
- }
- else if (utils::compareStrI(value, "SCRIPT") == 0)
- {
- scriptText = getObjectProperty(propertyNode, std::string());
- }
- }
+ std::string key = XML::getProperty(
+ propertyNode, "name", std::string());
+ std::string value = getObjectProperty(propertyNode,
+ std::string());
+ newObject->addProperty(key, value);
}
}
-
- if (npcId != -1 && !scriptText.empty())
- {
- s->loadNPC(objName, npcId, objX, objY, scriptText.c_str());
- }
- else
- {
- LOG_WARN("Unrecognized format for npc");
- }
}
- else if (utils::compareStrI(objType, "SCRIPT") == 0)
- {
- Script *s = composite->getScript();
- if (!s)
- {
- // Create a Lua context.
- s = Script::create("lua");
- composite->setScript(s);
- }
-
- std::string scriptFilename;
- std::string scriptText;
- for_each_xml_child_node(propertiesNode, objectNode)
- {
- if (!xmlStrEqual(propertiesNode->name, BAD_CAST "properties"))
- {
- continue;
- }
-
- for_each_xml_child_node(propertyNode, propertiesNode)
- {
- if (xmlStrEqual(propertyNode->name, BAD_CAST "property"))
- {
- std::string value = XML::getProperty(propertyNode, "name",
- std::string());
- value = utils::toUpper(value);
- if (utils::compareStrI(value, "FILENAME") == 0)
- {
- scriptFilename = getObjectProperty(propertyNode,
- std::string());
- utils::trim(scriptFilename);
- }
- else if (utils::compareStrI(value, "TEXT") == 0)
- {
- scriptText = getObjectProperty(propertyNode, "");
- }
- }
- }
- }
-
- if (!scriptFilename.empty())
- {
- s->loadFile(scriptFilename);
- }
- else if (!scriptText.empty())
- {
- const std::string name = "'" + objName + "'' in " + path;
- s->load(scriptText.c_str(), name.c_str());
- }
- else
- {
- LOG_WARN("Unrecognized format for script");
- }
- }
+ map->addObject(newObject);
}
}
}
diff --git a/src/game-server/mapreader.h b/src/game-server/mapreader.h
index f4a0e5f..725737f 100644
--- a/src/game-server/mapreader.h
+++ b/src/game-server/mapreader.h
@@ -1,6 +1,7 @@
/*
* The Mana Server
* Copyright (C) 2004-2010 The Mana World Development Team
+ * Copyright (C) 2010-2011 The Mana Development Team
*
* This file is part of The Mana Server.
*
@@ -38,19 +39,15 @@ class MapReader
public:
/**
* Read an XML map from a file.
- * @return true if it was successful.
+ * @return the map when successful, 0 otherwise.
*/
- static bool readMap(const std::string &filename,
- MapComposite *composite);
+ static Map *readMap(const std::string &filename);
private:
/**
- * Read an XML map from a parsed XML tree, and populate things with
- * objects in that map.
+ * Read an XML map from a parsed XML tree.
*/
- static Map *readMap(xmlNodePtr node, const std::string &path,
- MapComposite *composite,
- std::vector<Thing *> &things);
+ static Map *readMap(xmlNodePtr node);
/**
* Reads a map layer and adds it to the given map.
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 4d5d337..03d0877 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -1432,14 +1432,27 @@ static int chat_message(lua_State *s)
/**
* mana.get_beings_in_circle(int x, int y, int radius): table of Being*
+ * mana.get_beings_in_circle(handle centerBeing, int radius): table of Being*
* Gets a LUA table with the Being* pointers of all beings
* inside of a circular area of the current map.
*/
static int get_beings_in_circle(lua_State *s)
{
- const int x = luaL_checkint(s, 1);
- const int y = luaL_checkint(s, 2);
- const int r = luaL_checkint(s, 3);
+ int x, y, r;
+ if (lua_islightuserdata(s, 1))
+ {
+ Being *b = getBeing(s, 1);
+ const Point &pos = b->getPosition();
+ x = pos.x;
+ y = pos.y;
+ r = luaL_checkint(s, 2);
+ }
+ else
+ {
+ x = luaL_checkint(s, 1);
+ y = luaL_checkint(s, 2);
+ r = luaL_checkint(s, 3);
+ }
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -2139,6 +2152,132 @@ static int get_distance(lua_State *s)
return 1;
}
+/**
+ * mana.map_get_objects(): table of all objects
+ * mana.map_get_objects(string type): table of all objects of type
+ * Gets the objects of a map.
+ */
+static int map_get_objects(lua_State *s)
+{
+ const bool filtered = (lua_gettop(s) == 1);
+ std::string filter;
+ if (filtered)
+ filter = luaL_checkstring(s, 1);
+
+ lua_pushlightuserdata(s, (void *)&registryKey);
+ lua_gettable(s, LUA_REGISTRYINDEX);
+ Script *t = static_cast<Script *>(lua_touserdata(s, -1));
+ const std::vector<MapObject*> &objects = t->getMap()->getMap()->getObjects();
+
+ if (!filtered)
+ pushSTLContainer<MapObject*>(s, objects);
+ else
+ {
+ std::vector<MapObject*> filteredObjects;
+ for (std::vector<MapObject*>::const_iterator it = objects.begin();
+ it != objects.end(); ++it)
+ {
+ if (utils::compareStrI((*it)->getType(), filter) == 0)
+ {
+ filteredObjects.push_back(*it);
+ }
+ }
+ pushSTLContainer<MapObject*>(s, filteredObjects);
+ }
+ return 1;
+}
+
+/**
+ * mana.map_object_get_property(handle object, string key)
+ * Returns the value of the object property 'key'.
+ */
+static int map_object_get_property(lua_State *s)
+{
+ std::string key = luaL_checkstring(s, 2);
+ if (!lua_islightuserdata(s, 1))
+ {
+ raiseScriptError(s, "map_object_get_property called with invalid"
+ "object handle");
+ return 0;
+ }
+ MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ if (obj)
+ {
+ std::string property = obj->getProperty(key);
+ if (!property.empty())
+ {
+ lua_pushstring(s, property.c_str());
+ return 1;
+ }
+ else
+ {
+ // scripts can check for nil
+ return 0;
+ }
+ }
+ else
+ {
+ raiseScriptError(s, "map_object_get_property called with invalid"
+ "object handle");
+ return 0;
+ }
+}
+
+/**
+ * mana.map_object_get_bounds(object)
+ * Returns 4 int: x/y/width/height of object.
+ */
+static int map_object_get_bounds(lua_State *s)
+{
+ if (!lua_islightuserdata(s, 1))
+ {
+ raiseScriptError(s, "map_object_get_bounds called with invalid"
+ "object handle");
+ return 0;
+ }
+ MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ const Rectangle &bounds = obj->getBounds();
+ lua_pushinteger(s, bounds.x);
+ lua_pushinteger(s, bounds.y);
+ lua_pushinteger(s, bounds.w);
+ lua_pushinteger(s, bounds.h);
+ return 4;
+}
+
+/**
+ * mana.map_object_get_name(object)
+ * Returns the name of the object.
+ */
+static int map_object_get_name(lua_State *s)
+{
+ if (!lua_islightuserdata(s, 1))
+ {
+ raiseScriptError(s, "map_object_get_name called with invalid"
+ "object handle");
+ return 0;
+ }
+ MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ lua_pushstring(s, obj->getName().c_str());
+ return 1;
+}
+
+/**
+ * mana.map_object_get_type(object)
+ * Returns the type of the object.
+ */
+static int map_object_get_type(lua_State *s)
+{
+ if (!lua_islightuserdata(s, 1))
+ {
+ raiseScriptError(s, "map_object_get_type called with invalid"
+ "object handle");
+ return 0;
+ }
+ MapObject *obj = static_cast<MapObject *>(lua_touserdata(s, 1));
+ lua_pushstring(s, obj->getType().c_str());
+ return 1;
+}
+
static int require_loader(lua_State *s)
{
// Add .lua extension (maybe only do this when it doesn't have it already)
@@ -2248,6 +2387,11 @@ LuaScript::LuaScript():
{ "npc_ask_string", &npc_ask_string },
{ "log", &log },
{ "get_distance", &get_distance },
+ { "map_get_objects", &map_get_objects },
+ { "map_object_get_property", &map_object_get_property },
+ { "map_object_get_bounds", &map_object_get_bounds },
+ { "map_object_get_name", &map_object_get_name },
+ { "map_object_get_type", &map_object_get_type },
{ NULL, NULL }
};
luaL_register(mState, "mana", callbacks);
diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp
index b7680c6..a752142 100644
--- a/src/scripting/luautil.cpp
+++ b/src/scripting/luautil.cpp
@@ -116,3 +116,8 @@ void push(lua_State *s, double val)
{
lua_pushnumber(s, val);
}
+
+void push(lua_State *s, MapObject *val)
+{
+ lua_pushlightuserdata(s, val);
+}
diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h
index c55b04b..82bb78c 100644
--- a/src/scripting/luautil.h
+++ b/src/scripting/luautil.h
@@ -31,6 +31,8 @@ extern "C" {
#include <set>
#include <vector>
+#include "game-server/map.h"
+
class Being;
class NPC;
class Character;
@@ -52,8 +54,9 @@ Being *getBeing(lua_State *s, int p);
Useful for templates.*/
void push(lua_State *s, int val);
void push(lua_State *s, const std::string &val);
-void push(lua_State *s, Thing* val);
+void push(lua_State *s, Thing *val);
void push(lua_State *s, double val);
+void push(lua_State *s, MapObject *val);
/* Pushes an STL LIST */
diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp
index e5ceb9b..8a07057 100644
--- a/src/utils/logger.cpp
+++ b/src/utils/logger.cpp
@@ -20,6 +20,7 @@
*/
#include "logger.h"
+#include "common/configuration.h"
#include "common/resourcemanager.h"
#include "utils/string.h"
#include "utils/time.h"
@@ -63,7 +64,7 @@ static std::string mOldDate;
*
* @return whether the day has changed.
*/
-bool getDayChanged()
+static bool getDayChanged()
{
std::string dayDate = getCurrentDate();
@@ -78,6 +79,20 @@ bool getDayChanged()
return false;
}
+void Logger::initialize(const std::string &logFile)
+{
+ setLogFile(logFile, true);
+
+ // Write the messages to both the screen and the log file.
+ setTeeMode(Configuration::getBoolValue("log_toStandardOutput", true));
+ LOG_INFO("Using log file: " << logFile);
+
+ // Set up the options related to log rotation.
+ setLogRotation(Configuration::getBoolValue("log_enableRotation", false));
+ setMaxLogfileSize(Configuration::getValue("log_maxFileSize", 1024));
+ setSwitchLogEachDay(Configuration::getBoolValue("log_perDay", false));
+}
+
void Logger::output(std::ostream &os, const std::string &msg, const char *prefix)
{
if (mHasTimestamp)
diff --git a/src/utils/logger.h b/src/utils/logger.h
index ba64b10..65846be 100644
--- a/src/utils/logger.h
+++ b/src/utils/logger.h
@@ -82,6 +82,8 @@ class Logger
Debug
};
+ static void initialize(const std::string &logFile);
+
/**
* Sets the log file.
*
@@ -127,7 +129,7 @@ class Logger
*
* @param enable Set to true to enable logrotation.
*/
- static void enableLogRotation(bool enable = true)
+ static void setLogRotation(bool enable)
{ mLogRotation = enable; }
/**