mirror of
				https://github.com/edubart/otclient.git
				synced 2025-10-26 01:04:17 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			430 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			430 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local skillsWindow = nil
 | |
| local skillsButton = nil
 | |
| 
 | |
| function init()
 | |
|   connect(LocalPlayer, {
 | |
|     onExperienceChange = onExperienceChange,
 | |
|     onLevelChange = onLevelChange,
 | |
|     onHealthChange = onHealthChange,
 | |
|     onManaChange = onManaChange,
 | |
|     onSoulChange = onSoulChange,
 | |
|     onFreeCapacityChange = onFreeCapacityChange,
 | |
|     onTotalCapacityChange = onTotalCapacityChange,
 | |
|     onStaminaChange = onStaminaChange,
 | |
|     onOfflineTrainingChange = onOfflineTrainingChange,
 | |
|     onRegenerationChange = onRegenerationChange,
 | |
|     onSpeedChange = onSpeedChange,
 | |
|     onBaseSpeedChange = onBaseSpeedChange,
 | |
|     onMagicLevelChange = onMagicLevelChange,
 | |
|     onBaseMagicLevelChange = onBaseMagicLevelChange,
 | |
|     onSkillChange = onSkillChange,
 | |
|     onBaseSkillChange = onBaseSkillChange
 | |
|   })
 | |
|   connect(g_game, {
 | |
|     onGameStart = refresh,
 | |
|     onGameEnd = offline
 | |
|   })
 | |
| 
 | |
|   skillsButton = modules.client_topmenu.addRightGameToggleButton('skillsButton', tr('Skills') .. ' (Ctrl+S)', '/images/topbuttons/skills', toggle)
 | |
|   skillsButton:setOn(true)
 | |
|   skillsWindow = g_ui.loadUI('skills', modules.game_interface.getRightPanel())
 | |
| 
 | |
|   g_keyboard.bindKeyDown('Ctrl+S', toggle)
 | |
| 
 | |
|   refresh()
 | |
|   skillsWindow:setup()
 | |
| end
 | |
| 
 | |
| function terminate()
 | |
|   disconnect(LocalPlayer, {
 | |
|     onExperienceChange = onExperienceChange,
 | |
|     onLevelChange = onLevelChange,
 | |
|     onHealthChange = onHealthChange,
 | |
|     onManaChange = onManaChange,
 | |
|     onSoulChange = onSoulChange,
 | |
|     onFreeCapacityChange = onFreeCapacityChange,
 | |
|     onTotalCapacityChange = onTotalCapacityChange,
 | |
|     onStaminaChange = onStaminaChange,
 | |
|     onOfflineTrainingChange = onOfflineTrainingChange,
 | |
|     onRegenerationChange = onRegenerationChange,
 | |
|     onSpeedChange = onSpeedChange,
 | |
|     onBaseSpeedChange = onBaseSpeedChange,
 | |
|     onMagicLevelChange = onMagicLevelChange,
 | |
|     onBaseMagicLevelChange = onBaseMagicLevelChange,
 | |
|     onSkillChange = onSkillChange,
 | |
|     onBaseSkillChange = onBaseSkillChange
 | |
|   })
 | |
|   disconnect(g_game, {
 | |
|     onGameStart = refresh,
 | |
|     onGameEnd = offline
 | |
|   })
 | |
| 
 | |
|   g_keyboard.unbindKeyDown('Ctrl+S')
 | |
|   skillsWindow:destroy()
 | |
|   skillsButton:destroy()
 | |
| end
 | |
| 
 | |
| function expForLevel(level)
 | |
|   return math.floor((50*level*level*level)/3 - 100*level*level + (850*level)/3 - 200)
 | |
| end
 | |
| 
 | |
| function expToAdvance(currentLevel, currentExp)
 | |
|   return expForLevel(currentLevel+1) - currentExp
 | |
| end
 | |
| 
 | |
| function resetSkillColor(id)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('value')
 | |
|   widget:setColor('#bbbbbb')
 | |
| end
 | |
| 
 | |
| function toggleSkill(id, state)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   skill:setVisible(state)
 | |
| end
 | |
| 
 | |
| function setSkillBase(id, value, baseValue)
 | |
|   if baseValue <= 0 or value < 0 then
 | |
|     return
 | |
|   end
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('value')
 | |
| 
 | |
|   if value > baseValue then
 | |
|     widget:setColor('#008b00') -- green
 | |
|     skill:setTooltip(baseValue .. ' +' .. (value - baseValue))
 | |
|   elseif value < baseValue then
 | |
|     widget:setColor('#b22222') -- red
 | |
|     skill:setTooltip(baseValue .. ' ' .. (value - baseValue))
 | |
|   else
 | |
|     widget:setColor('#bbbbbb') -- default
 | |
|     skill:removeTooltip()
 | |
|   end
 | |
| end
 | |
| 
 | |
| function setSkillValue(id, value)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('value')
 | |
|   widget:setText(value)
 | |
| end
 | |
| 
 | |
| function setSkillColor(id, value)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('value')
 | |
|   widget:setColor(value)
 | |
| end
 | |
| 
 | |
| function setSkillTooltip(id, value)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('value')
 | |
|   widget:setTooltip(value)
 | |
| end
 | |
| 
 | |
| function setSkillPercent(id, percent, tooltip, color)
 | |
|   local skill = skillsWindow:recursiveGetChildById(id)
 | |
|   local widget = skill:getChildById('percent')
 | |
|   if widget then
 | |
|     widget:setPercent(math.floor(percent))
 | |
| 
 | |
|     if tooltip then
 | |
|       widget:setTooltip(tooltip)
 | |
|     end
 | |
| 
 | |
|     if color then
 | |
|     	widget:setBackgroundColor(color)
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| function checkAlert(id, value, maxValue, threshold, greaterThan)
 | |
|   if greaterThan == nil then greaterThan = false end
 | |
|   local alert = false
 | |
| 
 | |
|   -- maxValue can be set to false to check value and threshold
 | |
|   -- used for regeneration checking
 | |
|   if type(maxValue) == 'boolean' then
 | |
|     if maxValue then
 | |
|       return
 | |
|     end
 | |
| 
 | |
|     if greaterThan then
 | |
|       if value > threshold then
 | |
|         alert = true
 | |
|       end
 | |
|     else
 | |
|       if value < threshold then
 | |
|         alert = true
 | |
|       end
 | |
|     end
 | |
|   elseif type(maxValue) == 'number' then
 | |
|     if maxValue < 0 then
 | |
|       return
 | |
|     end
 | |
| 
 | |
|     local percent = math.floor((value / maxValue) * 100)
 | |
|     if greaterThan then
 | |
|       if percent > threshold then
 | |
|         alert = true
 | |
|       end
 | |
|     else
 | |
|       if percent < threshold then
 | |
|         alert = true
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   if alert then
 | |
|     setSkillColor(id, '#b22222') -- red
 | |
|   else
 | |
|     resetSkillColor(id)
 | |
|   end
 | |
| end
 | |
| 
 | |
| function update()
 | |
|   local offlineTraining = skillsWindow:recursiveGetChildById('offlineTraining')
 | |
|   if not g_game.getFeature(GameOfflineTrainingTime) then
 | |
|     offlineTraining:hide()
 | |
|   else
 | |
|     offlineTraining:show()
 | |
|   end
 | |
| 
 | |
|   local regenerationTime = skillsWindow:recursiveGetChildById('regenerationTime')
 | |
|   if not g_game.getFeature(GamePlayerRegenerationTime) then
 | |
|     regenerationTime:hide()
 | |
|   else
 | |
|     regenerationTime:show()
 | |
|   end
 | |
| end
 | |
| 
 | |
| function refresh()
 | |
|   local player = g_game.getLocalPlayer()
 | |
|   if not player then return end
 | |
| 
 | |
|   if expSpeedEvent then expSpeedEvent:cancel() end
 | |
|   expSpeedEvent = cycleEvent(checkExpSpeed, 30*1000)
 | |
| 
 | |
|   onExperienceChange(player, player:getExperience())
 | |
|   onLevelChange(player, player:getLevel(), player:getLevelPercent())
 | |
|   onHealthChange(player, player:getHealth(), player:getMaxHealth())
 | |
|   onManaChange(player, player:getMana(), player:getMaxMana())
 | |
|   onSoulChange(player, player:getSoul())
 | |
|   onFreeCapacityChange(player, player:getFreeCapacity())
 | |
|   onStaminaChange(player, player:getStamina())
 | |
|   onMagicLevelChange(player, player:getMagicLevel(), player:getMagicLevelPercent())
 | |
|   onOfflineTrainingChange(player, player:getOfflineTrainingTime())
 | |
|   onRegenerationChange(player, player:getRegenerationTime())
 | |
|   onSpeedChange(player, player:getSpeed())
 | |
| 
 | |
|   local hasAdditionalSkills = g_game.getFeature(GameAdditionalSkills)
 | |
|   for i = Skill.Fist, Skill.ManaLeechAmount do
 | |
|     onSkillChange(player, i, player:getSkillLevel(i), player:getSkillLevelPercent(i))
 | |
|     onBaseSkillChange(player, i, player:getSkillBaseLevel(i))
 | |
| 
 | |
|     if i > Skill.Fishing then
 | |
|       toggleSkill('skillId'..i, hasAdditionalSkills)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   update()
 | |
| 
 | |
|   local contentsPanel = skillsWindow:getChildById('contentsPanel')
 | |
|   skillsWindow:setContentMinimumHeight(44)
 | |
|   if hasAdditionalSkills then
 | |
|     skillsWindow:setContentMaximumHeight(480)
 | |
|   else
 | |
|     skillsWindow:setContentMaximumHeight(390)
 | |
|   end
 | |
| end
 | |
| 
 | |
| function offline()
 | |
|   if expSpeedEvent then expSpeedEvent:cancel() expSpeedEvent = nil end
 | |
| end
 | |
| 
 | |
| function toggle()
 | |
|   if skillsButton:isOn() then
 | |
|     skillsWindow:close()
 | |
|     skillsButton:setOn(false)
 | |
|   else
 | |
|     skillsWindow:open()
 | |
|     skillsButton:setOn(true)
 | |
|   end
 | |
| end
 | |
| 
 | |
| function checkExpSpeed()
 | |
|   local player = g_game.getLocalPlayer()
 | |
|   if not player then return end
 | |
| 
 | |
|   local currentExp = player:getExperience()
 | |
|   local currentTime = g_clock.seconds()
 | |
|   if player.lastExps ~= nil then
 | |
|     player.expSpeed = (currentExp - player.lastExps[1][1])/(currentTime - player.lastExps[1][2])
 | |
|     onLevelChange(player, player:getLevel(), player:getLevelPercent())
 | |
|   else
 | |
|     player.lastExps = {}
 | |
|   end
 | |
|   table.insert(player.lastExps, {currentExp, currentTime})
 | |
|   if #player.lastExps > 30 then
 | |
|     table.remove(player.lastExps, 1)
 | |
|   end
 | |
| end
 | |
| 
 | |
| function onMiniWindowClose()
 | |
|   skillsButton:setOn(false)
 | |
| end
 | |
| 
 | |
| function onSkillButtonClick(button)
 | |
|   local percentBar = button:getChildById('percent')
 | |
|   if percentBar then
 | |
|     percentBar:setVisible(not percentBar:isVisible())
 | |
|     if percentBar:isVisible() then
 | |
|       button:setHeight(21)
 | |
|     else
 | |
|       button:setHeight(21 - 6)
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| function onExperienceChange(localPlayer, value)
 | |
|   setSkillValue('experience', comma_value(value))
 | |
| end
 | |
| 
 | |
| function onLevelChange(localPlayer, value, percent)
 | |
|   setSkillValue('level', comma_value(value))
 | |
|   local text = tr('You have %s percent to go', 100 - percent) .. '\n' ..
 | |
|                tr('%s of experience left', expToAdvance(localPlayer:getLevel(), localPlayer:getExperience()))
 | |
| 
 | |
|   if localPlayer.expSpeed ~= nil then
 | |
|      local expPerHour = math.floor(localPlayer.expSpeed * 3600)
 | |
|      if expPerHour > 0 then
 | |
|         local nextLevelExp = expForLevel(localPlayer:getLevel()+1)
 | |
|         local hoursLeft = (nextLevelExp - localPlayer:getExperience()) / expPerHour
 | |
|         local minutesLeft = math.floor((hoursLeft - math.floor(hoursLeft))*60)
 | |
|         hoursLeft = math.floor(hoursLeft)
 | |
|         text = text .. '\n' .. tr('%s of experience per hour', comma_value(expPerHour))
 | |
|         text = text .. '\n' .. tr('Next level in %d hours and %d minutes', hoursLeft, minutesLeft)
 | |
|      end
 | |
|   end
 | |
| 
 | |
|   setSkillPercent('level', percent, text)
 | |
| end
 | |
| 
 | |
| function onHealthChange(localPlayer, health, maxHealth)
 | |
|   setSkillValue('health', comma_value(health))
 | |
|   checkAlert('health', health, maxHealth, 30)
 | |
| end
 | |
| 
 | |
| function onManaChange(localPlayer, mana, maxMana)
 | |
|   setSkillValue('mana', comma_value(mana))
 | |
|   checkAlert('mana', mana, maxMana, 30)
 | |
| end
 | |
| 
 | |
| function onSoulChange(localPlayer, soul)
 | |
|   setSkillValue('soul', comma_value(soul))
 | |
| end
 | |
| 
 | |
| function onFreeCapacityChange(localPlayer, freeCapacity)
 | |
|   setSkillValue('capacity', comma_value(freeCapacity))
 | |
|   checkAlert('capacity', freeCapacity, localPlayer:getTotalCapacity(), 20)
 | |
| end
 | |
| 
 | |
| function onTotalCapacityChange(localPlayer, totalCapacity)
 | |
|   checkAlert('capacity', localPlayer:getFreeCapacity(), totalCapacity, 20)
 | |
| end
 | |
| 
 | |
| function onStaminaChange(localPlayer, stamina)
 | |
|   local hours = math.floor(stamina / 60)
 | |
|   local minutes = stamina % 60
 | |
|   if minutes < 10 then
 | |
|     minutes = '0' .. minutes
 | |
|   end
 | |
|   local percent = math.floor(100 * stamina / (42 * 60)) -- max is 42 hours --TODO not in all client versions
 | |
| 
 | |
|   setSkillValue('stamina', hours .. ":" .. minutes)
 | |
| 
 | |
|   --TODO not all client versions have premium time
 | |
|   if stamina > 2400 and g_game.getClientVersion() >= 1038 and localPlayer:isPremium() then
 | |
|   	local text = tr("You have %s hours and %s minutes left", hours, minutes) .. '\n' ..
 | |
| 		tr("Now you will gain 50%% more experience")
 | |
| 		setSkillPercent('stamina', percent, text, 'green')
 | |
| 	elseif stamina > 2400 and g_game.getClientVersion() >= 1038 and not localPlayer:isPremium() then
 | |
| 		local text = tr("You have %s hours and %s minutes left", hours, minutes) .. '\n' ..
 | |
| 		tr("You will not gain 50%% more experience because you aren't premium player, now you receive only 1x experience points")
 | |
| 		setSkillPercent('stamina', percent, text, '#89F013')
 | |
| 	elseif stamina >= 2400 and g_game.getClientVersion() < 1038 then
 | |
| 		local text = tr("You have %s hours and %s minutes left", hours, minutes) .. '\n' ..
 | |
| 		tr("If you are premium player, you will gain 50%% more experience")
 | |
| 		setSkillPercent('stamina', percent, text, 'green')
 | |
| 	elseif stamina < 2400 and stamina > 840 then
 | |
| 		setSkillPercent('stamina', percent, tr("You have %s hours and %s minutes left", hours, minutes), 'orange')
 | |
| 	elseif stamina <= 840 and stamina > 0 then
 | |
| 		local text = tr("You have %s hours and %s minutes left", hours, minutes) .. "\n" ..
 | |
| 		tr("You gain only 50%% experience and you don't may gain loot from monsters")
 | |
| 		setSkillPercent('stamina', percent, text, 'red')
 | |
| 	elseif stamina == 0 then
 | |
| 		local text = tr("You have %s hours and %s minutes left", hours, minutes) .. "\n" ..
 | |
| 		tr("You don't may receive experience and loot from monsters")
 | |
| 		setSkillPercent('stamina', percent, text, 'black')
 | |
| 	end
 | |
| end
 | |
| 
 | |
| function onOfflineTrainingChange(localPlayer, offlineTrainingTime)
 | |
|   if not g_game.getFeature(GameOfflineTrainingTime) then
 | |
|     return
 | |
|   end
 | |
|   local hours = math.floor(offlineTrainingTime / 60)
 | |
|   local minutes = offlineTrainingTime % 60
 | |
|   if minutes < 10 then
 | |
|     minutes = '0' .. minutes
 | |
|   end
 | |
|   local percent = 100 * offlineTrainingTime / (12 * 60) -- max is 12 hours
 | |
| 
 | |
|   setSkillValue('offlineTraining', hours .. ":" .. minutes)
 | |
|   setSkillPercent('offlineTraining', percent, tr('You have %s percent', percent))
 | |
| end
 | |
| 
 | |
| function onRegenerationChange(localPlayer, regenerationTime)
 | |
|   if not g_game.getFeature(GamePlayerRegenerationTime) or regenerationTime < 0 then
 | |
|     return
 | |
|   end
 | |
|   local minutes = math.floor(regenerationTime / 60)
 | |
|   local seconds = regenerationTime % 60
 | |
|   if seconds < 10 then
 | |
|     seconds = '0' .. seconds
 | |
|   end
 | |
| 
 | |
|   setSkillValue('regenerationTime', minutes .. ":" .. seconds)
 | |
|   checkAlert('regenerationTime', regenerationTime, false, 300)
 | |
| end
 | |
| 
 | |
| function onSpeedChange(localPlayer, speed)
 | |
|   setSkillValue('speed', comma_value(speed))
 | |
| 
 | |
|   onBaseSpeedChange(localPlayer, localPlayer:getBaseSpeed())
 | |
| end
 | |
| 
 | |
| function onBaseSpeedChange(localPlayer, baseSpeed)
 | |
|   setSkillBase('speed', localPlayer:getSpeed(), baseSpeed)
 | |
| end
 | |
| 
 | |
| function onMagicLevelChange(localPlayer, magiclevel, percent)
 | |
|   setSkillValue('magiclevel', comma_value(magiclevel))
 | |
|   setSkillPercent('magiclevel', percent, tr('You have %s percent to go', 100 - percent))
 | |
| 
 | |
|   onBaseMagicLevelChange(localPlayer, localPlayer:getBaseMagicLevel())
 | |
| end
 | |
| 
 | |
| function onBaseMagicLevelChange(localPlayer, baseMagicLevel)
 | |
|   setSkillBase('magiclevel', localPlayer:getMagicLevel(), baseMagicLevel)
 | |
| end
 | |
| 
 | |
| function onSkillChange(localPlayer, id, level, percent)
 | |
|   setSkillValue('skillId' .. id, comma_value(level))
 | |
|   setSkillPercent('skillId' .. id, percent, tr('You have %s percent to go', 100 - percent))
 | |
| 
 | |
|   onBaseSkillChange(localPlayer, id, localPlayer:getSkillBaseLevel(id))
 | |
| end
 | |
| 
 | |
| function onBaseSkillChange(localPlayer, id, baseLevel)
 | |
|   setSkillBase('skillId'..id, localPlayer:getSkillLevel(id), baseLevel)
 | |
| end
 | 
