mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-04-29 17:19:20 +02:00
introduce changes from streamside fork
This commit is contained in:
parent
f2cbc2dc1c
commit
ad03b0eb3e
@ -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
|
||||
|
@ -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.",
|
||||
|
@ -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)
|
||||
|
28
data/events/events.xml
Normal file
28
data/events/events.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<events>
|
||||
<!-- Creature methods -->
|
||||
<event class="Creature" method="onChangeOutfit" enabled="0" />
|
||||
<event class="Creature" method="onAreaCombat" enabled="0" />
|
||||
<event class="Creature" method="onTargetCombat" enabled="0" />
|
||||
|
||||
<!-- Party methods -->
|
||||
<event class="Party" method="onJoin" enabled="0" />
|
||||
<event class="Party" method="onLeave" enabled="0" />
|
||||
<event class="Party" method="onDisband" enabled="0" />
|
||||
<event class="Party" method="onShareExperience" enabled="1" />
|
||||
|
||||
<!-- Player methods -->
|
||||
<event class="Player" method="onLook" enabled="1" />
|
||||
<event class="Player" method="onLookInBattleList" enabled="1" />
|
||||
<event class="Player" method="onLookInTrade" enabled="1" />
|
||||
<event class="Player" method="onMoveItem" enabled="1" />
|
||||
<event class="Player" method="onItemMoved" enabled="0" />
|
||||
<event class="Player" method="onMoveCreature" enabled="0" />
|
||||
<event class="Player" method="onReportBug" enabled="1" />
|
||||
<event class="Player" method="onTurn" enabled="0" />
|
||||
<event class="Player" method="onTradeRequest" enabled="0" />
|
||||
<event class="Player" method="onTradeAccept" enabled="0" />
|
||||
<event class="Player" method="onGainExperience" enabled="1" />
|
||||
<event class="Player" method="onLoseExperience" enabled="0" />
|
||||
<event class="Player" method="onGainSkillTries" enabled="1" />
|
||||
</events>
|
11
data/events/scripts/creature.lua
Normal file
11
data/events/scripts/creature.lua
Normal file
@ -0,0 +1,11 @@
|
||||
function Creature:onChangeOutfit(outfit)
|
||||
return true
|
||||
end
|
||||
|
||||
function Creature:onAreaCombat(tile, isAggressive)
|
||||
return RETURNVALUE_NOERROR
|
||||
end
|
||||
|
||||
function Creature:onTargetCombat(target)
|
||||
return RETURNVALUE_NOERROR
|
||||
end
|
35
data/events/scripts/party.lua
Normal file
35
data/events/scripts/party.lua
Normal file
@ -0,0 +1,35 @@
|
||||
function Party:onJoin(player)
|
||||
return true
|
||||
end
|
||||
|
||||
function Party:onLeave(player)
|
||||
return true
|
||||
end
|
||||
|
||||
function Party:onDisband()
|
||||
return true
|
||||
end
|
||||
|
||||
function Party:onShareExperience(exp)
|
||||
local sharedExperienceMultiplier = 1.20 --20%
|
||||
local vocationsIds = {}
|
||||
|
||||
local vocationId = self:getLeader():getVocation():getBase():getId()
|
||||
if vocationId ~= VOCATION_NONE then
|
||||
table.insert(vocationsIds, vocationId)
|
||||
end
|
||||
|
||||
for _, member in ipairs(self:getMembers()) do
|
||||
vocationId = member:getVocation():getBase():getId()
|
||||
if not table.contains(vocationsIds, vocationId) and vocationId ~= VOCATION_NONE then
|
||||
table.insert(vocationsIds, vocationId)
|
||||
end
|
||||
end
|
||||
|
||||
local size = #vocationsIds
|
||||
if size > 1 then
|
||||
sharedExperienceMultiplier = 1.0 + ((size * (5 * (size - 1) + 10)) / 100)
|
||||
end
|
||||
|
||||
return (exp * sharedExperienceMultiplier) / (#self:getMembers() + 1)
|
||||
end
|
169
data/events/scripts/player.lua
Normal file
169
data/events/scripts/player.lua
Normal file
@ -0,0 +1,169 @@
|
||||
function Player:onLook(thing, position, distance)
|
||||
local description = "You see " .. thing:getDescription(distance)
|
||||
if self:getGroup():getAccess() then
|
||||
if thing:isItem() then
|
||||
description = string.format("%s\nItem ID: %d", description, thing:getId())
|
||||
|
||||
local actionId = thing:getActionId()
|
||||
if actionId ~= 0 then
|
||||
description = string.format("%s, Action ID: %d", description, actionId)
|
||||
end
|
||||
|
||||
local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_MOVEMENTID)
|
||||
if uniqueId > 0 and uniqueId < 65536 then
|
||||
description = string.format("%s, Movement ID: %d", description, uniqueId)
|
||||
end
|
||||
|
||||
local itemType = thing:getType()
|
||||
|
||||
local transformEquipId = itemType:getTransformEquipId()
|
||||
local transformDeEquipId = itemType:getTransformDeEquipId()
|
||||
if transformEquipId ~= 0 then
|
||||
description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
|
||||
elseif transformDeEquipId ~= 0 then
|
||||
description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
|
||||
end
|
||||
|
||||
local decayId = itemType:getDecayId()
|
||||
if decayId ~= -1 then
|
||||
description = string.format("%s\nDecays to: %d", description, decayId)
|
||||
end
|
||||
if thing:getAttribute(ITEM_ATTRIBUTE_DECAYSTATE) == 1 then
|
||||
description = string.format("%s\nDecaying in %d minutes (%d seconds).", description, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000 / 60, thing:getAttribute(ITEM_ATTRIBUTE_DURATION) / 1000)
|
||||
end
|
||||
elseif thing:isCreature() then
|
||||
local str = "%s\nHealth: %d / %d"
|
||||
if thing:isPlayer() and thing:getMaxMana() > 0 then
|
||||
str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
|
||||
end
|
||||
description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
|
||||
end
|
||||
|
||||
local position = thing:getPosition()
|
||||
description = string.format(
|
||||
"%s\nPosition: %d, %d, %d",
|
||||
description, position.x, position.y, position.z
|
||||
)
|
||||
|
||||
if thing:isCreature() then
|
||||
if thing:isPlayer() then
|
||||
description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
|
||||
end
|
||||
end
|
||||
end
|
||||
self:sendTextMessage(MESSAGE_INFO_DESCR, description)
|
||||
end
|
||||
|
||||
function Player:onLookInBattleList(creature, distance)
|
||||
local description = "You see " .. creature:getDescription(distance)
|
||||
if self:getGroup():getAccess() then
|
||||
local str = "%s\nHealth: %d / %d"
|
||||
if creature:isPlayer() and creature:getMaxMana() > 0 then
|
||||
str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
|
||||
end
|
||||
description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
|
||||
|
||||
local position = creature:getPosition()
|
||||
description = string.format(
|
||||
"%s\nPosition: %d, %d, %d",
|
||||
description, position.x, position.y, position.z
|
||||
)
|
||||
|
||||
if creature:isPlayer() then
|
||||
description = string.format("%s\nIP: %s", description, Game.convertIpToString(creature:getIp()))
|
||||
end
|
||||
end
|
||||
self:sendTextMessage(MESSAGE_INFO_DESCR, description)
|
||||
end
|
||||
|
||||
function Player:onLookInTrade(partner, item, distance)
|
||||
self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
|
||||
end
|
||||
|
||||
function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||
return true
|
||||
end
|
||||
|
||||
function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||
end
|
||||
|
||||
function Player:onMoveCreature(creature, fromPosition, toPosition)
|
||||
return true
|
||||
end
|
||||
|
||||
function Player:onReportBug(message, position, category)
|
||||
if self:getAccountType() == ACCOUNT_TYPE_NORMAL then
|
||||
return false
|
||||
end
|
||||
|
||||
local name = self:getName()
|
||||
local file = io.open("data/reports/bugs/" .. name .. " report.txt", "a")
|
||||
|
||||
if not file then
|
||||
self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.")
|
||||
return true
|
||||
end
|
||||
|
||||
io.output(file)
|
||||
io.write("------------------------------\n")
|
||||
io.write("Name: " .. name)
|
||||
if category == BUG_CATEGORY_MAP then
|
||||
io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
|
||||
end
|
||||
local playerPosition = self:getPosition()
|
||||
io.write(" [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n")
|
||||
io.write("Comment: " .. message .. "\n")
|
||||
io.close(file)
|
||||
|
||||
self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".")
|
||||
return true
|
||||
end
|
||||
|
||||
function Player:onTurn(direction)
|
||||
return true
|
||||
end
|
||||
|
||||
function Player:onTradeRequest(target, item)
|
||||
return true
|
||||
end
|
||||
|
||||
function Player:onTradeAccept(target, item, targetItem)
|
||||
return true
|
||||
end
|
||||
|
||||
local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
|
||||
soulCondition:setTicks(4 * 60 * 1000)
|
||||
soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
|
||||
|
||||
function Player:onGainExperience(source, exp, rawExp)
|
||||
if not source or source:isPlayer() then
|
||||
return exp
|
||||
end
|
||||
|
||||
-- Soul regeneration
|
||||
local vocation = self:getVocation()
|
||||
if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
|
||||
soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
|
||||
self:addCondition(soulCondition)
|
||||
end
|
||||
|
||||
-- Apply experience stage multiplier
|
||||
exp = exp * Game.getExperienceStage(self:getLevel())
|
||||
|
||||
return exp
|
||||
end
|
||||
|
||||
function Player:onLoseExperience(exp)
|
||||
return exp
|
||||
end
|
||||
|
||||
function Player:onGainSkillTries(skill, tries)
|
||||
if APPLY_SKILL_MULTIPLIER == false then
|
||||
return tries
|
||||
end
|
||||
|
||||
if skill == SKILL_MAGLEVEL then
|
||||
return tries * configManager.getNumber(configKeys.RATE_MAGIC)
|
||||
end
|
||||
return tries * configManager.getNumber(configKeys.RATE_SKILL)
|
||||
end
|
@ -40,4 +40,8 @@ table.contains = function(array, value)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function isNumber(str)
|
||||
return tonumber(str) ~= nil
|
||||
end
|
@ -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')
|
@ -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
|
||||
|
||||
|
@ -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
|
7
data/lib/core/vocation.lua
Normal file
7
data/lib/core/vocation.lua
Normal file
@ -0,0 +1,7 @@
|
||||
function Vocation.getBase(self)
|
||||
local base = self
|
||||
while base:getDemotion() do
|
||||
base = base:getDemotion()
|
||||
end
|
||||
return base
|
||||
end
|
@ -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()
|
||||
|
65
data/talkactions/scripts/reload.lua
Normal file
65
data/talkactions/scripts/reload.lua
Normal file
@ -0,0 +1,65 @@
|
||||
local reloadTypes = {
|
||||
["all"] = { targetType = RELOAD_TYPE_ALL, name = "all" },
|
||||
|
||||
["action"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
|
||||
["actions"] = { targetType = RELOAD_TYPE_ACTIONS, name = "actions" },
|
||||
|
||||
["chat"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
|
||||
["channel"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
|
||||
["chatchannels"] = { targetType = RELOAD_TYPE_CHAT, name = "chatchannels" },
|
||||
|
||||
["config"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
|
||||
["configuration"] = { targetType = RELOAD_TYPE_CONFIG, name = "config" },
|
||||
|
||||
["creaturescript"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
|
||||
["creaturescripts"] = { targetType = RELOAD_TYPE_CREATURESCRIPTS, name = "creature scripts" },
|
||||
|
||||
["events"] = { targetType = RELOAD_TYPE_EVENTS, name = "events" },
|
||||
|
||||
["global"] = { targetType = RELOAD_TYPE_GLOBAL, name = "global.lua" },
|
||||
|
||||
["globalevent"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
|
||||
["globalevents"] = { targetType = RELOAD_TYPE_GLOBALEVENTS, name = "globalevents" },
|
||||
|
||||
["items"] = { targetType = RELOAD_TYPE_ITEMS, name = "items" },
|
||||
|
||||
["monster"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
|
||||
["monsters"] = { targetType = RELOAD_TYPE_MONSTERS, name = "monsters" },
|
||||
|
||||
["move"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
|
||||
["movement"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
|
||||
["movements"] = { targetType = RELOAD_TYPE_MOVEMENTS, name = "movements" },
|
||||
|
||||
["npc"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
||||
["npcs"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
||||
|
||||
["raid"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
||||
["raids"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
||||
|
||||
["spell"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
|
||||
["spells"] = { targetType = RELOAD_TYPE_SPELLS, name = "spells" },
|
||||
|
||||
["talk"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
|
||||
["talkaction"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" },
|
||||
["talkactions"] = { targetType = RELOAD_TYPE_TALKACTIONS, name = "talk actions" }
|
||||
}
|
||||
|
||||
function onSay(player, words, param)
|
||||
if not player:getGroup():getAccess() then
|
||||
return true
|
||||
end
|
||||
|
||||
if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
|
||||
return false
|
||||
end
|
||||
|
||||
local reloadType = reloadTypes[param and param:lower()]
|
||||
if not reloadType then
|
||||
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Reload type not found.")
|
||||
return false
|
||||
end
|
||||
|
||||
Game.reload(reloadType.targetType)
|
||||
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, string.format("Reloaded %s.", reloadType.name))
|
||||
return true
|
||||
end
|
23
data/talkactions/scripts/save.lua
Normal file
23
data/talkactions/scripts/save.lua
Normal file
@ -0,0 +1,23 @@
|
||||
function onSay(player, words, param)
|
||||
|
||||
local function timeSave(delay, msg)
|
||||
broadcastMessage(msg, MESSAGE_STATUS_WARNING)
|
||||
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, msg)
|
||||
addEvent(saveServer, delay)
|
||||
end
|
||||
|
||||
if not player:getGroup():getAccess() then
|
||||
return true
|
||||
end
|
||||
|
||||
if player:getAccountType() < ACCOUNT_TYPE_GOD then
|
||||
return false
|
||||
end
|
||||
|
||||
if isNumber(param) then
|
||||
local delay = tonumber(param) * 1000
|
||||
timeSave(delay, "Saving server in " .. tonumber(param) .. " seconds.")
|
||||
else
|
||||
saveServer()
|
||||
end
|
||||
end
|
19
data/talkactions/scripts/sellhouse.lua
Normal file
19
data/talkactions/scripts/sellhouse.lua
Normal file
@ -0,0 +1,19 @@
|
||||
function onSay(player, words, param)
|
||||
local tradePartner = Player(param)
|
||||
if not tradePartner or tradePartner == player then
|
||||
player:sendCancelMessage("Trade player not found.")
|
||||
return false
|
||||
end
|
||||
|
||||
local house = player:getTile():getHouse()
|
||||
if not house then
|
||||
player:sendCancelMessage("You must stand in your house to initiate the trade.")
|
||||
return false
|
||||
end
|
||||
|
||||
local returnValue = house:startTrade(player, tradePartner)
|
||||
if returnValue ~= RETURNVALUE_NOERROR then
|
||||
player:sendCancelMessage(returnValue)
|
||||
end
|
||||
return false
|
||||
end
|
@ -27,7 +27,9 @@
|
||||
<talkaction words="/removetutor" separator=" " script="remove_tutor.lua" />
|
||||
<talkaction words="/looktype" separator=" " script="looktype.lua" />
|
||||
<talkaction words="/summon" separator=" " script="place_summon.lua" />
|
||||
<talkaction words="/chameleon" separator=" " script="chameleon.lua" />
|
||||
<talkaction words="/reload" separator=" " script="reload.lua" />
|
||||
<talkaction words="/save" script="save.lua" />
|
||||
<talkaction words="/chameleon" separator=" " script="chameleon.lua" />
|
||||
<talkaction words="/addskill" separator=" " script="add_skill.lua" />
|
||||
<talkaction words="/mccheck" script="mccheck.lua" />
|
||||
<talkaction words="/ghost" script="ghost.lua" />
|
||||
@ -37,6 +39,7 @@
|
||||
<!-- player talkactions -->
|
||||
<talkaction words="!buypremium" script="buyprem.lua"/>
|
||||
<talkaction words="!buyhouse" script="buyhouse.lua"/>
|
||||
<talkaction words="!sellhouse" separator=" " script="sellhouse.lua" />
|
||||
<talkaction words="!leavehouse" script="leavehouse.lua"/>
|
||||
<talkaction words="!changesex" script="changesex.lua"/>
|
||||
<talkaction words="!uptime" script="uptime.lua"/>
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(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: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
213
src/combat.cpp
213
src/combat.cpp
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(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<ConditionDamage*>(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_POISON, 0, 0));
|
||||
@ -962,9 +965,9 @@ bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fight
|
||||
if (weapon->getWeaponType() == WEAPON_DISTANCE) {
|
||||
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<int32_t>(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<int32_t>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
23
src/combat.h
23
src/combat.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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", "");
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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 */
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
24
src/const.h
24
src/const.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -308,6 +308,28 @@ enum PlayerFlags : uint64_t {
|
||||
PlayerFlag_SpecialMoveUse = static_cast<uint64_t>(1) << 38,
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(capacity())) {
|
||||
}
|
||||
else if (index >= static_cast<int32_t>(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<Cylinder*>(*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<Cylinder*>(*destItem);
|
||||
if (subCylinder) {
|
||||
index = INDEX_WHEREEVER;
|
||||
*destItem = nullptr;
|
||||
return subCylinder;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(manaChange, getMaxMana() - mana);
|
||||
} else {
|
||||
mana = std::max<int32_t>(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 */)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(L, -4));
|
||||
damage.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
|
||||
damage.min = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -2));
|
||||
damage.max = LuaScriptInterface::getNumber<CombatType_t>(L, -1);
|
||||
|
||||
lua_pop(L, 4);
|
||||
if (damage.type != COMBAT_HEALING) {
|
||||
damage.value = -damage.value;
|
||||
}
|
||||
}
|
||||
|
||||
scriptInterface->resetScriptEnv();
|
||||
}
|
||||
|
||||
void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage) {
|
||||
//onManaChange(creature, attacker, value, type, min, max, origin)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeManaChange] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
|
||||
LuaScriptInterface::pushUserdata(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
if (attacker) {
|
||||
LuaScriptInterface::pushUserdata(L, attacker);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
LuaScriptInterface::pushCombatDamage(L, damage);
|
||||
|
||||
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
damage = LuaScriptInterface::getCombatDamage(L);
|
||||
}
|
||||
|
||||
scriptInterface->resetScriptEnv();
|
||||
}
|
||||
|
||||
void CreatureEvent::executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer)
|
||||
{
|
||||
//onExtendedOpcode(player, opcode, buffer)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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);
|
||||
//
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
18
src/enums.h
18
src/enums.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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;
|
||||
|
827
src/events.cpp
Normal file
827
src/events.cpp
Normal file
@ -0,0 +1,827 @@
|
||||
/**
|
||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "otpch.h"
|
||||
|
||||
#include "events.h"
|
||||
#include "tools.h"
|
||||
#include "item.h"
|
||||
#include "player.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
Events::Events() :
|
||||
scriptInterface("Event Interface")
|
||||
{
|
||||
clear();
|
||||
scriptInterface.initState();
|
||||
}
|
||||
|
||||
void Events::clear()
|
||||
{
|
||||
// Creature
|
||||
creatureOnChangeOutfit = -1;
|
||||
creatureOnAreaCombat = -1;
|
||||
creatureOnTargetCombat = -1;
|
||||
|
||||
// Party
|
||||
partyOnJoin = -1;
|
||||
partyOnLeave = -1;
|
||||
partyOnDisband = -1;
|
||||
|
||||
// Player
|
||||
playerOnLook = -1;
|
||||
playerOnLookInBattleList = -1;
|
||||
playerOnLookInTrade = -1;
|
||||
playerOnMoveItem = -1;
|
||||
playerOnItemMoved = -1;
|
||||
playerOnMoveCreature = -1;
|
||||
playerOnTurn = -1;
|
||||
playerOnTradeRequest = -1;
|
||||
playerOnTradeAccept = -1;
|
||||
playerOnGainExperience = -1;
|
||||
playerOnLoseExperience = -1;
|
||||
playerOnGainSkillTries = -1;
|
||||
playerOnReportBug = -1;
|
||||
|
||||
}
|
||||
|
||||
bool Events::load()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file("data/events/events.xml");
|
||||
if (!result) {
|
||||
printXMLError("Error - Events::load", "data/events/events.xml", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<std::string> classes;
|
||||
for (auto eventNode : doc.child("events").children()) {
|
||||
if (!eventNode.attribute("enabled").as_bool()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& className = eventNode.attribute("class").as_string();
|
||||
auto res = classes.insert(className);
|
||||
if (res.second) {
|
||||
const std::string& lowercase = asLowerCaseString(className);
|
||||
if (scriptInterface.loadFile("data/events/scripts/" + lowercase + ".lua") != 0) {
|
||||
std::cout << "[Warning - Events::load] Can not load script: " << lowercase << ".lua" << std::endl;
|
||||
std::cout << scriptInterface.getLastLuaError() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& methodName = eventNode.attribute("method").as_string();
|
||||
const int32_t event = scriptInterface.getMetaEvent(className, methodName);
|
||||
if (className == "Creature") {
|
||||
if (methodName == "onChangeOutfit") {
|
||||
creatureOnChangeOutfit = event;
|
||||
}
|
||||
else if (methodName == "onAreaCombat") {
|
||||
creatureOnAreaCombat = event;
|
||||
}
|
||||
else if (methodName == "onTargetCombat") {
|
||||
creatureOnTargetCombat = event;
|
||||
}
|
||||
else {
|
||||
std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
|
||||
}
|
||||
}
|
||||
else if (className == "Party") {
|
||||
if (methodName == "onJoin") {
|
||||
partyOnJoin = event;
|
||||
}
|
||||
else if (methodName == "onLeave") {
|
||||
partyOnLeave = event;
|
||||
}
|
||||
else if (methodName == "onDisband") {
|
||||
partyOnDisband = event;
|
||||
}
|
||||
else if (methodName == "onShareExperience") {
|
||||
partyOnShareExperience = event;
|
||||
}
|
||||
else {
|
||||
std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
|
||||
}
|
||||
}
|
||||
else if (className == "Player") {
|
||||
if (methodName == "onLook") {
|
||||
playerOnLook = event;
|
||||
}
|
||||
else if (methodName == "onLookInBattleList") {
|
||||
playerOnLookInBattleList = event;
|
||||
}
|
||||
else if (methodName == "onLookInTrade") {
|
||||
playerOnLookInTrade = event;
|
||||
}
|
||||
else if (methodName == "onTradeRequest") {
|
||||
playerOnTradeRequest = event;
|
||||
}
|
||||
else if (methodName == "onTradeAccept") {
|
||||
playerOnTradeAccept = event;
|
||||
}
|
||||
else if (methodName == "onMoveItem") {
|
||||
playerOnMoveItem = event;
|
||||
}
|
||||
else if (methodName == "onItemMoved") {
|
||||
playerOnItemMoved = event;
|
||||
}
|
||||
else if (methodName == "onMoveCreature") {
|
||||
playerOnMoveCreature = event;
|
||||
}
|
||||
else if (methodName == "onReportBug") {
|
||||
playerOnReportBug = event;
|
||||
}
|
||||
else if (methodName == "onTurn") {
|
||||
playerOnTurn = event;
|
||||
}
|
||||
else if (methodName == "onGainExperience") {
|
||||
playerOnGainExperience = event;
|
||||
}
|
||||
else if (methodName == "onLoseExperience") {
|
||||
playerOnLoseExperience = event;
|
||||
}
|
||||
else if (methodName == "onGainSkillTries") {
|
||||
playerOnGainSkillTries = event;
|
||||
}
|
||||
else {
|
||||
std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creature
|
||||
bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
|
||||
{
|
||||
// Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
|
||||
if (creatureOnChangeOutfit == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventCreatureOnChangeOutfit] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(creatureOnChangeOutfit, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(creatureOnChangeOutfit);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
|
||||
LuaScriptInterface::pushOutfit(L, outfit);
|
||||
|
||||
return scriptInterface.callFunction(2);
|
||||
}
|
||||
|
||||
ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
|
||||
{
|
||||
// Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
|
||||
if (creatureOnAreaCombat == -1) {
|
||||
return RETURNVALUE_NOERROR;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventCreatureOnAreaCombat] Call stack overflow" << std::endl;
|
||||
return RETURNVALUE_NOTPOSSIBLE;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(creatureOnAreaCombat, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(creatureOnAreaCombat);
|
||||
|
||||
if (creature) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
LuaScriptInterface::pushUserdata<Tile>(L, tile);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Tile");
|
||||
|
||||
LuaScriptInterface::pushBoolean(L, aggressive);
|
||||
|
||||
ReturnValue returnValue;
|
||||
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
||||
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
|
||||
{
|
||||
// Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
|
||||
if (creatureOnTargetCombat == -1) {
|
||||
return RETURNVALUE_NOERROR;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventCreatureOnTargetCombat] Call stack overflow" << std::endl;
|
||||
return RETURNVALUE_NOTPOSSIBLE;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(creatureOnTargetCombat, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(creatureOnTargetCombat);
|
||||
|
||||
if (creature) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, target);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, target);
|
||||
|
||||
ReturnValue returnValue;
|
||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
// Party
|
||||
bool Events::eventPartyOnJoin(Party* party, Player* player)
|
||||
{
|
||||
// Party:onJoin(player) or Party.onJoin(self, player)
|
||||
if (partyOnJoin == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPartyOnJoin] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(partyOnJoin, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(partyOnJoin);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
return scriptInterface.callFunction(2);
|
||||
}
|
||||
|
||||
bool Events::eventPartyOnLeave(Party* party, Player* player)
|
||||
{
|
||||
// Party:onLeave(player) or Party.onLeave(self, player)
|
||||
if (partyOnLeave == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPartyOnLeave] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(partyOnLeave, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(partyOnLeave);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
return scriptInterface.callFunction(2);
|
||||
}
|
||||
|
||||
bool Events::eventPartyOnDisband(Party* party)
|
||||
{
|
||||
// Party:onDisband() or Party.onDisband(self)
|
||||
if (partyOnDisband == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPartyOnDisband] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(partyOnDisband, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(partyOnDisband);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||
|
||||
return scriptInterface.callFunction(1);
|
||||
}
|
||||
|
||||
void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
||||
{
|
||||
// Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
|
||||
if (partyOnShareExperience == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPartyOnShareExperience] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(partyOnShareExperience, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(partyOnShareExperience);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||
|
||||
lua_pushnumber(L, exp);
|
||||
|
||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
|
||||
{
|
||||
// Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
|
||||
if (playerOnLook == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnLook] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnLook, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnLook);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
if (Creature* creature = thing->getCreature()) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
}
|
||||
else if (Item* item = thing->getItem()) {
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
LuaScriptInterface::pushPosition(L, position, stackpos);
|
||||
lua_pushnumber(L, lookDistance);
|
||||
|
||||
scriptInterface.callVoidFunction(4);
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
|
||||
{
|
||||
// Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
|
||||
if (playerOnLookInBattleList == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnLookInBattleList] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnLookInBattleList, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnLookInBattleList);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
|
||||
lua_pushnumber(L, lookDistance);
|
||||
|
||||
scriptInterface.callVoidFunction(3);
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
|
||||
{
|
||||
// Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
|
||||
if (playerOnLookInTrade == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnLookInTrade] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnLookInTrade, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnLookInTrade);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, partner);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
|
||||
lua_pushnumber(L, lookDistance);
|
||||
|
||||
scriptInterface.callVoidFunction(4);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
||||
{
|
||||
// Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||
if (playerOnMoveItem == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnMoveItem] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnMoveItem, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnMoveItem);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
|
||||
lua_pushnumber(L, count);
|
||||
LuaScriptInterface::pushPosition(L, fromPosition);
|
||||
LuaScriptInterface::pushPosition(L, toPosition);
|
||||
|
||||
LuaScriptInterface::pushCylinder(L, fromCylinder);
|
||||
LuaScriptInterface::pushCylinder(L, toCylinder);
|
||||
|
||||
return scriptInterface.callFunction(7);
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
||||
{
|
||||
// Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||
if (playerOnItemMoved == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnItemMoved] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnItemMoved, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnItemMoved);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
|
||||
lua_pushnumber(L, count);
|
||||
LuaScriptInterface::pushPosition(L, fromPosition);
|
||||
LuaScriptInterface::pushPosition(L, toPosition);
|
||||
|
||||
LuaScriptInterface::pushCylinder(L, fromCylinder);
|
||||
LuaScriptInterface::pushCylinder(L, toCylinder);
|
||||
|
||||
scriptInterface.callVoidFunction(7);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
|
||||
{
|
||||
// Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
|
||||
if (playerOnMoveCreature == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnMoveCreature] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnMoveCreature, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnMoveCreature);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
|
||||
LuaScriptInterface::pushPosition(L, fromPosition);
|
||||
LuaScriptInterface::pushPosition(L, toPosition);
|
||||
|
||||
return scriptInterface.callFunction(4);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position)
|
||||
{
|
||||
// Player:onReportBug(message, position, category)
|
||||
if (playerOnReportBug == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnReportBug] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnReportBug, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnReportBug);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushString(L, message);
|
||||
LuaScriptInterface::pushPosition(L, position);
|
||||
|
||||
return scriptInterface.callFunction(3);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnTurn(Player* player, Direction direction)
|
||||
{
|
||||
// Player:onTurn(direction) or Player.onTurn(self, direction)
|
||||
if (playerOnTurn == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnTurn] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnTurn, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnTurn);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
lua_pushnumber(L, direction);
|
||||
|
||||
return scriptInterface.callFunction(2);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
|
||||
{
|
||||
// Player:onTradeRequest(target, item)
|
||||
if (playerOnTradeRequest == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnTradeRequest] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnTradeRequest, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnTradeRequest);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, target);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
|
||||
return scriptInterface.callFunction(3);
|
||||
}
|
||||
|
||||
bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
|
||||
{
|
||||
// Player:onTradeAccept(target, item, targetItem)
|
||||
if (playerOnTradeAccept == -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnTradeAccept] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnTradeAccept, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnTradeAccept);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, target);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Item>(L, targetItem);
|
||||
LuaScriptInterface::setItemMetatable(L, -1, targetItem);
|
||||
|
||||
return scriptInterface.callFunction(4);
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp)
|
||||
{
|
||||
// Player:onGainExperience(source, exp, rawExp)
|
||||
// rawExp gives the original exp which is not multiplied
|
||||
if (playerOnGainExperience == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnGainExperience] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnGainExperience, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnGainExperience);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
if (source) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, source);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, source);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
lua_pushnumber(L, exp);
|
||||
lua_pushnumber(L, rawExp);
|
||||
|
||||
if (scriptInterface.protectedCall(L, 4, 1) != 0) {
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
||||
{
|
||||
// Player:onLoseExperience(exp)
|
||||
if (playerOnLoseExperience == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnLoseExperience] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnLoseExperience, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnLoseExperience);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
lua_pushnumber(L, exp);
|
||||
|
||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
}
|
||||
|
||||
void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
|
||||
{
|
||||
// Player:onGainSkillTries(skill, tries)
|
||||
if (playerOnGainSkillTries == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scriptInterface.reserveScriptEnv()) {
|
||||
std::cout << "[Error - Events::eventPlayerOnGainSkillTries] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||
env->setScriptId(playerOnGainSkillTries, &scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface.getLuaState();
|
||||
scriptInterface.pushFunction(playerOnGainSkillTries);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
lua_pushnumber(L, skill);
|
||||
lua_pushnumber(L, tries);
|
||||
|
||||
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||
}
|
||||
else {
|
||||
tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
scriptInterface.resetScriptEnv();
|
||||
}
|
95
src/events.h
Normal file
95
src/events.h
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
|
||||
#define FS_EVENTS_H_BD444CC0EE167E5777E4C90C766B36DC
|
||||
|
||||
#include "luascript.h"
|
||||
|
||||
class Party;
|
||||
class ItemType;
|
||||
class Tile;
|
||||
|
||||
class Events
|
||||
{
|
||||
public:
|
||||
Events();
|
||||
|
||||
void clear();
|
||||
bool load();
|
||||
|
||||
// Creature
|
||||
bool eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit);
|
||||
ReturnValue eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive);
|
||||
ReturnValue eventCreatureOnTargetCombat(Creature* creature, Creature* target);
|
||||
|
||||
// Party
|
||||
bool eventPartyOnJoin(Party* party, Player* player);
|
||||
bool eventPartyOnLeave(Party* party, Player* player);
|
||||
bool eventPartyOnDisband(Party* party);
|
||||
void eventPartyOnShareExperience(Party* party, uint64_t& exp);
|
||||
|
||||
// Player
|
||||
void eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance);
|
||||
void eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance);
|
||||
void eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance);
|
||||
bool eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
||||
void eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
||||
bool eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition);
|
||||
void eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
|
||||
bool eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position);
|
||||
bool eventPlayerOnTurn(Player* player, Direction direction);
|
||||
bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
|
||||
bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
|
||||
void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
|
||||
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
|
||||
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
|
||||
|
||||
private:
|
||||
LuaScriptInterface scriptInterface;
|
||||
|
||||
// Creature
|
||||
int32_t creatureOnChangeOutfit;
|
||||
int32_t creatureOnAreaCombat;
|
||||
int32_t creatureOnTargetCombat;
|
||||
|
||||
// Party
|
||||
int32_t partyOnJoin;
|
||||
int32_t partyOnLeave;
|
||||
int32_t partyOnDisband;
|
||||
int32_t partyOnShareExperience;
|
||||
|
||||
// Player
|
||||
int32_t playerOnLook;
|
||||
int32_t playerOnLookInBattleList;
|
||||
int32_t playerOnLookInTrade;
|
||||
int32_t playerOnMoveItem;
|
||||
int32_t playerOnItemMoved;
|
||||
int32_t playerOnMoveCreature;
|
||||
int32_t playerOnReportRuleViolation;
|
||||
int32_t playerOnReportBug;
|
||||
int32_t playerOnTurn;
|
||||
int32_t playerOnTradeRequest;
|
||||
int32_t playerOnTradeAccept;
|
||||
int32_t playerOnGainExperience;
|
||||
int32_t playerOnLoseExperience;
|
||||
int32_t playerOnGainSkillTries;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
396
src/game.cpp
396
src/game.cpp
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<Direction> listDir;
|
||||
@ -705,6 +715,10 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_events->eventPlayerOnMoveCreature(player, movingCreature, movingCreaturePos, toPos)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReturnValue ret = internalMoveCreature(*movingCreature, *toTile);
|
||||
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<int32_t>(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<int32_t>(target->getMana(), healthChange);
|
||||
int32_t manaDamage = std::min<int32_t>(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<int32_t>(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<int32_t>(target->getMana(), -manaChange);
|
||||
int32_t manaLoss = std::min<int32_t>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
src/game.h
13
src/game.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<Creature*> ToReleaseCreatures;
|
||||
std::vector<Item*> ToReleaseItems;
|
||||
std::vector<char> commandTags;
|
||||
|
||||
size_t lastBucket = 0;
|
||||
|
||||
@ -532,8 +527,6 @@ class Game
|
||||
|
||||
std::map<uint32_t, BedItem*> 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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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;
|
||||
}
|
||||
|
10
src/house.h
10
src/house.h
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -21,6 +21,7 @@
|
||||
#define FS_HOUSE_H_EB9732E7771A438F9CD0EFA8CB4C58C4
|
||||
|
||||
#include <regex>
|
||||
#include <set>
|
||||
|
||||
#include "container.h"
|
||||
#include "housetile.h"
|
||||
@ -212,10 +213,11 @@ class House
|
||||
return houseTiles;
|
||||
}
|
||||
|
||||
const std::list<Door*>& getDoors() const {
|
||||
return doorList;
|
||||
const std::set<Door*>& 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<Door*> doorList;
|
||||
std::set<Door*> doorSet;
|
||||
HouseBedItemList bedsList;
|
||||
|
||||
std::string houseName;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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<int32_t>(L, -4);
|
||||
damage.type = getNumber<CombatType_t>(L, -3);
|
||||
damage.min = getNumber<int32_t>(L, -2);
|
||||
damage.max = getNumber<CombatType_t>(L, -1);
|
||||
|
||||
lua_pop(L, 4);
|
||||
return damage;
|
||||
}
|
||||
|
||||
std::string LuaScriptInterface::getString(lua_State* L, int32_t arg)
|
||||
{
|
||||
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<uint32_t>(L, 1) != 0)) {
|
||||
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
|
||||
@ -2812,6 +2871,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
|
||||
params.impactEffect = getNumber<uint8_t>(L, 7);
|
||||
|
||||
CombatDamage damage;
|
||||
damage.origin = getNumber<CombatOrigin>(L, 8, ORIGIN_SPELL);
|
||||
damage.type = combatType;
|
||||
damage.value = normal_random(getNumber<int32_t>(L, 6), getNumber<int32_t>(L, 5));
|
||||
|
||||
@ -2826,7 +2886,7 @@ int LuaScriptInterface::luaDoAreaCombatHealth(lua_State* L)
|
||||
|
||||
int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
|
||||
{
|
||||
//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<uint32_t>(L, 1) != 0)) {
|
||||
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
|
||||
@ -2848,6 +2908,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
|
||||
params.impactEffect = getNumber<uint8_t>(L, 6);
|
||||
|
||||
CombatDamage damage;
|
||||
damage.origin = getNumber<CombatOrigin>(L, 7, ORIGIN_SPELL);
|
||||
damage.type = combatType;
|
||||
damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5));
|
||||
|
||||
@ -2858,7 +2919,7 @@ int LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
|
||||
|
||||
int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
|
||||
{
|
||||
//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<uint32_t>(L, 1) != 0)) {
|
||||
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
|
||||
@ -2873,6 +2934,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
|
||||
params.impactEffect = getNumber<uint8_t>(L, 6);
|
||||
|
||||
CombatDamage damage;
|
||||
damage.origin = getNumber<CombatOrigin>(L, 7, ORIGIN_SPELL);
|
||||
damage.type = COMBAT_MANADRAIN;
|
||||
damage.value = normal_random(getNumber<int32_t>(L, 4), getNumber<int32_t>(L, 5));
|
||||
|
||||
@ -2888,7 +2950,7 @@ int LuaScriptInterface::luaDoAreaCombatMana(lua_State* L)
|
||||
|
||||
int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
|
||||
{
|
||||
//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<uint32_t>(L, 1) != 0)) {
|
||||
reportErrorFunc(getErrorDesc(LUA_ERROR_CREATURE_NOT_FOUND));
|
||||
@ -2907,6 +2969,7 @@ int LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
|
||||
params.impactEffect = getNumber<uint8_t>(L, 5);
|
||||
|
||||
CombatDamage damage;
|
||||
damage.origin = getNumber<CombatOrigin>(L, 6, ORIGIN_SPELL);
|
||||
damage.type = COMBAT_MANADRAIN;
|
||||
damage.value = normal_random(getNumber<int32_t>(L, 3), getNumber<int32_t>(L, 4));
|
||||
|
||||
@ -4144,6 +4207,25 @@ int LuaScriptInterface::luaGameStartRaid(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaGameReload(lua_State* L)
|
||||
{
|
||||
// Game.reload(reloadType)
|
||||
ReloadTypes_t reloadType = getNumber<ReloadTypes_t>(L, 1);
|
||||
if (!reloadType) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (reloadType == RELOAD_TYPE_GLOBAL) {
|
||||
pushBoolean(L, g_luaEnvironment.loadFile("data/global.lua") == 0);
|
||||
}
|
||||
else {
|
||||
pushBoolean(L, g_game.reload(reloadType));
|
||||
}
|
||||
lua_gc(g_luaEnvironment.getLuaState(), LUA_GCCOLLECT, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Variant
|
||||
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<const Creature>(L, 1);
|
||||
if (creature) {
|
||||
lua_pushnumber(L, creature->getMana());
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaCreatureAddMana(lua_State* L)
|
||||
{
|
||||
// creature:addMana(manaChange[, animationOnLoss = false])
|
||||
Creature* creature = getUserdata<Creature>(L, 1);
|
||||
if (!creature) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t manaChange = getNumber<int32_t>(L, 2);
|
||||
bool animationOnLoss = getBoolean(L, 3, false);
|
||||
if (!animationOnLoss && manaChange < 0) {
|
||||
creature->changeMana(manaChange);
|
||||
} else {
|
||||
g_game.combatChangeMana(nullptr, creature, manaChange);
|
||||
}
|
||||
pushBoolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaCreatureGetMaxMana(lua_State* L)
|
||||
{
|
||||
// creature:getMaxMana()
|
||||
const Creature* creature = getUserdata<const Creature>(L, 1);
|
||||
if (creature) {
|
||||
lua_pushnumber(L, creature->getMaxMana());
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaCreatureGetSkull(lua_State* L)
|
||||
{
|
||||
// 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<Player>(L, 1);
|
||||
if (player) {
|
||||
int64_t experience = getNumber<int64_t>(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<const Player>(L, 1);
|
||||
if (player) {
|
||||
lua_pushnumber(L, player->getMana());
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerAddMana(lua_State* L)
|
||||
{
|
||||
// player:addMana(manaChange[, animationOnLoss = false])
|
||||
Player* player = getUserdata<Player>(L, 1);
|
||||
if (!player) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t manaChange = getNumber<int32_t>(L, 2);
|
||||
bool animationOnLoss = getBoolean(L, 3, false);
|
||||
if (!animationOnLoss && manaChange < 0) {
|
||||
player->changeMana(manaChange);
|
||||
}
|
||||
else {
|
||||
CombatDamage damage;
|
||||
damage.value = manaChange;
|
||||
damage.origin = ORIGIN_NONE;
|
||||
g_game.combatChangeMana(nullptr, player, damage);
|
||||
}
|
||||
pushBoolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerGetMaxMana(lua_State* L)
|
||||
{
|
||||
// player:getMaxMana()
|
||||
const Player* player = getUserdata<const Player>(L, 1);
|
||||
if (player) {
|
||||
lua_pushnumber(L, player->getMaxMana());
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerSetMaxMana(lua_State* L)
|
||||
{
|
||||
// player:setMaxMana(maxMana)
|
||||
@ -7723,12 +7811,20 @@ int LuaScriptInterface::luaPlayerSetBankBalance(lua_State* L)
|
||||
{
|
||||
// player:setBankBalance(bankBalance)
|
||||
Player* player = getUserdata<Player>(L, 1);
|
||||
if (player) {
|
||||
player->setBankBalance(getNumber<uint64_t>(L, 2));
|
||||
pushBoolean(L, true);
|
||||
} else {
|
||||
if (!player) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int64_t balance = getNumber<int64_t>(L, 2);
|
||||
if (balance < 0) {
|
||||
reportErrorFunc("Invalid bank balance value.");
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
player->setBankBalance(balance);
|
||||
pushBoolean(L, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -9473,6 +9569,53 @@ int LuaScriptInterface::luaHouseSetOwnerGuid(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaHouseStartTrade(lua_State* L)
|
||||
{
|
||||
// house:startTrade(player, tradePartner)
|
||||
House* house = getUserdata<House>(L, 1);
|
||||
Player* player = getUserdata<Player>(L, 2);
|
||||
Player* tradePartner = getUserdata<Player>(L, 3);
|
||||
|
||||
if (!player || !tradePartner || !house) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Position::areInRange<2, 2, 0>(tradePartner->getPosition(), player->getPosition())) {
|
||||
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERFARAWAY);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (house->getOwner() != player->getGUID()) {
|
||||
lua_pushnumber(L, RETURNVALUE_YOUDONTOWNTHISHOUSE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (g_game.map.houses.getHouseByPlayerId(tradePartner->getGUID())) {
|
||||
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (IOLoginData::hasBiddedOnHouse(tradePartner->getGUID())) {
|
||||
lua_pushnumber(L, RETURNVALUE_TRADEPLAYERHIGHESTBIDDER);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Item* transferItem = house->getTransferItem();
|
||||
if (!transferItem) {
|
||||
lua_pushnumber(L, RETURNVALUE_YOUCANNOTTRADETHISHOUSE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
transferItem->getParent()->setParent(player);
|
||||
if (!g_game.internalStartTrade(player, tradePartner, transferItem)) {
|
||||
house->resetTransferItem();
|
||||
}
|
||||
|
||||
lua_pushnumber(L, RETURNVALUE_NOERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaHouseGetBeds(lua_State* L)
|
||||
{
|
||||
// house:getBeds()
|
||||
@ -10225,6 +10368,20 @@ int LuaScriptInterface::luaCombatSetCallback(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaCombatSetOrigin(lua_State* L)
|
||||
{
|
||||
// combat:setOrigin(origin)
|
||||
Combat* combat = getUserdata<Combat>(L, 1);
|
||||
if (combat) {
|
||||
combat->setOrigin(getNumber<CombatOrigin>(L, 2));
|
||||
pushBoolean(L, true);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaCombatExecute(lua_State* L)
|
||||
{
|
||||
// combat:execute(creature, variant)
|
||||
@ -11222,7 +11379,7 @@ int LuaScriptInterface::luaPartyShareExperience(lua_State* L)
|
||||
uint64_t experience = getNumber<uint64_t>(L, 2);
|
||||
Party* party = getUserdata<Party>(L, 1);
|
||||
if (party) {
|
||||
party->shareExperience(experience);
|
||||
party->shareExperience(experience, nullptr);
|
||||
pushBoolean(L, true);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -320,6 +320,7 @@ class LuaScriptInterface
|
||||
}
|
||||
|
||||
static std::string getString(lua_State* L, int32_t arg);
|
||||
static CombatDamage getCombatDamage(lua_State* L);
|
||||
static Position getPosition(lua_State* L, int32_t arg, int32_t& stackpos);
|
||||
static Position getPosition(lua_State* L, int32_t arg);
|
||||
static Outfit_t getOutfit(lua_State* L, int32_t arg);
|
||||
@ -368,6 +369,7 @@ class LuaScriptInterface
|
||||
|
||||
// Push
|
||||
static void pushBoolean(lua_State* L, bool value);
|
||||
static void pushCombatDamage(lua_State* L, const CombatDamage& damage);
|
||||
static void pushPosition(lua_State* L, const Position& position, int32_t stackpos = 0);
|
||||
static void pushOutfit(lua_State* L, const Outfit_t& outfit);
|
||||
|
||||
@ -549,6 +551,8 @@ class LuaScriptInterface
|
||||
|
||||
static int luaGameStartRaid(lua_State* L);
|
||||
|
||||
static int luaGameReload(lua_State* L);
|
||||
|
||||
// Variant
|
||||
static int luaVariantCreate(lua_State* L);
|
||||
|
||||
@ -749,10 +753,6 @@ class LuaScriptInterface
|
||||
static int luaCreatureGetMaxHealth(lua_State* L);
|
||||
static int luaCreatureSetMaxHealth(lua_State* L);
|
||||
|
||||
static int luaCreatureGetMana(lua_State* L);
|
||||
static int luaCreatureAddMana(lua_State* L);
|
||||
static int luaCreatureGetMaxMana(lua_State* L);
|
||||
|
||||
static int luaCreatureGetSkull(lua_State* L);
|
||||
static int luaCreatureSetSkull(lua_State* L);
|
||||
|
||||
@ -809,6 +809,9 @@ class LuaScriptInterface
|
||||
|
||||
static int luaPlayerGetMagicLevel(lua_State* L);
|
||||
static int luaPlayerGetBaseMagicLevel(lua_State* L);
|
||||
static int luaPlayerGetMana(lua_State* L);
|
||||
static int luaPlayerAddMana(lua_State* L);
|
||||
static int luaPlayerGetMaxMana(lua_State* L);
|
||||
static int luaPlayerSetMaxMana(lua_State* L);
|
||||
static int luaPlayerGetManaSpent(lua_State* L);
|
||||
static int luaPlayerAddManaSpent(lua_State* L);
|
||||
@ -1011,6 +1014,7 @@ class LuaScriptInterface
|
||||
|
||||
static int luaHouseGetOwnerGuid(lua_State* L);
|
||||
static int luaHouseSetOwnerGuid(lua_State* L);
|
||||
static int luaHouseStartTrade(lua_State* L);
|
||||
|
||||
static int luaHouseGetBeds(lua_State* L);
|
||||
static int luaHouseGetBedCount(lua_State* L);
|
||||
@ -1082,6 +1086,7 @@ class LuaScriptInterface
|
||||
static int luaCombatSetArea(lua_State* L);
|
||||
static int luaCombatSetCondition(lua_State* L);
|
||||
static int luaCombatSetCallback(lua_State* L);
|
||||
static int luaCombatSetOrigin(lua_State* L);
|
||||
|
||||
static int luaCombatExecute(lua_State* L);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
111
src/monster.cpp
111
src/monster.cpp
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -744,23 +744,12 @@ void Monster::setIdle(bool idle)
|
||||
|
||||
void Monster::updateIdleStatus()
|
||||
{
|
||||
bool idle = true;
|
||||
bool idle = false;
|
||||
|
||||
if (!isSummon()) {
|
||||
if (!targetList.empty()) {
|
||||
// visible target
|
||||
idle = false;
|
||||
} else {
|
||||
for (Condition* condition : conditions) {
|
||||
if (condition->getType() >= CONDITION_ENERGY && condition->getType() <= CONDITION_ENERGY) {
|
||||
// monsters with aggressive conditions never become idle
|
||||
idle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (conditions.empty()) {
|
||||
if (!isSummon() && targetList.empty()) {
|
||||
idle = true;
|
||||
}
|
||||
} else {
|
||||
idle = false;
|
||||
}
|
||||
|
||||
setIdle(idle);
|
||||
@ -887,7 +876,7 @@ void Monster::doAttacking(uint32_t)
|
||||
|
||||
for (spellBlock_t& spellBlock : mType->info.attackSpells) {
|
||||
if (spellBlock.range != 0 && std::max<uint32_t>(Position::getDistanceX(myPos, targetPos), Position::getDistanceY(myPos, targetPos)) <= spellBlock.range) {
|
||||
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) {
|
||||
if (normal_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
|
||||
updateLookDirection();
|
||||
|
||||
minCombatValue = spellBlock.minCombatValue;
|
||||
@ -988,7 +977,7 @@ void Monster::onThinkTarget(uint32_t interval)
|
||||
void Monster::onThinkDefense(uint32_t)
|
||||
{
|
||||
for (const spellBlock_t& spellBlock : mType->info.defenseSpells) {
|
||||
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) {
|
||||
if (normal_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
|
||||
minCombatValue = spellBlock.minCombatValue;
|
||||
maxCombatValue = spellBlock.maxCombatValue;
|
||||
spellBlock.spell->castSpell(this, this);
|
||||
@ -1012,7 +1001,7 @@ void Monster::onThinkDefense(uint32_t)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uniform_random(0, summonBlock.chance) == 0 && (health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) {
|
||||
if (normal_random(0, summonBlock.chance) == 0 && (health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
|
||||
Monster* summon = Monster::createMonster(summonBlock.name);
|
||||
if (summon) {
|
||||
const Position& summonPos = getPosition();
|
||||
@ -1038,16 +1027,15 @@ void Monster::onThinkYell(uint32_t)
|
||||
}
|
||||
|
||||
int32_t randomResult = rand();
|
||||
if (randomResult == 50 * (randomResult / 50)) {
|
||||
if (!mType->info.voiceVector.empty()) {
|
||||
uint32_t index = uniform_random(0, mType->info.voiceVector.size() - 1);
|
||||
const voiceBlock_t& vb = mType->info.voiceVector[index];
|
||||
|
||||
if (vb.yellText) {
|
||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, vb.text, false);
|
||||
} else {
|
||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, vb.text, false);
|
||||
}
|
||||
if (rand() == 50 * (randomResult / 50)) {
|
||||
int32_t totalVoices = mType->info.voiceVector.size();
|
||||
const voiceBlock_t& voice = mType->info.voiceVector[rand() % totalVoices + 1];
|
||||
|
||||
if (voice.yellText) {
|
||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, voice.text, false);
|
||||
}
|
||||
else {
|
||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, voice.text, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1172,7 +1160,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
|
||||
if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) {
|
||||
if (OTSYS_TIME() >= nextDanceStepRound) {
|
||||
updateLookDirection();
|
||||
nextDanceStepRound = OTSYS_TIME() + 200 + getStepDuration();
|
||||
nextDanceStepRound = OTSYS_TIME() + getStepDuration();
|
||||
|
||||
//choose a random direction
|
||||
result = getRandomStep(getPosition(), direction);
|
||||
@ -1235,6 +1223,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
|
||||
egibleToDance = false;
|
||||
earliestWakeUpTime = OTSYS_TIME() + 1000;
|
||||
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
|
||||
earliestAttackTime += 200;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1276,6 +1265,7 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
|
||||
egibleToDance = false;
|
||||
earliestWakeUpTime = OTSYS_TIME() + 1000;
|
||||
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
|
||||
earliestAttackTime += 200;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2002,40 +1992,71 @@ void Monster::updateLookDirection()
|
||||
//look EAST/WEST
|
||||
if (offsetx < 0) {
|
||||
newDir = DIRECTION_WEST;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
newDir = DIRECTION_EAST;
|
||||
}
|
||||
} else if (dx < dy) {
|
||||
}
|
||||
else if (dx < dy) {
|
||||
//look NORTH/SOUTH
|
||||
if (offsety < 0) {
|
||||
newDir = DIRECTION_NORTH;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
newDir = DIRECTION_SOUTH;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Direction dir = getDirection();
|
||||
if (offsetx < 0 && offsety < 0) {
|
||||
if (dir == DIRECTION_SOUTH || dir == DIRECTION_NORTH) {
|
||||
if (offsetx == -1 && offsety == -1) {
|
||||
if (dir == DIRECTION_NORTH) {
|
||||
newDir = DIRECTION_WEST;
|
||||
}
|
||||
}
|
||||
if (dir == DIRECTION_SOUTH) {
|
||||
newDir = DIRECTION_WEST;
|
||||
} else if (dir == DIRECTION_EAST) {
|
||||
}
|
||||
else if (dir == DIRECTION_EAST) {
|
||||
newDir = DIRECTION_NORTH;
|
||||
}
|
||||
} else if (offsetx < 0 && offsety > 0) {
|
||||
if (dir == DIRECTION_NORTH || dir == DIRECTION_SOUTH) {
|
||||
}
|
||||
else if (offsetx < 0 && offsety > 0) {
|
||||
if (offsetx == -1 && offsety == 1) {
|
||||
if (dir == DIRECTION_SOUTH) {
|
||||
newDir = DIRECTION_WEST;
|
||||
}
|
||||
}
|
||||
if (dir == DIRECTION_NORTH) {
|
||||
newDir = DIRECTION_WEST;
|
||||
} else if (dir == DIRECTION_EAST) {
|
||||
}
|
||||
else if (dir == DIRECTION_EAST) {
|
||||
newDir = DIRECTION_SOUTH;
|
||||
}
|
||||
} else if (offsetx > 0 && offsety < 0) {
|
||||
if (dir == DIRECTION_SOUTH || dir == DIRECTION_NORTH) {
|
||||
}
|
||||
else if (offsetx > 0 && offsety < 0) {
|
||||
if (offsetx == 1 && offsety == -1) {
|
||||
if (dir == DIRECTION_NORTH) {
|
||||
newDir = DIRECTION_EAST;
|
||||
}
|
||||
}
|
||||
if (dir == DIRECTION_SOUTH) {
|
||||
newDir = DIRECTION_EAST;
|
||||
} else if (dir == DIRECTION_WEST) {
|
||||
}
|
||||
else if (dir == DIRECTION_WEST) {
|
||||
newDir = DIRECTION_NORTH;
|
||||
}
|
||||
} else {
|
||||
if (dir == DIRECTION_NORTH || dir == DIRECTION_SOUTH) {
|
||||
}
|
||||
else {
|
||||
if (offsetx == 1 && offsety == 1) {
|
||||
if (dir == DIRECTION_SOUTH) {
|
||||
newDir = DIRECTION_EAST;
|
||||
}
|
||||
}
|
||||
if (dir == DIRECTION_NORTH) {
|
||||
newDir = DIRECTION_EAST;
|
||||
} else if (dir == DIRECTION_WEST) {
|
||||
}
|
||||
else if (dir == DIRECTION_WEST) {
|
||||
newDir = DIRECTION_SOUTH;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -372,6 +372,18 @@ bool Monsters::deserializeSpell(const pugi::xml_node& node, spellBlock_t& sb, co
|
||||
combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE);
|
||||
combat->setParam(COMBAT_PARAM_BLOCKARMOR, 1);
|
||||
combat->setParam(COMBAT_PARAM_BLOCKSHIELD, 1);
|
||||
uint32_t tD = this->getMonsterType(description)->info.targetDistance;
|
||||
if (tD == 1) {
|
||||
if (sb.range > 1) {
|
||||
combat->setOrigin(ORIGIN_RANGED);
|
||||
}
|
||||
else {
|
||||
combat->setOrigin(ORIGIN_MELEE);
|
||||
}
|
||||
}
|
||||
else if (tD > 1 && sb.range > 1) {
|
||||
combat->setOrigin(ORIGIN_RANGED);
|
||||
}
|
||||
} else if (tmpName == "bleed") {
|
||||
combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE);
|
||||
} else if (tmpName == "poison" || tmpName == "earth") {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user