Guest User

battle.lua

a guest
Apr 11th, 2021
56
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. battleWindow = nil
  2. battleButton = nil
  3. battlePanel = nil
  4. filterPanel = nil
  5. toggleFilterButton = nil
  6. lastBattleButtonSwitched = nil
  7. battleButtonsByCreaturesList = {}
  8. creatureAgeList = {}
  9.  
  10. mouseWidget = nil
  11.  
  12. sortTypeBox = nil
  13. sortOrderBox = nil
  14. hidePlayersButton = nil
  15. hideNPCsButton = nil
  16. hideMonstersButton = nil
  17. hideSkullsButton = nil
  18. hidePartyButton = nil
  19.  
  20. function init()
  21.   g_ui.importStyle('battlebutton')
  22.   battleButton = modules.client_topmenu.addRightGameToggleButton('battleButton', tr('Battle') .. ' (Ctrl+B)', '/images/topbuttons/battle', toggle)
  23.   battleButton:setOn(true)
  24.   battleWindow = g_ui.loadUI('battle', modules.game_interface.getRightPanel())
  25.   g_keyboard.bindKeyDown('Ctrl+B', toggle)
  26.  
  27.   -- this disables scrollbar auto hiding
  28.   local scrollbar = battleWindow:getChildById('miniwindowScrollBar')
  29.   scrollbar:mergeStyle({ ['$!on'] = { }})
  30.  
  31.   battlePanel = battleWindow:recursiveGetChildById('battlePanel')
  32.  
  33.   filterPanel = battleWindow:recursiveGetChildById('filterPanel')
  34.   toggleFilterButton = battleWindow:recursiveGetChildById('toggleFilterButton')
  35.  
  36.   if isHidingFilters() then
  37.     hideFilterPanel()
  38.   end
  39.  
  40.   sortTypeBox = battleWindow:recursiveGetChildById('sortTypeBox')
  41.   sortOrderBox = battleWindow:recursiveGetChildById('sortOrderBox')
  42.   hidePlayersButton = battleWindow:recursiveGetChildById('hidePlayers')
  43.   hideNPCsButton = battleWindow:recursiveGetChildById('hideNPCs')
  44.   hideMonstersButton = battleWindow:recursiveGetChildById('hideMonsters')
  45.   hideSkullsButton = battleWindow:recursiveGetChildById('hideSkulls')
  46.   hidePartyButton = battleWindow:recursiveGetChildById('hideParty')
  47.  
  48.   mouseWidget = g_ui.createWidget('UIButton')
  49.   mouseWidget:setVisible(false)
  50.   mouseWidget:setFocusable(false)
  51.   mouseWidget.cancelNextRelease = false
  52.  
  53.   battleWindow:setContentMinimumHeight(80)
  54.  
  55.   sortTypeBox:addOption('Name', 'name')
  56.   sortTypeBox:addOption('Distance', 'distance')
  57.   sortTypeBox:addOption('Age', 'age')
  58.   sortTypeBox:addOption('Health', 'health')
  59.   sortTypeBox:setCurrentOptionByData(getSortType())
  60.   sortTypeBox.onOptionChange = onChangeSortType
  61.  
  62.   sortOrderBox:addOption('Asc.', 'asc')
  63.   sortOrderBox:addOption('Desc.', 'desc')
  64.   sortOrderBox:setCurrentOptionByData(getSortOrder())
  65.   sortOrderBox.onOptionChange = onChangeSortOrder
  66.  
  67.   connect(Creature, {
  68.     onSkullChange = updateCreatureSkull,
  69.     onEmblemChange = updateCreatureEmblem,
  70.     onOutfitChange = onCreatureOutfitChange,
  71.     onHealthPercentChange = onCreatureHealthPercentChange,
  72.     onPositionChange = onCreaturePositionChange,
  73.     onAppear = onCreatureAppear,
  74.     onDisappear = onCreatureDisappear
  75.   })
  76.  
  77.   connect(LocalPlayer, {
  78.     onPositionChange = onCreaturePositionChange
  79.   })
  80.  
  81.   connect(g_game, {
  82.     onAttackingCreatureChange = onAttack,
  83.     onFollowingCreatureChange = onFollow,
  84.     onGameEnd = removeAllCreatures
  85.   })
  86.  
  87.   checkCreatures()
  88.   battleWindow:setup()
  89. end
  90.  
  91. function terminate()
  92.   g_keyboard.unbindKeyDown('Ctrl+B')
  93.   battleButtonsByCreaturesList = {}
  94.   battleButton:destroy()
  95.   battleWindow:destroy()
  96.   mouseWidget:destroy()
  97.  
  98.   disconnect(Creature, {
  99.     onSkullChange = updateCreatureSkull,
  100.     onEmblemChange = updateCreatureEmblem,
  101.     onOutfitChange = onCreatureOutfitChange,
  102.     onHealthPercentChange = onCreatureHealthPercentChange,
  103.     onPositionChange = onCreaturePositionChange,
  104.     onAppear = onCreatureAppear,
  105.     onDisappear = onCreatureDisappear
  106.   })
  107.  
  108.   disconnect(LocalPlayer, {
  109.     onPositionChange = onCreaturePositionChange
  110.   })
  111.  
  112.   disconnect(g_game, {
  113.     onAttackingCreatureChange = onAttack,
  114.     onFollowingCreatureChange = onFollow,
  115.     onGameEnd = removeAllCreatures
  116.   })
  117. end
  118.  
  119. function toggle()
  120.   if battleButton:isOn() then
  121.     battleWindow:close()
  122.     battleButton:setOn(false)
  123.   else
  124.     battleWindow:open()
  125.     battleButton:setOn(true)
  126.   end
  127. end
  128.  
  129. function onMiniWindowClose()
  130.   battleButton:setOn(false)
  131. end
  132.  
  133. function getSortType()
  134.   local settings = g_settings.getNode('BattleList')
  135.   if not settings then
  136.     return 'name'
  137.   end
  138.   return settings['sortType']
  139. end
  140.  
  141. function setSortType(state)
  142.   settings = {}
  143.   settings['sortType'] = state
  144.   g_settings.mergeNode('BattleList', settings)
  145.  
  146.   checkCreatures()
  147. end
  148.  
  149. function getSortOrder()
  150.   local settings = g_settings.getNode('BattleList')
  151.   if not settings then
  152.     return 'asc'
  153.   end
  154.   return settings['sortOrder']
  155. end
  156.  
  157. function setSortOrder(state)
  158.   settings = {}
  159.   settings['sortOrder'] = state
  160.   g_settings.mergeNode('BattleList', settings)
  161.  
  162.   checkCreatures()
  163. end
  164.  
  165. function isSortAsc()
  166.     return getSortOrder() == 'asc'
  167. end
  168.  
  169. function isSortDesc()
  170.     return getSortOrder() == 'desc'
  171. end
  172.  
  173. function isHidingFilters()
  174.   local settings = g_settings.getNode('BattleList')
  175.   if not settings then
  176.     return false
  177.   end
  178.   return settings['hidingFilters']
  179. end
  180.  
  181. function setHidingFilters(state)
  182.   settings = {}
  183.   settings['hidingFilters'] = state
  184.   g_settings.mergeNode('BattleList', settings)
  185. end
  186.  
  187. function hideFilterPanel()
  188.   filterPanel.originalHeight = filterPanel:getHeight()
  189.   filterPanel:setHeight(0)
  190.   toggleFilterButton:getParent():setMarginTop(0)
  191.   toggleFilterButton:setImageClip(torect("0 0 21 12"))
  192.   setHidingFilters(true)
  193.   filterPanel:setVisible(false)
  194. end
  195.  
  196. function showFilterPanel()
  197.   toggleFilterButton:getParent():setMarginTop(5)
  198.   filterPanel:setHeight(filterPanel.originalHeight)
  199.   toggleFilterButton:setImageClip(torect("21 0 21 12"))
  200.   setHidingFilters(false)
  201.   filterPanel:setVisible(true)
  202. end
  203.  
  204. function toggleFilterPanel()
  205.   if filterPanel:isVisible() then
  206.     hideFilterPanel()
  207.   else
  208.     showFilterPanel()
  209.   end
  210. end
  211.  
  212. function onChangeSortType(comboBox, option)
  213.   setSortType(option:lower())
  214. end
  215.  
  216. function onChangeSortOrder(comboBox, option)
  217.   -- Replace dot in option name
  218.   setSortOrder(option:lower():gsub('[.]', ''))
  219. end
  220.  
  221. function checkCreatures()
  222.   removeAllCreatures()
  223.  
  224.   if not g_game.isOnline() then
  225.     return
  226.   end
  227.  
  228.   local player = g_game.getLocalPlayer()
  229.   local spectators = g_map.getSpectators(player:getPosition(), false)
  230.   for _, creature in ipairs(spectators) do
  231.     if doCreatureFitFilters(creature) then
  232.       addCreature(creature)
  233.     end
  234.   end
  235. end
  236.  
  237. function doCreatureFitFilters(creature)
  238.   if creature:isLocalPlayer() then
  239.     return false
  240.   end
  241.  
  242.   local pos = creature:getPosition()
  243.   if not pos then return false end
  244.  
  245.   local localPlayer = g_game.getLocalPlayer()
  246.   if pos.z ~= localPlayer:getPosition().z or not creature:canBeSeen() then return false end
  247.   return true
  248. end
  249.  
  250. function doShowCreatureAtBattle(creature)
  251.   if doCreatureFitFilters(creature) then
  252.     local hidePlayers = hidePlayersButton:isChecked()
  253.     local hideNPCs = hideNPCsButton:isChecked()
  254.     local hideMonsters = hideMonstersButton:isChecked()
  255.     local hideSkulls = hideSkullsButton:isChecked()
  256.     local hideParty = hidePartyButton:isChecked()
  257.  
  258.     if hidePlayers and creature:isPlayer() then
  259.       return false
  260.     elseif hideNPCs and creature:isNpc() then
  261.       return false
  262.     elseif hideMonsters and creature:isMonster() then
  263.       return false
  264.     elseif hideSkulls and creature:isPlayer() and creature:getSkull() == SkullNone then
  265.       return false
  266.     elseif hideParty and creature:getShield() > ShieldWhiteBlue then
  267.       return false
  268.     end
  269.  
  270.     return true
  271.   end
  272.   return false
  273. end
  274.  
  275. function onCreatureHealthPercentChange(creature, health)
  276.   local battleButton = battleButtonsByCreaturesList[creature:getId()]
  277.   if battleButton then
  278.     if getSortType() == 'health' then
  279.       removeCreature(creature)
  280.       addCreature(creature)
  281.       return
  282.     end
  283.     battleButton:setLifeBarPercent(creature:getHealthPercent())
  284.   end
  285. end
  286.  
  287. local function getDistanceBetween(p1, p2)
  288.  
  289.    return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
  290. end
  291.  
  292. function onCreaturePositionChange(creature, newPos, oldPos)
  293.   if creature:isLocalPlayer() then
  294.     if oldPos and newPos and newPos.z ~= oldPos.z then
  295.       checkCreatures()
  296.     else
  297.       -- Distance will change when moving, recalculate and move to correct index
  298.       if getSortType() == 'distance' then
  299.         local distanceList = {}
  300.         for _, battleButton in pairs(battleButtonsByCreaturesList) do
  301.           table.insert(distanceList, {distance = getDistanceBetween(newPos, battleButton.creature:getPosition()), widget = battleButton})
  302.         end
  303.  
  304.         if isSortAsc() then
  305.           table.sort(distanceList, function(a, b) return a.distance < b.distance end)
  306.         else
  307.           table.sort(distanceList, function(a, b) return a.distance > b.distance end)
  308.         end
  309.  
  310.         for i = 1, #distanceList do
  311.           battlePanel:moveChildToIndex(distanceList[i].widget, i)
  312.         end
  313.       end
  314.  
  315.       for _, battleButton in pairs(battleButtonsByCreaturesList) do
  316.         addCreature(battleButton.creature)
  317.       end
  318.     end
  319.   else
  320.     local has = hasCreature(creature)
  321.     local fit = doCreatureFitFilters(creature)
  322.     if has and not fit then
  323.       removeCreature(creature)
  324.     elseif fit then
  325.       if has and getSortType() == 'distance' then
  326.         removeCreature(creature)
  327.       end
  328.       addCreature(creature)
  329.     end
  330.   end
  331. end
  332.  
  333. function onCreatureOutfitChange(creature, outfit, oldOutfit)
  334.   if doCreatureFitFilters(creature) then
  335.     addCreature(creature)
  336.   else
  337.     removeCreature(creature)
  338.   end
  339. end
  340.  
  341. function onCreatureAppear(creature)
  342.   if creature:isLocalPlayer() then
  343.     addEvent(function()
  344.       updateStaticSquare()
  345.     end)
  346.   end
  347.  
  348.   if doCreatureFitFilters(creature) then
  349.     addCreature(creature)
  350.   end
  351. end
  352.  
  353. function onCreatureDisappear(creature)
  354.   removeCreature(creature)
  355. end
  356.  
  357. function hasCreature(creature)
  358.   return battleButtonsByCreaturesList[creature:getId()] ~= nil
  359. end
  360.  
  361. function addCreature(creature)
  362.   local creatureId = creature:getId()
  363.   local battleButton = battleButtonsByCreaturesList[creatureId]
  364.  
  365.   -- Register when creature is added to battlelist for the first time
  366.   if not creatureAgeList[creatureId] then
  367.     creatureAgeList[creatureId] = os.time()
  368.   end
  369.  
  370.   if not battleButton then
  371.     battleButton = g_ui.createWidget('BattleButton')
  372.     battleButton:setup(creature)
  373.  
  374.     battleButton.onHoverChange = onBattleButtonHoverChange
  375.     battleButton.onMouseRelease = onBattleButtonMouseRelease
  376.  
  377.     battleButtonsByCreaturesList[creatureId] = battleButton
  378.  
  379.     if creature == g_game.getAttackingCreature() then
  380.       onAttack(creature)
  381.     end
  382.  
  383.     if creature == g_game.getFollowingCreature() then
  384.       onFollow(creature)
  385.     end
  386.  
  387.     local inserted = false
  388.     local nameLower = creature:getName():lower()
  389.     local healthPercent = creature:getHealthPercent()
  390.     local playerPosition = g_game.getLocalPlayer():getPosition()
  391.     local distance = getDistanceBetween(playerPosition, creature:getPosition())
  392.     local age = creatureAgeList[creatureId]
  393.  
  394.     local childCount = battlePanel:getChildCount()
  395.     for i = 1, childCount do
  396.       local child = battlePanel:getChildByIndex(i)
  397.       local childName = child:getCreature():getName():lower()
  398.       local equal = false
  399.       if getSortType() == 'age' then
  400.         local childAge = creatureAgeList[child:getCreature():getId()]
  401.         if (age < childAge and isSortAsc()) or (age > childAge and isSortDesc()) then
  402.           battlePanel:insertChild(i, battleButton)
  403.           inserted = true
  404.           break
  405.         elseif age == childAge then
  406.           equal = true
  407.         end
  408.       elseif getSortType() == 'distance' then
  409.         local childDistance = getDistanceBetween(child:getCreature():getPosition(), playerPosition)
  410.         if (distance < childDistance and isSortAsc()) or (distance > childDistance and isSortDesc()) then
  411.           battlePanel:insertChild(i, battleButton)
  412.           inserted = true
  413.           break
  414.         elseif childDistance == distance then
  415.           equal = true
  416.         end
  417.       elseif getSortType() == 'health' then
  418.           local childHealth = child:getCreature():getHealthPercent()
  419.           if (healthPercent < childHealth and isSortAsc()) or (healthPercent > childHealth and isSortDesc()) then
  420.             battlePanel:insertChild(i, battleButton)
  421.             inserted = true
  422.             break
  423.           elseif healthPercent == childHealth then
  424.             equal = true
  425.           end
  426.       end
  427.  
  428.       -- If any other sort type is selected and values are equal, sort it by name also
  429.       if getSortType() == 'name' or equal then
  430.           local length = math.min(childName:len(), nameLower:len())
  431.           for j=1,length do
  432.             if (nameLower:byte(j) < childName:byte(j) and isSortAsc()) or (nameLower:byte(j) > childName:byte(j) and isSortDesc()) then
  433.               battlePanel:insertChild(i, battleButton)
  434.               inserted = true
  435.               break
  436.             elseif (nameLower:byte(j) > childName:byte(j) and isSortAsc()) or (nameLower:byte(j) < childName:byte(j) and isSortDesc()) then
  437.               break
  438.             elseif j == nameLower:len() and isSortAsc() then
  439.               battlePanel:insertChild(i, battleButton)
  440.               inserted = true
  441.             elseif j == childName:len() and isSortDesc() then
  442.               battlePanel:insertChild(i, battleButton)
  443.               inserted = true
  444.             end
  445.           end
  446.       end
  447.  
  448.       if inserted then
  449.         break
  450.       end
  451.     end
  452.  
  453.     -- Insert at the end if no other place is found
  454.     if not inserted then
  455.       battlePanel:insertChild(childCount + 1, battleButton)
  456.     end
  457.   else
  458.     battleButton:setLifeBarPercent(creature:getHealthPercent())
  459.   end
  460.  
  461.   local localPlayer = g_game.getLocalPlayer()
  462.   battleButton:setVisible(localPlayer:hasSight(creature:getPosition()) and creature:canBeSeen() and doShowCreatureAtBattle(creature))
  463. end
  464.  
  465. function removeAllCreatures()
  466.   creatureAgeList = {}
  467.   for _, battleButton in pairs(battleButtonsByCreaturesList) do
  468.     removeCreature(battleButton.creature)
  469.   end
  470. end
  471.  
  472. function removeCreature(creature)
  473.   if hasCreature(creature) then
  474.     local creatureId = creature:getId()
  475.  
  476.     if lastBattleButtonSwitched == battleButtonsByCreaturesList[creatureId] then
  477.       lastBattleButtonSwitched = nil
  478.     end
  479.  
  480.     battleButtonsByCreaturesList[creatureId].creature:hideStaticSquare()
  481.     battleButtonsByCreaturesList[creatureId]:destroy()
  482.     battleButtonsByCreaturesList[creatureId] = nil
  483.   end
  484. end
  485.  
  486. function onBattleButtonMouseRelease(self, mousePosition, mouseButton)
  487.   if mouseWidget.cancelNextRelease then
  488.     mouseWidget.cancelNextRelease = false
  489.     return false
  490.   end
  491.   if ((g_mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton)
  492.     or (g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
  493.     mouseWidget.cancelNextRelease = true
  494.     g_game.look(self.creature, true)
  495.     return true
  496.   elseif mouseButton == MouseLeftButton and g_keyboard.isShiftPressed() then
  497.     g_game.look(self.creature, true)
  498.     return true
  499.   elseif mouseButton == MouseRightButton and not g_mouse.isPressed(MouseLeftButton) then
  500.     modules.game_interface.createThingMenu(mousePosition, nil, nil, self.creature)
  501.     return true
  502.   elseif mouseButton == MouseLeftButton and not g_mouse.isPressed(MouseRightButton) then
  503.     if self.isTarget then
  504.       g_game.cancelAttack()
  505.     else
  506.       g_game.attack(self.creature)
  507.     end
  508.     return true
  509.   end
  510.   return false
  511. end
  512.  
  513. function onBattleButtonHoverChange(battleButton, hovered)
  514.   if battleButton.isBattleButton then
  515.     battleButton.isHovered = hovered
  516.     updateBattleButton(battleButton)
  517.   end
  518. end
  519.  
  520. function onAttack(creature)
  521.   local battleButton = creature and battleButtonsByCreaturesList[creature:getId()] or lastBattleButtonSwitched
  522.   if battleButton then
  523.     battleButton.isTarget = creature and true or false
  524.     updateBattleButton(battleButton)
  525.   end
  526. end
  527.  
  528. function onFollow(creature)
  529.   local battleButton = creature and battleButtonsByCreaturesList[creature:getId()] or lastBattleButtonSwitched
  530.   if battleButton then
  531.     battleButton.isFollowed = creature and true or false
  532.     updateBattleButton(battleButton)
  533.   end
  534. end
  535.  
  536. function updateStaticSquare()
  537.   for _, battleButton in pairs(battleButtonsByCreaturesList) do
  538.     if battleButton.isTarget then
  539.       battleButton:update()
  540.     end
  541.   end
  542. end
  543.  
  544. function updateCreatureSkull(creature, skullId)
  545.   local battleButton = battleButtonsByCreaturesList[creature:getId()]
  546.   if battleButton then
  547.     battleButton:updateSkull(skullId)
  548.   end
  549. end
  550.  
  551. function updateCreatureEmblem(creature, emblemId)
  552.   local battleButton = battleButtonsByCreaturesList[creature:getId()]
  553.   if battleButton then
  554.     battleButton:updateSkull(emblemId)
  555.   end
  556. end
  557.  
  558. function updateBattleButton(battleButton)
  559.   battleButton:update()
  560.   if battleButton.isTarget or battleButton.isFollowed then
  561.     -- set new last battle button switched
  562.     if lastBattleButtonSwitched and lastBattleButtonSwitched ~= battleButton then
  563.       lastBattleButtonSwitched.isTarget = false
  564.       lastBattleButtonSwitched.isFollowed = false
  565.       updateBattleButton(lastBattleButtonSwitched)
  566.     end
  567.     lastBattleButtonSwitched = battleButton
  568.   end
  569. end
RAW Paste Data