native UnitAlive takes unit u returns boolean
native GetUnitGoldCost takes integer id returns integer
native GetUnitWoodCost takes integer id returns integer
native GetUnitBuildTime takes integer id returns integer
Name | Type | is_array | initial_value |
ALLOW_FRIENDLY_FIRE | boolean | No | false |
AmericanAll | force | No | |
AmericanMajors | force | No | |
AmericanMinors | force | No | |
AmericanObservers | force | No | |
AmericanPlayersHere | integer | No | |
ApproachingUnit | unit | No | |
ApproachingUnitLoc | location | No | |
BonusTruckSpawn | location | No | |
BonusUnitSpawn | location | Yes | |
BonusUnitType | unitcode | No | |
BuffDummyGroup | group | No | |
CaptureCity | unit | No | |
CaptureCityDamageSource | unit | No | |
CaptureCityLifeAfterDmg | real | No | |
CaptureCityLifeBeforeDmg | real | No | |
CaptureCityMaxLife | real | No | |
CaptureCityType | unitcode | No | |
CaptureFriendlyFire | boolean | No | |
CaptureIrregular | boolean | No | |
CaptureNewOwner | player | No | |
CaptureOldOwner | player | No | |
CaptureOriginalOwner | player | No | |
CheckpointLocA | location | Yes | |
CheckpointLocB | location | Yes | |
CheckpointLocC | location | Yes | |
CITY_INCOME | real | No | 100.00 |
CITY_SUPPLY | integer | No | |
COLOR_NORTH_RED | string | No | |cffff0303 |
COLOR_SOUTH_YELLOW | string | No | |cffffff00 |
COMMUNIST_INCOME_BASE | real | No | 100.00 |
CommunistCities | real | No | |
CommunistIncome | real | No | |
CommunistIncomeFactor | real | No | 1.00 |
CommunistIncomeThisMonth | real | No | |
CommunistsRoyalists | force | No | |
DateTimer | timer | No | |
DateTimerWindow | timerdialog | No | |
DEBUG_ON | boolean | No | |
DerelictPlayer | player | No | |
FlagNorthHanoi | unit | No | |
FlagNorthSaigon | unit | No | |
FlagSouthHanoi | unit | No | |
FlagSouthSaigon | unit | No | |
GameOver | boolean | No | |
GLOBAL_INCOME_FACTOR | real | No | 1.00 |
LeavingPlayer | player | No | PlayerNP |
Missile | integer | No | |
Missile_onBoundaries | trigger | No | |
Missile_onCliff | trigger | No | |
Missile_onDestructable | trigger | No | |
Missile_onFinish | trigger | No | |
Missile_onHit | trigger | No | |
Missile_onItem | trigger | No | |
Missile_onMissile | trigger | No | |
Missile_onPause | trigger | No | |
Missile_onPeriod | trigger | No | |
Missile_onRemove | trigger | No | |
Missile_onResume | trigger | No | |
Missile_onTerrain | trigger | No | |
Missile_onTileset | trigger | No | |
MissileAcceleration | real | No | |
MissileAlpha | integer | No | |
MissileAnimation | integer | No | |
MissileArc | real | No | |
MissileAt | integer | No | |
MissileAttachModel | string | No | |
MissileAttachScale | real | No | |
MissileAttachX | real | No | |
MissileAttachY | real | No | |
MissileAttachZ | real | No | |
MissileBlue | integer | No | |
MissileCollideZ | boolean | No | |
MissileCollision | real | No | |
MissileCurve | real | No | |
MissileDamage | real | No | |
MissileData | integer | No | |
MissileDeflectPosition | location | No | |
MissileDeflectTarget | unit | No | |
MissileDeflectZ | real | No | |
MissileDestroy | boolean | No | |
MissileDetachEffect | effect | No | |
MissileDuration | real | No | |
MissileEvent | integer | No | |
MissileFinish | location | No | |
MissileFinishZ | real | No | |
MissileFlushUnit | unit | No | |
MissileGreen | integer | No | |
MissileGroup | integer | No | |
MissileGroupAddGroup | integer | No | |
MissileGroupCounted | integer | No | |
MissileGroupLocation | location | No | |
MissileGroupPlayer | player | No | |
MissileGroupRange | real | No | |
MissileGroupRect | rect | No | |
MissileGroupRemoveGroup | integer | No | |
MissileGroupSize | integer | No | |
MissileGroupType | integer | No | |
MissileHitDestructable | destructable | No | |
MissileHitItem | item | No | |
MissileHitMissile | integer | No | |
MissileHitted | boolean | No | |
MissileHittedUnit | unit | No | |
MissileHitUnit | unit | No | |
MissileLastPosition | location | No | |
MissileModel | string | No | |
MissileNextPosition | location | No | |
MissileNextZ | real | No | |
MissileOnBoundaries | integer | No | 8 |
MissileOnCliff | integer | No | 12 |
MissileOnDestructable | integer | No | 4 |
MissileOnFinish | integer | No | 7 |
MissileOnHit | integer | No | 2 |
MissileOnItem | integer | No | 5 |
MissileOnMissile | integer | No | 3 |
MissileOnPause | integer | No | 9 |
MissileOnPeriod | integer | No | 1 |
MissileOnRemove | integer | No | 11 |
MissileOnResume | integer | No | 10 |
MissileOnTerrain | integer | No | 6 |
MissileOnTileset | integer | No | 13 |
MissileOwner | player | No | |
MissilePaused | boolean | No | |
MissilePlayerColor | integer | No | |
MissilePosition | location | No | |
MissilePrevZ | real | No | |
MissileRed | integer | No | |
MissileRemoveLocations | boolean | No | true |
MissileRoll | boolean | No | |
MissileScale | real | No | |
MissileSource | unit | No | |
MissileSpeed | real | No | |
MissileStart | location | No | |
MissileStartZ | real | No | |
MissileTarget | unit | No | |
MissileTileset | integer | No | |
MissileTimeScale | real | No | |
MissileTravelled | real | No | |
MissileType | integer | No | |
MissileVelocity | real | No | |
MissileVision | real | No | |
MissileZ | real | No | |
Month | integer | No | 8 |
Months | string | Yes | |
NearestCheckpoint | unit | No | |
NearestCheckpointGroup | group | No | |
NORTH_INCOME_BASE | real | No | 65.00 |
NORTH_INCOME_FACTOR | real | No | 0.80 |
NORTH_OCC_FACTOR | real | No | 0.75 |
NORTH_OWN_OCC_FACTOR | real | No | 0.75 |
NORTH_VIET_INCOME_BASE | integer | No | 50 |
NORTH_VIETNAM_MONEY | integer | No | 1000 |
NorthIncome | real | No | |
NorthIncomeThisMonth | real | No | |
NorthOccCities | real | No | |
NorthOwnCities | real | No | |
NorthOwnOccCities | real | No | |
NorthPlayersHere | integer | No | |
NorthVietIncomeThisMonth | real | No | |
NorthWin | boolean | No | |
NumCheckpoints | integer | No | |
ObserverDialog | dialog | No | |
ObserverDialogButtons | button | Yes | |
ObserversAll | force | No | |
OriginalOwner | player | Yes | |
PLAYER_CHINA | player | No | Player05 |
PLAYER_COMMUNISTS | player | No | Player17 |
PLAYER_NORTH_VIETNAM | player | No | Player00 |
PLAYER_ROYALISTS | player | No | Player19 |
PLAYER_SOUTH_VIETNAM | player | No | Player04 |
PLAYER_THAILAND | player | No | Player06 |
PLAYER_US_BLUE | player | No | Player01 |
PLAYER_US_DARK_GREEN | player | No | Player10 |
PLAYER_US_LIGHT_BLUE | player | No | Player09 |
PLAYER_VIETCONG_BROWN | player | No | Player11 |
PLAYER_VIETCONG_GRAY | player | No | Player08 |
PLAYER_VIETCONG_PINK | player | No | Player07 |
PlayerColor | string | Yes | |
PlayerFactionId | integer | Yes | |
PlayerHere | boolean | Yes | |
PlayerOriginalName | string | Yes | |
PlayerTakingOver | player | No | |
QuestText | string | No | |
ROYALIST_INCOME_BASE | real | No | 100.00 |
RoyalistCities | real | No | |
RoyalistIncome | real | No | |
RoyalistIncomeFactor | real | No | 1.00 |
RoyalistIncomeThisMonth | real | No | |
SECONDS_PER_MONTH | real | No | 40.00 |
SOUTH_INCOME_BASE | real | No | 0.00 |
SOUTH_INCOME_FACTOR | real | No | 1.00 |
SOUTH_OCC_FACTOR | real | No | 0.00 |
SOUTH_OWN_OCC_FACTOR | real | No | 0.00 |
SOUTH_VIET_INCOME_BASE | integer | No | 50 |
SOUTH_VIETNAM_MONEY | integer | No | 1500 |
SouthIncome | real | No | |
SouthIncomeThisMonth | real | No | |
SouthOccCities | real | No | |
SouthOwnCities | real | No | |
SouthOwnOccCities | real | No | |
SouthPlayersHere | integer | No | |
SouthVietIncomeThisMonth | real | No | |
SouthVietnamIncomeFactor | real | No | 0.50 |
STARTING_MONEY_IS_EARNED | boolean | No | true |
StatsPlayer | player | No | |
StatsRotationInterval | real | No | 7.00 |
SupplyEarned | integer | No | |
SupplyPotential | integer | No | |
SupplyTruckSpawn | location | No | |
TOWN_INCOME | real | No | 40.00 |
TOWN_SUPPLY | integer | No | |
UNITED_STATES_FIXED_INCOME | integer | No | 880 |
US_MONEY | integer | No | 1000 |
VICTORY_POINTS_INTERVAL | real | No | 10.00 |
VICTORY_POINTS_TO_WIN | integer | No | 400 |
VictoryBalance | integer | No | |
VictoryLeaderboard | leaderboard | No | |
VictoryPointsNorth | integer | No | |
VictoryPointsSouth | integer | No | |
VietAll | force | No | |
VIETCONG_MONEY | integer | No | 1000 |
VietCongPlayersHere | integer | No | |
VietMajors | force | No | |
VietMinors | force | No | |
VietnamizationLevel | integer | No | 0 |
VietObservers | force | No | |
VILLAGE_INCOME | real | No | 15.00 |
VILLAGE_SUPPLY | integer | No | |
Year | integer | No | 1964 |
YEARLY_INCOME_INCREASE | real | No | 0.02 |
library AbilityConstants
//
// Abilities
//
globals
constant integer ABILITY_AGENT_BLUE = 'Aagb'
constant integer ABILITY_AGENT_ORANGE = 'Aago'
constant integer ABILITY_AIRFIELD_REPAIR = 'A00T'
constant integer ABILITY_ALARM = 'Aalr'
constant integer ABILITY_ARTILLERY_BARRAGE = 'Acab'
constant integer ABILITY_ARTILLERY_BARRAGE_Q = 'Acaa'
constant integer ABILITY_BARRACKS_HEAL = 'A00C'
constant integer ABILITY_BDM_ARMOR = 'A027'
constant integer ABILITY_BDM_HP = 'A029'
constant integer ABILITY_BDM_REGEN = 'A028'
constant integer ABILITY_BM21_ROCKET_BARRAGE = 'Avrb'
constant integer ABILITY_BUILD_AIRFIELD_A = 'A01K'
constant integer ABILITY_BUILD_AIRFIELD_V = 'A01G'
constant integer ABILITY_BUILD_BARRACKS_A = 'A01J'
constant integer ABILITY_BUILD_BARRACKS_V = 'A01F'
constant integer ABILITY_BUILD_BUNKER = 'A020'
constant integer ABILITY_BUILD_COMMAND_HQ_A = 'A01L'
constant integer ABILITY_BUILD_COMMAND_HQ_N = 'A00N'
constant integer ABILITY_BUILD_COMMAND_HQ_V = 'A01E'
constant integer ABILITY_BUILD_DROP_ZONE = 'A01P'
constant integer ABILITY_BUILD_FACTORY_A = 'A01M'
constant integer ABILITY_BUILD_FACTORY_V = 'A01I'
constant integer ABILITY_BUILD_GUERRILLA_CAMP = 'A00O'
constant integer ABILITY_BUILD_HELIPAD = 'A01N'
constant integer ABILITY_BUILD_STRATEGY_CENTER = 'A01O'
constant integer ABILITY_BUILD_UTILITY = 'A01H'
constant integer ABILITY_BUILD_ZPU_4 = 'A023'
constant integer ABILITY_BURST_FIRE = 'Abst'
constant integer ABILITY_CARPET_BOMBING = 'Abrn'
constant integer ABILITY_CEDE_RED = 'Acd0'
constant integer ABILITY_CEDE_BLUE = 'Acd1'
constant integer ABILITY_CEDE_YELLOW = 'Acd4'
constant integer ABILITY_CEDE_PINK = 'Acd7'
constant integer ABILITY_CEDE_GRAY = 'Acd8'
constant integer ABILITY_CEDE_LIGHT_BLUE = 'Acd9'
constant integer ABILITY_CEDE_DARK_GREEN = 'AcdA'
constant integer ABILITY_CEDE_BROWN = 'AcdB'
constant integer ABILITY_CEDE_NORTH = 'Aced'
constant integer ABILITY_CEDE_SOUTH = 'Acdf'
constant integer ABILITY_CLEAR_MINES = 'Aclm'
constant integer ABILITY_D30_DEPLOY = 'A00B'
constant integer ABILITY_DETECTION_POINTMAN = 'A01B'
constant integer ABILITY_DIG_IN = 'A011'
constant integer ABILITY_DISABLE_ATTACK_1 = 'A00Y'
constant integer ABILITY_DROP_MONEY = 'A002'
constant integer ABILITY_DROP_INFANTRY = 'A003'
constant integer ABILITY_DROP_DOZER = 'A004'
constant integer ABILITY_ENTER_TUNNEL = 'Aett'
constant integer ABILITY_ENTER_TUNNEL_SMART = 'Aets'
constant integer ABILITY_EXIT_FOXHOLE = 'A014'
constant integer ABILITY_EXPLOSIVE_TRAP_LONG = 'A005'
constant integer ABILITY_EXPLOSIVE_TRAP_SHORT = 'A00I'
constant integer ABILITY_FACTORY_REPAIR = 'A00S'
constant integer ABILITY_FIRE_ARTILLERY_SHELL = 'A00M'
constant integer ABILITY_FIRST_STRIKE_1 = 'A01V'
constant integer ABILITY_FOUGASSE_EXPLOSION = 'A000'
constant integer ABILITY_GARRISON = 'A012'
constant integer ABILITY_GARRISON_INSTANT = 'A015'
constant integer ABILITY_GARRISON_INVIS = 'A013'
constant integer ABILITY_GRAVEL_MINE_DROP = 'Aagm'
constant integer ABILITY_GRAVEL_MINE_EXPLOSION = 'A00H'
constant integer ABILITY_HUEY_INFANTRY_DROP = 'Aaid'
constant integer ABILITY_IMMOBILIZE_FOXHOLE = 'A016'
constant integer ABILITY_INFORMANTS_1 = 'Avr0'
constant integer ABILITY_INFORMANTS_2 = 'Avr1'
constant integer ABILITY_INSURGENCY = 'A026'
constant integer ABILITY_INTERCEPTOR = 'Avin'
constant integer ABILITY_LAND_MEDEVAC = 'A00G'
constant integer ABILITY_LOAD_DOZER = 'Aldz'
constant integer ABILITY_LOAD_LARGE = 'Aldb'
constant integer ABILITY_LOAD_TYPE_85 = 'Aldt'
constant integer ABILITY_LOCUST = 'Aloc'
constant integer ABILITY_MASS_SELECT_SMALL = 'Amss'
constant integer ABILITY_MASS_SELECT_MEDIUM = 'Amsm'
constant integer ABILITY_MASS_SELECT_LARGE = 'Amsl'
constant integer ABILITY_MASS_SELECT_ALL = 'Amsa'
constant integer ABILITY_MASS_ATTACK = 'Amat'
constant integer ABILITY_MASS_STOP = 'Amst'
constant integer ABILITY_MASS_HOLD_POSITION = 'Amhp'
constant integer ABILITY_MASS_MOVE = 'Ammv'
constant integer ABILITY_MASS_CLEAR = 'Amca'
constant integer ABILITY_MASS_EXIT_FOXHOLE = 'Amef'
constant integer ABILITY_MASS_DIG_IN = 'Amdi'
constant integer ABILITY_NAPALM_EXPLOSION = 'A00R'
constant integer ABILITY_NAPALM_STRIKE = 'Anap'
constant integer ABILITY_NEXT_DROPOFF = 'A001'
constant integer ABILITY_PRECISION_STRIKE_A = 'Apst'
constant integer ABILITY_PRECISION_STRIKE_V = 'Avbo'
constant integer ABILITY_PRIORITIZE_AIR = 'Aatp'
constant integer ABILITY_RADAR_DETECTION = 'A01Z'
constant integer ABILITY_RAPID_CONSCRIPTION = 'Avrc'
constant integer ABILITY_RECON_1 = 'Aar0'
constant integer ABILITY_RECON_2 = 'Aar1'
constant integer ABILITY_REINFORCEMENT = 'A019'
constant integer ABILITY_RELOCATE_MENU_A = 'Aars'
constant integer ABILITY_RELOCATE_MENU_V = 'Avrs'
constant integer ABILITY_RELOCATE_A = 'Aarl'
constant integer ABILITY_RELOCATE_V = 'Avrl'
constant integer ABILITY_REVIVE = 'A00K'
constant integer ABILITY_ROCKET_PODS_MI4 = 'A017'
constant integer ABILITY_ROCKET_PODS_MI4_D = 'A00F'
constant integer ABILITY_RPG_TRAP = 'A009'
constant integer ABILITY_SEND_MONEY = 'A02B'
constant integer ABILITY_SKYRAIDER_STRAFE = 'Astr'
constant integer ABILITY_SNEAK_ATTACK = 'Avsa'
constant integer ABILITY_SNIPE_A = 'Asnj'
constant integer ABILITY_SNIPE_V = 'Asni'
constant integer ABILITY_SPOT_TRAPS = 'A01A'
constant integer ABILITY_SUPPRESSION_INITIAL = 'A02C'
constant integer ABILITY_SUPPRESSION_SUBSEQUENT = 'A02E'
constant integer ABILITY_TRANSFER_FUNDS = 'A02G'
constant integer ABILITY_TRANSFER_FUNDS_INSTANT = 'A02H'
constant integer ABILITY_TRIPWIRE_FLARE = 'A00A'
constant integer ABILITY_TUNNEL_LOAD = 'Alod'
constant integer ABILITY_TUNNEL_LOAD_SMART = 'Alds'
constant integer ABILITY_TUNNEL_UNLOAD = 'Aunl'
constant integer ABILITY_UNLOAD_LARGE = 'Aulb'
constant integer ABILITY_UPRISING_1 = 'Avu0'
constant integer ABILITY_UPRISING_2 = 'Avu1'
constant integer ABILITY_UPRISING_3 = 'Avu2'
constant integer ABILITY_VEHICLE_LOAD = 'S001'
constant integer ABILITY_VEHICLE_LOAD_INSTANT = 'S008'
endglobals
//
// Attribute Abilities
//
globals
constant integer ATTR_AIRPLANE = 'Ax31'
constant integer ATTR_AIR_UNIT = 'Ax33'
constant integer ATTR_AMPHIBIOUS = 'Ax14'
constant integer ATTR_ARTILLERY = 'Ax09'
constant integer ATTR_ARVN_DEBUFF = 'Ax11'
constant integer ATTR_BUILT_BY_TRUCK = 'Ax25'
constant integer ATTR_CANNOT_CAPTURE = 'Ax15'
constant integer ATTR_CANNOT_MOVE = 'Ax06'
constant integer ATTR_CUSTOM_ATTACK_COOLDOWN = 'Ax30'
constant integer ATTR_DAMAGE_MOVE_DEBUFF = 'Ax26'
constant integer ATTR_DEPLOY_ON_ATTACK = 'Ax35'
constant integer ATTR_GLOBAL_CASTER = 'Ax23'
constant integer ATTR_HAS_CARGO = 'Ax10'
constant integer ATTR_HEALS_INFANTRY = 'Ax13'
constant integer ATTR_IGNORE_DEATH = 'Ax28'
constant integer ATTR_IMMUNE_TO_ARTILLERY = 'Ax08'
constant integer ATTR_NO_ALARMS = 'Ax29'
constant integer ATTR_NO_ATTACK = 'Ax01'
constant integer ATTR_NO_AUTO_ACQUIRE = 'Ax03'
constant integer ATTR_NO_DAMAGE = 'Ax02'
constant integer ATTR_NO_ORDER_EVENTS = 'Ax27'
constant integer ATTR_NON_COMBAT = 'Ax20'
constant integer ATTR_PRODUCTION_BUILDING = 'Ax21'
constant integer ATTR_REMOVE_UPON_COMPLETION = 'Ax34'
constant integer ATTR_REPAIRS_AIRCRAFT = 'Ax17'
constant integer ATTR_REPAIRS_VEHICLES = 'Ax16'
constant integer ATTR_RESISTANT_TO_ARTILLERY = 'Ax37'
constant integer ATTR_SETTLEMENT = 'Ax07'
constant integer ATTR_SNIPER = 'Ax00'
constant integer ATTR_TOWED = 'Ax18'
constant integer ATTR_TRACK_MOVEMENT = 'Ax05'
constant integer ATTR_TRAP = 'Ax04'
constant integer ATTR_TWO_BUILD_MENUS = 'Ax12'
constant integer ATTR_UNINDEXED = 'Axui'
endglobals
//
// Buffs
//
globals
constant integer BUFF_BARRAGING = 'B007'
constant integer BUFF_DUG_IN = 'B009'
constant integer BUFF_SUPPRESSION_INITIAL = 'B00G'
constant integer BUFF_SUPPRESSION_SUBSEQUENT = 'B00F'
constant integer BUFF_TIMED_LIFE = 'BTLF'
endglobals
endlibrary
library AttackTypeConstants
globals
constant attacktype ATTACK_TYPE_AP = ATTACK_TYPE_PIERCE
constant attacktype ATTACK_TYPE_BULLETS = ATTACK_TYPE_NORMAL
constant attacktype ATTACK_TYPE_HE = ATTACK_TYPE_SIEGE
constant attacktype ATTACK_TYPE_INCENDIARY = ATTACK_TYPE_MAGIC
endglobals
endlibrary
library DefenseTypeConstants
globals
constant defensetype DEFENSE_TYPE_ARMORED = DEFENSE_TYPE_MEDIUM
constant defensetype DEFENSE_TYPE_INFANTRY = DEFENSE_TYPE_NONE
constant defensetype DEFENSE_TYPE_STRUCTURE = DEFENSE_TYPE_FORT
constant defensetype DEFENSE_TYPE_VEHICLE = DEFENSE_TYPE_LIGHT
endglobals
endlibrary
library DestructibleConstants
globals
constant integer BLOCKER_GROUND_2X2 = 'YTpb'
constant integer BLOCKER_GROUND_4X4 = 'YTpc'
constant integer TREE_DENSE = 'B000'
constant integer TREE_MANGROVE = 'B002'
constant integer TREE_SPARSE = 'B00F'
constant integer TREE_VERY_DENSE = 'B001'
constant integer TREE_VERY_SPARSE = 'B00E'
endglobals
endlibrary
library OrderIdConstants
globals
constant integer ORDER_ACIDBOMB = 852662
constant integer ORDER_ATTACK = 851983
constant integer ORDER_BEARFORM = 852138
constant integer ORDER_BLIZZARD = 852089
constant integer ORDER_CHANNEL = 852600
constant integer ORDER_CLOUDOFFOG = 852473
constant integer ORDER_CREEPTHUNDERCLAP = 852253
constant integer ORDER_CRIPPLE = 852189
constant integer ORDER_DEATHANDDECAY = 852221
constant integer ORDER_DIVINESHIELD = 852090
constant integer ORDER_FARSIGHT = 852122
constant integer ORDER_FINGEROFDEATH = 852230
constant integer ORDER_HARVEST = 852018
constant integer ORDER_HOLDPOSITION = 851993
constant integer ORDER_HOWLOFTERROR = 852588
constant integer ORDER_MOVE = 851986
constant integer ORDER_PATROL = 851990
constant integer ORDER_PRIORITIZEAIR = 852677
constant integer ORDER_PURGE = 852111
constant integer ORDER_RAVENFORM = 852155
constant integer ORDER_REPAIR = 852024
constant integer ORDER_SMART = 851971
constant integer ORDER_STOP = 851972
constant integer ORDER_UNBEARFORM = 852139
constant integer ORDER_UNRAVENFORM = 852156
endglobals
endlibrary
library ResearchConstants
globals
constant integer TECH_AK47 = 'Rvak'
constant integer TECH_BOUNTIES = 'Rvb0'
constant integer TECH_M16 = 'Rm16'
constant integer TECH_RAPID_REPOSITIONING_1 = 'Rvap'
constant integer TECH_RAPID_REPOSITIONING_2 = 'Rvaq'
constant integer TECH_VIETNAMIZATION = 'Ravm'
constant integer REQ_BDM_TRAIN_LIMIT = 'Rx00'
endglobals
endlibrary
library SoundConstants initializer Init uses SoundUtils
private function Init takes nothing returns nothing
//
// Unit Ready
//
call DefineSoundEx("Bm21Ready", "Sounds\\Units\\BM21Ready1.wav", 1735, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("Btr60Ready", "Sounds\\Units\\BTR60Ready1.wav", 2048, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("CaptainReady", "Sounds\\Units\\CaptainReady1.wav", 4666, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("MedicReady", "Sounds\\Units\\MedicReady1.wav", 1964, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("M60Ready", "Sounds\\Units\\M60Ready1.wav", 1421, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("M113Ready", "Sounds\\Units\\M113Ready1.wav", 1028, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("M48PattonReady", "Sounds\\Units\\M48PattonReady1.wav", 1468, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("RedeyeReady", "Sounds\\Units\\RedeyeReady1.wav", 2080, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("RiflemanReady", "Sounds\\Units\\RiflemanReady1.wav", 1501, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("T34Ready", "Sounds\\Units\\T34Ready1.wav", 2066, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("T62Ready", "Sounds\\Units\\T62Ready1.wav", 1660, CHANNEL_UNIT_READY, EAX_DEFAULT)
call DefineSoundEx("Zsu57Ready", "Sounds\\Units\\ZSU57Ready1.wav", 848, CHANNEL_UNIT_READY, EAX_DEFAULT)
//
// Unit Attack
//
call DefineSoundEx("CobraMG", "Abilities\\Weapons\\BloodElfMissile\\BloodMageRangedAttack.wav", 1915, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("HueyGunshipMG", "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.wav", 847, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("HueyGunshipRocket", "Abilities\\Spells\\Orc\\Ensnare\\EnsnareMissile.wav", 2996, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("M16Shot1", "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissileLaunch1.wav", 1008, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("M16Shot2", "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissileLaunch2.wav", 966, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("M16Shot3", "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissileLaunch3.wav", 899, CHANNEL_COMBAT, EAX_COMBAT)
//
// Unit Ack
//
/*
call DefineSoundEx("Bm21Ack1", "Units\\Demon\\Infernal\\InfernalYesAttack1.wav", 1938, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("Bm21Ack2", "Units\\Demon\\Infernal\\InfernalYesAttack2.wav", 1909, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("Bm21Ack3", "Units\\Demon\\Infernal\\InfernalYesAttack3.wav", 2169, CHANNEL_UNIT_ACK, EAX_DEFAULT)
*/
//
// Weapons
//
call DefineSoundEx("CarpetBombExpl", "Sounds\\Effects\\CarpetBombExpl.wav", 2135, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Flare", "Sounds\\Effects\\flare_mine_fire.mp3", 2675, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Fougasse", "Sounds\\Effects\\molotov_noglass_03.mp3", 3239, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Mine1", "Sounds\\Effects\\medium_explosion_mines_01.mp3", 2121, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Mine2", "Sounds\\Effects\\medium_explosion_mines_02.mp3", 2029, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Mine3", "Sounds\\Effects\\medium_explosion_mines_03.mp3", 1522, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Mine4", "Sounds\\Effects\\medium_explosion_mines_04.mp3", 1660, CHANNEL_COMBAT, EAX_COMBAT)
call DefineSoundEx("Napalm", "Sounds\\Effects\\Weapon_Napalm_Ignite.wav", 6245, CHANNEL_COMBAT, EAX_COMBAT)
//
// Interface
//
call DefineSoundEx("JobsDone_A", "Sounds\\Interface\\AmericanJobsDone.wav", 1701, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("JobsDone_V", "Sounds\\Interface\\VietJobsDone.wav", 1205, CHANNEL_UNIT_ACK, EAX_DEFAULT)
//
// Abilities
//
call DefineSoundEx("Recon1", "Sounds\\Interface\\Recon1.wav", 3370, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("Recon2", "Sounds\\Interface\\Recon2.wav", 3169, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("Recon3", "Sounds\\Interface\\Recon3.wav", 3003, CHANNEL_UNIT_ACK, EAX_DEFAULT)
call DefineSoundEx("VerifyBombingRun", "Sounds\\Interface\\VerifyBombingRun.wav", 2054, CHANNEL_UNIT_ACK, EAX_DEFAULT)
endfunction
globals
constant string EAX_COMBAT = "CombatSoundsEAX"
constant string EAX_DEFAULT = "DefaultEAXON"
constant string EAX_DOODADS = "DoodadsEAX"
constant string EAX_HERO_ACKS = "HeroAcksEAX"
constant string EAX_KOTO_DRUMS = "KotoDrumsEAX"
constant string EAX_MISSILES = "MissilesEAX"
constant string EAX_SPELLS = "SpellsEAX"
constant integer CHANNEL_ANIMATIONS = 11
constant integer CHANNEL_BIRTH = 13
constant integer CHANNEL_CINE_AMBIENT = 17
constant integer CHANNEL_CINE_DIALOGUE = 19
constant integer CHANNEL_CINE_GENERAL = 16
constant integer CHANNEL_CINE_MUSIC = 18
constant integer CHANNEL_CINE_SFX1 = 20
constant integer CHANNEL_CINE_SFX2 = 21
constant integer CHANNEL_CINE_SFX3 = 22
constant integer CHANNEL_COMBAT = 5
constant integer CHANNEL_CONSTRUCTION = 12
constant integer CHANNEL_ERROR = 6
constant integer CHANNEL_FIRE = 14
constant integer CHANNEL_GENERAL = 0
constant integer CHANNEL_LEGACY_MIDI = 15
constant integer CHANNEL_LOOPING_AMBIENT = 10
constant integer CHANNEL_LOOPING_MOVEMENT = 9
constant integer CHANNEL_MUSIC = 7
constant integer CHANNEL_UNIT_ACK = 2
constant integer CHANNEL_UNIT_MOVEMENT = 3
constant integer CHANNEL_UNIT_READY = 4
constant integer CHANNEL_UNIT_SELECTION = 1
constant integer CHANNEL_USER_INTERFACE = 8
endglobals
endlibrary
library SpecialEffectConstants
//
// Special Effects
//
globals
constant string SFX_AGENT_BLUE_MIST = "Models\\Effects\\AgentBlueMist.mdl"
constant string SFX_AGENT_BLUE_TERRAIN = "Models\\Effects\\AgentBlueEffect.mdl"
constant string SFX_AGENT_ORANGE_MIST = "Models\\Effects\\AgentOrangeMist.mdl"
constant string SFX_AGENT_ORANGE_TERRAIN = "Models\\Effects\\AgentOrangeEffect.mdl"
constant string SFX_EXPLOSION_SMALL = "Models\\Effects\\NewDirtEXNofire.mdl"
constant string SFX_EXPLOSION_MEDIUM = "Models\\Effects\\NewSmokeEX.mdl"
constant string SFX_EXPLOSION_LARGE = "Models\\Effects\\NewGroundEX.mdl"
constant string SFX_FLAME_BOMB = "Models\\Effects\\FlameBomb.mdl"
constant string SFX_FRAG = "Models\\Effects\\ShrapnelExplosion.mdl"
constant string SFX_SMOKE_BLUE = "Models\\Effects\\StreamSmokeBlue.mdl"
constant string SFX_SMOKE_GREEN = "Models\\Effects\\StreamSmokeGreen.mdl"
constant string SFX_SMOKE_RED = "Models\\Effects\\StreamSmokeRed.mdl"
constant string SFX_STRAFE_TARGET = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl"
constant string SFX_TARGET_INDICATOR = "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl"
constant string SFX_MINE_REMOVED = "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl"
endglobals
//
// Projectiles
//
globals
constant string ARTILLERY_MISSILE = "Abilities\\Weapons\\Mortar\\MortarMissile.mdl"
constant string BOMB_MISSILE = "Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl"
constant string MORTAR_MISSILE = "Models\\Projectiles\\MortarMissile.mdl"
endglobals
endlibrary
library TableKeys
globals
constant key ATTACK_TYPE
constant key BARRAGE_ATTACK_INTERVAL
constant key BARRAGE_MAX_RANGE
constant key BARRAGE_SCATTER_FACTOR
constant key BARRAGE_SHELLS
constant key DAMAGE_BASE
constant key DAMAGE_NUMBER_OF_DICE
constant key DAMAGE_SIDES_PER_DIE
constant key DAMAGE_FACTOR_MEDIUM
constant key DAMAGE_FACTOR_SMALL
constant key DAMAGE_RADIUS_FULL
constant key DAMAGE_RADIUS_MEDIUM
constant key DAMAGE_RADIUS_SMALL
constant key IMPACT_ABILITY
constant key IMPACT_ABILITY_ORDER_STRING
constant key IMPACT_ART
constant key IMPACT_SOUND
constant key MAX_RANGE
constant key MAX_SCATTER_RADIUS
constant key MISSILE_ARC // Launch angle in degrees
constant key MISSILE_ART
constant key MISSILE_LAUNCH_Z
constant key MISSILE_SIZE
constant key MISSILE_SPEED
endglobals
endlibrary
library UnitConstants
//
// Units
//
globals
constant integer UNIT_ACH47_CHINOOK = 'achh'
constant integer UNIT_AH1_COBRA = 'acob'
constant integer UNIT_AIRFIELD_A = 'aair'
constant integer UNIT_AIRFIELD_A_TRUCK = 'aais'
constant integer UNIT_AIRFIELD_V = 'vair'
constant integer UNIT_AIRFIELD_V_TRUCK = 'vais'
constant integer UNIT_APC_M113 = 'aapc'
constant integer UNIT_APC_M113_MG = 'amg0'
constant integer UNIT_BARRACKS_A = 'abar'
constant integer UNIT_BARRACKS_A_TRUCK = 'abas'
constant integer UNIT_BARRACKS_V = 'vbar'
constant integer UNIT_BARRACKS_V_TRUCK = 'vbas'
constant integer UNIT_BLUE_DRAGON_MARINE = 'avk0'
constant integer UNIT_BLUE_DRAGON_MARINE_ICON = 'avkx'
constant integer UNIT_BM21 = 'vrar'
constant integer UNIT_BOUNCING_BETTY = 'vapm'
constant integer UNIT_BOUNCING_BETTY_B = 'vapn'
constant integer UNIT_BTR60 = 'vapc'
constant integer UNIT_BTR60_MG = 'vmg1'
constant integer UNIT_BUNKER = 'vbun'
constant integer UNIT_BUNKER_TRUCK = 'vbuo'
constant integer UNIT_CAPTAIN = 'acap'
constant integer UNIT_CITY = 'vcit'
constant integer UNIT_COMMAND_HQ_A = 'acom'
constant integer UNIT_COMMAND_HQ_A_TRUCK = 'acon'
constant integer UNIT_COMMAND_HQ_N = 'vcmg'
constant integer UNIT_COMMAND_HQ_N_TRUCK = 'vcmh'
constant integer UNIT_COMMAND_HQ_V = 'vcom'
constant integer UNIT_COMMAND_HQ_V_TRUCK = 'vcmi'
constant integer UNIT_DOZER = 'adoz'
constant integer UNIT_DROP_ZONE = 'adpz'
constant integer UNIT_DROP_ZONE_TRUCK = 'adpa'
constant integer UNIT_D30_DEPLOYED = 'vard'
constant integer UNIT_D30_ICON = 'varx'
constant integer UNIT_D30_TOWED = 'vart'
constant integer UNIT_FACTORY_A = 'afty'
constant integer UNIT_FACTORY_A_TRUCK = 'aftz'
constant integer UNIT_FACTORY_V = 'vfac'
constant integer UNIT_FACTORY_V_TRUCK = 'vfad'
constant integer UNIT_FOUGASSE = 'vfou'
constant integer UNIT_FOUGASSE_B = 'vfov'
constant integer UNIT_FOXHOLE = 'afox'
constant integer UNIT_GRAVEL_MINE = 'agvm'
constant integer UNIT_GUERRILLA = 'vgu0'
constant integer UNIT_GUERRILLA_UP = 'vgu1'
constant integer UNIT_GUERRILLA_CAMP = 'vgca'
constant integer UNIT_GUERRILLA_CAMP_TRUCK = 'vgcb'
constant integer UNIT_HELIPAD = 'ahpd'
constant integer UNIT_HELIPAD_TRUCK = 'ahpe'
constant integer UNIT_INSURGENCY = 'vins'
constant integer UNIT_INSURGENCY_GUERRILLA = 'vgui'
constant integer UNIT_LAW = 'alaw'
constant integer UNIT_LAW_V = 'avat'
constant integer UNIT_MAXIM = 'vmax'
constant integer UNIT_MAXIM_D = 'vmay'
constant integer UNIT_MAXIM_N = 'vcmx'
constant integer UNIT_MAXIM_N_D = 'vcmy'
constant integer UNIT_MEDEVAC = 'amdv'
constant integer UNIT_MEDIC = 'amed'
constant integer UNIT_MISSILE_LAUNCHER = 'vsam'
constant integer UNIT_MISSILE_LAUNCHER_UP = 'vsan'
constant integer UNIT_MI4 = 'vmi4'
constant integer UNIT_MORTAR = 'vmom'
constant integer UNIT_MORTAR_D = 'vmod'
constant integer UNIT_M48_PATTON = 'am48'
constant integer UNIT_M48_PATTON_MG = 'amg1'
constant integer UNIT_M48_PATTON_TURRET = 'atr0'
constant integer UNIT_M60 = 'amac'
constant integer UNIT_M60_V = 'avmg'
constant integer UNIT_M61_VULCAN_GUN = 'avul'
constant integer UNIT_M67_ZIPPO = 'am67'
constant integer UNIT_M67_ZIPPO_MG = 'amg1'
constant integer UNIT_M67_ZIPPO_TURRET = 'atr1'
constant integer UNIT_M102_DEPLOYED = 'aard'
constant integer UNIT_M102_TOWED = 'aart'
constant integer UNIT_M102_ICON = 'aarx'
constant integer UNIT_OH6_LOACH = 'aloa'
constant integer UNIT_PILLBOX = 'apil'
constant integer UNIT_PILLBOX_UP = 'apim'
constant integer UNIT_POINTMAN = 'apoi'
constant integer UNIT_PUNJI_TRAP = 'vpjt'
constant integer UNIT_PUNJI_TRAP_B = 'vpju'
constant integer UNIT_REDEYE = 'ared'
constant integer UNIT_REDEYE_V = 'avaa'
constant integer UNIT_REGULAR = 'vre0'
constant integer UNIT_REGULAR_UP = 'vre1'
constant integer UNIT_RIFLEMAN = 'are0'
constant integer UNIT_RIFLEMAN_UP = 'are1'
constant integer UNIT_RIFLEMAN_ARVN = 'avr0'
constant integer UNIT_RIFLEMAN_ARVN_UP = 'avr1'
constant integer UNIT_RPG = 'vrpg'
constant integer UNIT_RPG_N = 'vcrp'
constant integer UNIT_RPG_TRAP = 'vatm'
constant integer UNIT_RPG_TRAP_B = 'vatn'
constant integer UNIT_RPK = 'vmac'
constant integer UNIT_RPK_N = 'vcma'
constant integer UNIT_SAM_VEHICLE_DEPLOYED = 'vaas'
constant integer UNIT_SAM_VEHICLE_TOWED = 'vaam'
constant integer UNIT_SAPPER = 'vsap'
constant integer UNIT_SAPPER_N = 'vsaq'
constant integer UNIT_SA7 = 'vsa7'
constant integer UNIT_SA7_N = 'vcsa'
constant integer UNIT_SKYCRANE = 'askc'
constant integer UNIT_SKYRAIDER = 'asky'
constant integer UNIT_STRATEGY_CENTER = 'astr'
constant integer UNIT_STRATEGY_CENTER_TRUCK = 'asts'
constant integer UNIT_TOWN = 'vtow'
constant integer UNIT_TRIPWIRE_FLARE = 'vtwf'
constant integer UNIT_TRIPWIRE_FLARE_B = 'vtwg'
constant integer UNIT_TRUCK_A = 'atru'
constant integer UNIT_TRUCK_V = 'vtgc'
constant integer UNIT_TUNNEL = 'vtun'
constant integer UNIT_TYPE_85 = 'vbui'
constant integer UNIT_T34 = 'vt34'
constant integer UNIT_T34_MG = 'vmg0'
constant integer UNIT_T34_TURRET = 'vtr0'
constant integer UNIT_T54 = 'vt54'
constant integer UNIT_T54_TURRET = 'vtr2'
constant integer UNIT_T62 = 'vt62'
constant integer UNIT_T62_TURRET = 'vtr3'
constant integer UNIT_T62_MG = 'vmg2'
constant integer UNIT_UTILITY = 'vuti'
constant integer UNIT_UTILITY_TRUCK = 'vutk'
constant integer UNIT_UH1_HUEY_GUNSHIP = 'ahgs'
constant integer UNIT_UH1_HUEY_TRANSPORT = 'atrh'
constant integer UNIT_VILLAGE = 'vvil'
constant integer UNIT_ZPU_4 = 'vzpu'
constant integer UNIT_ZPU_4_TRUCK = 'vzpv'
constant integer UNIT_ZSU57 = 'vzsu'
constant integer UNIT_ZSU57_TURRET = 'vtr1'
endglobals
//
// Dummy Units
//
globals
constant integer DUMMY = 'xdum'
constant integer DUMMY_MASS_CONTROLLER = 'xmas'
constant integer DUMMY_RADAR_DETECTION_VISION = 'xvrv'
constant integer DUMMY_BRONCO = 'abro'
constant integer DUMMY_DRAGON_LADY = 'alu2'
constant integer DUMMY_HUEY = 'ahue'
constant integer DUMMY_INFORMANTS_VISION = 'xvrd'
constant integer DUMMY_SKYRAIDER = 'adsk'
constant integer DUMMY_STRATOFORTRESS = 'ab52'
endglobals
endlibrary
library DebugUtils initializer Init uses LocationUtils, SfxUtils
globals
private constant string HIGHLIGHT_EFFECT = "Abilities\\Weapons\\WitchDoctorMissile\\WitchDoctorMissile.mdl"
private boolean LogOn = true
private player Me = null
endglobals
function Log takes string msg returns nothing
if (LogOn) then
call DisplayTimedTextToPlayer(Me, 0, 0, 5, msg)
endif
endfunction
function B2S takes boolean b returns string
if (b) then
return "true"
endif
return "false"
endfunction
function P2S takes real x, real y returns string
return "(" + I2S(R2I(x)) + "," + I2S(R2I(y)) + ")"
endfunction
function U2S takes unit u returns string
return GetUnitName(u) + "[" + I2S(GetUnitId(u)) + "]"
endfunction
function LogB takes boolean b returns nothing
call Log(B2S(b))
endfunction
function LogP takes real x, real y returns nothing
call Log(P2S(x,y))
endfunction
function LogU takes unit u returns nothing
call Log(U2S(u))
endfunction
function LogR takes real r returns nothing
call Log(R2SW(r,0,2))
endfunction
function LogI takes integer i returns nothing
call Log(I2S(i))
endfunction
function GroupDebugPrint takes group g returns nothing
local integer size = BlzGroupGetSize(g)
local integer i = 0
loop
exitwhen (i >= size)
call LogU(BlzGroupUnitAt(g,i))
set i = i + 1
endloop
endfunction
function LogClear takes nothing returns nothing
call ClearTextMessages()
endfunction
function SetLogEnabled takes boolean flag returns nothing
set LogOn = flag
endfunction
function HighlightXY takes real x, real y, real z returns nothing
call CreateTimedEffectAtPoint(HIGHLIGHT_EFFECT, x, y, 5)
call BlzSetSpecialEffectHeight(bj_lastCreatedEffect, z + GetPointZ(x,y))
endfunction
function Highlight takes widget w returns nothing
if (w == null) then
call Log("Highlight - argument is null")
return
endif
call HighlightXY(GetWidgetX(w), GetWidgetY(w), 64)
endfunction
function GotoXY takes real x, real y returns nothing
call PanCameraToTimed(x,y,0)
endfunction
function Goto takes widget w returns nothing
if (w == null) then
call Log("Goto - argument is null")
return
endif
call GotoXY(GetWidgetX(w), GetWidgetY(w))
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
if (SubString(GetPlayerName(Player(i)), 0, 6) == "Derdan") then
set Me = Player(i)
exitwhen true
endif
set i = i + 1
exitwhen (i == bj_MAX_PLAYERS)
endloop
endfunction
endlibrary
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Alloc ~~ By Sevion ~~ Version 1.09 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Alloc?
// - Alloc implements an intuitive allocation method for array structs
//
// =Pros=
// - Efficient.
// - Simple.
// - Less overhead than regular structs.
//
// =Cons=
// - Must use array structs (hardly a con).
// - Must manually call OnDestroy.
// - Must use Delegates for inheritance.
// - No default values for variables (use onInit instead).
// - No array members (use another Alloc struct as a linked list or type declaration).
//
// Methods:
// - struct.allocate()
// - struct.deallocate()
//
// These methods are used just as they should be used in regular structs.
//
// Modules:
// - Alloc
// Implements the most basic form of Alloc. Includes only create and destroy
// methods.
//
// Details:
// - Less overhead than regular structs
//
// - Use array structs when using Alloc. Put the implement at the top of the struct.
//
// - Alloc operates almost exactly the same as default structs in debug mode with the exception of onDestroy.
//
// How to import:
// - Create a trigger named Alloc.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Nestharus for the method of allocation and suggestions on further merging.
// - Bribe for suggestions like the static if and method names.
// - PurgeandFire111 for some suggestions like the merging of Alloc and AllocX as well as OnDestroy stuff.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Alloc
module Alloc
private static integer instanceCount = 0
private thistype recycle
static method allocate takes nothing returns thistype
local thistype this
if (thistype(0).recycle == 0) then
debug if (instanceCount == 8190) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to allocate too many instances!")
debug return 0
debug endif
set instanceCount = instanceCount + 1
set this = instanceCount
else
set this = thistype(0).recycle
set thistype(0).recycle = thistype(0).recycle.recycle
endif
debug set this.recycle = -1
return this
endmethod
method deallocate takes nothing returns nothing
debug if (this.recycle != -1) then
debug call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Alloc ERROR: Attempted to deallocate an invalid instance at [" + I2S(this) + "]!")
debug return
debug endif
set this.recycle = thistype(0).recycle
set thistype(0).recycle = this
endmethod
endmodule
endlibrary
library Ascii /* v1.1.0.0 TheDamian/Nestharus
************************************************************************************
*
* function Char2Ascii takes string s returns integer
* integer ascii = Char2Ascii("F")
*
* function Ascii2Char takes integer a returns string
* string char = Ascii2Char('F')
*
* function A2S takes integer a returns string
* string rawcode = A2S('CODE')
*
* function S2A takes string s returns integer
* integer rawcode = S2A("CODE")
*
************************************************************************************/
globals
private integer array i //hash
private integer array h //hash2
private integer array y //hash3
private string array c //char
endglobals
function Char2Ascii takes string p returns integer
local integer z = i[StringHash(p)/0x1F0748+0x40D]
if (c[z] != p) then
if (c[z - 32] != p) then
if (c[h[z]] != p) then
if (c[y[z]] != p) then
if (c[83] != p) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER: " + p)
return 0
endif
return 83
endif
return y[z]
endif
return h[z]
endif
return z - 32
endif
return z
endfunction
function Ascii2Char takes integer a returns string
return c[a]
endfunction
function A2S takes integer a returns string
local string s=""
loop
set s=c[a-a/256*256]+s
set a=a/256
exitwhen 0==a
endloop
return s
endfunction
function S2A takes string s returns integer
local integer a=0
local integer l=StringLength(s)
local integer j=0
local string m
local integer h
loop
exitwhen j==l
set a = a*256 + Char2Ascii(SubString(s,j,j+1))
set j=j+1
endloop
return a
endfunction
private module Init
private static method onInit takes nothing returns nothing
set i[966] = 8
set i[1110] = 9
set i[1621] = 10
set i[1375] = 12
set i[447] = 13
set i[233] = 32
set i[2014] = 33
set i[1348] = 34
set i[1038] = 35
set i[1299] = 36
set i[1018] = 37
set i[1312] = 38
set i[341] = 39
set i[939] = 40
set i[969] = 41
set i[952] = 42
set i[2007] = 43
set i[1415] = 44
set i[2020] = 45
set i[904] = 46
set i[1941] = 47
set i[918] = 48
set i[1593] = 49
set i[719] = 50
set i[617] = 51
set i[703] = 52
set i[573] = 53
set i[707] = 54
set i[1208] = 55
set i[106] = 56
set i[312] = 57
set i[124] = 58
set i[1176] = 59
set i[74] = 60
set i[1206] = 61
set i[86] = 62
set i[340] = 63
set i[35] = 64
set i[257] = 65
set i[213] = 66
set i[271] = 67
set i[219] = 68
set i[1330] = 69
set i[1425] = 70
set i[1311] = 71
set i[238] = 72
set i[1349] = 73
set i[244] = 74
set i[1350] = 75
set i[205] = 76
set i[1392] = 77
set i[1378] = 78
set i[1432] = 79
set i[1455] = 80
set i[1454] = 81
set i[1431] = 82
set i[1409] = 83
set i[1442] = 84
set i[534] = 85
set i[1500] = 86
set i[771] = 87
set i[324] = 88
set i[1021] = 89
set i[73] = 90
set i[1265] = 91
set i[1941] = 92
set i[1671] = 93
set i[1451] = 94
set i[1952] = 95
set i[252] = 96
set i[257] = 97
set i[213] = 98
set i[271] = 99
set i[219] = 100
set i[1330] = 101
set i[1425] = 102
set i[1311] = 103
set i[238] = 104
set i[1349] = 105
set i[244] = 106
set i[1350] = 107
set i[205] = 108
set i[1392] = 109
set i[1378] = 110
set i[1432] = 111
set i[1455] = 112
set i[1454] = 113
set i[1431] = 114
set i[1409] = 115
set i[1442] = 116
set i[534] = 117
set i[1500] = 118
set i[771] = 119
set i[324] = 120
set i[1021] = 121
set i[73] = 122
set i[868] = 123
set i[1254] = 124
set i[588] = 125
set i[93] = 126
set i[316] = 161
set i[779] = 162
set i[725] = 163
set i[287] = 164
set i[212] = 165
set i[7] = 166
set i[29] = 167
set i[1958] = 168
set i[1009] = 169
set i[1580] = 170
set i[1778] = 171
set i[103] = 172
set i[400] = 174
set i[1904] = 175
set i[135] = 176
set i[1283] = 177
set i[469] = 178
set i[363] = 179
set i[550] = 180
set i[1831] = 181
set i[1308] = 182
set i[1234] = 183
set i[1017] = 184
set i[1093] = 185
set i[1577] = 186
set i[606] = 187
set i[1585] = 188
set i[1318] = 189
set i[980] = 190
set i[1699] = 191
set i[1292] = 192
set i[477] = 193
set i[709] = 194
set i[1600] = 195
set i[2092] = 196
set i[50] = 197
set i[546] = 198
set i[408] = 199
set i[853] = 200
set i[205] = 201
set i[411] = 202
set i[1311] = 203
set i[1422] = 204
set i[1808] = 205
set i[457] = 206
set i[1280] = 207
set i[614] = 208
set i[1037] = 209
set i[237] = 210
set i[1409] = 211
set i[1023] = 212
set i[1361] = 213
set i[695] = 214
set i[161] = 215
set i[1645] = 216
set i[1822] = 217
set i[644] = 218
set i[1395] = 219
set i[677] = 220
set i[1677] = 221
set i[881] = 222
set i[861] = 223
set i[1408] = 224
set i[1864] = 225
set i[1467] = 226
set i[1819] = 227
set i[1971] = 228
set i[949] = 229
set i[774] = 230
set i[1828] = 231
set i[865] = 232
set i[699] = 233
set i[786] = 234
set i[1806] = 235
set i[1286] = 236
set i[1128] = 237
set i[1490] = 238
set i[1720] = 239
set i[1817] = 240
set i[729] = 241
set i[1191] = 242
set i[1164] = 243
set i[413] = 244
set i[349] = 245
set i[1409] = 246
set i[660] = 247
set i[2016] = 248
set i[1087] = 249
set i[1497] = 250
set i[753] = 251
set i[1579] = 252
set i[1456] = 253
set i[606] = 254
set i[1625] = 255
set h[92] = 47
set h[201] = 108
set h[201] = 76
set h[203] = 103
set h[203] = 71
set h[246] = 115
set h[246] = 83
set h[246] = 211
set h[254] = 187
set y[201] = 108
set y[203] = 103
set y[246] = 115
set c[8]="\b"
set c[9]="\t"
set c[10]="\n"
set c[12]="\f"
set c[13]="\r"
set c[32]=" "
set c[33]="!"
set c[34]="\""
set c[35]="#"
set c[36]="$"
set c[37]="%"
set c[38]="&"
set c[39]="'"
set c[40]="("
set c[41]=")"
set c[42]="*"
set c[43]="+"
set c[44]=","
set c[45]="-"
set c[46]="."
set c[47]="/"
set c[48]="0"
set c[49]="1"
set c[50]="2"
set c[51]="3"
set c[52]="4"
set c[53]="5"
set c[54]="6"
set c[55]="7"
set c[56]="8"
set c[57]="9"
set c[58]=":"
set c[59]=";"
set c[60]="<"
set c[61]="="
set c[62]=">"
set c[63]="?"
set c[64]="@"
set c[65]="A"
set c[66]="B"
set c[67]="C"
set c[68]="D"
set c[69]="E"
set c[70]="F"
set c[71]="G"
set c[72]="H"
set c[73]="I"
set c[74]="J"
set c[75]="K"
set c[76]="L"
set c[77]="M"
set c[78]="N"
set c[79]="O"
set c[80]="P"
set c[81]="Q"
set c[82]="R"
set c[83]="S"
set c[84]="T"
set c[85]="U"
set c[86]="V"
set c[87]="W"
set c[88]="X"
set c[89]="Y"
set c[90]="Z"
set c[91]="["
set c[92]="\\"
set c[93]="]"
set c[94]="^"
set c[95]="_"
set c[96]="`"
set c[97]="a"
set c[98]="b"
set c[99]="c"
set c[100]="d"
set c[101]="e"
set c[102]="f"
set c[103]="g"
set c[104]="h"
set c[105]="i"
set c[106]="j"
set c[107]="k"
set c[108]="l"
set c[109]="m"
set c[110]="n"
set c[111]="o"
set c[112]="p"
set c[113]="q"
set c[114]="r"
set c[115]="s"
set c[116]="t"
set c[117]="u"
set c[118]="v"
set c[119]="w"
set c[120]="x"
set c[121]="y"
set c[122]="z"
set c[123]="{"
set c[124]="|"
set c[125]="}"
set c[126]="~"
set c[128] = "€"
set c[130] = "‚"
set c[131] = "ƒ"
set c[132] = "„"
set c[133] = "…"
set c[134] = "†"
set c[135] = "‡"
set c[136] = "ˆ"
set c[137] = "‰"
set c[138] = "Š"
set c[139] = "‹"
set c[140] = "Œ"
set c[142] = "Ž"
set c[145] = "‘"
set c[146] = "’"
set c[147] = "“"
set c[148] = "”"
set c[149] = "•"
set c[150] = "–"
set c[151] = "—"
set c[152] = "˜"
set c[153] = "™"
set c[154] = "š"
set c[155] = "›"
set c[156] = "œ"
set c[158] = "ž"
set c[159] = "Ÿ"
set c[160] = " "
set c[161] = "¡"
set c[162] = "¢"
set c[163] = "£"
set c[164] = "¤"
set c[165] = "¥"
set c[166] = "¦"
set c[167] = "§"
set c[168] = "¨"
set c[169] = "©"
set c[170] = "ª"
set c[171] = "«"
set c[172] = "¬"
set c[174] = "®"
set c[175] = "¯"
set c[176] = "°"
set c[177] = "±"
set c[178] = "²"
set c[179] = "³"
set c[180] = "´"
set c[181] = "µ"
set c[182] = "¶"
set c[183] = "·"
set c[184] = "¸"
set c[185] = "¹"
set c[186] = "º"
set c[187] = "»"
set c[188] = "¼"
set c[189] = "½"
set c[190] = "¾"
set c[191] = "¿"
set c[192] = "À"
set c[193] = "Á"
set c[194] = "Â"
set c[195] = "Ã"
set c[196] = "Ä"
set c[197] = "Å"
set c[198] = "Æ"
set c[199] = "Ç"
set c[200] = "È"
set c[201] = "É"
set c[202] = "Ê"
set c[203] = "Ë"
set c[204] = "Ì"
set c[205] = "Í"
set c[206] = "Î"
set c[207] = "Ï"
set c[208] = "Ð"
set c[209] = "Ñ"
set c[210] = "Ò"
set c[211] = "Ó"
set c[212] = "Ô"
set c[213] = "Õ"
set c[214] = "Ö"
set c[215] = "×"
set c[216] = "Ø"
set c[217] = "Ù"
set c[218] = "Ú"
set c[219] = "Û"
set c[220] = "Ü"
set c[221] = "Ý"
set c[222] = "Þ"
set c[223] = "ß"
set c[224] = "à"
set c[225] = "á"
set c[226] = "â"
set c[227] = "ã"
set c[228] = "ä"
set c[229] = "å"
set c[230] = "æ"
set c[231] = "ç"
set c[232] = "è"
set c[233] = "é"
set c[234] = "ê"
set c[235] = "ë"
set c[236] = "ì"
set c[237] = "í"
set c[238] = "î"
set c[239] = "ï"
set c[240] = "ð"
set c[241] = "ñ"
set c[242] = "ò"
set c[243] = "ó"
set c[244] = "ô"
set c[245] = "õ"
set c[246] = "ö"
set c[247] = "÷"
set c[248] = "ø"
set c[249] = "ù"
set c[250] = "ú"
set c[251] = "û"
set c[252] = "ü"
set c[253] = "ý"
set c[254] = "þ"
set c[255] = "ÿ"
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
library BoundSentinel initializer Init requires DebugUtils
//*************************************************
//* 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 OnLeave takes nothing returns boolean
local unit u = GetFilterUnit()
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
return false
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, Filter(function OnLeave))
set t = null
set r = null
set rc = null
endfunction
endlibrary
library DamageUtils initializer Init requires DebugUtils, UnitUtils
/*
* Public API
*
* function SetUnitDamageDeflectTarget takes unit fromUnit, unit toUnit, real damageFactor, boolean overflow returns nothing
* function RemoveUnitDamageDeflectTarget takes unit fromUnit returns nothing
*
*/
globals
private boolean AllowDamage = false
endglobals
function UnitDamageTargetEx takes unit source, widget target, real amount, attacktype attackType returns boolean
local boolean result
set AllowDamage = true
set result = UnitDamageTarget(source, target, amount, true, true, /*
*/ attackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
set AllowDamage = false
return result
endfunction
function UnitDamagePointEx takes unit source, real x, real y, real radius, real amount, attacktype attackType, boolexpr filter returns boolean
local boolean result = false
local integer size
local integer i = 0
set AllowDamage = true
call GroupEnumUnitsInRange(ENUM_GROUP, x, y, radius, filter)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set result = UnitDamageTarget(source, BlzGroupUnitAt(ENUM_GROUP, i), amount, /*
*/ true, true, attackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) or result
set i = i + 1
endloop
set AllowDamage = false
return result
endfunction
function UnitDamagePointSplash takes unit source, real x, real y, /*
*/ real radiusFull, real radiusMed, real radiusSmall, /*
*/ real damageFactorMed, real damageFactorSmall, real amount, /*
*/ attacktype attackType, boolexpr filter returns boolean
local boolean result = false
local integer size
local integer i = 0
local unit u
local real distance
set AllowDamage = true
call GroupEnumUnitsInRange(ENUM_GROUP, x, y, radiusSmall, filter)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
set distance = UnitDistanceToPoint(u,x,y)
if (distance <= radiusFull) then
set result = UnitDamageTarget(source, u, amount, true, true, /*
*/ attackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) or result
elseif (distance <= radiusMed) then
set result = UnitDamageTarget(source, u, amount * damageFactorMed, true, true, /*
*/ attackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) or result
else
set result = UnitDamageTarget(source, u, amount * damageFactorSmall, true, true, /*
*/ attackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) or result
endif
set i = i + 1
endloop
set AllowDamage = false
set u = null
return result
endfunction
function SetDamageAllowed takes boolean flag returns nothing
set AllowDamage = flag
endfunction
private struct DeflectDamage extends array
private static unit array target
private static real array factor
private static boolean array overflow
private static boolean enabled = true
static method setUnitTarget takes unit fromUnit, unit toUnit, real damageFactor, boolean overflows returns nothing
local integer id = GetUnitId(fromUnit)
if (not (damageFactor != 0)) then
return
endif
set target[id] = toUnit
set factor[id] = damageFactor
set overflow[id] = overflows
endmethod
static method removeUnitTarget takes unit fromUnit returns nothing
set target[GetUnitId(fromUnit)] = null
endmethod
private static method onDamage takes nothing returns nothing
local unit u
local integer id
local unit source
local real damage
local real damageFactor
local real overflowDamage
local boolean isAttack
local boolean isRanged
local attacktype attackType
local damagetype damageType
local weapontype weaponType
if (not enabled) then
return
endif
set u = BlzGetEventDamageTarget()
set id = GetUnitId(u)
if (target[id] != null) then
set enabled = false
set source = GetEventDamageSource()
set damage = GetEventDamage()
set damageFactor = factor[id]
set overflowDamage = 0
if (overflow[id]) then
set overflowDamage = RMaxBJ(0, damage * damageFactor - GetWidgetLife(target[id]))
endif
set isAttack = BlzGetEventIsAttack()
set isRanged = IsUnitType(source, UNIT_TYPE_RANGED_ATTACKER)
set attackType = BlzGetEventAttackType()
set damageType = BlzGetEventDamageType()
set weaponType = BlzGetEventWeaponType()
call BlzSetEventDamage(0)
call UnitDamageTarget(source, target[id], damage * damageFactor, /*
*/ isAttack, isRanged, attackType, damageType, weaponType)
set damageFactor = 1 - damageFactor
if (damageFactor > 0) then
call UnitDamageTarget(source, u, overflowDamage + damage * damageFactor, /*
*/ isAttack, isRanged, attackType, damageType, weaponType)
endif
set enabled = true
set source = null
endif
set u = null
endmethod
private static method onDeath takes nothing returns nothing
set target[GetUnitId(GetTriggerUnit())] = null
endmethod
private static method onDeindex takes nothing returns nothing
set target[GetIndexedUnitId()] = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function thistype.onDamage)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call OnUnitDeindex(function thistype.onDeindex)
endmethod
endstruct
function SetUnitDamageDeflectTarget takes unit fromUnit, unit toUnit, real damageFactor, boolean overflow returns nothing
call DeflectDamage.setUnitTarget(fromUnit, toUnit, damageFactor, overflow)
endfunction
function RemoveUnitDamageDeflectTarget takes unit fromUnit returns nothing
call DeflectDamage.removeUnitTarget(fromUnit)
endfunction
private function OnDamaging takes nothing returns nothing
if (UnitHasAbility(GetEventDamageSource(), ATTR_NO_DAMAGE) and not AllowDamage) then
call BlzSetEventDamage(0)
endif
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGING, function OnDamaging)
endfunction
endlibrary
library DelayedOrder uses TimerUtils, UnitDex
/*
* Public API
*
* function IssueImmediateOrderByIdDelayed takes unit u, integer orderId, real delay returns nothing
* function IssuePointOrderByIdDelayed takes unit u, integer orderId, real x, real y, real delay returns nothing
* function IssueTargetOrderByIdDelayed takes unit u, integer orderId, widget target, real delay returns nothing
*
*/
private struct DelayedOrder extends array
private unit unit
private integer orderId
private real x
private real y
private widget target
private timer timer
private static method create takes unit u, integer orderId returns thistype
local thistype this = GetUnitId(u)
set .unit = u
set .orderId = orderId
if (.timer == null) then
set .timer = NewTimer(this)
endif
return this
endmethod
private method destroy takes nothing returns nothing
set .unit = null
set .target = null
set .timer = null
endmethod
private static method executeImmediateOrder takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call IssueImmediateOrderById(.unit, .orderId)
call .destroy()
endmethod
private static method executePointOrder takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call IssuePointOrderById(.unit, .orderId, .x, .y)
call .destroy()
endmethod
private static method executeTargetOrder takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call IssueTargetOrderById(.unit, .orderId, .target)
call .destroy()
endmethod
static method immediateOrder takes unit u, integer orderId, real delay returns nothing
local thistype this = create(u, orderId)
call TimerStart(.timer, delay, false, function thistype.executeImmediateOrder)
endmethod
static method pointOrder takes unit u, integer orderId, real x, real y, real delay returns nothing
local thistype this = create(u, orderId)
set .x = x
set .y = y
call TimerStart(.timer, delay, false, function thistype.executePointOrder)
endmethod
static method targetOrder takes unit u, integer orderId, widget target, real delay returns nothing
local thistype this = create(u, orderId)
set .target = target
call TimerStart(.timer, delay, false, function thistype.executeTargetOrder)
endmethod
endstruct
function IssueImmediateOrderByIdDelayed takes unit u, integer orderId, real delay returns nothing
call DelayedOrder.immediateOrder(u, orderId, delay)
endfunction
function IssuePointOrderByIdDelayed takes unit u, integer orderId, real x, real y, real delay returns nothing
call DelayedOrder.pointOrder(u, orderId, x, y, delay)
endfunction
function IssueTargetOrderByIdDelayed takes unit u, integer orderId, widget target, real delay returns nothing
call DelayedOrder.targetOrder(u, orderId, target, delay)
endfunction
endlibrary
library DestUtils initializer Init uses RectUtils, UnitDex
globals
private Table Data
private integer TreeCount = 0
endglobals
function EnumDestInRange takes real x, real y, real radius, code actionFunc returns nothing
local rect r = GetRectFromCircle(x, y, radius)
set FilterX = x
set FilterY = y
set FilterRadius = radius
call EnumDestructablesInRect(r, FILTER_DEST_WITHIN_RANGE, actionFunc)
call RemoveRect(r)
set r = null
endfunction
function IsDestAlive takes destructable d returns boolean
return GetWidgetLife(d) > 0
endfunction
function IsDestTree takes destructable d returns boolean
return Data.boolean[GetDestructableTypeId(d)]
endfunction
private function TreeGetNeighborsEnum takes nothing returns nothing
if (IsDestTree(GetEnumDestructable())) then
set TreeCount = TreeCount + 1
endif
endfunction
private function TreeGetNeighborsAliveEnum takes nothing returns nothing
local destructable d = GetEnumDestructable()
if (GetWidgetLife(d) > 0 and IsDestTree(d)) then
set TreeCount = TreeCount + 1
endif
set d = null
endfunction
function TreeGetNeighbors takes destructable d, real radius, boolean includeDead returns integer
set TreeCount = 0
if (includeDead) then
call EnumDestInRange(GetWidgetX(d), GetWidgetY(d), radius, function TreeGetNeighborsEnum)
else
call EnumDestInRange(GetWidgetX(d), GetWidgetY(d), radius, function TreeGetNeighborsAliveEnum)
endif
return TreeCount
endfunction
// Tree models have been modified to use blight texture for certain animations
function TreeAddBlight takes destructable d returns nothing
call SetDestructableAnimation(d, "attack")
call SetDestructableOccluderHeight(d, 0)
endfunction
function TreeRemoveBlight takes destructable d returns nothing
call SetDestructableAnimation(d, "stand")
call SetDestructableOccluderHeight(d, 100)
endfunction
private function Init takes nothing returns nothing
set Data = Table.create()
set Data.boolean[TREE_DENSE] = true
set Data.boolean[TREE_SPARSE] = true
set Data.boolean[TREE_VERY_DENSE] = true
set Data.boolean[TREE_VERY_SPARSE] = true
endfunction
endlibrary
//*
//* DummyUnitStack is a library designed to give spell developers immediate
//* access to any number of dummy units at any time by hacking around the
//* engine limitations associated with CreateUnit() - essentially, all we do
//* is create units in a deferred manner which not only caches dummies, but
//* also prevents simultaneous unit instantiations on a more global scale.
//* In other words, we create a few units, very often, until we have a lot.
//*
//* The public API for DummyUnitStack is simple - just get and release:
//* local unit u = DummyUnitStack.get()
//* call DummyUnitStack.release(u)
//*
//* The more complex part is the preloading options available. For most cases
//* the default options will more than suffice, but if you really want to get
//* aggressive with your optimizations, you can do some maths yourself and
//* decide on every limit used in the system.
//*
//* Enjoy,
//* -Cokemonkey11
//*
library DummyUnitStack uses TimedUnitEffect, TimerUtils, UnitDex
globals
private constant real DEFAULT_LIFETIME = 2
unit Dummy = null
endglobals
private function ReleaseDummyExp takes nothing returns nothing
call DummyUnitStack.release(GetUnitById(ReleaseTimer(GetExpiredTimer())))
endfunction
function ReleaseDummyTimed takes unit u, real delay returns nothing
call TimerStart(NewTimer(GetUnitId(u)), delay, false, function ReleaseDummyExp)
endfunction
function GetDummy takes player p, real x, real y, boolean autoRelease returns unit
set Dummy = DummyUnitStack.get()
//call PauseUnit(Dummy, false)
call SetUnitOwner(Dummy, p, true)
call SetUnitPosition(Dummy, x, y)
call UnitAddAbility(Dummy, ABILITY_LOCUST)
if (autoRelease) then
call ReleaseDummyTimed(Dummy, DEFAULT_LIFETIME)
endif
return Dummy
endfunction
function DummyBuildOrder takes player p, integer unitId, real x, real y returns nothing
call GetDummy(p, x, y, true)
call IssuePointOrderById(Dummy, unitId, x, y)
// Instead of releasing it after a delay equal to the unit's build time,
// just make sure the constructed unit is undead so it can be summoned
//call ReleaseDummyTimed(Dummy, DEFAULT_LIFETIME + GetUnitBuildTime(unitId))
endfunction
function DummyPointCast takes player p, integer abilityId, integer orderId, real x, real y returns boolean
call GetDummy(p, x, y, true)
call UnitAddAbilityTimed(Dummy, abilityId, DEFAULT_LIFETIME)
return IssuePointOrderById(Dummy, orderId, x, y)
endfunction
function DummyTargetCast takes player p, integer abilityId, integer orderId, widget target returns boolean
call GetDummy(p, GetWidgetX(target), GetWidgetY(target), true)
call UnitAddAbilityTimed(Dummy, abilityId, DEFAULT_LIFETIME)
return IssueTargetOrderById(Dummy, orderId, target)
endfunction
function DummyInstantCast takes player p, integer abilityId, integer orderId, real x, real y returns boolean
call GetDummy(p, x, y, true)
call UnitAddAbilityTimed(Dummy, abilityId, DEFAULT_LIFETIME)
return IssueImmediateOrderById(Dummy, orderId)
endfunction
function ReleaseDummy takes unit u returns nothing
call DummyUnitStack.release(u)
endfunction
// Just a shim for the API, the struct is not actually instanciated.
struct DummyUnitStack extends array
//*********************************************************************
//* CUSTOMIZABLE SECTION
//*********************************************************************
// This bit is important - make sure this refers to the dummy unit
// in the test map
private static constant integer DUMMY_UNIT_ID='xdum'
// Whenever the preloading process turns on, we set a minimum number
// of units to load, to prevent turning the system on and off too
// often - here you can choose the minimum count (default 10)
private static constant integer MIN_PRELOAD_BLOCK_SIZE=8
// This value is the initialization preload value. Higher numbers
// will increase map load time, but give the best performance. The
// ideal value should be something between the number of dummies used
// in the first few minutes, and the maximum number of dummies used
// in theory. Additionally, you can turn the feature off entirely.
// (default 200)
private static constant integer PRELOAD_INIT_COUNT=256
private static constant boolean DO_PIC=true
// When a series of dummies are retrived using .get(), the stack size
// falls and approaches 0 - with this setting, we can turn on the
// preloader whenever the stack size falls to an arbitrary number.
// Again, this feature can be turned off. (default 20)
private static constant integer DYNAMIC_DEFERRED_PRELOAD_COUNT=20
private static constant boolean DO_DDPC=false
// When the map starts, the preloader turns on right away, preloading
// more units - this can be tweaked to reduce loading time without
// losing dummies available at the beginning of the game. (default 20)
private static constant integer INITIAL_DEFERRED_PRELOAD_COUNT=20
private static constant boolean DO_IDPC=false
// If a dummy unit is released and the stack exceeds this size, the unit
// will instead be removed.
private static constant integer MAX_PRELOADED_UNITS=512
private static constant boolean DO_MPU=false
// Here we have another "hack-like" design choice. The developer must
// specify an (x,y) coordinate pair where dummy units can be moved on
// release - we do this because there is a bug associaed with ShowUnit()
// and the locust ability. :(
private static constant real SAFE_LOC_X=-20400
private static constant real SAFE_LOC_Y=-26400
// Normally a not-so-useful tweaking variable, clock period in dummy unit
// stack is actually quite powerful because we're not relying on any
// kind of smooth movement for releasing/getting. (default 1./60.)
private static constant real CLOCK_PERIOD=1./10.
//*********************************************************************
//* END CUSTOMIZABLE SECTION
//*********************************************************************
private static unit array dummyStack
private static integer stackIndex=-1
private static integer deferredTodoCount=0
private static timer clock=CreateTimer()
//* Private method used for creating a unit by the system
private static method add takes boolean preloading returns unit
set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),thistype.DUMMY_UNIT_ID,thistype.SAFE_LOC_X,thistype.SAFE_LOC_Y,0.)
call UnitAddAbility(bj_lastCreatedUnit,'Aloc')
//call UnitAddAbility(bj_lastCreatedUnit,'Arav')
if preloading then
set thistype.stackIndex=thistype.stackIndex+1
set thistype.dummyStack[thistype.stackIndex]=bj_lastCreatedUnit
else
return bj_lastCreatedUnit
endif
return null
endmethod
//* Private periodic method used for preloading
private static method deferredPreloader takes nothing returns nothing
set thistype.deferredTodoCount=thistype.deferredTodoCount-1
call thistype.add(true)
if thistype.deferredTodoCount<1 then
call PauseTimer(thistype.clock)
endif
endmethod
//* Public method used to get a dummy. Use this at any time, as much
//* as you want.
public static method get takes nothing returns unit
if thistype.stackIndex!=-1 then
set thistype.stackIndex=thistype.stackIndex-1
set bj_lastCreatedUnit=thistype.dummyStack[thistype.stackIndex+1]
else
set bj_lastCreatedUnit=thistype.add(false)
endif
static if DO_DDPC then
if thistype.stackIndex<(thistype.DYNAMIC_DEFERRED_PRELOAD_COUNT-1) and thistype.deferredTodoCount<1 then
set thistype.deferredTodoCount=thistype.MIN_PRELOAD_BLOCK_SIZE
call TimerStart(thistype.clock,thistype.CLOCK_PERIOD,true,function thistype.deferredPreloader)
endif
endif
/* - Derd - */
//call ShowUnit(bj_lastCreatedUnit,true)
//call PauseUnit(bj_lastCreatedUnit,false)
/* -------- */
return bj_lastCreatedUnit
endmethod
//* Public method for releasing a dummy. Make sure you don't release
//* units that don't come from DummyUnitStack. Make sure you destroy
//* effects and anything else attached the unit because its handle
//* will be RECYCLED.
public static method release takes unit u returns nothing
static if DO_MPU then
if thistype.stackIndex>=thistype.MAX_PRELOADED_UNITS then
call RemoveUnit(u)
return
endif
endif
call SetUnitOwner(u,Player(PLAYER_NEUTRAL_PASSIVE),false)
call SetUnitX(u,thistype.SAFE_LOC_X)
call SetUnitY(u,thistype.SAFE_LOC_Y)
/* - Derd - */
//call ShowUnit(u,false)
//call PauseUnit(u,true)
/* -------- */
set thistype.stackIndex=thistype.stackIndex+1
set thistype.dummyStack[thistype.stackIndex]=u
endmethod
//* herpderp #programming
private static method onInit takes nothing returns nothing
local integer index=1
static if DO_PIC then
loop
exitwhen index>thistype.PRELOAD_INIT_COUNT
call thistype.add(true)
set index=index+1
endloop
endif
static if DO_IDPC then
set thistype.deferredTodoCount=thistype.INITIAL_DEFERRED_PRELOAD_COUNT
call TimerStart(thistype.clock,thistype.CLOCK_PERIOD,true,function thistype.deferredPreloader)
endif
endmethod
endstruct
endlibrary
library FileIO
/***************************************************************
*
* v1.1.0, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* Provides functionality to read and write files.
* _________________________________________________________________________
* 1. Requirements
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - Patch 1.29 or higher.
* - JassHelper (vJASS)
* _________________________________________________________________________
* 2. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it.
* _________________________________________________________________________
* 3. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct File extends array
*
* static constant integer AbilityCount
* static constant integer PreloadLimit
*
* readonly static boolean ReadEnabled
* readonly static integer Counter
* readonly static integer array List
*
* static method open takes string filename returns File
* static method create takes string filename returns File
*
* ---------
*
* method write takes string value returns File
* method read takes nothing returns string
*
* method readEx takes boolean close returns string
* method readAndClose takes nothing returns string
* method readBuffer takes nothing returns string
* method writeBuffer takes string contents returns nothing
* method appendBuffer takes string contents returns nothing
*
* method close takes nothing returns nothing
*
* public function Write takes string filename, string contents returns nothing
* public function Read takes string filename returns string
*
***************************************************************/
globals
// Enable this if you want to allow the system to read files generated in patch 1.30 or below.
// NOTE: For this to work properly you must edit the 'Amls' ability and change the levels to 2
// as well as typing something in "Level 2 - Text - Tooltip - Normal" text field.
//
// Enabling this will also cause the system to treat files written with .write("") as empty files.
//
// This setting is really only intended for those who were already using the system in their map
// prior to patch 1.31 and want to keep old files created with this system to still work.
private constant boolean BACKWARDS_COMPATABILITY = false
endglobals
private keyword FileInit
struct File extends array
static constant integer AbilityCount = 10
static constant integer PreloadLimit = 200
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList
readonly static boolean ReadEnabled = false
readonly string filename
private string buffer
static method open takes string filename returns thistype
local thistype this = .List[0]
if (this == 0) then
set this = Counter + 1
set Counter = this
else
set .List[0] = .List[this]
endif
set this.filename = filename
set this.buffer = null
debug if (this >= JASS_MAX_ARRAY_SIZE) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") WARNING: Maximum instance limit " + I2S(JASS_MAX_ARRAY_SIZE) + " reached.")
debug endif
return this
endmethod
// This is used to detect invalid characters which aren't supported in preload files.
static if (DEBUG_MODE) then
private static method validateInput takes string contents returns string
local integer i = 0
local integer l = StringLength(contents)
local string ch = ""
loop
exitwhen i >= l
set ch = SubString(contents, i, i + 1)
if (ch == "\\") then
return ch
elseif (ch == "\"") then
return ch
endif
set i = i + 1
endloop
return null
endmethod
endif
method write takes string contents returns thistype
local integer i = 0
local integer c = 0
local integer len = StringLength(contents)
local integer lev = 0
local string prefix = "-" // this is used to signify an empty string vs a null one
local string chunk
debug if (.validateInput(contents) != null) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: Invalid character |cffffcc00" + .validateInput(contents) + "|r")
debug return this
debug endif
set this.buffer = null
// Check if the string is empty. If null, the contents will be cleared.
if (contents == "") then
set len = len + 1
endif
// Begin to generate the file
call PreloadGenClear()
call PreloadGenStart()
loop
exitwhen i >= len
debug if (c >= .AbilityCount) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: String exceeds max length (" + I2S(.AbilityCount * .PreloadLimit) + ").|r")
debug endif
set lev = 0
static if (BACKWARDS_COMPATABILITY) then
if (c == 0) then
set lev = 1
set prefix = ""
else
set prefix = "-"
endif
endif
set chunk = SubString(contents, i, i + .PreloadLimit)
call Preload("\" )\ncall BlzSetAbilityTooltip(" + I2S(.AbilityList[c]) + ", \"" + prefix + chunk + "\", " + I2S(lev) + ")\n//")
set i = i + .PreloadLimit
set c = c + 1
endloop
call Preload("\" )\nendfunction\nfunction a takes nothing returns nothing\n //")
call PreloadGenEnd(this.filename)
return this
endmethod
method clear takes nothing returns thistype
return this.write(null)
endmethod
private method readPreload takes nothing returns string
local integer i = 0
local integer lev = 0
local string array original
local string chunk = ""
local string output = ""
loop
exitwhen i == .AbilityCount
set original[i] = BlzGetAbilityTooltip(.AbilityList[i], 0)
set i = i + 1
endloop
// Execute the preload file
call Preloader(this.filename)
// Read the output
set i = 0
loop
exitwhen i == .AbilityCount
set lev = 0
// Read from ability index 1 instead of 0 if
// backwards compatability is enabled
static if (BACKWARDS_COMPATABILITY) then
if (i == 0) then
set lev = 1
endif
endif
// Make sure the tooltip has changed
set chunk = BlzGetAbilityTooltip(.AbilityList[i], lev)
if (chunk == original[i]) then
if (i == 0 and output == "") then
return null // empty file
endif
return output
endif
// Check if the file is an empty string or null
static if not (BACKWARDS_COMPATABILITY) then
if (i == 0) then
if (SubString(chunk, 0, 1) != "-") then
return null // empty file
endif
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
endif
// Remove the prefix
if (i > 0) then
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
// Restore the tooltip and append the chunk
call BlzSetAbilityTooltip(.AbilityList[i], original[i], lev)
set output = output + chunk
set i = i + 1
endloop
return output
endmethod
method close takes nothing returns nothing
if (this.buffer != null) then
call .write(.readPreload() + this.buffer)
set this.buffer = null
endif
set .List[this] = .List[0]
set .List[0] = this
endmethod
method readEx takes boolean close returns string
local string output = .readPreload()
local string buf = this.buffer
if (close) then
call this.close()
endif
if (output == null) then
return buf
endif
if (buf != null) then
set output = output + buf
endif
return output
endmethod
method read takes nothing returns string
return .readEx(false)
endmethod
method readAndClose takes nothing returns string
return .readEx(true)
endmethod
method appendBuffer takes string contents returns thistype
set .buffer = .buffer + contents
return this
endmethod
method readBuffer takes nothing returns string
return .buffer
endmethod
method writeBuffer takes string contents returns nothing
set .buffer = contents
endmethod
static method create takes string filename returns thistype
return .open(filename).write("")
endmethod
implement FileInit
endstruct
private module FileInit
private static method onInit takes nothing returns nothing
local string originalTooltip
// We can't use a single ability with multiple levels because
// tooltips return the first level's value if the value hasn't
// been set. This way we don't need to edit any object editor data.
set File.AbilityList[0] = 'Amls'
set File.AbilityList[1] = 'Aroc'
set File.AbilityList[2] = 'Amic'
set File.AbilityList[3] = 'Amil'
set File.AbilityList[4] = 'Aclf'
set File.AbilityList[5] = 'Acmg'
set File.AbilityList[6] = 'Adef'
set File.AbilityList[7] = 'Adis'
set File.AbilityList[8] = 'Afbt'
set File.AbilityList[9] = 'Afbk'
// Backwards compatability check
static if (BACKWARDS_COMPATABILITY) then
static if (DEBUG_MODE) then
set originalTooltip = BlzGetAbilityTooltip(File.AbilityList[0], 1)
call BlzSetAbilityTooltip(File.AbilityList[0], SCOPE_PREFIX, 1)
if (BlzGetAbilityTooltip(File.AbilityList[0], 1) == originalTooltip) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO WARNING: Backwards compatability enabled but \"" + GetObjectName(File.AbilityList[0]) + "\" isn't setup properly.|r")
endif
endif
endif
// Read check
set File.ReadEnabled = File.open("FileTester.pld").write(SCOPE_PREFIX).readAndClose() == SCOPE_PREFIX
endmethod
endmodule
function Write takes string filename, string contents returns nothing
call File.open(filename).write(contents).close()
endfunction
function Read takes string filename returns string
return File.open(filename).readEx(true)
endfunction
endlibrary
library Filters initializer Init uses DestUtils, Math, UnitUtils
globals
real FilterX = 0
real FilterY = 0
real FilterRadius = 0
player FilterPlayer = null
boolexpr FILTER_ALIVE = null
boolexpr FILTER_ALLIED = null
boolexpr FILTER_ENEMY = null
boolexpr FILTER_FLYING = null
boolexpr FILTER_GROUND = null
boolexpr FILTER_MECHANICAL = null
boolexpr FILTER_ORGANIC = null
boolexpr FILTER_PLAYER = null
boolexpr FILTER_ALIVE_ALLIED = null
boolexpr FILTER_ALIVE_ENEMY = null
boolexpr FILTER_ALIVE_GROUND = null
boolexpr FILTER_ALIVE_ORGANIC = null
boolexpr FILTER_ALIVE_ALLIED_ORGANIC = null
boolexpr FILTER_ALIVE_ENEMY_GROUND = null
boolexpr FILTER_ALIVE_ENEMY_ORGANIC = null
boolexpr FILTER_ALIVE_MECHANICAL = null
boolexpr FILTER_ALIVE_ORGANIC_PLAYER = null
boolexpr FILTER_ENEMY_TRAP = null
integer FilterUnitAbility = 0
integer FilterUnitTypeId = 0
boolexpr FILTER_UNIT_TYPE_ID = null
boolexpr FILTER_SETTLEMENT = null
boolexpr FILTER_SETTLEMENT_NON_CITY = null
boolexpr FILTER_ENEMY_SETTLEMENT = null
boolexpr FILTER_UNIT_ABILITY = null
boolexpr FILTER_UNIT_TRAP = null
destructable FilterDest = null
boolexpr FILTER_DEST_WITHIN_RANGE = null
boolexpr FILTER_DEST_ALIVE = null
boolexpr FILTER_DEST_TREE = null
boolexpr FILTER_DEST_TREE_ALIVE = null
endglobals
private function FilterAlive takes nothing returns boolean
return UnitAlive(GetFilterUnit())
endfunction
private function FilterAllied takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), FilterPlayer)
endfunction
private function FilterEnemy takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), FilterPlayer)
endfunction
private function FilterFlying takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING)
endfunction
private function FilterMechanical takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)
endfunction
private function FilterOwningPlayer takes nothing returns boolean
return GetOwningPlayer(GetFilterUnit()) == FilterPlayer
endfunction
private function FilterUnitTypeId takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == FilterUnitTypeId
endfunction
private function FilterSettlement takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ATTR_SETTLEMENT)
endfunction
private function FilterSettlementSmall takes nothing returns boolean
local unit u = GetFilterUnit()
local integer id = GetUnitTypeId(u)
local boolean b = (id == UNIT_VILLAGE) or (id == UNIT_TOWN)
set u = null
return b
endfunction
private function FilterUnitAttr takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), FilterUnitAbility)
endfunction
private function FilterUnitTrap takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ATTR_TRAP)
endfunction
private function EnumDestInRangeFilter takes nothing returns boolean
set FilterDest = GetFilterDestructable()
return DistanceWithin(GetDestructableX(FilterDest), GetDestructableY(FilterDest), FilterX, FilterY, FilterRadius)
endfunction
private function FilterDestTree takes nothing returns boolean
return IsDestTree(GetFilterDestructable())
endfunction
private function FilterDestAlive takes nothing returns boolean
return IsDestAlive(GetFilterDestructable())
endfunction
private function Init takes nothing returns nothing
set FILTER_ALIVE = Filter(function FilterAlive)
set FILTER_ALLIED = Filter(function FilterAllied)
set FILTER_ENEMY = Filter(function FilterEnemy)
set FILTER_FLYING = Filter(function FilterFlying)
set FILTER_GROUND = Not(FILTER_FLYING)
set FILTER_MECHANICAL = Filter(function FilterMechanical)
set FILTER_ORGANIC = Not(FILTER_MECHANICAL)
set FILTER_PLAYER = Filter(function FilterOwningPlayer)
set FILTER_ALIVE_ALLIED = And(FILTER_ALIVE, FILTER_ALLIED)
set FILTER_ALIVE_ENEMY = And(FILTER_ALIVE, FILTER_ENEMY)
set FILTER_ALIVE_GROUND = And(FILTER_ALIVE, FILTER_GROUND)
set FILTER_ALIVE_ORGANIC = And(FILTER_ALIVE, FILTER_ORGANIC)
set FILTER_ALIVE_ALLIED_ORGANIC = And(FILTER_ALIVE_ALLIED, FILTER_ORGANIC)
set FILTER_ALIVE_ENEMY_GROUND = And(FILTER_ALIVE_ENEMY, FILTER_GROUND)
set FILTER_ALIVE_ENEMY_ORGANIC = And(FILTER_ALIVE_ENEMY, FILTER_ORGANIC)
set FILTER_ALIVE_MECHANICAL = And(FILTER_ALIVE, FILTER_MECHANICAL)
set FILTER_ALIVE_ORGANIC_PLAYER = And(FILTER_ALIVE_ORGANIC, FILTER_PLAYER)
set FILTER_UNIT_TYPE_ID = Filter(function FilterUnitTypeId)
set FILTER_SETTLEMENT = Filter(function FilterSettlement)
set FILTER_SETTLEMENT_NON_CITY = Filter(function FilterSettlementSmall)
set FILTER_ENEMY_SETTLEMENT = And(FILTER_ENEMY, FILTER_SETTLEMENT)
set FILTER_UNIT_ABILITY = Filter(function FilterUnitAttr)
set FILTER_UNIT_TRAP = Filter(function FilterUnitTrap)
set FILTER_ENEMY_TRAP = And(FILTER_ENEMY, FILTER_UNIT_TRAP)
set FILTER_DEST_WITHIN_RANGE = Filter(function EnumDestInRangeFilter)
set FILTER_DEST_TREE = Filter(function FilterDestTree)
set FILTER_DEST_ALIVE = Filter(function FilterDestAlive)
set FILTER_DEST_TREE_ALIVE = And(FILTER_DEST_TREE, FILTER_DEST_ALIVE)
endfunction
endlibrary
library GetBuildingUnit initializer Init requires DebugUtils, UnitUtils
//
// This system returns the unit who initiated the build order
// for a structure, not the one that finished it!
//
globals
// The hero of our story
// Can get when building is finished, cancelled, or has died while under construction
private unit Builder = null
// Data[structure x-pos][structure y-pos] = initiating builder
private HashTable Data
// Keeps track of the number of child keys in Data
// so the entire parent Table can be destroyed when
// it reaches zero
private Table Size
endglobals
function GetStructureBuilder takes nothing returns unit
return Builder
endfunction
private function RemoveEntry takes unit structure returns nothing
local integer x = R2I(GetUnitX(structure))
set Size[x] = Size[x] - 1
if (Size[x] == 0) then
call Data[x].destroy()
call Size.remove(x)
else
call Data[x].real.remove(R2I(GetUnitY(structure)))
endif
endfunction
private function OnBuildStart takes nothing returns nothing
local integer x
local integer y
if (IsUnitIdType(GetIssuedOrderId(), UNIT_TYPE_STRUCTURE)) then
set x = R2I(GetOrderPointX())
set y = R2I(GetOrderPointY())
set Data[x].unit[y] = GetTriggerUnit()
call Log("Build start by " + GetUnitName(Data[x].unit[y]))
set Size[x] = Size[x] + 1
endif
endfunction
private function SetBuilder takes unit structure returns nothing
set Builder = Data[R2I(GetUnitX(structure))].unit[R2I(GetUnitY(structure))]
call RemoveEntry(structure)
endfunction
private function OnBuildFinish takes nothing returns nothing
call Log("Build finish for " + GetUnitName(GetConstructedStructure()))
call SetBuilder(GetConstructedStructure())
call Log("Builder is " + GetUnitName(GetStructureBuilder()))
endfunction
private function OnBuildCancel takes nothing returns nothing
call SetBuilder(GetCancelledStructure())
endfunction
private function OnDeath takes nothing returns nothing
if (IsUnitUnderConstruction(GetTriggerUnit())) then
call SetBuilder(GetTriggerUnit())
endif
endfunction
private function Init takes nothing returns nothing
set Data = HashTable.create()
set Size = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function OnBuildStart)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnBuildFinish)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function OnBuildCancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
endfunction
endlibrary
library GroupUtils initializer Init requires UnitDex, UnitUtils
globals
private constant real MAX_COLLISION_SIZE = 100
group array PlayerUnits
group array PlayerCombatUnits
constant group EnumGroup = CreateGroup()
private group AltGroup = CreateGroup()
private group CopyGroup = null
private group RandomSubgroupGroup
private unit array RandomSubgroup
private integer RandomSize = 0
endglobals
// Doesn't work, no idea why
function GroupEnumUnitsOfPlayerOfType takes group g, player p, integer unitTypeId returns nothing
set FilterUnitTypeId = unitTypeId
call GroupEnumUnitsOfPlayer(g, p, FILTER_UNIT_TYPE_ID)
endfunction
function GroupEnumUnitsInRangeCollision takes group g, real x, real y, real radius, boolexpr filter returns nothing
local integer i = 0
local integer size
local unit u
call GroupClear(g)
call GroupEnumUnitsInRange(AltGroup, x, y, radius + MAX_COLLISION_SIZE, filter)
set size = BlzGroupGetSize(AltGroup)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(AltGroup, i)
if (IsUnitInRangeXY(u, x, y, radius + 0.5 * BlzGetUnitCollisionSize(u))) then
call GroupAddUnit(g,u)
endif
set i = i + 1
endloop
set u = null
endfunction
function GroupCopy takes group src returns group
/*
local integer i = 0
local integer size = BlzGroupGetSize(src)
set CopyGroup = CreateGroup()
loop
exitwhen (i == size)
call GroupAddUnit(CopyGroup, BlzGroupUnitAt(src, i))
set i = i + 1
endloop
*/
set CopyGroup = CreateGroup()
call BlzGroupAddGroupFast(src, CopyGroup)
return CopyGroup
endfunction
private function GroupGetRandomSubgroupEnum takes nothing returns nothing
set RandomSubgroup[RandomSize] = GetEnumUnit()
set RandomSize = RandomSize + 1
endfunction
private function RandomSubgroupShuffle takes nothing returns nothing
local unit t
local integer i = RandomSize - 1
local integer j
loop
exitwhen (i <= 1)
set j = GetRandomInt(0,i)
set t = RandomSubgroup[i]
set RandomSubgroup[i] = RandomSubgroup[j]
set RandomSubgroup[j] = t
set i = i - 1
endloop
set t = null
endfunction
function GroupGetRandomSubgroup takes group g, integer size returns group
local integer i = 0
set RandomSize = 0
call ForGroup(g, function GroupGetRandomSubgroupEnum)
call RandomSubgroupShuffle()
set RandomSubgroupGroup = CreateGroup()
loop
exitwhen ((i >= size) or (i >= RandomSize))
call GroupAddUnit(RandomSubgroupGroup, RandomSubgroup[i])
set i = i + 1
endloop
return RandomSubgroupGroup
endfunction
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer id = GetPlayerId(GetOwningPlayer(u))
call GroupAddUnit(PlayerUnits[id], u)
if (IsCombatUnit(u)) then
call GroupAddUnit(PlayerCombatUnits[id], u)
endif
set u = null
endfunction
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetPlayerId(GetTriggerPlayer())
call GroupRemoveUnit(PlayerUnits[id], u)
call GroupRemoveUnit(PlayerCombatUnits[id], u)
set u = null
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
set PlayerUnits[i] = CreateGroup()
set PlayerCombatUnits[i] = CreateGroup()
set i = i + 1
exitwhen (i > bj_MAX_PLAYER_SLOTS)
endloop
call OnUnitIndex(function OnIndex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
endfunction
endlibrary
library Iterator
/*
* Implementing structs
*
* Required:
* - static constant real UPDATE_INTERVAL
* - method update takes nothing returns nothing
* - method destroy takes nothing returns nothing
*
* Note:
* - Call .listAdd() once the instance should be included in the iteration
* - Use .finalize() if the instance has been added to the list,
* otherwise use .destroy()
* - Do not call .listRemove() when you are done with the instance,
* this is done automatically during finalization
*
*/
module Iterator
static thistype array instances
static integer count = 0
// Used to store instances that must be destroyed so
// the list isn't altered during iteration
static thistype array toDestroy
static integer destroyCount = 0
static timer timer = CreateTimer()
// Index of the struct instance inside the instances array
private integer index
private static method doUpdate takes nothing returns nothing
local integer i = 1
loop
exitwhen (i > count)
call instances[i].update()
set i = i + 1
endloop
loop
exitwhen (destroyCount == 0)
set destroyCount = destroyCount - 1
call toDestroy[destroyCount].listRemove()
call toDestroy[destroyCount].destroy()
set toDestroy[destroyCount] = 0
endloop
endmethod
method listAdd takes nothing returns nothing
if (this == 0) then
return
endif
set count = count + 1
set instances[count] = this
set .index = count
if (count == 1) then
// Begin iterating over instances if we haven't already
call TimerStart(timer, thistype.UPDATE_INTERVAL, true, function thistype.doUpdate)
endif
endmethod
private method listRemove takes nothing returns nothing
if (this == 0) then
return
endif
// Set the index of the last instance to this one
// so there are no gaps in the array
set instances[.index] = instances[count]
set instances[count].index = .index
set instances[count] = 0
set .index = 0
set count = count - 1
if (count == 0) then
// Stop iterating over instances if there are none left
call PauseTimer(timer)
endif
endmethod
method finalize takes nothing returns nothing
set toDestroy[destroyCount] = this
set destroyCount = destroyCount + 1
endmethod
endmodule
endlibrary
library LocationUtils initializer Init uses DestUtils, RectUtils, WorldBounds
/*
* Public API
*
* function GetPointZ takes real x, real y returns real
* function IsTerrainWalkable takes real x, real y returns boolean
* function IsPointWithinMapEdges takes real x, real y, real margin returns boolean
* function CountUnwalkableCellsNearPoint takes real x, real y, real radius returns integer
* function GetWalkablePoint takes real x, real y, real maxDistance returns location
*
*/
globals
private constant location LOC = Location(0,0)
// Number of walkable cells within CELL_CHECK_RADIUS required
// for a point to be considered walkable
private constant integer MIN_CELLS_REQUIRED = 16
// Radius considered when determining whether a point is walkable
private constant real CELL_CHECK_RADIUS = 256
// Amount distance is increased each iteration when searching for
// a nearby walkable point
private constant real DIST_INC = 48
// Number of directions that are considered each iteration when
// searching for a nearby walkable point
private constant integer ANGLES = 8
private real array COS
private real array SIN
private Table PathingData
private integer CellCount = 0
endglobals
function GetPointZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function CountUnwalkableDestsNearPointEnum takes nothing returns nothing
if (IsDestAlive(GetEnumDestructable())) then
set CellCount = CellCount + PathingData[GetDestructableTypeId(GetEnumDestructable())]
endif
endfunction
function CountUnwalkableCellsNearPoint takes real x, real y, real radius returns integer
set CellCount = 0
call EnumDestInRange(x, y, radius, function CountUnwalkableDestsNearPointEnum)
if (not IsTerrainWalkable(x,y)) then
// Arbitrary penalty for terrain causing unwalkability... in reality
// the patch of unwalkable terrain could be much larger
set CellCount = CellCount + 4
endif
return CellCount
endfunction
function GetWalkablePoint takes real x, real y, real maxDistance returns location
local real testX
local real testY
local real distance
local integer i
if (maxDistance < 0) then
set maxDistance = 99999
endif
set distance = DIST_INC
loop
exitwhen (distance > maxDistance)
set i = 0
loop
set testX = x + distance * COS[i]
set testY = y + distance * SIN[i]
if (IsTerrainWalkable(testX, testY) and CountUnwalkableCellsNearPoint(testX, testY, CELL_CHECK_RADIUS) <= MIN_CELLS_REQUIRED) then
return Location(testX, testY)
endif
set i = i + 1
exitwhen (i == ANGLES)
endloop
set distance = distance + DIST_INC
endloop
return null
endfunction
function IsPointWithinMapEdges takes real x, real y, real margin returns boolean
return (x < WorldBounds.minX + margin) or (x > WorldBounds.maxX - margin) /*
*/ or (y < WorldBounds.minY + margin) or (y > WorldBounds.maxY - margin)
endfunction
private function Init takes nothing returns nothing
local real rad = 2 * bj_PI / ANGLES
local integer i = 0
loop
set COS[i] = Cos(rad * i)
set SIN[i] = Sin(rad * i)
set i = i + 1
exitwhen (i == ANGLES)
endloop
set PathingData = Table.create()
// How many 2x2 (64 square game units) unwalkable cells
// the destructible takes up
set PathingData[BLOCKER_GROUND_2X2] = 1
set PathingData[BLOCKER_GROUND_4X4] = 4
set PathingData[TREE_DENSE] = 4
set PathingData[TREE_MANGROVE] = 4
set PathingData[TREE_SPARSE] = 9
set PathingData[TREE_VERY_DENSE] = 1
set PathingData[TREE_VERY_SPARSE] = 16
endfunction
endlibrary
library Math initializer Init
globals
constant real TAU = 2*bj_PI
private constant timer ElapsedGameTime = CreateTimer()
endglobals
function ClampR takes real x, real min, real max returns real
if (x <= min) then
return min
elseif (x >= max) then
return max
endif
return x
endfunction
function GetRandomAngle takes nothing returns real
return GetRandomReal(-bj_PI,bj_PI)
endfunction
function GetRandomAngleDeg takes nothing returns real
return GetRandomReal(0,360)
endfunction
function NormalizeAngle takes real a returns real
return ModuloReal(a, TAU)
endfunction
function NormalizeAngleDeg takes real a returns real
return ModuloReal(a, 360)
endfunction
function AngleBetween takes real srcX, real srcY, real destX, real destY returns real
return Atan2(destY - srcY, destX - srcX)
endfunction
function AngleBetweenDeg takes real srcX, real srcY, real destX, real destY returns real
return NormalizeAngleDeg(bj_RADTODEG * Atan2(destY - srcY, destX - srcX))
endfunction
function PointDistanceToPoint takes real x1, real y1, real x2, real y2 returns real
local real dx = x1 - x2
local real dy = y1 - y2
return SquareRoot(dx*dx + dy*dy)
endfunction
function DistanceWithin takes real x1, real y1, real x2, real y2, real maxDistance returns boolean
local real dx = x1 - x2
local real dy = y1 - y2
return dx*dx + dy*dy <= maxDistance*maxDistance
endfunction
function DiceInt takes integer base, integer numberOfDice, integer sidesPerDie returns integer
loop
exitwhen (numberOfDice <= 0)
set base = base + GetRandomInt(1,sidesPerDie)
set numberOfDice = numberOfDice - 1
endloop
return base
endfunction
function DiceReal takes real base, integer numberOfDice, integer sidesPerDie returns real
loop
exitwhen (numberOfDice <= 0)
set base = base + GetRandomInt(1,sidesPerDie)
set numberOfDice = numberOfDice - 1
endloop
return base
endfunction
function RoundDownReal takes real a, integer multiple returns integer
return R2I(a) / multiple * multiple
endfunction
function GetGameElapsedTime takes nothing returns real
return TimerGetElapsed(ElapsedGameTime)
endfunction
private function Init takes nothing returns nothing
call TimerStart(ElapsedGameTime, 86400, false, null)
endfunction
endlibrary
library MissileUtils
struct MissileData extends array
implement Alloc
unit source
unit target
method destroy takes nothing returns nothing
set .source = null
set .target = null
call .deallocate()
endmethod
static method create takes unit source, unit target returns thistype
local thistype this = allocate()
set .source = source
set .target = target
return this
endmethod
endstruct
endlibrary
library PlayerAbility uses TimedUnitEffect, TimerUtils, UnitUtils
/*
* Public API
*
* function GetPlayerAbilityCooldownRemaining takes player p, integer abilityId returns real
* function StartPlayerAbilityCooldown takes player p, integer abilityId returns nothing
* function StartPlayerAbilityCooldownEx takes player p, integer abilityId, real cooldown returns nothing
* function StartPlayerUpgradedAbilityCooldown takes player p, integer upgradeAbilityId, integer originalAbilityId returns nothing
*
*/
private struct PlayerAbilityCooldown extends array
// Number of abilities a player can ever have on cooldown simultaneously
// Can be more than needed but not less; adjust as necessary
private static constant integer MAX_PLAYER_ABILITIES = 8
private static group array globalCasters
private static TableArray data
private static integer array abilities
static method getPlayerAbilityCooldownRemaining takes player p, integer abilityId returns real
return TimerGetRemaining(data[GetPlayerId(p)].timer[abilityId])
endmethod
static method start takes player p, integer abilityId, real cooldown returns nothing
local integer playerId = GetPlayerId(p)
local integer size
local integer i = 0
local integer end
set size = BlzGroupGetSize(globalCasters[playerId])
loop
exitwhen (i == size)
call BlzStartUnitAbilityCooldown(BlzGroupUnitAt(globalCasters[playerId], i), abilityId, cooldown)
set i = i + 1
endloop
if (data[playerId].timer[abilityId] == null) then
set data[playerId].timer[abilityId] = NewTimer(0)
endif
call TimerStart(data[playerId].timer[abilityId], cooldown, false, null)
set i = playerId * MAX_PLAYER_ABILITIES
set end = i + MAX_PLAYER_ABILITIES
loop
exitwhen ((i == end) or (abilities[i] == abilityId))
if (abilities[i] == 0) then
set abilities[i] = abilityId
return
endif
set i = i + 1
endloop
endmethod
static method startUpgradedAbilityCooldown takes player p, integer upgradeAbilityId, integer originalAbilityId returns nothing
local integer playerId = GetPlayerId(p)
local real cooldown = getPlayerAbilityCooldownRemaining(p, originalAbilityId)
local integer size
local integer i = 0
local integer end
set size = BlzGroupGetSize(globalCasters[playerId])
loop
exitwhen (i == size)
call BlzStartUnitAbilityCooldown(BlzGroupUnitAt(globalCasters[playerId], i), upgradeAbilityId, cooldown)
set i = i + 1
endloop
set data[playerId].timer[upgradeAbilityId] = NewTimer(0)
call TimerStart(data[playerId].timer[upgradeAbilityId], cooldown, false, null)
set i = playerId * MAX_PLAYER_ABILITIES
set end = i + MAX_PLAYER_ABILITIES
loop
exitwhen (i == end)
if (abilities[i] == 0) then
set abilities[i] = upgradeAbilityId
return
endif
set i = i + 1
endloop
endmethod
private static method onConstructFinish takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p
local integer playerId
local integer abilityId
local real cooldown
local integer i
local integer end
if (UnitHasAbility(u, ATTR_GLOBAL_CASTER)) then
set p = GetTriggerPlayer()
set playerId = GetPlayerId(p)
set i = playerId * MAX_PLAYER_ABILITIES
set end = i + MAX_PLAYER_ABILITIES
loop
exitwhen ((i == end) or (abilities[i] == 0))
set abilityId = abilities[i]
set cooldown = BlzGetAbilityCooldown(abilityId, 0)
// Delayed call for structures built by trucks
call StartUnitAbilityCooldownTimed(u, abilityId, 0, getPlayerAbilityCooldownRemaining(p, abilityId))
set i = i + 1
endloop
endif
set u = null
endmethod
private static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_GLOBAL_CASTER)) then
call GroupAddUnit(globalCasters[GetPlayerId(GetOwningPlayer(u))], u)
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, null)
set globalCasters[i] = CreateGroup()
set i = i + 1
exitwhen (i == bj_MAX_PLAYERS)
endloop
call TriggerAddCondition(t, function thistype.onConstructFinish)
call OnUnitIndex(function thistype.onIndex)
set data = TableArray[bj_MAX_PLAYERS]
set t = null
endmethod
endstruct
function GetPlayerAbilityCooldownRemaining takes player p, integer abilityId returns real
return PlayerAbilityCooldown.getPlayerAbilityCooldownRemaining(p, abilityId)
endfunction
function StartPlayerAbilityCooldown takes player p, integer abilityId returns nothing
call PlayerAbilityCooldown.start(p, abilityId, BlzGetAbilityCooldown(abilityId, 0))
endfunction
function StartPlayerAbilityCooldownEx takes player p, integer abilityId, real cooldown returns nothing
call PlayerAbilityCooldown.start(p, abilityId, cooldown)
endfunction
// This should be called ONCE after an upgrade that replaces
// an ability is researched
function StartPlayerUpgradedAbilityCooldown takes player p, integer upgradeAbilityId, integer originalAbilityId returns nothing
call PlayerAbilityCooldown.startUpgradedAbilityCooldown(p, upgradeAbilityId, originalAbilityId)
endfunction
endlibrary
library PlayerResources initializer Init uses TimerUtils, optional Stats
/*
* Public API
*
* function PlayerAddMoney takes player p, real amount, boolean countAsEarned returns nothing
* function PlayerAddMoneyUnchecked takes player p, real amount, boolean countAsEarned returns nothing
* function PlayerRemoveMoney takes player p, integer amount returns nothing
* function PlayerSetMoney takes player p, integer amount returns nothing
* constant function PlayerGetMoney takes player p returns integer
*
*/
globals
// Number of money tech requirements
// in multiples of MONEY_TECH_INTERVAL gold
// Should be tuned to exact number
private constant integer MONEY_TECHS_COUNT = 10
private constant integer MONEY_TECH_INTERVAL = 50
private integer array MoneyTechReqs
private real array PlayerMoneyFrac
endglobals
function PlayerAddMoneyUnchecked takes player p, real amount, boolean countAsEarned returns nothing
local integer id = GetPlayerId(p)
local integer added = R2I(amount)
local integer integral
set PlayerMoneyFrac[id] = PlayerMoneyFrac[id] + (amount - added)
if (PlayerMoneyFrac[id] >= 1) then
set integral = R2I(PlayerMoneyFrac[id])
set added = added + integral
set PlayerMoneyFrac[id] = PlayerMoneyFrac[id] - integral
endif
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + added)
if (countAsEarned and amount > 0) then
call RecordMoneyEarned(id, added)
endif
endfunction
function PlayerAddMoney takes player p, real amount, boolean countAsEarned returns nothing
if (udg_PlayerHere[GetPlayerId(p)]) then
call PlayerAddMoneyUnchecked(p, amount, countAsEarned)
endif
endfunction
function PlayerRemoveMoney takes player p, integer amount returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) - amount)
endfunction
function PlayerSetMoney takes player p, integer amount returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, amount)
endfunction
constant function PlayerGetMoney takes player p returns integer
return GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)
endfunction
function PlayerAddSupplies takes player p, integer amount returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + amount)
endfunction
function PlayerRemoveSupplies takes player p, integer amount returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) - amount)
call ExecuteFunc(SCOPE_PRIVATE + "UpdateSupplyDependencies")
endfunction
function PlayerSetSupplies takes player p, integer amount returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, amount)
endfunction
constant function PlayerGetSupplies takes player p returns integer
return GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER)
endfunction
private function UpdateMoneyDependenciesEnum takes nothing returns nothing
local player p = GetEnumPlayer()
local integer money = GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)
local integer i = 1
loop
exitwhen (i > MONEY_TECHS_COUNT)
if (money >= MONEY_TECH_INTERVAL * i) then
call SetPlayerTechResearched(p, MoneyTechReqs[i], 1)
else
exitwhen true
endif
set i = i + 1
endloop
loop
exitwhen (i > MONEY_TECHS_COUNT)
call SetPlayerTechResearched(p, MoneyTechReqs[i], 0)
set i = i + 1
endloop
endfunction
private function UpdateSupplyDependencies takes nothing returns nothing
if (GetPlayerState(udg_PLAYER_NORTH_VIETNAM, PLAYER_STATE_RESOURCE_LUMBER) >= 500) then
call SetPlayerTechResearched(udg_PLAYER_NORTH_VIETNAM, 'L1F4', 1)
else
call SetPlayerTechResearched(udg_PLAYER_NORTH_VIETNAM, 'L1F4', 0)
endif
endfunction
private function UpdateMoneyDependencies takes nothing returns nothing
call ForForce(udg_AmericanMajors, function UpdateMoneyDependenciesEnum)
call ForForce(udg_VietMajors, function UpdateMoneyDependenciesEnum)
endfunction
private function Init takes nothing returns nothing
local integer i = 1
loop
exitwhen (i > MONEY_TECHS_COUNT)
set MoneyTechReqs[i] = ResourceToTechId('M', MONEY_TECH_INTERVAL * i)
set i = i + 1
endloop
call TimerStart(NewTimer(0), 0.50, true, function UpdateMoneyDependencies)
call TimerStart(NewTimer(0), 0.50, true, function UpdateSupplyDependencies)
endfunction
endlibrary
library PlayerUtils initializer Init uses TimerUtils, TypeIdUtils
/*
* Public API
*
* function TimedMessageAll takes real duration, string msg returns nothing
* function TimedMessage takes player p, real duration, string msg returns nothing
* function TimedMessageForce takes force f, real duration, string msg returns nothing
* function IsPlayerHere takes player p returns boolean
*
*/
globals
player PLAYER_LOCAL = null
//player array Players
// PlayerIndex[player-id] = index of player in Players
//integer array PlayerIndex
//integer PlayerCount = 0
endglobals
function MessageAll takes string msg returns nothing
call DisplayTimedTextToPlayer(PLAYER_LOCAL, 0, 0, 0, msg)
endfunction
function TimedMessageAll takes real duration, string msg returns nothing
call DisplayTimedTextToPlayer(PLAYER_LOCAL, 0, 0, duration, msg)
endfunction
function TimedMessage takes player p, real duration, string msg returns nothing
call DisplayTimedTextToPlayer(p, 0, 0, duration, msg)
endfunction
function TimedMessageForce takes force f, real duration, string msg returns nothing
if (IsPlayerInForce(PLAYER_LOCAL, f)) then
call DisplayTimedTextToPlayer(PLAYER_LOCAL, 0, 0, duration, msg)
endif
endfunction
function IsPlayerHere takes player p returns boolean
return GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p) == MAP_CONTROL_USER
endfunction
function GetPlayerFactionId takes player p returns integer
return udg_PlayerFactionId[GetPlayerId(p)]
endfunction
function GetPlayerNameColored takes player p returns string
return udg_PlayerColor[GetPlayerId(p)] + GetPlayerName(p) + "|r"
endfunction
/*
private function OnPlayerLeave takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if (id >= 0) then
set Players[PlayerIndex[id]] = Players[PlayerCount - 1]
set Players[PlayerCount - 1] = null
set PlayerCount = PlayerCount - 1
endif
endfunction
*/
private function DelayedInit takes nothing returns nothing
//local trigger t = CreateTrigger()
//local integer i = 0
set PLAYER_LOCAL = GetLocalPlayer()
/*
loop
if (IsPlayerHere(Player(i))) then
set Players[PlayerCount] = Player(i)
set PlayerIndex[i] = PlayerCount
set PlayerCount = PlayerCount + 1
call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_LEAVE)
else
set PlayerIndex[i] = -1
endif
set i = i + 1
exitwhen (i == bj_MAX_PLAYERS)
endloop
call TriggerAddCondition(t, function OnPlayerLeave)
call ReleaseTimer(GetExpiredTimer())
*/
endfunction
private function Init takes nothing returns nothing
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endlibrary
library RectUtils
function GetRectFromCircle takes real x, real y, real radius returns rect
return Rect(x - radius, y - radius, x + radius, y + radius)
endfunction
endlibrary
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = bj_MAX_PLAYER_SLOTS - 1
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = bj_MAX_PLAYER_SLOTS * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
library SfxUtils initializer Init uses LocationUtils, TimerUtils
/*
* Public API
*
* function HideEffect takes effect e returns nothing
* function SetEffectFacingXY takes effect e, real x, real y returns nothing
* function SetEffectFacingXYZ takes effect e, real x, real y, real z returns nothing
* function CreateTimedEffectAtPoint takes string modelName, real x, real y, real duration returns effect
* function CreateTimedEffectAtPointMultiple takes string modelName, integer count, real centerX, real centerY, real radius, real duration returns nothing
* function CreateTimedEffectOnTarget takes string modelName, widget target, string attachPointName, real duration returns effect
* function CreateEffectWithVelocity takes string modelName, real x, real y, real height, real velX, real velY, real velZ returns SpecialEffect
* function CreateTimedEffectWithVelocity takes string modelName, real duration, real x, real y, real height, real velX, real velY, real velZ returns SpecialEffect
*
*/
globals
private Table Stack
endglobals
// Functions by Wareditor
function SetEffectFacingXY takes effect e, real x, real y returns nothing
local real dx = x - BlzGetLocalSpecialEffectX(e)
local real dy = y - BlzGetLocalSpecialEffectY(e)
call BlzSetSpecialEffectOrientation(e, 0, 0, Atan2(dy,dx))
endfunction
function SetEffectFacingXYZ takes effect e, real x, real y, real z returns nothing
local real dx = x - BlzGetLocalSpecialEffectX(e)
local real dy = y - BlzGetLocalSpecialEffectY(e)
local real dz = z - BlzGetLocalSpecialEffectZ(e)
local real yaw
local real pitch
local real roll
local real py
local real px
local real ix = RAbsBJ(dx)
local real iy = RAbsBJ(dy)
// roll - z-axis
set roll = Atan2(dy,dx)
// yaw - x-axis
set py = (1-(ix/(ix+iy)))
if not (dy == 0) then
set yaw = Atan(dz/dy)*py
if dy < 0 then
//set yaw = -yaw
endif
else
set yaw = 0
endif
// pitch - y-axis
set px = (1-(iy/(ix+iy)))
if not (dx == 0) then
set pitch = -Atan(dz/dx)*px
if dx < 0 then
//set pitch = -pitch
endif
else
set pitch = 0
endif
call BlzSetSpecialEffectOrientation(e, yaw, pitch, roll)
endfunction
// --------
private function DestroyTimedEffect takes nothing returns nothing
local integer handleId = ReleaseTimer(GetExpiredTimer())
call DestroyEffect(Stack.effect[handleId])
call Stack.effect.remove(handleId)
endfunction
function CreateTimedEffectAtPoint takes string modelName, real x, real y, real duration returns effect
local integer handleId
if (modelName == "") then
return null
endif
set bj_lastCreatedEffect = AddSpecialEffect(modelName, x, y)
set handleId = GetHandleId(bj_lastCreatedEffect)
set Stack.effect[handleId] = bj_lastCreatedEffect
call TimerStart(NewTimer(handleId), duration, false, function DestroyTimedEffect)
return bj_lastCreatedEffect
endfunction
function CreateTimedEffectAtPointMultiple takes string modelName, integer count, real centerX, real centerY, real radius, real duration returns nothing
local real angle
local real distance
if (modelName == "") then
return
endif
loop
exitwhen (count <= 0)
set angle = GetRandomAngle()
set distance = GetRandomReal(0,radius)
call CreateTimedEffectAtPoint(modelName, centerX + distance * Cos(angle), centerY + distance * Sin(angle), duration)
set count = count - 1
endloop
endfunction
function CreateTimedEffectOnTarget takes string modelName, widget target, string attachPointName, real duration returns effect
local integer handleId
if (modelName == "") then
return null
endif
set bj_lastCreatedEffect = AddSpecialEffectTarget(modelName, target, attachPointName)
set handleId = GetHandleId(bj_lastCreatedEffect)
set Stack.effect[handleId] = bj_lastCreatedEffect
call TimerStart(NewTimer(handleId), duration, false, function DestroyTimedEffect)
return bj_lastCreatedEffect
endfunction
function HideEffect takes effect e returns nothing
call BlzSetSpecialEffectZ(e, -10000)
endfunction
struct SpecialEffect extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./60
readonly effect sfx
readonly real x
readonly real y
readonly real height
readonly real vx
readonly real vy
readonly real vz
readonly timer t
method destroy takes nothing returns nothing
call DestroyEffect(.sfx)
if (.t != null) then
call ReleaseTimer(.t)
endif
set .sfx = null
endmethod
method update takes nothing returns nothing
set .x = .x + .vx
set .y = .y + .vy
set .height = .height + .vz
call BlzSetSpecialEffectX(.sfx, .x)
call BlzSetSpecialEffectY(.sfx, .y)
call BlzSetSpecialEffectZ(.sfx, .height + GetPointZ(.x,.y))
endmethod
static method create takes string modelName, real x, real y returns thistype
local thistype this = allocate()
set .sfx = AddSpecialEffect(modelName, x, y)
call BlzSetSpecialEffectPitch(.sfx, bj_DEGTORAD * -90)
set .x = x
set .y = y
set .height = 0
set .vx = 0
set .vy = 0
set .vz = 0
set .t = null
call .listAdd()
return this
endmethod
private static method finalizeCallback takes nothing returns nothing
call thistype(ReleaseTimer(GetExpiredTimer())).finalize()
endmethod
method setDuration takes real duration returns nothing
if (.t == null) then
set .t = NewTimer(this)
endif
call TimerStart(.t, duration, false, function thistype.finalizeCallback)
endmethod
method setHeight takes real height returns nothing
set .height = height
call BlzSetSpecialEffectZ(.sfx, height + GetPointZ(.x,.y))
endmethod
method setVelocity takes real velX, real velY, real velZ returns nothing
set .vx = velX * UPDATE_INTERVAL
set .vy = velY * UPDATE_INTERVAL
set .vz = velZ * UPDATE_INTERVAL
endmethod
method setFacing takes real angle returns nothing
call BlzSetSpecialEffectYaw(.sfx, bj_DEGTORAD * angle)
endmethod
endstruct
function CreateEffectWithVelocity takes string modelName, real x, real y, real height, real velX, real velY, real velZ returns SpecialEffect
local SpecialEffect sfx = SpecialEffect.create(modelName, x, y)
call sfx.setHeight(height)
call sfx.setVelocity(velX, velY, velZ)
return sfx
endfunction
function CreateTimedEffectWithVelocity takes string modelName, real duration, real x, real y, real height, real velX, real velY, real velZ returns SpecialEffect
local SpecialEffect sfx = CreateEffectWithVelocity(modelName, x, y, height, velX, velY, velZ)
call sfx.setDuration(duration)
return sfx
endfunction
private function Init takes nothing returns nothing
set Stack = Table.create()
endfunction
endlibrary
library SoundUtils uses DebugUtils, TimerUtils
/*
* Public API
*
* function DefineSound takes string name, string fileName, integer duration returns nothing
* function DefineSoundEx takes string name, string fileName, integer duration, integer channel, string eax returns nothing
*
* function PlaySoundAtPoint takes string name, integer volume, real x, real y, real z returns integer
* function PlayMovingSoundAtPoint takes string name, integer volume, real x, real y, real z, real velX, real velY, real velZ returns integer
*
* function IsSoundPlayingForPlayer takes string name, player p returns boolean
* function PlaySoundForPlayer takes string name, player p, integer volume, boolean maxOneInstance returns integer
*
* function RegisterUnitSound takes integer unitTypeId, string soundFileName, integer volume returns nothing
* function UnitMoveSoundFadeOut takes unit u returns nothing
*
*/
private struct Sound extends array
private static TableArray data
private static HashTable stack
private static integer count = 0
private sound handle
private string name
private boolean is3d
private real duration
private player owner
private boolean playing
private static method create takes string name, boolean is3d returns thistype
local thistype this = count + 1
local integer hash = StringHash(name)
local integer durationMillis = getDuration(hash)
local integer i = 0
set .handle = CreateSound(getFileName(hash), false, is3d, false, 1, 1, getEaxSetting(hash))
set .name = name
set .is3d = is3d
set .duration = durationMillis * 0.001
set .playing = false
call SetSoundDuration(.handle, durationMillis)
call SetSoundPitch(.handle, 1.0)
call SetSoundChannel(.handle, getChannel(hash))
if (is3d) then
call SetSoundDistances(.handle, 0.0, 10000.0)
call SetSoundDistanceCutoff(.handle, 3000.0)
call SetSoundConeAngles(.handle, 0.0, 0.0, 127)
call SetSoundConeOrientation(.handle, 0.0, 0.0, 0.0)
endif
loop
exitwhen (stack[hash][i] == 0)
set i = i + 1
endloop
set stack[hash][i] = this
set count = this
return this
endmethod
private static method get takes string name, boolean is3d returns thistype
local thistype this
local integer hash = StringHash(name)
local integer i = 0
loop
set this = stack[hash][i]
exitwhen (this == 0 or (this > 0 and (this.is3d == is3d) and not .playing))
set i = i + 1
endloop
if (this > 0) then
return this
endif
return create(name, is3d)
endmethod
static method define takes string name, string fileName, integer duration, integer channel, string eax returns nothing
local integer hash = StringHash(name)
set data[0].string[hash] = fileName
set data[1][hash] = duration
set data[2].string[hash] = eax
set data[3][hash] = channel
endmethod
private static method getFileName takes integer hash returns string
return data[0].string[hash]
endmethod
private static method getDuration takes integer hash returns integer
return data[1][hash]
endmethod
private static method getEaxSetting takes integer hash returns string
return data[2].string[hash]
endmethod
private static method getChannel takes integer hash returns integer
return data[3][hash]
endmethod
private static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
set .owner = null
set .playing = false
endmethod
static method isPlayingForPlayer takes string name, player p returns boolean
local integer hash = StringHash(name)
local integer i = 0
local thistype this
loop
set this = stack[hash][i]
exitwhen (this == 0)
if (this > 0 and (.owner == null or .owner == p) and .playing) then
return true
endif
set i = i + 1
endloop
return false
endmethod
static method playAtPointEx takes string name, integer volume, real x, real y, real z, real velX, real velY, real velZ returns thistype
local thistype this = get(name, true)
call SetSoundVolume(.handle, volume)
call SetSoundPosition(.handle, x, y, z)
call SetSoundVelocity(.handle, velX, velY, velZ)
call StartSound(.handle)
set .playing = true
call TimerStart(NewTimer(this), .duration, false, function thistype.onFinish)
return this
endmethod
static method playAtPoint takes string name, integer volume, real x, real y, real z returns thistype
return playAtPointEx(name, volume, x, y, z, 0, 0, 0)
endmethod
static method playForPlayer takes string name, player p, integer volume, boolean maxOneInstance returns thistype
local thistype this
if (maxOneInstance and isPlayingForPlayer(name, p)) then
return 0
endif
set this = get(name, false)
if (PLAYER_LOCAL != p) then
set volume = 0
endif
call SetSoundVolume(.handle, volume)
call StartSound(.handle)
set .owner = p
set .playing = true
call TimerStart(NewTimer(this), .duration, false, function thistype.onFinish)
return this
endmethod
private static method onInit takes nothing returns nothing
set data = TableArray[4]
set stack = HashTable.create()
endmethod
endstruct
function DefineSoundEx takes string name, string fileName, integer duration, integer channel, string eax returns nothing
call Sound.define(name, fileName, duration, channel, eax)
endfunction
function DefineSound takes string name, string fileName, integer duration returns nothing
call DefineSoundEx(name, fileName, duration, CHANNEL_GENERAL, EAX_DEFAULT)
endfunction
function IsSoundPlayingForPlayer takes string name, player p returns boolean
return Sound.isPlayingForPlayer(name, p)
endfunction
function PlaySoundAtPoint takes string name, integer volume, real x, real y, real z returns integer
return Sound.playAtPoint(name, volume, x, y, z)
endfunction
function PlayMovingSoundAtPoint takes string name, integer volume, real x, real y, real z, real velX, real velY, real velZ returns integer
return Sound.playAtPointEx(name, volume, x, y, z, velX, velY, velZ)
endfunction
// If 'maxOneInstance' is true, then this does nothing if the sound is
// already playing for the player
function PlaySoundForPlayer takes string name, player p, integer volume, boolean maxOneInstance returns integer
return Sound.playForPlayer(name, p, volume, maxOneInstance)
endfunction
private struct UnitSound extends array
private static Table data
private unit unit
private sound handle
private method destroy takes nothing returns nothing
call StopSound(.handle, true, false)
set .unit = null
set .handle = null
endmethod
private static method create takes unit u, string soundFileName returns thistype
local thistype this = GetUnitId(u)
set .unit = u
set .handle = CreateSound(soundFileName, true, true, false, 100, 100, EAX_DEFAULT)
call SetSoundVolume(.handle, data[StringHash(soundFileName)])
call SetSoundChannel(.handle, CHANNEL_UNIT_MOVEMENT)
call AttachSoundToUnit(.handle, u)
call StartSoundEx(.handle, true)
return this
endmethod
static method fadeOut takes unit u returns nothing
local thistype this = GetUnitId(u)
call StopSound(.handle, false, true)
endmethod
static method register takes integer unitTypeId, string soundFileName, integer volume returns nothing
set data.string[unitTypeId] = soundFileName
set data[StringHash(soundFileName)] = volume
endmethod
private static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer id = GetUnitTypeId(u)
if (data.string.has(id)) then
call create(u, data.string[id])
endif
set u = null
endmethod
private static method onDeindex takes nothing returns nothing
local thistype this = GetIndexedUnitId()
if (this > 0) then
call .destroy()
endif
endmethod
private static method onDeath takes nothing returns nothing
local thistype this = GetUnitId(GetTriggerUnit())
if (this > 0) then
call .destroy()
endif
endmethod
private static method onInit takes nothing returns nothing
call OnUnitIndex(function thistype.onIndex)
call OnUnitDeindex(function thistype.onDeindex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
set data = Table.create()
endmethod
endstruct
function RegisterUnitSound takes integer unitTypeId, string soundFileName, integer volume returns nothing
call UnitSound.register(unitTypeId, soundFileName, volume)
endfunction
function UnitMoveSoundFadeOut takes unit u returns nothing
call UnitSound.fadeOut(u)
endfunction
endlibrary
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
library OrderEvent requires RegisterPlayerUnitEvent, Table
private function Predicate takes nothing returns boolean
return GetUnitAbilityLevel(GetTriggerUnit(), ATTR_NO_ORDER_EVENTS) == 0
endfunction
private module Initm
readonly static trigger anyOrderTrig
readonly static Table instant
readonly static Table point
readonly static Table target
static method onAnyOrder takes nothing returns nothing
call TriggerEvaluate(anyOrderTrig)
endmethod
static method onOrder takes nothing returns nothing
call TriggerEvaluate(instant.trigger[GetIssuedOrderId()])
endmethod
static method onPointOrder takes nothing returns nothing
call TriggerEvaluate(point.trigger[GetIssuedOrderId()])
endmethod
static method onTargetOrder takes nothing returns nothing
call TriggerEvaluate(target.trigger[GetIssuedOrderId()])
endmethod
private static method onInit takes nothing returns nothing
set anyOrderTrig = CreateTrigger()
set instant = Table.create()
set point = Table.create()
set target = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onAnyOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onPointOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onAnyOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onTargetOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onAnyOrder)
endmethod
endmodule
private struct OrderEvent extends array
implement Initm
endstruct
function RegisterAnyOrderEvent takes code func returns nothing
//call TriggerAddCondition(OrderEvent.anyOrderTrig, Filter(function Predicate))
//call TriggerAddCondition(OrderEvent.anyOrderTrig, Filter(function func))
call TriggerAddCondition(OrderEvent.anyOrderTrig, And(Filter(function Predicate), Filter(func)))
endfunction
function RegisterOrderEvent takes integer orderId, code func returns nothing
if (not OrderEvent.instant.handle.has(orderId)) then
set OrderEvent.instant.trigger[orderId] = CreateTrigger()
endif
call TriggerAddCondition(OrderEvent.instant.trigger[orderId], And(Filter(function Predicate), Filter(func)))
endfunction
function RegisterPointOrderEvent takes integer orderId, code func returns nothing
if (not OrderEvent.point.handle.has(orderId)) then
set OrderEvent.point.trigger[orderId] = CreateTrigger()
endif
call TriggerAddCondition(OrderEvent.point.trigger[orderId], And(Filter(function Predicate), Filter(func)))
endfunction
function RegisterTargetOrderEvent takes integer orderId, code func returns nothing
if (not OrderEvent.target.handle.has(orderId)) then
set OrderEvent.target.trigger[orderId] = CreateTrigger()
endif
call TriggerAddCondition(OrderEvent.target.trigger[orderId], And(Filter(function Predicate), Filter(func)))
endfunction
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
library TextTagUtils requires TimerUtils
globals
private constant real DEFAULT_SIZE = TextTagSize2Height(10)
private constant real DEFAULT_VELOCITY = TextTagSpeed2Velocity(40)
endglobals
private function TextTagBounty takes player p, integer amount, integer r, integer g, integer b, real x, real y, real z returns texttag
local string message = ""
if (amount > 0) then
set message = "+"
elseif (amount < 0) then
set message = "-"
else
return null
endif
set message = message + I2S(amount)
set bj_lastCreatedTextTag = CreateTextTag()
call SetTextTagText(bj_lastCreatedTextTag, message, DEFAULT_SIZE)
call SetTextTagPos(bj_lastCreatedTextTag, x, y, z)
call SetTextTagColor(bj_lastCreatedTextTag, r, g, b, 255)
call SetTextTagVelocity(bj_lastCreatedTextTag, 0, 0.03)
call SetTextTagVisibility(bj_lastCreatedTextTag, PLAYER_LOCAL == p)
call SetTextTagPermanent(bj_lastCreatedTextTag, false)
call SetTextTagLifespan(bj_lastCreatedTextTag, 3)
call SetTextTagFadepoint(bj_lastCreatedTextTag, 2)
return bj_lastCreatedTextTag
endfunction
private function TextTagBountyForce takes force f, integer amount, integer r, integer g, integer b, real x, real y, real z returns texttag
local string message = ""
if (amount > 0) then
set message = "+"
elseif (amount < 0) then
set message = "-"
else
return null
endif
set message = message + I2S(amount)
set bj_lastCreatedTextTag = CreateTextTag()
call SetTextTagText(bj_lastCreatedTextTag, message, DEFAULT_SIZE)
call SetTextTagPos(bj_lastCreatedTextTag, x, y, z)
call SetTextTagColor(bj_lastCreatedTextTag, r, g, b, 255)
call SetTextTagVelocity(bj_lastCreatedTextTag, 0, 0.03)
call SetTextTagVisibility(bj_lastCreatedTextTag, IsPlayerInForce(PLAYER_LOCAL, f))
call SetTextTagPermanent(bj_lastCreatedTextTag, false)
call SetTextTagLifespan(bj_lastCreatedTextTag, 3)
call SetTextTagFadepoint(bj_lastCreatedTextTag, 2)
return bj_lastCreatedTextTag
endfunction
function TextTagBountyGold takes player p, integer amount, real x, real y, real z returns texttag
return TextTagBounty(p, amount, 255, 220, 0, x, y, z)
endfunction
function TextTagBountyGoldForce takes force f, integer amount, real x, real y, real z returns texttag
return TextTagBountyForce(f, amount, 255, 220, 0, x, y, z)
endfunction
function TextTagBountyLumber takes player p, integer amount, real x, real y, real z returns texttag
return TextTagBounty(p, amount, 0, 200, 80, x, y, z)
endfunction
function TextTagBountyLumberForce takes force f, integer amount, real x, real y, real z returns texttag
return TextTagBountyForce(f, amount, 0, 200, 80, x, y, z)
endfunction
function TextTagError takes player p, string message, real x, real y, real z returns texttag
set bj_lastCreatedTextTag = CreateTextTag()
call SetTextTagText(bj_lastCreatedTextTag, message, DEFAULT_SIZE)
call SetTextTagPos(bj_lastCreatedTextTag, x, y, z)
call SetTextTagColor(bj_lastCreatedTextTag, 255, 0, 0, 255)
call SetTextTagVelocity(bj_lastCreatedTextTag, 0, DEFAULT_VELOCITY)
call SetTextTagVisibility(bj_lastCreatedTextTag, PLAYER_LOCAL == p)
call SetTextTagPermanent(bj_lastCreatedTextTag, false)
call SetTextTagLifespan(bj_lastCreatedTextTag, 3)
call SetTextTagFadepoint(bj_lastCreatedTextTag, 2)
return bj_lastCreatedTextTag
endfunction
private struct TextTagTimer extends array
implement Alloc
private static constant real FONT_SIZE = TextTagSize2Height(10)
private static constant real HEIGHT_OFFSET = 32
private unit target
private player owner
private texttag tag
private integer remaining
private timer clock
method destroy takes nothing returns nothing
call SetTextTagPermanent(.tag, false)
call DestroyTextTag(.tag)
call ReleaseTimer(.clock)
set .target = null
set .tag = null
set .clock = null
endmethod
static method onUpdate takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if ((GetOwningPlayer(.target) != .owner) or (not UnitAlive(.target))) then
call .destroy()
return
endif
call SetTextTagText(.tag, I2S(.remaining / 10) + "." + I2S(R2I(ModuloReal(.remaining, 10))), FONT_SIZE)
set .remaining = .remaining - 1
if (.remaining <= 0) then
call .destroy()
endif
endmethod
static method create takes unit u, real duration returns thistype
local thistype this = allocate()
set .target = u
set .owner = GetOwningPlayer(u)
set .remaining = R2I(10.0 * duration)
set .tag = CreateTextTag()
call SetTextTagPos(.tag, GetUnitX(u) - 32.0, GetUnitY(u), HEIGHT_OFFSET)
call SetTextTagColor(.tag, 0xFF, 0xCC, 0x00, 0xFF)
call SetTextTagText(.tag, I2S(.remaining / 10) + "." + I2S(R2I(ModuloReal(.remaining, 10))), FONT_SIZE)
call SetTextTagVisibility(.tag, GetLocalPlayer() == .owner)
call SetTextTagPermanent(.tag, true)
set .clock = NewTimer(this)
call TimerStart(.clock, 0.10, true, function thistype.onUpdate)
return this
endmethod
endstruct
function CreateTextTagTimer takes unit u, real duration returns nothing
call TextTagTimer.create(u, duration)
endfunction
endlibrary
library TimedUnitEffect uses TimerUtils, UnitDex, UnitTypeUtils, UnitUtils
/*
* Public API
*
* function UnitFadeIn takes unit u, real duration returns nothing
* function UnitFadeOut takes unit u, real duration returns nothing
* function UnitFadeOutDist takes unit u, real x, real y returns nothing
* function UnitFadeInDist takes unit u, real x, real y returns nothing
* function UnitFadeDistKill takes unit u returns nothing
*
* function SetUnitFlyHeightTimed takes unit u, real height, real duration returns nothing
*
* function SetUnitAcquireRangeTimed takes unit u, real tempVal, real duration returns nothing
* function UnitDisableAttackTimed takes unit u, real duration returns nothing
*
* function UnitDisableFriendlyDamage takes unit u, real duration returns nothing
* function IsFriendlyDamageDisabled takes unit u returns boolean
*
* function UnitShareVisionTimed takes unit u, force f, real duration returns nothing
*
* function UnitDisableAbilityTimed takes unit u, integer abilityId, boolean flag, boolean hideUI, real duration returns nothing
* function UnitIncAbilityLevelTimed takes unit u, integer abilityId, real duration returns nothing
* function UnitAddAbilityTimed takes unit u, integer abilityId, real duration returns nothing
* function UnitRemoveAbilityTimed takes unit u, integer abilityId, real duration returns nothing
*
*/
private struct Alpha extends array
implement Iterator
private static constant real UPDATE_INTERVAL = 1./32
private unit unit
private integer red
private integer green
private integer blue
private real alpha
private integer endAlpha
private real delta
private boolean increasing
private static method exists takes unit u returns boolean
return thistype[GetUnitId(u)].unit == u
endmethod
private method destroy takes nothing returns nothing
set .unit = null
endmethod
private method update takes nothing returns nothing
set .alpha = .alpha + .delta
if ((.unit == null) or ((.alpha >= .endAlpha and .increasing) or (.alpha <= .endAlpha and not .increasing))) then
set .alpha = .endAlpha
call .finalize()
endif
call SetUnitVertexColor(.unit, .red, .green, .blue, R2I(.alpha))
endmethod
static method create takes unit u, integer startValue, integer endValue, real duration returns thistype
local thistype this = GetUnitId(u)
local integer id = GetUnitTypeId(u)
// If there is already a fade in progress for this unit
// then do nothing
if (u == .unit) then
return 0
endif
set .unit = u
set .red = GetUnitTypeTintRed(id)
set .green = GetUnitTypeTintGreen(id)
set .blue = GetUnitTypeTintBlue(id)
set .alpha = startValue
set .endAlpha = endValue
set .delta = UPDATE_INTERVAL * (endValue - startValue) / RMaxBJ(duration, UPDATE_INTERVAL)
set .increasing = (.delta > 0)
call .listAdd()
return this
endmethod
private static method onDeindex takes nothing returns nothing
if (exists(GetIndexedUnit())) then
call thistype[GetIndexedUnitId()].finalize()
endif
endmethod
private static method onInit takes nothing returns nothing
call OnUnitDeindex(function thistype.onDeindex)
endmethod
endstruct
private function SetUnitVertexColorDelayedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call SetUnitVertexColor(data.unit[0], data[1], data[2], data[3], data[4])
call data.destroy()
endfunction
function SetUnitVertexColorDelayed takes unit u, integer r, integer g, integer b, integer a, real timeout returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = r
set data[2] = g
set data[3] = b
set data[4] = a
call TimerStart(NewTimer(data), timeout, false, function SetUnitVertexColorDelayedCallback)
endfunction
private struct AlphaDist extends array
implement Iterator
private static constant real UPDATE_INTERVAL = 1./32
private unit unit
private integer red
private integer green
private integer blue
private real startDist
private real destX
private real destY
private real alpha
private integer endAlpha
private boolean increasing
private boolean stop
private static method exists takes unit u returns boolean
return thistype[GetUnitId(u)].unit == u
endmethod
private method destroy takes nothing returns nothing
set .unit = null
endmethod
private method update takes nothing returns nothing
if (.stop) then
return
endif
set .alpha = 255 * (UnitDistanceToPoint(.unit, .destX, .destY) / .startDist)
if (not (UnitAlive(.unit)) or ((.alpha >= .endAlpha and .increasing) or (.alpha <= .endAlpha and not .increasing))) then
set .alpha = .endAlpha
call .finalize()
endif
call SetUnitVertexColor(.unit, .red, .green, .blue, R2I(.alpha))
endmethod
static method create takes unit u, integer startValue, integer endValue, real x1, real y1, real x2, real y2 returns thistype
local thistype this = GetUnitId(u)
local integer id = GetUnitTypeId(u)
// If there is already a fade in progress for this unit
// then do nothing
if (u == .unit) then
return 0
endif
set .unit = u
set .red = GetUnitTypeTintRed(id)
set .green = GetUnitTypeTintGreen(id)
set .blue = GetUnitTypeTintBlue(id)
set .alpha = startValue
set .endAlpha = endValue
set .startDist = PointDistanceToPoint(x1,y1,x2,y2)
set .destX = x2
set .destY = y2
set .increasing = (endValue > startValue)
call .listAdd()
return this
endmethod
static method kill takes unit u returns nothing
local integer id = GetUnitId(u)
set thistype[id].stop = true
call thistype[id].finalize()
endmethod
private static method onDeindex takes nothing returns nothing
if (exists(GetIndexedUnit())) then
call thistype[GetIndexedUnitId()].finalize()
endif
endmethod
private static method onInit takes nothing returns nothing
call OnUnitDeindex(function thistype.onDeindex)
endmethod
endstruct
function UnitFadeOutDist takes unit u, real x, real y returns nothing
call AlphaDist.create(u, 255, 0, GetUnitX(u), GetUnitY(u), x, y)
endfunction
function UnitFadeInDist takes unit u, real x, real y returns nothing
call AlphaDist.create(u, 0, 255, GetUnitX(u), GetUnitY(u), x, y)
endfunction
function UnitFadeDistKill takes unit u returns nothing
local integer id = GetUnitTypeId(u)
local integer red = GetUnitTypeTintRed(id)
local integer green = GetUnitTypeTintGreen(id)
local integer blue = GetUnitTypeTintBlue(id)
call AlphaDist.kill(u)
call SetUnitVertexColor(u, red, green, blue, 255)
endfunction
function UnitFadeIn takes unit u, real duration returns nothing
call Alpha.create(u, 0, 255, duration)
endfunction
function UnitFadeOut takes unit u, real duration returns nothing
call Alpha.create(u, 255, 0, duration)
endfunction
// Takes duration instead of rate
function SetUnitFlyHeightTimed takes unit u, real height, real duration returns nothing
call SetUnitFlyHeight(u, height, RAbsBJ((height - GetUnitFlyHeight(u)) / RMaxBJ(duration, 0.01)))
endfunction
/*
private function SetUnitAcquireRangeTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call SetUnitAcquireRange(data.unit[0], GetUnitDefaultAcquireRange(data.unit[0]))
call data.destroy()
endfunction
function SetUnitAcquireRangeTimed takes unit u, real tempVal, real duration returns nothing
local Table data = Table.create()
call SetUnitAcquireRange(u, tempVal)
set data.unit[0] = u
call TimerStart(NewTimer(data), duration, false, function SetUnitAcquireRangeTimedCallback)
endfunction
*/
private function UnitPauseTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call PauseUnit(data.unit[0], false)
call BlzPauseUnitEx(data.unit[0], false)
call data.destroy()
endfunction
function UnitPauseTimed takes unit u, boolean pause, boolean pauseEx, real duration returns nothing
local Table data = Table.create()
call PauseUnit(u, pause)
call BlzPauseUnitEx(u, pauseEx)
set data.unit[0] = u
call TimerStart(NewTimer(data), duration, false, function UnitPauseTimedCallback)
endfunction
private function UnitDisableAttackTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call BlzSetUnitWeaponBooleanField(data.unit[0], UNIT_WEAPON_BF_ATTACKS_ENABLED, 0, data.boolean[1])
call BlzSetUnitWeaponBooleanField(data.unit[0], UNIT_WEAPON_BF_ATTACKS_ENABLED, 1, data.boolean[2])
call data.destroy()
endfunction
function UnitDisableAttackTimed takes unit u, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data.boolean[1] = BlzGetUnitWeaponBooleanField(u, UNIT_WEAPON_BF_ATTACKS_ENABLED, 0)
set data.boolean[2] = BlzGetUnitWeaponBooleanField(u, UNIT_WEAPON_BF_ATTACKS_ENABLED, 1)
call BlzSetUnitWeaponBooleanField(u, UNIT_WEAPON_BF_ATTACKS_ENABLED, 0, false)
call BlzSetUnitWeaponBooleanField(u, UNIT_WEAPON_BF_ATTACKS_ENABLED, 1, false)
call TimerStart(NewTimer(data), duration, false, function UnitDisableAttackTimedCallback)
endfunction
private function UnitDisableAbilityTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call BlzUnitDisableAbility(data.unit[0], data[1], not data.boolean[2], false)
call data.destroy()
endfunction
function UnitDisableAbilityTimed takes unit u, integer abilityId, boolean flag, boolean hideUI, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
set data.boolean[2] = flag
call BlzUnitDisableAbility(u, abilityId, flag, hideUI)
call TimerStart(NewTimer(data), duration, false, function UnitDisableAbilityTimedCallback)
endfunction
private function UnitAddAbilityTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call UnitRemoveAbility(data.unit[0], data[1])
call data.destroy()
endfunction
function UnitAddAbilityTimed takes unit u, integer abilityId, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
call UnitAddAbility(u, abilityId)
call TimerStart(NewTimer(data), duration, false, function UnitAddAbilityTimedCallback)
endfunction
private function UnitRemoveAbilityTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call UnitAddAbility(data.unit[0], data[1])
call data.destroy()
endfunction
function UnitRemoveAbilityTimed takes unit u, integer abilityId, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
call UnitRemoveAbility(u, abilityId)
call TimerStart(NewTimer(data), duration, false, function UnitRemoveAbilityTimedCallback)
endfunction
private function UnitRemoveAbilityDelayedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call UnitRemoveAbility(data.unit[0], data[1])
call data.destroy()
endfunction
function UnitRemoveAbilityDelayed takes unit u, integer abilityId, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
call TimerStart(NewTimer(data), duration, false, function UnitRemoveAbilityDelayedCallback)
endfunction
function UnitResetAbilityCooldownTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call BlzEndUnitAbilityCooldown(data.unit[0], data[1])
call data.destroy()
endfunction
function UnitResetAbilityCooldownTimed takes unit u, integer abilityId, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
call TimerStart(NewTimer(data), duration, false, function UnitResetAbilityCooldownTimedCallback)
endfunction
function UnitRemoveTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call RemoveUnit(data.unit[0])
call data.destroy()
endfunction
function UnitRemoveTimed takes unit u, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
call TimerStart(NewTimer(data), duration, false, function UnitRemoveTimedCallback)
endfunction
private struct UnitKill extends array
implement Alloc
private static Table data
private unit unit
private timer timer
method destroy takes nothing returns nothing
call ReleaseTimer(.timer)
call data.remove(GetHandleId(.unit))
set .unit = null
set .timer = null
call .deallocate()
endmethod
private static method kill takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call KillUnit(.unit)
call .destroy()
endmethod
static method create takes unit u, real timeout returns thistype
local thistype this = allocate()
set .unit = u
set .timer = NewTimer(this)
set data[GetHandleId(u)] = this
call TimerStart(.timer, timeout, false, function thistype.kill)
return this
endmethod
static method cancel takes unit u returns nothing
call thistype[data[GetHandleId(u)]].destroy()
endmethod
private static method onInit takes nothing returns nothing
set data = Table.create()
endmethod
endstruct
function UnitKillTimedCancel takes unit u returns nothing
call UnitKill.cancel(u)
endfunction
function UnitKillTimed takes unit u, real duration returns nothing
call UnitKill.create(u, duration)
endfunction
/*
private function UnitSetPropWindowTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call SetUnitPropWindow(data.unit[0], GetUnitDefaultPropWindow(data.unit[0]))
call data.destroy()
endfunction
function UnitSetPropWindowTimed takes unit u, real value, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
call SetUnitPropWindow(u, value)
call TimerStart(NewTimer(data), duration, false, function UnitSetPropWindowTimedCallback)
endfunction
private function UnitAddTypeTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call UnitRemoveType(data.unit[0], ConvertUnitType(data[1]))
call data.destroy()
endfunction
function UnitAddTypeTimed takes unit u, unittype utype, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = GetHandleId(utype)
call TimerStart(NewTimer(data), duration, false, function UnitAddTypeTimedCallback)
endfunction
*/
private function StartUnitAbilityCooldownTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call BlzStartUnitAbilityCooldown(data.unit[0], data[1], data.real[2])
call data.destroy()
endfunction
function StartUnitAbilityCooldownTimed takes unit u, integer abilityId, real timeout, real cooldown returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
set data.real[2] = cooldown
call TimerStart(NewTimer(data), timeout, false, function StartUnitAbilityCooldownTimedCallback)
endfunction
/*
private function UnitIncAbilityLevelTimedCallback takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
call DecUnitAbilityLevel(data.unit[0], data[1])
call data.destroy()
endfunction
function UnitIncAbilityLevelTimed takes unit u, integer abilityId, real duration returns nothing
local Table data = Table.create()
set data.unit[0] = u
set data[1] = abilityId
call IncUnitAbilityLevel(u, abilityId)
call TimerStart(NewTimer(data), duration, false, function UnitIncAbilityLevelTimedCallback)
endfunction
*/
private struct FriendlyDamage extends array
private static Table data
private static method disableTimedCallback takes nothing returns nothing
local integer id = ReleaseTimer(GetExpiredTimer())
call data.timer.remove(id)
endmethod
static method disableTimed takes unit u, real duration returns nothing
local integer id = GetHandleId(u)
if (not data.timer.has(id)) then
set data.timer[id] = NewTimer(id)
endif
call TimerStart(data.timer[id], duration, false, function thistype.disableTimedCallback)
endmethod
static method isDisabled takes unit u returns boolean
return data.timer.has(GetHandleId(u))
endmethod
private static method onInit takes nothing returns nothing
set data = Table.create()
endmethod
endstruct
function UnitDisableFriendlyDamageTimed takes unit u, real duration returns nothing
call FriendlyDamage.disableTimed(u, duration)
endfunction
function IsFriendlyDamageDisabled takes unit u returns boolean
return FriendlyDamage.isDisabled(u)
endfunction
private struct Vision extends array
private static unit argUnit = null
private static boolean argShare = false
private unit u
private force f
private timer timer
private method destroy takes nothing returns nothing
set .u = null
set .f = null
set .timer = null
endmethod
private static method shareVisionEnum takes nothing returns nothing
call UnitShareVision(argUnit, GetEnumPlayer(), argShare)
endmethod
private static method removeVision takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
set argUnit = .u
set argShare = false
call ForForce(.f, function thistype.shareVisionEnum)
call .destroy()
endmethod
static method grantVisionTimed takes unit u, force f, real duration returns nothing
local thistype this = GetUnitId(u)
set .u = u
set .f = f
if (.timer == null) then
set .timer = NewTimer(this)
endif
call TimerStart(.timer, duration, false, function thistype.removeVision)
set argUnit = u
set argShare = true
call ForForce(f, function thistype.shareVisionEnum)
endmethod
endstruct
function UnitShareVisionTimed takes unit u, force f, real duration returns nothing
call Vision.grantVisionTimed(u, f, duration)
endfunction
endlibrary
library TimerUtils requires optional Table
/*************************************************
*
* TimerUtilsEx
* v2.1.0.2
* By Vexorian, Bribe & Magtheridon96
*
* Original version by Vexorian.
*
* Flavors:
* Hashtable:
* - RAM: Minimal
* - TimerData: Slow
*
* Array:
* - RAM: Maximal
* - TimerData: Fast
*
* All the functions have O(1) complexity.
* The Array version is the fastest, but the hashtable
* version is the safest. The Array version is still
* quite safe though, and I would recommend using it.
* The system is much slower in debug mode.
*
* Optional Requirement:
* - Table by Bribe
* - hiveworkshop.com/forums/showthread.php?t=188084
*
* API:
* ----
* - function NewTimer takes integer i returns timer
* - Returns a new timer from the stack and attaches a value to it.
* - function ReleaseTimer takes timer t returns integer
* - Throws a timer back into the stack. Also returns timer data.
* - function SetTimerData takes timer t, integer value returns nothing
* - Attaches a value to a timer.
* - function GetTimerData takes timer t returns integer
* - Returns the attached value.
*
*************************************************/
// Configuration
globals
// Use hashtable, or fast array?
private constant boolean USE_HASH = true
// Max Number of Timers Held in Stack
private constant integer QUANTITY = 512
endglobals
globals
private timer array tT
private integer tN = 0
endglobals
private module Init
private static method onInit takes nothing returns nothing
static if not USE_HASH then
local integer i = QUANTITY
loop
set i = i - 1
set tT[i] = CreateTimer()
exitwhen i == 0
endloop
set tN = QUANTITY
elseif LIBRARY_Table then
set tb = Table.create()
endif
endmethod
endmodule
// JassHelper doesn't support static ifs for globals.
private struct Data extends array
static if not USE_HASH then
static integer array data
endif
static if LIBRARY_Table then
static Table tb = 0
else
static hashtable ht = InitHashtable()
endif
implement Init
endstruct
// Double free protection
private function ValidTimer takes integer i returns boolean
static if LIBRARY_Table then
return Data.tb.boolean[-i]
else
return LoadBoolean(Data.ht, i, 1)
endif
endfunction
private function Get takes integer id returns integer
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to get data from invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
return Data.tb[id]
else
return LoadInteger(Data.ht, id, 0)
endif
else
return Data.data[id - 0x100000]
endif
endfunction
private function Set takes integer id, integer data returns nothing
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to attach data to invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
set Data.tb[id] = data
else
call SaveInteger(Data.ht, id, 0, data)
endif
else
set Data.data[id - 0x100000] = data
endif
endfunction
function SetTimerData takes timer t, integer data returns nothing
call Set(GetHandleId(t), data)
endfunction
function GetTimerData takes timer t returns integer
return Get(GetHandleId(t))
endfunction
function NewTimer takes integer data returns timer
local integer id
if tN == 0 then
static if USE_HASH then
set tT[0] = CreateTimer()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: No Timers In The Stack! You must increase 'QUANTITY'")
return null
endif
else
set tN = tN - 1
endif
set id = GetHandleId(tT[tN])
static if LIBRARY_Table then
set Data.tb.boolean[-id] = true
else
call SaveBoolean(Data.ht, id, 1, true)
endif
call Set(id, data)
return tT[tN]
endfunction
function ReleaseTimer takes timer t returns integer
local integer id = GetHandleId(t)
local integer data = 0
// Pause the timer just in case.
call PauseTimer(t)
// Make sure the timer is valid.
if ValidTimer(id) then
// Get the timer's data.
set data = Get(id)
// Unmark handle id as a valid timer.
static if LIBRARY_Table then
call Data.tb.boolean.remove(-id)
else
call RemoveSavedBoolean(Data.ht, id, 1)
endif
//If it's not run in USE_HASH mode, this next block is useless.
static if USE_HASH then
//At least clear hash memory while it's in the recycle stack.
static if LIBRARY_Table then
call Data.tb.remove(id)
else
call RemoveSavedInteger(Data.ht, id, 0)
endif
// If the recycle limit is reached
if tN == QUANTITY then
// then we destroy the timer.
call DestroyTimer(t)
return data
endif
endif
//Recycle the timer.
set tT[tN] = t
set tN = tN + 1
//Tried to pass a bad timer.
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to release non-active timer!")
endif
//Return Timer Data.
return data
endfunction
endlibrary
library TypeIdUtils initializer Init
globals
//private constant string INVALID_OBJECT_NAME = GetObjectName(0)
/*
// --------
// Income requirements setup
private constant integer MIN_COST = 100 // Higher number is better
private constant integer COST_STEP = 100 // Higher number is better
private constant integer MAX_COST = 500 // Lower number is better
// --------
*/
private integer array mask
private integer array pow256
private integer array hexChar
//private Table LimitTrigTable
endglobals
/*
// TypeIdToChar('ABCD', 1) == 'B'
function TypeIdToChar takes integer id, integer pos returns integer
return BlzBitAnd(id, mask[pos]) / pow256[pos]
endfunction
*/
constant function IsValidTypeId takes integer id returns boolean
local string s = GetObjectName(id)
return s != "Default string" and s != "(null)"
endfunction
function PlayerSetTech takes player p, integer techTypeId, boolean flag returns nothing
if (IsValidTypeId(techTypeId)) then
if (flag) then
call SetPlayerTechResearched(p, techTypeId, 1)
else
call SetPlayerTechResearched(p, techTypeId, 0)
endif
endif
endfunction
function DateToTechId takes integer month, integer year returns integer
local integer ones = ModuloInteger(year, 10) // Ones place of year
local integer tens = ModuloInteger(year, 100) / 10 // Tens place of year
return ('D' * pow256[3]) + (hexChar[month] * pow256[2]) + /*
*/ (hexChar[tens] * pow256[1]) + (hexChar[ones] * pow256[0])
endfunction
// Can store any integer from 0-4095 (0x0FFF)
function ResourceToTechId takes integer prefix, integer amount returns integer
local integer result = prefix * pow256[3]
local integer hexDigit = amount / 256
set result = result + hexChar[hexDigit] * pow256[2]
set amount = amount - hexDigit * 256
set hexDigit = amount / 16
set result = result + hexChar[hexDigit] * pow256[1]
set amount = amount - hexDigit * 16
set hexDigit = amount / 1
set result = result + hexChar[hexDigit] * pow256[0]
return result
endfunction
/*
private function RegisterAnyPlayerLimitEvent takes trigger t, playerstate state, limitop op, real limit returns nothing
local integer i = 0
loop
// Loop over Players array to cut down on events
call TriggerRegisterPlayerStateEvent(t, Players[i], state, op, limit)
set i = i + 1
exitwhen (i == PlayerCount)
endloop
endfunction
private function OnMoneyGreaterThan takes nothing returns nothing
call PlayerSetTechUnchecked(GetTriggerPlayer(), LimitTrigTable[GetHandleId(GetTriggeringTrigger())], true)
endfunction
private function OnMoneyLessThan takes nothing returns nothing
call PlayerSetTechUnchecked(GetTriggerPlayer(), LimitTrigTable[GetHandleId(GetTriggeringTrigger())], false)
endfunction
private function InitResourceLimitTrigs takes nothing returns nothing
local trigger t = null
local integer amount = MIN_COST
local integer techId
set LimitTrigTable = Table.create()
loop
exitwhen (amount > MAX_COST)
set techId = ResourceToTechId('M', amount)
if (IsValidTypeId(techId)) then
set t = CreateTrigger()
call RegisterAnyPlayerLimitEvent(t, PLAYER_STATE_RESOURCE_GOLD, GREATER_THAN_OR_EQUAL, amount)
call TriggerAddCondition(t, Condition(function OnMoneyGreaterThan))
set LimitTrigTable[GetHandleId(t)] = techId
set t = CreateTrigger()
call RegisterAnyPlayerLimitEvent(t, PLAYER_STATE_RESOURCE_GOLD, LESS_THAN, amount)
call TriggerAddCondition(t, Condition(function OnMoneyLessThan))
set LimitTrigTable[GetHandleId(t)] = techId
endif
set amount = amount + COST_STEP
endloop
call ReleaseTimer(GetExpiredTimer())
endfunction
*/
private function Init takes nothing returns nothing
// Constants
set mask[0] = 0xFF000000
set mask[1] = 0x00FF0000
set mask[2] = 0x0000FF00
set mask[3] = 0x000000FF
set pow256[0] = 0x00000001
set pow256[1] = 0x00000100
set pow256[2] = 0x00010000
set pow256[3] = 0x01000000
set hexChar[0] = '0'
set hexChar[1] = '1'
set hexChar[2] = '2'
set hexChar[3] = '3'
set hexChar[4] = '4'
set hexChar[5] = '5'
set hexChar[6] = '6'
set hexChar[7] = '7'
set hexChar[8] = '8'
set hexChar[9] = '9'
set hexChar[10] = 'A'
set hexChar[11] = 'B'
set hexChar[12] = 'C'
set hexChar[13] = 'D'
set hexChar[14] = 'E'
set hexChar[15] = 'F'
// Run at 0.25 seconds so Players array (PlayerUtils) is populated
//call TimerStart(NewTimer(0), 0.25, false, function InitResourceLimitTrigs)
endfunction
endlibrary
library UnitCargo requires UnitDex, UnitUtils
private struct DefaultCargo extends array
readonly static unit array transport
readonly group cargo
private method destroy takes nothing returns nothing
if (.cargo != null) then
call DestroyGroup(.cargo)
endif
endmethod
private static method create takes unit u returns thistype
local thistype this = GetUnitId(u)
set .cargo = CreateGroup()
return this
endmethod
private static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_HAS_CARGO)) then
call create(u)
endif
set u = null
endmethod
private static method onDeindex takes nothing returns nothing
local integer id = GetIndexedUnitId()
call thistype[id].destroy()
set transport[id] = null
endmethod
private static method transportDeathLoadedUnitsEnum takes nothing returns nothing
local unit u = GetEnumUnit()
set transport[GetUnitId(u)] = null
call KillUnit(u)
set u = null
endmethod
private static method onDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local thistype this
if (UnitHasAbility(u, ATTR_HAS_CARGO)) then
set this = GetUnitId(u)
call ForGroup(.cargo, function thistype.transportDeathLoadedUnitsEnum)
call DestroyGroup(.cargo)
set .cargo = null
endif
set u = null
endmethod
private static method onUnitLoaded takes nothing returns nothing
local unit transportingUnit = GetTransportUnit()
local unit loadedUnit = GetLoadedUnit()
local thistype this = GetUnitId(transportingUnit)
call GroupAddUnit(.cargo, loadedUnit)
set transport[GetUnitId(loadedUnit)] = transportingUnit
set transportingUnit = null
set loadedUnit = null
endmethod
// Units are issued a "stop" order when they are unloaded from a transport
// We check here if the unit is no longer loaded so it can be removed from
// its transport's tracked cargo group
private static method checkIfUnloaded takes nothing returns nothing
local unit u
local integer id
local thistype this
if (GetIssuedOrderId() == ORDER_STOP) then
set u = GetTriggerUnit()
set id = GetUnitId(u)
if (transport[id] != null and not IsUnitLoaded(u)) then
set this = GetUnitId(transport[id])
call GroupRemoveUnit(.cargo, u)
set transport[id] = null
endif
set u = null
endif
endmethod
private static method onInit takes nothing returns nothing
call OnUnitIndex(function thistype.onIndex)
call OnUnitDeindex(function thistype.onDeindex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_LOADED, function thistype.onUnitLoaded)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.checkIfUnloaded)
endmethod
endstruct
endlibrary
library UnitDex uses optional WorldBounds
/***************************************************************
*
* v1.2.2, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex assigns every unit an unique integer. It attempts to make that number within the
* maximum array limit so you can associate it with one.
* _________________________________________________________________________
* 1. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map, save it, then restart the editor and comment out the line below.
*/
///! external ObjectMerger w3a Adef uDex anam "Detect Leave" ansf "(UnitDex)" aart "" acat "" arac 0
/* ________________________________________________________________________
* 2. Configuration
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
private module UnitDexConfig
// The raw code of the leave detection ability.
static constant integer DETECT_LEAVE_ABILITY = 'uDex'
// Allow debug messages (debug mode must also be on)
static constant boolean ALLOW_DEBUGGING = true
// Uncomment the lines below to define a global filter for units being indexed
static method onFilter takes unit u returns boolean
return GetUnitAbilityLevel(u, ATTR_UNINDEXED) == 0
endmethod
endmodule
/* _________________________________________________________________________
* 3. Function API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Every function inlines.
*
* function GetUnitId takes unit whichUnit returns integer
* function GetUnitById takes integer index returns unit
*
* function UnitDexEnable takes boolean flag returns nothing
* function UnitDexRemove takes unit u, boolean runEvents returns boolean
*
* function IsUnitIndexed takes unit u returns boolean
* function IsIndexingEnabled takes nothing returns boolean
*
* function GetIndexedUnit takes nothing returns unit
* function GetIndexedUnitId takes nothing returns integer
*
* function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns indexevent
* function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
* function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
*
* function OnUnitIndex takes code func returns triggercondition
* function OnUnitDeindex takes code func returns triggercondition
* _________________________________________________________________________
* 4. Struct API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* UnitDex.Enabled = false // toggle the indexer
* UnitDex.Initialized // returns true if the preload timer has finished
* UnitDex.Count // returns the amount of units indexed
* UnitDex.Unit[0] // access the UnitDex array directly
* UnitDex.Group // a unit group containing every indexed unit (for enumeration)
* UnitDex.LastIndex // returns the last indexed unit's id
* _________________________________________________________________________
* 5. Public Variables
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* These are to be used with the "eventtype" argument of the event API:
*
* constant integer EVENT_UNIT_INDEX = 0
* constant integer EVENT_UNIT_DEINDEX = 1
* _________________________________________________________________________
* 6. Examples
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Associate a unit with a variable
*
* set UnitFlag[GetUnitId(yourUnit)] = true
*
* 2. Allocate a struct instance using a units assigned ID
*
* local somestruct data = GetUnitId(yourUnit)
*
* 3. Detect when a unit leaves the map
*
* function Exit takes nothing returns nothing
* call BJDebugMsg("The unit " + GetUnitName(GetIndexedUnit()) + " has left the map.")
* endfunction
*
* call OnUnitDeindex(function Exit)
* // or
* call RegisterUnitIndexEvent(Filter(function Exit), EVENT_UNIT_DEINDEX)
*
*
* _________________________________________________________________________
* 7. How it works
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* 1. Enumerate all preplaced units
* 2. TriggerRegisterEnterRegion native to detect when a unit enters the map
* 3. Assign each unit that enters the map a unique integer
* 4. Give every unit an ability based off of defend. There is no native to accurately
* detect when a unit leaves the map but when a unit dies or is removed from the game
* they are issued the "undefend" order
* 5. Catch the "undefend" order and remove unit from the queue
* _________________________________________________________________________
* 8. Notes
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - This system is compatable with GUI because it utilizes UnitUserData (custom values for units).
* - The object merger line should be commented out after saving and restarting.
*
* -http://www.hiveworkshop.com/forums/submissions-414/unitdex-lightweight-unit-indexer-248209/
*
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
globals
// Event types
constant integer EVENT_UNIT_INDEX = 0
constant integer EVENT_UNIT_DEINDEX = 1
// System variables
private trigger array IndexTrig
private integer Index = 0
private real E=-1
private boolexpr FilterEnter
endglobals
function GetUnitId takes unit whichUnit returns integer
return GetUnitUserData(whichUnit)
endfunction
function GetUnitById takes integer index returns unit
return UnitDex.Unit[index]
endfunction
function GetIndexedUnit takes nothing returns unit
return UnitDex.Unit[UnitDex.LastIndex]
endfunction
function GetIndexedUnitId takes nothing returns integer
return UnitDex.LastIndex
endfunction
function IsUnitIndexed takes unit u returns boolean
return (GetUnitById(GetUnitId(u)) == u)
endfunction
function UnitDexEnable takes boolean flag returns nothing
set UnitDex.Enabled = flag
endfunction
function IsIndexingEnabled takes nothing returns boolean
return UnitDex.Enabled
endfunction
function RegisterUnitIndexEvent takes boolexpr func, integer eventtype returns triggercondition
return TriggerAddCondition(IndexTrig[eventtype], func)
endfunction
function RemoveUnitIndexEvent takes triggercondition c, integer eventtype returns nothing
call TriggerRemoveCondition(IndexTrig[eventtype], c)
endfunction
function TriggerRegisterUnitIndexEvent takes trigger t, integer eventtype returns nothing
call TriggerRegisterVariableEvent(t, SCOPE_PRIVATE + "E", EQUAL, eventtype)
endfunction
function OnUnitIndex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_INDEX], Filter(func))
endfunction
function OnUnitDeindex takes code func returns triggercondition
return TriggerAddCondition(IndexTrig[EVENT_UNIT_DEINDEX], Filter(func))
endfunction
/****************************************************************/
private keyword UnitDexCore
struct UnitDex extends array
static boolean Enabled = true
readonly static integer LastIndex
readonly static boolean Initialized=false
readonly static group Group=CreateGroup()
readonly static unit array Unit
readonly static integer Count = 0
readonly static integer array List
implement UnitDexConfig
private static integer Counter = 0
implement UnitDexCore
endstruct
function UnitDexRemove takes unit u, boolean runEvents returns boolean
return UnitDex.Remove(u, runEvents)
endfunction
/****************************************************************/
private module UnitDexCore
static method Remove takes unit u, boolean runEvents returns boolean
local integer i
if (IsUnitIndexed(u)) then
set i = GetUnitId(u)
set UnitDex.List[i] = Index
set Index = i
call GroupRemoveUnit(UnitDex.Group, u)
call SetUnitUserData(u, 0)
if (runEvents) then
set UnitDex.LastIndex = i
set E = EVENT_UNIT_DEINDEX
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
set E = -1
endif
set UnitDex.Unit[i] = null
set UnitDex.Count = UnitDex.Count - 1
return true
endif
return false
endmethod
private static method onGameStart takes nothing returns nothing
local integer i = 1
loop
exitwhen i > Counter
set LastIndex = i
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
set E = EVENT_UNIT_INDEX
set E = -1
set i = i + 1
endloop
set LastIndex = Counter
set Initialized = true
set FilterEnter = null
call DestroyTimer(GetExpiredTimer())
endmethod
private static method onEnter takes nothing returns boolean
local unit u = GetFilterUnit()
local integer i = GetUnitId(u)
local integer t = Index
if (i == 0 and thistype.Enabled) then
// If a filter was defined pass the unit through it.
static if (thistype.onFilter.exists) then
if (not thistype.onFilter(u)) then
set u = null
return false // check failed
endif
endif
// Handle debugging
static if (thistype.DEBUG_MODE and thistype.ALLOW_DEBUGGING) then
if (t == 0 and Counter+1 >= JASS_MAX_ARRAY_SIZE) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "UnitDex: Maximum number of units reached!")
set u = null
return false
endif
endif
// Add to group of indexed units
call GroupAddUnit(thistype.Group, u)
// Give unit the leave detection ability
call UnitAddAbility(u, thistype.DETECT_LEAVE_ABILITY)
call UnitMakeAbilityPermanent(u, true, thistype.DETECT_LEAVE_ABILITY)
// Allocate index
if (Index != 0) then
set Index = List[t]
else
set Counter = Counter + 1
set t = Counter
endif
set List[t] = -1
set LastIndex = t
set thistype.Unit[t] = u
set Count = Count + 1
// Store the index
call SetUnitUserData(u, t)
if (thistype.Initialized) then
// Execute custom events registered with RegisterUnitIndexEvent
call TriggerEvaluate(IndexTrig[EVENT_UNIT_INDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_INDEX
// Reset so the event can occur again
set E = -1
endif
endif
set u = null
return false
endmethod
private static method onLeave takes nothing returns boolean
local unit u
local integer i
// Check if order is undefend.
if (thistype.Enabled and GetIssuedOrderId() == 852056) then
set u = GetTriggerUnit()
// If unit was killed (not removed) then don't continue
if (GetUnitAbilityLevel(u, thistype.DETECT_LEAVE_ABILITY) != 0) then
set u = null
return false
endif
set i = GetUnitId(u)
// If unit has been indexed then deindex it
if (i > 0 and i <= Counter and u == GetUnitById(i)) then
// Recycle the index
set List[i] = Index
set Index = i
set LastIndex = i
// Remove to group of indexed units
call GroupRemoveUnit(thistype.Group, u)
// Execute custom events without any associated triggers
call TriggerEvaluate(IndexTrig[EVENT_UNIT_DEINDEX])
// Handle TriggerRegisterUnitIndexEvent
set E = EVENT_UNIT_DEINDEX
// Remove entry
call SetUnitUserData(u, 0)
set thistype.Unit[i] = null
// Decrement unit count
set Count = Count - 1
// Reset so the event can occur again
set E = -1
endif
set u = null
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local player p
local unit u
static if (not LIBRARY_WorldBounds) then // Check if WorldBounts exists, if not then define the necessary vars
local region reg = CreateRegion() // If WorldBounds wasn't found, create the region manually
local rect world = GetWorldBounds()
endif
static if (not LIBRARY_GroupUtils) then // Check if GroupUtils exists so we can use it's enumeration group.
local group ENUM_GROUP = CreateGroup() // If not, create the group.
endif
set FilterEnter = Filter(function thistype.onEnter)
// Begin to index units when they enter the map
static if (LIBRARY_WorldBounds) then
call TriggerRegisterEnterRegion(CreateTrigger(), WorldBounds.worldRegion, FilterEnter)
else
call RegionAddRect(reg, world)
call TriggerRegisterEnterRegion(CreateTrigger(), reg, FilterEnter)
call RemoveRect(world)
set world = null
endif
call TriggerAddCondition(t, Filter(function thistype.onLeave))
set IndexTrig[EVENT_UNIT_INDEX] = CreateTrigger()
set IndexTrig[EVENT_UNIT_DEINDEX] = CreateTrigger()
loop
set p = Player(i)
// Detect "undefend"
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
// Hide the detect ability from players
call SetPlayerAbilityAvailable(p, thistype.DETECT_LEAVE_ABILITY, false)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
// Index preplaced units
set i = 0
loop
call GroupEnumUnitsOfPlayer(ENUM_GROUP, Player(i), FilterEnter)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
static if (not LIBRARY_GroupUtils) then
call DestroyGroup(ENUM_GROUP)
set ENUM_GROUP = null
endif
set LastIndex = Counter
// run init triggers
call TimerStart(CreateTimer(), 0.00, false, function thistype.onGameStart)
endmethod
endmodule
endlibrary
library UnitMovement uses UnitDex, UnitUtils
private struct UnitMovementTracker extends array
implement Iterator
private static constant real UPDATE_INTERVAL = 1./60
private static thistype array unit2thistype
private unit unit
private real x
private real y
private real angle
readonly real dx
readonly real dy
readonly real da
readonly boolean moving
readonly boolean rotating
static method operator[] takes unit u returns thistype
return unit2thistype[GetUnitId(u)]
endmethod
static method operator[]= takes unit u, thistype this returns nothing
set unit2thistype[GetUnitId(u)] = this
endmethod
private method destroy takes nothing returns nothing
set thistype[.unit] = 0
set .unit = null
endmethod
private method update takes nothing returns nothing
local real newX = GetUnitX(.unit)
local real newY = GetUnitY(.unit)
local real newAngle = GetUnitFacing(.unit)
set .dx = newX - .x
set .dy = newY - .y
set .da = newAngle - .angle
set .moving = ((newX != .x) or (newY != .y))
set .rotating = (newAngle != .angle)
set .x = newX
set .y = newY
set .angle = newAngle
endmethod
static method exists takes unit u returns boolean
return thistype[u] > 0
endmethod
static method create takes unit u returns thistype
local thistype this = 0
if (not exists(u)) then
set this = GetUnitId(u)
set thistype[u] = this
set .unit = u
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .angle = GetUnitFacing(u)
set .moving = false
set .rotating = false
call .listAdd()
endif
return this
endmethod
private static method onDeindex takes nothing returns nothing
call thistype[GetIndexedUnit()].finalize()
endmethod
private static method onInit takes nothing returns nothing
call OnUnitDeindex(function thistype.onDeindex)
endmethod
endstruct
function UnitTrackMovement takes unit u, boolean flag returns nothing
if (flag) then
call UnitMovementTracker.create(u)
else
call UnitMovementTracker[u].finalize()
endif
endfunction
function GetUnitPositionDeltaX takes unit u returns real
return UnitMovementTracker[u].dx
endfunction
function GetUnitPositionDeltaY takes unit u returns real
return UnitMovementTracker[u].dy
endfunction
function GetUnitAngleDelta takes unit u returns real
return UnitMovementTracker[u].da
endfunction
function IsUnitMoving takes unit u returns boolean
return UnitMovementTracker[u].moving
endfunction
function IsUnitRotating takes unit u returns boolean
return UnitMovementTracker[u].rotating
endfunction
private struct UnitMovement extends array
implement Iterator
private static constant real UPDATE_INTERVAL = 1./60
private static thistype array unit2thistype
private unit unit
private real dx
private real dy
private real angle
private real duration
private real elapsed
private boolean autoDestroy
static method operator[] takes unit u returns thistype
return unit2thistype[GetUnitId(u)]
endmethod
private method destroy takes nothing returns nothing
//call IssueImmediateOrderById(.unit, ORDER_STOP)
//call SetUnitMoveSpeed(.unit, GetUnitDefaultMoveSpeed(.unit))
set unit2thistype[this] = 0
set .unit = null
endmethod
private method update takes nothing returns nothing
if (not UnitAlive(.unit)) then
call .finalize()
return
endif
//call SetUnitX(.unit, GetUnitX(.unit) + .dx)
//call SetUnitY(.unit, GetUnitY(.unit) + .dy)
call SetUnitPosition(.unit, GetUnitX(.unit) + .dx, GetUnitY(.unit) + .dy)
call BlzSetUnitFacingEx(.unit, .angle)
set .elapsed = .elapsed + UPDATE_INTERVAL
if (.elapsed >= .duration) then
set .dx = 0
set .dy = 0
call SetUnitAnimation(.unit, "stand")
if (.autoDestroy) then
call .finalize()
endif
endif
endmethod
method setDestination takes real destX, real destY, real duration, boolean autoDestroy returns nothing
local real x = GetUnitX(.unit)
local real y = GetUnitY(.unit)
set duration = RMaxBJ(duration, UPDATE_INTERVAL)
set .dx = UPDATE_INTERVAL * (destX - x) / duration
set .dy = UPDATE_INTERVAL * (destY - y) / duration
set .angle = AngleBetweenDeg(x, y, destX, destY)
set .elapsed = 0
set .duration = duration
set .autoDestroy = autoDestroy
endmethod
static method create takes unit u, real destX, real destY, real duration, boolean autoDestroy returns thistype
local thistype this = GetUnitId(u)
if (unit2thistype[this] == 0) then
set unit2thistype[this] = this
set .unit = u
call .listAdd()
endif
//call SetUnitMoveSpeed(u, 0)
//call IssuePointOrderById(u, ORDER_MOVE, destX, destY)
call .setDestination(destX, destY, duration, autoDestroy)
return this
endmethod
endstruct
function UnitMovementKill takes unit u returns nothing
call UnitMovement[u].finalize()
endfunction
function SetUnitPositionTimed takes unit u, real x, real y, real duration, boolean autoDestroy returns nothing
call UnitMovement.create(u, x, y, duration, autoDestroy)
endfunction
endlibrary
library UnitUtils initializer Init requires DebugUtils, Table, TimerUtils, UnitDex
/*
* Public API
*
* constant group ENUM_GROUP
*
* function CreateTempUnit takes integer unitTypeId returns unit
* function CreateUnits takes player p, integer unitTypeId, integer count, real x, real y returns nothing
* function CreateUnitsAroundPoint takes player p, integer unitTypeId, integer count, real x, real y, real minDistance, real maxDistance returns nothing
* function UnitHasAbility takes unit u, integer abilityId returns boolean
*
* function GetNearestUnit takes real x, real y, real maxRange, boolexpr filter returns unit
* function UnitAngleToPointDeg takes unit u, real x, real y returns real
* function UnitDistanceToPoint takes unit u, real x, real y returns real
* function UnitDistanceToUnit takes unit u, unit v returns real
* function IsUnitInCone takes unit u, real x, real y, real direction, real angle returns boolean
*
* function UnitDisableAttack takes unit u, integer weaponIndex, boolean disable returns nothing
* function UnitSetManaRegen takes unit u, real value returns nothing
* function UnitStartAbilityCooldown takes unit u, integer abilityId returns nothing
*
* function IsCombatUnit takes unit u returns boolean
* function IsUnitBusy takes unit u returns boolean
* function IsUnitUnderConstruction takes unit u returns boolean
*
* function QueueUnitRemove takes unit u returns nothing
* function RemoveQueuedUnits takes nothing returns nothing
*
*/
globals
private unit NearestUnit = null
private boolean array UnderConstruction
private unit array RemoveUnits
private integer RemoveUnitsCount = 0
constant group ENUM_GROUP = CreateGroup()
endglobals
function UnitHasAbility takes unit u, integer abilityId returns boolean
return GetUnitAbilityLevel(u, abilityId) > 0
endfunction
function CreateTempUnit takes integer unitTypeId returns unit
return CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), unitTypeId, WorldBounds.minX, WorldBounds.minY, 0)
endfunction
function CreateUnits takes player p, integer unitTypeId, integer count, real x, real y returns nothing
loop
exitwhen (count <= 0)
call CreateUnit(p, unitTypeId, x, y, bj_UNIT_FACING)
set count = count - 1
endloop
endfunction
function CreateUnitsAroundPoint takes player p, integer unitTypeId, integer count, real x, real y, real minDistance, real maxDistance returns nothing
local integer i = 0
local real d
local real a
loop
exitwhen (i == count)
set d = GetRandomReal(minDistance, maxDistance)
set a = TAU / count * i
call CreateUnit(p, unitTypeId, x + d*Cos(a), y + d*Sin(a), bj_UNIT_FACING)
set i = i + 1
endloop
endfunction
function GetNearestUnit takes real x, real y, real maxRange, boolexpr filter returns unit
local real dx
local real dy
local real distsq
local real best = maxRange*maxRange
local integer i = 0
local integer size
local unit u
set NearestUnit = null
call GroupEnumUnitsInRange(ENUM_GROUP, x, y, maxRange, filter)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
set dx = x - GetUnitX(u)
set dy = y - GetUnitY(u)
set distsq = dx*dx + dy*dy
if (distsq < best) then
set best = distsq
set NearestUnit = u
endif
set i = i + 1
endloop
set u = null
return NearestUnit
endfunction
// The angle from the unit to the target point in the interval [0,360)
function UnitAngleToPointDeg takes unit u, real x, real y returns real
return AngleBetweenDeg(GetUnitX(u), GetUnitY(u), x, y)
endfunction
function UnitAngleToUnitDeg takes unit u, unit v returns real
return AngleBetweenDeg(GetUnitX(u), GetUnitY(u), GetUnitX(v), GetUnitY(v))
endfunction
function UnitDistanceToPoint takes unit u, real x, real y returns real
local real dx = GetUnitX(u) - x
local real dy = GetUnitY(u) - y
return SquareRoot(dx*dx + dy*dy)
endfunction
function UnitDistanceToUnit takes unit u, unit v returns real
local real dx = GetUnitX(u) - GetUnitX(v)
local real dy = GetUnitY(u) - GetUnitY(v)
return SquareRoot(dx*dx + dy*dy)
endfunction
function IsUnitInCone takes unit u, real x, real y, real direction, real angle returns boolean
set direction = bj_DEGTORAD * direction
set angle = bj_DEGTORAD * angle
return Acos(Cos((Atan2(GetUnitY(u) - y, GetUnitX(u) - x)) - direction)) < angle
endfunction
function UnitDisableAttack takes unit u, integer weaponIndex, boolean disable returns nothing
call BlzSetUnitWeaponBooleanField(u, UNIT_WEAPON_BF_ATTACKS_ENABLED, weaponIndex, not disable)
endfunction
function QueueUnitRemove takes unit u returns nothing
set RemoveUnits[RemoveUnitsCount] = u
set RemoveUnitsCount = RemoveUnitsCount + 1
endfunction
function RemoveQueuedUnits takes nothing returns nothing
loop
exitwhen (RemoveUnitsCount == 0)
set RemoveUnitsCount = RemoveUnitsCount - 1
call RemoveUnit(RemoveUnits[RemoveUnitsCount])
set RemoveUnits[RemoveUnitsCount] = null
endloop
endfunction
function UnitSetManaRegen takes unit u, real value returns nothing
call BlzSetUnitRealField(u, UNIT_RF_MANA_REGENERATION, value)
endfunction
function UnitStartAbilityCooldown takes unit u, integer abilityId returns nothing
call BlzStartUnitAbilityCooldown(u, abilityId, BlzGetUnitAbilityCooldown(u, abilityId, GetUnitAbilityLevel(u, abilityId) - 1))
endfunction
function IsUnitUnderConstruction takes unit u returns boolean
return UnderConstruction[GetUnitId(u)]
endfunction
function IsCombatUnit takes unit u returns boolean
return UnitAlive(u) /*
*/ and (not IsUnitType(u, UNIT_TYPE_PEON)) /*
*/ and (not IsUnitType(u, UNIT_TYPE_STRUCTURE)) /*
*/ and (not UnitHasAbility(u, ATTR_TRAP)) /*
*/ and (not UnitHasAbility(u, ATTR_NON_COMBAT))
endfunction
private function OnBuildStart takes nothing returns nothing
set UnderConstruction[GetUnitId(GetConstructingStructure())] = true
endfunction
private function OnBuildFinish takes nothing returns nothing
set UnderConstruction[GetUnitId(GetConstructedStructure())] = false
endfunction
private function OnDeindex takes nothing returns nothing
set UnderConstruction[GetIndexedUnitId()] = false
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START, function OnBuildStart)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnBuildFinish)
call OnUnitDeindex(function OnDeindex)
endfunction
private struct UnitBusy extends array
private static boolean enabled = true
// A unit is busy if it's currently building, repairing, or on its way to do either
static method isUnitBusy takes unit u returns boolean
local integer orderId = GetUnitCurrentOrder(u)
if ((orderId == ORDER_REPAIR) or (IsUnitIdType(orderId, UNIT_TYPE_STRUCTURE))) then
return true
endif
return false
endmethod
// If a unit is issued a smart order, switch it to a repair order if possible
// so we can detect if a unit is repairing even if doing so from a smart order
private static method onSmartTargetOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit v = GetOrderTargetUnit()
if (enabled and not IssueTargetOrderById(u, ORDER_REPAIR, v)) then
set enabled = false
call IssueTargetOrderById(u, ORDER_SMART, v)
set enabled = true
endif
set u = null
set v = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterTargetOrderEvent(ORDER_SMART, function thistype.onSmartTargetOrder)
endmethod
endstruct
function IsUnitBusy takes unit u returns boolean
return UnitBusy.isUnitBusy(u)
endfunction
endlibrary
library UnitTypeUtils initializer Init requires UnitUtils
/*
* Public API
*
* function GetUnitTypeGoldCost takes integer id returns integer
*
* function GetUnitTypeMaxLife takes integer id returns integer
* function GetUnitTypeLifeRegen takes integer id returns real
* function GetUnitTypeBaseDamage takes integer id, integer weaponIndex returns integer
* function GetUnitTypeAttackBackswing takes integer id, integer weaponIndex returns real
* function GetUnitTypeAttackInterval takes integer id, integer weaponIndex returns real
*
* function GetUnitTypeTintRed takes integer id returns integer
* function GetUnitTypeTintGreen takes integer id returns integer
* function GetUnitTypeTintBlue takes integer id returns integer
*
*/
globals
private HashTable UnitTypeData
private unit DataDummy = null
private constant key MAX_LIFE
private constant key LIFE_REGEN
private constant key BASE_DAMAGE
private constant key ATTACK_INTERVAL_1
private constant key ATTACK_INTERVAL_2
private constant key ATTACK_BACKSWING_1
private constant key ATTACK_BACKSWING_2
private constant key VERTEX_COLOR
endglobals
function GetUnitTypeGoldCost takes integer id returns integer
if (IsHeroUnitId(id)) then
return 0
endif
return GetUnitGoldCost(id)
endfunction
function GetUnitTypeWoodCost takes integer id returns integer
if (IsHeroUnitId(id)) then
return 0
endif
return GetUnitWoodCost(id)
endfunction
function GetUnitTypeMaxLife takes integer id returns integer
if (not UnitTypeData[id].has(MAX_LIFE)) then
set DataDummy = CreateTempUnit(id)
set UnitTypeData[id][MAX_LIFE] = BlzGetUnitMaxHP(DataDummy)
call RemoveUnit(DataDummy)
endif
return UnitTypeData[id][MAX_LIFE]
endfunction
function GetUnitTypeLifeRegen takes integer id returns real
if (not UnitTypeData[id].real.has(LIFE_REGEN)) then
set DataDummy = CreateTempUnit(id)
set UnitTypeData[id].real[LIFE_REGEN] = BlzGetUnitRealField(DataDummy, UNIT_RF_HIT_POINTS_REGENERATION_RATE)
call RemoveUnit(DataDummy)
endif
return UnitTypeData[id].real[LIFE_REGEN]
endfunction
function GetUnitTypeBaseDamage takes integer id, integer weaponIndex returns integer
if (not UnitTypeData[id].has(BASE_DAMAGE)) then
set DataDummy = CreateTempUnit(id)
set UnitTypeData[id][BASE_DAMAGE] = BlzGetUnitBaseDamage(DataDummy, weaponIndex)
call RemoveUnit(DataDummy)
endif
return UnitTypeData[id][BASE_DAMAGE]
endfunction
function GetUnitTypeAttackInterval takes integer id, integer weaponIndex returns real
local integer k = IntegerTertiaryOp(weaponIndex == 0, ATTACK_INTERVAL_1, ATTACK_INTERVAL_2)
if (not UnitTypeData[id].real.has(k)) then
set DataDummy = CreateTempUnit(id)
set UnitTypeData[id].real[k] = BlzGetUnitWeaponRealField(DataDummy, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, weaponIndex)
call RemoveUnit(DataDummy)
endif
return UnitTypeData[id].real[k]
endfunction
function GetUnitTypeAttackBackswing takes integer id, integer weaponIndex returns real
local integer k = IntegerTertiaryOp(weaponIndex == 0, ATTACK_BACKSWING_1, ATTACK_BACKSWING_2)
if (not UnitTypeData[id].real.has(k)) then
set DataDummy = CreateTempUnit(id)
set UnitTypeData[id].real[k] = BlzGetUnitWeaponRealField(DataDummy, UNIT_WEAPON_RF_ATTACK_BACKSWING_POINT, weaponIndex)
call RemoveUnit(DataDummy)
endif
return UnitTypeData[id].real[k]
endfunction
private function GetTintData takes integer id returns nothing
local integer r
local integer g
local integer b
if (not UnitTypeData[id].has(VERTEX_COLOR)) then
set DataDummy = CreateTempUnit(id)
set r = BlzGetUnitIntegerField(DataDummy, UNIT_IF_TINTING_COLOR_RED)
set g = BlzGetUnitIntegerField(DataDummy, UNIT_IF_TINTING_COLOR_GREEN)
set b = BlzGetUnitIntegerField(DataDummy, UNIT_IF_TINTING_COLOR_BLUE)
set UnitTypeData[id][VERTEX_COLOR] = (r * 0x00010000) + (g * 0x00000100) + (b * 0x00000001)
call RemoveUnit(DataDummy)
endif
endfunction
function GetUnitTypeTintRed takes integer id returns integer
call GetTintData(id)
return BlzBitAnd(UnitTypeData[id][VERTEX_COLOR], 0x00FF0000) / 0x00010000
endfunction
function GetUnitTypeTintGreen takes integer id returns integer
call GetTintData(id)
return BlzBitAnd(UnitTypeData[id][VERTEX_COLOR], 0x0000FF00) / 0x00000100
endfunction
function GetUnitTypeTintBlue takes integer id returns integer
call GetTintData(id)
return BlzBitAnd(UnitTypeData[id][VERTEX_COLOR], 0x000000FF) / 0x00000001
endfunction
private function Init takes nothing returns nothing
set UnitTypeData = HashTable.create()
endfunction
endlibrary
library UpgradeUtils
function GetPlayerGuerrillaUnitId takes player p returns integer
return IntegerTertiaryOp(GetPlayerTechResearched(p, TECH_AK47, true), UNIT_GUERRILLA_UP, UNIT_GUERRILLA)
endfunction
function GetPlayerRegularUnitId takes player p returns integer
return IntegerTertiaryOp(GetPlayerTechResearched(p, TECH_AK47, true), UNIT_REGULAR_UP, UNIT_REGULAR)
endfunction
function GetPlayerRiflemanUnitId takes player p returns integer
if (p == udg_PLAYER_SOUTH_VIETNAM) then
return IntegerTertiaryOp(GetPlayerTechResearched(p, TECH_M16, true), UNIT_RIFLEMAN_ARVN_UP, UNIT_RIFLEMAN_ARVN)
endif
return IntegerTertiaryOp(GetPlayerTechResearched(p, TECH_M16, true), UNIT_RIFLEMAN_UP, UNIT_RIFLEMAN)
endfunction
endlibrary
library WorldBounds /* v2.0.0.0
************************************************************************************
*
* struct WorldBounds extends array
*
* Fields
* -------------------------
*
* readonly static integer maxX
* readonly static integer maxY
* readonly static integer minX
* readonly static integer minY
*
* readonly static integer centerX
* readonly static integer centerY
*
* readonly static rect world
* readonly static region worldRegion
*
************************************************************************************/
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world = GetWorldBounds()
set maxX = R2I(GetRectMaxX(world))
set maxY = R2I(GetRectMaxY(world))
set minX = R2I(GetRectMinX(world))
set minY = R2I(GetRectMinY(world))
set centerX = R2I((maxX + minX)/2)
set centerY = R2I((minY + maxY)/2)
set playMaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set playMaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set playMinX = GetRectMinX(bj_mapInitialPlayableArea)
set playMinY = GetRectMinY(bj_mapInitialPlayableArea)
set worldRegion = CreateRegion()
call RegionAddRect(worldRegion, world)
endmethod
endmodule
struct WorldBounds extends array
readonly static integer maxX
readonly static integer maxY
readonly static integer minX
readonly static integer minY
readonly static integer centerX
readonly static integer centerY
readonly static rect world
readonly static region worldRegion
readonly static real playMaxX
readonly static real playMaxY
readonly static real playMinX
readonly static real playMinY
implement WorldBoundInit
endstruct
endlibrary
library MissileEffect requires WorldBounds, Alloc
/* -------------------- Missile Effect v2.6 by Chopinski -------------------- */
// This is a simple helper library for the Relativistic Missiles system.
// Credits:
// Sevion for the Alloc module
// - www.hiveworkshop.com/threads/snippet-alloc.192348/
// Nestharus for World Bounds Library
/* ----------------------------------- END ---------------------------------- */
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module LinkedList
readonly thistype next
readonly thistype prev
method init takes nothing returns thistype
set next = this
set prev = this
return this
endmethod
method pushBack takes thistype node returns thistype
set node.prev = prev
set node.next = this
set prev.next = node
set prev = node
return node
endmethod
method pushFront takes thistype node returns thistype
set node.prev = this
set node.next = next
set next.prev = node
set next = node
return node
endmethod
method pop takes nothing returns nothing
set prev.next = next
set next.prev = prev
endmethod
endmodule
private struct Effect extends array
implement LinkedList
implement Alloc
real x
real y
real z
real size
real yaw
real pitch
real roll
string path
effect effect
method remove takes nothing returns nothing
call DestroyEffect(effect)
call pop()
call deallocate()
set effect = null
endmethod
method insert takes string fxpath, real x, real y, real z, real scale returns thistype
local thistype node = pushBack(allocate())
set node.x = x
set node.y = y
set node.z = z
set node.yaw = 0.
set node.pitch = 0.
set node.roll = 0.
set node.path = fxpath
set node.size = scale
set node.effect = AddSpecialEffect(fxpath, x, y)
call BlzSetSpecialEffectZ(node.effect, z)
call BlzSetSpecialEffectScale(node.effect, scale)
return node
endmethod
static method create takes nothing returns thistype
return thistype(allocate()).init()
endmethod
endstruct
struct MissileEffect
real size
real yaw
real pitch
real roll
real time
integer transparency
integer animtype
integer playercolor
string path
effect effect
Effect attachments
/* -------------------------------- Operators ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set time = newTimeScale
call BlzSetSpecialEffectTimeScale(effect, time)
endmethod
method operator timeScale takes nothing returns real
return time
endmethod
method operator alpha= takes integer newAlpha returns nothing
set transparency = newAlpha
call BlzSetSpecialEffectAlpha(effect, transparency)
endmethod
method operator alpha takes nothing returns integer
return transparency
endmethod
method operator playerColor= takes integer playerId returns nothing
set playercolor = playerId
call BlzSetSpecialEffectColorByPlayer(effect, Player(playerId))
endmethod
method operator playerColor takes nothing returns integer
return playercolor
endmethod
method operator animation= takes integer animType returns nothing
set animtype = animType
call BlzPlaySpecialEffect(effect, ConvertAnimType(animtype))
endmethod
method operator animation takes nothing returns integer
return animtype
endmethod
/* --------------------------------- Methods -------------------------------- */
method scale takes effect sfx, real scale returns nothing
set size = scale
call BlzSetSpecialEffectScale(sfx, scale)
endmethod
method orient takes real yaw, real pitch, real roll returns nothing
local Effect node = attachments.next
set .yaw = yaw
set .pitch = pitch
set .roll = roll
call BlzSetSpecialEffectOrientation(effect, yaw, pitch, roll)
loop
exitwhen node == attachments
set node.yaw = yaw
set node.pitch = pitch
set node.roll = roll
call BlzSetSpecialEffectOrientation(node.effect, yaw, pitch, roll)
set node = node.next
endloop
endmethod
method move takes real x, real y, real z returns boolean
local Effect node = attachments.next
if not (x > WorldBounds.maxX or x < WorldBounds.minX or y > WorldBounds.maxY or y < WorldBounds.minY) then
call BlzSetSpecialEffectPosition(effect, x, y, z)
loop
exitwhen node == attachments
call BlzSetSpecialEffectPosition(node.effect, x - node.x, y - node.y, z - node.z)
set node = node.next
endloop
return true
endif
return false
endmethod
method attach takes string fxpath, real dx, real dy, real dz, real scale returns effect
local Effect node = attachments.insert(fxpath, dx, dy, dz, scale)
call BlzSetSpecialEffectPosition(node.effect, BlzGetLocalSpecialEffectX(effect) - dx, BlzGetLocalSpecialEffectY(effect) - dy, BlzGetLocalSpecialEffectZ(effect) - dz)
return node.effect
endmethod
method detach takes effect sfx returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
if GetHandleId(node.effect) == GetHandleId(sfx) then
call node.remove()
exitwhen true
endif
set node = node.next
endloop
endmethod
method setColor takes integer red, integer green, integer blue returns nothing
call BlzSetSpecialEffectColor(effect, red, green, blue)
endmethod
/* -------------------------- Contructor/Destructor ------------------------- */
method destroy takes nothing returns nothing
local Effect node = attachments.next
loop
exitwhen node == attachments
call node.remove()
set node = node.next
endloop
call DestroyEffect(effect)
call attachments.deallocate()
set effect = null
set path = null
set size = 1.
call deallocate()
endmethod
static method create takes real x, real y, real z returns thistype
local thistype this = thistype.allocate()
set effect = AddSpecialEffect("", x, y)
set path = ""
set size = 1
set time = 0
set transparency = 0
set animtype = 0
set playercolor = 0
set attachments = Effect.create()
call BlzSetSpecialEffectZ(effect, z)
return this
endmethod
endstruct
endlibrary
library Missiles requires MissileEffect
/* ----------------------- Missiles v2.6 by Chopinski ----------------------- */
// Thanks and Credits to BPower, Dirac and Vexorian for the Missile Library's at which i based
// this Missiles library. Credits and thanks to AGD and for the effect orientation ideas.
// This version of Missiles requires patch 1.31+
// How to Import:
// 1 - Copy this and MissileEffect librarys into your map
/* -------------------------------------------------------------------------- */
/* Configuration */
/* -------------------------------------------------------------------------- */
globals
// The update period of the system
public constant real PERIOD = 1./40.
// The max amount of Missiles processed in a PERIOD
// You can play around with both these values to find
// your sweet spot. If equal to 0, the system will
// process all missiles at once every period.
public constant real SWEET_SPOT = 100
// the avarage collision size compensation when detecting collisions
private constant real COLLISION_SIZE = 128.
// item size used in z collision
private constant real ITEM_SIZE = 16.
// Raw code of the dummy unit used for vision
private constant integer DUMMY = 'dumi'
// Needed, don't touch.
private location LOC = Location(0., 0.)
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation(LOC, x, y)
return GetLocationZ(LOC)
endfunction
private function GetUnitZ takes unit u returns real
return GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
endfunction
private function SetUnitZ takes unit u, real z returns nothing
call SetUnitFlyHeight(u, z - GetLocZ(GetUnitX(u), GetUnitY(u)), 0)
endfunction
private function GetMapCliffLevel takes nothing returns integer
return GetTerrainCliffLevel(WorldBounds.maxX, WorldBounds.maxY)
endfunction
private struct Pool
private static player player = Player(PLAYER_NEUTRAL_PASSIVE)
private static group group = CreateGroup()
timer timer
unit unit
static method recycle takes unit dummy returns nothing
if GetUnitTypeId(dummy) == DUMMY then
call GroupAddUnit(group, dummy)
call SetUnitX(dummy, WorldBounds.maxX)
call SetUnitY(dummy, WorldBounds.maxY)
call SetUnitOwner(dummy, player, false)
call PauseUnit(dummy, true)
endif
endmethod
static method retrieve takes real x, real y, real z, real face returns unit
if BlzGroupGetSize(group) > 0 then
set bj_lastCreatedUnit = FirstOfGroup(group)
call PauseUnit(bj_lastCreatedUnit, false)
call GroupRemoveUnit(group, bj_lastCreatedUnit)
call SetUnitX(bj_lastCreatedUnit, x)
call SetUnitY(bj_lastCreatedUnit, y)
call SetUnitZ(bj_lastCreatedUnit, z)
call BlzSetUnitFacingEx(bj_lastCreatedUnit, face)
else
set bj_lastCreatedUnit = CreateUnit(player, DUMMY, x, y, face)
call SetUnitZ(bj_lastCreatedUnit, z)
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amrf')
endif
return bj_lastCreatedUnit
endmethod
private static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call recycle(unit)
call ReleaseTimer(timer)
set timer = null
set unit = null
call deallocate()
endmethod
static method recycleTimed takes unit dummy, real delay returns nothing
local thistype this
if GetUnitTypeId(dummy) != DUMMY then
debug call BJDebugMsg("[DummyPool] Error: Trying to recycle a non dummy unit")
else
set this = thistype.allocate()
set timer = NewTimer(this)
set unit = dummy
call TimerStart(timer, delay, false, function thistype.onExpire)
endif
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local unit u
loop
exitwhen i == SWEET_SPOT
set u = CreateUnit(player, DUMMY, WorldBounds.maxX, WorldBounds.maxY, 0)
call PauseUnit(u, false)
call GroupAddUnit(group, u)
call UnitRemoveAbility(u, 'Amrf')
set i = i + 1
endloop
set u = null
endmethod
endstruct
private struct Coordinates
readonly real x
readonly real y
readonly real z
readonly real angle
readonly real distance
readonly real square
readonly real slope
readonly real alpha
// Creates an origin - impact link.
private thistype ref
private static method math takes thistype a, thistype b returns nothing
local real dx
local real dy
loop
set dx = b.x - a.x
set dy = b.y - a.y
set dx = dx*dx + dy*dy
set dy = SquareRoot(dx)
exitwhen dx != 0. and dy != 0.
set b.x = b.x + .01
set b.z = b.z - GetLocZ(b.x -.01, b.y) + GetLocZ(b.x, b.y)
endloop
set a.square = dx
set a.distance = dy
set a.angle = Atan2(b.y - a.y, b.x - a.x)
set a.slope = (b.z - a.z)/dy
set a.alpha = Atan(a.slope)
// Set b.
if b.ref == a then
set b.angle = a.angle + bj_PI
set b.distance = dy
set b.slope = -a.slope
set b.alpha = -a.alpha
set b.square = dx
endif
endmethod
static method link takes thistype a, thistype b returns nothing
set a.ref = b
set b.ref = a
call math(a, b)
endmethod
method move takes real toX, real toY, real toZ returns nothing
set x = toX
set y = toY
set z = toZ + GetLocZ(toX, toY)
if ref != this then
call math(this, ref)
endif
endmethod
method destroy takes nothing returns nothing
call .deallocate()
endmethod
static method create takes real x, real y, real z returns Coordinates
local thistype this = thistype.allocate()
set ref = this
call move(x, y, z)
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
private module OnHit
set o = origin
set h = height
set c = open
set d = o.distance
call setup()
if onHit != null then
set udg_MissileEvent = udg_MissileOnHit
if allocated and udg_MissileCollision > 0 then
call GroupEnumUnitsInRange(group, x, y, udg_MissileCollision + COLLISION_SIZE, null)
loop
set u = FirstOfGroup(group)
exitwhen u == null
if not HaveSavedBoolean(table, this, GetHandleId(u)) then
if IsUnitInRangeXY(u, x, y, udg_MissileCollision) then
if udg_MissileCollideZ then
set dx = GetLocZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u)
set dy = BlzGetUnitCollisionSize(u)
if dx + dy >= z - udg_MissileCollision and dx <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
else
call SaveBoolean(table, this, GetHandleId(u), true)
set udg_MissileHitUnit = u
if allocated and IsTriggerEnabled(onHit) then
set udg_Missile = this
if TriggerEvaluate(onHit) then
call TriggerExecute(onHit)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitUnit = null
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitUnit = null
endif
endif
endif
call GroupRemoveUnit(group, u)
endloop
endif
endif
endmodule
private module OnMissile
if onMissile != null then
set udg_MissileEvent = udg_MissileOnMissile
if allocated and udg_MissileCollision > 0 then
set k = 0
loop
exitwhen k > count
set missile = collection[k]
if missile != this then
if not HaveSavedBoolean(table, this, missile) then
set dx = missile.x - x
set dy = missile.y - y
if SquareRoot(dx*dx + dy*dy) <= udg_MissileCollision then
call SaveBoolean(table, this, missile, true)
set udg_MissileHitMissile = missile
if allocated and IsTriggerEnabled(onMissile) then
set udg_Missile = this
if TriggerEvaluate(onMissile) then
call TriggerExecute(onMissile)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitMissile = 0
call terminate()
exitwhen true
endif
endif
endif
set udg_MissileHitMissile = 0
endif
endif
endif
set k = k + 1
endloop
endif
endif
endmodule
private module OnDestructable
if onDestructable != null then
set udg_MissileEvent = udg_MissileOnDestructable
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumDestructablesInRect(rect, null, function thistype.onDest)
endif
endif
endmodule
private module OnItem
if onItem != null then
set udg_MissileEvent = udg_MissileOnItem
if allocated and udg_MissileCollision > 0 then
set dx = udg_MissileCollision
call SetRect(rect, x - dx, y - dx, x + dx, y + dx)
call EnumItemsInRect(rect, null, function thistype.onItems)
endif
endif
endmodule
private module OnCliff
if onCliff != null then
set dx = GetTerrainCliffLevel(nextX, nextY)
set dy = GetTerrainCliffLevel(x, y)
set udg_MissileEvent = udg_MissileOnCliff
if dy < dx and z < (dx - GetMapCliffLevel())*bj_CLIFFHEIGHT then
if allocated and IsTriggerEnabled(onCliff) then
set udg_Missile = this
if TriggerEvaluate(onCliff) then
call TriggerExecute(onCliff)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTerrain
if onTerrain != null then
set udg_MissileEvent = udg_MissileOnTerrain
if GetLocZ(x, y) > z then
if allocated and IsTriggerEnabled(onTerrain) then
set udg_Missile = this
if TriggerEvaluate(onTerrain) then
call TriggerExecute(onTerrain)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endif
endmodule
private module OnTileset
if onTileset != null then
set udg_MissileTileset = GetTerrainType(x, y)
set udg_MissileEvent = udg_MissileOnTileset
if udg_MissileTileset != tileset then
if allocated and IsTriggerEnabled(onTileset) then
set udg_Missile = this
if TriggerEvaluate(onTileset) then
call TriggerExecute(onTileset)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
set tileset = udg_MissileTileset
set udg_MissileTileset = 0
endif
endmodule
private module OnPeriod
if onPeriod != null then
set udg_MissileEvent = udg_MissileOnPeriod
if allocated and IsTriggerEnabled(onPeriod) then
set udg_Missile = this
if TriggerEvaluate(onPeriod) then
call TriggerExecute(onPeriod)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnOrient
// Homing or not
if udg_MissileTarget != null and GetUnitTypeId(udg_MissileTarget) != 0 then
call impact.move(GetUnitX(udg_MissileTarget), GetUnitY(udg_MissileTarget), GetUnitFlyHeight(udg_MissileTarget) + toZ)
set dx = impact.x - nextX
set dy = impact.y - nextY
set a = Atan2(dy, dx)
set travel = o.distance - SquareRoot(dx*dx + dy*dy)
else
set a = o.angle
set target = null
set udg_MissileTarget = null
endif
// turn rate
if turn != 0 and not (Cos(cA-a) >= Cos(turn)) then
if Sin(a-cA) >= 0 then
set cA = cA + turn
else
set cA = cA - turn
endif
else
set cA = a
endif
set vel = veloc*dilation
set yaw = cA
set s = travel + vel
set veloc = veloc + acceleration
set travel = s
set pitch = o.alpha
set prevX = x
set prevY = y
set prevZ = z
set x = nextX
set y = nextY
set z = nextZ
set nextX = x + vel*Cos(yaw)
set nextY = y + vel*Sin(yaw)
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
// arc calculation
if h != 0 or o.slope != 0 then
set nextZ = 4*h*s*(d-s)/(d*d) + o.slope*s + o.z
set pitch = pitch - Atan(((4*h)*(2*s - d))/(d*d))
endif
// curve calculation
if c != 0 then
set dx = 4*c*s*(d-s)/(d*d)
set a = yaw + bj_PI/2
set x = x + dx*Cos(a)
set y = y + dx*Sin(a)
set yaw = yaw + Atan(-((4*c)*(2*s - d))/(d*d))
endif
endmodule
private module OnFinish
if s >= d - 0.0001 then
set finished = true
if onFinish != null then
set udg_MissileEvent = udg_MissileOnFinish
if allocated and IsTriggerEnabled(onFinish) then
set udg_Missile = this
if TriggerEvaluate(onFinish) then
call TriggerExecute(onFinish)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if travel > 0 and not paused then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
if travel > 0 then
call terminate()
endif
endif
else
call terminate()
endif
else
if not udg_MissileRoll then
call effect.orient(yaw, -pitch, 0)
else
call effect.orient(yaw, -pitch, Atan2(c, h))
endif
endif
endmodule
private module OnBoundaries
if not effect.move(x, y, z) then
if onBoundaries != null then
set udg_MissileEvent = udg_MissileOnBoundaries
if allocated and IsTriggerEnabled(onBoundaries) then
set udg_Missile = this
if TriggerEvaluate(onBoundaries) then
call TriggerExecute(onBoundaries)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
else
if dummy != null then
call SetUnitX(dummy, x)
call SetUnitY(dummy, y)
endif
endif
call cleanup()
endmodule
private module OnPause
set pid = pid + 1
set pkey = pid
set frozen[pid] = this
set udg_MissilePaused = paused
if onPause != null then
set udg_MissileEvent = udg_MissileOnPause
if allocated and IsTriggerEnabled(onPause) then
call setup()
if TriggerEvaluate(onPause) then
call TriggerExecute(onPause)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
endif
endif
endif
endif
endmodule
private module OnResume
local thistype aux
set paused = flag
set udg_MissilePaused = flag
if not paused and pkey != -1 then
set id = id + 1
set missiles[id] = this
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
if onResume != null then
set udg_MissileEvent = udg_MissileOnResume
if allocated and IsTriggerEnabled(onResume) then
call setup()
if TriggerEvaluate(onResume) then
call TriggerExecute(onResume)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
call terminate()
else
if finished then
call terminate()
endif
endif
endif
endif
else
if finished then
call terminate()
endif
endif
endif
endmodule
private module OnRemove
local thistype aux
if allocated and launched then
set allocated = false
if pkey != -1 then
set aux = frozen[pid]
set aux.pkey = pkey
set frozen[pkey] = frozen[pid]
set pid = pid - 1
set pkey = -1
endif
if onRemove != null then
set udg_MissileEvent = udg_MissileOnRemove
if IsTriggerEnabled(onRemove) then
set udg_Missile = this
if TriggerEvaluate(onRemove) then
call TriggerExecute(onRemove)
call update()
endif
endif
endif
if dummy != null then
call Pool.recycle(dummy)
endif
set aux = collection[count]
set aux.index = index
set collection[index] = collection[count]
set count = count - 1
set index = -1
set onPeriod = null
set onHit = null
set onMissile = null
set onItem = null
set onDestructable = null
set onCliff = null
set onTerrain = null
set onTileset = null
set onFinish = null
set onBoundaries = null
set onResume = null
set onPause = null
set onRemove = null
call origin.destroy()
call impact.destroy()
call effect.destroy()
call reset()
call FlushChildHashtable(table, this)
endif
endmodule
private module Operators
/* -------------------------- Model of the missile -------------------------- */
method operator model= takes string fx returns nothing
call DestroyEffect(effect.effect)
set effect.path = fx
set effect.effect = AddSpecialEffect(fx, origin.x, origin.y)
call BlzSetSpecialEffectZ(effect.effect, origin.z)
call BlzSetSpecialEffectYaw(effect.effect, cA)
endmethod
method operator model takes nothing returns string
return effect.path
endmethod
/* ----------------------------- Curved movement ---------------------------- */
method operator curve= takes real value returns nothing
set open = Tan(value*bj_DEGTORAD)*origin.distance
endmethod
method operator curve takes nothing returns real
return Atan(open/origin.distance)*bj_RADTODEG
endmethod
/* ----------------------------- Arced Movement ----------------------------- */
method operator arc= takes real value returns nothing
set height = Tan(value*bj_DEGTORAD)*origin.distance/4
endmethod
method operator arc takes nothing returns real
return Atan(4*height/origin.distance)*bj_RADTODEG
endmethod
/* ------------------------------ Effect scale ------------------------------ */
method operator scale= takes real value returns nothing
set effect.size = value
call effect.scale(effect.effect, value)
endmethod
method operator scale takes nothing returns real
return effect.size
endmethod
/* ------------------------------ Missile Speed ----------------------------- */
method operator speed= takes real newspeed returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = newspeed*PERIOD
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator speed takes nothing returns real
return veloc/PERIOD
endmethod
/* ------------------------------- Flight Time ------------------------------ */
method operator duration= takes real flightTime returns nothing
local real d = origin.distance
local real s
local real vel
set veloc = RMaxBJ(0.00000001, (origin.distance - travel)*PERIOD/RMaxBJ(0.00000001, flightTime))
set time = flightTime
set vel = veloc*dilation
set s = travel + vel
set nextX = x + vel*Cos(cA)
set nextY = y + vel*Sin(cA)
if height != 0 or origin.slope != 0 then
set nextZ = 4*height*s*(d-s)/(d*d) + origin.slope*s + origin.z
set z = nextZ
endif
endmethod
method operator duration takes nothing returns real
return time
endmethod
/* ------------------------------- Sight Range ------------------------------ */
method operator vision= takes real sightRange returns nothing
set sight = sightRange
if dummy == null then
if owner == null then
if source != null then
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, GetOwningPlayer(source), false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
set dummy = Pool.retrieve(x, y, z, 0)
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
else
call SetUnitOwner(dummy, owner, false)
call BlzSetUnitRealField(dummy, UNIT_RF_SIGHT_RADIUS, sightRange)
endif
endmethod
method operator vision takes nothing returns real
return sight
endmethod
/* ------------------------------- Time Scale ------------------------------- */
method operator timeScale= takes real newTimeScale returns nothing
set effect.timeScale = newTimeScale
endmethod
method operator timeScale takes nothing returns real
return effect.timeScale
endmethod
/* ---------------------------------- Alpha --------------------------------- */
method operator alpha= takes integer newAlpha returns nothing
set effect.alpha = newAlpha
endmethod
method operator alpha takes nothing returns integer
return effect.alpha
endmethod
/* ------------------------------ Player Color ------------------------------ */
method operator playerColor= takes integer playerId returns nothing
set effect.playerColor = playerId
endmethod
method operator playerColor takes nothing returns integer
return effect.playerColor
endmethod
/* -------------------------------- Animation ------------------------------- */
method operator animation= takes integer animType returns nothing
set effect.animation = animType
endmethod
method operator animation takes nothing returns integer
return effect.animation
endmethod
endmodule
private module Methods
/* --------------------------- Bounce and Deflect --------------------------- */
method bounce takes nothing returns nothing
call origin.move(x, y, z - GetLocZ(x, y))
set travel = 0
set finished = false
endmethod
method deflect takes real tx, real ty, real tz returns nothing
local real locZ = GetLocZ(x, y)
set udg_MissileTarget = null
set target = null
set toZ = tz
if z < locZ then
set nextX = prevX
set nextY = prevY
set nextZ = prevZ
endif
call impact.move(tx, ty, tz)
call origin.move(x, y, z - locZ)
set travel = 0
set finished = false
endmethod
method deflectTarget takes unit u returns nothing
call deflect(GetUnitX(u), GetUnitY(u), toZ)
set target = u
set udg_MissileTarget = u
endmethod
/* ---------------------------- Flush hit targets --------------------------- */
method flushAll takes nothing returns nothing
call FlushChildHashtable(table, this)
endmethod
method flush takes widget w returns nothing
if w != null then
call RemoveSavedBoolean(table, this, GetHandleId(w))
endif
endmethod
method hitted takes widget w returns boolean
return HaveSavedBoolean(table, this, GetHandleId(w))
endmethod
/* ----------------------- Missile attachment methods ----------------------- */
method attach takes string model, real dx, real dy, real dz, real scale returns effect
return effect.attach(model, dx, dy, dz, scale)
endmethod
method detach takes effect attachment returns nothing
if attachment != null then
call effect.detach(attachment)
endif
endmethod
/* ------------------------------ Missile Pause ----------------------------- */
method pause takes boolean flag returns nothing
implement OnResume
endmethod
/* ---------------------------------- Color --------------------------------- */
method color takes integer red, integer green, integer blue returns nothing
call effect.setColor(red, green, blue)
endmethod
/* ---------------------- Destructable collision method --------------------- */
static method onDest takes nothing returns nothing
local thistype this = temp
local destructable d = GetEnumDestructable()
local real dz
local real tz
if not HaveSavedBoolean(table, this, GetHandleId(d)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetWidgetX(d), GetWidgetY(d))
set tz = GetDestructableOccluderHeight(d)
if dz + tz >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
else
call SaveBoolean(table, this, GetHandleId(d), true)
set udg_MissileHitDestructable = d
if allocated and IsTriggerEnabled(onDestructable) then
set udg_Missile = this
if TriggerEvaluate(onDestructable) then
call TriggerExecute(onDestructable)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitDestructable = null
set d = null
call terminate()
return
endif
endif
endif
set udg_MissileHitDestructable = null
endif
endif
set d = null
endmethod
/* -------------------------- Item collision method ------------------------- */
static method onItems takes nothing returns nothing
local thistype this = temp
local item i = GetEnumItem()
local real dz
if not HaveSavedBoolean(table, this, GetHandleId(i)) then
if udg_MissileCollideZ then
set dz = GetLocZ(GetItemX(i), GetItemY(i))
if dz + ITEM_SIZE >= z - udg_MissileCollision and dz <= z + udg_MissileCollision then
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
else
call SaveBoolean(table, this, GetHandleId(i), true)
set udg_MissileHitItem = i
if allocated and IsTriggerEnabled(onItem) then
set udg_Missile = this
if TriggerEvaluate(onItem) then
call TriggerExecute(onItem)
call update()
if udg_MissileDestroy then
set udg_MissileDestroy = false
set udg_MissileHitItem = null
set i = null
call terminate()
return
endif
endif
endif
set udg_MissileHitItem = null
endif
endif
set i = null
endmethod
/* -------------------------------- Terminate ------------------------------- */
method terminate takes nothing returns nothing
implement OnRemove
endmethod
/* ------------------------------- GUI Update ------------------------------- */
method setup takes nothing returns nothing
set udg_Missile = this
set udg_MissileStart = Location(origin.x, origin.y)
set udg_MissileStartZ = origin.z
set udg_MissileFinish = Location(impact.x, impact.y)
set udg_MissileFinishZ = impact.z
set udg_MissileTarget = target
set udg_MissileSource = source
set udg_MissileOwner = owner
set udg_MissileRoll = roll
set udg_MissilePaused = paused
set udg_MissileType = type
set udg_MissileData = data
set udg_MissileModel = effect.path
set udg_MissileScale = effect.size
set udg_MissileTimeScale = timeScale
set udg_MissileAlpha = alpha
set udg_MissilePlayerColor = playerColor
set udg_MissileAnimation = animation
set udg_MissileDamage = damage
set udg_MissileCollision = collision
set udg_MissileCollideZ = collideZ
set udg_MissileVelocity = veloc
set udg_MissileTravelled = travel
set udg_MissileSpeed = veloc/PERIOD
set udg_MissileDuration = time
set udg_MissileArc = arc
set udg_MissileCurve = curve
set udg_MissileAcceleration = acceleration
set udg_MissileVision = sight
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endmethod
method update takes nothing returns nothing
if not paused then
set damage = udg_MissileDamage
set collision = udg_MissileCollision
set acceleration = udg_MissileAcceleration
set collideZ = udg_MissileCollideZ
set source = udg_MissileSource
set target = udg_MissileTarget
set owner = udg_MissileOwner
set roll = udg_MissileRoll
set type = udg_MissileType
set data = udg_MissileData
if effect.path != udg_MissileModel then
set model = udg_MissileModel
endif
if effect.size != udg_MissileScale then
set scale = udg_MissileScale
endif
if speed != udg_MissileSpeed then
set speed = udg_MissileSpeed
endif
if time != udg_MissileDuration then
set duration = udg_MissileDuration
endif
if arc != udg_MissileArc then
set arc = udg_MissileArc
endif
if curve != udg_MissileCurve then
set curve = udg_MissileCurve
endif
if sight != udg_MissileVision then
set vision = udg_MissileVision
endif
if timeScale != udg_MissileTimeScale then
set timeScale = udg_MissileTimeScale
endif
if alpha != udg_MissileAlpha then
set alpha = udg_MissileAlpha
endif
if playerColor != udg_MissilePlayerColor then
set playerColor = udg_MissilePlayerColor
endif
if animation != udg_MissileAnimation then
set animation = udg_MissileAnimation
endif
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_MissilePosition = Location(x, y)
set udg_MissileZ = z
set udg_MissileLastPosition = Location(prevX, prevY)
set udg_MissilePrevZ = prevZ
set udg_MissileNextPosition = Location(nextX, nextY)
set udg_MissileNextZ = nextZ
endif
endmethod
method cleanup takes nothing returns nothing
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
call RemoveLocation(udg_MissilePosition)
call RemoveLocation(udg_MissileLastPosition)
call RemoveLocation(udg_MissileNextPosition)
set udg_Missile = 0
set udg_MissileStart = null
set udg_MissileStartZ = 0
set udg_MissileFinish = null
set udg_MissileFinishZ = 0
set udg_MissileTarget = null
set udg_MissileSource = null
set udg_MissileOwner = null
set udg_MissileRoll = false
set udg_MissilePaused = false
set udg_MissileType = 0
set udg_MissileData = 0
set udg_MissileModel = ""
set udg_MissileScale = 0
set udg_MissileTimeScale = 0
set udg_MissileAlpha = 0
set udg_MissilePlayerColor = 0
set udg_MissileAnimation = 0
set udg_MissileDamage = 0
set udg_MissileCollision = 0
set udg_MissileCollideZ = false
set udg_MissileVelocity = 0
set udg_MissileTravelled = 0
set udg_MissileSpeed = 0
set udg_MissileDuration = 0
set udg_MissileArc = 0
set udg_MissileCurve = 0
set udg_MissileAcceleration = 0
set udg_MissileVision = 0
set udg_MissilePosition = null
set udg_MissileZ = 0
set udg_MissileLastPosition = null
set udg_MissilePrevZ = 0
set udg_MissileNextPosition = null
set udg_MissileNextZ = 0
endmethod
endmodule
struct Missiles
private static timer timer = CreateTimer()
private static group group = CreateGroup()
private static rect rect = Rect(0., 0., 0., 0.)
private static hashtable table = InitHashtable()
private static integer last = 0
private static thistype temp = 0
private static integer id = -1
private static integer pid = -1
private static thistype array missiles
private static thistype array frozen
private static real dilation = 1
readonly static thistype array collection
readonly static integer count = -1
private real cA
private real height
private real open
private real toZ
private real time
private real sight
private unit dummy
private integer pkey
private integer index
Coordinates impact
Coordinates origin
MissileEffect effect
readonly real x
readonly real y
readonly real z
readonly real prevX
readonly real prevY
readonly real prevZ
readonly real nextX
readonly real nextY
readonly real nextZ
readonly real turn
readonly real veloc
readonly real travel
readonly boolean launched
readonly boolean allocated
readonly boolean finished
readonly boolean paused
readonly integer tileset
unit source
unit target
player owner
boolean collideZ
real collision
real damage
real acceleration
integer data
integer type
boolean roll
trigger onPeriod = null
trigger onHit = null
trigger onMissile = null
trigger onItem = null
trigger onDestructable = null
trigger onCliff = null
trigger onTerrain = null
trigger onTileset = null
trigger onFinish = null
trigger onBoundaries = null
trigger onResume = null
trigger onPause = null
trigger onRemove = null
implement Operators
implement Methods
/* ------------------------------ Reset members ----------------------------- */
private method reset takes nothing returns nothing
set launched = false
set finished = false
set collideZ = false
set paused = false
set roll = false
set source = null
set target = null
set owner = null
set dummy = null
set open = 0.
set height = 0.
set veloc = 0.
set acceleration = 0.
set collision = 0.
set damage = 0.
set travel = 0.
set turn = 0.
set time = 0.
set sight = 0.
set data = 0
set type = 0
set tileset = 0
set pkey = -1
set index = -1
endmethod
/* -------------------------- Destroys the missile -------------------------- */
private method remove takes integer i returns integer
if paused then
implement OnPause
else
implement OnRemove
endif
set missiles[i] = missiles[id]
set id = id - 1
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1
endif
if id == -1 then
call PauseTimer(timer)
endif
if not allocated then
call deallocate()
endif
return i - 1
endmethod
/* ---------------------------- Missiles movement --------------------------- */
private static method move takes nothing returns nothing
local integer j = 0
local integer i
local integer k
local unit u
local real a
local real d
local real s
local real h
local real c
local real dx
local real dy
local real vel
local real yaw
local real pitch
local real locZ
local Missiles missile
local Coordinates o
local thistype this
if SWEET_SPOT > 0 then
set i = last
else
set i = 0
endif
loop
exitwhen ((j >= SWEET_SPOT and SWEET_SPOT > 0) or j > id)
set this = missiles[i]
set temp = this
if allocated and not paused then
implement OnHit
implement OnMissile
implement OnDestructable
implement OnItem
implement OnCliff
implement OnTerrain
implement OnTileset
implement OnPeriod
implement OnOrient
implement OnFinish
implement OnBoundaries
else
set i = remove(i)
set j = j - 1
endif
set i = i + 1
set j = j + 1
if i > id and SWEET_SPOT > 0 then
set i = 0
endif
endloop
set last = i
set u = null
endmethod
/* --------------------------- Launch the Missile --------------------------- */
method launch takes nothing returns nothing
if not launched and allocated then
set launched = true
set id = id + 1
set missiles[id] = this
set count = count + 1
set index = count
set collection[count] = this
if id + 1 > SWEET_SPOT and SWEET_SPOT > 0 then
set dilation = (id + 1)/SWEET_SPOT
else
set dilation = 1.
endif
if id == 0 then
call TimerStart(timer, PERIOD, true, function thistype.move)
endif
endif
endmethod
/* --------------------------- Main Creator method -------------------------- */
static method create takes real x, real y, real z, real toX, real toY, real toZ returns thistype
local thistype this = thistype.allocate()
call .reset()
set .origin = Coordinates.create(x, y, z)
set .impact = Coordinates.create(toX, toY, toZ)
set .effect = MissileEffect.create(x, y, origin.z)
call Coordinates.link(origin, impact)
set .allocated = true
set .cA = origin.angle
set .x = x
set .y = y
set .z = impact.z
set .prevX = x
set .prevY = y
set .prevZ = impact.z
set .nextX = x
set .nextY = y
set .nextZ = impact.z
set .toZ = toZ
return this
endmethod
endstruct
/* -------------------------------------------------------------------------- */
/* GUI API */
/* -------------------------------------------------------------------------- */
function MissileCreate takes nothing returns nothing
local Missiles missile = Missiles.create(GetLocationX(udg_MissileStart), GetLocationY(udg_MissileStart), udg_MissileStartZ, GetLocationX(udg_MissileFinish), GetLocationY(udg_MissileFinish), udg_MissileFinishZ)
if udg_MissileRemoveLocations then
call RemoveLocation(udg_MissileStart)
call RemoveLocation(udg_MissileFinish)
else
set udg_MissileRemoveLocations = true
endif
set udg_Missile = missile
set udg_MissileStartZ = 0
set udg_MissileFinishZ = 0
set udg_MissileStart = null
set udg_MissileFinish = null
if udg_MissileModel != "" then
set missile.model = udg_MissileModel
set udg_MissileModel = ""
endif
if udg_MissileScale != 0 then
set missile.scale = udg_MissileScale
set udg_MissileScale = 0
endif
if udg_MissileSpeed != 0 then
set missile.speed = udg_MissileSpeed
set udg_MissileSpeed = 0
endif
if udg_MissileDuration != 0 then
set missile.duration = udg_MissileDuration
set udg_MissileDuration = 0
endif
if udg_MissileArc != 0 then
set missile.arc = udg_MissileArc
set udg_MissileArc = 0
endif
if udg_MissileCurve != 0 then
set missile.curve = udg_MissileCurve
set udg_MissileCurve = 0
endif
if udg_MissileDamage != 0 then
set missile.damage = udg_MissileDamage
set udg_MissileDamage = 0
endif
if udg_MissileCollision > 0 then
set missile.collision = udg_MissileCollision
set udg_MissileCollision = 0
endif
if udg_MissileAcceleration != 0 then
set missile.acceleration = udg_MissileAcceleration
set udg_MissileAcceleration = 0
endif
if udg_MissileCollideZ then
set missile.collideZ = udg_MissileCollideZ
set udg_MissileCollideZ = false
endif
if udg_MissileSource != null then
set missile.source = udg_MissileSource
set udg_MissileSource = null
endif
if udg_MissileTarget != null then
set missile.target = udg_MissileTarget
set udg_MissileTarget = null
endif
if udg_MissileOwner != null then
set missile.owner = udg_MissileOwner
set udg_MissileOwner = null
endif
if udg_MissileRoll then
set missile.roll = udg_MissileRoll
set udg_MissileRoll = false
endif
if udg_MissileType != 0 then
set missile.type = udg_MissileType
set udg_MissileType = 0
endif
if udg_MissileData != 0 then
set missile.data = udg_MissileData
set udg_MissileData = 0
endif
if udg_MissileVision != 0 then
set missile.vision = udg_MissileVision
set udg_MissileVision = 0
endif
if udg_MissileTimeScale != 0 then
set missile.timeScale = udg_MissileTimeScale
set udg_MissileTimeScale = 0
endif
if udg_MissileAlpha != 0 then
set missile.alpha = udg_MissileAlpha
set udg_MissileAlpha = 0
endif
if udg_MissilePlayerColor != 0 then
set missile.playerColor = udg_MissilePlayerColor
set udg_MissilePlayerColor = 0
endif
if udg_MissileAnimation != 0 then
set missile.animation = udg_MissileAnimation
set udg_MissileAnimation = 0
endif
if udg_Missile_onPeriod != null then
set missile.onPeriod = udg_Missile_onPeriod
set udg_Missile_onPeriod = null
endif
if udg_Missile_onHit != null then
set missile.onHit = udg_Missile_onHit
set udg_Missile_onHit = null
endif
if udg_Missile_onDestructable != null then
set missile.onDestructable = udg_Missile_onDestructable
set udg_Missile_onDestructable = null
endif
if udg_Missile_onItem != null then
set missile.onItem = udg_Missile_onItem
set udg_Missile_onItem = null
endif
if udg_Missile_onMissile != null then
set missile.onMissile = udg_Missile_onMissile
set udg_Missile_onMissile = null
endif
if udg_Missile_onCliff != null then
set missile.onCliff = udg_Missile_onCliff
set udg_Missile_onCliff = null
endif
if udg_Missile_onTerrain != null then
set missile.onTerrain = udg_Missile_onTerrain
set udg_Missile_onTerrain = null
endif
if udg_Missile_onTileset != null then
set missile.onTileset = udg_Missile_onTileset
set udg_Missile_onTileset = null
endif
if udg_Missile_onFinish != null then
set missile.onFinish = udg_Missile_onFinish
set udg_Missile_onFinish = null
endif
if udg_Missile_onBoundaries != null then
set missile.onBoundaries = udg_Missile_onBoundaries
set udg_Missile_onBoundaries = null
endif
if udg_Missile_onResume != null then
set missile.onResume = udg_Missile_onResume
set udg_Missile_onResume = null
endif
if udg_Missile_onPause != null then
set missile.onPause = udg_Missile_onPause
set udg_Missile_onPause = null
endif
if udg_Missile_onRemove != null then
set missile.onRemove = udg_Missile_onRemove
set udg_Missile_onRemove = null
endif
call missile.launch()
endfunction
function MissileBounce takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.bounce()
endfunction
function MissileDeflectTarget takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflectTarget(udg_MissileDeflectTarget)
endfunction
function MissileDeflect takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.deflect(GetLocationX(udg_MissileDeflectPosition), GetLocationY(udg_MissileDeflectPosition), udg_MissileDeflectZ)
call RemoveLocation(udg_MissileDeflectPosition)
set udg_MissileDeflectPosition = null
endfunction
function MissileFlush takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flush(udg_MissileFlushUnit)
set udg_MissileFlushUnit = null
endfunction
function MissileFlushAll takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.flushAll()
endfunction
function MissileHitted takes nothing returns nothing
local Missiles missile = udg_Missile
set udg_MissileHitted = missile.hitted(udg_MissileHittedUnit)
endfunction
function MissileAttach takes nothing returns nothing
local Missiles missile = udg_Missile
set bj_lastCreatedEffect = missile.attach(udg_MissileAttachModel, udg_MissileAttachX, udg_MissileAttachY, udg_MissileAttachZ, udg_MissileAttachScale)
endfunction
function MissileDetach takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.detach(udg_MissileDetachEffect)
set udg_MissileDetachEffect = null
endfunction
function MissilePause takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(true)
endfunction
function MissileResume takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.pause(false)
endfunction
function MissileColor takes nothing returns nothing
local Missiles missile = udg_Missile
call missile.color(udg_MissileRed, udg_MissileGreen, udg_MissileBlue)
endfunction
endlibrary
library Bomb requires DamageUtils, DummyUnitStack, Filters, SfxUtils, TimerUtils, DebugUtils
globals
HashTable BombData
endglobals
private struct Bomb extends array
implement Alloc
readonly player owner
readonly SpecialEffect bomb
readonly unit source
readonly Table data
method destroy takes nothing returns nothing
call .bomb.finalize()
set .source = null
call .deallocate()
endmethod
static method explode takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
local integer damageBase = .data[DAMAGE_BASE]
local integer numberOfDice = .data[DAMAGE_NUMBER_OF_DICE]
local integer sidesPerDie = .data[DAMAGE_SIDES_PER_DIE]
local real radiusFull = .data.real[DAMAGE_RADIUS_FULL]
local real radiusMed = .data.real[DAMAGE_RADIUS_MEDIUM]
local real radiusSmall = .data.real[DAMAGE_RADIUS_SMALL]
local real damageFactorMed = .data.real[DAMAGE_FACTOR_MEDIUM]
local real damageFactorSmall = .data.real[DAMAGE_FACTOR_SMALL]
local real damage = DiceReal(damageBase, numberOfDice, sidesPerDie)
local attacktype attackType = ConvertAttackType(.data[ATTACK_TYPE])
local real x = .bomb.x
local real y = .bomb.y
call UnitDamagePointSplash(.source, x, y, radiusFull, radiusMed, radiusSmall, /*
*/ damageFactorMed, damageFactorSmall, damage, attackType, FILTER_ALIVE_GROUND)
if (.data.has(IMPACT_ABILITY)) then
call GetDummy(.owner, x, y, true)
call UnitAddAbilityTimed(Dummy, .data[IMPACT_ABILITY], 1)
call IssuePointOrder(Dummy, .data.string[IMPACT_ABILITY_ORDER_STRING], x, y)
endif
if (.data.string.has(IMPACT_ART)) then
call CreateTimedEffectAtPoint(.data.string[IMPACT_ART], x, y, 10)
endif
if (.data.string.has(IMPACT_SOUND)) then
call PlaySoundAtPoint(.data.string[IMPACT_SOUND], 127, x, y, 0)
endif
call .destroy()
endmethod
static method create takes unit source, string typeName returns thistype
local thistype this
local integer typeId = StringHash(typeName)
local real x
local real y
local real z
local real timeToImpact
if (not BombData.has(typeId)) then
return 0
endif
set this = allocate()
set .data = BombData[typeId]
set .source = source
set .owner = GetOwningPlayer(source)
set x = GetUnitX(source)
set y = GetUnitY(source)
set z = GetUnitFlyHeight(source)
set timeToImpact = z / .data.real[MISSILE_SPEED]
set .bomb = CreateEffectWithVelocity(.data.string[MISSILE_ART], x, y, z, 0, 0, 0 - .data.real[MISSILE_SPEED])
call .bomb.setFacing(GetUnitFacing(source))
call TimerStart(NewTimer(this), timeToImpact, false, function thistype.explode)
return this
endmethod
private static method onInit takes nothing returns nothing
local integer id
local Table data
set BombData = HashTable.create()
// bomb_carpet
set id = StringHash("bomb_carpet")
set data = BombData[id]
set data.string[MISSILE_ART] = BOMB_MISSILE
set data.real[MISSILE_SPEED] = 250
set data[ATTACK_TYPE] = GetHandleId(ATTACK_TYPE_CHAOS)
set data[DAMAGE_BASE] = 200
set data[DAMAGE_NUMBER_OF_DICE] = 8
set data[DAMAGE_SIDES_PER_DIE] = 25
set data.real[DAMAGE_RADIUS_FULL] = 200
set data.real[DAMAGE_RADIUS_MEDIUM] = 325
set data.real[DAMAGE_RADIUS_SMALL] = 450
set data.real[DAMAGE_FACTOR_MEDIUM] = 0.50
set data.real[DAMAGE_FACTOR_SMALL] = 0.25
set data.string[IMPACT_ART] = SFX_EXPLOSION_SMALL
set data.string[IMPACT_SOUND] = "CarpetBombExpl"
// bomb_napalm
set id = StringHash("bomb_napalm")
set data = BombData[id]
set data.string[MISSILE_ART] = BOMB_MISSILE
set data.real[MISSILE_SPEED] = 250
set data[ATTACK_TYPE] = GetHandleId(ATTACK_TYPE_INCENDIARY)
set data[DAMAGE_BASE] = 150
set data[DAMAGE_NUMBER_OF_DICE] = 2
set data[DAMAGE_SIDES_PER_DIE] = 25
set data.real[DAMAGE_RADIUS_FULL] = 175
set data.real[DAMAGE_RADIUS_MEDIUM] = 275
set data.real[DAMAGE_RADIUS_SMALL] = 375
set data.real[DAMAGE_FACTOR_MEDIUM] = 0.50
set data.real[DAMAGE_FACTOR_SMALL] = 0.25
set data[IMPACT_ABILITY] = ABILITY_NAPALM_EXPLOSION
set data.string[IMPACT_ABILITY_ORDER_STRING] = "flamestrike"
set data.string[IMPACT_ART] = SFX_FLAME_BOMB
set data.string[IMPACT_SOUND] = "Napalm"
// bomb_precision
set id = StringHash("bomb_precision")
set data = BombData[id]
set data.string[MISSILE_ART] = BOMB_MISSILE
set data.real[MISSILE_SPEED] = 325
set data[ATTACK_TYPE] = GetHandleId(ATTACK_TYPE_CHAOS)
set data[DAMAGE_BASE] = 500
set data[DAMAGE_NUMBER_OF_DICE] = 4
set data[DAMAGE_SIDES_PER_DIE] = 40
set data.real[DAMAGE_RADIUS_FULL] = 150
set data.real[DAMAGE_RADIUS_MEDIUM] = 210
set data.real[DAMAGE_RADIUS_SMALL] = 280
set data.real[DAMAGE_FACTOR_MEDIUM] = 0.50
set data.real[DAMAGE_FACTOR_SMALL] = 0.25
set data.string[IMPACT_ART] = SFX_EXPLOSION_LARGE
endmethod
endstruct
function CreateBomb takes unit source, string typeName returns nothing
call Bomb.create(source, typeName)
endfunction
endlibrary
library AirplaneMovement requires DamageUtils, TimedUnitEffect, UnitDex, UnitUtils
private struct Strafe extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 0.08
private static constant integer MAX_TICKS = 24
private unit plane
private player owner
private real x
private real y
private real z
private real angle
private real dx
private real dy
private integer ticks
method destroy takes nothing returns nothing
set .plane = null
call .deallocate()
endmethod
method update takes nothing returns nothing
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
call PlaySoundAtPoint("CobraMG", 127, .x, .y, .z)
call CreateTimedEffectAtPoint(SFX_STRAFE_TARGET, .x, .y, 1)
set FilterPlayer = .owner
call UnitDamagePointSplash(.plane, .x, .y, 50, 100, 150, 0.50, 0.25, 50, ATTACK_TYPE_BULLETS, FILTER_ALIVE_ENEMY_GROUND)
set .x = .x + .dx
set .y = .y + .dy
set .ticks = .ticks + 1
if (.ticks >= MAX_TICKS) then
//call UnitRemoveAbilityTimed(.plane, ABILITY_SKYRAIDER_STRAFE, 0.5)
call .finalize()
endif
endmethod
static method create takes unit u, real x, real y returns thistype
local thistype this = allocate()
local real cos
local real sin
set .plane = u
set .owner = GetOwningPlayer(u)
set .angle = AngleBetween(GetUnitX(u), GetUnitY(u), x, y)
set cos = Cos(.angle)
set sin = Sin(.angle)
set .x = x - 200 * cos
set .y = y - 200 * sin
set .z = GetUnitFlyHeight(u)
set .dx = 400 * UPDATE_INTERVAL * cos
set .dy = 400 * UPDATE_INTERVAL * sin
call BlzSetUnitFacingEx(u, bj_RADTODEG * .angle)
set .ticks = 0
call .listAdd()
return this
endmethod
endstruct
private struct Airplane extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 0.03125
private unit plane
private real speed
private trigger acquireTrig
method destroy takes nothing returns nothing
set .plane = null
call .deallocate()
endmethod
static method orbit takes unit u returns nothing
local real angle = GetUnitFacing(u) * bj_DEGTORAD
call IssuePointOrderById(u, ORDER_MOVE, GetUnitX(u) - 128*Cos(angle), GetUnitY(u) - 128*Sin(angle))
endmethod
method update takes nothing returns nothing
local real angle
local real speed
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
set angle = GetUnitFacing(.plane) * bj_DEGTORAD
call SetUnitX(.plane, GetUnitX(.plane) + .speed * Cos(angle))
call SetUnitY(.plane, GetUnitY(.plane) + .speed * Sin(angle))
if (GetUnitCurrentOrder(.plane) == 0) then
call orbit(.plane)
endif
endmethod
static method onStopOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
if (UnitHasAbility(u, ATTR_AIRPLANE)) then
call orbit(u)
endif
set u = null
endmethod
static method onAttack takes nothing returns nothing
local unit u = GetAttacker()
local unit t
if (UnitHasAbility(u, ATTR_AIRPLANE)) then
set t = GetTriggerUnit()
call IssuePointOrderById(u, ORDER_CHANNEL, GetUnitX(t), GetUnitY(t))
set t = null
endif
set u = null
endmethod
static method onAcquire takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t
if (UnitHasAbility(u, ATTR_AIRPLANE)) then
set t = GetEventTargetUnit()
call IssueTargetOrderById(u, ORDER_CHANNEL, t)
set t = null
endif
set u = null
endmethod
static method onStrafe takes nothing returns nothing
call Strafe.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endmethod
static method create takes unit u returns thistype
local thistype this = allocate()
set .plane = u
set .speed = GetUnitDefaultMoveSpeed(u) * UPDATE_INTERVAL
call SetUnitMoveSpeed(u,1)
set .acquireTrig = CreateTrigger()
call TriggerRegisterUnitEvent(.acquireTrig, u, EVENT_UNIT_ACQUIRED_TARGET)
call TriggerAddCondition(.acquireTrig, function thistype.onAcquire)
call .listAdd()
return this
endmethod
static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_AIRPLANE)) then
call create(u)
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
call OnUnitIndex(function thistype.onIndex)
call RegisterOrderEvent(ORDER_STOP, function thistype.onStopOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function thistype.onAttack)
call RegisterSpellEffectEvent(ABILITY_SKYRAIDER_STRAFE, function thistype.onStrafe)
endmethod
endstruct
endlibrary
scope Amphibious initializer Init
globals
private group Amphibious = CreateGroup()
private constant real UPDATE_INTERVAL = .125
private constant real DAMAGE_PER_SECOND = 100
private constant real DAMAGE_PER_INTERVAL = DAMAGE_PER_SECOND * UPDATE_INTERVAL
endglobals
private function CheckTerrainHeight takes nothing returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(Amphibious)
local unit u
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(Amphibious, i)
if (BlzGetLocalUnitZ(u) <= 134) then
call SetWidgetLife(u, GetWidgetLife(u) - DAMAGE_PER_INTERVAL)
endif
set i = i + 1
endloop
set u = null
endfunction
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_AMPHIBIOUS)) then
call GroupAddUnit(Amphibious, u)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
call TimerStart(NewTimer(0), UPDATE_INTERVAL, true, function CheckTerrainHeight)
endfunction
endscope
scope CannotMove initializer Init
private function OnIndex takes nothing returns nothing
if (UnitHasAbility(GetIndexedUnit(), 'Ax06')) then
call SetUnitMoveSpeed(GetIndexedUnit(), 0)
endif
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
endfunction
endscope
scope DeployOnAttack initializer Init
private function OnAttack takes nothing returns nothing
local unit u = GetAttacker()
if (UnitHasAbility(u, ATTR_DEPLOY_ON_ATTACK)) then
call IssueImmediateOrderById(u, ORDER_BEARFORM)
call BlzQueueTargetOrderById(u, ORDER_ATTACK, GetTriggerUnit())
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function OnAttack)
endfunction
endscope
scope NoAlarms initializer Init
private function OnIndex takes nothing returns nothing
if (UnitHasAbility(GetIndexedUnit(), ATTR_NO_ALARMS)) then
call UnitIgnoreAlarm(GetIndexedUnit(), true)
endif
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
endfunction
endscope
scope NoAutoAcquire initializer Init
private function OnIndex takes nothing returns nothing
if (UnitHasAbility(GetIndexedUnit(), ATTR_NO_AUTO_ACQUIRE)) then
call UnitAddType(GetIndexedUnit(), UNIT_TYPE_PEON)
endif
endfunction
private function OnFilter takes nothing returns nothing
if (UnitHasAbility(GetFilterUnit(), ATTR_NO_AUTO_ACQUIRE)) then
call UnitAddType(GetFilterUnit(), UNIT_TYPE_PEON)
endif
endfunction
private function DelayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, Filter(function OnFilter))
call ReleaseTimer(GetExpiredTimer())
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope OverheadIcons initializer Init
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
call UnitRemoveAbility(u, 'Aiaa')
call UnitRemoveAbility(u, 'Aiat')
call UnitRemoveAbility(u, 'Aica')
call UnitRemoveAbility(u, 'Aimg')
call UnitRemoveAbility(u, 'Aime')
call UnitRemoveAbility(u, 'Aisa')
call UnitRemoveAbility(u, 'Aimd')
call UnitRemoveAbility(u, 'Aimo')
call UnitRemoveAbility(u, 'Aiof')
call UnitRemoveAbility(u, 'Aisn')
call UnitRemoveAbility(u, 'Aipo')
call UnitRemoveAbility(u, 'Aimx')
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
endfunction
endscope
scope PrioritizeAir initializer Init
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ABILITY_PRIORITIZE_AIR)) then
call IssueImmediateOrderById(u, ORDER_PRIORITIZEAIR)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
endfunction
endscope
scope DamageMoveDebuff initializer Init
globals
private constant group DebuffGroup = CreateGroup()
endglobals
private function Update takes nothing returns nothing
local integer size = BlzGroupGetSize(DebuffGroup)
local unit u
local real r
local real m
local integer i = 0
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(DebuffGroup, i)
set r = GetWidgetLife(u) / GetUnitState(u, UNIT_STATE_MAX_LIFE)
set m = GetUnitDefaultMoveSpeed(u) * 0.50
call SetUnitMoveSpeed(u, m*(r+1))
set i = i + 1
endloop
set u = null
endfunction
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_DAMAGE_MOVE_DEBUFF)) then
call GroupAddUnit(DebuffGroup, u)
endif
set u = null
endfunction
private function OnDeindex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_DAMAGE_MOVE_DEBUFF)) then
call GroupRemoveUnit(DebuffGroup, u)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call TimerStart(NewTimer(0), 0.50, true, function Update)
call OnUnitIndex(function OnIndex)
call OnUnitDeindex(function OnDeindex)
endfunction
endscope
scope Relocatable initializer Init
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ABILITY_RELOCATE_MENU_A)) then
call UnitMakeAbilityPermanent(u, true, ABILITY_RELOCATE_A)
elseif (UnitHasAbility(u, ABILITY_RELOCATE_MENU_V)) then
call UnitMakeAbilityPermanent(u, true, ABILITY_RELOCATE_V)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
endfunction
endscope
scope RemoveUponCompletion initializer Init
private function OnTrain takes nothing returns nothing
local unit u = GetTrainedUnit()
if (UnitHasAbility(u, ATTR_REMOVE_UPON_COMPLETION)) then
call RemoveUnit(u)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function OnTrain)
endfunction
endscope
scope ResistantToArtillery initializer Init
globals
private constant real DAMAGE_FACTOR = 0.50
endglobals
private function OnDamaged takes nothing returns nothing
if (UnitHasAbility(GetEventDamageSource(), ATTR_ARTILLERY) and UnitHasAbility(BlzGetEventDamageTarget(), ATTR_RESISTANT_TO_ARTILLERY)) then
call BlzSetEventDamage(GetEventDamage() * DAMAGE_FACTOR)
endif
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnDamaged)
endfunction
endscope
scope BlueDragonMarines initializer Init
globals
private constant integer MAX_LEVEL = 11
private constant integer MAX_TRAINABLE_PER_TECH = 8
private constant real DAMAGED_THRESHOLD = 10.0
private constant real DAMAGED_EXP = 0.008
private constant real DAMAGING_EXP = 0.024
private constant real KILL_EXP = 0.40
private integer BASE_HP = 0
private real BASE_REGEN = 0
private integer array BONUS_HP
private integer array BONUS_REGEN
private real array Experience
endglobals
private constant function GetMaxTrainable takes player p returns integer
return MAX_TRAINABLE_PER_TECH * GetPlayerTechCount(p, TECH_VIETNAMIZATION, true)
endfunction
// The item abilities to modify max hitpoints and regeneration don't work
// past level 1
private function SetAbilityLevels takes unit u, integer level returns nothing
set level = IMinBJ(level, MAX_LEVEL)
call SetUnitAbilityLevel(u, ABILITY_BDM_ARMOR, level)
//call SetUnitAbilityLevel(u, ABILITY_BDM_HP, level)
//call SetUnitAbilityLevel(u, ABILITY_BDM_REGEN, level)
call BlzSetUnitMaxHP(u, BASE_HP + BONUS_HP[level])
call BlzSetUnitRealField(u, UNIT_RF_HIT_POINTS_REGENERATION_RATE, BASE_REGEN + BONUS_REGEN[level])
endfunction
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local player p
if (GetUnitTypeId(u) == UNIT_BLUE_DRAGON_MARINE) then
set Experience[GetIndexedUnitId()] = 0
set p = GetOwningPlayer(u)
if (GetPlayerTechCount(p, UNIT_BLUE_DRAGON_MARINE, true) >= GetMaxTrainable(p)) then
call SetPlayerTechResearched(p, REQ_BDM_TRAIN_LIMIT, 0)
endif
endif
set u = null
endfunction
private function OnDamaged takes nothing returns nothing
local unit source = GetEventDamageSource()
local unit target = BlzGetEventDamageTarget()
local integer id
if (IsPlayerEnemy(GetOwningPlayer(source), GetOwningPlayer(target))) then
set id = GetUnitId(source)
if ((GetUnitTypeId(source) == UNIT_BLUE_DRAGON_MARINE) and (not IsUnitType(target, UNIT_TYPE_STRUCTURE))) then
set Experience[id] = Experience[id] + DAMAGING_EXP
if (GetWidgetLife(target) - GetEventDamage() <= 0.405) then
set Experience[id] = Experience[id] + KILL_EXP
endif
call SetAbilityLevels(source, 1 + R2I(Experience[id]))
elseif ((GetUnitTypeId(target) == UNIT_BLUE_DRAGON_MARINE) and (GetEventDamage() > DAMAGED_THRESHOLD)) then
set id = GetUnitId(target)
set Experience[id] = Experience[id] + DAMAGED_EXP
call SetAbilityLevels(target, 1 + R2I(Experience[id]))
endif
endif
set source = null
set target = null
endfunction
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p
if (GetUnitTypeId(u) == UNIT_BLUE_DRAGON_MARINE) then
set p = GetTriggerPlayer()
if (GetPlayerTechCount(p, UNIT_BLUE_DRAGON_MARINE, true) < GetMaxTrainable(p)) then
call SetPlayerTechMaxAllowed(p, UNIT_BLUE_DRAGON_MARINE_ICON, 1)
endif
endif
set u = null
endfunction
private function OnResearch takes nothing returns nothing
local player p
if (GetResearched() == TECH_VIETNAMIZATION) then
set p = GetTriggerPlayer()
call SetPlayerTechMaxAllowed(p, UNIT_BLUE_DRAGON_MARINE_ICON, 0)
call SetPlayerTechMaxAllowed(p, UNIT_BLUE_DRAGON_MARINE, GetMaxTrainable(p) / 2)
endif
endfunction
private function Init takes nothing returns nothing
call OnUnitIndex(function OnIndex)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnDamaged)
//call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_FINISH, function OnResearch)
call SetPlayerTechMaxAllowed(Player(4), UNIT_BLUE_DRAGON_MARINE, GetMaxTrainable(Player(4)) / 2)
set BASE_HP = GetUnitTypeMaxLife(UNIT_BLUE_DRAGON_MARINE)
set BASE_REGEN = GetUnitTypeLifeRegen(UNIT_BLUE_DRAGON_MARINE)
set BONUS_HP[1] = 0
set BONUS_HP[2] = 10
set BONUS_HP[3] = 20
set BONUS_HP[4] = 30
set BONUS_HP[5] = 40
set BONUS_HP[6] = 50
set BONUS_HP[7] = 60
set BONUS_HP[8] = 70
set BONUS_HP[9] = 80
set BONUS_HP[10] = 90
set BONUS_HP[11] = 125
set BONUS_REGEN[1] = 0
set BONUS_REGEN[2] = 0
set BONUS_REGEN[3] = 1
set BONUS_REGEN[4] = 1
set BONUS_REGEN[5] = 1
set BONUS_REGEN[6] = 2
set BONUS_REGEN[7] = 2
set BONUS_REGEN[8] = 2
set BONUS_REGEN[9] = 3
set BONUS_REGEN[10] = 3
set BONUS_REGEN[11] = 4
endfunction
endscope
scope BombingRun
private struct BombingRun extends array
implement Alloc
private static constant integer COST = 500
private static constant integer BOMB_COUNT = 10
private static constant real PLANE_SPAWN_DELAY = 5
private static constant real MOVE_SPEED = 550
private static constant real MIN_DISTANCE = 1200
private static constant real EXIT_DISTANCE = 10000
private static constant real EXIT_HEIGHT = 1000
private player owner
private unit plane
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real angle
private real duration
private integer remaining
method destroy takes nothing returns nothing
call RemoveUnit(.plane)
set .plane = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call SetUnitFlyHeightTimed(.plane, EXIT_HEIGHT, 2)
call UnitFadeOut(.plane, 2)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method dropBombs takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local integer i = 0
if (UnitAlive(.plane)) then
call CreateBomb(.plane, "bomb_carpet")
endif
set .remaining = .remaining - 1
if (.remaining <= 0) then
call TimerStart(t, 2, false, function thistype.onExit)
endif
set t = null
endmethod
static method onApproach takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call TimerStart(t, 0.21, true, function thistype.dropBombs)
endif
set t = null
endmethod
static method createPlane takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .plane = CreateUnit(.owner, DUMMY_STRATOFORTRESS, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.plane, .exitX, .exitY, .duration, false)
call TimerStart(t, PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY) / MOVE_SPEED, false, function thistype.onApproach)
set t = null
endmethod
static method onCast takes nothing returns nothing
local thistype this = allocate()
local unit caster = GetTriggerUnit()
local real distance
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .owner = GetTriggerPlayer()
set .targetX = GetSpellTargetX()
set .targetY = GetSpellTargetY()
set distance = PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY)
if (distance < MIN_DISTANCE) then
call TextTagError(.owner, "Too close!", .casterX - 80, .casterY, 72)
call IssueImmediateOrderById(caster, ORDER_STOP)
call UnitResetAbilityCooldownTimed(caster, ABILITY_CARPET_BOMBING, 0)
set caster = null
call .destroy()
return
endif
set .angle = AngleBetweenDeg(.casterX, .casterY, .targetX, .targetY)
set .exitX = .targetX + EXIT_DISTANCE * CosBJ(angle)
set .exitY = .targetY + EXIT_DISTANCE * SinBJ(angle)
set .duration = (distance + EXIT_DISTANCE) / MOVE_SPEED
set .remaining = BOMB_COUNT
call CreateTimedEffectAtPoint(SFX_TARGET_INDICATOR, .targetX, .targetY, 3.5)
if (PLAYER_LOCAL != .owner) then
call HideEffect(bj_lastCreatedEffect)
endif
call TimerStart(NewTimer(this), PLANE_SPAWN_DELAY, false, function thistype.createPlane)
call StartPlayerAbilityCooldown(.owner, ABILITY_CARPET_BOMBING)
call PlayerRemoveMoney(.owner, COST)
//call PlaySoundForPlayer("VerifyBombingRun", .owner, 127, false)
set caster = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_CARPET_BOMBING, function thistype.onCast)
call RegisterSpellEffectEvent('Abrv', function thistype.onCast)
endmethod
endstruct
endscope
scope DigIn
private struct DigIn extends array
private static constant real INACTIVE_LIFESPAN = 30
private static constant real DEFLECT_DAMAGE_FACTOR = 1.00
private static constant boolean DEAL_OVERFLOW_DAMAGE = false
private static constant real RANGE_BONUS = 100
private static constant integer COST = 2
private static constant real BUILDER_SEARCH_RADIUS = 32
private static constant real FOXHOLE_SEARCH_RADIUS = 500
private static boolexpr BUILDER_FILTER = null
private static boolexpr BUILDING_FILTER = null
private static boolexpr AVAILABLE_FOXHOLE_FILTER = null
readonly static unit array defender
readonly static unit array foxhole
readonly static boolean array digging
static method remove takes unit u, unit f returns nothing
local integer foxholeId = GetUnitId(f)
call UnitRemoveAbility(u, BUFF_DUG_IN)
call UnitRemoveAbility(u, ABILITY_GARRISON_INVIS)
call BlzUnitDisableAbility(u, ABILITY_EXIT_FOXHOLE, true, false)
call BlzUnitDisableAbility(u, ABILITY_DIG_IN, false, false)
call BlzUnitDisableAbility(u, ABILITY_GARRISON_INSTANT, false, false)
call BlzSetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1, BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 1) - RANGE_BONUS)
call RemoveUnitDamageDeflectTarget(u)
if (UnitAlive(f)) then
call UnitKillTimed(f, INACTIVE_LIFESPAN)
endif
set defender[foxholeId] = null
set foxhole[GetUnitId(u)] = null
endmethod
private static method digIn takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
if (PlayerGetMoney(p) >= COST) then
call PlayerRemoveMoney(p, COST)
call DummyBuildOrder(p, UNIT_FOXHOLE, GetUnitX(u), GetUnitY(u))
set digging[GetUnitId(u)] = true
else
call UnitRemoveAbility(u, ABILITY_DIG_IN)
call UnitAddAbility(u, ABILITY_DIG_IN)
endif
set u = null
endmethod
private static method garrison takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local integer id = GetUnitId(target)
// Assume the target is a Foxhole since the order is always triggered
if (defender[id] == null) then
// Foxhole is empty
call BlzUnitDisableAbility(caster, ABILITY_GARRISON_INSTANT, true, false)
call BlzUnitDisableAbility(caster, ABILITY_EXIT_FOXHOLE, false, false)
call BlzUnitDisableAbility(caster, ABILITY_DIG_IN, true, false)
call UnitAddAbility(caster, ABILITY_GARRISON_INVIS)
call BlzSetUnitWeaponRealField(caster, UNIT_WEAPON_RF_ATTACK_RANGE, 1, BlzGetUnitWeaponRealField(caster, UNIT_WEAPON_RF_ATTACK_RANGE, 1) + RANGE_BONUS)
call SetUnitX(caster, GetUnitX(target))
call SetUnitY(caster, GetUnitY(target))
call UnitKillTimedCancel(target)
call SetUnitDamageDeflectTarget(caster, target, DEFLECT_DAMAGE_FACTOR, DEAL_OVERFLOW_DAMAGE)
call DummyTargetCast(GetTriggerPlayer(), ABILITY_IMMOBILIZE_FOXHOLE, OrderId("ensnare"), caster)
set defender[id] = caster
set foxhole[GetUnitId(caster)] = target
else
// Foxhole is occupied
endif
set caster = null
set target = null
endmethod
private static method tryGarrison takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit target = GetNearestUnit(GetUnitX(caster), GetUnitY(caster), FOXHOLE_SEARCH_RADIUS, AVAILABLE_FOXHOLE_FILTER)
call IssueTargetOrderById(caster, ORDER_FINGEROFDEATH, target)
set caster = null
set target = null
endmethod
private static method exit takes nothing returns nothing
local unit u = GetTriggerUnit()
call remove(u, foxhole[GetUnitId(u)])
set u = null
endmethod
private static method freeCaster takes unit f returns nothing
local unit u = GetNearestUnit(GetUnitX(f), GetUnitY(f), BUILDER_SEARCH_RADIUS, BUILDER_FILTER)
// Temporarily remove ability to cancel casting
if (UnitRemoveAbility(u, ABILITY_DIG_IN)) then
call UnitAddAbility(u, ABILITY_DIG_IN)
call BlzStartUnitAbilityCooldown(u, ABILITY_DIG_IN, 5)
endif
set digging[GetUnitId(u)] = false
set u = null
endmethod
private static method onBuildFinish takes nothing returns nothing
local unit u = GetConstructedStructure()
local unit v
if (GetUnitTypeId(u) == UNIT_FOXHOLE) then
set v = GetNearestUnit(GetUnitX(u), GetUnitY(u), BUILDER_SEARCH_RADIUS, BUILDER_FILTER)
call UnitKillTimed(u, INACTIVE_LIFESPAN)
call IssueTargetOrderById(v, ORDER_FINGEROFDEATH, u)
set v = null
endif
set u = null
endmethod
private static method onBuildCancel takes nothing returns nothing
local unit u = GetCancelledStructure()
if (GetUnitTypeId(u) == UNIT_FOXHOLE) then
call freeCaster(u)
endif
set u = null
endmethod
private static method onDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitId(u)
local unit v = defender[id]
if (digging[id]) then
call RemoveUnit(GetNearestUnit(GetUnitX(u), GetUnitY(u), BUILDER_SEARCH_RADIUS, BUILDING_FILTER))
endif
if (v != null) then
call remove(v,u)
else
set v = foxhole[id]
if (v != null) then
call remove(u,v)
elseif (isBuildingFoxhole(u)) then
call freeCaster(u)
endif
endif
set u = null
set v = null
endmethod
private static method isBuildingFoxhole takes unit u returns boolean
return GetUnitTypeId(u) == UNIT_FOXHOLE and IsUnitUnderConstruction(u)
endmethod
private static method isBuildingFoxholeFilter takes nothing returns boolean
return isBuildingFoxhole(GetFilterUnit())
endmethod
private static method isAvailableFoxhole takes unit u returns boolean
return GetUnitTypeId(u) == UNIT_FOXHOLE /*
*/ and defender[GetUnitId(u)] == null /*
*/ and UnitAlive(u) /*
*/ and not IsUnitUnderConstruction(u)
endmethod
private static method isAvailableFoxholeFilter takes nothing returns boolean
return isAvailableFoxhole(GetFilterUnit())
endmethod
private static method isPossibleBuilder takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ABILITY_DIG_IN)
endmethod
private static method redoGarrison takes player p, integer unitTypeId returns nothing
local integer size
local unit u
local integer i = 0
call GroupEnumUnitsOfPlayer(ENUM_GROUP, p, null)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
if (GetUnitTypeId(u) == unitTypeId) then
if (foxhole[GetUnitId(u)] != null) then
call UnitRemoveAbilityDelayed(u, ABILITY_DIG_IN, 0)
call UnitRemoveAbilityDelayed(u, ABILITY_GARRISON_INSTANT, 0)
call UnitAddAbility(u, ABILITY_GARRISON_INVIS)
endif
endif
set i = i + 1
endloop
set u = null
endmethod
private static method onResearch takes nothing returns nothing
local integer techId = GetResearched()
local player p = GetTriggerPlayer()
if (techId == TECH_M16) then
if (p == udg_PLAYER_SOUTH_VIETNAM) then
call redoGarrison(p, UNIT_RIFLEMAN_ARVN)
else
call redoGarrison(p, UNIT_RIFLEMAN)
endif
elseif (techId == TECH_AK47) then
/*
if (p == udg_PLAYER_NORTH_VIETNAM) then
call redoGarrison(p, UNIT_REGULAR)
else
call redoGarrison(p, UNIT_GUERRILLA)
endif
*/
endif
endmethod
private static method onPointOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer orderId = GetIssuedOrderId()
if ((foxhole[GetUnitId(u)] != null) and ((orderId == ORDER_MOVE) or (orderId == ORDER_PATROL) or (orderId == ORDER_SMART))) then
call IssueImmediateOrderByIdDelayed(u, ORDER_STOP, 0)
endif
set u = null
endmethod
private static method onTargetOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer orderId = GetIssuedOrderId()
if ((foxhole[GetUnitId(u)] != null) and (orderId != ORDER_ATTACK) and (orderId != ORDER_SMART)) then
call IssueImmediateOrderByIdDelayed(u, ORDER_STOP, 0)
endif
set u = null
endmethod
private static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ABILITY_EXIT_FOXHOLE)) then
call BlzUnitDisableAbility(u, ABILITY_EXIT_FOXHOLE, true, false)
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
set BUILDER_FILTER = Filter(function thistype.isPossibleBuilder)
set BUILDING_FILTER = Filter(function thistype.isBuildingFoxholeFilter)
set AVAILABLE_FOXHOLE_FILTER = Filter(function thistype.isAvailableFoxholeFilter)
call RegisterSpellEffectEvent(ABILITY_DIG_IN, function thistype.digIn)
call RegisterSpellEffectEvent(ABILITY_GARRISON, function thistype.garrison)
call RegisterSpellEffectEvent(ABILITY_GARRISON_INSTANT, function thistype.tryGarrison)
call RegisterSpellEffectEvent(ABILITY_EXIT_FOXHOLE, function thistype.exit)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.onBuildFinish)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function thistype.onBuildCancel)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_FINISH, function thistype.onResearch)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onPointOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onTargetOrder)
call OnUnitIndex(function thistype.onIndex)
endmethod
endstruct
function FoxholeRemoveUnit takes unit u returns nothing
local integer id = GetUnitId(u)
if (DigIn.foxhole[id] != null) then
call DigIn.remove(u, DigIn.foxhole[id])
endif
endfunction
endscope
scope DozerBuildDefenses initializer Init
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ATTR_TWO_BUILD_MENUS)) then
call BlzUnitHideAbility(u, 'AHbu', false)
endif
set u = null
endfunction
private function AltMenu takes nothing returns nothing
local unit u = GetTriggerUnit()
call UnitAddAbility(u, 'S005')
if (GetTriggerPlayer() == PLAYER_LOCAL) then
call ForceUIKey("B")
//call BlzUnitHideAbility(u, 'AHbu', true)
endif
set u = null
endfunction
private function RegMenu takes nothing returns nothing
local unit u = GetTriggerUnit()
call UnitAddAbility(GetTriggerUnit(), 'S006')
if (GetTriggerPlayer() == PLAYER_LOCAL) then
call BlzUnitHideAbility(u, 'AHbu', false)
call ForceUIKey("B")
endif
set u = null
endfunction
private function Init takes nothing returns nothing
//call OnUnitIndex(function OnIndex)
call RegisterSpellEffectEvent('A00L', function AltMenu)
call RegisterSpellEffectEvent('A00J', function RegMenu)
endfunction
endscope
scope DropZone
globals
private constant integer MODE_NONE = 0
private constant integer MODE_MONEY = 1
private constant integer MODE_INFANTRY = 2
private constant integer MODE_DOZER = 3
endglobals
private struct CargoPlane extends array
implement Alloc
endstruct
private struct DropZone extends array
private unit building
private timer timer
private integer mode
private effect sfx
static method create takes nothing returns thistype
local unit u = GetConstructedStructure()
local thistype this = GetUnitId(u)
if (GetUnitTypeId(u) != UNIT_DROP_ZONE) then
set u = null
return 0
endif
set .building = u
set .timer = NewTimer(this)
call IssueImmediateOrder(.building, "avatar")
set u = null
return this
endmethod
static method onExpire takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
endmethod
method resetTimer takes nothing returns nothing
call BlzStartUnitAbilityCooldown(.building, ABILITY_NEXT_DROPOFF, 120)
call BlzStartUnitAbilityCooldown(.building, ABILITY_DROP_MONEY, 1)
call BlzStartUnitAbilityCooldown(.building, ABILITY_DROP_INFANTRY, 1)
call BlzStartUnitAbilityCooldown(.building, ABILITY_DROP_DOZER, 1)
call TimerStart(.timer, 120, true, function thistype.onExpire)
endmethod
method setEffect takes string model returns nothing
if (.sfx != null) then
call DestroyEffect(.sfx)
endif
set .sfx = AddSpecialEffectTarget(model, .building, "origin")
endmethod
static method setToMoney takes nothing returns nothing
local thistype this = GetUnitId(GetTriggerUnit())
if (.mode != MODE_MONEY) then
set .mode = MODE_MONEY
call .resetTimer()
call .setEffect(SFX_SMOKE_GREEN)
endif
endmethod
static method setToInfantry takes nothing returns nothing
local thistype this = GetUnitId(GetTriggerUnit())
if (.mode != MODE_INFANTRY) then
set .mode = MODE_INFANTRY
call .resetTimer()
call .setEffect(SFX_SMOKE_RED)
endif
endmethod
static method setToDozer takes nothing returns nothing
local thistype this = GetUnitId(GetTriggerUnit())
if (.mode != MODE_DOZER) then
set .mode = MODE_DOZER
call .resetTimer()
call .setEffect(SFX_SMOKE_BLUE)
endif
endmethod
method destroy takes nothing returns nothing
call ReleaseTimer(.timer)
call DestroyEffect(.sfx)
set .building = null
set .timer = null
set .sfx = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.create)
call RegisterSpellEffectEvent(ABILITY_DROP_MONEY, function thistype.setToMoney)
call RegisterSpellEffectEvent(ABILITY_DROP_INFANTRY, function thistype.setToInfantry)
call RegisterSpellEffectEvent(ABILITY_DROP_DOZER, function thistype.setToDozer)
endmethod
endstruct
endscope
scope GravelMineDrop
private struct GravelMineDrop extends array
implement Alloc
private static constant integer COST = 200
private static constant integer MINE_COUNT = 20
private static constant real MIN_RADIUS = 50
private static constant real MAX_RADIUS = 300
private static constant real HELI_SPAWN_DELAY = 3
private static constant real MOVE_SPEED = 400
private static constant real MIN_DISTANCE = 600
private static constant real EXIT_DISTANCE = 3200
private static constant real EXIT_HEIGHT = 600
private unit heli
private player owner
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real distance
private real angle
private real duration
method destroy takes nothing returns nothing
call RemoveUnit(.heli)
set .heli = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.heli)) then
call SetUnitPositionTimed(.heli, .exitX, .exitY, EXIT_DISTANCE / MOVE_SPEED, true)
call SetUnitFlyHeightTimed(.heli, EXIT_HEIGHT, 2)
//call UnitFadeOut(.heli, 2)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method drop takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.heli)) then
call CreateUnitsAroundPoint(.owner, UNIT_GRAVEL_MINE, MINE_COUNT, .targetX, .targetY, MIN_RADIUS, MAX_RADIUS)
endif
call TimerStart(t, 3, false, function thistype.onExit)
set t = null
endmethod
static method createHeli takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .heli = CreateUnit(.owner, DUMMY_HUEY, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.heli, .targetX, .targetY, .duration, false)
call TimerStart(t, .distance / MOVE_SPEED, false, function thistype.drop)
set t = null
endmethod
static method create takes player owner, unit caster, integer abilityId, real targetX, real targetY returns thistype
local thistype this = allocate()
set .owner = owner
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .targetX = targetX
set .targetY = targetY
set .distance = PointDistanceToPoint(.casterX, .casterY, targetX, targetY)
if (.distance < MIN_DISTANCE) then
call TextTagError(.owner, "Too close!", .casterX - 80, .casterY, 72)
call UnitResetAbilityCooldownTimed(caster, abilityId, 0)
call .destroy()
return 0
endif
set .angle = AngleBetweenDeg(.casterX, .casterY, targetX, targetY)
set .exitX = targetX + EXIT_DISTANCE * CosBJ(.angle)
set .exitY = targetY + EXIT_DISTANCE * SinBJ(.angle)
set .duration = .distance / MOVE_SPEED
call TimerStart(NewTimer(this), HELI_SPAWN_DELAY, false, function thistype.createHeli)
return this
endmethod
static method onCast takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer abilityId = GetSpellAbilityId()
if (PlayerGetMoney(p) >= COST) then
call create(p, GetTriggerUnit(), abilityId, GetSpellTargetX(), GetSpellTargetY())
call StartPlayerAbilityCooldown(p, abilityId)
call PlayerRemoveMoney(p, COST)
else
call UnitResetAbilityCooldownTimed(GetTriggerUnit(), abilityId, 0)
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_GRAVEL_MINE_DROP, function thistype.onCast)
endmethod
endstruct
endscope
scope GravelMineExplode initializer Init
globals
private constant real TEMP_DISABLE_RANGE = 100
endglobals
/*
private function TempDisable takes nothing returns boolean
if (GetUnitTypeId(GetFilterUnit()) == UNIT_GRAVEL_MINE) then
call UnitRemoveAbilityTimed(GetFilterUnit(), ABILITY_EXPLOSIVE_TRAP_SHORT, 10)
endif
return false
endfunction
*/
private function Remove takes nothing returns boolean
if (GetUnitTypeId(GetFilterUnit()) == UNIT_GRAVEL_MINE) then
call RemoveUnit(GetFilterUnit())
endif
return false
endfunction
private function OnExplode takes nothing returns nothing
local unit u = GetTriggerUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
if (GetUnitTypeId(u) == UNIT_GRAVEL_MINE) then
call GroupEnumUnitsInRange(EnumGroup, x, y, TEMP_DISABLE_RANGE, function Remove)
if (GetLocalPlayer() == GetTriggerPlayer()) then
call PingMinimapEx(x, y, 5, 255, 0, 0, false)
endif
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnExplode)
endfunction
endscope
scope Herbicides
private struct EffectArea extends array
implement Alloc
implement Iterator
//
// Configuration
//
static constant integer SFX_COUNT = 6
// Trees with less than this proportion of their max life are blighted
static constant real BLIGHT_THRESHOLD = 0.50
// Minimum life of a tree is TREE_LIFE_FACTOR_LOW * TREE_MIN_LIFE
static constant real TREE_MIN_LIFE = 30
// Variation in max life of trees
static constant real TREE_LIFE_FACTOR_LOW = 0.80
static constant real TREE_LIFE_FACTOR_HIGH = 1.20
// Area used to calculate how many neighbors a tree has
static constant real TREE_NEIGHBORHOOD_RADIUS = 500
// Determines how much life a tree should start off with
// Trees can only ever have their life decrease
private static method calcTreeMaxLife takes destructable d returns real
return Pow(TreeGetNeighbors(d, TREE_NEIGHBORHOOD_RADIUS, false), 1.5)
endmethod
// --------
private static constant real UPDATE_INTERVAL = 1./8
private static constant integer MAX_TREES = 256
private static destructable array trees
private static Table neighbors
private static thistype thisEnum = 0
private real x
private real y
private real radius
private real damage
private real duration
private integer size
private integer treeIndex
private boolean processing
private integer ticks
private integer maxTicks
private method operator[] takes integer index returns destructable
return trees[(this-1) * MAX_TREES + index]
endmethod
private method operator[]= takes integer index, destructable d returns nothing
set trees[(this-1) * MAX_TREES + index] = d
endmethod
private static method addTreeEnum takes nothing returns nothing
local destructable d = GetEnumDestructable()
local thistype this
if (IsDestTree(d)) then
set this = thisEnum
set this[.size] = d
set .size = .size + 1
endif
set d = null
endmethod
private method destroy takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == .size)
set this[i] = null
set i = i + 1
endloop
call .deallocate()
endmethod
private method process takes nothing returns nothing
local destructable d
local real life
if (.treeIndex == .size) then
set .processing = false
return
endif
set d = this[.treeIndex]
set life = RMinBJ(GetWidgetLife(d), RMaxBJ(TREE_MIN_LIFE, calcTreeMaxLife(d)))
set life = life * GetRandomReal(TREE_LIFE_FACTOR_LOW, TREE_LIFE_FACTOR_HIGH)
call SetDestructableMaxLife(d, life)
set .treeIndex = .treeIndex + 1
set d = null
endmethod
private method update2 takes nothing returns nothing
local integer i = 0
local real life
loop
exitwhen (i == .size)
set life = GetWidgetLife(this[i])
call SetWidgetLife(this[i], life - .damage)
if (GetWidgetLife(this[i]) < BLIGHT_THRESHOLD * GetDestructableMaxLife(this[i])) then
if (GetWidgetLife(this[i]) == 0) then
call KillDestructable(this[i])
else
call TreeAddBlight(this[i])
endif
endif
set i = i + 1
endloop
set .ticks = .ticks + 1
if (.ticks > .maxTicks) then
call .finalize()
endif
endmethod
private method update takes nothing returns nothing
if (.processing) then
call .process()
else
call .update2()
endif
endmethod
static method create takes real x, real y, real radius, real dps, real duration, string sfx returns thistype
local thistype this = allocate()
set .x = x
set .y = y
set .radius = radius
set .damage = dps * UPDATE_INTERVAL
set .size = 0
set .treeIndex = 0
set .processing = true
set .ticks = 0
set .maxTicks = R2I(duration / UPDATE_INTERVAL)
set thisEnum = this
call EnumDestInRange(x, y, radius, function thistype.addTreeEnum)
call CreateTimedEffectAtPointMultiple(sfx, SFX_COUNT, x, y, 0.5 * radius, duration)
call .listAdd()
return this
endmethod
private static method onInit takes nothing returns nothing
set neighbors = Table.create()
endmethod
endstruct
private struct Herbicides extends array
implement Alloc
private static constant real HELI_SPAWN_DELAY = 3
private static constant real MOVE_SPEED = 400
private static constant real MIN_DISTANCE = 600
private static constant real APPROACH_DISTANCE = 200
private static constant real EXIT_DISTANCE = 3200
private static constant real EXIT_HEIGHT = 600
// Level 1
private static constant integer COST_1 = 0
private static constant real AREA_OF_EFFECT_1 = 500
private static constant real DURATION_1 = 90
private static constant real DAMAGE_PER_SECOND_1 = 1.00
// --------
// Level 2
private static constant integer COST_2 = 0
private static constant real AREA_OF_EFFECT_2 = 500
private static constant real DURATION_2 = 1.50 * DURATION_1
private static constant real DAMAGE_PER_SECOND_2 = 1.25 * DAMAGE_PER_SECOND_1
// --------
private unit heli
private player owner
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real distance
private real angle
private real duration
private boolean upgrade
method destroy takes nothing returns nothing
call RemoveUnit(.heli)
set .heli = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.heli)) then
call SetUnitPositionTimed(.heli, .exitX, .exitY, EXIT_DISTANCE / MOVE_SPEED, true)
call SetUnitFlyHeightTimed(.heli, EXIT_HEIGHT, 2)
call UnitFadeOut(.heli, 2)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method spray2 takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x
local real y
local real z
if (UnitAlive(.heli)) then
set x = GetUnitX(.heli)
set y = GetUnitY(.heli)
set z = GetPointZ(x,y)
if (.upgrade) then
call CreateTimedEffectWithVelocity(SFX_AGENT_BLUE_MIST, 1.5, x, y, z, 0, 0, -100)
else
call CreateTimedEffectWithVelocity(SFX_AGENT_ORANGE_MIST, 1.5, x, y, z, 0, 0, -100)
endif
endif
call TimerStart(t, 3, false, function thistype.onExit)
set t = null
endmethod
static method spray1 takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x
local real y
local real z
if (UnitAlive(.heli)) then
set x = GetUnitX(.heli)
set y = GetUnitY(.heli)
set z = GetPointZ(x,y)
if (.upgrade) then
call CreateTimedEffectWithVelocity(SFX_AGENT_BLUE_MIST, 1.5, x, y, z, 0, 0, -100)
call EffectArea.create(.targetX, .targetY, AREA_OF_EFFECT_2, DAMAGE_PER_SECOND_2, DURATION_2, SFX_AGENT_BLUE_TERRAIN)
else
call CreateTimedEffectWithVelocity(SFX_AGENT_ORANGE_MIST, 1.5, x, y, z, 0, 0, -100)
call EffectArea.create(.targetX, .targetY, AREA_OF_EFFECT_1, DAMAGE_PER_SECOND_1, DURATION_1, SFX_AGENT_ORANGE_TERRAIN)
endif
endif
call TimerStart(t, 0.75, false, function thistype.spray2)
set t = null
endmethod
static method onApproach takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x
local real y
local real z
if (UnitAlive(.heli)) then
set x = GetUnitX(.heli)
set y = GetUnitY(.heli)
set z = GetPointZ(x,y)
if (.upgrade) then
call CreateTimedEffectWithVelocity(SFX_AGENT_BLUE_MIST, 1.5, x, y, z, 0, 0, -100)
else
call CreateTimedEffectWithVelocity(SFX_AGENT_ORANGE_MIST, 1.5, x, y, z, 0, 0, -100)
endif
endif
call SetUnitPositionTimed(.heli, .exitX, .exitY, EXIT_DISTANCE / MOVE_SPEED, true)
call TimerStart(t, 0.75, false, function thistype.spray1)
set t = null
endmethod
static method createHeli takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .heli = CreateUnit(.owner, DUMMY_HUEY, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.heli, .targetX, .targetY, .duration, false)
call TimerStart(t, (.distance - APPROACH_DISTANCE) / MOVE_SPEED, false, function thistype.onApproach)
set t = null
endmethod
static method create takes player owner, unit caster, integer abilityId, real targetX, real targetY returns thistype
local thistype this = allocate()
set .owner = owner
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .targetX = targetX
set .targetY = targetY
set .distance = PointDistanceToPoint(.casterX, .casterY, targetX, targetY)
if (.distance < MIN_DISTANCE) then
call TextTagError(.owner, "Too close!", .casterX - 80, .casterY, 72)
call UnitResetAbilityCooldownTimed(caster, abilityId, 0)
call .destroy()
return 0
endif
set .angle = AngleBetweenDeg(.casterX, .casterY, targetX, targetY)
set .exitX = targetX + EXIT_DISTANCE * CosBJ(.angle)
set .exitY = targetY + EXIT_DISTANCE * SinBJ(.angle)
set .duration = .distance / MOVE_SPEED
set .upgrade = (abilityId == ABILITY_AGENT_BLUE)
call TimerStart(NewTimer(this), HELI_SPAWN_DELAY, false, function thistype.createHeli)
return this
endmethod
static method onCast1 takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer abilityId = GetSpellAbilityId()
if (PlayerGetMoney(p) >= COST_1) then
call create(p, GetTriggerUnit(), abilityId, GetSpellTargetX(), GetSpellTargetY())
call StartPlayerAbilityCooldown(p, abilityId)
call PlayerRemoveMoney(p, COST_1)
else
call UnitResetAbilityCooldownTimed(GetTriggerUnit(), abilityId, 0)
endif
endmethod
static method onCast2 takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer abilityId = GetSpellAbilityId()
if (PlayerGetMoney(p) >= COST_2) then
call create(p, GetTriggerUnit(), abilityId, GetSpellTargetX(), GetSpellTargetY())
call StartPlayerAbilityCooldown(p, abilityId)
call PlayerRemoveMoney(p, COST_2)
else
call UnitResetAbilityCooldownTimed(GetTriggerUnit(), abilityId, 0)
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_AGENT_ORANGE, function thistype.onCast1)
call RegisterSpellEffectEvent(ABILITY_AGENT_BLUE, function thistype.onCast2)
endmethod
endstruct
function IsTreeBlighted takes destructable d returns boolean
return GetWidgetLife(d) < EffectArea.BLIGHT_THRESHOLD * GetDestructableMaxLife(d)
endfunction
endscope
scope HueyInfantryDrop
private struct HueyInfantryDrop extends array
implement Alloc
private static constant real INITIAL_COOLDOWN = 180
private static constant integer COST = 250
private static constant integer SPAWN_COUNT = 6
private static constant real HELI_SPAWN_DELAY = 3
private static constant real MOVE_SPEED = 400
private static constant real MIN_DISTANCE = 800
private static constant real APPROACH_DISTANCE = 800
private static constant real EXIT_DISTANCE = 10000
private static constant real LAND_HEIGHT = 40
private static constant real NORMAL_HEIGHT = 360
private static constant real EXIT_HEIGHT = 600
private player owner
private unit heli
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real angle
private real duration
method destroy takes nothing returns nothing
call RemoveUnit(.heli)
set .heli = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.heli)) then
call SetUnitPositionTimed(.heli, .exitX, .exitY, EXIT_DISTANCE / MOVE_SPEED, true)
call SetUnitFlyHeightTimed(.heli, EXIT_HEIGHT, 2)
call UnitFadeOut(.heli, 2)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method onLand takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local integer spawnTypeId = GetPlayerRiflemanUnitId(.owner)
local integer i = 0
if (UnitAlive(.heli)) then
loop
call CreateUnit(.owner, spawnTypeId, .targetX, .targetY, bj_UNIT_FACING)
set i = i + 1
exitwhen (i == SPAWN_COUNT)
endloop
call SetUnitFlyHeightTimed(.heli, NORMAL_HEIGHT, 2)
endif
call TimerStart(t, 5, false, function thistype.onExit)
set t = null
endmethod
static method onApproach takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.heli)) then
call SetUnitFlyHeightTimed(.heli, LAND_HEIGHT, 2)
endif
call TimerStart(t, 2, false, function thistype.onLand)
set t = null
endmethod
static method createHeli takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .heli = CreateUnit(.owner, DUMMY_HUEY, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.heli, .exitX, .exitY, PointDistanceToPoint(.casterX, .casterY, .exitX, .exitY) / MOVE_SPEED, false)
call TimerStart(t, .duration - APPROACH_DISTANCE / MOVE_SPEED, false, function thistype.onApproach)
set t = null
endmethod
static method onCast takes nothing returns nothing
local thistype this = allocate()
local unit caster = GetTriggerUnit()
local location targetLoc
local real distance
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .owner = GetTriggerPlayer()
set .targetX = GetSpellTargetX()
set .targetY = GetSpellTargetY()
if (.casterX == .targetX and .casterY == .targetY) then
set .angle = AngleBetweenDeg(.casterX, .casterY, WorldBounds.centerX, WorldBounds.centerY)
else
set .angle = AngleBetweenDeg(.casterX, .casterY, .targetX, .targetY)
endif
set distance = PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY)
if (distance < MIN_DISTANCE) then
set .targetX = .casterX + MIN_DISTANCE * CosBJ(angle)
set .targetY = .casterY + MIN_DISTANCE * SinBJ(angle)
set distance = MIN_DISTANCE
endif
set targetLoc = GetWalkablePoint(.targetX, .targetY, 160)
if (targetLoc == null) then
call UnitResetAbilityCooldownTimed(caster, ABILITY_HUEY_INFANTRY_DROP, 0)
call TextTagError(.owner, "Can't land there!", .casterX - 100, .casterY, 72)
call .destroy()
set caster = null
return
endif
set .targetX = GetLocationX(targetLoc)
set .targetY = GetLocationY(targetLoc)
set .angle = AngleBetweenDeg(.casterX, .casterY, .targetX, .targetY)
set .duration = distance / MOVE_SPEED
set .exitX = .targetX + EXIT_DISTANCE * CosBJ(angle)
set .exitY = .targetY + EXIT_DISTANCE * SinBJ(angle)
call CreateTimedEffectAtPoint(SFX_TARGET_INDICATOR, .targetX, .targetY, 3.5)
if (PLAYER_LOCAL != .owner) then
call HideEffect(bj_lastCreatedEffect)
endif
call TimerStart(NewTimer(this), HELI_SPAWN_DELAY, false, function thistype.createHeli)
call StartPlayerAbilityCooldown(.owner, ABILITY_HUEY_INFANTRY_DROP)
call PlayerRemoveMoney(.owner, COST)
call RemoveLocation(targetLoc)
set caster = null
set targetLoc = null
endmethod
private static method delayedInit takes nothing returns nothing
call StartPlayerAbilityCooldownEx(udg_PLAYER_US_BLUE, ABILITY_HUEY_INFANTRY_DROP, INITIAL_COOLDOWN)
call StartPlayerAbilityCooldownEx(udg_PLAYER_US_LIGHT_BLUE, ABILITY_HUEY_INFANTRY_DROP, INITIAL_COOLDOWN)
call StartPlayerAbilityCooldownEx(udg_PLAYER_US_DARK_GREEN, ABILITY_HUEY_INFANTRY_DROP, INITIAL_COOLDOWN)
call ReleaseTimer(GetExpiredTimer())
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_HUEY_INFANTRY_DROP, function thistype.onCast)
call TimerStart(NewTimer(0), 0, false, function thistype.delayedInit)
endmethod
endstruct
endscope
scope Revive
private struct Revive extends array
private static constant integer REVIVE_COUNT = 6
private static constant real AREA_OF_EFFECT = 500
private static constant real REVIVE_LIFE = 1
static method onRevive takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit u
local player p = GetTriggerPlayer()
local integer size
local integer revived = 0
local integer i = 0
call GroupEnumUnitsInRange(EnumGroup, GetUnitX(caster), GetUnitY(caster), AREA_OF_EFFECT, null)
set size = BlzGroupGetSize(EnumGroup)
loop
exitwhen ((i == size) or (revived == REVIVE_COUNT))
set u = BlzGroupUnitAt(EnumGroup, i)
if ((GetOwningPlayer(u) == p) and (not IsUnitType(u, UNIT_TYPE_MECHANICAL)) and (not UnitAlive(u))) then
set bj_lastCreatedUnit = CreateUnit(p, GetUnitTypeId(u), GetUnitX(u), GetUnitY(u), GetUnitFacing(u))
call SetWidgetLife(bj_lastCreatedUnit, 1)
call IssueTargetOrderById(bj_lastCreatedUnit, ORDER_SMART, caster)
call QueueUnitRemove(u)
set revived = revived + 1
endif
set i = i + 1
endloop
call RemoveQueuedUnits()
set caster = null
set u = null
endmethod
static method onLandTakeOff takes nothing returns nothing
local integer orderId = GetIssuedOrderId()
if (orderId == ORDER_RAVENFORM) then
// Landing
call BlzUnitDisableAbility(GetTriggerUnit(), ABILITY_REVIVE, false, false)
elseif (orderId == ORDER_UNRAVENFORM) then
// Taking off
call BlzUnitDisableAbility(GetTriggerUnit(), ABILITY_REVIVE, true, false)
endif
endmethod
static method onIndex takes nothing returns nothing
if (GetUnitTypeId(GetIndexedUnit()) == UNIT_MEDEVAC) then
call BlzUnitDisableAbility(GetIndexedUnit(), ABILITY_REVIVE, true, false)
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_REVIVE, function thistype.onRevive)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onLandTakeOff)
call OnUnitIndex(function thistype.onIndex)
endmethod
endstruct
endscope
scope NapalmStrike
private struct NapalmStrike extends array
implement Alloc
private static constant integer COST = 400
private static constant real PLANE_SPAWN_DELAY = 3
private static constant real MOVE_SPEED = 450
private static constant real MIN_DISTANCE = 1000
private static constant real EXIT_DISTANCE = 10000
private static constant real EXIT_HEIGHT = 600
private player owner
private unit plane
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real angle
private real duration
method destroy takes nothing returns nothing
call RemoveUnit(.plane)
set .plane = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call SetUnitFlyHeightTimed(.plane, EXIT_HEIGHT, 2)
call UnitFadeOut(.plane, 2)
call UnitMoveSoundFadeOut(.plane)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method onApproach takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call CreateBomb(.plane, "bomb_napalm")
endif
call TimerStart(t, 2, false, function thistype.onExit)
set t = null
endmethod
static method createPlane takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .plane = CreateUnit(.owner, DUMMY_SKYRAIDER, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.plane, .exitX, .exitY, .duration, false)
call TimerStart(t, PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY) / MOVE_SPEED, false, function thistype.onApproach)
set t = null
endmethod
static method onCast takes nothing returns nothing
local thistype this = allocate()
local unit caster = GetTriggerUnit()
local real distance
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .owner = GetTriggerPlayer()
set .targetX = GetSpellTargetX()
set .targetY = GetSpellTargetY()
set distance = PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY)
if (distance < MIN_DISTANCE) then
call TextTagError(.owner, "Too close!", .casterX - 80, .casterY, 72)
call IssueImmediateOrderById(caster, ORDER_STOP)
call UnitResetAbilityCooldownTimed(caster, ABILITY_NAPALM_STRIKE, 0)
set caster = null
call .destroy()
return
endif
set .angle = AngleBetweenDeg(.casterX, .casterY, .targetX, .targetY)
set .exitX = .targetX + EXIT_DISTANCE * CosBJ(angle)
set .exitY = .targetY + EXIT_DISTANCE * SinBJ(angle)
set .duration = (distance + EXIT_DISTANCE) / MOVE_SPEED
call CreateTimedEffectAtPoint(SFX_TARGET_INDICATOR, .targetX, .targetY, 3.5)
if (PLAYER_LOCAL != .owner) then
call HideEffect(bj_lastCreatedEffect)
endif
call TimerStart(NewTimer(this), PLANE_SPAWN_DELAY, false, function thistype.createPlane)
call StartPlayerAbilityCooldown(.owner, ABILITY_NAPALM_STRIKE)
call PlayerRemoveMoney(.owner, COST)
set caster = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_NAPALM_STRIKE, function thistype.onCast)
call RegisterSpellEffectEvent('Anav', function thistype.onCast)
endmethod
endstruct
endscope
scope PrecisionStrikeA
private struct PrecisionStrikeA extends array
implement Alloc
private static constant integer COST = 250
private static constant real PLANE_SPAWN_DELAY = 3
private static constant real MOVE_SPEED = 450
private static constant real MIN_DISTANCE = 1000
private static constant real EXIT_DISTANCE = 10000
private static constant real EXIT_HEIGHT = 600
private player owner
private unit plane
private real targetX
private real targetY
private real exitX
private real exitY
private real casterX
private real casterY
private real angle
private real duration
method destroy takes nothing returns nothing
call RemoveUnit(.plane)
set .plane = null
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .destroy()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call SetUnitFlyHeightTimed(.plane, EXIT_HEIGHT, 2)
call UnitFadeOut(.plane, 2)
endif
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
static method onApproach takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (UnitAlive(.plane)) then
call CreateBomb(.plane, "bomb_precision")
endif
call TimerStart(t, 2, false, function thistype.onExit)
set t = null
endmethod
static method createPlane takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
set .plane = CreateUnit(.owner, DUMMY_SKYRAIDER, .casterX, .casterY, .angle)
call SetUnitPositionTimed(.plane, .exitX, .exitY, .duration, false)
call TimerStart(t, PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY) / MOVE_SPEED, false, function thistype.onApproach)
set t = null
endmethod
static method onCast takes nothing returns nothing
local thistype this = allocate()
local unit caster = GetTriggerUnit()
local real distance
set .casterX = GetUnitX(caster)
set .casterY = GetUnitY(caster)
set .owner = GetTriggerPlayer()
set .targetX = GetSpellTargetX()
set .targetY = GetSpellTargetY()
set distance = PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY)
if (distance < MIN_DISTANCE) then
call TextTagError(.owner, "Too close!", .casterX - 80, .casterY, 72)
call IssueImmediateOrderById(caster, ORDER_STOP)
call UnitResetAbilityCooldownTimed(caster, ABILITY_PRECISION_STRIKE_A, 0)
set caster = null
call .destroy()
return
endif
set .angle = AngleBetweenDeg(.casterX, .casterY, .targetX, .targetY)
set .exitX = .targetX + EXIT_DISTANCE * CosBJ(angle)
set .exitY = .targetY + EXIT_DISTANCE * SinBJ(angle)
set .duration = (distance + EXIT_DISTANCE) / MOVE_SPEED
call CreateTimedEffectAtPoint(SFX_TARGET_INDICATOR, .targetX, .targetY, 3.5)
if (PLAYER_LOCAL != .owner) then
call HideEffect(bj_lastCreatedEffect)
endif
call TimerStart(NewTimer(this), PLANE_SPAWN_DELAY, false, function thistype.createPlane)
call StartPlayerAbilityCooldown(.owner, ABILITY_PRECISION_STRIKE_A)
call PlayerRemoveMoney(.owner, COST)
set caster = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_PRECISION_STRIKE_A, function thistype.onCast)
call RegisterSpellEffectEvent('Apsv', function thistype.onCast)
endmethod
endstruct
endscope
scope RapidConscription
private struct RapidConscription extends array
implement Iterator
private static constant real UPDATE_INTERVAL = 3.00
private static constant integer COST = 200
private static constant integer SPAWN_COUNT = 20
private static constant real DURATION = SPAWN_COUNT * UPDATE_INTERVAL
private unit caster
private player owner
private real x
private real y
private integer remaining
method destroy takes nothing returns nothing
set .caster = null
endmethod
method update takes nothing returns nothing
if (UnitAlive(.caster) and GetOwningPlayer(.caster) == .owner and .remaining > 0) then
call CreateUnit(.owner, GetPlayerRiflemanUnitId(.owner), .x, .y, 0)
set .remaining = .remaining - 1
else
call .finalize()
endif
endmethod
static method onCast takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit u
local thistype this
if (PlayerGetMoney(p) >= COST) then
set u = GetTriggerUnit()
set this = GetUnitId(u)
set .caster = u
set .owner = p
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .remaining = SPAWN_COUNT
call CreateTextTagTimer(u, DURATION)
call .listAdd()
call PlayerRemoveMoney(p, COST)
set u = null
endif
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_RAPID_CONSCRIPTION, function thistype.onCast)
endmethod
endstruct
endscope
scope ReconPlane
private struct ReconPlane extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./60
private static constant real MIN_DISTANCE = 1000
private static constant real MARGIN = 1600
private static constant real PLANE_SPAWN_DELAY = 3
// Level 1
private static constant integer COST_1 = 200
private static constant real ORBIT_RADIUS_1 = 1200
private static constant real SIGHT_RADIUS_1 = 1600
private static constant real PLANE_SPEED_1 = 410
private static constant real DURATION_1 = 30
private static constant real ANGLE_INCREMENT_1 = (2 * bj_PI * ORBIT_RADIUS_1 / PLANE_SPEED_1) * UPDATE_INTERVAL * bj_DEGTORAD
private static constant integer TICKS_TO_EXIT_1 = R2I(DURATION_1 / UPDATE_INTERVAL)
// --------
// Level 2
private static constant integer COST_2 = 200
private static constant real ORBIT_RADIUS_2 = 1600
private static constant real SIGHT_RADIUS_2 = 2400
private static constant real PLANE_SPEED_2 = 540
private static constant real DURATION_2 = 45
private static constant real ANGLE_INCREMENT_2 = (2 * bj_PI * ORBIT_RADIUS_2 / PLANE_SPEED_2) * UPDATE_INTERVAL * bj_DEGTORAD
private static constant integer TICKS_TO_EXIT_2 = R2I(DURATION_2 / UPDATE_INTERVAL)
// --------
private player owner
private unit caster
private unit plane
private fogmodifier vision
private integer planeType
private real orbitRadius
private real sightRadius
private real planeSpeed
private real angleIncrement
private real duration
private integer ticksToExit
private real casterX
private real casterY
private real targetX
private real targetY
private real enterX
private real enterY
private boolean enter
private boolean exit
private boolean done
private real angle
private integer ticks
method destroy takes nothing returns nothing
if (.vision != null) then
call DestroyFogModifier(.vision)
set .vision = null
endif
if (.plane != null) then
call RemoveUnit(.plane)
set .plane = null
endif
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .finalize()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
call SetUnitFlyHeight(.plane, 2 * GetUnitDefaultFlyHeight(.plane), 100)
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
method update takes nothing returns nothing
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
if (.done) then
return
endif
if (.exit) then
call DestroyFogModifier(.vision)
set .angle = bj_DEGTORAD * GetUnitFacing(.plane)
call SetUnitPositionTimed(.plane, GetUnitX(.plane) + 2 * .orbitRadius * Cos(.angle), /*
*/ GetUnitY(.plane) + 2 * .orbitRadius * Sin(.angle), 2 * .orbitRadius / .planeSpeed, false)
call TimerStart(NewTimer(this), 1.5, false, function thistype.onExit)
set .done = true
elseif (.enter) then
set .angle = .angle + .angleIncrement
call SetUnitX(.plane, .targetX + .orbitRadius * Cos(angle))
call SetUnitY(.plane, .targetY + .orbitRadius * Sin(angle))
call BlzSetUnitFacingEx(.plane, 90 + bj_RADTODEG * .angle)
set .ticks = .ticks + 1
if (.ticks >= .ticksToExit) then
set .exit = true
endif
elseif (DistanceWithin(GetUnitX(.plane), GetUnitY(.plane), .enterX, .enterY, 64)) then
set .enter = true
set .vision = CreateFogModifierRadius(.owner, FOG_OF_WAR_VISIBLE, .targetX, .targetY, .sightRadius, true, true)
call FogModifierStart(.vision)
call UnitMovementKill(.plane)
endif
endmethod
static method createPlane takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
set .enterX = .targetX + .orbitRadius
set .enterY = .targetY
set .plane = CreateUnit(.owner, .planeType, .casterX, .casterY, AngleBetweenDeg(.casterX, .casterY, .enterX, .enterY))
call SetUnitPositionTimed(.plane, .enterX, .enterY, UnitDistanceToPoint(.plane, .enterX, .enterY) / .planeSpeed, false)
call .listAdd()
endmethod
static method init takes integer planeType, integer cost, real orbitRadius, real sightRadius, /*
*/ real planeSpeed, real angleIncrement, real duration, integer ticksToExit returns nothing
local thistype this = allocate()
local integer abilityId = GetSpellAbilityId()
set .owner = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .planeType = planeType
set .orbitRadius = orbitRadius
set .sightRadius = sightRadius
set .planeSpeed = planeSpeed
set .angleIncrement = angleIncrement
set .duration = duration
set .ticksToExit = ticksToExit
set .casterX = GetUnitX(.caster)
set .casterY = GetUnitY(.caster)
set .targetX = ClampR(GetSpellTargetX(), WorldBounds.minX + MARGIN, WorldBounds.maxX - MARGIN)
set .targetY = ClampR(GetSpellTargetY(), WorldBounds.minY + MARGIN, WorldBounds.maxY - MARGIN)
if (DistanceWithin(.casterX, .casterY, .targetX, .targetY, MIN_DISTANCE)) then
call UnitResetAbilityCooldownTimed(.caster, abilityId, 0)
call TextTagError(.owner, "Too close!", .casterX - 64, .casterY, 72)
call .destroy()
return
endif
set .enter = false
set .exit = false
set .done = false
set .angle = 0
set .ticks = 0
call TimerStart(NewTimer(this), PLANE_SPAWN_DELAY, false, function thistype.createPlane)
call StartPlayerAbilityCooldown(.owner, abilityId)
call PlayerRemoveMoney(.owner, cost)
call PlaySoundForPlayer("Recon" + I2S(GetRandomInt(1,3)), .owner, 127, false)
endmethod
static method onCast1 takes nothing returns nothing
call init(DUMMY_BRONCO, COST_1, ORBIT_RADIUS_1, SIGHT_RADIUS_1, PLANE_SPEED_1, /*
*/ ANGLE_INCREMENT_1, DURATION_1, TICKS_TO_EXIT_1)
endmethod
static method onCast2 takes nothing returns nothing
call init(DUMMY_DRAGON_LADY, COST_2, ORBIT_RADIUS_2, SIGHT_RADIUS_2, PLANE_SPEED_2, /*
*/ ANGLE_INCREMENT_2, DURATION_2, TICKS_TO_EXIT_2)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_RECON_1, function thistype.onCast1)
call RegisterSpellEffectEvent(ABILITY_RECON_2, function thistype.onCast2)
endmethod
endstruct
endscope
scope ReconPlane
private struct ReconPlane extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./60
private static constant real MIN_DISTANCE = 1000
private static constant real MARGIN = 1600
private static constant real PLANE_SPAWN_DELAY = 3
// Level 1
private static constant integer COST_1 = 200
private static constant real ORBIT_RADIUS_1 = 1200
private static constant real SIGHT_RADIUS_1 = 1600
private static constant real PLANE_SPEED_1 = 410
private static constant real DURATION_1 = 30
private static constant real ANGLE_INCREMENT_1 = (2 * bj_PI * ORBIT_RADIUS_1 / PLANE_SPEED_1) * UPDATE_INTERVAL
private static constant integer TICKS_TO_EXIT_1 = R2I(DURATION_1 / UPDATE_INTERVAL)
// --------
// Level 2
private static constant integer COST_2 = 200
private static constant real ORBIT_RADIUS_2 = 1600
private static constant real SIGHT_RADIUS_2 = 2400
private static constant real PLANE_SPEED_2 = 540
private static constant real DURATION_2 = 45
private static constant real ANGLE_INCREMENT_2 = (2 * bj_PI * ORBIT_RADIUS_2 / PLANE_SPEED_2) * UPDATE_INTERVAL
private static constant integer TICKS_TO_EXIT_2 = R2I(DURATION_2 / UPDATE_INTERVAL)
// --------
private player owner
private unit caster
private unit plane
private fogmodifier vision
private integer planeType
private real orbitRadius
private real sightRadius
private real planeSpeed
private real angleIncrement
private real duration
private integer ticksToExit
private real casterX
private real casterY
private real targetX
private real targetY
private real enterX
private real enterY
private real enterDistance
private boolean enter
private boolean exit
private boolean done
private real angle
private integer ticks
method destroy takes nothing returns nothing
if (.vision != null) then
call DestroyFogModifier(.vision)
set .vision = null
endif
if (.plane != null) then
call RemoveUnit(.plane)
set .plane = null
endif
call .deallocate()
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
call .finalize()
endmethod
static method onExit takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
call SetUnitFlyHeight(.plane, 2 * GetUnitDefaultFlyHeight(.plane), 100)
call UnitFadeOut(.plane, 2)
call TimerStart(t, 2, false, function thistype.onFinish)
set t = null
endmethod
method update takes nothing returns nothing
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
if (.done) then
return
endif
if (.exit) then
call DestroyFogModifier(.vision)
set .angle = bj_DEGTORAD * GetUnitFacing(.plane)
call SetUnitPositionTimed(.plane, GetUnitX(.plane) + 2 * .orbitRadius * CosBJ(.angle), /*
*/ GetUnitY(.plane) + 2 * .orbitRadius * SinBJ(.angle), 2 * .orbitRadius / .planeSpeed, false)
call TimerStart(NewTimer(this), 1.5, false, function thistype.onExit)
set .done = true
elseif (.enter) then
call SetUnitX(.plane, .targetX + .orbitRadius * CosBJ(.angle - 90))
call SetUnitY(.plane, .targetY + .orbitRadius * SinBJ(.angle - 90))
call BlzSetUnitFacingEx(.plane, .angle)
set .angle = .angle + .angleIncrement
set .ticks = .ticks + 1
if (.ticks >= .ticksToExit) then
set .exit = true
endif
elseif (DistanceWithin(GetUnitX(.plane), GetUnitY(.plane), .enterX, .enterY, 8)) then
set .enter = true
set .vision = CreateFogModifierRadius(.owner, FOG_OF_WAR_VISIBLE, .targetX, .targetY, .sightRadius, true, true)
call FogModifierStart(.vision)
call UnitMovementKill(.plane)
endif
endmethod
static method createPlane takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local real d1 = PointDistanceToPoint(.casterX, .casterY, .targetX, .targetY)
local real d2 = SquareRoot(d1*d1 - .orbitRadius*.orbitRadius)
local real a = -Atan(.orbitRadius / d2)
set .enterX = .casterX + d2 * Cos(a)
set .enterY = .casterY + d2 * Sin(a)
set .angle = a * bj_RADTODEG
set .plane = CreateUnit(.owner, .planeType, .casterX, .casterY, AngleBetweenDeg(.casterX, .casterY, .enterX, .enterY))
call SetUnitPositionTimed(.plane, .enterX, .enterY, UnitDistanceToPoint(.plane, .enterX, .enterY) / .planeSpeed, false)
call .listAdd()
endmethod
static method init takes integer planeType, integer cost, real orbitRadius, real sightRadius, /*
*/ real planeSpeed, real angleIncrement, real duration, integer ticksToExit returns nothing
local thistype this = allocate()
local integer abilityId = GetSpellAbilityId()
set .owner = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .planeType = planeType
set .orbitRadius = orbitRadius
set .sightRadius = sightRadius
set .planeSpeed = planeSpeed
set .angleIncrement = angleIncrement
set .duration = duration
set .ticksToExit = ticksToExit
set .casterX = GetUnitX(.caster)
set .casterY = GetUnitY(.caster)
set .targetX = ClampR(GetSpellTargetX(), WorldBounds.minX + MARGIN, WorldBounds.maxX - MARGIN)
set .targetY = ClampR(GetSpellTargetY(), WorldBounds.minY + MARGIN, WorldBounds.maxY - MARGIN)
if (DistanceWithin(.casterX, .casterY, .targetX, .targetY, MIN_DISTANCE)) then
call UnitResetAbilityCooldownTimed(.caster, abilityId, 0)
call TextTagError(.owner, "Too close!", .casterX - 64, .casterY, 72)
call .destroy()
return
endif
set .enter = false
set .exit = false
set .done = false
set .ticks = 0
call TimerStart(NewTimer(this), PLANE_SPAWN_DELAY, false, function thistype.createPlane)
call StartPlayerAbilityCooldown(.owner, abilityId)
call PlayerRemoveMoney(.owner, cost)
call PlaySoundForPlayer("Recon" + I2S(GetRandomInt(1,3)), .owner, 127, false)
endmethod
static method onCast1 takes nothing returns nothing
call init(DUMMY_BRONCO, COST_1, ORBIT_RADIUS_1, SIGHT_RADIUS_1, PLANE_SPEED_1, /*
*/ ANGLE_INCREMENT_1, DURATION_1, TICKS_TO_EXIT_1)
endmethod
static method onCast2 takes nothing returns nothing
call init(DUMMY_DRAGON_LADY, COST_2, ORBIT_RADIUS_2, SIGHT_RADIUS_2, PLANE_SPEED_2, /*
*/ ANGLE_INCREMENT_2, DURATION_2, TICKS_TO_EXIT_2)
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_RECON_1, function thistype.onCast1)
call RegisterSpellEffectEvent(ABILITY_RECON_2, function thistype.onCast2)
endmethod
endstruct
endscope
scope SendMoney initializer Init
globals
constant integer AMOUNT = 100
endglobals
private function SendMoney takes nothing returns nothing
call PlayerAddMoneyUnchecked(udg_PLAYER_SOUTH_VIETNAM, AMOUNT, false)
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_SEND_MONEY, function SendMoney)
endfunction
endscope
scope SkyraiderStrafe
private struct Strafe extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 0.50
private static constant real TARGET_SEARCH_DISTANCE = 500
private static constant real TARGET_SEARCH_RADIUS = 175
private static constant real COOLDOWN = 3.00
private static boolexpr FILTER
private unit plane
private player owner
private real cooldown
private real targetX
private real targetY
private boolean strafing
private boolean damage
method destroy takes nothing returns nothing
set .plane = null
call .deallocate()
endmethod
static method filter takes nothing returns boolean
local unit u = GetFilterUnit()
if (not UnitAlive(u)) then
return false
endif
if (not IsUnitEnemy(u, FilterPlayer)) then
return false
endif
if (IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_FLYING)) then
return false
endif
if (not IsUnitVisible(u, FilterPlayer)) then
return false
endif
if (IsUnitHidden(u)) then
return false
endif
if ((not BlzIsUnitSelectable(u)) or (not BlzIsUnitInvulnerable(u))) then
return false
endif
set u = null
return true
endmethod
static method onStrafingRun takes nothing returns nothing
set thistype(1).cooldown = COOLDOWN
set thistype(1).strafing = true
set thistype(1).damage = true
endmethod
method lookForTargets takes nothing returns nothing
local real angle = GetUnitFacing(.plane) * bj_DEGTORAD
local real x = GetUnitX(.plane) + TARGET_SEARCH_DISTANCE * Cos(angle)
local real y = GetUnitY(.plane) + TARGET_SEARCH_DISTANCE * Sin(angle)
set FilterPlayer = .owner
call GroupEnumUnitsInRange(ENUM_GROUP, x, y, TARGET_SEARCH_RADIUS, null)
if (BlzGroupGetSize(ENUM_GROUP) > 0) then
call BlzSetUnitFacingEx(.plane, AngleBetweenDeg(GetUnitX(.plane),GetUnitY(.plane),x,y))
endif
endmethod
method update takes nothing returns nothing
local real angle = GetUnitFacing(.plane) * bj_DEGTORAD
local real x = GetUnitX(.plane) + TARGET_SEARCH_DISTANCE * Cos(angle)
local real y = GetUnitY(.plane) + TARGET_SEARCH_DISTANCE * Sin(angle)
if (not UnitAlive(.plane)) then
call .finalize()
return
endif
if (.strafing) then
if (.damage) then
set Dummy = GetDummy(.owner, GetUnitX(.plane), GetUnitY(.plane), true)
call UnitAddAbility(Dummy, 'A01Y')
call IssuePointOrder(Dummy, "carrionswarm", x, y)
set .damage = false
endif
else
if (.cooldown > 0) then
set .cooldown = .cooldown - UPDATE_INTERVAL
else
set .cooldown = 0
call .lookForTargets()
endif
endif
call LogI(this)
//call LogR(.cooldown)
endmethod
static method onUnitIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (UnitHasAbility(u, ABILITY_SKYRAIDER_STRAFE)) then
call create(u)
endif
set u = null
endmethod
static method create takes unit u returns thistype
local thistype this = allocate()
set .plane = u
set .owner = GetOwningPlayer(u)
set .cooldown = 0
set .strafing = false
set .damage = false
call .listAdd()
return this
endmethod
private static method onInit takes nothing returns nothing
set FILTER = Filter(function thistype.filter)
call OnUnitIndex(function thistype.onUnitIndex)
call RegisterSpellEffectEvent(ABILITY_SKYRAIDER_STRAFE, function thistype.onStrafingRun)
endmethod
endstruct
endscope
scope SpotTraps
private struct SpotTraps extends array
implement Alloc
private static constant real AREA_OF_EFFECT = 500
private static constant real CAST_TIME = 2.5
private static constant real DURATION = 20
private static integer array trapAbility
private static timer array effectTimer
private unit caster
private player owner
private real x
private real y
method destroy takes nothing returns nothing
set .caster = null
call .deallocate()
endmethod
static method onExpire takes nothing returns nothing
local integer id = ReleaseTimer(GetExpiredTimer())
local unit u = GetUnitById(id)
if (UnitHasAbility(u, ATTR_TRAP)) then
call UnitAddAbility(u, trapAbility[id])
endif
set effectTimer[id] = null
set u = null
endmethod
static method applyEffect takes unit u, integer trapAbilityId returns nothing
local integer id = GetUnitId(u)
set trapAbility[id] = trapAbilityId
if (effectTimer[id] == null) then
set effectTimer[id] = NewTimer(id)
endif
call UnitRemoveAbility(u, trapAbilityId)
call TimerStart(effectTimer[id], DURATION, false, function thistype.onExpire)
endmethod
static method onFinish takes nothing returns nothing
local thistype this = ReleaseTimer(GetExpiredTimer())
local unit u
local integer id
local integer size
local integer i = 0
if (not UnitAlive(.caster)) then
return
endif
call GroupEnumUnitsInRangeCollision(ENUM_GROUP, .x, .y, AREA_OF_EFFECT, null)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
set id = GetUnitTypeId(u)
if (IsUnitEnemy(u, .owner)) then
if (id == UNIT_BOUNCING_BETTY) then
call applyEffect(u, ABILITY_EXPLOSIVE_TRAP_SHORT)
elseif (id == UNIT_TRIPWIRE_FLARE or id == UNIT_RPG_TRAP or id == UNIT_FOUGASSE) then
call applyEffect(u, ABILITY_EXPLOSIVE_TRAP_LONG)
endif
endif
set i = i + 1
endloop
set u = null
call .destroy()
endmethod
static method onCast takes nothing returns nothing
local thistype this
if (GetSpellAbilityId() != ABILITY_SPOT_TRAPS) then
return
endif
set this = allocate()
set .caster = GetTriggerUnit()
set .owner = GetTriggerPlayer()
set .x = GetSpellTargetX()
set .y = GetSpellTargetY()
call TimerStart(NewTimer(this), CAST_TIME, false, function thistype.onFinish)
// Spot Traps disables other abilities, including detection,
// so enemy traps may temporarily disappear
// Get a dummy to reveal the area around the caster to avoid this
call DummyPointCast(.owner, 'A01C', OrderId("farsight"), GetUnitX(.caster), GetUnitY(.caster))
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.onCast)
endmethod
endstruct
endscope
scope TransferFunds initializer Init
globals
private constant integer AMOUNT = 200
endglobals
private function UnitCast takes nothing returns nothing
local unit target = GetSpellTargetUnit()
if ((target == gg_unit_vsai_0001) and (GetOwningPlayer(target) == udg_PLAYER_SOUTH_VIETNAM)) then
call PlayerAddMoneyUnchecked(udg_PLAYER_SOUTH_VIETNAM, AMOUNT, false)
call TextTagBountyGoldForce(udg_AmericanAll, AMOUNT, GetUnitX(gg_unit_vsai_0001), GetUnitY(gg_unit_vsai_0001), 0)
call RemoveUnit(GetTriggerUnit())
endif
set target = null
endfunction
private function InstantCast takes nothing returns nothing
call IssueTargetOrder(GetTriggerUnit(), "smart", gg_unit_vsai_0001)
endfunction
private function OnUnitTrained takes nothing returns nothing
if (GetUnitRallyUnit(GetTriggerUnit()) == gg_unit_vsai_0001) then
call IssueTargetOrder(GetTrainedUnit(), "smart", gg_unit_vsai_0001)
endif
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_TRANSFER_FUNDS, function UnitCast)
call RegisterSpellEffectEvent(ABILITY_TRANSFER_FUNDS_INSTANT, function InstantCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function OnUnitTrained)
endfunction
endscope
scope HoChiMinhTrailSpawn initializer Init
globals
private constant real GUERRILLA_WEIGHT = 25.0
private constant real MG_WEIGHT_FACTOR = 0.23
private constant real AT_WEIGHT_FACTOR = 0.16
private constant real AA_WEIGHT_FACTOR = 0.13
private constant real SAPPER_WEIGHT_FACTOR = 0.12
private constant real EXTRA_CHANCE_FACTOR = .04
//private constant integer MAX_QUEUE_SIZE = 24
private unitpool Pool
private real array SpawnPointX
private real array SpawnPointY
//private integer array Queued
//private integer array NumQueued
endglobals
private function SpawnForPlayer takes player p, real x, real y, real extraChance returns nothing
local unit u = PlaceRandomUnit(Pool, p, x, y, bj_UNIT_FACING)
if (GetUnitTypeId(u) == UNIT_GUERRILLA) then
if (GetPlayerTechCount(p, TECH_AK47, true) == 0) then
//call CreateUnit(p, UNIT_GUERRILLA, x, y, bj_UNIT_FACING)
else
call RemoveUnit(u)
call CreateUnit(p, UNIT_GUERRILLA_UP, x, y, bj_UNIT_FACING)
//call CreateUnit(p, UNIT_GUERRILLA_UP, x, y, bj_UNIT_FACING)
endif
endif
set u = null
if (GetRandomReal(0,1) < extraChance) then
call SpawnForPlayer(p, x, y, extraChance * 0.50)
endif
endfunction
private function Spawn takes nothing returns nothing
if (GetOwningPlayer(gg_unit_vhan_0043) != udg_PLAYER_NORTH_VIETNAM) then
return
endif
call UnitPoolRemoveUnitType(Pool, UNIT_GUERRILLA)
call UnitPoolRemoveUnitType(Pool, UNIT_RPK_N)
call UnitPoolRemoveUnitType(Pool, UNIT_RPG_N)
call UnitPoolRemoveUnitType(Pool, UNIT_SA7_N)
call UnitPoolRemoveUnitType(Pool, UNIT_SAPPER_N)
call UnitPoolAddUnitType(Pool, UNIT_GUERRILLA, GUERRILLA_WEIGHT)
call UnitPoolAddUnitType(Pool, UNIT_RPK_N, udg_NumCheckpoints * MG_WEIGHT_FACTOR)
call UnitPoolAddUnitType(Pool, UNIT_RPG_N, udg_NumCheckpoints * AT_WEIGHT_FACTOR)
call UnitPoolAddUnitType(Pool, UNIT_SA7_N, udg_NumCheckpoints * AA_WEIGHT_FACTOR)
call UnitPoolAddUnitType(Pool, UNIT_SAPPER_N, udg_NumCheckpoints * SAPPER_WEIGHT_FACTOR)
call SpawnForPlayer(udg_PLAYER_VIETCONG_PINK, SpawnPointX[0], SpawnPointY[0], udg_NumCheckpoints * EXTRA_CHANCE_FACTOR)
call SpawnForPlayer(udg_PLAYER_VIETCONG_GRAY, SpawnPointX[1], SpawnPointY[1], udg_NumCheckpoints * EXTRA_CHANCE_FACTOR)
call SpawnForPlayer(udg_PLAYER_VIETCONG_BROWN, SpawnPointX[2], SpawnPointY[2], udg_NumCheckpoints * EXTRA_CHANCE_FACTOR)
endfunction
private function DelayedInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerExpireEvent(t, udg_DateTimer)
call TriggerAddAction(t, function Spawn)
set SpawnPointX[0] = GetLocationX(udg_BonusUnitSpawn[0])
set SpawnPointY[0] = GetLocationY(udg_BonusUnitSpawn[0])
set SpawnPointX[1] = GetLocationX(udg_BonusUnitSpawn[1])
set SpawnPointY[1] = GetLocationY(udg_BonusUnitSpawn[1])
set SpawnPointX[2] = GetLocationX(udg_BonusUnitSpawn[2])
set SpawnPointY[2] = GetLocationY(udg_BonusUnitSpawn[2])
endfunction
private function Init takes nothing returns nothing
set Pool = CreateUnitPool()
call TimerStart(CreateTimer(), 0, false, function DelayedInit)
endfunction
endscope
scope TunnelNetwork
struct TunnelNetwork extends array
private static constant integer MAX_CAPACITY = 30
static boolean array isUnitLoading
//static boolean array isUnitUnloading
group loading
group loaded
integer cargo
integer queued
method operator owner takes nothing returns player
return Player(this - 1)
endmethod
method getCapacityRemaining takes nothing returns integer
return MAX_CAPACITY - .cargo - .queued
endmethod
method getQueued takes nothing returns integer
return .queued
endmethod
static method ofPlayer takes player p returns thistype
if (p == null) then
return 0
endif
return GetPlayerId(p) + 1
endmethod
method destroy takes nothing returns nothing
call DestroyGroup(.loading)
call DestroyGroup(.loaded)
set .loading = null
set .loaded = null
set .cargo = 0
set .queued = 0
endmethod
static method create takes player p returns thistype
local thistype this = ofPlayer(p)
set .loading = CreateGroup()
set .loaded = CreateGroup()
set .cargo = 0
set .queued = 0
return this
endmethod
method killLoadedUnits takes nothing returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(.loaded)
local unit u
loop
exitwhen (i == size)
set u = BlzGroupUnitAt(.loaded, i)
call ShowUnit(u, true)
call RemoveUnit(u)
set i = i + 1
endloop
call GroupClear(.loaded)
set .cargo = 0
set .queued = 0
endmethod
method transferToPlayer takes player p returns nothing
local thistype that = ofPlayer(p)
if (this == that) then
return
endif
call GroupAddGroup(that.loading, this.loading)
call GroupAddGroup(that.loaded, this.loaded)
set that.cargo = that.cargo + this.cargo
set that.queued = that.queued + this.queued
//call .destroy()
endmethod
method addUnitToCargo takes unit u returns nothing
call UnitTrackMovement(u, false)
call GroupAddUnit(.loaded, u)
call ShowUnit(u, false)
call PauseUnit(u, true)
set .cargo = .cargo + 1
set .queued = .queued - 1
set isUnitLoading[GetUnitId(u)] = false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYER_SLOTS)
call create(Player(i))
set i = i + 1
endloop
endmethod
endstruct
function TunnelNetworkTransferToPlayer takes player oldPlayer, player newPlayer returns nothing
call TunnelNetwork.ofPlayer(oldPlayer).transferToPlayer(newPlayer)
endfunction
endscope
library Tunnel uses NetworkLoadOrder, NetworkUnloadOrder, UnitDex, TimedUnitEffect
struct Tunnel extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./8
private static boolexpr TUNNEL_LOAD_FILTER = null
private static constant integer MAX_CAPACITY = 30
private static constant real TEXT_SIZE = TextTagSize2Height(10)
private static thistype array unit2thistype
// Points to this.loading for a unit in the process of entering a Tunnel
private static group array unitLoadingGroup
// Points to this for a unit in the process of entering a Tunnel
private static thistype array unitLoadingTunnel
private TunnelNetwork network
private player owner
private unit tunnel
private real x
private real y
private group loading
private integer queued
private texttag info
method destroy takes nothing returns nothing
set unit2thistype[GetUnitId(.tunnel)] = 0
call RemoveUnit(.tunnel)
call DestroyGroup(.loading)
call DestroyTextTag(.info)
set .tunnel = null
set .loading = null
set .info = null
call .deallocate()
endmethod
method update takes nothing returns nothing
if (not UnitAlive(.tunnel)) then
if (GetPlayerTechCount(.owner, UNIT_TUNNEL, true) == 0) then
call .network.killLoadedUnits()
endif
call .finalize()
return
endif
call SetTextTagText(.info, I2S(.network.cargo) + "|cffffcc00/|r" + I2S(MAX_CAPACITY), TEXT_SIZE)
if (IsUnitSelected(.tunnel, .owner)) then
call SetTextTagVisibility(.info, PLAYER_LOCAL == .owner)
elseif (PLAYER_LOCAL == .owner and BlzGetMouseFocusUnit() == .tunnel) then
call SetTextTagVisibility(.info, true)
else
call SetTextTagVisibility(.info, false)
endif
endmethod
static method create takes unit u returns thistype
local thistype this = allocate()
set unit2thistype[GetUnitId(u)] = this
set .owner = GetOwningPlayer(u)
set .network = TunnelNetwork.ofPlayer(.owner)
set .tunnel = u
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .loading = CreateGroup()
set .queued = 0
set .info = CreateTextTag()
call SetTextTagPermanent(.info, true)
call SetTextTagPos(.info, .x - 32, .y, 64)
call .listAdd()
return this
endmethod
static method onLoad takes nothing returns nothing
local thistype this = unit2thistype[GetUnitId(GetTriggerUnit())]
local integer i = 0
local integer size
local boolean createLoadOrder = false
local unit u
local integer id
call GroupClear(.loading)
set FilterPlayer = .owner
call GroupEnumUnitsInRangeCollision(ENUM_GROUP, GetSpellTargetX(), GetSpellTargetY(), 300, TUNNEL_LOAD_FILTER)
set size = IMinBJ(.network.getCapacityRemaining(), BlzGroupGetSize(ENUM_GROUP))
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
set id = GetUnitId(u)
if (not TunnelNetwork.isUnitLoading[id]) then
set TunnelNetwork.isUnitLoading[id] = true
call GroupAddUnit(.loading, u)
set unitLoadingGroup[id] = .loading
set unitLoadingTunnel[id] = this
call SetUnitPathing(u, false)
call IssueTargetOrderById(u, ORDER_CRIPPLE, .tunnel)
call UnitFadeOutDist(u, .x, .y)
set .queued = .queued + 1
set .network.queued = .network.queued + 1
set createLoadOrder = true
endif
set i = i + 1
endloop
if (createLoadOrder) then
call SetUnitInvulnerable(.tunnel, true)
call LoadOrder.create(.network, .tunnel, .loading)
endif
set u = null
endmethod
static method onLoadSmart takes nothing returns nothing
local thistype this = unit2thistype[GetUnitId(GetTriggerUnit())]
local unit u = GetSpellTargetUnit()
local integer id = GetUnitId(u)
call GroupClear(.loading)
if (.network.getCapacityRemaining() > 0 and not TunnelNetwork.isUnitLoading[GetUnitId(u)]) then
set TunnelNetwork.isUnitLoading[GetUnitId(u)] = true
call GroupAddUnit(.loading, u)
set unitLoadingGroup[id] = .loading
set unitLoadingTunnel[id] = this
call SetUnitPathing(u, false)
call IssueTargetOrderById(u, ORDER_CRIPPLE, .tunnel)
call UnitFadeOutDist(u, .x, .y)
set .queued = .queued + 1
set .network.queued = .network.queued + 1
call SetUnitInvulnerable(.tunnel, true)
call LoadOrder.create(.network, .tunnel, .loading)
endif
set u = null
endmethod
static method onUnload takes nothing returns nothing
local thistype this = unit2thistype[GetUnitId(GetTriggerUnit())]
if (.network.cargo > 0) then
call BlzUnitDisableAbility(.tunnel, ABILITY_TUNNEL_UNLOAD, true, false)
call UnloadOrder.create(.network, .tunnel, GetSpellTargetX(), GetSpellTargetY())
endif
endmethod
private static method onConstructed takes nothing returns nothing
if (UnitHasAbility(GetTriggerUnit(), ABILITY_TUNNEL_LOAD)) then
call create(GetTriggerUnit())
endif
endmethod
private static method createPreplaced takes nothing returns boolean
if (UnitHasAbility(GetFilterUnit(), ABILITY_TUNNEL_LOAD)) then
call create(GetFilterUnit())
endif
return false
endmethod
private static method delayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, Filter(function thistype.createPreplaced))
call ReleaseTimer(GetExpiredTimer())
endmethod
private static method canLoad takes unit u, player p returns boolean
return UnitHasAbility(u, ABILITY_ENTER_TUNNEL) and GetOwningPlayer(u) == p
endmethod
private static method canLoadFilter takes nothing returns boolean
return canLoad(GetFilterUnit(), FilterPlayer)
endmethod
private static method onEnter takes nothing returns nothing
local thistype this = unit2thistype[GetUnitId(GetSpellTargetUnit())]
local unit u = GetTriggerUnit()
call UnitFadeDistKill(u)
call .network.addUnitToCargo(u)
set u = null
endmethod
private static method onOrder takes nothing returns nothing
local thistype this
local unit u = GetTriggerUnit()
local integer id = GetUnitId(u)
if (TunnelNetwork.isUnitLoading[id] and (not IsUnitHidden(u)) and GetIssuedOrderId() != ORDER_CRIPPLE) then
set TunnelNetwork.isUnitLoading[id] = false
call GroupRemoveUnit(unitLoadingGroup[id], u)
call UnitFadeDistKill(u)
call SetUnitPathing(u, true)
set this = unitLoadingTunnel[id]
set .queued = IMaxBJ(.queued - 1, 0)
set .network.queued = IMaxBJ(.network.queued - 1, 0)
endif
set u = null
endmethod
private static method smartOrder takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit t = GetOrderTargetUnit()
if (GetIssuedOrderId() == ORDER_SMART and GetUnitTypeId(t) == UNIT_TUNNEL and UnitHasAbility(u, ABILITY_ENTER_TUNNEL) and GetOwningPlayer(u) == GetOwningPlayer(t)) then
call IssueTargetOrderById(u, ORDER_PURGE, t)
endif
set u = null
set t = null
endmethod
private static method enterSmart takes nothing returns nothing
call IssueTargetOrderById(GetSpellTargetUnit(), ORDER_SMART, GetTriggerUnit())
endmethod
private static method onDeindex takes nothing returns nothing
local integer id = GetIndexedUnitId()
set unitLoadingGroup[id] = null
set unitLoadingTunnel[id] = 0
set TunnelNetwork.isUnitLoading[id] = false
endmethod
private static method onInit takes nothing returns nothing
set TUNNEL_LOAD_FILTER = Filter(function thistype.canLoadFilter)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.onConstructed)
call RegisterSpellEffectEvent(ABILITY_TUNNEL_LOAD_SMART, function thistype.onLoadSmart)
call RegisterSpellEffectEvent(ABILITY_TUNNEL_LOAD, function thistype.onLoad)
call RegisterSpellEffectEvent(ABILITY_TUNNEL_UNLOAD, function thistype.onUnload)
call RegisterSpellEffectEvent(ABILITY_ENTER_TUNNEL, function thistype.onEnter)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.smartOrder)
call RegisterSpellEffectEvent(ABILITY_ENTER_TUNNEL_SMART, function thistype.enterSmart)
call OnUnitDeindex(function thistype.onDeindex)
call TimerStart(NewTimer(0), 0, false, function thistype.delayedInit)
endmethod
endstruct
endlibrary
library NetworkLoadOrder uses TimedUnitEffect
struct LoadOrder extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./8
private TunnelNetwork network
private unit tunnel
private real x
private real y
private group loadingOriginal
private group loading
private group loaded
private integer ticks
method destroy takes nothing returns nothing
call SetUnitInvulnerable(.tunnel, false)
call DestroyGroup(.loading)
call DestroyGroup(.loaded)
set .tunnel = null
set .loadingOriginal = null
set .loading = null
set .loaded = null
endmethod
method update takes nothing returns nothing
local integer i = 0
local integer size = BlzGroupGetSize(.loading)
local unit u
if (size == 0) then
call .finalize()
return
endif
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(.loading, i)
if ((not UnitAlive(u)) or (not IsUnitInGroup(u, .loadingOriginal))) then
call GroupRemoveUnit(.loading, u)
elseif (IsUnitInRangeXY(u, .x, .y, 32)) then
call UnitFadeDistKill(u)
call network.addUnitToCargo(u)
call GroupAddUnit(.loaded, u)
endif
set i = i + 1
endloop
call BlzGroupRemoveGroupFast(.loaded, .loading)
call GroupClear(.loaded)
endmethod
static method create takes TunnelNetwork network, unit tunnel, group loading returns thistype
local thistype this = allocate()
set .network = network
set .tunnel = tunnel
set .x = GetUnitX(tunnel)
set .y = GetUnitY(tunnel)
set .loadingOriginal = .loading
set .loading = GroupCopy(loading)
set .loaded = CreateGroup()
call .listAdd()
return this
endmethod
endstruct
endlibrary
library NetworkUnloadOrder uses TimedUnitEffect, UnitDex
struct UnloadOrder extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./8
private TunnelNetwork network
private unit tunnel
private real x
private real y
method destroy takes nothing returns nothing
call BlzUnitDisableAbility(.tunnel, ABILITY_TUNNEL_UNLOAD, false, false)
set .tunnel = null
call .deallocate()
endmethod
method update takes nothing returns nothing
local unit u = FirstOfGroup(.network.loaded)
if (u != null) then
call SetUnitX(u, GetUnitX(.tunnel))
call SetUnitY(u, GetUnitY(.tunnel))
call SetUnitPathing(u, true)
call ShowUnit(u, true)
call PauseUnit(u, false)
call UnitFadeIn(u, 2)
call IssuePointOrderById(u, ORDER_ATTACK, .x, .y)
set .network.cargo = .network.cargo - 1
call GroupRemoveUnit(.network.loaded, u)
set u = null
else
call .finalize()
endif
endmethod
static method create takes TunnelNetwork network, unit tunnel, real x, real y returns thistype
local thistype this = allocate()
set .network = network
set .tunnel = tunnel
set .x = x
set .y = y
call .listAdd()
return this
endmethod
endstruct
endlibrary
scope D30Deploy initializer Init
private function OnCast takes nothing returns nothing
local unit u = GetTriggerUnit()
if ((GetUnitTypeId(u) == UNIT_D30_TOWED) and (GetPlayerTechResearched(GetTriggerPlayer(), TECH_RAPID_REPOSITIONING_2, true))) then
call UnitAddAbility(u, ABILITY_ENTER_TUNNEL)
call UnitAddAbility(u, ABILITY_ENTER_TUNNEL_SMART)
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_D30_DEPLOY, function OnCast)
endfunction
endscope
scope Informants initializer Init
globals
// Level 1
private constant integer COST_1 = 0
private constant real DURATION_1 = 30
// Level 2
private constant integer COST_2 = 0
private constant real DURATION_2 = 45
endglobals
private function OnCast1 takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit caster = GetTriggerUnit()
local unit target
set FilterPlayer = p
set target = GetNearestUnit(GetSpellTargetX(), GetSpellTargetY(), 500, FILTER_ENEMY_SETTLEMENT)
if (target != null) then
call UnitShareVisionTimed(target, udg_VietAll, DURATION_1)
call StartPlayerAbilityCooldown(p, ABILITY_INFORMANTS_1)
set target = null
else
call TextTagError(p, "Invalid target!", GetUnitX(caster) - 80, GetUnitY(caster), 72)
call UnitResetAbilityCooldownTimed(caster, ABILITY_INFORMANTS_1, 0)
call PlayerRemoveMoney(p, COST_1)
endif
set caster = null
endfunction
private function OnCast2 takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit caster = GetTriggerUnit()
local unit target
set FilterPlayer = p
set target = GetNearestUnit(GetSpellTargetX(), GetSpellTargetY(), 500, FILTER_ENEMY_SETTLEMENT)
if (target != null) then
set bj_lastCreatedUnit = CreateUnit(p, DUMMY_INFORMANTS_VISION, GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', DURATION_2)
call StartPlayerAbilityCooldown(p, ABILITY_INFORMANTS_2)
set target = null
else
call TextTagError(p, "Invalid target!", GetUnitX(caster) - 80, GetUnitY(caster), 72)
call UnitResetAbilityCooldownTimed(caster, ABILITY_INFORMANTS_2, 0)
call PlayerRemoveMoney(p, COST_2)
endif
set caster = null
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_INFORMANTS_1, function OnCast1)
call RegisterSpellEffectEvent(ABILITY_INFORMANTS_2, function OnCast2)
endfunction
endscope
scope Insurgency initializer Init
globals
private constant integer SUPPLY_COST = 500
private constant integer MAX_TARGETS = 9
private constant integer GUERRILLAS = 10
private constant real EFFECT_DELAY = 10
private constant real DURATION = 120
private constant real MESSAGE_DURATION = 10
private constant real PING_DURATION = 5
private group Targets = null
endglobals
private function CreateInsurgencyEnum takes nothing returns nothing
local unit town = GetEnumUnit()
local unit insurgency
local real x = GetUnitX(town)
local real y = GetUnitY(town)
set insurgency = CreateUnit(udg_PLAYER_NORTH_VIETNAM, UNIT_INSURGENCY, x, y, bj_UNIT_FACING)
call UnitApplyTimedLife(insurgency, 'BTLF', DURATION)
call CreateUnits(udg_PLAYER_NORTH_VIETNAM, UNIT_GUERRILLA_UP, GUERRILLAS, x, y)
if (IsPlayerInForce(PLAYER_LOCAL, udg_VietAll)) then
call PingMinimapEx(x, y, PING_DURATION, 255, 0, 0, false)
endif
set town = null
set insurgency = null
endfunction
private function AfterDelay takes nothing returns nothing
call ReleaseTimer(GetExpiredTimer())
call GroupEnumUnitsOfPlayer(ENUM_GROUP, udg_PLAYER_SOUTH_VIETNAM, FILTER_SETTLEMENT_NON_CITY)
set Targets = GroupGetRandomSubgroup(ENUM_GROUP, MAX_TARGETS)
call ForGroup(Targets, function CreateInsurgencyEnum)
call DestroyGroup(Targets)
endfunction
private function OnCast takes nothing returns nothing
local player p = GetTriggerPlayer()
if (PlayerGetSupplies(p) < SUPPLY_COST) then
return
endif
call PlayerRemoveSupplies(p, SUPPLY_COST)
call TimerStart(NewTimer(0), EFFECT_DELAY, false, function AfterDelay)
if (IsPlayerInForce(PLAYER_LOCAL, udg_VietAll)) then
call StartSound(gg_snd_HumanCallToArmsWhat1)
call TimedMessage(PLAYER_LOCAL, MESSAGE_DURATION, "\n|cffff0303ATTENTION:|r |cffffcc00Insurgencies|r will break out across South Vietnam in " + I2S(R2I(EFFECT_DELAY)) + " seconds!\n")
endif
endfunction
private function OnUnitSold takes nothing returns nothing
local unit u = GetSoldUnit()
if (GetUnitTypeId(u) == UNIT_INSURGENCY_GUERRILLA) then
if (GetPlayerTechCount(GetOwningPlayer(u), TECH_AK47, true) > 0) then
call UnitAddAbility(u, 'S00R')
else
call UnitAddAbility(u, 'S00O')
endif
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_INSURGENCY, function OnCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL, function OnUnitSold)
endfunction
endscope
scope RadarVision
globals
private constant real DETECTION_RANGE = 1800
private constant real PING_DURATION = 2.25 // Set to 0 for no ping
endglobals
private struct Vision extends array
implement Alloc
implement Iterator
static constant real UPDATE_INTERVAL = 0.125
unit radar
unit flyer
unit visionDummy
real prevX
real prevY
method destroy takes nothing returns nothing
call RemoveUnit(.visionDummy)
set .radar = null
set .flyer = null
set .visionDummy = null
endmethod
method update takes nothing returns nothing
if (not IsUnitInRange(.radar, .flyer, DETECTION_RANGE)) then
call .finalize()
return
endif
if ((not UnitAlive(.radar)) or (not UnitAlive(.flyer))) then
call .finalize()
return
endif
call SetUnitX(.visionDummy, GetUnitX(.flyer))
call SetUnitY(.visionDummy, GetUnitY(.flyer))
endmethod
static method create takes unit radar, unit flyer returns thistype
local thistype this = allocate()
local real x = GetUnitX(flyer)
local real y = GetUnitY(flyer)
set .radar = radar
set .flyer = flyer
set .visionDummy = CreateUnit(GetOwningPlayer(radar), DUMMY_RADAR_DETECTION_VISION, x, y, 0)
if ((PLAYER_LOCAL == GetOwningPlayer(radar)) and (PING_DURATION > 0)) then
call PingMinimapEx(x, y, PING_DURATION, 255, 0, 0, false)
endif
call .listAdd()
return this
endmethod
endstruct
private struct Radar extends array
static Table trigger2thistype
unit radar
player owner
trigger inRangeTrig
method destroy takes nothing returns nothing
set trigger2thistype[GetHandleId(.inRangeTrig)] = 0
call DestroyTrigger(.inRangeTrig)
set .radar = null
set .inRangeTrig = null
endmethod
static method onTargetInRange takes nothing returns nothing
local unit u = GetTriggerUnit()
local thistype this = trigger2thistype[GetHandleId(GetTriggeringTrigger())]
if (UnitHasAbility(u, ATTR_AIR_UNIT) and IsUnitEnemy(u, .owner)) then
call Vision.create(.radar, u)
endif
set u = null
endmethod
static method create takes unit u returns thistype
local thistype this = GetUnitId(u)
set .radar = u
set .owner = GetOwningPlayer(u)
set .inRangeTrig = CreateTrigger()
call TriggerRegisterUnitInRange(.inRangeTrig, u, DETECTION_RANGE, null)
call TriggerAddCondition(.inRangeTrig, function thistype.onTargetInRange)
set trigger2thistype[GetHandleId(.inRangeTrig)] = this
return this
endmethod
static method createEnum takes nothing returns nothing
call create(GetEnumUnit())
endmethod
static method new takes nothing returns nothing
local unit u = GetTriggerUnit()
if (UnitHasAbility(u, ABILITY_RADAR_DETECTION)) then
call create(u)
endif
set u = null
endmethod
static method onDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local thistype this = GetUnitId(u)
if (.radar == u) then
call .destroy()
endif
set u = null
endmethod
private static method delayedInit takes nothing returns nothing
set FilterUnitAbility = ABILITY_RADAR_DETECTION
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, FILTER_UNIT_ABILITY)
call ForGroup(ENUM_GROUP, function thistype.createEnum)
call ReleaseTimer(GetExpiredTimer())
endmethod
private static method onInit takes nothing returns nothing
set trigger2thistype = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_FINISH, function thistype.new)
//call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function thistype.new)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call TimerStart(NewTimer(0), 0, false, function thistype.delayedInit)
endmethod
endstruct
endscope
scope Reinforcement initializer Init
globals
private integer COST = 0
endglobals
private function OnCast takes nothing returns nothing
local player p = GetTriggerPlayer()
call StartPlayerAbilityCooldown(p, ABILITY_REINFORCEMENT)
call PlayerRemoveMoney(p, COST)
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_REINFORCEMENT, function OnCast)
endfunction
endscope
scope RocketBarrage
private struct RocketBarrage extends array
implement Alloc
implement Iterator
private static constant real UPDATE_INTERVAL = 1./32
private static constant real MINIMUM_RANGE = 800
private static constant real COOLDOWN = 0.5
private static constant integer ROCKETS = 40
private static constant real MISSILE_SPEED = 1300
private static constant real MISSILE_ARC = 54
private static constant real SCATTER_RADIUS = 350
private static constant real DAMAGE_BASE = 75
private static constant integer DAMAGE_NUMBER_OF_DICE = 5
private static constant integer DAMAGE_SIDES_PER_DIE = 10
private static constant real DAMAGE_RADIUS = 250
private static constant attacktype ATTACK_TYPE = ATTACK_TYPE_HE
private static thistype array unit2thistype
private static trigger finishTrig = CreateTrigger()
private static trigger orderTrig = CreateTrigger()
private player owner
private unit caster
private real casterX
private real casterY
private real targetX
private real targetY
private real nextX
private real nextY
private real cooldown
private integer remaining
static method onFinish takes nothing returns nothing
local real damage = DiceReal(DAMAGE_NUMBER_OF_DICE, DAMAGE_NUMBER_OF_DICE, DAMAGE_SIDES_PER_DIE)
local integer size
local integer i = 0
local unit u
call GroupEnumUnitsInRange(ENUM_GROUP, GetLocationX(udg_MissilePosition), GetLocationY(udg_MissilePosition), DAMAGE_RADIUS, null)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i == size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
if (not IsUnitType(u, UNIT_TYPE_FLYING)) then
call UnitDamageTarget(udg_MissileSource, u, damage, true, true, ATTACK_TYPE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
set i = i + 1
endloop
set u = null
endmethod
static method onOrder takes nothing returns nothing
local integer id = GetUnitId(GetTriggerUnit())
if (unit2thistype[id] > 0) then
call unit2thistype[id].finalize()
endif
endmethod
method destroy takes nothing returns nothing
set unit2thistype[GetUnitId(.caster)] = 0
set .caster = null
call .deallocate()
endmethod
method update takes nothing returns nothing
local real angle
set .cooldown = .cooldown - UPDATE_INTERVAL
if (.cooldown <= 0) then
if (UnitAlive(.caster) and .remaining > 0) then
call SetUnitAnimation(.caster, "attack")
set angle = GetRandomAngle()
set .nextX = .targetX + GetRandomReal(0,SCATTER_RADIUS) * Cos(angle)
set .nextY = .targetY + GetRandomReal(0,SCATTER_RADIUS) * Sin(angle)
set udg_MissileSource = .caster
set udg_MissileOwner = .owner
set udg_MissileStart = Location(.casterX, .casterY)
set udg_MissileStartZ = 45
set udg_MissileFinish = Location(.nextX, .nextY)
set udg_MissileFinishZ = 0
set udg_MissileModel = "Models\\Projectiles\\RocketMissile-BlackRedWhite.mdl"
set udg_MissileScale = 0.5
set udg_MissileSpeed = MISSILE_SPEED
set udg_MissileArc = MISSILE_ARC
set udg_MissileRemoveLocations = true
set udg_Missile_onFinish = finishTrig
call MissileCreate()
else
call QueueUnitAnimation(.caster, "stand")
call .finalize()
endif
set .remaining = .remaining - 1
set .cooldown = COOLDOWN
endif
endmethod
static method create takes nothing returns thistype
local thistype this
local unit caster = GetTriggerUnit()
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
if (DistanceWithin(casterX, casterY, targetX, targetY, MINIMUM_RANGE)) then
call IssueImmediateOrderById(caster, ORDER_STOP)
set caster = null
return 0
endif
set this = allocate()
set .owner = GetTriggerPlayer()
set .caster = caster
set .casterX = casterX
set .casterY = casterY
set .targetX = targetX
set .targetY = targetY
set .cooldown = COOLDOWN
set .remaining = ROCKETS
set unit2thistype[GetUnitId(caster)] = this
call .listAdd()
set caster = null
return this
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_BM21_ROCKET_BARRAGE, function thistype.create)
call TriggerAddCondition(finishTrig, function thistype.onFinish)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
endmethod
endstruct
endscope
scope RocketPodsMI4 initializer Init
globals
private constant real DURATION = 15
endglobals
private function OnFinish takes nothing returns nothing
local Table data = ReleaseTimer(GetExpiredTimer())
if (UnitAlive(data.unit[0])) then
call BlzSetUnitWeaponBooleanField(data.unit[0], UNIT_WEAPON_BF_ATTACKS_ENABLED, 0, true)
call UnitRemoveAbility(data.unit[0], ABILITY_ROCKET_PODS_MI4_D)
call UnitRemoveAbility(data.unit[0], ATTR_NON_COMBAT)
endif
call data.destroy()
endfunction
private function OnCast takes nothing returns nothing
local unit u = GetTriggerUnit()
local Table data = Table.create()
set data.unit[0] = u
call UnitRemoveAbility(u, ABILITY_ROCKET_PODS_MI4)
call UnitAddAbility(u, ABILITY_ROCKET_PODS_MI4_D)
call IssueImmediateOrderById(u, ORDER_CHANNEL)
call TimerStart(NewTimer(data), DURATION, false, function OnFinish)
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_ROCKET_PODS_MI4, function OnCast)
endfunction
endscope
scope SneakAttack initializer Init
globals
private constant real INITIAL_COOLDOWN = 600
private constant integer COST = 300
endglobals
private function OnCast takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
if (DistanceWithin(GetUnitX(u), GetUnitY(u), GetSpellTargetX(), GetSpellTargetY(), 128)) then
call IssueImmediateOrderById(u, ORDER_STOP)
elseif (PlayerGetMoney(p) >= COST) then
call StartPlayerAbilityCooldown(GetTriggerPlayer(), ABILITY_SNEAK_ATTACK)
call PlayerRemoveMoney(p, COST)
endif
set u = null
endfunction
private function DelayedInit takes nothing returns nothing
call StartPlayerAbilityCooldownEx(udg_PLAYER_VIETCONG_PINK, ABILITY_SNEAK_ATTACK, INITIAL_COOLDOWN)
call StartPlayerAbilityCooldownEx(udg_PLAYER_VIETCONG_GRAY, ABILITY_SNEAK_ATTACK, INITIAL_COOLDOWN)
call StartPlayerAbilityCooldownEx(udg_PLAYER_VIETCONG_BROWN, ABILITY_SNEAK_ATTACK, INITIAL_COOLDOWN)
call ReleaseTimer(GetExpiredTimer())
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_SNEAK_ATTACK, function OnCast)
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope Uprising initializer Init
globals
private integer COST_1 = 100
private integer COST_2 = 150
private integer COST_3 = 200
endglobals
private function OnCast1 takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit caster = GetTriggerUnit()
local unit target
local real x
local real y
local integer spawnUnitId = GetPlayerGuerrillaUnitId(p)
set FilterPlayer = p
set target = GetNearestUnit(GetSpellTargetX(), GetSpellTargetY(), 500, FILTER_ENEMY_SETTLEMENT)
if (target != null) then
set x = GetUnitX(target)
set y = GetUnitY(target)
call CreateUnits(p, spawnUnitId, 5, x, y)
call StartPlayerAbilityCooldown(p, ABILITY_UPRISING_1)
call PlayerRemoveMoney(p, COST_1)
set target = null
else
call TextTagError(p, "Invalid target!", GetUnitX(caster) - 80, GetUnitY(caster), 72)
call UnitResetAbilityCooldownTimed(caster, ABILITY_UPRISING_1, 0)
endif
set caster = null
endfunction
private function OnCast2 takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit caster = GetTriggerUnit()
local unit target
local real x
local real y
local integer spawnUnitId = GetPlayerGuerrillaUnitId(p)
set FilterPlayer = p
set target = GetNearestUnit(GetSpellTargetX(), GetSpellTargetY(), 500, FILTER_ENEMY_SETTLEMENT)
if (target != null) then
set x = GetUnitX(target)
set y = GetUnitY(target)
call CreateUnits(p, spawnUnitId, 9, x, y)
call CreateUnits(p, UNIT_RPK_N, 1, x, y)
call StartPlayerAbilityCooldown(p, ABILITY_UPRISING_2)
call PlayerRemoveMoney(p, COST_2)
set target = null
else
call TextTagError(p, "Invalid target!", GetUnitX(caster) - 80, GetUnitY(caster), 72)
call UnitResetAbilityCooldownTimed(caster, ABILITY_UPRISING_2, 0)
endif
set caster = null
endfunction
private function OnCast3 takes nothing returns nothing
local player p = GetTriggerPlayer()
local unit caster = GetTriggerUnit()
local unit target
local real x
local real y
local integer spawnUnitId = GetPlayerGuerrillaUnitId(p)
set FilterPlayer = p
set target = GetNearestUnit(GetSpellTargetX(), GetSpellTargetY(), 500, FILTER_ENEMY_SETTLEMENT)
if (target != null) then
set x = GetUnitX(target)
set y = GetUnitY(target)
call CreateUnits(p, spawnUnitId, 12, x, y)
call CreateUnits(p, UNIT_RPK_N, 2, x, y)
call CreateUnits(p, UNIT_RPG_N, 1, x, y)
call StartPlayerAbilityCooldown(p, ABILITY_UPRISING_3)
call PlayerRemoveMoney(p, COST_3)
set target = null
else
call TextTagError(p, "Invalid target!", GetUnitX(caster) - 80, GetUnitY(caster), 72)
call UnitResetAbilityCooldownTimed(caster, ABILITY_UPRISING_3, 0)
endif
set caster = null
endfunction
private function Init takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_UPRISING_1, function OnCast1)
call RegisterSpellEffectEvent(ABILITY_UPRISING_2, function OnCast2)
call RegisterSpellEffectEvent(ABILITY_UPRISING_3, function OnCast3)
endfunction
endscope
scope Traps initializer Init
globals
private Table SfxTable
private player OwningPlayer = null
private unit FilterUnit = null
endglobals
private function RPGFilter takes nothing returns boolean
set FilterUnit = GetFilterUnit()
return (UnitAlive(FilterUnit) and IsUnitType(FilterUnit, UNIT_TYPE_MECHANICAL) /*
*/ and IsUnitEnemy(FilterUnit, OwningPlayer))
endfunction
private function OnExplode takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer typeId = GetUnitTypeId(u)
local player p = GetTriggerPlayer()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
if (UnitHasAbility(u, ATTR_TRAP) and SfxTable.has(typeId)) then
call DestroyEffect(AddSpecialEffect(SfxTable.string[typeId], x, y))
call ShowUnit(u, false)
endif
if (typeId == UNIT_BOUNCING_BETTY) then
call PlaySoundAtPoint("Mine" + I2S(GetRandomInt(1,4)), 110, x, y, 340)
elseif (typeId == UNIT_FOUGASSE) then
call PlaySoundAtPoint("Fougasse", 100, x, y, 340)
call GetDummy(p, x, y, true)
call UnitAddAbilityTimed(Dummy, ABILITY_FOUGASSE_EXPLOSION, 1)
call IssuePointOrder(Dummy, "flamestrike", x, y)
elseif (typeId == UNIT_RPG_TRAP) then
call GetDummy(p, x, y, true)
call UnitAddAbilityTimed(Dummy, ABILITY_RPG_TRAP, 1)
set OwningPlayer = p
call IssueTargetOrder(Dummy, "thunderbolt", GetNearestUnit(x, y, 500, Filter(function RPGFilter)))
elseif (typeId == UNIT_TRIPWIRE_FLARE) then
call GetDummy(p, x, y, true)
call UnitAddAbilityTimed(Dummy, ABILITY_TRIPWIRE_FLARE, 1)
call IssuePointOrder(Dummy, "flare", x, y)
if (GetLocalPlayer() == p) then
call PingMinimapEx(x, y, 8, 255, 0, 0, false)
endif
call PlayMovingSoundAtPoint("Flare", 75, x, y, 270, 0, 0, 800)
endif
set u = null
endfunction
private function OnPunjiAttack takes nothing returns nothing
local unit u = GetEventDamageSource()
if (GetUnitTypeId(u) == UNIT_PUNJI_TRAP) then
call KillUnit(u)
endif
set u = null
endfunction
private function OnConstruct takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p
local real x
local real y
local real a
local integer id
if (UnitHasAbility(u, ATTR_TRAP)) then
set p = GetTriggerPlayer()
set x = GetUnitX(u)
set y = GetUnitY(u)
set id = GetUnitTypeId(u)
call RemoveUnit(u)
if (id == UNIT_BOUNCING_BETTY_B) then
call CreateUnit(p, UNIT_BOUNCING_BETTY, x, y, bj_UNIT_FACING)
set a = GetRandomAngle()
call CreateUnit(p, UNIT_BOUNCING_BETTY, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_BOUNCING_BETTY, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_BOUNCING_BETTY, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_BOUNCING_BETTY, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
elseif (id == UNIT_FOUGASSE_B) then
call CreateUnit(p, UNIT_FOUGASSE, x, y, bj_UNIT_FACING)
elseif (id == UNIT_RPG_TRAP_B) then
call CreateUnit(p, UNIT_RPG_TRAP, x, y, bj_UNIT_FACING)
elseif (id == UNIT_TRIPWIRE_FLARE_B) then
set a = GetRandomAngle()
call CreateUnit(p, UNIT_TRIPWIRE_FLARE, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.67 * bj_PI
call CreateUnit(p, UNIT_TRIPWIRE_FLARE, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.67 * bj_PI
call CreateUnit(p, UNIT_TRIPWIRE_FLARE, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
elseif (id == UNIT_PUNJI_TRAP_B) then
call CreateUnit(p, UNIT_PUNJI_TRAP, x, y, bj_UNIT_FACING)
set a = GetRandomAngle()
call CreateUnit(p, UNIT_PUNJI_TRAP, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_PUNJI_TRAP, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_PUNJI_TRAP, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
set a = a + 0.5 * bj_PI
call CreateUnit(p, UNIT_PUNJI_TRAP, x + 128 * Cos(a), y + 128 * Sin(a), bj_UNIT_FACING)
endif
endif
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnConstruct)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnExplode)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnPunjiAttack)
set SfxTable = Table.create()
set SfxTable.string[UNIT_BOUNCING_BETTY] = SFX_FRAG
set SfxTable.string[UNIT_FOUGASSE] = SFX_FLAME_BOMB
endfunction
endscope
library Artillery initializer Init requires UnitUtils
globals
private integer DataUnitTypeId = 0
HashTable ArtilleryData
endglobals
private function AddUnit takes integer unitId returns nothing
local unit u = CreateTempUnit(unitId)
local Table data = ArtilleryData[unitId]
set DataUnitTypeId = unitId
set data.real[MISSILE_SPEED] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_PROJECTILE_SPEED, 0)
set data[DAMAGE_BASE] = BlzGetUnitBaseDamage(u,0)
set data[DAMAGE_NUMBER_OF_DICE] = BlzGetUnitDiceNumber(u,0)
set data[DAMAGE_SIDES_PER_DIE] = BlzGetUnitDiceSides(u,0)
set data.real[DAMAGE_RADIUS_FULL] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_AREA_OF_EFFECT_FULL_DAMAGE, 0)
set data.real[DAMAGE_RADIUS_MEDIUM] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_AREA_OF_EFFECT_MEDIUM_DAMAGE, 0)
set data.real[DAMAGE_RADIUS_SMALL] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_AREA_OF_EFFECT_SMALL_DAMAGE, 0)
set data.real[DAMAGE_FACTOR_MEDIUM] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_DAMAGE_FACTOR_MEDIUM, 0)
set data.real[DAMAGE_FACTOR_SMALL] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_DAMAGE_FACTOR_SMALL, 0)
set data.real[MAX_RANGE] = BlzGetUnitWeaponRealField(u, UNIT_WEAPON_RF_ATTACK_RANGE, 0)
set data.real[BARRAGE_MAX_RANGE] = BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, ABILITY_ARTILLERY_BARRAGE), ABILITY_RLF_CAST_RANGE, 0)
set data[ATTACK_TYPE] = BlzGetUnitWeaponIntegerField(u, UNIT_WEAPON_IF_ATTACK_ATTACK_TYPE, 0)
call RemoveUnit(u)
set u = null
endfunction
private function SetAttackProperties takes string missileArt, real launchZ, real missileSize, real missileArc, real maxScatterRadius returns nothing
local Table data = ArtilleryData[DataUnitTypeId]
set data.string[MISSILE_ART] = missileArt
set data.real[MISSILE_LAUNCH_Z] = launchZ
set data.real[MISSILE_SIZE] = missileSize
set data.real[MISSILE_ARC] = missileArc
set data.real[MAX_SCATTER_RADIUS] = maxScatterRadius
endfunction
private function SetBarrageProperties takes integer shells, real cooldown, real scatterFactor returns nothing
local Table data = ArtilleryData[DataUnitTypeId]
set data.real[BARRAGE_ATTACK_INTERVAL] = cooldown
set data[BARRAGE_SHELLS] = shells
set data.real[BARRAGE_SCATTER_FACTOR] = scatterFactor
endfunction
private function Init takes nothing returns nothing
set ArtilleryData = HashTable.create()
call AddUnit(UNIT_D30_DEPLOYED)
call SetAttackProperties(ARTILLERY_MISSILE, 45, 1.0, 54, 350)
call SetBarrageProperties(10, 3.0, 0.5)
call AddUnit(UNIT_M102_DEPLOYED)
call SetAttackProperties(ARTILLERY_MISSILE, 45, 1.0, 54, 350)
call SetBarrageProperties(10, 3.0, 0.5)
call AddUnit(UNIT_MORTAR_D)
call SetAttackProperties(MORTAR_MISSILE, 15, 0.60, 72, 125)
call SetBarrageProperties(8, 2.89, 0.65)
endfunction
endlibrary
scope ArtilleryAutoAttack
private struct ArtilleryAutoAttack extends array
private static trigger finishTrig = CreateTrigger()
static method onFinish takes nothing returns nothing
local Table data = ArtilleryData[GetUnitTypeId(udg_MissileSource)]
local real x = GetLocationX(udg_MissilePosition)
local real y = GetLocationY(udg_MissilePosition)
local integer damageBase = data[DAMAGE_BASE]
local integer numberOfDice = data[DAMAGE_NUMBER_OF_DICE]
local integer sidesPerDie = data[DAMAGE_SIDES_PER_DIE]
local real radiusFull = data.real[DAMAGE_RADIUS_FULL]
local real radiusMed = data.real[DAMAGE_RADIUS_MEDIUM]
local real radiusSmall = data.real[DAMAGE_RADIUS_SMALL]
local real damageFactorMed = data.real[DAMAGE_FACTOR_MEDIUM]
local real damageFactorSmall = data.real[DAMAGE_FACTOR_SMALL]
local real damage = DiceReal(damageBase, numberOfDice, sidesPerDie)
local attacktype attackType = ConvertAttackType(data[ATTACK_TYPE])
set FilterPlayer = GetOwningPlayer(udg_MissileSource)
call UnitDamagePointSplash(udg_MissileSource, x, y, radiusFull, radiusMed, radiusSmall, /*
*/ damageFactorMed, damageFactorSmall, damage, attackType, FILTER_ALIVE_ENEMY_GROUND)
endmethod
static method launchMissile takes nothing returns nothing
local MissileData d = ReleaseTimer(GetExpiredTimer())
local Table data = ArtilleryData[GetUnitTypeId(d.source)]
local real maxScatter = data.real[MAX_SCATTER_RADIUS] * UnitDistanceToUnit(d.source, d.target) / data.real[MAX_RANGE]
local real scatter = GetRandomReal(0, maxScatter)
local real angle = GetRandomAngle()
local real targetX = GetUnitX(d.target) + scatter * Cos(angle)
local real targetY = GetUnitY(d.target) + scatter * Sin(angle)
set udg_MissileSource = d.source
set udg_MissileOwner = GetOwningPlayer(udg_MissileSource)
set udg_MissileStart = Location(GetUnitX(d.source), GetUnitY(d.source))
set udg_MissileStartZ = data.real[MISSILE_LAUNCH_Z]
set udg_MissileFinish = Location(targetX, targetY)
set udg_MissileFinishZ = 0
set udg_MissileModel = data.string[MISSILE_ART]
set udg_MissileScale = data.real[MISSILE_SIZE]
set udg_MissileSpeed = data.real[MISSILE_SPEED]
set udg_MissileArc = data.real[MISSILE_ARC]
set udg_MissileRemoveLocations = true
set udg_Missile_onFinish = finishTrig
call MissileCreate()
call d.destroy()
endmethod
static method onAttack takes nothing returns nothing
local unit u = GetAttacker()
local integer id = GetUnitTypeId(u)
if (ArtilleryData.has(id)) then
if (not UnitHasAbility(u, ATTR_CUSTOM_ATTACK_COOLDOWN)) then
call TimerStart(NewTimer(MissileData.create(u, GetTriggerUnit())), GetUnitTypeAttackBackswing(id,0), false, function thistype.launchMissile)
call UnitAddAbilityTimed(u, ATTR_CUSTOM_ATTACK_COOLDOWN, GetUnitTypeAttackInterval(id, 0))
else
call SetUnitAnimation(u, "stand")
endif
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function thistype.onAttack)
call TriggerAddCondition(finishTrig, function thistype.onFinish)
endmethod
endstruct
endscope
scope ArtilleryBarrage
private struct ArtilleryBarrage extends array
implement Alloc
private static constant real MINIMUM_RANGE = 750
private static thistype array unit2thistype
private static thistype array missile2thistype
private static trigger finishTrig = CreateTrigger()
private timer fireTimer
private timer launchTimer
private player owner
private unit caster
private integer casterId
private integer casterTypeId
private Table data
private real casterX
private real casterY
private real targetX
private real targetY
private real nextX
private real nextY
private real backswing
private integer remaining
method destroy takes nothing returns nothing
call UnitDisableAttack(.caster, 0, false)
//call UnitRemoveAbility(.caster, BUFF_BARRAGING)
call ReleaseTimer(.fireTimer)
call ReleaseTimer(.launchTimer)
set unit2thistype[.casterId] = 0
set .fireTimer = null
set .launchTimer = null
set .caster = null
call .deallocate()
endmethod
static method onImpact takes nothing returns nothing
local thistype this = missile2thistype[udg_Missile]
local real x = GetLocationX(udg_MissilePosition)
local real y = GetLocationY(udg_MissilePosition)
local integer damageBase = .data[DAMAGE_BASE]
local integer numberOfDice = .data[DAMAGE_NUMBER_OF_DICE]
local integer sidesPerDie = .data[DAMAGE_SIDES_PER_DIE]
local real radiusFull = .data.real[DAMAGE_RADIUS_FULL]
local real radiusMed = .data.real[DAMAGE_RADIUS_MEDIUM]
local real radiusSmall = .data.real[DAMAGE_RADIUS_SMALL]
local real damageFactorMed = .data.real[DAMAGE_FACTOR_MEDIUM]
local real damageFactorSmall = .data.real[DAMAGE_FACTOR_SMALL]
local real damage = DiceReal(damageBase, numberOfDice, sidesPerDie)
local attacktype attackType = ConvertAttackType(.data[ATTACK_TYPE])
set FilterPlayer = .owner
call UnitDamagePointSplash(udg_MissileSource, x, y, radiusFull, radiusMed, radiusSmall, /*
*/ damageFactorMed, damageFactorSmall, damage, attackType, FILTER_ALIVE_ENEMY_GROUND)
set missile2thistype[udg_Missile] = 0
endmethod
static method launchMissile takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set udg_MissileSource = .caster
set udg_MissileOwner = .owner
set udg_MissileStart = Location(GetUnitX(.caster), GetUnitY(.caster))
set udg_MissileStartZ = .data.real[MISSILE_LAUNCH_Z]
set udg_MissileFinish = Location(.nextX, .nextY)
set udg_MissileFinishZ = 0
set udg_MissileModel = .data.string[MISSILE_ART]
set udg_MissileScale = .data.real[MISSILE_SIZE]
set udg_MissileSpeed = .data.real[MISSILE_SPEED]
set udg_MissileArc = .data.real[MISSILE_ARC]
set udg_MissileRemoveLocations = true
set udg_Missile_onFinish = finishTrig
call MissileCreate()
set missile2thistype[udg_Missile] = this
endmethod
static method fireAtTarget takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real a
local real d
if (t != .fireTimer) then
call ReleaseTimer(t)
endif
set .remaining = .remaining - 1
if (.remaining == 0) then
call .destroy()
else
set a = GetRandomAngle()
set d = GetRandomReal(0, .data.real[BARRAGE_SCATTER_FACTOR] * .data.real[MAX_SCATTER_RADIUS])
set d = d * UnitDistanceToPoint(.caster, .targetX, .targetY) / .data.real[BARRAGE_MAX_RANGE]
set .nextX = .targetX + d * Cos(a)
set .nextY = .targetY + d * Sin(a)
call IssuePointOrderById(.caster, ORDER_CLOUDOFFOG, .targetX, .targetY)
call TimerStart(.launchTimer, .backswing, false, function thistype.launchMissile)
endif
set t = null
endmethod
static method onCastDeployed takes nothing returns nothing
local thistype this
if (UnitHasAbility(GetTriggerUnit(), ATTR_TOWED)) then
return
endif
set this = allocate()
set .fireTimer = NewTimer(this)
set .launchTimer = NewTimer(this)
set .owner = GetTriggerPlayer()
set .caster = GetTriggerUnit()
set .casterId = GetUnitId(.caster)
set .casterTypeId = GetUnitTypeId(.caster)
set .data = ArtilleryData[.casterTypeId]
set .casterX = GetUnitX(.caster)
set .casterY = GetUnitY(.caster)
set .targetX = GetSpellTargetX()
set .targetY = GetSpellTargetY()
set .backswing = GetUnitTypeAttackBackswing(.casterTypeId, 0)
set .remaining = .data[BARRAGE_SHELLS]
set unit2thistype[.casterId] = this
call UnitDisableAttack(.caster, 0, true)
//call DummyTargetCast(.owner, ABILITY_DISABLE_ATTACK_1, OrderId("silence"), .caster)
call TimerStart(NewTimer(this), 0, false, function thistype.fireAtTarget)
call TimerStart(.fireTimer, .data.real[BARRAGE_ATTACK_INTERVAL], true, function thistype.fireAtTarget)
endmethod
static method onCastTowed takes nothing returns nothing
local unit u = GetTriggerUnit()
local real x
local real y
if (GetSpellAbilityId() == ABILITY_ARTILLERY_BARRAGE and UnitHasAbility(u, ATTR_TOWED)) then
set x = GetSpellTargetX()
set y = GetSpellTargetY()
call IssueImmediateOrderById(u, ORDER_STOP)
call IssuePointOrderById(u, ORDER_DEATHANDDECAY, x, y)
endif
set u = null
endmethod
static method onCastQueue takes nothing returns nothing
local unit u = GetTriggerUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
call IssueImmediateOrderById(u, ORDER_STOP)
call IssueImmediateOrderById(u, ORDER_BEARFORM)
call BlzQueuePointOrderById(u, ORDER_BLIZZARD, x, y)
set u = null
endmethod
static method onOrder takes nothing returns nothing
local integer id = GetUnitId(GetTriggerUnit())
if (unit2thistype[id] > 0 and GetIssuedOrderId() != ORDER_CLOUDOFFOG) then
call unit2thistype[id].destroy()
endif
endmethod
static method onDeath takes nothing returns nothing
local integer id = GetUnitId(GetTriggerUnit())
if (unit2thistype[id] > 0) then
call unit2thistype[id].destroy()
endif
endmethod
static method checkRange takes nothing returns nothing
local integer abilityId = GetSpellAbilityId()
local unit u = GetTriggerUnit()
local real casterX
local real casterY
if ((not UnitHasAbility(u, ATTR_TOWED)) and (abilityId == ABILITY_ARTILLERY_BARRAGE)) then
set casterX = GetUnitX(u)
set casterY = GetUnitY(u)
if (DistanceWithin(casterX, casterY, GetSpellTargetX(), GetSpellTargetY(), MINIMUM_RANGE)) then
call TextTagError(GetTriggerPlayer(), "Too close!", casterX - 72, casterY, 80)
call IssueImmediateOrderById(u, ORDER_STOP)
call UnitResetAbilityCooldownTimed(u, abilityId, 0)
endif
endif
set u = null
endmethod
private static method onInit takes nothing returns nothing
// The instant a unit uses Artillery Barrage (without necessarily following through)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.checkRange)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function thistype.onCastTowed)
// Artillery Barrage has finished casting and will then begin to fire
call RegisterSpellEffectEvent(ABILITY_ARTILLERY_BARRAGE, function thistype.onCastDeployed)
// Unit is ordered to get in range and then use Artillery Barrage on target
call RegisterSpellEffectEvent(ABILITY_ARTILLERY_BARRAGE_Q, function thistype.onCastQueue)
// Actions that will cancel an ongoing barrage
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.onOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call TriggerAddCondition(finishTrig, function thistype.onImpact)
endmethod
endstruct
endscope
scope AirfieldRepair initializer Init
globals
private unit array DummyHealers
endglobals
private function CreateDummyHealer takes unit u returns nothing
call GetDummy(GetOwningPlayer(u), GetUnitX(u), GetUnitY(u), false)
call UnitAddAbility(Dummy, ABILITY_AIRFIELD_REPAIR)
call IssueImmediateOrderById(Dummy, OrderId("replenishlifeon"))
set DummyHealers[GetUnitId(u)] = Dummy
endfunction
private function OnConstructed takes nothing returns nothing
if (UnitHasAbility(GetConstructedStructure(), ATTR_REPAIRS_AIRCRAFT)) then
call CreateDummyHealer(GetConstructedStructure())
endif
endfunction
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
if (DummyHealers[GetUnitId(u)] != null) then
set u = DummyHealers[GetUnitId(u)]
call UnitRemoveAbility(u, ABILITY_AIRFIELD_REPAIR)
call ReleaseDummy(u)
endif
set u = null
endfunction
private function RepairsAircraftFilter takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ATTR_REPAIRS_AIRCRAFT)
endfunction
private function CreateDummyHealerEnum takes nothing returns nothing
call CreateDummyHealer(GetEnumUnit())
endfunction
private function DelayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, Filter(function RepairsAircraftFilter))
call ForGroup(ENUM_GROUP, function CreateDummyHealerEnum)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnConstructed)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope BarracksHeal initializer Init
globals
private unit array DummyHealers
endglobals
private function CreateDummyHealer takes unit u returns nothing
call GetDummy(GetOwningPlayer(u), GetUnitX(u), GetUnitY(u), false)
call UnitAddAbility(Dummy, ABILITY_BARRACKS_HEAL)
call IssueImmediateOrderById(Dummy, OrderId("replenishlifeon"))
set DummyHealers[GetUnitId(u)] = Dummy
endfunction
private function OnConstructed takes nothing returns nothing
if (UnitHasAbility(GetConstructedStructure(), ATTR_HEALS_INFANTRY)) then
call CreateDummyHealer(GetConstructedStructure())
endif
endfunction
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
if (DummyHealers[GetUnitId(u)] != null) then
set u = DummyHealers[GetUnitId(u)]
call UnitRemoveAbility(u, ABILITY_BARRACKS_HEAL)
call ReleaseDummy(u)
endif
set u = null
endfunction
private function HealsInfantryFilter takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ATTR_HEALS_INFANTRY)
endfunction
private function CreateDummyHealerEnum takes nothing returns nothing
call CreateDummyHealer(GetEnumUnit())
endfunction
private function DelayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, Filter(function HealsInfantryFilter))
call ForGroup(ENUM_GROUP, function CreateDummyHealerEnum)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnConstructed)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope BurstFire
globals
// If true, units' first attacks will have a
// random burst length
// If false, units will always fire their maximum
// burst length on their first attack
private constant boolean RANDOMIZE_FIRST_ATTACK = true
// Time between burst shots fired
private constant key BURST_INTERVAL
// Time after burst fire is complete
private constant key BURST_COOLDOWN
// Minimum and maximum amount of shots fired
// during a burst
// Each possible length is equally likely to occur
private constant key BURST_ROUNDS_MIN
private constant key BURST_ROUNDS_MAX
endglobals
private struct BurstFire extends array
private static HashTable data
private static method onAttacked takes nothing returns nothing
local unit attacker = GetAttacker()
local integer id = GetUnitTypeId(attacker)
local integer level
local integer max
if (data.has(id)) then
set level = GetUnitAbilityLevel(attacker, ABILITY_BURST_FIRE)
set max = data[id][BURST_ROUNDS_MAX]
if (level < max) then
call BlzSetUnitAttackCooldown(attacker, data[id].real[BURST_INTERVAL], 0)
call IncUnitAbilityLevel(attacker, ABILITY_BURST_FIRE)
else
call BlzSetUnitAttackCooldown(attacker, data[id].real[BURST_COOLDOWN], 0)
call SetUnitAbilityLevel(attacker, ABILITY_BURST_FIRE, 1 + GetRandomInt(0, max - data[id][BURST_ROUNDS_MIN]))
endif
endif
set attacker = null
endmethod
static if (RANDOMIZE_FIRST_ATTACK) then
private static method onIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer id = GetUnitTypeId(u)
local integer min
local integer max
if (data.has(id)) then
set min = data[id][BURST_ROUNDS_MIN]
set max = data[id][BURST_ROUNDS_MAX]
call SetUnitAbilityLevel(u, ABILITY_BURST_FIRE, 1 + GetRandomInt(0, max - min))
endif
set u = null
endmethod
endif
private static method setBurstFireProperties takes integer unitTypeId, real interval, real cooldown, integer min, integer max returns nothing
local Table data = thistype.data[unitTypeId]
set data.real[BURST_INTERVAL] = interval
set data.real[BURST_COOLDOWN] = cooldown
set data[BURST_ROUNDS_MIN] = min
set data[BURST_ROUNDS_MAX] = max
endmethod
private static method onInit takes nothing returns nothing
static if (RANDOMIZE_FIRST_ATTACK) then
call OnUnitIndex(function thistype.onIndex)
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function thistype.onAttacked)
set data = HashTable.create()
call setBurstFireProperties(UNIT_RIFLEMAN_UP, 0.15, 0.65, 3, 4)
call setBurstFireProperties(UNIT_RIFLEMAN_ARVN_UP, 0.15, 0.65, 3, 4)
call setBurstFireProperties(UNIT_BLUE_DRAGON_MARINE, 0.15, 0.65, 3, 4)
call setBurstFireProperties(UNIT_M60, 0.10, 1.50, 4, 8)
call setBurstFireProperties(UNIT_M60_V, 0.10, 1.50, 4, 8)
call setBurstFireProperties(UNIT_M61_VULCAN_GUN, 0.10, 10.00, 35, 45)
call setBurstFireProperties(UNIT_PILLBOX, 0.10, 1.11, 5, 8)
call setBurstFireProperties(UNIT_PILLBOX_UP, 0.10, 1.11, 5, 8)
call setBurstFireProperties(UNIT_REGULAR_UP, 0.24, 0.88, 2, 3)
call setBurstFireProperties(UNIT_GUERRILLA_UP, 0.24, 0.88, 2, 3)
call setBurstFireProperties(UNIT_RPK, 0.11, 1.50, 4, 8)
call setBurstFireProperties(UNIT_RPK_N, 0.11, 1.50, 4, 8)
call setBurstFireProperties(UNIT_MAXIM_D, 0.10, 1.55, 4, 6)
call setBurstFireProperties(UNIT_MAXIM_N_D, 0.10, 1.55, 4, 6)
call setBurstFireProperties(UNIT_SAPPER, 0.10, 4.00, 6, 10)
call setBurstFireProperties(UNIT_SAPPER_N, 0.10, 4.00, 6, 10)
call setBurstFireProperties(UNIT_ZSU57_TURRET, 0.50, 2.35, 8, 8)
call setBurstFireProperties(UNIT_SAM_VEHICLE_DEPLOYED, 1.00, 4.00, 2, 2)
call setBurstFireProperties(UNIT_MI4, 0.29, 3.10, 2, 2)
call setBurstFireProperties(UNIT_BUNKER, 0.10, 1.00, 5, 8)
call setBurstFireProperties(UNIT_MISSILE_LAUNCHER, 0.33, 3.00, 3, 3)
call setBurstFireProperties(UNIT_MISSILE_LAUNCHER_UP, 0.33, 3.00, 3, 3)
endmethod
endstruct
endscope
scope Cede initializer Init
private function Cede takes unit u, player p returns nothing
if (IsPlayerHere(p)) then
call SetUnitOwner(u, p, true)
if (UnitHasAbility(u, ATTR_PRODUCTION_BUILDING)) then
call UnitRemoveAbility(u, ABILITY_CEDE_NORTH)
call UnitRemoveAbility(u, ABILITY_CEDE_SOUTH)
endif
endif
endfunction
private function CedeRed takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_NORTH_VIETNAM)
endfunction
private function CedeBlue takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_US_BLUE)
endfunction
private function CedeYellow takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_SOUTH_VIETNAM)
endfunction
private function CedePink takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_VIETCONG_PINK)
endfunction
private function CedeGray takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_VIETCONG_GRAY)
endfunction
private function CedeLightBlue takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_US_LIGHT_BLUE)
endfunction
private function CedeDarkGreen takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_US_DARK_GREEN)
endfunction
private function CedeBrown takes nothing returns nothing
call Cede(GetTriggerUnit(), udg_PLAYER_VIETCONG_BROWN)
endfunction
private function MakeCedeAbilityPermanent takes unit u returns nothing
if (UnitHasAbility(u, ABILITY_CEDE_SOUTH)) then
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_BLUE)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_YELLOW)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_LIGHT_BLUE)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_DARK_GREEN)
elseif (UnitHasAbility(u, ABILITY_CEDE_NORTH)) then
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_RED)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_PINK)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_GRAY)
call UnitMakeAbilityPermanent(u, true, ABILITY_CEDE_BROWN)
endif
endfunction
private function OnUnitConstructed takes nothing returns nothing
call MakeCedeAbilityPermanent(GetTriggerUnit())
endfunction
private function MakeCedeAbilityPermanentFilter takes nothing returns nothing
call MakeCedeAbilityPermanent(GetFilterUnit())
endfunction
private function DelayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(EnumGroup, bj_mapInitialPlayableArea, Filter(function MakeCedeAbilityPermanentFilter))
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(t, Condition(function OnUnitConstructed))
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
call RegisterSpellEffectEvent(ABILITY_CEDE_RED, function CedeRed)
call RegisterSpellEffectEvent(ABILITY_CEDE_BLUE, function CedeBlue)
call RegisterSpellEffectEvent(ABILITY_CEDE_YELLOW, function CedeYellow)
call RegisterSpellEffectEvent(ABILITY_CEDE_PINK, function CedePink)
call RegisterSpellEffectEvent(ABILITY_CEDE_GRAY, function CedeGray)
call RegisterSpellEffectEvent(ABILITY_CEDE_LIGHT_BLUE, function CedeLightBlue)
call RegisterSpellEffectEvent(ABILITY_CEDE_DARK_GREEN, function CedeDarkGreen)
call RegisterSpellEffectEvent(ABILITY_CEDE_BROWN, function CedeBrown)
endfunction
endscope
scope ClearMines initializer Init
globals
private constant real AREA_OF_EFFECT = 500
private constant unittype IMMUNE_TO_MINES = UNIT_TYPE_SAPPER
endglobals
private function SetUnitImmuneToMines takes unit u, boolean immune returns nothing
if (immune) then
call UnitAddType(u, IMMUNE_TO_MINES)
else
call UnitRemoveType(u, IMMUNE_TO_MINES)
endif
endfunction
private function OnFinish takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer size
local integer i = 0
local integer cleared = 0
call SetUnitImmuneToMines(u, false)
call GroupEnumUnitsInRangeCollision(EnumGroup, GetUnitX(u), GetUnitY(u), AREA_OF_EFFECT, null)
set size = BlzGroupGetSize(EnumGroup)
loop
exitwhen (i == size)
set u = BlzGroupUnitAt(EnumGroup, i)
if (UnitHasAbility(u, ATTR_TRAP) and IsUnitEnemy(u,p)) then
call CreateTimedEffectAtPoint(SFX_MINE_REMOVED, GetUnitX(u), GetUnitY(u), 3)
call RemoveUnit(u)
set cleared = cleared + 1
endif
set i = i + 1
endloop
call StatsAddMinesCleared(p, cleared)
set u = null
endfunction
private function OnCast takes nothing returns nothing
if (GetSpellAbilityId() == ABILITY_CLEAR_MINES) then
call SetUnitImmuneToMines(GetTriggerUnit(), true)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, function OnCast)
call RegisterSpellEffectEvent(ABILITY_CLEAR_MINES, function OnFinish)
endfunction
endscope
scope FactoryRepair initializer Init
globals
private unit array DummyHealers
endglobals
private function CreateDummyHealer takes unit u returns nothing
call GetDummy(GetOwningPlayer(u), GetUnitX(u), GetUnitY(u), false)
call UnitAddAbility(Dummy, ABILITY_FACTORY_REPAIR)
call IssueImmediateOrderById(Dummy, OrderId("replenishlifeon"))
set DummyHealers[GetUnitId(u)] = Dummy
endfunction
private function OnConstructed takes nothing returns nothing
if (UnitHasAbility(GetConstructedStructure(), ATTR_REPAIRS_VEHICLES)) then
call CreateDummyHealer(GetConstructedStructure())
endif
endfunction
private function OnDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
if (DummyHealers[GetUnitId(u)] != null) then
set u = DummyHealers[GetUnitId(u)]
call UnitRemoveAbility(u, ABILITY_FACTORY_REPAIR)
call ReleaseDummy(u)
endif
set u = null
endfunction
private function OnDeindex takes nothing returns nothing
local unit u = GetIndexedUnit()
if (DummyHealers[GetUnitId(u)] != null) then
set u = DummyHealers[GetUnitId(u)]
call UnitRemoveAbility(u, ABILITY_FACTORY_REPAIR)
call ReleaseDummy(u)
endif
set u = null
endfunction
private function RepairsVehiclesFilter takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), ATTR_REPAIRS_VEHICLES)
endfunction
private function CreateDummyHealerEnum takes nothing returns nothing
call CreateDummyHealer(GetEnumUnit())
endfunction
private function DelayedInit takes nothing returns nothing
call GroupEnumUnitsInRect(ENUM_GROUP, bj_mapInitialPlayableArea, Filter(function RepairsVehiclesFilter))
call ForGroup(ENUM_GROUP, function CreateDummyHealerEnum)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnConstructed)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
call OnUnitDeindex(function OnDeindex)
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope FirstStrike initializer Init
globals
private constant real COOLDOWN = 15
private Table data
endglobals
private function Reset takes nothing returns nothing
local integer id = GetTimerData(GetExpiredTimer())
local unit u = GetUnitById(id)
// Do it this way because the icon is not properly returned to its "enabled" state
call UnitRemoveAbility(u, ABILITY_FIRST_STRIKE_1)
call UnitAddAbility(u, ABILITY_FIRST_STRIKE_1)
//call BlzUnitDisableAbility(GetUnitById(id), ABILITY_FIRST_STRIKE_1, false, false)
set u = null
endfunction
private function OnAttack takes nothing returns nothing
local unit u = GetAttacker()
local integer id
if ((UnitHasAbility(u, ABILITY_FIRST_STRIKE_1)) and (IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(u)))) then
call BlzUnitDisableAbility(u, ABILITY_FIRST_STRIKE_1, true, false)
set id = GetUnitId(u)
if (not data.timer.has(id)) then
set data.timer[id] = NewTimer(id)
endif
call TimerStart(data.timer[id], COOLDOWN, false, function Reset)
endif
set u = null
endfunction
/*
private function OnIndex takes nothing returns nothing
local unit u = GetIndexedUnit()
local integer id
if (UnitHasAbility(u, ABILITY_FIRST_STRIKE_1)) then
set id = GetUnitId(u)
set data.timer[id] = NewTimer(id)
endif
set u = null
endfunction
*/
private function OnDeindex takes nothing returns nothing
local integer id = GetIndexedUnitId()
if (data.timer[id] != null) then
call ReleaseTimer(data.timer[id])
endif
endfunction
private function Init takes nothing returns nothing
set data = Table.create()
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function OnAttack)
//call OnUnitIndex(function OnIndex)
call OnUnitDeindex(function OnDeindex)
endfunction
endscope
scope ForceMove initializer Init
private function OnCast takes nothing returns nothing
local unit u = GetTriggerUnit()
call IssueImmediateOrder(u, "unbearform")
call LogB(BlzQueuePointOrderById(u, ORDER_MOVE, GetOrderPointX(), GetOrderPointY()))
set u = null
endfunction
private function Init takes nothing returns nothing
//call RegisterSpellEffectEvent('A02J', function OnCast)
call RegisterPointOrderEvent(ORDER_SMART, function OnCast)
endfunction
endscope
scope MassControl
private struct MassControl extends array
static unit array control
static group array selected
private static method attack takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local real x
local real y
local unit target = GetSpellTargetUnit()
local unit u
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
if (target == null) then
set x = GetSpellTargetX()
set y = GetSpellTargetY()
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssuePointOrderById(u, ORDER_ATTACK, x, y)
endif
set i = i + 1
endloop
else
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssueTargetOrderById(u, ORDER_ATTACK, target)
endif
set i = i + 1
endloop
endif
set target = null
set u = null
endmethod
private static method stop takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
local unit u
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssueImmediateOrderById(u, ORDER_STOP)
endif
set i = i + 1
endloop
set u = null
endmethod
private static method holdPosition takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
local unit u
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssueImmediateOrderById(u, ORDER_HOLDPOSITION)
endif
set i = i + 1
endloop
set u = null
endmethod
private static method move takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local real x
local real y
local unit target = GetSpellTargetUnit()
local unit u
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
if (target == null) then
set x = GetSpellTargetX()
set y = GetSpellTargetY()
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssuePointOrderById(u, ORDER_MOVE, x, y)
endif
set i = i + 1
endloop
else
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(selected[id], i)
if (not IsUnitBusy(u)) then
call IssueTargetOrderById(u, ORDER_MOVE, target)
endif
set i = i + 1
endloop
endif
set target = null
set u = null
endmethod
private static method clear takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
call GroupClear(selected[id])
call BlzSetUnitName(control[id], "|cffffcc00Selected:|r 0")
endmethod
private static method exitFoxhole takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
loop
exitwhen (i >= size)
call IssueImmediateOrderById(BlzGroupUnitAt(selected[id], i), ORDER_HOWLOFTERROR)
set i = i + 1
endloop
endmethod
private static method digIn takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer size = BlzGroupGetSize(selected[id])
local integer i = 0
loop
exitwhen (i >= size)
call IssueImmediateOrderById(BlzGroupUnitAt(selected[id], i), ORDER_DIVINESHIELD)
set i = i + 1
endloop
endmethod
private static method selectInRange takes player p, real x, real y, real radius returns nothing
local integer size
local unit u
local integer id = GetPlayerId(p)
local integer i = 0
call GroupClear(selected[id])
call GroupEnumUnitsInRangeCollision(ENUM_GROUP, x, y, radius, null)
set size = BlzGroupGetSize(ENUM_GROUP)
loop
exitwhen (i >= size)
set u = BlzGroupUnitAt(ENUM_GROUP, i)
if ((GetOwningPlayer(u) == p) and (IsCombatUnit(u))) then
call GroupAddUnit(selected[id], u)
endif
set i = i + 1
endloop
call BlzSetUnitName(control[id], "|cffffcc00Selected:|r " + I2S(BlzGroupGetSize(selected[id])))
set u = null
endmethod
private static method selectUnits takes nothing returns nothing
local real radius = BlzGetAbilityRealLevelField(BlzGetUnitAbility(GetTriggerUnit(), GetSpellAbilityId()), ABILITY_RLF_AREA_OF_EFFECT, 0)
call selectInRange(GetTriggerPlayer(), GetSpellTargetX(), GetSpellTargetY(), radius)
endmethod
private static method selectAll takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer size = BlzGroupGetSize(PlayerCombatUnits[id])
local integer i = 0
call GroupClear(selected[id])
loop
exitwhen (i >= size)
call GroupAddUnit(selected[id], BlzGroupUnitAt(PlayerCombatUnits[id], i))
set i = i + 1
endloop
call BlzSetUnitName(control[id], "|cffffcc00Selected:|r " + I2S(BlzGroupGetSize(selected[id])))
endmethod
private static method selectController takes nothing returns nothing
local player p = GetTriggerPlayer()
if ((not IsPlayerInForce(p, udg_ObserversAll)) and (PLAYER_LOCAL == p)) then
call ClearSelection()
call SelectUnit(control[GetPlayerId(p)], true)
endif
endmethod
private static method onDeath takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetPlayerId(GetTriggerPlayer())
if (IsUnitInGroup(u, selected[id])) then
call GroupRemoveUnit(selected[id], u)
call BlzSetUnitName(control[id], "|cffffcc00Selected:|r " + I2S(BlzGroupGetSize(selected[id])))
endif
set u = null
endmethod
private static method delayedInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
if (IsPlayerHere(Player(i))) then
call BlzTriggerRegisterPlayerKeyEvent(t, Player(i), OSKEY_F1, 0, true)
set control[i] = CreateUnit(Player(i), DUMMY_MASS_CONTROLLER, WorldBounds.minX, WorldBounds.minY, 0)
set selected[i] = CreateGroup()
endif
set i = i + 1
exitwhen (i > bj_MAX_PLAYERS)
endloop
call TriggerAddCondition(t, function thistype.selectController)
call ReleaseTimer(GetExpiredTimer())
set t = null
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call RegisterSpellEffectEvent(ABILITY_MASS_SELECT_SMALL, function thistype.selectUnits)
call RegisterSpellEffectEvent(ABILITY_MASS_SELECT_MEDIUM, function thistype.selectUnits)
call RegisterSpellEffectEvent(ABILITY_MASS_SELECT_LARGE, function thistype.selectUnits)
call RegisterSpellEffectEvent(ABILITY_MASS_SELECT_ALL, function thistype.selectAll)
call RegisterSpellEffectEvent(ABILITY_MASS_ATTACK, function thistype.attack)
call RegisterSpellEffectEvent(ABILITY_MASS_STOP, function thistype.stop)
call RegisterSpellEffectEvent(ABILITY_MASS_HOLD_POSITION, function thistype.holdPosition)
call RegisterSpellEffectEvent(ABILITY_MASS_MOVE, function thistype.move)
call RegisterSpellEffectEvent(ABILITY_MASS_CLEAR, function thistype.clear)
call RegisterSpellEffectEvent(ABILITY_MASS_EXIT_FOXHOLE, function thistype.exitFoxhole)
call RegisterSpellEffectEvent(ABILITY_MASS_DIG_IN, function thistype.digIn)
call TimerStart(NewTimer(0), 0, false, function thistype.delayedInit)
endmethod
endstruct
function RemoveMassController takes player p returns nothing
local integer id = GetPlayerId(p)
call RemoveUnit(MassControl.control[id])
call DestroyGroup(MassControl.selected[id])
endfunction
endscope
scope Relocate initializer Init
globals
private constant real CAST_TIME = 30.0
private Table Data
endglobals
private function OnCancel takes nothing returns nothing
local unit u = GetCancelledStructure()
local integer typeId = GetUnitTypeId(u)
if (UnitHasAbility(u, ATTR_BUILT_BY_TRUCK)) then
if (IsUnitInForce(u, udg_AmericanAll)) then
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(u), UNIT_TRUCK_A, GetUnitX(u), GetUnitY(u), bj_UNIT_FACING)
else
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(u), UNIT_TRUCK_V, GetUnitX(u), GetUnitY(u), bj_UNIT_FACING)
endif
call UnitAddAbility(bj_lastCreatedUnit, Data[typeId])
endif
set u = null
endfunction
private function CreateTruck takes unit u, integer truckId, integer abilityId returns nothing
call ShowUnit(u, false)
set bj_lastCreatedUnit = CreateUnit(GetOwningPlayer(u), truckId, GetUnitX(u), GetUnitY(u), bj_UNIT_FACING)
call UnitAddAbility(bj_lastCreatedUnit, abilityId)
call ShowUnit(u, true)
call UnitAddAbility(u, ATTR_IGNORE_DEATH)
call KillUnit(u)
call RemoveUnit(u)
endfunction
private function RelocateA takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitTypeId(u)
call CreateTruck(u, UNIT_TRUCK_A, Data[id])
set u = null
endfunction
private function RelocateV takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer id = GetUnitTypeId(u)
call CreateTruck(u, UNIT_TRUCK_V, Data[id])
set u = null
endfunction
private function Build takes nothing returns nothing
call UnitRemoveTimed(GetTriggerUnit(), 0)
endfunction
private function LinkBuildingAbility takes integer buildingId, integer truckBuildingId, integer abilityId returns nothing
set Data[buildingId] = abilityId
set Data[truckBuildingId] = abilityId
call RegisterSpellEffectEvent(abilityId, function Build)
endfunction
private function OnCast takes nothing returns nothing
local integer id = GetSpellAbilityId()
if ((id == ABILITY_RELOCATE_A) or (id == ABILITY_RELOCATE_V)) then
call CreateTextTagTimer(GetTriggerUnit(), CAST_TIME)
endif
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function OnCast)
call RegisterSpellEffectEvent(ABILITY_RELOCATE_A, function RelocateA)
call RegisterSpellEffectEvent(ABILITY_RELOCATE_V, function RelocateV)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function OnCancel)
set Data = Table.create()
call LinkBuildingAbility(UNIT_AIRFIELD_A, UNIT_AIRFIELD_A_TRUCK, ABILITY_BUILD_AIRFIELD_A)
call LinkBuildingAbility(UNIT_AIRFIELD_V, UNIT_AIRFIELD_V_TRUCK, ABILITY_BUILD_AIRFIELD_V)
call LinkBuildingAbility(UNIT_BARRACKS_A, UNIT_BARRACKS_A_TRUCK, ABILITY_BUILD_BARRACKS_A)
call LinkBuildingAbility(UNIT_BARRACKS_V, UNIT_BARRACKS_V_TRUCK, ABILITY_BUILD_BARRACKS_V)
call LinkBuildingAbility(UNIT_BUNKER, UNIT_BUNKER_TRUCK, ABILITY_BUILD_BUNKER)
call LinkBuildingAbility(UNIT_COMMAND_HQ_A, UNIT_COMMAND_HQ_A_TRUCK, ABILITY_BUILD_COMMAND_HQ_A)
call LinkBuildingAbility(UNIT_COMMAND_HQ_N, UNIT_COMMAND_HQ_N_TRUCK, ABILITY_BUILD_COMMAND_HQ_N)
call LinkBuildingAbility(UNIT_COMMAND_HQ_V, UNIT_COMMAND_HQ_V_TRUCK, ABILITY_BUILD_COMMAND_HQ_V)
call LinkBuildingAbility(UNIT_DROP_ZONE, UNIT_DROP_ZONE_TRUCK, ABILITY_BUILD_DROP_ZONE)
call LinkBuildingAbility(UNIT_FACTORY_A, UNIT_FACTORY_A_TRUCK, ABILITY_BUILD_FACTORY_A)
call LinkBuildingAbility(UNIT_FACTORY_V, UNIT_FACTORY_V_TRUCK, ABILITY_BUILD_FACTORY_V)
call LinkBuildingAbility(UNIT_GUERRILLA_CAMP, UNIT_GUERRILLA_CAMP_TRUCK, ABILITY_BUILD_GUERRILLA_CAMP)
call LinkBuildingAbility(UNIT_HELIPAD, UNIT_HELIPAD_TRUCK, ABILITY_BUILD_HELIPAD)
call LinkBuildingAbility(UNIT_STRATEGY_CENTER, UNIT_STRATEGY_CENTER_TRUCK, ABILITY_BUILD_STRATEGY_CENTER)
call LinkBuildingAbility(UNIT_UTILITY, UNIT_UTILITY_TRUCK, ABILITY_BUILD_UTILITY)
call LinkBuildingAbility(UNIT_ZPU_4, UNIT_ZPU_4_TRUCK, ABILITY_BUILD_ZPU_4)
endfunction
endscope
scope SnipeAbility initializer Init
globals
private unit array Target
private integer array Ticks
// Number of times the sniper must "attack" its target
// to snipe it; the time it takes to do this is the
// value of this constant times the unit's cooldown
private constant integer TICKS_TO_SNIPE = 3
endglobals
private function OnAttack takes nothing returns nothing
local integer id
local unit sniper
if (not UnitHasAbility(GetAttacker(), ATTR_SNIPER)) then
return
endif
set sniper = GetAttacker()
set id = GetUnitId(sniper)
if (Target[id] != GetTriggerUnit()) then
set Target[id] = GetTriggerUnit()
set Ticks[id] = 0
else
set Ticks[id] = Ticks[id] + 1
if (Ticks[id] > TICKS_TO_SNIPE) then
call IssueTargetOrder(sniper, "acidbomb", Target[id])
endif
endif
set sniper = null
endfunction
private function OnOrder takes nothing returns nothing
local integer id
if (not UnitHasAbility(GetTriggerUnit(), ATTR_SNIPER)) then
return
endif
set id = GetUnitId(GetTriggerUnit())
set Target[id] = null
set Ticks[id] = 0
endfunction
private function OnSnipe takes nothing returns nothing
local unit sniper = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
// If the target is in a Foxhole, ungarrison it
call FoxholeRemoveUnit(target)
// Cause the sniper to damage the target so it gets
// credit for the kill
call UnitDamageTarget(sniper, target, GetWidgetLife(target), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
call IssueImmediateOrderByIdDelayed(sniper, ORDER_HOLDPOSITION, 0.25)
set sniper = null
set target = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function OnOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function OnOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function OnOrder)
call RegisterSpellEffectEvent(ABILITY_SNIPE_A, function OnSnipe)
call RegisterSpellEffectEvent(ABILITY_SNIPE_V, function OnSnipe)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function OnAttack)
endfunction
endscope
scope Suppression initializer Init
globals
private constant real COOLDOWN = 2.50
endglobals
private function OnDamaged takes nothing returns nothing
local unit source
local unit target = BlzGetEventDamageTarget()
if (UnitHasAbility(target, BUFF_SUPPRESSION_INITIAL)) then
set source = GetEventDamageSource()
call UnitRemoveAbility(target, BUFF_SUPPRESSION_INITIAL)
if (BlzGetUnitAbilityCooldownRemaining(source, ABILITY_SUPPRESSION_INITIAL) == 0) then
call BlzStartUnitAbilityCooldown(source, ABILITY_SUPPRESSION_INITIAL, COOLDOWN)
if (not UnitHasAbility(target, BUFF_SUPPRESSION_SUBSEQUENT)) then
call DummyTargetCast(GetOwningPlayer(source), ABILITY_SUPPRESSION_SUBSEQUENT, ORDER_ACIDBOMB, target)
endif
endif
endif
set source = null
set target = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnDamaged)
endfunction
endscope
scope WeaponAttachments
private struct WeaponAttachment extends array
implement Alloc
implement Iterator
// Maximum number of ticks the secondary weapon can go without
// dealing damage before it will attempt to acquire a new target
private static constant integer TICKS_TO_RETARGET = 60
private static constant real UPDATE_INTERVAL = 1./60
// Populated in method onInit
private static HashTable data
// Keys for the data table
private static key KEY_PRIMARY_WEAPON_ID
private static key KEY_SECONDARY_WEAPON_ID
// x2thistype[x unit index] = this
private static thistype array vehicle2thistype
private static thistype array primary2thistype
private static thistype array secondary2thistype
private unit vehicle
// Rotating weapon, typically the turret or pintle machine gun
private unit primary
// Static front-facing weapon, typically the hull machine gun
private unit secondary
private real attackRange
private unit target
private integer ticks
private boolean ignore
private trigger onAcquireTrig
// Fires when a weapon is ordered to move for whatever reason
private trigger onMoveTrig
// Fires when the vehicle is ordered to attack,
// forcing the primary weapon to attack the target
private trigger onAttackTrig
// Fires when the vehicle is ordered to stop
private trigger onVehicleStopTrig
method update takes nothing returns nothing
local real x
local real y
local real facing
if (UnitAlive(.vehicle)) then
set x = GetUnitX(.vehicle)
set y = GetUnitY(.vehicle)
set facing = GetUnitFacing(.vehicle)
if (.primary != null) then
call SetUnitX(.primary, x)
call SetUnitY(.primary, y)
if (.target != null) then
call SetUnitFacing(.primary, UnitAngleToUnitDeg(.primary, .target))
if (not (IsUnitInRangeXY(.target, x, y, .attackRange)) or not (UnitAlive(.target))) then
set .target = null
endif
else
call IssueImmediateOrderById(.primary, ORDER_STOP)
if (RAbsBJ(GetUnitFacing(.primary) - facing) < 5) then
call BlzSetUnitFacingEx(.primary, facing)
else
call SetUnitFacing(.primary, facing)
endif
endif
endif
if (.secondary != null) then
call SetUnitX(.secondary, x)
call SetUnitY(.secondary, y)
call BlzSetUnitFacingEx(.secondary, facing)
endif
set .ticks = .ticks + 1
if (.ticks > TICKS_TO_RETARGET) then
// FIXME
// Acquire new target
//call UnitDisableAttackTimed(.secondary, 0)
// try something like attack nearest enemy near point
set .ticks = 0
endif
else
call .finalize()
endif
endmethod
static method onVehicleStopOrder takes nothing returns nothing
local thistype this = vehicle2thistype[GetUnitId(GetTriggerUnit())]
if (GetIssuedOrderId() == ORDER_STOP and not .ignore) then
call IssueImmediateOrderById(.primary, ORDER_STOP)
set .target = null
endif
set .ignore = false
endmethod
static method onWeaponMoveOrder takes nothing returns nothing
if (GetIssuedOrderId() == ORDER_MOVE) then
// Prevents the weapon from forever trying to complete a move order
call IssueImmediateOrderByIdDelayed(GetTriggerUnit(), ORDER_STOP, 0)
endif
endmethod
static method onPrimaryAttack takes nothing returns nothing
local unit source = GetAttacker()
local unit target
local thistype this = primary2thistype[GetUnitId(source)]
if (this != 0) then
set target = GetTriggerUnit()
call IssueTargetOrderById(source, ORDER_ATTACK, target)
set .target = target
endif
set source = null
set target = null
endmethod
static method onAttackOrder takes nothing returns nothing
local thistype this = vehicle2thistype[GetUnitId(GetTriggerUnit())]
local unit target = GetOrderTargetUnit()
if (GetIssuedOrderId() == ORDER_ATTACK or (GetIssuedOrderId() == ORDER_SMART and IsUnitEnemy(target, GetTriggerPlayer()))) then
set .target = target
call IssueTargetOrderById(.primary, ORDER_ATTACK, target)
// Prevent vehicle from facing its target if it's in range
if (IsUnitInRange(.primary, target, .attackRange)) then
set .ignore = true
call IssueImmediateOrderByIdDelayed(.vehicle, ORDER_STOP, 0)
endif
endif
set target = null
endmethod
static method onAcquire takes nothing returns nothing
local thistype this = primary2thistype[GetUnitId(GetTriggerUnit())]
set .target = GetEventTargetUnit()
endmethod
static method create takes nothing returns thistype
local unit u = GetIndexedUnit()
local integer typeId = GetUnitTypeId(u)
local integer unitId
local player p
local real x
local real y
local real facing
local thistype this
// Only run if this unit type has an associated weapon attachment
if (not data.has(typeId)) then
set u = null
return 0
endif
set unitId = GetUnitId(u)
set this = allocate()
set p = GetOwningPlayer(u)
set x = GetUnitX(u)
set y = GetUnitY(u)
set facing = GetUnitFacing(u)
set .vehicle = u
if (data[typeId].has(KEY_PRIMARY_WEAPON_ID)) then
set .primary = CreateUnit(p, data[typeId][KEY_PRIMARY_WEAPON_ID], x, y, facing)
set primary2thistype[GetUnitId(.primary)] = this
set .attackRange = GetUnitAcquireRange(.primary)
call RemoveGuardPosition(.primary) // Prevent weapons from trying to move back to wherever they were created
set .onAcquireTrig = CreateTrigger()
call TriggerRegisterUnitEvent(.onAcquireTrig, .primary, EVENT_UNIT_ACQUIRED_TARGET)
call TriggerAddCondition(.onAcquireTrig, function thistype.onAcquire)
set .onMoveTrig = CreateTrigger()
call TriggerRegisterUnitEvent(.onMoveTrig, .primary, EVENT_UNIT_ISSUED_POINT_ORDER)
else
set .attackRange = 0
endif
if (data[typeId].has(KEY_SECONDARY_WEAPON_ID)) then
set .secondary = CreateUnit(p, data[typeId][KEY_SECONDARY_WEAPON_ID], x, y, facing)
set secondary2thistype[GetUnitId(.secondary)] = this
call RemoveGuardPosition(.secondary)
if (.onMoveTrig == null) then
set .onMoveTrig = CreateTrigger()
endif
call TriggerRegisterUnitEvent(.onMoveTrig, .secondary, EVENT_UNIT_ISSUED_POINT_ORDER)
endif
set .target = null
set .ignore = false
// Provide access to this instance through vehicle and weapons unit index
set vehicle2thistype[unitId] = this
if (.onMoveTrig != null) then
call TriggerAddCondition(.onMoveTrig, function thistype.onWeaponMoveOrder)
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function thistype.onPrimaryAttack)
set .onAttackTrig = CreateTrigger()
call TriggerRegisterUnitEvent(.onAttackTrig, .vehicle, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(.onAttackTrig, function thistype.onAttackOrder)
set .onVehicleStopTrig = CreateTrigger()
call TriggerRegisterUnitEvent(.onVehicleStopTrig, .vehicle, EVENT_UNIT_ISSUED_ORDER)
call TriggerAddCondition(.onVehicleStopTrig, function thistype.onVehicleStopOrder)
call .listAdd()
set u = null
return this
endmethod
method destroy takes nothing returns nothing
set vehicle2thistype[GetUnitId(.vehicle)] = 0
set .vehicle = null
if (.primary != null) then
set primary2thistype[GetUnitId(.primary)] = 0
call KillUnit(.primary)
set .primary = null
endif
if (.secondary != null) then
set secondary2thistype[GetUnitId(.secondary)] = 0
call KillUnit(.secondary)
set .secondary = null
endif
if (.onAcquireTrig != null) then
call DestroyTrigger(.onAcquireTrig)
set .onAcquireTrig = null
endif
if (.onMoveTrig != null) then
call DestroyTrigger(.onMoveTrig)
set .onMoveTrig = null
endif
if (.onAttackTrig != null) then
call DestroyTrigger(.onAttackTrig)
set .onAttackTrig = null
endif
call DestroyTrigger(.onVehicleStopTrig)
set .onVehicleStopTrig = null
set .target = null
call .deallocate()
endmethod
private static method onInit takes nothing returns nothing
set data = HashTable.create()
// Configuration
set data[UNIT_APC_M113] [KEY_PRIMARY_WEAPON_ID] = UNIT_APC_M113_MG
set data[UNIT_BTR60] [KEY_PRIMARY_WEAPON_ID] = UNIT_BTR60_MG
set data[UNIT_M48_PATTON] [KEY_PRIMARY_WEAPON_ID] = UNIT_M48_PATTON_TURRET
set data[UNIT_M48_PATTON] [KEY_SECONDARY_WEAPON_ID] = UNIT_M48_PATTON_MG
set data[UNIT_M67_ZIPPO] [KEY_PRIMARY_WEAPON_ID] = UNIT_M67_ZIPPO_TURRET
set data[UNIT_M67_ZIPPO] [KEY_SECONDARY_WEAPON_ID] = UNIT_M67_ZIPPO_MG
set data[UNIT_T34] [KEY_PRIMARY_WEAPON_ID] = UNIT_T34_TURRET
set data[UNIT_T34] [KEY_SECONDARY_WEAPON_ID] = UNIT_T34_MG
set data[UNIT_T54] [KEY_PRIMARY_WEAPON_ID] = UNIT_T54_TURRET
set data[UNIT_T62] [KEY_PRIMARY_WEAPON_ID] = UNIT_T62_TURRET
set data[UNIT_T62] [KEY_SECONDARY_WEAPON_ID] = UNIT_T62_MG
set data[UNIT_ZSU57] [KEY_PRIMARY_WEAPON_ID] = UNIT_ZSU57_TURRET
// ----
call OnUnitIndex(function thistype.create)
endmethod
endstruct
endscope
library TimerUpdate initializer init
globals
integer GameTimeSec = 1
endglobals
function Sec2Timer takes integer i returns string
local integer timeSec = i
local integer timeMin = 0
local string timeString = ""
set timeMin = timeSec / 60
set timeSec = timeSec - (timeMin * 60)
if timeMin < 10 then
set timeString = "0" + I2S(timeMin) + ":"
else
set timeString = I2S(timeMin) + ":"
endif
if timeSec < 10 then
set timeString = timeString + "0" + I2S(timeSec)
else
set timeString = timeString + I2S(timeSec)
endif
return timeString
endfunction
private function periodic takes nothing returns nothing
local framehandle timerTextFrame = BlzGetFrameByName("ResourceBarUpkeepText", 0)
set GameTimeSec = (GameTimeSec + 1)
call BlzFrameSetText(timerTextFrame, Sec2Timer(GameTimeSec))
endfunction
private function init takes nothing returns nothing
call TimerStart(CreateTimer(), 1, true, function periodic)
endfunction
endlibrary
function UISetup takes nothing returns nothing
//Local Variables
//local framehandle fh = null
//local framehandle chatButton = null
local framehandle questButton = null
//local framehandle allyButton = null
//local framehandle MiniMap = null
//local framehandle gridButtons = null
//local framehandle imageTest = BlzCreateFrameByType("BACKDROP", "image", BlzGetFrameByName("ConsoleUIBackdrop", 0), "ButtonBackdropTemplate", 0)
/*
//Top UI & System Buttons
set fh = BlzGetFrameByName("UpperButtonBarFrame", 0)
call BlzFrameSetVisible(fh, true)
set allyButton = BlzGetFrameByName("UpperButtonBarAlliesButton", 0)
set fh = BlzGetFrameByName("UpperButtonBarMenuButton", 0)
set chatButton = BlzGetFrameByName("UpperButtonBarChatButton", 0)
set questButton = BlzGetFrameByName("UpperButtonBarQuestsButton", 0)
call BlzFrameClearAllPoints(fh)
call BlzFrameClearAllPoints(allyButton)
call BlzFrameClearAllPoints(chatButton)
call BlzFrameClearAllPoints(questButton)
call BlzFrameSetAbsPoint(questButton, FRAMEPOINT_TOPLEFT, 0.77, 0.6)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPLEFT, 0.85, 0.6)
call BlzFrameSetAbsPoint(allyButton, FRAMEPOINT_TOPLEFT, 0.77, 0.583)
call BlzFrameSetAbsPoint(chatButton, FRAMEPOINT_TOPLEFT, 0.85, 0.583)
//Hiding clock UI and creating new frame bar
call BlzFrameSetTexture(imageTest, "UI\\ResourceBar.tga", 0, true)
call BlzFrameSetPoint(imageTest, FRAMEPOINT_TOP, BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME, 0), FRAMEPOINT_TOP, 0, 0)
call BlzFrameSetSize(imageTest, 0.4, 0.025)
call BlzFrameSetVisible(BlzFrameGetChild(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 5), 0), false)
call BlzFrameSetLevel(imageTest, 1)
//Food
set fh = BlzGetFrameByName("ResourceBarSupplyText", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.58, 0.5965)
//Upkeep
set fh = BlzGetFrameByName("ResourceBarUpkeepText", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.295, 0.5965)
//Gold
set fh = BlzGetFrameByName("ResourceBarGoldText", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.389, 0.5965)
//Lumber
set fh = BlzGetFrameByName("ResourceBarLumberText", 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.485, 0.5965)
//Bottom UI & Idle Worker Icon
set fh = BlzGetFrameByName("ConsoleUI", 0)
set fh = BlzFrameGetChild(fh, 7)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.09, 0.179)
//Remove Deadspace
set fh = BlzGetFrameByName("ConsoleUI", 0)
call BlzFrameSetVisible(BlzFrameGetChild(fh, 5), false)
//Minimap
set MiniMap = BlzGetFrameByName("MiniMapFrame", 0)
call BlzFrameSetVisible(MiniMap, true)
call BlzFrameClearAllPoints(MiniMap)
call BlzFrameSetAbsPoint(MiniMap, FRAMEPOINT_BOTTOMLEFT, 0.0525, 0.0)
call BlzFrameSetAbsPoint(MiniMap, FRAMEPOINT_TOPRIGHT, 0.2125, 0.141)
//Minimap Buttons
set fh = BlzGetFrameByName("MinimapSignalButton", 0)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_BOTTOMLEFT, 0.222, 0.116)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.242, 0.136)
call BlzFrameSetTexture(fh, "UI\\ButtonBorder.dds", 0, true)
set fh = BlzGetFrameByName("MiniMapAllyButton", 0)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_BOTTOMLEFT, 0.242, 0.116)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.262, 0.136)
call BlzFrameSetTexture(fh, "UI\\ButtonBorder.dds", 0, true)
set fh = BlzGetFrameByName("MiniMapTerrainButton", 0)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_BOTTOMLEFT, 0.262, 0.116)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.282, 0.136)
call BlzFrameSetTexture(fh, "UI\\ButtonBorder.dds", 0, true)
set fh = BlzGetFrameByName("MiniMapCreepButton", 0)
call BlzFrameSetVisible(fh, false)
set fh = BlzGetFrameByName("FormationButton", 0)
call BlzFrameSetVisible(fh, false)
//Minimap Border
set fh = BlzCreateFrameByType("BACKDROP", "MinimapBorder", MiniMap, "", 0)
call BlzFrameSetPoint(fh, FRAMEPOINT_TOPLEFT, MiniMap, FRAMEPOINT_TOPLEFT, 0, 0)
call BlzFrameSetPoint(fh, FRAMEPOINT_BOTTOMRIGHT, MiniMap, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
call BlzFrameSetTexture(fh, "UI\\MiniMapBorder.dds", 0, true)
//Tooltips
set fh = BlzGetOriginFrame(ORIGIN_FRAME_TOOLTIP, 0)
call BlzFrameSetVisible(fh, true)
set fh = BlzGetOriginFrame(ORIGIN_FRAME_UBERTOOLTIP, 0)
call BlzFrameSetVisible(fh, true)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_BOTTOMRIGHT, 0.7725, 0.141)
//Command Buttons
set gridButtons = BlzGetFrameByName("CommandBarFrame", 0)
call BlzFrameSetVisible(gridButtons, true)
call BlzFrameClearAllPoints(gridButtons)
call BlzFrameSetAbsPoint(gridButtons, FRAMEPOINT_BOTTOMLEFT, 0.5950, 0.005)
//Backdrop
set fh = BlzGetFrameByName("ConsoleUIBackdrop", 0)
call BlzFrameClearAllPoints(fh)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_BOTTOMLEFT, 0.052, 0)
call BlzFrameSetAbsPoint(fh, FRAMEPOINT_TOPRIGHT, 0.770, 0.141)
//Command buttons border
set fh = BlzCreateFrameByType("BACKDROP", "CommandBorder", MiniMap, "", 0)
call BlzFrameSetPoint(fh, FRAMEPOINT_TOPLEFT, gridButtons, FRAMEPOINT_TOPLEFT, -0.007, 0.007)
call BlzFrameSetPoint(fh, FRAMEPOINT_BOTTOMRIGHT, gridButtons, FRAMEPOINT_BOTTOMRIGHT, 0.0025, -0.005)
call BlzFrameSetTexture(fh, "UI\\CommandCard.dds", 0, true)
*/
// Prevent multiplayer desyncs by forcing the creation of the QuestDialog frame
call BlzFrameClick(BlzGetFrameByName("UpperButtonBarQuestsButton", 0))
call ForceUICancel()
// Expand TextArea
call BlzFrameSetPoint(BlzGetFrameByName("QuestDisplay", 0), FRAMEPOINT_TOPLEFT, BlzGetFrameByName("QuestDetailsTitle", 0), FRAMEPOINT_BOTTOMLEFT, 0.003, -0.003)
call BlzFrameSetPoint(BlzGetFrameByName("QuestDisplay", 0), FRAMEPOINT_BOTTOMRIGHT, BlzGetFrameByName("QuestDisplayBackdrop", 0), FRAMEPOINT_BOTTOMRIGHT, -0.003, 0.)
// Relocate button
call BlzFrameSetPoint(BlzGetFrameByName("QuestDisplayBackdrop", 0), FRAMEPOINT_BOTTOM, BlzGetFrameByName("QuestBackdrop", 0), FRAMEPOINT_BOTTOM, 0., 0.017)
call BlzFrameClearAllPoints(BlzGetFrameByName("QuestAcceptButton", 0))
call BlzFrameSetPoint(BlzGetFrameByName("QuestAcceptButton", 0), FRAMEPOINT_TOPRIGHT, BlzGetFrameByName("QuestBackdrop", 0), FRAMEPOINT_TOPRIGHT, -0.016, -0.016)
call BlzFrameSetText(BlzGetFrameByName("QuestAcceptButton", 0), "×")
call BlzFrameSetSize(BlzGetFrameByName("QuestAcceptButton", 0), 0.03, 0.03)
/*
// Add back ally resource icons
call BlzFrameSetTexture(BlzGetFrameByName("InfoPanelIconAllyGoldIcon", 7), "UI\\RGReplacement.dds", 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("InfoPanelIconAllyWoodIcon", 7), "UI\\RLReplacement.dds", 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("InfoPanelIconAllyFoodIcon", 7), "UI\\RSReplacement.dds", 0, false)
*/
call ReleaseTimer(GetExpiredTimer())
endfunction
scope init initializer Init
private function Init takes nothing returns nothing
call TimerStart(NewTimer(0), 0, false, function UISetup)
endfunction
endscope
scope Income initializer Init
globals
// Redefined so the constant can exist here as well as publicly in GUI
// Make sure they match
private constant real SECONDS_PER_MONTH = 40.0
// How often you earn money in seconds
private constant real INCOME_INTERVAL = 0.125
private constant real INCOME_FACTOR = INCOME_INTERVAL / SECONDS_PER_MONTH
// Seconds per month should be divisible by income interval
private constant integer TICKS_PER_MONTH = R2I(SECONDS_PER_MONTH / INCOME_INTERVAL)
private integer Ticks = 0
endglobals
private function OnIncome takes nothing returns nothing
local real total
local real extra
local string display
if (udg_GameOver) then
call PauseTimer(GetExpiredTimer())
endif
set udg_SouthIncome = udg_SOUTH_INCOME_BASE
set udg_SouthIncome = udg_SouthIncome + udg_SouthOwnCities
set udg_SouthIncome = udg_SouthIncome + udg_SOUTH_OCC_FACTOR * udg_SouthOccCities
set udg_SouthIncome = udg_SouthIncome + udg_SOUTH_OWN_OCC_FACTOR * udg_SouthOwnOccCities
set total = udg_SouthIncome * udg_GLOBAL_INCOME_FACTOR * udg_SOUTH_INCOME_FACTOR * INCOME_FACTOR
set extra = udg_SOUTH_VIET_INCOME_BASE * udg_GLOBAL_INCOME_FACTOR * INCOME_FACTOR
call PlayerAddMoneyUnchecked(udg_PLAYER_SOUTH_VIETNAM, extra + total * udg_SouthVietnamIncomeFactor * 0.25, true)
set udg_SouthVietIncomeThisMonth = udg_SouthVietIncomeThisMonth + extra + total * udg_SouthVietnamIncomeFactor * 0.25
if (udg_AmericanPlayersHere > 0) then
set total = udg_UNITED_STATES_FIXED_INCOME * udg_GLOBAL_INCOME_FACTOR * INCOME_FACTOR / udg_AmericanPlayersHere
call PlayerAddMoney(udg_PLAYER_US_BLUE, total, true)
call PlayerAddMoney(udg_PLAYER_US_LIGHT_BLUE, total, true)
call PlayerAddMoney(udg_PLAYER_US_DARK_GREEN, total, true)
set udg_SouthIncomeThisMonth = udg_SouthIncomeThisMonth + total
endif
set udg_NorthIncome = udg_NORTH_INCOME_BASE
set udg_NorthIncome = udg_NorthIncome + udg_NorthOwnCities
set udg_NorthIncome = udg_NorthIncome + udg_NORTH_OCC_FACTOR * udg_NorthOccCities
set udg_NorthIncome = udg_NorthIncome + udg_NORTH_OWN_OCC_FACTOR * udg_NorthOwnOccCities
if (udg_NorthPlayersHere > 0) then
set total = udg_NorthIncome * udg_GLOBAL_INCOME_FACTOR * udg_NORTH_INCOME_FACTOR * INCOME_FACTOR / udg_NorthPlayersHere
set extra = udg_NORTH_VIET_INCOME_BASE * udg_GLOBAL_INCOME_FACTOR * INCOME_FACTOR
call PlayerAddMoney(udg_PLAYER_NORTH_VIETNAM, extra + total, true)
if (udg_PlayerHere[0]) then
set udg_NorthVietIncomeThisMonth = udg_NorthVietIncomeThisMonth + extra + total
endif
if (udg_VietCongPlayersHere > 0) then
call PlayerAddMoney(udg_PLAYER_VIETCONG_PINK, total, true)
call PlayerAddMoney(udg_PLAYER_VIETCONG_GRAY, total, true)
call PlayerAddMoney(udg_PLAYER_VIETCONG_BROWN, total, true)
set udg_NorthIncomeThisMonth = udg_NorthIncomeThisMonth + total
endif
endif
set Ticks = Ticks + 1
if (Ticks > TICKS_PER_MONTH) then
call Log("|cffff0303NV|r: " + I2S(RoundDownReal(udg_NorthVietIncomeThisMonth, 5)) + " (" + I2S(udg_NorthPlayersHere - udg_VietCongPlayersHere) + ")")
call Log("|cffe55bb0VC|r: " + I2S(RoundDownReal(udg_NorthIncomeThisMonth, 5)) + " (" + I2S(udg_VietCongPlayersHere) + ")")
call Log("|cfffffc01SV|r: " + I2S(RoundDownReal(udg_SouthVietIncomeThisMonth, 5)) + " (" + I2S(udg_SouthPlayersHere - udg_AmericanPlayersHere) + ")")
call Log("|cff0042ffUS|r: " + I2S(RoundDownReal(udg_SouthIncomeThisMonth, 5)) + " (" + I2S(udg_AmericanPlayersHere) + ")")
call DisplayTimedTextToPlayer(udg_PLAYER_SOUTH_VIETNAM, 0, 0, 5, /*
*/ "|cffffcc00Income: |r" + I2S(RoundDownReal(udg_SouthVietIncomeThisMonth, 5)))
set display = "|cffffcc00Income: |r" + I2S(IMaxBJ(0, RoundDownReal(udg_SouthIncomeThisMonth, 5)))
call DisplayTimedTextToPlayer(udg_PLAYER_US_BLUE, 0, 0, 5, display)
call DisplayTimedTextToPlayer(udg_PLAYER_US_LIGHT_BLUE, 0, 0, 5, display)
call DisplayTimedTextToPlayer(udg_PLAYER_US_DARK_GREEN, 0, 0, 5, display)
call DisplayTimedTextToPlayer(udg_PLAYER_NORTH_VIETNAM, 0, 0, 5, /*
*/ "|cffffcc00Income: |r" + I2S(RoundDownReal(udg_NorthVietIncomeThisMonth, 5)))
set display = "|cffffcc00Income: |r" + I2S(IMaxBJ(0, RoundDownReal(udg_NorthIncomeThisMonth, 5)))
call DisplayTimedTextToPlayer(udg_PLAYER_VIETCONG_PINK, 0, 0, 5, display)
call DisplayTimedTextToPlayer(udg_PLAYER_VIETCONG_GRAY, 0, 0, 5, display)
call DisplayTimedTextToPlayer(udg_PLAYER_VIETCONG_BROWN, 0, 0, 5, display)
set udg_SouthIncomeThisMonth = 0
set udg_SouthVietIncomeThisMonth = 0
set udg_NorthIncomeThisMonth = 0
set udg_NorthVietIncomeThisMonth = 0
set Ticks = 0
endif
endfunction
private function Init takes nothing returns nothing
call TimerStart(CreateTimer(), INCOME_INTERVAL, true, function OnIncome)
endfunction
endscope
scope UnitAckSounds initializer Init
globals
private HashTable Data
endglobals
private function OnUnitPointOrder takes nothing returns nothing
local integer typeId = GetUnitTypeId(GetTriggerUnit())
local integer rand
if (Data.has(typeId) and GetIssuedOrderId() == Data[typeId][0]) then
set rand = GetRandomInt(2, Data[typeId][1] + 1)
call PlaySoundForPlayer(Data[typeId].string[rand], GetTriggerPlayer(), 127, true)
endif
endfunction
private function DelayedInit takes nothing returns nothing
call ReleaseTimer(GetExpiredTimer())
// Configure data below
set Data[UNIT_BM21][0] = OrderId("blizzard")
set Data[UNIT_BM21][1] = 3
set Data[UNIT_BM21].string[2] = "Bm21Ack1"
set Data[UNIT_BM21].string[3] = "Bm21Ack2"
set Data[UNIT_BM21].string[4] = "Bm21Ack3"
// --------
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function OnUnitPointOrder)
set Data = HashTable.create()
// Perform setup at game start so we can use the OrderId native
call TimerStart(NewTimer(0), 0, false, function DelayedInit)
endfunction
endscope
scope UnitAttackSounds initializer Init
private function interface UnitPredicate takes unit u returns boolean
globals
private HashTable Data
private key ATTACK_FILTER
private key ATTACK_SOUND_1
private key ATTACK_SOUND_VOLUME_1
private key ATTACK_SOUND_2
private key ATTACK_SOUND_VOLUME_2
private key ATTACK_SOUND_3
private key ATTACK_SOUND_VOLUME_3
private key USE_SIMPLE
private UnitPredicate ATTACK_FILTER_ORGANIC
endglobals
private function PlayAttackSound1 takes nothing returns nothing
local unit u = GetUnitById(ReleaseTimer(GetExpiredTimer()))
local Table data = Data[GetUnitTypeId(u)]
call PlaySoundAtPoint(data.string[ATTACK_SOUND_1], data[ATTACK_SOUND_VOLUME_1], /*
*/ GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u))
set u = null
endfunction
private function PlayAttackSound2 takes nothing returns nothing
local unit u = GetUnitById(ReleaseTimer(GetExpiredTimer()))
local Table data = Data[GetUnitTypeId(u)]
call PlaySoundAtPoint(data.string[ATTACK_SOUND_2], data[ATTACK_SOUND_VOLUME_2], /*
*/ GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u))
set u = null
endfunction
private function PlayAttackSound3 takes nothing returns nothing
local unit u = GetUnitById(ReleaseTimer(GetExpiredTimer()))
local Table data = Data[GetUnitTypeId(u)]
call PlaySoundAtPoint(data.string[ATTACK_SOUND_3], data[ATTACK_SOUND_VOLUME_3], /*
*/ GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u))
set u = null
endfunction
private function OnAttack takes nothing returns nothing
local unit attacker = GetAttacker()
local integer id = GetUnitTypeId(attacker)
local integer r
if (Data.has(id)) then
if (Data[id].boolean[USE_SIMPLE]) then
set r = GetRandomInt(1,3)
if (r == 1) then
call TimerStart(NewTimer(GetUnitId(attacker)), GetUnitTypeAttackBackswing(id,0), false, function PlayAttackSound1)
elseif (r == 2) then
call TimerStart(NewTimer(GetUnitId(attacker)), GetUnitTypeAttackBackswing(id,0), false, function PlayAttackSound2)
else
call TimerStart(NewTimer(GetUnitId(attacker)), GetUnitTypeAttackBackswing(id,0), false, function PlayAttackSound3)
endif
else
if (UnitPredicate(Data[id][ATTACK_FILTER]).evaluate(GetTriggerUnit())) then
call TimerStart(NewTimer(GetUnitId(attacker)), GetUnitTypeAttackBackswing(id,0), false, function PlayAttackSound1)
else
call TimerStart(NewTimer(GetUnitId(attacker)), GetUnitTypeAttackBackswing(id,1), false, function PlayAttackSound2)
endif
endif
endif
set attacker = null
endfunction
private function AttackFilterOrganic takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_MECHANICAL)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ATTACKED, function OnAttack)
set Data = HashTable.create()
set ATTACK_FILTER_ORGANIC = AttackFilterOrganic
// UH-1 Huey Gunship
set Data[UNIT_UH1_HUEY_GUNSHIP][ATTACK_FILTER] = ATTACK_FILTER_ORGANIC
set Data[UNIT_UH1_HUEY_GUNSHIP].string[ATTACK_SOUND_1] = "HueyGunshipMG"
set Data[UNIT_UH1_HUEY_GUNSHIP][ATTACK_SOUND_VOLUME_1] = 20
set Data[UNIT_UH1_HUEY_GUNSHIP].string[ATTACK_SOUND_2] = "HueyGunshipRocket"
set Data[UNIT_UH1_HUEY_GUNSHIP][ATTACK_SOUND_VOLUME_2] = 20
set Data[UNIT_UH1_HUEY_GUNSHIP].boolean[USE_SIMPLE] = false
// AH-1 Cobra
set Data[UNIT_AH1_COBRA][ATTACK_FILTER] = ATTACK_FILTER_ORGANIC
set Data[UNIT_AH1_COBRA].string[ATTACK_SOUND_1] = "CobraMG"
set Data[UNIT_AH1_COBRA][ATTACK_SOUND_VOLUME_1] = 20
set Data[UNIT_AH1_COBRA].string[ATTACK_SOUND_2] = "HueyGunshipRocket"
set Data[UNIT_AH1_COBRA][ATTACK_SOUND_VOLUME_2] = 20
set Data[UNIT_AH1_COBRA].boolean[USE_SIMPLE] = false
endfunction
endscope
scope UnitHitSounds initializer Init
globals
private Table Data
endglobals
private function OnUnitDamaged takes nothing returns nothing
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnUnitDamaged)
set Data = Table.create()
endfunction
endscope
scope UnitMoveSounds initializer Init
globals
private constant string BRONCO_LOOP = "Abilities\\Spells\\Demon\\RainOfFire\\RainOfFireLoop1.wav"
private constant string CHINOOK_LOOP = "Abilities\\Spells\\NightElf\\Tranquility\\TranquilityHealLoop1.wav"
private constant string COBRA_LOOP = "Abilities\\Spells\\Other\\BlackArrow\\TheBlackArrow.wav"
private constant string B52_LOOP = "Abilities\\Spells\\Human\\AerialShackles\\MagicLariatLoop1.wav"
private constant string HUEY_LOOP = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareLoop.wav"
private constant string LOACH_LOOP = "Abilities\\Spells\\Human\\CloudOfFog\\CloudOfFogLoop1.wav"
private constant string MI4_LOOP = "Abilities\\Spells\\Human\\Blizzard\\BlizzardLoop1.wav"
private constant string SKYCRANE_LOOP = "Abilities\\Spells\\Human\\Banish\\BanishLoop1.wav"
private constant string SKYRAIDER_LOOP = "Abilities\\Spells\\NightElf\\Cyclone\\CycloneLoop1.wav"
endglobals
private function Init takes nothing returns nothing
call RegisterUnitSound(DUMMY_BRONCO, BRONCO_LOOP, 30)
call RegisterUnitSound(DUMMY_HUEY, HUEY_LOOP, 20)
call RegisterUnitSound(DUMMY_SKYRAIDER, SKYRAIDER_LOOP, 30)
call RegisterUnitSound(DUMMY_STRATOFORTRESS, B52_LOOP, 50)
call RegisterUnitSound(UNIT_AH1_COBRA, COBRA_LOOP, 20)
call RegisterUnitSound(UNIT_ACH47_CHINOOK, CHINOOK_LOOP, 20)
call RegisterUnitSound(UNIT_UH1_HUEY_GUNSHIP, HUEY_LOOP, 20)
call RegisterUnitSound(UNIT_UH1_HUEY_TRANSPORT, HUEY_LOOP, 20)
call RegisterUnitSound(UNIT_MEDEVAC, HUEY_LOOP, 20)
call RegisterUnitSound(UNIT_MI4, MI4_LOOP, 30)
call RegisterUnitSound(UNIT_OH6_LOACH, LOACH_LOOP, 20)
call RegisterUnitSound(UNIT_SKYCRANE, SKYCRANE_LOOP, 20)
call RegisterUnitSound(UNIT_SKYRAIDER, SKYRAIDER_LOOP, 30)
endfunction
endscope
scope UnitReadySounds initializer Init
globals
private Table Data
endglobals
private function OnUnitTrained takes nothing returns nothing
call PlaySoundForPlayer(Data.string[GetUnitTypeId(GetTriggerUnit())], GetTriggerPlayer(), 127, false)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function OnUnitTrained)
set Data = Table.create()
set Data.string[UNIT_APC_M113] = "M113Ready"
set Data.string[UNIT_BM21] = "Bm21Ready"
set Data.string[UNIT_BTR60] = "Btr60Ready"
set Data.string[UNIT_CAPTAIN] = "CaptainReady"
set Data.string[UNIT_MEDIC] = "MedicReady"
set Data.string[UNIT_M60] = "M60Ready"
set Data.string[UNIT_M48_PATTON] = "M48PattonReady"
set Data.string[UNIT_REDEYE] = "RedeyeReady"
set Data.string[UNIT_RIFLEMAN] = "RiflemanReady"
set Data.string[UNIT_RIFLEMAN_UP] = "RiflemanReady"
set Data.string[UNIT_T34] = "T34Ready"
set Data.string[UNIT_T62] = "T62Ready"
set Data.string[UNIT_ZSU57] = "Zsu57Ready"
endfunction
endscope
library Stats initializer Init uses UnitUtils
/*
* Public API
*
* function StatsGetUnitsBuilt takes player p returns integer
* function StatsGetUnitsLost takes player p returns integer
* function StatsGetUnitsKilled takes player p returns integer
* function StatsGetUnitsSniped takes player p returns integer
* function StatsGetMoneyEarned takes player p returns integer
* function StatsGetBountyMoneyEarned takes player p returns integer
* function StatsGetDamageDealt takes player p returns integer
* function StatsGetFriendlyDamageDealt takes player p returns integer
* function StatsGetActionsPerMinute takes player p returns integer
* function StatsGetMinesCleared takes player p returns integer
*
* function StatsAddUnitsBuilt takes player p, integer amount returns nothing
* function StatsAddBountyMoneyEarned takes player p, integer amount returns nothing
* function StatsAddMinesCleared takes player p, integer amount returns nothing
*
* function RecordMoneyEarned takes integer playerId, integer amount returns nothing
*
*/
globals
constant boolean TRACK_APM = false
private integer array UnitsBuilt
private integer array UnitsLost
private integer array UnitsKilled
private integer array UnitsSniped
private integer array MoneyEarned
private integer array BountyMoneyEarned
private integer array MinesCleared
private real array DamageDealt
private real array FriendlyDamageDealt
endglobals
function StatsGetUnitsBuilt takes player p returns integer
return UnitsBuilt[GetPlayerFactionId(p)]
endfunction
function StatsGetUnitsLost takes player p returns integer
return UnitsLost[GetPlayerFactionId(p)]
endfunction
function StatsGetUnitsKilled takes player p returns integer
return UnitsKilled[GetPlayerFactionId(p)]
endfunction
function StatsGetUnitsSniped takes player p returns integer
return UnitsSniped[GetPlayerFactionId(p)]
endfunction
function StatsGetMoneyEarned takes player p returns integer
return MoneyEarned[GetPlayerFactionId(p)]
endfunction
function StatsGetBountyMoneyEarned takes player p returns integer
return BountyMoneyEarned[GetPlayerFactionId(p)]
endfunction
function StatsGetDamageDealt takes player p returns integer
return R2I(DamageDealt[GetPlayerFactionId(p)])
endfunction
function StatsGetFriendlyDamageDealt takes player p returns integer
return R2I(FriendlyDamageDealt[GetPlayerFactionId(p)])
endfunction
function StatsGetMinesCleared takes player p returns integer
return MinesCleared[GetPlayerFactionId(p)]
endfunction
private function OnUnitTrained takes nothing returns nothing
local integer id = GetPlayerFactionId(GetTriggerPlayer())
set UnitsBuilt[id] = UnitsBuilt[id] + 1
endfunction
private function OnUnitDeath takes nothing returns nothing
local unit dyingUnit = GetTriggerUnit()
local unit killingUnit
local player killingOwner
local player dyingOwner
local integer playerId
if ((not UnitHasAbility(dyingUnit, ATTR_UNINDEXED)) and (not UnitHasAbility(dyingUnit, ATTR_TRAP)) and (not UnitHasAbility(dyingUnit, ATTR_IGNORE_DEATH))) then
set killingUnit = GetKillingUnit()
set killingOwner = GetOwningPlayer(killingUnit)
set dyingOwner = GetTriggerPlayer()
if ((killingOwner == null) or (dyingOwner == null)) then
set dyingUnit = null
set killingUnit = null
return
endif
set playerId = GetPlayerFactionId(dyingOwner)
set UnitsLost[playerId] = UnitsLost[playerId] + 1
set playerId = GetPlayerFactionId(killingOwner)
if (IsUnitEnemy(dyingUnit, killingOwner)) then
set UnitsKilled[playerId] = UnitsKilled[playerId] + 1
endif
if (UnitHasAbility(killingUnit, ATTR_SNIPER)) then
set UnitsSniped[playerId] = UnitsSniped[playerId] + 1
endif
endif
set dyingUnit = null
set killingUnit = null
endfunction
private function OnUnitDamaged takes nothing returns nothing
local unit source = GetEventDamageSource()
local unit target = BlzGetEventDamageTarget()
local player sourceOwner = GetOwningPlayer(source)
//local player targetOwner = GetOwningPlayer(target)
//local integer targetOwnerId = GetPlayerFactionId(targetOwner)
local integer sourceOwnerId = GetPlayerFactionId(sourceOwner)
local real damage = GetEventDamage()
if (sourceOwner == null) then
return
endif
if (IsUnitAlly(target, sourceOwner)) then
set FriendlyDamageDealt[sourceOwnerId] = FriendlyDamageDealt[sourceOwnerId] + damage
else
set DamageDealt[sourceOwnerId] = DamageDealt[sourceOwnerId] + damage
endif
set source = null
set target = null
endfunction
// This is not private because it needs to be exposed to PlayerUtils
function RecordMoneyEarned takes integer playerId, integer amount returns nothing
local integer id = GetPlayerFactionId(Player(playerId))
set MoneyEarned[playerId] = MoneyEarned[playerId] + amount
endfunction
function StatsAddUnitsBuilt takes player p, integer amount returns nothing
local integer id = GetPlayerFactionId(p)
set UnitsBuilt[id] = UnitsBuilt[id] + amount
endfunction
function StatsAddBountyMoneyEarned takes player p, integer amount returns nothing
local integer id = GetPlayerFactionId(p)
set BountyMoneyEarned[id] = BountyMoneyEarned[id] + amount
endfunction
function StatsAddMinesCleared takes player p, integer amount returns nothing
local integer id = GetPlayerFactionId(p)
set MinesCleared[id] = MinesCleared[id] + amount
endfunction
private struct Apm extends array
static integer array actions
static if (TRACK_APM) then
private static boolean array registerAction
private static timer array resetTimer
private static Table array selectedUnits
private static method reset takes nothing returns nothing
set registerAction[GetTimerData(GetExpiredTimer())] = true
endmethod
private static method onUnitSelected takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetTriggerPlayer()
local integer handleId = GetHandleId(u)
local integer playerId = GetPlayerId(p)
local integer factionId = GetPlayerFactionId(p)
if (not selectedUnits[playerId].unit.has(handleId)) then
set selectedUnits[playerId].unit[handleId] = u
set actions[factionId] = actions[factionId] + 1
endif
set u = null
endmethod
private static method onUnitDeselected takes nothing returns nothing
local unit u = GetTriggerUnit()
call selectedUnits[GetPlayerId(GetTriggerPlayer())].unit.remove(GetHandleId(u))
set u = null
endmethod
private static method onUnitDeath takes nothing returns nothing
local integer handleId = GetHandleId(GetTriggerUnit())
local integer i = 0
loop
exitwhen (i == bj_MAX_PLAYERS)
call selectedUnits[i].unit.remove(handleId)
set i = i + 1
endloop
endmethod
private static method onUnitIssuedOrder takes nothing returns nothing
local integer playerId = GetPlayerFactionId(GetTriggerPlayer())
// This is so that an action performed with multiple units selected
// still only counts as a single action
if (registerAction[playerId]) then
set actions[playerId] = actions[playerId] + 1
set registerAction[playerId] = false
call TimerStart(resetTimer[playerId], 0, false, function thistype.reset)
endif
endmethod
private static method delayedInit takes nothing returns nothing
local integer i = 0
loop
set registerAction[i] = true
set resetTimer[i] = NewTimer(i)
set selectedUnits[i] = Table.create()
set i = i + 1
exitwhen (i == bj_MAX_PLAYERS)
endloop
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function thistype.onUnitSelected)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DESELECTED, function thistype.onUnitDeselected)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onUnitDeath)
call RegisterAnyOrderEvent(function thistype.onUnitIssuedOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, function thistype.onUnitIssuedOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL, function thistype.onUnitIssuedOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_UPGRADE_CANCEL, function thistype.onUnitIssuedOrder)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_CANCEL, function thistype.onUnitIssuedOrder)
call TimerStart(NewTimer(0), 0, false, function thistype.delayedInit)
endmethod
endif
endstruct
function StatsGetActionsPerMinute takes player p returns integer
return R2I(Apm.actions[GetPlayerFactionId(p)] / GetGameElapsedTime() * 60)
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DAMAGED, function OnUnitDamaged)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function OnUnitTrained)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnUnitDeath)
endfunction
endlibrary
scope UnitTrained initializer Init
globals
private Table ReplaceUnits
private Table ReplicateUnits
endglobals
private function OnUnitTrained takes nothing returns nothing
local unit barracks = GetTriggerUnit()
local unit rallyUnit = GetUnitRallyUnit(barracks)
local unit u = GetTrainedUnit()
local integer id = GetUnitTypeId(u)
local player p = GetTriggerPlayer()
local location rally = GetUnitRallyPoint(barracks)
local real x1 = GetLocationX(rally)
local real y1 = GetLocationY(rally)
local real x2 = GetUnitX(u)
local real y2 = GetUnitY(u)
local integer count
local integer i
if (ReplaceUnits.has(id)) then
call ShowUnit(u, false)
set bj_lastCreatedUnit = CreateUnit(p, ReplaceUnits[id], x2, y2, 0)
if (x1 != 0 or y1 != 0) then
if (rallyUnit == null) then
call IssuePointOrderById(bj_lastCreatedUnit, ORDER_ATTACK, x1, y1)
else
call IssueTargetOrderById(bj_lastCreatedUnit, ORDER_SMART, rallyUnit)
endif
endif
if ((GetUnitTypeId(bj_lastCreatedUnit) == UNIT_D30_TOWED) and (GetPlayerTechResearched(p, TECH_RAPID_REPOSITIONING_2, true))) then
call UnitAddAbility(bj_lastCreatedUnit, ABILITY_ENTER_TUNNEL)
//call UnitAddAbility(bj_lastCreatedUnit, ABILITY_ENTER_TUNNEL_SMART)
endif
call ShowUnit(u, true)
call RemoveUnit(u)
elseif (ReplicateUnits.has(id)) then
set count = ReplicateUnits[id]
set i = 2
loop
exitwhen (i > count)
set bj_lastCreatedUnit = CreateUnit(p, id, x2, y2, 0)
if (x1 != 0 or y1 != 0) then
if (rallyUnit == null) then
call IssuePointOrderById(bj_lastCreatedUnit, ORDER_ATTACK, x1, y1)
else
call IssueTargetOrderById(bj_lastCreatedUnit, ORDER_SMART, rallyUnit)
endif
endif
call StatsAddUnitsBuilt(p, 1)
set i = i + 1
endloop
endif
if (rallyUnit == null) then
call IssuePointOrderById(u, ORDER_ATTACK, x1, y1)
else
call IssueTargetOrderById(u, ORDER_SMART, rallyUnit)
endif
if (rally != null) then
call RemoveLocation(rally)
set rally = null
endif
set barracks = null
set rallyUnit = null
set u = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_TRAIN_FINISH, function OnUnitTrained)
set ReplaceUnits = Table.create()
set ReplaceUnits[UNIT_D30_ICON] = UNIT_D30_TOWED
set ReplaceUnits[UNIT_M102_ICON] = UNIT_M102_TOWED
set ReplicateUnits = Table.create()
set ReplicateUnits[UNIT_BLUE_DRAGON_MARINE] = 2
set ReplicateUnits[UNIT_GUERRILLA] = 2
set ReplicateUnits[UNIT_GUERRILLA_UP] = 2
set ReplicateUnits[UNIT_REGULAR] = 2
set ReplicateUnits[UNIT_REGULAR_UP] = 2
set ReplicateUnits[UNIT_RIFLEMAN] = 2
set ReplicateUnits[UNIT_RIFLEMAN_UP] = 2
set ReplicateUnits[UNIT_RIFLEMAN_ARVN] = 2
set ReplicateUnits[UNIT_RIFLEMAN_ARVN_UP] = 2
endfunction
endscope
scope BountiesUpgrade initializer Init
globals
private real array MoneyFactor
endglobals
function BountiesTransferToPlayer takes player oldPlayer, player newPlayer returns nothing
set MoneyFactor[GetPlayerId(newPlayer)] = MoneyFactor[GetPlayerId(oldPlayer)]
endfunction
private function OnResearch takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if (GetResearched() == TECH_BOUNTIES) then
set MoneyFactor[id] = MoneyFactor[id] + 0.05
endif
endfunction
private function OnDeath takes nothing returns nothing
local unit dyingUnit = GetTriggerUnit()
local unit killingUnit = GetKillingUnit()
local player p = GetOwningPlayer(killingUnit)
local integer id = GetPlayerId(p)
local integer bounty
if (MoneyFactor[id] > 0 and IsUnitEnemy(dyingUnit, p) and not IsUnitType(dyingUnit, UNIT_TYPE_STRUCTURE)) then
set bounty = R2I(MoneyFactor[id] * GetUnitTypeGoldCost(GetUnitTypeId(dyingUnit)))
call TextTagBountyGold(p, bounty, GetUnitX(dyingUnit), GetUnitY(dyingUnit), BlzGetUnitZ(dyingUnit) - 271.25)
call PlayerAddMoney(p, I2R(bounty), true)
call StatsAddBountyMoneyEarned(p, bounty)
endif
set dyingUnit = null
set killingUnit = null
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_FINISH, function OnResearch)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
endfunction
endscope
scope Vietnamization initializer Init
globals
private constant integer MAX_LEVELS = 5
private constant group SOUTH_VIET_UNITS = CreateGroup()
private triggercondition OnIndexEvent = null
endglobals
private function DebuffSingle takes unit u returns nothing
local real factor = 0.50 + 0.10 * udg_VietnamizationLevel
local real percentLife = GetUnitLifePercent(u)
local integer id = GetUnitTypeId(u)
call BlzSetUnitMaxHP(u, RoundDownReal(9 + R2I(factor * GetUnitTypeMaxLife(id)), 10))
if (not UnitHasAbility(u, ATTR_SNIPER)) then
call BlzSetUnitBaseDamage(u, R2I(factor * GetUnitTypeBaseDamage(id, 0)), 0)
call BlzSetUnitBaseDamage(u, R2I(factor * GetUnitTypeBaseDamage(id, 1)), 1)
endif
call SetUnitLifePercentBJ(u, percentLife)
endfunction
private function DebuffAll takes nothing returns nothing
local integer size = BlzGroupGetSize(SOUTH_VIET_UNITS)
local integer i = 0
local unit u
loop
exitwhen (i == size)
set u = BlzGroupUnitAt(SOUTH_VIET_UNITS, i)
if (UnitAlive(u)) then
call DebuffSingle(u)
endif
set i = i + 1
endloop
set u = null
endfunction
private function NewUnit takes nothing returns nothing
local unit u = GetIndexedUnit()
if ((GetOwningPlayer(u) != Player(PLAYER_NEUTRAL_PASSIVE)) and (udg_VietnamizationLevel < MAX_LEVELS) and (UnitHasAbility(u, ATTR_ARVN_DEBUFF))) then
call DebuffSingle(u)
call GroupAddUnit(SOUTH_VIET_UNITS, u)
endif
set u = null
endfunction
private function OnResearchFinish takes nothing returns nothing
if (GetResearched() == TECH_VIETNAMIZATION) then
set udg_VietnamizationLevel = udg_VietnamizationLevel + 1
call DebuffAll()
if (udg_VietnamizationLevel == MAX_LEVELS) then
call GroupClear(SOUTH_VIET_UNITS)
call DestroyGroup(SOUTH_VIET_UNITS)
call RemoveUnitIndexEvent(OnIndexEvent, EVENT_UNIT_INDEX)
endif
endif
endfunction
private function Init takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_RESEARCH_FINISH, function OnResearchFinish)
set OnIndexEvent = OnUnitIndex(function NewUnit)
endfunction
endscope
scope IteratorTest
struct Test extends array
implement Alloc
implement Iterator
static constant real UPDATE_INTERVAL = 1
method destroy takes nothing returns nothing
call .deallocate()
endmethod
method update takes nothing returns nothing
endmethod
static method create takes nothing returns thistype
local thistype this = allocate()
call .listAdd()
return this
endmethod
endstruct
endscope
scope DisplayPressedKey initializer Init
private function DisplayKey takes nothing returns nothing
call Log(I2S(GetHandleId(BlzGetTriggerPlayerKey())) + " (" + I2S(BlzGetTriggerPlayerMetaKey()) + ")")
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 0, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 1, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 2, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 3, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 4, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 5, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 6, true)
call BlzTriggerRegisterPlayerKeyEvent(t, Player(0), ConvertOsKeyType(i), 7, true)
set i = i + 1
exitwhen i > 255
endloop
call TriggerAddAction(t, function DisplayKey)
endfunction
endscope