- Joined
- Oct 12, 2011
- Messages
- 3,449
Code
Demo
Demo spell
JASS:
library LockBone uses optional TimerUtils, optional Table, optional MissileRecycler
/* v1.6 */
globals
// If only you don't use MissileRecycler
private constant integer DUMMY_ID = 'dumi'
endglobals
/*
Description
¯¯¯¯¯¯¯¯¯¯¯
Allows you to lock a unit's body part to face certain angle or point.
External Dependencies
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
(Requires) - Nothing
(Optional) - These libs are completely optional. But it's a win win to have all of these to go with the system.
1. This lib allows the system to save data into timers, which is useful for struct based spells/systems
| TimerUtils @ wc3c.net/showthread.php?t=101322
2. This lib can ease the handling of hashtables as well as make it perfectly efficient uses of hashtables.
| Table @ hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
3. This system uses a lot of dummy units. Unit creations are heavy process, and other problems as well.
Here is where dummy recycler comes important.
| MissileRecycler @ hiveworkshop.com/forums/jass-resources-412/system-missilerecycler-206086/
API
¯¯¯
struct LockBone
1. Lock body part at given coordinate
| static method lockAtPoint takes unit whichUnit, string whichBone, real targetX, real targetY, real zOffset returns thistype
- targetX : x-axis of the target point
- targetY : y-axis of the target point
- zOffset : height level at which the bone will be locked
2. Lock body part at given angle (in radian)
| static method lockAtAngle takes unit whichUnit, string whichBone, real radian, real hOffset, real vOffset returns thistype
- radian : at what angle (in radian) unit's bone will be locked
- hOffset : horizontal offset
- vOffset : vertical offset
0 ............... -> lock point
unit <- | ______________: -> vOffset
\_____________/
hOffset
3. Reset any body locking
| static method resetLock takes unit whichUnit returns nothing
4. Bones part constants
BONE_PART_CHEST => rotate chest bone
BONE_PART_HEAD => rotate head bone
Resource Link
¯¯¯¯¯¯¯¯¯¯¯¯¯
hiveworkshop.com/forums/submissions-414/snippet-lockbone-259005/
*/
globals
constant string BONE_PART_CHEST = "bone_chest"
constant string BONE_PART_HEAD = "bone_head"
private constant real INTERVAL = 0.03125
private constant player PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
endglobals
struct LockBone
private timer t
private unit u
private unit d
private real cos
private real sin
private static real MapMaxX
private static real MapMaxY
private static real MapMinX
private static real MapMinY
static if LIBRARY_Table then
private static Table Ht
else
private static hashtable Ht
endif
private static method onPeriodic takes nothing returns nothing
local thistype this
local real x
local real y
static if LIBRARY_TimerUtils then
set this = GetTimerData(GetExpiredTimer())
else
static if LIBRARY_Table then
set this = Ht.integer[GetHandleId(GetExpiredTimer())]
else
set this = LoadInteger(Ht, GetHandleId(GetExpiredTimer()), 0)
endif
endif
set x = GetUnitX(.u)+.cos
set y = GetUnitY(.u)+.sin
if x > MapMinX and x < MapMaxX and y > MapMinY and y < MapMaxY then
call SetUnitX(.d, x)
call SetUnitY(.d, y)
else
call SetUnitPosition(.d, x, y)
endif
endmethod
static method resetLock takes unit whichUnit returns nothing
local thistype this
local integer hand = GetHandleId(whichUnit)
static if LIBRARY_Table then
set this = Ht.integer[hand]
else
set this = LoadInteger(Ht, hand, 0)
endif
if this != 0 then
call ResetUnitLookAt(.u)
static if LIBRARY_MissileRecycler then
call RecycleMissile(.d)
call SetUnitX(.d, MapMaxX)
call SetUnitY(.d, MapMaxY)
else
call RemoveUnit(.d)
endif
static if LIBRARY_TimerUtils then
call ReleaseTimer(.t)
else
call DestroyTimer(.t)
static if LIBRARY_Table then
call Ht.integer.remove[GetHandleId(.t)]
else
call RemoveSavedInteger(Ht, GetHandleId(.t), 0)
endif
endif
static if LIBRARY_Table then
set Ht.integer[hand] = 0
else
call SaveInteger(Ht, hand, 0, 0)
endif
call destroy()
set .u = null
set .d = null
set .t = null
endif
endmethod
static method lockAtPoint takes unit whichUnit, string whichBone, real targetX, real targetY, real zOffset returns thistype
local thistype this
static if LIBRARY_Table then
set this = Ht.integer[GetHandleId(whichUnit)]
else
set this = LoadInteger(Ht, GetHandleId(whichUnit), 0)
endif
if this == 0 then
set this = allocate()
static if LIBRARY_Table then
set Ht.integer[GetHandleId(whichUnit)] = this
else
call SaveInteger(Ht, GetHandleId(whichUnit), 0, this)
endif
static if LIBRARY_TimerUtils then
set .t = NewTimerEx(this)
else
set .t = CreateTimer()
static if LIBRARY_Table then
set Ht.integer[GetHandleId(.t)] = this
else
call SaveInteger(Ht, GetHandleId(.t), 0, this)
endif
endif
static if LIBRARY_MissileRecycler then
set .d = GetRecycledMissile(0, 0, 0, 0)
else
set .d = CreateUnit(PASSIVE, DUMMY_ID, 0, 0, 0)
static if not LIBRARY_AutoFly then
if UnitAddAbility(.d, 'Amrf') and UnitRemoveAbility(.d, 'Amrf') then
endif
endif
endif
set .u = whichUnit
call UnitRemoveAbility(.d, 'Amov')
call SetUnitLookAt(.u, whichBone, .d, 0, 0, 0)
endif
if TimerGetTimeout(.t) > 0 then
call TimerStart(.t, 0, false, null)
call PauseTimer(.t)
endif
call SetUnitFlyHeight(.d, zOffset, 0)
call SetUnitX(.d, targetX)
call SetUnitY(.d, targetY)
return this
endmethod
static method lockAtAngle takes unit whichUnit, string whichBone, real radian, real hOffset, real vOffset returns thistype
local thistype this
static if LIBRARY_Table then
set this = Ht.integer[GetHandleId(whichUnit)]
else
set this = LoadInteger(Ht, GetHandleId(whichUnit), 0)
endif
if this == 0 then
set this = allocate()
static if LIBRARY_Table then
set Ht.integer[GetHandleId(whichUnit)] = this
else
call SaveInteger(Ht, GetHandleId(whichUnit), 0, this)
endif
static if LIBRARY_TimerUtils then
set .t = NewTimerEx(this)
else
set .t = CreateTimer()
static if LIBRARY_Table then
set Ht.integer[GetHandleId(.t)] = this
else
call SaveInteger(Ht, GetHandleId(.t), 0, this)
endif
endif
static if LIBRARY_MissileRecycler then
set .d = GetRecycledMissile(0, 0, 0, 0)
else
set .d = CreateUnit(PASSIVE, DUMMY_ID, 0, 0, 0)
static if not LIBRARY_AutoFly then
if UnitAddAbility(.d, 'Amrf') and UnitRemoveAbility(.d, 'Amrf') then
endif
endif
endif
set .u = whichUnit
call UnitRemoveAbility(.d, 'Amov')
call SetUnitLookAt(.u, whichBone, .d, 0, 0, 0)
endif
if TimerGetTimeout(.t) == 0 then
call TimerStart(.t, INTERVAL, true, function thistype.onPeriodic)
endif
set .cos = hOffset*Cos(radian)
set .sin = hOffset*Sin(radian)
call SetUnitFlyHeight(.d, vOffset, 0)
call SetUnitX(.d, GetUnitX(.u)+.cos)
call SetUnitY(.d, GetUnitY(.u)+.sin)
return this
endmethod
private static method onDeath takes nothing returns boolean
local unit u = GetTriggerUnit()
local thistype this
static if LIBRARY_Table then
set this = Ht.integer[GetHandleId(u)]
else
set this = LoadInteger(Ht, GetHandleId(u), 0)
endif
if this != 0 then
call resetLock(u)
endif
set u = null
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
static if LIBRARY_Table then
set Ht = Table.create()
else
set Ht = InitHashtable()
endif
set MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MapMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MapMinX = GetRectMinX(bj_mapInitialPlayableArea)
set MapMinY = GetRectMinY(bj_mapInitialPlayableArea)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function thistype.onDeath))
endmethod
endstruct
endlibrary
Demo
Demo spell
Last edited: