|
[jass]
//*******************************************************************************
//* *
//* Unit Properties *
//* v.D *
//* (because numbers are for ninnies) *
//* *
//* By: Cassiel and Kaz *
//* *
//*******************************************************************************
//*******************************************************************************
// The ObjectMerger command will automatically generate all the necessary
// abilities for you using the external LUA script, which shouldbe placed in the
// same directory as the map you're installing to. It only needs to be run once.
//
////! external ObjectMerger UnitPropertiesGenerator.lua
library UnitProperties initializer Init
globals
//*******************************************************************************
// Max: Specifies the highest power of 2 the property ability sets use. A Max
// of 8 means the system supports values of +/- 511. Higher values
// requires reconfiguring the system and cannot be automated.
//
// Offset: Specifies the difference between the + and - abilities for any
// property.
//
private constant integer Max = 8
private constant integer Offset = 512
//*******************************************************************************
// These globals reference the starting abilities for properties that use binary
// counting. Changing them means changing the rawcodes of all the abilities the
// system uses for that property. As far as I know this list includes all
// properties that stack linearly and are binary countable.
//
constant integer Agi = 'AG+a'
constant integer Int = 'IN+a'
constant integer Str = 'ST+a'
constant integer AttackSpeed = 'AT+a'
constant integer Armor = 'AR+a'
constant integer Damage = 'DA+a'
constant integer LifeRegen = 'LI+a'
constant integer ManaRegenPercent = 'MR+a'
//*******************************************************************************
// These globals reference the starting abilities for properties that use the
// life/mana bug.
//
constant integer MaxLife = 'Lif+'
constant integer MaxMana = 'Man+'
// ******************************************************************************
// Timer: Used for any periodic properties that you want/need to
// trigger. Static mana gain (as opposed to percentage mana gain)
// is included in the system as an example.
//
// pow2: Powers of 2 up to 30 are calculated and stored in this array at
// Init.
//
// UnitProperties: This array stores the properties struct for each unit that has
// it. It and the properties struct are public so that advanced
// users have the option of manipulating properties directly
// instead of relying on the UnitGet/Set functions.
//
private timer Timer = CreateTimer()
private integer array pow2
properties array UnitProperties
endglobals
struct properties
// ******************************************************************************
// These are the standard properties you would want to manipulate on a given unit
//
real Agi = 0
real Int = 0
real Str = 0
// real MaxLife The system uses these properties, but WC3 tracks them on its
// real MaxMana own, so the struct does not need them.
real LifeRegen = 0
real ManaRegen = 0
real ManaRegenPercent = 0
real Armor = 0
real Damage = 0
real AttackSpeed = 0
real MoveSpeed
// ******************************************************************************
// These properties are used by the Evasion module, which gives fully dynamic
// control over a unit's chance to evade incoming or miss on outgoing attacks.
//
unit unit
real AttackEvasion = 0
real AttackMiss = 0
// ******************************************************************************
// These are examples of additional properties which would require other systems
// to take advantage of.
//
//real AttackCritical = 0
//real SpellEvasion = 0
//real SpellMiss = 0
//real SpellReflection = 0
//real SpellCritical = 0
//real SpellResistance = 0
// ******************************************************************************
// JASS doesn't handle decimal values very well. 1. + .05 = 1.049999952, and
// 1. + .05 - .05 != 1. Thus it is necessary to store the values without decimals
// and then convert them when they they are retrieved.
//
//real SpellPower = 100
//real ExpRate = 100
//real BountyRate = 100
//real BloodRate = 100
static method create takes unit u returns properties
local properties this = properties.allocate()
set .unit = u
set .MoveSpeed = GetUnitDefaultMoveSpeed(u)
return this
endmethod
method onDestroy takes nothing returns nothing
set UnitProperties[.unit:Id] = 0
set .unit = null
endmethod
endstruct
// ******************************************************************************
// These functions that allow you to retrieve the handle index of a unit. Other
// methods of indexing units, like UnitUserData and HAIL, would also work. This
// method is only viable if you correctly dispose of used handles, so if your
// map suffers from inflated handle indices you should either change
// the "UnitProperties" array above to "UnitProperties[verybignumber]", or use a
// different system. A UnitUserData system is recommended as a replacement
// regardless.
//
// The Id wrapper allows you to retrieve a unit's Id as with:
//
// unit:Id
//
private function H2I takes handle h returns integer
return h
return 0
endfunction
function GetUnitId takes unit u returns integer
return H2I(u)-0x100000
endfunction
struct Id
static method operator [] takes unit u returns integer
return H2I(u)-0x100000
endmethod
endstruct
// ******************************************************************************
// Creates a set of properties for a given unit.
//
function CreateUnitProperties takes unit u returns nothing
local integer id = u:Id
if UnitProperties[id] == 0 then
set UnitProperties[id] = properties.create(u)
endif
endfunction
//*******************************************************************************
// These are the custom functions that allow you to manipulate specific
// properties. For each property, the macros generate a UnitSet, UnitModify and
// UnitGet function.
//
// UnitSetAgi(u, 10): This would set a unit's bonus Agility to 10.
//
// UnitModifyAgi(u, 10): This would add 10 to a unit's bonus Agility. A
// negative number could be used to subtract.
//
// UnitGetAgi(u): This would return a unit's current Agi bonus.
//
// The OperatorWrappers library offers a different interface for those who are
// comfortable with vJASS. More details are available at the top of the library.
//
function UnitModifyMoveSpeed takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.MoveSpeed = p.MoveSpeed + R2I(amount)
call SetUnitMoveSpeed(u, p.MoveSpeed)
endfunction
function UnitSetMoveSpeed takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.MoveSpeed = R2I(amount)
call SetUnitMoveSpeed(u, p.MoveSpeed)
endfunction
//There's already a native for this, but for the sake of completeness:
function UnitGetMoveSpeed takes unit u returns real
return UnitProperties[GetUnitId(u)].MoveSpeed
endfunction
// ******************************************************************************
// Periodic properties, like static mana regeneration.
//
//! textmacro UnitSetPeriodic takes member
globals
private group $member$Group = CreateGroup()
endglobals
function UnitModify$member$ takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.$member$ = p.$member$ + amount
if p.$member$ != 0 then
call GroupAddUnit($member$Group, u)
else
call GroupRemoveUnit($member$Group, u)
endif
endfunction
function UnitSet$member$ takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.$member$ = amount
if amount != 0 then
call GroupAddUnit($member$Group, u)
else
call GroupRemoveUnit($member$Group, u)
endif
endfunction
function UnitGet$member$ takes unit u returns real
return UnitProperties[GetUnitId(u)].$member$
endfunction
//! endtextmacro
//! runtextmacro UnitSetPeriodic("ManaRegen")
// ******************************************************************************
// Triggered properties like Spell Crits and Spell Evasion use these macros.
//
//! textmacro UnitSetProperty takes member
function UnitModify$member$ takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.$member$ = p.$member$ + R2I(amount)
endfunction
function UnitSet$member$ takes unit u, real amount returns nothing
set UnitProperties[GetUnitId(u)].$member$ = R2I(amount)
endfunction
function UnitGet$member$ takes unit u returns real
return UnitProperties[GetUnitId(u)].$member$
endfunction
//! endtextmacro
//! runtextmacro UnitSetProperty("AttackEvasion")
//! runtextmacro UnitSetProperty("AttackMiss")
////! runtextmacro UnitSetProperty("AttackCritical")
////! runtextmacro UnitSetProperty("SpellCritical")
////! runtextmacro UnitSetProperty("SpellEvasion")
////! runtextmacro UnitSetProperty("SpellMiss")
////! runtextmacro UnitSetProperty("SpellResistance")
////! runtextmacro UnitSetProperty("SpellReflection")
//! textmacro UnitSetPercentageProperty takes member
function UnitModify$member$ takes unit u, real amount returns nothing
local properties p = UnitProperties[GetUnitId(u)]
set p.$member$ = p.$member$ + R2I(amount)
endfunction
function UnitSet$member$ takes unit u, real amount returns nothing
set UnitProperties[GetUnitId(u)].$member$ = R2I(amount)
endfunction
function UnitGet$member$ takes unit u returns real
return UnitProperties[GetUnitId(u)].$member$
endfunction
//! endtextmacro
////! runtextmacro UnitSetPercentageProperty("SpellPower")
////! runtextmacro UnitSetPercentageProperty("ExpRate")
////! runtextmacro UnitSetPercentageProperty("BountyRate")
////! runtextmacro UnitSetPercentageProperty("BloodRate")
// ******************************************************************************
// Properties that are modified by using a binary count system. This includes
// stats, armor, damage etc.
//
//! textmacro UnitSetBinary takes member
function UnitModify$member$ takes unit u, real amount returns nothing
local integer i = 1
local integer e
local integer a
local properties p = UnitProperties[GetUnitId(u)]
local real r = p.$member$
set p.$member$ = p.$member$ + R2I(amount)
set amount = R2I(p.$member$)
loop
exitwhen i > 1
if amount >= 0 and r >= 0 then
set e = $member$
set r = amount
elseif amount <= 0 and r <= 0 then
set e = $member$ + Offset
set r = -amount
elseif amount <= 0 and r >= 0 then
set e = $member$
set r = 0
set i = 0
elseif amount >= 0 and r <= 0 then
set e = $member$ + Offset
set r = 0
set i = 0
endif
set a = Max
loop
exitwhen a < 0
if r >= pow2[a] then
call UnitAddAbility(u, e + a)
set r = r - pow2[a]
else
call UnitRemoveAbility(u, e + a)
endif
set a = a - 1
endloop
set i = i + 1
endloop
endfunction
function UnitSet$member$ takes unit u, real amount returns nothing
local integer i = 1
local integer e
local integer a
local properties p = UnitProperties[GetUnitId(u)]
local real r = p.$member$
set p.$member$ = R2I(amount)
set amount = R2I(p.$member$)
loop
exitwhen i > 1
if amount >= 0 and r >= 0 then
set e = $member$
set r = amount
elseif amount <= 0 and r <= 0 then
set e = $member$ + Offset
set r = -amount
elseif amount <= 0 and r >= 0 then
set e = $member$
set r = 0
set i = 0
elseif amount >= 0 and r <= 0 then
set e = $member$ + Offset
set r = 0
set i = 0
endif
set a = Max
loop
exitwhen a < 0
if r >= pow2[a] then
call UnitAddAbility(u, e + a)
set r = r - pow2[a]
else
call UnitRemoveAbility(u, e + a)
endif
set a = a - 1
endloop
set i = i + 1
endloop
endfunction
function UnitGet$member$ takes unit u returns real
return UnitProperties[GetUnitId(u)].$member$
endfunction
//! endtextmacro
//! runtextmacro UnitSetBinary("Agi")
//! runtextmacro UnitSetBinary("Int")
//! runtextmacro UnitSetBinary("Str")
//! runtextmacro UnitSetBinary("Damage")
//! runtextmacro UnitSetBinary("Armor")
//! runtextmacro UnitSetBinary("AttackSpeed")
//! runtextmacro UnitSetBinary("LifeRegen")
//! runtextmacro UnitSetBinary("ManaRegenPercent")
// ******************************************************************************
// Modifying max life and mana are special cases, although they could also be
// done using binary counting.
//
//! textmacro UnitSetMaxState takes member, state
function UnitModify$member$ takes unit u, real amount returns nothing
local integer comp = 100
local integer i = 4
local integer abil = $member$
if amount < 0 then
set abil = abil + 2
set amount = RAbsBJ(amount)
endif
set amount = R2I(amount)
loop
exitwhen i < 2
if amount >= comp then
loop
exitwhen amount < comp
call UnitAddAbility(u, abil)
call SetUnitAbilityLevel(u, abil, i)
call UnitRemoveAbility(u, abil)
set amount = amount - comp
endloop
endif
set comp = comp / 10
set i = i - 1
endloop
endfunction
function UnitSet$member$ takes unit u, real amount returns nothing
local integer comp = 100
local integer i = 4
local integer abil = $member$
local real r = GetUnitState(u, UNIT_STATE_$state$)
if amount > r then
set amount = R2I(amount - r)
elseif amount < r then
set amount = R2I(RAbsBJ(r - amount))
set abil = abil + 2
endif
loop
exitwhen i < 2
if amount >= comp then
loop
exitwhen amount < comp
call UnitAddAbility(u, abil)
call SetUnitAbilityLevel(u, abil, i)
call UnitRemoveAbility(u, abil)
set amount = amount - comp
endloop
endif
set comp = comp / 10
set i = i - 1
endloop
endfunction
function UnitGet$member$ takes unit u returns real
return GetUnitState(u, UNIT_STATE_MAX_$state$)
endfunction
//! endtextmacro
//! runtextmacro UnitSetMaxState("MaxLife", "LIFE")
//! runtextmacro UnitSetMaxState("MaxMana", "MANA")
// ******************************************************************************
// Refreshes properties for a unit in case a morph ability or something else
// causes them to vanish.
//
function RefreshUnitProperties takes unit u returns nothing
call UnitModifyAgi(u, 0)
call UnitModifyInt(u, 0)
call UnitModifyStr(u, 0)
call UnitModifyLifeRegen(u, 0)
call UnitModifyManaRegen(u, 0)
call UnitModifyManaRegenPercent(u, 0)
call UnitModifyArmor(u, 0)
call UnitModifyDamage(u, 0)
call UnitModifyAttackSpeed(u, 0)
call UnitModifyMoveSpeed(u, 0)
endfunction
// ******************************************************************************
// Additional periodic properties would be added to the Periodic function and
// would require their own ForGroup.
//
private function UnitAdjustMana takes nothing returns nothing
local unit u = GetEnumUnit()
set u:Mana = u:Mana + u:ManaRegen
set u = null
endfunction
private function Periodic takes nothing returns nothing
call ForGroup(ManaRegenGroup, function UnitAdjustMana)
endfunction
// ******************************************************************************
// Initialization stores powers of 2 up to 30, starts the periodic timer and
// preloads all property abilities.
//
private function Init takes nothing returns nothing
local unit u
local integer exit
local integer i = 1
set pow2[0] = 1
call TimerStart(Timer, 1, true, function Periodic)
loop
exitwhen i > 30 // Can't go above 2^30, integer will overflow
set pow2 = pow2[i - 1] * 2
set i = i + 1
endloop
set u = CreateUnit(Player(14), 'hfoo', 0, 0, 0)
set i = Agi + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Int
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Int + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Str
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Str + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = AttackSpeed
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = AttackSpeed + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Armor
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Armor + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Damage
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = Damage + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = LifeRegen
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
set i = LifeRegen + Offset
set exit = i + Max
loop
exitwhen i >= exit
call UnitAddAbility(u, i)
call UnitRemoveAbility(u, i)
set i = i + 1
endloop
call UnitAddAbility(u, MaxLife)
call UnitAddAbility(u, MaxLife+2)
call UnitAddAbility(u, MaxMana)
call UnitAddAbility(u, MaxMana+2)
call UnitRemoveAbility(u, MaxLife)
call UnitRemoveAbility(u, MaxLife+2)
call UnitRemoveAbility(u, MaxMana)
call UnitRemoveAbility(u, MaxMana+2)
call UnitAddAbility(u, 'Evas')
call UnitAddAbility(u, 'Evas')
call KillUnit(u)
call RemoveUnit(u)
set u = null
endfunction
endlibrary
[/jass] |
评分
-
查看全部评分
|