diff --git a/config.lua b/config.lua
index 5bedf78..e354f60 100644
--- a/config.lua
+++ b/config.lua
@@ -69,7 +69,9 @@ freePremium = false
kickIdlePlayerAfterMinutes = 15
maxMessageBuffer = 4
showMonsterLoot = false
-queryPlayerContainers = false
+blockHeight = false
+dropItems = false
+
-- Character Rooking
-- Level threshold is the level requirement to teleport players back to newbie town
diff --git a/data/actions/scripts/misc/fluids.lua b/data/actions/scripts/misc/fluids.lua
index 3277f38..e300dcb 100644
--- a/data/actions/scripts/misc/fluids.lua
+++ b/data/actions/scripts/misc/fluids.lua
@@ -2,7 +2,12 @@ local drunk = Condition(CONDITION_DRUNK)
drunk:setParameter(CONDITION_PARAM_TICKS, 60000)
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 = {
[FLUID_WATER] = "Gulp.",
diff --git a/data/creaturescripts/scripts/firstitems.lua b/data/creaturescripts/scripts/firstitems.lua
index 7c837c9..0c3c75a 100644
--- a/data/creaturescripts/scripts/firstitems.lua
+++ b/data/creaturescripts/scripts/firstitems.lua
@@ -1,7 +1,5 @@
function onLogin(player)
- if player:getLastLoginSaved() <= 0 or player:getStorageValue(30017) == 1 then
- player:setStorageValue(30017, 0) -- reset storage for first items
-
+ if player:getLastLoginSaved() <= 0 then
-- Items
if player:getSex() == PLAYERSEX_FEMALE then
player:addItem(3562, 1, true, -1, CONST_SLOT_ARMOR)
diff --git a/data/events/events.xml b/data/events/events.xml
new file mode 100644
index 0000000..1b75858
--- /dev/null
+++ b/data/events/events.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/events/scripts/creature.lua b/data/events/scripts/creature.lua
new file mode 100644
index 0000000..ac4ff89
--- /dev/null
+++ b/data/events/scripts/creature.lua
@@ -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
diff --git a/data/events/scripts/party.lua b/data/events/scripts/party.lua
new file mode 100644
index 0000000..1a6b561
--- /dev/null
+++ b/data/events/scripts/party.lua
@@ -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
diff --git a/data/events/scripts/player.lua b/data/events/scripts/player.lua
new file mode 100644
index 0000000..86262d7
--- /dev/null
+++ b/data/events/scripts/player.lua
@@ -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
diff --git a/data/global.lua b/data/global.lua
index 89a84ec..13608e1 100644
--- a/data/global.lua
+++ b/data/global.lua
@@ -40,4 +40,8 @@ table.contains = function(array, value)
end
end
return false
+end
+
+function isNumber(str)
+ return tonumber(str) ~= nil
end
\ No newline at end of file
diff --git a/data/lib/core/core.lua b/data/lib/core/core.lua
index 9491e80..8bc8ac0 100644
--- a/data/lib/core/core.lua
+++ b/data/lib/core/core.lua
@@ -9,3 +9,4 @@ dofile('data/lib/core/player.lua')
dofile('data/lib/core/position.lua')
dofile('data/lib/core/teleport.lua')
dofile('data/lib/core/tile.lua')
+dofile('data/lib/core/vocation.lua')
\ No newline at end of file
diff --git a/data/lib/core/game.lua b/data/lib/core/game.lua
index 5bbec2b..29cacef 100644
--- a/data/lib/core/game.lua
+++ b/data/lib/core/game.lua
@@ -9,7 +9,7 @@ function Game.removeItemsOnMap(position)
local i = 0
while i < tileCount do
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()
else
i = i + 1
@@ -24,10 +24,8 @@ function Game.transformItemOnMap(position, itemId, toItemId, subtype)
local tile = Tile(position)
local item = tile:getItemById(itemId)
- if item ~= nil then
- item:transform(toItemId, subtype)
- item:decay()
- end
+ item:transform(toItemId, subtype)
+ item:decay()
return item
end
diff --git a/data/lib/core/tile.lua b/data/lib/core/tile.lua
index c254ad7..de3072f 100644
--- a/data/lib/core/tile.lua
+++ b/data/lib/core/tile.lua
@@ -21,3 +21,45 @@ end
function Tile.isTile(self)
return true
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
\ No newline at end of file
diff --git a/data/lib/core/vocation.lua b/data/lib/core/vocation.lua
new file mode 100644
index 0000000..33772a5
--- /dev/null
+++ b/data/lib/core/vocation.lua
@@ -0,0 +1,7 @@
+function Vocation.getBase(self)
+ local base = self
+ while base:getDemotion() do
+ base = base:getDemotion()
+ end
+ return base
+end
\ No newline at end of file
diff --git a/data/movements/scripts/misc/floorchange.lua b/data/movements/scripts/misc/floorchange.lua
index 58b54aa..6e1f365 100644
--- a/data/movements/scripts/misc/floorchange.lua
+++ b/data/movements/scripts/misc/floorchange.lua
@@ -81,8 +81,7 @@ function onStepIn(creature, item, position, fromPosition)
return false
end
- doRelocate(position, relPos)
-
+ Tile(item:getPosition()):relocateTo(relPos)
if item:getId() == 293 then
item:transform(294)
item:decay()
diff --git a/data/talkactions/scripts/reload.lua b/data/talkactions/scripts/reload.lua
new file mode 100644
index 0000000..1dd9c14
--- /dev/null
+++ b/data/talkactions/scripts/reload.lua
@@ -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
\ No newline at end of file
diff --git a/data/talkactions/scripts/save.lua b/data/talkactions/scripts/save.lua
new file mode 100644
index 0000000..d704c4c
--- /dev/null
+++ b/data/talkactions/scripts/save.lua
@@ -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
\ No newline at end of file
diff --git a/data/talkactions/scripts/sellhouse.lua b/data/talkactions/scripts/sellhouse.lua
new file mode 100644
index 0000000..9920a8a
--- /dev/null
+++ b/data/talkactions/scripts/sellhouse.lua
@@ -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
\ No newline at end of file
diff --git a/data/talkactions/talkactions.xml b/data/talkactions/talkactions.xml
index ad15b22..ac214b4 100644
--- a/data/talkactions/talkactions.xml
+++ b/data/talkactions/talkactions.xml
@@ -27,7 +27,9 @@
-
+
+
+
@@ -37,6 +39,7 @@
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6ccc19f..76c0cad 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,7 +7,6 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/behaviourdatabase.cpp
${CMAKE_CURRENT_LIST_DIR}/chat.cpp
${CMAKE_CURRENT_LIST_DIR}/combat.cpp
- ${CMAKE_CURRENT_LIST_DIR}/commands.cpp
${CMAKE_CURRENT_LIST_DIR}/condition.cpp
${CMAKE_CURRENT_LIST_DIR}/configmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/connection.cpp
@@ -19,6 +18,7 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp
${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/events.cpp
${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp
${CMAKE_CURRENT_LIST_DIR}/game.cpp
${CMAKE_CURRENT_LIST_DIR}/globalevent.cpp
diff --git a/src/account.h b/src/account.h
index a7741f4..5bdc53a 100644
--- a/src/account.h
+++ b/src/account.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/actions.cpp b/src/actions.cpp
index 748bcab..439748d 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/actions.h b/src/actions.h
index 02c4924..f4ae6d9 100644
--- a/src/actions.h
+++ b/src/actions.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/ban.cpp b/src/ban.cpp
index a531ea9..547ad29 100644
--- a/src/ban.cpp
+++ b/src/ban.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/ban.h b/src/ban.h
index 0ca2360..86535a6 100644
--- a/src/ban.h
+++ b/src/ban.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/baseevents.cpp b/src/baseevents.cpp
index f8191fc..c99243e 100644
--- a/src/baseevents.cpp
+++ b/src/baseevents.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/baseevents.h b/src/baseevents.h
index 3529a6a..c5b528f 100644
--- a/src/baseevents.h
+++ b/src/baseevents.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/bed.cpp b/src/bed.cpp
index a2f55aa..90629a9 100644
--- a/src/bed.cpp
+++ b/src/bed.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/bed.h b/src/bed.h
index b45486d..f1f836d 100644
--- a/src/bed.h
+++ b/src/bed.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/behaviourdatabase.cpp b/src/behaviourdatabase.cpp
index 7ddc588..e331abb 100644
--- a/src/behaviourdatabase.cpp
+++ b/src/behaviourdatabase.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
-* Copyright (C) 2017 Alejandro Mujica
+* Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -820,10 +820,6 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
}
} while (amount);
} else {
- if (it.charges) {
- data = it.charges;
- }
-
for (int32_t i = 0; i < std::max(1, amount); i++) {
Item* item = Item::CreateItem(itemId, data);
if (!item) {
@@ -937,7 +933,7 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
}
case BEHAVIOUR_TYPE_EXPERIENCE: {
int32_t experience = evaluate(action->expression, player, message);
- player->addExperience(experience, true, false);
+ player->addExperience(nullptr, experience, false);
break;
}
case BEHAVIOUR_TYPE_WITHDRAW: {
diff --git a/src/behaviourdatabase.h b/src/behaviourdatabase.h
index 73e1856..de7eca6 100644
--- a/src/behaviourdatabase.h
+++ b/src/behaviourdatabase.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
-* Copyright (C) 2017 Alejandro Mujica
+* Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/chat.cpp b/src/chat.cpp
index bee075e..59973c8 100644
--- a/src/chat.cpp
+++ b/src/chat.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/chat.h b/src/chat.h
index 3d7b973..e181142 100644
--- a/src/chat.h
+++ b/src/chat.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/combat.cpp b/src/combat.cpp
index 2e62e91..52bc2da 100644
--- a/src/combat.cpp
+++ b/src/combat.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -24,13 +24,16 @@
#include "game.h"
#include "configmanager.h"
#include "monster.h"
+#include "events.h"
extern Game g_game;
extern ConfigManager g_config;
+extern Events* g_events;
CombatDamage Combat::getCombatDamage(Creature* creature) const
{
CombatDamage damage;
+ damage.origin = params.origin;
damage.type = params.combatType;
if (formulaType == COMBAT_FORMULA_DAMAGE) {
damage.min = static_cast(mina);
@@ -175,11 +178,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
return RETURNVALUE_NOTENOUGHROOM;
}
- /*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)) {
+ if (tile->hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) && tile->hasProperty(CONST_PROP_UNLAY)) {
return RETURNVALUE_NOTENOUGHROOM;
}
@@ -192,7 +191,8 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
const Position& tilePosition = tile->getPosition();
if (casterPosition.z < tilePosition.z) {
return RETURNVALUE_FIRSTGODOWNSTAIRS;
- } else if (casterPosition.z > tilePosition.z) {
+ }
+ else if (casterPosition.z > tilePosition.z) {
return RETURNVALUE_FIRSTGOUPSTAIRS;
}
@@ -208,7 +208,7 @@ ReturnValue Combat::canDoCombat(Creature* caster, Tile* tile, bool aggressive)
return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE;
}
- return RETURNVALUE_NOERROR;
+ return g_events->eventCreatureOnAreaCombat(caster, tile, aggressive);
}
bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
@@ -232,74 +232,78 @@ bool Combat::isProtected(const Player* attacker, const Player* target)
ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target)
{
- if (attacker) {
- if (const Player* targetPlayer = target->getPlayer()) {
- if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
+ if (!attacker) {
+ return g_events->eventCreatureOnTargetCombat(attacker, target);
+ }
+
+ if (const Player* targetPlayer = target->getPlayer()) {
+ if (targetPlayer->hasFlag(PlayerFlag_CannotBeAttacked)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
+ }
+
+ if (const Player* attackerPlayer = attacker->getPlayer()) {
+ if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
- if (const Player* attackerPlayer = attacker->getPlayer()) {
- if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
- }
-
- if (isProtected(attackerPlayer, targetPlayer)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
- }
-
- //nopvp-zone
- const Tile* targetPlayerTile = targetPlayer->getTile();
- if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
- return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
- } else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
- return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
- }
+ if (isProtected(attackerPlayer, targetPlayer)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
- if (attacker->isSummon()) {
- if (const Player* masterAttackerPlayer = attacker->getMaster()->getPlayer()) {
- if (masterAttackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
- }
-
- if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
- return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
- }
-
- if (isProtected(masterAttackerPlayer, targetPlayer)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
- }
- }
+ //nopvp-zone
+ const Tile* targetPlayerTile = targetPlayer->getTile();
+ if (targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
+ return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
}
- } else if (target->getMonster()) {
- if (const Player* attackerPlayer = attacker->getPlayer()) {
- if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
- }
-
- if (target->isSummon() && target->getMaster()->getPlayer() && target->getZone() == ZONE_NOPVP) {
- return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
- }
+ else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
+ return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
}
}
- if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
- if (attacker->getPlayer() || (attacker->isSummon() && attacker->getMaster()->getPlayer())) {
- if (target->getPlayer()) {
- if (!isInPvpZone(attacker, target)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
- }
+ if (attacker->isSummon()) {
+ if (const Player* masterAttackerPlayer = attacker->getMaster()->getPlayer()) {
+ if (masterAttackerPlayer->hasFlag(PlayerFlag_CannotAttackPlayer)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
- if (target->isSummon() && target->getMaster()->getPlayer()) {
- if (!isInPvpZone(attacker, target)) {
- return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
- }
+ if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
+ return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
+ }
+
+ if (isProtected(masterAttackerPlayer, targetPlayer)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
}
}
}
- return RETURNVALUE_NOERROR;
+ else if (target->getMonster()) {
+ if (const Player* attackerPlayer = attacker->getPlayer()) {
+ if (attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
+ }
+
+ if (target->isSummon() && target->getMaster()->getPlayer() && target->getZone() == ZONE_NOPVP) {
+ return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
+ }
+ }
+ }
+
+ if (g_game.getWorldType() == WORLD_TYPE_NO_PVP) {
+ if (attacker->getPlayer() || (attacker->isSummon() && attacker->getMaster()->getPlayer())) {
+ if (target->getPlayer()) {
+ if (!isInPvpZone(attacker, target)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
+ }
+ }
+
+ if (target->isSummon() && target->getMaster()->getPlayer()) {
+ if (!isInPvpZone(attacker, target)) {
+ return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
+ }
+ }
+ }
+ }
+ return g_events->eventCreatureOnTargetCombat(attacker, target);
}
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;
}
-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);
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)) {
- return false;
+ return;
}
if (g_game.combatChangeHealth(caster, target, damage)) {
- CombatConditionFunc(caster, target, params, nullptr);
+ CombatConditionFunc(caster, target, params, &damage);
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);
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);
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) {
if (caster == target || !target->isImmune(condition->getType())) {
Condition* conditionCopy = condition->clone();
@@ -486,21 +490,17 @@ bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const Comba
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);
- 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);
CombatDispelFunc(caster, target, params, nullptr);
- return true;
}
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;
g_game.map.getSpectators(list, pos, true, true, rangeX, rangeX, rangeY, rangeY);
+ postCombatEffects(caster, pos, params);
+
uint16_t decreasedDamage = 0;
const uint16_t maximumDecreasedDamage = params.maximumDecreasedDamage;
@@ -721,6 +723,8 @@ void Combat::CombatFunc(Creature* caster, const Position& pos, const AreaCombat*
continue;
}
+ combatTileEffects(list, caster, tile, params);
+
if (CreatureVector* creatures = tile->getCreatures()) {
const Creature* topCreature = tile->getTopCreature();
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
@@ -834,7 +836,7 @@ bool Combat::attack(Creature* attacker, Creature* target)
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& targetPos = target->getPosition();
@@ -859,7 +861,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
uint32_t skillValue = 0;
uint8_t skill = SKILL_FIST;
- Combat::getAttackValue(attacker, attackValue, skillValue, skill, fist);
+ Combat::getAttackValue(attacker, attackValue, skillValue, skill);
int32_t defense = target->getDefense();
@@ -876,6 +878,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
combatDamage.type = combatParams.combatType;
int32_t totalDamage = Combat::getTotalDamage(skillValue, attackValue, fightMode);
combatDamage.value = totalDamage;
+ combatDamage.origin = ORIGIN_MELEE;
bool hit = Combat::doCombatHealth(attacker, target, combatDamage, combatParams);
@@ -884,7 +887,7 @@ bool Combat::closeAttack(Creature* attacker, Creature* target, fightMode_t fight
if (poison) {
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);
if (poison) {
ConditionDamage* condition = static_cast(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) {
ammunition = player->getAmmunition();
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
- return closeAttack(attacker, target, fightMode, true);
+ return closeAttack(attacker, target, fightMode);
}
distanceEffect = ammunition->getMissileType();
@@ -991,6 +994,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
CombatDamage combatDamage;
combatDamage.type = combatParams.combatType;
combatDamage.value = Combat::getTotalDamage(skillValue, attackValue, fightMode);
+ combatDamage.origin = ORIGIN_RANGED;
if (weapon) {
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
specialEffect = ammunition->getWeaponSpecialEffect();
attackStrength = ammunition->getAttackStrength();
@@ -1037,10 +1041,12 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
bool hit = false;
- if (rand() % distance <= skillValue) {
- hit = rand() % 100 <= hitChance;
+ int32_t random = rand();
+ if (random % distance <= static_cast(skillValue)) {
+ hit = random % 100 <= hitChance;
}
+
if (Player* player = attacker->getPlayer()) {
if (player->getAddAttackSkill()) {
switch (player->getLastAttackBlockType()) {
@@ -1130,6 +1136,7 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
CombatDamage combatDamage;
combatDamage.type = combatParams.combatType;
combatDamage.value = -(variation + weapon->getAttackStrength());
+ combatDamage.origin = ORIGIN_RANGED;
g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect);
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;
if (Player* player = creature->getPlayer()) {
Item* weapon = player->getWeapon();
- if (weapon && !fist) {
+ if (weapon) {
switch (weapon->getWeaponType()) {
case WEAPON_AXE: {
skill = SKILL_AXE;
@@ -1243,7 +1250,7 @@ bool Combat::canUseWeapon(Player* player, Item* weapon)
return false;
}
- if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && player->getMana() < weapon->getManaConsumption()) {
+ if (!player->hasFlag(PlayerFlag_HasInfiniteMana) && static_cast(player->getMana()) < weapon->getManaConsumption()) {
return false;
}
@@ -1278,14 +1285,14 @@ bool Combat::doCombatHealth(Creature* caster, Creature* target, CombatDamage& da
}
if (canCombat) {
- canCombat = CombatHealthFunc(caster, target, params, &damage);
- if (params.targetCallback) {
- params.targetCallback->onTargetCombat(caster, target);
- }
-
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
}
+
+ CombatHealthFunc(caster, target, params, &damage);
+ if (params.targetCallback) {
+ params.targetCallback->onTargetCombat(caster, target);
+ }
}
return canCombat;
@@ -1304,14 +1311,14 @@ void Combat::doCombatMana(Creature* caster, Creature* target, CombatDamage& dama
}
if (canCombat) {
+ if (caster && params.distanceEffect != CONST_ANI_NONE) {
+ addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
+ }
+
CombatManaFunc(caster, target, params, &damage);
if (params.targetCallback) {
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 (caster && params.distanceEffect != CONST_ANI_NONE) {
+ addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
+ }
+
CombatConditionFunc(caster, target, params, nullptr);
if (params.targetCallback) {
params.targetCallback->onTargetCombat(caster, target);
}
-
- if (caster && params.distanceEffect != CONST_ANI_NONE) {
- addDistanceEffect(caster->getPosition(), target->getPosition(), params.distanceEffect);
- }
}
}
diff --git a/src/combat.h b/src/combat.h
index bc07037..a6b6b70 100644
--- a/src/combat.h
+++ b/src/combat.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -73,6 +73,7 @@ struct CombatParams {
ConditionType_t dispelType = CONDITION_NONE;
CombatType_t combatType = COMBAT_NONE;
+ CombatOrigin origin = ORIGIN_SPELL;
uint8_t impactEffect = CONST_ME_NONE;
uint8_t distanceEffect = CONST_ANI_NONE;
@@ -116,7 +117,7 @@ struct DunkenImpact : Impact
void handleCreature(Creature* target) final;
};
-typedef bool (*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
+typedef void(*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
class MatrixArea
{
@@ -285,12 +286,12 @@ class Combat
static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode);
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 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 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);
}
+ void setOrigin(CombatOrigin origin) {
+ params.origin = origin;
+ }
+
protected:
static bool canUseWeapon(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 bool CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
- static bool CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
- static bool CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
- static bool CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
- static bool CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+ static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+ static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
+ static void CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
+ static void CombatDispelFunc(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);
CombatDamage getCombatDamage(Creature* creature) const;
diff --git a/src/commands.cpp b/src/commands.cpp
index 0e42920..83db35e 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/commands.h b/src/commands.h
index 2be9ac1..828ef8a 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/condition.cpp b/src/condition.cpp
index e07d8d5..13b02cd 100644
--- a/src/condition.cpp
+++ b/src/condition.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -227,7 +227,7 @@ bool Condition::isPersistent() const
return false;
}
- if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT)) {
+ if (!(id == CONDITIONID_DEFAULT || id == CONDITIONID_COMBAT || conditionType == CONDITION_MUTED)) {
return false;
}
@@ -655,7 +655,9 @@ bool ConditionRegeneration::executeCondition(Creature* creature, int32_t interva
if (internalManaTicks >= manaTicks) {
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)
{
- Condition::setParam(param, value);
-
switch (param) {
case CONDITION_PARAM_OWNER:
owner = value;
@@ -927,6 +927,7 @@ bool ConditionDamage::doDamage(Creature* creature, int32_t healthChange)
}
CombatDamage damage;
+ damage.origin = ORIGIN_CONDITION;
damage.value = healthChange;
damage.type = Combat::ConditionToDamageType(conditionType);
diff --git a/src/condition.h b/src/condition.h
index efee824..2535aa0 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/configmanager.cpp b/src/configmanager.cpp
index d1e60c4..2993702 100644
--- a/src/configmanager.cpp
+++ b/src/configmanager.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -77,7 +77,9 @@ bool ConfigManager::load()
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);
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[SERVER_NAME] = getGlobalString(L, "serverName", "");
diff --git a/src/configmanager.h b/src/configmanager.h
index f2105fe..6c14b68 100644
--- a/src/configmanager.h
+++ b/src/configmanager.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -40,7 +40,8 @@ class ConfigManager
CONVERT_UNSAFE_SCRIPTS,
TELEPORT_NEWBIES,
STACK_CUMULATIVES,
- QUERY_PLAYER_CONTAINERS,
+ BLOCK_HEIGHT,
+ DROP_ITEMS,
LAST_BOOLEAN_CONFIG /* this must be the last one */
};
diff --git a/src/connection.cpp b/src/connection.cpp
index 5f21835..859066c 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/connection.h b/src/connection.h
index 34c6ac9..b885749 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/const.h b/src/const.h
index afefe77..8490b1f 100644
--- a/src/const.h
+++ b/src/const.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -308,6 +308,28 @@ enum PlayerFlags : uint64_t {
PlayerFlag_SpecialMoveUse = static_cast(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_PARTY = 0x01;
static constexpr int32_t CHANNEL_RULE_REP = 0x02;
diff --git a/src/container.cpp b/src/container.cpp
index e404695..f949f81 100644
--- a/src/container.cpp
+++ b/src/container.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -370,7 +370,7 @@ ReturnValue Container::queryRemove(const Thing& thing, uint32_t count, uint32_t
}
Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item** destItem,
- uint32_t& flags)
+ uint32_t& flags)
{
if (index == 254 /*move up*/) {
index = INDEX_WHEREEVER;
@@ -386,7 +386,8 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
if (index == 255 /*add wherever*/) {
index = INDEX_WHEREEVER;
*destItem = nullptr;
- } else if (index >= static_cast(capacity())) {
+ }
+ else if (index >= static_cast(capacity())) {
/*
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
@@ -403,6 +404,20 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item**
return this;
}
+ if (index != INDEX_WHEREEVER) {
+ Item* itemFromIndex = getItemByIndex(index);
+ if (itemFromIndex) {
+ *destItem = itemFromIndex;
+ }
+
+ Cylinder* subCylinder = dynamic_cast(*destItem);
+ if (subCylinder) {
+ index = INDEX_WHEREEVER;
+ *destItem = nullptr;
+ return subCylinder;
+ }
+ }
+
if (g_config.getBoolean(ConfigManager::STACK_CUMULATIVES)) {
bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags);
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(*destItem);
- if (subCylinder) {
- index = INDEX_WHEREEVER;
- *destItem = nullptr;
- return subCylinder;
- }
- }
return this;
}
diff --git a/src/container.h b/src/container.h
index 7af5675..495c92f 100644
--- a/src/container.h
+++ b/src/container.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/creature.cpp b/src/creature.cpp
index 781c87d..8bd0318 100644
--- a/src/creature.cpp
+++ b/src/creature.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -619,7 +619,8 @@ void Creature::onDeath()
if (lastHitCreature) {
lastHitUnjustified = lastHitCreature->onKilledCreature(this);
lastHitCreatureMaster = lastHitCreature->getMaster();
- } else {
+ }
+ else {
lastHitCreatureMaster = nullptr;
}
@@ -639,8 +640,9 @@ void Creature::onDeath()
if (attacker != this) {
uint64_t gainExp = getGainedExperience(attacker);
- if (Player* player = attacker->getPlayer()) {
- Party* party = player->getParty();
+ if (Player* attackerPlayer = attacker->getPlayer()) {
+ attackerPlayer->removeAttacked(getPlayer());
+ Party* party = attackerPlayer->getParty();
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
attacker = party->getLeader();
}
@@ -649,7 +651,8 @@ void Creature::onDeath()
auto tmpIt = experienceMap.find(attacker);
if (tmpIt == experienceMap.end()) {
experienceMap[attacker] = gainExp;
- } else {
+ }
+ else {
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(manaChange, getMaxMana() - mana);
- } else {
- mana = std::max(0, mana + manaChange);
- }
-}
-
void Creature::gainHealth(Creature* healer, int32_t 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,
bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field = false */)
{
diff --git a/src/creature.h b/src/creature.h
index 39afb11..994556b 100644
--- a/src/creature.h
+++ b/src/creature.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -220,12 +220,6 @@ class Creature : virtual public Thing
virtual int32_t getMaxHealth() const {
return healthMax;
}
- uint32_t getMana() const {
- return mana;
- }
- virtual uint32_t getMaxMana() const {
- return 0;
- }
const Outfit_t getCurrentOutfit() const {
return currentOutfit;
@@ -320,11 +314,9 @@ class Creature : virtual public Thing
}
virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
- virtual void changeMana(int32_t manaChange);
void gainHealth(Creature* attacker, int32_t healthGain);
virtual void drainHealth(Creature* attacker, int32_t damage);
- virtual void drainMana(Creature* attacker, int32_t manaLoss);
virtual bool challengeCreature(Creature*) {
return false;
@@ -494,7 +486,6 @@ class Creature : virtual public Thing
uint32_t blockTicks = 0;
uint32_t lastStepCost = 1;
uint32_t baseSpeed = 70;
- uint32_t mana = 0;
uint32_t latestKillEvent = 0;
int32_t varSpeed = 0;
int32_t health = 1000;
diff --git a/src/creatureevent.cpp b/src/creatureevent.cpp
index 990fa64..eb72b28 100644
--- a/src/creatureevent.cpp
+++ b/src/creatureevent.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -177,6 +177,10 @@ bool CreatureEvent::configureEvent(const pugi::xml_node& node)
type = CREATURE_EVENT_KILL;
} else if (tmpStr == "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") {
type = CREATURE_EVENT_EXTENDED_OPCODE;
} else {
@@ -213,6 +217,12 @@ std::string CreatureEvent::getScriptEventName() const
case CREATURE_EVENT_ADVANCE:
return "onAdvance";
+ case CREATURE_EVENT_HEALTHCHANGE:
+ return "onHealthChange";
+
+ case CREATURE_EVENT_MANACHANGE:
+ return "onManaChange";
+
case CREATURE_EVENT_EXTENDED_OPCODE:
return "onExtendedOpcode";
@@ -409,6 +419,85 @@ void CreatureEvent::executeOnKill(Creature* creature, Creature* target)
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(L, -4));
+ damage.type = LuaScriptInterface::getNumber(L, -3);
+ damage.min = std::abs(LuaScriptInterface::getNumber(L, -2));
+ damage.max = LuaScriptInterface::getNumber(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)
{
//onExtendedOpcode(player, opcode, buffer)
diff --git a/src/creatureevent.h b/src/creatureevent.h
index 7617c46..6dbdeac 100644
--- a/src/creatureevent.h
+++ b/src/creatureevent.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -33,6 +33,8 @@ enum CreatureEventType_t {
CREATURE_EVENT_DEATH,
CREATURE_EVENT_KILL,
CREATURE_EVENT_ADVANCE,
+ CREATURE_EVENT_HEALTHCHANGE,
+ CREATURE_EVENT_MANACHANGE,
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);
void executeOnKill(Creature* creature, Creature* target);
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);
//
diff --git a/src/cylinder.cpp b/src/cylinder.cpp
index 9e9e289..406ca9a 100644
--- a/src/cylinder.cpp
+++ b/src/cylinder.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/cylinder.h b/src/cylinder.h
index b31765f..872609c 100644
--- a/src/cylinder.h
+++ b/src/cylinder.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/database.cpp b/src/database.cpp
index 5079e08..0dfc590 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/database.h b/src/database.h
index f9ccf57..e0168ba 100644
--- a/src/database.h
+++ b/src/database.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/databasemanager.cpp b/src/databasemanager.cpp
index 07f2325..dc38b37 100644
--- a/src/databasemanager.cpp
+++ b/src/databasemanager.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/databasemanager.h b/src/databasemanager.h
index 4592687..d15f1ec 100644
--- a/src/databasemanager.h
+++ b/src/databasemanager.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/databasetasks.cpp b/src/databasetasks.cpp
index a741e9f..37f1176 100644
--- a/src/databasetasks.cpp
+++ b/src/databasetasks.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/databasetasks.h b/src/databasetasks.h
index 131a173..42b36e2 100644
--- a/src/databasetasks.h
+++ b/src/databasetasks.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/definitions.h b/src/definitions.h
index 2dfc2c6..4ab6c38 100644
--- a/src/definitions.h
+++ b/src/definitions.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -20,9 +20,9 @@
#ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
#define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
-static constexpr auto STATUS_SERVER_NAME = "Nostalrius";
-static constexpr auto STATUS_SERVER_VERSION = "3.0";
-static constexpr auto STATUS_SERVER_DEVELOPERS = "Alejandro Mujica";
+static constexpr auto STATUS_SERVER_NAME = "Sabrehaven";
+static constexpr auto STATUS_SERVER_VERSION = "1.0";
+static constexpr auto STATUS_SERVER_DEVELOPERS = "Sabrehaven Developers Team";
static constexpr auto CLIENT_VERSION_MIN = 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:4351) // new behavior: elements of array will be default initialized
#pragma warning(disable:4458) // declaration hides class member
-#pragma warning(disable:4018) // signed/unsigned mismatch
+#pragma warning(disable:4996) // inetpton warning
#endif
#define strcasecmp _stricmp
diff --git a/src/depotlocker.cpp b/src/depotlocker.cpp
index 10f5f15..09189a1 100644
--- a/src/depotlocker.cpp
+++ b/src/depotlocker.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/depotlocker.h b/src/depotlocker.h
index 9d03f8b..094defc 100644
--- a/src/depotlocker.h
+++ b/src/depotlocker.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/enums.h b/src/enums.h
index c4a89d7..1ae3739 100644
--- a/src/enums.h
+++ b/src/enums.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -345,6 +345,11 @@ enum ReturnValue {
RETURNVALUE_CANONLYUSEONESHIELD,
RETURNVALUE_NOPARTYMEMBERSINRANGE,
RETURNVALUE_YOUARENOTTHEOWNER,
+ RETURNVALUE_TRADEPLAYERFARAWAY,
+ RETURNVALUE_YOUDONTOWNTHISHOUSE,
+ RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
+ RETURNVALUE_TRADEPLAYERHIGHESTBIDDER,
+ RETURNVALUE_YOUCANNOTTRADETHISHOUSE,
};
struct Outfit_t {
@@ -363,15 +368,26 @@ struct LightInfo {
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
{
CombatType_t type;
int32_t value;
int32_t min;
int32_t max;
+ CombatOrigin origin;
CombatDamage()
{
+ origin = ORIGIN_NONE;
type = COMBAT_NONE;
value = 0;
min = 0;
diff --git a/src/events.cpp b/src/events.cpp
new file mode 100644
index 0000000..868901e
--- /dev/null
+++ b/src/events.cpp
@@ -0,0 +1,827 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2016 Mark Samman
+ *
+ * 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
+
+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 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(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(L, creature);
+ LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ LuaScriptInterface::pushUserdata(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(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(L, creature);
+ LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ LuaScriptInterface::pushUserdata(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(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(L, party);
+ LuaScriptInterface::setMetatable(L, -1, "Party");
+
+ LuaScriptInterface::pushUserdata(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(L, party);
+ LuaScriptInterface::setMetatable(L, -1, "Party");
+
+ LuaScriptInterface::pushUserdata(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(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(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(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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ if (Creature* creature = thing->getCreature()) {
+ LuaScriptInterface::pushUserdata(L, creature);
+ LuaScriptInterface::setCreatureMetatable(L, -1, creature);
+ }
+ else if (Item* item = thing->getItem()) {
+ LuaScriptInterface::pushUserdata- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata(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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata(L, partner);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata
- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata
- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata
- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata(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(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(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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata(L, target);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata
- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata(L, target);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ LuaScriptInterface::pushUserdata
- (L, item);
+ LuaScriptInterface::setItemMetatable(L, -1, item);
+
+ LuaScriptInterface::pushUserdata
- (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(L, player);
+ LuaScriptInterface::setMetatable(L, -1, "Player");
+
+ if (source) {
+ LuaScriptInterface::pushUserdata(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(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(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(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(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(L, -1);
+ lua_pop(L, 1);
+ }
+
+ scriptInterface.resetScriptEnv();
+}
\ No newline at end of file
diff --git a/src/events.h b/src/events.h
new file mode 100644
index 0000000..7582c29
--- /dev/null
+++ b/src/events.h
@@ -0,0 +1,95 @@
+/**
+ * The Forgotten Server - a free and open-source MMORPG server emulator
+ * Copyright (C) 2016 Mark Samman
+ *
+ * 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
\ No newline at end of file
diff --git a/src/fileloader.cpp b/src/fileloader.cpp
index d37955f..be25ecf 100644
--- a/src/fileloader.cpp
+++ b/src/fileloader.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/fileloader.h b/src/fileloader.h
index 5ce9c5b..74872b0 100644
--- a/src/fileloader.h
+++ b/src/fileloader.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/game.cpp b/src/game.cpp
index 1c6d3d6..1d587b6 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -22,9 +22,9 @@
#include "pugicast.h"
#include "items.h"
-#include "commands.h"
#include "creature.h"
#include "monster.h"
+#include "events.h"
#include "game.h"
#include "actions.h"
#include "iologindata.h"
@@ -36,6 +36,7 @@
#include "bed.h"
#include "scheduler.h"
#include "databasetasks.h"
+#include "movement.h"
extern ConfigManager g_config;
extern Actions* g_actions;
@@ -44,6 +45,10 @@ extern TalkActions* g_talkActions;
extern Spells* g_spells;
extern Vocations g_vocations;
extern GlobalEvents* g_globalEvents;
+extern Events* g_events;
+extern CreatureEvents* g_creatureEvents;
+extern Monsters g_monsters;
+extern MoveEvents* g_moveEvents;
Game::~Game()
{
@@ -84,8 +89,6 @@ void Game::setGameState(GameState_t newState)
gameState = newState;
switch (newState) {
case GAME_STATE_INIT: {
- commands.loadFromXml();
-
loadExperienceStages();
groups.load();
@@ -219,7 +222,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
}
case STACKPOS_USEITEM: {
- thing = tile->getUseItem();
+ thing = tile->getUseItem(index);
break;
}
@@ -231,7 +234,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
case STACKPOS_USETARGET: {
thing = tile->getTopCreature();
if (!thing) {
- thing = tile->getUseItem();
+ thing = tile->getUseItem(index);
}
break;
}
@@ -651,6 +654,13 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
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())) {
//need to walk to the creature first before moving it
std::forward_list 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);
if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret);
@@ -729,7 +743,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
internalCreatureTurn(creature, DIRECTION_NORTH);
}
}
- } else {
+ }
+ else {
//try go down
Tile* tmpTile = map.getTile(destPos.x, destPos.y, destPos.z);
if (currentPos.z != 7 && (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID)))) {
@@ -742,11 +757,37 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
}
}
+ ReturnValue ret = RETURNVALUE_NOTPOSSIBLE;
Tile* toTile = map.getTile(destPos);
- if (!toTile) {
- return RETURNVALUE_NOTPOSSIBLE;
+
+ 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) {
+ return RETURNVALUE_NOTPOSSIBLE;
+ }
+ return internalMoveCreature(*creature, *toTile, flags);
}
- return internalMoveCreature(*creature, *toTile, flags);
}
ReturnValue Game::internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags /*= 0*/)
@@ -964,6 +1005,10 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
return;
}
+ if (!g_events->eventPlayerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)) {
+ return;
+ }
+
uint8_t toIndex = 0;
if (toPos.x == 0xFFFF) {
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);
if (ret != RETURNVALUE_NOERROR) {
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;
}
+ if (!g_events->eventPlayerOnTradeRequest(player, tradePartner, tradeItem)) {
+ return;
+ }
+
internalStartTrade(player, tradePartner, tradeItem);
}
@@ -2379,6 +2430,11 @@ void Game::playerAcceptTrade(uint32_t playerId)
Item* tradeItem1 = player->tradeItem;
Item* tradeItem2 = tradePartner->tradeItem;
+ if (!g_events->eventPlayerOnTradeAccept(player, tradePartner, tradeItem1, tradeItem2)) {
+ internalCloseTrade(player);
+ return;
+ }
+
player->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(Position::getDistanceX(playerPosition, tradeItemPosition),
Position::getDistanceY(playerPosition, tradeItemPosition));
- std::stringstream ss;
if (index == 0) {
- ss << "You see " << tradeItem->getDescription(lookDistance);
- player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+ g_events->eventPlayerOnLookInTrade(player, tradePartner, tradeItem, lookDistance);
return;
}
@@ -2531,8 +2585,7 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
}
if (--index == 0) {
- ss << "You see " << item->getDescription(lookDistance);
- player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
+ g_events->eventPlayerOnLookInTrade(player, tradePartner, item, lookDistance);
return;
}
}
@@ -2624,52 +2677,7 @@ void Game::playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos
lookDistance = -1;
}
- std::ostringstream ss;
- 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());
+ g_events->eventPlayerOnLook(player, pos, thing, stackPos, lookDistance);
}
void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
@@ -2704,21 +2712,7 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
lookDistance = -1;
}
- std::ostringstream ss;
- 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());
+ g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
}
void Game::playerCancelAttackAndFollow(uint32_t playerId)
@@ -2847,6 +2841,10 @@ void Game::playerTurn(uint32_t playerId, Direction dir)
return;
}
+ if (!g_events->eventPlayerOnTurn(player, dir)) {
+ return;
+ }
+
player->resetIdleTime();
internalCreatureTurn(player, dir);
}
@@ -2897,6 +2895,10 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
player->resetIdleTime();
+ if (playerSaySpell(player, type, text)) {
+ return;
+ }
+
uint32_t muteTime = player->isMuted();
if (muteTime > 0) {
std::ostringstream ss;
@@ -2905,14 +2907,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
return;
}
- if (playerSayCommand(player, text)) {
- return;
- }
-
- if (playerSaySpell(player, type, text)) {
- return;
- }
-
if (!text.empty() && text.front() == '/' && player->isAccessPlayer()) {
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)
{
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)
{
+ if (!g_events->eventCreatureOnChangeOutfit(creature, outfit)) {
+ return;
+ }
+
creature->setCurrentOutfit(outfit);
if (creature->isInvisible()) {
@@ -3403,6 +3384,17 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
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();
target->gainHealth(attacker, damage.value);
realHealthChange = target->getHealth() - realHealthChange;
@@ -3410,7 +3402,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (realHealthChange > 0 && !target->isInGhostMode()) {
addMagicEffect(targetPos, CONST_ME_MAGIC_BLUE);
}
- } else {
+ }
+ else {
if (Monster* monster = target->getMonster()) {
// makes monsters aggressive when damaged
// basically stands for UNDERATTACK stance under CipSoft servers
@@ -3431,7 +3424,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
Player* attackerPlayer;
if (attacker) {
attackerPlayer = attacker->getPlayer();
- } else {
+ }
+ else {
attackerPlayer = nullptr;
}
damage.value = std::abs(damage.value);
@@ -3440,25 +3434,39 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (healthChange == 0) {
return true;
}
-
+ Player* targetPlayer = target->getPlayer();
SpectatorVec list;
if (target->hasCondition(CONDITION_MANASHIELD) && damage.type != COMBAT_UNDEFINEDDAMAGE) {
- int32_t manaDamage = std::min(target->getMana(), healthChange);
+ int32_t manaDamage = std::min(targetPlayer->getMana(), healthChange);
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(targetPlayer->getMana(), healthChange);
+ }
+ }
+ targetPlayer->drainMana(attacker, manaDamage);
map.getSpectators(list, targetPos, true, true);
addMagicEffect(list, targetPos, CONST_ME_LOSEENERGY);
std::string damageString = std::to_string(manaDamage);
- Player* targetPlayer = target->getPlayer();
if (targetPlayer) {
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << " mana.";
- } else if (targetPlayer == attackerPlayer) {
+ }
+ else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack.";
- } else {
+ }
+ else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3489,19 +3497,11 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
realDamage = damage.value;
if (realDamage == 0) {
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()) {
map.getSpectators(list, targetPos, true, true);
}
- addCreatureHealth(list, target);
TextColor_t color = TEXTCOLOR_NONE;
uint8_t hitEffect;
@@ -3514,15 +3514,15 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (color != TEXTCOLOR_NONE) {
std::string damageString = std::to_string(realDamage) + (realDamage != 1 ? " hitpoints" : " hitpoint");
-
- Player* targetPlayer = target->getPlayer();
if (targetPlayer) {
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << ".";
- } else if (targetPlayer == attackerPlayer) {
+ }
+ else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " due to your own attack.";
- } else {
+ }
+ else {
ss << "You lose " << damageString << " due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3534,16 +3534,43 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
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;
}
-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) {
- target->changeMana(manaChange);
- } else {
+ 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->changeMana(manaChange);
+ }
+ else {
const Position& targetPos = target->getPosition();
if (!target->isAttackable()) {
if (!target->isInGhostMode()) {
@@ -3555,11 +3582,12 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
Player* attackerPlayer;
if (attacker) {
attackerPlayer = attacker->getPlayer();
- } else {
+ }
+ else {
attackerPlayer = nullptr;
}
- int32_t manaLoss = std::min(target->getMana(), -manaChange);
+ int32_t manaLoss = std::min(targetPlayer->getMana(), -manaChange);
BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
if (blockType != BLOCK_NONE) {
addMagicEffect(targetPos, CONST_ME_POFF);
@@ -3570,11 +3598,20 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
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);
-
- Player* targetPlayer = target->getPlayer();
SpectatorVec list;
map.getSpectators(list, targetPos, false, true);
@@ -3582,9 +3619,11 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << " mana.";
- } else if (targetPlayer == attackerPlayer) {
+ }
+ else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack.";
- } else {
+ }
+ else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3814,23 +3853,9 @@ void Game::getWorldLightInfo(LightInfo& lightInfo) const
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()
{
+ saveGameState();
std::cout << "Shutting down..." << std::flush;
g_scheduler.shutdown();
@@ -4324,22 +4349,8 @@ void Game::playerReportBug(uint32_t playerId, const std::string& message)
return;
}
- if (player->getAccountType() == ACCOUNT_TYPE_NORMAL) {
- return;
- }
-
- 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) + ".");
+ const Position& position = player->getPosition();
+ g_events->eventPlayerOnReportBug(player, message, position);
}
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);
}
}
+
+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;
+ }
+ }
+}
diff --git a/src/game.h b/src/game.h
index 20d80e2..a484818 100644
--- a/src/game.h
+++ b/src/game.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -22,7 +22,6 @@
#include "account.h"
#include "combat.h"
-#include "commands.h"
#include "groups.h"
#include "map.h"
#include "position.h"
@@ -436,7 +435,7 @@ class Game
void combatGetTypeInfo(CombatType_t combatType, Creature* target, TextColor_t& color, uint8_t& effect);
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
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);
void addMonsterSayText(const Position& pos, const std::string& text);
- void addCommandTag(char tag);
- void resetCommandTag();
-
void startDecay(Item* item);
int32_t getLightHour() const {
return lightHour;
@@ -488,13 +484,13 @@ class Game
BedItem* getBedBySleeper(uint32_t guid) const;
void setBedSleeper(BedItem* bed, uint32_t guid);
void removeBedSleeper(uint32_t guid);
+ bool reload(ReloadTypes_t reloadType);
Groups groups;
Map map;
Raids raids;
protected:
- bool playerSayCommand(Player* player, const std::string& text);
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
void playerWhisper(Player* player, const std::string& text);
bool playerYell(Player* player, const std::string& text);
@@ -518,7 +514,6 @@ class Game
std::vector ToReleaseCreatures;
std::vector
- ToReleaseItems;
- std::vector commandTags;
size_t lastBucket = 0;
@@ -532,8 +527,6 @@ class Game
std::map bedSleepersMap;
- Commands commands;
-
static constexpr int32_t LIGHT_LEVEL_DAY = 250;
static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
static constexpr int32_t SUNSET = 1305;
diff --git a/src/globalevent.cpp b/src/globalevent.cpp
index 53463a8..96c9d71 100644
--- a/src/globalevent.cpp
+++ b/src/globalevent.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/globalevent.h b/src/globalevent.h
index 1232ddf..b4ba1cb 100644
--- a/src/globalevent.h
+++ b/src/globalevent.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/groups.cpp b/src/groups.cpp
index f56956c..8b4460d 100644
--- a/src/groups.cpp
+++ b/src/groups.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/groups.h b/src/groups.h
index 2215678..e16adfb 100644
--- a/src/groups.h
+++ b/src/groups.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/guild.cpp b/src/guild.cpp
index 34db634..e6bed21 100644
--- a/src/guild.cpp
+++ b/src/guild.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/guild.h b/src/guild.h
index 1aeefe9..3085ec9 100644
--- a/src/guild.h
+++ b/src/guild.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/house.cpp b/src/house.cpp
index 88614f9..29f375c 100644
--- a/src/house.cpp
+++ b/src/house.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -82,7 +82,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* play
setAccessList(SUBOWNER_LIST, "");
setAccessList(GUEST_LIST, "");
- for (Door* door : doorList) {
+ for (Door* door : doorSet) {
door->setAccessList("");
}
@@ -116,7 +116,7 @@ void House::updateDoorDescription() const
}
}
- for (const auto& it : doorList) {
+ for (const auto& it : doorSet) {
it->setSpecialDescription(ss.str());
}
}
@@ -277,17 +277,17 @@ bool House::isInvited(const Player* player)
void House::addDoor(Door* door)
{
door->incrementReferenceCounter();
- doorList.push_back(door);
+ doorSet.insert(door);
door->setHouse(this);
updateDoorDescription();
}
void House::removeDoor(Door* door)
{
- auto it = std::find(doorList.begin(), doorList.end(), door);
- if (it != doorList.end()) {
+ auto it = doorSet.find(door);
+ if (it != doorSet.end()) {
door->decrementReferenceCounter();
- doorList.erase(it);
+ doorSet.erase(it);
}
}
@@ -299,7 +299,7 @@ void House::addBed(BedItem* bed)
Door* House::getDoorByNumber(uint32_t doorId) const
{
- for (Door* door : doorList) {
+ for (Door* door : doorSet) {
if (door->getDoorId() == doorId) {
return door;
}
@@ -309,7 +309,7 @@ Door* House::getDoorByNumber(uint32_t doorId) const
Door* House::getDoorByPosition(const Position& pos)
{
- for (Door* door : doorList) {
+ for (Door* door : doorSet) {
if (door->getPosition() == pos) {
return door;
}
diff --git a/src/house.h b/src/house.h
index 2b126c3..3d9b543 100644
--- a/src/house.h
+++ b/src/house.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -21,6 +21,7 @@
#define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
#include
+#include
#include "container.h"
#include "housetile.h"
@@ -212,10 +213,11 @@ class House
return houseTiles;
}
- const std::list& getDoors() const {
- return doorList;
+ const std::set& getDoors() const {
+ return doorSet;
}
+
void addBed(BedItem* bed);
const HouseBedItemList& getBeds() const {
return bedsList;
@@ -234,7 +236,7 @@ class House
Container transfer_container{ITEM_LOCKER1};
HouseTileList houseTiles;
- std::list doorList;
+ std::set doorSet;
HouseBedItemList bedsList;
std::string houseName;
diff --git a/src/housetile.cpp b/src/housetile.cpp
index d206b48..f3fccf5 100644
--- a/src/housetile.cpp
+++ b/src/housetile.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/housetile.h b/src/housetile.h
index ba55d43..17ef634 100644
--- a/src/housetile.h
+++ b/src/housetile.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/ioguild.cpp b/src/ioguild.cpp
index 69675dc..b4ef9b5 100644
--- a/src/ioguild.cpp
+++ b/src/ioguild.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/ioguild.h b/src/ioguild.h
index d956c77..e5f058c 100644
--- a/src/ioguild.h
+++ b/src/ioguild.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iologindata.cpp b/src/iologindata.cpp
index a2e5708..4fb9fbc 100644
--- a/src/iologindata.cpp
+++ b/src/iologindata.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iologindata.h b/src/iologindata.h
index 9b58fdf..d207507 100644
--- a/src/iologindata.h
+++ b/src/iologindata.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iomap.cpp b/src/iomap.cpp
index 3f6f426..197bf97 100644
--- a/src/iomap.cpp
+++ b/src/iomap.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iomap.h b/src/iomap.h
index 9386141..5062e98 100644
--- a/src/iomap.h
+++ b/src/iomap.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iomapserialize.cpp b/src/iomapserialize.cpp
index 0e83463..a6a5b9d 100644
--- a/src/iomapserialize.cpp
+++ b/src/iomapserialize.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/iomapserialize.h b/src/iomapserialize.h
index c7b269b..1a87c28 100644
--- a/src/iomapserialize.h
+++ b/src/iomapserialize.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/item.cpp b/src/item.cpp
index cb69843..acf2f1b 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/item.h b/src/item.h
index 45e1e58..fc92915 100644
--- a/src/item.h
+++ b/src/item.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/items.cpp b/src/items.cpp
index dcb1463..767ada3 100644
--- a/src/items.cpp
+++ b/src/items.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/items.h b/src/items.h
index af2f76e..6411e99 100644
--- a/src/items.h
+++ b/src/items.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/lockfree.h b/src/lockfree.h
index 0b9860c..7c8cc7b 100644
--- a/src/lockfree.h
+++ b/src/lockfree.h
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
diff --git a/src/luascript.cpp b/src/luascript.cpp
index 231d2b5..8099d24 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2017 Alejandro Mujica
+ * Copyright (C) 2019 Sabrehaven and Mark Samman
*
* 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
@@ -676,6 +676,18 @@ void LuaScriptInterface::setCreatureMetatable(lua_State* L, int32_t index, const
}
// Get
+CombatDamage LuaScriptInterface::getCombatDamage(lua_State* L)
+{
+ CombatDamage damage;
+ damage.value = getNumber(L, -4);
+ damage.type = getNumber(L, -3);
+ damage.min = getNumber(L, -2);
+ damage.max = getNumber(L, -1);
+
+ lua_pop(L, 4);
+ return damage;
+}
+
std::string LuaScriptInterface::getString(lua_State* L, int32_t arg)
{
size_t len;
@@ -839,6 +851,16 @@ void LuaScriptInterface::pushBoolean(lua_State* L, bool value)
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*/)
{
lua_createtable(L, 0, 4);
@@ -1465,6 +1487,13 @@ void LuaScriptInterface::registerFunctions()
registerEnum(SLOTP_DEPOT)
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
registerEnum(GUEST_LIST)
registerEnum(SUBOWNER_LIST)
@@ -1533,6 +1562,31 @@ void LuaScriptInterface::registerFunctions()
registerEnum(RETURNVALUE_CANONLYUSEONESHIELD)
registerEnum(RETURNVALUE_NOPARTYMEMBERSINRANGE)
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
registerGlobalVariable("INDEX_WHEREEVER", INDEX_WHEREEVER);
@@ -1608,6 +1662,8 @@ void LuaScriptInterface::registerFunctions()
registerEnumIn("configKeys", ConfigManager::MAX_PACKETS_PER_SECOND)
registerEnumIn("configKeys", ConfigManager::NEWBIE_TOWN)
registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD)
+ registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT)
+ registerEnumIn("configKeys", ConfigManager::DROP_ITEMS)
// os
registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime);
@@ -1646,6 +1702,8 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Game", "startRaid", LuaScriptInterface::luaGameStartRaid);
+ registerMethod("Game", "reload", LuaScriptInterface::luaGameReload);
+
// Variant
registerClass("Variant", "", LuaScriptInterface::luaVariantCreate);
@@ -1853,10 +1911,6 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Creature", "getMaxHealth", LuaScriptInterface::luaCreatureGetMaxHealth);
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", "setSkull", LuaScriptInterface::luaCreatureSetSkull);
@@ -1914,6 +1968,9 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getMagicLevel", LuaScriptInterface::luaPlayerGetMagicLevel);
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", "getManaSpent", LuaScriptInterface::luaPlayerGetManaSpent);
registerMethod("Player", "addManaSpent", LuaScriptInterface::luaPlayerAddManaSpent);
@@ -2122,6 +2179,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("House", "getOwnerGuid", LuaScriptInterface::luaHouseGetOwnerGuid);
registerMethod("House", "setOwnerGuid", LuaScriptInterface::luaHouseSetOwnerGuid);
+ registerMethod("House", "startTrade", LuaScriptInterface::luaHouseStartTrade);
registerMethod("House", "getBeds", LuaScriptInterface::luaHouseGetBeds);
registerMethod("House", "getBedCount", LuaScriptInterface::luaHouseGetBedCount);
@@ -2196,6 +2254,7 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Combat", "setArea", LuaScriptInterface::luaCombatSetArea);
registerMethod("Combat", "setCondition", LuaScriptInterface::luaCombatSetCondition);
registerMethod("Combat", "setCallback", LuaScriptInterface::luaCombatSetCallback);
+ registerMethod("Combat", "setOrigin", LuaScriptInterface::luaCombatSetOrigin);
registerMethod("Combat", "execute", LuaScriptInterface::luaCombatExecute);
@@ -2794,7 +2853,7 @@ int LuaScriptInterface::luaCreateCombatArea(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);
if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2812,6 +2871,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
params.impactEffect = getNumber(L, 7);
CombatDamage damage;
+ damage.origin = getNumber(L, 8, ORIGIN_SPELL);
damage.type = combatType;
damage.value = normal_random(getNumber(L, 6), getNumber(L, 5));
@@ -2826,7 +2886,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(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);
if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2848,6 +2908,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
params.impactEffect = getNumber(L, 6);
CombatDamage damage;
+ damage.origin = getNumber(L, 7, ORIGIN_SPELL);
damage.type = combatType;
damage.value = normal_random(getNumber(L, 4), getNumber(L, 5));
@@ -2858,7 +2919,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(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);
if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2873,6 +2934,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
params.impactEffect = getNumber(L, 6);
CombatDamage damage;
+ damage.origin = getNumber(L, 7, ORIGIN_SPELL);
damage.type = COMBAT_MANADRAIN;
damage.value = normal_random(getNumber(L, 4), getNumber(L, 5));
@@ -2888,7 +2950,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(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);
if (!creature && (!isNumber(L, 1) || getNumber(L, 1) != 0)) {
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
@@ -2907,6 +2969,7 @@ int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
params.impactEffect = getNumber(L, 5);
CombatDamage damage;
+ damage.origin = getNumber(L, 6, ORIGIN_SPELL);
damage.type = COMBAT_MANADRAIN;
damage.value = normal_random(getNumber(L, 3), getNumber(L, 4));
@@ -4144,6 +4207,25 @@ int LuaScriptInterface::luaGameStartRaid(lua_State* L)
return 1;
}
+int LuaScriptInterface::luaGameReload(lua_State* L)
+{
+ // Game.reload(reloadType)
+ ReloadTypes_t reloadType = getNumber(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
int LuaScriptInterface::luaVariantCreate(lua_State* L)
{
@@ -6575,50 +6657,6 @@ int LuaScriptInterface::luaCreatureSetMaxHealth(lua_State* L)
return 1;
}
-int LuaScriptInterface::luaCreatureGetMana(lua_State* L)
-{
- // creature:getMana()
- const Creature* creature = getUserdata(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(L, 1);
- if (!creature) {
- lua_pushnil(L);
- return 1;
- }
-
- int32_t manaChange = getNumber(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(L, 1);
- if (creature) {
- lua_pushnumber(L, creature->getMaxMana());
- } else {
- lua_pushnil(L);
- }
- return 1;
-}
-
int LuaScriptInterface::luaCreatureGetSkull(lua_State* L)
{
// creature:getSkull()
@@ -7191,15 +7229,15 @@ int LuaScriptInterface::luaPlayerGetExperience(lua_State* L)
int LuaScriptInterface::luaPlayerAddExperience(lua_State* L)
{
- // player:addExperience(experience[, sendText = false[, applyStages = true])
+ // player:addExperience(experience[, sendText = false])
Player* player = getUserdata(L, 1);
if (player) {
int64_t experience = getNumber(L, 2);
bool sendText = getBoolean(L, 3, false);
- bool applyStages = getBoolean(L, 4, true);
- player->addExperience(experience, sendText, applyStages);
+ player->addExperience(nullptr, experience, sendText);
pushBoolean(L, true);
- } else {
+ }
+ else {
lua_pushnil(L);
}
return 1;
@@ -7255,6 +7293,56 @@ int LuaScriptInterface::luaPlayerGetBaseMagicLevel(lua_State* L)
return 1;
}
+int LuaScriptInterface::luaPlayerGetMana(lua_State* L)
+{
+ // player:getMana()
+ const Player* player = getUserdata(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(L, 1);
+ if (!player) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ int32_t manaChange = getNumber