- Joined
- Mar 6, 2006
- Messages
- 9,243
I'm looking for some feedback on this system. How to improve it or are there some things I've missed. I'm going to use it in a project.
The system makes each point of armor reduce damage by one point.
Here's how it works:
All unit types are save into an array. There's also an array for attack- and defence types and base armor. There's a hidden dummy ability that is leveled, it keeps track of the armor value.
All items are set to an array, and there's an array for item armor values. When an item is acquired/lost, , I loop through the item types and then find the armor value. The level of the armor ability is changed.
There's a boolean that checks whether the damage is from a normal attack or from an ability. When "unit is attacked" the boolean is saved as true so the next damage the unit does by normal attack. When a "unit begins casting an ability", the booleas is set to false since the next damage will be from spells.
I have two damage modifier arrays. One is for default Blizzard values and another for custom modifiers.
When a unit takes damage, I save the damage to a variable. Then I load the attack- and defence types and get the damage modifier based on them.
I divide the damage done with the Blizzard modifier to get unmodified damage. Then that damage is modified by custom modifier and armor.
I set the damaged unit's life to max life of the unit. That prevents it from dying if armor is high enough to soak enough damage.
Then I calculate what the unit's health should be after the real damage is applied.
I set the life to correct value after a timer with 0 expiration time expires.
So normal attacks can be configured to use custom modifiers, spells use default Blizz modifiers.
I appreciate the time taken to test it a bit. Don't mind the GUI stuff, it's incomplete. vJASS system works. Hit ESC to spawn a knight to your right.
The system makes each point of armor reduce damage by one point.
Here's how it works:
All unit types are save into an array. There's also an array for attack- and defence types and base armor. There's a hidden dummy ability that is leveled, it keeps track of the armor value.
All items are set to an array, and there's an array for item armor values. When an item is acquired/lost, , I loop through the item types and then find the armor value. The level of the armor ability is changed.
There's a boolean that checks whether the damage is from a normal attack or from an ability. When "unit is attacked" the boolean is saved as true so the next damage the unit does by normal attack. When a "unit begins casting an ability", the booleas is set to false since the next damage will be from spells.
I have two damage modifier arrays. One is for default Blizzard values and another for custom modifiers.
When a unit takes damage, I save the damage to a variable. Then I load the attack- and defence types and get the damage modifier based on them.
I divide the damage done with the Blizzard modifier to get unmodified damage. Then that damage is modified by custom modifier and armor.
I set the damaged unit's life to max life of the unit. That prevents it from dying if armor is high enough to soak enough damage.
Then I calculate what the unit's health should be after the real damage is applied.
I set the life to correct value after a timer with 0 expiration time expires.
So normal attacks can be configured to use custom modifiers, spells use default Blizz modifiers.
JASS:
library ArmorSystem initializer InitTrig_Armor_System
globals
// How many item types the system uses
private constant integer ITEMS = 3
// How many unit types the system uses
private constant integer UNITS = 5
// Raw code of armor AbilityId
private constant integer ARMORABILITY = 'A000'
// Is floating text displayed
private constant boolean FLOAT = true
private integer itype
private integer armor
private boolean melee
private string string1
private string string2
private real modifier
private real finalDamage
private group damageGroup = CreateGroup()
trigger damageDetect = CreateTrigger()
private timer damageDeal = CreateTimer()
private constant integer array unitTypes
private constant integer array baseArmor
private constant integer array itemTypes
private constant integer array armorValues
private constant string array attackTypes
private constant string array defenceTypes
private constant real array damageModifiersB
private constant real array damageModifiersC
private hashtable Unit_Hash = InitHashtable()
endglobals
private function init_Items takes nothing returns nothing
// Set item type raw codes here. Don't use index 0.
// Also set armor values for each item.
set itemTypes[1] = 'I000'
set armorValues[1] = 2
set itemTypes[2] = 'I001'
set armorValues[2] = 3
set itemTypes[3] = 'I002'
set armorValues[3] = 15
endfunction
private function init_Unit_Data takes nothing returns nothing
// Set unit types, defence- and attack types and base armor.
set unitTypes[1] = 'Hpal'
set defenceTypes[1] = "5"
set attackTypes[1] = "7"
set baseArmor[1] = 3
set unitTypes[2] = 'Hamg'
set defenceTypes[2] = "1"
set attackTypes[2] = "4"
set baseArmor[2] = 1
set unitTypes[3] = 'Hmkg'
set defenceTypes[3] = "3"
set attackTypes[3] = "3"
set baseArmor[3] = 2
set unitTypes[4] = 'Hblm'
set defenceTypes[4] = "6"
set attackTypes[4] = "2"
set baseArmor[4] = 0
set unitTypes[5] = 'hkni'
set defenceTypes[5] = "3"
set attackTypes[5] = "1"
set baseArmor[5] = 5
endfunction
private function init_Custom_Values takes nothing returns nothing
// --------------------------------------------------
// YOU CAN FREELY EDIT THESE VALUES
// Example: [11] = Normal damage to light armor
// [43] = Magic damage to heavy armor
// --------------------------------------------------
// Attack Types Armor Types
// 1 = Normal 1 = Light
// 2 = Pierce 2 = Medium
// 3 = Siege 3 = Heavy
// 4 = Magic 4 = Fortified
// 5 = Chaos 5 = Hero
// 6 = Spells 6 = Unarmored
// 7 = Hero
// --Normal damage--
set damageModifiersC[11] = 1.00
set damageModifiersC[12] = 1.50
set damageModifiersC[13] = 1.00
set damageModifiersC[14] = 0.70
set damageModifiersC[15] = 1.00
set damageModifiersC[16] = 1.00
// --Pierce damage--
set damageModifiersC[21] = 2.00
set damageModifiersC[22] = 0.75
set damageModifiersC[23] = 1.00
set damageModifiersC[24] = 0.35
set damageModifiersC[25] = 0.50
set damageModifiersC[26] = 1.50
// --Siege damage--
set damageModifiersC[31] = 1.00
set damageModifiersC[32] = 0.50
set damageModifiersC[33] = 1.00
set damageModifiersC[34] = 1.50
set damageModifiersC[35] = 0.50
set damageModifiersC[36] = 1.50
// --Magic damage--
set damageModifiersC[41] = 1.25
set damageModifiersC[42] = 0.75
set damageModifiersC[43] = 2.00
set damageModifiersC[44] = 0.35
set damageModifiersC[45] = 0.50
set damageModifiersC[46] = 1.00
// --Chaos damage--
set damageModifiersC[51] = 1.00
set damageModifiersC[52] = 1.00
set damageModifiersC[53] = 1.00
set damageModifiersC[54] = 1.00
set damageModifiersC[55] = 1.00
set damageModifiersC[56] = 1.00
// --Spells damage--
set damageModifiersC[61] = 1.00
set damageModifiersC[62] = 1.00
set damageModifiersC[63] = 1.00
set damageModifiersC[64] = 1.00
set damageModifiersC[65] = 0.70
set damageModifiersC[66] = 1.00
// --Hero damage--
set damageModifiersC[71] = 1.00
set damageModifiersC[72] = 1.00
set damageModifiersC[73] = 1.00
set damageModifiersC[74] = 0.50
set damageModifiersC[75] = 1.00
set damageModifiersC[76] = 1.00
endfunction
//*************************************//
// END OF CONFIGURABLE SECTION //
//*************************************//
private function init_Blizz_Values takes nothing returns nothing
// --------------------------------------------------
// DON'T CHANGE THESE VALUES !
// The are default Blizzard values to get unmodified damage.
// Example: [11] = Normal damage to light armor
// --------------------------------------------------
// --Normal damage--
set damageModifiersB[11] = 1.00
set damageModifiersB[12] = 1.50
set damageModifiersB[13] = 1.00
set damageModifiersB[14] = 0.70
set damageModifiersB[15] = 1.00
set damageModifiersB[16] = 1.00
// --Pierce damage--
set damageModifiersB[21] = 2.00
set damageModifiersB[22] = 0.75
set damageModifiersB[23] = 1.00
set damageModifiersB[24] = 0.35
set damageModifiersB[25] = 0.50
set damageModifiersB[26] = 1.50
// --Siege damage--
set damageModifiersB[31] = 1.00
set damageModifiersB[32] = 0.50
set damageModifiersB[33] = 1.00
set damageModifiersB[34] = 1.50
set damageModifiersB[35] = 0.50
set damageModifiersB[36] = 1.50
// --Magic damage--
set damageModifiersB[41] = 1.25
set damageModifiersB[42] = 0.75
set damageModifiersB[43] = 2.00
set damageModifiersB[44] = 0.35
set damageModifiersB[45] = 0.50
set damageModifiersB[46] = 1.00
// --Chaos damage--
set damageModifiersB[51] = 1.00
set damageModifiersB[52] = 1.00
set damageModifiersB[53] = 1.00
set damageModifiersB[54] = 1.00
set damageModifiersB[55] = 1.00
set damageModifiersB[56] = 1.00
// --Spells damage--
set damageModifiersB[61] = 1.00
set damageModifiersB[62] = 1.00
set damageModifiersB[63] = 1.00
set damageModifiersB[64] = 1.00
set damageModifiersB[65] = 0.70
set damageModifiersB[66] = 1.00
// --Hero damage--
set damageModifiersB[71] = 1.00
set damageModifiersB[72] = 1.00
set damageModifiersB[73] = 1.00
set damageModifiersB[74] = 0.50
set damageModifiersB[75] = 1.00
set damageModifiersB[76] = 1.00
endfunction
// Updates armor value when acquiring an item.
private function Acquire_Item takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetHandleId(u)
local integer i = 1
set itype = GetItemTypeId(GetManipulatedItem())
loop
exitwhen i > ITEMS
if itype == itemTypes[i] then
call SetUnitAbilityLevel( u , ARMORABILITY , GetUnitAbilityLevel( u , ARMORABILITY ) + armorValues[i] )
set i = 10000
endif
set i = i + 1
endloop
set u = null
endfunction
// Updates armor value when losing an item
private function Lose_Item takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetHandleId(u)
local integer i = 1
set itype = GetItemTypeId(GetManipulatedItem())
loop
exitwhen i > ITEMS
if itype == itemTypes[i] then
call SetUnitAbilityLevel( u , ARMORABILITY , GetUnitAbilityLevel( u , ARMORABILITY ) - armorValues[i] )
set i = 10000
endif
set i = i + 1
endloop
set u = null
endfunction
// Creates floating text above the damaged unit
private function damageDisplay takes unit u , integer damage , integer armor returns nothing
set string1 = I2S(damage) + " |c0080FF80(-" + I2S(armor) + ")"
call CreateTextTagUnitBJ( string1 , u , 50 , 10 , 100 , 0 , 0 , 0 )
call SetTextTagVelocity( bj_lastCreatedTextTag , 0, 0.05 )
call SetTextTagPermanent( bj_lastCreatedTextTag , false )
call SetTextTagLifespan( bj_lastCreatedTextTag , 2.00 )
call SetTextTagFadepoint( bj_lastCreatedTextTag , 1.70 )
endfunction
// Deals damage to the damaged unit
private function dealDamage takes nothing returns nothing
local unit u = GetEnumUnit()
local integer id = GetHandleId(u)
local real life = LoadReal( Unit_Hash , id , StringHash("life") )
call SetUnitState( u , UNIT_STATE_LIFE , life )
call GroupRemoveUnit( damageGroup , u )
set u = null
endfunction
// Handles the expiring timer
private function timerExpires takes nothing returns nothing
call ForGroup( damageGroup , function dealDamage )
endfunction
// Damage detection, calculation
private function Damage_Actions takes nothing returns nothing
local unit u1 = GetTriggerUnit()
local unit u2 = GetEventDamageSource()
local integer id1 = GetHandleId(u1)
local integer id2 = GetHandleId(u2)
local integer index
local real damage = GetEventDamage()
local real life = GetUnitState( u1 , UNIT_STATE_LIFE )
local real max_life = GetUnitState( u1 , UNIT_STATE_MAX_LIFE )
// Get armor value
set armor = GetUnitAbilityLevel( u1 , ARMORABILITY )
// This boolean checks whether the damage is deal with normal attack
if LoadBoolean( Unit_Hash , id2 , StringHash("boolean") ) == true then
// If it is then load defence- and attack types of the attacker
set string1 = LoadStringBJ( StringHash("defence") , id1 , Unit_Hash )
set string2 = LoadStringBJ( StringHash("attack") , id2 , Unit_Hash )
// Converts the types to an index
set index = S2I( string2 + string1 )
// Calculates the damage unmodified by Blizzard's values
set damage = damage / damageModifiersB[index]
// Loads custom damage modifier
set modifier = damageModifiersC[index]
else
// If damage done by spell or ability, then custom modifier
// is 1, standard Blizzard modifier is used.
set modifier = 1.00
endif
// Calculate how much damage should be dealt
set finalDamage = damage * modifier - I2R(armor)
// If armor soaks all damage, set damage to 0
// and set armor to damage done, so damage done is displayed correctly
if finalDamage <= 0 then
set finalDamage = 0
set armor = R2I(damage)
endif
// Prevents the unit from dying before armor is applied.
// Unit that has 10 hp, 5 armor and takes 10 damage would die without this.
if life <= damage then
call SetUnitState( u1 , UNIT_STATE_LIFE , damage + 1 )
endif
// Saves the value that the unit's life should be set to
call SaveReal( Unit_Hash , id1 , StringHash("life") , life - finalDamage )
// Add the damaged unit to a group and starts the timer which sets the life to correct value
call GroupAddUnit( damageGroup , u1 )
call TimerStart( damageDeal , 0 , false , function timerExpires )
// Displays damage
if FLOAT == true then
call damageDisplay( u1 , R2I(finalDamage) , armor )
endif
set u1 = null
set u2 = null
endfunction
// Configures units that are in the map at map initialization
// or that enter playable map area during the game
private function Set_Unit_Data takes nothing returns boolean
local integer i = 1
local integer j
local integer k
local integer id
local integer utype
local unit u = GetEnumUnit()
// GetEnumUnit is used to add units at map initialization
// GetTriggerUnit is used to add units that enter the map later
if u == null then
set u = GetTriggerUnit()
endif
set id = GetHandleId(u)
set utype = GetUnitTypeId(u)
// Loops through unit types to find a matching unit type
loop
if utype == unitTypes[i] then
// Stores the attack- and defence types
call SaveStringBJ( attackTypes[i] , StringHash("attack") , id , Unit_Hash )
call SaveStringBJ( defenceTypes[i] , StringHash("defence") , id , Unit_Hash )
// Enables damage detection for this unit
call TriggerRegisterUnitEvent( damageDetect , u , EVENT_UNIT_DAMAGED )
// Sets base armor for the unit
if baseArmor[i] > 0 then
call UnitAddAbility( u , ARMORABILITY )
call SetUnitAbilityLevel( u , ARMORABILITY , baseArmor[i] )
endif
// Loops through items, adds armor value
set j = 0
loop
set itype = GetItemTypeId(UnitItemInSlot( u , j ))
if itype != null then
set k = 1
loop
if itype == itemTypes[k] then
call SetUnitAbilityLevel( u , ARMORABILITY , GetUnitAbilityLevel( u , ARMORABILITY ) + armorValues[k] )
set k = ITEMS + 1
endif
set k = k + 1
exitwhen k > ITEMS
endloop
endif
set j = j + 1
exitwhen j > 5
endloop
// Breaks out of the loop when unit type is found
set i = 10000
endif
set i = i + 1
exitwhen i > UNITS
endloop
set u = null
return true
endfunction
// Picks all units in the playable map area at map initialization
// and enables the system for them
private function Init_Units takes nothing returns nothing
local group g = CreateGroup()
call GroupEnumUnitsInRect( g , bj_mapInitialPlayableArea , null )
call ForGroup( g , function Set_Unit_Data )
call DestroyGroup(g)
set g = null
endfunction
// If a unit begins casting an ability, then the damage it deals after that won't be from it's normal attack
private function Spell_Effect_Actions takes nothing returns nothing
call SaveBoolean( Unit_Hash , GetHandleId(GetTriggerUnit()) , StringHash("boolean") , false )
endfunction
// If a unit attacks a unit, then the next damage it deals will be from it's normal attack
private function Attacked_Actions takes nothing returns nothing
call SaveBoolean( Unit_Hash , GetHandleId(GetAttacker()) , StringHash("boolean") , true )
endfunction
private function InitTrig_Armor_System takes nothing returns nothing
local region mapArea = CreateRegion()
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
local trigger t4 = CreateTrigger()
local trigger t5 = CreateTrigger()
call RegionAddRect( mapArea , bj_mapInitialPlayableArea )
call TriggerAddAction( t1 , function Attacked_Actions )
call TriggerAddAction( t2 , function Spell_Effect_Actions )
call TriggerAddAction( t3 , function Set_Unit_Data )
call TriggerAddAction( t4 , function Acquire_Item )
call TriggerAddAction( t5 , function Lose_Item )
call TriggerAddAction( damageDetect , function Damage_Actions )
call TriggerRegisterAnyUnitEventBJ( t1 , EVENT_PLAYER_UNIT_ATTACKED )
call TriggerRegisterAnyUnitEventBJ( t2 , EVENT_PLAYER_UNIT_SPELL_CAST )
//call TriggerRegisterAnyUnitEventBJ( t2 , EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerRegisterEnterRegion( t3 , mapArea , null )
call TriggerRegisterAnyUnitEventBJ( t4 , EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerRegisterAnyUnitEventBJ( t5 , EVENT_PLAYER_UNIT_DROP_ITEM )
call init_Items()
call init_Unit_Data()
call Init_Units()
call init_Blizz_Values()
call init_Custom_Values()
endfunction
endlibrary
I appreciate the time taken to test it a bit. Don't mind the GUI stuff, it's incomplete. vJASS system works. Hit ESC to spawn a knight to your right.
Attachments
Last edited: