Name | Type | is_array | initial_value |
TempX | real | No | |
TempY | real | No | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UMovNext | integer | Yes | |
UMovPrev | integer | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitMoving | boolean | Yes | |
UnitMovingEvent | real | No | |
UnitMovingX | real | Yes | |
UnitMovingY | real | Yes |
library RigidBody requires UnitZ, TimerUtils, UnitIndexer, Table
/*
~ RigidBody v1.3 ~
Applies highly realistic physics to the native Warcraft 3 movements.
I. Requirements:
• TimerUtils : www.wc3c.net/showthread.php?t=101322
• UnitIndexer : www.hiveworkshop.com/forums/spells-569/unit-indexer-v5-3-0-1-a-260859/
• UnitZ : www.hiveworkshop.com/forums/jass-resources-412/snippet-getterrainz-unitz-236942/
• Table : www.hiveworkshop.com/threads/snippet-new-table.188084/
II. How to install:
• Install and configure the unit indexer properly
• Copy the RigidBody trigger group to your map
• Adjust the system configuration below if neccesary
• Define frictions for each tile in your map
• Input unit data to the data reference for better accuracy
III. User API
1. Applies some physics to unit body
struct RigidBody
real acceleration
- Unit's acceleration rate
real deacceleration
- Unit's deacceleration rate
real turnRate
- Unit's turn rate
real angle
- Unit's current motion direction
real speed
- Unit's current motion velocity
real zVel
- Unit's current gravitational velocity
readonly boolean isEnabled
- True if unit's movement is currrently enabled
readonly boolean isAirborne
- True if the unit is currently mid-air
readonly unit object
- The unit agent
static method RegisterUnit takes unit whichUnit returns thistype
- Applies movement physics to a unit
static method IsUnitRegistered takes unit u returns boolean
- Check if the unit is registered to the system or not
method accelerate takes real power, real maxspeed, real direction, real turnRate returns nothing
- Accelerate with certain power toward given direction
method move takes real x, real y, real z returns nothing
- Move the unit to certain coordinate
method jump takes real power returns nothing
- Jump with certain velocity
method enable takes boolean b returns nothing
- If disabled, physics will be disabled for the unit
method destroy takes nothing returns nothing
- Unregister the unit
static method operator [] takes unit u returns thistype
- Get unit's index
2. Unit's object data reference
public struct UnitDataRef
static method IsRegistered takes unit whichUnit returns boolean
- True if the unit data has been defined
static method GetAttackRange takes unit whichUnit returns real
static method GetBackswingPoint takes unit whichUnit returns real
- Get unit data
static method Add takes integer unitId, real attackRange, real backswingPoint returns nothing
- Define unit data
3. Terrain type specifications
public struct TerrainUtils
static method GetTerrainSteepness takes real x1, real y1, real x2, real y2 returns real
- Get tiltness between two points
static method GetTerrainFriction takes real x, real y returns real
- Get terrain friction at given coordinate
static method SetTerrainTypeFriction takes integer terrainId, real friction returns nothing
- Define tile friction
IV. Credits:
• Nestharus
• Garfield1337
• Vexorian
• Bribe
*/ ////////////////////
// Configurations //
////////////////////
// Warning! Every tiny bit of modification to these settings may
// causes significant impact to the motion behavior!
// So be careful when you are modifying it if you have "deeply"
// implement the system to your map.
globals
// 1. Physic calculations interval
private constant real INTERVAL = 0.0312500
// 2. Unit position update rate
// - Higher values will significantly improve performance
// - But it causes the movement looks rough
private constant real RELOCATION_RATE = 0.01
// 3. Gravitational force of your world (map)
private constant real GRAVITY = 9.8*INTERVAL
// 4. Max friction of the ground to be identified as slippery
private constant real SLIPPERY_TILE_MAX_FRICTION = 1.0
// 5. Offset accuracy of tiltness detection
// - Different value may result in different motion behavior
private constant real SLOPE_DETECTION_RADIUS = 0.1
// 6. Number of tiltness detection iterations
// - Higher value means higher precision (more realistic theoritically)
// - Different value may result in different motion behavior
private constant integer SLOPE_DETECTION_ACCURACY = 5
// 7. Ground tiltness speed factors
// - Downhill movement speed bonus
private constant real SLOPE_SPEED_INCREMENT_STRENGTH = 0.05
// - Maximum speed bonus on downhill movement
private constant real MAXIMUM_SLOPE_SPEED_BONUS_RATE = 1.5
// - Uphill movement speed penalty
private constant real SLOPE_SPEED_REDUCTION_STRENGTH = 0.05
// 8. Ground tiltness strength
// - Tiltness affects movement exponentially
// - Higher value causes slopier ground to have stronger impact to the motion
private constant real SLOPE_STRENGTH_FACTOR = 1.25
// 9. Maximum walktable ground tiltness (in radian)
// - Units can't move on ground tiltness beyond this value
private constant real MAX_WALKABLE_SLOPE = 85.0*bj_DEGTORAD
// 10. Maximum speed of unit slipping
// - Units will be passively slipped when standing on sloppy ground
// - The effect can be overcame by ground friction so it will be seemingly idle
private constant real SLIP_MAXIMUM_SPEED = 522.0*INTERVAL
// 11. Turn rate of unit slipping
// - Higher value causes motion to direct downward more quickly when slipping
private constant real SLIP_TURN_RATE = 15.0*bj_DEGTORAD
// 12. Absolute motion speed limit
// - Nothing can move faster than following specified value
private constant real ABSOLUTE_SPEED_LIMIT = 1566.0*INTERVAL
// 13. If true, units will try to deaccelerate themselves when idle
// - Acts like additional friction
// - Ideally turned on for battle-based maps
private constant boolean IDLE_DEACCELERATION = false
// 14. If true, every classified units will be registered to the system on creation
private constant boolean AUTO_REGISTER = true
// 15. Units can't take off if the ground has lower tiltness than following specified value
// - A unit can take off (for example from ramps) if it has enough velocity to escape the gravitation
private constant real MINIMUM_TAKE_OFF_TILTNESS = 45.0*bj_DEGTORAD
// 16. General unit attack range (used for units without pre-registered data)
// - For range attackers
private constant real RANGE_UNIT_ATTACK_RANGE = 600.0
// - For melee attackers
private constant real MELEE_UNIT_ATTACK_RANGE = 128.0
// 17. General unit backswing point (used for units without pre-defined data)
private constant real GENERAL_UNIT_BACKSWING_POINT = 0.800
// 18. General unit turn rate
// - Turn rate on slippery grounds
private constant real GENERAL_UNIT_TURN_RATE = 5.0*bj_DEGTORAD
// - Turn rate on non-slippery grounds
private constant real GENERAL_UNIT_TURN_RATE_2 = 90.0*bj_DEGTORAD
// 19. General unit acceleration
private constant real GENERAL_UNIT_ACCELERATION = 25.0*INTERVAL
// 20. General unit deacceleration
// - Only works if IDLE_DEACCELERATION is set to "true"
private constant real GENERAL_UNIT_DEACCELERATION = 5.0*INTERVAL
// 21. General unit mass
// - Acts like additional gravitational force
private constant real GENERAL_UNIT_MASS = 5.0*INTERVAL
// 22. Detection trigger will be recycled if have more wasted events than the following value
private constant integer TRIGGER_RECYCLE_THRESHOLD = 15
// 23. Target adjustment range
private constant real TARGET_ADJUSTMENT_RANGE = 64.0
// 24. Target adjustment movespeed factor
// - Factor applied to movespeed when adjusting target
private constant real TARGET_ADJUSTMENT_SPEED = 0.5
// 25. Speed reduction on collision
private constant real COLLISION_BOUNCE_FACTOR = 0.5
endglobals
native UnitAlive takes unit id returns boolean
private function FilterUnit takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitType(u, UNIT_TYPE_FLYING) and GetUnitAbilityLevel(u, 'Aloc') == 0
endfunction
globals
private real WorldMaxX = 0
private real WorldMaxY = 0
private real WorldMinX = 0
private real WorldMinY = 0
private integer EventWasted = 0
private constant real TAU = bj_PI*2
private constant real HP = bj_PI/2
endglobals
private module Init
private static method onInit takes nothing returns nothing
call Initialize()
endmethod
endmodule
public struct UnitDataRef
private static Table AttackRangeTable
private static Table BackswingPointTable
static method IsRegistered takes unit whichUnit returns boolean
return BackswingPointTable.boolean[GetUnitTypeId(whichUnit)]
endmethod
static method GetAttackRange takes unit whichUnit returns real
return AttackRangeTable.real[GetUnitTypeId(whichUnit)]
endmethod
static method GetBackswingPoint takes unit whichUnit returns real
return BackswingPointTable.real[GetUnitTypeId(whichUnit)]
endmethod
static method Add takes integer unitId, real attackRange, real backswingPoint returns nothing
set AttackRangeTable.real[unitId] = attackRange
set BackswingPointTable.real[unitId] = backswingPoint
set BackswingPointTable.boolean[unitId] = true
endmethod
private static method Initialize takes nothing returns nothing
set AttackRangeTable = Table.create()
set BackswingPointTable = Table.create()
endmethod
implement Init
endstruct
public struct TerrainUtils extends array
private static Table TerrainUtils
static method GetTerrainSteepness takes real x1, real y1, real x2, real y2 returns real
return Sin(GetTerrainZ(x1, y1)-GetTerrainZ(x2, y2))/SLOPE_DETECTION_RADIUS
endmethod
static method GetTerrainFriction takes real x, real y returns real
return TerrainUtils.real[GetTerrainType(x, y)]
endmethod
static method SetTerrainTypeFriction takes integer id, real friction returns nothing
set TerrainUtils.real[id] = friction
endmethod
private static method Initialize takes nothing returns nothing
set TerrainUtils = Table.create()
endmethod
implement Init
endstruct
struct RigidBody extends array
real acceleration
real deacceleration
real turnRate
real angle // Unit's motion direction
real speed // Unit's motion velocity
real zVel // Unit's gravitational velocity
private boolean isMoving
private boolean isPatroling
readonly boolean isEnabled
readonly boolean isAirborne
readonly unit object
private unit target
private real locX
private real locY
private real locZ
private timer tick
private timer locator
private timer disabler
private real orderX
private real orderY
private widget orderTarget
private integer orderId
private static real LowestA = 0
private static real LowestX = 0
private static real LowestY = 0
private static real LowestZ = 0
private static group Objects = CreateGroup()
private static trigger DetectTrigger = CreateTrigger()
private static conditionfunc DetectFunc
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
static method IsUnitRegistered takes unit u returns boolean
return thistype(GetUnitUserData(u)).object != null
endmethod
private static method AngularDifferenceAbs takes real a, real b returns real
return RAbsBJ(Atan2(Sin(a-b), Cos(a-b)))
endmethod
private static method Exponent takes real b returns real
return Pow(SLOPE_STRENGTH_FACTOR, b)
endmethod
method destroy takes nothing returns nothing
call ReleaseTimer(.tick)
call ReleaseTimer(.locator)
call ReleaseTimer(.disabler)
set .object = null
set .target = null
set .tick = null
set .locator = null
set .disabler = null
endmethod
// Detecting lowest ground with constant time complexity of O(n) = N
// depending on specified SLOPE_DETECTION_ACCURACY
private method getLowestPoint takes nothing returns nothing
local real x
local real y
local real z
local real x2
local real y2
local real z2
local real inc = bj_PI
local real angle = GetRandomReal(0, bj_PI-.1) // Significantly reduces no-slope detection error possibility
local integer i
set LowestZ = 99999999
loop
exitwhen angle >= TAU
set x = .locX+SLOPE_DETECTION_RADIUS*Cos(.angle+angle)
set y = .locY+SLOPE_DETECTION_RADIUS*Sin(.angle+angle)
set z = GetTerrainZ(x, y)
if z < LowestZ then
set LowestX = x
set LowestY = y
set LowestZ = z
set LowestA =.angle+ angle
elseif z == LowestZ then
set LowestX = .locX
set LowestY = .locY
set LowestA = .angle
return
endif
set angle = angle+inc
endloop
set i = 0
loop
set i = i + 1
set inc = inc/2
set x = .locX+SLOPE_DETECTION_RADIUS*Cos(LowestA+inc)
set y = .locY+SLOPE_DETECTION_RADIUS*Sin(LowestA+inc)
set z = GetTerrainZ(x, y)
set x2 = .locX+SLOPE_DETECTION_RADIUS*Cos(LowestA-inc)
set y2 = .locY+SLOPE_DETECTION_RADIUS*Sin(LowestA-inc)
set z2 = GetTerrainZ(x2, y2)
if z < LowestZ or z2 < LowestZ then
if z < z2 then
set LowestX = x
set LowestY = y
set LowestZ = z
set LowestA = LowestA+inc
else
set LowestX = x2
set LowestY = y2
set LowestZ = z2
set LowestA = LowestA-inc
endif
endif
exitwhen i == SLOPE_DETECTION_ACCURACY
endloop
endmethod
private method turn takes real targetAngle, real turnRate returns nothing
if Cos(.angle-targetAngle) <= Cos(turnRate) then
if Sin(targetAngle-.angle) >= 0 then
set .angle = .angle+turnRate
else
set .angle = .angle-turnRate
endif
else
set .angle = targetAngle
endif
endmethod
// Apply gravitational forces
private method slip takes real power, real direction, real turnRate returns nothing
local real diff = AngularDifferenceAbs(direction, .angle)
local real spdPow = 1-diff*2/bj_PI
local boolean b
call turn(direction, turnRate*(1-AngularDifferenceAbs(diff, HP)/HP))
set b = .speed < SLIP_MAXIMUM_SPEED
if spdPow < 0 or b then
set .speed = .speed+power*spdPow
if .speed > SLIP_MAXIMUM_SPEED and b then
set .speed = SLIP_MAXIMUM_SPEED
elseif .speed < 0 then
set .angle = direction
set .speed = 0.0
endif
endif
endmethod
method accelerate takes real power, real maxspeed, real direction, real turnRate returns nothing
local real diff
local real spdPow
if .speed == 0 then
set .angle = direction
if .speed < power then
set .speed = power
endif
set diff = 0.0
else
set diff = AngularDifferenceAbs(direction, .angle)
call turn(direction, turnRate*(1-AngularDifferenceAbs(diff, HP)/HP))
endif
set spdPow = 1-diff*2/bj_PI
if spdPow < 0 or .speed < maxspeed then
set .speed = .speed+power*spdPow
if .speed > maxspeed and spdPow >= 0 then
set .speed = maxspeed
elseif .speed < 0 then
set .angle = direction
set .speed = -.speed
endif
elseif .speed > maxspeed then
set .speed = .speed-.deacceleration
endif
endmethod
method enable takes boolean b returns nothing
set .isEnabled = b
if b then
set .locX = GetUnitX(.object)
set .locY = GetUnitY(.object)
set .locZ = GetUnitZ(.object)
set .isAirborne = true
endif
endmethod
method jump takes real power returns nothing
set .zVel = power
set .isAirborne = true
endmethod
method move takes real x, real y, real z returns nothing
set .locX = x
set .locY = y
set .locZ = GetTerrainZ(x, y)+z
call SetUnitX(.object, .locX)
call SetUnitY(.object, .locY)
call SetUnitZ(.object, .locZ)
if z > 0 then
set .isAirborne = true
else
set .isAirborne = false
call SetUnitFlyHeight(.object, 0, 0)
endif
endmethod
private static method Relocate takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if .isEnabled and (.speed > 0 or .isMoving) then
// Detect teleportation
if not IsUnitInRangeXY(.object, .locX, .locY, .speed) then
set .locX = GetUnitX(.object)
set .locY = GetUnitY(.object)
else
call SetUnitX(.object, .locX)
call SetUnitY(.object, .locY)
endif
if .isAirborne then
call SetUnitZ(.object, .locZ)
endif
endif
endmethod
private static method OnPeriodic takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real slope
local real slopeC
local real slopeS
local real slope2
local real reduction
local real friction
local real diff
local real a
local real r
local real x
local real y
local real z
local real x2
local real y2
local real ms
local integer order
local boolean moving
local boolean slippy
if .isEnabled and UnitAlive(.object) then
set x = .locX
set y = .locY
set a = GetUnitFacing(object)*bj_DEGTORAD
set ms = GetUnitMoveSpeed(object)*INTERVAL
if not .isAirborne then
call getLowestPoint()
if LowestX != .locX or LowestY != .locY then
set slope = TerrainUtils.GetTerrainSteepness(x, y, LowestX, LowestY)
if slope > HP then
set slope = HP
endif
set slopeC = Cos(slope)
set slopeS = Sin(slope)
else
set slope = 0
set slopeS = 0
set slopeC = 1
endif
set friction = TerrainUtils.GetTerrainFriction(x, y)
set slippy = friction <= SLIPPERY_TILE_MAX_FRICTION
set order = GetUnitCurrentOrder(.object)
set moving = .isMoving and order != 0 or .isPatroling and not IsUnitPaused(.object)
if UnitAlive(.target) then
if TimerGetRemaining(.disabler) == 0 then
if UnitDataRef.IsRegistered(.object) then
set r = UnitDataRef.GetAttackRange(.object)
elseif IsUnitType(.object, UNIT_TYPE_RANGED_ATTACKER) then
set r = RANGE_UNIT_ATTACK_RANGE
else
set r = MELEE_UNIT_ATTACK_RANGE
endif
set x2 = x-GetUnitX(.target)
set y2 = y-GetUnitY(.target)
set moving = moving or x2*x2+y2*y2 > r*r
endif
elseif .target != null then
set .isMoving = order != 0
if not .isMoving then
set .target = null
endif
set moving = not IsUnitPaused(.object)
endif
if moving then
if .orderTarget == null then
if IsUnitInRangeXY(.object, .orderX, .orderY, TARGET_ADJUSTMENT_RANGE) then
set ms = ms * TARGET_ADJUSTMENT_SPEED
endif
endif
if slippy then
call accelerate(.acceleration, ms, a, .turnRate*slopeC)
elseif slope < MAX_WALKABLE_SLOPE then
call accelerate(.acceleration, ms, a, GENERAL_UNIT_TURN_RATE_2*slopeC)
endif
endif
set diff = AngularDifferenceAbs(LowestA, .angle)
if not slippy then
set r = .speed*slopeS*SLOPE_SPEED_INCREMENT_STRENGTH*(1-diff*2/bj_PI)
if r < 0 then
if slope > MAX_WALKABLE_SLOPE then
set .speed = 0
elseif .speed >= ms*.5 then
set .speed = .speed+r
endif
else
set .speed = .speed+r
endif
if .speed > ms*MAXIMUM_SLOPE_SPEED_BONUS_RATE then
set .speed = ms*MAXIMUM_SLOPE_SPEED_BONUS_RATE
endif
endif
if diff >= HP and slope > MAX_WALKABLE_SLOPE then
set .speed = 0
endif
if slope != 0 then
call slip((GRAVITY+GENERAL_UNIT_MASS)*Exponent(slopeS+1), LowestA, SLIP_TURN_RATE*slopeS)
endif
if moving then
if slippy then
set .speed = .speed-friction*slopeC
endif
else
if slope > MAX_WALKABLE_SLOPE then
set .speed = .speed-friction*slopeC
else
set .speed = .speed-friction
endif
static if IDLE_DEACCELERATION then
set .speed = .speed-.deacceleration
endif
endif
if .speed > ABSOLUTE_SPEED_LIMIT then
set .speed = ABSOLUTE_SPEED_LIMIT
elseif .speed < 0 then
set .speed = 0
endif
if moving then
if .orderTarget == null then
if AngularDifferenceAbs(Atan2(.orderY-.locY, .orderX-.locX), GetUnitFacing(.object)*bj_DEGTORAD) > HP / 2 then
call IssuePointOrderById(.object, .orderId, .orderX, .orderY)
endif
else
if AngularDifferenceAbs(Atan2(GetWidgetY(.orderTarget)-.locY, GetWidgetX(.orderTarget)-.locX), GetUnitFacing(.object)*bj_DEGTORAD) > HP / 2 then
call IssueTargetOrderById(.object, .orderId, .orderTarget)
endif
endif
endif
endif
if x < WorldMaxX and x > WorldMinX and y < WorldMaxY and y > WorldMinY then
set x2 = x+SLOPE_DETECTION_RADIUS*Cos(.angle)
set y2 = y+SLOPE_DETECTION_RADIUS*Sin(.angle)
set x = x+.speed*Cos(.angle)
set y = y+.speed*Sin(.angle)
set slope = -TerrainUtils.GetTerrainSteepness(.locX, .locY, x2, y2)
if .isAirborne then
set .locZ = .locZ+.zVel
set .zVel = .zVel-(GRAVITY+GENERAL_UNIT_MASS)
set z = GetTerrainZ(x, y)
if .locZ <= z+.01 then
set .locZ = z
set .isAirborne = false
// Calculate speed change when colliding with the ground
set reduction = Atan((z-GetTerrainZ(.locX, .locY))/.speed)
set .speed = .speed*((bj_PI-Atan(RAbsBJ(.zVel)/.speed)-reduction)/HP-1)
if .speed > ABSOLUTE_SPEED_LIMIT then
set .speed = ABSOLUTE_SPEED_LIMIT
elseif .speed < 0 then
set .speed = 0
endif
call SetUnitFlyHeight(.object, 0, 0)
endif
else
set x2 = x-SLOPE_DETECTION_RADIUS*Cos(.angle)
set y2 = y-SLOPE_DETECTION_RADIUS*Sin(.angle)
set slope2 = -TerrainUtils.GetTerrainSteepness(x2, y2, x, y)
if slope2 > HP then
set slope2 = HP
endif
if slope > slope2 and slope-slope2 > MINIMUM_TAKE_OFF_TILTNESS then
// Check if the velocity is enough to escape the gravitational force
set .zVel = .speed*Sin(slope)
if .zVel > ((GetTerrainZ(x, y)-GetTerrainZ(x2, y2))+(GRAVITY+GENERAL_UNIT_MASS)) then
set .isAirborne = true
set .locZ = GetTerrainZ(.locX, .locY)+.zVel
endif
endif
endif
call SetUnitX(.object, WorldBounds.maxX)
call SetUnitY(.object, WorldBounds.maxY)
if IsTerrainWalkable(x, y) or .isAirborne then
set .locX = x
set .locY = y
else
set .angle = angle + bj_PI
set .speed = .speed * COLLISION_BOUNCE_FACTOR
endif
call SetUnitX(.object, .locX)
call SetUnitY(.object, .locY)
endif
endif
set t = null
endmethod
static method RegisterUnit takes unit whichUnit returns thistype
local thistype this = GetUnitUserData(whichUnit)
if .object == null then
set .object = whichUnit
set .angle = GetUnitFacing(whichUnit)*bj_DEGTORAD
set .isAirborne = false
set .isEnabled = true
set .isPatroling = false
set .locX = GetUnitX(whichUnit)
set .locY = GetUnitY(whichUnit)
set .locZ = 0.0
set .speed = 0
set .turnRate = GENERAL_UNIT_TURN_RATE
set .tick = NewTimerEx(this)
set .locator = NewTimerEx(this)
set .disabler = NewTimerEx(this)
set .acceleration = GENERAL_UNIT_ACCELERATION
set .deacceleration = GENERAL_UNIT_DEACCELERATION
static if not LIBRARY_AutoFly then
if UnitAddAbility(.object, 'Amrf') and UnitRemoveAbility(.object, 'Amrf') then
endif
endif
call GroupAddUnit(Objects, .object)
call TriggerRegisterUnitEvent(DetectTrigger, .object, EVENT_UNIT_ACQUIRED_TARGET)
call TimerStart(.locator, RELOCATION_RATE, true, function thistype.Relocate)
call TimerStart(.tick, INTERVAL, true, function thistype.OnPeriodic)
endif
return this
endmethod
private static method OnImmediateOrder takes nothing returns boolean
local unit u = GetTriggerUnit()
local thistype this = GetUnitUserData(u)
local integer order = GetIssuedOrderId()
if .object != null and .isEnabled and GetUnitCurrentOrder(u) == order then
set .isMoving = false
set .isPatroling = false
set .orderId = order
set .orderTarget = null
endif
set u = null
return false
endmethod
private static method OnOrder takes nothing returns boolean
local unit u = GetTriggerUnit()
local thistype this = GetUnitUserData(u)
local integer order = GetIssuedOrderId()
if .object != null and .isEnabled and GetUnitCurrentOrder(u) == order then
set .isPatroling = false
set .target = null
set .orderId = order
set .orderTarget = GetOrderTarget()
if order == 851973 then // If stun order
set .isMoving = false
else
if .orderTarget == null then
set .orderX = GetOrderPointX()
set .orderY = GetOrderPointY()
set .isMoving = true
else
set .isMoving = true
endif
endif
endif
set u = null
return false
endmethod
private static method OnAttack takes nothing returns boolean
local unit u = GetAttacker()
local thistype this = GetUnitUserData(u)
if .object != null and .isEnabled then
set .isMoving = false
set .target = GetTriggerUnit()
if UnitDataRef.IsRegistered(u) then
call TimerStart(.disabler, UnitDataRef.GetBackswingPoint(u), false, null)
else
call TimerStart(.disabler, GENERAL_UNIT_BACKSWING_POINT, false, null)
endif
endif
set u = null
return false
endmethod
private static method OnDetect takes nothing returns boolean
local thistype this = GetUnitUserData(GetTriggerUnit())
if .object != null and .isEnabled then
set .isMoving = true
set .isPatroling = true
endif
return false
endmethod
private static method OnCast takes nothing returns boolean
local thistype this = GetUnitUserData(GetTriggerUnit())
if .object != null and .isEnabled and (GetSpellTargetX() != 0 or GetSpellTargetY() != 0) then
set .isMoving = false
set .target = null
endif
return false
endmethod
static if AUTO_REGISTER then
private static method OnIndex takes nothing returns boolean
local unit u = GetIndexedUnit()
if FilterUnit(u) then
call RegisterUnit(u)
endif
set u = null
return false
endmethod
endif
private static method OnDeindex takes nothing returns boolean
local thistype this = thistype[GetIndexedUnit()]
local group tempG
local unit u
if .object != null then
call GroupRemoveUnit(Objects, .object)
call destroy()
set EventWasted = EventWasted+1
if EventWasted == TRIGGER_RECYCLE_THRESHOLD then
set EventWasted = 0
call DestroyTrigger(DetectTrigger)
set DetectTrigger = CreateTrigger()
call TriggerAddCondition(DetectTrigger, DetectFunc)
set tempG = CreateGroup()
loop
set u = FirstOfGroup(Objects)
exitwhen u == null
call GroupRemoveUnit(Objects, u)
call GroupAddUnit(tempG, u)
call TriggerRegisterUnitEvent(DetectTrigger, u, EVENT_UNIT_ACQUIRED_TARGET)
endloop
call DestroyGroup(Objects)
set Objects = tempG
set tempG = null
endif
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local player p
local integer i = 0
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
local trigger t4 = CreateTrigger()
set WorldMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set WorldMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set WorldMinX = GetRectMinX(bj_mapInitialPlayableArea)
set WorldMinY = GetRectMinX(bj_mapInitialPlayableArea)
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
set p = Player(i)
call TriggerRegisterPlayerUnitEvent(t4, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
call TriggerRegisterPlayerUnitEvent(t1, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
call TriggerRegisterPlayerUnitEvent(t1, p, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
call TriggerRegisterPlayerUnitEvent(t2, p, EVENT_PLAYER_UNIT_SPELL_CAST, null)
call TriggerRegisterPlayerUnitEvent(t3, p, EVENT_PLAYER_UNIT_ATTACKED, null)
set i = i + 1
endloop
set DetectFunc = Condition(function thistype.OnDetect)
call TriggerAddCondition(DetectTrigger, DetectFunc)
call TriggerAddCondition(t1, Condition(function thistype.OnOrder))
call TriggerAddCondition(t2, Condition(function thistype.OnCast))
call TriggerAddCondition(t3, Condition(function thistype.OnAttack))
call TriggerAddCondition(t4, Condition(function thistype.OnImmediateOrder))
static if AUTO_REGISTER then
call RegisterUnitIndexEvent(Condition(function thistype.OnIndex), UnitIndexer.INDEX)
endif
call RegisterUnitIndexEvent(Condition(function thistype.OnDeindex), UnitIndexer.DEINDEX)
endmethod
endstruct
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.1.0
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library_once Event /* v2.0.0.1
************************************************************************************
*
* Functions
*
* function CreateEvent takes nothing returns integer
* function TriggerRegisterEvent takes trigger t, integer ev returns nothing
*
************************************************************************************
*
* struct Event extends array
*
* static method create takes nothing returns thistype
* method registerTrigger takes trigger t returns nothing
* method register takes boolexpr c returns nothing
* method fire takes nothing returns nothing
*
************************************************************************************/
globals
private real q=0
endglobals
struct Event extends array
private static integer w=0
private static trigger array e
static method create takes nothing returns thistype
set w=w+1
set e[w]=CreateTrigger()
return w
endmethod
method registerTrigger takes trigger t returns nothing
call TriggerRegisterVariableEvent(t,SCOPE_PRIVATE+"q",EQUAL,this)
endmethod
method register takes boolexpr c returns nothing
call TriggerAddCondition(e[this],c)
endmethod
method fire takes nothing returns nothing
set q=0
set q=this
call TriggerEvaluate(e[this])
endmethod
endstruct
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function TriggerRegisterEvent takes trigger t,Event ev returns nothing
call ev.registerTrigger(t)
endfunction
function RegisterEvent takes boolexpr c,Event ev returns nothing
call ev.register(c)
endfunction
function FireEvent takes Event ev returns nothing
call ev.fire()
endfunction
endlibrary
library_once WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
* readonly static integer centerX
* readonly static integer centerY
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=R2I(GetRectMaxX(world))
set maxY=R2I(GetRectMaxY(world))
set minX=R2I(GetRectMinX(world))
set minY=R2I(GetRectMinY(world))
set centerX=R2I((maxX+minX)/2)
set centerY=R2I((minY+maxY)/2)
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
library UnitIndexer /* v4.0.2.7
*************************************************************************************
*
* Assigns unique indexes to units via unit user data.
*
*************************************************************************************
*
* */uses/*
*
* */ WorldBounds /* hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
* */ Event /* hiveworkshop.com/forums/submissions-414/snippet-event-186555/
*
************************************************************************************
*
* SETTINGS
*/
globals
constant integer ABILITIES_UNIT_INDEXER = 'A000'
endglobals
/*
************************************************************************************
*
* Functions
*
* function RegisterUnitIndexEvent takes boolexpr codeToRegister, Event unitIndexEvent returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger triggerToRegister, Event unitIndexEvent returns nothing
*
* function GetUnitById takes integer index returns unit
* - Returns unit given a unit index
* function GetUnitId takes unit u returns integer
* - Returns unit index given a unit
*
* function IsUnitIndexed takes unit u returns boolean
* function IsUnitDeindexing takes unit u returns boolean
*
* function GetIndexedUnitId takes nothing returns integer
* function GetIndexedUnit takes nothing returns unit
*
************************************************************************************
*
* module UnitIndexStructMethods
* static method operator [] takes unit u returns thistype
* - Return GetUnitUserData(u)
*
* readonly unit unit
* - The indexed unit of the struct
*
************************************************************************************
*
* module UnitIndexStruct extends UnitIndexStructMethods
*
* - A pseudo module interface that runs a set of methods if they exist and provides
* - a few fields and operators. Runs on static ifs to minimize code.
*
* readonly boolean allocated
* - Is unit allocated for the struct
*
* Interface:
*
* - These methods don't have to exist. If they don't exist, the code
* - that calls them won't even be in the module.
*
* private method index takes nothing returns nothing
* - called when a unit is indexed and passes the filter.
* -
* - thistype this: Unit's index
* private method deindex takes nothing returns nothing
* - called when a unit is deindexed and is allocated for struct
* -
* - thistype this: Unit's index
* private static method filter takes unit unitToIndex returns boolean
* - Determines whether or not to allocate struct for unit
* -
* - unit unitToIndex: Unit being filtered
*
************************************************************************************
*
* struct UnitIndexer extends array
*
* - Controls the unit indexer system.
*
* static constant Event UnitIndexer.INDEX
* static constant Event UnitIndexer.DEINDEX
* - Don't register functions and triggers directly to the events. Register them via
* - RegisterUnitIndexEvent and TriggerRegisterUnitIndexEvent.
*
* static boolean enabled
* - Enables and disables unit indexing. Useful for filtering out dummy units.
*
************************************************************************************
*
* struct UnitIndex extends UnitIndexStructMethods
*
* - Constrols specific unit indexes.
*
* method lock takes nothing returns nothing
* - Locks an index. When an index is locked, it will not be recycled
* - when the unit is deindexed until all locks are removed. Deindex
* - events still fire at the appropriate times, the index just doesn't
* - get thrown into the recycler.
* method unlock takes nothing returns nothing
* - Unlocks an index.
*
************************************************************************************/
globals
private trigger q=CreateTrigger()
private trigger l=CreateTrigger()
private unit array e
private integer r=0
private integer y=0
private integer o=0
private boolean a=false
private integer array n
private integer array p
private integer array lc
endglobals
function GetIndexedUnitId takes nothing returns integer
return o
endfunction
function GetIndexedUnit takes nothing returns unit
return e[o]
endfunction
//! runtextmacro optional UNIT_LIST_LIB()
private struct PreLoader extends array
public static method run takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
set a=true
endmethod
public static method eval takes trigger t returns nothing
local integer f=n[0]
local integer d=o
loop
exitwhen 0==f
if (IsTriggerEnabled(t)) then
set o=f
if (TriggerEvaluate(t)) then
call TriggerExecute(t)
endif
else
exitwhen true
endif
set f=n[f]
endloop
set o=d
endmethod
public static method evalb takes boolexpr c returns nothing
local trigger t=CreateTrigger()
local thistype f=n[0]
local integer d=o
call TriggerAddCondition(t,c)
loop
exitwhen 0==f
set o=f
call TriggerEvaluate(t)
set f=n[f]
endloop
call DestroyTrigger(t)
set t=null
set o=d
endmethod
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO()
private module UnitIndexerInit
private static method onInit takes nothing returns nothing
local integer i=15
local boolexpr bc=Condition(function thistype.onLeave)
local boolexpr bc2=Condition(function thistype.onEnter)
local group g=CreateGroup()
local player p
set INDEX=CreateEvent()
set DEINDEX=CreateEvent()
call TriggerRegisterEnterRegion(q,WorldBounds.worldRegion,bc2)
loop
set p=Player(i)
call TriggerRegisterPlayerUnitEvent(l,p,EVENT_PLAYER_UNIT_ISSUED_ORDER,bc)
call SetPlayerAbilityAvailable(p,ABILITIES_UNIT_INDEXER,false)
call GroupEnumUnitsOfPlayer(g,p,bc2)
exitwhen 0==i
set i=i-1
endloop
call DestroyGroup(g)
set bc=null
set g=null
set bc2=null
set p=null
call TimerStart(CreateTimer(),0,false,function PreLoader.run)
endmethod
endmodule
struct UnitIndex extends array
method lock takes nothing returns nothing
debug if (null!=e[this]) then
set lc[this]=lc[this]+1
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO LOCK NULL INDEX")
debug endif
endmethod
method unlock takes nothing returns nothing
debug if (0<lc[this]) then
set lc[this]=lc[this]-1
if (0==lc[this] and null==e[this]) then
set n[this]=y
set y=this
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"UNIT INDEXER ERROR: ATTEMPT TO UNLOCK UNLOCKED INDEX")
debug endif
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
static method operator [] takes unit whichUnit returns thistype
return GetUnitUserData(whichUnit)
endmethod
endstruct
struct UnitIndexer extends array
readonly static Event INDEX
readonly static Event DEINDEX
static boolean enabled=true
private static method onEnter takes nothing returns boolean
local unit Q=GetFilterUnit()
local integer i
local integer d=o
if (enabled and Q!=e[GetUnitUserData(Q)] and 0==GetUnitUserData(Q)) then
if (0==y) then
set r=r+1
set i=r
else
set i=y
set y=n[y]
endif
call UnitAddAbility(Q,ABILITIES_UNIT_INDEXER)
call UnitMakeAbilityPermanent(Q,true,ABILITIES_UNIT_INDEXER)
call SetUnitUserData(Q,i)
set e[i]=Q
static if not LIBRARY_UnitList then
if (not a)then
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
endif
else
set p[i]=p[0]
set n[p[0]]=i
set n[i]=0
set p[0]=i
call GroupAddUnit(g,e[i])
endif
set o=i
call FireEvent(INDEX)
set o=d
endif
set Q=null
return false
endmethod
private static method onLeave takes nothing returns boolean
static if LIBRARY_UnitEvent then
implement optional UnitEventModule
else
local unit u=GetFilterUnit()
local integer i=GetUnitUserData(u)
local integer d=o
if (0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER) and u==e[i]) then
static if not LIBRARY_UnitList then
if (not a)then
set n[p[i]]=n[i]
set p[n[i]]=p[i]
endif
else
set n[p[i]]=n[i]
set p[n[i]]=p[i]
call GroupRemoveUnit(g,e[i])
endif
set o=i
call FireEvent(DEINDEX)
set o=d
if (0==lc[i]) then
set n[i]=y
set y=i
endif
set e[i]=null
endif
set u=null
endif
return false
endmethod
implement UnitIndexerInit
endstruct
//! runtextmacro optional UNIT_EVENT_MACRO_2()
function RegisterUnitIndexEvent takes boolexpr c,integer ev returns nothing
call RegisterEvent(c, ev)
if (not a and ev==UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.evalb(c)
endif
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t,integer ev returns nothing
call TriggerRegisterEvent(t,ev)
if (not a and ev == UnitIndexer.INDEX and 0!=n[0]) then
call PreLoader.eval(t)
endif
endfunction
function GetUnitById takes integer W returns unit
return e[W]
endfunction
function GetUnitId takes unit u returns integer
return GetUnitUserData(u)
endfunction
function IsUnitIndexed takes unit u returns boolean
return u==e[GetUnitUserData(u)]
endfunction
function IsUnitDeindexing takes unit u returns boolean
return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u,ABILITIES_UNIT_INDEXER)
endfunction
module UnitIndexStructMethods
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
method operator unit takes nothing returns unit
return e[this]
endmethod
endmodule
module UnitIndexStruct
implement UnitIndexStructMethods
static if thistype.filter.exists then
static if thistype.index.exists then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return filter(e[this])
endmethod
endif
elseif (thistype.index.exists) then
static if thistype.deindex.exists then
readonly boolean allocated
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
else
method operator allocated takes nothing returns boolean
return this==GetUnitUserData(e[this])
endmethod
endif
static if thistype.index.exists then
private static method onIndexEvent takes nothing returns boolean
static if thistype.filter.exists then
if (filter(e[o])) then
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
else
static if thistype.deindex.exists then
set thistype(o).allocated=true
endif
call thistype(o).index()
endif
return false
endmethod
endif
static if thistype.deindex.exists then
private static method onDeindexEvent takes nothing returns boolean
static if thistype.filter.exists then
static if thistype.index.exists then
if (thistype(o).allocated) then
set thistype(o).allocated=false
call thistype(o).deindex()
endif
else
if (filter(e[o])) then
call thistype(o).deindex()
endif
endif
else
static if thistype.index.exists then
set thistype(o).allocated=false
endif
call thistype(o).deindex()
endif
return false
endmethod
endif
static if thistype.index.exists then
static if thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
else
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent),UnitIndexer.INDEX)
endmethod
endif
elseif thistype.deindex.exists then
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent),UnitIndexer.DEINDEX)
endmethod
endif
endmodule
endlibrary
library GetTerrainZ /* v1.0.0.0
********************************************************************
*
* function GetTerrainZ takes real x, real y returns real
*
********************************************************************/
globals
private constant location L = Location(0, 0)
endglobals
function GetTerrainZ takes real x, real y returns real
call MoveLocation(L, x, y)
return GetLocationZ(L)
endfunction
endlibrary
library UnitZ /* v1.0.0.0
********************************************************************
*
* */uses/*
* */ GetTerrainZ /*
* */optional/*
* */ AutoFly /* hiveworkshop.com/forums/jass-resources-412/snippet-autofly-unitindexer-version-195563/
*
* function GetUnitZ takes unit whichUnit returns real
* function SetUnitZ takes unit whichUnit, real z returns real
*
********************************************************************/
function GetUnitZ takes unit u returns real
return GetTerrainZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetTerrainZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
endlibrary
library PathingLib
// Object generator
///! external ObjectMerger w3u hgry hPLF unsf "(PathingLib) FlyChecker" unam "" umdl ".mdl" ubdg 0 uabi "Aloc" uble 0 ulum 0 upoi 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" ugol 0 uaen "" udea "" umvt "fly" usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
///! external ObjectMerger w3u hfoo hPLW unsf "(PathingLib) WalkChecker" unam "" umdl ".mdl" ubdg 0 uabi "Aloc" uble 0 ulum 0 upoi 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" ugol 0 uaen "" udea "" umvt "foot" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
///! external ObjectMerger w3u hhou hPLB unsf "(PathingLib) BuildChecker" unam "" umdl ".mdl" ubdg 1 uabi "Aloc" upat "" ulum 0 upoi 0 uubs "" uble 0 ushb "" uico "" ugol 0 ufma 0 umxp 0 ubsl "" umxr 0 ussc 0 ushu "" uaen "" udea "" umvt "" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
///! external ObjectMerger w3u hpea hPLP unsf "(PathingLib) PathChecker" unam "" umdl ".mdl" ubdg 0 uabi "Aloc" uble 0 ubui "hPLF,hPLW,hPLB" ulum 0 upoi 0 uico "" umxp 0 umxr 0 ussc 0 ushu "" ugol 0 uaen "" udea "" umvt "foot" ucol 0 usnd "" ufle 0 ufoo 0 uspe 1 uhom 1 urac "unknown" usid 0 usin 0 upgr "" uhot "" utip "" utub ""
// Configuration
globals
private constant integer PATH_CHECKER = 'hPLP'
private constant integer FLY_CHECKER = 'hPLF'
private constant integer WALK_CHECKER = 'hPLW'
private constant integer BUILD_CHECKER = 'hPLB'
private constant player DUMMY_PLAYER = Player(15)
endglobals
/*
Pathing Library v1.6
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Description
¯¯¯¯¯¯¯¯¯¯¯
Allows you to detect all pathability types:
walkablility, flyability, and buildability.
Warning!
Please keep informed that this system is more sensitive than
any other walkability checker systems out there, as it also
detects pathing map generated by normal units as well.
API
¯¯¯
| function IsTerrainFlyable takes real x, real y returns boolean
| function IsTerrainWalkable takes real x, real y returns boolean
| function IsTerrainBuildable takes real x, real y returns boolean
How to import
¯¯¯¯¯¯¯¯¯¯¯¯¯
- Copy Fly, Walk, Build, and Path Checker at object editor (Unit).
- Make sure Path Checker is able to build Fly, Walk, and Build Checker
(at object editor>unit>Path Checker>"Techtree - Structures built")
- Configure this system correctly.
Link: hiveworkshop.com/forums/spells-569/pathing-type-v1-2-a-263230/
*/
globals
private unit PathChecker
endglobals
function IsTerrainFlyable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, FLY_CHECKER, x, y)
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, WALK_CHECKER, x, y)
endfunction
function IsTerrainBuildable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, BUILD_CHECKER, x, y)
endfunction
private module Init
private static method onInit takes nothing returns nothing
call init()
endmethod
endmodule
private struct InitStruct extends array
private static method init takes nothing returns nothing
set PathChecker = CreateUnit(DUMMY_PLAYER, PATH_CHECKER, 0, 0, 0)
call UnitRemoveAbility(PathChecker, 'Amov')
call ShowUnit(PathChecker, false)
if GetLocalPlayer() == DUMMY_PLAYER then
call FogEnable(false)
endif
endmethod
implement Init
endstruct
endlibrary
library PathingColor requires PathingLib
/*
Pathing Color v1.5
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Pathing may generate color based on their characteristics.
If the pathing is not walkable, it will have red color. If
the pathing is not buildable, it will have blue color. And
if the pathing is not flyable, it will have green color.
The rests are just combinations between these colors.
Here is the summary to ease everything: (o = yes, x = no)
Color Buildable Walkable Flyable Red Green Blue
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
White x x x 255 255 255
Magenta x x o 255 0 255
Cyan x o x 0 255 255
Blue x o o 0 0 255
Yellow o x x 255 255 0
Red o x o 255 0 0
Green o o x 0 255 0
Black o o o 0 0 0
(You can check your pathing map by pressing 'p' at terrain editor)
API
¯¯¯
| function GetTerrainPathingColor takes real x, real y returns integer
(Constants)
| PATHING_COLOR_WHITE
| PATHING_COLOR_MAGENTA
| PATHING_COLOR_CYAN
| PATHING_COLOR_BLUE
| PATHING_COLOR_YELLOW
| PATHING_COLOR_RED
| PATHING_COLOR_GREEN
| PATHING_COLOR_BLACK
*/
globals
constant integer PATHING_COLOR_WHITE = 0
constant integer PATHING_COLOR_MAGENTA = 1
constant integer PATHING_COLOR_CYAN = 2
constant integer PATHING_COLOR_BLUE = 3
constant integer PATHING_COLOR_YELLOW = 4
constant integer PATHING_COLOR_RED = 5
constant integer PATHING_COLOR_GREEN = 6
constant integer PATHING_COLOR_BLACK = 7
endglobals
function GetTerrainPathingColor takes real x, real y returns integer
local integer color = 0
if IsTerrainFlyable(x, y) then
set color = color + 1
endif
if IsTerrainWalkable(x, y) then
set color = color + 2
endif
if IsTerrainBuildable(x, y) then
set color = color + 4
endif
return color
endfunction
endlibrary
scope DemoCode initializer init
private function init takes nothing returns nothing
call FogEnable(false)
call FogMaskEnable(false)
// Initialize terrain frictions
call RigidBody_TerrainUtils.SetTerrainTypeFriction(1665229617, 2.0) // Grass
call RigidBody_TerrainUtils.SetTerrainTypeFriction(1666081585, 2.0) // Snow
call RigidBody_TerrainUtils.SetTerrainTypeFriction('Adrd', 2.0) // Ashenvale Dirt Rough
call RigidBody_TerrainUtils.SetTerrainTypeFriction('Idki', 0.0) // Icecrown Dark Ice
call RigidBody_TerrainUtils.SetTerrainTypeFriction('Idrt', 2.0) // Icecrown Dirt
call RigidBody_TerrainUtils.SetTerrainTypeFriction('Nice', 0.15) // Nothrend Ice
// Initialize unit data
call RigidBody_UnitDataRef.Add('Hamg', 600.0, 0.850) // Archmage
call RigidBody_UnitDataRef.Add('Hpal', 132.0, 0.567) // Paladin
call RigidBody_UnitDataRef.Add('Hmkg', 132.0, 0.650) // Mountain King
call RigidBody_UnitDataRef.Add('Hblm', 600.0, 0.850) // Blood Mage
endfunction
endscope
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
local RigidBody s = RigidBody[GetTriggerUnit()]
call IssueImmediateOrder(GetTriggerUnit(), "stop")
call s.accelerate(17, 100, 270*bj_DEGTORAD, 360*bj_DEGTORAD)
endfunction
function Trig_Untitled_Trigger_002_Actions takes nothing returns nothing
local RigidBody s = RigidBody[GetTriggerUnit()]
call IssueImmediateOrder(GetTriggerUnit(), "stop")
call s.accelerate(20, 100, 0, 360*bj_DEGTORAD)
endfunction
function Trig_Untitled_Trigger_003_Actions takes nothing returns nothing
local RigidBody s = RigidBody[GetTriggerUnit()]
call IssueImmediateOrder(GetTriggerUnit(), "stop")
call s.move(4223.26, -2143.93, 0)
endfunction
function Trig_Untitled_Trigger_004_Actions takes nothing returns nothing
local RigidBody s = RigidBody[GetTriggerUnit()]
call s.move(-3091.95, GetUnitY(s.object), 300)
endfunction
function InitTrig_OnRectEnter takes nothing returns nothing
set gg_trg_OnRectEnter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_OnRectEnter, gg_rct_Rect_000 )
call TriggerAddAction( gg_trg_OnRectEnter, function Trig_Untitled_Trigger_001_Actions )
set gg_trg_OnRectEnter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_OnRectEnter, gg_rct_Rect_001 )
call TriggerAddAction( gg_trg_OnRectEnter, function Trig_Untitled_Trigger_002_Actions )
set gg_trg_OnRectEnter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_OnRectEnter, gg_rct_Rect_002 )
call TriggerAddAction( gg_trg_OnRectEnter, function Trig_Untitled_Trigger_003_Actions )
set gg_trg_OnRectEnter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_OnRectEnter, gg_rct_Rect_003 )
call TriggerAddAction( gg_trg_OnRectEnter, function Trig_Untitled_Trigger_004_Actions )
endfunction
function Trig_Untitled_Trigger_0033_Actions takes nothing returns nothing
call BJDebugMsg(OrderId2String(GetUnitCurrentOrder(GetTriggerUnit())))
endfunction
//===========================================================================
function InitTrig_GetCurrentOrder takes nothing returns nothing
set gg_trg_GetCurrentOrder = CreateTrigger( )
call TriggerRegisterPlayerSelectionEventBJ( gg_trg_GetCurrentOrder, Player(0), true )
call TriggerAddAction( gg_trg_GetCurrentOrder, function Trig_Untitled_Trigger_0033_Actions )
endfunction