Advertisement
Cykada

Custom Barrier Library

Apr 9th, 2024 (edited)
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.03 KB | Source Code | 0 0
  1. if CustomBarriers == nil then CustomBarriers = {} end
  2.  
  3. -- Created by Cykada (@oniisama on discord)
  4. -- Version 1.1.0 (lib)
  5. -- check https://moddota.com/abilities/lua-modifiers/5 for a guide
  6.  
  7. function CustomBarriers:__GetBarrierOptions()
  8.    
  9.     --? All damage barriers will not block physical or magical (doesn't effect HP Removal)
  10.     self.ALL_BARRIER_ONLY_BLOCKS_PURE = false
  11.  
  12.     --? All damage barrier will also block hp removal flagged damage
  13.     self.ALL_BARRIER_BLOCK_HP_REMOVAL = false
  14.  
  15.     --? Whether barriers will have a blocked damage overhead alert
  16.     self.SHOW_BARRIER_BLOCK_OVERHEAD_ALERT = true
  17.  
  18. end
  19.  
  20. --=======================================================================================
  21.  
  22. function CustomBarriers:TurnModifierIntoBarrier( mod )
  23.  
  24.     -- inject the barriers into the declared functions
  25.     if mod.DeclareFunctions ~= nil and mod:DeclareFunctions() ~= nil then
  26.         mod.__OldDeclareFunctions = mod.DeclareFunctions
  27.     else mod.__OldDeclareFunctions = function(self) return {} end end
  28.    
  29.     mod.DeclareFunctions = function(self)
  30.         local declared_funcs = self:__OldDeclareFunctions()
  31.         table.insert( declared_funcs, MODIFIER_PROPERTY_INCOMING_PHYSICAL_DAMAGE_CONSTANT )
  32.         table.insert( declared_funcs, MODIFIER_PROPERTY_INCOMING_SPELL_DAMAGE_CONSTANT )
  33.         table.insert( declared_funcs, MODIFIER_PROPERTY_INCOMING_DAMAGE_CONSTANT )
  34.         return declared_funcs
  35.     end
  36.     mod.GetModifierIncomingPhysicalDamageConstant = self.GetModifierIncomingPhysicalDamageConstant
  37.     mod.GetModifierIncomingSpellDamageConstant = self.GetModifierIncomingSpellDamageConstant
  38.     mod.GetModifierIncomingDamageConstant = self.GetModifierIncomingDamageConstant
  39.  
  40.     mod.HandleCustomTransmitterData = function(self, data) for k,v in pairs(data) do self[k] = v end end
  41.  
  42.     -- add the setup to OnCreated()
  43.     if mod.OnCreated ~= nil then
  44.         mod.__OldOnCreated = mod.OnCreated else mod.__OldOnCreated = function() end
  45.     end
  46.     mod.OnCreated = function(self, kv)
  47.         self:__OldOnCreated(kv)
  48.         if IsServer() then CustomBarriers:__SetupBarrierModifier(self) end
  49.     end
  50.    
  51.     -- append a client update to OnRefresh()
  52.     if mod.OnRefresh ~= nil then
  53.         mod.__OldOnRefresh = mod.OnRefresh else mod.__OldOnRefresh = function(self) return end
  54.     end
  55.     mod.OnRefresh = function(self, kv)
  56.         self:__OldOnRefresh(kv)
  57.         self:OnCreated(kv)
  58.         if IsServer() then self:__BarrierUpdate() end
  59.     end
  60.  
  61.     -- check if they have made a damage filter
  62.     if mod.OnBarrierDamagedFilter == nil then mod.OnBarrierDamagedFilter = function(self) return true end end
  63.  
  64.     -- new functions that can just be copied over, respect tweaks
  65.     local general_funcs = {
  66.         "__IsBarrier",
  67.         "IsBarrierFor",
  68.         "SetBarrierType",
  69.         --"GetBarrierType",
  70.         "SetBarrierMaxHealth",
  71.         --"GetBarrierMaxHealth",
  72.         "SetBarrierHealth",
  73.         "GetBarrierHealth",
  74.         "SetBarrierInitialHealth",
  75.         "GetBarrierInitialHealth",
  76.         "IsPersistent",
  77.         "ShowOnZeroHP",
  78.         "__BarrierUpdate",
  79.         "__DoBarrierBlock",
  80.         "__GetBarrierOptions",
  81.     }
  82.     for _,func in ipairs(general_funcs) do if mod[func] == nil then mod[func] = self[func] end end
  83. end
  84.  
  85. function CustomBarriers:__SetupBarrierModifier(mod)
  86.  
  87.     -- Missing data error handler
  88.     local error_msg = "CustomBarriers Error: Undeclared barrier initialisation properties!"
  89.     local missing_props = {}
  90.     if mod.GetBarrierType == nil and mod.__barrier_type == nil then table.insert(missing_props, "- Type") end
  91.     if mod.GetBarrierMaxHealth == nil and mod.__max_barrier_health == nil then table.insert(missing_props, "- Max Health") end
  92.     if #missing_props > 0 then
  93.         print("Missing Properties;")
  94.         for _,s in ipairs(missing_props) do print(s) end
  95.         return
  96.     end
  97.  
  98.     -- setup the internal properties
  99.     if mod.GetBarrierType ~= nil then mod.__barrier_type = mod:GetBarrierType() end
  100.     mod.GetBarrierType = function(self) return self.__barrier_type end
  101.  
  102.     if mod.GetBarrierMaxHealth ~= nil then mod.__max_barrier_health = mod:GetBarrierMaxHealth() end
  103.     mod.GetBarrierMaxHealth = function (self) return self.__max_barrier_health end
  104.  
  105.     if mod.GetBarrierInitialHealth ~= nil then mod.__initial_barrier_health = mod:GetBarrierInitialHealth() end
  106.     mod.GetBarrierInitialHealth = function (self) return self.__initial_barrier_health end
  107.  
  108.     mod.__current_barrier_health = mod.__initial_barrier_health
  109.  
  110.     -- add the internal properties to the transmitter
  111.     if mod.__OldAddCustomTransmitterData == nil then
  112.         if mod.AddCustomTransmitterData ~= nil and mod:AddCustomTransmitterData() ~= nil then
  113.             mod.__OldAddCustomTransmitterData = mod.AddCustomTransmitterData
  114.         else mod.__OldAddCustomTransmitterData = function(self) return {} end end
  115.         mod.AddCustomTransmitterData = function(self)
  116.             local transmit_data = self:__OldAddCustomTransmitterData()
  117.             transmit_data.__barrier_type = mod.__barrier_type
  118.             transmit_data.__max_barrier_health = mod.__max_barrier_health
  119.             transmit_data.__current_barrier_health = mod.__current_barrier_health
  120.             transmit_data.__initial_barrier_health = mod.__initial_barrier_health
  121.             return transmit_data
  122.         end
  123.     end
  124.  
  125.     -- add the options
  126.     mod:__GetBarrierOptions()
  127.  
  128.     -- send the new data to the client
  129.     mod:SetHasCustomTransmitterData(true)
  130. end
  131.  
  132. -- generic handler for when the barrier values are changed
  133. function CustomBarriers:__BarrierUpdate()
  134.     if self.__current_barrier_health == nil then self.__current_barrier_health = 1 end
  135.  
  136.     if not self:IsPersistent() then
  137.         if self.__current_barrier_health <= 0 then return self:Destroy() end
  138.     else self.__current_barrier_health = math.max(0, self.__current_barrier_health) end
  139.  
  140.     if self.__max_barrier_health ~= nil then
  141.         self.__current_barrier_health = math.min( self.__current_barrier_health, self.__max_barrier_health )
  142.     end
  143.  
  144.     self:SendBuffRefreshToClients()
  145. end
  146.  
  147. -- set / get barrier type
  148. function CustomBarriers:GetBarrierType() return DAMAGE_TYPE_ALL end
  149. function CustomBarriers:SetBarrierType(dmg_type)
  150.     self.__barrier_type = dmg_type
  151.     self:__BarrierUpdate()
  152. end
  153.  
  154. -- destroy on 0 hp, show on 0 hp
  155. function CustomBarriers:IsPersistent() return false end
  156. function CustomBarriers:ShowOnZeroHP() return false end
  157.  
  158. function CustomBarriers:__IsBarrier()
  159.     if not self:ShowOnZeroHP() and self.__current_barrier_health <= 0 then return false else return true end
  160. end
  161.  
  162. -- compare the damage type to what the respective barrier blocks
  163. function CustomBarriers:IsBarrierFor(dmg_type)
  164.     if self:IsPersistent() then
  165.         if self.__current_barrier_health <= 0 and not self:ShowOnZeroHP() then
  166.             return false
  167.         end
  168.     end
  169.  
  170.     local b = self.__barrier_type
  171.     if b == dmg_type then return true end
  172.     if IsClient() then return false end
  173.  
  174.     if b == DAMAGE_TYPE_PURE or b == DAMAGE_TYPE_ALL then
  175.         local not_pure = (dmg_type == DAMAGE_TYPE_PHYSICAL or dmg_type == DAMAGE_TYPE_MAGICAL)
  176.         if self.ALL_BARRIER_ONLY_BLOCKS_PURE and not_pure then return false end
  177.         return true
  178.     end
  179.        
  180.     return false
  181. end
  182.  
  183. -- set / get barrier max health
  184. function CustomBarriers:SetBarrierMaxHealth(amount)
  185.     self.__max_barrier_health = math.ceil(amount)
  186.     self:__BarrierUpdate()
  187. end
  188. function CustomBarriers:GetBarrierMaxHealth() return self.__max_barrier_health end
  189.  
  190. -- set / get barrier health
  191. function CustomBarriers:GetBarrierHealth() return self.__current_barrier_health end
  192. function CustomBarriers:SetBarrierHealth(amount)
  193.     self.__current_barrier_health = math.ceil(amount)
  194.     self:__BarrierUpdate()
  195. end
  196. function CustomBarriers:GetBarrierInitialHealth() return self.__initial_barrier_health or self.__max_barrier_health end
  197. function CustomBarriers:SetBarrierInitialHealth(amount) self.__initial_barrier_health = amount end
  198.  
  199. -- functions for handling the damage block
  200. function CustomBarriers:GetModifierIncomingPhysicalDamageConstant(keys) return self:__DoBarrierBlock(1, keys) end
  201. function CustomBarriers:GetModifierIncomingSpellDamageConstant(keys) return self:__DoBarrierBlock(2, keys) end
  202. function CustomBarriers:GetModifierIncomingDamageConstant(keys) return self:__DoBarrierBlock(4, keys) end
  203.  
  204. function CustomBarriers:__DoBarrierBlock(d, keys)
  205.     if IsClient() then
  206.  
  207.         -- check and report hp on client
  208.         if not self:IsBarrierFor(d) then return end
  209.         if keys.report_max then return self.__max_barrier_health else return self.__current_barrier_health end
  210.     else
  211.  
  212.         -- check damage on server
  213.         if keys.attacker == self:GetParent() then return 0 end
  214.         if not self:IsBarrierFor(keys.damage_type) then return 0 end
  215.  
  216.         -- check if we want to block hp loss
  217.         if not self.ALL_BARRIER_BLOCK_HP_REMOVAL then
  218.             if bit.band(keys.damage_flags, DOTA_DAMAGE_FLAG_HPLOSS) == DOTA_DAMAGE_FLAG_HPLOSS then
  219.                 return 0
  220.             end
  221.         end
  222.  
  223.         -- call the filter
  224.         if not self:OnBarrierDamagedFilter(keys) then return keys.damage end
  225.     end
  226.  
  227.     -- Don't block more than the barrier hp
  228.     local blocked_amount = math.min(keys.damage, self.__current_barrier_health)
  229.     self.__current_barrier_health = self.__current_barrier_health - blocked_amount
  230.     self:__BarrierUpdate()
  231.  
  232.     -- block visual
  233.     if self.SHOW_BARRIER_BLOCK_OVERHEAD_ALERT and blocked_amount > 0 then
  234.         SendOverheadEventMessage(
  235.             self:GetParent():GetPlayerOwner(),
  236.             OVERHEAD_ALERT_BLOCK,
  237.             self:GetParent(),
  238.             blocked_amount,
  239.             keys.attacker:GetPlayerOwner()
  240.         )
  241.     end
  242.  
  243.     return -blocked_amount
  244. end
  245.  
  246. -- damage filter
  247. function CustomBarriers:OnBarrierDamagedFilter(keys) return true end
  248.  
  249. -- yeah I'm cheating, shut up
  250. function CDOTA_Buff:IsBarrier() if self.__IsBarrier ~= nil then return self:__IsBarrier() else return false end end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement