First commit
This commit is contained in:
1000
app/SabrehavenServer/data/lib/compat/compat.lua
Normal file
1000
app/SabrehavenServer/data/lib/compat/compat.lua
Normal file
File diff suppressed because it is too large
Load Diff
1
app/SabrehavenServer/data/lib/core/constants.lua
Normal file
1
app/SabrehavenServer/data/lib/core/constants.lua
Normal file
@@ -0,0 +1 @@
|
||||
CONTAINER_POSITION = 0xFFFF
|
49
app/SabrehavenServer/data/lib/core/container.lua
Normal file
49
app/SabrehavenServer/data/lib/core/container.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
function Container.isContainer(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function Container.isItem(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function Container.isMonster(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Container.isCreature(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Container.isPlayer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Container.isTeleport(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Container.isTile(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Container.getItemsById(self, itemId)
|
||||
local list = {}
|
||||
for index = 0, (self:getSize() - 1) do
|
||||
local item = self:getItem(index)
|
||||
if item then
|
||||
if item:isContainer() then
|
||||
local rlist = item:getItemsById(itemId)
|
||||
if type(rlist) == 'table' then
|
||||
for _, v in pairs(rlist) do
|
||||
table.insert(list, v)
|
||||
end
|
||||
end
|
||||
else
|
||||
if item:getId() == itemId then
|
||||
table.insert(list, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
13
app/SabrehavenServer/data/lib/core/core.lua
Normal file
13
app/SabrehavenServer/data/lib/core/core.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
dofile('data/lib/core/constants.lua')
|
||||
dofile('data/lib/core/container.lua')
|
||||
dofile('data/lib/core/creature.lua')
|
||||
dofile('data/lib/core/monster.lua')
|
||||
dofile('data/lib/core/game.lua')
|
||||
dofile('data/lib/core/item.lua')
|
||||
dofile('data/lib/core/itemtype.lua')
|
||||
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')
|
||||
dofile('data/lib/core/guildwars.lua')
|
116
app/SabrehavenServer/data/lib/core/creature.lua
Normal file
116
app/SabrehavenServer/data/lib/core/creature.lua
Normal file
@@ -0,0 +1,116 @@
|
||||
function Creature.getClosestFreePosition(self, position, extended)
|
||||
local usePosition = Position(position)
|
||||
local tiles = { Tile(usePosition) }
|
||||
local length = extended and 2 or 1
|
||||
|
||||
local tile
|
||||
for y = -length, length do
|
||||
for x = -length, length do
|
||||
if x ~= 0 or y ~= 0 then
|
||||
usePosition.x = position.x + x
|
||||
usePosition.y = position.y + y
|
||||
|
||||
tile = Tile(usePosition)
|
||||
if tile then
|
||||
tiles[#tiles + 1] = tile
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #tiles do
|
||||
tile = tiles[i]
|
||||
if tile:getCreatureCount() == 0 and not tile:hasProperty(CONST_PROP_IMMOVABLEBLOCKSOLID) then
|
||||
return tile:getPosition()
|
||||
end
|
||||
end
|
||||
return Position()
|
||||
end
|
||||
|
||||
function Creature:setMonsterOutfit(monster, time)
|
||||
local monsterType = MonsterType(monster)
|
||||
if not monsterType then
|
||||
return false
|
||||
end
|
||||
|
||||
if self:isPlayer() and not (getPlayerFlagValue(self, PlayerFlag_CanIllusionAll) or monsterType:isIllusionable()) then
|
||||
return false
|
||||
end
|
||||
|
||||
local condition = Condition(CONDITION_OUTFIT)
|
||||
condition:setOutfit(monsterType:getOutfit())
|
||||
condition:setTicks(time)
|
||||
self:addCondition(condition)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function Creature:setItemOutfit(item, time)
|
||||
local itemType = ItemType(item)
|
||||
if not itemType then
|
||||
return false
|
||||
end
|
||||
|
||||
local condition = Condition(CONDITION_OUTFIT)
|
||||
condition:setOutfit({
|
||||
lookTypeEx = itemType:getId()
|
||||
})
|
||||
condition:setTicks(time)
|
||||
self:addCondition(condition)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function Creature:addSummon(monster)
|
||||
local summon = Monster(monster)
|
||||
if not summon then
|
||||
return false
|
||||
end
|
||||
|
||||
summon:setTarget(nil)
|
||||
summon:setFollowCreature(nil)
|
||||
summon:setDropLoot(false)
|
||||
summon:setMaster(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function Creature:removeSummon(monster)
|
||||
local summon = Monster(monster)
|
||||
if not summon or summon:getMaster() ~= self then
|
||||
return false
|
||||
end
|
||||
|
||||
summon:setTarget(nil)
|
||||
summon:setFollowCreature(nil)
|
||||
summon:setDropLoot(true)
|
||||
summon:setMaster(nil)
|
||||
return true
|
||||
end
|
||||
|
||||
function Creature.getPlayer(self)
|
||||
return self:isPlayer() and self or nil
|
||||
end
|
||||
|
||||
function Creature.isItem(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Creature.isMonster(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Creature.isNpc(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Creature.isPlayer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Creature.isTile(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Creature.isContainer(self)
|
||||
return false
|
||||
end
|
159
app/SabrehavenServer/data/lib/core/game.lua
Normal file
159
app/SabrehavenServer/data/lib/core/game.lua
Normal file
@@ -0,0 +1,159 @@
|
||||
function Game.sendMagicEffect(position, effect)
|
||||
local pos = Position(position)
|
||||
pos:sendMagicEffect(effect)
|
||||
end
|
||||
|
||||
function Game.removeItemsOnMap(position)
|
||||
local tile = Tile(position)
|
||||
local tileCount = tile:getThingCount()
|
||||
local i = 0
|
||||
while i < tileCount do
|
||||
local tileItem = tile:getThing(i)
|
||||
if tileItem and tileItem:getType():isMovable() then
|
||||
tileItem:remove()
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Game.transformItemOnMap(position, itemId, toItemId, subtype)
|
||||
if not subtype then
|
||||
subtype = -1
|
||||
end
|
||||
|
||||
local tile = Tile(position)
|
||||
local item = tile:getItemById(itemId)
|
||||
item:transform(toItemId, subtype)
|
||||
item:decay()
|
||||
return item
|
||||
end
|
||||
|
||||
function Game.removeItemOnMap(position, itemId, subtype)
|
||||
if not subtype then
|
||||
subtype = -1
|
||||
end
|
||||
|
||||
local tile = Tile(position)
|
||||
local item = tile:getItemById(itemId, subtype)
|
||||
item:remove()
|
||||
end
|
||||
|
||||
function Game.isItemThere(position, itemId)
|
||||
local tile = Tile(position)
|
||||
return tile:getItemById(itemId) ~= nil
|
||||
end
|
||||
|
||||
function Game.isPlayerThere(position)
|
||||
local tile = Tile(position)
|
||||
local creatures = tile:getCreatures()
|
||||
for _, creature in ipairs(creatures) do
|
||||
if creature:isPlayer() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Game.isMonsterThere(position, monsterName)
|
||||
local tile = Tile(position)
|
||||
local creatures = tile:getCreatures()
|
||||
for _, creature in ipairs(creatures) do
|
||||
if creature:isMonster() and creature:getName():lower() == monsterName:lower() then
|
||||
return creature
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function Game.broadcastMessage(message, messageType)
|
||||
if messageType == nil then
|
||||
messageType = MESSAGE_STATUS_WARNING
|
||||
end
|
||||
|
||||
for _, player in ipairs(Game.getPlayers()) do
|
||||
player:sendTextMessage(messageType, message)
|
||||
end
|
||||
end
|
||||
|
||||
function Game.convertIpToString(ip)
|
||||
local band = bit.band
|
||||
local rshift = bit.rshift
|
||||
return string.format("%d.%d.%d.%d",
|
||||
band(ip, 0xFF),
|
||||
band(rshift(ip, 8), 0xFF),
|
||||
band(rshift(ip, 16), 0xFF),
|
||||
rshift(ip, 24)
|
||||
)
|
||||
end
|
||||
|
||||
function Game.getReverseDirection(direction)
|
||||
if direction == WEST then
|
||||
return EAST
|
||||
elseif direction == EAST then
|
||||
return WEST
|
||||
elseif direction == NORTH then
|
||||
return SOUTH
|
||||
elseif direction == SOUTH then
|
||||
return NORTH
|
||||
elseif direction == NORTHWEST then
|
||||
return SOUTHEAST
|
||||
elseif direction == NORTHEAST then
|
||||
return SOUTHWEST
|
||||
elseif direction == SOUTHWEST then
|
||||
return NORTHEAST
|
||||
elseif direction == SOUTHEAST then
|
||||
return NORTHWEST
|
||||
end
|
||||
return NORTH
|
||||
end
|
||||
|
||||
function Game.getSkillType(weaponType)
|
||||
if weaponType == WEAPON_CLUB then
|
||||
return SKILL_CLUB
|
||||
elseif weaponType == WEAPON_SWORD then
|
||||
return SKILL_SWORD
|
||||
elseif weaponType == WEAPON_AXE then
|
||||
return SKILL_AXE
|
||||
elseif weaponType == WEAPON_DISTANCE then
|
||||
return SKILL_DISTANCE
|
||||
elseif weaponType == WEAPON_SHIELD then
|
||||
return SKILL_SHIELD
|
||||
end
|
||||
return SKILL_FIST
|
||||
end
|
||||
|
||||
if not globalStorageTable then
|
||||
globalStorageTable = {}
|
||||
end
|
||||
|
||||
function Game.getStorageValue(key)
|
||||
-- Return from local table if possible
|
||||
if globalStorageTable[key] ~= nil then
|
||||
return globalStorageTable[key]
|
||||
end
|
||||
|
||||
-- Else look for it on the DB
|
||||
local dbData = db.storeQuery("SELECT `value` FROM `global_storage` WHERE `key` = " .. key .. " LIMIT 1;")
|
||||
if dbData ~= false then
|
||||
local value = result.getNumber(dbData, "value")
|
||||
if value ~= nil then
|
||||
-- Save it to globalStorageTable
|
||||
globalStorageTable[key] = value
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function Game.setStorageValue(key, value)
|
||||
globalStorageTable[key] = value
|
||||
|
||||
local dbData = db.storeQuery("SELECT `value` FROM `global_storage` WHERE `key` = " .. key .. " LIMIT 1;")
|
||||
if dbData ~= false then
|
||||
db.query("UPDATE `global_storage` SET `value`='".. value .."' WHERE `key` = " .. key .. " LIMIT 1;")
|
||||
else
|
||||
db.query("INSERT INTO `global_storage` (`key`, `value`) VALUES (" .. key .. ", " .. value .. ");")
|
||||
end
|
||||
end
|
199
app/SabrehavenServer/data/lib/core/guildwars.lua
Normal file
199
app/SabrehavenServer/data/lib/core/guildwars.lua
Normal file
@@ -0,0 +1,199 @@
|
||||
guildwars = {}
|
||||
|
||||
guildwars.__index = guildwars
|
||||
|
||||
function guildwars:isInWar(player1, player2)
|
||||
if not player1:getGuild() or not player2:getGuild() then
|
||||
return 0
|
||||
end
|
||||
|
||||
if player1:getGuild():getId() == 0 or player2:getGuild():getId() == 0 then
|
||||
return 0
|
||||
end
|
||||
|
||||
if player1:getGuild():getId() == player2:getGuild():getId() then
|
||||
return 0
|
||||
end
|
||||
|
||||
return isInWar(player1:getId(), player2:getId())
|
||||
end
|
||||
|
||||
function guildwars:processKill(warId, killer, player)
|
||||
local fragLimit = self:getFragLimit(warId)
|
||||
|
||||
local killerFrags = self:getKills(warId, killer:getGuild():getId()) + 1
|
||||
local deadFrags = self:getKills(warId, player:getGuild():getId())
|
||||
|
||||
local killerMsg = "Opponent " .. player:getName() .. " of the " .. player:getGuild():getName() .. " was killed by " .. killer:getName() .. ". The new score is " .. killerFrags .. ":" .. deadFrags .. " frags (limit " .. fragLimit .. ")."
|
||||
sendGuildChannelMessage(killer:getGuild():getId(), TALKTYPE_CHANNEL_O, killerMsg)
|
||||
|
||||
local deadMsg = "Guild member " .. player:getName() .. " was killed by " .. killer:getName() .. " of the " .. killer:getGuild():getName() .. ". The new score is " .. deadFrags .. ":" .. killerFrags .. " frags (limit " .. fragLimit .. ")."
|
||||
sendGuildChannelMessage(player:getGuild():getId(), TALKTYPE_CHANNEL_O, deadMsg)
|
||||
|
||||
self:insertKill(warId, killer, player)
|
||||
|
||||
if killerFrags >= fragLimit then
|
||||
self:endWar(warId, killer, player, killerFrags)
|
||||
end
|
||||
end
|
||||
|
||||
function guildwars:getFragLimit(warId)
|
||||
local resultId = db.storeQuery("SELECT `frag_limit` FROM `guild_wars` WHERE `id` = " .. warId)
|
||||
if resultId ~= false then
|
||||
local frag_limit = result.getDataInt(resultId, "frag_limit")
|
||||
result.free(resultId)
|
||||
return frag_limit
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function guildwars:getBounty(warId)
|
||||
local resultId = db.storeQuery("SELECT `bounty` FROM `guild_wars` WHERE `id` = " .. warId)
|
||||
if resultId ~= false then
|
||||
local bounty = result.getDataInt(resultId, "bounty")
|
||||
result.free(resultId)
|
||||
return bounty
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function guildwars:getKills(warId, guildId)
|
||||
local resultId = db.storeQuery("SELECT COUNT(*) as frags FROM `guildwar_kills` WHERE `warid` = " .. warId .. " and `killerguild` = " .. guildId)
|
||||
if resultId ~= false then
|
||||
local frags = result.getDataInt(resultId, "frags")
|
||||
result.free(resultId)
|
||||
return frags
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function guildwars:insertKill(warId, killer, target)
|
||||
db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `warid`, `time`) VALUES (" .. db.escapeString(killer:getName()) .. ", " .. db.escapeString(target:getName()) .. ", " .. killer:getGuild():getId() .. ", " .. target:getGuild():getId() .. ", " .. warId .. ", " .. os.time() .. ")")
|
||||
end
|
||||
|
||||
function guildwars:endWar(warId, killer, player, frags)
|
||||
local winGuildInternalMessage = "Congratulations! You have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags."
|
||||
sendGuildChannelMessage(killer:getGuild():getId(), TALKTYPE_CHANNEL_O, winGuildInternalMessage)
|
||||
|
||||
local loseGuildInternalMessage = "You have lost the war against " .. killer:getGuild():getName() .. ". They have reached the limit of " .. frags .. " frags."
|
||||
sendGuildChannelMessage(player:getGuild():getId(), TALKTYPE_CHANNEL_O, loseGuildInternalMessage)
|
||||
|
||||
broadcastMessage(killer:getGuild():getName() .. " have won the war against " .. player:getGuild():getName() .. " with " .. frags .. " frags.", MESSAGE_EVENT_ADVANCE)
|
||||
|
||||
self:updateState(warId, 5)
|
||||
|
||||
self:setWarEmblem(killer:getGuild(), player:getGuild())
|
||||
|
||||
local bounty = self:getBounty(warId)
|
||||
if bounty > 0 then
|
||||
killer:getGuild():increaseBankBalance(bounty * 2)
|
||||
end
|
||||
end
|
||||
|
||||
function guildwars:setWarEmblem(guild1, guild2)
|
||||
guild1:setGuildWarEmblem(guild2)
|
||||
end
|
||||
|
||||
function guildwars:updateState(warId, status)
|
||||
db.query("UPDATE `guild_wars` SET `status` = " .. status .. " WHERE `id` = " .. warId)
|
||||
end
|
||||
|
||||
function guildwars:getPendingInvitation(guild1, guild2)
|
||||
local resultId = db.storeQuery("SELECT `id`, `bounty` FROM `guild_wars` WHERE `guild1` = " .. guild1 .. " AND `guild2` = " .. guild2 .. " AND `status` = 0")
|
||||
|
||||
if resultId then
|
||||
local id = result.getDataInt(resultId, "id")
|
||||
local bounty = result.getDataInt(resultId, "bounty")
|
||||
result.free(resultId)
|
||||
|
||||
return id, bounty
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function guildwars:startWar(player, warId, guild1, guild2, bounty)
|
||||
if bounty > 0 then
|
||||
local guildBalance = guild1:getBankBalance()
|
||||
if guildBalance < bounty then
|
||||
player:sendCancelMessage("Your guild does not have that much money in the bank account balance to accept this war with the bounty of " .. bounty .. " gold.")
|
||||
return true
|
||||
end
|
||||
|
||||
if not guild1:decreaseBankBalance(bounty) then
|
||||
player:sendCancelMessage("Your guild does not have that much money in the bank account balance to accept this war with the bounty of " .. bounty .. " gold.")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
self:updateState(warId, 1)
|
||||
|
||||
self:setWarEmblem(guild1, guild2)
|
||||
|
||||
broadcastMessage(guild1:getName() .. " has accepted " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE)
|
||||
end
|
||||
|
||||
function guildwars:rejectWar(warId, guild1, guild2, bounty)
|
||||
self:updateState(warId, 2)
|
||||
broadcastMessage(guild1:getName() .. " has rejected " .. guild2:getName() .. " invitation to war.", MESSAGE_EVENT_ADVANCE)
|
||||
|
||||
if bounty > 0 then
|
||||
guild2:increaseBankBalance(bounty)
|
||||
end
|
||||
end
|
||||
|
||||
function guildwars:cancelWar(warId, guild1, guild2, bounty)
|
||||
self:updateState(warId, 3)
|
||||
broadcastMessage(guild1:getName() .. " has canceled invitation to a war with " .. guild2:getName() .. ".", MESSAGE_EVENT_ADVANCE)
|
||||
|
||||
if bounty > 0 then
|
||||
guild1:increaseBankBalance(bounty)
|
||||
end
|
||||
end
|
||||
|
||||
function guildwars:invite(player, guild1, guild2, frags, bounty)
|
||||
local str = ""
|
||||
local tmpQuery = db.storeQuery("SELECT `guild1`, `status` FROM `guild_wars` WHERE `guild1` IN (" .. guild1:getId() .. "," .. guild2:getId() .. ") AND `guild2` IN (" .. guild2:getId() .. "," .. guild1:getId() .. ") AND `status` IN (0, 1)")
|
||||
if tmpQuery then
|
||||
if result.getDataInt(tmpQuery, "status") == 0 then
|
||||
if result.getDataInt(tmpQuery, "guild1") == guild1:getId() then
|
||||
str = "You have already invited " .. guild2:getName() .. " to war."
|
||||
else
|
||||
str = guild2:getName() .. " have already invited you to war."
|
||||
end
|
||||
else
|
||||
str = "You are already on a war with " .. guild2:getName() .. "."
|
||||
end
|
||||
|
||||
result.free(tmpQuery)
|
||||
end
|
||||
|
||||
if str ~= "" then
|
||||
player:sendCancelMessage(str)
|
||||
return true
|
||||
end
|
||||
|
||||
frags = math.max(10, math.min(500, frags))
|
||||
bounty = math.max(0, math.min(10000000, bounty))
|
||||
|
||||
if bounty > 0 then
|
||||
local guildBalance = guild1:getBankBalance()
|
||||
if guildBalance < bounty then
|
||||
player:sendCancelMessage("Your guild does not have that much money in the bank account balance to set this bounty.")
|
||||
return true
|
||||
end
|
||||
|
||||
if not guild1:decreaseBankBalance(bounty) then
|
||||
player:sendCancelMessage("Your guild does not have that much money in the bank account balance to set this bounty.")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
db.asyncQuery("INSERT INTO `guild_wars` (`guild1`, `guild2`, `frag_limit`, `bounty`) VALUES (" .. guild1:getId() .. ", " .. guild2:getId() .. ", " .. frags .. ", " .. bounty .. ");")
|
||||
|
||||
local message = guild1:getName() .. " has invited " .. guild2:getName() .. " to war for " .. frags .. " frags."
|
||||
if bounty > 0 then
|
||||
message = message .. " The bounty reward is set to " .. bounty .. " gold."
|
||||
end
|
||||
broadcastMessage(message, MESSAGE_EVENT_ADVANCE)
|
||||
end
|
31
app/SabrehavenServer/data/lib/core/item.lua
Normal file
31
app/SabrehavenServer/data/lib/core/item.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
function Item.getType(self)
|
||||
return ItemType(self:getId())
|
||||
end
|
||||
|
||||
function Item.isItem(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function Item.isContainer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Item.isCreature(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Item.isMonster(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Item.isPlayer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Item.isTeleport(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Item.isTile(self)
|
||||
return false
|
||||
end
|
16
app/SabrehavenServer/data/lib/core/itemtype.lua
Normal file
16
app/SabrehavenServer/data/lib/core/itemtype.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
local slotBits = {
|
||||
[CONST_SLOT_HEAD] = SLOTP_HEAD,
|
||||
[CONST_SLOT_NECKLACE] = SLOTP_NECKLACE,
|
||||
[CONST_SLOT_BACKPACK] = SLOTP_BACKPACK,
|
||||
[CONST_SLOT_ARMOR] = SLOTP_ARMOR,
|
||||
[CONST_SLOT_RIGHT] = SLOTP_RIGHT,
|
||||
[CONST_SLOT_LEFT] = SLOTP_LEFT,
|
||||
[CONST_SLOT_LEGS] = SLOTP_LEGS,
|
||||
[CONST_SLOT_FEET] = SLOTP_FEET,
|
||||
[CONST_SLOT_RING] = SLOTP_RING,
|
||||
[CONST_SLOT_AMMO] = SLOTP_AMMO
|
||||
}
|
||||
|
||||
function ItemType.usesSlot(self, slot)
|
||||
return bit.band(self:getSlotPosition(), slotBits[slot] or 0) ~= 0
|
||||
end
|
27
app/SabrehavenServer/data/lib/core/monster.lua
Normal file
27
app/SabrehavenServer/data/lib/core/monster.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
function Monster.getMonster(self)
|
||||
return self:isMonster() and self or nil
|
||||
end
|
||||
|
||||
function Monster.isItem(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Monster.isMonster(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function Monster.isNpc(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Monster.isPlayer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Monster.isTile(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Monster.isContainer(self)
|
||||
return false
|
||||
end
|
99
app/SabrehavenServer/data/lib/core/player.lua
Normal file
99
app/SabrehavenServer/data/lib/core/player.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
local foodCondition = Condition(CONDITION_REGENERATION, CONDITIONID_DEFAULT)
|
||||
|
||||
function Player.feed(self, food)
|
||||
local condition = self:getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT)
|
||||
if condition then
|
||||
condition:setTicks(condition:getTicks() + (food * 1000))
|
||||
else
|
||||
local vocation = self:getVocation()
|
||||
if not vocation then
|
||||
return nil
|
||||
end
|
||||
|
||||
foodCondition:setTicks(food * 1000)
|
||||
foodCondition:setParameter(CONDITION_PARAM_HEALTHGAIN, vocation:getHealthGainAmount())
|
||||
foodCondition:setParameter(CONDITION_PARAM_HEALTHTICKS, vocation:getHealthGainTicks() * 1000)
|
||||
foodCondition:setParameter(CONDITION_PARAM_MANAGAIN, vocation:getManaGainAmount())
|
||||
foodCondition:setParameter(CONDITION_PARAM_MANATICKS, vocation:getManaGainTicks() * 1000)
|
||||
|
||||
self:addCondition(foodCondition)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Player.getClosestFreePosition(self, position, extended)
|
||||
if self:getAccountType() >= ACCOUNT_TYPE_GOD then
|
||||
return position
|
||||
end
|
||||
return Creature.getClosestFreePosition(self, position, extended)
|
||||
end
|
||||
|
||||
function Player.getDepotItems(self, depotId)
|
||||
return self:getDepotChest(depotId, true):getItemHoldingCount()
|
||||
end
|
||||
|
||||
function Player.isNoVocation(self)
|
||||
return self:getVocation():getId() == 0
|
||||
end
|
||||
|
||||
function Player.isSorcerer(self)
|
||||
return self:getVocation():getId() == 1 or self:getVocation():getId() == 5
|
||||
end
|
||||
|
||||
function Player.isDruid(self)
|
||||
return self:getVocation():getId() == 2 or self:getVocation():getId() == 6
|
||||
end
|
||||
|
||||
function Player.isPaladin(self)
|
||||
return self:getVocation():getId() == 3 or self:getVocation():getId() == 7
|
||||
end
|
||||
|
||||
function Player.isKnight(self)
|
||||
return self:getVocation():getId() == 4 or self:getVocation():getId() == 8
|
||||
end
|
||||
|
||||
function Player.isPremium(self)
|
||||
return self:getPremiumDays() > 0 or configManager.getBoolean(configKeys.FREE_PREMIUM)
|
||||
end
|
||||
|
||||
function Player.sendCancelMessage(self, message)
|
||||
if type(message) == "number" then
|
||||
message = Game.getReturnMessage(message)
|
||||
end
|
||||
return self:sendTextMessage(MESSAGE_STATUS_SMALL, message)
|
||||
end
|
||||
|
||||
function Player.isUsingOtClient(self)
|
||||
return self:getClient().os >= CLIENTOS_OTCLIENT_LINUX
|
||||
end
|
||||
|
||||
function Player.sendExtendedOpcode(self, opcode, buffer)
|
||||
if not self:isUsingOtClient() then
|
||||
return false
|
||||
end
|
||||
|
||||
local networkMessage = NetworkMessage()
|
||||
networkMessage:addByte(0x32)
|
||||
networkMessage:addByte(opcode)
|
||||
networkMessage:addString(buffer)
|
||||
networkMessage:sendToPlayer(self)
|
||||
networkMessage:delete()
|
||||
return true
|
||||
end
|
||||
|
||||
APPLY_SKILL_MULTIPLIER = true
|
||||
local addSkillTriesFunc = Player.addSkillTries
|
||||
function Player.addSkillTries(...)
|
||||
APPLY_SKILL_MULTIPLIER = false
|
||||
local ret = addSkillTriesFunc(...)
|
||||
APPLY_SKILL_MULTIPLIER = true
|
||||
return ret
|
||||
end
|
||||
|
||||
local addManaSpentFunc = Player.addManaSpent
|
||||
function Player.addManaSpent(...)
|
||||
APPLY_SKILL_MULTIPLIER = false
|
||||
local ret = addManaSpentFunc(...)
|
||||
APPLY_SKILL_MULTIPLIER = true
|
||||
return ret
|
||||
end
|
99
app/SabrehavenServer/data/lib/core/position.lua
Normal file
99
app/SabrehavenServer/data/lib/core/position.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
Position.directionOffset = {
|
||||
[DIRECTION_NORTH] = {x = 0, y = -1},
|
||||
[DIRECTION_EAST] = {x = 1, y = 0},
|
||||
[DIRECTION_SOUTH] = {x = 0, y = 1},
|
||||
[DIRECTION_WEST] = {x = -1, y = 0},
|
||||
[DIRECTION_SOUTHWEST] = {x = -1, y = 1},
|
||||
[DIRECTION_SOUTHEAST] = {x = 1, y = 1},
|
||||
[DIRECTION_NORTHWEST] = {x = -1, y = -1},
|
||||
[DIRECTION_NORTHEAST] = {x = 1, y = -1}
|
||||
}
|
||||
|
||||
function Position:getNextPosition(direction, steps)
|
||||
local offset = Position.directionOffset[direction]
|
||||
if offset then
|
||||
steps = steps or 1
|
||||
self.x = self.x + offset.x * steps
|
||||
self.y = self.y + offset.y * steps
|
||||
end
|
||||
end
|
||||
|
||||
function Position:moveUpstairs()
|
||||
local isWalkable = function (position)
|
||||
local tile = Tile(position)
|
||||
if not tile then
|
||||
return false
|
||||
end
|
||||
|
||||
local ground = tile:getGround()
|
||||
if not ground or ground:hasProperty(CONST_PROP_BLOCKSOLID) then
|
||||
return false
|
||||
end
|
||||
|
||||
local items = tile:getItems()
|
||||
for i = 1, tile:getItemCount() do
|
||||
local item = items[i]
|
||||
local itemType = item:getType()
|
||||
if itemType:getType() ~= ITEM_TYPE_MAGICFIELD and not itemType:isMovable() and item:hasProperty(CONST_PROP_BLOCKSOLID) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local swap = function (lhs, rhs)
|
||||
lhs.x, rhs.x = rhs.x, lhs.x
|
||||
lhs.y, rhs.y = rhs.y, lhs.y
|
||||
lhs.z, rhs.z = rhs.z, lhs.z
|
||||
end
|
||||
|
||||
self.z = self.z - 1
|
||||
|
||||
local defaultPosition = self + Position.directionOffset[DIRECTION_SOUTH]
|
||||
if not isWalkable(defaultPosition) then
|
||||
for direction = DIRECTION_NORTH, DIRECTION_NORTHEAST do
|
||||
if direction == DIRECTION_SOUTH then
|
||||
direction = DIRECTION_WEST
|
||||
end
|
||||
|
||||
local position = self + Position.directionOffset[direction]
|
||||
if isWalkable(position) then
|
||||
swap(self, position)
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
swap(self, defaultPosition)
|
||||
return self
|
||||
end
|
||||
|
||||
function Position:moveRel(x, y, z)
|
||||
self.x = self.x + x
|
||||
self.y = self.y + y
|
||||
self.z = self.z + z
|
||||
return self
|
||||
end
|
||||
|
||||
function Position:isInRange(from, to)
|
||||
-- No matter what corner from and to is, we want to make
|
||||
-- life easier by calculating north-west and south-east
|
||||
local zone = {
|
||||
nW = {
|
||||
x = (from.x < to.x and from.x or to.x),
|
||||
y = (from.y < to.y and from.y or to.y),
|
||||
z = (from.z < to.z and from.z or to.z)
|
||||
},
|
||||
sE = {
|
||||
x = (to.x > from.x and to.x or from.x),
|
||||
y = (to.y > from.y and to.y or from.y),
|
||||
z = (to.z > from.z and to.z or from.z)
|
||||
}
|
||||
}
|
||||
|
||||
if self.x >= zone.nW.x and self.x <= zone.sE.x
|
||||
and self.y >= zone.nW.y and self.y <= zone.sE.y
|
||||
and self.z >= zone.nW.z and self.z <= zone.sE.z then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
3
app/SabrehavenServer/data/lib/core/teleport.lua
Normal file
3
app/SabrehavenServer/data/lib/core/teleport.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
function Teleport.isTeleport(self)
|
||||
return true
|
||||
end
|
65
app/SabrehavenServer/data/lib/core/tile.lua
Normal file
65
app/SabrehavenServer/data/lib/core/tile.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
function Tile.isItem(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Tile.isContainer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Tile.isCreature(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Tile.isPlayer(self)
|
||||
return false
|
||||
end
|
||||
|
||||
function Tile.isTeleport(self)
|
||||
return false
|
||||
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
app/SabrehavenServer/data/lib/core/vocation.lua
Normal file
7
app/SabrehavenServer/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
|
5
app/SabrehavenServer/data/lib/lib.lua
Normal file
5
app/SabrehavenServer/data/lib/lib.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
-- Core API functions implemented in Lua
|
||||
dofile('data/lib/core/core.lua')
|
||||
|
||||
-- Compatibility library for our old Lua API
|
||||
dofile('data/lib/compat/compat.lua')
|
Reference in New Issue
Block a user