Ir para conteúdo
  • Cadastre-se

Posts Recomendados

Tem como alguém adaptar esse código para o TFS 0.4 rev 3884 para mim?

 

Segue o código:

 

1. spells.cpp

Find:

    if (player->getSummonCount() >= 2) {
       player->sendCancel("You cannot summon more creatures.");
       g_game.addMagicEffect(player->getPosition(), NM_ME_POFF);
       return false;
     }

Replace it with:

    if (player->getSummonCount() >= player->getMaxSummons()) {
       player->sendCancel("You cannot summon more creatures.");
       g_game.addMagicEffect(player->getPosition(), NM_ME_POFF);
       return false;
     }
---------------------------------------------------------------------------------

2. vocations.h

Find:

uint32_t getCapGain() const {
     return gainCap;
}

After it paste:

uint32_t getMaxSummons() const {
     return maxSummons;
}

Find:

uint32_t gainCap;

After it paste:

uint32_t maxSummons;
---------------------------------------------------------------------------------

3. vocations.cpp

Find:

          if (readXMLInteger(p, "gaincap", intVal)) {
             voc->gainCap = intVal;
           }

After it paste:

if(readXMLInteger(p, "maxsummons", intVal)) {
     voc->maxSummons = intVal;
}
Find:

gainCap = 5;

After it paste:

maxSummons = 2;
---------------------------------------------------------------------------------

4. player.h

Find:

    Vocation* getVocation() const {
       return vocation;
     }

After it paste:

uint32_t getMaxSummons() const {
     return vocation->getMaxSummons();
}

Link para o post
Compartilhar em outros sites

Você quer que compile?

Porque isso é só substituir...

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites

Não compilar, é que, por exemplo:

Essa parte>> 

if

(player->getSummonCount() >= 2) {

player->sendCancel("You cannot summon more creatures.");
g_game.addMagicEffect(player->getPosition(), NM_ME_POFF);
return false

 

Não encontro na rev 3884, então creio que precise adaptar a essa rev.

Link para o post
Compartilhar em outros sites

Não encontro na rev 3884, então creio que precise adaptar a essa rev.

 

é porque tem um bool nessa versão, para o máximo de summon ser configurável no config.lua

	if((int32_t)player->getSummonCount() >= g_config.getNumber(ConfigManager::MAX_PLAYER_SUMMONS))
		{
			player->sendCancel("You cannot summon more creatures.");
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		} 

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites

Mas esse código é pra permitir que vocações sumonem quantidades diferentes de monstros. Isso faz com que possa por maxsummons=X depois de gaincap=X no vocations.xml.

Link para o post
Compartilhar em outros sites

Mas esse código é pra permitir que vocações sumonem quantidades diferentes de monstros. Isso faz com que possa por maxsummons=X depois de gaincap=X no vocations.xml.

 

Então, pô.

 

todos esses códigos você conseguiu achar?

o único que você não achou, não é o exemplificado no tutorial, certo?

 

O que eu to dizendo é para.

 

 

você procurar isso:

if((int32_t)player->getSummonCount() >= g_config.getNumber(ConfigManager::MAX_PLAYER_SUMMONS))
		{
			player->sendCancel("You cannot summon more creatures.");
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		} 

Ao invés disso:

   if (player->getSummonCount() >= 2) {
       player->sendCancel("You cannot summon more creatures.");
       g_game.addMagicEffect(player->getPosition(), NM_ME_POFF);
       return false;
     }

E colar isso:

  if (player->getSummonCount() >= player->getMaxSummons()) {
       player->sendCancel("You cannot summon more creatures.");
       g_game.addMagicEffect(player->getPosition(), NM_ME_POFF);
       return false;
     }

Porque o seu TFS está configurado para ser alterável no config.lua, aí não precisa ser re-compilado toda hora, mas mesmo assim, não é o que você quer, então você coloca em cima...

 

 

A questão é: o seu TFS é mais atualizado do que o TFS que o cara usou para fazer o tutorial.

 

 

 

Depois de fazer isso, é só você colocar isso no vocations.xml

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites

Todos os códigos eu não acho, peguei aquele como um exemplo só.

 

Como você está procurando?

poste as source requisitadas no tutorial.

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites

spells.cpp, vocation.h, vocation.cpp e spell.h. Procuro dando ctrl+f.

Poste as source.

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites

spells.cpp

 

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "const.h"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "spells.h"
#include "tools.h"

#include "house.h"
#include "housetile.h"
#include "combat.h"

#include "monsters.h"
#include "configmanager.h"
#include "game.h"

extern Game g_game;
extern Spells* g_spells;
extern Monsters g_monsters;
extern ConfigManager g_config;

Spells::Spells():
m_interface("Spell Interface")
{
	m_interface.initState();
}

ReturnValue Spells::onPlayerSay(Player* player, const std::string& words)
{
	std::string reWords = words;
	trimString(reWords);

	InstantSpell* instantSpell = getInstantSpell(reWords);
	if(!instantSpell)
		return RET_NOTPOSSIBLE;

	size_t size = instantSpell->getWords().length();
	std::string param = reWords.substr(size, reWords.length() - size), reParam = "";
	if(instantSpell->getHasParam() && !param.empty() && param[0] == ' ')
	{
		size_t quote = param.find('"', 1);
		if(quote != std::string::npos)
		{
			size_t tmp = param.find('"', quote + 1);
			if(tmp == std::string::npos)
				tmp = param.length();

			reParam = param.substr(quote + 1, tmp - quote - 1);
		}
		else if(param.find(' ', 1) == std::string::npos)
			reParam = param.substr(1, param.length());

		trimString(reParam);
	}

	Position pos = player->getPosition();
	if(!instantSpell->castInstant(player, reParam))
		return RET_NEEDEXCHANGE;

	SpeakClasses type = SPEAK_SAY;
	if(g_config.getBool(ConfigManager::EMOTE_SPELLS))
		type = SPEAK_MONSTER_SAY;

	if(!g_config.getBool(ConfigManager::SPELL_NAME_INSTEAD_WORDS))
	{
		if(g_config.getBool(ConfigManager::UNIFIED_SPELLS))
		{
			reWords = instantSpell->getWords();
			if(instantSpell->getHasParam())
				reWords += " \"" + param + "\"";
		}

		return g_game.internalCreatureSay(player, type, reWords, player->isGhost()) ?
			RET_NOERROR : RET_NOTPOSSIBLE;
	}

	std::string ret = instantSpell->getName();
	if(param.length())
	{
		trimString(param);
		size_t tmp = 0, rtmp = param.length();
		if(param[0] == '"')
			tmp = 1;

		if(param[rtmp] == '"')
			rtmp -= 1;

		ret += ": " + param.substr(tmp, rtmp);
	}

	return g_game.internalCreatureSay(player, type, ret, player->isGhost(),
		NULL, &pos) ? RET_NOERROR : RET_NOTPOSSIBLE;
}

void Spells::clear()
{
	for(RunesMap::iterator rit = runes.begin(); rit != runes.end(); ++rit)
		delete rit->second;

	runes.clear();
	for(InstantsMap::iterator it = instants.begin(); it != instants.end(); ++it)
		delete it->second;

	instants.clear();
	m_interface.reInitState();
}

Event* Spells::getEvent(const std::string& nodeName)
{
	std::string tmpNodeName = asLowerCaseString(nodeName);
	if(tmpNodeName == "rune")
		return new RuneSpell(&m_interface);

	if(tmpNodeName == "instant")
		return new InstantSpell(&m_interface);

	if(tmpNodeName == "conjure")
		return new ConjureSpell(&m_interface);

	return NULL;
}

bool Spells::registerEvent(Event* event, xmlNodePtr, bool override)
{
	if(InstantSpell* instant = dynamic_cast<InstantSpell*>(event))
	{
		InstantsMap::iterator it = instants.find(instant->getWords());
		if(it == instants.end())
		{
			instants[instant->getWords()] = instant;
			return true;
		}

		if(override)
		{
			delete it->second;
			it->second = instant;
			return true;
		}

		std::clog << "[Warning - Spells::registerEvent] Duplicate registered instant spell with words: " << instant->getWords() << std::endl;
		return false;
	}

	if(RuneSpell* rune = dynamic_cast<RuneSpell*>(event))
	{
		RunesMap::iterator it = runes.find(rune->getRuneItemId());
		if(it == runes.end())
		{
			runes[rune->getRuneItemId()] = rune;
			return true;
		}

		if(override)
		{
			delete it->second;
			it->second = rune;
			return true;
		}

		std::clog << "[Warning - Spells::registerEvent] Duplicate registered rune with id: " << rune->getRuneItemId() << std::endl;
		return false;
	}

	return false;
}

Spell* Spells::getSpellByName(const std::string& name)
{
	Spell* spell;
	if((spell = getRuneSpellByName(name)) || (spell = getInstantSpellByName(name)))
		return spell;

	return NULL;
}

RuneSpell* Spells::getRuneSpell(uint32_t id)
{
	RunesMap::iterator it = runes.find(id);
	if(it != runes.end())
		return it->second;

	return NULL;
}

RuneSpell* Spells::getRuneSpellByName(const std::string& name)
{
	for(RunesMap::iterator it = runes.begin(); it != runes.end(); ++it)
	{
		if(strcasecmp(it->second->getName().c_str(), name.c_str()) == 0)
			return it->second;
	}

	return NULL;
}

InstantSpell* Spells::getInstantSpell(const std::string& words)
{
	InstantSpell* result = NULL;
	for(InstantsMap::iterator it = instants.begin(); it != instants.end(); ++it)
	{
		InstantSpell* instantSpell = it->second;
		if(strncasecmp(instantSpell->getWords().c_str(), words.c_str(), instantSpell->getWords().length()) == 0)
		{
			if(!result || instantSpell->getWords().length() > result->getWords().length())
				result = instantSpell;
		}
	}

	if(result && words.length() > result->getWords().length())
	{
		std::string param = words.substr(result->getWords().length(), words.length());
		if(param[0] != ' ' || (param.length() > 1 && (!result->getHasParam() || param.find(' ', 1) != std::string::npos) && param[1] != '"'))
			return NULL;
	}

	return result;
}

uint32_t Spells::getInstantSpellCount(const Player* player)
{
	uint32_t count = 0;
	for(InstantsMap::iterator it = instants.begin(); it != instants.end(); ++it)
	{
		if(it->second->canCast(player))
			++count;
	}

	return count;
}

InstantSpell* Spells::getInstantSpellByIndex(const Player* player, uint32_t index)
{
	uint32_t count = 0;
	for(InstantsMap::iterator it = instants.begin(); it != instants.end(); ++it)
	{
		InstantSpell* instantSpell = it->second;
		if(!instantSpell->canCast(player))
			continue;

		if(count == index)
			return instantSpell;

		++count;
	}

	return NULL;
}

InstantSpell* Spells::getInstantSpellByName(const std::string& name)
{
	std::string tmpName = asLowerCaseString(name);
	for(InstantsMap::iterator it = instants.begin(); it != instants.end(); ++it)
	{
		if(tmpName == asLowerCaseString(it->second->getName()))
			return it->second;
	}

	return NULL;
}

Position Spells::getCasterPosition(Creature* creature, Direction dir)
{
	return getNextPosition(dir, creature->getPosition());
}

bool BaseSpell::castSpell(Creature* creature)
{
	if(!creature)
		return false;

	bool success = true;
	CreatureEventList castEvents = creature->getCreatureEvents(CREATURE_EVENT_CAST);
	for(CreatureEventList::iterator it = castEvents.begin(); it != castEvents.end(); ++it)
	{
		if(!(*it)->executeCast(creature) && success)
			success = false;
	}

	return success;
}

bool BaseSpell::castSpell(Creature* creature, Creature* target)
{
	if(!creature || !target)
		return false;

	bool success = true;
	CreatureEventList castEvents = creature->getCreatureEvents(CREATURE_EVENT_CAST);
	for(CreatureEventList::iterator it = castEvents.begin(); it != castEvents.end(); ++it)
	{
		if(!(*it)->executeCast(creature, target) && success)
			success = false;
	}

	return success;
}

CombatSpell::CombatSpell(Combat* _combat, bool _needTarget, bool _needDirection) :
	Event(&g_spells->getInterface())
{
	combat =_combat;
	needTarget = _needTarget;
	needDirection = _needDirection;
}

CombatSpell::~CombatSpell()
{
	if(combat)
		delete combat;
}

bool CombatSpell::loadScriptCombat()
{
	if(m_interface->reserveEnv())
	{
		ScriptEnviroment* env = m_interface->getEnv();
		combat = env->getCombatObject(env->getLastCombatId());

		env->resetCallback();
		m_interface->releaseEnv();
	}

	return combat != NULL;
}

bool CombatSpell::castSpell(Creature* creature)
{
	if(!BaseSpell::castSpell(creature))
		return false;

	if(isScripted())
	{
		LuaVariant var;
		var.type = VARIANT_POSITION;
		if(needDirection)
			var.pos = Spells::getCasterPosition(creature, creature->getDirection());
		else
			var.pos = creature->getPosition();

		return executeCastSpell(creature, var);
	}

	Position pos;
	if(needDirection)
		pos = Spells::getCasterPosition(creature, creature->getDirection());
	else
		pos = creature->getPosition();

	combat->doCombat(creature, pos);
	return true;
}

bool CombatSpell::castSpell(Creature* creature, Creature* target)
{
	if(!BaseSpell::castSpell(creature, target))
		return false;

	if(isScripted())
	{
		LuaVariant var;
		if(combat->hasArea())
		{
			var.type = VARIANT_POSITION;
			if(needTarget)
				var.pos = target->getPosition();
			else if(needDirection)
				var.pos = Spells::getCasterPosition(creature, creature->getDirection());
			else
				var.pos = creature->getPosition();
		}
		else
		{
			var.type = VARIANT_NUMBER;
			var.number = target->getID();
		}

		return executeCastSpell(creature, var);
	}

	if(combat->hasArea())
	{
		if(!needTarget)
			return castSpell(creature);

		combat->doCombat(creature, target->getPosition());
	}
	else
		combat->doCombat(creature, target);

	return true;
}

bool CombatSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
{
	//onCastSpell(cid, var)
	if(m_interface->reserveEnv())
	{
		ScriptEnviroment* env = m_interface->getEnv();
		if(m_scripted == EVENT_SCRIPT_BUFFER)
		{
			env->setRealPos(creature->getPosition());
			std::stringstream scriptstream;

			scriptstream << "local cid = " << env->addThing(creature) << std::endl;
			env->streamVariant(scriptstream, "var", var);

			scriptstream << m_scriptData;
			bool result = true;
			if(m_interface->loadBuffer(scriptstream.str()))
			{
				lua_State* L = m_interface->getState();
				result = m_interface->getGlobalBool(L, "_result", true);
			}

			m_interface->releaseEnv();
			return result;
		}
		else
		{
			#ifdef __DEBUG_LUASCRIPTS__
			char desc[60];
			sprintf(desc, "onCastSpell - %s", creature->getName().c_str());
			env->setEvent(desc);
			#endif

			env->setScriptId(m_scriptId, m_interface);
			env->setRealPos(creature->getPosition());
			lua_State* L = m_interface->getState();

			m_interface->pushFunction(m_scriptId);
			lua_pushnumber(L, env->addThing(creature));
			m_interface->pushVariant(L, var);

			bool result = m_interface->callFunction(2);
			m_interface->releaseEnv();
			return result;
		}
	}
	else
	{
		std::clog << "[Error - CombatSpell::executeCastSpell] Call stack overflow." << std::endl;
		return false;
	}
}

Spell::Spell()
{
	level = 0;
	magLevel = 0;
	mana = 0;
	manaPercent = 0;
	soul = 0;
	range = -1;
	exhaustion = 1000;
	needTarget = false;
	needWeapon = false;
	selfTarget = false;
	blockingSolid = false;
	blockingCreature = false;
	enabled = true;
	premium = false;
	isAggressive = true;
	learnable = false;
}

bool Spell::configureSpell(xmlNodePtr p)
{
	int32_t intValue;
	std::string strValue;
	if(readXMLString(p, "name", strValue))
	{
		name = strValue;
		const char* reservedList[] =
		{
			"melee", "physical", "poison", "earth", "fire", "ice", "freeze", "energy", "drown", "death", "curse", "holy",
			"lifedrain", "manadrain", "healing", "speed", "outfit", "invisible", "drunk", "firefield", "poisonfield",
			"energyfield", "firecondition", "poisoncondition", "energycondition", "drowncondition", "freezecondition",
			"cursecondition"
		};

		for(uint32_t i = 0; i < sizeof(reservedList) / sizeof(const char*); ++i)
		{
			if(!strcasecmp(reservedList[i], name.c_str()))
			{
				std::clog << "Error: [Spell::configureSpell] Spell is using a reserved name: " << reservedList[i] << std::endl;
				return false;
			}
		}
	}
	else
	{
		std::clog << "Error: [Spell::configureSpell] Spell without name." << std::endl;
		return false;
	}

	if(readXMLInteger(p, "lvl", intValue) || readXMLInteger(p, "level", intValue))
	 	level = intValue;

	if(readXMLInteger(p, "maglv", intValue) || readXMLInteger(p, "magiclevel", intValue))
	 	magLevel = intValue;

	if(readXMLInteger(p, "mana", intValue))
	 	mana = intValue;

	if(readXMLInteger(p, "manapercent", intValue))
	 	manaPercent = intValue;

	if(readXMLInteger(p, "soul", intValue))
	 	soul = intValue;

	if(readXMLInteger(p, "exhaustion", intValue))
		exhaustion = intValue;

	if(readXMLString(p, "enabled", strValue))
		enabled = booleanString(strValue);

	if(readXMLString(p, "prem", strValue) || readXMLString(p, "premium", strValue))
		premium = booleanString(strValue);

	if(readXMLString(p, "needtarget", strValue))
		needTarget = booleanString(strValue);

	if(readXMLString(p, "needweapon", strValue))
		needWeapon = booleanString(strValue);

	if(readXMLString(p, "selftarget", strValue))
		selfTarget = booleanString(strValue);

	if(readXMLString(p, "needlearn", strValue))
		learnable = booleanString(strValue);

	if(readXMLInteger(p, "range", intValue))
		range = intValue;

	if(readXMLString(p, "blocking", strValue))
		blockingCreature = blockingSolid = booleanString(strValue);

	if(readXMLString(p, "blocktype", strValue))
	{
		std::string tmpStrValue = asLowerCaseString(strValue);
		if(tmpStrValue == "all")
			blockingCreature = blockingSolid = true;
		else if(tmpStrValue == "solid")
			blockingSolid = true;
		else if(tmpStrValue == "creature")
			blockingCreature = true;
		else
			std::clog << "[Warning - Spell::configureSpell] Blocktype \"" <<strValue << "\" does not exist." << std::endl;
	}

	if(readXMLString(p, "aggressive", strValue))
		isAggressive = booleanString(strValue);

	std::string error = "";
	xmlNodePtr vocationNode = p->children;
	while(vocationNode)
	{
		if(!parseVocationNode(vocationNode, vocSpellMap, vocStringVec, error))
			std::clog << "[Warning - Spell::configureSpell] " << error << std::endl;

		vocationNode = vocationNode->next;
	}

	return true;
}

bool Spell::checkSpell(Player* player) const
{
	if(player->hasFlag(PlayerFlag_CannotUseSpells))
		return false;

	if(player->hasFlag(PlayerFlag_IgnoreSpellCheck))
		return true;

	if(!isEnabled())
		return false;

	bool exhausted = false;
	if(isAggressive)
	{
		if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone) && player->getZone() == ZONE_PROTECTION)
		{
			player->sendCancelMessage(RET_ACTIONNOTPERMITTEDINPROTECTIONZONE);
			return false;
		}

		if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_COMBAT))
			exhausted = true;
	}
	else if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_HEALING))
		exhausted = true;

	if(exhausted && !player->hasFlag(PlayerFlag_HasNoExhaustion))
	{
		player->sendCancelMessage(RET_YOUAREEXHAUSTED);
		if(isInstant())
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);

		return false;
	}

	if(isPremium() && !player->isPremium())
	{
		player->sendCancelMessage(RET_YOUNEEDPREMIUMACCOUNT);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if((int32_t)player->getLevel() < level)
	{
		player->sendCancelMessage(RET_NOTENOUGHLEVEL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if((int32_t)player->getMagicLevel() < magLevel)
	{
		player->sendCancelMessage(RET_NOTENOUGHMAGICLEVEL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(player->getMana() < getManaCost(player) && !player->hasFlag(PlayerFlag_HasInfiniteMana))
	{
		player->sendCancelMessage(RET_NOTENOUGHMANA);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(player->getSoul() < soul && !player->hasFlag(PlayerFlag_HasInfiniteSoul))
	{
		player->sendCancelMessage(RET_NOTENOUGHSOUL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(isInstant() && isLearnable() && !player->hasLearnedInstantSpell(getName()))
	{
		player->sendCancelMessage(RET_YOUNEEDTOLEARNTHISSPELL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!vocSpellMap.empty())
	{
		if(vocSpellMap.find(player->getVocationId()) == vocSpellMap.end())
		{
			player->sendCancelMessage(RET_YOURVOCATIONCANNOTUSETHISSPELL);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}
	}

	if(needWeapon)
	{
		switch(player->getWeaponType())
		{
			case WEAPON_SWORD:
			case WEAPON_CLUB:
			case WEAPON_AXE:
			case WEAPON_FIST:
				break;

			default:
			{
				player->sendCancelMessage(RET_YOUNEEDAWEAPONTOUSETHISSPELL);
				g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
				return false;
			}
		}
	}

	return true;
}

bool Spell::checkInstantSpell(Player* player, Creature* creature)
{
	if(!checkSpell(player))
		return false;

	const Position& toPos = creature->getPosition();
	const Position& playerPos = player->getPosition();
	if(playerPos.z > toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(playerPos.z < toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Tile* tile = g_game.getTile(toPos);
	if(!tile)
	{
		tile = new StaticTile(toPos.x, toPos.y, toPos.z);
		g_game.setTile(tile);
	}

	ReturnValue ret;
	if((ret = Combat::canDoCombat(player, tile, isAggressive)) != RET_NOERROR)
	{
		player->sendCancelMessage(ret);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(blockingCreature && creature)
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(blockingSolid && tile->hasProperty(BLOCKSOLID))
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!needTarget)
	{
		if(!isAggressive || player->getSkull() != SKULL_BLACK)
			return true;

		player->sendCancelMessage(RET_YOUMAYNOTCASTAREAONBLACKSKULL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!creature)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Player* targetPlayer = creature->getPlayer();
	if(!isAggressive || !targetPlayer || Combat::isInPvpZone(player, targetPlayer)
		|| player->getSkullType(targetPlayer) != SKULL_NONE)
		return true;

	if(player->getSecureMode() == SECUREMODE_ON)
	{
		player->sendCancelMessage(RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(player->getSkull() == SKULL_BLACK)
	{
		player->sendCancelMessage(RET_YOUMAYNOTATTACKTHISPLAYER);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	return true;
}

bool Spell::checkInstantSpell(Player* player, const Position& toPos)
{
	if(!checkSpell(player))
		return false;

	if(toPos.x == 0xFFFF)
		return true;

	const Position& playerPos = player->getPosition();
	if(playerPos.z > toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(playerPos.z < toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Tile* tile = g_game.getTile(toPos);
	if(!tile)
	{
		tile = new StaticTile(toPos.x, toPos.y, toPos.z);
		g_game.setTile(tile);
	}

	ReturnValue ret;
	if((ret = Combat::canDoCombat(player, tile, isAggressive)) != RET_NOERROR)
	{
		player->sendCancelMessage(ret);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(blockingCreature && tile->getTopVisibleCreature(player))
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(blockingSolid && tile->hasProperty(BLOCKSOLID))
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(player->getSkull() == SKULL_BLACK && isAggressive && range == -1) //-1 is (usually?) an area spell
	{
		player->sendCancelMessage(RET_YOUMAYNOTCASTAREAONBLACKSKULL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	return true;
}

bool Spell::checkRuneSpell(Player* player, const Position& toPos)
{
	if(!checkSpell(player))
		return false;

	if(toPos.x == 0xFFFF)
		return true;

	const Position& playerPos = player->getPosition();
	if(playerPos.z > toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(playerPos.z < toPos.z)
	{
		player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Tile* tile = g_game.getTile(toPos);
	if(!tile)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(range != -1 && !g_game.canThrowObjectTo(playerPos, toPos, true, range, range))
	{
		player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	ReturnValue ret;
	if((ret = Combat::canDoCombat(player, tile, isAggressive)) != RET_NOERROR)
	{
		player->sendCancelMessage(ret);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Creature* targetCreature = tile->getTopVisibleCreature(player);
	if(blockingCreature && targetCreature)
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(blockingSolid && tile->hasProperty(BLOCKSOLID))
	{
		player->sendCancelMessage(RET_NOTENOUGHROOM);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!needTarget)
	{
		if(!isAggressive || player->getSkull() != SKULL_BLACK)
			return true;

		player->sendCancelMessage(RET_YOUMAYNOTCASTAREAONBLACKSKULL);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!targetCreature)
	{
		player->sendCancelMessage(RET_CANONLYUSETHISRUNEONCREATURES);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Player* targetPlayer = targetCreature->getPlayer();
	if(!isAggressive || !targetPlayer || Combat::isInPvpZone(player, targetPlayer)
		|| player->getSkullType(targetPlayer) != SKULL_NONE)
		return true;

	if(player->getSecureMode() == SECUREMODE_ON)
	{
		player->sendCancelMessage(RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(player->getSkull() == SKULL_BLACK)
	{
		player->sendCancelMessage(RET_YOUMAYNOTATTACKTHISPLAYER);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	return true;
}

void Spell::postSpell(Player* player) const
{
	if(!player->hasFlag(PlayerFlag_HasNoExhaustion) && exhaustion > 0)
		player->addExhaust(exhaustion, isAggressive ? EXHAUST_COMBAT : EXHAUST_HEALING);

	if(isAggressive && !player->hasFlag(PlayerFlag_NotGainInFight))
		player->addInFightTicks(false);

	postSpell(player, (uint32_t)getManaCost(player), (uint32_t)getSoulCost());
}

void Spell::postSpell(Player* player, uint32_t manaCost, uint32_t soulCost) const
{
	if(manaCost > 0)
	{
		player->changeMana(-(int32_t)manaCost);
		if(!player->hasFlag(PlayerFlag_NotGainMana) && (player->getZone() != ZONE_HARDCORE
			|| g_config.getBool(ConfigManager::PVPZONE_ADDMANASPENT)))
			player->addManaSpent(manaCost);
	}

	if(soulCost > 0)
		player->changeSoul(-(int32_t)soulCost);
}

int32_t Spell::getManaCost(const Player* player) const
{
	if(player && manaPercent)
		return (int32_t)std::floor(double(player->getMaxMana() * manaPercent) / 100);

	return mana;
}

ReturnValue Spell::CreateIllusion(Creature* creature, const Outfit_t& outfit, int32_t time)
{
	ConditionOutfit* outfitCondition = new ConditionOutfit(CONDITIONID_COMBAT, CONDITION_OUTFIT, time, false, 0);
	if(!outfitCondition)
		return RET_NOTPOSSIBLE;

	outfitCondition->addOutfit(outfit);
	creature->addCondition(outfitCondition);
	return RET_NOERROR;
}

ReturnValue Spell::CreateIllusion(Creature* creature, const std::string& name, int32_t time)
{
	uint32_t mId = g_monsters.getIdByName(name);
	if(!mId)
		return RET_CREATUREDOESNOTEXIST;

	const MonsterType* mType = g_monsters.getMonsterType(mId);
	if(!mType)
		return RET_CREATUREDOESNOTEXIST;

	Player* player = creature->getPlayer();
	if(player && !player->hasFlag(PlayerFlag_CanIllusionAll) && !mType->isIllusionable)
		return RET_NOTPOSSIBLE;

	return CreateIllusion(creature, mType->outfit, time);
}

ReturnValue Spell::CreateIllusion(Creature* creature, uint32_t itemId, int32_t time)
{
	const ItemType& it = Item::items[itemId];
	if(!it.id)
		return RET_NOTPOSSIBLE;

	Outfit_t outfit;
	outfit.lookTypeEx = itemId;
	return CreateIllusion(creature, outfit, time);
}

InstantSpell::InstantSpell(LuaInterface* _interface) : TalkAction(_interface)
{
	needDirection = false;
	hasParam = false;
	checkLineOfSight = true;
	casterTargetOrDirection = false;
	limitRange = 0;
	function = NULL;
}

bool InstantSpell::configureEvent(xmlNodePtr p)
{
	if(!Spell::configureSpell(p))
		return false;

	if(!TalkAction::configureEvent(p))
		return false;

	std::string strValue;
	if(readXMLString(p, "param", strValue) || readXMLString(p, "params", strValue))
 		hasParam = booleanString(strValue);

	if(readXMLString(p, "direction", strValue))
		needDirection = booleanString(strValue);

	if(readXMLString(p, "casterTargetOrDirection", strValue))
		casterTargetOrDirection = booleanString(strValue);

	if(readXMLString(p, "blockwalls", strValue))
		checkLineOfSight = booleanString(strValue);

	int32_t intValue;
	if(readXMLInteger(p, "limitRange", intValue))
		limitRange = intValue;

	return true;
}

bool InstantSpell::loadFunction(const std::string& functionName)
{
	std::string tmpFunctionName = asLowerCaseString(functionName);
	if(tmpFunctionName == "summonmonster")
		function = SummonMonster;
	else if(tmpFunctionName == "searchplayer")
	{
		isAggressive = false;
		function = SearchPlayer;
	}
	else if(tmpFunctionName == "levitate")
	{
		isAggressive = false;
		function = Levitate;
	}
	else if(tmpFunctionName == "illusion")
	{
		isAggressive = false;
		function = Illusion;
	}
	else
	{
		std::clog << "[Warning - InstantSpell::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
		return false;
	}

	m_scripted = EVENT_SCRIPT_FALSE;
	return true;
}

bool InstantSpell::castInstant(Player* player, const std::string& param)
{
	LuaVariant var;
	if(selfTarget)
	{
		var.type = VARIANT_NUMBER;
		var.number = player->getID();
		if(!checkInstantSpell(player, player))
			return false;
	}
	else if(needTarget || casterTargetOrDirection)
	{
		Creature* target = NULL;
		if(hasParam)
		{
			Player* targetPlayer = NULL;
			ReturnValue ret = g_game.getPlayerByNameWildcard(param, targetPlayer);

			target = targetPlayer;
			if(limitRange && target && !Position::areInRange(Position(limitRange,
				limitRange, 0), target->getPosition(), player->getPosition()))
				target = NULL;

			if((!target || target->getHealth() <= 0) && !casterTargetOrDirection)
			{
				player->sendCancelMessage(ret);
				g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
				return false;
			}
		}
		else
		{
			target = player->getAttackedCreature();
			if(limitRange && target && !Position::areInRange(Position(limitRange,
				limitRange, 0), target->getPosition(), player->getPosition()))
				target = NULL;

			if((!target || target->getHealth() <= 0) && !casterTargetOrDirection)
			{
				player->sendCancelMessage(RET_YOUCANONLYUSEITONCREATURES);
				g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
				return false;
			}
		}

		if(target)
		{
			bool canSee = player->canSeeCreature(target);
			if(!canSee || !canThrowSpell(player, target))
			{
				player->sendCancelMessage(canSee ? RET_CREATUREISNOTREACHABLE : RET_PLAYERWITHTHISNAMEISNOTONLINE);
				g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
				return false;
			}

			var.type = VARIANT_NUMBER;
			var.number = target->getID();
			if(!checkInstantSpell(player, target))
				return false;
		}
		else
		{
			var.type = VARIANT_POSITION;
			var.pos = Spells::getCasterPosition(player, player->getDirection());
			if(!checkInstantSpell(player, var.pos))
				return false;
		}
	}
	else if(hasParam)
	{
		var.type = VARIANT_STRING;
		var.text = param;
		if(!checkSpell(player))
			return false;
	}
	else
	{
		var.type = VARIANT_POSITION;
		if(needDirection)
			var.pos = Spells::getCasterPosition(player, player->getDirection());
		else
			var.pos = player->getPosition();

		if(!checkInstantSpell(player, var.pos))
			return false;
	}

	if(!internalCastSpell(player, var))
		return false;

	Spell::postSpell(player);
	return true;
}

bool InstantSpell::canThrowSpell(const Creature* creature, const Creature* target) const
{
	const Position& fromPos = creature->getPosition();
	const Position& toPos = target->getPosition();
	return (!(fromPos.z != toPos.z || (range == -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight))
		|| (range != -1 && !g_game.canThrowObjectTo(fromPos, toPos, checkLineOfSight, range, range))));
}

bool InstantSpell::castSpell(Creature* creature)
{
	if(!BaseSpell::castSpell(creature))
		return false;

	LuaVariant var;
	if(casterTargetOrDirection)
	{
		Creature* target = creature->getAttackedCreature();
		if(target && target->getHealth() > 0)
		{
			if(!creature->canSeeCreature(target) || !canThrowSpell(creature, target))
				return false;

			var.type = VARIANT_NUMBER;
			var.number = target->getID();
			return internalCastSpell(creature, var);
		}

		return false;
	}

	if(needDirection)
	{
		var.type = VARIANT_POSITION;
		var.pos = Spells::getCasterPosition(creature, creature->getDirection());
	}
	else
	{
		var.type = VARIANT_POSITION;
		var.pos = creature->getPosition();
	}

	return internalCastSpell(creature, var);
}

bool InstantSpell::castSpell(Creature* creature, Creature* target)
{
	if(!BaseSpell::castSpell(creature, target))
		return false;

	if(!needTarget)
		return castSpell(creature);

	LuaVariant var;
	var.type = VARIANT_NUMBER;
	var.number = target->getID();
	return internalCastSpell(creature, var);
}

bool InstantSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
{
	if(isScripted())
		return executeCastSpell(creature, var);

	return function ? function(this, creature, var.text) : false;
}

bool InstantSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
{
	//onCastSpell(cid, var)
	if(m_interface->reserveEnv())
	{
		ScriptEnviroment* env = m_interface->getEnv();
		if(m_scripted == EVENT_SCRIPT_BUFFER)
		{
			env->setRealPos(creature->getPosition());
			std::stringstream scriptstream;

			scriptstream << "local cid = " << env->addThing(creature) << std::endl;
			env->streamVariant(scriptstream, "var", var);

			scriptstream << m_scriptData;
			bool result = true;
			if(m_interface->loadBuffer(scriptstream.str()))
			{
				lua_State* L = m_interface->getState();
				result = m_interface->getGlobalBool(L, "_result", true);
			}

			m_interface->releaseEnv();
			return result;
		}
		else
		{
			#ifdef __DEBUG_LUASCRIPTS__
			char desc[60];
			sprintf(desc, "onCastSpell - %s", creature->getName().c_str());
			env->setEvent(desc);
			#endif

			env->setScriptId(m_scriptId, m_interface);
			env->setRealPos(creature->getPosition());
			lua_State* L = m_interface->getState();

			m_interface->pushFunction(m_scriptId);
			lua_pushnumber(L, env->addThing(creature));
			m_interface->pushVariant(L, var);

			bool result = m_interface->callFunction(2);
			m_interface->releaseEnv();
			return result;
		}
	}
	else
	{
		std::clog << "[Error - InstantSpell::executeCastSpell] Call stack overflow." << std::endl;
		return false;
	}
}

bool InstantSpell::SearchPlayer(const InstantSpell*, Creature* creature, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player || player->isRemoved())
		return false;

	Player* targetPlayer = NULL;
	ReturnValue ret = g_game.getPlayerByNameWildcard(param, targetPlayer);
	if(ret != RET_NOERROR || !targetPlayer || targetPlayer->isRemoved())
	{
		player->sendCancelMessage(ret);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(targetPlayer->hasCustomFlag(PlayerCustomFlag_NotSearchable) && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges))
	{
		player->sendCancelMessage(RET_PLAYERWITHTHISNAMEISNOTONLINE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	std::stringstream ss;
	ss << targetPlayer->getName() << " " << g_game.getSearchString(player->getPosition(), targetPlayer->getPosition(), true, true) << ".";
	player->sendTextMessage(MSG_INFO_DESCR, ss.str().c_str());

	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
	return true;
}

bool InstantSpell::SummonMonster(const InstantSpell* spell, Creature* creature, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	MonsterType* mType = g_monsters.getMonsterType(param);
	if(!mType)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	int32_t manaCost = (int32_t)(mType->manaCost * g_config.getDouble(ConfigManager::RATE_MONSTER_MANA));
	if(!player->hasFlag(PlayerFlag_CanSummonAll))
	{
		if(player->getSkull() == SKULL_BLACK)
		{
			player->sendCancelMessage(RET_NOTPOSSIBLE);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}

		if(!mType->isSummonable)
		{
			player->sendCancelMessage(RET_NOTPOSSIBLE);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}

		if(player->getMana() < manaCost)
		{
			player->sendCancelMessage(RET_NOTENOUGHMANA);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}

		if((int32_t)player->getSummonCount() >= g_config.getNumber(ConfigManager::MAX_PLAYER_SUMMONS))
		{
			player->sendCancel("You cannot summon more creatures.");
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}
	}

	ReturnValue ret = g_game.placeSummon(creature, param);
	if(ret == RET_NOERROR)
	{
		spell->postSpell(player, (uint32_t)manaCost, (uint32_t)spell->getSoulCost());
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
		return true;
	}

	player->sendCancelMessage(ret);
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
	return false;
}

bool InstantSpell::Levitate(const InstantSpell*, Creature* creature, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	uint16_t floor = 7;
	ReturnValue ret = RET_NOERROR;
	const Position& position = creature->getPosition();
	Position destination = Spells::getCasterPosition(creature, creature->getDirection());

	std::string tmpParam = asLowerCaseString(param);
	if(tmpParam == "up")
		floor = 8;
	else if(tmpParam != "down")
		ret = RET_NOTPOSSIBLE;

	if(ret == RET_NOERROR)
	{
		ret = RET_NOTPOSSIBLE;
		if(position.z != floor)
		{
			Tile* tmpTile = NULL;
			if(floor != 7)
			{
				tmpTile = g_game.getTile(position.x, position.y, position.z - 1);
				destination.z--;
			}
			else
			{
				tmpTile = g_game.getTile(destination);
				destination.z++;
			}

			if(!tmpTile || (!tmpTile->ground && !tmpTile->hasProperty(IMMOVABLEBLOCKSOLID)))
			{
				Tile* tile = player->getTile();
				tmpTile = g_game.getTile(destination);
				if(tile && tmpTile && tmpTile->ground && !tmpTile->hasProperty(IMMOVABLEBLOCKSOLID) &&
					!tmpTile->floorChange() && tile->hasFlag(TILESTATE_HOUSE) == tmpTile->hasFlag(TILESTATE_HOUSE)
					&& tile->hasFlag(TILESTATE_PROTECTIONZONE) == tmpTile->hasFlag(TILESTATE_PROTECTIONZONE))
					ret = g_game.internalMoveCreature(NULL, player, tile, tmpTile, FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE);
			}
		}
	}

	if(ret == RET_NOERROR)
	{
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_TELEPORT, player->isGhost());
		return true;
	}

	player->sendCancelMessage(ret);
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF, player->isGhost());
	return false;
}

bool InstantSpell::Illusion(const InstantSpell*, Creature* creature, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	ReturnValue ret = CreateIllusion(creature, param, 60000);
	if(ret == RET_NOERROR)
	{
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_RED);
		return true;
	}

	player->sendCancelMessage(ret);
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
	return (ret == RET_NOERROR);
}

bool InstantSpell::canCast(const Player* player) const
{
	if(player->hasFlag(PlayerFlag_CannotUseSpells))
		return false;

	if(player->hasFlag(PlayerFlag_IgnoreSpellCheck) || (!isLearnable() && (vocSpellMap.empty()
		|| vocSpellMap.find(player->getVocationId()) != vocSpellMap.end())))
		return true;

	return player->hasLearnedInstantSpell(getName());
}

ConjureSpell::ConjureSpell(LuaInterface* _interface):
	InstantSpell(_interface)
{
	isAggressive = false;
	conjureId = 0;
	conjureCount = 1;
	conjureReagentId = 0;
}

bool ConjureSpell::configureEvent(xmlNodePtr p)
{
	if(!InstantSpell::configureEvent(p))
		return false;

	int32_t intValue;
	if(readXMLInteger(p, "conjureId", intValue))
		conjureId = intValue;

	if(readXMLInteger(p, "conjureCount", intValue))
		conjureCount = intValue;
	else if(conjureId != 0)
	{
		//load the default charge from items.xml
		const ItemType& it = Item::items[conjureId];
		if(it.charges != 0)
			conjureCount = it.charges;
	}

	if(readXMLInteger(p, "reagentId", intValue))
		conjureReagentId = intValue;

	return true;
}

bool ConjureSpell::loadFunction(const std::string& functionName)
{
	std::string tmpFunctionName = asLowerCaseString(functionName);
	if(tmpFunctionName == "conjureitem" || tmpFunctionName == "conjurerune")
		function = ConjureItem;
	else
	{
		std::clog << "[Warning - ConjureSpell::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
		return false;
	}

	m_scripted = EVENT_SCRIPT_FALSE;
	return true;
}

ReturnValue ConjureSpell::internalConjureItem(Player* player, uint32_t conjureId, uint32_t conjureCount,
	bool transform/* = false*/, uint32_t reagentId/* = 0*/)
{
	if(!transform)
	{
		Item* newItem = Item::CreateItem(conjureId, conjureCount);
		if(!newItem)
			return RET_NOTPOSSIBLE;

		ReturnValue ret = g_game.internalPlayerAddItem(player, player, newItem, true);
		if(ret != RET_NOERROR)
			delete newItem;

		return ret;
	}

	if(!reagentId)
		return RET_NOTPOSSIBLE;

	std::list<Container*> containers;
	Item *item = NULL, *fromItem = NULL;
	for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
	{
		if(!(item = player->getInventoryItem((slots_t)i)))
			continue;

		if(!fromItem && item->getID() == reagentId)
			fromItem = item;
		else if(Container* container = item->getContainer())
			containers.push_back(container);
	}

	if(!fromItem)
	{
		for(std::list<Container*>::iterator cit = containers.begin(); cit != containers.end(); ++cit)
		{
			for(ItemList::const_reverse_iterator it = (*cit)->getReversedItems(); it != (*cit)->getReversedEnd(); ++it)
			{
				if((*it)->getID() == reagentId)
				{
					fromItem = (*it);
					break;
				}

				if(Container* tmp = (*it)->getContainer())
					containers.push_back(tmp);
			}
		}
	}

	if(!fromItem)
		return RET_YOUNEEDAMAGICITEMTOCASTSPELL;

	item = Item::CreateItem(conjureId, conjureCount);
	ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, item, false);
	if(ret != RET_NOERROR)
		return ret;

	g_game.transformItem(fromItem, reagentId, fromItem->getItemCount() - 1);
	g_game.startDecay(item);
	return RET_NOERROR;
}

bool ConjureSpell::ConjureItem(const ConjureSpell* spell, Creature* creature, const std::string&)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	if(!player->hasFlag(PlayerFlag_IgnoreSpellCheck) && player->getZone() == ZONE_HARDCORE)
	{
		player->sendCancelMessage(RET_CANNOTCONJUREITEMHERE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	ReturnValue result = RET_NOTPOSSIBLE;
	if(spell->getReagentId() != 0)
	{
		if((result = internalConjureItem(player, spell->getConjureId(), spell->getConjureCount(), true, spell->getReagentId())) == RET_NOERROR)
		{
			spell->postSpell(player);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_RED);
			return true;
		}
	}
	else if((result = internalConjureItem(player, spell->getConjureId(), spell->getConjureCount())) == RET_NOERROR)
	{
		spell->postSpell(player);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_RED);
		return true;
	}

	player->sendCancelMessage(result);
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
	return false;
}

bool ConjureSpell::castInstant(Player* player, const std::string& param)
{
	if(!checkSpell(player))
		return false;

	if(!isScripted())
		return function ? function(this, player, param) : false;

	LuaVariant var;
	var.type = VARIANT_STRING;
	var.text = param;
	return executeCastSpell(player, var);
}

RuneSpell::RuneSpell(LuaInterface* _interface):
Action(_interface)
{
	runeId = 0;
	function = NULL;
	hasCharges = allowFarUse = true;
}

bool RuneSpell::configureEvent(xmlNodePtr p)
{
	if(!Spell::configureSpell(p))
		return false;

	if(!Action::configureEvent(p))
		return false;

	int32_t intValue;
	if(readXMLInteger(p, "id", intValue))
		runeId = intValue;
	else
	{
		std::clog << "Error: [RuneSpell::configureSpell] Rune spell without id." << std::endl;
		return false;
	}

	std::string strValue;
	if(readXMLString(p, "charges", strValue))
		hasCharges = booleanString(strValue);

	ItemType& it = Item::items.getItemType(runeId);
	if(level && level != it.runeLevel)
		it.runeLevel = level;

	if(magLevel && magLevel != it.runeMagLevel)
		it.runeMagLevel = magLevel;

	it.vocationString = parseVocationString(vocStringVec);
	return true;
}

bool RuneSpell::loadFunction(const std::string& functionName)
{
	std::string tmpFunctionName = asLowerCaseString(functionName);
	if(tmpFunctionName == "chameleon")
		function = Illusion;
	else if(tmpFunctionName == "convince")
		function = Convince;
	else
	{
		std::clog << "[Warning - RuneSpell::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
		return false;
	}

	m_scripted = EVENT_SCRIPT_FALSE;
	return true;
}

bool RuneSpell::Illusion(const RuneSpell*, Creature* creature, Item*, const Position&, const Position& posTo)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	Thing* thing = g_game.internalGetThing(player, posTo, 0, 0, STACKPOS_MOVE);
	if(!thing)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Item* illusionItem = thing->getItem();
	if(!illusionItem || !illusionItem->isMovable())
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	ReturnValue ret = CreateIllusion(creature, illusionItem->getID(), 60000);
	if(ret == RET_NOERROR)
	{
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_RED);
		return true;
	}

	player->sendCancelMessage(ret);
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
	return false;
}

bool RuneSpell::Convince(const RuneSpell* spell, Creature* creature, Item*, const Position&, const Position& posTo)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	if(!player->hasFlag(PlayerFlag_CanConvinceAll))
	{
		if(player->getSkull() == SKULL_BLACK)
		{
			player->sendCancelMessage(RET_NOTPOSSIBLE);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}

		if((int32_t)player->getSummonCount() >= g_config.getNumber(ConfigManager::MAX_PLAYER_SUMMONS))
		{
			player->sendCancelMessage(RET_NOTPOSSIBLE);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
			return false;
		}
	}

	Thing* thing = g_game.internalGetThing(player, posTo, 0, 0, STACKPOS_LOOK);
	if(!thing)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	Creature* convinceCreature = thing->getCreature();
	if(!convinceCreature)
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	int32_t manaCost = 0;
	if(Monster* monster = convinceCreature->getMonster())
		manaCost = (int32_t)(monster->getManaCost() * g_config.getDouble(ConfigManager::RATE_MONSTER_MANA));

	if(!player->hasFlag(PlayerFlag_HasInfiniteMana) && player->getMana() < manaCost)
	{
		player->sendCancelMessage(RET_NOTENOUGHMANA);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	if(!convinceCreature->convinceCreature(creature))
	{
		player->sendCancelMessage(RET_NOTPOSSIBLE);
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return false;
	}

	spell->postSpell(player, (uint32_t)manaCost, (uint32_t)spell->getSoulCost());
	g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_RED);
	return true;
}

ReturnValue RuneSpell::canExecuteAction(const Player* player, const Position& toPos)
{
	if(player->hasFlag(PlayerFlag_CannotUseSpells))
		return RET_CANNOTUSETHISOBJECT;

	ReturnValue ret = Action::canExecuteAction(player, toPos);
	if(ret != RET_NOERROR)
		return ret;

	if(toPos.x == 0xFFFF)
	{
		if(needTarget)
			return RET_CANONLYUSETHISRUNEONCREATURES;

		if(!selfTarget)
			return RET_NOTENOUGHROOM;
	}

	return RET_NOERROR;
}

bool RuneSpell::executeUse(Player* player, Item* item, const PositionEx& posFrom,
	const PositionEx& posTo, bool, uint32_t creatureId)
{
	if(!checkRuneSpell(player, posTo))
		return false;

	bool result = false;
	if(isScripted())
	{
		LuaVariant var;
		if(creatureId && needTarget)
		{
			var.type = VARIANT_NUMBER;
			var.number = creatureId;
		}
		else
		{
			var.type = VARIANT_POSITION;
			var.pos = posTo;
		}

		result = internalCastSpell(player, var);
	}
	else if(function)
		result = function(this, player, item, posFrom, posTo);

	if(result)
	{
		Spell::postSpell(player);
		if(hasCharges && item && g_config.getBool(ConfigManager::REMOVE_RUNE_CHARGES))
			g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getItemCount()) - 1));
	}

	return result;
}

bool RuneSpell::castSpell(Creature* creature)
{
	if(!BaseSpell::castSpell(creature))
		return false;

	LuaVariant var;
	var.type = VARIANT_NUMBER;
	var.number = creature->getID();
	return internalCastSpell(creature, var);
}

bool RuneSpell::castSpell(Creature* creature, Creature* target)
{
	if(!BaseSpell::castSpell(creature, target))
		return false;

	LuaVariant var;
	var.type = VARIANT_NUMBER;
	var.number = target->getID();
	return internalCastSpell(creature, var);
}

bool RuneSpell::internalCastSpell(Creature* creature, const LuaVariant& var)
{
	return isScripted() ? executeCastSpell(creature, var) : false;
}

bool RuneSpell::executeCastSpell(Creature* creature, const LuaVariant& var)
{
	//onCastSpell(cid, var)
	if(m_interface->reserveEnv())
	{
		ScriptEnviroment* env = m_interface->getEnv();
		if(m_scripted == EVENT_SCRIPT_BUFFER)
		{
			env->setRealPos(creature->getPosition());
			std::stringstream scriptstream;

			scriptstream << "local cid = " << env->addThing(creature) << std::endl;
			env->streamVariant(scriptstream, "var", var);

			scriptstream << m_scriptData;
			bool result = true;
			if(m_interface->loadBuffer(scriptstream.str()))
			{
				lua_State* L = m_interface->getState();
				result = m_interface->getGlobalBool(L, "_result", true);
			}

			m_interface->releaseEnv();
			return result;
		}
		else
		{
			#ifdef __DEBUG_LUASCRIPTS__
			char desc[60];
			sprintf(desc, "onCastSpell - %s", creature->getName().c_str());
			env->setEvent(desc);
			#endif

			env->setScriptId(m_scriptId, m_interface);
			env->setRealPos(creature->getPosition());
			lua_State* L = m_interface->getState();

			m_interface->pushFunction(m_scriptId);
			lua_pushnumber(L, env->addThing(creature));
			m_interface->pushVariant(L, var);

			bool result = m_interface->callFunction(2);
			m_interface->releaseEnv();
			return result;
		}
	}
	else
	{
		std::clog << "[Error - RuneSpell::executeCastSpell] Call stack overflow." << std::endl;
		return false;
	}
}

 

spells.h

 

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __SPELLS__
#define __SPELLS__
#include "otsystem.h"

#include "enums.h"
#include "player.h"
#include "luascript.h"

#include "baseevents.h"
#include "actions.h"
#include "talkaction.h"

class InstantSpell;
class ConjureSpell;
class RuneSpell;
class Spell;

typedef std::map<uint32_t, RuneSpell*> RunesMap;
typedef std::map<std::string, InstantSpell*> InstantsMap;

class Spells : public BaseEvents
{
	public:
		Spells();
		virtual ~Spells() {clear();}

		Spell* getSpellByName(const std::string& name);

		RuneSpell* getRuneSpell(uint32_t id);
		RuneSpell* getRuneSpellByName(const std::string& name);

		InstantSpell* getInstantSpell(const std::string& words);
		InstantSpell* getInstantSpellByName(const std::string& name);
		InstantSpell* getInstantSpellByIndex(const Player* player, uint32_t index);

		uint32_t getInstantSpellCount(const Player* player);
		ReturnValue onPlayerSay(Player* player, const std::string& words);
		virtual std::string getScriptBaseName() const {return "spells";}
		static Position getCasterPosition(Creature* creature, Direction dir);

	protected:
		virtual void clear();

		virtual Event* getEvent(const std::string& nodeName);
		virtual bool registerEvent(Event* event, xmlNodePtr p, bool override);

		virtual LuaInterface& getInterface() {return m_interface;}
		LuaInterface m_interface;

		RunesMap runes;
		InstantsMap instants;

		friend class CombatSpell;
};

typedef bool (InstantSpellFunction)(const InstantSpell* spell, Creature* creature, const std::string& param);
typedef bool (ConjureSpellFunction)(const ConjureSpell* spell, Creature* creature, const std::string& param);
typedef bool (RuneSpellFunction)(const RuneSpell* spell, Creature* creature, Item* item, const Position& posFrom, const Position& posTo);

class BaseSpell
{
	public:
		BaseSpell() {}
		virtual ~BaseSpell() {}

		virtual bool castSpell(Creature* creature);
		virtual bool castSpell(Creature* creature, Creature* target);
};

class CombatSpell : public Event, public BaseSpell
{
	public:
		CombatSpell(Combat* _combat, bool _needTarget, bool _needDirection);
		virtual ~CombatSpell();

		virtual bool castSpell(Creature* creature);
		virtual bool castSpell(Creature* creature, Creature* target);
		virtual bool configureEvent(xmlNodePtr) {return true;}

		//scripting
		bool executeCastSpell(Creature* creature, const LuaVariant& var);

		bool loadScriptCombat();
		Combat* getCombat() {return combat;}

	protected:
		virtual std::string getScriptEventName() const {return "onCastSpell";}
		virtual std::string getScriptEventParams() const {return "cid, var";}

		bool needDirection;
		bool needTarget;
		Combat* combat;
};

class Spell : public BaseSpell
{
	public:
		Spell();
		virtual ~Spell() {}

		bool configureSpell(xmlNodePtr xmlspell);
		const std::string& getName() const {return name;}

		void postSpell(Player* player) const;
		void postSpell(Player* player, uint32_t manaCost, uint32_t soulCost) const;

		int32_t getManaCost(const Player* player) const;
		int32_t getSoulCost() const {return soul;}
		uint32_t getLevel() const {return level;}
		int32_t getMagicLevel() const {return magLevel;}
		int32_t getMana() const {return mana;}
		int32_t getManaPercent() const {return manaPercent;}
		uint32_t getExhaustion() const {return exhaustion;}
		bool isEnabled() const {return enabled;}
		bool isPremium() const {return premium;}

		virtual bool isInstant() const = 0;
		bool isLearnable() const {return learnable;}

		static ReturnValue CreateIllusion(Creature* creature, const Outfit_t& outfit, int32_t time);
		static ReturnValue CreateIllusion(Creature* creature, const std::string& name, int32_t time);
		static ReturnValue CreateIllusion(Creature* creature, uint32_t itemId, int32_t time);

	protected:
		bool checkSpell(Player* player) const;
		bool checkInstantSpell(Player* player, Creature* creature);
		bool checkInstantSpell(Player* player, const Position& toPos);
		bool checkRuneSpell(Player* player, const Position& toPos);

		int32_t level;
		int32_t magLevel;
		bool premium;
		bool learnable;
		bool enabled;

		int32_t mana;
		int32_t manaPercent;
		int32_t soul;
		int32_t range;
		uint32_t exhaustion;

		bool needTarget;
		bool needWeapon;
		bool blockingSolid;
		bool blockingCreature;
		bool selfTarget;
		bool isAggressive;

		VocationMap vocSpellMap;
		typedef std::vector<std::string> VocStringVec;
		VocStringVec vocStringVec;

	private:
		std::string name;
};

class InstantSpell : public TalkAction, public Spell
{
	public:
		InstantSpell(LuaInterface* _interface);
		virtual ~InstantSpell() {}

		virtual bool configureEvent(xmlNodePtr p);
		virtual bool loadFunction(const std::string& functionName);

		virtual bool castInstant(Player* player, const std::string& param);

		virtual bool castSpell(Creature* creature);
		virtual bool castSpell(Creature* creature, Creature* target);

		//scripting
		bool executeCastSpell(Creature* creature, const LuaVariant& var);

		virtual bool isInstant() const {return true;}
		bool getHasParam() const {return hasParam;}
		bool canCast(const Player* player) const;
		bool canThrowSpell(const Creature* creature, const Creature* target) const;

	protected:
		virtual std::string getScriptEventName() const {return "onCastSpell";}
		virtual std::string getScriptEventParams() const {return "cid, var";}

		static InstantSpellFunction SearchPlayer;
		static InstantSpellFunction SummonMonster;
		static InstantSpellFunction Levitate;
		static InstantSpellFunction Illusion;

		bool internalCastSpell(Creature* creature, const LuaVariant& var);

		bool needDirection;
		bool hasParam;
		bool checkLineOfSight;
		bool casterTargetOrDirection;
		uint8_t limitRange;

		InstantSpellFunction* function;
};

class ConjureSpell : public InstantSpell
{
	public:
		ConjureSpell(LuaInterface* _interface);
		virtual ~ConjureSpell() {}

		virtual bool configureEvent(xmlNodePtr p);
		virtual bool loadFunction(const std::string& functionName);

		virtual bool castInstant(Player* player, const std::string& param);

		virtual bool castSpell(Creature*) {return false;}
		virtual bool castSpell(Creature*, Creature*) {return false;}

		uint32_t getConjureId() const {return conjureId;}
		uint32_t getConjureCount() const {return conjureCount;}
		uint32_t getReagentId() const {return conjureReagentId;}

	protected:
		virtual std::string getScriptEventName() const {return "onCastSpell";}
		virtual std::string getScriptEventParams() const {return "cid, var";}

		static ReturnValue internalConjureItem(Player* player, uint32_t conjureId, uint32_t conjureCount,
			bool transform = false, uint32_t reagentId = 0);

		static ConjureSpellFunction ConjureItem;

		bool internalCastSpell(Creature* creature, const LuaVariant& var);
		Position getCasterPosition(Creature* creature);

		ConjureSpellFunction* function;

		uint32_t conjureId;
		uint32_t conjureCount;
		uint32_t conjureReagentId;
};

class RuneSpell : public Action, public Spell
{
	public:
		RuneSpell(LuaInterface* _interface);
		virtual ~RuneSpell() {}

		virtual bool configureEvent(xmlNodePtr p);
		virtual bool loadFunction(const std::string& functionName);

		virtual ReturnValue canExecuteAction(const Player* player, const Position& toPos);
		virtual bool hasOwnErrorHandler() {return true;}

		virtual bool executeUse(Player* player, Item* item, const PositionEx& posFrom,
			const PositionEx& posTo, bool extendedUse, uint32_t creatureId);

		virtual bool castSpell(Creature* creature);
		virtual bool castSpell(Creature* creature, Creature* target);

		//scripting
		bool executeCastSpell(Creature* creature, const LuaVariant& var);

		virtual bool isInstant() const {return false;}
		uint32_t getRuneItemId(){return runeId;}

	protected:
		virtual std::string getScriptEventName() const {return "onCastSpell";}
		virtual std::string getScriptEventParams() const {return "cid, var";}

		static RuneSpellFunction Illusion;
		static RuneSpellFunction Convince;

		bool internalCastSpell(Creature* creature, const LuaVariant& var);

		bool hasCharges;
		uint32_t runeId;

		RuneSpellFunction* function;
};
#endif

 

vocation.h

 

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __OTSERV_VOCATION__
#define __OTSERV_VOCATION__

#include "otsystem.h"
#include "enums.h"

enum multiplier_t
{
	MULTIPLIER_FIRST = 0,
	MULTIPLIER_MELEE = MULTIPLIER_FIRST,
	MULTIPLIER_DISTANCE = 1,
	MULTIPLIER_DEFENSE = 2,
	MULTIPLIER_MAGICDEFENSE = 3,
	MULTIPLIER_ARMOR = 4,
	MULTIPLIER_MAGIC = 5,
	MULTIPLIER_HEALING = 6,
	MULTIPLIER_WAND = 7,
	MULTIPLIER_MANA = 8,
	MULTIPLIER_LAST = MULTIPLIER_MANA
};

enum gain_t
{
	GAIN_FIRST = 0,
	GAIN_HEALTH = GAIN_FIRST,
	GAIN_MANA = 1,
	GAIN_SOUL = 2,
	GAIN_LAST = GAIN_SOUL
};

class Vocation
{
	public:
		virtual ~Vocation();

		Vocation() {reset();}
		Vocation(uint32_t _id): id(_id) {reset();}

		void reset();

		uint32_t getId() const {return id;}
		void setId(int32_t v) {id = v;}

		uint32_t getFromVocation() const {return fromVocation;}
		void setFromVocation(int32_t v) {fromVocation = v;}

		const std::string& getName() const {return name;}
		void setName(const std::string& v) {name = v;}

		const std::string& getDescription() const {return description;}
		void setDescription(const std::string& v) {description = v;}

		bool isAttackable() const {return attackable;}
		void setAttackable(bool v) {attackable = v;}

		bool isPremiumNeeded() const {return needPremium;}
		void setNeedPremium(bool v) {needPremium = v;}

		uint32_t getAttackSpeed() const {return attackSpeed;}
		void setAttackSpeed(uint32_t v) {attackSpeed = v;}

		uint32_t getBaseSpeed() const {return baseSpeed;}
		void setBaseSpeed(uint32_t v) {baseSpeed = v;}

		int32_t getLessLoss() const {return lessLoss;}
		void setLessLoss(int32_t v) {lessLoss = v;}

		int32_t getGainCap() const {return capGain;}
		void setGainCap(int32_t v) {capGain = v;}

		uint32_t getGain(gain_t type) const {return gain[type];}
		void setGain(gain_t type, uint32_t v) {gain[type] = v;}

		uint32_t getGainTicks(gain_t type) const {return gainTicks[type];}
		void setGainTicks(gain_t type, uint32_t v) {gainTicks[type] = v;}

		uint32_t getGainAmount(gain_t type) const {return gainAmount[type];}
		void setGainAmount(gain_t type, uint32_t v) {gainAmount[type] = v;}

		float getMultiplier(multiplier_t type) const {return formulaMultipliers[type];}
		void setMultiplier(multiplier_t type, float v) {formulaMultipliers[type] = v;}

		int16_t getAbsorb(CombatType_t combat) const {return absorb[combat];}
		void increaseAbsorb(CombatType_t combat, int16_t v) {absorb[combat] += v;}

		int16_t getReflect(CombatType_t combat) const;
		void increaseReflect(Reflect_t type, CombatType_t combat, int16_t v) {reflect[type][combat] += v;}

		double getExperienceMultiplier() const {return skillMultipliers[SKILL__LEVEL];}
		void setSkillMultiplier(skills_t s, float v) {skillMultipliers[s] = v;}
		void setSkillBase(skills_t s, uint32_t v) {skillBase[s] = v;}

		uint64_t getReqSkillTries(int32_t skill, int32_t level);
		uint64_t getReqMana(uint32_t magLevel);

	private:
		typedef std::map<uint32_t, uint64_t> cacheMap;
		cacheMap cacheSkill[SKILL_LAST + 1];
		cacheMap cacheMana;

		bool attackable, needPremium;
		int32_t lessLoss, capGain;
		uint32_t id, fromVocation, baseSpeed, attackSpeed;
		std::string name, description;

		int16_t absorb[COMBAT_LAST + 1], reflect[REFLECT_LAST + 1][COMBAT_LAST + 1];
		uint32_t gain[GAIN_LAST + 1], gainTicks[GAIN_LAST + 1], gainAmount[GAIN_LAST + 1], skillBase[SKILL_LAST + 1];
		float skillMultipliers[SKILL__LAST + 1], formulaMultipliers[MULTIPLIER_LAST + 1];
};

typedef std::map<uint32_t, Vocation*> VocationsMap;
class Vocations
{
	public:
		virtual ~Vocations() {clear();}
		static Vocations* getInstance()
		{
			static Vocations instance;
			return &instance;
		}

		bool reload();
		bool loadFromXml();
		bool parseVocationNode(xmlNodePtr p);

		Vocation* getVocation(uint32_t vocId);
		int32_t getVocationId(const std::string& name);
		int32_t getPromotedVocation(uint32_t vocationId);

		VocationsMap::iterator getFirstVocation() {return vocationsMap.begin();}
		VocationsMap::iterator getLastVocation() {return vocationsMap.end();}

	private:
		static Vocation defVoc;
		VocationsMap vocationsMap;

		Vocations() {}
		void clear();
};
#endif

 

vocation.cpp

 

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include <iostream>

#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "vocation.h"
#include "tools.h"

Vocation Vocations::defVoc = Vocation();

void Vocations::clear()
{
	for(VocationsMap::iterator it = vocationsMap.begin(); it != vocationsMap.end(); ++it)
		delete it->second;

	vocationsMap.clear();
}

bool Vocations::reload()
{
	clear();
	return loadFromXml();
}

bool Vocations::parseVocationNode(xmlNodePtr p)
{
	std::string strValue;
	int32_t intValue;
	float floatValue;
	if(xmlStrcmp(p->name, (const xmlChar*)"vocation"))
		return false;

	if(!readXMLInteger(p, "id", intValue))
	{
		std::clog << "[Error - Vocations::parseVocationNode] Missing vocation id." << std::endl;
		return false;
	}

	Vocation* voc = new Vocation(intValue);
	if(readXMLString(p, "name", strValue))
		voc->setName(strValue);

	if(readXMLString(p, "description", strValue))
		voc->setDescription(strValue);

	if(readXMLString(p, "needpremium", strValue))
		voc->setNeedPremium(booleanString(strValue));

	if(readXMLInteger(p, "gaincap", intValue) || readXMLInteger(p, "gaincapacity", intValue))
		voc->setGainCap(intValue);

	if(readXMLInteger(p, "gainhp", intValue) || readXMLInteger(p, "gainhealth", intValue))
		voc->setGain(GAIN_HEALTH, intValue);

	if(readXMLInteger(p, "gainmana", intValue))
		voc->setGain(GAIN_MANA, intValue);

	if(readXMLInteger(p, "gainhpticks", intValue) || readXMLInteger(p, "gainhealthticks", intValue))
		voc->setGainTicks(GAIN_HEALTH, intValue);

	if(readXMLInteger(p, "gainhpamount", intValue) || readXMLInteger(p, "gainhealthamount", intValue))
		voc->setGainAmount(GAIN_HEALTH, intValue);

	if(readXMLInteger(p, "gainmanaticks", intValue))
		voc->setGainTicks(GAIN_MANA, intValue);

	if(readXMLInteger(p, "gainmanaamount", intValue))
		voc->setGainAmount(GAIN_MANA, intValue);

	if(readXMLFloat(p, "manamultiplier", floatValue))
		voc->setMultiplier(MULTIPLIER_MANA, floatValue);

	if(readXMLInteger(p, "attackspeed", intValue))
		voc->setAttackSpeed(intValue);

	if(readXMLInteger(p, "basespeed", intValue))
		voc->setBaseSpeed(intValue);

	if(readXMLInteger(p, "soulmax", intValue))
		voc->setGain(GAIN_SOUL, intValue);

	if(readXMLInteger(p, "gainsoulamount", intValue))
		voc->setGainAmount(GAIN_SOUL, intValue);

	if(readXMLInteger(p, "gainsoulticks", intValue))
		voc->setGainTicks(GAIN_SOUL, intValue);

	if(readXMLString(p, "attackable", strValue))
		voc->setAttackable(booleanString(strValue));

	if(readXMLInteger(p, "fromvoc", intValue) || readXMLInteger(p, "fromvocation", intValue))
		voc->setFromVocation(intValue);

	if(readXMLInteger(p, "lessloss", intValue))
		voc->setLessLoss(intValue);

	for(xmlNodePtr configNode = p->children; configNode; configNode = configNode->next)
	{
		if(!xmlStrcmp(configNode->name, (const xmlChar*)"skill"))
		{
			if(readXMLFloat(configNode, "fist", floatValue))
				voc->setSkillMultiplier(SKILL_FIST, floatValue);

			if(readXMLInteger(configNode, "fistBase", intValue))
				voc->setSkillBase(SKILL_FIST, intValue);

			if(readXMLFloat(configNode, "club", floatValue))
				voc->setSkillMultiplier(SKILL_CLUB, floatValue);

			if(readXMLInteger(configNode, "clubBase", intValue))
				voc->setSkillBase(SKILL_CLUB, intValue);

			if(readXMLFloat(configNode, "axe", floatValue))
				voc->setSkillMultiplier(SKILL_AXE, floatValue);

			if(readXMLInteger(configNode, "axeBase", intValue))
				voc->setSkillBase(SKILL_AXE, intValue);

			if(readXMLFloat(configNode, "sword", floatValue))
				voc->setSkillMultiplier(SKILL_SWORD, floatValue);

			if(readXMLInteger(configNode, "swordBase", intValue))
				voc->setSkillBase(SKILL_SWORD, intValue);

			if(readXMLFloat(configNode, "distance", floatValue) || readXMLFloat(configNode, "dist", floatValue))
				voc->setSkillMultiplier(SKILL_DIST, floatValue);

			if(readXMLInteger(configNode, "distanceBase", intValue) || readXMLInteger(configNode, "distBase", intValue))
				voc->setSkillBase(SKILL_DIST, intValue);

			if(readXMLFloat(configNode, "shielding", floatValue) || readXMLFloat(configNode, "shield", floatValue))
				voc->setSkillMultiplier(SKILL_SHIELD, floatValue);

			if(readXMLInteger(configNode, "shieldingBase", intValue) || readXMLInteger(configNode, "shieldBase", intValue))
				voc->setSkillBase(SKILL_SHIELD, intValue);

			if(readXMLFloat(configNode, "fishing", floatValue) || readXMLFloat(configNode, "fish", floatValue))
				voc->setSkillMultiplier(SKILL_FISH, floatValue);

			if(readXMLInteger(configNode, "fishingBase", intValue) || readXMLInteger(configNode, "fishBase", intValue))
				voc->setSkillBase(SKILL_FISH, intValue);

			if(readXMLFloat(configNode, "experience", floatValue) || readXMLFloat(configNode, "exp", floatValue))
				voc->setSkillMultiplier(SKILL__LEVEL, floatValue);

			if(readXMLInteger(configNode, "id", intValue))
			{
				skills_t skill = (skills_t)intValue;
				if(intValue < SKILL_FIRST || intValue >= SKILL__LAST)
				{
					std::clog << "[Error - Vocations::parseVocationNode] No valid skill id (" << intValue << ")." << std::endl;
					continue;
				}

				if(readXMLInteger(configNode, "base", intValue))
					voc->setSkillBase(skill, intValue);

				if(readXMLFloat(configNode, "multiplier", floatValue))
					voc->setSkillMultiplier(skill, floatValue);
			}
		}
		else if(!xmlStrcmp(configNode->name, (const xmlChar*)"formula"))
		{
			if(readXMLFloat(configNode, "meleeDamage", floatValue))
				voc->setMultiplier(MULTIPLIER_MELEE, floatValue);

			if(readXMLFloat(configNode, "distDamage", floatValue) || readXMLFloat(configNode, "distanceDamage", floatValue))
				voc->setMultiplier(MULTIPLIER_DISTANCE, floatValue);

			if(readXMLFloat(configNode, "wandDamage", floatValue) || readXMLFloat(configNode, "rodDamage", floatValue))
				voc->setMultiplier(MULTIPLIER_WAND, floatValue);

			if(readXMLFloat(configNode, "magDamage", floatValue) || readXMLFloat(configNode, "magicDamage", floatValue))
				voc->setMultiplier(MULTIPLIER_MAGIC, floatValue);

			if(readXMLFloat(configNode, "magHealingDamage", floatValue) || readXMLFloat(configNode, "magicHealingDamage", floatValue))
				voc->setMultiplier(MULTIPLIER_HEALING, floatValue);

			if(readXMLFloat(configNode, "defense", floatValue))
				voc->setMultiplier(MULTIPLIER_DEFENSE, floatValue);

			if(readXMLFloat(configNode, "magDefense", floatValue) || readXMLFloat(configNode, "magicDefense", floatValue))
				voc->setMultiplier(MULTIPLIER_MAGICDEFENSE, floatValue);

			if(readXMLFloat(configNode, "armor", floatValue))
				voc->setMultiplier(MULTIPLIER_ARMOR, floatValue);
		}
		else if(!xmlStrcmp(configNode->name, (const xmlChar*)"absorb"))
		{
			if(readXMLInteger(configNode, "percentAll", intValue))
			{
				for(int32_t i = COMBAT_FIRST; i <= COMBAT_LAST; i++)
					voc->increaseAbsorb((CombatType_t)i, intValue);
			}

			if(readXMLInteger(configNode, "percentElements", intValue))
			{
				voc->increaseAbsorb(COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_FIREDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_EARTHDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_ICEDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "percentMagic", intValue))
			{
				voc->increaseAbsorb(COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_FIREDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_EARTHDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_ICEDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_HOLYDAMAGE, intValue);
				voc->increaseAbsorb(COMBAT_DEATHDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "percentEnergy", intValue))
				voc->increaseAbsorb(COMBAT_ENERGYDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentFire", intValue))
				voc->increaseAbsorb(COMBAT_FIREDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentPoison", intValue) || readXMLInteger(configNode, "percentEarth", intValue))
				voc->increaseAbsorb(COMBAT_EARTHDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentIce", intValue))
				voc->increaseAbsorb(COMBAT_ICEDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentHoly", intValue))
				voc->increaseAbsorb(COMBAT_HOLYDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentDeath", intValue))
				voc->increaseAbsorb(COMBAT_DEATHDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentLifeDrain", intValue))
				voc->increaseAbsorb(COMBAT_LIFEDRAIN, intValue);

			if(readXMLInteger(configNode, "percentManaDrain", intValue))
				voc->increaseAbsorb(COMBAT_MANADRAIN, intValue);

			if(readXMLInteger(configNode, "percentDrown", intValue))
				voc->increaseAbsorb(COMBAT_DROWNDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentPhysical", intValue))
				voc->increaseAbsorb(COMBAT_PHYSICALDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentHealing", intValue))
				voc->increaseAbsorb(COMBAT_HEALING, intValue);

			if(readXMLInteger(configNode, "percentUndefined", intValue))
				voc->increaseAbsorb(COMBAT_UNDEFINEDDAMAGE, intValue);
		}
		else if(!xmlStrcmp(configNode->name, (const xmlChar*)"reflect"))
		{
			if(readXMLInteger(configNode, "percentAll", intValue))
			{
				for(int32_t i = COMBAT_FIRST; i <= COMBAT_LAST; i++)
					voc->increaseReflect(REFLECT_PERCENT, (CombatType_t)i, intValue);
			}

			if(readXMLInteger(configNode, "percentElements", intValue))
			{
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_FIREDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_EARTHDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ICEDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "percentMagic", intValue))
			{
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_FIREDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_EARTHDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ICEDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_HOLYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_DEATHDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "percentEnergy", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ENERGYDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentFire", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_FIREDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentPoison", intValue) || readXMLInteger(configNode, "percentEarth", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_EARTHDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentIce", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_ICEDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentHoly", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_HOLYDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentDeath", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_DEATHDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentLifeDrain", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_LIFEDRAIN, intValue);

			if(readXMLInteger(configNode, "percentManaDrain", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_MANADRAIN, intValue);

			if(readXMLInteger(configNode, "percentDrown", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_DROWNDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentPhysical", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_PHYSICALDAMAGE, intValue);

			if(readXMLInteger(configNode, "percentHealing", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_HEALING, intValue);

			if(readXMLInteger(configNode, "percentUndefined", intValue))
				voc->increaseReflect(REFLECT_PERCENT, COMBAT_UNDEFINEDDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceAll", intValue))
			{
				for(int32_t i = COMBAT_FIRST; i <= COMBAT_LAST; i++)
					voc->increaseReflect(REFLECT_CHANCE, (CombatType_t)i, intValue);
			}

			if(readXMLInteger(configNode, "chanceElements", intValue))
			{
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_FIREDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_EARTHDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ICEDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "chanceMagic", intValue))
			{
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ENERGYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_FIREDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_EARTHDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ICEDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_HOLYDAMAGE, intValue);
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_DEATHDAMAGE, intValue);
			}

			if(readXMLInteger(configNode, "chanceEnergy", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ENERGYDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceFire", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_FIREDAMAGE, intValue);

			if(readXMLInteger(configNode, "chancePoison", intValue) || readXMLInteger(configNode, "chanceEarth", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_EARTHDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceIce", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_ICEDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceHoly", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_HOLYDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceDeath", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_DEATHDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceLifeDrain", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_LIFEDRAIN, intValue);

			if(readXMLInteger(configNode, "chanceManaDrain", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_MANADRAIN, intValue);

			if(readXMLInteger(configNode, "chanceDrown", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_DROWNDAMAGE, intValue);

			if(readXMLInteger(configNode, "chancePhysical", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_PHYSICALDAMAGE, intValue);

			if(readXMLInteger(configNode, "chanceHealing", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_HEALING, intValue);

			if(readXMLInteger(configNode, "chanceUndefined", intValue))
				voc->increaseReflect(REFLECT_CHANCE, COMBAT_UNDEFINEDDAMAGE, intValue);
		}
	}

	vocationsMap[voc->getId()] = voc;
	return true;
}

bool Vocations::loadFromXml()
{
	xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML,"vocations.xml").c_str());
	if(!doc)
	{
		std::clog << "[Warning - Vocations::loadFromXml] Cannot load vocations file." << std::endl;
		std::clog << getLastXMLError() << std::endl;
		return false;
	}

	xmlNodePtr p, root = xmlDocGetRootElement(doc);
	if(xmlStrcmp(root->name,(const xmlChar*)"vocations"))
	{
		std::clog << "[Error - Vocations::loadFromXml] Malformed vocations file." << std::endl;
		xmlFreeDoc(doc);
		return false;
	}

	for(p = root->children; p; p = p->next)
		parseVocationNode(p);

	xmlFreeDoc(doc);
	return true;
}

Vocation* Vocations::getVocation(uint32_t vocId)
{
	VocationsMap::iterator it = vocationsMap.find(vocId);
	if(it != vocationsMap.end())
		return it->second;

	std::clog << "[Warning - Vocations::getVocation] Vocation " << vocId << " not found." << std::endl;
	return &Vocations::defVoc;
}

int32_t Vocations::getVocationId(const std::string& name)
{
	for(VocationsMap::iterator it = vocationsMap.begin(); it != vocationsMap.end(); ++it)
	{
		if(!strcasecmp(it->second->getName().c_str(), name.c_str()))
			return it->first;
	}

	return -1;
}

int32_t Vocations::getPromotedVocation(uint32_t vocationId)
{
	for(VocationsMap::iterator it = vocationsMap.begin(); it != vocationsMap.end(); ++it)
	{
		if(it->second->getFromVocation() == vocationId && it->first != vocationId)
			return it->first;
	}

	return -1;
}

Vocation::~Vocation()
{
	cacheMana.clear();
	for(int32_t i = SKILL_FIRST; i < SKILL_LAST; ++i)
		cacheSkill[i].clear();
}

void Vocation::reset()
{
	memset(absorb, 0, sizeof(absorb));
	memset(reflect[REFLECT_PERCENT], 0, sizeof(reflect[REFLECT_PERCENT]));
	memset(reflect[REFLECT_CHANCE], 0, sizeof(reflect[REFLECT_CHANCE]));

	needPremium = false;
	attackable = true;
	lessLoss = fromVocation = 0;
	gain[GAIN_SOUL] = 100;
	gainTicks[GAIN_SOUL] = 120;
	baseSpeed = 220;
	attackSpeed = 1500;
	name = description = "";

	gainAmount[GAIN_HEALTH] = gainAmount[GAIN_MANA] = gainAmount[GAIN_SOUL] = 1;
	gain[GAIN_HEALTH] = gain[GAIN_MANA] = capGain = 5;
	gainTicks[GAIN_HEALTH] = gainTicks[GAIN_MANA] = 6;

	skillBase[SKILL_SHIELD] = 100;
	skillBase[SKILL_DIST] = 30;
	skillBase[SKILL_FISH] = 20;
	for(int32_t i = SKILL_FIST; i < SKILL_DIST; i++)
		skillBase[i] = 50;

	skillMultipliers[SKILL_FIST] = 1.5f;
	skillMultipliers[SKILL_FISH] = 1.1f;
	skillMultipliers[SKILL__LEVEL] = 1.0f;
	for(int32_t i = SKILL_CLUB; i < SKILL_FISH; i++)
		skillMultipliers[i] = 2.0f;

	formulaMultipliers[MULTIPLIER_MANA] = 4.0f;
	for(int32_t i = MULTIPLIER_FIRST; i < MULTIPLIER_LAST; i++)
		formulaMultipliers[i] = 1.0f;
}

int16_t Vocation::getReflect(CombatType_t combat) const
{
	if(reflect[REFLECT_CHANCE][combat] < random_range(0, 100))
		return reflect[REFLECT_PERCENT][combat];

	return 0;
}

uint64_t Vocation::getReqSkillTries(int32_t skill, int32_t level)
{
	if(skill < SKILL_FIRST || skill > SKILL_LAST)
		return 0;

	cacheMap& skillMap = cacheSkill[skill];
	cacheMap::iterator it = skillMap.find(level);
	if(it != cacheSkill[skill].end())
		return it->second;

	skillMap[level] = (uint64_t)(skillBase[skill] * std::pow(skillMultipliers[skill], (level - 11)));
	return skillMap[level];
}

uint64_t Vocation::getReqMana(uint32_t magLevel)
{
	cacheMap::iterator it = cacheMana.find(magLevel);
	if(it != cacheMana.end())
		return it->second;

	cacheMana[magLevel] = (uint64_t)(1600 * std::pow(formulaMultipliers[MULTIPLIER_MANA], (float)(magLevel - 1)));
	return cacheMana[magLevel];
}

Link para o post
Compartilhar em outros sites

@gabriel28, Tem como você mandar todas as suas source? assim eu compilo e mando para você! 

Se quiser sua dúvida tirada, mande PM com os links, e não com a dúvida (outros podem ter a mesma dúvida, e o fórum serve para ser usado).

 

Tópicos:


 

yNlhRVC.png

 

55px-Judo_yellow_belt.svg.png

Link para o post
Compartilhar em outros sites
  • 2 months later...

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.

  • Conteúdo Similar

    • Por Jaurez
      .
    • Por Cat
      Em alguns casos, o tibia 8.60 comum não abre de jeito nenhum no map editor, mesmo desmarcando check file signatures e configurando o path corretamente.
       
      Este é o client 8.60 adaptado para o Remere's Map Editor. Resolvi postar já que ele foi removido do site oficial do RME. (ficou apenas a versão para linux lá)
      Se estiver tendo problemas para abrir a versão 8.60, tente utilizar este.
                                                                                                                     
      Baixar o Tibia Client 8.60 que funciona no Remere’s Map Editor
      Essa versão do Tibia 8.60 client resolve o erro unsupported client version ou Could not locate tibia.dat and/or tibia.spr, please navigate to your tibia 8.60 installation folder.
       
      Downloads
      https://tibiaking.com/applications/core/interface/file/attachment.php?id=47333

      Scan: https://www.virustotal.com/gui/file/333e172ac49ba2028db9eb5889994509e7d2de28ebccfa428c04e86defbe15cc
       
    • Por danilo belato
      Fala Galera To Com um problema aki 
       
      quero exporta umas sprites de um server para colocar em outro 
       
      eu clico na sprites ai aparece tds a forma delas do lado de la >>
       
      ai eu clico nela e ponho a opiçao de export mais quando salvo a sprite ela n abri 
       
      aparece isso quando tento vê-la 
       
      visualização não disponível ( no formatos png e bitmap)
       
      Agora no formato idc fala que o paint n pode ler 
       
      me ajudem ae...
    • Por Vitor Bicaleto
      Galera to com o script do addon doll aqui, quando eu digito apenas "!addon" ele aparece assim: Digite novamente, algo está errado!"
      quando digito por exemplo: "!addon citizen" ele não funciona e não da nenhum erro
       
      mesma coisa acontece com o mount doll.. 
    • Por Ayron5
      Substitui uma stone no serve, deu tudo certo fora  esse  erro ajudem  Valendo  Rep+  Grato  

      Erro: data/actions/scripts/boost.lua:557: table index is nil
       [Warning - Event::loadScript] Cannot load script (data/actions/scripts/boost.lua)

      Script:
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo