introduce changes from streamside fork

This commit is contained in:
ErikasKontenis 2019-09-16 20:38:16 +03:00
parent f2cbc2dc1c
commit ad03b0eb3e
162 changed files with 2485 additions and 698 deletions

View File

@ -69,7 +69,9 @@ freePremium = false
kickIdlePlayerAfterMinutes = 15 kickIdlePlayerAfterMinutes = 15
maxMessageBuffer = 4 maxMessageBuffer = 4
showMonsterLoot = false showMonsterLoot = false
queryPlayerContainers = false blockHeight = false
dropItems = false
-- Character Rooking -- Character Rooking
-- Level threshold is the level requirement to teleport players back to newbie town -- Level threshold is the level requirement to teleport players back to newbie town

View File

@ -2,7 +2,12 @@ local drunk = Condition(CONDITION_DRUNK)
drunk:setParameter(CONDITION_PARAM_TICKS, 60000) drunk:setParameter(CONDITION_PARAM_TICKS, 60000)
local poison = Condition(CONDITION_POISON) local poison = Condition(CONDITION_POISON)
poison:setTiming(100) poison:setParameter(CONDITION_PARAM_DELAYED, true)
poison:setParameter(CONDITION_PARAM_MINVALUE, -50)
poison:setParameter(CONDITION_PARAM_MAXVALUE, -120)
poison:setParameter(CONDITION_PARAM_STARTVALUE, -5)
poison:setParameter(CONDITION_PARAM_TICKINTERVAL, 5000)
poison:setParameter(CONDITION_PARAM_FORCEUPDATE, true)
local messages = { local messages = {
[FLUID_WATER] = "Gulp.", [FLUID_WATER] = "Gulp.",

View File

@ -1,7 +1,5 @@
function onLogin(player) function onLogin(player)
if player:getLastLoginSaved() <= 0 or player:getStorageValue(30017) == 1 then if player:getLastLoginSaved() <= 0 then
player:setStorageValue(30017, 0) -- reset storage for first items
-- Items -- Items
if player:getSex() == PLAYERSEX_FEMALE then if player:getSex() == PLAYERSEX_FEMALE then
player:addItem(3562, 1, true, -1, CONST_SLOT_ARMOR) player:addItem(3562, 1, true, -1, CONST_SLOT_ARMOR)

28
data/events/events.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<events>
<!-- Creature methods -->
<event class="Creature" method="onChangeOutfit" enabled="0" />
<event class="Creature" method="onAreaCombat" enabled="0" />
<event class="Creature" method="onTargetCombat" enabled="0" />
<!-- Party methods -->
<event class="Party" method="onJoin" enabled="0" />
<event class="Party" method="onLeave" enabled="0" />
<event class="Party" method="onDisband" enabled="0" />
<event class="Party" method="onShareExperience" enabled="1" />
<!-- Player methods -->
<event class="Player" method="onLook" enabled="1" />
<event class="Player" method="onLookInBattleList" enabled="1" />
<event class="Player" method="onLookInTrade" enabled="1" />
<event class="Player" method="onMoveItem" enabled="1" />
<event class="Player" method="onItemMoved" enabled="0" />
<event class="Player" method="onMoveCreature" enabled="0" />
<event class="Player" method="onReportBug" enabled="1" />
<event class="Player" method="onTurn" enabled="0" />
<event class="Player" method="onTradeRequest" enabled="0" />
<event class="Player" method="onTradeAccept" enabled="0" />
<event class="Player" method="onGainExperience" enabled="1" />
<event class="Player" method="onLoseExperience" enabled="0" />
<event class="Player" method="onGainSkillTries" enabled="1" />
</events>

View File

@ -0,0 +1,11 @@
function Creature:onChangeOutfit(outfit)
return true
end
function Creature:onAreaCombat(tile, isAggressive)
return RETURNVALUE_NOERROR
end
function Creature:onTargetCombat(target)
return RETURNVALUE_NOERROR
end

View File

@ -0,0 +1,35 @@
function Party:onJoin(player)
return true
end
function Party:onLeave(player)
return true
end
function Party:onDisband()
return true
end
function Party:onShareExperience(exp)
local sharedExperienceMultiplier = 1.20 --20%
local vocationsIds = {}
local vocationId = self:getLeader():getVocation():getBase():getId()
if vocationId ~= VOCATION_NONE then
table.insert(vocationsIds, vocationId)
end
for _, member in ipairs(self:getMembers()) do
vocationId = member:getVocation():getBase():getId()
if not table.contains(vocationsIds, vocationId) and vocationId ~= VOCATION_NONE then
table.insert(vocationsIds, vocationId)
end
end
local size = #vocationsIds
if size > 1 then
sharedExperienceMultiplier = 1.0 + ((size * (5 * (size - 1) + 10)) / 100)
end
return (exp * sharedExperienceMultiplier) / (#self:getMembers() + 1)
end

View File

@ -0,0 +1,169 @@
function Player:onLook(thing, position, distance)
local description = "You see " .. thing:getDescription(distance)
if self:getGroup():getAccess() then
if thing:isItem() then
description = string.format("%s\nItem ID: %d", description, thing:getId())
local actionId = thing:getActionId()
if actionId ~= 0 then
description = string.format("%s, Action ID: %d", description, actionId)
end
local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_MOVEMENTID)
if uniqueId > 0 and uniqueId < 65536 then
description = string.format("%s, Movement ID: %d", description, uniqueId)
end
local itemType = thing:getType()
local transformEquipId = itemType:getTransformEquipId()
local transformDeEquipId = itemType:getTransformDeEquipId()
if transformEquipId ~= 0 then
description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
elseif transformDeEquipId ~= 0 then
description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
end
local decayId = itemType:getDecayId()
if decayId ~= -1 then
description = string.format("%s\nDecays to: %d", description, decayId)
end
if thing:getAttribute(ITEM_ATTRIBUTE_DECAYSTATE) == 1 then
description = string.format("%s\nDecaying in %d minutes (%d seconds).", description, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000 / 60, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000)
end
elseif thing:isCreature() then
local str = "%s\nHealth: %d / %d"
if thing:isPlayer() and thing:getMaxMana() > 0 then
str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
end
description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
end
local position = thing:getPosition()
description = string.format(
"%s\nPosition: %d, %d, %d",
description, position.x, position.y, position.z
)
if thing:isCreature() then
if thing:isPlayer() then
description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
end
end
end
self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end
function Player:onLookInBattleList(creature, distance)
local description = "You see " .. creature:getDescription(distance)
if self:getGroup():getAccess() then
local str = "%s\nHealth: %d / %d"
if creature:isPlayer() and creature:getMaxMana() > 0 then
str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
end
description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
local position = creature:getPosition()
description = string.format(
"%s\nPosition: %d, %d, %d",
description, position.x, position.y, position.z
)
if creature:isPlayer() then
description = string.format("%s\nIP: %s", description, Game.convertIpToString(creature:getIp()))
end
end
self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end
function Player:onLookInTrade(partner, item, distance)
self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
end
function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
return true
end
function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
end
function Player:onMoveCreature(creature, fromPosition, toPosition)
return true
end
function Player:onReportBug(message, position, category)
if self:getAccountType() == ACCOUNT_TYPE_NORMAL then
return false
end
local name = self:getName()
local file = io.open("data/reports/bugs/" .. name .. " report.txt", "a")
if not file then
self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.")
return true
end
io.output(file)
io.write("------------------------------\n")
io.write("Name: " .. name)
if category == BUG_CATEGORY_MAP then
io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
end
local playerPosition = self:getPosition()
io.write(" [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n")
io.write("Comment: " .. message .. "\n")
io.close(file)
self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".")
return true
end
function Player:onTurn(direction)
return true
end
function Player:onTradeRequest(target, item)
return true
end
function Player:onTradeAccept(target, item, targetItem)
return true
end
local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
soulCondition:setTicks(4 * 60 * 1000)
soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
function Player:onGainExperience(source, exp, rawExp)
if not source or source:isPlayer() then
return exp
end
-- Soul regeneration
local vocation = self:getVocation()
if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
self:addCondition(soulCondition)
end
-- Apply experience stage multiplier
exp = exp * Game.getExperienceStage(self:getLevel())
return exp
end
function Player:onLoseExperience(exp)
return exp
end
function Player:onGainSkillTries(skill, tries)
if APPLY_SKILL_MULTIPLIER == false then
return tries
end
if skill == SKILL_MAGLEVEL then
return tries * configManager.getNumber(configKeys.RATE_MAGIC)
end
return tries * configManager.getNumber(configKeys.RATE_SKILL)
end

View File

@ -41,3 +41,7 @@ table.contains = function(array, value)
end end
return false return false
end end
function isNumber(str)
return tonumber(str) ~= nil
end

View File

@ -9,3 +9,4 @@ dofile('data/lib/core/player.lua')
dofile('data/lib/core/position.lua') dofile('data/lib/core/position.lua')
dofile('data/lib/core/teleport.lua') dofile('data/lib/core/teleport.lua')
dofile('data/lib/core/tile.lua') dofile('data/lib/core/tile.lua')
dofile('data/lib/core/vocation.lua')

View File

@ -9,7 +9,7 @@ function Game.removeItemsOnMap(position)
local i = 0 local i = 0
while i < tileCount do while i < tileCount do
local tileItem = tile:getThing(i) local tileItem = tile:getThing(i)
if tileItem and not tileItem:isCreature() and ItemType(tileItem:getId()):isMovable() then if tileItem and tileItem:getType():isMovable() then
tileItem:remove() tileItem:remove()
else else
i = i + 1 i = i + 1
@ -24,10 +24,8 @@ function Game.transformItemOnMap(position, itemId, toItemId, subtype)
local tile = Tile(position) local tile = Tile(position)
local item = tile:getItemById(itemId) local item = tile:getItemById(itemId)
if item ~= nil then
item:transform(toItemId, subtype) item:transform(toItemId, subtype)
item:decay() item:decay()
end
return item return item
end end

View File

@ -21,3 +21,45 @@ end
function Tile.isTile(self) function Tile.isTile(self)
return true return true
end end
function Tile.relocateTo(self, toPosition, pushMove, monsterPosition)
if self:getPosition() == toPosition then
return false
end
if not Tile(toPosition) then
return false
end
for i = self:getThingCount() - 1, 0, -1 do
local thing = self:getThing(i)
if thing then
if thing:isItem() then
if ItemType(thing.itemid):isMovable() then
thing:moveTo(toPosition)
end
elseif thing:isCreature() then
if monsterPosition and thing:isMonster() then
thing:teleportTo(monsterPosition, pushMove)
else
thing:teleportTo(toPosition, pushMove)
end
end
end
end
return true
end
function Tile:getPlayers()
local players = {}
local creatures = self:getCreatures()
if (creatures) then
for i = 1, #creatures do
if (creatures[i]:isPlayer()) then
table.insert(players, creatures[i])
end
end
end
return players
end

View File

@ -0,0 +1,7 @@
function Vocation.getBase(self)
local base = self
while base:getDemotion() do
base = base:getDemotion()
end
return base
end

View File

@ -81,8 +81,7 @@ function onStepIn(creature, item, position, fromPosition)
return false return false
end end
doRelocate(position, relPos) Tile(item:getPosition()):relocateTo(relPos)
if item:getId() == 293 then if item:getId() == 293 then
item:transform(294) item:transform(294)
item:decay() item:decay()

View File

@ -0,0 +1,65 @@
local reloadTypes = {
["all"] = { targetType = RELOAD_TYPE_ALL, name = "all" },
["action"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
["actions"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
["chat"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
["channel"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
["chatchannels"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
["config"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
["configuration"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
["creaturescript"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
["creaturescripts"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
["events"] = { targetType = RELOAD_TYPE_EVENTS, name = "events" },
["global"] = { targetType = RELOAD_TYPE_GLOBAL, name = "global.lua" },
["globalevent"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
["globalevents"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
["items"] = { targetType = RELOAD_TYPE_ITEMS, name = "items" },
["monster"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
["monsters"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
["move"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
["movement"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
["movements"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
["npc"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
["npcs"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
["raid"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
["raids"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
["spell"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
["spells"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
["talk"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
["talkaction"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
["talkactions"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" }
}
function onSay(player, words, param)
if not player:getGroup():getAccess() then
return true
end
if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
return false
end
local reloadType = reloadTypes[param and param:lower()]
if not reloadType then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Reload type not found.")
return false
end
Game.reload(reloadType.targetType)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("Reloaded %s.", reloadType.name))
return true
end

View File

@ -0,0 +1,23 @@
function onSay(player, words, param)
local function timeSave(delay, msg)
broadcastMessage(msg, MESSAGE_STATUS_WARNING)
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, msg)
addEvent(saveServer, delay)
end
if not player:getGroup():getAccess() then
return true
end
if player:getAccountType() < ACCOUNT_TYPE_GOD then
return false
end
if isNumber(param) then
local delay = tonumber(param) * 1000
timeSave(delay, "Saving server in " .. tonumber(param) .. " seconds.")
else
saveServer()
end
end

View File

@ -0,0 +1,19 @@
function onSay(player, words, param)
local tradePartner = Player(param)
if not tradePartner or tradePartner == player then
player:sendCancelMessage("Trade player not found.")
return false
end
local house = player:getTile():getHouse()
if not house then
player:sendCancelMessage("You must stand in your house to initiate the trade.")
return false
end
local returnValue = house:startTrade(player, tradePartner)
if returnValue ~= RETURNVALUE_NOERROR then
player:sendCancelMessage(returnValue)
end
return false
end

View File

@ -27,6 +27,8 @@
<talkaction words="/removetutor" separator=" " script="remove_tutor.lua" /> <talkaction words="/removetutor" separator=" " script="remove_tutor.lua" />
<talkaction words="/looktype" separator=" " script="looktype.lua" /> <talkaction words="/looktype" separator=" " script="looktype.lua" />
<talkaction words="/summon" separator=" " script="place_summon.lua" /> <talkaction words="/summon" separator=" " script="place_summon.lua" />
<talkaction words="/reload" separator=" " script="reload.lua" />
<talkaction words="/save" script="save.lua" />
<talkaction words="/chameleon" separator=" " script="chameleon.lua" /> <talkaction words="/chameleon" separator=" " script="chameleon.lua" />
<talkaction words="/addskill" separator=" " script="add_skill.lua" /> <talkaction words="/addskill" separator=" " script="add_skill.lua" />
<talkaction words="/mccheck" script="mccheck.lua" /> <talkaction words="/mccheck" script="mccheck.lua" />
@ -37,6 +39,7 @@
<!-- player talkactions --> <!-- player talkactions -->
<talkaction words="!buypremium" script="buyprem.lua"/> <talkaction words="!buypremium" script="buyprem.lua"/>
<talkaction words="!buyhouse" script="buyhouse.lua"/> <talkaction words="!buyhouse" script="buyhouse.lua"/>
<talkaction words="!sellhouse" separator=" " script="sellhouse.lua" />
<talkaction words="!leavehouse" script="leavehouse.lua"/> <talkaction words="!leavehouse" script="leavehouse.lua"/>
<talkaction words="!changesex" script="changesex.lua"/> <talkaction words="!changesex" script="changesex.lua"/>
<talkaction words="!uptime" script="uptime.lua"/> <talkaction words="!uptime" script="uptime.lua"/>

View File

@ -7,7 +7,6 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/behaviourdatabase.cpp ${CMAKE_CURRENT_LIST_DIR}/behaviourdatabase.cpp
${CMAKE_CURRENT_LIST_DIR}/chat.cpp ${CMAKE_CURRENT_LIST_DIR}/chat.cpp
${CMAKE_CURRENT_LIST_DIR}/combat.cpp ${CMAKE_CURRENT_LIST_DIR}/combat.cpp
${CMAKE_CURRENT_LIST_DIR}/commands.cpp
${CMAKE_CURRENT_LIST_DIR}/condition.cpp ${CMAKE_CURRENT_LIST_DIR}/condition.cpp
${CMAKE_CURRENT_LIST_DIR}/configmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/configmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/connection.cpp ${CMAKE_CURRENT_LIST_DIR}/connection.cpp
@ -19,6 +18,7 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp ${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp
${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp ${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp
${CMAKE_CURRENT_LIST_DIR}/events.cpp
${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp ${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp
${CMAKE_CURRENT_LIST_DIR}/game.cpp ${CMAKE_CURRENT_LIST_DIR}/game.cpp
${CMAKE_CURRENT_LIST_DIR}/globalevent.cpp ${CMAKE_CURRENT_LIST_DIR}/globalevent.cpp

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -820,10 +820,6 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
} }
} while (amount); } while (amount);
} else { } else {
if (it.charges) {
data = it.charges;
}
for (int32_t i = 0; i < std::max<int32_t>(1, amount); i++) { for (int32_t i = 0; i < std::max<int32_t>(1, amount); i++) {
Item* item = Item::CreateItem(itemId, data); Item* item = Item::CreateItem(itemId, data);
if (!item) { if (!item) {
@ -937,7 +933,7 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
} }
case BEHAVIOUR_TYPE_EXPERIENCE: { case BEHAVIOUR_TYPE_EXPERIENCE: {
int32_t experience = evaluate(action->expression, player, message); int32_t experience = evaluate(action->expression, player, message);
player->addExperience(experience, true, false); player->addExperience(nullptr, experience, false);
break; break;
} }
case BEHAVIOUR_TYPE_WITHDRAW: { case BEHAVIOUR_TYPE_WITHDRAW: {

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -24,13 +24,16 @@
#include "game.h" #include "game.h"
#include "configmanager.h" #include "configmanager.h"
#include "monster.h" #include "monster.h"
#include "events.h"
extern Game g_game; extern Game g_game;
extern ConfigManager g_config; extern ConfigManager g_config;
extern Events* g_events;
CombatDamage Combat::getCombatDamage(Creature* creature) const CombatDamage Combat::getCombatDamage(Creature* creature) const
{ {
CombatDamage damage; CombatDamage damage;
damage.origin = params.origin;
damage.type = params.combatType; damage.type = params.combatType;
if (formulaType == COMBAT_FORMULA_DAMAGE) { if (formulaType == COMBAT_FORMULA_DAMAGE) {
damage.min = static_cast<int32_t>(mina); damage.min = static_cast<int32_t>(mina);
@ -175,11 +178,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
return RETURNVALUE_NOTENOUGHROOM; return RETURNVALUE_NOTENOUGHROOM;
} }
/*if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tile->hasProperty(CONST_PROP_UNLAY)) { if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tile->hasProperty(CONST_PROP_UNLAY)) {
return RETURNVALUE_NOTENOUGHROOM;
}*/
if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKPATH) && tile->hasProperty(CONST_PROP_IMMOVABLENOFIELDBLOCKPATH)) {
return RETURNVALUE_NOTENOUGHROOM; return RETURNVALUE_NOTENOUGHROOM;
} }
@ -192,7 +191,8 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
const Position& tilePosition = tile->getPosition(); const Position& tilePosition = tile->getPosition();
if (casterPosition.z < tilePosition.z) { if (casterPosition.z < tilePosition.z) {
return RETURNVALUE_FIRSTGODOWNSTAIRS; return RETURNVALUE_FIRSTGODOWNSTAIRS;
} else if (casterPosition.z > tilePosition.z) { }
else if (casterPosition.z > tilePosition.z) {
return RETURNVALUE_FIRSTGOUPSTAIRS; return RETURNVALUE_FIRSTGOUPSTAIRS;
} }
@ -208,7 +208,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE; return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE;
} }
return RETURNVALUE_NOERROR; return g_events->eventCreatureOnAreaCombat(caster, tile, aggressive);
} }
bool Combat::isInPvpZone(const Creature* attacker, const Creature* target) bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
@ -232,7 +232,10 @@ bool Combat::isProtected(const Player* attacker, const Player* target)
ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target) ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
{ {
if (attacker) { if (!attacker) {
return g_events->eventCreatureOnTargetCombat(attacker, target);
}
if (const Player* targetPlayer = target->getPlayer()) { if (const Player* targetPlayer = target->getPlayer()) {
if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) { if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER; return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
@ -251,7 +254,8 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
const Tile* targetPlayerTile = targetPlayer->getTile(); const Tile* targetPlayerTile = targetPlayer->getTile();
if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) { if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE; return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
} else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) { }
else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE; return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
} }
} }
@ -271,7 +275,8 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
} }
} }
} }
} else if (target->getMonster()) { }
else if (target->getMonster()) {
if (const Player* attackerPlayer = attacker->getPlayer()) { if (const Player* attackerPlayer = attacker->getPlayer()) {
if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) { if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE; return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
@ -298,8 +303,7 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
} }
} }
} }
} return g_events->eventCreatureOnTargetCombat(attacker, target);
return RETURNVALUE_NOERROR;
} }
void Combat::setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb) void Combat::setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb)
@ -422,7 +426,7 @@ CallBack* Combat::getCallback(CallBackParam_t key)
return nullptr; return nullptr;
} }
bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data) void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{ {
assert(data); assert(data);
CombatDamage damage = *data; CombatDamage damage = *data;
@ -439,18 +443,16 @@ bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatPa
} }
if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) { if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
return false; return;
} }
if (g_game.combatChangeHealth(caster, target, damage)) { if (g_game.combatChangeHealth(caster, target, damage)) {
CombatConditionFunc(caster, target, params, nullptr); CombatConditionFunc(caster, target, params, &damage);
CombatDispelFunc(caster, target, params, nullptr); CombatDispelFunc(caster, target, params, nullptr);
} }
return true;
} }
bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data) void Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{ {
assert(data); assert(data);
CombatDamage damage = *data; CombatDamage damage = *data;
@ -465,16 +467,18 @@ bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatPara
} }
} }
if (g_game.combatChangeMana(caster, target, damage.value)) { if (g_game.combatChangeMana(caster, target, damage)) {
CombatConditionFunc(caster, target, params, nullptr); CombatConditionFunc(caster, target, params, nullptr);
CombatDispelFunc(caster, target, params, nullptr); CombatDispelFunc(caster, target, params, nullptr);
} }
return true;
} }
bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*) void Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{ {
if (params.origin == ORIGIN_MELEE && data && data->value == 0) {
return;
}
for (const auto& condition : params.conditionList) { for (const auto& condition : params.conditionList) {
if (caster == target || !target->isImmune(condition->getType())) { if (caster == target || !target->isImmune(condition->getType())) {
Condition* conditionCopy = condition->clone(); Condition* conditionCopy = condition->clone();
@ -486,21 +490,17 @@ bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const Comba
target->addCombatCondition(conditionCopy); target->addCombatCondition(conditionCopy);
} }
} }
return true;
} }
bool Combat::CombatDispelFunc(Creature*, Creature* target, const CombatParams& params, CombatDamage*) void Combat::CombatDispelFunc(Creature*, Creature* target, const CombatParams& params, CombatDamage*)
{ {
target->removeCombatCondition(params.dispelType); target->removeCombatCondition(params.dispelType);
return true;
} }
bool Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*) void Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage*)
{ {
CombatConditionFunc(caster, target, params, nullptr); CombatConditionFunc(caster, target, params, nullptr);
CombatDispelFunc(caster, target, params, nullptr); CombatDispelFunc(caster, target, params, nullptr);
return true;
} }
void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params) void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
@ -632,6 +632,8 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
const int32_t rangeY = maxY + Map::maxViewportY; const int32_t rangeY = maxY + Map::maxViewportY;
g_game.map.getSpectators(list, pos, true, true, rangeX, rangeX, rangeY, rangeY); g_game.map.getSpectators(list, pos, true, true, rangeX, rangeX, rangeY, rangeY);
postCombatEffects(caster, pos, params);
uint16_t decreasedDamage = 0; uint16_t decreasedDamage = 0;
const uint16_t maximumDecreasedDamage = params.maximumDecreasedDamage; const uint16_t maximumDecreasedDamage = params.maximumDecreasedDamage;
@ -721,6 +723,8 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
continue; continue;
} }
combatTileEffects(list, caster, tile, params);
if (CreatureVector* creatures = tile->getCreatures()) { if (CreatureVector* creatures = tile->getCreatures()) {
const Creature* topCreature = tile->getTopCreature(); const Creature* topCreature = tile->getTopCreature();
for (Creature* creature : *creatures) { for (Creature* creature : *creatures) {
@ -746,9 +750,7 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
} }
} }
} }
combatTileEffects(list, caster, tile, params);
} }
postCombatEffects(caster, pos, params);
} }
void Combat::doCombat(Creature* caster, Creature* target) const void Combat::doCombat(Creature* caster, Creature* target) const
@ -834,7 +836,7 @@ bool Combat::attack(Creature* attacker, Creature* target)
return false; return false;
} }
bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode, bool fist) bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode)
{ {
const Position& attackerPos = attacker->getPosition(); const Position& attackerPos = attacker->getPosition();
const Position& targetPos = target->getPosition(); const Position& targetPos = target->getPosition();
@ -859,7 +861,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
uint32_t skillValue = 0; uint32_t skillValue = 0;
uint8_t skill = SKILL_FIST; uint8_t skill = SKILL_FIST;
Combat::getAttackValue(attacker, attackValue, skillValue, skill, fist); Combat::getAttackValue(attacker, attackValue, skillValue, skill);
int32_t defense = target->getDefense(); int32_t defense = target->getDefense();
@ -876,6 +878,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
combatDamage.type = combatParams.combatType; combatDamage.type = combatParams.combatType;
int32_t totalDamage = Combat::getTotalDamage(skillValue, attackValue, fightMode); int32_t totalDamage = Combat::getTotalDamage(skillValue, attackValue, fightMode);
combatDamage.value = totalDamage; combatDamage.value = totalDamage;
combatDamage.origin = ORIGIN_MELEE;
bool hit = Combat::doCombatHealth(attacker, target, combatDamage, combatParams); bool hit = Combat::doCombatHealth(attacker, target, combatDamage, combatParams);
@ -884,7 +887,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
if (poison) { if (poison) {
int32_t randTest = rand(); int32_t randTest = rand();
if (hit || -totalDamage > defense && (randTest == 5 * (randTest / 5))) { if (hit || ((-totalDamage > defense) && (randTest == 5 * (randTest / 5)))) {
poison = normal_random(poison / 2, poison); poison = normal_random(poison / 2, poison);
if (poison) { if (poison) {
ConditionDamage* condition = static_cast<ConditionDamage*>(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_POISON, 0, 0)); ConditionDamage* condition = static_cast<ConditionDamage*>(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_POISON, 0, 0));
@ -962,9 +965,9 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
if (weapon->getWeaponType() == WEAPON_DISTANCE) { if (weapon->getWeaponType() == WEAPON_DISTANCE) {
ammunition = player->getAmmunition(); ammunition = player->getAmmunition();
if (weapon->getAmmoType() != AMMO_NONE) { if (weapon->getAmmoType() != AMMO_NONE) {
if (!ammunition || ammunition->getWeaponType() != WEAPON_AMMO || weapon->getAmmoType() != ammunition->getAmmoType()) { if (!ammunition || weapon->getAmmoType() != ammunition->getAmmoType()) {
// redirect to fist fighting // redirect to fist fighting
return closeAttack(attacker, target, fightMode, true); return closeAttack(attacker, target, fightMode);
} }
distanceEffect = ammunition->getMissileType(); distanceEffect = ammunition->getMissileType();
@ -991,6 +994,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
CombatDamage combatDamage; CombatDamage combatDamage;
combatDamage.type = combatParams.combatType; combatDamage.type = combatParams.combatType;
combatDamage.value = Combat::getTotalDamage(skillValue, attackValue, fightMode); combatDamage.value = Combat::getTotalDamage(skillValue, attackValue, fightMode);
combatDamage.origin = ORIGIN_RANGED;
if (weapon) { if (weapon) {
hitChance = 75; // throwables and such hitChance = 75; // throwables and such
@ -1011,7 +1015,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
} }
} }
if (ammunition && ammunition->getWeaponType() == WEAPON_AMMO && weapon->getAmmoType() != AMMO_NONE && weapon->getAmmoType() == ammunition->getAmmoType()) { if (ammunition && weapon->getAmmoType() != AMMO_NONE && weapon->getAmmoType() == ammunition->getAmmoType()) {
hitChance = 90; // bows and crossbows hitChance = 90; // bows and crossbows
specialEffect = ammunition->getWeaponSpecialEffect(); specialEffect = ammunition->getWeaponSpecialEffect();
attackStrength = ammunition->getAttackStrength(); attackStrength = ammunition->getAttackStrength();
@ -1037,10 +1041,12 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
bool hit = false; bool hit = false;
if (rand() % distance <= skillValue) { int32_t random = rand();
hit = rand() % 100 <= hitChance; if (random % distance <= static_cast<int32_t>(skillValue)) {
hit = random % 100 <= hitChance;
} }
if (Player* player = attacker->getPlayer()) { if (Player* player = attacker->getPlayer()) {
if (player->getAddAttackSkill()) { if (player->getAddAttackSkill()) {
switch (player->getLastAttackBlockType()) { switch (player->getLastAttackBlockType()) {
@ -1130,6 +1136,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
CombatDamage combatDamage; CombatDamage combatDamage;
combatDamage.type = combatParams.combatType; combatDamage.type = combatParams.combatType;
combatDamage.value = -(variation + weapon->getAttackStrength()); combatDamage.value = -(variation + weapon->getAttackStrength());
combatDamage.origin = ORIGIN_RANGED;
g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect); g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect);
Combat::doCombatHealth(attacker, target, combatDamage, combatParams); Combat::doCombatHealth(attacker, target, combatDamage, combatParams);
@ -1182,13 +1189,13 @@ void Combat::circleShapeSpell(Creature* attacker, const Position& toPos, int32_t
} }
} }
void Combat::getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill, bool fist) void Combat::getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill)
{ {
skill = SKILL_FIST; skill = SKILL_FIST;
if (Player* player = creature->getPlayer()) { if (Player* player = creature->getPlayer()) {
Item* weapon = player->getWeapon(); Item* weapon = player->getWeapon();
if (weapon && !fist) { if (weapon) {
switch (weapon->getWeaponType()) { switch (weapon->getWeaponType()) {
case WEAPON_AXE: { case WEAPON_AXE: {
skill = SKILL_AXE; skill = SKILL_AXE;
@ -1243,7 +1250,7 @@ bool Combat::canUseWeapon(Player* player, Item* weapon)
return false; return false;
} }
if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && player->getMana() < weapon->getManaConsumption()) { if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && static_cast<int32_t>(player->getMana()) < weapon->getManaConsumption()) {
return false; return false;
} }
@ -1278,14 +1285,14 @@ bool Combat::doCombatHealth(Creature* caster, Creature* target, CombatDamage& da
} }
if (canCombat) { if (canCombat) {
canCombat = CombatHealthFunc(caster, target, params, &damage);
if (params.targetCallback) {
params.targetCallback->onTargetCombat(caster, target);
}
if (caster && params.distanceEffect != CONST_ANI_NONE) { if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect); addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
} }
CombatHealthFunc(caster, target, params, &damage);
if (params.targetCallback) {
params.targetCallback->onTargetCombat(caster, target);
}
} }
return canCombat; return canCombat;
@ -1304,14 +1311,14 @@ void Combat::doCombatMana(Creature* caster, Creature* target, CombatDamage& dama
} }
if (canCombat) { if (canCombat) {
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
}
CombatManaFunc(caster, target, params, &damage); CombatManaFunc(caster, target, params, &damage);
if (params.targetCallback) { if (params.targetCallback) {
params.targetCallback->onTargetCombat(caster, target); params.targetCallback->onTargetCombat(caster, target);
} }
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
}
} }
} }
@ -1333,14 +1340,14 @@ void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatP
} }
if (canCombat) { if (canCombat) {
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
}
CombatConditionFunc(caster, target, params, nullptr); CombatConditionFunc(caster, target, params, nullptr);
if (params.targetCallback) { if (params.targetCallback) {
params.targetCallback->onTargetCombat(caster, target); params.targetCallback->onTargetCombat(caster, target);
} }
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
}
} }
} }

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -73,6 +73,7 @@ struct CombatParams {
ConditionType_t dispelType = CONDITION_NONE; ConditionType_t dispelType = CONDITION_NONE;
CombatType_t combatType = COMBAT_NONE; CombatType_t combatType = COMBAT_NONE;
CombatOrigin origin = ORIGIN_SPELL;
uint8_t impactEffect = CONST_ME_NONE; uint8_t impactEffect = CONST_ME_NONE;
uint8_t distanceEffect = CONST_ANI_NONE; uint8_t distanceEffect = CONST_ANI_NONE;
@ -116,7 +117,7 @@ struct DunkenImpact : Impact
void handleCreature(Creature* target) final; void handleCreature(Creature* target) final;
}; };
typedef bool (*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*); typedef void(*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
class MatrixArea class MatrixArea
{ {
@ -285,12 +286,12 @@ class Combat
static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode); static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode);
static bool attack(Creature* attacker, Creature* target); static bool attack(Creature* attacker, Creature* target);
static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode, bool fist = false); static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
static bool rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode); static bool rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
static void circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect); static void circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect);
static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill, bool fist = false); static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill);
static bool doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params); static bool doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params); static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
@ -339,6 +340,10 @@ class Combat
postCombatEffects(caster, pos, params); postCombatEffects(caster, pos, params);
} }
void setOrigin(CombatOrigin origin) {
params.origin = origin;
}
protected: protected:
static bool canUseWeapon(Player* player, Item* weapon); static bool canUseWeapon(Player* player, Item* weapon);
static void postWeaponEffects(Player* player, Item* weapon); static void postWeaponEffects(Player* player, Item* weapon);
@ -347,11 +352,11 @@ class Combat
static void CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, COMBATFUNC func, CombatDamage* data); static void CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, COMBATFUNC func, CombatDamage* data);
static bool CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data); static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
static bool CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage); static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
static bool CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data); static void CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
static bool CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data); static void CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
static bool CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data); static void CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params); static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params);
CombatDamage getCombatDamage(Creature* creature) const; CombatDamage getCombatDamage(Creature* creature) const;

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -227,7 +227,7 @@ bool Condition::isPersistent() const
return false; return false;
} }
if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT)) { if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT || conditionType == CONDITION_MUTED)) {
return false; return false;
} }
@ -655,7 +655,9 @@ bool ConditionRegeneration::executeCondition(Creature* creature, int32_t interva
if (internalManaTicks >= manaTicks) { if (internalManaTicks >= manaTicks) {
internalManaTicks = 0; internalManaTicks = 0;
creature->changeMana(manaGain); if (Player* player = creature->getPlayer()) {
player->changeMana(manaGain);
}
} }
} }
@ -756,8 +758,6 @@ bool ConditionSoul::setParam(ConditionParam_t param, int32_t value)
bool ConditionDamage::setParam(ConditionParam_t param, int32_t value) bool ConditionDamage::setParam(ConditionParam_t param, int32_t value)
{ {
Condition::setParam(param, value);
switch (param) { switch (param) {
case CONDITION_PARAM_OWNER: case CONDITION_PARAM_OWNER:
owner = value; owner = value;
@ -927,6 +927,7 @@ bool ConditionDamage::doDamage(Creature* creature, int32_t healthChange)
} }
CombatDamage damage; CombatDamage damage;
damage.origin = ORIGIN_CONDITION;
damage.value = healthChange; damage.value = healthChange;
damage.type = Combat::ConditionToDamageType(conditionType); damage.type = Combat::ConditionToDamageType(conditionType);

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -77,7 +77,9 @@ bool ConfigManager::load()
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true); boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true); boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);
boolean[STACK_CUMULATIVES] = getGlobalBoolean(L, "autoStackCumulatives", false); boolean[STACK_CUMULATIVES] = getGlobalBoolean(L, "autoStackCumulatives", false);
boolean[QUERY_PLAYER_CONTAINERS] = getGlobalBoolean(L, "queryPlayerContainers", false); boolean[BLOCK_HEIGHT] = getGlobalBoolean(L, "blockHeight", false);
boolean[DROP_ITEMS] = getGlobalBoolean(L, "dropItems", false);
string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high"); string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
string[SERVER_NAME] = getGlobalString(L, "serverName", ""); string[SERVER_NAME] = getGlobalString(L, "serverName", "");

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -40,7 +40,8 @@ class ConfigManager
CONVERT_UNSAFE_SCRIPTS, CONVERT_UNSAFE_SCRIPTS,
TELEPORT_NEWBIES, TELEPORT_NEWBIES,
STACK_CUMULATIVES, STACK_CUMULATIVES,
QUERY_PLAYER_CONTAINERS, BLOCK_HEIGHT,
DROP_ITEMS,
LAST_BOOLEAN_CONFIG /* this must be the last one */ LAST_BOOLEAN_CONFIG /* this must be the last one */
}; };

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -308,6 +308,28 @@ enum PlayerFlags : uint64_t {
PlayerFlag_SpecialMoveUse = static_cast<uint64_t>(1) << 38, PlayerFlag_SpecialMoveUse = static_cast<uint64_t>(1) << 38,
}; };
enum ReloadTypes_t : uint8_t {
RELOAD_TYPE_ALL,
RELOAD_TYPE_ACTIONS,
RELOAD_TYPE_CHAT,
RELOAD_TYPE_COMMANDS,
RELOAD_TYPE_CONFIG,
RELOAD_TYPE_CREATURESCRIPTS,
RELOAD_TYPE_EVENTS,
RELOAD_TYPE_GLOBAL,
RELOAD_TYPE_GLOBALEVENTS,
RELOAD_TYPE_ITEMS,
RELOAD_TYPE_MONSTERS,
RELOAD_TYPE_MOUNTS,
RELOAD_TYPE_MOVEMENTS,
RELOAD_TYPE_NPCS,
RELOAD_TYPE_QUESTS,
RELOAD_TYPE_RAIDS,
RELOAD_TYPE_SPELLS,
RELOAD_TYPE_TALKACTIONS,
RELOAD_TYPE_WEAPONS,
};
static constexpr int32_t CHANNEL_GUILD = 0x00; static constexpr int32_t CHANNEL_GUILD = 0x00;
static constexpr int32_t CHANNEL_PARTY = 0x01; static constexpr int32_t CHANNEL_PARTY = 0x01;
static constexpr int32_t CHANNEL_RULE_REP = 0x02; static constexpr int32_t CHANNEL_RULE_REP = 0x02;

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -386,7 +386,8 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
if (index == 255 /*add wherever*/) { if (index == 255 /*add wherever*/) {
index = INDEX_WHEREEVER; index = INDEX_WHEREEVER;
*destItem = nullptr; *destItem = nullptr;
} else if (index >= static_cast<int32_t>(capacity())) { }
else if (index >= static_cast<int32_t>(capacity())) {
/* /*
if you have a container, maximize it to show all 20 slots if you have a container, maximize it to show all 20 slots
then you open a bag that is inside the container you will have a bag with 8 slots then you open a bag that is inside the container you will have a bag with 8 slots
@ -403,6 +404,20 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
return this; return this;
} }
if (index != INDEX_WHEREEVER) {
Item* itemFromIndex = getItemByIndex(index);
if (itemFromIndex) {
*destItem = itemFromIndex;
}
Cylinder* subCylinder = dynamic_cast<Cylinder*>(*destItem);
if (subCylinder) {
index = INDEX_WHEREEVER;
*destItem = nullptr;
return subCylinder;
}
}
if (g_config.getBoolean(ConfigManager::STACK_CUMULATIVES)) { if (g_config.getBoolean(ConfigManager::STACK_CUMULATIVES)) {
bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags); bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags);
if (autoStack && item->isStackable() && item->getParent() != this) { if (autoStack && item->isStackable() && item->getParent() != this) {
@ -419,19 +434,6 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
} }
} }
if (index != INDEX_WHEREEVER) {
Item* itemFromIndex = getItemByIndex(index);
if (itemFromIndex) {
*destItem = itemFromIndex;
}
Cylinder* subCylinder = dynamic_cast<Cylinder*>(*destItem);
if (subCylinder) {
index = INDEX_WHEREEVER;
*destItem = nullptr;
return subCylinder;
}
}
return this; return this;
} }

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -619,7 +619,8 @@ void Creature::onDeath()
if (lastHitCreature) { if (lastHitCreature) {
lastHitUnjustified = lastHitCreature->onKilledCreature(this); lastHitUnjustified = lastHitCreature->onKilledCreature(this);
lastHitCreatureMaster = lastHitCreature->getMaster(); lastHitCreatureMaster = lastHitCreature->getMaster();
} else { }
else {
lastHitCreatureMaster = nullptr; lastHitCreatureMaster = nullptr;
} }
@ -639,8 +640,9 @@ void Creature::onDeath()
if (attacker != this) { if (attacker != this) {
uint64_t gainExp = getGainedExperience(attacker); uint64_t gainExp = getGainedExperience(attacker);
if (Player* player = attacker->getPlayer()) { if (Player* attackerPlayer = attacker->getPlayer()) {
Party* party = player->getParty(); attackerPlayer->removeAttacked(getPlayer());
Party* party = attackerPlayer->getParty();
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) { if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
attacker = party->getLeader(); attacker = party->getLeader();
} }
@ -649,7 +651,8 @@ void Creature::onDeath()
auto tmpIt = experienceMap.find(attacker); auto tmpIt = experienceMap.find(attacker);
if (tmpIt == experienceMap.end()) { if (tmpIt == experienceMap.end()) {
experienceMap[attacker] = gainExp; experienceMap[attacker] = gainExp;
} else { }
else {
tmpIt->second += gainExp; tmpIt->second += gainExp;
} }
} }
@ -752,15 +755,6 @@ void Creature::changeHealth(int32_t healthChange, bool sendHealthChange/* = true
} }
} }
void Creature::changeMana(int32_t manaChange)
{
if (manaChange > 0) {
mana += std::min<int32_t>(manaChange, getMaxMana() - mana);
} else {
mana = std::max<int32_t>(0, mana + manaChange);
}
}
void Creature::gainHealth(Creature* healer, int32_t healthGain) void Creature::gainHealth(Creature* healer, int32_t healthGain)
{ {
changeHealth(healthGain); changeHealth(healthGain);
@ -778,16 +772,6 @@ void Creature::drainHealth(Creature* attacker, int32_t damage)
} }
} }
void Creature::drainMana(Creature* attacker, int32_t manaLoss)
{
onAttacked();
changeMana(-manaLoss);
if (attacker) {
addDamagePoints(attacker, manaLoss);
}
}
BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage, BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field = false */) bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field = false */)
{ {

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -220,12 +220,6 @@ class Creature : virtual public Thing
virtual int32_t getMaxHealth() const { virtual int32_t getMaxHealth() const {
return healthMax; return healthMax;
} }
uint32_t getMana() const {
return mana;
}
virtual uint32_t getMaxMana() const {
return 0;
}
const Outfit_t getCurrentOutfit() const { const Outfit_t getCurrentOutfit() const {
return currentOutfit; return currentOutfit;
@ -320,11 +314,9 @@ class Creature : virtual public Thing
} }
virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true); virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
virtual void changeMana(int32_t manaChange);
void gainHealth(Creature* attacker, int32_t healthGain); void gainHealth(Creature* attacker, int32_t healthGain);
virtual void drainHealth(Creature* attacker, int32_t damage); virtual void drainHealth(Creature* attacker, int32_t damage);
virtual void drainMana(Creature* attacker, int32_t manaLoss);
virtual bool challengeCreature(Creature*) { virtual bool challengeCreature(Creature*) {
return false; return false;
@ -494,7 +486,6 @@ class Creature : virtual public Thing
uint32_t blockTicks = 0; uint32_t blockTicks = 0;
uint32_t lastStepCost = 1; uint32_t lastStepCost = 1;
uint32_t baseSpeed = 70; uint32_t baseSpeed = 70;
uint32_t mana = 0;
uint32_t latestKillEvent = 0; uint32_t latestKillEvent = 0;
int32_t varSpeed = 0; int32_t varSpeed = 0;
int32_t health = 1000; int32_t health = 1000;

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -177,6 +177,10 @@ bool CreatureEvent::configureEvent(const pugi::xml_node& node)
type = CREATURE_EVENT_KILL; type = CREATURE_EVENT_KILL;
} else if (tmpStr == "advance") { } else if (tmpStr == "advance") {
type = CREATURE_EVENT_ADVANCE; type = CREATURE_EVENT_ADVANCE;
} else if (tmpStr == "healthchange") {
type = CREATURE_EVENT_HEALTHCHANGE;
} else if (tmpStr == "manachange") {
type = CREATURE_EVENT_MANACHANGE;
} else if (tmpStr == "extendedopcode") { } else if (tmpStr == "extendedopcode") {
type = CREATURE_EVENT_EXTENDED_OPCODE; type = CREATURE_EVENT_EXTENDED_OPCODE;
} else { } else {
@ -213,6 +217,12 @@ std::string CreatureEvent::getScriptEventName() const
case CREATURE_EVENT_ADVANCE: case CREATURE_EVENT_ADVANCE:
return "onAdvance"; return "onAdvance";
case CREATURE_EVENT_HEALTHCHANGE:
return "onHealthChange";
case CREATURE_EVENT_MANACHANGE:
return "onManaChange";
case CREATURE_EVENT_EXTENDED_OPCODE: case CREATURE_EVENT_EXTENDED_OPCODE:
return "onExtendedOpcode"; return "onExtendedOpcode";
@ -409,6 +419,85 @@ void CreatureEvent::executeOnKill(Creature* creature, Creature* target)
scriptInterface->callVoidFunction(2); scriptInterface->callVoidFunction(2);
} }
void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage)
{
//onHealthChange(creature, attacker, value, type, min, max, origin)
if (!scriptInterface->reserveScriptEnv()) {
std::cout << "[Error - CreatureEvent::executeHealthChange] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface->getScriptEnv();
env->setScriptId(scriptId, scriptInterface);
lua_State* L = scriptInterface->getLuaState();
scriptInterface->pushFunction(scriptId);
LuaScriptInterface::pushUserdata(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
if (attacker) {
LuaScriptInterface::pushUserdata(L, attacker);
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
}
else {
lua_pushnil(L);
}
LuaScriptInterface::pushCombatDamage(L, damage);
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
damage.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -4));
damage.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
damage.min = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -2));
damage.max = LuaScriptInterface::getNumber<CombatType_t>(L, -1);
lua_pop(L, 4);
if (damage.type != COMBAT_HEALING) {
damage.value = -damage.value;
}
}
scriptInterface->resetScriptEnv();
}
void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage) {
//onManaChange(creature, attacker, value, type, min, max, origin)
if (!scriptInterface->reserveScriptEnv()) {
std::cout << "[Error - CreatureEvent::executeManaChange] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface->getScriptEnv();
env->setScriptId(scriptId, scriptInterface);
lua_State* L = scriptInterface->getLuaState();
scriptInterface->pushFunction(scriptId);
LuaScriptInterface::pushUserdata(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
if (attacker) {
LuaScriptInterface::pushUserdata(L, attacker);
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
}
else {
lua_pushnil(L);
}
LuaScriptInterface::pushCombatDamage(L, damage);
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
damage = LuaScriptInterface::getCombatDamage(L);
}
scriptInterface->resetScriptEnv();
}
void CreatureEvent::executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer) void CreatureEvent::executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer)
{ {
//onExtendedOpcode(player, opcode, buffer) //onExtendedOpcode(player, opcode, buffer)

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -33,6 +33,8 @@ enum CreatureEventType_t {
CREATURE_EVENT_DEATH, CREATURE_EVENT_DEATH,
CREATURE_EVENT_KILL, CREATURE_EVENT_KILL,
CREATURE_EVENT_ADVANCE, CREATURE_EVENT_ADVANCE,
CREATURE_EVENT_HEALTHCHANGE,
CREATURE_EVENT_MANACHANGE,
CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes
}; };
@ -97,6 +99,8 @@ class CreatureEvent final : public Event
bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified); bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified);
void executeOnKill(Creature* creature, Creature* target); void executeOnKill(Creature* creature, Creature* target);
bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t); bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t);
void executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage);
void executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage);
void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer); void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer);
// //

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,9 +20,9 @@
#ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963 #ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
#define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963 #define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
static constexpr auto STATUS_SERVER_NAME = "Nostalrius"; static constexpr auto STATUS_SERVER_NAME = "Sabrehaven";
static constexpr auto STATUS_SERVER_VERSION = "3.0"; static constexpr auto STATUS_SERVER_VERSION = "1.0";
static constexpr auto STATUS_SERVER_DEVELOPERS = "Alejandro Mujica"; static constexpr auto STATUS_SERVER_DEVELOPERS = "Sabrehaven Developers Team";
static constexpr auto CLIENT_VERSION_MIN = 772; static constexpr auto CLIENT_VERSION_MIN = 772;
static constexpr auto CLIENT_VERSION_MAX = 772; static constexpr auto CLIENT_VERSION_MAX = 772;
@ -57,7 +57,7 @@ static constexpr auto CLIENT_VERSION_STR = "7.72";
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data #pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
#pragma warning(disable:4351) // new behavior: elements of array will be default initialized #pragma warning(disable:4351) // new behavior: elements of array will be default initialized
#pragma warning(disable:4458) // declaration hides class member #pragma warning(disable:4458) // declaration hides class member
#pragma warning(disable:4018) // signed/unsigned mismatch #pragma warning(disable:4996) // inetpton warning
#endif #endif
#define strcasecmp _stricmp #define strcasecmp _stricmp

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -345,6 +345,11 @@ enum ReturnValue {
RETURNVALUE_CANONLYUSEONESHIELD, RETURNVALUE_CANONLYUSEONESHIELD,
RETURNVALUE_NOPARTYMEMBERSINRANGE, RETURNVALUE_NOPARTYMEMBERSINRANGE,
RETURNVALUE_YOUARENOTTHEOWNER, RETURNVALUE_YOUARENOTTHEOWNER,
RETURNVALUE_TRADEPLAYERFARAWAY,
RETURNVALUE_YOUDONTOWNTHISHOUSE,
RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
RETURNVALUE_TRADEPLAYERHIGHESTBIDDER,
RETURNVALUE_YOUCANNOTTRADETHISHOUSE,
}; };
struct Outfit_t { struct Outfit_t {
@ -363,15 +368,26 @@ struct LightInfo {
constexpr LightInfo(uint8_t level, uint8_t color) : level(level), color(color) {} constexpr LightInfo(uint8_t level, uint8_t color) : level(level), color(color) {}
}; };
enum CombatOrigin
{
ORIGIN_NONE,
ORIGIN_CONDITION,
ORIGIN_SPELL,
ORIGIN_MELEE,
ORIGIN_RANGED,
};
struct CombatDamage struct CombatDamage
{ {
CombatType_t type; CombatType_t type;
int32_t value; int32_t value;
int32_t min; int32_t min;
int32_t max; int32_t max;
CombatOrigin origin;
CombatDamage() CombatDamage()
{ {
origin = ORIGIN_NONE;
type = COMBAT_NONE; type = COMBAT_NONE;
value = 0; value = 0;
min = 0; min = 0;

827
src/events.cpp Normal file
View File

@ -0,0 +1,827 @@
/**
* The Forgotten Server - a free and open-source MMORPG server emulator
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "otpch.h"
#include "events.h"
#include "tools.h"
#include "item.h"
#include "player.h"
#include <set>
Events::Events() :
scriptInterface("Event Interface")
{
clear();
scriptInterface.initState();
}
void Events::clear()
{
// Creature
creatureOnChangeOutfit = -1;
creatureOnAreaCombat = -1;
creatureOnTargetCombat = -1;
// Party
partyOnJoin = -1;
partyOnLeave = -1;
partyOnDisband = -1;
// Player
playerOnLook = -1;
playerOnLookInBattleList = -1;
playerOnLookInTrade = -1;
playerOnMoveItem = -1;
playerOnItemMoved = -1;
playerOnMoveCreature = -1;
playerOnTurn = -1;
playerOnTradeRequest = -1;
playerOnTradeAccept = -1;
playerOnGainExperience = -1;
playerOnLoseExperience = -1;
playerOnGainSkillTries = -1;
playerOnReportBug = -1;
}
bool Events::load()
{
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file("data/events/events.xml");
if (!result) {
printXMLError("Error - Events::load", "data/events/events.xml", result);
return false;
}
std::set<std::string> classes;
for (auto eventNode : doc.child("events").children()) {
if (!eventNode.attribute("enabled").as_bool()) {
continue;
}
const std::string& className = eventNode.attribute("class").as_string();
auto res = classes.insert(className);
if (res.second) {
const std::string& lowercase = asLowerCaseString(className);
if (scriptInterface.loadFile("data/events/scripts/" + lowercase + ".lua") != 0) {
std::cout << "[Warning - Events::load] Can not load script: " << lowercase << ".lua" << std::endl;
std::cout << scriptInterface.getLastLuaError() << std::endl;
}
}
const std::string& methodName = eventNode.attribute("method").as_string();
const int32_t event = scriptInterface.getMetaEvent(className, methodName);
if (className == "Creature") {
if (methodName == "onChangeOutfit") {
creatureOnChangeOutfit = event;
}
else if (methodName == "onAreaCombat") {
creatureOnAreaCombat = event;
}
else if (methodName == "onTargetCombat") {
creatureOnTargetCombat = event;
}
else {
std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
}
}
else if (className == "Party") {
if (methodName == "onJoin") {
partyOnJoin = event;
}
else if (methodName == "onLeave") {
partyOnLeave = event;
}
else if (methodName == "onDisband") {
partyOnDisband = event;
}
else if (methodName == "onShareExperience") {
partyOnShareExperience = event;
}
else {
std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
}
}
else if (className == "Player") {
if (methodName == "onLook") {
playerOnLook = event;
}
else if (methodName == "onLookInBattleList") {
playerOnLookInBattleList = event;
}
else if (methodName == "onLookInTrade") {
playerOnLookInTrade = event;
}
else if (methodName == "onTradeRequest") {
playerOnTradeRequest = event;
}
else if (methodName == "onTradeAccept") {
playerOnTradeAccept = event;
}
else if (methodName == "onMoveItem") {
playerOnMoveItem = event;
}
else if (methodName == "onItemMoved") {
playerOnItemMoved = event;
}
else if (methodName == "onMoveCreature") {
playerOnMoveCreature = event;
}
else if (methodName == "onReportBug") {
playerOnReportBug = event;
}
else if (methodName == "onTurn") {
playerOnTurn = event;
}
else if (methodName == "onGainExperience") {
playerOnGainExperience = event;
}
else if (methodName == "onLoseExperience") {
playerOnLoseExperience = event;
}
else if (methodName == "onGainSkillTries") {
playerOnGainSkillTries = event;
}
else {
std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
}
}
else {
std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
}
}
return true;
}
// Creature
bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
{
// Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
if (creatureOnChangeOutfit == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventCreatureOnChangeOutfit] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(creatureOnChangeOutfit, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(creatureOnChangeOutfit);
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
LuaScriptInterface::pushOutfit(L, outfit);
return scriptInterface.callFunction(2);
}
ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
{
// Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
if (creatureOnAreaCombat == -1) {
return RETURNVALUE_NOERROR;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventCreatureOnAreaCombat] Call stack overflow" << std::endl;
return RETURNVALUE_NOTPOSSIBLE;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(creatureOnAreaCombat, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(creatureOnAreaCombat);
if (creature) {
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
}
else {
lua_pushnil(L);
}
LuaScriptInterface::pushUserdata<Tile>(L, tile);
LuaScriptInterface::setMetatable(L, -1, "Tile");
LuaScriptInterface::pushBoolean(L, aggressive);
ReturnValue returnValue;
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
returnValue = RETURNVALUE_NOTPOSSIBLE;
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
return returnValue;
}
ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
{
// Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
if (creatureOnTargetCombat == -1) {
return RETURNVALUE_NOERROR;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventCreatureOnTargetCombat] Call stack overflow" << std::endl;
return RETURNVALUE_NOTPOSSIBLE;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(creatureOnTargetCombat, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(creatureOnTargetCombat);
if (creature) {
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
}
else {
lua_pushnil(L);
}
LuaScriptInterface::pushUserdata<Creature>(L, target);
LuaScriptInterface::setCreatureMetatable(L, -1, target);
ReturnValue returnValue;
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
returnValue = RETURNVALUE_NOTPOSSIBLE;
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
return returnValue;
}
// Party
bool Events::eventPartyOnJoin(Party* party, Player* player)
{
// Party:onJoin(player) or Party.onJoin(self, player)
if (partyOnJoin == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPartyOnJoin] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(partyOnJoin, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(partyOnJoin);
LuaScriptInterface::pushUserdata<Party>(L, party);
LuaScriptInterface::setMetatable(L, -1, "Party");
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
return scriptInterface.callFunction(2);
}
bool Events::eventPartyOnLeave(Party* party, Player* player)
{
// Party:onLeave(player) or Party.onLeave(self, player)
if (partyOnLeave == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPartyOnLeave] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(partyOnLeave, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(partyOnLeave);
LuaScriptInterface::pushUserdata<Party>(L, party);
LuaScriptInterface::setMetatable(L, -1, "Party");
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
return scriptInterface.callFunction(2);
}
bool Events::eventPartyOnDisband(Party* party)
{
// Party:onDisband() or Party.onDisband(self)
if (partyOnDisband == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPartyOnDisband] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(partyOnDisband, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(partyOnDisband);
LuaScriptInterface::pushUserdata<Party>(L, party);
LuaScriptInterface::setMetatable(L, -1, "Party");
return scriptInterface.callFunction(1);
}
void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
{
// Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
if (partyOnShareExperience == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPartyOnShareExperience] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(partyOnShareExperience, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(partyOnShareExperience);
LuaScriptInterface::pushUserdata<Party>(L, party);
LuaScriptInterface::setMetatable(L, -1, "Party");
lua_pushnumber(L, exp);
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
}
void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
{
// Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
if (playerOnLook == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnLook] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnLook, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnLook);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
if (Creature* creature = thing->getCreature()) {
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
}
else if (Item* item = thing->getItem()) {
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
}
else {
lua_pushnil(L);
}
LuaScriptInterface::pushPosition(L, position, stackpos);
lua_pushnumber(L, lookDistance);
scriptInterface.callVoidFunction(4);
}
void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
{
// Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
if (playerOnLookInBattleList == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnLookInBattleList] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnLookInBattleList, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnLookInBattleList);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
lua_pushnumber(L, lookDistance);
scriptInterface.callVoidFunction(3);
}
void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
{
// Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
if (playerOnLookInTrade == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnLookInTrade] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnLookInTrade, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnLookInTrade);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Player>(L, partner);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
lua_pushnumber(L, lookDistance);
scriptInterface.callVoidFunction(4);
}
bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
{
// Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
if (playerOnMoveItem == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnMoveItem] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnMoveItem, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnMoveItem);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
lua_pushnumber(L, count);
LuaScriptInterface::pushPosition(L, fromPosition);
LuaScriptInterface::pushPosition(L, toPosition);
LuaScriptInterface::pushCylinder(L, fromCylinder);
LuaScriptInterface::pushCylinder(L, toCylinder);
return scriptInterface.callFunction(7);
}
void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
{
// Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
if (playerOnItemMoved == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnItemMoved] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnItemMoved, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnItemMoved);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
lua_pushnumber(L, count);
LuaScriptInterface::pushPosition(L, fromPosition);
LuaScriptInterface::pushPosition(L, toPosition);
LuaScriptInterface::pushCylinder(L, fromCylinder);
LuaScriptInterface::pushCylinder(L, toCylinder);
scriptInterface.callVoidFunction(7);
}
bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
{
// Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
if (playerOnMoveCreature == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnMoveCreature] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnMoveCreature, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnMoveCreature);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Creature>(L, creature);
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
LuaScriptInterface::pushPosition(L, fromPosition);
LuaScriptInterface::pushPosition(L, toPosition);
return scriptInterface.callFunction(4);
}
bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position)
{
// Player:onReportBug(message, position, category)
if (playerOnReportBug == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnReportBug] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnReportBug, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnReportBug);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushString(L, message);
LuaScriptInterface::pushPosition(L, position);
return scriptInterface.callFunction(3);
}
bool Events::eventPlayerOnTurn(Player* player, Direction direction)
{
// Player:onTurn(direction) or Player.onTurn(self, direction)
if (playerOnTurn == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnTurn] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnTurn, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnTurn);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
lua_pushnumber(L, direction);
return scriptInterface.callFunction(2);
}
bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
{
// Player:onTradeRequest(target, item)
if (playerOnTradeRequest == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnTradeRequest] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnTradeRequest, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnTradeRequest);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Player>(L, target);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
return scriptInterface.callFunction(3);
}
bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
{
// Player:onTradeAccept(target, item, targetItem)
if (playerOnTradeAccept == -1) {
return true;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnTradeAccept] Call stack overflow" << std::endl;
return false;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnTradeAccept, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnTradeAccept);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Player>(L, target);
LuaScriptInterface::setMetatable(L, -1, "Player");
LuaScriptInterface::pushUserdata<Item>(L, item);
LuaScriptInterface::setItemMetatable(L, -1, item);
LuaScriptInterface::pushUserdata<Item>(L, targetItem);
LuaScriptInterface::setItemMetatable(L, -1, targetItem);
return scriptInterface.callFunction(4);
}
void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp)
{
// Player:onGainExperience(source, exp, rawExp)
// rawExp gives the original exp which is not multiplied
if (playerOnGainExperience == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnGainExperience] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnGainExperience, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnGainExperience);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
if (source) {
LuaScriptInterface::pushUserdata<Creature>(L, source);
LuaScriptInterface::setCreatureMetatable(L, -1, source);
}
else {
lua_pushnil(L);
}
lua_pushnumber(L, exp);
lua_pushnumber(L, rawExp);
if (scriptInterface.protectedCall(L, 4, 1) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
}
void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
{
// Player:onLoseExperience(exp)
if (playerOnLoseExperience == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnLoseExperience] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnLoseExperience, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnLoseExperience);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
lua_pushnumber(L, exp);
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
}
void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
{
// Player:onGainSkillTries(skill, tries)
if (playerOnGainSkillTries == -1) {
return;
}
if (!scriptInterface.reserveScriptEnv()) {
std::cout << "[Error - Events::eventPlayerOnGainSkillTries] Call stack overflow" << std::endl;
return;
}
ScriptEnvironment* env = scriptInterface.getScriptEnv();
env->setScriptId(playerOnGainSkillTries, &scriptInterface);
lua_State* L = scriptInterface.getLuaState();
scriptInterface.pushFunction(playerOnGainSkillTries);
LuaScriptInterface::pushUserdata<Player>(L, player);
LuaScriptInterface::setMetatable(L, -1, "Player");
lua_pushnumber(L, skill);
lua_pushnumber(L, tries);
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
}
else {
tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
lua_pop(L, 1);
}
scriptInterface.resetScriptEnv();
}

95
src/events.h Normal file
View File

@ -0,0 +1,95 @@
/**
* The Forgotten Server - a free and open-source MMORPG server emulator
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
#define FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
#include "luascript.h"
class Party;
class ItemType;
class Tile;
class Events
{
public:
Events();
void clear();
bool load();
// Creature
bool eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit);
ReturnValue eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive);
ReturnValue eventCreatureOnTargetCombat(Creature* creature, Creature* target);
// Party
bool eventPartyOnJoin(Party* party, Player* player);
bool eventPartyOnLeave(Party* party, Player* player);
bool eventPartyOnDisband(Party* party);
void eventPartyOnShareExperience(Party* party, uint64_t& exp);
// Player
void eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance);
void eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance);
void eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance);
bool eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
void eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
bool eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition);
void eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
bool eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position);
bool eventPlayerOnTurn(Player* player, Direction direction);
bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
private:
LuaScriptInterface scriptInterface;
// Creature
int32_t creatureOnChangeOutfit;
int32_t creatureOnAreaCombat;
int32_t creatureOnTargetCombat;
// Party
int32_t partyOnJoin;
int32_t partyOnLeave;
int32_t partyOnDisband;
int32_t partyOnShareExperience;
// Player
int32_t playerOnLook;
int32_t playerOnLookInBattleList;
int32_t playerOnLookInTrade;
int32_t playerOnMoveItem;
int32_t playerOnItemMoved;
int32_t playerOnMoveCreature;
int32_t playerOnReportRuleViolation;
int32_t playerOnReportBug;
int32_t playerOnTurn;
int32_t playerOnTradeRequest;
int32_t playerOnTradeAccept;
int32_t playerOnGainExperience;
int32_t playerOnLoseExperience;
int32_t playerOnGainSkillTries;
};
#endif

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,9 +22,9 @@
#include "pugicast.h" #include "pugicast.h"
#include "items.h" #include "items.h"
#include "commands.h"
#include "creature.h" #include "creature.h"
#include "monster.h" #include "monster.h"
#include "events.h"
#include "game.h" #include "game.h"
#include "actions.h" #include "actions.h"
#include "iologindata.h" #include "iologindata.h"
@ -36,6 +36,7 @@
#include "bed.h" #include "bed.h"
#include "scheduler.h" #include "scheduler.h"
#include "databasetasks.h" #include "databasetasks.h"
#include "movement.h"
extern ConfigManager g_config; extern ConfigManager g_config;
extern Actions* g_actions; extern Actions* g_actions;
@ -44,6 +45,10 @@ extern TalkActions* g_talkActions;
extern Spells* g_spells; extern Spells* g_spells;
extern Vocations g_vocations; extern Vocations g_vocations;
extern GlobalEvents* g_globalEvents; extern GlobalEvents* g_globalEvents;
extern Events* g_events;
extern CreatureEvents* g_creatureEvents;
extern Monsters g_monsters;
extern MoveEvents* g_moveEvents;
Game::~Game() Game::~Game()
{ {
@ -84,8 +89,6 @@ void Game::setGameState(GameState_t newState)
gameState = newState; gameState = newState;
switch (newState) { switch (newState) {
case GAME_STATE_INIT: { case GAME_STATE_INIT: {
commands.loadFromXml();
loadExperienceStages(); loadExperienceStages();
groups.load(); groups.load();
@ -219,7 +222,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
} }
case STACKPOS_USEITEM: { case STACKPOS_USEITEM: {
thing = tile->getUseItem(); thing = tile->getUseItem(index);
break; break;
} }
@ -231,7 +234,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
case STACKPOS_USETARGET: { case STACKPOS_USETARGET: {
thing = tile->getTopCreature(); thing = tile->getTopCreature();
if (!thing) { if (!thing) {
thing = tile->getUseItem(); thing = tile->getUseItem(index);
} }
break; break;
} }
@ -651,6 +654,13 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
player->setNextActionTask(nullptr); player->setNextActionTask(nullptr);
if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
if (toTile->getHeight() > 1) {
player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
return;
}
}
if (!Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) { if (!Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) {
//need to walk to the creature first before moving it //need to walk to the creature first before moving it
std::forward_list<Direction> listDir; std::forward_list<Direction> listDir;
@ -705,6 +715,10 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
} }
} }
if (!g_events->eventPlayerOnMoveCreature(player, movingCreature, movingCreaturePos, toPos)) {
return;
}
ReturnValue ret = internalMoveCreature(*movingCreature, *toTile); ReturnValue ret = internalMoveCreature(*movingCreature, *toTile);
if (ret != RETURNVALUE_NOERROR) { if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret); player->sendCancelMessage(ret);
@ -729,7 +743,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
internalCreatureTurn(creature, DIRECTION_NORTH); internalCreatureTurn(creature, DIRECTION_NORTH);
} }
} }
} else { }
else {
//try go down //try go down
Tile* tmpTile = map.getTile(destPos.x, destPos.y, destPos.z); Tile* tmpTile = map.getTile(destPos.x, destPos.y, destPos.z);
if (currentPos.z != 7 && (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID)))) { if (currentPos.z != 7 && (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID)))) {
@ -742,12 +757,38 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
} }
} }
ReturnValue ret = RETURNVALUE_NOTPOSSIBLE;
Tile* toTile = map.getTile(destPos); Tile* toTile = map.getTile(destPos);
Tile* toPos = map.getTile(destPos.x, destPos.y, destPos.z);
Tile* fromPos = map.getTile(currentPos.x, currentPos.y, currentPos.z);
if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
if (toTile) {
if (currentPos.z > destPos.z && toPos->getHeight() > 1);
// not possible
else if ((((toPos->getHeight() - fromPos->getHeight()) < 2)) ||
(fromPos->hasHeight(3) && (currentPos.z == destPos.z)) ||
((currentPos.z < destPos.z) && (toPos->hasHeight(3) && (fromPos->getHeight() < 2))))
ret = internalMoveCreature(*creature, *toTile, flags);
}
if (ret != RETURNVALUE_NOERROR) {
if (Player* player = creature->getPlayer()) {
player->sendCancelMessage(ret);
player->sendCancelWalk();
}
}
return ret;
}
else {
if (!toTile) { if (!toTile) {
return RETURNVALUE_NOTPOSSIBLE; return RETURNVALUE_NOTPOSSIBLE;
} }
return internalMoveCreature(*creature, *toTile, flags); return internalMoveCreature(*creature, *toTile, flags);
} }
}
ReturnValue Game::internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags /*= 0*/) ReturnValue Game::internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags /*= 0*/)
{ {
@ -964,6 +1005,10 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
return; return;
} }
if (!g_events->eventPlayerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)) {
return;
}
uint8_t toIndex = 0; uint8_t toIndex = 0;
if (toPos.x == 0xFFFF) { if (toPos.x == 0xFFFF) {
if (toPos.y & 0x40) { if (toPos.y & 0x40) {
@ -976,6 +1021,8 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player); ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player);
if (ret != RETURNVALUE_NOERROR) { if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret); player->sendCancelMessage(ret);
} else {
g_events->eventPlayerOnItemMoved(player, item, count, fromPos, toPos, fromCylinder, toCylinder);
} }
} }
@ -2316,6 +2363,10 @@ void Game::playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t st
return; return;
} }
if (!g_events->eventPlayerOnTradeRequest(player, tradePartner, tradeItem)) {
return;
}
internalStartTrade(player, tradePartner, tradeItem); internalStartTrade(player, tradePartner, tradeItem);
} }
@ -2379,6 +2430,11 @@ void Game::playerAcceptTrade(uint32_t playerId)
Item* tradeItem1 = player->tradeItem; Item* tradeItem1 = player->tradeItem;
Item* tradeItem2 = tradePartner->tradeItem; Item* tradeItem2 = tradePartner->tradeItem;
if (!g_events->eventPlayerOnTradeAccept(player, tradePartner, tradeItem1, tradeItem2)) {
internalCloseTrade(player);
return;
}
player->setTradeState(TRADE_TRANSFER); player->setTradeState(TRADE_TRANSFER);
tradePartner->setTradeState(TRADE_TRANSFER); tradePartner->setTradeState(TRADE_TRANSFER);
@ -2508,10 +2564,8 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
int32_t lookDistance = std::max<int32_t>(Position::getDistanceX(playerPosition, tradeItemPosition), int32_t lookDistance = std::max<int32_t>(Position::getDistanceX(playerPosition, tradeItemPosition),
Position::getDistanceY(playerPosition, tradeItemPosition)); Position::getDistanceY(playerPosition, tradeItemPosition));
std::stringstream ss;
if (index == 0) { if (index == 0) {
ss << "You see " << tradeItem->getDescription(lookDistance); g_events->eventPlayerOnLookInTrade(player, tradePartner, tradeItem, lookDistance);
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
return; return;
} }
@ -2531,8 +2585,7 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
} }
if (--index == 0) { if (--index == 0) {
ss << "You see " << item->getDescription(lookDistance); g_events->eventPlayerOnLookInTrade(player, tradePartner, item, lookDistance);
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
return; return;
} }
} }
@ -2624,52 +2677,7 @@ void Game::playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos
lookDistance = -1; lookDistance = -1;
} }
std::ostringstream ss; g_events->eventPlayerOnLook(player, pos, thing, stackPos, lookDistance);
ss << "You see " << thing->getDescription(lookDistance);
if (player->isAccessPlayer()) {
Item* item = thing->getItem();
if (item) {
ss << std::endl << "ItemID: [" << item->getID() << ']';
uint16_t actionId = item->getActionId();
if (actionId != 0) {
ss << ", ActionID: [" << actionId << ']';
}
uint16_t movementID = item->getMovementId();
if (movementID != 0) {
ss << ", MovementID: [" << movementID << ']';
}
ss << '.';
const ItemType& it = Item::items[item->getID()];
if (it.transformEquipTo) {
ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
} else if (it.transformDeEquipTo) {
ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
}
if (it.decayTo != -1) {
ss << std::endl << "DecayTo: [" << it.decayTo << "].";
}
}
if (const Creature* creature = thing->getCreature()) {
ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
if (creature->getMaxMana() > 0) {
ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
}
ss << '.';
}
ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.getZ() << "].";
}
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
} }
void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId) void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
@ -2704,21 +2712,7 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
lookDistance = -1; lookDistance = -1;
} }
std::ostringstream ss; g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
ss << "You see " << creature->getDescription(lookDistance);
if (player->isAccessPlayer()) {
ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
if (creature->getMaxMana() > 0) {
ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
}
ss << '.' << std::endl;
ss << "Position: [X: " << creaturePos.x << "] [Y: " << creaturePos.y << "] [Z: " << creaturePos.getZ() << "].";
}
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
} }
void Game::playerCancelAttackAndFollow(uint32_t playerId) void Game::playerCancelAttackAndFollow(uint32_t playerId)
@ -2847,6 +2841,10 @@ void Game::playerTurn(uint32_t playerId, Direction dir)
return; return;
} }
if (!g_events->eventPlayerOnTurn(player, dir)) {
return;
}
player->resetIdleTime(); player->resetIdleTime();
internalCreatureTurn(player, dir); internalCreatureTurn(player, dir);
} }
@ -2897,6 +2895,10 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
player->resetIdleTime(); player->resetIdleTime();
if (playerSaySpell(player, type, text)) {
return;
}
uint32_t muteTime = player->isMuted(); uint32_t muteTime = player->isMuted();
if (muteTime > 0) { if (muteTime > 0) {
std::ostringstream ss; std::ostringstream ss;
@ -2905,14 +2907,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
return; return;
} }
if (playerSayCommand(player, text)) {
return;
}
if (playerSaySpell(player, type, text)) {
return;
}
if (!text.empty() && text.front() == '/' && player->isAccessPlayer()) { if (!text.empty() && text.front() == '/' && player->isAccessPlayer()) {
return; return;
} }
@ -2966,23 +2960,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
} }
} }
bool Game::playerSayCommand(Player* player, const std::string& text)
{
if (text.empty()) {
return false;
}
char firstCharacter = text.front();
for (char commandTag : commandTags) {
if (commandTag == firstCharacter) {
if (commands.exeCommand(*player, text)) {
return true;
}
}
}
return false;
}
bool Game::playerSaySpell(Player* player, SpeakClasses type, const std::string& text) bool Game::playerSaySpell(Player* player, SpeakClasses type, const std::string& text)
{ {
std::string words = text; std::string words = text;
@ -3234,6 +3211,10 @@ void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit) void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit)
{ {
if (!g_events->eventCreatureOnChangeOutfit(creature, outfit)) {
return;
}
creature->setCurrentOutfit(outfit); creature->setCurrentOutfit(outfit);
if (creature->isInvisible()) { if (creature->isInvisible()) {
@ -3403,6 +3384,17 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
return false; return false;
} }
if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_HEALTHCHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeHealthChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeHealth(attacker, target, damage);
}
}
int32_t realHealthChange = target->getHealth(); int32_t realHealthChange = target->getHealth();
target->gainHealth(attacker, damage.value); target->gainHealth(attacker, damage.value);
realHealthChange = target->getHealth() - realHealthChange; realHealthChange = target->getHealth() - realHealthChange;
@ -3410,7 +3402,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (realHealthChange > 0 && !target->isInGhostMode()) { if (realHealthChange > 0 && !target->isInGhostMode()) {
addMagicEffect(targetPos, CONST_ME_MAGIC_BLUE); addMagicEffect(targetPos, CONST_ME_MAGIC_BLUE);
} }
} else { }
else {
if (Monster* monster = target->getMonster()) { if (Monster* monster = target->getMonster()) {
// makes monsters aggressive when damaged // makes monsters aggressive when damaged
// basically stands for UNDERATTACK stance under CipSoft servers // basically stands for UNDERATTACK stance under CipSoft servers
@ -3431,7 +3424,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
Player* attackerPlayer; Player* attackerPlayer;
if (attacker) { if (attacker) {
attackerPlayer = attacker->getPlayer(); attackerPlayer = attacker->getPlayer();
} else { }
else {
attackerPlayer = nullptr; attackerPlayer = nullptr;
} }
damage.value = std::abs(damage.value); damage.value = std::abs(damage.value);
@ -3440,25 +3434,39 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (healthChange == 0) { if (healthChange == 0) {
return true; return true;
} }
Player* targetPlayer = target->getPlayer();
SpectatorVec list; SpectatorVec list;
if (target->hasCondition(CONDITION_MANASHIELD) && damage.type != COMBAT_UNDEFINEDDAMAGE) { if (target->hasCondition(CONDITION_MANASHIELD) && damage.type != COMBAT_UNDEFINEDDAMAGE) {
int32_t manaDamage = std::min<int32_t>(target->getMana(), healthChange); int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
if (manaDamage != 0) { if (manaDamage != 0) {
target->drainMana(attacker, manaDamage); if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
healthChange = damage.value;
if (healthChange == 0) {
return true;
}
manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
}
}
targetPlayer->drainMana(attacker, manaDamage);
map.getSpectators(list, targetPos, true, true); map.getSpectators(list, targetPos, true, true);
addMagicEffect(list, targetPos, CONST_ME_LOSEENERGY); addMagicEffect(list, targetPos, CONST_ME_LOSEENERGY);
std::string damageString = std::to_string(manaDamage); std::string damageString = std::to_string(manaDamage);
Player* targetPlayer = target->getPlayer();
if (targetPlayer) { if (targetPlayer) {
std::stringstream ss; std::stringstream ss;
if (!attacker) { if (!attacker) {
ss << "You lose " << damageString << " mana."; ss << "You lose " << damageString << " mana.";
} else if (targetPlayer == attackerPlayer) { }
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack."; ss << "You lose " << damageString << " mana due to your own attack.";
} else { }
else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.'; ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
} }
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str()); targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@ -3489,19 +3497,11 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
realDamage = damage.value; realDamage = damage.value;
if (realDamage == 0) { if (realDamage == 0) {
return true; return true;
} else if (realDamage >= targetHealth) {
for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
return false;
}
}
} }
target->drainHealth(attacker, realDamage);
if (list.empty()) { if (list.empty()) {
map.getSpectators(list, targetPos, true, true); map.getSpectators(list, targetPos, true, true);
} }
addCreatureHealth(list, target);
TextColor_t color = TEXTCOLOR_NONE; TextColor_t color = TEXTCOLOR_NONE;
uint8_t hitEffect; uint8_t hitEffect;
@ -3514,15 +3514,15 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (color != TEXTCOLOR_NONE) { if (color != TEXTCOLOR_NONE) {
std::string damageString = std::to_string(realDamage) + (realDamage != 1 ? " hitpoints" : " hitpoint"); std::string damageString = std::to_string(realDamage) + (realDamage != 1 ? " hitpoints" : " hitpoint");
Player* targetPlayer = target->getPlayer();
if (targetPlayer) { if (targetPlayer) {
std::stringstream ss; std::stringstream ss;
if (!attacker) { if (!attacker) {
ss << "You lose " << damageString << "."; ss << "You lose " << damageString << ".";
} else if (targetPlayer == attackerPlayer) { }
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " due to your own attack."; ss << "You lose " << damageString << " due to your own attack.";
} else { }
else {
ss << "You lose " << damageString << " due to an attack by " << attacker->getNameDescription() << '.'; ss << "You lose " << damageString << " due to an attack by " << attacker->getNameDescription() << '.';
} }
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str()); targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@ -3534,16 +3534,43 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
tmpPlayer->sendAnimatedText(targetPos, color, realDamageStr); tmpPlayer->sendAnimatedText(targetPos, color, realDamageStr);
} }
} }
if (realDamage >= targetHealth) {
for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
return false;
}
}
}
target->drainHealth(attacker, realDamage);
addCreatureHealth(list, target);
} }
return true; return true;
} }
bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange) bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
{ {
Player* targetPlayer = target->getPlayer();
if (!targetPlayer) {
return true;
}
int32_t manaChange = damage.value;
if (manaChange > 0) { if (manaChange > 0) {
target->changeMana(manaChange); if (damage.origin != ORIGIN_NONE) {
} else { const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeMana(attacker, target, damage);
}
}
targetPlayer->changeMana(manaChange);
}
else {
const Position& targetPos = target->getPosition(); const Position& targetPos = target->getPosition();
if (!target->isAttackable()) { if (!target->isAttackable()) {
if (!target->isInGhostMode()) { if (!target->isInGhostMode()) {
@ -3555,11 +3582,12 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
Player* attackerPlayer; Player* attackerPlayer;
if (attacker) { if (attacker) {
attackerPlayer = attacker->getPlayer(); attackerPlayer = attacker->getPlayer();
} else { }
else {
attackerPlayer = nullptr; attackerPlayer = nullptr;
} }
int32_t manaLoss = std::min<int32_t>(target->getMana(), -manaChange); int32_t manaLoss = std::min<int32_t>(targetPlayer->getMana(), -manaChange);
BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss); BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
if (blockType != BLOCK_NONE) { if (blockType != BLOCK_NONE) {
addMagicEffect(targetPos, CONST_ME_POFF); addMagicEffect(targetPos, CONST_ME_POFF);
@ -3570,21 +3598,32 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
return true; return true;
} }
target->drainMana(attacker, manaLoss); if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeMana(attacker, target, damage);
}
}
targetPlayer->drainMana(attacker, manaLoss);
std::string damageString = std::to_string(manaLoss); std::string damageString = std::to_string(manaLoss);
Player* targetPlayer = target->getPlayer();
SpectatorVec list; SpectatorVec list;
map.getSpectators(list, targetPos, false, true); map.getSpectators(list, targetPos, false, true);
if (targetPlayer) { if (targetPlayer) {
std::stringstream ss; std::stringstream ss;
if (!attacker) { if (!attacker) {
ss << "You lose " << damageString << " mana."; ss << "You lose " << damageString << " mana.";
} else if (targetPlayer == attackerPlayer) { }
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack."; ss << "You lose " << damageString << " mana due to your own attack.";
} else { }
else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.'; ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
} }
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str()); targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@ -3814,23 +3853,9 @@ void Game::getWorldLightInfo(LightInfo& lightInfo) const
lightInfo.color = 0xD7; lightInfo.color = 0xD7;
} }
void Game::addCommandTag(char tag)
{
for (char commandTag : commandTags) {
if (commandTag == tag) {
return;
}
}
commandTags.push_back(tag);
}
void Game::resetCommandTag()
{
commandTags.clear();
}
void Game::shutdown() void Game::shutdown()
{ {
saveGameState();
std::cout << "Shutting down..." << std::flush; std::cout << "Shutting down..." << std::flush;
g_scheduler.shutdown(); g_scheduler.shutdown();
@ -4324,22 +4349,8 @@ void Game::playerReportBug(uint32_t playerId, const std::string& message)
return; return;
} }
if (player->getAccountType() == ACCOUNT_TYPE_NORMAL) { const Position& position = player->getPosition();
return; g_events->eventPlayerOnReportBug(player, message, position);
}
std::string fileName = "data/reports/" + player->getName() + " report.txt";
FILE* file = fopen(fileName.c_str(), "a");
if (!file) {
player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.");
return;
}
const Position& playerPosition = player->getPosition();
fprintf(file, "------------------------------\nName: %s [Player Position: %u, %u, %u]\nComment: %s\n", player->getName().c_str(), playerPosition.x, playerPosition.y, playerPosition.z, message.c_str());
fclose(file);
player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " + g_config.getString(ConfigManager::SERVER_NAME) + ".");
} }
void Game::playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment) void Game::playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment)
@ -4534,3 +4545,64 @@ void Game::removeBedSleeper(uint32_t guid)
bedSleepersMap.erase(it); bedSleepersMap.erase(it);
} }
} }
bool Game::reload(ReloadTypes_t reloadType)
{
switch (reloadType) {
case RELOAD_TYPE_ACTIONS: return g_actions->reload();
case RELOAD_TYPE_CHAT: return g_chat->load();
case RELOAD_TYPE_CONFIG: return g_config.reload();
case RELOAD_TYPE_CREATURESCRIPTS: return g_creatureEvents->reload();
case RELOAD_TYPE_EVENTS: return g_events->load();
case RELOAD_TYPE_GLOBALEVENTS: return g_globalEvents->reload();
case RELOAD_TYPE_ITEMS: return Item::items.reload();
case RELOAD_TYPE_MONSTERS: return g_monsters.reload();
case RELOAD_TYPE_MOVEMENTS: return g_moveEvents->reload();
case RELOAD_TYPE_NPCS: {
Npcs::reload();
return true;
}
case RELOAD_TYPE_RAIDS: return raids.reload() && raids.startup();
case RELOAD_TYPE_SPELLS: {
if (!g_spells->reload()) {
std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
std::terminate();
}
else if (!g_monsters.reload()) {
std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
std::terminate();
}
return true;
}
case RELOAD_TYPE_TALKACTIONS: return g_talkActions->reload();
default: {
if (!g_spells->reload()) {
std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
std::terminate();
return false;
}
else if (!g_monsters.reload()) {
std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
std::terminate();
return false;
}
g_actions->reload();
g_config.reload();
g_creatureEvents->reload();
g_monsters.reload();
g_moveEvents->reload();
Npcs::reload();
raids.reload() && raids.startup();
g_talkActions->reload();
Item::items.reload();
g_globalEvents->reload();
g_events->load();
g_chat->load();
return true;
}
}
}

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include "account.h" #include "account.h"
#include "combat.h" #include "combat.h"
#include "commands.h"
#include "groups.h" #include "groups.h"
#include "map.h" #include "map.h"
#include "position.h" #include "position.h"
@ -436,7 +435,7 @@ class Game
void combatGetTypeInfo(CombatType_t combatType, Creature* target, TextColor_t& color, uint8_t& effect); void combatGetTypeInfo(CombatType_t combatType, Creature* target, TextColor_t& color, uint8_t& effect);
bool combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage); bool combatChangeHealth(Creature* attacker, Creature* target, CombatDamage& damage);
bool combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange); bool combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage);
//animation help functions //animation help functions
void addCreatureHealth(const Creature* target); void addCreatureHealth(const Creature* target);
@ -449,9 +448,6 @@ class Game
static void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t color, const std::string& text); static void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t color, const std::string& text);
void addMonsterSayText(const Position& pos, const std::string& text); void addMonsterSayText(const Position& pos, const std::string& text);
void addCommandTag(char tag);
void resetCommandTag();
void startDecay(Item* item); void startDecay(Item* item);
int32_t getLightHour() const { int32_t getLightHour() const {
return lightHour; return lightHour;
@ -488,13 +484,13 @@ class Game
BedItem* getBedBySleeper(uint32_t guid) const; BedItem* getBedBySleeper(uint32_t guid) const;
void setBedSleeper(BedItem* bed, uint32_t guid); void setBedSleeper(BedItem* bed, uint32_t guid);
void removeBedSleeper(uint32_t guid); void removeBedSleeper(uint32_t guid);
bool reload(ReloadTypes_t reloadType);
Groups groups; Groups groups;
Map map; Map map;
Raids raids; Raids raids;
protected: protected:
bool playerSayCommand(Player* player, const std::string& text);
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text); bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
void playerWhisper(Player* player, const std::string& text); void playerWhisper(Player* player, const std::string& text);
bool playerYell(Player* player, const std::string& text); bool playerYell(Player* player, const std::string& text);
@ -518,7 +514,6 @@ class Game
std::vector<Creature*> ToReleaseCreatures; std::vector<Creature*> ToReleaseCreatures;
std::vector<Item*> ToReleaseItems; std::vector<Item*> ToReleaseItems;
std::vector<char> commandTags;
size_t lastBucket = 0; size_t lastBucket = 0;
@ -532,8 +527,6 @@ class Game
std::map<uint32_t, BedItem*> bedSleepersMap; std::map<uint32_t, BedItem*> bedSleepersMap;
Commands commands;
static constexpr int32_t LIGHT_LEVEL_DAY = 250; static constexpr int32_t LIGHT_LEVEL_DAY = 250;
static constexpr int32_t LIGHT_LEVEL_NIGHT = 40; static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
static constexpr int32_t SUNSET = 1305; static constexpr int32_t SUNSET = 1305;

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -82,7 +82,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* play
setAccessList(SUBOWNER_LIST, ""); setAccessList(SUBOWNER_LIST, "");
setAccessList(GUEST_LIST, ""); setAccessList(GUEST_LIST, "");
for (Door* door : doorList) { for (Door* door : doorSet) {
door->setAccessList(""); door->setAccessList("");
} }
@ -116,7 +116,7 @@ void House::updateDoorDescription() const
} }
} }
for (const auto& it : doorList) { for (const auto& it : doorSet) {
it->setSpecialDescription(ss.str()); it->setSpecialDescription(ss.str());
} }
} }
@ -277,17 +277,17 @@ bool House::isInvited(const Player* player)
void House::addDoor(Door* door) void House::addDoor(Door* door)
{ {
door->incrementReferenceCounter(); door->incrementReferenceCounter();
doorList.push_back(door); doorSet.insert(door);
door->setHouse(this); door->setHouse(this);
updateDoorDescription(); updateDoorDescription();
} }
void House::removeDoor(Door* door) void House::removeDoor(Door* door)
{ {
auto it = std::find(doorList.begin(), doorList.end(), door); auto it = doorSet.find(door);
if (it != doorList.end()) { if (it != doorSet.end()) {
door->decrementReferenceCounter(); door->decrementReferenceCounter();
doorList.erase(it); doorSet.erase(it);
} }
} }
@ -299,7 +299,7 @@ void House::addBed(BedItem* bed)
Door* House::getDoorByNumber(uint32_t doorId) const Door* House::getDoorByNumber(uint32_t doorId) const
{ {
for (Door* door : doorList) { for (Door* door : doorSet) {
if (door->getDoorId() == doorId) { if (door->getDoorId() == doorId) {
return door; return door;
} }
@ -309,7 +309,7 @@ Door* House::getDoorByNumber(uint32_t doorId) const
Door* House::getDoorByPosition(const Position& pos) Door* House::getDoorByPosition(const Position& pos)
{ {
for (Door* door : doorList) { for (Door* door : doorSet) {
if (door->getPosition() == pos) { if (door->getPosition() == pos) {
return door; return door;
} }

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -21,6 +21,7 @@
#define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4 #define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
#include <regex> #include <regex>
#include <set>
#include "container.h" #include "container.h"
#include "housetile.h" #include "housetile.h"
@ -212,10 +213,11 @@ class House
return houseTiles; return houseTiles;
} }
const std::list<Door*>& getDoors() const { const std::set<Door*>& getDoors() const {
return doorList; return doorSet;
} }
void addBed(BedItem* bed); void addBed(BedItem* bed);
const HouseBedItemList& getBeds() const { const HouseBedItemList& getBeds() const {
return bedsList; return bedsList;
@ -234,7 +236,7 @@ class House
Container transfer_container{ITEM_LOCKER1}; Container transfer_container{ITEM_LOCKER1};
HouseTileList houseTiles; HouseTileList houseTiles;
std::list<Door*> doorList; std::set<Door*> doorSet;
HouseBedItemList bedsList; HouseBedItemList bedsList;
std::string houseName; std::string houseName;

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -676,6 +676,18 @@ void LuaScriptInterface::setCreatureMetatable(lua_State* L, int32_t index, const
} }
// Get // Get
CombatDamage LuaScriptInterface::getCombatDamage(lua_State* L)
{
CombatDamage damage;
damage.value = getNumber<int32_t>(L, -4);
damage.type = getNumber<CombatType_t>(L, -3);
damage.min = getNumber<int32_t>(L, -2);
damage.max = getNumber<CombatType_t>(L, -1);
lua_pop(L, 4);
return damage;
}
std::string LuaScriptInterface::getString(lua_State* L, int32_t arg) std::string LuaScriptInterface::getString(lua_State* L, int32_t arg)
{ {
size_t len; size_t len;
@ -839,6 +851,16 @@ void LuaScriptInterface::pushBoolean(lua_State* L, bool value)
lua_pushboolean(L, value ? 1 : 0); lua_pushboolean(L, value ? 1 : 0);
} }
void LuaScriptInterface::pushCombatDamage(lua_State* L, const CombatDamage& damage)
{
lua_pushnumber(L, damage.value);
lua_pushnumber(L, damage.type);
lua_pushnumber(L, damage.min);
lua_pushnumber(L, damage.max);
lua_pushnumber(L, damage.origin);
}
void LuaScriptInterface::pushPosition(lua_State* L, const Position& position, int32_t stackpos/* = 0*/) void LuaScriptInterface::pushPosition(lua_State* L, const Position& position, int32_t stackpos/* = 0*/)
{ {
lua_createtable(L, 0, 4); lua_createtable(L, 0, 4);
@ -1465,6 +1487,13 @@ void LuaScriptInterface::registerFunctions()
registerEnum(SLOTP_DEPOT) registerEnum(SLOTP_DEPOT)
registerEnum(SLOTP_TWO_HAND) registerEnum(SLOTP_TWO_HAND)
// Use with combat functions
registerEnum(ORIGIN_NONE)
registerEnum(ORIGIN_CONDITION)
registerEnum(ORIGIN_SPELL)
registerEnum(ORIGIN_MELEE)
registerEnum(ORIGIN_RANGED)
// Use with house:getAccessList, house:setAccessList // Use with house:getAccessList, house:setAccessList
registerEnum(GUEST_LIST) registerEnum(GUEST_LIST)
registerEnum(SUBOWNER_LIST) registerEnum(SUBOWNER_LIST)
@ -1533,6 +1562,31 @@ void LuaScriptInterface::registerFunctions()
registerEnum(RETURNVALUE_CANONLYUSEONESHIELD) registerEnum(RETURNVALUE_CANONLYUSEONESHIELD)
registerEnum(RETURNVALUE_NOPARTYMEMBERSINRANGE) registerEnum(RETURNVALUE_NOPARTYMEMBERSINRANGE)
registerEnum(RETURNVALUE_YOUARENOTTHEOWNER) registerEnum(RETURNVALUE_YOUARENOTTHEOWNER)
registerEnum(RETURNVALUE_TRADEPLAYERFARAWAY)
registerEnum(RETURNVALUE_YOUDONTOWNTHISHOUSE)
registerEnum(RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE)
registerEnum(RETURNVALUE_TRADEPLAYERHIGHESTBIDDER)
registerEnum(RETURNVALUE_YOUCANNOTTRADETHISHOUSE)
registerEnum(RELOAD_TYPE_ALL)
registerEnum(RELOAD_TYPE_ACTIONS)
registerEnum(RELOAD_TYPE_CHAT)
registerEnum(RELOAD_TYPE_COMMANDS)
registerEnum(RELOAD_TYPE_CONFIG)
registerEnum(RELOAD_TYPE_CREATURESCRIPTS)
registerEnum(RELOAD_TYPE_EVENTS)
registerEnum(RELOAD_TYPE_GLOBAL)
registerEnum(RELOAD_TYPE_GLOBALEVENTS)
registerEnum(RELOAD_TYPE_ITEMS)
registerEnum(RELOAD_TYPE_MONSTERS)
registerEnum(RELOAD_TYPE_MOUNTS)
registerEnum(RELOAD_TYPE_MOVEMENTS)
registerEnum(RELOAD_TYPE_NPCS)
registerEnum(RELOAD_TYPE_QUESTS)
registerEnum(RELOAD_TYPE_RAIDS)
registerEnum(RELOAD_TYPE_SPELLS)
registerEnum(RELOAD_TYPE_TALKACTIONS)
registerEnum(RELOAD_TYPE_WEAPONS)
// _G // _G
registerGlobalVariable("INDEX_WHEREEVER", INDEX_WHEREEVER); registerGlobalVariable("INDEX_WHEREEVER", INDEX_WHEREEVER);
@ -1608,6 +1662,8 @@ void LuaScriptInterface::registerFunctions()
registerEnumIn("configKeys", ConfigManager::MAX_PACKETS_PER_SECOND) registerEnumIn("configKeys", ConfigManager::MAX_PACKETS_PER_SECOND)
registerEnumIn("configKeys", ConfigManager::NEWBIE_TOWN) registerEnumIn("configKeys", ConfigManager::NEWBIE_TOWN)
registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD) registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD)
registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT)
registerEnumIn("configKeys", ConfigManager::DROP_ITEMS)
// os // os
registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime); registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime);
@ -1646,6 +1702,8 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Game", "startRaid", LuaScriptInterface::luaGameStartRaid); registerMethod("Game", "startRaid", LuaScriptInterface::luaGameStartRaid);
registerMethod("Game", "reload", LuaScriptInterface::luaGameReload);
// Variant // Variant
registerClass("Variant", "", LuaScriptInterface::luaVariantCreate); registerClass("Variant", "", LuaScriptInterface::luaVariantCreate);
@ -1853,10 +1911,6 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Creature", "getMaxHealth", LuaScriptInterface::luaCreatureGetMaxHealth); registerMethod("Creature", "getMaxHealth", LuaScriptInterface::luaCreatureGetMaxHealth);
registerMethod("Creature", "setMaxHealth", LuaScriptInterface::luaCreatureSetMaxHealth); registerMethod("Creature", "setMaxHealth", LuaScriptInterface::luaCreatureSetMaxHealth);
registerMethod("Creature", "getMana", LuaScriptInterface::luaCreatureGetMana);
registerMethod("Creature", "addMana", LuaScriptInterface::luaCreatureAddMana);
registerMethod("Creature", "getMaxMana", LuaScriptInterface::luaCreatureGetMaxMana);
registerMethod("Creature", "getSkull", LuaScriptInterface::luaCreatureGetSkull); registerMethod("Creature", "getSkull", LuaScriptInterface::luaCreatureGetSkull);
registerMethod("Creature", "setSkull", LuaScriptInterface::luaCreatureSetSkull); registerMethod("Creature", "setSkull", LuaScriptInterface::luaCreatureSetSkull);
@ -1914,6 +1968,9 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getMagicLevel", LuaScriptInterface::luaPlayerGetMagicLevel); registerMethod("Player", "getMagicLevel", LuaScriptInterface::luaPlayerGetMagicLevel);
registerMethod("Player", "getBaseMagicLevel", LuaScriptInterface::luaPlayerGetBaseMagicLevel); registerMethod("Player", "getBaseMagicLevel", LuaScriptInterface::luaPlayerGetBaseMagicLevel);
registerMethod("Player", "getMana", LuaScriptInterface::luaPlayerGetMana);
registerMethod("Player", "addMana", LuaScriptInterface::luaPlayerAddMana);
registerMethod("Player", "getMaxMana", LuaScriptInterface::luaPlayerGetMaxMana);
registerMethod("Player", "setMaxMana", LuaScriptInterface::luaPlayerSetMaxMana); registerMethod("Player", "setMaxMana", LuaScriptInterface::luaPlayerSetMaxMana);
registerMethod("Player", "getManaSpent", LuaScriptInterface::luaPlayerGetManaSpent); registerMethod("Player", "getManaSpent", LuaScriptInterface::luaPlayerGetManaSpent);
registerMethod("Player", "addManaSpent", LuaScriptInterface::luaPlayerAddManaSpent); registerMethod("Player", "addManaSpent", LuaScriptInterface::luaPlayerAddManaSpent);
@ -2122,6 +2179,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("House", "getOwnerGuid", LuaScriptInterface::luaHouseGetOwnerGuid); registerMethod("House", "getOwnerGuid", LuaScriptInterface::luaHouseGetOwnerGuid);
registerMethod("House", "setOwnerGuid", LuaScriptInterface::luaHouseSetOwnerGuid); registerMethod("House", "setOwnerGuid", LuaScriptInterface::luaHouseSetOwnerGuid);
registerMethod("House", "startTrade", LuaScriptInterface::luaHouseStartTrade);
registerMethod("House", "getBeds", LuaScriptInterface::luaHouseGetBeds); registerMethod("House", "getBeds", LuaScriptInterface::luaHouseGetBeds);
registerMethod("House", "getBedCount", LuaScriptInterface::luaHouseGetBedCount); registerMethod("House", "getBedCount", LuaScriptInterface::luaHouseGetBedCount);
@ -2196,6 +2254,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Combat", "setArea", LuaScriptInterface::luaCombatSetArea); registerMethod("Combat", "setArea", LuaScriptInterface::luaCombatSetArea);
registerMethod("Combat", "setCondition", LuaScriptInterface::luaCombatSetCondition); registerMethod("Combat", "setCondition", LuaScriptInterface::luaCombatSetCondition);
registerMethod("Combat", "setCallback", LuaScriptInterface::luaCombatSetCallback); registerMethod("Combat", "setCallback", LuaScriptInterface::luaCombatSetCallback);
registerMethod("Combat", "setOrigin", LuaScriptInterface::luaCombatSetOrigin);
registerMethod("Combat", "execute", LuaScriptInterface::luaCombatExecute); registerMethod("Combat", "execute", LuaScriptInterface::luaCombatExecute);
@ -2794,7 +2853,7 @@ int LuaScriptInterface::luaCreateCombatArea(lua_State* L)
int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L) int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
{ {
//doAreaCombatHealth(cid, type, pos, area, min, max, effect) //doAreaCombatHealth(cid, type, pos, area, min, max, effect[, origin = ORIGIN_SPELL])
Creature* creature = getCreature(L, 1); Creature* creature = getCreature(L, 1);
if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) { if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND)); reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@ -2812,6 +2871,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
params.impactEffect = getNumber<uint8_t>(L, 7); params.impactEffect = getNumber<uint8_t>(L, 7);
CombatDamage damage; CombatDamage damage;
damage.origin = getNumber<CombatOrigin>(L, 8, ORIGIN_SPELL);
damage.type = combatType; damage.type = combatType;
damage.value = normal_random(getNumber<int32_t>(L, 6), getNumber<int32_t>(L, 5)); damage.value = normal_random(getNumber<int32_t>(L, 6), getNumber<int32_t>(L, 5));
@ -2826,7 +2886,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L) int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
{ {
//doTargetCombatHealth(cid, target, type, min, max, effect) //doTargetCombatHealth(cid, target, type, min, max, effect[, origin = ORIGIN_SPELL])
Creature* creature = getCreature(L, 1); Creature* creature = getCreature(L, 1);
if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) { if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND)); reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@ -2848,6 +2908,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
params.impactEffect = getNumber<uint8_t>(L, 6); params.impactEffect = getNumber<uint8_t>(L, 6);
CombatDamage damage; CombatDamage damage;
damage.origin = getNumber<CombatOrigin>(L, 7, ORIGIN_SPELL);
damage.type = combatType; damage.type = combatType;
damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5)); damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5));
@ -2858,7 +2919,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L) int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
{ {
//doAreaCombatMana(cid, pos, area, min, max, effect) //doAreaCombatMana(cid, pos, area, min, max, effect[, origin = ORIGIN_SPELL])
Creature* creature = getCreature(L, 1); Creature* creature = getCreature(L, 1);
if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) { if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND)); reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@ -2873,6 +2934,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
params.impactEffect = getNumber<uint8_t>(L, 6); params.impactEffect = getNumber<uint8_t>(L, 6);
CombatDamage damage; CombatDamage damage;
damage.origin = getNumber<CombatOrigin>(L, 7, ORIGIN_SPELL);
damage.type = COMBAT_MANADRAIN; damage.type = COMBAT_MANADRAIN;
damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5)); damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5));
@ -2888,7 +2950,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L) int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
{ {
//doTargetCombatMana(cid, target, min, max, effect) //doTargetCombatMana(cid, target, min, max, effect[, origin = ORIGIN_SPELL)
Creature* creature = getCreature(L, 1); Creature* creature = getCreature(L, 1);
if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) { if (!creature && (!isNumber(L, 1) || getNumber<uint32_t>(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND)); reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@ -2907,6 +2969,7 @@ int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
params.impactEffect = getNumber<uint8_t>(L, 5); params.impactEffect = getNumber<uint8_t>(L, 5);
CombatDamage damage; CombatDamage damage;
damage.origin = getNumber<CombatOrigin>(L, 6, ORIGIN_SPELL);
damage.type = COMBAT_MANADRAIN; damage.type = COMBAT_MANADRAIN;
damage.value = normal_random(getNumber<int32_t>(L, 3), getNumber<int32_t>(L, 4)); damage.value = normal_random(getNumber<int32_t>(L, 3), getNumber<int32_t>(L, 4));
@ -4144,6 +4207,25 @@ int LuaScriptInterface::luaGameStartRaid(lua_State* L)
return 1; return 1;
} }
int LuaScriptInterface::luaGameReload(lua_State* L)
{
// Game.reload(reloadType)
ReloadTypes_t reloadType = getNumber<ReloadTypes_t>(L, 1);
if (!reloadType) {
lua_pushnil(L);
return 1;
}
if (reloadType == RELOAD_TYPE_GLOBAL) {
pushBoolean(L, g_luaEnvironment.loadFile("data/global.lua") == 0);
}
else {
pushBoolean(L, g_game.reload(reloadType));
}
lua_gc(g_luaEnvironment.getLuaState(), LUA_GCCOLLECT, 0);
return 1;
}
// Variant // Variant
int LuaScriptInterface::luaVariantCreate(lua_State* L) int LuaScriptInterface::luaVariantCreate(lua_State* L)
{ {
@ -6575,50 +6657,6 @@ int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L)
return 1; return 1;
} }
int LuaScriptInterface::luaCreatureGetMana(lua_State* L)
{
// creature:getMana()
const Creature* creature = getUserdata<const Creature>(L, 1);
if (creature) {
lua_pushnumber(L, creature->getMana());
} else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaCreatureAddMana(lua_State* L)
{
// creature:addMana(manaChange[, animationOnLoss = false])
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
int32_t manaChange = getNumber<int32_t>(L, 2);
bool animationOnLoss = getBoolean(L, 3, false);
if (!animationOnLoss && manaChange < 0) {
creature->changeMana(manaChange);
} else {
g_game.combatChangeMana(nullptr, creature, manaChange);
}
pushBoolean(L, true);
return 1;
}
int LuaScriptInterface::luaCreatureGetMaxMana(lua_State* L)
{
// creature:getMaxMana()
const Creature* creature = getUserdata<const Creature>(L, 1);
if (creature) {
lua_pushnumber(L, creature->getMaxMana());
} else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaCreatureGetSkull(lua_State* L) int LuaScriptInterface::luaCreatureGetSkull(lua_State* L)
{ {
// creature:getSkull() // creature:getSkull()
@ -7191,15 +7229,15 @@ int LuaScriptInterface::luaPlayerGetExperience(lua_State* L)
int LuaScriptInterface::luaPlayerAddExperience(lua_State* L) int LuaScriptInterface::luaPlayerAddExperience(lua_State* L)
{ {
// player:addExperience(experience[, sendText = false[, applyStages = true]) // player:addExperience(experience[, sendText = false])
Player* player = getUserdata<Player>(L, 1); Player* player = getUserdata<Player>(L, 1);
if (player) { if (player) {
int64_t experience = getNumber<int64_t>(L, 2); int64_t experience = getNumber<int64_t>(L, 2);
bool sendText = getBoolean(L, 3, false); bool sendText = getBoolean(L, 3, false);
bool applyStages = getBoolean(L, 4, true); player->addExperience(nullptr, experience, sendText);
player->addExperience(experience, sendText, applyStages);
pushBoolean(L, true); pushBoolean(L, true);
} else { }
else {
lua_pushnil(L); lua_pushnil(L);
} }
return 1; return 1;
@ -7255,6 +7293,56 @@ int LuaScriptInterface::luaPlayerGetBaseMagicLevel(lua_State* L)
return 1; return 1;
} }
int LuaScriptInterface::luaPlayerGetMana(lua_State* L)
{
// player:getMana()
const Player* player = getUserdata<const Player>(L, 1);
if (player) {
lua_pushnumber(L, player->getMana());
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerAddMana(lua_State* L)
{
// player:addMana(manaChange[, animationOnLoss = false])
Player* player = getUserdata<Player>(L, 1);
if (!player) {
lua_pushnil(L);
return 1;
}
int32_t manaChange = getNumber<int32_t>(L, 2);
bool animationOnLoss = getBoolean(L, 3, false);
if (!animationOnLoss && manaChange < 0) {
player->changeMana(manaChange);
}
else {
CombatDamage damage;
damage.value = manaChange;
damage.origin = ORIGIN_NONE;
g_game.combatChangeMana(nullptr, player, damage);
}
pushBoolean(L, true);
return 1;
}
int LuaScriptInterface::luaPlayerGetMaxMana(lua_State* L)
{
// player:getMaxMana()
const Player* player = getUserdata<const Player>(L, 1);
if (player) {
lua_pushnumber(L, player->getMaxMana());
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerSetMaxMana(lua_State* L) int LuaScriptInterface::luaPlayerSetMaxMana(lua_State* L)
{ {
// player:setMaxMana(maxMana) // player:setMaxMana(maxMana)
@ -7723,12 +7811,20 @@ int LuaScriptInterface::luaPlayerSetBankBalance(lua_State* L)
{ {
// player:setBankBalance(bankBalance) // player:setBankBalance(bankBalance)
Player* player = getUserdata<Player>(L, 1); Player* player = getUserdata<Player>(L, 1);
if (player) { if (!player) {
player->setBankBalance(getNumber<uint64_t>(L, 2));
pushBoolean(L, true);
} else {
lua_pushnil(L); lua_pushnil(L);
return 1;
} }
int64_t balance = getNumber<int64_t>(L, 2);
if (balance < 0) {
reportErrorFunc("Invalid bank balance value.");
lua_pushnil(L);
return 1;
}
player->setBankBalance(balance);
pushBoolean(L, true);
return 1; return 1;
} }
@ -9473,6 +9569,53 @@ int LuaScriptInterface::luaHouseSetOwnerGuid(lua_State* L)
return 1; return 1;
} }
int LuaScriptInterface::luaHouseStartTrade(lua_State* L)
{
// house:startTrade(player, tradePartner)
House* house = getUserdata<House>(L, 1);
Player* player = getUserdata<Player>(L, 2);
Player* tradePartner = getUserdata<Player>(L, 3);
if (!player || !tradePartner || !house) {
lua_pushnil(L);
return 1;
}
if (!Position::areInRange<2, 2, 0>(tradePartner->getPosition(), player->getPosition())) {
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERFARAWAY);
return 1;
}
if (house->getOwner() != player->getGUID()) {
lua_pushnumber(L, RETURNVALUE_YOUDONTOWNTHISHOUSE);
return 1;
}
if (g_game.map.houses.getHouseByPlayerId(tradePartner->getGUID())) {
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE);
return 1;
}
if (IOLoginData::hasBiddedOnHouse(tradePartner->getGUID())) {
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERHIGHESTBIDDER);
return 1;
}
Item* transferItem = house->getTransferItem();
if (!transferItem) {
lua_pushnumber(L, RETURNVALUE_YOUCANNOTTRADETHISHOUSE);
return 1;
}
transferItem->getParent()->setParent(player);
if (!g_game.internalStartTrade(player, tradePartner, transferItem)) {
house->resetTransferItem();
}
lua_pushnumber(L, RETURNVALUE_NOERROR);
return 1;
}
int LuaScriptInterface::luaHouseGetBeds(lua_State* L) int LuaScriptInterface::luaHouseGetBeds(lua_State* L)
{ {
// house:getBeds() // house:getBeds()
@ -10225,6 +10368,20 @@ int LuaScriptInterface::luaCombatSetCallback(lua_State* L)
return 1; return 1;
} }
int LuaScriptInterface::luaCombatSetOrigin(lua_State* L)
{
// combat:setOrigin(origin)
Combat* combat = getUserdata<Combat>(L, 1);
if (combat) {
combat->setOrigin(getNumber<CombatOrigin>(L, 2));
pushBoolean(L, true);
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaCombatExecute(lua_State* L) int LuaScriptInterface::luaCombatExecute(lua_State* L)
{ {
// combat:execute(creature, variant) // combat:execute(creature, variant)
@ -11222,7 +11379,7 @@ int LuaScriptInterface::luaPartyShareExperience(lua_State* L)
uint64_t experience = getNumber<uint64_t>(L, 2); uint64_t experience = getNumber<uint64_t>(L, 2);
Party* party = getUserdata<Party>(L, 1); Party* party = getUserdata<Party>(L, 1);
if (party) { if (party) {
party->shareExperience(experience); party->shareExperience(experience, nullptr);
pushBoolean(L, true); pushBoolean(L, true);
} else { } else {
lua_pushnil(L); lua_pushnil(L);

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -320,6 +320,7 @@ class LuaScriptInterface
} }
static std::string getString(lua_State* L, int32_t arg); static std::string getString(lua_State* L, int32_t arg);
static CombatDamage getCombatDamage(lua_State* L);
static Position getPosition(lua_State* L, int32_t arg, int32_t& stackpos); static Position getPosition(lua_State* L, int32_t arg, int32_t& stackpos);
static Position getPosition(lua_State* L, int32_t arg); static Position getPosition(lua_State* L, int32_t arg);
static Outfit_t getOutfit(lua_State* L, int32_t arg); static Outfit_t getOutfit(lua_State* L, int32_t arg);
@ -368,6 +369,7 @@ class LuaScriptInterface
// Push // Push
static void pushBoolean(lua_State* L, bool value); static void pushBoolean(lua_State* L, bool value);
static void pushCombatDamage(lua_State* L, const CombatDamage& damage);
static void pushPosition(lua_State* L, const Position& position, int32_t stackpos = 0); static void pushPosition(lua_State* L, const Position& position, int32_t stackpos = 0);
static void pushOutfit(lua_State* L, const Outfit_t& outfit); static void pushOutfit(lua_State* L, const Outfit_t& outfit);
@ -549,6 +551,8 @@ class LuaScriptInterface
static int luaGameStartRaid(lua_State* L); static int luaGameStartRaid(lua_State* L);
static int luaGameReload(lua_State* L);
// Variant // Variant
static int luaVariantCreate(lua_State* L); static int luaVariantCreate(lua_State* L);
@ -749,10 +753,6 @@ class LuaScriptInterface
static int luaCreatureGetMaxHealth(lua_State* L); static int luaCreatureGetMaxHealth(lua_State* L);
static int luaCreatureSetMaxHealth(lua_State* L); static int luaCreatureSetMaxHealth(lua_State* L);
static int luaCreatureGetMana(lua_State* L);
static int luaCreatureAddMana(lua_State* L);
static int luaCreatureGetMaxMana(lua_State* L);
static int luaCreatureGetSkull(lua_State* L); static int luaCreatureGetSkull(lua_State* L);
static int luaCreatureSetSkull(lua_State* L); static int luaCreatureSetSkull(lua_State* L);
@ -809,6 +809,9 @@ class LuaScriptInterface
static int luaPlayerGetMagicLevel(lua_State* L); static int luaPlayerGetMagicLevel(lua_State* L);
static int luaPlayerGetBaseMagicLevel(lua_State* L); static int luaPlayerGetBaseMagicLevel(lua_State* L);
static int luaPlayerGetMana(lua_State* L);
static int luaPlayerAddMana(lua_State* L);
static int luaPlayerGetMaxMana(lua_State* L);
static int luaPlayerSetMaxMana(lua_State* L); static int luaPlayerSetMaxMana(lua_State* L);
static int luaPlayerGetManaSpent(lua_State* L); static int luaPlayerGetManaSpent(lua_State* L);
static int luaPlayerAddManaSpent(lua_State* L); static int luaPlayerAddManaSpent(lua_State* L);
@ -1011,6 +1014,7 @@ class LuaScriptInterface
static int luaHouseGetOwnerGuid(lua_State* L); static int luaHouseGetOwnerGuid(lua_State* L);
static int luaHouseSetOwnerGuid(lua_State* L); static int luaHouseSetOwnerGuid(lua_State* L);
static int luaHouseStartTrade(lua_State* L);
static int luaHouseGetBeds(lua_State* L); static int luaHouseGetBeds(lua_State* L);
static int luaHouseGetBedCount(lua_State* L); static int luaHouseGetBedCount(lua_State* L);
@ -1082,6 +1086,7 @@ class LuaScriptInterface
static int luaCombatSetArea(lua_State* L); static int luaCombatSetArea(lua_State* L);
static int luaCombatSetCondition(lua_State* L); static int luaCombatSetCondition(lua_State* L);
static int luaCombatSetCallback(lua_State* L); static int luaCombatSetCallback(lua_State* L);
static int luaCombatSetOrigin(lua_State* L);
static int luaCombatExecute(lua_State* L); static int luaCombatExecute(lua_State* L);

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -744,24 +744,13 @@ void Monster::setIdle(bool idle)
void Monster::updateIdleStatus() void Monster::updateIdleStatus()
{ {
bool idle = true; bool idle = false;
if (!isSummon()) { if (conditions.empty()) {
if (!targetList.empty()) { if (!isSummon() && targetList.empty()) {
// visible target idle = true;
idle = false;
} else {
for (Condition* condition : conditions) {
if (condition->getType() >= CONDITION_ENERGY && condition->getType() <= CONDITION_ENERGY) {
// monsters with aggressive conditions never become idle
idle = false;
break;
} }
} }
}
} else {
idle = false;
}
setIdle(idle); setIdle(idle);
} }
@ -887,7 +876,7 @@ void Monster::doAttacking(uint32_t)
for (spellBlock_t& spellBlock : mType->info.attackSpells) { for (spellBlock_t& spellBlock : mType->info.attackSpells) {
if (spellBlock.range != 0 && std::max<uint32_t>(Position::getDistanceX(myPos, targetPos), Position::getDistanceY(myPos, targetPos)) <= spellBlock.range) { if (spellBlock.range != 0 && std::max<uint32_t>(Position::getDistanceX(myPos, targetPos), Position::getDistanceY(myPos, targetPos)) <= spellBlock.range) {
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) { if (normal_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
updateLookDirection(); updateLookDirection();
minCombatValue = spellBlock.minCombatValue; minCombatValue = spellBlock.minCombatValue;
@ -988,7 +977,7 @@ void Monster::onThinkTarget(uint32_t interval)
void Monster::onThinkDefense(uint32_t) void Monster::onThinkDefense(uint32_t)
{ {
for (const spellBlock_t& spellBlock : mType->info.defenseSpells) { for (const spellBlock_t& spellBlock : mType->info.defenseSpells) {
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) { if (normal_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
minCombatValue = spellBlock.minCombatValue; minCombatValue = spellBlock.minCombatValue;
maxCombatValue = spellBlock.maxCombatValue; maxCombatValue = spellBlock.maxCombatValue;
spellBlock.spell->castSpell(this, this); spellBlock.spell->castSpell(this, this);
@ -1012,7 +1001,7 @@ void Monster::onThinkDefense(uint32_t)
continue; continue;
} }
if (uniform_random(0, summonBlock.chance) == 0 && (health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) { if (normal_random(0, summonBlock.chance) == 0 && (health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
Monster* summon = Monster::createMonster(summonBlock.name); Monster* summon = Monster::createMonster(summonBlock.name);
if (summon) { if (summon) {
const Position& summonPos = getPosition(); const Position& summonPos = getPosition();
@ -1038,16 +1027,15 @@ void Monster::onThinkYell(uint32_t)
} }
int32_t randomResult = rand(); int32_t randomResult = rand();
if (randomResult == 50 * (randomResult / 50)) { if (rand() == 50 * (randomResult / 50)) {
if (!mType->info.voiceVector.empty()) { int32_t totalVoices = mType->info.voiceVector.size();
uint32_t index = uniform_random(0, mType->info.voiceVector.size() - 1); const voiceBlock_t& voice = mType->info.voiceVector[rand() % totalVoices + 1];
const voiceBlock_t& vb = mType->info.voiceVector[index];
if (vb.yellText) { if (voice.yellText) {
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, vb.text, false); g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, voice.text, false);
} else {
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, vb.text, false);
} }
else {
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, voice.text, false);
} }
} }
} }
@ -1172,7 +1160,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) { if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) {
if (OTSYS_TIME() >= nextDanceStepRound) { if (OTSYS_TIME() >= nextDanceStepRound) {
updateLookDirection(); updateLookDirection();
nextDanceStepRound = OTSYS_TIME() + 200 + getStepDuration(); nextDanceStepRound = OTSYS_TIME() + getStepDuration();
//choose a random direction //choose a random direction
result = getRandomStep(getPosition(), direction); result = getRandomStep(getPosition(), direction);
@ -1235,6 +1223,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
egibleToDance = false; egibleToDance = false;
earliestWakeUpTime = OTSYS_TIME() + 1000; earliestWakeUpTime = OTSYS_TIME() + 1000;
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration(); earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
earliestAttackTime += 200;
} }
} }
} }
@ -1276,6 +1265,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
egibleToDance = false; egibleToDance = false;
earliestWakeUpTime = OTSYS_TIME() + 1000; earliestWakeUpTime = OTSYS_TIME() + 1000;
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration(); earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
earliestAttackTime += 200;
} }
} }
} }
@ -2002,40 +1992,71 @@ void Monster::updateLookDirection()
//look EAST/WEST //look EAST/WEST
if (offsetx < 0) { if (offsetx < 0) {
newDir = DIRECTION_WEST; newDir = DIRECTION_WEST;
} else { }
else {
newDir = DIRECTION_EAST; newDir = DIRECTION_EAST;
} }
} else if (dx < dy) { }
else if (dx < dy) {
//look NORTH/SOUTH //look NORTH/SOUTH
if (offsety < 0) { if (offsety < 0) {
newDir = DIRECTION_NORTH; newDir = DIRECTION_NORTH;
} else { }
else {
newDir = DIRECTION_SOUTH; newDir = DIRECTION_SOUTH;
} }
} else { }
else {
Direction dir = getDirection(); Direction dir = getDirection();
if (offsetx < 0 && offsety < 0) { if (offsetx < 0 && offsety < 0) {
if (dir == DIRECTION_SOUTH || dir == DIRECTION_NORTH) { if (offsetx == -1 && offsety == -1) {
if (dir == DIRECTION_NORTH) {
newDir = DIRECTION_WEST; newDir = DIRECTION_WEST;
} else if (dir == DIRECTION_EAST) { }
}
if (dir == DIRECTION_SOUTH) {
newDir = DIRECTION_WEST;
}
else if (dir == DIRECTION_EAST) {
newDir = DIRECTION_NORTH; newDir = DIRECTION_NORTH;
} }
} else if (offsetx < 0 && offsety > 0) { }
if (dir == DIRECTION_NORTH || dir == DIRECTION_SOUTH) { else if (offsetx < 0 && offsety > 0) {
if (offsetx == -1 && offsety == 1) {
if (dir == DIRECTION_SOUTH) {
newDir = DIRECTION_WEST; newDir = DIRECTION_WEST;
} else if (dir == DIRECTION_EAST) { }
}
if (dir == DIRECTION_NORTH) {
newDir = DIRECTION_WEST;
}
else if (dir == DIRECTION_EAST) {
newDir = DIRECTION_SOUTH; newDir = DIRECTION_SOUTH;
} }
} else if (offsetx > 0 && offsety < 0) { }
if (dir == DIRECTION_SOUTH || dir == DIRECTION_NORTH) { else if (offsetx > 0 && offsety < 0) {
if (offsetx == 1 && offsety == -1) {
if (dir == DIRECTION_NORTH) {
newDir = DIRECTION_EAST; newDir = DIRECTION_EAST;
} else if (dir == DIRECTION_WEST) { }
}
if (dir == DIRECTION_SOUTH) {
newDir = DIRECTION_EAST;
}
else if (dir == DIRECTION_WEST) {
newDir = DIRECTION_NORTH; newDir = DIRECTION_NORTH;
} }
} else { }
if (dir == DIRECTION_NORTH || dir == DIRECTION_SOUTH) { else {
if (offsetx == 1 && offsety == 1) {
if (dir == DIRECTION_SOUTH) {
newDir = DIRECTION_EAST; newDir = DIRECTION_EAST;
} else if (dir == DIRECTION_WEST) { }
}
if (dir == DIRECTION_NORTH) {
newDir = DIRECTION_EAST;
}
else if (dir == DIRECTION_WEST) {
newDir = DIRECTION_SOUTH; newDir = DIRECTION_SOUTH;
} }
} }

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -372,6 +372,18 @@ bool Monsters::deserializeSpell(const pugi::xml_node& node, spellBlock_t& sb, co
combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE); combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE);
combat->setParam(COMBAT_PARAM_BLOCKARMOR, 1); combat->setParam(COMBAT_PARAM_BLOCKARMOR, 1);
combat->setParam(COMBAT_PARAM_BLOCKSHIELD, 1); combat->setParam(COMBAT_PARAM_BLOCKSHIELD, 1);
uint32_t tD = this->getMonsterType(description)->info.targetDistance;
if (tD == 1) {
if (sb.range > 1) {
combat->setOrigin(ORIGIN_RANGED);
}
else {
combat->setOrigin(ORIGIN_MELEE);
}
}
else if (tD > 1 && sb.range > 1) {
combat->setOrigin(ORIGIN_RANGED);
}
} else if (tmpName == "bleed") { } else if (tmpName == "bleed") {
combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE); combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE);
} else if (tmpName == "poison" || tmpName == "earth") { } else if (tmpName == "poison" || tmpName == "earth") {

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/** /**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator * Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com> * Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

Some files were not shown because too many files have changed in this diff Show More