Name | Type | is_array | initial_value |
acceleration | real | No | |
angle | real | No | |
Blizzard_Damage | real | Yes | |
caster | unit | No | |
circumference | real | No | |
CMS_ABILITY_GHOST | abilcode | No | |
CMS_ABILITY_MORPH | abilcode | No | |
CMS_Amount | integer | No | |
CMS_Collided_Dest | destructable | No | |
CMS_Collided_Item | item | No | |
CMS_Collided_Unit | unit | No | |
CMS_COLLISIONTYPE_CIRCLE | integer | No | |
CMS_COLLISIONTYPE_NONE | integer | No | |
CMS_COLLISIONTYPE_RECTANGLE | integer | No | |
CMS_COLLISIONTYPE_SIMPLE | integer | No | |
CMS_DUMMY_UNITTYPE | unitcode | No | |
CMS_Event_Missile_Collided_D | real | No | |
CMS_Event_Missile_Collided_I | real | No | |
CMS_Event_Missile_Collided_T | real | No | |
CMS_Event_Missile_Collided_U | real | No | |
CMS_Event_Missile_Created | real | No | |
CMS_Event_Missile_Destroyed | real | No | |
CMS_Event_Missile_Tick | real | No | |
CMS_Index | integer | No | |
CMS_INTERVAL | real | No | |
CMS_LoopIndex | integer | No | |
CMS_MISSILE_UNITTYPE | unitcode | No | |
CMS_Param_Collision_Cooldown | real | Yes | |
CMS_Param_Collision_Dest | boolean | Yes | |
CMS_Param_Collision_Height | real | Yes | |
CMS_Param_Collision_Height_Inc | real | Yes | |
CMS_Param_Collision_Item | boolean | Yes | |
CMS_Param_Collision_Type | integer | Yes | |
CMS_Param_Collision_Unit | boolean | Yes | |
CMS_Param_Collision_Width | real | Yes | |
CMS_Param_Collision_Width_Inc | real | Yes | |
CMS_Param_Distance | real | Yes | |
CMS_Param_Duration | real | Yes | |
CMS_Param_Effect | effect | Yes | |
CMS_Param_Gravity | real | Yes | |
CMS_Param_Index | integer | Yes | |
CMS_Param_IsAUnit | boolean | Yes | |
CMS_Param_IsDestroyed | boolean | Yes | |
CMS_Param_IsFlying | boolean | Yes | |
CMS_Param_IsHoming | boolean | Yes | |
CMS_Param_MaxDistance | real | Yes | |
CMS_Param_MaxDuration | real | Yes | |
CMS_Param_Missile | unit | Yes | |
CMS_Param_Source | unit | Yes | |
CMS_Param_Subtype | integer | Yes | |
CMS_Param_Target_Location | location | Yes | |
CMS_Param_Target_Type | integer | Yes | |
CMS_Param_Target_Unit | unit | Yes | |
CMS_Param_TurnRate | real | Yes | |
CMS_Param_Type | integer | Yes | |
CMS_Param_WalkingHeight | real | Yes | |
CMS_SecondsPerTick | real | No | |
CMS_SecondsPerTickSquared | real | No | |
CMS_StartingAcceleration | real | No | |
CMS_StartingAngle | real | No | |
CMS_StartingDefaultValues | boolean | No | |
CMS_StartingHeight | real | No | |
CMS_StartingLocation | location | No | |
CMS_StartingLocust | boolean | No | |
CMS_StartingMissile | unit | No | |
CMS_StartingPitch | real | No | |
CMS_StartingSource | unit | No | |
CMS_StartingSourceFilter | boolean | No | |
CMS_StartingSpeed | real | No | |
CMS_StartingType | integer | No | |
CMS_StopCollision | boolean | No | |
CMS_TARGETTYPE_LOCATION | integer | No | |
CMS_TARGETTYPE_NONE | integer | No | |
CMS_TARGETTYPE_UNIT | integer | No | |
CMS_TicksPerSecond | real | No | |
CMS_TicksPerSecondSquared | real | No | |
CMS_ValidTarget | boolean | No | |
count | integer | No | |
damage | real | No | |
diameter | real | No | |
distance | real | No | |
gravity | real | No | |
height | real | No | |
index | integer | No | |
level | integer | No | |
PI | real | No | 3.14 |
radius | real | No | |
RocketBarrage_CancelTimer | timer | No | |
RocketBarrage_Caster | unit | No | |
RocketBarrage_CasterPoint | location | No | |
RocketBarrage_Damage | real | No | |
RocketBarrage_RemainingRockets | integer | No | |
RocketBarrage_TargetPoint | location | No | |
RocketBarrage_Timer | timer | No | |
seconds_per_turn | real | No | |
SeekerMissile_Damage | real | Yes | |
source_location | location | No | |
target_location | location | No | |
TempAbility | abilcode | No | |
TempInteger | integer | No | |
TempInteger2 | integer | No | |
TempLocation | location | No | |
TempLocation2 | location | No | |
TempReal | real | No | |
TempReal2 | real | No | |
TempReal3 | real | No | |
TempUnit | unit | No | |
TempUnit2 | unit | No | |
test_case | integer | No | |
ticks_per_second | real | No | |
turn_rate | real | No | |
velocity | real | No |
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// library BasicFunctions:
// Author: Wietlol
// Version: 2.0
// Date: 1/12/2015
//library BasicFunctions
// contains:
// GlobalVariables,
// ConvertionFunctions,
// ColorFunctions,
// PositionFunctions,
// GroupFunctions,
// ItemFunctions,
// MathFunctions,
// TimeFunctions.
//
// special thanks:
// - edo494
// - IcemanBo
// - Xonok
// - Geries
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Custom natives:
//
//Returns wether the given unit is alive or not.
native UnitAlive takes unit id returns boolean
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Global constant variables:
//
library GlobalVariables initializer BF_INIT_GlobalVariables
globals
//The local player.
player LOCAL_PLAYER
integer LOCAL_PLAYER_ID
//The initial world bounds of the map.
rect WORLD_BOUNDS
//A rect for public use.
rect RECT = Rect(0, 0, 0, 0)
//A location for public use.
location LOCATION = Location(0, 0)
//Maximum and minimum values of an integer.
constant integer INTEGER_MAX = 2147483647
constant integer INTEGER_MIN = 2147483648
//Maximum and minimum values of a real.
constant real REAL_MAX = 2147483647
constant real REAL_MIN = 2147483648
//bj_E with 6 decimals.
constant real E = 2.718282
//bj_PI with 6 decimals.
constant real PI = 3.141593
//Double of PI.
constant real TAU = 2*PI
//bj_RADTODEG and bj_DEGTORAD calculated with the PI from this library.
constant real RADTODEG = 180.0/PI
constant real DEGTORAD = PI/180.0
//A temporary variable for each object type using the name "objecttype" in upper case followed by "_VAR".
boolean BOOLEAN_VAR = false
integer INTEGER_VAR = 0
real REAL_VAR = 0.
string STRING_VAR = ""
code CODE_VAR = null
handle HANDLE_VAR = null
agent AGENT_VAR = null
event EVENT_VAR = null
player PLAYER_VAR = null
widget WIDGET_VAR = null
unit UNIT_VAR = null
destructable DESTRUCTABLE_VAR = null
item ITEM_VAR = null
ability ABILITY_VAR = null
buff BUFF_VAR = null
force FORCE_VAR = null
group GROUP_VAR = null
trigger TRIGGER_VAR = null
triggercondition TRIGGERCONDITION_VAR = null
triggeraction TRIGGERACTION_VAR = null
timer TIMER_VAR = null
location LOCATION_VAR = null
region REGION_VAR = null
rect RECT_VAR = null
boolexpr BOOLEXPR_VAR = null
sound SOUND_VAR = null
conditionfunc CONDITIONFUNC_VAR = null
filterfunc FILTERFUNC_VAR = null
unitpool UNITPOOL_VAR = null
itempool ITEMPOOL_VAR = null
race RACE_VAR = null
alliancetype ALLIANCETYPE_VAR = null
racepreference RACEPREFERENCE_VAR = null
gamestate GAMESTATE_VAR = null
igamestate IGAMESTATE_VAR = null
fgamestate FGAMESTATE_VAR = null
playerstate PLAYERSTATE_VAR = null
playerscore PLAYERSCORE_VAR = null
playergameresult PLAYERGAMERESULT_VAR = null
unitstate UNITSTATE_VAR = null
aidifficulty AIDIFFICULTY_VAR = null
eventid EVENTID_VAR = null
gameevent GAMEEVENT_VAR = null
playerevent PLAYEREVENT_VAR = null
playerunitevent PLAYERUNITEVENT_VAR = null
unitevent UNITEVENT_VAR = null
limitop LIMITOP_VAR = null
widgetevent WIDGETEVENT_VAR = null
dialogevent DIALOGEVENT_VAR = null
unittype UNITTYPE_VAR = null
gamespeed GAMESPEED_VAR = null
gamedifficulty GAMEDIFFICULTY_VAR = null
gametype GAMETYPE_VAR = null
mapflag MAPFLAG_VAR = null
mapvisibility MAPVISIBILITY_VAR = null
mapsetting MAPSETTING_VAR = null
mapdensity MAPDENSITY_VAR = null
mapcontrol MAPCONTROL_VAR = null
playerslotstate PLAYERSLOTSTATE_VAR = null
volumegroup VOLUMEGROUP_VAR = null
camerafield CAMERAFIELD_VAR = null
camerasetup CAMERASETUP_VAR = null
playercolor PLAYERCOLOR_VAR = null
placement PLACEMENT_VAR = null
startlocprio STARTLOCPRIO_VAR = null
raritycontrol RARITYCONTROL_VAR = null
blendmode BLENDMODE_VAR = null
texmapflags TEXMAPFLAGS_VAR = null
effect EFFECT_VAR = null
effecttype EFFECTTYPE_VAR = null
weathereffect WEATHEREFFECT_VAR = null
terraindeformation TERRAINDEFORMATION_VAR = null
fogstate FOGSTATE_VAR = null
fogmodifier FOGMODIFIER_VAR = null
dialog DIALOG_VAR = null
button BUTTON_VAR = null
quest QUEST_VAR = null
questitem QUESTITEM_VAR = null
defeatcondition DEFEATCONDITION_VAR = null
timerdialog TIMERDIALOG_VAR = null
leaderboard LEADERBOARD_VAR = null
multiboard MULTIBOARD_VAR = null
multiboarditem MULTIBOARDITEM_VAR = null
trackable TRACKABLE_VAR = null
gamecache GAMECACHE_VAR = null
version VERSION_VAR = null
itemtype ITEMTYPE_VAR = null
texttag TEXTTAG_VAR = null
attacktype ATTACKTYPE_VAR = null
damagetype DAMAGETYPE_VAR = null
weapontype WEAPONTYPE_VAR = null
soundtype SOUNDTYPE_VAR = null
lightning LIGHTNING_VAR = null
pathingtype PATHINGTYPE_VAR = null
image IMAGE_VAR = null
ubersplat UBERSPLAT_VAR = null
hashtable HASHTABLE_VAR = null
//A temporary variable array for each object type using the name "objecttype" in upper case followed by "_ARRAY".
//With exception of code array.
boolean array BOOLEAN_ARRAY
integer array INTEGER_ARRAY
real array REAL_ARRAY
string array STRING_ARRAY
//code array CODE_ARRAY
handle array HANDLE_ARRAY
agent array AGENT_ARRAY
event array EVENT_ARRAY
player array PLAYER_ARRAY
widget array WIDGET_ARRAY
unit array UNIT_ARRAY
destructable array DESTRUCTABLE_ARRAY
item array ITEM_ARRAY
ability array ABILITY_ARRAY
buff array BUFF_ARRAY
force array FORCE_ARRAY
group array GROUP_ARRAY
trigger array TRIGGER_ARRAY
triggercondition array TRIGGERCONDITION_ARRAY
triggeraction array TRIGGERACTION_ARRAY
timer array TIMER_ARRAY
location array LOCATION_ARRAY
region array REGION_ARRAY
rect array RECT_ARRAY
boolexpr array BOOLEXPR_ARRAY
sound array SOUND_ARRAY
conditionfunc array CONDITIONFUNC_ARRAY
filterfunc array FILTERFUNC_ARRAY
unitpool array UNITPOOL_ARRAY
itempool array ITEMPOOL_ARRAY
race array RACE_ARRAY
alliancetype array ALLIANCETYPE_ARRAY
racepreference array RACEPREFERENCE_ARRAY
gamestate array GAMESTATE_ARRAY
igamestate array IGAMESTATE_ARRAY
fgamestate array FGAMESTATE_ARRAY
playerstate array PLAYERSTATE_ARRAY
playerscore array PLAYERSCORE_ARRAY
playergameresult array PLAYERGAMERESULT_ARRAY
unitstate array UNITSTATE_ARRAY
aidifficulty array AIDIFFICULTY_ARRAY
eventid array EVENTID_ARRAY
gameevent array GAMEEVENT_ARRAY
playerevent array PLAYEREVENT_ARRAY
playerunitevent array PLAYERUNITEVENT_ARRAY
unitevent array UNITEVENT_ARRAY
limitop array LIMITOP_ARRAY
widgetevent array WIDGETEVENT_ARRAY
dialogevent array DIALOGEVENT_ARRAY
unittype array UNITTYPE_ARRAY
gamespeed array GAMESPEED_ARRAY
gamedifficulty array GAMEDIFFICULTY_ARRAY
gametype array GAMETYPE_ARRAY
mapflag array MAPFLAG_ARRAY
mapvisibility array MAPVISIBILITY_ARRAY
mapsetting array MAPSETTING_ARRAY
mapdensity array MAPDENSITY_ARRAY
mapcontrol array MAPCONTROL_ARRAY
playerslotstate array PLAYERSLOTSTATE_ARRAY
volumegroup array VOLUMEGROUP_ARRAY
camerafield array CAMERAFIELD_ARRAY
camerasetup array CAMERASETUP_ARRAY
playercolor array PLAYERCOLOR_ARRAY
placement array PLACEMENT_ARRAY
startlocprio array STARTLOCPRIO_ARRAY
raritycontrol array RARITYCONTROL_ARRAY
blendmode array BLENDMODE_ARRAY
texmapflags array TEXMAPFLAGS_ARRAY
effect array EFFECT_ARRAY
effecttype array EFFECTTYPE_ARRAY
weathereffect array WEATHEREFFECT_ARRAY
terraindeformation array TERRAINDEFORMATION_ARRAY
fogstate array FOGSTATE_ARRAY
fogmodifier array FOGMODIFIER_ARRAY
dialog array DIALOG_ARRAY
button array BUTTON_ARRAY
quest array QUEST_ARRAY
questitem array QUESTITEM_ARRAY
defeatcondition array DEFEATCONDITION_ARRAY
timerdialog array TIMERDIALOG_ARRAY
leaderboard array LEADERBOARD_ARRAY
multiboard array MULTIBOARD_ARRAY
multiboarditem array MULTIBOARDITEM_ARRAY
trackable array TRACKABLE_ARRAY
gamecache array GAMECACHE_ARRAY
version array VERSION_ARRAY
itemtype array ITEMTYPE_ARRAY
texttag array TEXTTAG_ARRAY
attacktype array ATTACKTYPE_ARRAY
damagetype array DAMAGETYPE_ARRAY
weapontype array WEAPONTYPE_ARRAY
soundtype array SOUNDTYPE_ARRAY
lightning array LIGHTNING_ARRAY
pathingtype array PATHINGTYPE_ARRAY
image array IMAGE_ARRAY
ubersplat array UBERSPLAT_ARRAY
hashtable array HASHTABLE_ARRAY
//A variable array containing global constants in an array to use "Convert<T>(i)" without function call.
//With exception of MAP_CHEATS_HIDDEN, MAP_LOCK_SPEED, MAP_LOCK_RANDOM_SEED, MAP_SHARED_ADVANCED_CONTROL,
// MAP_RANDOM_HERO, MAP_RANDOM_RACES, MAP_RELOADED and MAP_PLACEMENT_RANDOM because of array limit.
//With exception of mapsetting and mapvisibility.
//Also contains PLAYER[x].
constant player array PLAYER
constant aidifficulty array AI_DIFFICULTY
constant alliancetype array ALLIANCE_TYPE
constant attacktype array ATTACK_TYPE
constant blendmode array BLEND_MODE
constant camerafield array CAMERA_FIELD
constant damagetype array DAMAGE_TYPE
constant dialogevent array DIALOG_EVENT
constant effecttype array EFFECT_TYPE
constant fgamestate array F_GAME_STATE
constant fogstate array FOG_STATE
constant gamedifficulty array GAME_DIFFICULTY
constant gameevent array GAME_EVENT
constant gamespeed array GAME_SPEED
constant gametype array GAME_TYPE
constant igamestate array I_GAME_STATE
constant itemtype array ITEM_TYPE
constant limitop array LIMIT_OP
constant mapcontrol array MAP_CONTROL
constant mapdensity array MAP_DENSITY
constant mapflag array MAP_FLAG
//constant mapsetting array MAP_SETTING
//constant mapvisibility array MAP_VISIBILITY
constant pathingtype array PATHING_TYPE
constant placement array PLACEMENT
constant playercolor array PLAYER_COLOR
constant playerevent array PLAYER_EVENT
constant playergameresult array PLAYER_GAME_RESULT
constant playerscore array PLAYER_SCORE
constant playerslotstate array PLAYER_SLOT_STATE
constant playerstate array PLAYER_STATE
constant playerunitevent array PLAYER_UNIT_EVENT
constant race array RACE
constant racepreference array RACE_PREFERENCE
constant raritycontrol array RARITY_CONTROL
constant soundtype array SOUND_TYPE
constant startlocprio array START_LOC_PRIO
constant texmapflags array TEX_MAP_FLAGS
constant unitevent array UNIT_EVENT
constant unitstate array UNIT_STATE
constant unittype array UNIT_TYPE
constant version array VERSION
constant volumegroup array VOLUME_GROUP
constant weapontype array WEAPON_TYPE
constant widgetevent array WIDGET_EVENT
endglobals
function BF_INIT_GlobalVariables takes nothing returns nothing
set LOCAL_PLAYER = GetLocalPlayer()
set LOCAL_PLAYER_ID = GetPlayerId(LOCAL_PLAYER)
set WORLD_BOUNDS = GetWorldBounds()
set PLAYER[0] = Player(0)
set PLAYER[1] = Player(1)
set PLAYER[2] = Player(2)
set PLAYER[3] = Player(3)
set PLAYER[4] = Player(4)
set PLAYER[5] = Player(5)
set PLAYER[6] = Player(6)
set PLAYER[7] = Player(7)
set PLAYER[8] = Player(8)
set PLAYER[9] = Player(9)
set PLAYER[10] = Player(10)
set PLAYER[11] = Player(11)
set PLAYER[12] = Player(12)
set PLAYER[13] = Player(13)
set PLAYER[14] = Player(14)
set PLAYER[15] = Player(15)
set PLAYER_COLOR[0] = PLAYER_COLOR_RED
set PLAYER_COLOR[1] = PLAYER_COLOR_BLUE
set PLAYER_COLOR[2] = PLAYER_COLOR_CYAN
set PLAYER_COLOR[3] = PLAYER_COLOR_PURPLE
set PLAYER_COLOR[4] = PLAYER_COLOR_YELLOW
set PLAYER_COLOR[5] = PLAYER_COLOR_ORANGE
set PLAYER_COLOR[6] = PLAYER_COLOR_GREEN
set PLAYER_COLOR[7] = PLAYER_COLOR_PINK
set PLAYER_COLOR[8] = PLAYER_COLOR_LIGHT_GRAY
set PLAYER_COLOR[9] = PLAYER_COLOR_LIGHT_BLUE
set PLAYER_COLOR[10] = PLAYER_COLOR_AQUA
set PLAYER_COLOR[11] = PLAYER_COLOR_BROWN
set RACE[1] = RACE_HUMAN
set RACE[2] = RACE_ORC
set RACE[3] = RACE_UNDEAD
set RACE[4] = RACE_NIGHTELF
set RACE[5] = RACE_DEMON
set RACE[7] = RACE_OTHER
set PLAYER_GAME_RESULT[0] = PLAYER_GAME_RESULT_VICTORY
set PLAYER_GAME_RESULT[1] = PLAYER_GAME_RESULT_DEFEAT
set PLAYER_GAME_RESULT[2] = PLAYER_GAME_RESULT_TIE
set PLAYER_GAME_RESULT[3] = PLAYER_GAME_RESULT_NEUTRAL
set ALLIANCE_TYPE[0] = ALLIANCE_PASSIVE
set ALLIANCE_TYPE[1] = ALLIANCE_HELP_REQUEST
set ALLIANCE_TYPE[2] = ALLIANCE_HELP_RESPONSE
set ALLIANCE_TYPE[3] = ALLIANCE_SHARED_XP
set ALLIANCE_TYPE[4] = ALLIANCE_SHARED_SPELLS
set ALLIANCE_TYPE[5] = ALLIANCE_SHARED_VISION
set ALLIANCE_TYPE[6] = ALLIANCE_SHARED_CONTROL
set ALLIANCE_TYPE[8] = ALLIANCE_RESCUABLE
set ALLIANCE_TYPE[9] = ALLIANCE_SHARED_VISION_FORCED
set VERSION[0] = VERSION_REIGN_OF_CHAOS
set VERSION[1] = VERSION_FROZEN_THRONE
set ATTACK_TYPE[0] = ATTACK_TYPE_NORMAL
set ATTACK_TYPE[1] = ATTACK_TYPE_MELEE
set ATTACK_TYPE[2] = ATTACK_TYPE_PIERCE
set ATTACK_TYPE[3] = ATTACK_TYPE_SIEGE
set ATTACK_TYPE[4] = ATTACK_TYPE_MAGIC
set ATTACK_TYPE[5] = ATTACK_TYPE_CHAOS
set ATTACK_TYPE[6] = ATTACK_TYPE_HERO
set DAMAGE_TYPE[0] = DAMAGE_TYPE_UNKNOWN
set DAMAGE_TYPE[4] = DAMAGE_TYPE_NORMAL
set DAMAGE_TYPE[5] = DAMAGE_TYPE_ENHANCED
set DAMAGE_TYPE[8] = DAMAGE_TYPE_FIRE
set DAMAGE_TYPE[9] = DAMAGE_TYPE_COLD
set DAMAGE_TYPE[10] = DAMAGE_TYPE_LIGHTNING
set DAMAGE_TYPE[11] = DAMAGE_TYPE_POISON
set DAMAGE_TYPE[12] = DAMAGE_TYPE_DISEASE
set DAMAGE_TYPE[13] = DAMAGE_TYPE_DIVINE
set DAMAGE_TYPE[14] = DAMAGE_TYPE_MAGIC
set DAMAGE_TYPE[15] = DAMAGE_TYPE_SONIC
set DAMAGE_TYPE[16] = DAMAGE_TYPE_ACID
set DAMAGE_TYPE[17] = DAMAGE_TYPE_FORCE
set DAMAGE_TYPE[18] = DAMAGE_TYPE_DEATH
set DAMAGE_TYPE[19] = DAMAGE_TYPE_MIND
set DAMAGE_TYPE[20] = DAMAGE_TYPE_PLANT
set DAMAGE_TYPE[21] = DAMAGE_TYPE_DEFENSIVE
set DAMAGE_TYPE[22] = DAMAGE_TYPE_DEMOLITION
set DAMAGE_TYPE[23] = DAMAGE_TYPE_SLOW_POISON
set DAMAGE_TYPE[24] = DAMAGE_TYPE_SPIRIT_LINK
set DAMAGE_TYPE[25] = DAMAGE_TYPE_SHADOW_STRIKE
set DAMAGE_TYPE[26] = DAMAGE_TYPE_UNIVERSAL
set WEAPON_TYPE[0] = WEAPON_TYPE_WHOKNOWS
set WEAPON_TYPE[1] = WEAPON_TYPE_METAL_LIGHT_CHOP
set WEAPON_TYPE[2] = WEAPON_TYPE_METAL_MEDIUM_CHOP
set WEAPON_TYPE[3] = WEAPON_TYPE_METAL_HEAVY_CHOP
set WEAPON_TYPE[4] = WEAPON_TYPE_METAL_LIGHT_SLICE
set WEAPON_TYPE[5] = WEAPON_TYPE_METAL_MEDIUM_SLICE
set WEAPON_TYPE[6] = WEAPON_TYPE_METAL_HEAVY_SLICE
set WEAPON_TYPE[7] = WEAPON_TYPE_METAL_MEDIUM_BASH
set WEAPON_TYPE[8] = WEAPON_TYPE_METAL_HEAVY_BASH
set WEAPON_TYPE[9] = WEAPON_TYPE_METAL_MEDIUM_STAB
set WEAPON_TYPE[10] = WEAPON_TYPE_METAL_HEAVY_STAB
set WEAPON_TYPE[11] = WEAPON_TYPE_WOOD_LIGHT_SLICE
set WEAPON_TYPE[12] = WEAPON_TYPE_WOOD_MEDIUM_SLICE
set WEAPON_TYPE[13] = WEAPON_TYPE_WOOD_HEAVY_SLICE
set WEAPON_TYPE[14] = WEAPON_TYPE_WOOD_LIGHT_BASH
set WEAPON_TYPE[15] = WEAPON_TYPE_WOOD_MEDIUM_BASH
set WEAPON_TYPE[16] = WEAPON_TYPE_WOOD_HEAVY_BASH
set WEAPON_TYPE[17] = WEAPON_TYPE_WOOD_LIGHT_STAB
set WEAPON_TYPE[18] = WEAPON_TYPE_WOOD_MEDIUM_STAB
set WEAPON_TYPE[19] = WEAPON_TYPE_CLAW_LIGHT_SLICE
set WEAPON_TYPE[20] = WEAPON_TYPE_CLAW_MEDIUM_SLICE
set WEAPON_TYPE[21] = WEAPON_TYPE_CLAW_HEAVY_SLICE
set WEAPON_TYPE[22] = WEAPON_TYPE_AXE_MEDIUM_CHOP
set WEAPON_TYPE[23] = WEAPON_TYPE_ROCK_HEAVY_BASH
set PATHING_TYPE[0] = PATHING_TYPE_ANY
set PATHING_TYPE[1] = PATHING_TYPE_WALKABILITY
set PATHING_TYPE[2] = PATHING_TYPE_FLYABILITY
set PATHING_TYPE[3] = PATHING_TYPE_BUILDABILITY
set PATHING_TYPE[4] = PATHING_TYPE_PEONHARVESTPATHING
set PATHING_TYPE[5] = PATHING_TYPE_BLIGHTPATHING
set PATHING_TYPE[6] = PATHING_TYPE_FLOATABILITY
set PATHING_TYPE[7] = PATHING_TYPE_AMPHIBIOUSPATHING
set RACE_PREFERENCE[1] = RACE_PREF_HUMAN
set RACE_PREFERENCE[2] = RACE_PREF_ORC
set RACE_PREFERENCE[4] = RACE_PREF_NIGHTELF
set RACE_PREFERENCE[8] = RACE_PREF_UNDEAD
set RACE_PREFERENCE[16] = RACE_PREF_DEMON
set RACE_PREFERENCE[32] = RACE_PREF_RANDOM
set RACE_PREFERENCE[64] = RACE_PREF_USER_SELECTABLE
set MAP_CONTROL[0] = MAP_CONTROL_USER
set MAP_CONTROL[1] = MAP_CONTROL_COMPUTER
set MAP_CONTROL[2] = MAP_CONTROL_RESCUABLE
set MAP_CONTROL[3] = MAP_CONTROL_NEUTRAL
set MAP_CONTROL[4] = MAP_CONTROL_CREEP
set MAP_CONTROL[5] = MAP_CONTROL_NONE
set GAME_TYPE[1] = GAME_TYPE_MELEE
set GAME_TYPE[2] = GAME_TYPE_FFA
set GAME_TYPE[4] = GAME_TYPE_USE_MAP_SETTINGS
set GAME_TYPE[8] = GAME_TYPE_BLIZ
set GAME_TYPE[16] = GAME_TYPE_ONE_ON_ONE
set GAME_TYPE[32] = GAME_TYPE_TWO_TEAM_PLAY
set GAME_TYPE[64] = GAME_TYPE_THREE_TEAM_PLAY
set GAME_TYPE[128] = GAME_TYPE_FOUR_TEAM_PLAY
set MAP_FLAG[1] = MAP_FOG_HIDE_TERRAIN
set MAP_FLAG[2] = MAP_FOG_MAP_EXPLORED
set MAP_FLAG[4] = MAP_FOG_ALWAYS_VISIBLE
set MAP_FLAG[8] = MAP_USE_HANDICAPS
set MAP_FLAG[16] = MAP_OBSERVERS
set MAP_FLAG[32] = MAP_OBSERVERS_ON_DEATH
set MAP_FLAG[128] = MAP_FIXED_COLORS
set MAP_FLAG[256] = MAP_LOCK_RESOURCE_TRADING
set MAP_FLAG[512] = MAP_RESOURCE_TRADING_ALLIES_ONLY
set MAP_FLAG[1024] = MAP_LOCK_ALLIANCE_CHANGES
set MAP_FLAG[2048] = MAP_ALLIANCE_CHANGES_HIDDEN
set MAP_FLAG[4096] = MAP_CHEATS
set MAP_FLAG[8192] = MAP_CHEATS_HIDDEN
set MAP_FLAG[16384] = MAP_LOCK_SPEED
set MAP_FLAG[32768] = MAP_LOCK_RANDOM_SEED
set MAP_FLAG[65536] = MAP_SHARED_ADVANCED_CONTROL
set MAP_FLAG[131072] = MAP_RANDOM_HERO
set MAP_FLAG[262144] = MAP_RANDOM_RACES
set MAP_FLAG[524288] = MAP_RELOADED
set PLACEMENT[0] = MAP_PLACEMENT_RANDOM
set PLACEMENT[1] = MAP_PLACEMENT_FIXED
set PLACEMENT[2] = MAP_PLACEMENT_USE_MAP_SETTINGS
set PLACEMENT[3] = MAP_PLACEMENT_TEAMS_TOGETHER
set START_LOC_PRIO[0] = MAP_LOC_PRIO_LOW
set START_LOC_PRIO[1] = MAP_LOC_PRIO_HIGH
set START_LOC_PRIO[2] = MAP_LOC_PRIO_NOT
set MAP_DENSITY[0] = MAP_DENSITY_NONE
set MAP_DENSITY[1] = MAP_DENSITY_LIGHT
set MAP_DENSITY[2] = MAP_DENSITY_MEDIUM
set MAP_DENSITY[3] = MAP_DENSITY_HEAVY
set GAME_DIFFICULTY[0] = MAP_DIFFICULTY_EASY
set GAME_DIFFICULTY[1] = MAP_DIFFICULTY_NORMAL
set GAME_DIFFICULTY[2] = MAP_DIFFICULTY_HARD
set GAME_DIFFICULTY[3] = MAP_DIFFICULTY_INSANE
set GAME_SPEED[0] = MAP_SPEED_SLOWEST
set GAME_SPEED[1] = MAP_SPEED_SLOW
set GAME_SPEED[2] = MAP_SPEED_NORMAL
set GAME_SPEED[3] = MAP_SPEED_FAST
set GAME_SPEED[4] = MAP_SPEED_FASTEST
set PLAYER_SLOT_STATE[0] = PLAYER_SLOT_STATE_EMPTY
set PLAYER_SLOT_STATE[1] = PLAYER_SLOT_STATE_PLAYING
set PLAYER_SLOT_STATE[2] = PLAYER_SLOT_STATE_LEFT
set VOLUME_GROUP[0] = SOUND_VOLUMEGROUP_UNITMOVEMENT
set VOLUME_GROUP[1] = SOUND_VOLUMEGROUP_UNITSOUNDS
set VOLUME_GROUP[2] = SOUND_VOLUMEGROUP_COMBAT
set VOLUME_GROUP[3] = SOUND_VOLUMEGROUP_SPELLS
set VOLUME_GROUP[4] = SOUND_VOLUMEGROUP_UI
set VOLUME_GROUP[5] = SOUND_VOLUMEGROUP_MUSIC
set VOLUME_GROUP[6] = SOUND_VOLUMEGROUP_AMBIENTSOUNDS
set VOLUME_GROUP[7] = SOUND_VOLUMEGROUP_FIRE
set I_GAME_STATE[0] = GAME_STATE_DIVINE_INTERVENTION
set I_GAME_STATE[1] = GAME_STATE_DISCONNECTED
set F_GAME_STATE[2] = GAME_STATE_TIME_OF_DAY
set PLAYER_STATE[0] = PLAYER_STATE_GAME_RESULT
set PLAYER_STATE[1] = PLAYER_STATE_RESOURCE_GOLD
set PLAYER_STATE[2] = PLAYER_STATE_RESOURCE_LUMBER
set PLAYER_STATE[3] = PLAYER_STATE_RESOURCE_HERO_TOKENS
set PLAYER_STATE[4] = PLAYER_STATE_RESOURCE_FOOD_CAP
set PLAYER_STATE[5] = PLAYER_STATE_RESOURCE_FOOD_USED
set PLAYER_STATE[6] = PLAYER_STATE_FOOD_CAP_CEILING
set PLAYER_STATE[7] = PLAYER_STATE_GIVES_BOUNTY
set PLAYER_STATE[8] = PLAYER_STATE_ALLIED_VICTORY
set PLAYER_STATE[9] = PLAYER_STATE_PLACED
set PLAYER_STATE[10] = PLAYER_STATE_OBSERVER_ON_DEATH
set PLAYER_STATE[11] = PLAYER_STATE_OBSERVER
set PLAYER_STATE[12] = PLAYER_STATE_UNFOLLOWABLE
set PLAYER_STATE[13] = PLAYER_STATE_GOLD_UPKEEP_RATE
set PLAYER_STATE[14] = PLAYER_STATE_LUMBER_UPKEEP_RATE
set PLAYER_STATE[15] = PLAYER_STATE_GOLD_GATHERED
set PLAYER_STATE[16] = PLAYER_STATE_LUMBER_GATHERED
set PLAYER_STATE[25] = PLAYER_STATE_NO_CREEP_SLEEP
set UNIT_STATE[0] = UNIT_STATE_LIFE
set UNIT_STATE[1] = UNIT_STATE_MAX_LIFE
set UNIT_STATE[2] = UNIT_STATE_MANA
set UNIT_STATE[3] = UNIT_STATE_MAX_MANA
set AI_DIFFICULTY[0] = AI_DIFFICULTY_NEWBIE
set AI_DIFFICULTY[1] = AI_DIFFICULTY_NORMAL
set AI_DIFFICULTY[2] = AI_DIFFICULTY_INSANE
set PLAYER_SCORE[0] = PLAYER_SCORE_UNITS_TRAINED
set PLAYER_SCORE[1] = PLAYER_SCORE_UNITS_KILLED
set PLAYER_SCORE[2] = PLAYER_SCORE_STRUCT_BUILT
set PLAYER_SCORE[3] = PLAYER_SCORE_STRUCT_RAZED
set PLAYER_SCORE[4] = PLAYER_SCORE_TECH_PERCENT
set PLAYER_SCORE[5] = PLAYER_SCORE_FOOD_MAXPROD
set PLAYER_SCORE[6] = PLAYER_SCORE_FOOD_MAXUSED
set PLAYER_SCORE[7] = PLAYER_SCORE_HEROES_KILLED
set PLAYER_SCORE[8] = PLAYER_SCORE_ITEMS_GAINED
set PLAYER_SCORE[9] = PLAYER_SCORE_MERCS_HIRED
set PLAYER_SCORE[10] = PLAYER_SCORE_GOLD_MINED_TOTAL
set PLAYER_SCORE[11] = PLAYER_SCORE_GOLD_MINED_UPKEEP
set PLAYER_SCORE[12] = PLAYER_SCORE_GOLD_LOST_UPKEEP
set PLAYER_SCORE[13] = PLAYER_SCORE_GOLD_LOST_TAX
set PLAYER_SCORE[14] = PLAYER_SCORE_GOLD_GIVEN
set PLAYER_SCORE[15] = PLAYER_SCORE_GOLD_RECEIVED
set PLAYER_SCORE[16] = PLAYER_SCORE_LUMBER_TOTAL
set PLAYER_SCORE[17] = PLAYER_SCORE_LUMBER_LOST_UPKEEP
set PLAYER_SCORE[18] = PLAYER_SCORE_LUMBER_LOST_TAX
set PLAYER_SCORE[19] = PLAYER_SCORE_LUMBER_GIVEN
set PLAYER_SCORE[20] = PLAYER_SCORE_LUMBER_RECEIVED
set PLAYER_SCORE[21] = PLAYER_SCORE_UNIT_TOTAL
set PLAYER_SCORE[22] = PLAYER_SCORE_HERO_TOTAL
set PLAYER_SCORE[23] = PLAYER_SCORE_RESOURCE_TOTAL
set PLAYER_SCORE[24] = PLAYER_SCORE_TOTAL
set GAME_EVENT[0] = EVENT_GAME_VICTORY
set GAME_EVENT[1] = EVENT_GAME_END_LEVEL
set GAME_EVENT[2] = EVENT_GAME_VARIABLE_LIMIT
set GAME_EVENT[3] = EVENT_GAME_STATE_LIMIT
set GAME_EVENT[4] = EVENT_GAME_TIMER_EXPIRED
set GAME_EVENT[5] = EVENT_GAME_ENTER_REGION
set GAME_EVENT[6] = EVENT_GAME_LEAVE_REGION
set GAME_EVENT[7] = EVENT_GAME_TRACKABLE_HIT
set GAME_EVENT[8] = EVENT_GAME_TRACKABLE_TRACK
set GAME_EVENT[9] = EVENT_GAME_SHOW_SKILL
set GAME_EVENT[10] = EVENT_GAME_BUILD_SUBMENU
set PLAYER_EVENT[11] = EVENT_PLAYER_STATE_LIMIT
set PLAYER_EVENT[12] = EVENT_PLAYER_ALLIANCE_CHANGED
set PLAYER_EVENT[13] = EVENT_PLAYER_DEFEAT
set PLAYER_EVENT[14] = EVENT_PLAYER_VICTORY
set PLAYER_EVENT[15] = EVENT_PLAYER_LEAVE
set PLAYER_EVENT[16] = EVENT_PLAYER_CHAT
set PLAYER_EVENT[17] = EVENT_PLAYER_END_CINEMATIC
set PLAYER_UNIT_EVENT[18] = EVENT_PLAYER_UNIT_ATTACKED
set PLAYER_UNIT_EVENT[19] = EVENT_PLAYER_UNIT_RESCUED
set PLAYER_UNIT_EVENT[20] = EVENT_PLAYER_UNIT_DEATH
set PLAYER_UNIT_EVENT[21] = EVENT_PLAYER_UNIT_DECAY
set PLAYER_UNIT_EVENT[22] = EVENT_PLAYER_UNIT_DETECTED
set PLAYER_UNIT_EVENT[23] = EVENT_PLAYER_UNIT_HIDDEN
set PLAYER_UNIT_EVENT[24] = EVENT_PLAYER_UNIT_SELECTED
set PLAYER_UNIT_EVENT[25] = EVENT_PLAYER_UNIT_DESELECTED
set PLAYER_UNIT_EVENT[26] = EVENT_PLAYER_UNIT_CONSTRUCT_START
set PLAYER_UNIT_EVENT[27] = EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL
set PLAYER_UNIT_EVENT[28] = EVENT_PLAYER_UNIT_CONSTRUCT_FINISH
set PLAYER_UNIT_EVENT[29] = EVENT_PLAYER_UNIT_UPGRADE_START
set PLAYER_UNIT_EVENT[30] = EVENT_PLAYER_UNIT_UPGRADE_CANCEL
set PLAYER_UNIT_EVENT[31] = EVENT_PLAYER_UNIT_UPGRADE_FINISH
set PLAYER_UNIT_EVENT[32] = EVENT_PLAYER_UNIT_TRAIN_START
set PLAYER_UNIT_EVENT[33] = EVENT_PLAYER_UNIT_TRAIN_CANCEL
set PLAYER_UNIT_EVENT[34] = EVENT_PLAYER_UNIT_TRAIN_FINISH
set PLAYER_UNIT_EVENT[35] = EVENT_PLAYER_UNIT_RESEARCH_START
set PLAYER_UNIT_EVENT[36] = EVENT_PLAYER_UNIT_RESEARCH_CANCEL
set PLAYER_UNIT_EVENT[37] = EVENT_PLAYER_UNIT_RESEARCH_FINISH
set PLAYER_UNIT_EVENT[38] = EVENT_PLAYER_UNIT_ISSUED_ORDER
set PLAYER_UNIT_EVENT[39] = EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER
set PLAYER_UNIT_EVENT[40] = EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER
set PLAYER_UNIT_EVENT[40] = EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER
set PLAYER_UNIT_EVENT[41] = EVENT_PLAYER_HERO_LEVEL
set PLAYER_UNIT_EVENT[42] = EVENT_PLAYER_HERO_SKILL
set PLAYER_UNIT_EVENT[43] = EVENT_PLAYER_HERO_REVIVABLE
set PLAYER_UNIT_EVENT[44] = EVENT_PLAYER_HERO_REVIVE_START
set PLAYER_UNIT_EVENT[45] = EVENT_PLAYER_HERO_REVIVE_CANCEL
set PLAYER_UNIT_EVENT[46] = EVENT_PLAYER_HERO_REVIVE_FINISH
set PLAYER_UNIT_EVENT[47] = EVENT_PLAYER_UNIT_SUMMON
set PLAYER_UNIT_EVENT[48] = EVENT_PLAYER_UNIT_DROP_ITEM
set PLAYER_UNIT_EVENT[49] = EVENT_PLAYER_UNIT_PICKUP_ITEM
set PLAYER_UNIT_EVENT[50] = EVENT_PLAYER_UNIT_USE_ITEM
set PLAYER_UNIT_EVENT[51] = EVENT_PLAYER_UNIT_LOADED
set UNIT_EVENT[52] = EVENT_UNIT_DAMAGED
set UNIT_EVENT[53] = EVENT_UNIT_DEATH
set UNIT_EVENT[54] = EVENT_UNIT_DECAY
set UNIT_EVENT[55] = EVENT_UNIT_DETECTED
set UNIT_EVENT[56] = EVENT_UNIT_HIDDEN
set UNIT_EVENT[57] = EVENT_UNIT_SELECTED
set UNIT_EVENT[58] = EVENT_UNIT_DESELECTED
set UNIT_EVENT[59] = EVENT_UNIT_STATE_LIMIT
set UNIT_EVENT[60] = EVENT_UNIT_ACQUIRED_TARGET
set UNIT_EVENT[61] = EVENT_UNIT_TARGET_IN_RANGE
set UNIT_EVENT[62] = EVENT_UNIT_ATTACKED
set UNIT_EVENT[63] = EVENT_UNIT_RESCUED
set UNIT_EVENT[64] = EVENT_UNIT_CONSTRUCT_CANCEL
set UNIT_EVENT[65] = EVENT_UNIT_CONSTRUCT_FINISH
set UNIT_EVENT[66] = EVENT_UNIT_UPGRADE_START
set UNIT_EVENT[67] = EVENT_UNIT_UPGRADE_CANCEL
set UNIT_EVENT[68] = EVENT_UNIT_UPGRADE_FINISH
set UNIT_EVENT[69] = EVENT_UNIT_TRAIN_START
set UNIT_EVENT[70] = EVENT_UNIT_TRAIN_CANCEL
set UNIT_EVENT[71] = EVENT_UNIT_TRAIN_FINISH
set UNIT_EVENT[72] = EVENT_UNIT_RESEARCH_START
set UNIT_EVENT[73] = EVENT_UNIT_RESEARCH_CANCEL
set UNIT_EVENT[74] = EVENT_UNIT_RESEARCH_FINISH
set UNIT_EVENT[75] = EVENT_UNIT_ISSUED_ORDER
set UNIT_EVENT[76] = EVENT_UNIT_ISSUED_POINT_ORDER
set UNIT_EVENT[77] = EVENT_UNIT_ISSUED_TARGET_ORDER
set UNIT_EVENT[78] = EVENT_UNIT_HERO_LEVEL
set UNIT_EVENT[79] = EVENT_UNIT_HERO_SKILL
set UNIT_EVENT[80] = EVENT_UNIT_HERO_REVIVABLE
set UNIT_EVENT[81] = EVENT_UNIT_HERO_REVIVE_START
set UNIT_EVENT[82] = EVENT_UNIT_HERO_REVIVE_CANCEL
set UNIT_EVENT[83] = EVENT_UNIT_HERO_REVIVE_FINISH
set UNIT_EVENT[84] = EVENT_UNIT_SUMMON
set UNIT_EVENT[85] = EVENT_UNIT_DROP_ITEM
set UNIT_EVENT[86] = EVENT_UNIT_PICKUP_ITEM
set UNIT_EVENT[87] = EVENT_UNIT_USE_ITEM
set UNIT_EVENT[88] = EVENT_UNIT_LOADED
set WIDGET_EVENT[89] = EVENT_WIDGET_DEATH
set DIALOG_EVENT[90] = EVENT_DIALOG_BUTTON_CLICK
set DIALOG_EVENT[91] = EVENT_DIALOG_CLICK
set GAME_EVENT[256] = EVENT_GAME_LOADED
set GAME_EVENT[257] = EVENT_GAME_TOURNAMENT_FINISH_SOON
set GAME_EVENT[258] = EVENT_GAME_TOURNAMENT_FINISH_NOW
set GAME_EVENT[259] = EVENT_GAME_SAVE
set PLAYER_EVENT[261] = EVENT_PLAYER_ARROW_LEFT_DOWN
set PLAYER_EVENT[262] = EVENT_PLAYER_ARROW_LEFT_UP
set PLAYER_EVENT[263] = EVENT_PLAYER_ARROW_RIGHT_DOWN
set PLAYER_EVENT[264] = EVENT_PLAYER_ARROW_RIGHT_UP
set PLAYER_EVENT[265] = EVENT_PLAYER_ARROW_DOWN_DOWN
set PLAYER_EVENT[266] = EVENT_PLAYER_ARROW_DOWN_UP
set PLAYER_EVENT[267] = EVENT_PLAYER_ARROW_UP_DOWN
set PLAYER_EVENT[268] = EVENT_PLAYER_ARROW_UP_UP
set PLAYER_UNIT_EVENT[269] = EVENT_PLAYER_UNIT_SELL
set PLAYER_UNIT_EVENT[270] = EVENT_PLAYER_UNIT_CHANGE_OWNER
set PLAYER_UNIT_EVENT[271] = EVENT_PLAYER_UNIT_SELL_ITEM
set PLAYER_UNIT_EVENT[272] = EVENT_PLAYER_UNIT_SPELL_CHANNEL
set PLAYER_UNIT_EVENT[273] = EVENT_PLAYER_UNIT_SPELL_CAST
set PLAYER_UNIT_EVENT[274] = EVENT_PLAYER_UNIT_SPELL_EFFECT
set PLAYER_UNIT_EVENT[275] = EVENT_PLAYER_UNIT_SPELL_FINISH
set PLAYER_UNIT_EVENT[276] = EVENT_PLAYER_UNIT_SPELL_ENDCAST
set PLAYER_UNIT_EVENT[277] = EVENT_PLAYER_UNIT_PAWN_ITEM
set UNIT_EVENT[286] = EVENT_UNIT_SELL
set UNIT_EVENT[287] = EVENT_UNIT_CHANGE_OWNER
set UNIT_EVENT[288] = EVENT_UNIT_SELL_ITEM
set UNIT_EVENT[289] = EVENT_UNIT_SPELL_CHANNEL
set UNIT_EVENT[290] = EVENT_UNIT_SPELL_CAST
set UNIT_EVENT[291] = EVENT_UNIT_SPELL_EFFECT
set UNIT_EVENT[292] = EVENT_UNIT_SPELL_FINISH
set UNIT_EVENT[293] = EVENT_UNIT_SPELL_ENDCAST
set UNIT_EVENT[294] = EVENT_UNIT_PAWN_ITEM
set LIMIT_OP[0] = LESS_THAN
set LIMIT_OP[1] = LESS_THAN_OR_EQUAL
set LIMIT_OP[2] = EQUAL
set LIMIT_OP[3] = GREATER_THAN_OR_EQUAL
set LIMIT_OP[4] = GREATER_THAN
set LIMIT_OP[5] = NOT_EQUAL
set UNIT_TYPE[0] = UNIT_TYPE_HERO
set UNIT_TYPE[1] = UNIT_TYPE_DEAD
set UNIT_TYPE[2] = UNIT_TYPE_STRUCTURE
set UNIT_TYPE[3] = UNIT_TYPE_FLYING
set UNIT_TYPE[4] = UNIT_TYPE_GROUND
set UNIT_TYPE[5] = UNIT_TYPE_ATTACKS_FLYING
set UNIT_TYPE[6] = UNIT_TYPE_ATTACKS_GROUND
set UNIT_TYPE[7] = UNIT_TYPE_MELEE_ATTACKER
set UNIT_TYPE[8] = UNIT_TYPE_RANGED_ATTACKER
set UNIT_TYPE[9] = UNIT_TYPE_GIANT
set UNIT_TYPE[10] = UNIT_TYPE_SUMMONED
set UNIT_TYPE[11] = UNIT_TYPE_STUNNED
set UNIT_TYPE[12] = UNIT_TYPE_PLAGUED
set UNIT_TYPE[13] = UNIT_TYPE_SNARED
set UNIT_TYPE[14] = UNIT_TYPE_UNDEAD
set UNIT_TYPE[15] = UNIT_TYPE_MECHANICAL
set UNIT_TYPE[16] = UNIT_TYPE_PEON
set UNIT_TYPE[17] = UNIT_TYPE_SAPPER
set UNIT_TYPE[18] = UNIT_TYPE_TOWNHALL
set UNIT_TYPE[19] = UNIT_TYPE_ANCIENT
set UNIT_TYPE[20] = UNIT_TYPE_TAUREN
set UNIT_TYPE[21] = UNIT_TYPE_POISONED
set UNIT_TYPE[22] = UNIT_TYPE_POLYMORPHED
set UNIT_TYPE[23] = UNIT_TYPE_SLEEPING
set UNIT_TYPE[24] = UNIT_TYPE_RESISTANT
set UNIT_TYPE[25] = UNIT_TYPE_ETHEREAL
set UNIT_TYPE[26] = UNIT_TYPE_MAGIC_IMMUNE
set ITEM_TYPE[0] = ITEM_TYPE_PERMANENT
set ITEM_TYPE[1] = ITEM_TYPE_CHARGED
set ITEM_TYPE[2] = ITEM_TYPE_POWERUP
set ITEM_TYPE[3] = ITEM_TYPE_ARTIFACT
set ITEM_TYPE[4] = ITEM_TYPE_PURCHASABLE
set ITEM_TYPE[5] = ITEM_TYPE_CAMPAIGN
set ITEM_TYPE[6] = ITEM_TYPE_MISCELLANEOUS
set ITEM_TYPE[7] = ITEM_TYPE_UNKNOWN
set ITEM_TYPE[8] = ITEM_TYPE_ANY
set ITEM_TYPE[2] = ITEM_TYPE_TOME
set CAMERA_FIELD[0] = CAMERA_FIELD_TARGET_DISTANCE
set CAMERA_FIELD[1] = CAMERA_FIELD_FARZ
set CAMERA_FIELD[2] = CAMERA_FIELD_ANGLE_OF_ATTACK
set CAMERA_FIELD[3] = CAMERA_FIELD_FIELD_OF_VIEW
set CAMERA_FIELD[4] = CAMERA_FIELD_ROLL
set CAMERA_FIELD[5] = CAMERA_FIELD_ROTATION
set CAMERA_FIELD[6] = CAMERA_FIELD_ZOFFSET
set BLEND_MODE[0] = BLEND_MODE_NONE
set BLEND_MODE[0] = BLEND_MODE_DONT_CARE
set BLEND_MODE[1] = BLEND_MODE_KEYALPHA
set BLEND_MODE[2] = BLEND_MODE_BLEND
set BLEND_MODE[3] = BLEND_MODE_ADDITIVE
set BLEND_MODE[4] = BLEND_MODE_MODULATE
set BLEND_MODE[5] = BLEND_MODE_MODULATE_2X
set RARITY_CONTROL[0] = RARITY_FREQUENT
set RARITY_CONTROL[1] = RARITY_RARE
set TEX_MAP_FLAGS[0] = TEXMAP_FLAG_NONE
set TEX_MAP_FLAGS[1] = TEXMAP_FLAG_WRAP_U
set TEX_MAP_FLAGS[2] = TEXMAP_FLAG_WRAP_V
set TEX_MAP_FLAGS[3] = TEXMAP_FLAG_WRAP_UV
set FOG_STATE[1] = FOG_OF_WAR_MASKED
set FOG_STATE[2] = FOG_OF_WAR_FOGGED
set FOG_STATE[4] = FOG_OF_WAR_VISIBLE
set EFFECT_TYPE[0] = EFFECT_TYPE_EFFECT
set EFFECT_TYPE[1] = EFFECT_TYPE_TARGET
set EFFECT_TYPE[2] = EFFECT_TYPE_CASTER
set EFFECT_TYPE[3] = EFFECT_TYPE_SPECIAL
set EFFECT_TYPE[4] = EFFECT_TYPE_AREA_EFFECT
set EFFECT_TYPE[5] = EFFECT_TYPE_MISSILE
set EFFECT_TYPE[6] = EFFECT_TYPE_LIGHTNING
set SOUND_TYPE[0] = SOUND_TYPE_EFFECT
set SOUND_TYPE[1] = SOUND_TYPE_EFFECT_LOOPED
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Convertion functions:
//
library ConvertionFunctions
//All "Convert<T>()" function in reverse mode according to the results of Common.j.
//With exception of MapSettingToInteger() and MapVisibilityToInteger().
function AIDifficultyToInteger takes aidifficulty ad returns integer
if ad == AI_DIFFICULTY_NEWBIE then
return 0
elseif ad == AI_DIFFICULTY_NORMAL then
return 1
elseif ad == AI_DIFFICULTY_INSANE then
return 2
endif//default
return 0
endfunction
function AllianceTypeToInteger takes alliancetype at returns integer
if at == ALLIANCE_PASSIVE then
return 0
elseif at == ALLIANCE_HELP_REQUEST then
return 1
elseif at == ALLIANCE_HELP_RESPONSE then
return 2
elseif at == ALLIANCE_SHARED_XP then
return 3
elseif at == ALLIANCE_SHARED_SPELLS then
return 4
elseif at == ALLIANCE_SHARED_VISION then
return 5
elseif at == ALLIANCE_SHARED_CONTROL then
return 6
elseif at == ALLIANCE_SHARED_ADVANCED_CONTROL then
return 7
elseif at == ALLIANCE_RESCUABLE then
return 8
elseif at == ALLIANCE_SHARED_VISION_FORCED then
return 9
endif//default
return 0
endfunction
function AttackTypeToInteger takes attacktype at returns integer
if at == ATTACK_TYPE_NORMAL then
return 0
elseif at == ATTACK_TYPE_MELEE then
return 1
elseif at == ATTACK_TYPE_PIERCE then
return 2
elseif at == ATTACK_TYPE_SIEGE then
return 3
elseif at == ATTACK_TYPE_MAGIC then
return 4
elseif at == ATTACK_TYPE_CHAOS then
return 5
elseif at == ATTACK_TYPE_HERO then
return 6
endif//default
return 0
endfunction
function BlendModeToInteger takes blendmode bm returns integer
if bm == BLEND_MODE_NONE then
return 0
elseif bm == BLEND_MODE_DONT_CARE then
return 0
elseif bm == BLEND_MODE_KEYALPHA then
return 1
elseif bm == BLEND_MODE_BLEND then
return 2
elseif bm == BLEND_MODE_ADDITIVE then
return 3
elseif bm == BLEND_MODE_MODULATE then
return 4
elseif bm == BLEND_MODE_MODULATE_2X then
return 5
endif//default
return 0
endfunction
function CameraFieldToInteger takes camerafield cf returns integer
if cf == CAMERA_FIELD_TARGET_DISTANCE then
return 0
elseif cf == CAMERA_FIELD_FARZ then
return 1
elseif cf == CAMERA_FIELD_ANGLE_OF_ATTACK then
return 2
elseif cf == CAMERA_FIELD_FIELD_OF_VIEW then
return 3
elseif cf == CAMERA_FIELD_ROLL then
return 4
elseif cf == CAMERA_FIELD_ROTATION then
return 5
elseif cf == CAMERA_FIELD_ZOFFSET then
return 6
endif//default
return 0
endfunction
function DamageTypeToInteger takes damagetype dt returns integer
if dt == DAMAGE_TYPE_UNKNOWN then
return 0
elseif dt == DAMAGE_TYPE_NORMAL then
return 4
elseif dt == DAMAGE_TYPE_ENHANCED then
return 5
elseif dt == DAMAGE_TYPE_FIRE then
return 8
elseif dt == DAMAGE_TYPE_COLD then
return 9
elseif dt == DAMAGE_TYPE_LIGHTNING then
return 10
elseif dt == DAMAGE_TYPE_POISON then
return 11
elseif dt == DAMAGE_TYPE_DISEASE then
return 12
elseif dt == DAMAGE_TYPE_DIVINE then
return 13
elseif dt == DAMAGE_TYPE_MAGIC then
return 14
elseif dt == DAMAGE_TYPE_SONIC then
return 15
elseif dt == DAMAGE_TYPE_ACID then
return 16
elseif dt == DAMAGE_TYPE_FORCE then
return 17
elseif dt == DAMAGE_TYPE_DEATH then
return 18
elseif dt == DAMAGE_TYPE_MIND then
return 19
elseif dt == DAMAGE_TYPE_PLANT then
return 20
elseif dt == DAMAGE_TYPE_DEFENSIVE then
return 21
elseif dt == DAMAGE_TYPE_DEMOLITION then
return 22
elseif dt == DAMAGE_TYPE_SLOW_POISON then
return 23
elseif dt == DAMAGE_TYPE_SPIRIT_LINK then
return 24
elseif dt == DAMAGE_TYPE_SHADOW_STRIKE then
return 25
elseif dt == DAMAGE_TYPE_UNIVERSAL then
return 26
endif//default
return 0
endfunction
function DialogEventToInteger takes dialogevent de returns integer
if de == EVENT_DIALOG_BUTTON_CLICK then
return 90
elseif de == EVENT_DIALOG_CLICK then
return 91
endif//default
return 0
endfunction
function EffectTypeToInteger takes effecttype et returns integer
if et == EFFECT_TYPE_EFFECT then
return 0
elseif et == EFFECT_TYPE_TARGET then
return 1
elseif et == EFFECT_TYPE_CASTER then
return 2
elseif et == EFFECT_TYPE_SPECIAL then
return 3
elseif et == EFFECT_TYPE_AREA_EFFECT then
return 4
elseif et == EFFECT_TYPE_MISSILE then
return 5
elseif et == EFFECT_TYPE_LIGHTNING then
return 6
endif//default
return 0
endfunction
function FGameStateToInteger takes fgamestate fs returns integer
if fs == GAME_STATE_TIME_OF_DAY then
return 2
endif//default
return 0
endfunction
function FogStateToInteger takes fogstate fs returns integer
if fs == FOG_OF_WAR_MASKED then
return 1
elseif fs == FOG_OF_WAR_FOGGED then
return 2
elseif fs == FOG_OF_WAR_VISIBLE then
return 4
endif//default
return 0
endfunction
function GameDifficultyToInteger takes gamedifficulty gd returns integer
if gd == MAP_DIFFICULTY_EASY then
return 0
elseif gd == MAP_DIFFICULTY_NORMAL then
return 1
elseif gd == MAP_DIFFICULTY_HARD then
return 2
elseif gd == MAP_DIFFICULTY_INSANE then
return 3
endif//default
return 0
endfunction
function GameEventToInteger takes gameevent ge returns integer
if ge == EVENT_GAME_VICTORY then
return 0
elseif ge == EVENT_GAME_END_LEVEL then
return 1
elseif ge == EVENT_GAME_VARIABLE_LIMIT then
return 2
elseif ge == EVENT_GAME_STATE_LIMIT then
return 3
elseif ge == EVENT_GAME_TIMER_EXPIRED then
return 4
elseif ge == EVENT_GAME_ENTER_REGION then
return 5
elseif ge == EVENT_GAME_LEAVE_REGION then
return 6
elseif ge == EVENT_GAME_TRACKABLE_HIT then
return 7
elseif ge == EVENT_GAME_TRACKABLE_TRACK then
return 8
elseif ge == EVENT_GAME_SHOW_SKILL then
return 9
elseif ge == EVENT_GAME_BUILD_SUBMENU then
return 10
elseif ge == EVENT_GAME_LOADED then
return 256
elseif ge == EVENT_GAME_TOURNAMENT_FINISH_SOON then
return 257
elseif ge == EVENT_GAME_TOURNAMENT_FINISH_NOW then
return 258
elseif ge == EVENT_GAME_SAVE then
return 259
endif//default
return 0
endfunction
function GameSpeedToInteger takes gamespeed gs returns integer
if gs == MAP_SPEED_SLOWEST then
return 0
elseif gs == MAP_SPEED_SLOW then
return 1
elseif gs == MAP_SPEED_NORMAL then
return 2
elseif gs == MAP_SPEED_FAST then
return 3
elseif gs == MAP_SPEED_FASTEST then
return 4
endif//default
return 0
endfunction
function GameTypeToInteger takes gametype gt returns integer
if gt == GAME_TYPE_MELEE then
return 1
elseif gt == GAME_TYPE_FFA then
return 2
elseif gt == GAME_TYPE_USE_MAP_SETTINGS then
return 4
elseif gt == GAME_TYPE_BLIZ then
return 8
elseif gt == GAME_TYPE_ONE_ON_ONE then
return 16
elseif gt == GAME_TYPE_TWO_TEAM_PLAY then
return 32
elseif gt == GAME_TYPE_THREE_TEAM_PLAY then
return 64
elseif gt == GAME_TYPE_FOUR_TEAM_PLAY then
return 128
endif//default
return 0
endfunction
function IGameStateToInteger takes igamestate is returns integer
if is == GAME_STATE_DIVINE_INTERVENTION then
return 0
elseif is == GAME_STATE_DISCONNECTED then
return 1
endif//default
return 0
endfunction
function ItemTypeToInteger takes itemtype it returns integer
if it == ITEM_TYPE_PERMANENT then
return 0
elseif it == ITEM_TYPE_CHARGED then
return 1
elseif it == ITEM_TYPE_POWERUP then
return 2
elseif it == ITEM_TYPE_TOME then
return 2
elseif it == ITEM_TYPE_ARTIFACT then
return 3
elseif it == ITEM_TYPE_PURCHASABLE then
return 4
elseif it == ITEM_TYPE_CAMPAIGN then
return 5
elseif it == ITEM_TYPE_MISCELLANEOUS then
return 6
elseif it == ITEM_TYPE_UNKNOWN then
return 7
elseif it == ITEM_TYPE_ANY then
return 8
endif//default
return 0
endfunction
function LimitOpToInteger takes limitop lo returns integer
if lo == LESS_THAN then
return 0
elseif lo == LESS_THAN_OR_EQUAL then
return 1
elseif lo == EQUAL then
return 2
elseif lo == GREATER_THAN_OR_EQUAL then
return 3
elseif lo == GREATER_THAN then
return 4
elseif lo == NOT_EQUAL then
return 5
endif//default
return 0
endfunction
function MapControlToInteger takes mapcontrol mc returns integer
if mc == MAP_CONTROL_USER then
return 0
elseif mc == MAP_CONTROL_COMPUTER then
return 1
elseif mc == MAP_CONTROL_RESCUABLE then
return 2
elseif mc == MAP_CONTROL_NEUTRAL then
return 3
elseif mc == MAP_CONTROL_CREEP then
return 4
elseif mc == MAP_CONTROL_NONE then
return 5
endif//default
return 0
endfunction
function MapDensityToInteger takes mapdensity md returns integer
if md == MAP_DENSITY_NONE then
return 0
elseif md == MAP_DENSITY_LIGHT then
return 1
elseif md == MAP_DENSITY_MEDIUM then
return 2
elseif md == MAP_DENSITY_HEAVY then
return 3
endif//default
return 0
endfunction
function MapFlagToInteger takes mapflag mf returns integer
if mf == MAP_FOG_HIDE_TERRAIN then
return 1
elseif mf == MAP_FOG_MAP_EXPLORED then
return 2
elseif mf == MAP_FOG_ALWAYS_VISIBLE then
return 4
elseif mf == MAP_USE_HANDICAPS then
return 8
elseif mf == MAP_OBSERVERS then
return 16
elseif mf == MAP_OBSERVERS_ON_DEATH then
return 32
elseif mf == MAP_FIXED_COLORS then
return 128
elseif mf == MAP_LOCK_RESOURCE_TRADING then
return 256
elseif mf == MAP_RESOURCE_TRADING_ALLIES_ONLY then
return 512
elseif mf == MAP_LOCK_ALLIANCE_CHANGES then
return 1024
elseif mf == MAP_ALLIANCE_CHANGES_HIDDEN then
return 2048
elseif mf == MAP_CHEATS then
return 4096
elseif mf == MAP_CHEATS_HIDDEN then
return 8192
elseif mf == MAP_LOCK_SPEED then
return 16384
elseif mf == MAP_LOCK_RANDOM_SEED then
return 32768
elseif mf == MAP_SHARED_ADVANCED_CONTROL then
return 65536
elseif mf == MAP_RANDOM_HERO then
return 131072
elseif mf == MAP_RANDOM_RACES then
return 262144
elseif mf == MAP_RELOADED then
return 524288
endif//default
return 0
endfunction
/*unknown
function MapSettingToInteger takes mapsetting ms returns integer
return 0
endfunction*/
/*unknown
function MapVisibilityToInteger takes mapvisibility mv returns integer
return 0
endfunction*/
function PathingTypeToInteger takes pathingtype pt returns integer
if pt == PATHING_TYPE_ANY then
return 0
elseif pt == PATHING_TYPE_WALKABILITY then
return 1
elseif pt == PATHING_TYPE_FLYABILITY then
return 2
elseif pt == PATHING_TYPE_BUILDABILITY then
return 3
elseif pt == PATHING_TYPE_PEONHARVESTPATHING then
return 4
elseif pt == PATHING_TYPE_BLIGHTPATHING then
return 5
elseif pt == PATHING_TYPE_FLOATABILITY then
return 6
elseif pt == PATHING_TYPE_AMPHIBIOUSPATHING then
return 7
endif//default
return 0
endfunction
function PlacementToInteger takes placement pm returns integer
if pm == MAP_PLACEMENT_RANDOM then
return 0
elseif pm == MAP_PLACEMENT_FIXED then
return 1
elseif pm == MAP_PLACEMENT_USE_MAP_SETTINGS then
return 2
elseif pm == MAP_PLACEMENT_TEAMS_TOGETHER then
return 3
endif//default
return 0
endfunction
function PlayerColorToInteger takes playercolor pc returns integer
if pc == PLAYER_COLOR_RED then
return 0
elseif pc == PLAYER_COLOR_BLUE then
return 1
elseif pc == PLAYER_COLOR_CYAN then
return 2
elseif pc == PLAYER_COLOR_PURPLE then
return 3
elseif pc == PLAYER_COLOR_YELLOW then
return 4
elseif pc == PLAYER_COLOR_ORANGE then
return 5
elseif pc == PLAYER_COLOR_GREEN then
return 6
elseif pc == PLAYER_COLOR_PINK then
return 7
elseif pc == PLAYER_COLOR_LIGHT_GRAY then
return 8
elseif pc == PLAYER_COLOR_LIGHT_BLUE then
return 9
elseif pc == PLAYER_COLOR_AQUA then
return 10
elseif pc == PLAYER_COLOR_BROWN then
return 11
endif//default
return 0
endfunction
function PlayerEventToInteger takes playerevent pe returns integer
if pe == EVENT_PLAYER_STATE_LIMIT then
return 11
elseif pe == EVENT_PLAYER_ALLIANCE_CHANGED then
return 12
elseif pe == EVENT_PLAYER_DEFEAT then
return 13
elseif pe == EVENT_PLAYER_VICTORY then
return 14
elseif pe == EVENT_PLAYER_LEAVE then
return 15
elseif pe == EVENT_PLAYER_CHAT then
return 16
elseif pe == EVENT_PLAYER_END_CINEMATIC then
return 17
elseif pe == EVENT_PLAYER_ARROW_LEFT_DOWN then
return 261
elseif pe == EVENT_PLAYER_ARROW_LEFT_UP then
return 262
elseif pe == EVENT_PLAYER_ARROW_RIGHT_DOWN then
return 263
elseif pe == EVENT_PLAYER_ARROW_RIGHT_UP then
return 264
elseif pe == EVENT_PLAYER_ARROW_DOWN_DOWN then
return 265
elseif pe == EVENT_PLAYER_ARROW_DOWN_UP then
return 266
elseif pe == EVENT_PLAYER_ARROW_UP_DOWN then
return 267
elseif pe == EVENT_PLAYER_ARROW_UP_UP then
return 268
endif//default
return 0
endfunction
function PlayerGameResultToInteger takes playergameresult pr returns integer
if pr == PLAYER_GAME_RESULT_VICTORY then
return 0
elseif pr == PLAYER_GAME_RESULT_DEFEAT then
return 1
elseif pr == PLAYER_GAME_RESULT_TIE then
return 2
elseif pr == PLAYER_GAME_RESULT_NEUTRAL then
return 3
endif//default
return 0
endfunction
function PlayerScoreToInteger takes playerscore ps returns integer
if ps == PLAYER_SCORE_UNITS_TRAINED then
return 0
elseif ps == PLAYER_SCORE_UNITS_KILLED then
return 1
elseif ps == PLAYER_SCORE_STRUCT_BUILT then
return 2
elseif ps == PLAYER_SCORE_STRUCT_RAZED then
return 3
elseif ps == PLAYER_SCORE_TECH_PERCENT then
return 4
elseif ps == PLAYER_SCORE_FOOD_MAXPROD then
return 5
elseif ps == PLAYER_SCORE_FOOD_MAXUSED then
return 6
elseif ps == PLAYER_SCORE_HEROES_KILLED then
return 7
elseif ps == PLAYER_SCORE_ITEMS_GAINED then
return 8
elseif ps == PLAYER_SCORE_MERCS_HIRED then
return 9
elseif ps == PLAYER_SCORE_GOLD_MINED_TOTAL then
return 10
elseif ps == PLAYER_SCORE_GOLD_MINED_UPKEEP then
return 11
elseif ps == PLAYER_SCORE_GOLD_LOST_UPKEEP then
return 12
elseif ps == PLAYER_SCORE_GOLD_LOST_TAX then
return 13
elseif ps == PLAYER_SCORE_GOLD_GIVEN then
return 14
elseif ps == PLAYER_SCORE_GOLD_RECEIVED then
return 15
elseif ps == PLAYER_SCORE_LUMBER_TOTAL then
return 16
elseif ps == PLAYER_SCORE_LUMBER_LOST_UPKEEP then
return 17
elseif ps == PLAYER_SCORE_LUMBER_LOST_TAX then
return 18
elseif ps == PLAYER_SCORE_LUMBER_GIVEN then
return 19
elseif ps == PLAYER_SCORE_LUMBER_RECEIVED then
return 20
elseif ps == PLAYER_SCORE_UNIT_TOTAL then
return 21
elseif ps == PLAYER_SCORE_HERO_TOTAL then
return 22
elseif ps == PLAYER_SCORE_RESOURCE_TOTAL then
return 23
elseif ps == PLAYER_SCORE_TOTAL then
return 24
endif//default
return 0
endfunction
function PlayerSlotStateToInteger takes playerslotstate ps returns integer
if ps == PLAYER_SLOT_STATE_EMPTY then
return 0
elseif ps == PLAYER_SLOT_STATE_PLAYING then
return 1
elseif ps == PLAYER_SLOT_STATE_LEFT then
return 2
endif//default
return 0
endfunction
function PlayerStateToInteger takes playerstate ps returns integer
if ps == PLAYER_STATE_GAME_RESULT then
return 0
elseif ps == PLAYER_STATE_RESOURCE_GOLD then
return 1
elseif ps == PLAYER_STATE_RESOURCE_LUMBER then
return 2
elseif ps == PLAYER_STATE_RESOURCE_HERO_TOKENS then
return 3
elseif ps == PLAYER_STATE_RESOURCE_FOOD_CAP then
return 4
elseif ps == PLAYER_STATE_RESOURCE_FOOD_USED then
return 5
elseif ps == PLAYER_STATE_FOOD_CAP_CEILING then
return 6
elseif ps == PLAYER_STATE_GIVES_BOUNTY then
return 7
elseif ps == PLAYER_STATE_ALLIED_VICTORY then
return 8
elseif ps == PLAYER_STATE_PLACED then
return 9
elseif ps == PLAYER_STATE_OBSERVER_ON_DEATH then
return 10
elseif ps == PLAYER_STATE_OBSERVER then
return 11
elseif ps == PLAYER_STATE_UNFOLLOWABLE then
return 12
elseif ps == PLAYER_STATE_GOLD_UPKEEP_RATE then
return 13
elseif ps == PLAYER_STATE_LUMBER_UPKEEP_RATE then
return 14
elseif ps == PLAYER_STATE_GOLD_GATHERED then
return 15
elseif ps == PLAYER_STATE_LUMBER_GATHERED then
return 16
elseif ps == PLAYER_STATE_NO_CREEP_SLEEP then
return 25
endif//default
return 0
endfunction
function PlayerUnitEventToInteger takes playerunitevent pe returns integer
if pe == EVENT_PLAYER_UNIT_ATTACKED then
return 18
elseif pe == EVENT_PLAYER_UNIT_RESCUED then
return 19
elseif pe == EVENT_PLAYER_UNIT_DEATH then
return 20
elseif pe == EVENT_PLAYER_UNIT_DECAY then
return 21
elseif pe == EVENT_PLAYER_UNIT_DETECTED then
return 22
elseif pe == EVENT_PLAYER_UNIT_HIDDEN then
return 23
elseif pe == EVENT_PLAYER_UNIT_SELECTED then
return 24
elseif pe == EVENT_PLAYER_UNIT_DESELECTED then
return 25
elseif pe == EVENT_PLAYER_UNIT_CONSTRUCT_START then
return 26
elseif pe == EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL then
return 27
elseif pe == EVENT_PLAYER_UNIT_CONSTRUCT_FINISH then
return 28
elseif pe == EVENT_PLAYER_UNIT_UPGRADE_START then
return 29
elseif pe == EVENT_PLAYER_UNIT_UPGRADE_CANCEL then
return 30
elseif pe == EVENT_PLAYER_UNIT_UPGRADE_FINISH then
return 31
elseif pe == EVENT_PLAYER_UNIT_TRAIN_START then
return 32
elseif pe == EVENT_PLAYER_UNIT_TRAIN_CANCEL then
return 33
elseif pe == EVENT_PLAYER_UNIT_TRAIN_FINISH then
return 34
elseif pe == EVENT_PLAYER_UNIT_RESEARCH_START then
return 35
elseif pe == EVENT_PLAYER_UNIT_RESEARCH_CANCEL then
return 36
elseif pe == EVENT_PLAYER_UNIT_RESEARCH_FINISH then
return 37
elseif pe == EVENT_PLAYER_UNIT_ISSUED_ORDER then
return 38
elseif pe == EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER then
return 39
elseif pe == EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER then
return 40
elseif pe == EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER then
return 40
elseif pe == EVENT_PLAYER_HERO_LEVEL then
return 41
elseif pe == EVENT_PLAYER_HERO_SKILL then
return 42
elseif pe == EVENT_PLAYER_HERO_REVIVABLE then
return 43
elseif pe == EVENT_PLAYER_HERO_REVIVE_START then
return 44
elseif pe == EVENT_PLAYER_HERO_REVIVE_CANCEL then
return 45
elseif pe == EVENT_PLAYER_HERO_REVIVE_FINISH then
return 46
elseif pe == EVENT_PLAYER_UNIT_SUMMON then
return 47
elseif pe == EVENT_PLAYER_UNIT_DROP_ITEM then
return 48
elseif pe == EVENT_PLAYER_UNIT_PICKUP_ITEM then
return 49
elseif pe == EVENT_PLAYER_UNIT_USE_ITEM then
return 50
elseif pe == EVENT_PLAYER_UNIT_LOADED then
return 51
elseif pe == EVENT_PLAYER_UNIT_SELL then
return 269
elseif pe == EVENT_PLAYER_UNIT_CHANGE_OWNER then
return 270
elseif pe == EVENT_PLAYER_UNIT_SELL_ITEM then
return 271
elseif pe == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
return 272
elseif pe == EVENT_PLAYER_UNIT_SPELL_CAST then
return 273
elseif pe == EVENT_PLAYER_UNIT_SPELL_EFFECT then
return 274
elseif pe == EVENT_PLAYER_UNIT_SPELL_FINISH then
return 275
elseif pe == EVENT_PLAYER_UNIT_SPELL_ENDCAST then
return 276
elseif pe == EVENT_PLAYER_UNIT_PAWN_ITEM then
return 277
endif//default
return 0
endfunction
function RaceToInteger takes race rc returns integer
if rc == RACE_HUMAN then
return 1
elseif rc == RACE_ORC then
return 2
elseif rc == RACE_UNDEAD then
return 3
elseif rc == RACE_NIGHTELF then
return 4
elseif rc == RACE_DEMON then
return 5
elseif rc == RACE_OTHER then
return 7
endif//default
return 0
endfunction
function RacePrefToInteger takes racepreference rp returns integer
if rp == RACE_PREF_HUMAN then
return 1
elseif rp == RACE_PREF_ORC then
return 2
elseif rp == RACE_PREF_NIGHTELF then
return 4
elseif rp == RACE_PREF_UNDEAD then
return 8
elseif rp == RACE_PREF_DEMON then
return 16
elseif rp == RACE_PREF_RANDOM then
return 32
elseif rp == RACE_PREF_USER_SELECTABLE then
return 64
endif//default
return 0
endfunction
function RarityControlToInteger takes raritycontrol rc returns integer
if rc == RARITY_FREQUENT then
return 0
elseif rc == RARITY_RARE then
return 1
endif//default
return 0
endfunction
function SoundTypeToInteger takes soundtype st returns integer
if st == SOUND_TYPE_EFFECT then
return 0
elseif st == SOUND_TYPE_EFFECT_LOOPED then
return 1
endif//default
return 0
endfunction
function StartLocPrioToInteger takes startlocprio sp returns integer
if sp == MAP_LOC_PRIO_LOW then
return 0
elseif sp == MAP_LOC_PRIO_HIGH then
return 1
elseif sp == MAP_LOC_PRIO_NOT then
return 2
endif//default
return 0
endfunction
function TexMapFlagsToInteger takes texmapflags tf returns integer
if tf == TEXMAP_FLAG_NONE then
return 0
elseif tf == TEXMAP_FLAG_WRAP_U then
return 1
elseif tf == TEXMAP_FLAG_WRAP_V then
return 2
elseif tf == TEXMAP_FLAG_WRAP_UV then
return 3
endif//default
return 0
endfunction
function UnitEventToInteger takes unitevent ue returns integer
if ue == EVENT_UNIT_DAMAGED then
return 52
elseif ue == EVENT_UNIT_DEATH then
return 53
elseif ue == EVENT_UNIT_DECAY then
return 54
elseif ue == EVENT_UNIT_DETECTED then
return 55
elseif ue == EVENT_UNIT_HIDDEN then
return 56
elseif ue == EVENT_UNIT_SELECTED then
return 57
elseif ue == EVENT_UNIT_DESELECTED then
return 58
elseif ue == EVENT_UNIT_STATE_LIMIT then
return 59
elseif ue == EVENT_UNIT_ACQUIRED_TARGET then
return 60
elseif ue == EVENT_UNIT_TARGET_IN_RANGE then
return 61
elseif ue == EVENT_UNIT_ATTACKED then
return 62
elseif ue == EVENT_UNIT_RESCUED then
return 63
elseif ue == EVENT_UNIT_CONSTRUCT_CANCEL then
return 64
elseif ue == EVENT_UNIT_CONSTRUCT_FINISH then
return 65
elseif ue == EVENT_UNIT_UPGRADE_START then
return 66
elseif ue == EVENT_UNIT_UPGRADE_CANCEL then
return 67
elseif ue == EVENT_UNIT_UPGRADE_FINISH then
return 68
elseif ue == EVENT_UNIT_TRAIN_START then
return 69
elseif ue == EVENT_UNIT_TRAIN_CANCEL then
return 70
elseif ue == EVENT_UNIT_TRAIN_FINISH then
return 71
elseif ue == EVENT_UNIT_RESEARCH_START then
return 72
elseif ue == EVENT_UNIT_RESEARCH_CANCEL then
return 73
elseif ue == EVENT_UNIT_RESEARCH_FINISH then
return 74
elseif ue == EVENT_UNIT_ISSUED_ORDER then
return 75
elseif ue == EVENT_UNIT_ISSUED_POINT_ORDER then
return 76
elseif ue == EVENT_UNIT_ISSUED_TARGET_ORDER then
return 77
elseif ue == EVENT_UNIT_HERO_LEVEL then
return 78
elseif ue == EVENT_UNIT_HERO_SKILL then
return 79
elseif ue == EVENT_UNIT_HERO_REVIVABLE then
return 80
elseif ue == EVENT_UNIT_HERO_REVIVE_START then
return 81
elseif ue == EVENT_UNIT_HERO_REVIVE_CANCEL then
return 82
elseif ue == EVENT_UNIT_HERO_REVIVE_FINISH then
return 83
elseif ue == EVENT_UNIT_SUMMON then
return 84
elseif ue == EVENT_UNIT_DROP_ITEM then
return 85
elseif ue == EVENT_UNIT_PICKUP_ITEM then
return 86
elseif ue == EVENT_UNIT_USE_ITEM then
return 87
elseif ue == EVENT_UNIT_LOADED then
return 88
elseif ue == EVENT_UNIT_SELL then
return 286
elseif ue == EVENT_UNIT_CHANGE_OWNER then
return 287
elseif ue == EVENT_UNIT_SELL_ITEM then
return 288
elseif ue == EVENT_UNIT_SPELL_CHANNEL then
return 289
elseif ue == EVENT_UNIT_SPELL_CAST then
return 290
elseif ue == EVENT_UNIT_SPELL_EFFECT then
return 291
elseif ue == EVENT_UNIT_SPELL_FINISH then
return 292
elseif ue == EVENT_UNIT_SPELL_ENDCAST then
return 293
elseif ue == EVENT_UNIT_PAWN_ITEM then
return 294
endif//default
return 0
endfunction
function UnitStateToInteger takes unitstate us returns integer
if us == UNIT_STATE_LIFE then
return 0
elseif us == UNIT_STATE_MAX_LIFE then
return 1
elseif us == UNIT_STATE_MANA then
return 2
elseif us == UNIT_STATE_MAX_MANA then
return 3
endif//default
return 0
endfunction
function UnitTypeToInteger takes unittype ut returns integer
if ut == UNIT_TYPE_HERO then
return 0
elseif ut == UNIT_TYPE_DEAD then
return 1
elseif ut == UNIT_TYPE_STRUCTURE then
return 2
elseif ut == UNIT_TYPE_FLYING then
return 3
elseif ut == UNIT_TYPE_GROUND then
return 4
elseif ut == UNIT_TYPE_ATTACKS_FLYING then
return 5
elseif ut == UNIT_TYPE_ATTACKS_GROUND then
return 6
elseif ut == UNIT_TYPE_MELEE_ATTACKER then
return 7
elseif ut == UNIT_TYPE_RANGED_ATTACKER then
return 8
elseif ut == UNIT_TYPE_GIANT then
return 9
elseif ut == UNIT_TYPE_SUMMONED then
return 10
elseif ut == UNIT_TYPE_STUNNED then
return 11
elseif ut == UNIT_TYPE_PLAGUED then
return 12
elseif ut == UNIT_TYPE_SNARED then
return 13
elseif ut == UNIT_TYPE_UNDEAD then
return 14
elseif ut == UNIT_TYPE_MECHANICAL then
return 15
elseif ut == UNIT_TYPE_PEON then
return 16
elseif ut == UNIT_TYPE_SAPPER then
return 17
elseif ut == UNIT_TYPE_TOWNHALL then
return 18
elseif ut == UNIT_TYPE_ANCIENT then
return 19
elseif ut == UNIT_TYPE_TAUREN then
return 20
elseif ut == UNIT_TYPE_POISONED then
return 21
elseif ut == UNIT_TYPE_POLYMORPHED then
return 22
elseif ut == UNIT_TYPE_SLEEPING then
return 23
elseif ut == UNIT_TYPE_RESISTANT then
return 24
elseif ut == UNIT_TYPE_ETHEREAL then
return 25
elseif ut == UNIT_TYPE_MAGIC_IMMUNE then
return 26
endif//default
return 0
endfunction
function VersionToInteger takes version ve returns integer
if ve == VERSION_REIGN_OF_CHAOS then
return 0
elseif ve == VERSION_FROZEN_THRONE then
return 1
endif//default
return 0
endfunction
function VolumeGroupToInteger takes volumegroup vg returns integer
if vg == SOUND_VOLUMEGROUP_UNITMOVEMENT then
return 0
elseif vg == SOUND_VOLUMEGROUP_UNITSOUNDS then
return 1
elseif vg == SOUND_VOLUMEGROUP_COMBAT then
return 2
elseif vg == SOUND_VOLUMEGROUP_SPELLS then
return 3
elseif vg == SOUND_VOLUMEGROUP_UI then
return 4
elseif vg == SOUND_VOLUMEGROUP_MUSIC then
return 5
elseif vg == SOUND_VOLUMEGROUP_AMBIENTSOUNDS then
return 6
elseif vg == SOUND_VOLUMEGROUP_FIRE then
return 7
endif//default
return 0
endfunction
function WeaponTypeToInteger takes weapontype wt returns integer
if wt == WEAPON_TYPE_WHOKNOWS then
return 0
elseif wt == WEAPON_TYPE_METAL_LIGHT_CHOP then
return 1
elseif wt == WEAPON_TYPE_METAL_MEDIUM_CHOP then
return 2
elseif wt == WEAPON_TYPE_METAL_HEAVY_CHOP then
return 3
elseif wt == WEAPON_TYPE_METAL_LIGHT_SLICE then
return 4
elseif wt == WEAPON_TYPE_METAL_MEDIUM_SLICE then
return 5
elseif wt == WEAPON_TYPE_METAL_HEAVY_SLICE then
return 6
elseif wt == WEAPON_TYPE_METAL_MEDIUM_BASH then
return 7
elseif wt == WEAPON_TYPE_METAL_HEAVY_BASH then
return 8
elseif wt == WEAPON_TYPE_METAL_MEDIUM_STAB then
return 9
elseif wt == WEAPON_TYPE_METAL_HEAVY_STAB then
return 10
elseif wt == WEAPON_TYPE_WOOD_LIGHT_SLICE then
return 11
elseif wt == WEAPON_TYPE_WOOD_MEDIUM_SLICE then
return 12
elseif wt == WEAPON_TYPE_WOOD_HEAVY_SLICE then
return 13
elseif wt == WEAPON_TYPE_WOOD_LIGHT_BASH then
return 14
elseif wt == WEAPON_TYPE_WOOD_MEDIUM_BASH then
return 15
elseif wt == WEAPON_TYPE_WOOD_HEAVY_BASH then
return 16
elseif wt == WEAPON_TYPE_WOOD_LIGHT_STAB then
return 17
elseif wt == WEAPON_TYPE_WOOD_MEDIUM_STAB then
return 18
elseif wt == WEAPON_TYPE_CLAW_LIGHT_SLICE then
return 19
elseif wt == WEAPON_TYPE_CLAW_MEDIUM_SLICE then
return 20
elseif wt == WEAPON_TYPE_CLAW_HEAVY_SLICE then
return 21
elseif wt == WEAPON_TYPE_AXE_MEDIUM_CHOP then
return 22
elseif wt == WEAPON_TYPE_ROCK_HEAVY_BASH then
return 23
endif//default
return 0
endfunction
function WidgetEventToInteger takes widgetevent we returns integer
if we == EVENT_WIDGET_DEATH then
return 89
endif//default
return 0
endfunction
///////////////////////////////////////
// Other convertions:
//Convertion from boolean to integer.
function B2I takes boolean bool returns integer
if bool then
return 1
endif
return 0
endfunction
//Convertion from integer to boolean.
function I2B takes integer int returns boolean
return int != 0
endfunction
//Convertion from boolean to string.
function B2S takes boolean bool returns string
if bool then
return "true"
endif
return "false"
endfunction
//Convertion from string to boolean.
function S2B takes string str returns boolean
return str == "true" or str == "TRUE"
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Color functions:
//
library ColorFunctions
//Sets the color of the "affectedPlayer" only for the "client".
function SetPlayerColorLocally takes player client, player affectedPlayer, playercolor pc, boolean changeUnits returns nothing
local group g
local unit FoG
local boolean isClient = LOCAL_PLAYER == client
if isClient then
call SetPlayerColor(affectedPlayer, pc)
endif
if changeUnits then
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, affectedPlayer, null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g, FoG)
if isClient then
call SetUnitColor(FoG, pc)
endif
endloop
call DestroyGroup(g)
set g = null
endif
endfunction
//Returns the hex color code of "pc".
//Does not work with custom colors.
function GetPlayerColorHexCode takes playercolor pc returns integer
if pc == PLAYER_COLOR_RED then
return 0xFFFF0202
elseif pc == PLAYER_COLOR_BLUE then
return 0xFF0041FF
elseif pc == PLAYER_COLOR_CYAN then
return 0xFF1BE5B8
elseif pc == PLAYER_COLOR_PURPLE then
return 0xFF530080
elseif pc == PLAYER_COLOR_YELLOW then
return 0xFFFFFC00
elseif pc == PLAYER_COLOR_ORANGE then
return 0xFFFE890D
elseif pc == PLAYER_COLOR_GREEN then
return 0xFF1FBF00
elseif pc == PLAYER_COLOR_PINK then
return 0xFFE45AAF
elseif pc == PLAYER_COLOR_LIGHT_GRAY then
return 0xFF949596
elseif pc == PLAYER_COLOR_LIGHT_BLUE then
return 0xFF7DBEF1
elseif pc == PLAYER_COLOR_AQUA then
return 0xFF0F6145
elseif pc == PLAYER_COLOR_BROWN then
return 0xFF4D2903
endif//default
return 0xFF000000
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Position/Coordination functions:
//
library PositionFunctions
//Returns the terrain height of the given coordinates.
function GetCoordinateZ takes real x, real y returns real
call MoveLocation(LOCATION, x, y)
return GetLocationZ(LOCATION)
endfunction
//Returns the distance between the given coordinates.
function DistanceBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
local real x = x2 - x1
local real y = y2 - y1
return SquareRoot(x*x + y*y)
endfunction
//Returns the angle from xy1 to xy2 in radians(Rad)/degrees(Deg)
//The returned value is between -180 and 180 for degrees and between -PI and PI for radians.
function AngleBetweenCoordinatesRad takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2 - y1, x2 - x1)
endfunction
function AngleBetweenCoordinatesDeg takes real x1, real y1, real x2, real y2 returns real
return AngleBetweenCoordinatesRad(x1, y1, x2, y2) * RADTODEG
endfunction
//Deprecated function pointing at "AngleBetweenCoordinatesRad()" for backwards compatibility.
function AngleBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
return AngleBetweenCoordinatesRad(x1, y1, x2, y2) * RADTODEG
endfunction
//Returns a normalized angle from the given angle.
//Normalized angles are between 0 and 360 for degrees and 0 and TAU for radians.
function NormalizeAngleRad takes real angle returns real
local real modulus = angle - I2R(R2I(angle / TAU)) * TAU
if modulus < 0 then
set modulus = modulus + TAU
endif
return modulus
endfunction
function NormalizeAngleDeg takes real angle returns real
local real modulus = angle - I2R(R2I(angle / 360)) * 360
if modulus < 0 then
set modulus = modulus + 360
endif
return modulus
endfunction
//Deprecated function pointing at "NormalizeAngleDeg()" for backwards compatibility.
function NormalizeAngle takes real angle returns real
return NormalizeAngleDeg(angle)
endfunction
//Returns a denormalized angle from the given angle.
//Denomalized angles are between -180 and 180 for degrees and -PI and PI for radians.
function DenormalizeAngleRad takes real angle returns real
local real modulus = angle - I2R(R2I(angle / TAU)) * TAU
if modulus > PI then
set modulus = modulus - TAU
endif
return modulus
endfunction
function DenormalizeAngleDeg takes real angle returns real
local real modulus = angle - I2R(R2I(angle / 360)) * 360
if modulus > 180 then
set modulus = modulus - 360
elseif modulus < -180 then
set modulus = modulus + 360
endif
return modulus
endfunction
//Deprecated function pointing at "DenormalizeAngleDeg()" for backwards compatibility.
function DenormalizeAngle takes real angle returns real
return DenormalizeAngleDeg(angle)
endfunction
//Return wether point ("px", "py") is in a rectangle of size ("width", "height") on point ("x", "y")
// angled to "angle" radians(Rad)/degrees(Deg).
function IsPointInAngledRectangleRad takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
local real halfWidth = width/2
local real halfHeight = height/2
local real distance = DistanceBetweenCoordinates(rx, ry, px, py)
local real newPX
local real newPY
set angle = angle - AngleBetweenCoordinatesRad(rx, ry, px, py)
set newPX = distance * Cos(angle)
set newPY = distance * Sin(angle)
return newPX > -halfWidth and newPX < halfWidth and newPY > -halfHeight and newPY < halfHeight
endfunction
function IsPointInAngledRectangleDeg takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
return IsPointInAngledRectangleRad(rx, ry, width, height, angle * DEGTORAD, px, py)
endfunction
//Deprecated function pointing at "IsPointInAngledRectangleRad()" for backwards compatibility.
function IsPointInAngledRectangle takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
return IsPointInAngledRectangleRad(rx, ry, width, height, angle * DEGTORAD, px, py)
endfunction
//Ex functions for calls where angle is already calculated as radian.
//Use "angle * DEGTORAD" to convert degrees to radians.
function IsPointInAngledRectangleEx takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
local real halfWidth = width/2
local real halfHeight = height/2
local real distance = DistanceBetweenCoordinates(rx, ry, px, py)
local real newPX = distance * Cos(angle)
local real newPY = distance * Sin(angle)
return newPX > -halfWidth and newPX < halfWidth and newPY > -halfHeight and newPY < halfHeight
endfunction
//Returns a string format of two coordinates with 2 decimal precision.
function Coordinates2String takes real x, real y returns string
return "(" + R2SW(x, 1, 2) + ", " + R2SW(y, 1, 2) + ")"
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Group functions:
//
library GroupFunctions uses PositionFunctions optional Polygon2D
//Groups all units of type "unitTypeId" in group "whichGroup" without leaking and using FirstOfGroup iteration.
//Returns "whichGroup" for easy usage: "local group g = GroupEnumUnitsOfTypeId(CreateGroup(), 'hfoo')".
function GroupEnumUnitsOfTypeId takes group whichGroup, integer unitTypeId returns group
local group tempgroup = CreateGroup()
local unit FoG
local integer index = 0
loop
call GroupEnumUnitsOfPlayer(tempgroup, PLAYER[index], null)
loop
set FoG = FirstOfGroup(tempgroup)
exitwhen FoG == null
call GroupRemoveUnit(tempgroup, FoG)
if GetUnitTypeId(FoG) == unitTypeId then
call GroupAddUnit(whichGroup, FoG)
endif
endloop
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call DestroyGroup(tempgroup)
set tempgroup = null
return whichGroup
endfunction
function GroupEnumUnitsInRectEx takes group whichGroup, rect rectangle returns group
call GroupEnumUnitsInRect(whichGroup, rectangle, null)
return whichGroup
endfunction
function GroupEnumUnitsInRangeEx takes group whichGroup, real x, real y, real radius returns group
call GroupEnumUnitsInRange(whichGroup, x, y, radius, null)
return whichGroup
endfunction
function GroupEnumUnitsInRegion takes group whichGroup, real minX, real minY, real maxX, real maxY returns group
call SetRect(RECT, minX, minY, maxX, maxY)
return GroupEnumUnitsInRectEx(whichGroup, RECT)
endfunction
//Groups all units in a cone facing "direction" degrees from position ("x", "y").
//"radius" is the length of the cone. "size" is the maximum difference in angle in radians(Rad)/degrees(Deg) from ("x", "y") towards the unit.
//Returns "whichGroup" for easy usage: "local group g = GroupEnumUnitsInCone(CreateGroup(), x, y, r, d, s)".
function GroupEnumUnitsInConeRad takes group whichGroup, real x, real y, real radius, real direction, real size returns group
local unit FoG
local group g = CreateGroup()
local real x2
local real y2
local real difference
call GroupEnumUnitsInRange(g, x, y, radius, null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g,FoG)
set difference = DenormalizeAngleRad(AngleBetweenCoordinatesRad(x, y, GetUnitX(FoG), GetUnitY(FoG)) - direction)
if difference > -size and difference < size then
call GroupAddUnit(whichGroup, FoG)
endif
endloop
call DestroyGroup(g)
set g = null
return whichGroup
endfunction
function GroupEnumUnitsInConeDeg takes group whichGroup, real x, real y, real radius, real direction, real size returns group
local unit FoG
local group g = CreateGroup()
local real x2
local real y2
local real difference
call GroupEnumUnitsInRange(g, x, y, radius, null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g,FoG)
set difference = DenormalizeAngleDeg(AngleBetweenCoordinatesDeg(x, y, GetUnitX(FoG), GetUnitY(FoG)) - direction)
if difference > -size and difference < size then
call GroupAddUnit(whichGroup, FoG)
endif
endloop
call DestroyGroup(g)
set g = null
return whichGroup
endfunction
//Deprecated function pointing at "GroupEnumUnitsInConeDeg()" for backwards compatibility.
function GroupEnumUnitsInCone takes group whichGroup, real x, real y, real radius, real direction, real size returns group
return GroupEnumUnitsInConeDeg(whichGroup, x, y, radius, direction, size)
endfunction
//Groups all units in a rectangle of size ("width", "height") on point ("x", "y") angled to "angle" degrees(Deg)/radians(Rad).
//Returns "whichGroup" for easy usage: "local group g = GroupEnumUnitsInRectangle(CreateGroup(), x, y, w, h, a)".
function GroupEnumUnitsInRectangleRad takes group whichGroup, real x, real y, real width, real height, real angle returns group
local unit FoG
local group g = CreateGroup()
local real ux
local real uy
call GroupEnumUnitsInRange(g, x, y, SquareRoot(width*width + height*height)*0.5, null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g,FoG)
set ux = GetUnitX(FoG)
set uy = GetUnitY(FoG)
if IsPointInAngledRectangleEx(x, y, width, height, angle - AngleBetweenCoordinatesRad(x, y, ux, uy), ux, uy) then
call GroupAddUnit(whichGroup, FoG)
endif
endloop
call DestroyGroup(g)
set g = null
return whichGroup
endfunction
//Deprecated function pointing at "GroupEnumUnitsInRectangleRad()" for backwards compatibility.
function GroupEnumUnitsInRectangleDeg takes group whichGroup, real x, real y, real width, real height, real angle returns group
return GroupEnumUnitsInRectangleRad(whichGroup, x, y, width, height, angle * DEGTORAD)
endfunction
//Deprecated function pointing at "GroupEnumUnitsInRectangleRad()" for backwards compatibility.
function GroupEnumUnitsInRectangle takes group whichGroup, real x, real y, real width, real height, real angle returns group
return GroupEnumUnitsInRectangleRad(whichGroup, x, y, width, height, angle * DEGTORAD)
endfunction
static if LIBRARY_Polygon then
//Groups all units within a polygon created by the Polygon2D library.
function GroupEnumUnitsInPolygon takes group whichGroup, Polygon polygon returns group
local group g = GroupEnumUnitsInRectEx(CreateGroup(), polygon.getBounds())
local unit FoG
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g,FoG)
if polygon.containsPoint(GetUnitX(FoG), GetUnitY(FoG)) then
call GroupAddUnit(whichGroup, FoG)
endif
endloop
call DestroyGroup(g)
set g = null
return whichGroup
endfunction
endif
//Makes "groupPaste" a copy of "groupCopy" using FirstOfGroup iteration.
//Returns "groupPaste" for easy usage: "local group g2 = DuplicateGroup(g1, CreateGroup())".
function DuplicateGroup takes group groupCopy, group groupPaste returns group
local unit FoG
local group swap = CreateGroup()
call GroupClear(groupPaste)
loop
set FoG = FirstOfGroup(groupCopy)
exitwhen FoG == null
call GroupRemoveUnit(groupCopy, FoG)
call GroupAddUnit(swap, FoG)
call GroupAddUnit(groupPaste, FoG)
endloop
loop
set FoG = FirstOfGroup(swap)
exitwhen FoG == null
call GroupRemoveUnit(swap, FoG)
call GroupAddUnit(groupCopy, FoG)
endloop
call DestroyGroup(swap)
set swap = null
return groupPaste
endfunction
//Transfers all units from "g2" to "g1" using FirstOfGroup iteration.
//"g2" will be cleared during the process.
function GroupAddG takes group g1, group g2 returns nothing
local unit FoG
loop
set FoG = FirstOfGroup(g2)
exitwhen FoG == null
call GroupRemoveUnit(g2, FoG)
call GroupAddUnit(g1, FoG)
endloop
endfunction
//Removes all units from "g1" that are also in "g2" using FirstOfGroup iteration.
//"g2" will be cleared during the process.
function GroupRemoveG takes group g1, group g2 returns nothing
local unit FoG
loop
set FoG = FirstOfGroup(g2)
exitwhen FoG == null
call GroupRemoveUnit(g2, FoG)
call GroupRemoveUnit(g1, FoG)
endloop
endfunction
//Returns the amount of units in "whichGroup" using FirstOfGroup iteration.
function GroupCountUnits takes group whichGroup returns integer
local unit FoG
local group swap = CreateGroup()
local integer count = 0
loop
set FoG = FirstOfGroup(whichGroup)
exitwhen FoG == null
call GroupRemoveUnit(whichGroup, FoG)
set count = count +1
call GroupAddUnit(swap, FoG)
endloop
loop
set FoG = FirstOfGroup(swap)
exitwhen FoG == null
call GroupRemoveUnit(swap, FoG)
call GroupAddUnit(whichGroup, FoG)
endloop
call DestroyGroup(swap)
set swap = null
return count
endfunction
//Returns a random unit from "whichGroup" using FirstOfGroup iteration.
//Uses global variable UNIT_VAR which will be the same as the returned unit.
function GroupGetRandomUnit takes group whichGroup returns unit
local unit FoG
local group swap = CreateGroup()
local integer count = 0
local integer random
set UNIT_VAR = null
loop
set FoG = FirstOfGroup(whichGroup)
exitwhen FoG == null
call GroupRemoveUnit(whichGroup, FoG)
set count = count +1
call GroupAddUnit(swap, FoG)
endloop
set random = GetRandomInt(0, count)
set count = 0
loop
set FoG = FirstOfGroup(swap)
exitwhen FoG == null
call GroupRemoveUnit(swap, FoG)
call GroupAddUnit(whichGroup, FoG)
set count = count +1
if count == random then
set UNIT_VAR = FoG
endif
endloop
call DestroyGroup(swap)
set swap = null
return UNIT_VAR
endfunction
//Returns the nearest unit in "maxDistance" radius from ("x", "y").
//Uses global variable UNIT_VAR which will be the same as the returned unit.
function GetClosestUnit takes real x, real y, real maxDistance returns unit
local group g = CreateGroup()
local real distance
local unit FoG
local real closestDistance = maxDistance +1
set UNIT_VAR = null
call GroupEnumUnitsInRange(g, x, y, maxDistance, null)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
call GroupRemoveUnit(g, FoG)
set distance = DistanceBetweenCoordinates(x, y, GetUnitX(FoG), GetUnitY(FoG))
if distance < closestDistance then
set closestDistance = distance
set UNIT_VAR = FoG
endif
endloop
call DestroyGroup(g)
set g = null
return UNIT_VAR
endfunction
//Returns the nearest unit in "maxDistance" radius from ("x", "y"),
// filtering units that do not pass the TriggerEvaluate() of "filter".
//Uses global variable UNIT_VAR which will be the same as the returned unit.
//Uses global variable UNIT_ARRAY index "arrayIndex" which will be the picked unit that can be used in the filter.
// Set "arrayIndex" to 0 if you don't know what to do with it.
function GetClosestUnitFiltered takes real x, real y, real maxDistance, trigger filter, integer arrayIndex returns unit
local group g = CreateGroup()
local real distance
local real closestDistance = maxDistance +1
set UNIT_VAR = null
call GroupEnumUnitsInRange(g, x, y, maxDistance, null)
loop
set UNIT_ARRAY[arrayIndex] = FirstOfGroup(g)
exitwhen UNIT_ARRAY[arrayIndex] == null
call GroupRemoveUnit(g, UNIT_ARRAY[arrayIndex])
if TriggerEvaluate(filter) then
set distance = DistanceBetweenCoordinates(x, y, GetUnitX(UNIT_ARRAY[arrayIndex]), GetUnitY(UNIT_ARRAY[arrayIndex]))
if distance < closestDistance then
set closestDistance = distance
set UNIT_VAR = UNIT_ARRAY[arrayIndex]
endif
endif
endloop
call DestroyGroup(g)
set g = null
return UNIT_VAR
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Item functions:
//
library ItemFunctions
//Checks if the given unit has items of the given types.
//Fill the parameters with 0 to have fewer required item types.
//Works with multiple items of the same type.
function UnitCheckItems takes unit whichUnit, integer i1, integer i2, integer i3, integer i4, integer i5, integer i6 returns boolean
local integer array heldItems
local integer array requestedItems
local integer index1
local integer index2
local integer requestedItemsLength = 6
set requestedItems[0] = i1
set requestedItems[1] = i2
set requestedItems[2] = i3
set requestedItems[3] = i4
set requestedItems[4] = i5
set requestedItems[5] = i6
set heldItems[0] = GetItemTypeId(UnitItemInSlot(whichUnit, 0))
set heldItems[1] = GetItemTypeId(UnitItemInSlot(whichUnit, 1))
set heldItems[2] = GetItemTypeId(UnitItemInSlot(whichUnit, 2))
set heldItems[3] = GetItemTypeId(UnitItemInSlot(whichUnit, 3))
set heldItems[4] = GetItemTypeId(UnitItemInSlot(whichUnit, 4))
set heldItems[5] = GetItemTypeId(UnitItemInSlot(whichUnit, 5))
set index1 = 0
loop
if requestedItems[index1] == 0 then
set requestedItemsLength = requestedItemsLength-1
set requestedItems[index1] = requestedItems[requestedItemsLength]
if requestedItemsLength == 0 then
return true
endif
endif
exitwhen index1 == 5
set index1 = index1 +1
endloop
set index1 = 0
loop
set index2 = 0
loop
exitwhen index2 >= requestedItemsLength
if heldItems[index1] == requestedItems[index2] then
set requestedItemsLength = requestedItemsLength-1
set requestedItems[index2] = requestedItems[requestedItemsLength]
if requestedItemsLength == 0 then
return true
endif
exitwhen true
endif
set index2 = index2 +1
endloop
exitwhen index1 == 5
set index1 = index1 +1
endloop
return false
endfunction
function UnitCountItemsOfType takes unit whichUnit, integer itemType returns integer
local integer result = 0
local integer i = 0
loop
exitwhen i >= 6
if GetItemTypeId(UnitItemInSlot(whichUnit, i)) == itemType then
set result = result +1
endif
set i = i +1
endloop
return result
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Math functions:
//
library MathFunctions
//Returns a random integer with slice'n'dice calculations.
function GetDiceInt takes integer slice, integer dice returns integer
local integer number = 0
local integer i = 0
loop
exitwhen i >= dice
set number = number + GetRandomInt(0, slice)
set i = i +1
endloop
return number
endfunction
//Returns a random real with slice'n'dice calculations.
function GetDiceReal takes real slice, integer dice returns real
local real number = 0.
local integer i = 0
loop
exitwhen i >= dice
set number = number + GetRandomReal(0., slice)
set i = i +1
endloop
return number
endfunction
//Constricts "i" between "min" and "max".
function ConstrictInteger takes integer i, integer min, integer max returns integer
if i >= max then
return max
elseif i <= min then
return min
endif
return i
endfunction
//Constricts "r" between "min" and "max".
function ConstrictReal takes real r, real min, real max returns real
if r >= max then
return max
elseif r <= min then
return min
endif
return r
endfunction
//Rounds "i" down to the nearest Integer-multiplication of "place".
function TrimIntegerDown takes integer i, integer place returns integer
return i / place * place
endfunction
//Rounds "i" up to the nearest Integer-multiplication of "place".
function TrimIntegerUp takes integer i, integer place returns integer
local real value = I2R(i) / place
local real a = value
set a = a - I2R(R2I(a))
if a > 0 then
set value = I2R(R2I(value) +1)
endif
return R2I(value * place)
endfunction
//Rounds "i" to the nearest Integer-multiplication of "place".
function TrimIntegerNearest takes integer i, integer place returns integer
return (i + (place/2)) / place * place
endfunction
//Rounds "r" down to the nearest Integer-multiplication of "place".
function TrimRealDown takes real r, integer place returns real
return I2R(R2I(r / place)) * place
endfunction
//Rounds "r" up to the nearest Integer-multiplication of "place".
function TrimRealUp takes real r, integer place returns real
local real value = r / place
local real a = value
set a = a - I2R(R2I(a))
if a > 0 then
set value = I2R(R2I(value) +1)
endif
return value * place
endfunction
//Rounds "r" to the nearest Integer-multiplication of "place".
function TrimRealNearest takes real r, integer place returns real
return I2R(R2I(r / place + 0.5)) * place
endfunction
//Returns the x-root of "base".
function Root takes real base, real x returns real
return Pow(base, 1/x)
endfunction
//Returns the value of "i".
//Also known as "abs".
function IAbs takes integer i returns integer
if i < -i then
return -i
else
return i
endif
endfunction
//Returns the value of "r".
//Also known as "abs".
function RAbs takes real r returns real
if r < -r then
return -r
else
return r
endif
endfunction
//Rounds "value" down towards the next lower integer value.
function Floor takes real value returns real
return I2R(R2I(value))
endfunction
//Rounds "value" up towards the next higher integer value.
function Ceil takes real value returns real
local real a = I2R(R2I(value))
if a == value then
return value
endif
return a +1
endfunction
//Rounds "value" towards the nearest integer value.
function Round takes real value returns real
return I2R(R2I(value + 0.5))
endfunction
//Returns the signum of the argument.
//Zero if the argument is zero,
//1. if the argument is larger than 0,
//-1. if the argument is smaller than 0.
function Signum takes real value returns real
if value > 0. then
return 1.
elseif value < 0. then
return -1.
endif
return value
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Time functions:
//
library TimeFunctions initializer BF_INIT_TimeFunctions
//Runs a non-leaking PolledWait(duration).
function WaitGameTime takes real duration returns nothing
local timer t
local real timeRemaining
if duration > 0 then
set t = CreateTimer()
call TimerStart(t, duration, false, null)
loop
set timeRemaining = TimerGetRemaining(t)
exitwhen timeRemaining <= 0
if timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD then
call TriggerSleepAction(0.1 * timeRemaining)
else
call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
endif
endloop
call DestroyTimer(t)
set t = null
endif
endfunction
globals
timer GT_TIMER = CreateTimer()
real GT_ELAPSED_TIME = 0
endglobals
//Return the current elapsed gametime.
function GetElapsedGameTime takes nothing returns real
return GT_ELAPSED_TIME + TimerGetElapsed(GT_TIMER)
endfunction
function GT_AddHour takes nothing returns nothing
set GT_ELAPSED_TIME = GT_ELAPSED_TIME +3600.
endfunction
function BF_INIT_TimeFunctions takes nothing returns nothing
call TimerStart(GT_TIMER, 3600, true, function GT_AddHour)
endfunction
endlibrary
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library BasicFunctions uses GlobalVariables, ConvertionFunctions, ColorFunctions, PositionFunctions, GroupFunctions, ItemFunctions, MathFunctions, TimeFunctions
//Standard requirement.
endlibrary
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//! textmacro NewLinkedList takes NAME
struct $NAME$
//Id data
private static integer nextId = 0
private static boolean array index_Occupied
//List data:
private static integer array list_firstIndex
private static integer array list_lastIndex
//Index data:
private static integer array list_nextIndex
private static integer array list_prevIndex
private static integer array list_ID
//Iterator data:
public static integer iterator
private static integer array nextIterator
private static method createId takes nothing returns integer
loop
set $NAME$.nextId = $NAME$.nextId + 1
if $NAME$.nextId > 8190 then
set $NAME$.nextId = 1
endif
exitwhen not $NAME$.index_Occupied[$NAME$.nextId]
endloop
set $NAME$.index_Occupied[$NAME$.nextId] = true
return $NAME$.nextId
endmethod
private static method releaseId takes integer id returns nothing
set $NAME$.index_Occupied[id] = false
endmethod
public static method addIndex takes integer list returns integer
local integer newIndex
if list == 0 then
return 0
endif
set newIndex = $NAME$.createId()
set $NAME$.list_ID[newIndex] = list
set $NAME$.list_nextIndex[$NAME$.list_lastIndex[list]] = newIndex
set $NAME$.list_prevIndex[newIndex] = $NAME$.list_lastIndex[list]
set $NAME$.list_lastIndex[list] = newIndex
if $NAME$.list_firstIndex[list] == 0 then
set $NAME$.list_firstIndex[list] = newIndex
endif
return newIndex
endmethod
public static method insertIndex takes integer list, integer index returns integer
local integer newIndex
if list == 0 then
return 0
elseif index == 0 then
return $NAME$.addIndex(list)
elseif $NAME$.list_ID[index] != list then
return 0
endif
set newIndex = $NAME$.createId()
set $NAME$.list_ID[newIndex] = list
set $NAME$.list_prevIndex[newIndex] = $NAME$.list_prevIndex[index]
set $NAME$.list_nextIndex[$NAME$.list_prevIndex[index]] = newIndex
set $NAME$.list_prevIndex[index] = newIndex
set $NAME$.list_nextIndex[newIndex] = index
if $NAME$.list_firstIndex[list] == index then
set $NAME$.list_firstIndex[list] = newIndex
endif
return newIndex
endmethod
public static method removeIndex takes integer index returns nothing
set $NAME$.list_prevIndex[$NAME$.list_nextIndex[index]] = $NAME$.list_prevIndex[index]
set $NAME$.list_nextIndex[$NAME$.list_prevIndex[index]] = $NAME$.list_nextIndex[index]
call $NAME$.releaseId(index)
if index == $NAME$.list_lastIndex[$NAME$.list_ID[index]] then
set $NAME$.list_lastIndex[$NAME$.list_ID[index]] = $NAME$.list_prevIndex[index]
endif
if index == $NAME$.list_firstIndex[$NAME$.list_ID[index]] then
set $NAME$.list_firstIndex[$NAME$.list_ID[index]] = $NAME$.list_nextIndex[index]
endif
set $NAME$.list_ID[index] = 0
endmethod
public static method prepareIterator takes integer list returns boolean
set $NAME$.iterator = 0
set $NAME$.nextIterator[list] = $NAME$.list_firstIndex[list]
return $NAME$.nextIterator[list] != 0
endmethod
public static method next takes integer list returns boolean
set $NAME$.iterator = $NAME$.nextIterator[list]
set $NAME$.nextIterator[list] = $NAME$.list_nextIndex[$NAME$.iterator]
return $NAME$.iterator != 0
endmethod
public static method clearList takes integer list returns nothing
call $NAME$.prepareIterator(list)
loop
exitwhen not $NAME$.next(list)
call $NAME$.removeIndex($NAME$.iterator)
endloop
endmethod
endstruct
//! endtextmacro
library Polygon uses PositionFunctions
//! runtextmacro NewLinkedList("polygonList")
/** <to-do>
* - public method split takes nothing returns Polygon[]
* - public method add takes Polygon p returns nothing
* - public method substract takes Polygon p returns nothing
* - public method exclusiveOr takes Polygon p returns nothing
* - public method intersect takes Polygon p returns nothing
* - public static method add takes Polygon p1, Polygon p2, Polygon dest returns Polygon
* - public static method substract takes Polygon p1, Polygon p2, Polygon dest returns Polygon
* - public static method exclusiveOr takes Polygon p1, Polygon p2, Polygon dest returns Polygon
* - public static method intersect takes Polygon p1, Polygon p2, Polygon dest returns Polygon
* - implement trigger calls for some functions to prevent OP limits
*/
struct Polygon
//Data storage for each line.
private static real array line_startX
private static real array line_startY
private static real array line_endX
private static real array line_endY
//Data storage for each polygon.
private real rotation
private real scaling
private real minX
private real minY
private real maxX
private real maxY
private real centerX
private real centerY
private integer numberOfLines
//private static LinkedList polygonList
public static method create takes nothing returns Polygon
local Polygon this = Polygon.allocate()
set this.numberOfLines = 0
set this.minX = 0
set this.minY = 0
set this.maxX = 0
set this.maxY = 0
set this.centerX = 0
set this.centerY = 0
set this.scaling = 1
return this
endmethod
public method clear takes nothing returns nothing
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set line_startX[polygonList.iterator] = 0
set line_startY[polygonList.iterator] = 0
set line_endX[polygonList.iterator] = 0
set line_endY[polygonList.iterator] = 0
call polygonList.removeIndex(polygonList.iterator)
endloop
endif
set this.numberOfLines = 0
set this.minX = 0
set this.minY = 0
set this.maxX = 0
set this.maxY = 0
set this.centerX = 0
set this.centerY = 0
set this.scaling = 0
endmethod
public method remove takes nothing returns nothing
call this.clear()
call this.deallocate()
endmethod
public method getBounds takes nothing returns rect
call SetRect(RECT, this.minX, this.minY, this.maxX, this.maxY)
return RECT
endmethod
public method getCenter takes nothing returns Coord
return Coord.create(this.centerX, this.centerY)
endmethod
public method insertLine takes real startX, real startY, real endX, real endY, integer index returns integer
local integer id = polygonList.insertIndex(this, index)
set line_startX[id] = startX
set line_startY[id] = startY
set line_endX[id] = endX
set line_endY[id] = endY
if this.numberOfLines == 0 then
if startX < endX then
set this.minX = startX
set this.maxX = endX
else
set this.minX = endX
set this.maxX = startX
endif
if startY < endY then
set this.minY = startY
set this.maxY = endY
else
set this.minY = endY
set this.maxY = startY
endif
set this.centerX = (startX + endX)/2
set this.centerY = (startY + endY)/2
else
if startX < this.minX then
set this.minX = startX
elseif startX > this.maxX then
set this.maxX = startX
endif
if endX < this.minX then
set this.minX = endX
elseif endX > this.maxX then
set this.maxX = endX
endif
if startY < this.minY then
set this.minY = startY
elseif startY > this.maxY then
set this.maxY = startY
endif
if endY < this.minY then
set this.minY = endY
elseif endY > this.maxY then
set this.maxY = endY
endif
set this.centerX = (this.centerX*this.numberOfLines*2 + startX + endX) / ((numberOfLines+1)*2)
set this.centerY = (this.centerY*this.numberOfLines*2 + startY + endY) / ((numberOfLines+1)*2)
endif
set this.numberOfLines = this.numberOfLines +1
return id
endmethod
public method addLine takes real startX, real startY, real endX, real endY returns integer
return insertLine(startX, startY, endX, endY, 0)
endmethod
public method move takes real xOffset, real yOffset returns nothing
set this.minX = this.minX + xOffset
set this.minY = this.minY + yOffset
set this.maxX = this.maxX + xOffset
set this.maxY = this.maxY + yOffset
set this.centerX = this.centerX + xOffset
set this.centerY = this.centerY + yOffset
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set line_startX[polygonList.iterator] = line_startX[polygonList.iterator] + xOffset
set line_startY[polygonList.iterator] = line_startY[polygonList.iterator] + yOffset
set line_endX[polygonList.iterator] = line_endX[polygonList.iterator] + xOffset
set line_endY[polygonList.iterator] = line_endY[polygonList.iterator] + yOffset
endloop
endif
endmethod
public method setPosition takes real x, real y returns nothing
call this.move(x - this.centerX, y - this.centerY)
endmethod
public method rotateAroundPoint takes real angle, real originX, real originY returns nothing
local real sin = Sin(angle)
local real cos = Cos(angle)
local real oldX
local real oldY
set this.rotation = this.rotation + angle
set this.centerX = (originX + ((this.centerX - originX) * cos) - ((this.centerY - originY) * sin))
set this.centerY = (originY + ((this.centerX - originX) * sin) + ((this.centerY - originY) * cos))
set this.minX = this.centerX
set this.minY = this.centerY
set this.maxX = this.centerX
set this.maxY = this.centerY
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set oldX = line_startX[polygonList.iterator]
set oldY = line_startY[polygonList.iterator]
set line_startX[polygonList.iterator] = (originX + ((oldX - originX) * cos) - ((oldY - originY) * sin))
set line_startY[polygonList.iterator] = (originY + ((oldX - originX) * sin) + ((oldY - originY) * cos))
set oldX = line_endX[polygonList.iterator]
set oldY = line_endY[polygonList.iterator]
set line_endX[polygonList.iterator] = (originX + ((oldX - originX) * cos) - ((oldY - originY) * sin))
set line_endY[polygonList.iterator] = (originY + ((oldX - originX) * sin) + ((oldY - originY) * cos))
if line_startX[polygonList.iterator] < this.minX then
set this.minX = line_startX[polygonList.iterator]
elseif line_startX[polygonList.iterator] > this.maxX then
set this.maxX = line_startX[polygonList.iterator]
endif
if line_endX[polygonList.iterator] < this.minX then
set this.minX = line_endX[polygonList.iterator]
elseif line_endX[polygonList.iterator] > this.maxX then
set this.maxX = line_endX[polygonList.iterator]
endif
if line_startY[polygonList.iterator] < this.minY then
set this.minY = line_startY[polygonList.iterator]
elseif line_startY[polygonList.iterator] > this.maxY then
set this.maxY = line_startY[polygonList.iterator]
endif
if line_endY[polygonList.iterator] < this.minY then
set this.minY = line_endY[polygonList.iterator]
elseif line_endY[polygonList.iterator] > this.maxY then
set this.maxY = line_endY[polygonList.iterator]
endif
endloop
endif
endmethod
public method rotateAroundPointDeg takes real angle, real originX, real originY returns nothing
call this.rotateAroundPoint(angle*DEGTORAD, originX, originY)
endmethod
public method rotate takes real angle returns nothing
call this.rotateAroundPoint(angle, this.centerX, this.centerY)
endmethod
public method rotateDeg takes real angle returns nothing
call this.rotate(angle*DEGTORAD)
endmethod
public method setRotation takes real angle returns nothing
call this.rotate(angle - this.rotation)
endmethod
public method setRotationDeg takes real angle returns nothing
call this.setRotation(angle*DEGTORAD)
endmethod
public method rotateAsDefault takes real angle returns nothing
call this.rotate(angle)
set this.rotation = 0
endmethod
public method rotateAsDefaultDeg takes real angle returns nothing
call this.rotateAsDefault(angle*DEGTORAD)
endmethod
public method setRotationAsDefault takes real angle returns nothing
call this.rotateAsDefault(angle - this.rotation)
endmethod
public method setRotationAsDefaultDeg takes real angle returns nothing
call this.setRotationAsDefault(angle*DEGTORAD)
endmethod
public method getRotation takes nothing returns real
return this.rotation
endmethod
public method getRotationDeg takes nothing returns real
return this.rotation*RADTODEG
endmethod
public method scale takes real scale returns nothing
set this.scaling = this.scaling * scale
set this.minX = this.centerX - (this.minX - this.centerX)*scale
set this.minY = this.centerY - (this.minY - this.centerY)*scale
set this.maxX = this.centerX - (this.maxX - this.centerX)*scale
set this.maxY = this.centerY - (this.maxY - this.centerY)*scale
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set line_startX[polygonList.iterator] = this.centerX - (line_startX[polygonList.iterator] - this.centerX)*scale
set line_startY[polygonList.iterator] = this.centerX - (line_startY[polygonList.iterator] - this.centerY)*scale
set line_endX[polygonList.iterator] = this.centerX - (line_endX[polygonList.iterator] - this.centerX)*scale
set line_endY[polygonList.iterator] = this.centerX - (line_endY[polygonList.iterator] - this.centerY)*scale
endloop
endif
endmethod
public method setScale takes real scale returns nothing
call this.scale(scale / this.scaling)
endmethod
public method scaleAsDefault takes real scale returns nothing
call this.scale(scale)
set this.scaling = 1
endmethod
public method setScaleAsDefault takes real scale returns nothing
call this.scaleAsDefault(scale / this.scaling)
endmethod
public method getScale takes nothing returns real
return this.scaling
endmethod
//Point in Polygon iteration variables.
private static integer pip_hits
private static real pip_leftX
private static real pip_testX
private static real pip_testY
private method containsPointIteration takes real px, real py returns nothing
if line_endY[polygonList.iterator] == line_startY[polygonList.iterator] then
return
endif
if line_endX[polygonList.iterator] < line_startX[polygonList.iterator] then
if px >= line_startX[polygonList.iterator] then
return
endif
set pip_leftX = line_endX[polygonList.iterator]
else
if px >= line_endX[polygonList.iterator] then
return
endif
set pip_leftX = line_startX[polygonList.iterator]
endif
if line_endY[polygonList.iterator] < line_startY[polygonList.iterator] then
if py < line_endY[polygonList.iterator] or py >= line_startY[polygonList.iterator] then
return
endif
if (px < pip_leftX) then
set pip_hits = pip_hits +1
return
endif
set pip_testX = px - line_endX[polygonList.iterator]
set pip_testY = py - line_endY[polygonList.iterator]
else
if py < line_startY[polygonList.iterator] or py >= line_endY[polygonList.iterator] then
return
endif
if px < pip_leftX then
set pip_hits = pip_hits +1
return
endif
set pip_testX = px - line_startX[polygonList.iterator]
set pip_testY = py - line_startY[polygonList.iterator]
endif
if pip_testX < (pip_testY / (line_startY[polygonList.iterator] - line_endY[polygonList.iterator]) * (line_startX[polygonList.iterator] - line_endX[polygonList.iterator])) then
set pip_hits = pip_hits +1
endif
endmethod
public method containsPoint takes real px, real py returns boolean
set pip_hits = 0
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
call this.containsPointIteration(px, py)
endloop
endif
return pip_hits - pip_hits/2*2 != 0
endmethod
public method getSurface takes nothing returns real
//Method 1: All polygons must be clockwise.
//Method 2: All polygons must be clockwise.
/* Method 1:
local real area = 0
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set area = area + (line_startX[polygonList.iterator] + line_endX[polygonList.iterator]) * (line_startY[polygonList.iterator] - line_endY[polygonList.iterator])
endloop
endif
return RAbsBJ(area/2)
*/
/* Method 2:
*/
local real area = 0
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set area = area + line_endX[polygonList.iterator] * line_startY[polygonList.iterator] - line_startX[polygonList.iterator] * line_endY[polygonList.iterator]
endloop
endif
return RAbsBJ(area/2)
endmethod
public method clone takes nothing returns Polygon
local Polygon poly = Polygon.create()
local integer id
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set id = polygonList.insertIndex(poly, 0)
set line_startX[id] = line_startX[polygonList.iterator]
set line_startY[id] = line_startY[polygonList.iterator]
set line_endX[id] = line_endX[polygonList.iterator]
set line_endY[id] = line_endY[polygonList.iterator]
endloop
endif
set poly.numberOfLines = this.numberOfLines
set poly.minX = this.minX
set poly.minY = this.minY
set poly.maxX = this.maxX
set poly.maxY = this.maxY
set poly.centerX = this.centerX
set poly.centerY = this.centerY
set poly.scaling = this.scaling
return poly
endmethod
public static integer pointCount
public static real array pointX
public static real array pointY
private method getLineIntersection takes integer i1, integer i2 returns boolean
local real s1_x
local real s1_y
local real s2_x
local real s2_y
local real s
local real t
local real a
set s1_x = line_endX[i1] - line_startX[i1]
set s1_y = line_endY[i1] - line_startY[i1]
set s2_x = line_endX[i2] - line_startX[i2]
set s2_y = line_endY[i2] - line_startY[i2]
set a = -s2_x * s1_y + s1_x * s2_y
if a == 0 then
return false
endif
set s = (-s1_y * (line_startX[i1] - line_startX[i2]) + s1_x * (line_startY[i1] - line_startY[i2])) / a
set t = ( s2_x * (line_startY[i1] - line_startY[i2]) - s2_y * (line_startX[i1] - line_startX[i2])) / a
if s >= 0 and s <= 1 and t >= 0 and t <= 1 then
// Collision detected
set pointX[pointCount] = line_startX[i1] + t*s1_x
set pointY[pointCount] = line_startY[i1] + t*s1_y
set pointCount = pointCount +1
return true
endif
return false
endmethod
public method getIntersectionPoints takes Polygon p returns nothing
local integer i1
local integer i2
set pointCount = 0
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set i1 = polygonList.iterator
call polygonList.prepareIterator(p)
loop
exitwhen not polygonList.next(p)
set i2 = polygonList.iterator
call getLineIntersection(i1, i2)
endloop
endloop
endif
endmethod
public method toString takes nothing returns string
local string result = ""
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set result = result + ", ["+Coordinates2String(line_startX[polygonList.iterator], line_startY[polygonList.iterator])+", "+Coordinates2String(line_endX[polygonList.iterator], line_endY[polygonList.iterator])+"]"
endloop
endif
return "[ "+SubString(result, 2, StringLength(result))+" ]"
endmethod
//Test method
public method generateLightnings takes string model, real duration returns nothing
local lightning l
if polygonList.prepareIterator(this) then
loop
exitwhen not polygonList.next(this)
set l = AddLightning(model, true, line_startX[polygonList.iterator], line_startY[polygonList.iterator], line_endX[polygonList.iterator], line_endY[polygonList.iterator])
call TimedL.P2P(l, duration, 100, 100)
set l = null
endloop
endif
endmethod
//Test method
public static method createStar takes integer numberOfPoints, real centerX, real centerY, real outerRadius, real innerRadius returns Polygon
local Polygon this = Polygon.create()
local real angleStep = TAU/numberOfPoints/2
local integer i = 0
local real angle = 0
local real startX
local real startY
local real endX
local real endY
set startX = centerX + innerRadius * Cos(-angleStep)
set startY = centerY + innerRadius * Sin(-angleStep)
loop
exitwhen i >= numberOfPoints
set endX = centerX + outerRadius * Cos(angle)
set endY = centerY + outerRadius * Sin(angle)
call this.addLine(startX, startY, endX, endY)
set startX = endX
set startY = endY
set angle = angle + angleStep
set endX = centerX + innerRadius * Cos(angle)
set endY = centerY + innerRadius * Sin(angle)
call this.addLine(startX, startY, endX, endY)
set startX = endX
set startY = endY
set angle = angle + angleStep
set i = i +1
endloop
return this
endmethod
//Test method
public static method createCircle takes integer numberOfVertices, real centerX, real centerY, real radius returns Polygon
local Polygon this = Polygon.create()
local real angleStep = TAU/numberOfVertices
local integer i = 0
local real angle = 0
local real startX
local real startY
local real endX
local real endY
set startX = centerX + radius * Cos(-angleStep)
set startY = centerX + radius * Sin(-angleStep)
loop
exitwhen i >= numberOfVertices
set endX = centerX + radius * Cos(angle)
set endY = centerY + radius * Sin(angle)
call this.addLine(startX, startY, endX, endY)
set startX = endX
set startY = endY
set angle = angle + angleStep
set i = i +1
endloop
return this
endmethod
endstruct
endlibrary
library Real2D
struct Coord extends array
private static integer count = 0
private thistype recycle
real x
real y
static method create takes real xx, real yy returns thistype
local thistype this = thistype(0).recycle
if ( this == 0 ) then
set count = count + 1
set this = count
else
set thistype(0).recycle = recycle
endif
set x = xx
set y = yy
return this
endmethod
static method createFromLoc takes location l returns thistype
return create(GetLocationX(l), GetLocationY(l))
endmethod
static method operator[] takes thistype c returns thistype
return create(c.x, c.y)
endmethod
method destroy takes nothing returns nothing
set recycle = thistype(0).recycle
set thistype(0).recycle = this
endmethod
method setXY takes real xx, real yy returns nothing
set x = xx
set y = yy
endmethod
method operator== takes thistype c returns boolean
return ( x == c.x ) and ( y == c.y )
endmethod
method project takes real dist, real angle returns thistype
set x = x + dist * Cos(angle * bj_DEGTORAD)
set y = y + dist * Sin(angle * bj_DEGTORAD)
return this
endmethod
method offset takes real xx, real yy returns thistype
set x = x + xx
set y = y + yy
return this
endmethod
method loc takes nothing returns location
return Location(x, y)
endmethod
endstruct
struct Size extends array
private static integer count = 0
private thistype recycle
real width
real height
static method create takes real ww, real hh returns thistype
local thistype this = thistype(0).recycle
if ( this == 0 ) then
set count = count + 1
set this = count
else
set thistype(0).recycle = recycle
endif
set width = ww
set height = hh
return this
endmethod
static method operator[] takes thistype s returns thistype
return create(s.width, s.height)
endmethod
method destroy takes nothing returns nothing
set recycle = thistype(0).recycle
set thistype(0).recycle = this
endmethod
method setWH takes real ww, real hh returns nothing
set width = ww
set height = hh
endmethod
method operator== takes thistype s returns boolean
return ( width == s.width ) and ( height == s.height )
endmethod
method incTo takes thistype s returns thistype
if ( s.width > width ) then
set width = s.width
endif
if ( s.height > height ) then
set height = s.height
endif
return this
endmethod
method decTo takes thistype s returns thistype
if ( s.width < width ) then
set width = s.width
endif
if ( s.height < height ) then
set height = s.height
endif
return this
endmethod
method incBy takes real dw, real dh returns thistype
set width = width + dw
set height = height + dh
return this
endmethod
method decBy takes real dw, real dh returns thistype
call incBy(-dw, -dh)
return this
endmethod
method scale takes real wscale, real hscale returns thistype
set width = width * wscale
set height = height * hscale
return this
endmethod
endstruct
endlibrary
/******************************************************************************
*
* TIMED LIGHTNINGS by Maker v1.0.1.1
*
* Allows the creation of lightnings with expiration timer.
* Supports:
* o Fading lightnings in and out
* o Attaching to units
* o Attaching to points
* o Linear movement in x-, y- and z-axes
*
*
* Methods
*
* P2U
* From a static point attached to a unit
* static method P2U takes lightning l, unit t, real time, real x1, real y1, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, target unit, duration, origin x, origin y, origin z, end z
*
*
* P2UEx
* From a moving point attached to a unit
* static method P2UEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, target unit, duration, target z, origin start x, origin start y, origin start z, origin end x, origin end y, origin end z
*
* U2P
* From attached to a unit to a static point
* static method U2P takes lightning l, unit s, real t, real x1, real y1, real x2, real y2, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, duration, origin x, origin y, point x , point y, source z, point z
*
* U2PEx
* From attached to a unit to a moving point
* static method U2PEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, duration, source z, point start x, point start y, point start z, point end x, point end y, point end z
*
* U2U
* From attached to a unit to attached to a unit
* static method U2U takes lightning l, unit s, unit t, real time, real z1, real z2, real startAlpha, real endAlpha returns nothing
*
* The lightning, source unit, target unit, duration, source z, target z
*
* P2P
* From a static point to a static point
* static method P2P takes lightning l, real t, real startAlpha, real endAlpha returns nothing
*
* The lightning, duration
*
* P2PEx
* From a moving point to a moving point
* static method P2PEx takes lightning l, real t, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4, real startAlpha, real endAlpha returns nothing
*
* The lightning, duration, origin start x, origin start y, origin start z, origin end x, origin end y, origin end z, target start x, target start y, target start z, target end x, target end y, target end z
*
*
* Alpha values are between 1 and 0. 1 is fully visible, 0 is transparent.
*
*******************************************************************************/
library TimedLightnings
globals
private constant real TO = 0.03125000 // Update interval
private integer CT = 0 // Lightning count
private timer TMR = CreateTimer()
private location loc = Location(0,0)
endglobals
struct TimedL extends array
lightning l
real av // aplha value
real da // transparency change rate
real x1
real x2
real y1
real y2
real z1
real z2
real dx1
real dy1
real dz1
real dx2
real dy2
real dz2
unit s // source
unit t // target
integer time // how many ticks, time
integer next // next node
integer prev // previous node
boolean moves
private static integer rlast = 0 // previous created
private static thistype first // first node
private static integer ic = 0
private static integer ir = 0
private thistype rn
private static thistype dat
private static thistype dat2
private static thistype dat3
private static method destroyL takes nothing returns nothing
/*-Link previous node with next one-*/
set dat3 = dat2.prev
set dat3.next = dat2.next
/*-----Set new last created node----*/
if dat2 == rlast then
set rlast = dat3
endif
/*-Link next node with previous one-*/
set dat3 = dat2.next
set dat3.prev = dat2.prev
/*--------Set new first node--------*/
if dat2 == first then
set first = dat3
endif
call DestroyLightning(dat2.l)
set CT = CT - 1
if CT == 0 then
call PauseTimer(TMR)
endif
set dat2.rn=ir
set ir=dat2
endmethod
private static method looping takes nothing returns nothing
local real z1
local real z2
set dat = first
loop
set z1 = 0
set z2 = 0
set dat.time = dat.time - 1
if dat.da != 0 then
set dat.av = dat.av - dat.da
call SetLightningColor(dat.l, 1, 1, 1, dat.av)
endif
if dat.s == null then
if dat.dx1 != 0 then
set dat.x1 = dat.x1 + dat.dx1
endif
if dat.dy1 != 0 then
set dat.y1 = dat.y1 + dat.dy1
endif
if dat.dz1 != 0 then
set dat.z1 = dat.z1 + dat.dz1
endif
else
set dat.x1 = GetUnitX(dat.s)
set dat.y1 = GetUnitY(dat.s)
set z1 = GetUnitFlyHeight(dat.s)
endif
if dat.t == null then
if dat.dx2 != 0 then
set dat.x2 = dat.x2 + dat.dx2
endif
if dat.dy2 != 0 then
set dat.y2 = dat.y2 + dat.dy2
endif
if dat.dz2 != 0 then
set dat.z2 = dat.z2 + dat.dz2
endif
else
set dat.x2 = GetUnitX(dat.t)
set dat.y2 = GetUnitY(dat.t)
set z2 = GetUnitFlyHeight(dat.t)
endif
if dat.moves then
call MoveLocation(loc, dat.x1, dat.y1)
set z1 = GetLocationZ(loc) + dat.z1 + z1
call MoveLocation(loc, dat.x2, dat.y2)
set z2 = GetLocationZ(loc) + dat.z2 + z2
call MoveLightningEx(dat.l, true, dat.x1, dat.y1, z1, dat.x2, dat.y2, z2)
endif
if dat.time == 0 then
set dat2 = dat
set dat = dat.next
call destroyL()
else
set dat = dat.next
endif
exitwhen dat == 0
endloop
endmethod
private static method InitAdd takes nothing returns nothing
/* Add node to list, make this the last on list */
if rlast != 0 then
set dat2 = rlast
set dat2.next = dat
endif
/* Link this with previous node */
set dat.prev = rlast
/* Make this the last created node */
set rlast = dat
set CT = CT + 1
if CT == 1 then
/* Make this the first node */
set first = dat
call TimerStart(TMR, TO, true, function thistype.looping)
endif
endmethod
private static method Recycle takes nothing returns nothing
if 0==ir then
set ic=ic+1
set dat=ic
else
set dat=ir
set ir=dat.rn
endif
endmethod
static method P2U takes lightning l, unit t, real time, real x1, real y1, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .x1 = x1
set .y1 = y1
set .z1 = z1
set .z2 = z2
set .s = null
set .t = t
set .next = 0 // Nodes are added to the end of the list, there is no next node
set .l = l
set .time = R2I(time/TO) // Calculates how many loops does the lightning lasts
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/time // Transparency change speed
set .moves = true
call InitAdd()
endmethod
static method U2P takes lightning l, unit s, real t, real x1, real y1, real x2, real y2, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .x1 = x1
set .y1 = y1
set .x2 = x2
set .y2 = y2
set .z1 = z1
set .z2 = z2
set .s = s
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/t
set .moves = true
call InitAdd()
endmethod
static method U2U takes lightning l, unit s, unit t, real time, real z1, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .z1 = z1
set .z2 = z2
set .s = s
set .t = t
set .next = 0
set .l = l
set .time = R2I(time/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/time
set .moves = true
call InitAdd()
endmethod
static method P2P takes lightning l, real t, real startAlpha, real endAlpha returns nothing
local thistype this
call Recycle()
set this = dat
set .s = null
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*TO/t
set .moves = false
call InitAdd()
endmethod
static method P2UEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x1 = x1
set dx1 = (x2-x1)*n
set .y1 = y1
set dy1 = (y2-y1)*n
set .z1 = z1
set dz1 = (z2-z1)*n
set .z2 = zu
set .s = null
set .t = a
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call InitAdd()
endmethod
static method U2PEx takes lightning l, unit a, real t, real zu, real x1, real y1, real z1, real x2, real y2, real z2, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x2 = x1
set .dx2 = (x2-x1)*n
set .y2 = y1
set .dy2 = (y2-y1)*n
set .z2 = z1
set .dz2 = (z2-z1)*n
set .z1 = zu
set .s = a
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call thistype.InitAdd()
endmethod
static method P2PEx takes lightning l, real t, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4, real startAlpha, real endAlpha returns nothing
local thistype this
local real n = TO/t
call Recycle()
set this = dat
set .x1 = x1
set .x2 = x3
set .y1 = y1
set .y2 = y3
set .z1 = z1
set .z2 = z3
set .dx1 = (x2-x1)*n
set .dy1 = (y2-y1)*n
set .dz1 = (z2-z1)*n
set .dx2 = (x4-x3)*n
set .dy2 = (y4-y3)*n
set .dz2 = (z4-z3)*n
set .s = null
set .t = null
set .next = 0
set .l = l
set .time = R2I(t/TO)
set .av = startAlpha
set .da = (startAlpha-endAlpha)*n
set .moves = true
call InitAdd()
endmethod
endstruct
endlibrary
globals
integer udg_CMS_DUMMY_UNITTYPE
integer udg_CMS_MISSILE_UNITTYPE
integer udg_CMS_ABILITY_MORPH
integer udg_CMS_ABILITY_GHOST
integer udg_CMS_COLLISIONTYPE_NONE
integer udg_CMS_COLLISIONTYPE_SIMPLE
integer udg_CMS_COLLISIONTYPE_CIRCLE
integer udg_CMS_COLLISIONTYPE_RECTANGLE
integer udg_CMS_TARGETTYPE_NONE
integer udg_CMS_TARGETTYPE_UNIT
integer udg_CMS_TARGETTYPE_LOCATION
integer udg_CMS_Index
integer udg_CMS_LoopIndex
integer udg_CMS_Amount
real udg_CMS_Event_Missile_Collided_D
real udg_CMS_Event_Missile_Collided_I
real udg_CMS_Event_Missile_Collided_U
real udg_CMS_Event_Missile_Created
real udg_CMS_Event_Missile_Destroyed
boolean udg_CMS_ValidTarget
destructable udg_CMS_Collided_Dest
item udg_CMS_Collided_Item
unit udg_CMS_Collided_Unit
real udg_CMS_StartingAcceleration
real udg_CMS_StartingAngle
boolean udg_CMS_StartingDefaultValues
real udg_CMS_StartingHeight
location udg_CMS_StartingLocation
boolean udg_CMS_StartingLocust
boolean udg_CMS_StartingMissile
real udg_CMS_StartingPitch
boolean udg_CMS_StartingSource
boolean udg_CMS_StartingSourceFilter
real udg_CMS_StartingSpeed
boolean udg_CMS_StartingType
real array udg_CMS_Param_Collision_Cooldown
boolean array udg_CMS_Param_Collision_Dest
real array udg_CMS_Param_Collision_Height
real array udg_CMS_Param_Collision_Height_Inc
boolean array udg_CMS_Param_Collision_Item
integer array udg_CMS_Param_Collision_Type
boolean array udg_CMS_Param_Collision_Unit
real array udg_CMS_Param_Collision_Width
real array udg_CMS_Param_Collision_Width_Inc
real array udg_CMS_Param_Duration
real array udg_CMS_Param_Distance
effect array udg_CMS_Param_Effect
real array udg_CMS_Param_Gravity
boolean array udg_CMS_Param_Index
boolean array udg_CMS_Param_IsAUnit
boolean array udg_CMS_Param_IsDestroyed
boolean array udg_CMS_Param_IsFlying
boolean array udg_CMS_Param_IsHoming
real array udg_CMS_Param_MaxDuration
real array udg_CMS_Param_MaxDistance
unit array udg_CMS_Param_Missile
unit array udg_CMS_Param_Source
integer array udg_CMS_Param_Subtype
integer array udg_CMS_Param_Target_Type
unit array udg_CMS_Param_Target_Unit
location array udg_CMS_Param_Target_Location
real array udg_CMS_Param_TurnRate
integer array udg_CMS_Param_Type
real array udg_CMS_Param_WalkingHeight
endglobals
//! textmacro CMS_COLLISION_FUNCTIONS
//Units
function CMS_Collide_Unit takes unit enumUnit returns nothing
local real difference
local timer t
local integer id
local integer collidedId
local integer missileId
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return
endif
//If the collided unit has locust then don't do anything.
if GetUnitAbilityLevel(enumUnit, 'Aloc') > 0 then
return
endif
set udg_CMS_Collided_Unit = enumUnit
set collidedId = GetHandleId(udg_CMS_Collided_Unit)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetUnitFlyHeight(udg_CMS_Collided_Unit) + GetCoordinateZ(GetUnitX(udg_CMS_Collided_Unit), GetUnitY(udg_CMS_Collided_Unit)) + 50
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_U = -1
set udg_CMS_Event_Missile_Collided_U = 0
set udg_CMS_Event_Missile_Collided_U = -1
set udg_CMS_Event_Missile_Collided_U = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
endfunction
//SIMPLE
function CMS_Collide_Dest_Simple takes nothing returns boolean
local real difference
local timer t
local integer id
local integer collidedId
local integer missileId
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Dest = GetEnumDestructable()
set collidedId = GetHandleId(udg_CMS_Collided_Dest)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(GetDestructableX(udg_CMS_Collided_Dest), GetDestructableY(udg_CMS_Collided_Dest))
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = 0
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
function CMS_Collide_Item_Simple takes nothing returns boolean
local real difference
local integer collidedId
local integer missileId
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Item = GetEnumItem()
set collidedId = GetHandleId(udg_CMS_Collided_Item)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(GetItemX(udg_CMS_Collided_Item), GetItemY(udg_CMS_Collided_Item))
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = 0
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
//CIRCLE
function CMS_Collide_Dest_Circle takes nothing returns boolean
local real difference
local timer t
local integer id
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Dest = GetEnumDestructable()
set x = GetDestructableX(udg_CMS_Collided_Dest)
set y = GetDestructableY(udg_CMS_Collided_Dest)
if DistanceBetweenCoordinates(udg_CMS_X, udg_CMS_Y, x, y) > udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Dest)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = 0
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
function CMS_Collide_Item_Circle takes nothing returns boolean
local real difference
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Item = GetEnumItem()
set x = GetItemX(udg_CMS_Collided_Item)
set y = GetItemY(udg_CMS_Collided_Item)
if DistanceBetweenCoordinates(udg_CMS_X, udg_CMS_Y, x, y) > udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Item)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = 0
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
//RECTANGLE
function CMS_Collide_Dest_Rectangle takes nothing returns boolean
local real difference
local timer t
local integer id
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Dest = GetEnumDestructable()
set x = GetDestructableX(udg_CMS_Collided_Dest)
set y = GetDestructableY(udg_CMS_Collided_Dest)
if not IsPointInAngledRectangleRad(udg_CMS_RX, udg_CMS_RY, udg_CMS_RW, udg_CMS_RH, udg_CMS_RA, x, y) then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Dest)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = 0
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
function CMS_Collide_Item_Rectangle takes nothing returns boolean
local real difference
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Item = GetEnumItem()
set x = GetItemX(udg_CMS_Collided_Item)
set y = GetItemY(udg_CMS_Collided_Item)
if not IsPointInAngledRectangleRad(udg_CMS_RX, udg_CMS_RY, udg_CMS_RW, udg_CMS_RH, udg_CMS_RA, x, y) then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Item)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = 0
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
//POLYGON
function CMS_Collide_Dest_Polygon takes nothing returns boolean
local real difference
local timer t
local integer id
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Dest = GetEnumDestructable()
set x = GetDestructableX(udg_CMS_Collided_Dest)
set y = GetDestructableY(udg_CMS_Collided_Dest)
if not udg_CMS_Param_Polygon[udg_CMS_LoopIndex].containsPoint(x, y) then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Dest)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = 0
set udg_CMS_Event_Missile_Collided_D = -1
set udg_CMS_Event_Missile_Collided_D = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
function CMS_Collide_Item_Polygon takes nothing returns boolean
local real difference
local integer collidedId
local integer missileId
local real x
local real y
// if the missile trigger told the system to stop the collision checks
if udg_CMS_StopCollision then
return false
endif
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return false
endif
set udg_CMS_Collided_Item = GetEnumItem()
set x = GetItemX(udg_CMS_Collided_Item)
set y = GetItemY(udg_CMS_Collided_Item)
if not udg_CMS_Param_Polygon[udg_CMS_LoopIndex].containsPoint(x, y) then
return false
endif
set collidedId = GetHandleId(udg_CMS_Collided_Item)
set missileId = GetHandleId(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
//If the target is not targetable by this missile then don't do anything.
if LoadReal(udg_CMS_HASHTABLE, missileId, collidedId) > udg_CMS_GameTime - udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] then
return false
endif
//Check if the target collides in height.
if udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] > 0 then
set difference = GetCoordinateZ(x, y)
set difference = difference - (GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y))
if difference > udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] or difference < -udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] then
return false
endif
endif
//Call the event.
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = 0
set udg_CMS_Event_Missile_Collided_I = -1
set udg_CMS_Event_Missile_Collided_I = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//The unit is a valid target.
if udg_CMS_ValidTarget then
set udg_CMS_ValidTarget = false
//Make the unit untargetable for a set amount of time.
if udg_CMS_Param_Collision_Cooldown[udg_CMS_LoopIndex] > udg_CMS_INTERVAL then
call SaveReal(udg_CMS_HASHTABLE, missileId, collidedId, udg_CMS_GameTime)
endif
endif
return false
endfunction
// Terrain
function CMS_Collide_Terrain takes nothing returns nothing
//If the missile is destroyed then don't do anything.
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
return
endif
// collision with terrain by default destroys the missile, turning this off should be done by a trigger being invoked by the following event
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
//Call the event.
set udg_CMS_Event_Missile_Collided_T = -1
set udg_CMS_Event_Missile_Collided_T = 0
set udg_CMS_Event_Missile_Collided_T = -1
set udg_CMS_Event_Missile_Collided_T = udg_CMS_Param_Type[udg_CMS_LoopIndex]
endfunction
//! endtextmacro
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Wietlol's Custom Missile System 1.4.1 11/8/2024
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Description:
// This system is made to create custom missiles.
// It is designed to have 3D movement, events on collision, de-locusted missiles, different collision detections,
// targetable missiles, units as missiles, full missile control, collisions with units, items, destructables, and terrain,
// missiles that can hit targets multiple times, and with GUI support.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// How to install:
// See the guide on the Hive Workshop page of this system.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Feature list:
// This system:
// - allows you to create missiles with
// - 3d movement visualizations.
// - 3d movement calculations.
// - 3d acceleration.
// - collision detection with all widgets with various algorithms.
// - homing behavior.
// - a unique index for arrays with your custom data.
// - allows the creation of missiles from existing units (for usages like a dash or knockback).
// - has on-collide events for units, items, destructables, and terrain.
// - can run a relatively large amount of missiles.
// - allows missile to hit the same target multiple times with a configurable delay as "Collision_Cooldown".
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function List:
// function CMS_CreateMissile takes unit source, integer typeId, unit whichMissile, boolean importDefaultValues returns integer
// Creates a new missile using the starting variables and the given parameters.
//
// function CMS_CreateMissileEx takes nothing returns integer
// Creates a new missile only using the starting variables.
// This function is recommended for GUI users.
//
// function CMS_DestroyMissile takes integer index returns boolean
// Immediately destroys the missile of the given index.
//
// function CMS_GetIndex takes unit whichMissile returns integer
// Returns the index of a missile.
// This can be used in combination with "CMS_DestroyMissile()".
//
// function CMS_SetDefaultVariables takes integer index returns nothing
// Sets all the param variables to their default value.
//
// function CMS_GetSpeedPerSecond takes integer index returns real
// Returns the speed per second.
// function CMS_SetSpeedPerSecond takes integer index, real speed returns nothing
// Sets the speed per second.
//
// function CMS_GetAngleDeg takes integer index returns real
// Returns the angle in degrees.
// function CMS_SetAngleDeg takes integer index, real angle returns nothing
// Sets the angle in degrees.
//
// function CMS_GetPitchDeg takes integer index returns real
// Returns the pitch in degrees.
// function CMS_SetPitchDeg takes integer index, real pitch returns nothing
// Sets the pitch in degrees.
//
// function CMS_GetAccelerationPerSecond takes integer index returns real
// Returns the acceleration per second.
// function CMS_SetAccelerationPerSecond takes integer index, real acc returns nothing
// Sets the acceleration per second.
//
// function CMS_ComputeRequiredPitch takes real velocity, real gravity, real distance returns real
// Computes the pitch required to hit a target point
// @param velocity the projectile's velocity in units per second
// @param gravity the projectile's acceleration to the ground in units per second per second
// @param distance the distance that the projectile should travel
// @return the pitch required to hit the target in degrees
//
// function CMS_ComputeRandomPointInRange takes location point, real radius returns location
// Computes a random point in a circle with uniform distribution
// @param point the center point of the circle
// @param radius the radius of the circle
// @returns a random point in the circle
// @source https://stackoverflow.com/a/50746409/2764866
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Credits:
// * To Vexorian and Tickles
// - For Vexorian's dummy model that is used as the missile model which is editted by Tickles.
// * To Xonok
// - For showing me his missile system on which this structure is designed.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Changelog:
// 1.4.1 - 11/8/2024
// - Fixed example abilities and added more examples.
// - Added utility functions to do some calculations
// - Added collision with terrain
// - Updated for new World Editor features (such as GUI variables)
// - Added tests and showcases
//
// 1.4 - 15/12/2015 - Additional features (detection, optimized events, acceleration).
// - Replaced locations with coordinates.
// - Removed "_Param" prefixes from variables that are not array variables of the missiles.
// - Added Acceleration.
// - Added event calls with udg_CMS_Param_Type[] as value.
// - Trigger calls for each X missiles to prevent op limit.
// - Optmized collision cooldown.
// - Added Rectangular collision detection.
// - Added Polygon collision detection.
// - Added booleans to check for Unit, Destructable and Item separately.
//
// 1.3.3 - 6/12/2015 - Fixed bugs
// - Replaced widget handles in hashtable with their handle index to prevent timer/widget leak
// when the target or missile is removed during the timer.
// - Fixed a bug where the missiles didn't start at their StartingHeight when a new missile was created.
// - Replaced some GetWidgetX/Y() with GetUnitX/Y().
// - Updated BasicFunctions usage.
// - Removed "_Param" from starting variables because of GUI variable length limit.
// - Added StartingDefaultValues to import default values for GUI usage. (Default true.)
// - Added CMS_CreateMissileEx(source, missile, typeId, importDefaultValues).
//
// 1.3.2 - 14/11/2015 - Reviewed system.
// - Added final starting parameters.
// - Replaced GetWidgetX()/GetWidgetY() with GetUnitX()/GetUnitY().
// - Replaced KillUnit() with UnitApplyTimedLife().
//
// 1.3 - 20/05/2015 - Redesigned system structure.
// - Placed calculations inside functions with a cache.
// - Removed calculations from the interval function.
// - Finished system's concept.
// - Removed the missile acceleration option.
//
// 1.2 - 15/05/2015 - Rewritten System
// - Rewrote the data structure into arrays only.
// - Ripped stuff that is not necessary.
// - Uses locust bugged units so the missiles are targetable but unselectable.
// - Uses better getter and setter.
// - Uses library and got rid of triggers.
//
// 1.1 - 26/03/2015 - Collision Fixes
// - Fixed map bounds check.
// - Added Ghost ability.
// - Added CMS_Param_Remove_Collision.
//
// 1.0 - 01/03/2015 - First official release.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Known bugs:
// - None
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CMS System
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library CustomMissileSystem uses PositionFunctions, TimeFunctions
//These globals are not needed in GUI so they are implemented inside the system itself.
globals
integer udg_CMS_COLLISIONTYPE_POLYGON
Polygon array udg_CMS_Param_Polygon
hashtable udg_CMS_HASHTABLE = InitHashtable()
group udg_CMS_GROUP = CreateGroup()
timer udg_CMS_TIMER = CreateTimer()
trigger udg_CMS_TRIGGER = CreateTrigger()
integer udg_CMS_LOOP_MAX = 100
//Missile positions in interval function.
real udg_CMS_X = 0
real udg_CMS_Y = 0
real udg_CMS_X_OLD = 0
real udg_CMS_Y_OLD = 0
//Rectangular collision detection.
real udg_CMS_RX = 0
real udg_CMS_RY = 0
real udg_CMS_RW = 0
real udg_CMS_RH = 0
real udg_CMS_RA = 0
real udg_CMS_GameTime = 0
integer udg_CMS_NextIndex = 0
boolean array udg_CMS_Index_Occupied
integer array udg_CMS_MissileIndex
real array udg_CMS_Param_OriginalHeight
real array udg_CMS_Param_V_X
real array udg_CMS_Param_V_Y
real array udg_CMS_Param_V_Z
real array udg_CMS_Param_A_X
real array udg_CMS_Param_A_Y
real array udg_CMS_Param_A_Z
integer udg_CMS_IntervalCount
real array udg_CMS_Cache_V_H
integer array udg_CMS_Cache_V_H_Index
real array udg_CMS_Cache_A_H
integer array udg_CMS_Cache_A_H_Index
real array udg_CMS_Cache_Angle
integer array udg_CMS_Cache_Angle_Index
real array udg_CMS_Cache_Pitch
integer array udg_CMS_Cache_Pitch_Index
real array udg_CMS_Cache_Speed
integer array udg_CMS_Cache_Speed_Index
real array udg_CMS_Cache_Acceleration
integer array udg_CMS_Cache_Acceleration_Index
endglobals
//Set the default variables of the params with the given index.
function CMS_SetDefaultVariables takes integer index returns nothing
set udg_CMS_Param_Collision_Cooldown[index] = 1.
set udg_CMS_Param_Collision_Dest[index] = false
set udg_CMS_Param_Collision_Height[index] = 0.
set udg_CMS_Param_Collision_Height_Inc[index] = 0.
set udg_CMS_Param_Collision_Item[index] = false
set udg_CMS_Param_Collision_Type[index] = 0
set udg_CMS_Param_Collision_Unit[index] = true
set udg_CMS_Param_Collision_Width[index] = 50.
set udg_CMS_Param_Collision_Width_Inc[index] = 0.
set udg_CMS_Param_Distance[index] = 0.
set udg_CMS_Param_Duration[index] = 0.
set udg_CMS_Param_Effect[index] = null
set udg_CMS_Param_Gravity[index] = 0.
set udg_CMS_Param_IsAUnit[index] = false
set udg_CMS_Param_IsDestroyed[index] = false
set udg_CMS_Param_IsFlying[index] = false
set udg_CMS_Param_IsHoming[index] = false
set udg_CMS_Param_MaxDistance[index] = 0.
set udg_CMS_Param_MaxDuration[index] = 0.
set udg_CMS_Param_Missile[index] = null
set udg_CMS_Param_OriginalHeight[index] = 0.
set udg_CMS_Param_Source[index] = null
set udg_CMS_Param_Subtype[index] = 0
set udg_CMS_Param_Target_Location[index] = null
set udg_CMS_Param_Target_Type[index] = 0
set udg_CMS_Param_Target_Unit[index] = null
set udg_CMS_Param_TurnRate[index] = 0.
set udg_CMS_Param_Type[index] = -1
set udg_CMS_Param_WalkingHeight[index] = 0
set udg_CMS_Param_A_X[index] = 0.
set udg_CMS_Param_A_Y[index] = 0.
set udg_CMS_Param_A_Z[index] = 0.
set udg_CMS_Param_V_X[index] = 0.
set udg_CMS_Param_V_Y[index] = 0.
set udg_CMS_Param_V_Z[index] = 0.
set udg_CMS_Cache_A_H[index] = 0.
set udg_CMS_Cache_V_H[index] = 0.
set udg_CMS_Cache_Acceleration[index] = 0.
set udg_CMS_Cache_Angle[index] = 0.
set udg_CMS_Cache_Pitch[index] = 0.
set udg_CMS_Cache_Speed[index] = 0.
set udg_CMS_Cache_V_H_Index[index] = 0
set udg_CMS_Cache_Acceleration_Index[index] = 0
set udg_CMS_Cache_Angle_Index[index] = 0
set udg_CMS_Cache_Pitch_Index[index] = 0
set udg_CMS_Cache_Speed_Index[index] = 0
endfunction
/**
* Computes the pitch required to hit a target point
* @param velocity the projectile's velocity in units per second
* @param gravity the projectile's acceleration to the ground in units per second per second
* @param distance the distance that the projectile should travel
* @return the pitch required to hit the target in degrees
*/
function CMS_ComputeRequiredPitch takes real velocity, real gravity, real distance returns real
local real v = velocity
local real g = gravity
local real R = distance
local real pitch = 0.5 * Asin((R*g) / (v*v)) * bj_RADTODEG
return pitch
endfunction
/**
* Computes a random point in a circle with uniform distribution
* @param point the center point of the circle
* @param radius the radius of the circle
* @returns a random point in the circle
* @source https://stackoverflow.com/a/50746409/2764866
*/
function CMS_ComputeRandomPointInRange takes location point, real radius returns location
local real distance = radius * SquareRoot(GetRandomReal(0, 1))
local real angle = GetRandomReal(0, TAU)
local real x = GetLocationX(point) + distance * Cos(angle)
local real y = GetLocationY(point) + distance * Sin(angle)
return Location(x, y)
endfunction
//Create a new unique id for the missile.
function CMS_CreateUniqueId takes nothing returns integer
loop
set udg_CMS_NextIndex = udg_CMS_NextIndex + 1
if udg_CMS_NextIndex > 8190 then
set udg_CMS_NextIndex = 1
endif
exitwhen not udg_CMS_Index_Occupied[udg_CMS_NextIndex]
endloop
set udg_CMS_Index_Occupied[udg_CMS_NextIndex] = true
return udg_CMS_NextIndex
endfunction
//Set the Z angle animation.
function CMS_SetUnitZAngle takes unit whichUnit, real angle returns nothing
//Can only be used on Vexorian's Dummy model or other models which use the same animations.
local integer i = GetUnitTypeId(whichUnit)
if i != udg_CMS_MISSILE_UNITTYPE and i != udg_CMS_DUMMY_UNITTYPE then
return
endif
set i = R2I(angle*RADTODEG + 90.5)
if i >= 180 then
set i = 179
elseif i < 0 then
set i = 0
endif
call SetUnitAnimationByIndex(whichUnit, i)
endfunction
//Get the missile index of the given unit.
function CMS_GetIndex takes unit whichMissile returns integer
local integer userData = GetUnitUserData(whichMissile)
if userData > 0 then
return udg_CMS_MissileIndex[userData]
else
return 0
endif
endfunction
//Set/get horizontal velocity.
//Only used internal.
function CMS_GetVH takes integer index returns real
local real V_H
if udg_CMS_Cache_V_H_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_V_H[index]
endif
set V_H = SquareRoot(udg_CMS_Param_V_X[index]*udg_CMS_Param_V_X[index] + udg_CMS_Param_V_Y[index]*udg_CMS_Param_V_Y[index])
set udg_CMS_Cache_V_H[index] = V_H
set udg_CMS_Cache_V_H_Index[index] = udg_CMS_IntervalCount
return V_H
endfunction
function CMS_SetVH takes integer index, real V_H returns nothing
local real V_H_Factor
if CMS_GetVH(index) == 0. then
set udg_CMS_Param_V_X[index] = 0.
set udg_CMS_Param_V_Y[index] = 0.
else
set V_H_Factor = V_H / udg_CMS_Cache_V_H[index]
set udg_CMS_Param_V_X[index] = udg_CMS_Param_V_X[index] * V_H_Factor
set udg_CMS_Param_V_Y[index] = udg_CMS_Param_V_Y[index] * V_H_Factor
endif
set udg_CMS_Cache_V_H[index] = V_H
set udg_CMS_Cache_V_H_Index[index] = udg_CMS_IntervalCount
endfunction
//Set/get 3D speed.
//BJ functions for speed per second and normal functions for speed per interval.
function CMS_GetSpeed takes integer index returns real
local real speed
if udg_CMS_Cache_Speed_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_Speed[index]
endif
set speed = SquareRoot(udg_CMS_Param_V_X[index]*udg_CMS_Param_V_X[index] + udg_CMS_Param_V_Y[index]*udg_CMS_Param_V_Y[index] + udg_CMS_Param_V_Z[index]*udg_CMS_Param_V_Z[index])
set udg_CMS_Cache_Speed[index] = speed
set udg_CMS_Cache_Speed_Index[index] = udg_CMS_IntervalCount
return speed
endfunction
function CMS_SetSpeed takes integer index, real speed returns nothing
local real factor
local real oldSpeed = CMS_GetSpeed(index)
if oldSpeed == 0. then
set udg_CMS_Param_V_X[index] = speed
else
set factor = speed/oldSpeed
set udg_CMS_Param_V_X[index] = udg_CMS_Param_V_X[index] * factor
set udg_CMS_Param_V_Y[index] = udg_CMS_Param_V_Y[index] * factor
set udg_CMS_Param_V_Z[index] = udg_CMS_Param_V_Z[index] * factor
endif
set udg_CMS_Cache_Speed[index] = speed
set udg_CMS_Cache_Speed_Index[index] = udg_CMS_IntervalCount
endfunction
function CMS_GetSpeedPerSecond takes integer index returns real
return CMS_GetSpeed(index) / udg_CMS_INTERVAL
endfunction
function CMS_SetSpeedPerSecond takes integer index, real speed returns nothing
call CMS_SetSpeed(index, speed * udg_CMS_INTERVAL)
endfunction
function CMS_GetAH takes integer index returns real
local real A_H
if udg_CMS_Cache_A_H_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_A_H[index]
endif
set A_H = SquareRoot(udg_CMS_Param_A_X[index]*udg_CMS_Param_A_X[index] + udg_CMS_Param_A_Y[index]*udg_CMS_Param_A_Y[index])
set udg_CMS_Cache_A_H[index] = A_H
set udg_CMS_Cache_A_H_Index[index] = udg_CMS_IntervalCount
return A_H
endfunction
function CMS_SetAH takes integer index, real A_H returns nothing
local real A_H_Factor
local real speed
if CMS_GetAH(index) == 0. then
set speed = CMS_GetSpeed(index)
if speed == 0. then
set udg_CMS_Param_A_X[index] = A_H
else
set udg_CMS_Param_A_X[index] = A_H * (udg_CMS_Param_V_X[index] / speed)
set udg_CMS_Param_A_Y[index] = A_H * (udg_CMS_Param_V_Y[index] / speed)
set udg_CMS_Param_A_Z[index] = A_H * (udg_CMS_Param_V_Z[index] / speed)
endif
else
set A_H_Factor = A_H / udg_CMS_Cache_A_H[index]
set udg_CMS_Param_A_X[index] = udg_CMS_Param_A_X[index] * A_H_Factor
set udg_CMS_Param_A_Y[index] = udg_CMS_Param_A_Y[index] * A_H_Factor
endif
set udg_CMS_Cache_A_H[index] = A_H
set udg_CMS_Cache_A_H_Index[index] = udg_CMS_IntervalCount
endfunction
//Set/get angle (facing angle).
function CMS_GetAngle takes integer index returns real
local real angle
if udg_CMS_Cache_Angle_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_Angle[index]
endif
if udg_CMS_Param_V_X[index] == 0. then
if udg_CMS_Param_V_Y[index] < 0. then
set angle = PI * 1.5
elseif udg_CMS_Param_V_Y[index] > 0. then
set angle = PI * 0.5
else
set angle = 0.
endif
else
set angle = Atan(udg_CMS_Param_V_Y[index] / udg_CMS_Param_V_X[index])
if udg_CMS_Param_V_X[index] < 0. then
set angle = angle -PI
endif
endif
set udg_CMS_Cache_Angle[index] = angle
set udg_CMS_Cache_Angle_Index[index] = udg_CMS_IntervalCount
return angle
endfunction
function CMS_SetAngle takes integer index, real angle returns nothing
local real V_H = CMS_GetVH(index)
local real A_H = CMS_GetAH(index)
local real cos = Cos(angle)
local real sin = Sin(angle)
set udg_CMS_Param_V_X[index] = cos * V_H
set udg_CMS_Param_V_Y[index] = sin * V_H
set udg_CMS_Param_A_X[index] = cos * A_H
set udg_CMS_Param_A_Y[index] = sin * A_H
call SetUnitFacing(udg_CMS_Param_Missile[udg_CMS_LoopIndex], angle*RADTODEG)
set udg_CMS_Cache_Angle[index] = angle
set udg_CMS_Cache_Angle_Index[index] = udg_CMS_IntervalCount
endfunction
function CMS_GetAngleDeg takes integer index returns real
return CMS_GetAngle(index) * RADTODEG
endfunction
function CMS_SetAngleDeg takes integer index, real angle returns nothing
call CMS_SetAngle(index, angle * DEGTORAD)
endfunction
//Set/get pitch (vertical angle).
//BJ functions for degree and normal functions for radians.
function CMS_GetPitch takes integer index returns real
local real pitch
local real V_H
if udg_CMS_Cache_Pitch_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_Pitch[index]
endif
set V_H = CMS_GetVH(index)
if V_H == 0. then
if udg_CMS_Param_V_Z[index] < 0. then
set pitch = PI * 1.5
elseif udg_CMS_Param_V_Z[index] > 0. then
set pitch = PI * 0.5
else
set pitch = 0.
endif
else
set pitch = Atan(udg_CMS_Param_V_Z[index] / V_H)
endif
set udg_CMS_Cache_Pitch[index] = pitch
set udg_CMS_Cache_Pitch_Index[index] = udg_CMS_IntervalCount
return pitch
endfunction
function CMS_SetPitch takes integer index, real pitch returns nothing
local real V_H = CMS_GetVH(index)
local real V = SquareRoot(V_H*V_H + udg_CMS_Param_V_Z[index]*udg_CMS_Param_V_Z[index])
local real A_H = CMS_GetAH(index)
local real A = SquareRoot(A_H*A_H + udg_CMS_Param_A_Z[index]*udg_CMS_Param_A_Z[index])
local real sin = Sin(pitch)
local real cos = Cos(pitch)
call CMS_SetVH(index, cos * V)
set udg_CMS_Param_V_Z[index] = sin * V
call CMS_SetAH(index, cos * A)
set udg_CMS_Param_A_Z[index] = sin * A
call CMS_SetUnitZAngle(udg_CMS_Param_Missile[index], pitch)
set udg_CMS_Cache_Pitch[index] = pitch
set udg_CMS_Cache_Pitch_Index[index] = udg_CMS_IntervalCount
endfunction
function CMS_GetPitchDeg takes integer index returns real
return CMS_GetPitch(index) * RADTODEG
endfunction
function CMS_SetPitchDeg takes integer index, real pitch returns nothing
call CMS_SetPitch(index, pitch * DEGTORAD)
endfunction
function CMS_GetAcceleration takes integer index returns real
local real acc
if udg_CMS_Cache_Acceleration_Index[index] == udg_CMS_IntervalCount then
return udg_CMS_Cache_Acceleration[index]
endif
set acc = SquareRoot(udg_CMS_Param_A_X[index]*udg_CMS_Param_A_X[index] + udg_CMS_Param_A_Y[index]*udg_CMS_Param_A_Y[index] + udg_CMS_Param_A_Z[index]*udg_CMS_Param_A_Z[index])
set udg_CMS_Cache_Acceleration[index] = acc
set udg_CMS_Cache_Acceleration_Index[index] = udg_CMS_IntervalCount
return acc
endfunction
function CMS_SetAcceleration takes integer index, real acc returns nothing
local real factor
local real oldAcc = CMS_GetAcceleration(index)
local real speed
if oldAcc == 0. then
set speed = CMS_GetSpeed(index)
if speed == 0. then
set udg_CMS_Param_A_X[index] = acc
else
set udg_CMS_Param_A_X[index] = acc * (udg_CMS_Param_V_X[index] / speed)
set udg_CMS_Param_A_Y[index] = acc * (udg_CMS_Param_V_Y[index] / speed)
set udg_CMS_Param_A_Z[index] = acc * (udg_CMS_Param_V_Z[index] / speed)
endif
else
set factor = acc/oldAcc
set udg_CMS_Param_A_X[index] = udg_CMS_Param_A_X[index] * factor
set udg_CMS_Param_A_Y[index] = udg_CMS_Param_A_Y[index] * factor
set udg_CMS_Param_A_Z[index] = udg_CMS_Param_A_Z[index] * factor
endif
set udg_CMS_Cache_Acceleration[index] = acc
set udg_CMS_Cache_Acceleration_Index[index] = udg_CMS_IntervalCount
endfunction
function CMS_GetAccelerationPerSecond takes integer index returns real
return CMS_GetAcceleration(index) / (udg_CMS_INTERVAL*udg_CMS_INTERVAL)
endfunction
function CMS_SetAccelerationPerSecond takes integer index, real acc returns nothing
call CMS_SetAcceleration(index, acc * (udg_CMS_INTERVAL*udg_CMS_INTERVAL))
endfunction
//Destroy the missile of index "index".
function CMS_DestroyMissile takes integer index returns boolean
local unit missile
local real originalHeight
local boolean isAUnit
set udg_CMS_Param_IsDestroyed[index] = true
set udg_CMS_Index = index
set udg_CMS_Event_Missile_Destroyed = -1
set udg_CMS_Event_Missile_Destroyed = 0
set udg_CMS_Event_Missile_Destroyed = -1
set udg_CMS_Event_Missile_Destroyed = udg_CMS_Param_Type[udg_CMS_Index]
if not udg_CMS_Param_IsDestroyed[index] then
return false
endif
set missile = udg_CMS_Param_Missile[udg_CMS_Index]
set originalHeight = udg_CMS_Param_OriginalHeight[udg_CMS_Index]
set originalHeight = GetUnitDefaultFlyHeight(udg_CMS_Param_Missile[index])
set isAUnit = udg_CMS_Param_IsAUnit[udg_CMS_Index]
//Remove the special effect and target location.
call DestroyEffect(udg_CMS_Param_Effect[index])
call RemoveLocation(udg_CMS_Param_Target_Location[index])
set udg_CMS_MissileIndex[GetUnitUserData(udg_CMS_Param_Missile[udg_CMS_Amount])] = index
set udg_CMS_MissileIndex[GetUnitUserData(udg_CMS_Param_Missile[index])] = 0
call FlushChildHashtable(udg_CMS_HASHTABLE, GetHandleId(udg_CMS_Param_Missile[index]))
set udg_CMS_Param_Collision_Cooldown[index] = udg_CMS_Param_Collision_Cooldown[udg_CMS_Amount]
set udg_CMS_Param_Collision_Dest[index] = udg_CMS_Param_Collision_Dest[udg_CMS_Amount]
set udg_CMS_Param_Collision_Height[index] = udg_CMS_Param_Collision_Height[udg_CMS_Amount]
set udg_CMS_Param_Collision_Height_Inc[index] = udg_CMS_Param_Collision_Height_Inc[udg_CMS_Amount]
set udg_CMS_Param_Collision_Item[index] = udg_CMS_Param_Collision_Item[udg_CMS_Amount]
set udg_CMS_Param_Collision_Type[index] = udg_CMS_Param_Collision_Type[udg_CMS_Amount]
set udg_CMS_Param_Collision_Unit[index] = udg_CMS_Param_Collision_Unit[udg_CMS_Amount]
set udg_CMS_Param_Collision_Width[index] = udg_CMS_Param_Collision_Width[udg_CMS_Amount]
set udg_CMS_Param_Collision_Width_Inc[index] = udg_CMS_Param_Collision_Width_Inc[udg_CMS_Amount]
set udg_CMS_Param_Distance[index] = udg_CMS_Param_Distance[udg_CMS_Amount]
set udg_CMS_Param_Duration[index] = udg_CMS_Param_Duration[udg_CMS_Amount]
set udg_CMS_Param_Effect[index] = udg_CMS_Param_Effect[udg_CMS_Amount]
set udg_CMS_Param_Gravity[index] = udg_CMS_Param_Gravity[udg_CMS_Amount]
set udg_CMS_Param_Index[index] = udg_CMS_Param_Index[udg_CMS_Amount]
set udg_CMS_Param_IsAUnit[index] = udg_CMS_Param_IsAUnit[udg_CMS_Amount]
set udg_CMS_Param_IsDestroyed[index] = udg_CMS_Param_IsDestroyed[udg_CMS_Amount]
set udg_CMS_Param_IsFlying[index] = udg_CMS_Param_IsFlying[udg_CMS_Amount]
set udg_CMS_Param_IsHoming[index] = udg_CMS_Param_IsHoming[udg_CMS_Amount]
set udg_CMS_Param_MaxDistance[index] = udg_CMS_Param_MaxDistance[udg_CMS_Amount]
set udg_CMS_Param_MaxDuration[index] = udg_CMS_Param_MaxDuration[udg_CMS_Amount]
set udg_CMS_Param_Missile[index] = udg_CMS_Param_Missile[udg_CMS_Amount]
set udg_CMS_Param_OriginalHeight[index] = udg_CMS_Param_OriginalHeight[udg_CMS_Amount]
set udg_CMS_Param_Source[index] = udg_CMS_Param_Source[udg_CMS_Amount]
set udg_CMS_Param_Subtype[index] = udg_CMS_Param_Subtype[udg_CMS_Amount]
set udg_CMS_Param_Target_Location[index] = udg_CMS_Param_Target_Location[udg_CMS_Amount]
set udg_CMS_Param_Target_Type[index] = udg_CMS_Param_Target_Type[udg_CMS_Amount]
set udg_CMS_Param_Target_Unit[index] = udg_CMS_Param_Target_Unit[udg_CMS_Amount]
set udg_CMS_Param_TurnRate[index] = udg_CMS_Param_TurnRate[udg_CMS_Amount]
set udg_CMS_Param_Type[index] = udg_CMS_Param_Type[udg_CMS_Amount]
set udg_CMS_Param_WalkingHeight[index] = udg_CMS_Param_WalkingHeight[udg_CMS_Amount]
set udg_CMS_Param_A_X[index] = udg_CMS_Param_A_X[udg_CMS_Amount]
set udg_CMS_Param_A_Y[index] = udg_CMS_Param_A_Y[udg_CMS_Amount]
set udg_CMS_Param_A_Z[index] = udg_CMS_Param_A_Z[udg_CMS_Amount]
set udg_CMS_Param_V_X[index] = udg_CMS_Param_V_X[udg_CMS_Amount]
set udg_CMS_Param_V_Y[index] = udg_CMS_Param_V_Y[udg_CMS_Amount]
set udg_CMS_Param_V_Z[index] = udg_CMS_Param_V_Z[udg_CMS_Amount]
set udg_CMS_Cache_A_H[index] = udg_CMS_Cache_A_H[udg_CMS_Amount]
set udg_CMS_Cache_V_H[index] = udg_CMS_Cache_V_H[udg_CMS_Amount]
set udg_CMS_Cache_Acceleration[index] = udg_CMS_Cache_Acceleration[udg_CMS_Amount]
set udg_CMS_Cache_Angle[index] = udg_CMS_Cache_Angle[udg_CMS_Amount]
set udg_CMS_Cache_Pitch[index] = udg_CMS_Cache_Pitch[udg_CMS_Amount]
set udg_CMS_Cache_Speed[index] = udg_CMS_Cache_Speed[udg_CMS_Amount]
set udg_CMS_Cache_V_H_Index[index] = udg_CMS_Cache_V_H_Index[udg_CMS_Amount]
set udg_CMS_Cache_Acceleration_Index[index] = udg_CMS_Cache_Acceleration_Index[udg_CMS_Amount]
set udg_CMS_Cache_Angle_Index[index] = udg_CMS_Cache_Angle_Index[udg_CMS_Amount]
set udg_CMS_Cache_Pitch_Index[index] = udg_CMS_Cache_Pitch_Index[udg_CMS_Amount]
set udg_CMS_Cache_Speed_Index[index] = udg_CMS_Cache_Speed_Index[udg_CMS_Amount]
set udg_CMS_Param_Collision_Cooldown[udg_CMS_Amount] = 0.
set udg_CMS_Param_Collision_Dest[udg_CMS_Amount] = false
set udg_CMS_Param_Collision_Height[udg_CMS_Amount] = 0.
set udg_CMS_Param_Collision_Height_Inc[udg_CMS_Amount] = 0.
set udg_CMS_Param_Collision_Item[udg_CMS_Amount] = false
set udg_CMS_Param_Collision_Type[udg_CMS_Amount] = 0
set udg_CMS_Param_Collision_Unit[udg_CMS_Amount] = false
set udg_CMS_Param_Collision_Width[udg_CMS_Amount] = 0.
set udg_CMS_Param_Collision_Width_Inc[udg_CMS_Amount] = 0.
set udg_CMS_Param_Distance[udg_CMS_Amount] = 0.
set udg_CMS_Param_Duration[udg_CMS_Amount] = 0.
set udg_CMS_Param_Effect[udg_CMS_Amount] = null
set udg_CMS_Param_Gravity[udg_CMS_Amount] = 0.
set udg_CMS_Param_Index[udg_CMS_Amount] = 0
set udg_CMS_Param_IsAUnit[udg_CMS_Amount] = false
set udg_CMS_Param_IsDestroyed[udg_CMS_Amount] = false
set udg_CMS_Param_IsFlying[udg_CMS_Amount] = false
set udg_CMS_Param_IsHoming[udg_CMS_Amount] = false
set udg_CMS_Param_MaxDistance[udg_CMS_Amount] = 0.
set udg_CMS_Param_MaxDuration[udg_CMS_Amount] = 0.
set udg_CMS_Param_Missile[udg_CMS_Amount] = null
set udg_CMS_Param_OriginalHeight[udg_CMS_Amount] = 0.
set udg_CMS_Param_Source[udg_CMS_Amount] = null
set udg_CMS_Param_Subtype[udg_CMS_Amount] = 0
set udg_CMS_Param_Target_Location[udg_CMS_Amount] = null
set udg_CMS_Param_Target_Type[udg_CMS_Amount] = 0
set udg_CMS_Param_Target_Unit[udg_CMS_Amount] = null
set udg_CMS_Param_TurnRate[udg_CMS_Amount] = 0.
set udg_CMS_Param_Type[udg_CMS_Amount] = 0
set udg_CMS_Param_WalkingHeight[udg_CMS_Amount] = 0.
set udg_CMS_Param_A_X[udg_CMS_Amount] = 0.
set udg_CMS_Param_A_Y[udg_CMS_Amount] = 0.
set udg_CMS_Param_A_Z[udg_CMS_Amount] = 0.
set udg_CMS_Param_V_X[udg_CMS_Amount] = 0.
set udg_CMS_Param_V_Y[udg_CMS_Amount] = 0.
set udg_CMS_Param_V_Z[udg_CMS_Amount] = 0.
set udg_CMS_Cache_A_H[udg_CMS_Amount] = 0.
set udg_CMS_Cache_V_H[udg_CMS_Amount] = 0.
set udg_CMS_Cache_Acceleration[udg_CMS_Amount] = 0.
set udg_CMS_Cache_Angle[udg_CMS_Amount] = 0.
set udg_CMS_Cache_Pitch[udg_CMS_Amount] = 0.
set udg_CMS_Cache_Speed[udg_CMS_Amount] = 0.
set udg_CMS_Cache_V_H_Index[udg_CMS_Amount] = 0
set udg_CMS_Cache_Acceleration_Index[udg_CMS_Amount] = 0
set udg_CMS_Cache_Angle_Index[udg_CMS_Amount] = 0
set udg_CMS_Cache_Pitch_Index[udg_CMS_Amount] = 0
set udg_CMS_Cache_Speed_Index[udg_CMS_Amount] = 0
set udg_CMS_Amount = udg_CMS_Amount -1
if not isAUnit then
call UnitApplyTimedLife(missile, 0, 0.01)
else
call UnitRemoveAbility(missile, udg_CMS_ABILITY_GHOST)
call SetUnitPathing(missile, true)
call SetUnitPosition(missile, GetUnitX(missile), GetUnitY(missile))
call SetUnitFlyHeight(missile, originalHeight, 999) // huh?
endif
if udg_CMS_LoopIndex > -1 then
set udg_CMS_LoopIndex = udg_CMS_LoopIndex -1
endif
if udg_CMS_Amount == 0 then
call PauseTimer(udg_CMS_TIMER)
endif
set missile = null
return true
endfunction
//! runtextmacro CMS_COLLISION_FUNCTIONS()
function GetUnitCenterZ takes unit whichUnit returns real
local real z = GetUnitFlyHeight(whichUnit)
if z < 60. then
return 60.
endif
return z
endfunction
function CMS_Interval_X takes nothing returns boolean
local rect r
local unit FoG
local real z
local real angle
local real x
local real y
local integer iteration = 0
loop
if udg_CMS_LoopIndex > udg_CMS_Amount then
return true
endif
exitwhen iteration > udg_CMS_LOOP_MAX
set iteration = iteration +1
//Move missile.
set udg_CMS_X_OLD = GetUnitX(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
set udg_CMS_Y_OLD = GetUnitY(udg_CMS_Param_Missile[udg_CMS_LoopIndex])
set udg_CMS_X = udg_CMS_X_OLD + udg_CMS_Param_V_X[udg_CMS_LoopIndex]
set udg_CMS_Y = udg_CMS_Y_OLD + udg_CMS_Param_V_Y[udg_CMS_LoopIndex]
call SetUnitX(udg_CMS_Param_Missile[udg_CMS_LoopIndex], udg_CMS_X)
call SetUnitY(udg_CMS_Param_Missile[udg_CMS_LoopIndex], udg_CMS_Y)
set z = GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex]) + udg_CMS_Param_V_Z[udg_CMS_LoopIndex] - (GetCoordinateZ(udg_CMS_X, udg_CMS_Y) - GetCoordinateZ(udg_CMS_X_OLD, udg_CMS_Y_OLD))
if z <= udg_CMS_Param_WalkingHeight[udg_CMS_LoopIndex] then
if udg_CMS_Param_IsFlying[udg_CMS_LoopIndex] or z < -20. then
call CMS_Collide_Terrain()
call SetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex], z, 0)
else
set z = udg_CMS_Param_WalkingHeight[udg_CMS_LoopIndex]
set udg_CMS_Param_V_Z[udg_CMS_LoopIndex] = 0.
call SetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex], z, 0)
endif
else
call SetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex], z, 0)
//Add gravity effect.
if udg_CMS_Param_Gravity[udg_CMS_LoopIndex] != 0. then
set udg_CMS_Param_V_Z[udg_CMS_LoopIndex] = udg_CMS_Param_V_Z[udg_CMS_LoopIndex] + udg_CMS_Param_Gravity[udg_CMS_LoopIndex]
call CMS_SetPitch(udg_CMS_LoopIndex, CMS_GetPitch(udg_CMS_LoopIndex))
endif
endif
//Check for the missile's limits.
set udg_CMS_Param_Distance[udg_CMS_LoopIndex] = udg_CMS_Param_Distance[udg_CMS_LoopIndex] + CMS_GetSpeed(udg_CMS_LoopIndex)
if udg_CMS_Param_MaxDistance[udg_CMS_LoopIndex] > 0. and udg_CMS_Param_Distance[udg_CMS_LoopIndex] >= udg_CMS_Param_MaxDistance[udg_CMS_LoopIndex] - 0.00001 then
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
endif
set udg_CMS_Param_Duration[udg_CMS_LoopIndex] = udg_CMS_Param_Duration[udg_CMS_LoopIndex] + udg_CMS_INTERVAL
if udg_CMS_Param_MaxDuration[udg_CMS_LoopIndex] > 0. and udg_CMS_Param_Duration[udg_CMS_LoopIndex] >= udg_CMS_Param_MaxDuration[udg_CMS_LoopIndex] - 0.00001 then
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
endif
set udg_CMS_Event_Missile_Tick = -1
set udg_CMS_Event_Missile_Tick = 0
set udg_CMS_Event_Missile_Tick = -1
set udg_CMS_Event_Missile_Tick = udg_CMS_Param_Type[udg_CMS_LoopIndex]
//Check collision.
set udg_CMS_StopCollision = false
if udg_CMS_Param_Collision_Type[udg_CMS_LoopIndex] == udg_CMS_COLLISIONTYPE_SIMPLE then
call SetRect(RECT, udg_CMS_X - udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_Y - udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_X + udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_Y + udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex])
//Collision with units.
if udg_CMS_Param_Collision_Unit[udg_CMS_LoopIndex] then
call GroupEnumUnitsInRect(udg_CMS_GROUP, RECT, null)
loop
set FoG = FirstOfGroup(udg_CMS_GROUP)
exitwhen FoG == null
call GroupRemoveUnit(udg_CMS_GROUP, FoG)
call CMS_Collide_Unit(FoG)
endloop
endif
//Collision with destructables.
if udg_CMS_Param_Collision_Dest[udg_CMS_LoopIndex] then
call EnumDestructablesInRect(RECT, null, function CMS_Collide_Dest_Simple)
endif
//Collision with items.
if udg_CMS_Param_Collision_Item[udg_CMS_LoopIndex] then
call EnumItemsInRect(RECT, null, function CMS_Collide_Item_Simple)
endif
//Increase width and height.
set udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Width_Inc[udg_CMS_LoopIndex]
set udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Height_Inc[udg_CMS_LoopIndex]
elseif udg_CMS_Param_Collision_Type[udg_CMS_LoopIndex] == udg_CMS_COLLISIONTYPE_CIRCLE then
call SetRect(RECT, udg_CMS_X - udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_Y - udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_X + udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], udg_CMS_Y + udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex])
//Collision with units.
if udg_CMS_Param_Collision_Unit[udg_CMS_LoopIndex] then
call GroupEnumUnitsInRange(udg_CMS_GROUP, udg_CMS_X, udg_CMS_Y, udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex], null)
loop
set FoG = FirstOfGroup(udg_CMS_GROUP)
exitwhen FoG == null
call GroupRemoveUnit(udg_CMS_GROUP, FoG)
call CMS_Collide_Unit(FoG)
endloop
endif
//Collision with destructables.
if udg_CMS_Param_Collision_Dest[udg_CMS_LoopIndex] then
call EnumDestructablesInRect(RECT, null, function CMS_Collide_Dest_Circle)
endif
//Collision with items.
if udg_CMS_Param_Collision_Item[udg_CMS_LoopIndex] then
call EnumItemsInRect(RECT, null, function CMS_Collide_Item_Circle)
endif
//Increase width and height.
set udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Width_Inc[udg_CMS_LoopIndex]
set udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Height_Inc[udg_CMS_LoopIndex]
elseif udg_CMS_Param_Collision_Type[udg_CMS_LoopIndex] == udg_CMS_COLLISIONTYPE_RECTANGLE then
set udg_CMS_RA = GetUnitFacing(udg_CMS_Param_Missile[udg_CMS_LoopIndex])*DEGTORAD
set udg_CMS_RX = (udg_CMS_X+udg_CMS_X_OLD) /2 // rectangle center x
set udg_CMS_RY = (udg_CMS_Y+udg_CMS_Y_OLD) /2 // rectangle center y
set udg_CMS_RW = udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex]*2 + DistanceBetweenCoordinates(udg_CMS_X, udg_CMS_Y, udg_CMS_X_OLD, udg_CMS_Y_OLD)
set udg_CMS_RH = udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex]*2
set z = udg_CMS_RW/2
call SetRect(RECT, udg_CMS_RX-z, udg_CMS_RY-z, udg_CMS_RX+z, udg_CMS_RY+z)
//Collision with units.
if udg_CMS_Param_Collision_Unit[udg_CMS_LoopIndex] then
call GroupEnumUnitsInRect(udg_CMS_GROUP, RECT, null)
loop
set FoG = FirstOfGroup(udg_CMS_GROUP)
exitwhen FoG == null
call GroupRemoveUnit(udg_CMS_GROUP, FoG)
if IsPointInAngledRectangleRad(udg_CMS_RX, udg_CMS_RY, udg_CMS_RW, udg_CMS_RH, udg_CMS_RA, GetUnitX(FoG), GetUnitY(FoG)) then
call CMS_Collide_Unit(FoG)
endif
endloop
endif
//Collision with destructables.
if udg_CMS_Param_Collision_Dest[udg_CMS_LoopIndex] then
call EnumDestructablesInRect(RECT, null, function CMS_Collide_Dest_Rectangle)
endif
//Collision with items.
if udg_CMS_Param_Collision_Item[udg_CMS_LoopIndex] then
call EnumItemsInRect(RECT, null, function CMS_Collide_Item_Rectangle)
endif
//Increase width and height.
set udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Width[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Width_Inc[udg_CMS_LoopIndex]
set udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] = udg_CMS_Param_Collision_Height[udg_CMS_LoopIndex] + udg_CMS_Param_Collision_Height_Inc[udg_CMS_LoopIndex]
elseif udg_CMS_Param_Collision_Type[udg_CMS_LoopIndex] == udg_CMS_COLLISIONTYPE_POLYGON then
call udg_CMS_Param_Polygon[udg_CMS_LoopIndex].setPosition(udg_CMS_X, udg_CMS_Y)
call udg_CMS_Param_Polygon[udg_CMS_LoopIndex].setRotationDeg(GetUnitFacing(udg_CMS_Param_Missile[udg_CMS_LoopIndex]))
call udg_CMS_Param_Polygon[udg_CMS_LoopIndex].getBounds() //Stores the bounds in RECT (BasicFunctions)
//Collision with units.
if udg_CMS_Param_Collision_Unit[udg_CMS_LoopIndex] then
call GroupEnumUnitsInRect(udg_CMS_GROUP, RECT, null)
loop
set FoG = FirstOfGroup(udg_CMS_GROUP)
exitwhen FoG == null
call GroupRemoveUnit(udg_CMS_GROUP,FoG)
if udg_CMS_Param_Polygon[udg_CMS_LoopIndex].containsPoint(GetUnitX(FoG), GetUnitY(FoG)) then
call CMS_Collide_Unit(FoG)
endif
endloop
endif
//Collision with destructables.
if udg_CMS_Param_Collision_Dest[udg_CMS_LoopIndex] then
call EnumDestructablesInRect(RECT, null, function CMS_Collide_Dest_Polygon)
endif
//Collision with items.
if udg_CMS_Param_Collision_Item[udg_CMS_LoopIndex] then
call EnumItemsInRect(RECT, null, function CMS_Collide_Item_Polygon)
endif
endif
//Update direction if the missile is homing.
if udg_CMS_Param_IsHoming[udg_CMS_LoopIndex] then
if udg_CMS_Param_Target_Type[udg_CMS_LoopIndex] == udg_CMS_TARGETTYPE_UNIT then
//Update angle.
set x = GetUnitX(udg_CMS_Param_Target_Unit[udg_CMS_LoopIndex])
set y = GetUnitY(udg_CMS_Param_Target_Unit[udg_CMS_LoopIndex])
set angle = DenormalizeAngleDeg(AngleBetweenCoordinatesDeg(udg_CMS_X, udg_CMS_Y, x, y) - CMS_GetAngleDeg(udg_CMS_LoopIndex))
if angle > udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
elseif angle < -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
endif
call CMS_SetAngleDeg(udg_CMS_LoopIndex, CMS_GetAngleDeg(udg_CMS_LoopIndex) + angle)
//Update pitch.
if udg_CMS_Param_IsFlying[udg_CMS_LoopIndex] then
// hardcoded 50 for assumed target height offset
set angle = AngleBetweenCoordinatesDeg(0, GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y), DistanceBetweenCoordinates(x, y, udg_CMS_X, udg_CMS_Y), GetUnitCenterZ(udg_CMS_Param_Target_Unit[udg_CMS_LoopIndex])+GetCoordinateZ(x, y)) - CMS_GetPitchDeg(udg_CMS_LoopIndex)
if angle > udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
elseif angle < -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
endif
call CMS_SetPitchDeg(udg_CMS_LoopIndex, CMS_GetPitchDeg(udg_CMS_LoopIndex) + angle)
endif
elseif udg_CMS_Param_Target_Type[udg_CMS_LoopIndex] == udg_CMS_TARGETTYPE_LOCATION then
//Update angle.
set x = GetLocationX(udg_CMS_Param_Target_Location[udg_CMS_LoopIndex])
set y = GetLocationY(udg_CMS_Param_Target_Location[udg_CMS_LoopIndex])
set angle = DenormalizeAngleDeg(AngleBetweenCoordinatesDeg(udg_CMS_X, udg_CMS_Y, x, y) - CMS_GetAngleDeg(udg_CMS_LoopIndex))
if angle > udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
elseif angle < -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
endif
call CMS_SetAngleDeg(udg_CMS_LoopIndex, CMS_GetAngleDeg(udg_CMS_LoopIndex) + angle)
//Update pitch.
if udg_CMS_Param_IsFlying[udg_CMS_LoopIndex] then
set angle = AngleBetweenCoordinatesDeg(0, GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_LoopIndex])+GetCoordinateZ(udg_CMS_X, udg_CMS_Y), DistanceBetweenCoordinates(x, y, udg_CMS_X, udg_CMS_Y), GetCoordinateZ(x, y)) - CMS_GetPitchDeg(udg_CMS_LoopIndex)
if angle > udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
elseif angle < -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex] then
set angle = -udg_CMS_Param_TurnRate[udg_CMS_LoopIndex]
endif
call CMS_SetPitchDeg(udg_CMS_LoopIndex, CMS_GetPitchDeg(udg_CMS_LoopIndex) + angle)
endif
endif
endif
set udg_CMS_Param_V_X[udg_CMS_LoopIndex] = udg_CMS_Param_V_X[udg_CMS_LoopIndex] + udg_CMS_Param_A_X[udg_CMS_LoopIndex]
set udg_CMS_Param_V_Y[udg_CMS_LoopIndex] = udg_CMS_Param_V_Y[udg_CMS_LoopIndex] + udg_CMS_Param_A_Y[udg_CMS_LoopIndex]
set udg_CMS_Param_V_Z[udg_CMS_LoopIndex] = udg_CMS_Param_V_Z[udg_CMS_LoopIndex] + udg_CMS_Param_A_Z[udg_CMS_LoopIndex]
if udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] then
call CMS_DestroyMissile(udg_CMS_LoopIndex)
endif
set udg_CMS_LoopIndex = udg_CMS_LoopIndex + 1
endloop
return false
endfunction
//This is the interval of the timer.
function CMS_Interval takes nothing returns nothing
set udg_CMS_LoopIndex = 1
set udg_CMS_IntervalCount = udg_CMS_IntervalCount +1
set udg_CMS_GameTime = GetElapsedGameTime()
loop
exitwhen TriggerEvaluate(udg_CMS_TRIGGER)
endloop
set udg_CMS_LoopIndex = -1
endfunction
function CMS_CreateMissile takes unit source, integer typeId, unit whichMissile, boolean importDefaultValues returns integer
local integer id
local timer t
local location startingLocation = udg_CMS_StartingLocation
local integer otherIndex = 0
local integer sourceId
local integer missileId
local integer userData
set udg_CMS_Amount = udg_CMS_Amount +1
if importDefaultValues then
call CMS_SetDefaultVariables(udg_CMS_Amount)
endif
set udg_CMS_Param_Missile[udg_CMS_Amount] = whichMissile
set udg_CMS_Param_Source[udg_CMS_Amount] = source
set udg_CMS_Param_Type[udg_CMS_Amount] = typeId
if udg_CMS_Param_Missile[udg_CMS_Amount] == null then
if udg_CMS_StartingLocust then
//Create a new missile dummy and give it locust.
set udg_CMS_Param_Missile[udg_CMS_Amount] = CreateUnit(GetOwningPlayer(source), udg_CMS_MISSILE_UNITTYPE, GetLocationX(startingLocation), GetLocationY(startingLocation), udg_CMS_StartingAngle)
call UnitAddAbility(udg_CMS_Param_Missile[udg_CMS_Amount], 'Aloc')
call UnitMakeAbilityPermanent(udg_CMS_Param_Missile[udg_CMS_Amount], true, 'Aloc')
else
//Create a new dummy unit and transform it into the missile dummy to de-locust the unit.
set udg_CMS_Param_Missile[udg_CMS_Amount] = CreateUnit(GetOwningPlayer(source), udg_CMS_DUMMY_UNITTYPE, GetLocationX(startingLocation), GetLocationY(startingLocation), udg_CMS_StartingAngle)
call UnitAddAbility(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_ABILITY_MORPH)
call UnitRemoveAbility(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_ABILITY_MORPH)
//Remove collision.
call UnitAddAbility(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_ABILITY_GHOST)
call UnitMakeAbilityPermanent(udg_CMS_Param_Missile[udg_CMS_Amount], true, udg_CMS_ABILITY_GHOST)
call SetUnitPathing(udg_CMS_Param_Missile[udg_CMS_Amount], false)
endif
else
set otherIndex = CMS_GetIndex(udg_CMS_Param_Missile[udg_CMS_Amount])
//Remove collision.
call UnitAddAbility(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_ABILITY_GHOST)
call UnitMakeAbilityPermanent(udg_CMS_Param_Missile[udg_CMS_Amount], true, udg_CMS_ABILITY_GHOST)
call SetUnitPathing(udg_CMS_Param_Missile[udg_CMS_Amount], false)
endif
//Add and remove crow form.
if UnitAddAbility(udg_CMS_Param_Missile[udg_CMS_Amount], 'Arav') then
call UnitRemoveAbility(udg_CMS_Param_Missile[udg_CMS_Amount], 'Arav')
endif
//Make sure that the source is not immediately hit.
if udg_CMS_StartingSourceFilter then
call SaveReal(udg_CMS_HASHTABLE, GetHandleId(udg_CMS_Param_Missile[udg_CMS_Amount]), GetHandleId(source), GetElapsedGameTime())
endif
//Save the original height.
if otherIndex == 0 then
set udg_CMS_Param_OriginalHeight[udg_CMS_Amount] = GetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_Amount])
call SetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_StartingHeight, 0) // huh?
else
set udg_CMS_Param_OriginalHeight[udg_CMS_Amount] = udg_CMS_Param_OriginalHeight[otherIndex]
call SetUnitFlyHeight(udg_CMS_Param_Missile[udg_CMS_Amount], udg_CMS_StartingHeight, 0)
endif
//Generate speed and direction.
call CMS_SetSpeedPerSecond(udg_CMS_Amount, udg_CMS_StartingSpeed)
call CMS_SetAngleDeg(udg_CMS_Amount, udg_CMS_StartingAngle)
call CMS_SetPitchDeg(udg_CMS_Amount, udg_CMS_StartingPitch)
call CMS_SetAccelerationPerSecond(udg_CMS_Amount, udg_CMS_StartingAcceleration)
//Start the timer if this is the first missile.
if udg_CMS_Amount == 1 then
call TimerStart(udg_CMS_TIMER, udg_CMS_INTERVAL, true, function CMS_Interval)
endif
//Create the unique index.
set udg_CMS_Param_Index[udg_CMS_Amount] = CMS_CreateUniqueId()
set userData = GetUnitUserData(udg_CMS_Param_Missile[udg_CMS_Amount])
if userData > 0 then
set udg_CMS_MissileIndex[userData] = udg_CMS_Amount
endif
//Call the event.
set udg_CMS_Event_Missile_Created = -1
set udg_CMS_Event_Missile_Created = 0
set udg_CMS_Event_Missile_Created = -1
set udg_CMS_Event_Missile_Created = udg_CMS_Param_Type[udg_CMS_Amount]
//Clean leaks.
call RemoveLocation(startingLocation)
set startingLocation = null
//Reset variables to standard settings.
set udg_CMS_StartingAcceleration = 0.
set udg_CMS_StartingAngle = 0.
set udg_CMS_StartingHeight = 0.
set udg_CMS_StartingLocation = null
set udg_CMS_StartingLocust = true
set udg_CMS_StartingPitch = 0.
set udg_CMS_StartingSourceFilter = true
set udg_CMS_StartingSpeed = 0.
return udg_CMS_Amount
endfunction
//This function creates a new missile.
//It uses the missile source and all starting variables.
function CMS_CreateMissileEx takes nothing returns integer
local integer id = CMS_CreateMissile(udg_CMS_StartingSource, udg_CMS_StartingType, udg_CMS_StartingMissile, udg_CMS_StartingDefaultValues)
set udg_CMS_StartingSource = null
set udg_CMS_StartingType = -1
set udg_CMS_StartingMissile = null
set udg_CMS_StartingDefaultValues = true
return id
endfunction
endlibrary
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This code initializes the standard settings.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This is the initial function.
function InitTrig_CMS_System takes nothing returns nothing
call TriggerAddCondition(udg_CMS_TRIGGER, Filter(function CMS_Interval_X))
//Initialize the constants.
set udg_CMS_COLLISIONTYPE_NONE = 0
set udg_CMS_COLLISIONTYPE_SIMPLE = 1
set udg_CMS_COLLISIONTYPE_CIRCLE = 2
set udg_CMS_COLLISIONTYPE_RECTANGLE = 3
set udg_CMS_COLLISIONTYPE_POLYGON = 4
set udg_CMS_TARGETTYPE_NONE = 0
set udg_CMS_TARGETTYPE_UNIT = 1
set udg_CMS_TARGETTYPE_LOCATION = 2
//Initialize the indexes.
set udg_CMS_IntervalCount = 1
set udg_CMS_LoopIndex = -1
set udg_CMS_Amount = 0
//Initialize standard starting settings.
set udg_CMS_StartingAcceleration = 0.
set udg_CMS_StartingAngle = 0.
set udg_CMS_StartingDefaultValues = true
set udg_CMS_StartingHeight = 0.
set udg_CMS_StartingLocation = null
set udg_CMS_StartingLocust = true
set udg_CMS_StartingMissile = null
set udg_CMS_StartingPitch = 0.
set udg_CMS_StartingSource = null
set udg_CMS_StartingSourceFilter = true
set udg_CMS_StartingSpeed = 0.
set udg_CMS_StartingType = -1
//! runtextmacro CMS_INIT()
set udg_CMS_SecondsPerTick = udg_CMS_INTERVAL
set udg_CMS_TicksPerSecond = 1 / udg_CMS_SecondsPerTick
set udg_CMS_SecondsPerTickSquared = udg_CMS_SecondsPerTick * udg_CMS_SecondsPerTick
set udg_CMS_TicksPerSecondSquared = 1 / udg_CMS_SecondsPerTickSquared
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CMS System end
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct Assert
private string name
private boolean hasFailed = false
method Reset takes nothing returns nothing
set hasFailed = false
endmethod
method HasFailed takes nothing returns boolean
return hasFailed
endmethod
method GetName takes nothing returns string
return name
endmethod
static method create takes string name returns Assert
local thistype this = thistype.allocate()
set this.name = name
return this
endmethod
method Equal_String takes string expected, string actual, string message returns nothing
if expected != actual then
set hasFailed = true
call BJDebugMsg(" failure, expected: '" + expected + "' but got: '" + actual + "' " + message)
endif
endmethod
method Equal_Real takes real expected, real actual, string message returns nothing
local real margin = 1.001
local real lowerBound = expected / margin
local real upperBound = expected * margin
if upperBound < actual or actual < lowerBound then
set hasFailed = true
call BJDebugMsg(" failure, expected: " + R2S(expected) + " but got: " + R2S(actual) + " " + message)
endif
endmethod
method Equal_RealRange takes real lowerBound, real upperBound, real actual, string message returns nothing
if upperBound <= actual or actual <= lowerBound then
set hasFailed = true
call BJDebugMsg(" failure, expected: " + R2S(lowerBound) + " <= value <= " + R2S(upperBound) + " but got: " + R2S(actual) + " " + message)
endif
endmethod
method Equal_Integer takes integer expected, integer actual, string message returns nothing
if expected < actual or actual < expected then
set hasFailed = true
call BJDebugMsg(" failure, expected: " + I2S(expected) + " but got: " + I2S(actual) + " " + message)
endif
endmethod
endstruct
interface UnitTest
method GetName takes nothing returns string
method Run takes nothing returns nothing
endinterface
library TestFramework initializer init
struct Time
real startedAt
real duration
static method create takes real startedAt, real duration returns Time
local thistype this = thistype.allocate()
set this.startedAt = startedAt
set this.duration = duration
return this
endmethod
endstruct
globals
boolean TEST_OUTPUT = true
UnitTest array TEST_QUEUE
integer TEST_QUEUE_COUNT = 0
timer CLOCK
trigger array TRIGGERS
integer TRIGGERS_COUNT = 0
timer array TIMERS
integer TIMERS_COUNT = 0
unit array UNITS
integer UNITS_COUNT = 0
group NORMAL_UNITS = null
endglobals
function QueueTest takes UnitTest test returns nothing
set TEST_QUEUE[TEST_QUEUE_COUNT] = test
set TEST_QUEUE_COUNT = TEST_QUEUE_COUNT + 1
endfunction
function NextTest takes nothing returns UnitTest
local integer i = 0
local UnitTest test = TEST_QUEUE[0]
loop
exitwhen i == TEST_QUEUE_COUNT
set TEST_QUEUE[i] = TEST_QUEUE[i + 1]
set i = i + 1
endloop
if TEST_QUEUE_COUNT > 0 then
set TEST_QUEUE_COUNT = TEST_QUEUE_COUNT - 1
endif
return test
endfunction
function Now takes nothing returns Time
local real startedAt = TimerGetElapsed(CLOCK)
return Time.create(startedAt, 0.0)
endfunction
function TimeSince takes Time time returns Time
local real now = TimerGetElapsed(CLOCK)
local real startedAt = time.startedAt + time.duration
local real duration = now - startedAt
return Time.create(startedAt, duration)
endfunction
private function AddTrigger takes trigger t returns nothing
set TRIGGERS[TRIGGERS_COUNT] = t
set TRIGGERS_COUNT = TRIGGERS_COUNT + 1
endfunction
private function AddTimer takes timer t returns nothing
set TIMERS[TIMERS_COUNT] = t
set TIMERS_COUNT = TIMERS_COUNT + 1
endfunction
function AddTriggerCustomEvent takes string whichEvent, real whichCode, code action returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterVariableEvent(t, whichEvent, EQUAL, whichCode)
call TriggerAddCondition(t, Filter(action))
call AddTrigger(t)
endfunction
function AddTriggerPlayerUnitEvent takes player targetPlayer, playerunitevent whichEvent, code action returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t, targetPlayer, whichEvent, null)
call TriggerAddCondition(t, Condition(action))
call AddTrigger(t)
endfunction
private function ClearTriggers takes nothing returns nothing
loop
exitwhen TRIGGERS_COUNT == 0
set TRIGGERS_COUNT = TRIGGERS_COUNT - 1
call DestroyTrigger(TRIGGERS[TRIGGERS_COUNT])
endloop
endfunction
function Delayed takes real timeout, code action returns nothing
local timer t = CreateTimer()
call TimerStart(t, timeout, false, action)
call AddTimer(t)
endfunction
private function ClearTimers takes nothing returns nothing
loop
exitwhen TIMERS_COUNT == 0
set TIMERS_COUNT = TIMERS_COUNT - 1
call DestroyTimer(TIMERS[TIMERS_COUNT])
endloop
endfunction
function AddUnit takes unit u returns unit
set UNITS[UNITS_COUNT] = u
set UNITS_COUNT = UNITS_COUNT + 1
return u
endfunction
private function ClearUnits takes nothing returns nothing
loop
exitwhen UNITS_COUNT == 0
set UNITS_COUNT = UNITS_COUNT - 1
call RemoveUnit(UNITS[UNITS_COUNT])
endloop
endfunction
private function HidePickedUnit takes nothing returns nothing
call ShowUnit(GetEnumUnit(), false)
endfunction
private function ShowPickedUnit takes nothing returns nothing
call ShowUnit(GetEnumUnit(), true)
endfunction
private function HideAllUnits takes nothing returns nothing
if NORMAL_UNITS == null then
set NORMAL_UNITS = CreateGroup()
call GroupEnumUnitsInRect(NORMAL_UNITS, bj_mapInitialPlayableArea, null)
call ForGroup(NORMAL_UNITS, function HidePickedUnit)
endif
endfunction
private function ShowAllUnits takes nothing returns nothing
call ForGroup(NORMAL_UNITS, function ShowPickedUnit)
call DestroyGroup(NORMAL_UNITS)
set NORMAL_UNITS = null
endfunction
function RunTests takes nothing returns nothing
local UnitTest nextTest = NextTest()
call HideAllUnits()
if nextTest != null then
call nextTest.Run()
else
call ShowAllUnits()
endif
endfunction
private function DebugMessage takes string message returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 3, message)
endfunction
function EndTest takes Assert assert returns nothing
call ClearTriggers()
call ClearTimers()
call ClearUnits()
if TEST_OUTPUT then
if assert.HasFailed() then
call DebugMessage("Test " + assert.GetName() + " failed")
else
call DebugMessage("Test " + assert.GetName() + " succeeded")
endif
endif
call RunTests()
endfunction
// camera
function TestSetCamera takes real x, real y returns nothing
call PanCameraToTimed(x, y, 0.0)
// call PanCameraToTimedLocForPlayer(p, GetRectCenter(GetPlayableMapRect()), 0 )
// call SetCameraFieldForPlayer(p, CAMERA_FIELD_TARGET_DISTANCE, 0.00, 0 )
// call SetCameraFieldForPlayer(p, CAMERA_FIELD_ANGLE_OF_ATTACK, 0.00, 0 )
endfunction
// initializer
private function init takes nothing returns nothing
set CLOCK = CreateTimer()
call TimerStart(CLOCK, 3600, true, null)
endfunction
endlibrary
library TestCommands initializer init requires TestFramework
globals
UnitTest array UnitTests
integer UnitTestsCount = 0
UnitTest array Showcases
integer ShowcasesCount = 0
endglobals
private function StringContains takes string haystack, string needle, boolean caseInSensitive returns boolean
local integer needleLength = StringLength(needle)
local integer haystackLength = StringLength(haystack)
local integer index = 0
local integer iterations = haystackLength - needleLength + 1
local string haystack2
local string needle2
if caseInSensitive then
set haystack2 = StringCase(haystack, true)
set needle2 = StringCase(needle, true)
else
set haystack2 = haystack
set needle2 = needle
endif
if needleLength > haystackLength then
return false
elseif needleLength == 0 then
return true
elseif haystackLength == 0 then
return false
elseif needleLength == haystackLength then
return haystack2 == needle2
else
loop
exitwhen index == iterations
if SubString(haystack2, index, index + needleLength) == needle2 then
return true
endif
set index = index + 1
endloop
endif
return false
endfunction
private function RunTest takes nothing returns boolean
local string command = GetEventPlayerChatString()
local string filter
local integer index
local integer matched = 0
local boolean isTest = SubString(command, 0, 5) == "/test"
if isTest then
if StringLength(command) > 6 then
set filter = SubString(command, 6, StringLength(command))
else
set filter = ""
endif
set index = 0
loop
exitwhen index == UnitTestsCount
if StringContains(UnitTests[index].GetName(), filter, true) then
call QueueTest(UnitTests[index])
set matched = matched + 1
endif
set index = index + 1
endloop
if matched == 0 then
call BJDebugMsg("no tests matched the filter '" + filter + "'")
endif
else
if StringLength(command) > 10 then
set filter = SubString(command, 10, StringLength(command))
else
set filter = ""
endif
set index = 0
loop
exitwhen index == ShowcasesCount
if StringContains(Showcases[index].GetName(), filter, true) then
call QueueTest(Showcases[index])
set matched = matched + 1
endif
set index = index + 1
endloop
if matched == 0 then
call BJDebugMsg("no showcases matched the filter '" + filter + "'")
endif
endif
call RunTests()
return false
endfunction
private function RegisterUnitTest takes UnitTest unitTest returns nothing
set UnitTests[UnitTestsCount] = unitTest
set UnitTestsCount = UnitTestsCount + 1
endfunction
private function RegisterShowcase takes UnitTest unitTest returns nothing
set Showcases[ShowcasesCount] = unitTest
set ShowcasesCount = ShowcasesCount + 1
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "/test", false)
call TriggerRegisterPlayerChatEvent(t, GetLocalPlayer(), "/showcase", false)
call TriggerAddCondition(t, Filter(function RunTest))
call RegisterUnitTest(Test_BasicMissile_WithMaxDuration.create())
call RegisterUnitTest(Test_BasicMissile_WithMaxDistance.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Simple.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Circle.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Circle_Miss.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Rectangle.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Rectangle_Reverse.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Terrain_Block.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Terrain_Walk_Up.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Terrain_Fall_Down.create())
call RegisterUnitTest(Test_BasicMissile_Collision_Terrain_Fly_Straight.create())
call RegisterShowcase(Showcase_MagicMissile.create())
call RegisterShowcase(Showcase_Firebolt.create())
call RegisterShowcase(Showcase_FuryFire.create())
call RegisterShowcase(Showcase_MeteorStrike.create())
call RegisterShowcase(Showcase_Blizzard.create())
call RegisterShowcase(Showcase_FrostNova.create())
call RegisterShowcase(Showcase_RocketBarrage.create())
call RegisterShowcase(Showcase_SeekerMissile.create())
endfunction
endlibrary
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after 1.5 second due to CMS_Param_MaxDuration.
*/
struct Test_BasicMissile_WithMaxDuration extends UnitTest
static string NAME = "BasicMissile_WithMaxDuration"
static real DURATION = 2.5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
private method Start takes nothing returns nothing
local real source_x = X - 200
local real source_y = Y
local real target_x = source_x + 400
local real target_y = source_y
local unit caster = CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0)
call AddUnit(caster)
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 500.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_MaxDuration[missile] = 1.5
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(1.500, TIMING_FLIGHT.duration, "destruction moment should be 1.5s after the casting of the ability")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after 1.5 second due to the combination of CMS_Param_MaxDistance and CMD_Starting_Speed.
*/
struct Test_BasicMissile_WithMaxDistance extends UnitTest
static string NAME = "BasicMissile_WithMaxDistance"
static real DURATION = 2.5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
private method Start takes nothing returns nothing
local real source_x = X - 200
local real source_y = Y
local real target_x = source_x + 400
local real target_y = source_y
local unit caster = CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0)
call AddUnit(caster)
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 500.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_MaxDistance[missile] = 750.0 // distance of 750 should be reached after 1.5 seconds given starting speed of 500
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(1.500, TIMING_FLIGHT.duration, "destruction moment should be 1.5s after the casting of the ability")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the enemy unit.
*/
struct Test_BasicMissile_Collision_Simple extends UnitTest
static string NAME = "BasicMissile_Collision_Simple"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X + 400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_SIMPLE
set udg_CMS_Param_Collision_Width[missile] = 40.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_RealRange(1.919, 1.981, TIMING_FLIGHT.duration, "destruction moment should be around 1.95s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Footman", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the enemy unit.
*/
struct Test_BasicMissile_Collision_Circle extends UnitTest
static string NAME = "BasicMissile_Collision_Circle"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X + 408
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
// speed per second = 400
// ticks per second = 33
// speed per tick = 12
// 12-24-36-48-60-72-84-96-108-120-132-144-156-168-180
// 360
// 372-384-396-408
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_CIRCLE
set udg_CMS_Param_Collision_Width[missile] = 20.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_RealRange(1.919, 1.981, TIMING_FLIGHT.duration, "destruction moment should be around 1.95s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Footman", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the enemy unit.
* But it should hit the footman behind the peon.
*
* if the velocity = 2000 per second
* and the interval = 0.03
* then the velocity per tick = 60 (2000 * 0.03)
* if the collision is only 20, then between every adjacent tick, the collision check has a gap, allowing units to not be detected
* this test scenario shows that gap with a raised tick duration to show the effect
*/
struct Test_BasicMissile_Collision_Circle_Miss extends UnitTest
static string NAME = "BasicMissile_Collision_Circle_Miss"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer TARGET_UNIT_TYPE_2 = 'opeo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X + 400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
local unit target2 = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_2, target_x - 100, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_CIRCLE
set udg_CMS_Param_Collision_Width[missile] = 20.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
set udg_CMS_INTERVAL = 0.03
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(2.000, TIMING_FLIGHT.duration, "destruction moment should be 2.00s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Footman", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
// arbitrarily set the CMS interval to 0.5 for better visualization of the process
// this variable should NEVER be altered during gameplay
set udg_CMS_INTERVAL = 0.5
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the enemy unit.
* Unlike Test_BasicMissile_Collision_Circle_Miss, this should correctly hit the peon.
*/
struct Test_BasicMissile_Collision_Rectangle extends UnitTest
static string NAME = "BasicMissile_Collision_Rectangle"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer TARGET_UNIT_TYPE_2 = 'opeo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X + 400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
local unit target2 = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_2, target_x - 100, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_RECTANGLE
set udg_CMS_Param_Collision_Width[missile] = 20.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method B2S takes boolean flag returns string
if flag then
return "true"
else
return "false"
endif
endmethod
private static method OnCollide takes nothing returns boolean
local boolean hasLocust = GetUnitAbilityLevel(udg_CMS_Collided_Unit, 'Aloc') > 0
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
set udg_CMS_INTERVAL = 0.03
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(2.000, TIMING_FLIGHT.duration, "destruction moment should be 2.00s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Peon", COLLIDED_UNIT_NAME, "the collided unit should be the peon")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
// arbitrarily set the CMS interval to 0.5 for better visualization of the process
// this variable should NEVER be altered during gameplay
set udg_CMS_INTERVAL = 0.5
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the enemy unit.
*/
struct Test_BasicMissile_Collision_Rectangle_Reverse extends UnitTest
static string NAME = "BasicMissile_Collision_Rectangle_Reverse"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer TARGET_UNIT_TYPE_2 = 'opeo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X + 400
local real source_y = Y
local real target_x = X - 400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 0))
local unit target2 = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_2, target_x + 100, target_y, 0))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 180.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_RECTANGLE
set udg_CMS_Param_Collision_Width[missile] = 20.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
local boolean hasLocust = GetUnitAbilityLevel(udg_CMS_Collided_Unit, 'Aloc') > 0
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
set udg_CMS_INTERVAL = 0.03
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(2.000, TIMING_FLIGHT.duration, "destruction moment should be 2.00s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Peon", COLLIDED_UNIT_NAME, "the collided unit should be the peon")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
// arbitrarily set the CMS interval to 0.5 for better visualization of the process
// this variable should NEVER be altered during gameplay
set udg_CMS_INTERVAL = 0.5
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should be destroyed after hitting the terrain.
*/
struct Test_BasicMissile_Collision_Terrain_Block extends UnitTest
static string NAME = "BasicMissile_Collision_Terrain_Block"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X + 400
local real source_y = Y
local real target_x = X - 400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 180.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 400.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(1.410, TIMING_FLIGHT.duration, "destruction moment should be 1.41s after the casting of the ability, when it reached the cliff")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1536.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_T", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should walk up on the terrain and hit the footman on top of the cliff.
*/
struct Test_BasicMissile_Collision_Terrain_Walk_Up extends UnitTest
static string NAME = "BasicMissile_Collision_Terrain_Walk_Up"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X + 400
local real source_y = Y
local real target_x = X - 384
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
local unit target = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 0))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 180.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 500.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_SIMPLE
set udg_CMS_Param_Collision_Width[missile] = 40.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_RealRange(1.469, 1.531, TIMING_FLIGHT.duration, "destruction moment should be around 1.5s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Footman", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1536.0
set Y = 0.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should walk up on the terrain and hit the footman on top of the cliff.
*/
struct Test_BasicMissile_Collision_Terrain_Fly_Straight extends UnitTest
static string NAME = "BasicMissile_Collision_Terrain_Fly_Straight"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE_1 = 'hfoo'
static integer TARGET_UNIT_TYPE_2 = 'hgry'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 512
local real source_y = Y
local real target_x = X + 512
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_1, target_x, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_2, target_x, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 500.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_SIMPLE
set udg_CMS_Param_Collision_Width[missile] = 40.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(2.04, TIMING_FLIGHT.duration, "destruction moment should be around 1.5s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Gryphon Rider", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1536.0
set Y = 1024.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
/**
* Create a caster and cast an ability with a missile.
* The missile should walk up on the terrain and hit the footman on top of the cliff.
*/
struct Test_BasicMissile_Collision_Terrain_Fall_Down extends UnitTest
static string NAME = "BasicMissile_Collision_Terrain_Fall_Down"
static real DURATION = 3.0
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'hsor'
static integer TARGET_UNIT_TYPE_1 = 'hfoo'
static integer TARGET_UNIT_TYPE_2 = 'hgry'
static integer ABILITY_ID = 't000'
static string CAST_ORDER = "darksummoning"
static unit MISSILE = null
static integer MISSILE_TYPE = 100
static string MISSILE_MODEL = "Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl"
// outputs:
static Time TIMING_START = 0
static Time TIMING_CAST = 0
static Time TIMING_DESTROY = 0
static Time TIMING_FLIGHT = 0
static string COLLIDED_UNIT_NAME = ""
static integer COLLISION_COUNT = 0
private method Start takes nothing returns nothing
local real source_x = X - 512
local real source_y = Y
local real target_x = X + 512
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_1, target_x, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE_2, target_x, target_y, 180))
call UnitAddAbility(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
set TIMING_START = Now()
endmethod
private static method OnCast takes nothing returns boolean
local integer missile
if GetSpellAbilityId() != ABILITY_ID then
return false
endif
set TIMING_CAST = TimeSince(TIMING_START)
set udg_CMS_StartingLocation = GetUnitLoc(GetTriggerUnit())
set udg_CMS_StartingSource = GetTriggerUnit()
set udg_CMS_StartingAngle = 0.0
set udg_CMS_StartingHeight = 50.0
set udg_CMS_StartingSpeed = 500.0
set udg_CMS_StartingType = MISSILE_TYPE
set missile = CMS_CreateMissileEx()
set udg_CMS_Param_WalkingHeight[missile] = 55.0
set udg_CMS_Param_Gravity[missile] = -45 * udg_CMS_INTERVAL
set udg_CMS_Param_Collision_Type[missile] = udg_CMS_COLLISIONTYPE_SIMPLE
set udg_CMS_Param_Collision_Width[missile] = 40.0
set udg_CMS_Param_Collision_Height[missile] = 50.0
set udg_CMS_Param_Effect[missile] = AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Param_Missile[missile], "origin")
set MISSILE = udg_CMS_Param_Missile[missile]
return false
endmethod
private static method OnCollide takes nothing returns boolean
set COLLISION_COUNT = COLLISION_COUNT + 1
set COLLIDED_UNIT_NAME = GetUnitName(udg_CMS_Collided_Unit)
set udg_CMS_Param_IsDestroyed[udg_CMS_LoopIndex] = true
call DestroyEffect(AddSpecialEffectTarget(MISSILE_MODEL, udg_CMS_Collided_Unit, "origin"))
return false
endmethod
private static method OnDestroy takes nothing returns boolean
set TIMING_DESTROY = TimeSince(TIMING_START)
set TIMING_FLIGHT = TimeSince(TIMING_CAST)
return false
endmethod
private static method OnComplete takes nothing returns nothing
call assert.Equal_Real(0.450, TIMING_CAST.duration, "cast moment should be equal to the casting point of the caster")
call assert.Equal_Real(2.04, TIMING_FLIGHT.duration, "destruction moment should be around 1.5s after the casting of the ability, when it reached the target unit")
call assert.Equal_String("Footman", COLLIDED_UNIT_NAME, "the collided unit should be the footman")
call assert.Equal_Integer(1, COLLISION_COUNT, "there should be one and only one collision")
call TIMING_START.destroy()
call TIMING_CAST.destroy()
call TIMING_DESTROY.destroy()
call TIMING_FLIGHT.destroy()
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1536.0
set Y = 1024.0
set TIMING_START = 0
set TIMING_CAST = 0
set TIMING_DESTROY = 0
set TIMING_FLIGHT = 0
set COLLIDED_UNIT_NAME = ""
set COLLISION_COUNT = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call AddTriggerPlayerUnitEvent(CASTER_OWNER, EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.OnCast)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Collided_U", MISSILE_TYPE, function thistype.OnCollide)
call AddTriggerCustomEvent("udg_CMS_Event_Missile_Destroyed", MISSILE_TYPE, function thistype.OnDestroy)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_MagicMissile extends UnitTest
static string NAME = "Paladin_MagicMissile"
static real DURATION = 5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A004'
static string CAST_ORDER = "charm"
static unit CASTER
static unit TARGET
private static method MoveTargetUp takes nothing returns nothing
call SetUnitY(TARGET, Y + 256)
endmethod
private static method MoveTargetDown takes nothing returns nothing
call SetUnitY(TARGET, Y - 256)
endmethod
private method Start takes nothing returns nothing
local real source_x = X + 512
local real source_y = Y
local real target_x = X - 128
local real target_y = Y - 256
set CASTER = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
set TARGET = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 0))
call SetHeroLevel(CASTER, 10, false)
call SelectHeroSkill(CASTER, ABILITY_ID)
call SetUnitAbilityLevel(CASTER, ABILITY_ID, 3)
call IssueTargetOrder(CASTER, CAST_ORDER, TARGET)
call Delayed(1.0, function thistype.MoveTargetUp)
call Delayed(1.5, function thistype.MoveTargetDown)
call Delayed(2.0, function thistype.MoveTargetUp)
call Delayed(2.5, function thistype.MoveTargetDown)
endmethod
private static method OnComplete takes nothing returns nothing
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1280.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_Firebolt extends UnitTest
static string NAME = "Paladin_Firebolt"
static real DURATION = 5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A003'
static string CAST_ORDER = "channel"
static unit CASTER
static unit TARGET
private static method CastAgain takes nothing returns nothing
call IssueTargetOrder(CASTER, CAST_ORDER, TARGET)
endmethod
private method Start takes nothing returns nothing
local real source_x = X + 512
local real source_y = Y
local real target_x = X - 128
local real target_y = Y
set CASTER = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
set TARGET = AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 0))
call SetHeroLevel(CASTER, 10, false)
call SelectHeroSkill(CASTER, ABILITY_ID)
call SetUnitAbilityLevel(CASTER, ABILITY_ID, 3)
call IssueTargetOrder(CASTER, CAST_ORDER, TARGET)
call Delayed(2.0, function thistype.CastAgain)
endmethod
private static method OnComplete takes nothing returns nothing
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = -1280.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_FuryFire extends UnitTest
static string NAME = "Paladin_FuryFire"
static real DURATION = 5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A005'
static string CAST_ORDER = "chemicalrage"
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 200, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + 200, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 200, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - 200, 180))
call SetHeroLevel(caster, 10, false)
call SelectHeroSkill(caster, ABILITY_ID)
call SetUnitAbilityLevel(caster, ABILITY_ID, 3)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
endmethod
private static method OnComplete takes nothing returns nothing
set udg_CMS_Param_IsDestroyed[udg_CMS_Amount] = true
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_MeteorStrike extends UnitTest
static string NAME = "Paladin_MeteorStrike"
static real DURATION = 5
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A009'
static string CAST_ORDER = "inferno"
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 100, target_y + 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 200, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 100, target_y - 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + 200, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 100, target_y - 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 200, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 100, target_y + 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - 200, 180))
call SetHeroLevel(caster, 10, false)
call SelectHeroSkill(caster, ABILITY_ID)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
endmethod
private static method OnComplete takes nothing returns nothing
call ResetToGameCamera(0)
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 0)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_Blizzard extends UnitTest
static string NAME = "Jaina_Blizzard"
static real DURATION = 8
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H004'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A00A'
static string CAST_ORDER = "blizzard"
private method Start takes nothing returns nothing
local real source_x = X - 400
local real source_y = Y
local real target_x = X
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 100, target_y + 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 150, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + 100, target_y - 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + 150, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 100, target_y - 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 150, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - 100, target_y + 100, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - 150, 180))
call SetHeroLevel(caster, 10, false)
call SelectHeroSkill(caster, ABILITY_ID)
call SetUnitAbilityLevel(caster, ABILITY_ID, 3)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
endmethod
private static method OnComplete takes nothing returns nothing
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_FrostNova extends UnitTest
static string NAME = "Jaina_FrostNova"
static real DURATION = 8
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'H004'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A00D'
static string CAST_ORDER = "berserk"
private method Start takes nothing returns nothing
local real d1 = 800
local real d2 = SquareRoot(d1 * d1 * 0.5)
local real source_x = X
local real source_y = Y
local real target_x = X
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d2, target_y + d2, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d1, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d2, target_y - d2, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + d1, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d2, target_y - d2, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d1, target_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d2, target_y + d2, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - d1, 180))
call SetHeroLevel(caster, 10, false)
call SelectHeroSkill(caster, ABILITY_ID)
call IssueImmediateOrder(caster, CAST_ORDER)
endmethod
private static method OnComplete takes nothing returns nothing
call ResetToGameCamera(0)
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 0
set Y = 0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 0)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_RocketBarrage extends UnitTest
static string NAME = "Tinker_RocketBarrage"
static real DURATION = 7
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'N000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A00C'
static string CAST_ORDER = "blizzard"
private method Start takes nothing returns nothing
local real d1 = 200
local real d2 = SquareRoot(d1 * d1 * 0.5)
local real source_x = X + 1400
local real source_y = Y
local real target_x = X - 1400
local real target_y = Y
local unit caster = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d2, target_y + d2, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d1, target_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x + d2, target_y - d2, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + d1, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d2, target_y - d2, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d1, target_y, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x - d2, target_y + d2, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - d1, 0))
call SetHeroLevel(caster, 10, false)
call SelectHeroSkill(caster, ABILITY_ID)
call SetUnitAbilityLevel(caster, ABILITY_ID, 3)
call IssuePointOrder(caster, CAST_ORDER, target_x, target_y)
endmethod
private static method OnComplete takes nothing returns nothing
call ResetToGameCamera(0)
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 1000.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 3000.00, 0)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct
struct Showcase_SeekerMissile extends UnitTest
static string NAME = "Tinker_SeekerMissile"
static real DURATION = 7
// inputs:
static Assert assert = 0
static real X = 0.0
static real Y = 0.0
static player CASTER_OWNER = Player(0)
static player TARGET_OWNER = Player(1)
static integer CASTER_UNIT_TYPE = 'N000'
static integer TARGET_UNIT_TYPE = 'hfoo'
static integer ABILITY_ID = 'A00B'
static string CAST_ORDER = "blink"
static unit CASTER
private static method CastAgain takes nothing returns nothing
call IssuePointOrder(CASTER, CAST_ORDER, X, Y)
endmethod
private method Start takes nothing returns nothing
local real source_x = X + 1000
local real source_y = Y
local real target_x = X - 1000
local real target_y = Y
set CASTER = AddUnit(CreateUnit(CASTER_OWNER, CASTER_UNIT_TYPE, source_x, source_y, 180))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y + 500, 0))
call AddUnit(CreateUnit(TARGET_OWNER, TARGET_UNIT_TYPE, target_x, target_y - 500, 0))
call SetHeroLevel(CASTER, 10, false)
call SelectHeroSkill(CASTER, ABILITY_ID)
call SetUnitAbilityLevel(CASTER, ABILITY_ID, 3)
call IssuePointOrder(CASTER, CAST_ORDER, target_x, target_y)
call Delayed(1.0, function thistype.CastAgain)
endmethod
private static method OnComplete takes nothing returns nothing
call ResetToGameCamera(0)
call EndTest(assert)
endmethod
method GetName takes nothing returns string
return NAME
endmethod
method Run takes nothing returns nothing
set X = 1000.0
set Y = 0.0
if assert == 0 then
set assert = Assert.create(NAME)
endif
call assert.Reset()
call TestSetCamera(X, Y)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 2000.00, 0)
call Delayed(DURATION, function thistype.OnComplete)
call Start()
endmethod
endstruct