Esse sistema foi feito utilizando a source disponibilizada neste link
Pode funcionar em TFS 0.4, OTX 2.X e, talvez, em TFS 0.4 só que a probabilidade erros é maior por ter diferentes nomes de funções e variáveis.
Fiz um vídeo seguindo o passo a passo abaixo para facilitar o processo de instalação do sistema.
Hoje estarei ensinando a instalar os seguintes novos atributos/sistemas em sua source
CriticalHitChance e DodgeChance -- (Funciona da mesma maneira que o critical básico de script, porém sem bugs de callstack)
Life e Mana Absorb -- (Regenera, de acordo com a % atribuida, a partir de dano recebido)
Life e Mana Leech -- (Regenera, de acordo com a % atribuida, a partir do dano causado)
Exemplo de como vai ficar
Primeiro e antes de tudo, você terá de desativar o critical padrão do Tibia (Você pode pular essa parte se quiser)
Vamos lá! Vá em items.cpp e procure por:
attackSpeed = 0;
Abaixo coloque:
criticalHitChance = dodgeChance = lifeAbsorb = manaAbsorb = lifeLeech = manaLeech = 0;
Depois, ainda em items.cpp, procure por:
else if(tmpStrValue == "extradefense" || tmpStrValue == "extradef")
{
if(readXMLInteger(itemAttributesNode, "chance", intValue))
it.extraDefenseChance = intValue;
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.extraDefense = intValue;
if(readXMLInteger(itemAttributesNode, "random_min", intValue))
it.extraDefenseRndMin = intValue;
if(readXMLInteger(itemAttributesNode, "random_max", intValue))
it.extraDefenseRndMax = intValue;
}
Abaixo coloque:
else if(tmpStrValue == "criticalhitchance")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.criticalHitChance = intValue;
}
else if(tmpStrValue == "dodgechance")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.dodgeChance = intValue;
}
else if(tmpStrValue == "lifeabsorb")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.lifeAbsorb = intValue;
}
else if(tmpStrValue == "manaabsorb")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.manaAbsorb = intValue;
}
else if(tmpStrValue == "lifeleech")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.lifeLeech = intValue;
}
else if(tmpStrValue == "manaleech")
{
if(readXMLInteger(itemAttributesNode, "value", intValue))
it.manaLeech = intValue;
}
Agora vá em items.h e procure por:
int32_t attack, extraAttack, defense, extraDefense, armor, breakChance, hitChance, maxHitChance,
runeLevel, runeMagLevel, lightLevel, lightColor, decayTo, rotateTo, alwaysOnTopOrder;
Abaixo coloque:
int32_t criticalHitChance, dodgeChance, lifeAbsorb, manaAbsorb, lifeLeech, manaLeech;
Agora vá em item.cpp e procure por:
case ATTR_ATTACK:
{
int32_t attack;
if(!propStream.getLong((uint32_t&)attack))
return ATTR_READ_ERROR;
setAttribute("attack", attack);
break;
}
Acima coloque:
case ATTR_CRITICALHITCHANCE:
{
int32_t criticalHitChance;
if(!propStream.getLong((uint32_t&)criticalHitChance))
return ATTR_READ_ERROR;
setAttribute("criticalhitchance", criticalHitChance);
break;
}
case ATTR_DODGECHANCE:
{
int32_t dodgeChance;
if(!propStream.getLong((uint32_t&)dodgeChance))
return ATTR_READ_ERROR;
setAttribute("dodgechance", dodgeChance);
break;
}
case ATTR_LIFEABSORB:
{
int32_t lifeAbsorb;
if(!propStream.getLong((uint32_t&)lifeAbsorb))
return ATTR_READ_ERROR;
setAttribute("lifeabsorb", lifeAbsorb);
break;
}
case ATTR_MANAABSORB:
{
int32_t manaAbsorb;
if(!propStream.getLong((uint32_t&)manaAbsorb))
return ATTR_READ_ERROR;
setAttribute("manaabsorb", manaAbsorb);
break;
}
case ATTR_LIFELEECH:
{
int32_t lifeLeech;
if(!propStream.getLong((uint32_t&)lifeLeech))
return ATTR_READ_ERROR;
setAttribute("lifeleech", lifeLeech);
break;
}
case ATTR_MANALEECH:
{
int32_t manaLeech;
if(!propStream.getLong((uint32_t&)manaLeech))
return ATTR_READ_ERROR;
setAttribute("manaleech", manaLeech);
break;
}
Procure por:
if(it.weaponType == WEAPON_DIST && it.ammoType != AMMO_NONE)
{
begin = false;
s << " (Range:" << int32_t(item ? item->getShootRange() : it.shootRange);
if(it.attack || it.extraAttack || (item && (item->getAttack() || item->getExtraAttack())))
{
s << ", Atk " << std::showpos << int32_t(item ? item->getAttack() : it.attack);
if(it.extraAttack || (item && item->getExtraAttack()))
s << " " << std::showpos << int32_t(item ? item->getExtraAttack() : it.extraAttack) << std::noshowpos;
}
if(it.hitChance != -1 || (item && item->getHitChance() != -1))
s << ", Hit% " << std::showpos << (item ? item->getHitChance() : it.hitChance) << std::noshowpos;
}
else if(it.weaponType != WEAPON_AMMO && it.weaponType != WEAPON_WAND)
{
if(it.attack || it.extraAttack || (item && (item->getAttack() || item->getExtraAttack())))
{
begin = false;
s << " (Atk:";
if(it.abilities.elementType != COMBAT_NONE && it.decayTo < 1)
{
s << std::max((int32_t)0, int32_t((item ? item->getAttack() : it.attack) - it.abilities.elementDamage));
if(it.extraAttack || (item && item->getExtraAttack()))
s << " " << std::showpos << int32_t(item ? item->getExtraAttack() : it.extraAttack) << std::noshowpos;
s << " physical + " << it.abilities.elementDamage << " " << getCombatName(it.abilities.elementType);
}
else
{
s << int32_t(item ? item->getAttack() : it.attack);
if(it.extraAttack || (item && item->getExtraAttack()))
s << " " << std::showpos << int32_t(item ? item->getExtraAttack() : it.extraAttack) << std::noshowpos;
}
}
if(it.defense || it.extraDefense || (item && (item->getDefense() || item->getExtraDefense())))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Def:" << int32_t(item ? item->getDefense() : it.defense);
if(it.extraDefense || (item && item->getExtraDefense()))
s << " " << std::showpos << int32_t(item ? item->getExtraDefense() : it.extraDefense) << std::noshowpos;
}
}
Abaixo coloque:
if(it.criticalHitChance || (item && item->getCriticalHitChance()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Crit Chance:" << std::showpos << int32_t(item ? item->getCriticalHitChance() : it.criticalHitChance) << "%"<< std::noshowpos;
}
if(it.dodgeChance || (item && item->getDodgeChance()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Dodge Chance:" << std::showpos << int32_t(item ? item->getDodgeChance() : it.dodgeChance) << "%"<< std::noshowpos;
}
if(it.lifeAbsorb || (item && item->getLifeAbsorb()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Life Absorb:" << std::showpos << int32_t(item ? item->getLifeAbsorb() : it.lifeAbsorb) << "%"<< std::noshowpos;
}
if(it.manaAbsorb || (item && item->getManaAbsorb()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Mana Absorb:" << std::showpos << int32_t(item ? item->getManaAbsorb() : it.manaAbsorb) << "%"<< std::noshowpos;
}
if(it.lifeLeech || (item && item->getLifeLeech()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Life Leech:" << std::showpos << int32_t(item ? item->getLifeLeech() : it.lifeLeech) << "%"<< std::noshowpos;
}
if(it.manaLeech || (item && item->getManaLeech()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Mana Leech:" << std::showpos << int32_t(item ? item->getManaLeech() : it.manaLeech) << "%"<< std::noshowpos;
}
Procure por:
int32_t tmp = it.armor;
if(item)
tmp = item->getArmor();
bool begin = true;
if(tmp)
{
s << " (Arm:" << tmp;
begin = false;
}
Abaixo coloque:
if(it.criticalHitChance || (item && item->getCriticalHitChance()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Crit Chance:" << std::showpos << int32_t(item ? item->getCriticalHitChance() : it.criticalHitChance) << "%"<< std::noshowpos;
}
if(it.dodgeChance || (item && item->getDodgeChance()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Dodge Chance:" << std::showpos << int32_t(item ? item->getDodgeChance() : it.dodgeChance) << "%"<< std::noshowpos;
}
if(it.lifeAbsorb || (item && item->getLifeAbsorb()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Life Absorb:" << std::showpos << int32_t(item ? item->getLifeAbsorb() : it.lifeAbsorb) << "%"<< std::noshowpos;
}
if(it.manaAbsorb || (item && item->getManaAbsorb()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Mana Absorb:" << std::showpos << int32_t(item ? item->getManaAbsorb() : it.manaAbsorb) << "%"<< std::noshowpos;
}
if(it.lifeLeech || (item && item->getLifeLeech()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Life Leech:" << std::showpos << int32_t(item ? item->getLifeLeech() : it.lifeLeech) << "%"<< std::noshowpos;
}
if(it.manaLeech || (item && item->getManaLeech()))
{
if(begin)
{
begin = false;
s << " (";
}
else
s << ", ";
s << "Mana Leech:" << std::showpos << int32_t(item ? item->getManaLeech() : it.manaLeech) << "%"<< std::noshowpos;
}
Agora vá em item.h e procure por:
ATTR_DUALWIELD = 43,
Abaixo coloque:
ATTR_CRITICALHITCHANCE = 44,
ATTR_DODGECHANCE = 45,
ATTR_LIFEABSORB = 46,
ATTR_MANAABSORB = 47,
ATTR_LIFELEECH = 48,
ATTR_MANALEECH = 49,
Procure por:
int32_t getExtraDefense() const;
Abaixo coloque:
int32_t getCriticalHitChance() const;
int32_t getDodgeChance() const;
int32_t getLifeAbsorb() const;
int32_t getManaAbsorb() const;
int32_t getLifeLeech() const;
int32_t getManaLeech() const;
Procure por:
inline int32_t Item::getExtraDefense() const
{
bool ok;
int32_t v = getIntegerAttribute("extradefense", ok);
if(ok)
return v;
return items[id].extraDefense;
}
Abaixo coloque:
inline int32_t Item::getCriticalHitChance() const
{
bool ok;
int32_t v = getIntegerAttribute("criticalhitchance", ok);
if(ok)
return v;
return items[id].criticalHitChance;
}
inline int32_t Item::getDodgeChance() const
{
bool ok;
int32_t v = getIntegerAttribute("dodgechance", ok);
if(ok)
return v;
return items[id].dodgeChance;
}
inline int32_t Item::getLifeAbsorb() const
{
bool ok;
int32_t v = getIntegerAttribute("lifeabsorb", ok);
if(ok)
return v;
return items[id].lifeAbsorb;
}
inline int32_t Item::getManaAbsorb() const
{
bool ok;
int32_t v = getIntegerAttribute("manaabsorb", ok);
if(ok)
return v;
return items[id].manaAbsorb;
}
inline int32_t Item::getLifeLeech() const
{
bool ok;
int32_t v = getIntegerAttribute("lifeleech", ok);
if(ok)
return v;
return items[id].lifeLeech;
}
inline int32_t Item::getManaLeech() const
{
bool ok;
int32_t v = getIntegerAttribute("manaleech", ok);
if(ok)
return v;
return items[id].manaLeech;
}
Agora vá em player.cpp e procure por:
int32_t Player::getArmor() const
{
int32_t i = SLOT_FIRST, armor = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
armor += item->getArmor();
}
if(vocation->getMultiplier(MULTIPLIER_ARMOR) != 1.0)
return int32_t(armor * vocation->getMultiplier(MULTIPLIER_ARMOR));
return armor;
}
Abaixo coloque:
int32_t Player::getCriticalHitChance() const
{
int32_t i = SLOT_FIRST, crit = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
crit += item->getCriticalHitChance();
}
return crit;
}
int32_t Player::getDodgeChance() const
{
int32_t i = SLOT_FIRST, dodge = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
dodge += item->getDodgeChance();
}
return dodge;
}
int32_t Player::getLifeAbsorb() const
{
int32_t i = SLOT_FIRST, life = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
life += item->getLifeAbsorb();
}
return life;
}
int32_t Player::getManaAbsorb() const
{
int32_t i = SLOT_FIRST, mana = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
mana += item->getManaAbsorb();
}
return mana;
}
int32_t Player::getLifeLeech() const
{
int32_t i = SLOT_FIRST, life = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
life += item->getLifeLeech();
}
return life;
}
int32_t Player::getManaLeech() const
{
int32_t i = SLOT_FIRST, mana = 0;
for(; i < SLOT_LAST; ++i)
{
if(Item* item = getInventoryItem((slots_t)i))
mana += item->getManaLeech();
}
return mana;
}
Agora vá em player.h e procure por:
virtual int32_t getDefense() const;
Abaixo coloque:
virtual int32_t getCriticalHitChance() const;
virtual int32_t getDodgeChance() const;
virtual int32_t getLifeAbsorb() const;
virtual int32_t getManaAbsorb() const;
virtual int32_t getLifeLeech() const;
virtual int32_t getManaLeech() const;
Agora vá em luascript.cpp e procure por:
//getCreatureHealth(cid)
lua_register(m_luaState, "getCreatureHealth", LuaInterface::luaGetCreatureHealth);
Abaixo coloque:
//getPlayerCriticalHitChance(cid)
lua_register(m_luaState, "getPlayerCriticalHitChance", LuaInterface::luaGetPlayerCriticalHitChance);
//getPlayerDodgeChance(cid)
lua_register(m_luaState, "getPlayerDodgeChance", LuaInterface::luaGetPlayerDodgeChance);
//getPlayerLifeAbsorb(cid)
lua_register(m_luaState, "getPlayerLifeAbsorb", LuaInterface::luaGetPlayerLifeAbsorb);
//getPlayerManaAbsorb(cid)
lua_register(m_luaState, "getPlayerManaAbsorb", LuaInterface::luaGetPlayerManaAbsorb);
//getPlayerLifeLeech(cid)
lua_register(m_luaState, "getPlayerLifeLeech", LuaInterface::luaGetPlayerLifeLeech);
//getPlayerManaLeech(cid)
lua_register(m_luaState, "getPlayerManaLeech", LuaInterface::luaGetPlayerManaLeech);
Procure por:
int32_t LuaInterface::luaGetCreatureMaxHealth(lua_State* L)
{
//getCreatureMaxHealth(cid[, ignoreModifiers = false])
bool ignoreModifiers = false;
if(lua_gettop(L) > 1)
ignoreModifiers = popBoolean(L);
ScriptEnviroment* env = getEnv();
if(Creature* creature = env->getCreatureByUID(popNumber(L)))
lua_pushnumber(L, creature->getPlayer() && ignoreModifiers ? creature->healthMax : creature->getMaxHealth());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
Abaixo coloque:
int32_t LuaInterface::luaGetPlayerCriticalHitChance(lua_State* L)
{
//getPlayerCriticalHitChance(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getCriticalHitChance());
else
{
errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
int32_t LuaInterface::luaGetPlayerDodgeChance(lua_State* L)
{
//getPlayerDodgeChance(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getDodgeChance());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
int32_t LuaInterface::luaGetPlayerLifeAbsorb(lua_State* L)
{
//getPlayerLifeAbsorb(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getLifeAbsorb());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
int32_t LuaInterface::luaGetPlayerManaAbsorb(lua_State* L)
{
//getPlayerManaAbsorb(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getManaAbsorb());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
int32_t LuaInterface::luaGetPlayerLifeLeech(lua_State* L)
{
//getPlayerLifeLeech(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getLifeLeech());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
int32_t LuaInterface::luaGetPlayerManaLeech(lua_State* L)
{
//getPlayerManaLeech(cid)
ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L)))
lua_pushnumber(L, player->getManaLeech());
else
{
errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
lua_pushboolean(L, false);
}
return 1;
}
Agora vá em luascript.h e procure por:
static int32_t luaGetPlayerSpentMana(lua_State* L);
Abaixo coloque:
static int32_t luaGetPlayerCriticalHitChance(lua_State* L);
static int32_t luaGetPlayerDodgeChance(lua_State* L);
static int32_t luaGetPlayerLifeAbsorb(lua_State* L);
static int32_t luaGetPlayerManaAbsorb(lua_State* L);
static int32_t luaGetPlayerLifeLeech(lua_State* L);
static int32_t luaGetPlayerManaLeech(lua_State* L);
As funções Lua adicionadas foram
getPlayerCriticalHitChance(cid)
getPlayerDodgeChance(cid)
getPlayerLifeAbsorb(cid)
getPlayerManaAbsorb(cid)
getPlayerLifeLeech(cid)
getPlayerManaLeech(cid)
Agora a parte do game.cpp. (Esta é uma parte opcional, você pode optar por não adicioná-la)
Créditos: ~Mathias Kenfi