Ir para conteúdo
  • Cadastre-se

Posts Recomendados

Acabei implementando um sistema de skill stages em meu server, ele até funciona, porém a cada magia que um player utiliza, aparece o seguinte erro no console:

(Estou usando tfs 1.3x)

 

 

Citar

Lua Script Error: [Event Interface]
data/events/scripts/player.lua:Player@onGainSkillTries
data/events/scripts/player.lua:896: bad argument #1 to 'next' (table expected, got nil)
stack traceback:
        [C]: at 0x005be450
        [C]: in function 'next'
        data/events/scripts/player.lua:896: in function <data/events/scripts/player.lua:891>

 

Players.lua:

 -- Internal Use
STONE_SKIN_AMULET = 2197
GOLD_POUNCH = 26377
ITEM_STORE_INBOX = 26052
ITEM_PARCEL = 2595
CONTAINER_PESO = 450000

-- No move items with actionID 8000
NOT_MOVEABLE_ACTION = 8000

-- Players cannot throw items on teleports if set to true
local blockTeleportTrashing = true

local titles = {
	{storageID = 14960, title = " Scout"},
	{storageID = 14961, title = " Sentinel"},
	{storageID = 14962, title = " Steward"},
	{storageID = 14963, title = " Warden"},
	{storageID = 14964, title = " Squire"},
	{storageID = 14965, title = " Warrior"},
	{storageID = 14966, title = " Keeper"},
	{storageID = 14967, title = " Guardian"},
	{storageID = 14968, title = " Sage"},
	{storageID = 14969, title = " Tutor"},
	{storageID = 14970, title = " Senior Tutor"},
	{storageID = 14971, title = " King"},
}

local function getTitle(uid)
	local player = Player(uid)
	if not player then return false end

	for i = #titles, 1, -1 do
		if player:getStorageValue(titles[i].storageID) == 1 then
			return titles[i].title
		end
	end

	return false
end

function Player:onBrowseField(position)
	return true
end

local function getHours(seconds)
	return math.floor((seconds/60)/60)
end

local function getMinutes(seconds)
	return math.floor(seconds/60)
end

local function getSeconds(seconds)
	return seconds%60
end

local function getTime(seconds)
	local hours, minutes = getHours(seconds), getMinutes(seconds)
	if (minutes > 59) then
		minutes = minutes-hours*60
	end

	if (minutes < 10) then
		minutes = "0" ..minutes
	end

	return hours..":"..minutes.. "h"
end

local function getTimeinWords(secs)
	local hours, minutes, seconds = getHours(secs), getMinutes(secs), getSeconds(secs)
	if (minutes > 59) then
		minutes = minutes-hours*60
	end

	local timeStr = ''

	if hours > 0 then
		timeStr = timeStr .. ' hours '
	end

	timeStr = timeStr .. minutes .. ' minutes and '.. seconds .. 'seconds.'

	return timeStr
end

function Player:onLook(thing, position, distance)
	local description = "You see "
	if thing:isItem() then
		if thing.actionid == 5640 then
			description = description .. "a honeyflower patch."
		elseif thing.actionid == 5641 then
			description = description .. "a banana palm."
		elseif thing.itemid >= ITEM_HEALTH_CASK_START and thing.itemid <= ITEM_HEALTH_CASK_END 
		or thing.itemid >= ITEM_MANA_CASK_START and thing.itemid <= ITEM_MANA_CASK_END 
		or thing.itemid >= ITEM_SPIRIT_CASK_START and thing.itemid <= ITEM_SPIRIT_CASK_END 
		or thing.itemid >= ITEM_KEG_START and thing.itemid <= ITEM_KEG_END then
			description = description .. thing:getDescription(distance)
			local charges = thing:getCharges()
			if charges then
			description = string.format("%s\nIt has %d refillings left.", description, charges)
			end
		else
			description = description .. thing:getDescription(distance)
		end
	else
		description = description .. thing:getDescription(distance)
		if thing:isMonster() then
			local master = thing:getMaster()
			if master and table.contains({'thundergiant','grovebeast','emberwing','skullfrost'}, thing:getName():lower()) then
				description = description..' (Master: ' .. master:getName() .. '). It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
			end
		end
	end

	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_UNIQUEID)
			if uniqueId > 0 and uniqueId < 65536 then
				description = string.format("%s, Unique 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
		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
	
	if thing:isCreature() then
		if thing:isPlayer() then
			local KD = (math.max(0, thing:getStorageValue(STORAGEVALUE_KILLS)) + math.max(0, thing:getStorageValue(STORAGEVALUE_ASSISTS))) / math.max(1, thing:getStorageValue(STORAGEVALUE_DEATHS))
			description = string.format("%s\nKD: [%0.2f]", description, KD)
		end
	end
	self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end

function Player:onLookInBattleList(creature, distance)
	local description = "You see " .. creature:getDescription(distance)
	if creature:isMonster() then
		local master = creature:getMaster()
		if master and table.contains({'thundergiant','grovebeast','emberwing','skullfrost'}, creature:getName():lower()) then
			description = description..' (Master: ' .. master:getName() .. '). It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
		end
	end
	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:onLookInShop(itemType, count)
	return true
end

local config = {
	maxItemsPerSeconds = 1,
	exhaustTime = 2000,
}

if not pushDelay then
	pushDelay = { }
end

local function antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
	if toPosition.x == CONTAINER_POSITION then
		return true
	end

	local tile = Tile(toPosition)
	if not tile then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		return false
	end

	local cid = self:getId()
	if not pushDelay[cid] then
		pushDelay[cid] = {items = 0, time = 0}
	end

	pushDelay[cid].items = pushDelay[cid].items + 1

	local currentTime = os.mtime()
	if pushDelay[cid].time == 0 then
		pushDelay[cid].time = currentTime
	elseif pushDelay[cid].time == currentTime then
		pushDelay[cid].items = pushDelay[cid].items + 1
	elseif currentTime > pushDelay[cid].time then
		pushDelay[cid].time = 0
		pushDelay[cid].items = 0
	end

	if pushDelay[cid].items > config.maxItemsPerSeconds then
		pushDelay[cid].time = currentTime + config.exhaustTime
	end

	if pushDelay[cid].time > currentTime then
		self:sendCancelMessage("You can't move that item so fast.")
		return false
	end

	return true
end

function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
	-- No move if item count > 20 items
	local tile = Tile(toPosition)
	if tile and tile:getItemCount() > 20 then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		return false
	end
	
	-- Loot Analyser apenas 11.x+
	--[[if self:getClient().os == CLIENTOS_NEW_WINDOWS then
    	local t = Tile(fromCylinder:getPosition())
    	local corpse = t:getTopDownItem()
    	if corpse then
    	    local itemType = corpse:getType()
    		if itemType:isCorpse() and toPosition.x == CONTAINER_POSITION then
    		    self:sendLootStats(item)
    		end
    	end
    end]]--

	checkWallArito(item, toPosition)

	-- No move parcel very heavy
	if ItemType(item:getId()):isContainer() and item:getWeight() > CONTAINER_PESO then
       self:sendCancelMessage('You cannot move containers with more than ' .. CONTAINER_PESO .. ' oz.')
        return false
    end

	-- Cults of Tibia begin
	local frompos = Position(33023, 31904, 14) -- Checagem
	local topos = Position(33052, 31932, 15) -- Checagem
	if self:getPosition():isInRange(frompos, topos) and item:getId() == 26397 then
		local tileBoss = Tile(toPosition)
		if tileBoss and tileBoss:getTopCreature() and tileBoss:getTopCreature():isMonster() then
			if tileBoss:getTopCreature():getName():lower() == 'the remorseless corruptor' then
				tileBoss:getTopCreature():addHealth(-17000)
				item:remove(1)
				if tileBoss:getTopCreature():getHealth() <= 300 then
					tileBoss:getTopCreature():remove()
					local monster  = Game.createMonster('the corruptor of souls', toPosition)
					monster:registerEvent('checkPiso')
					if Game.getStorageValue('healthSoul') > 0 then
						monster:addHealth(-(monster:getHealth() - Game.getStorageValue('healthSoul')))
					end
					Game.setStorageValue('checkPiso', os.time()+30)
				end
			elseif tileBoss:getTopCreature():getName():lower() == 'the corruptor of souls' then
				Game.setStorageValue('checkPiso', os.time()+30)
				item:remove(1)
			end
		end
	end
	-- Cults of Tibia end
	
	--- LIONS ROCK START 
	if self:getStorageValue(lionrock.storages.playerCanDoTasks) - os.time() < 0 then
		local p, i = lionrock.positions, lionrock.items
		local checkPr = false
		if item:getId() == 2147 and toPosition.x == 33069 and toPosition.y == 32298  and toPosition.z == 9 then
			-- Ruby
			self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You place the ruby on the small socket. A red flame begins to burn.")
				checkPr = true
			if lionrock.taskactive.ruby ~= true then
				lionrock.taskactive.ruby = true
			end

			local item = Tile(Position(33069, 32298, 9))
			if (item:getItemCountById(1488) > 0) then
			local flameruby = Game.createItem(1488, 1, Position(33069, 32298, 9))
			end
		end

		if item:getId() == 2146 and toPosition.x == 33069 and toPosition.y == 32302  and toPosition.z == 9 then
			-- Sapphire
			self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You place the sapphire on the small socket. A blue flame begins to burn.")
				checkPr = true
			if lionrock.taskactive.sapphire ~= true then
				lionrock.taskactive.sapphire = true
			end

			local item = Tile(Position(33069, 32302, 9))
			if (item:getItemCountById(8058) > 0) then
			local flamesapphire = Game.createItem(8058, 1, Position(33069, 32302, 9))
			end
		end

		if item:getId() == 2150 and toPosition.x == 33077 and toPosition.y == 32302  and toPosition.z == 9 then
			-- Amethyst
			self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You place the amethyst on the small socket. A violet flame begins to burn.")
				checkPr = true
			if lionrock.taskactive.amethyst ~= true then
				lionrock.taskactive.amethyst = true
			end

			local item = Tile(Position(33077, 32302, 9))
			if (item:getItemCountById(1500) > 0) then
			local flameamethyst = Game.createItem(1500, 1, Position(33077, 32302, 9))
			end
		end

		if item:getId() == 9970 and toPosition.x == 33077 and toPosition.y == 32298  and toPosition.z == 9 then
			-- Topaz
			self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You place the topaz on the small socket. A yellow flame begins to burn.")
				checkPr = true
			if lionrock.taskactive.topaz ~= true then
				lionrock.taskactive.topaz = true
			end

			local item = Tile(Position(33077, 32298, 9))
			if (item:getItemCountById(7473) > 0) then
			local flametopaz = Game.createItem(7473, 1, Position(33077, 32298, 9))
			end
		end

		if checkPr == true then
			-- Adding the Fountain which gives present
			if lionrock.taskactive.ruby == true and lionrock.taskactive.sapphire == true and lionrock.taskactive.amethyst == true and lionrock.taskactive.topaz == true then
				local fountain = Game.createItem(6390, 1, Position(33073, 32300, 9))
				fountain:setActionId(41357)
				local stone = Tile(Position(33073, 32300, 9)):getItemById(3608)
				if stone ~= nil then
					stone:remove()
				end
				self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Something happens at the centre of the room ...");
			end

			-- Removing Item
			item:remove(1)
		end
	end
	---- LIONS ROCK END
	
	-- SSA exhaust
	local exhaust = { }
	if toPosition.x == CONTAINER_POSITION and toPosition.y == CONST_SLOT_NECKLACE and item:getId() == STONE_SKIN_AMULET then
		local pid = self:getId()
		if exhaust[pid] then
			self:sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED)
			return false
		else
			exhaust[pid] = true
			addEvent(function() exhaust[pid] = false end, 4000, pid)
			return true
		end
	end

	-- Store Inbox
	local containerIdFrom = fromPosition.y - 64
	local containerFrom = self:getContainerById(containerIdFrom)
	if (containerFrom) then
		if (containerFrom:getId() == ITEM_STORE_INBOX and toPosition.y >= 1 and toPosition.y <= 11 and toPosition.y ~= 3) then
			self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
			return false
		end
	end

	local containerTo = self:getContainerById(toPosition.y-64)
	if (containerTo) then
		if (containerTo:getId() == ITEM_STORE_INBOX) then
			self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
			return false
		end
		-- Gold Pounch
		if (containerTo:getId() == GOLD_POUNCH) then
			if (not (item:getId() == ITEM_CRYSTAL_COIN or item:getId() == ITEM_PLATINUM_COIN or item:getId() == ITEM_GOLD_COIN)) then
				self:sendCancelMessage("You can move only money to this container.")
				return false
			end
		end
	end

	-- No move gold pounch
	if item:getId() == GOLD_POUNCH then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		return false
	end

	-- No move items with actionID 8000
	if item:getActionId() == NOT_MOVEABLE_ACTION then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		return false
	end

	-- Check two-handed weapons
	if toPosition.x ~= CONTAINER_POSITION then
		return true
	end

	if item:getTopParent() == self and bit.band(toPosition.y, 0x40) == 0 then
		local itemType, moveItem = ItemType(item:getId())
		if bit.band(itemType:getSlotPosition(), SLOTP_TWO_HAND) ~= 0 and toPosition.y == CONST_SLOT_LEFT then
			moveItem = self:getSlotItem(CONST_SLOT_RIGHT)
		elseif itemType:getWeaponType() == WEAPON_SHIELD and toPosition.y == CONST_SLOT_RIGHT then
			moveItem = self:getSlotItem(CONST_SLOT_LEFT)
			if moveItem and bit.band(ItemType(moveItem:getId()):getSlotPosition(), SLOTP_TWO_HAND) == 0 then
				return true
			end
		end

		if moveItem then
			local parent = item:getParent()
			if parent:getSize() == parent:getCapacity() then
				self:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM))
				return false
			else
				return moveItem:moveTo(parent)
			end
		end
	end

	-- Reward System
	if toPosition.x == CONTAINER_POSITION then
		local containerId = toPosition.y - 64
		local container = self:getContainerById(containerId)
		if not container then
			return true
		end

		-- Do not let the player insert items into either the Reward Container or the Reward Chest
		local itemId = container:getId()
		if itemId == ITEM_REWARD_CONTAINER or itemId == ITEM_REWARD_CHEST then
			self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
			return false
		end

		-- The player also shouldn't be able to insert items into the boss corpse
		local tile = Tile(container:getPosition())
		for _, item in ipairs(tile:getItems() or { }) do
			if item:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 and item:getName() == container:getName() then
				self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
				return false
			end
		end
	end

	-- Do not let the player move the boss corpse.
	if item:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		return false
	end

	-- Players cannot throw items on reward chest
	local tile = Tile(toPosition)
	if tile and tile:getItemById(ITEM_REWARD_CHEST) then
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		self:getPosition():sendMagicEffect(CONST_ME_POFF)
		return false
	end

	-- Players cannot throw items on teleports
	if blockTeleportTrashing and toPosition.x ~= CONTAINER_POSITION then
		local thing = Tile(toPosition):getItemByType(ITEM_TYPE_TELEPORT)
		if thing then
			self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
			self:getPosition():sendMagicEffect(CONST_ME_POFF)
			return false
		end
	end

	if tile and tile:getItemById(370) then -- Trapdoor
		self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
		self:getPosition():sendMagicEffect(CONST_ME_POFF)
		return false
	end

	if not antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder) then
		return false
	end

	return true
end

function Player:onMoveCreature(creature, fromPosition, toPosition)
	return true
end

local function hasPendingReport(name, targetName, reportType)
	local f = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "r")
	if f then
		io.close(f)
		return true
	else
		return false
	end
end

function Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
	local name = self:getName()
	if hasPendingReport(name, targetName, reportType) then
		self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your report is being processed.")
		return
	end

	local file = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "a")
	if not file then
		self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when processing your report, please contact a gamemaster.")
		return
	end

	io.output(file)
	io.write("------------------------------\n")
	io.write("Reported by: " .. name .. "\n")
	io.write("Target: " .. targetName .. "\n")
	io.write("Type: " .. reportType .. "\n")
	io.write("Reason: " .. reportReason .. "\n")
	io.write("Comment: " .. comment .. "\n")
	if reportType ~= REPORT_TYPE_BOT then
		io.write("Translation: " .. translation .. "\n")
	end
	io.write("------------------------------\n")
	io.close(file)
	self:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Thank you for reporting %s. Your report will be processed by %s team as soon as possible.", targetName, configManager.getString(configKeys.SERVER_NAME)))
	return
end

function Player:onReportBug(message, position, category)
	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)
	if self:getGroup():getAccess() and self:getDirection() == direction then
		local nextPosition = self:getPosition()
		nextPosition:getNextPosition(direction)

		self:teleportTo(nextPosition, true)
	end

	return true
end

function Player:onTradeRequest(target, item)
	getTrade = 1
	return true
end

function Player:onTradeAccept(target, item, targetItem)
	getTrade = 0
	return true
end

local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
soulCondition:setTicks(4 * 60 * 1000)
soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)

local function useStamina(player)
	local staminaMinutes = player:getStamina()
	if staminaMinutes == 0 then
		return
	end

	local playerId = player:getId()
	local currentTime = os.time()
	local timePassed = currentTime - nextUseStaminaTime[playerId]
	if timePassed <= 0 then
		return
	end

	if timePassed > 60 then
		if staminaMinutes > 2 then
			staminaMinutes = staminaMinutes - 2
		else
			staminaMinutes = 0
		end
		nextUseStaminaTime[playerId] = currentTime + 120
	else
		staminaMinutes = staminaMinutes - 1
		nextUseStaminaTime[playerId] = currentTime + 60
	end
	player:setStamina(staminaMinutes)
end

local function useStaminaXp(player)
	local staminaMinutes = player:getExpBoostStamina() / 60
	if staminaMinutes == 0 then
		return
	end

	local playerId = player:getId()
	local currentTime = os.time()
	local timePassed = currentTime - nextUseXpStamina[playerId]
	if timePassed <= 0 then
		return
	end

	if timePassed > 60 then
		if staminaMinutes > 2 then
			staminaMinutes = staminaMinutes - 2
		else
			staminaMinutes = 0
		end
		nextUseXpStamina[playerId] = currentTime + 120
	else
		staminaMinutes = staminaMinutes - 1
		nextUseXpStamina[playerId] = currentTime + 60
	end
	player:setExpBoostStamina(staminaMinutes * 60)
end

function Player:onGainExperience(source, exp, rawExp)
    if not source or source:isPlayer() then
        return exp
    end
   
    if CASTEXP[self:getName()] then
        if CASTEXP[self:getName()] <= os.time() then
            exp = (exp * CASTEXP_PERCENT) + exp
        end
    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())

	if (self:getExpBoostStamina() <= 0 and self:getStoreXpBoost() > 0) then
		self:setStoreXpBoost(0) -- reset xp boost to 0
	end

	-- More compact, after checking before (reset) it only of xp if you have
	if (self:getStoreXpBoost() > 0) then
		exp = exp + (exp * (self:getStoreXpBoost()/100)) -- Exp Boost
	end

	local party = self:getParty()
	if (party) then
		if (party:isSharedExperienceActive() and
			party:isSharedExperienceEnabled()) then
			local tableVocs = {}
			local count = 0
			local totalCount = 0
			local leaderId = party:getLeader():getVocation():getId()
			if (leaderId) then
				tableVocs[leaderId] = 1
				count = count + 1
				totalCount = totalCount + 1
			end
			for i, v in pairs(party:getMembers()) do
				local vocId = v:getVocation():getId()
				if (tableVocs[vocId] == nil) then
					tableVocs[vocId] = 1
					count = count + 1
				end
				totalCount = totalCount + 1
			end

			if (totalCount <= 10 and
				count >= 4) then
				exp = exp * 2
			end
		end
	end

	-- Exp Boost Modifier
	useStaminaXp(self)

		-- Exp stats  Redundante!
	--local staminaMinutes = self:getStamina()
	--local Boost = self:getExpBoostStamina()
	--if staminaMinutes > 2400 and self:isPremium() and Boost > 0 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*2) -- 200 = 1.0x, 200 = 2.0x, ... premium account
	--elseif staminaMinutes > 2400 and self:isPremium() and Boost <= 0 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*1.5) -- 150 = 1.0x, 150 = 1.5x, ... premium account		
	--elseif staminaMinutes <= 2400 and staminaMinutes > 840 and self:isPremium() and Boost > 0 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*1.5) -- 150 = 1.5x		premium account
	--elseif staminaMinutes > 840 and Boost > 0 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*1.5) -- 150 = 1.5x		free account
	--elseif staminaMinutes <= 840 and Boost > 0 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*1) -- 50 = 0.5x	all players
	--elseif staminaMinutes <= 840 then
	--	self:setBaseXpGain(Game.getExperienceStage(self:getLevel())*0.5) -- 50 = 0.5x	all players
	--end


	-- Extra xp to use client 12
	if self:getClient().version >= 1200 then
		exp = (exp * 0.25) + exp
	end

	-- Stamina modifier
	if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
		useStamina(self)

		local staminaMinutes = self:getStamina()
		if staminaMinutes > 2400 and self:isPremium() then
			exp = exp * 2
		elseif staminaMinutes <= 840 then
			exp = exp * 1
		end
	end

	return exp
end

function Player:onLoseExperience(exp)
	return exp
end

SkillsTable = {
  [0] = { --[[ SKILL_FIST ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 35,
      [{51, 70}] = 20,
      [{71, 80}] = 15,
	  [{81, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [1] = { --[[ SKILL_CLUB ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 35,
      [{51, 70}] = 20,
      [{71, 80}] = 15,
	  [{81, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [2] = { --[[ SKILL_SWORD ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 35,
      [{51, 70}] = 20,
      [{71, 80}] = 15,
	  [{81, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [3] = { --[[ SKILL_AXE ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 35,
      [{51, 70}] = 20,
      [{71, 80}] = 15,
	  [{81, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [4] = { --[[ SKILL_DISTANCE ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 35,
      [{51, 70}] = 20,
      [{71, 80}] = 15,
	  [{81, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [5] = { --[[ SKILL_SHIELD ]]
    stage = {
      [{0, 30}] = 50,
      [{31, 50}] = 30,
      [{51, 70}] = 20,
      [{71, 90}] = 10,
      [{91, 110}] = 5,
      [{111, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [6] = { --[[ SKILL_FISHING ]]
    stage = {
      [{0, 20}] = 40,
      [{21, 40}] = 30,
      [{41, 60}] = 20,
	  [{61, 80}] = 10,
      [{81, 100}] = 5,
      [{101, 300}] = 2
    },
    rate = configKeys.RATE_SKILL
  },
  [7] = { --[[ SKILL_MAGLEVEL ]]
    stage = {
      [{0, 25}] = 13,
      [{26, 50}] = 10,
      [{51, 70}] = 6,
	  [{71, 80}] = 5,
      [{81, 90}] = 4,
      [{91, 100}] = 3,
      [{101, 300}] = 2
    },
    rate = configKeys.RATE_MAGIC
  }
}

function getSkillsRate(level, skill)
  local skillRange = SkillsTable[skill]
  if next(skillRange.stage) then
    for sLevel, multiplier in pairs(skillRange.stage) do
      if level >= sLevel[1] and level <= sLevel[2] then
        return multiplier
      end
    end
  end
  return 1
end

function Player:onGainSkillTries(skill, tries)
	if APPLY_SKILL_MULTIPLIER == false then
    return tries
  end
  local skills = SkillsTable[skill]
  if next(skills) and skills.rate then
    local rate = configManager.getNumber(skills.rate)
    if rate > 0 then
      return tries * rate
    else
      return tries * getSkillsRate(self:getEffectiveSkillLevel(skill), skill)
    end
  end
end

function Player:onRemoveCount(item)
    -- Apenas cliente 11.x
    if self:getClient().os == CLIENTOS_NEW_WINDOWS then
  	    self:sendWaste(item:getId())
    end
end

local breakableItems = {29087, 3798, 3799, 7539, 7538}
function Player:onUseItem(item, target)	
	local itemId = item:getId()
	if (itemId == 2550) and (target:getId() == 1445) then
		if (target:getActionId() == 32931) then
			if (player:getStorageValue(SECRET_LIBRARY_FINAL_STORAGE) ~= 1) then return true end
			self:teleportTo({x = 32515, y = 32537, z = 12})
			self:getPosition():sendMagicEffect(CONST_ME_MORTAREA)
			self:updateSecretLibraryQuestlog(SL_VELLED_HOARD, 1)
		end
	end
	
	if isInArray({WEAPON_AXE, WEAPON_SWORD, WEAPON_CLUB}, ItemType(itemId):getWeaponType()) then
		if isInArray(breakableItems, target:getId()) then
			local bi_mr = math.random(1, 10)
			if (bi_mr > 7) then
				target:remove()
				target:getPosition():sendMagicEffect(CONST_ME_POFF)
				return false
			else
				target:getPosition():sendMagicEffect(CONST_ME_POFF)
				return false
			end
		end
	end
return true
end

function Player:onSendBestiaryMonsters(requestType, className)
	if (requestType == 1) then
		sendSearchedCreatures(self:getId(), requestType, className)
	else
		sendCreatures(self:getId(), requestType, className)
	end
	return true
end

function Player:onLoadCyclopedia()
	sendRaces(self:getId())
	Charms.sendCharmInfo(self:getId())
	return true
end

function Player:onBestiaryMonsterInfo(monsterId)
	sendMonsterData(self:getId(), monsterId)
	return true
end

function Player:onCharmSlots(charmId, state, raceId)
	Charms.charmSlots(self:getId(), charmId + 1, state, raceId)
	return true
end

function Player:onSendBestiaryTracker(raceId, isEnabled)
	if (isEnabled == true) then
		BestiaryTracker[#BestiaryTracker + 1] = raceId
	else
		BestiaryTracker[#BestiaryTracker] = nil
	end
	
	Bestiary.sendBestiaryTracker(self:getId(), raceId)
	return true
end

 

Link para o post
Compartilhar em outros sites

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.


  • Conteúdo Similar

    • Por cloudrun2023
      CloudRun - Sua Melhor Escolha para Hospedagem de OTServer!
      Você está procurando a solução definitiva para hospedar seu OTServer com desempenho imbatível e segurança inigualável? Não procure mais! Apresentamos a CloudRun, sua parceira confiável em serviços de hospedagem na nuvem.
       
      Recursos Exclusivos - Proteção DDoS Avançada:
      Mantenha seu OTServer online e seguro com nossa robusta proteção DDoS, garantindo uma experiência de jogo ininterrupta para seus jogadores.
       
      Servidores Ryzen 7 Poderosos: Desfrute do poder de processamento superior dos servidores Ryzen 7 para garantir um desempenho excepcional do seu OTServer. Velocidade e estabilidade garantidas!
       
      Armazenamento NVMe de Alta Velocidade:
      Reduza o tempo de carregamento do jogo com nosso armazenamento NVMe ultrarrápido. Seus jogadores vão adorar a rapidez com que podem explorar o mundo do seu OTServer.
       
      Uplink de até 1GB:
      Oferecemos uma conexão de alta velocidade com até 1GB de largura de banda, garantindo uma experiência de jogo suave e livre de lag para todos os seus jogadores, mesmo nos momentos de pico.
       
      Suporte 24 Horas:
      Estamos sempre aqui para você! Nossa equipe de suporte está disponível 24 horas por dia, 7 dias por semana, para resolver qualquer problema ou responder a qualquer pergunta que você possa ter. Sua satisfação é a nossa prioridade.
       
      Fácil e Rápido de Começar:
      Configurar seu OTServer na CloudRun é simples e rápido. Concentre-se no desenvolvimento do seu jogo enquanto cuidamos da hospedagem.
       
      Entre em Contato Agora!
      Website: https://central.cloudrun.com.br/index.php?rp=/store/cloud-ryzen-brasil
      Email: [email protected]
      Telefone: (47) 99902-5147

      Não comprometa a qualidade da hospedagem do seu OTServer. Escolha a CloudRun e ofereça aos seus jogadores a melhor experiência de jogo possível. Visite nosso site hoje mesmo para conhecer nossos planos e começar!
       
      https://central.cloudrun.com.br/index.php?rp=/store/cloud-ryzen-brasil
       
      CloudRun - Onde a Velocidade Encontra a Confiabilidade!
       

    • Por FeeTads
      SALVE rapaziada do TK, esses dias vim pensando em novos scripts pro meu OT, e em um deles eu precisava que determinada area não contasse frag pro player que matasse outros, PORÉM eu precisava que os players que morressem nessa area ainda assim tivessem as penalidades da sua morte, procurei por ai, achei alguns scripts que apenas tiravam o SKULL e não realmente o FRAG do player.

      **script atualizado 22/10/2023** - melhorado e otimizado, levei o script pra puxar as infos por .lua / creatureScripts

      vou disponibilizar o code aqui, e o que fazer pra determinada area não contar frag.

      SOURCE OTX 2 / TFS 0.x, Funciona em TFS 1.x mudando as tags e ajeitando as sintaxes.

      vá em creatureevent.cpp

      procure por:
      else if(type == "preparedeath") _type = CREATURE_EVENT_PREPAREDEATH;
      Adiciona abaixo:
      else if(type == "nocountfrag") _type = CREATURE_EVENT_NOCOUNTFRAG;

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "onPrepareDeath";  
      Adicione abaixo: 
      case CREATURE_EVENT_NOCOUNTFRAG: return "noCountFragArea";

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "cid, deathList";
      Adicione abaixo:
      case CREATURE_EVENT_NOCOUNTFRAG: return "cid, target";

      agora no mesmo arquivo, vá até o final do arquivo e adicione essa função:
      uint32_t CreatureEvent::executeNoCountFragArea(Creature* creature, Creature* target) { //noCountFragArea(cid, target) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(creature->getPosition()); std::ostringstream scriptstream; scriptstream << "local cid = " << env->addThing(creature) << std::endl; scriptstream << "local target = " << env->addThing(target) << std::endl; if(m_scriptData) scriptstream << *m_scriptData; bool result = true; if(m_interface->loadBuffer(scriptstream.str())) { lua_State* L = m_interface->getState(); result = m_interface->getGlobalBool(L, "_result", true); } m_interface->releaseEnv(); return result; } else { #ifdef __DEBUG_LUASCRIPTS__ std::ostringstream desc; desc << creature->getName(); env->setEvent(desc.str()); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(creature->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(creature)); lua_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::clog << "[Error - CreatureEvent::noCountFragArea] Call stack overflow." << std::endl; return 0; } }

      agora vá em creatureevent.h

      procure por:
      CREATURE_EVENT_PREPAREDEATH
      adicione abaixo:
      CREATURE_EVENT_NOCOUNTFRAG

      procure por:
      uint32_t executePrepareDeath(Creature* creature, DeathList deathList);
      Adicione abaixo:
      uint32_t executeNoCountFragArea(Creature* creature, Creature* target);

      agora vá em player.cpp

      procure por:
      bool Player::onKilledCreature(Creature* target, DeathEntry& entry)
      abaixo de:
      War_t enemy; if(targetPlayer->getEnemy(this, enemy)) { if(entry.isLast()) IOGuild::getInstance()->updateWar(enemy); entry.setWar(enemy); }
      Adicione o seguinte código:
      if (targetPlayer){ CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_NOCOUNTFRAG); for (const auto &event : killEvents) { if (!event->executeNoCountFragArea(this, target)) { return true; } } }

      //

      Feito isso, tudo completo na sua source, agora é necessário adicionar o creaturescript dentro do servidor

      vá até creaturescripts/scripts
      crie um arquivo chamado, "noCountFragInArea.lua"
      e dentro dele cole o código:
       
      --[[ script feito por feetads / TibiaKing ]]-- --[[ discord: feetads / FeeTads#0246 ]]-- -- Add positions here for which you do not want to count frags local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, -- from = area superior esquerda / to = area inferior direita (formando um quadrado) } local onlyKillerInArea = false -- only killer need to be in area? function noCountFragArea(cid, target) if not isCreature(cid) or not isCreature(target) then return true end local posKiller = getPlayerPosition(cid) local posTarget = getPlayerPosition(target) for i = 1, #areas do local area = areas[i] if isInArea(posKiller, area.from, area.to) then if onlyKillerInArea then return false elseif isInArea(posTarget, area.from, area.to) then return false end end end return true end
      agora em creaturescripts.xml
      <event type="nocountfrag" name="fragarea" event="script" value="noCountFragInArea.lua"/>
      agora em creaturescripts/scripts/login.lua
       procure por OU semelhante a esse:
      registerCreatureEvent(cid, "AdvanceSave")
      e abaixo adicione:
      registerCreatureEvent(cid, "fragarea")

      //


      Agora tudo certo, quando quiser adiciona uma area que não pega frag, vá até o script e apenas coloque a area, igual o demonstrado no script

      Exemplo:
      local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, [2] = {from = {x = 1000, y = 1000, z = 7}, to = {x = 1100, y = 1100, z = 7}}, }
      assim somente colocando a area no script e abrindo o server ou dando /reload, já funcionará a area como não pegar frag.
      Esse sistema pode ser bom pra areas de pvp ativo, onde você ainda quer que o player que morrer perca os atributos, como se fosse uma morte normal, porém não conta frag pra quem matar.
      Bom pra sistemas tipo castle 48h (guild war), onde há diversas mortes e risco de pegar red, atrapalhando a war.

      Façam bom proveito dos scripts, e deixem os créditos no script rsrs

      **Eu fiz as alterações e o simples código por isso vim disponibilizar, créditos meus**
    • Por Muvuka
      Abri canal a força creaturescript acho que funcione no creaturescript cria script creaturescript
       
      <channel id="9" name="HELP" logged="yes"/>
      <channel id="12" name="Report Bugs" logged="yes"/>
      <channel id="13" name="Loot" logged="yes"/>
      <channel id="14" name="Report Character Rules Tibia Rules" logged="yes"/>
      <channel id="15" name="Death Channel"/>
      <channel id="6548" name="DexSoft" level="1"/>
      <channel id="7" name="Reports" logged="yes"/>
       
      antes de 
              if(lastLogin > 0) then adicione isso:
                      doPlayerOpenChannel(cid, CHANNEL_HELP) doPlayerOpenChannel(cid, 1,  2, 3) = 1,2 ,3 Channels, entendeu? NÃO FUNCIONA EU QUERO UM MEIO DE ABRI SEM USA A SOURCE
       
      EU NÃO CONSEGUI ABRI EU NÃO TENHO SOURCE
       
       
    • Por bolachapancao
      Rapaziada seguinte preciso de um script que ao utilizar uma alavanca para até 4 jogadores.
      Os jogadores serão teleportados para hunt durante uma hora e depois de uma hora os jogadores serão teleportados de volta para o templo.
       
      Observação: caso o jogador morra ou saia da hunt o evento hunt é cancelado.

      Estou a base canary
      GitHub - opentibiabr/canary: Canary Server 13.x for OpenTibia community.
       
    • Por RAJADAO
      .Qual servidor ou website você utiliza como base? 
      Sabrehaven 8.0
      Qual o motivo deste tópico? 
      Ajuda com novos efeitos
       
      Olá amigos, gostaria de ajuda para introduzir os seguintes efeitos no meu servidor (usando o Sabrehaven 8.0 como base), adicionei algumas runas novas (avalanche, icicle, míssil sagrado, stoneshower & Thunderstorm) e alguns novos feitiços (exevo mas san, exori san, exori tera, exori frigo, exevo gran mas frigo, exevo gran mas tera, exevo tera hur, exevo frigo hur) mas nenhum dos efeitos dessas magias parece existir no servidor, alguém tem um link para um tutorial ou algo assim para que eu possa fazer isso funcionar?
      Desculpe pelo mau inglês, sou brasileiro.

      Obrigado!


      AVALANCHE RUNE id:3161 \/
      (COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_ICEAREA)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ICE)

      STONESHOWER RUNE id:3175 \/
      (COMBAT_PARAM_TYPE, COMBAT_EARTHDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_STONES)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_EARTH)

      THUNDERSTORM RUNE id:3202 \/
      (COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_E NERGYHIT)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ENERGYBALL)

      ICICLE RUNE id:3158 \/
      COMBAT_ICEDAMAGE
      CONST_ME_ICEAREA
      CONST_ANI_ICE

      SANTO MÍSSIL RUNA id:3182 \/
      (COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_HOLYDAMAGE)
      (COMBAT_PARAM_EFFECT, CONST_ME_HOLYAREA)
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_HOLY)

      CONST_ME_PLANTATTACK (exevo gran mas tera)
      CONST_ME_ICETORNADO (exevo gran mas frigo)
      CONST_ME_SMALLPLANTS (exevo tera hur)
      CONST_ME_ICEAREA (exevo frigo hur)
      CONST_ME_ICEATTACK (exori frigo)
      CONST_ME_CARNIPHILA (exori tera)

      EXORI SAN \/
      (COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_SMALLHOLY)
      CONST_ME_HOLYDAM IDADE

      EXEVO MAS SAN \/
      CONST_ME_HOLYAREA
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo