native GetUnitGoldCost takes integer unitid returns integer
native GetUnitWoodCost takes integer unitid returns integer
native GetFoodUsed takes integer unitId returns integer
native GetUnitBuildTime takes integer unitid returns integer
native UnitAlive takes unit u returns boolean
Name | Type | is_array | initial_value |
Ability_Temp | ability | No | |
AbilityCode_SpinWebAbilities | abilcode | No | |
Bool_AllPlayersOut | boolean | No | |
Bool_PlayersReady | boolean | No | |
Bool_RaceMultiboardVisState | boolean | Yes | |
Bool_SelectedByPlayer | boolean | Yes | |
Bool_ShowBuildOrder | boolean | Yes | |
Bool_Temp | boolean | No | |
Buff_Temp | buffcode | No | |
Destructible_ExpansionMarkers | destructable | Yes | |
Destructible_Temp | destructable | No | |
Dialog_RaceSelection | dialog | No | |
Dialog_RacialSelection | dialog | Yes | |
DialogButton_RaceSelection | button | Yes | |
DialogButton_RSArcaniac | button | Yes | |
DialogButton_RSDeathlord | button | Yes | |
DialogButton_RSDemoniac | button | Yes | |
DialogButton_RSEmperor | button | Yes | |
DialogButton_RSLord | button | Yes | |
DialogButton_RSRandom | button | Yes | |
DialogButton_RSTidemaster_Copy | button | Yes | |
ElapsedGameTime | timer | No | |
HashTable_Auras | hashtable | No | |
HashTable_Autocast | hashtable | No | |
HashTable_BSCarriers | hashtable | No | |
HashTable_BuffOwnership | hashtable | No | |
HashTable_Colors | hashtable | No | |
HashTable_ConstructionEffects | hashtable | No | |
HashTable_DOTs | hashtable | No | |
HashTable_Exiled | hashtable | No | |
HashTable_FaerieDust | hashtable | No | |
HashTable_LifelinkedUnits | hashtable | No | |
HashTable_ManaRefund | hashtable | No | |
HashTable_Missiles | hashtable | No | |
HashTable_Orders | hashtable | No | |
HashTable_Resources | hashtable | No | |
HashTable_SimMovement | hashtable | No | |
HashTable_SizeBlending | hashtable | No | |
HashTable_Soothe | hashtable | No | |
HashTable_SpecialEffects | hashtable | No | |
HashTable_TargetToCaster | hashtable | No | |
HashTable_Timers | hashtable | No | |
HashTable_UnitInfo | hashtable | No | |
HashTable_UnitOwnership | hashtable | No | |
HashTable_Visibility | hashtable | No | |
Int_ExpansionMarkerCount | integer | No | |
Int_FuncInput | integer | Yes | |
Int_FuncTemp | integer | Yes | |
Int_GatedAbilityTriggerCount | integer | No | |
Int_ItsAliveMaxZombieCount | integer | No | 8 |
Int_Race | integer | Yes | |
Int_RaceCount | integer | No | 3 |
Int_RaceNum_Chaos | integer | No | 5 |
Int_RaceNum_Death | integer | No | 3 |
Int_RaceNum_Magic | integer | No | 4 |
Int_RaceNum_Nature | integer | No | 2 |
Int_RaceNum_Order | integer | No | 1 |
Int_RaceNum_Random | integer | No | 0 |
Int_RecallInstanceCount | integer | No | |
Int_Temp | integer | No | |
Int_Temp_2 | integer | No | |
Int_Temp_3 | integer | No | |
Int_Temp_4 | integer | No | |
Int_UnitID | integer | No | |
IntArr_EffectTranslations | integer | Yes | |
IntArr_GatedAbilityTriggers | integer | Yes | |
IntArr_RecallInstances | integer | Yes | |
IntArr_Swarms | integer | Yes | |
IntArray_Temp | integer | Yes | |
Lightning_Temp | lightning | No | |
Multiboard_GameClock | multiboard | No | |
Multiboard_RaceSelection | multiboard | No | |
Player_Temp | player | No | |
PlayerGroup_Temp | force | No | |
Point_FuncInput | location | Yes | |
Point_FunctionTemp | location | Yes | |
Point_StartingUnits | location | No | |
Point_Target | location | No | |
Point_Temp | location | No | |
Point_Temp_2 | location | No | |
Point_Temp_3 | location | No | |
Point_Temp_4 | location | No | |
Point_WildGrowthTarget | location | No | |
Point_With_Offset | location | No | |
Real_AbsorbEssenceManaFactor | real | No | 0.20 |
Real_AOE | real | No | |
Real_CloudOfMistAOE | real | No | 250.00 |
Real_Damage | real | No | |
Real_Delay | real | No | 0.00 |
Real_Distance | real | No | |
Real_Duration | real | No | |
Real_FaerieDustAOE | real | No | 500.00 |
Real_FalconMaxRange | real | No | 2000.00 |
Real_FuncInput | real | Yes | |
Real_FuncTemp | real | Yes | |
Real_MaxCollisionSize | real | No | 72.00 |
Real_NecroButtonPlayer | real | No | |
Real_RaceSelectionTime | real | No | 60.00 |
Real_SlurpSpeed | real | No | 2500.00 |
Real_SoulPreservationAOE | real | No | 600.00 |
Real_Speed | real | No | |
Real_SpinWebAOE | real | No | 350.00 |
Real_Temp | real | No | |
Real_Temp_2 | real | No | |
Real_Temp_3 | real | No | |
Real_Time | real | No | |
RealArray_Temp | real | Yes | |
SpecialEffect_Temp | effect | No | |
SpecialEffect_Temp_2 | effect | No | |
String_ColorCodes | string | Yes | |
String_FuncInput | string | Yes | |
String_FunctionTemp | string | No | |
String_PlayerColors | string | Yes | |
String_PlayerRaceName | string | Yes | None |
String_RaceNameChaos | string | No | |cffff4600Chaos|r |
String_RaceNameDeath | string | No | |cff6d0065Death|r |
String_RaceNameMagic | string | No | |cff92b5ffMagic|r |
String_RaceNameNature | string | No | |cff00b105Nature|r |
String_RaceNameOrder | string | No | |cffffe428Order|r |
String_RaceNameRandom | string | No | Random |
String_RaceNames | string | Yes | |
String_RSMBTitle | string | No | Race Selection |
String_Temp | string | No | |
TechType_Level2SBSpell | techcode | Yes | |
TechType_Level3SBSpell | techcode | Yes | |
Timer_DestroyRSMultiboard | timer | No | |
Timer_Eclipse | timer | No | |
Trigger_StartingUnits | trigger | Yes | |
Trigger_Temp | trigger | No | |
Unit_CryptOrManor | unit | Yes | |
Unit_EclipseDependency | unit | Yes | |
Unit_FuncInput | unit | Yes | |
Unit_HallOfWarriorsOrHaven | unit | Yes | |
Unit_SpellbringerDependency | unit | Yes | |
Unit_Temp | unit | No | |
Unit_Temp_2 | unit | No | |
Unit_Temp_3 | unit | No | |
UnitArray_FunctionTemp | unit | Yes | |
UnitGroup_AbsorbEssence | group | No | |
UnitGroup_AbsorbLumber | group | No | |
UnitGroup_BattleStandards | group | No | |
UnitGroup_BlackPyramids | group | No | |
UnitGroup_BlightBonus | group | No | |
UnitGroup_BuffEffects | group | No | |
UnitGroup_CloudCoverCasters | group | No | |
UnitGroup_CloudOfMist | group | No | |
UnitGroup_ColorBlending | group | No | |
UnitGroup_DeathsGraspTargets | group | No | |
UnitGroup_Devour | group | No | |
UnitGroup_DiseaseClouds | group | No | |
UnitGroup_DOTs | group | No | |
UnitGroup_Entwine | group | No | |
UnitGroup_EssenceDrainCasters | group | No | |
UnitGroup_ExpansionMarkers | group | No | |
UnitGroup_Falcons | group | No | |
UnitGroup_Fear | group | No | |
UnitGroup_FollowDummyTargets | group | No | |
UnitGroup_FuncInput | group | Yes | |
UnitGroup_FunctionTemp | group | Yes | |
UnitGroup_GaseousBloat | group | No | |
UnitGroup_GraspOfDeath | group | No | |
UnitGroup_Haunted | group | No | |
UnitGroup_HydePotion | group | No | |
UnitGroup_InTransport | group | No | |
UnitGroup_ItemUnits | group | No | |
UnitGroup_ItsAlive | group | No | |
UnitGroup_LeechSeed | group | No | |
UnitGroup_LifeDrainCasters | group | No | |
UnitGroup_LightningPointer | group | No | |
UnitGroup_ManaBomb | group | No | |
UnitGroup_MarkOfDoom | group | No | |
UnitGroup_MissileTargets | group | No | |
UnitGroup_Necrogenesis | group | No | |
UnitGroup_Offering | group | No | |
UnitGroup_Recall | group | No | |
UnitGroup_ReleaseFalcon | group | No | |
UnitGroup_ReplaceMe | group | No | |
UnitGroup_Saplings | group | No | |
UnitGroup_SFX | group | No | |
UnitGroup_SimMovement | group | No | |
UnitGroup_SizeBlending | group | No | |
UnitGroup_SlurpDevoured | group | No | |
UnitGroup_SlurpTargets | group | No | |
UnitGroup_Soothe | group | No | |
UnitGroup_SoulPreservation | group | No | |
UnitGroup_SpiritOwls | group | Yes | |
UnitGroup_SporeClouds | group | No | |
UnitGroup_Temp | group | No | |
UnitGroup_Temp_2 | group | No | |
UnitGroup_Temp_3 | group | No | |
UnitGroup_Temp_4 | group | No | |
UnitGroup_ThornsArmor | group | No | |
UnitGroup_TradeLumber | group | No | |
UnitGroup_Trample | group | No | |
UnitGroup_TransformingNecros | group | No | |
UnitGroup_UnderConstruction | group | No | |
UnitGroup_Upgrading | group | No | |
UnitGroup_Warpers | group | No | |
UnitGroup_WebResidents | group | No | |
UnitGroup_Webs | group | No | |
UnitGroup_ZombiePlague | group | No | |
UnitHandle_Temp | handle | No | |
UnitType_Spellbringer | unitcode | Yes | |
UnitType_SpellbringerDeath | unitcode | Yes | |
UnitType_Temp | unitcode | No | |
VisMod_Temp | fogmodifier | No |
globals
constant integer MAX_INTEGER = 2147483647
constant real BIG_REAL = 1000000000.0
constant string EMPTY_STRING = ""
constant string DEFAULT_STRING = "Default string"
integer array BUFFS_THAT_SLOW
integer BUFFS_THAT_SLOW_SIZE
constant integer RACE_NUM_RANDOM = 0
constant integer RACE_NUM_ORDER = 1
constant integer RACE_NUM_NATURE = 2
constant integer RACE_NUM_DEATH = 3
constant integer RACE_NUM_MAGIC = 4
constant integer RACE_NUM_CHAOS = 5
endglobals
globals
//************** UNITS **************
constant integer SB_ALTAR_OF_DARKNESS = 'h01X'
constant integer SB_ALTAR_OF_LIGHT = 'h019'
constant integer SB_ALTAR_OF_NATURE = 'h01J'
constant integer SB_ARCHANGEL_OF_LIFE = 'h00N'
constant integer SB_ARCHON_AIR = 'h02B'
constant integer SB_ARCHON_GROUND = 'h02A'
constant integer SB_AVATAR_OF_COMMAND = 'h00F'
constant integer SB_BARRACKS = 'h002'
constant integer SB_BATTLE_STANDARD_UNIT = 'h01G'
constant integer SB_BLACK_HOLE = 'A03T'
constant integer SB_BLACK_PYRAMID = 'u018'
constant integer SB_BLACKSMITH = 'h006'
constant integer SB_BLIGHT_FACTORY = 'u00J'
constant integer SB_BLIGHT_VESSEL = 'u008'
constant integer SB_BLIGHT_VESSEL_UPGRADE_DUMMY = 'u00E'
constant integer SB_BLIGHT_WIDOW = 'n00T'
constant integer SB_BLIGHT_WIDOW_WEBBED = 'n01A'
constant integer SB_BLOOD_MISTRESS = 'h01Q'
constant integer SB_BURNING_BLOOD_EXPLOSION = 'h01M'
constant integer SB_CELESTIAL_BEACON = 'h00E'
constant integer SB_CELESTIAL_GATEWAY = 'h01K'
constant integer SB_CHICKEN = 'n017'
constant integer SB_CHANGELING_CONTROL_DUMMY = 'n01C'
constant integer SB_CHURCH = 'h01E'
constant integer SB_CITADEL = 'o000'
constant integer SB_CLEAVE = 'A037'
constant integer SB_CLERIC = 'n002'
constant integer SB_CONSTRUCTION_DUMMY_BLIGHT_FACTORY = 'h00H'
constant integer SB_CONSTRUCTION_DUMMY_DARK_NEXUS = 'u006'
constant integer SB_CONSTRUCTION_DUMMY_SPELLBRINGER_DEATH = 'h007'
constant integer SB_CROW = 'u001'
constant integer SB_CROW_AIR = 'u005'
constant integer SB_CRUSADER = 'h02G'
constant integer SB_CRYPT = 'u00D'
constant integer SB_CRYPT_OR_MANOR = 'h010'
constant integer SB_DARK_NEXUS = 'u00C'
constant integer SB_DEATH_KNIGHT = 'n01D'
constant integer SB_DENDROID_CHIEFTAIN = 'e00I'
constant integer SB_DENDROID_ELDER = 'e00G'
constant integer SB_DENDROID_TREEHERD = 'e00E'
constant integer SB_DENDROID_TREEHERD_WARRIOR_MODE = 'e000'
constant integer SB_DENDROID_WARRIOR = 'e007'
constant integer SB_DREAD_SPIRE = 'u00Z'
constant integer SB_ECLIPSE_DEPENDENCY = 'h022'
constant integer SB_ELVEN_ARTISAN = 'h00I'
constant integer SB_ELVEN_ENCHANTRESS = 'h00M'
constant integer SB_ENFORCER = 'h01O'
constant integer SB_FALCONER = 'n001'
constant integer SB_FALCON = 'u000'
constant integer SB_FALCON_ATTACKER = 'u008'
constant integer SB_FIRE_ELEMENTAL = 'hfel'
constant integer SB_FLESH_GOLEM = 'u016'
constant integer SB_FLESHLESS_ZOMBIE = 'n00M'
constant integer SB_FORTIFY = 'A07L'
constant integer SB_FORTRESS = 'h018'
constant integer SB_FROST_TITAN = 'mtit'
constant integer SB_GARGOYLE = 'u00A'
constant integer SB_GIANT_TOAD = 'n003'
constant integer SB_GLACIAL_STASIS_HIDDEN_ATTACKER = 'h01U'
constant integer SB_GOLD_MINE = 'ngol'
constant integer SB_GRAVEYARD = 'u010'
constant integer SB_GREAT_STAG = 'n013'
constant integer SB_GREMLIN = 'h00O'
constant integer SB_HALL_OF_ELITES = 'n00A'
constant integer SB_HALL_OF_SCHOLARS = 'n00C'
constant integer SB_HALL_OF_WARRIORS = 'e002'
constant integer SB_HAVEN = 'e003'
constant integer SB_HEADMASTER = 'n010'
constant integer SB_HIDDEN_CASTER = 'h00B'
constant integer SB_HIDDEN_CASTER_RELEASE_FALCON = 'h012'
constant integer SB_HOLD = 'e001'
constant integer SB_HOODLING = 'n01G'
constant integer SB_ICE_ELEMENTAL = 'h026'
constant integer SB_LOST_SOUL = 'u00X'
constant integer SB_LOST_SOUL_HAUNTING = 'u00N'
constant integer SB_LUMBER_MILL = 'h005'
constant integer SB_MAGIC_HALL = 'o001'
constant integer SB_MAGIC_HALL_2 = 'o002'
constant integer SB_MANOR = 'h00V'
constant integer SB_MIND_VISION_DUMMY = 'hcmv'
constant integer SB_NECROPOLIS = 'u002'
constant integer SB_NECROMANCER = 'u003'
constant integer SB_NECROMANCER_LICH = 'u00F'
constant integer SB_OBLIVION_VAULT_UNIT = 'n01E'
constant integer SB_PEASANT = 'h000'
constant integer SB_PHANTOM_CARRIAGE = 'n00P'
constant integer SB_PHANTOM_CARRIAGE_LANDED = 'n015'
constant integer SB_PLACE_BLIGHT_EMBLEM = 'A07P'
constant integer SB_PUTRID_BLOAT_UNIT = 'n01K'
constant integer SB_ROWDY_CREW = 'n01I'
constant integer SB_SANCTUM = 'o001'
constant integer SB_SAPLING = 'e009'
constant integer SB_SAPLING_WARRIOR_MODE = 'e006'
constant integer SB_SCOUT_TOWER = 'h00W'
constant integer SB_SCRY = 'A02N'
constant integer SB_SEED_OF_CORRUPTION = 'A057'
constant integer SB_SHAPELING = 'h00O'
constant integer SB_SHAPER = 'tink'
constant integer SB_SHEPHERD_OF_ROT = 'o005'
constant integer SB_SKY_TOTEM = 'e004'
constant integer SB_SLAVE = 'h01A'
constant integer SB_SPEARMAN = 'n000'
constant integer SB_SPEARMAN_SIEGE_SPEARS = 'n004'
constant integer SB_SPEARTANK = 'h029'
constant integer SB_SPEARTANK_FORTIFIED = 'h01P'
constant integer SB_SPECIAL_EFFECT_UNIT_BLACK_HOLE = 'h027'
constant integer SB_SPECIAL_EFFECT_UNIT_CLOUD_OF_MIST = 'h01D'
constant integer SB_SPECIAL_EFFECT_UNIT_DEVOURING_SWARM = 'h01W'
constant integer SB_SPECIAL_EFFECT_UNIT_ENTWINE = 'h00R'
constant integer SB_SPECIAL_EFFECT_UNIT_GAVEL_OF_JUDGMENT = 'h00P'
constant integer SB_SPECIAL_EFFECT_UNIT_SPIN_WEB = 'h02F'
constant integer SB_SPECIAL_EFFECT_UNIT_UNDYING = 'h021'
constant integer SB_SPECIAL_EFFECT_UNIT_VAMPIRE_LORD = 'n00P'
constant integer SB_SPECIAL_EFFECT_UNIT_WALL_OF_FIRE = 'h013'
constant integer SB_SPECIAL_EFFECT_UNIT_WHIRLWIND = 'h01C'
constant integer SB_SPECIAL_EFFECT_UNIT_WILD_GROWTH = 'h02H'
constant integer SB_SPECIAL_EFFECT_UNIT_WIND_BARRIER = 'h020'
constant integer SB_SPECIAL_EFFECT_UNIT_ZOMBIE = 'n00S'
constant integer SB_SPECIAL_EFFECT_UNIT_ZOMBIE_PLAGUE = 'h009'
constant integer SB_SPELLBRINGER_ORDER = 'H001'
constant integer SB_SPELLBRINGER_NATURE = 'H016'
constant integer SB_SPELLBRINGER_DEATH = 'H00A'
constant integer SB_SPELLBRINGER_DUMMY_DEPENDENCY = 'h01L'
constant integer SB_SPITTER_PLANT = 'n00L'
constant integer SB_SPIRIT_DWARF = 'h01I'
constant integer SB_SPIRIT_OWL_UNIT = 'n00B'
constant integer SB_SWARM_BAT = 'u009'
constant integer SB_T_REX = 'n00V'
constant integer SB_THICKET_UNIT = 'h02A'
constant integer SB_TIGER = 'e00B'
constant integer SB_TREEHERD = 'e00E'
constant integer SB_UNIT_HAUNT = 'n007'
constant integer SB_UNHOLY_BANNER_UNIT = 'o006'
constant integer SB_VAMPIRE_LORD = 'n006'
constant integer SB_VAMPIRE_BLOODFIEND = 'n00O'
constant integer SB_VAMPIRE_LORD_COFFIN_FORM = 'n008'
constant integer SB_VAULT_OF_PHYLACTERIES = 'u00P'
constant integer SB_VILE_LABORATORY = 'u007'
constant integer SB_WATER_ELEMENTAL = 'h01S'
constant integer SB_WAR_FACTORY = 'h01F'
constant integer SB_WAR_FACTORY_OR_CHURCH_OR_CELESTIAL_BEACON = 'h02C'
constant integer SB_WAR_MILL = 'h02F'
constant integer SB_WILD_GROWTH_UNIT = 'h02K'
constant integer SB_ZOMBIE = 'n00J'
constant integer SB_ZOMBIE_BUILD_DUMMY = 'n007'
//************ ABILITIES ************
constant integer SB_ABSORB_ESSENCE = 'A00B'
constant integer SB_ABSORB_LUMBER = 'A00T'
constant integer SB_ABSORB_LUMBER_NECROPOLIS = 'A082'
constant integer SB_ACID_BREATH = 'A009'
constant integer SB_ACID_BREATH_HIDDEN_CASTER_GROUND = 'A03I'
constant integer SB_ACID_BREATH_HIDDEN_CASTER_AIR = 'A03K'
constant integer SB_ACID_BREATH_CS = 'A084'
constant integer SB_ACID_BREATH_SWOOP = 'A08K'
constant integer SB_ANIMATE_DEAD = 'A001'
constant integer SB_ANIMATE_DEAD_VISUAL_EFFECT = 'A039'
constant integer SB_ARBOREAL_AVENGER = 'A005'
constant integer SB_ARCANE_PULSE = 'A08C'
constant integer SB_ARCANE_PULSE_BUFF = 'A009'
constant integer SB_ARCANE_PULSE_EXPLOSION_GROUND = 'A03K'
constant integer SB_ARCANE_PULSE_EXPLOSION_AIR = 'A084'
constant integer SB_ARCANE_RIDDLE = 'A01W'
constant integer SB_ARMY_TOGGLE_ADD = 'A07B'
constant integer SB_ARMY_TOGGLE_REMOVE = 'A079'
constant integer SB_ASCEND = 'A072'
constant integer SB_ASCEND_DUMMY = 'A08I'
constant integer SB_ATTACK_ARMY = 'A05S'
constant integer SB_BANISH = 'A012'
constant integer SB_BANISH_HIDDEN = 'A03L'
constant integer SB_BARRAGE = 'A07W'
constant integer SB_BATTLE_STANDARD = 'A06Y'
constant integer SB_BATTLE_STANDARD_AURA = 'A00I'
constant integer SB_BEAST_WITHIN = 'A02F'
constant integer SB_BILE_BLOSSOMS = 'A03E'
constant integer SB_BILE_BLOSSOMS_DAMAGE = 'A03B'
constant integer SB_BILE_BLOSSOMS_SLOW = 'A03D'
constant integer SB_BOMBARD = 'A04V'
constant integer SB_BOUNTY = 'A078'
constant integer SB_BLIND_HIDDEN_CASTER = 'A07F'
constant integer SB_BLINDING_FLASH = 'A006'
constant integer SB_BLINDING_FLASH_HIDDEN_CASTER = 'A06E'
constant integer SB_BLIGHT_ARMOR = 'A02I'
constant integer SB_BLIGHT_GROWTH_512 = 'A07D'
constant integer SB_BLIGHT_GROWTH_768 = 'Abgs'
constant integer SB_BLIGHT_GROWTH_960 = 'Abgl'
constant integer SB_BLIGHT_SHOT = 'A07T'
constant integer SB_BLIZZARD = 'A015'
constant integer SB_BLIZZARD_SLOW_ABILITY = 'A013'
constant integer SB_BLOOD_GORGE = 'S00D'
constant integer SB_BRINK_OF_DEATH = 'A05X'
constant integer SB_BURST_ATTACK = 'A00D'
constant integer SB_CALL_GREAT_STAG = 'A05F'
constant integer SB_CAMOFLAGE = 'A04S'
constant integer SB_CAMOFLAGE_DUMMY = 'A077'
constant integer SB_CARGO_HOLD_DEATH = 'Achd'
constant integer SB_CARGO_HOLD_PHANTOM_CARRIAGE = 'S009'
constant integer SB_CELESTIAL_FIRE = 'A093'
constant integer SB_CELESTIAL_FIRE_HIDDEN_CASTER = 'A094'
constant integer SB_CHAIN_LIGHTNING = 'A056'
constant integer SB_CHAIN_LIGHTNING_HIDDEN_CASTER = 'A055'
constant integer SB_CLOUD_COVER = 'A030'
constant integer SB_CLOUD_OF_MIST = 'A06I'
constant integer SB_CLOUD_OF_MIST_EVASION = 'A04U'
constant integer SB_CLOUD_OF_MIST_MAGIC_IMMUNITY = 'A06F'
constant integer SB_COFFIN_SLUMBER = 'A02M'
constant integer SB_CONE_OF_FLAME = 'A045'
constant integer SB_COUNTERSPELL = 'A01Y'
constant integer SB_COUNTERSPELL_HIDDEN_CASTER = 'A02G'
constant integer SB_DAMAGE_RESISTANCE = 'A06B'
constant integer SB_DARKNESS = 'A06V'
constant integer SB_DARKNESS_HIDDEN_CASTER = 'A06W'
constant integer SB_DEATH_BEAM = 'A08T'
constant integer SB_DEATH_WAVE = 'A03V'
constant integer SB_DECONSTRUCT = 'A050'
constant integer SB_DESCEND = 'A07J'
constant integer SB_DEVOURING_SWARM = 'A033'
constant integer SB_DISABLE_DAMAGE_DEALT = 'A07C'
constant integer SB_DIVINE_INTERVENTION = 'A00G'
constant integer SB_EAGLE_EYE = 'A02M'
constant integer SB_ECLIPSE = 'A07A'
constant integer SB_EJECT = 'A075'
constant integer SB_ELDRITCH_GAZE = 'A08H'
constant integer SB_ELDRITCH_GAZE_HIDDEN = 'A08F'
constant integer SB_ENTWINE = 'A020'
constant integer SB_ESSENCE_DRAIN = 'A02Z'
constant integer SB_ESSENCE_DRAIN_HIDDEN_CASTER = 'A031'
constant integer SB_EYE_BEAM = 'A014'
constant integer SB_FAERIE_DUST = 'A005'
constant integer SB_FEEDING_FRENZY = 'A03D'
constant integer SB_FIND_FREE_NECROMANCERS = 'A07U'
constant integer SB_FIND_RITUAL_NECROMANCERS = 'A00F'
constant integer SB_FIRE_BOLT = 'A05I'
constant integer SB_FLICKER = 'A03W'
constant integer SB_FORCE_ARMY_UNIT = 'A00J'
constant integer SB_FREEZETHAW = 'A052'
constant integer SB_FROST_ARMOR = 'A05B'
constant integer SB_FROST_ARMOR_SLOW_AURA = 'A05C'
constant integer SB_GASEOUS_BLOAT = 'A00A'
constant integer SB_GAVEL_OF_JUDGMENT = 'A064'
constant integer SB_GAVEL_OF_JUDGMENT_HIDDEN_CASTER = 'A05L'
constant integer SB_GHOST = 'Agho'
constant integer SB_GHOST_VISIBLE = 'Aeth'
constant integer SB_GOLD_MINE_ABILITY = 'Agld'
constant integer SB_HARVEST_CHAOS_WEAK = 'A01O'
constant integer SB_HARVEST_CHAOS_NORMAL = 'A022'
constant integer SB_HARVEST_GOLD_AND_LUMBER = 'Ahar'
constant integer SB_HARVEST_GOLD_AND_LUMBER_MAGIC = 'A03U'
constant integer SB_HARVEST_GOLD_ONLY = 'A018'
constant integer SB_HARVEST_ORDER_SUPER_PEASANT = 'A06C'
constant integer SB_HAUNT = 'A05M'
constant integer SB_HIDE_HP_BAR = 'A048'
constant integer SB_HIDE_HP_BAR_MORPH = 'A06Q'
constant integer SB_HOLD_THE_LINE = 'A08P'
constant integer SB_HOLD_THE_LINE_HIDDEN_CASTER = 'A08Q'
constant integer SB_HYDE_POTION_AOE = 'A07Q'
constant integer SB_HYDE_POTION_HIDDEN_CASTER = 'A091'
constant integer SB_ILLUSION = 'A01A'
constant integer SB_ILLUSION_HIDDEN = 'A01N'
constant integer SB_ILLUSION_HIDDEN_CASTER = 'A01R'
constant integer SB_IMMOLATE = 'A011'
constant integer SB_INTERDICTION_AURA = 'A06J'
constant integer SB_INTERDICTION_AURA_HIDDEN = 'A06K'
constant integer SB_ITS_ALIVE = 'A040'
constant integer SB_KISS_OF_IMMORTALITY = 'A05U'
constant integer SB_KISS_OF_IMMORTALITY_HIDDEN_CASTER = 'A092'
constant integer SB_KUNDALINI = 'A04W'
constant integer SB_LASH_OF_THE_WHIP = 'A01X'
constant integer SB_LASH_OF_THE_WHIP_HIDDEN_CASTER = 'A01Z'
constant integer SB_LAND = 'A065'
constant integer SB_LAND_DUMMY = 'A02V'
constant integer SB_LEAP = 'A01M'
constant integer SB_LEECH_SEED = 'A03Z'
constant integer SB_LEECH_SEED_HIDDEN_CASTER = 'A02N'
constant integer SB_LICH_UPGRADE = 'S004'
constant integer SB_LIFE_DRAIN = 'A01A'
constant integer SB_LIFT_DEBUFF = 'A00D'
constant integer SB_LIGHTNING_STRIKE = 'A01S'
constant integer SB_LOAD_PHANTOM_CARRIAGE_DUMMY = 'A06Z'
constant integer SB_LOCUST = 'Aloc'
constant integer SB_MAGIC_MISSILE = 'A059'
constant integer SB_MANA_BATTERY = 'A08J'
constant integer SB_MANA_GENERATOR_HIDDEN = 'A03O'
constant integer SB_MANA_SHIELD = 'A051'
constant integer SB_METEOR = 'A019'
constant integer SB_MIND_VISION = 'Ammv'
constant integer SB_MIND_VISION_DUMMY_CAST = 'dcmv'
constant integer SB_MOVE_ARMY = 'A05T'
constant integer SB_MURDER_OF_CROWS = 'A04P'
constant integer SB_MURDER_OF_CROWS_HIDDEN_CASTER_AIR = 'A01J'
constant integer SB_MURDER_OF_CROWS_HIDDEN_CASTER_GROUND = 'A04O'
constant integer SB_NECRO_RESTORE = 'A01L'
constant integer SB_NECROGENESIS = 'A05Z'
constant integer SB_NECROMANCER_UPROOT = 'A00Y'
constant integer SB_NIGHT_STALKER = 'S00F'
constant integer SB_NO_COLLISION = 'A01H'
constant integer SB_NO_HERO_GLOW = 'nohg'
constant integer SB_NON_ARMY_UNIT = 'A06R'
constant integer SB_NULL_BOMB = 'A03N'
constant integer SB_OBLITERATE = 'A034'
constant integer SB_OBLIVION_VAULT = 'A07H'
constant integer SB_OFFERING = 'A02B'
constant integer SB_OFFERING_DUMMY = 'A02D'
constant integer SB_OUST = 'A03H'
constant integer SB_OVERCLOCK = 'A00P'
constant integer SB_OVERCLOCK_ARMOR_BONUS = 'A03S'
constant integer SB_PERMANENT_INVISIBILITY_TREETOP_SENTRY = 'A07O'
constant integer SB_PERMANENT_INVISIBILITY_ECLIPSE = 'A08D'
constant integer SB_PERMANENT_INVISIBILITY_ECLIPSE_NO_FADE = 'A036'
constant integer SB_PERMANENT_INVISIBILITY_FLICKER = 'A00H'
constant integer SB_PLAGUE_DIVE = 'A05H'
constant integer SB_PLAGUE_DIVE_EFFECT = 'A05J'
constant integer SB_PLAGUE_DIVE_HIDDEN_CASTER = 'A05K'
constant integer SB_POSSESSION = 'A063'
constant integer SB_PUTREFY = 'A00A'
constant integer SB_PUTREFY_HIDDEN_CASTER = 'A01D'
constant integer SB_PYRE = 'A07R'
constant integer SB_RAPTOR_EYE = 'A04X'
constant integer SB_RECALL = 'A01C'
constant integer SB_RELEASE_FALCON = 'A05W'
constant integer SB_RELEASE_FALCON_UNTARGETED = 'A044'
constant integer SB_RELEASE_FALCON_HIDDEN_CASTER = 'A000'
constant integer SB_RELEASE_FALCON_AUTOCAST_ON = 'A06M'
constant integer SB_RELEASE_FALCON_AUTOCAST_OFF = 'A06O'
constant integer SB_RENEW = 'Aren'
constant integer SB_RENEW_SAPLING = 'A00N'
constant integer SB_REPAIR = 'Arep'
constant integer SB_REPAIR_DWARVES = 'A06D'
constant integer SB_REPAIR_HUMAN = 'Ahrp'
constant integer SB_RESTORE = 'Arst'
constant integer SB_RESTORE_LOST_SOUL = 'A00S'
constant integer SB_RESTORE_NECRO = 'A01L'
constant integer SB_RESURRECTION = 'A00K'
constant integer SB_RETURN_GOLD = 'Argd'
constant integer SB_RETURN_GOLD_AND_LUMBER = 'Argl'
constant integer SB_RETURN_RESOURCES_BLIGHT_FACTORY = 'A004'
constant integer SB_RETURN_TO_HAUNT = 'A03P'
constant integer SB_ROOTGRASP = 'A00E'
constant integer SB_ROOTGRASP_AIR = 'A002'
constant integer SB_ROOTGRASP_GROUND = 'A06A'
constant integer SB_SCRY_HIDDEN_CASTER = 'A03Q'
constant integer SB_SLURP = 'A02E'
constant integer SB_SOOTHE = 'A025'
constant integer SB_SOOTHE_HIDDEN = 'A07E'
constant integer SB_SOUL_CAPTURE = 'A07Y'
constant integer SB_SOUL_HARVEST = 'A01U'
constant integer SB_SOUL_HARVEST_DAMAGE_BONUS = 'A01K'
constant integer SB_SPAWN_SAPLING_UNITS = 'A02X'
constant integer SB_SPAWN_SAPLING_STRUCTURES = 'A05Q'
constant integer SB_SPECTRAL_SHOT = 'A03D'
constant integer SB_SPELL_IMMUNITY_HIDDEN = 'A021'
constant integer SB_SPIN_WEB = 'A06P'
constant integer SB_SPIN_WEB_MORPH = 'A06P'
constant integer SB_SPIRIT = 'A08E'
constant integer SB_SPIRIT_OWL = 'A04E'
constant integer SB_STAND_GROUND = 'A01P'
constant integer SB_START_SUMMONING_RITUAL = 'A01E'
constant integer SB_START_SUMMONING_RITUAL_LICH = 'A04G'
constant integer SB_STOP_SUMMONING_RITUAL = 'A01F'
constant integer SB_STOP_SUMMONING_RITUAL_LICH = 'A04H'
constant integer SB_STORMRAGE = 'A050'
constant integer SB_STORMRAGE_DUMMY = 'A08L'
constant integer SB_SUICIDE = 'A08X'
constant integer SB_SUICIDE_ATTACK = 'A090'
constant integer SB_SUMMON_AVATAR_OF_COMMAND = 'A06L'
constant integer SB_SUMMON_SPIRIT_DWARVES = 'A054'
constant integer SB_SUMMONING_RITUAL_EFFECT = 'A07G'
constant integer SB_SURGE = 'A011'
constant integer SB_SWOOP = 'A04D'
constant integer SB_TAIL_WHIP = 'A046'
constant integer SB_TAIL_WHIP_SLOW = 'A04A'
constant integer SB_TAKE_FORM = 'A00B'
constant integer SB_TAUNT = 'A049'
constant integer SB_THICKET = 'A06I'
constant integer SB_THICKET_PHYS_REDUCTION = 'A068'
constant integer SB_THICKET_SPELL_REDUCTION = 'A069'
constant integer SB_THORNS_ARMOR = 'A05P'
constant integer SB_THORNS_ARMOR_HIDDEN_ABILITY = 'A058'
constant integer SB_THOUSAND_NEEDLES = 'A04J'
constant integer SB_TIME_WARP = 'A03F'
constant integer SB_TITANIC_INVOCATION = 'A05A'
constant integer SB_TOGGLE_GROUND_ATTACK = 'A00Z'
constant integer SB_TOWER_SHIELDS = 'A04L'
constant integer SB_TRACTOR_BEAM = 'A02J'
constant integer SB_TRAMPLE = 'A029'
constant integer SB_TREETOP_SENTRY = 'A04B'
constant integer SB_TRUE_SIGHT_HIDDEN = 'A024'
constant integer SB_ORC_BUILD = 'AObu'
constant integer SB_QUICKSAND = 'A04L'
constant integer SB_QUICKSAND_HIDDEN = 'A04Y'
constant integer SB_UD_BUILD = 'AUbu'
constant integer SB_UNDYING = 'A08O'
constant integer SB_UNHOLY_BANNER = 'A06T'
constant integer SB_UNHOLY_CROWN = 'A08S'
constant integer SB_UNIT_SELL_UNITS = 'A01G'
constant integer SB_UNSUMMON_GENERIC = 'A01Q'
constant integer SB_VIPER_STRIKE = 'A08B'
constant integer SB_WALL_OF_FIRE = 'A02U'
constant integer SB_WALL_OF_THORNS = 'A01Q'
constant integer SB_WAVEFORM = 'A010'
constant integer SB_WHIRLWIND = 'A03A'
constant integer SB_WILD_GROWTH = 'A095'
constant integer SB_WILD_GROWTH_SB = 'A00U'
constant integer SB_WIND_BARRIER = 'A01Y'
constant integer SB_WIND_BARRIER_HIDDEN = 'A03Q'
constant integer SB_WINDED = 'A071'
constant integer SB_WINDRUN = 'A03H'
constant integer SB_WORKER_MODE_DENDROID_TREEHERD = 'A02O'
constant integer SB_WORKER_MODE_SAPLING = 'A02P'
constant integer SB_ZOMBIE_PLAGUE = 'A04K'
constant integer SB_ZOMBIE_PLAGUE_HIDDEN_CASTER = 'A041'
//************ BUFFS ************
constant integer SB_BUFF_ARBOREAL_AVENGER = 'B02T'
constant integer SB_BUFF_ARCANE_PULSE = 'B02J'
constant integer SB_BUFF_BANISH = 'B02P'
constant integer SB_BUFF_BANISH_HIDDEN = 'B000'
constant integer SB_BUFF_BLIGHT_ARMOR = 'B022'
constant integer SB_BUFF_BRINK_OF_DEATH= 'B011'
constant integer SB_BUFF_COUNTERSPELL = 'B00M'
constant integer SB_BUFF_DISEASE = 'Bapl'
constant integer SB_BUFF_DOMINATE = 'B007'
constant integer SB_BUFF_EAGLE_EYE = 'B02W'
constant integer SB_BUFF_ELDRITCH_GAZE = 'B01H'
constant integer SB_BUFF_ENTWINE = 'B00R'
constant integer SB_BUFF_ESSENCE_DRAIN_CASTER = 'B029'
constant integer SB_BUFF_ESSENCE_DRAIN_TARGET = 'B01P'
constant integer SB_BUFF_FAERIE_DUST = 'B009'
constant integer SB_BUFF_FEAR = 'B02A'
constant integer SB_BUFF_GAVEL_OF_JUDGMENT = 'B014'
constant integer SB_BUFF_GLACIAL_STASIS = 'B00F'
constant integer SB_BUFF_GRASP_OF_DEATH = 'B02K'
constant integer SB_BUFF_GROUNDED = 'B02A'
constant integer SB_BUFF_HAUNT = 'B01B'
constant integer SB_BUFF_IMMOLATE = 'B00Y'
constant integer SB_BUFF_INTERDICTION_AURA = 'B015'
constant integer SB_BUFF_KISS_OF_IMMORTALITY = 'B02T'
constant integer SB_BUFF_KISS_OF_IMMORTALITY_HEAL = 'B02U'
constant integer SB_BUFF_LEECH_SEED = 'B00U'
constant integer SB_BUFF_LIFE_DRAIN = 'B013'
constant integer SB_BUFF_LIFT = 'B02O'
constant integer SB_BUFF_MANA_BATTERY = 'B01M'
constant integer SB_BUFF_MIND_VISION = 'Bmmv'
constant integer SB_BUFF_NULL_BOMB = 'B00I'
constant integer SB_BUFF_OBLIVION_VAULT = 'B02P'
constant integer SB_BUFF_OUST = 'B00W'
constant integer SB_BUFF_OVERCLOCK = 'B00A'
constant integer SB_BUFF_PLAGUE = 'B00Z'
constant integer SB_BUFF_PLANESHIFT = 'B00K'
constant integer SB_BUFF_POSSESSION = 'B013'
constant integer SB_BUFF_PUTREFY = 'B019'
constant integer SB_BUFF_QUICKSAND = 'B00X'
constant integer SB_BUFF_REND_FLESH = 'B012'
constant integer SB_BUFF_ROOTGRASP = 'B00V'
constant integer SB_BUFF_SEED_OF_CORRUPTION = 'B017'
constant integer SB_BUFF_SERRATED_SPEARS = 'B01U'
constant integer SB_BUFF_SLOWED = 'Bfro'
constant integer SB_BUFF_SLURP = 'B02M'
constant integer SB_BUFF_SPECTRAL_SHOT = 'B02X'
constant integer SB_BUFF_SPELLBURN = 'B023'
constant integer SB_BUFF_SPORE_CLOUD = 'B01R'
constant integer SB_BUFF_SURGE = 'B00E'
constant integer SB_BUFF_SOOTHE = 'B00P'
constant integer SB_BUFF_TAIL_WHIP = 'B003'
constant integer SB_BUFF_TASKMASTER = 'B005'
constant integer SB_BUFF_THORNS_ARMOR = 'B021'
constant integer SB_BUFF_THOUSAND_NEEDLES = 'B006'
constant integer SB_BUFF_TIMED_LIFE_ANIMATE_DEAD = 'BUan'
constant integer SB_BUFF_TIMED_LIFE_GENERIC = 'BTLF'
constant integer SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL = 'BHwe'
constant integer SB_BUFF_TRACTOR_BEAM = 'B00Q'
constant integer SB_BUFF_TRACTOR_BEAM_CASTER = 'B00S'
constant integer SB_BUFF_WEBBED = 'B01Z'
constant integer SB_BUFF_WHIRLWIND = 'B02C'
constant integer SB_BUFF_WILD_GROWTH = 'B01Z'
constant integer SB_BUFF_WIND_BARRIER = 'B009'
constant integer SB_BUFF_WINDED = 'B01C'
constant integer SB_BUFF_WINDRUN = 'B00Z'
constant integer SB_BUFF_ZOMBIE_PLAGUE = 'B02E'
//************ TECH ************
constant integer SB_TECH_ABSORB_ESSENCE = 'R02Q'
constant integer SB_TECH_ACID_BREATH = 'R01K'
constant integer SB_TECH_ARBOREAL_AVENGER = 'R00O'
constant integer SB_TECH_ARCANE_RIDDLE = 'R00S'
constant integer SB_TECH_BLIGHT_SHOT = 'R010'
constant integer SB_TECH_CLEAVE = 'R00K'
constant integer SB_TECH_CLOUD_COVER = 'R00G'
constant integer SB_TECH_DARK_NEXUS = 'R00Q'
constant integer SB_TECH_ELDER_TREEHERDS = 'R02H'
constant integer SB_TECH_ELDER_TREEHERDS_HIDDEN = 'R01T'
constant integer SB_TECH_ELDRITCH_GAZE = 'R01U'
constant integer SB_TECH_ESSENCE_DRAIN = 'R015'
constant integer SB_TECH_FALCON_TRAINING = 'R00F'
constant integer SB_TECH_FALCON_TRAINING_HIDDEN = 'R006'
constant integer SB_TECH_GREATER_HYDROMANCY = 'R01I'
constant integer SB_TECH_HOLD_THE_LINE = 'R014'
constant integer SB_TECH_IMPROVED_SOUL_HARVEST = 'R02D'
constant integer SB_TECH_MANA_SHIELD = 'R01H'
constant integer SB_TECH_PUTREFY = 'R02X'
constant integer SB_TECH_SIEGE_SPEARS = 'R02A'
constant integer SB_TECH_SLURP = 'R004'
constant integer SB_TECH_SPELLBURN = 'R00S'
constant integer SB_TECH_SOUL_CONNOISSEUR = 'R00D'
constant integer SB_TECH_SURGE = 'R01B'
constant integer SB_TECH_THOUSAND_NEEDLES = 'R01R'
constant integer SB_TECH_TOWER_SHIELDS = 'R023'
constant integer SB_TECH_UNDYING = 'R00H'
constant integer SB_TECH_UNHOLY_STRENGTH = 'R00L'
//************ DESTRUCTIBLES ************
constant integer SB_ASHENVALE_TREE_WALL = 'ATtr'
constant integer SB_ASHENVALE_CANOPY_TREE = 'ATtc'
constant integer SB_BARRENS_TREE_WALL = 'BTtw'
constant integer SB_BARRENS_CANOPY_TREE = 'BTtc'
constant integer SB_BLACK_CITADEL_TREE_WALL = 'KTtw'
constant integer SB_CITYSCAPE_FALL_TREE_WALL = 'YTft'
constant integer SB_CITYSCAPE_SNOWY_TREE_WALL = 'YTst'
constant integer SB_CITYSCAPE_SUMMER_TREE_WALL = 'YTct'
constant integer SB_CITYSCAPE_WINTER_TREE_WALL = 'YTwt'
constant integer SB_CITYSCAPE_RUINED_TREE_WALL = 'JTct'
constant integer SB_DALARAN_RUINS_TREE_WALL = 'JTtw'
constant integer SB_DUNGEON_TREE_WALL = 'DTsh'
constant integer SB_FELWOOD_TREE_WALL = 'CTtr'
constant integer SB_FELWOOD_CANOPY_TREE = 'CTtc'
constant integer SB_ICECROWN_TREE_WALL = 'ITtw'
constant integer SB_ICECROWN_CANOPY_TREE = 'ITtc'
constant integer SB_NORTHREND_CANOPY_TREE = 'NTtc'
constant integer SB_NORTHREND_ICY_TREE_WALL = 'NTiw'
constant integer SB_FALL_TREE_WALL = 'FTtw'
constant integer SB_SUMMER_TREE_WALL = 'LTlt'
constant integer SB_SNOWY_TREE_WALL = 'WTst'
constant integer SB_WINTER_TREE_WALL = 'WTtw'
constant integer SB_NORTHREND_TREE_WALL = 'NTtw'
constant integer SB_OUTLAND_TREE_WALL = 'OTtw'
constant integer SB_RUINS_TREE_WALL = 'ZTtw'
constant integer SB_RUINS_CANOPY_TREE = 'ZTtc'
constant integer SB_UNDERGROUND_TREE_WALL = 'GTsh'
constant integer SB_VILLAGE_TREE_WALL = 'VTlt'
//************ ITEMS ************
constant integer SB_ITEM_PATHING_CHECKER = 'I000'
//************ LIGHTNING ************
constant string SB_LIGHTNING_LIFE_DRAIN = "DRAL"
constant string SB_LIGHTNING_MANA_FLARE = "MFPB"
constant string SB_LIGHTNING_MYSTIC_CHAIN = "MYCH"
//************ WEATHER ************
constant integer SB_WEATHER_NORTHREND_BLIZZARD = 'SNbs'
//************ ORDERS ************
constant integer SB_ORDER_ACTIVATE_MANA_BATTERY = 852177
constant integer SB_ORDER_DEACTIVATE_MANA_BATTERY = 852178
constant integer SB_ORDER_AMBUSH = 852131
constant integer SB_ORDER_ARMY_TOGGLE_ADD = 852055
constant integer SB_ORDER_ARMY_TOGGLE_REMOVE = 852055
constant integer SB_ORDER_ARMY_TOGGLE_UNADD = 852056
constant integer SB_ORDER_ARMY_TOGGLE_UNREMOVE = 852056
constant integer SB_ORDER_ATTACK = 851983
constant integer SB_ORDER_CANCEL = 851976
constant integer SB_ORDER_DEFEND_ON = 852055
constant integer SB_ORDER_DEFEND_OFF = 852056
constant integer SB_ORDER_HARVEST = 852018
constant integer SB_ORDER_HOLD_POSITION = 851993
constant integer SB_ORDER_MIND_VISION_AOE = 852588
constant integer SB_ORDER_RALLY_SMART = 851970
constant integer SB_ORDER_REPAIR = 852024
constant integer SB_ORDER_RESUME_HARVESTING = 852017
constant integer SB_ORDER_SMART = 851971
constant integer SB_ORDER_STOP = 851972
constant integer SB_ORDER_STUNNED = 851973
constant integer SB_ORDER_WISH = 852066
endglobals
library Vectors
struct vec3
real x = 0.0
real y = 0.0
real z = 0.0
static method create takes real x, real y, real z returns vec3
local vec3 v = vec3.allocate()
set v.x = x
set v.y = y
set v.z = z
return v
endmethod
// Copy another vector's values to this one
method copy takes vec3 other returns vec3
set x = other.x
set y = other.y
set z = other.z
return this
endmethod
// Creates a new vector by duplicating this vector's value
method dupe takes nothing returns vec3
return vec3.create(x, y, z)
endmethod
method setAll takes real x, real y, real z returns vec3
set this.x = x
set this.y = y
set this.z = z
return this
endmethod
method setX takes real value returns vec3
set x = value
return this
endmethod
method setY takes real value returns vec3
set y = value
return this
endmethod
method setZ takes real value returns vec3
set z = value
return this
endmethod
method addX takes real value returns vec3
set this.x = this.x + value
return this
endmethod
method addY takes real value returns vec3
set this.y = this.y + value
return this
endmethod
method addZ takes real value returns vec3
set this.z = this.z + value
return this
endmethod
method sqrMag takes nothing returns real
return (x * x) + (y * y) + (z * z)
endmethod
method mag takes nothing returns real
return SquareRoot(sqrMag())
endmethod
method normalize takes nothing returns vec3
local real len = mag()
set x = x / len
set y = y / len
set z = z / len
return this
endmethod
method add takes vec3 other returns vec3
set x = x + other.x
set y = y + other.y
set z = z + other.z
return this
endmethod
method sub takes vec3 other returns vec3
set x = x - other.x
set y = y - other.y
set z = z - other.z
return this
endmethod
method multiply takes real value returns vec3
set x = x * value
set y = y * value
set z = z * value
return this
endmethod
method equals takes vec3 other returns boolean
return x == other.x and y == other.y and z == other.z
endmethod
method toString takes nothing returns string
return "(" + R2S(x) + ", " + R2S(y) + ", " + R2S(z) + ")"
endmethod
endstruct
function VecDivideA takes vec3 dividend, real divisor returns vec3
set dividend.x = dividend.x / divisor
set dividend.y = dividend.y / divisor
set dividend.z = dividend.z / divisor
return dividend
endfunction
function VecDivideB takes real dividend, vec3 divisor returns vec3
set divisor.x = dividend / divisor.x
set divisor.y = dividend / divisor.y
set divisor.z = dividend / divisor.z
return divisor
endfunction
// Returns a new Vec3
function VecMultiply takes vec3 v, real multiplier returns vec3
return vec3.create(v.x * multiplier, v.y * multiplier, v.z * multiplier)
endfunction
function VecAdd takes vec3 v1, vec3 v2 returns vec3
return vec3.create(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
endfunction
function VecSub takes vec3 v1, vec3 v2 returns vec3
return vec3.create(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
endfunction
function VecNormalize takes vec3 v returns vec3
local real len = v.mag()
return vec3.create(v.x / len, v.y / len, v.z / len)
endfunction
function VecMoveTowards takes vec3 source, vec3 target, real maxDelta returns vec3
local vec3 diff = vec3.create(target.x - source.x, target.y - source.y, target.z - source.z)
local real dist = RMinBJ(diff.mag(), maxDelta)
local vec3 translation = VecMultiply(diff.normalize(), dist)
call diff.destroy()
return translation.add(source)
endfunction
function VecSqrDistance takes vec3 v1, vec3 v2 returns real
local vec3 diff = VecSub(v2, v1)
local real result = diff.sqrMag()
call diff.destroy()
return result
endfunction
function VecDistance takes vec3 v1, vec3 v2 returns real
local vec3 diff = VecSub(v2, v1)
local real result = diff.mag()
call diff.destroy()
return result
endfunction
function VecYawRad takes vec3 v returns real
return Atan2(v.y, v.x)
endfunction
function VecPitchRad takes vec3 v returns real
return -Asin(v.z)
endfunction
function VecAngle takes vec3 v returns real
return Rad2Deg(VecYawRad(v))
endfunction
function VecPitchDeg takes vec3 v returns real
return Rad2Deg(VecPitchRad(v))
endfunction
function VecRotateZ takes vec3 point, real angle returns vec3
local real radian = Deg2Rad(angle)
local real ca = Cos(radian)
local real sa = Sin(radian)
local real x = (point.x * ca) - (point.y * sa)
local real y = (point.x * sa) + (point.y * ca)
return vec3.create(x, y, point.z)
endfunction
function YawBetweenVecsRad takes vec3 v1, vec3 v2 returns real
local vec3 diff = VecSub(v2, v1)
local vec3 normal = VecNormalize(diff)
local real result = VecYawRad(normal)
call diff.destroy()
call normal.destroy()
return result
endfunction
function PitchBetweenVecsRad takes vec3 v1, vec3 v2 returns real
local vec3 diff = VecSub(v2, v1)
local vec3 normal = VecNormalize(diff)
local real result = VecPitchRad(normal)
call diff.destroy()
call normal.destroy()
return result
endfunction
function VecDirection takes real yawInRadians, real pitchInRadians returns vec3
return vec3.create(Cos(yawInRadians) * Cos(pitchInRadians), Sin(yawInRadians) * Cos(pitchInRadians), Sin(pitchInRadians))
endfunction
function GetUnitVec takes unit whichUnit returns vec3
return vec3.create(GetUnitX(whichUnit), GetUnitY(whichUnit), BlzGetUnitZ(whichUnit) + GetUnitFlyHeight(whichUnit))
endfunction
function GetLocVec takes location loc returns vec3
return vec3.create(GetLocationX(loc), GetLocationY(loc), GetLocationZ(loc))
endfunction
function GetEffectVec takes effect sfx returns vec3
return vec3.create(BlzGetLocalSpecialEffectX(sfx),BlzGetLocalSpecialEffectY(sfx), BlzGetLocalSpecialEffectZ(sfx))
endfunction
endlibrary
//-------------------------------------------------
library Color
struct Color
integer r = 0
integer g = 0
integer b = 0
integer a = 0
endstruct
function CreateColor takes integer r, integer g, integer b, integer a returns Color
local Color c = Color.create()
set c.r = r
set c.g = g
set c.b = b
set c.a = a
return c
endfunction
function RCreateColor takes real r, real g, real b, real a returns Color
return CreateColor(R2I(r * 255), R2I(g * 255), R2I(b * 255), R2I(a * 255))
endfunction
function ColorGetR takes Color c returns real
return c.r / 255.0
endfunction
function ColorGetG takes Color c returns real
return c.g / 255.0
endfunction
function ColorGetB takes Color c returns real
return c.b / 255.0
endfunction
function ColorGetA takes Color c returns real
return c.a / 255.0
endfunction
function GetUnitVertexColor takes unit whichUnit returns Color
local integer r = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TINTING_COLOR_RED)
local integer g = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TINTING_COLOR_GREEN)
local integer b = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TINTING_COLOR_BLUE)
local integer a = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TINTING_COLOR_ALPHA)
return CreateColor(r, g, b, a)
endfunction
function ColorToString takes Color c returns string
return "RGBA(" + I2S(c.r) + ", " + I2S(c.g) + ", " + I2S(c.b) + ", " + I2S(c.a) + ")"
endfunction
endlibrary
//-------------------------------------------------
library PlayerColors initializer Init requires Color
globals
Color array PLAYER_COLORS
endglobals
function PlayerColorToColor takes playercolor pc returns Color
return PLAYER_COLORS[GetHandleId(pc)]
endfunction
function PlayerColor takes player p returns Color
local playercolor pc = GetPlayerColor(p)
return PlayerColorToColor(pc)
endfunction
function Init takes nothing returns nothing
set PLAYER_COLORS[0] = CreateColor(255, 3, 3, 255) // Red
set PLAYER_COLORS[1] = CreateColor(0, 66, 255, 255) // Blue
set PLAYER_COLORS[2] = CreateColor(27, 231, 186, 255) // Teal
set PLAYER_COLORS[3] = CreateColor(85, 0, 129, 255) // Purple
set PLAYER_COLORS[4] = CreateColor(254, 252, 0, 255) // Yellow
set PLAYER_COLORS[5] = CreateColor(254, 137, 13, 255) // Orange
set PLAYER_COLORS[6] = CreateColor(33, 191, 0, 255) // Green
set PLAYER_COLORS[7] = CreateColor(228, 92, 175, 255) // Pink
set PLAYER_COLORS[8] = CreateColor(148, 150, 150, 255) // Gray
set PLAYER_COLORS[9] = CreateColor(126, 191, 241, 255) // Light Blue
set PLAYER_COLORS[10] = CreateColor(16, 98, 71, 255) // Dark Green
set PLAYER_COLORS[11] = CreateColor(79, 43, 5, 255) // Brown
set PLAYER_COLORS[12] = CreateColor(156, 0, 0, 255) // Maroon
set PLAYER_COLORS[13] = CreateColor(0, 0, 195, 255) // Navy
set PLAYER_COLORS[14] = CreateColor(0, 235, 255, 255) // Turquoise
set PLAYER_COLORS[15] = CreateColor(189, 0, 255, 255) // Violet
set PLAYER_COLORS[16] = CreateColor(236, 206, 135, 255) // Wheat
set PLAYER_COLORS[17] = CreateColor(247, 165, 139, 255) // Peach
set PLAYER_COLORS[18] = CreateColor(191, 255, 129, 255) // Mint
set PLAYER_COLORS[19] = CreateColor(219, 184, 235, 255) // Lavendar
set PLAYER_COLORS[20] = CreateColor(79, 80, 85, 255) // Coal
set PLAYER_COLORS[21] = CreateColor(236, 240, 255, 255) // Snow
set PLAYER_COLORS[22] = CreateColor(0, 120, 30, 255) // Emerald
set PLAYER_COLORS[23] = CreateColor(165, 111, 52, 255) // Peanut
set PLAYER_COLORS[24] = CreateColor(46, 45, 46, 255) // Black
endfunction
endlibrary
function interface ConditionFunc takes nothing returns boolean
function interface ActionFunc takes nothing returns nothing
function interface UnitFunc takes unit whichUnit returns nothing
function interface EffectFunc takes effect whichEffect returns nothing
function interface IntFunc takes integer i returns nothing
function interface UnitCondition takes unit whichUnit returns boolean
function interface IntCondition takes integer input returns boolean
function interface UnitComparer takes unit u1, unit u2 returns integer
struct RecallInstance
unit caster = null
real time = 0.0
group units = null
effect casterEffect = null
ubersplat casterSplat = null
endstruct
library LinkedList
function interface ILinkedListPredicate takes ILinkedListNode node returns boolean
interface ILinkedListNode
ILinkedListNode next = 0
ILinkedListNode prev = 0
endinterface
interface ILinkedList
ILinkedListNode head = 0
ILinkedListNode tail = 0
integer count = 0
endinterface
function LinkedListGetFirst takes ILinkedList list returns ILinkedListNode
return list.head
endfunction
function LinkedListGetLast takes ILinkedList list returns ILinkedListNode
return list.tail
endfunction
function LinkedListGetAtIndex takes ILinkedList list, integer index returns ILinkedListNode
local integer i = 1
local ILinkedListNode node = LinkedListGetFirst(list)
loop
exitwhen i >= index or i >= list.count
set node = node.next
set i = i + 1
endloop
return node
endfunction
function LinkedListAddFirst takes ILinkedList list, ILinkedListNode node returns nothing
if (node != 0) then
if (list.head != 0) then
set list.head.prev = node
set node.next = list.head
endif
set list.head = node
set list.count = list.count + 1
endif
endfunction
function LinkedListAddLast takes ILinkedList list, ILinkedListNode node returns nothing
if (node != 0) then
if (list.head == 0) then
set list.head = node
set list.tail = node
elseif (list.tail != 0) then
set node.prev = list.tail
set list.tail.next = node
endif
set list.tail = node
set list.count = list.count + 1
endif
endfunction
function LinkedListRemoveFirst takes ILinkedList list returns ILinkedListNode
local ILinkedListNode removed = list.head
if (removed != 0) then
if (list.tail == removed) then
set list.tail = 0
endif
set list.head = removed.next
if (list.head != 0) then
set list.head.prev = 0
endif
set removed.next = 0
set list.count = list.count - 1
endif
return removed
endfunction
function LinkedListRemoveLast takes ILinkedList list returns ILinkedListNode
local ILinkedListNode removed = list.tail
if (removed != 0) then
if (list.head == removed) then
set list.head = 0
endif
set list.tail = removed.prev
if (list.tail != 0) then
set list.tail.next = 0
endif
set removed.prev = 0
set list.count = list.count - 1
endif
return removed
endfunction
function LinkedListRemove takes ILinkedList list, ILinkedListNode remove returns boolean
if (remove != 0) then
if (remove == list.head) then
return LinkedListRemoveFirst(list) != 0
elseif (remove == list.tail) then
return LinkedListRemoveLast(list) != 0
else
set remove.prev.next = remove.next
set remove.next.prev = remove.prev
set remove.next = 0
set remove.prev = 0
set list.count = list.count - 1
return true
endif
endif
return false
endfunction
function LinkedListDestroyFirst takes ILinkedList list returns nothing
local ILinkedListNode node = LinkedListRemoveFirst(list)
if (node != 0) then
call node.destroy()
endif
endfunction
function LinkedListDestroyLast takes ILinkedList list returns nothing
local ILinkedListNode node = LinkedListRemoveLast(list)
if (node != 0) then
call node.destroy()
endif
endfunction
function LinkedListDestroyNode takes ILinkedList list, ILinkedListNode remove returns boolean
local boolean result = LinkedListRemove(list, remove)
if (result) then
call remove.destroy()
endif
return result
endfunction
function LinkedListFind takes ILinkedList list, ILinkedListPredicate predicate returns ILinkedListNode
local ILinkedListNode node = LinkedListGetFirst(list)
loop
exitwhen node == 0
if (predicate.evaluate(node)) then
return node
endif
set node = node.next
endloop
return 0
endfunction
function DestroyLinkedList takes ILinkedList list returns nothing
local ILinkedListNode node = 0
loop
exitwhen list.count <= 0
set node = LinkedListRemoveFirst(node)
call node.destroy()
endloop
call list.destroy()
endfunction
function LinkedListToString takes ILinkedList list returns string
local string s = ""
local ILinkedListNode node = list.head
loop
exitwhen node == 0
set s = s + I2S(node) + ","
set node = node.next
endloop
return s
endfunction
//------------------------------------------------------------
// LinkedList_Int
//------------------------------------------------------------
struct LinkedListNode_Int extends ILinkedListNode
integer value
endstruct
struct LinkedList_Int extends ILinkedList
endstruct
function CreateLinkedList_Int takes nothing returns LinkedList_Int
return LinkedList_Int.create()
endfunction
function LinkedListAddFirstInt takes LinkedList_Int list, integer i returns LinkedListNode_Int
local LinkedListNode_Int node = LinkedListNode_Int.create()
set node.value = i
call LinkedListAddFirst(list, node)
return node
endfunction
function LinkedListAddLastInt takes LinkedList_Int list, integer i returns LinkedListNode_Int
local LinkedListNode_Int node = LinkedListNode_Int.create()
set node.value = i
call LinkedListAddLast(list, node)
return node
endfunction
function LinkedListFindInt takes LinkedList_Int list, integer value returns LinkedListNode_Int
local LinkedListNode_Int node = LinkedListGetFirst(list)
loop
exitwhen node == 0
if (node.value == value) then
return node
endif
set node = node.next
endloop
return 0
endfunction
endlibrary
globals
constant integer ORDER_TYPE_IMMEDIATE = 0
constant integer ORDER_TYPE_TARGET = 1
constant integer ORDER_TYPE_POINT = 2
endglobals
struct SavedOrder
unit whichUnit = null
integer orderId = 0
integer orderType = ORDER_TYPE_IMMEDIATE
real targetX = 0.0
real targetY = 0.0
widget targetWidget = null
endstruct
function CreateSavedPointOrder takes integer orderId, real x, real y returns SavedOrder
local SavedOrder order = SavedOrder.create()
set order.orderId = orderId
set order.targetX = x
set order.targetY = y
set order.orderType = ORDER_TYPE_POINT
return order
endfunction
function CreateSavedTargetOrder takes integer orderId, widget target returns SavedOrder
local SavedOrder order = SavedOrder.create()
set order.orderId = orderId
set order.targetWidget = target
set order.orderType = ORDER_TYPE_TARGET
return order
endfunction
function CreateSavedImmedateOrder takes integer orderId returns SavedOrder
local SavedOrder order = SavedOrder.create()
set order.orderId = orderId
return order
endfunction
function CreateSavedOrder takes integer orderId, widget targetWidget, real targetX, real targetY returns SavedOrder
if (targetWidget != null) then
return CreateSavedTargetOrder(orderId, targetWidget)
elseif (targetX != 0.0 and targetY != 0.0) then
return CreateSavedPointOrder(orderId, targetX, targetY)
else
return CreateSavedImmedateOrder(orderId)
endif
endfunction
function GetSavedOrderTargetX takes SavedOrder so returns real
if (so.orderType == ORDER_TYPE_POINT) then
return so.targetX
elseif (so.orderType == ORDER_TYPE_TARGET) then
return GetWidgetX(so.targetWidget)
else
return 0.0
endif
endfunction
function GetSavedOrderTargetY takes SavedOrder so returns real
if (so.orderType == ORDER_TYPE_POINT) then
return so.targetY
elseif (so.orderType == ORDER_TYPE_TARGET) then
return GetWidgetY(so.targetWidget)
else
return 0.0
endif
endfunction
function IssueSavedOrder takes unit whichUnit, SavedOrder order returns boolean
if (order.orderType == ORDER_TYPE_IMMEDIATE) then
return IssueImmediateOrderById(whichUnit, order.orderId)
elseif (order.orderType == ORDER_TYPE_TARGET) then
return IssueTargetOrderById(whichUnit, order.orderId, order.targetWidget)
elseif (order.orderType == ORDER_TYPE_POINT) then
return IssuePointOrderById(whichUnit, order.orderId, order.targetX, order.targetY)
endif
return false
endfunction
function IssueSavedOrderDelayed takes unit whichUnit, SavedOrder order, real delay returns nothing
call PolledWait(delay)
call IssueSavedOrder(whichUnit, order)
endfunction
function IsOrderEqual takes SavedOrder order, integer orderId, widget targetWidget, real targetX, real targetY returns boolean
if (order.orderId != orderId) then
return false
elseif (order.orderType == ORDER_TYPE_TARGET and targetWidget != order.targetWidget) then
return false
elseif (order.orderType == ORDER_TYPE_POINT and (targetX != order.targetX or targetY != order.targetY)) then
return false
endif
return true
endfunction
function Write takes string message returns nothing
call DisplayTextToForce(GetPlayersAll(), message)
endfunction
function WriteReal takes string label, real r returns nothing
call Write(label + R2S(r))
endfunction
function WriteInt takes string label, integer i returns nothing
call Write(label + I2S(i))
endfunction
function WriteLoc takes string label, location l returns nothing
call Write(label + "(" + R2S(GetLocationX(l)) + ", " + R2S(GetLocationY(l)) + ")")
endfunction
function DisplayError takes player whichPlayer, string message returns nothing
local sound snd = CreateSound("Sound\\Interface\\Error.flac", false, false, true, 12700, 12700, "DefaultEAXON")
call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffffcc00" + message + "|r")
if (GetLocalPlayer() == whichPlayer) then
call StartSound(snd)
endif
call KillSoundWhenDone(snd)
endfunction
function ClearUnitTrainingQueue takes unit whichUnit returns nothing
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
call IssueImmediateOrderById(whichUnit, 851976)
endfunction
function GetFormattedTimeString takes real time returns string
local integer seconds = R2I(ModuloReal(time, 60.0))
local integer minutes = R2I(ModuloReal(time / 60.0, 60.0))
local integer hours = R2I(time / 3600.00)
local string timeFormat = ""
if (hours > 0) then
set timeFormat = timeFormat + I2S(hours) + ":"
if (minutes < 10) then
set timeFormat = timeFormat + "0"
endif
endif
set timeFormat = timeFormat + I2S(minutes) + ":"
if (seconds < 10) then
set timeFormat = timeFormat + "0"
endif
set timeFormat = timeFormat + I2S(seconds)
return timeFormat
endfunction
function SetUnitPathingSB takes unit whichUnit, boolean flag returns nothing
if (flag and GetUnitAbilityLevel(whichUnit, SB_NO_COLLISION) > 0) then
return
endif
call SetUnitPathing(whichUnit, flag)
endfunction
function CreateNUnitsAtLocSB takes integer count, integer unitId, player whichPlayer, location loc, real face returns group
local group created = CreateGroup()
loop
set count = count - 1
exitwhen count < 0
call GroupAddUnit(created, CreateUnitAtLoc(whichPlayer, unitId, loc, face))
endloop
return created
endfunction
function CreateNUnitsAtLocFacingLocSB takes integer count, integer unitId, player whichPlayer, location loc, location lookAt returns group
return CreateNUnitsAtLocSB(count, unitId, whichPlayer, loc, AngleBetweenPoints(loc, lookAt))
endfunction
function GetMissileHeight takes real arc, real d, real x returns real
if (d == 0.0) then
return 0.0
endif
return (4 * arc) * (d - x) * (x / d)
endfunction
function IsOrder takes integer orderId, string order returns boolean
return orderId == String2OrderIdBJ(order)
endfunction
function HashTableAddInteger takes hashtable ht, integer parentKey, integer childKey, integer add, boolean removeOnZero returns integer
local integer value = LoadInteger(ht, parentKey, childKey)
set value = value + add
if (value <= 0 and removeOnZero) then
call RemoveSavedInteger(ht, parentKey, childKey)
else
call SaveInteger(ht, parentKey, childKey, value)
endif
return value
endfunction
function HashTableAddReal takes hashtable ht, integer parentKey, integer childKey, real add, boolean removeOnZero returns real
local real value = LoadReal(ht, parentKey, childKey)
set value = value + add
if (value <= 0.0 and removeOnZero) then
call RemoveSavedReal(ht, parentKey, childKey)
else
call SaveReal(ht, parentKey, childKey, value)
endif
return value
endfunction
library MathUtil
function RMax takes real a, real b returns real
if (b > a) then
return b
else
return a
endif
endfunction
function RMin takes real a, real b returns real
if (b < a) then
return b
else
return a
endif
endfunction
function IMax takes integer a, integer b returns integer
if (b > a) then
return b
else
return a
endif
endfunction
function IMin takes integer a, integer b returns integer
if (b < a) then
return b
else
return a
endif
endfunction
function DistanceBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
function DistanceBetweenUnits takes unit unit1, unit unit2 returns real
local real dx = GetUnitX(unit2) - GetUnitX(unit1)
local real dy = GetUnitY(unit2) - GetUnitY(unit1)
return SquareRoot(dx * dx + dy * dy)
endfunction
function DistanceBetweenUnitAndPoint takes unit whichUnit, real x, real y returns real
return DistanceBetweenPointsXY(GetUnitX(whichUnit), GetUnitY(whichUnit), x, y)
endfunction
function SqrDistanceBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return dx * dx + dy * dy
endfunction
function SqrDistanceBetweenPoints takes location loc1, location loc2 returns real
return SqrDistanceBetweenPointsXY(GetLocationX(loc1), GetLocationY(loc1), GetLocationX(loc2), GetLocationY(loc2))
endfunction
function SqrDistanceBetweenUnits takes unit unit1, unit unit2 returns real
return SqrDistanceBetweenPointsXY(GetUnitX(unit1), GetUnitY(unit1), GetUnitX(unit2), GetUnitY(unit2))
endfunction
function SqrDistanceFromUnitToPoint takes unit whichUnit, real x, real y returns real
return SqrDistanceBetweenPointsXY(GetUnitX(whichUnit), GetUnitY(whichUnit), x, y)
endfunction
function DistanceFromUnitToPoint takes unit whichUnit, real x, real y returns real
local real sqrDist = SqrDistanceFromUnitToPoint(whichUnit, x, y)
return SquareRoot(sqrDist)
endfunction
function DistanceFromUnitToDestructable takes unit whichUnit, destructable whichDestructable returns real
return DistanceBetweenPointsXY(GetUnitX(whichUnit), GetUnitY(whichUnit), GetDestructableX(whichDestructable), GetDestructableY(whichDestructable))
endfunction
function AngleBetweenUnits takes unit unit1, unit unit2 returns real
return bj_RADTODEG * Atan2(GetUnitY(unit2) - GetUnitY(unit1), GetUnitX(unit2) - GetUnitX(unit1))
endfunction
function AngleBetweenPointsXY takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
function PolarProjectionX takes real sourceX, real dist, real angle returns real
return sourceX + dist * Cos(angle * bj_DEGTORAD)
endfunction
function PolarProjectionY takes real sourceY, real dist, real angle returns real
return sourceY + dist * Sin(angle * bj_DEGTORAD)
endfunction
function RandomRadius takes real center, real radius returns real
local real offset = GetRandomReal(-radius, radius)
return center + offset
endfunction
function RandomPointInCircle takes real centerX, real centerY, real radius returns location
return Location(RandomRadius(centerX, radius), RandomRadius(centerY, radius))
endfunction
function RandomPointInCircleLoc takes location center, real radius returns location
return Location(RandomRadius(GetLocationX(center), radius), RandomRadius(GetLocationY(center), radius))
endfunction
function RDefaultIfZero takes real maybeZero, real value, real default returns real
if (maybeZero == 0.0) then
return default
endif
return value
endfunction
function Ceil takes real val returns real
local integer int = R2I(val)
if (val == int) then
return val
elseif (val > 0.0) then
return I2R(int + 1)
endif
return I2R(int)
endfunction
function CeilToInt takes real val returns integer
local integer int = R2I(val)
if (val != int and val > 0.0) then
return int + 1
endif
return int
endfunction
function DBZ takes real dividend, real divisor, real defaultValue returns real
if (divisor == 0.0) then
return defaultValue
endif
return dividend / divisor
endfunction
function RClamp takes real value, real min, real max returns real
return RMaxBJ(RMinBJ(value, max), min)
endfunction
endlibrary
function IsPlayingPlayer takes player whichPlayer, boolean usersOnly returns boolean
return GetPlayerSlotState(whichPlayer) == PLAYER_SLOT_STATE_PLAYING and (not usersOnly or GetPlayerController(whichPlayer) == MAP_CONTROL_USER)
endfunction
function AddPlayerState takes player p, playerstate whichState, integer value returns nothing
call SetPlayerState(p, whichState, GetPlayerState(p, whichState) + value)
endfunction
function GetPlayingPlayers takes boolean usersOnly, boolean includeLeft, boolean includeNeutrals returns force
local force players = CreateForce()
local player pickedPlayer = null
local integer pIndex = 0
local integer pCount = GetBJMaxPlayers()
if (includeNeutrals) then
set pCount = pCount + 4
endif
loop
exitwhen pIndex >= pCount
set pickedPlayer = Player(pIndex)
if (usersOnly and GetPlayerController(pickedPlayer) != MAP_CONTROL_USER) then
// Do nothing
elseif (IsPlayerSlotState(pickedPlayer, PLAYER_SLOT_STATE_PLAYING)) then
call ForceAddPlayer(players, pickedPlayer)
elseif (includeNeutrals and (GetPlayerController(pickedPlayer) == MAP_CONTROL_NEUTRAL or GetPlayerController(pickedPlayer) == MAP_CONTROL_CREEP)) then
call ForceAddPlayer(players, pickedPlayer)
elseif (includeLeft and IsPlayerSlotState(pickedPlayer, PLAYER_SLOT_STATE_LEFT)) then
call ForceAddPlayer(players, pickedPlayer)
endif
set pIndex = pIndex + 1
endloop
return players
endfunction
function GetObservers takes nothing returns force
local force f = CreateForce()
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYERS
if (IsPlayerObserver(Player(i))) then
call ForceAddPlayer(f, Player(i))
endif
set i = i + 1
endloop
return f
endfunction
function GetPlayerNameColored takes player p returns string
local integer playerNumber = GetConvertedPlayerId(p)
return udg_String_PlayerColors[playerNumber] + GetPlayerName(p) + "|r"
endfunction
function PlayerHasTech takes player p, integer techId returns boolean
return GetPlayerTechCount(p, techId, true) > 0
endfunction
function SpellbringerFilter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitType(filter, UNIT_TYPE_HERO)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
function GetPlayerSpellbringers takes player p returns group
return GetUnitsOfPlayerMatching(p, Condition(function SpellbringerFilter))
endfunction
function CountSpellbringersForPlayer takes player p returns integer
local integer raceNumber = 1
local integer count = 0
loop
exitwhen raceNumber > udg_Int_RaceCount
set count = count + CountLivingPlayerUnitsOfTypeId(udg_UnitType_Spellbringer[raceNumber], p)
set raceNumber = raceNumber + 1
endloop
return count
endfunction
function GetSpellbringerLevelByTech takes player p, integer raceNumber returns integer
if (PlayerHasTech(p, udg_TechType_Level3SBSpell[raceNumber])) then
return 3
elseif (PlayerHasTech(p, udg_TechType_Level2SBSpell[raceNumber])) then
return 2
else
return 1
endif
endfunction
function GetAllPlayersExcept takes player whichPlayer returns force
local force players = CreateForce()
local player p = null
local integer playerIndex = 0
loop
exitwhen playerIndex >= bj_MAX_PLAYERS
set p = Player(playerIndex)
if (p != whichPlayer) then
call ForceAddPlayer(players, p)
endif
set playerIndex = playerIndex + 1
endloop
return players
endfunction
function GetPlayersSelectingUnit takes unit whichUnit returns force
local force result = CreateForce()
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYERS
if (IsUnitSelected(whichUnit, Player(i))) then
call ForceAddPlayer(result, Player(i))
endif
set i = i + 1
endloop
return result
endfunction
function TransferUnitSelection takes unit sourceUnit, unit targetUnit returns nothing
local integer i = 0
local player p = null
loop
exitwhen i >= bj_MAX_PLAYERS
set p = Player(i)
if (IsUnitSelected(sourceUnit, p)) then
call SelectUnitRemoveForPlayer(sourceUnit, p)
call SelectUnitAddForPlayer(targetUnit, p)
endif
set i = i + 1
endloop
endfunction
globals
constant key KEY_TARGETED_AS
endglobals
function GetUnitAbilityIntegerLevelField takes unit whichUnit, integer abilityId, abilityintegerlevelfield whichField returns integer
return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(whichUnit, abilityId), whichField, GetUnitAbilityLevel(whichUnit, abilityId) - 1)
endfunction
function GetUnitAbilityRealLevelField takes unit whichUnit, integer abilityId, abilityreallevelfield whichField returns real
return BlzGetAbilityRealLevelField(BlzGetUnitAbility(whichUnit, abilityId), whichField, GetUnitAbilityLevel(whichUnit, abilityId) - 1)
endfunction
function GetUnitAbilityStringLevelField takes unit whichUnit, integer abilityId, abilitystringlevelfield whichField returns string
return BlzGetAbilityStringLevelField(BlzGetUnitAbility(whichUnit, abilityId), whichField, GetUnitAbilityLevel(whichUnit, abilityId) - 1)
endfunction
function GetUnitAbilityIntegerField takes unit whichUnit, integer abilityId, abilityintegerfield whichfield returns integer
return BlzGetAbilityIntegerField(BlzGetUnitAbility(whichUnit, abilityId), whichfield)
endfunction
function GetUnitAbilityRealField takes unit whichUnit, integer abilityId, abilityrealfield whichfield returns real
return BlzGetAbilityRealField(BlzGetUnitAbility(whichUnit, abilityId), whichfield)
endfunction
function GetUnitAbilityStringField takes unit whichUnit, integer abilityId, abilitystringfield whichField returns string
return BlzGetAbilityStringField(BlzGetUnitAbility(whichUnit, abilityId), whichField)
endfunction
function SetUnitAbilityBooleanField takes unit whichUnit, integer abilityId, abilitybooleanfield whichfield, boolean value returns boolean
return BlzSetAbilityBooleanField(BlzGetUnitAbility(whichUnit, abilityId), whichfield, value)
endfunction
function SetUnitAbilityIntegerField takes unit whichUnit, integer abilityId, abilityintegerfield whichField, integer value returns nothing
call BlzSetAbilityIntegerField(BlzGetUnitAbility(whichUnit, abilityId), whichField, value)
endfunction
function SetUnitAbilityRealLevelField takes unit whichUnit, integer abilityId, abilityreallevelfield whichField, real value returns nothing
call BlzSetAbilityRealLevelField(BlzGetUnitAbility(whichUnit, abilityId), whichField, GetUnitAbilityLevel(whichUnit, abilityId) - 1, value)
endfunction
function SetUnitAbilityIntegerLevelField takes unit whichUnit, integer abilityId, abilityintegerlevelfield whichField, integer value returns nothing
call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(whichUnit, abilityId), whichField, GetUnitAbilityLevel(whichUnit, abilityId) - 1, value)
endfunction
function IsUnitWard takes unit whichUnit returns boolean
local integer classification = BlzGetUnitIntegerField(whichUnit, UNIT_IF_UNIT_CLASSIFICATION)
return (BlzBitAnd(classification, GetHandleId(UNIT_CATEGORY_WARD)) != 0)
endfunction
function IsUnitNonNeutralAlly takes unit whichUnit, player whichPlayer returns boolean
local player unitOwner = GetOwningPlayer(whichUnit)
return IsPlayerAlly(unitOwner, whichPlayer) and unitOwner != Player(PLAYER_NEUTRAL_PASSIVE)
endfunction
function IsUnitGoldHarvester takes unit whichUnit returns boolean
if (GetUnitAbilityLevel(whichUnit, SB_HARVEST_GOLD_AND_LUMBER) > 0) then
return true
elseif (GetUnitAbilityLevel(whichUnit, SB_HARVEST_GOLD_ONLY) > 0) then
return true
elseif (GetUnitAbilityLevel(whichUnit, SB_HARVEST_ORDER_SUPER_PEASANT) > 0) then
return true
elseif (GetUnitAbilityLevel(whichUnit, SB_HARVEST_GOLD_AND_LUMBER_MAGIC) > 0) then
return true
else
return false
endif
endfunction
function UnitHasAbility takes unit whichUnit, integer abilityId returns boolean
return GetUnitAbilityLevel(whichUnit, abilityId) > 0
endfunction
function IsZombieLike takes unit whichUnit returns boolean
local integer unitType = GetUnitTypeId(whichUnit)
return unitType == SB_ZOMBIE or unitType == SB_FLESHLESS_ZOMBIE or unitType == SB_FLESH_GOLEM
endfunction
function IsUnitAlive takes unit whichUnit returns boolean
if (whichUnit != null) then
return not IsUnitType(whichUnit, UNIT_TYPE_DEAD)
endif
return false
endfunction
function GetSpellbringerRace takes unit sb returns integer
local integer raceNumber = 1
loop
exitwhen raceNumber > udg_Int_RaceCount
if (GetUnitTypeId(sb) == udg_UnitType_Spellbringer[raceNumber]) then
return raceNumber
endif
set raceNumber = raceNumber + 1
endloop
return -1
endfunction
function ChangeUnitState takes unit whichUnit, unitstate whichUnitState, real change returns nothing
if (whichUnitState == UNIT_STATE_MAX_LIFE) then
call BlzSetUnitMaxHP(whichUnit, BlzGetUnitMaxHP(whichUnit) + R2I(change))
elseif (whichUnitState == UNIT_STATE_MAX_MANA) then
call BlzSetUnitMaxMana(whichUnit, BlzGetUnitMaxMana(whichUnit) + R2I(change))
else
call SetUnitState(whichUnit, whichUnitState, GetUnitState(whichUnit, whichUnitState) + change)
endif
endfunction
function GetUnitsMiningMine takes unit mine returns integer
return LoadInteger(udg_HashTable_UnitInfo, GetHandleId(mine), StringHash("NUM MINERS"))
endfunction
function GetUnitMinWeaponDamage takes unit whichUnit, integer weaponIndex returns integer
local integer base = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, weaponIndex)
local integer numDice = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_NUMBER_OF_DICE, weaponIndex)
return base + numDice
endfunction
function GetUnitMaxWeaponDamage takes unit whichUnit, integer weaponIndex returns integer
local integer base = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, weaponIndex)
local integer numDice = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_NUMBER_OF_DICE, weaponIndex)
local integer diceSides = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_SIDES_PER_DIE, weaponIndex)
return base + (numDice * diceSides)
endfunction
function GetUnitDamageRoll takes unit whichUnit, integer weaponIndex returns integer
local integer min = GetUnitMinWeaponDamage(whichUnit, weaponIndex)
local integer max = GetUnitMaxWeaponDamage(whichUnit, weaponIndex)
return GetRandomInt(min, max)
endfunction
function GetUnitAttackRange takes unit whichUnit, integer weaponIndex returns real
return BlzGetUnitWeaponRealField(whichUnit, UNIT_WEAPON_RF_ATTACK_RANGE, weaponIndex)
endfunction
function SetUnitAttackRange takes unit whichUnit, integer weaponIndex, real range returns nothing
local real currentRange1 = GetUnitAttackRange(whichUnit, weaponIndex)
local real currentRange2 = GetUnitAttackRange(whichUnit, weaponIndex + 1)
call BlzSetUnitWeaponRealField(whichUnit, UNIT_WEAPON_RF_ATTACK_RANGE, weaponIndex + 1, range - currentRange1 + currentRange2)
endfunction
function UnitAddBaseWeaponDamage takes unit whichUnit, integer weaponIndex, integer damageAmt returns nothing
local integer base = BlzGetUnitWeaponIntegerField(whichUnit, UNIT_WEAPON_IF_ATTACK_DAMAGE_BASE, weaponIndex)
call BlzSetUnitBaseDamage(whichUnit, base + damageAmt, weaponIndex)
endfunction
function UnitSimulateAttack takes unit attacker, unit victim, integer weaponIndex returns nothing
local integer damage = GetUnitDamageRoll(attacker, weaponIndex)
local attacktype aType = ConvertAttackType(BlzGetUnitWeaponIntegerField(attacker, UNIT_WEAPON_IF_ATTACK_ATTACK_TYPE, weaponIndex))
local weapontype wType = ConvertWeaponType(BlzGetUnitWeaponIntegerField(attacker, UNIT_WEAPON_IF_ATTACK_WEAPON_SOUND, weaponIndex))
call UnitDamageTarget(attacker, victim, damage, true, true, aType, DAMAGE_TYPE_NORMAL, wType)
endfunction
function EnableUnitFlyHeight takes unit whichUnit returns nothing
call UnitAddAbility(whichUnit, 'Arav')
call UnitRemoveAbility(whichUnit, 'Arav')
endfunction
function UnitRemoveSlows takes unit whichUnit returns nothing
local integer i = 0
loop
exitwhen i >= BUFFS_THAT_SLOW_SIZE
loop
exitwhen not UnitHasBuffBJ(whichUnit, BUFFS_THAT_SLOW[i]) or not UnitRemoveBuffBJ(BUFFS_THAT_SLOW[i], whichUnit)
endloop
set i = i + 1
endloop
endfunction
function UnitApplyFakeBuff takes unit whichUnit, integer abilityId, integer buffId, real duration returns nothing
call UnitAddAbility(whichUnit, abilityId)
call UnitRemoveAbilityDelayed.execute(whichUnit, abilityId, buffId, duration)
endfunction
function UnitRemoveAbilityDelayed takes unit whichUnit, integer abilityId, integer buffId, real duration returns nothing
call TriggerSleepAction(duration)
call UnitRemoveAbility(whichUnit, abilityId)
call UnitRemoveBuffBJ(buffId, whichUnit)
endfunction
function UnitSetMoveType takes unit whichUnit, movetype whichMoveType returns nothing
call BlzSetUnitIntegerField(whichUnit, UNIT_IF_MOVE_TYPE, GetHandleId(whichMoveType))
endfunction
function SetUnitTargetedAsFlying takes unit whichUnit returns nothing
local integer originalTargetedAs = 0
local integer newTargetedAs = 0
if (HaveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_TARGETED_AS)) then
set originalTargetedAs = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_TARGETED_AS)
else
set originalTargetedAs = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TARGETED_AS)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_TARGETED_AS, originalTargetedAs)
endif
set newTargetedAs = BlzBitXor(BlzBitOr(originalTargetedAs, GetHandleId(TARGET_FLAG_AIR)), GetHandleId(TARGET_FLAG_GROUND))
call BlzSetUnitIntegerField(whichUnit, UNIT_IF_TARGETED_AS, newTargetedAs)
endfunction
function RestoreUnitTargetedAs takes unit whichUnit returns nothing
local integer originalTargetedAs = 0
if (HaveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_TARGETED_AS)) then
set originalTargetedAs = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_TARGETED_AS)
call BlzSetUnitIntegerField(whichUnit, UNIT_IF_TARGETED_AS, originalTargetedAs)
endif
endfunction
function UnitAddCategory takes unit whichUnit, unitcategory category returns nothing
local integer categories = BlzGetUnitIntegerField(whichUnit, UNIT_IF_UNIT_CLASSIFICATION)
set categories = BlzBitOr(categories, GetHandleId(category))
call BlzSetUnitIntegerField(whichUnit, UNIT_IF_UNIT_CLASSIFICATION, categories)
endfunction
function IsUnitInAOE takes unit whichUnit,real x,real y,real radius returns boolean
return DistanceBetweenPointsXY(GetUnitX(whichUnit) , GetUnitY(whichUnit) , x , y) <= radius + BlzGetUnitCollisionSize(whichUnit)
endfunction
function SetUnitAnimationByIndexDelayed_Impl takes unit whichUnit, integer whichAnimation, real delay, real timeScale returns nothing
call TriggerSleepAction(delay)
call SetUnitAnimationByIndex(whichUnit, whichAnimation)
call SetUnitTimeScale(whichUnit, timeScale)
endfunction
function SetUnitAnimationByIndexDelayedWithTimeScale takes unit whichUnit, integer whichAnimation, real delay, real timeScale returns nothing
call SetUnitAnimationByIndexDelayed_Impl.execute(whichUnit, whichAnimation, delay, timeScale)
endfunction
function SetUnitAnimationByIndexDelayed takes unit whichUnit, integer whichAnimation, real delay returns nothing
call SetUnitAnimationByIndexDelayed_Impl.execute(whichUnit, whichAnimation, delay, 1.0)
endfunction
function UnitDisableAbilitySB takes unit whichUnit, integer abilityId, boolean disable returns nothing
call BlzUnitDisableAbility(whichUnit, abilityId, disable, false)
if (not disable) then
call BlzUnitHideAbility(whichUnit, abilityId, true) // This is so we dont touch the internal "hide" stack counter
endif
endfunction
function SetUnitPositionExact takes unit u, real x, real y returns nothing
local integer gridSize = 0
if (IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
call SetUnitPosition(u, x, y)
else
set gridSize = R2I(BlzGetUnitCollisionSize(u)) / 16
if (gridSize == 1 or gridSize >= 3) then
call SetUnitPosition(u, x + 16, y + 16)
else
call SetUnitPosition(u, x, y)
endif
endif
endfunction
function GetUnitXExact takes unit u returns real
local integer gridSize = 0
if (IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
return GetUnitX(u)
endif
set gridSize = R2I(BlzGetUnitCollisionSize(u)) / 16
if (gridSize == 1 or gridSize >= 3) then
return GetUnitX(u) - 16
endif
return GetUnitX(u)
endfunction
function GetUnitYExact takes unit u returns real
local integer gridSize = 0
if (IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
return GetUnitY(u)
endif
set gridSize = R2I(BlzGetUnitCollisionSize(u)) / 16
if (gridSize == 1 or gridSize >= 3) then
return GetUnitY(u) - 16
endif
return GetUnitY(u)
endfunction
function IssueImmediateOrderAfter takes unit whichUnit, string order, real seconds returns nothing
call IssueImmediateOrderAfter_Impl.execute(whichUnit, order, seconds)
endfunction
function IssueImmediateOrderAfter_Impl takes unit whichUnit, string order, real seconds returns nothing
call TriggerSleepAction(seconds)
call IssueImmediateOrder(whichUnit, order)
endfunction
function IssuePointOrderByIdAfter takes unit whichUnit, integer orderId, real x, real y, real seconds returns nothing
call IssuePointOrderByIdAfter_Impl.execute(whichUnit, orderId, x, y, seconds)
endfunction
function IssuePointOrderByIdAfter_Impl takes unit whichUnit, integer orderId, real x, real y, real seconds returns nothing
call TriggerSleepAction(seconds)
call IssuePointOrderById(whichUnit, orderId, x, y)
endfunction
function IssueTargetOrderByIdAfter takes unit whichUnit, integer orderId, widget target, real seconds returns nothing
call IssueTargetOrderByIdAfter_Impl.execute(whichUnit, orderId, target, seconds)
endfunction
function IssueTargetOrderByIdAfter_Impl takes unit whichUnit, integer orderId, widget target, real seconds returns nothing
call TriggerSleepAction(seconds)
call IssueTargetOrderById(whichUnit, orderId, target)
endfunction
function IsHarvestOrder takes integer orderId, unit ordered, unit orderTargetUnit returns boolean
if (not UnitHasAbility(orderTargetUnit, SB_GOLD_MINE_ABILITY)) then
return false
elseif (not IsUnitGoldHarvester(ordered)) then
return false
elseif (orderId != SB_ORDER_HARVEST and orderId != SB_ORDER_SMART) then
return false
endif
return true
endfunction
function IsReturnGoldOrder takes integer orderId, unit ordered, unit orderTargetUnit returns boolean
if (not IsUnitGoldHarvester(ordered)) then
return false
elseif (orderId == SB_ORDER_RESUME_HARVESTING) then
return true
elseif (orderId != SB_ORDER_SMART) then
return false
elseif (not UnitHasAbility(orderTargetUnit, SB_RETURN_GOLD) and not UnitHasAbility(orderTargetUnit, SB_RETURN_GOLD_AND_LUMBER)) then
return false
endif
return true
endfunction
function IsRepairOrder takes integer orderId, unit ordered, unit orderTargetUnit returns boolean
if (orderId == SB_ORDER_REPAIR) then
return true
elseif (orderId == SB_ORDER_SMART) then
if (not IsUnitNonNeutralAlly(ordered, GetOwningPlayer(orderTargetUnit))) then
return false
elseif (GetUnitLifePercent(orderTargetUnit) >= 100.0) then
return false
elseif (IsUnitType(orderTargetUnit, UNIT_TYPE_MECHANICAL)) then
if (UnitHasAbility(ordered, SB_RENEW)) then
return true
elseif (UnitHasAbility(ordered, SB_RENEW_SAPLING)) then
return true
elseif (UnitHasAbility(ordered, SB_REPAIR)) then
return true
elseif (UnitHasAbility(ordered, SB_REPAIR_HUMAN)) then
return true
elseif (UnitHasAbility(ordered, SB_RESTORE)) then
return true
elseif (UnitHasAbility(ordered, SB_RESTORE_LOST_SOUL)) then
return true
elseif (UnitHasAbility(ordered, SB_RESTORE_NECRO)) then
return true
endif
return false
elseif (IsUnitType(orderTargetUnit, UNIT_TYPE_STRUCTURE)) then
if (UnitHasAbility(ordered, SB_RENEW)) then
return true
elseif (UnitHasAbility(ordered, SB_RENEW_SAPLING)) then
return true
endif
endif
endif
return false
endfunction
function IsBuildOrder takes integer orderId returns boolean
return IsUnitIdType(orderId, UNIT_TYPE_STRUCTURE)
endfunction
scope GroupUtils
globals
private integer COUNT = 0
private UnitCondition UNIT_CONDITION = 0
private integer UNIT_TYPE_ID = 0
private integer FOR_GROUP_INT_DATA = 0
private integer FOR_GROUP_INT_ACTION = 0
endglobals
function CountUnitsInGroupWithAbility takes group whichGroup, integer abilityId returns integer
local integer size = BlzGroupGetSize(whichGroup)
local integer index = 0
local integer count = 0
local unit pickedUnit = null
loop
exitwhen index >= size
if (GetUnitAbilityLevel(BlzGroupUnitAt(whichGroup, index), abilityId) > 0) then
set count = count + 1
endif
set index = index + 1
endloop
return count
endfunction
private function CountUnitsInGroupOfTypeIdLoop takes nothing returns nothing
if (GetUnitTypeId(GetEnumUnit()) == UNIT_TYPE_ID) then
set COUNT = COUNT + 1
endif
endfunction
function CountUnitsInGroupOfTypeId takes group whichGroup, integer unitTypeId returns integer
set COUNT = 0
set UNIT_TYPE_ID = unitTypeId
call ForGroup(whichGroup, function CountUnitsInGroupOfTypeIdLoop)
return COUNT
endfunction
private function CountUnitsInGroupMatchingLoop takes nothing returns nothing
if (UNIT_CONDITION.evaluate(GetEnumUnit())) then
set COUNT = COUNT + 1
endif
endfunction
function CountUnitsInGroupMatching takes group whichGroup, UnitCondition condition returns integer
set COUNT = 0
set UNIT_CONDITION = condition
call ForGroup(whichGroup, function CountUnitsInGroupMatchingLoop)
return COUNT
endfunction
function GetUnitsInRectWithAbility takes rect r, integer abilityId returns group
local group g = GetUnitsInRectAll(r)
local group result = CreateGroup()
local unit picked = null
loop
set picked = FirstOfGroup(g)
exitwhen picked == null
if (GetUnitAbilityLevel(picked, abilityId) > 0) then
call GroupAddUnit(result, picked)
endif
call GroupRemoveUnit(g, picked)
endloop
call DestroyGroup(g)
return result
endfunction
function GetUnitsOfPlayerWithAbility takes player p, integer abilityId returns group
local group g = GetUnitsOfPlayerAll(p)
local group result = CreateGroup()
local unit picked = null
loop
set picked = FirstOfGroup(g)
exitwhen picked == null
if (GetUnitAbilityLevel(picked, abilityId) > 0) then
call GroupAddUnit(result, picked)
endif
call GroupRemoveUnit(g, picked)
endloop
call DestroyGroup(g)
return result
endfunction
function GetUnitInGroupOfType takes group g, integer unitTypeId returns unit
local integer size = BlzGroupGetSize(g)
local integer index = 0
local unit pickedUnit = null
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(g, index)
if (GetUnitTypeId(pickedUnit) == unitTypeId) then
return pickedUnit
endif
set index = index + 1
endloop
return null
endfunction
private function UnitsWithAbilityFilter_Impl takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), udg_Int_Temp)
endfunction
function UnitsWithAbilityFilter takes integer abilityId returns conditionfunc
set udg_Int_Temp = abilityId
return Condition(function UnitsWithAbilityFilter_Impl)
endfunction
function GoldMineFilter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == SB_GOLD_MINE
endfunction
function GroupPickClosestUnitMatching takes group g, real x, real y, UnitCondition filter returns unit
local integer size = BlzGroupGetSize(g)
local integer index = 0
local unit pickedUnit = null
local unit resultUnit = null
local real unitX = 0.0
local real unitY = 0.0
local real minDist = BIG_REAL
local real dist = 0.0
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(g, index)
if (filter == 0 or filter.evaluate(pickedUnit)) then
set unitX = GetUnitX(pickedUnit)
set unitY = GetUnitY(pickedUnit)
set dist = SqrDistanceBetweenPointsXY(unitX, unitY, x, y)
if (dist < minDist) then
set minDist = dist
set resultUnit = pickedUnit
endif
endif
set index = index + 1
endloop
return resultUnit
endfunction
function GroupPickClosestUnit takes group g, real x, real y returns unit
return GroupPickClosestUnitMatching(g, x, y, 0)
endfunction
function GroupPickFurthestUnitMatching takes group g, real x, real y, UnitCondition filter returns unit
local integer size = BlzGroupGetSize(g)
local integer index = 0
local unit pickedUnit = null
local unit resultUnit = null
local real unitX = 0.0
local real unitY = 0.0
local real maxDist = 0.0
local real dist = 0.0
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(g, index)
if (filter == 0 or filter.evaluate(pickedUnit)) then
set unitX = GetUnitX(pickedUnit)
set unitY = GetUnitY(pickedUnit)
set dist = SqrDistanceBetweenPointsXY(unitX, unitY, x, y)
if (dist > maxDist) then
set maxDist = dist
set resultUnit = pickedUnit
endif
endif
set index = index + 1
endloop
return resultUnit
endfunction
function GroupPickFurthestUnit takes group g, real x, real y returns unit
return GroupPickFurthestUnitMatching(g, x, y, 0)
endfunction
private function KillGroupLoop takes nothing returns nothing
call KillUnit(GetEnumUnit())
endfunction
function KillGroup takes group g returns nothing
call ForGroup(g, function KillGroupLoop)
endfunction
private function ForGroupIntAction takes nothing returns nothing
local IntFunc action = FOR_GROUP_INT_ACTION
local integer input = FOR_GROUP_INT_DATA
call action.evaluate(input)
endfunction
function ForGroupInt takes group g, IntFunc action, integer input returns nothing
set FOR_GROUP_INT_ACTION = action
set FOR_GROUP_INT_DATA = input
call ForGroup(g, function ForGroupIntAction)
endfunction
endscope
scope TriggerUtil
globals
private constant hashtable HT_TRIGGERS = InitHashtable()
private constant key KEY_SPELL_ABILITY
endglobals
function interface ItemAbilityCallback takes ability a returns nothing
private function SpellCondition takes nothing returns boolean
local integer abilityId = LoadInteger(HT_TRIGGERS, GetHandleId(GetTriggeringTrigger()), KEY_SPELL_ABILITY)
return GetSpellAbilityId() == abilityId
endfunction
function CreateSpellBeginTrigger takes integer abilityId, code action returns trigger
local trigger t = CreateTrigger()
call SaveInteger(HT_TRIGGERS, GetHandleId(t), KEY_SPELL_ABILITY, abilityId)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition(function SpellCondition))
call TriggerAddAction(t, action)
return t
endfunction
function CreateSpellChannelTrigger takes integer abilityId, code action returns trigger
local trigger t = CreateTrigger()
call SaveInteger(HT_TRIGGERS, GetHandleId(t), KEY_SPELL_ABILITY, abilityId)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddCondition(t, Condition(function SpellCondition))
call TriggerAddAction(t, action)
return t
endfunction
function CreateSpellEffectTrigger takes integer abilityId, code action returns trigger
local trigger t = CreateTrigger()
call SaveInteger(HT_TRIGGERS, GetHandleId(t), KEY_SPELL_ABILITY, abilityId)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function SpellCondition))
call TriggerAddAction(t, action)
return t
endfunction
function CreateSpellCancelTrigger takes integer abilityId, code action returns trigger
local trigger t = CreateTrigger()
call SaveInteger(HT_TRIGGERS, GetHandleId(t), KEY_SPELL_ABILITY, abilityId)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerAddCondition(t, Condition(function SpellCondition))
call TriggerAddAction(t, action)
return t
endfunction
function CreateSpellFinishTrigger takes integer abilityId, code action returns trigger
local trigger t = CreateTrigger()
call SaveInteger(HT_TRIGGERS, GetHandleId(t), KEY_SPELL_ABILITY, abilityId)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(t, Condition(function SpellCondition))
call TriggerAddAction(t, action)
return t
endfunction
function CreateAnyUnitTrigger takes playerunitevent ev, code condition, code action returns trigger
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, ev)
call TriggerAddCondition(t, Condition(condition))
call TriggerAddAction(t, action)
return t
endfunction
endscope
globals
constant integer AUDIO_CHANNEL_GENERAL = 0
constant integer AUDIO_CHANNEL_UNIT_SELECTION = 1
constant integer AUDIO_CHANNEL_UNIT_ACKNOWLEDEGMENT = 2
constant integer AUDIO_CHANNEL_UNIT_MOVEMENT = 3
constant integer AUDIO_CHANNEL_UNIT_READY = 4
constant integer AUDIO_CHANNEL_COMBAT = 5
constant integer AUDIO_CHANNEL_ERROR = 6
constant integer AUDIO_CHANNEL_MUSIC = 7
constant integer AUDIO_CHANNEL_USER_INTERFACE = 8
constant integer AUDIO_CHANNEL_LOOPING_MOVEMENT = 9
constant integer AUDIO_CHANNEL_LOOPING_AMBIENT = 10
constant integer AUDIO_CHANNEL_ANIMATIONS = 11
constant integer AUDIO_CHANNEL_CONSTRUCTION = 12
constant integer AUDIO_CHANNEL_BIRTH = 13
constant integer AUDIO_CHANNEL_FIRE = 14
constant integer AUDIO_CHANNEL_LEGACY_MIDI = 15
constant integer AUDIO_CHANNEL_CINEMATIC_GENERAL = 16
constant integer AUDIO_CHANNEL_CINEMATIC_AMBIENT = 17
constant integer AUDIO_CHANNEL_CINEMATIC_MUSIC = 18
constant integer AUDIO_CHANNEL_CINEMATIC_DIALOG = 19
constant integer AUDIO_CHANNEL_CINEMATIC_SFX1 = 20
constant integer AUDIO_CHANNEL_CINEMATIC_SFX2 = 21
constant integer AUDIO_CHANNEL_CINEMATIC_SFX3 = 22
endglobals
function PlayPitchedSound takes string fileName, integer volume, real pitch returns nothing
local sound soundHandle = CreateSound(fileName, false, false, true, 12700, 12700, "")
call SetSoundVolume(soundHandle, volume)
call SetSoundPitch(soundHandle, pitch)
call StartSound(soundHandle)
call KillSoundWhenDone(soundHandle)
endfunction
function PlayPitchedSoundAtPositionSB takes string fileName, string eaxSetting, integer channel, real x, real y, real volume, real pitch returns nothing
local sound snd = CreateSound(fileName, false, true, true, 1, 1, eaxSetting)
call SetSoundChannel(snd, channel)
call SetSoundPosition(snd, x, y, 0.0)
call SetSoundVolumeBJ(snd, volume)
call SetSoundPitch(snd, pitch)
call StartSound(snd)
call KillSoundWhenDone(snd)
endfunction
function PlaySoundAtPositionSB takes string fileName, string eaxSetting, integer channel, real x, real y, real volume returns nothing
call PlayPitchedSoundAtPositionSB(fileName, eaxSetting, channel, x, y, volume, 1.0)
endfunction
function PlayPitchedSoundAtPointSB takes string fileName, string eaxSetting, integer channel, location point, real volume, real pitch returns nothing
call PlayPitchedSoundAtPositionSB(fileName, eaxSetting, channel, GetLocationX(point), GetLocationY(point), volume, pitch)
endfunction
function PlaySoundAtPointSB takes string fileName, string eaxSetting, integer channel, location point, real volume returns nothing
call PlayPitchedSoundAtPointSB(fileName, eaxSetting, channel, point, volume, 1.0)
endfunction
function PlaySoundForPlayer takes string fileName, player p returns nothing
local sound snd = CreateSound(fileName, false, false, true, 12700, 12700, "")
if (p == GetLocalPlayer()) then
call PlaySoundBJ(snd)
endif
call KillSoundWhenDone(snd)
endfunction
library EffectUtil requires TimersPlus
globals
private constant hashtable HT = InitHashtable()
private constant hashtable HT_THROTTLED_EFFECTS = InitHashtable()
private constant key KEY_THROTTLE_UNIT
private constant key KEY_THROTTLE_TIMER
private constant string AREA_INDICATOR_ART = "war3mapImported\\Spell Marker TC.mdx"
private constant real AREA_INDICATOR_RADIUS_AT_NORMAL_SCALE = 100.0
endglobals
function AddSpecialEffectOneShotWithZ takes string modelName, real x, real y, real z returns nothing
local effect e = AddSpecialEffect(modelName, x, y)
call BlzSetSpecialEffectZ(e, z)
call DestroyEffect(e)
endfunction
function AddSpecialEffectOneShot takes string modelName, real x, real y returns nothing
call DestroyEffect(AddSpecialEffect(modelName, x, y))
endfunction
function AddSpecialEffectOneShotEx takes string modelName, real x, real y, real height, real scale, real timeScale returns nothing
local effect e = AddSpecialEffect(modelName, x, y)
call BlzSetSpecialEffectHeight(e, height)
call BlzSetSpecialEffectScale(e, scale)
call BlzSetSpecialEffectTimeScale(e, timeScale)
call DestroyEffect(e)
endfunction
function AddSpecialEffectTargetOneShot takes string modelName, widget target, string attachmentPoint returns nothing
call DestroyEffect(AddSpecialEffectTarget(modelName, target, attachmentPoint))
endfunction
private function EndEffectCooldown takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit whichUnit = LoadUnitHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_UNIT, GetHandleId(t))
call RemoveSavedHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_UNIT, GetHandleId(t))
call RemoveSavedHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_TIMER, GetHandleId(whichUnit))
call DestroyTimer(t)
endfunction
function AddSpecialEffectTargetOneShotThrottled takes string modelName, unit target, string attachmentPoint, real cooldown returns nothing
local timer t = LoadTimerHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_TIMER, GetHandleId(target))
if (t == null) then
set t = CreateTimer()
call SaveTimerHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_TIMER, GetHandleId(target), t)
call SaveUnitHandle(HT_THROTTLED_EFFECTS, KEY_THROTTLE_UNIT, GetHandleId(t), target)
call TimerStart(t, cooldown, false, function EndEffectCooldown)
call AddSpecialEffectTargetOneShot(modelName, target, attachmentPoint)
endif
endfunction
private function AddSpecialEffectTargetOneShotDelayed_Impl takes string modelName, widget target, string attachmentPoint, real delay returns nothing
call TriggerSleepAction(delay)
call AddSpecialEffectTargetOneShot(modelName, target, attachmentPoint)
endfunction
function AddSpecialEffectTargetOneShotDelayed takes string modelName, widget target, string attachmentPoint, real delay returns nothing
call AddSpecialEffectTargetOneShotDelayed_Impl.execute(modelName, target, attachmentPoint, delay)
endfunction
function DestroyKeyedEffect takes integer parentKey, integer childKey returns nothing
local effect e = LoadEffectHandle(HT, parentKey, childKey)
call DestroyEffect(e)
call RemoveSavedHandle(HT, parentKey, childKey)
endfunction
function AddKeyedEffect takes string modelName, real x, real y, integer parentKey, integer childKey returns effect
local effect e = null
call DestroyKeyedEffect(parentKey, childKey)
set e = AddSpecialEffect(modelName, x, y)
call SaveEffectHandle(HT, parentKey, childKey, e)
return e
endfunction
function AddKeyedEffectTarget takes string modelName, widget target, string attachmentPoint, integer parentKey, integer childKey returns effect
local effect e = null
call DestroyKeyedEffect(parentKey, childKey)
set e = AddSpecialEffectTarget(modelName, target, attachmentPoint)
call SaveEffectHandle(HT, parentKey, childKey, e)
return e
endfunction
struct AreaIndicator
unit target = null
effect indicator = null
IntTimer followTimer = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(indicator)
call followTimer.destroy()
endmethod
endstruct
function CreateAreaIndicator takes player owner, real x, real y, real radius returns AreaIndicator
local AreaIndicator ae = AreaIndicator.create()
set ae.indicator = AddSpecialEffect(AREA_INDICATOR_ART, x, y)
call BlzSetSpecialEffectColorByPlayer(ae.indicator, owner)
call BlzSetSpecialEffectScale(ae.indicator, radius / AREA_INDICATOR_RADIUS_AT_NORMAL_SCALE)
return ae
endfunction
private function AreaIndicatorUpdate takes IntTimer it returns nothing
local AreaIndicator ae = it.owner
if (UnitAlive(ae.target)) then
call BlzSetSpecialEffectX(ae.indicator, GetUnitX(ae.target))
call BlzSetSpecialEffectY(ae.indicator, GetUnitY(ae.target))
else
call ae.destroy()
endif
endfunction
function CreateAreaIndicatorUnit takes unit owner, real radius returns AreaIndicator
local AreaIndicator ae = CreateAreaIndicator(GetOwningPlayer(owner), GetUnitX(owner), GetUnitY(owner), radius)
set ae.target = owner
set ae.followTimer = CreateIntTimer(ae, false)
call StartTimerPlusPeriodic(ae.followTimer, 0.0, 0.01, AreaIndicatorUpdate, 0)
return ae
endfunction
function DestroyKeyedAreaIndicator takes integer parentKey, integer childKey returns nothing
local AreaIndicator ae = LoadInteger(HT, parentKey, childKey)
if (ae != 0) then
call ae.destroy()
endif
call RemoveSavedInteger(HT, parentKey, childKey)
endfunction
function CreateAreaIndicatorKeyed takes player owner, real x, real y, real radius, integer parentKey, integer childKey returns AreaIndicator
local AreaIndicator ae = CreateAreaIndicator(owner, x, y, radius)
call DestroyKeyedAreaIndicator(parentKey, childKey)
call SaveInteger(HT, parentKey, childKey, ae)
return ae
endfunction
function CreateAreaIndicatorUnitKeyed takes unit owner, real radius, integer parentKey, integer childKey returns AreaIndicator
local AreaIndicator ae = CreateAreaIndicatorUnit(owner, radius)
call DestroyKeyedAreaIndicator(parentKey, childKey)
call SaveInteger(HT, parentKey, childKey, ae)
return ae
endfunction
endlibrary
globals
item PATHING_CHECKER = null
endglobals
function IsPointWalkable takes real x, real y returns boolean
local boolean result = false
local real xDiff = 0.0
local real yDiff = 0.0
if (PATHING_CHECKER == null) then
set PATHING_CHECKER = CreateItem(SB_ITEM_PATHING_CHECKER, x, y)
endif
call SetItemVisible(PATHING_CHECKER, true)
call SetItemPosition(PATHING_CHECKER, x, y)
call SetItemVisible(PATHING_CHECKER, false)
set xDiff = RAbsBJ(GetItemX(PATHING_CHECKER) - x)
set yDiff = RAbsBJ(GetItemY(PATHING_CHECKER) - y)
set result = xDiff <= 0.01 and yDiff <= 0.01
return result
endfunction
function LineTraceWalkability takes real startX, real startY, real endX, real endY, real maxDelta returns location
local vec3 current = vec3.create(startX, startY, 0)
local vec3 diff = vec3.create(0, 0, 0)
local real dist = 0.0
local location result = null
loop
exitwhen current.x == endX and current.y == endY
set diff.x = endX - current.x
set diff.y = endY - current.y
set dist = RMinBJ(diff.mag(), maxDelta)
call diff.normalize().multiply(dist)
call current.add(diff)
if (not IsPointWalkable(current.x, current.y)) then
return Location(current.x - diff.x, current.y - diff.y)
endif
endloop
set result = Location(endX, endY)
call diff.destroy()
call current.destroy()
return result
endfunction
function LineTraceWalkabilityReverse takes real startX, real startY, real endX, real endY, real maxDelta returns location
local vec3 current = vec3.create(startX, startY, 0)
local vec3 diff = vec3.create(0, 0, 0)
local real dist = 0.0
local location result = null
loop
exitwhen current.x == endX and current.y == endY
set diff.x = endX - current.x
set diff.y = endY - current.y
set dist = RMinBJ(diff.mag(), maxDelta)
call diff.normalize().multiply(dist)
call current.add(diff)
if (IsPointWalkable(current.x, current.y)) then
return Location(current.x - diff.x, current.y - diff.y)
endif
endloop
set result = Location(endX, endY)
call diff.destroy()
call current.destroy()
return result
endfunction
globals
real ENUM_DESTRUCTABLE_RADIUS = 0.0
real ENUM_DESTRUCTABLE_X = 0.0
real ENUM_DESTRUCTABLE_Y = 0.0
endglobals
function IsTree takes destructable whichDestructable returns boolean
if (whichDestructable == null) then
return false
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_ASHENVALE_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_ASHENVALE_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_BARRENS_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_BARRENS_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_BLACK_CITADEL_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_CITYSCAPE_FALL_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_CITYSCAPE_SNOWY_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_CITYSCAPE_SUMMER_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_CITYSCAPE_WINTER_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_CITYSCAPE_RUINED_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_DALARAN_RUINS_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_DUNGEON_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_FELWOOD_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_FELWOOD_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_ICECROWN_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_ICECROWN_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_NORTHREND_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_NORTHREND_ICY_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_FALL_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_SUMMER_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_SNOWY_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_WINTER_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_NORTHREND_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_OUTLAND_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_RUINS_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_RUINS_CANOPY_TREE ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_UNDERGROUND_TREE_WALL ) ) then
return true
endif
if ( ( GetDestructableTypeId(whichDestructable) == SB_VILLAGE_TREE_WALL ) ) then
return true
endif
return false
endfunction
function GetRandomLivingTreeInRangeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real dist = 0.0
if (IsDestructableDeadBJ(d)) then
return false
elseif (not IsTree(d)) then
return false
endif
set dist = DistanceBetweenPointsXY(ENUM_DESTRUCTABLE_X, ENUM_DESTRUCTABLE_Y, GetDestructableX(d), GetDestructableY(d))
return dist <= ENUM_DESTRUCTABLE_RADIUS
endfunction
function GetRandomLivingTreeInRange takes real x, real y, real radius returns destructable
local rect r = Rect(x - radius, y - radius, x + radius, y + radius)
local destructable result = null
set ENUM_DESTRUCTABLE_RADIUS = radius
set ENUM_DESTRUCTABLE_X = x
set ENUM_DESTRUCTABLE_Y = y
set result = RandomDestructableInRectBJ(r, Condition(function GetRandomLivingTreeInRangeFilter))
call RemoveRect(r)
return result
endfunction
function IsDigit takes string s returns boolean
if (s == "0") then
return true
elseif (s == "1") then
return true
elseif (s == "2") then
return true
elseif (s == "3") then
return true
elseif (s == "4") then
return true
elseif (s == "5") then
return true
elseif (s == "6") then
return true
elseif (s == "7") then
return true
elseif (s == "8") then
return true
elseif (s == "9") then
return true
endif
return false
endfunction
function IsNumber takes string s returns boolean
local integer decimalCount = 0
local integer charIndex = 0
local integer len = StringLength(s)
local string char = null
loop
exitwhen charIndex >= len
set char = SubString(s, charIndex, charIndex)
if (char == ".") then
set decimalCount = decimalCount + 1
if (decimalCount > 1) then
return false
endif
elseif (not IsDigit(char)) then
return false
endif
set charIndex = charIndex + 1
endloop
return true
endfunction
function PosToString takes real x, real y returns string
return R2S(x) + "," + R2S(y)
endfunction
function LocToString takes location loc returns string
return PosToString(GetLocationX(loc), GetLocationY(loc))
endfunction
function StringLastIndexOf takes string whichString, string find returns integer
local integer stringLen = StringLength(whichString)
local integer findLen = StringLength(find)
local integer c = stringLen - findLen
loop
exitwhen c < findLen
if (SubString(whichString, c, c + findLen) == find) then
return c
endif
set c = c - 1
endloop
return -1
endfunction
function ParseLoc takes string s returns location
local integer indexOfComma = StringLastIndexOf(s, ",")
if (indexOfComma != -1) then
return Location(S2R(SubString(s, 0, indexOfComma)), S2R(SubString(s, indexOfComma + 1, StringLength(s))))
endif
return null
endfunction
library AbilityInit
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_ABILITY_ID
private constant key KEY_CALLBACK
private integer ability_id = 0
endglobals
private function interface UnitInitFunc takes unit whichUnit returns nothing
private function UnitsWithAbilityFilter takes nothing returns boolean
return GetUnitAbilityLevel(GetFilterUnit(), ability_id) > 0
endfunction
private function UnitEntersCondition takes nothing returns boolean
local integer abilityId = LoadInteger(HT, GetHandleId(GetTriggeringTrigger()), KEY_ABILITY_ID)
if (abilityId != 0) then
return GetUnitAbilityLevel(GetEnteringUnit(), abilityId) > 0
endif
return false
endfunction
private function UnitEntersAction takes nothing returns nothing
local UnitInitFunc callback = LoadInteger(HT, GetHandleId(GetTriggeringTrigger()), KEY_CALLBACK)
if (callback != 0) then
call callback.evaluate(GetEnteringUnit())
endif
endfunction
function InitAbility takes integer abilityId, UnitInitFunc initFunc returns nothing
local group abilityUnits = CreateGroup()
local trigger entersTrigger = CreateTrigger()
local unit picked = null
call TriggerRegisterEnterRectSimple(entersTrigger, GetEntireMapRect())
call TriggerAddCondition(entersTrigger, Condition(function UnitEntersCondition))
call TriggerAddAction(entersTrigger, function UnitEntersAction)
call SaveInteger(HT, GetHandleId(entersTrigger), KEY_ABILITY_ID, abilityId)
call SaveInteger(HT, GetHandleId(entersTrigger), KEY_CALLBACK, initFunc)
set ability_id = abilityId
call GroupEnumUnitsInRect(abilityUnits, GetPlayableMapRect(), Condition(function UnitsWithAbilityFilter))
loop
set picked = FirstOfGroup(abilityUnits)
exitwhen picked == null
call initFunc.evaluate(picked)
call GroupRemoveUnit(abilityUnits, picked)
endloop
call DestroyGroup(abilityUnits)
endfunction
endlibrary
library Curves
function EaseIn takes real t, real power returns real
return Pow(t, power)
endfunction
function EaseInOutQuad takes real t returns real
if (t < 0.5) then
return 2 * t * t
else
return 1 - Pow(-2 * t + 2, 2) / 2
endif
endfunction
endlibrary
globals
unit array QUICK_SORT_CONTAINER
endglobals
function GroupSortPartition takes integer low, integer high, UnitComparer comparer returns integer
local unit pivot = QUICK_SORT_CONTAINER[high]
local unit temp = null
local integer i = (low - 1)
local integer j = low
loop
exitwhen j > high - 1
if (comparer.evaluate(QUICK_SORT_CONTAINER[j], pivot) < 0) then
set i = i + 1
set temp = QUICK_SORT_CONTAINER[i]
set QUICK_SORT_CONTAINER[i] = QUICK_SORT_CONTAINER[j]
set QUICK_SORT_CONTAINER[j] = temp
endif
set j = j + 1
endloop
set temp = QUICK_SORT_CONTAINER[i + 1]
set QUICK_SORT_CONTAINER[i + 1] = QUICK_SORT_CONTAINER[high]
set QUICK_SORT_CONTAINER[high] = temp
return i + 1
endfunction
function GroupSortRecursive takes integer low, integer high, UnitComparer comparer returns nothing
local integer partitionIndex = 0
if (low < high) then
set partitionIndex = GroupSortPartition(low, high, comparer)
call GroupSortRecursive(low, partitionIndex - 1, comparer)
call GroupSortRecursive(partitionIndex + 1, high, comparer)
endif
endfunction
function GroupSortDestructive takes group whichGroup, UnitComparer comparer, UnitFunc callback returns integer
local unit pickedUnit = null
local integer i = 0
local integer size = 0
loop
set pickedUnit = FirstOfGroup(whichGroup)
exitwhen pickedUnit == null
set QUICK_SORT_CONTAINER[size] = pickedUnit
set size = size + 1
call GroupRemoveUnit(whichGroup, pickedUnit)
endloop
call GroupSortRecursive(0, size - 1, comparer)
if (callback != 0) then
loop
exitwhen i >= size
call callback.evaluate(QUICK_SORT_CONTAINER[i])
set i = i + 1
endloop
endif
return size
endfunction
library FrameLoader initializer init_function
// in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
// This library runs all functions added to it with a 0s delay after the game was loaded.
// function FrameLoaderAdd takes code func returns nothing
// func runs when the game is loaded.
globals
private trigger eventTrigger = CreateTrigger()
private trigger actionTrigger = CreateTrigger()
private timer t = CreateTimer()
endglobals
function FrameLoaderAdd takes code func returns nothing
call TriggerAddAction(actionTrigger, func)
endfunction
private function timerAction takes nothing returns nothing
call TriggerExecute(actionTrigger)
endfunction
private function eventAction takes nothing returns nothing
call TimerStart(t, 0, false, function timerAction)
endfunction
private function init_function takes nothing returns nothing
call TriggerRegisterGameEvent(eventTrigger, EVENT_GAME_LOADED)
call TriggerAddAction(eventTrigger, function eventAction)
endfunction
endlibrary
library HideMinDamageText initializer init_function requires FrameLoader
// HideMinDamageV3
globals
private framehandle DamageA
private framehandle DamageB
private framehandle DamageA2
private framehandle DamageB2
private framehandle ParentA
private framehandle ParentB
private string Text
private integer Index
private integer LoopA
private integer LoopAEnd
endglobals
private function find takes nothing returns nothing
set LoopAEnd = StringLength(Text) - 1
set LoopA = 1
loop
exitwhen LoopA >= LoopAEnd
if SubString(Text, LoopA, LoopA +3) == " - " then
set Index = LoopA + 3
return
endif
set LoopA = LoopA + 1
endloop
set Index = 0
endfunction
private function update takes nothing returns nothing
if BlzFrameIsVisible(ParentA) then
set Text = BlzFrameGetText(DamageA)
call find()
call BlzFrameSetText(DamageA2, SubString(Text, Index, StringLength(Text)))
endif
if BlzFrameIsVisible(ParentB) then
set Text = BlzFrameGetText(DamageB)
call find()
call BlzFrameSetText(DamageB2, SubString(Text, Index, StringLength(Text)))
endif
endfunction
private function At0s takes nothing returns nothing
call BlzLoadTOCFile("war3mapImported\\HideMinDamage.toc")
set ParentA = BlzGetFrameByName("SimpleInfoPanelIconDamage", 0)
set ParentB = BlzGetFrameByName("SimpleInfoPanelIconDamage", 1)
set DamageA = BlzGetFrameByName("InfoPanelIconValue", 0)
set DamageB = BlzGetFrameByName("InfoPanelIconValue", 1)
call BlzCreateSimpleFrame("CustomDamageString", ParentA, 0)
set DamageA2 = BlzGetFrameByName("CustomDamageStringValue", 0)
call BlzCreateSimpleFrame("CustomDamageString", ParentB, 1)
set DamageB2 = BlzGetFrameByName("CustomDamageStringValue", 1)
call BlzFrameSetFont(DamageA, "", 0, 0)
call BlzFrameSetFont(DamageB, "", 0, 0)
call TimerStart(GetExpiredTimer(), 0.05, true, function update)
endfunction
private function init_function takes nothing returns nothing
call FrameLoaderAdd(function At0s)
call TimerStart(CreateTimer(), 0, false, function At0s)
endfunction
endlibrary
function Trig_HideHeroUI_Actions takes nothing returns nothing
// Hide the hero attributes (strength, agility, intelligence)
call BlzFrameSetVisible(BlzGetFrameByName("SimpleInfoPanelIconHeroText", 6), false)
// Hide the hero attribute icon (primary attribute)
call BlzFrameSetSize(BlzGetFrameByName("InfoPanelIconHeroIcon", 6), 0.00001, 0.00001)
// Hide the hero exp bar tooltip
call BlzFrameSetTooltip(BlzGetFrameByName("SimpleHeroLevelBar", 0), BlzCreateFrameByType("SIMPLEFRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0))
endfunction
//===========================================================================
function InitTrig_HideHeroUI takes nothing returns nothing
set gg_trg_HideHeroUI = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_HideHeroUI, 0.00 )
call TriggerAddAction( gg_trg_HideHeroUI, function Trig_HideHeroUI_Actions )
endfunction
library CustomConsoleUI initializer init_function requires optional FrameLoader
// CustomConsoleUI by Tasyen
// CustomConsoleUI allows to change the UI during the game, when setuped correctly. This excludes the mouse cursor and the UI sounds.
// In non reforged it can also not change the Idle worker Button nor the no inventory cover.
// How to setup this: First you have to make the default Console Textures be hidden that is done in Game Interface.
// Set ConsoleTexture01 to ConsoleTexture06 to UI\Widgets\EscMenu\Human\blank-background.blp
// The Day of Time clock has hardcoded textures therefore you need to swap it out. That also should be done in Gameinterface.
// TimeOfDayIndicator to the model included in this system.
// Now export and Import war3mapImported\CustomConsoleUI.toc & war3mapImported\CustomConsoleUI.fdf
// Finally you have to set the used textures into local data
globals
private framehandle idleWorkerButton
private framehandle idleWorkerButtonOverlay
private framehandle idleWorkerButtonOverlayParent
private framehandle customInventoryCover
private framehandle customInventoryCoverParent
public string array data
public integer array dataCount
private integer dataPageSize = 11
public real array x
public real array y
// workerFace = true can only be used when you save the map in 1.32.6+
private constant boolean workerFace = false
endglobals
function AddCustomConsole takes integer index, string texture returns nothing
set dataCount[index] = dataCount[index] + 1
set data[index*dataPageSize + dataCount[index]] = texture
endfunction
function UseCustomConsole takes player p, integer index returns nothing
local integer pageValue
if GetLocalPlayer() != p then
return
endif
if index < 1 then
set index = GetHandleId(GetPlayerRace(p))
endif
set pageValue = index*dataPageSize
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5T", 0), data[pageValue + 5], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6T", 0), data[pageValue + 6], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4T", 0), data[pageValue + 4], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3T", 0), data[pageValue + 3], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TL", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2TR", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1T", 0), data[pageValue + 1], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI1B", 0), data[pageValue + 1], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI2B", 0), data[pageValue + 2], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI3B", 0), data[pageValue + 3], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI4B", 0), data[pageValue + 4], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI5B", 0), data[pageValue + 5], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUI6B", 0), data[pageValue + 6], 0, false)
call BlzFrameSetTexture(BlzGetFrameByName("CustomConsoleUIClock", 0), data[pageValue + 7] ,0, true)
if GetLocalizedString("REFORGED") != "REFORGED" then
call BlzFrameSetTexture(BlzGetFrameByName("InventoryCoverTexture", 0), data[pageValue + 8] ,0, true)
static if workerFace then
call BlzFrameSetTexture(idleWorkerButtonOverlay, data[pageValue + 9], 0, false)
endif
else
call BlzFrameSetTexture(customInventoryCover, data[pageValue + 8] ,0, true)
endif
call BlzFrameSetPoint(BlzGetFrameByName("CustomConsoleUIClock", 0), FRAMEPOINT_TOP, BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOP, x[index], y[index])
endfunction
function CreateCustomConsole takes nothing returns nothing
call BlzLoadTOCFile( "war3mapimported\\CustomConsoleUI.toc" )
call BlzCreateSimpleFrame( "CustomConsoleUI", BlzGetFrameByName("ConsoleUI", 0), 0)
call BlzFrameSetLevel(BlzGetFrameByName("CustomConsoleUI", 0), 0)
if GetLocalizedString("REFORGED") != "REFORGED" then
// Requires a native existing only in Reforged
static if workerFace then
set idleWorkerButton = BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7)
set idleWorkerButtonOverlayParent = BlzCreateSimpleFrame( "SimpleTextureFrame", idleWorkerButton, 0 )
set idleWorkerButtonOverlay = BlzGetFrameByName("SimpleTextureFrameValue", 0)
call BlzFrameSetAllPoints(idleWorkerButtonOverlay, idleWorkerButton)
call BlzFrameSetLevel(idleWorkerButtonOverlayParent, 4)
endif
else
set customInventoryCoverParent = BlzCreateSimpleFrame( "SimpleTextureFrame", BlzGetFrameByName("ConsoleUI", 0), 0)
call BlzFrameSetLevel(customInventoryCoverParent, 4)
set customInventoryCover = BlzGetFrameByName("SimpleTextureFrameValue", 0)
call BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_BOTTOMRIGHT, 0.6, 0)
call BlzFrameSetAbsPoint(customInventoryCover, FRAMEPOINT_TOPLEFT, 0.6 - 0.128, 0.2558)
endif
// Preload
call BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)
call BlzGetFrameByName("InventoryCoverTexture", 0)
call BlzGetFrameByName("CustomConsoleUIClock", 0)
call BlzGetFrameByName("CustomConsoleUI5T", 0)
call BlzGetFrameByName("CustomConsoleUI6T", 0)
call BlzGetFrameByName("CustomConsoleUI4T", 0)
call BlzGetFrameByName("CustomConsoleUI3T", 0)
call BlzGetFrameByName("CustomConsoleUI2TL", 0)
call BlzGetFrameByName("CustomConsoleUI2TR", 0)
call BlzGetFrameByName("CustomConsoleUI1T", 0)
call BlzGetFrameByName("CustomConsoleUI1B", 0)
call BlzGetFrameByName("CustomConsoleUI2B", 0)
call BlzGetFrameByName("CustomConsoleUI3B", 0)
call BlzGetFrameByName("CustomConsoleUI4B", 0)
call BlzGetFrameByName("CustomConsoleUI5B", 0)
call BlzGetFrameByName("CustomConsoleUI6B", 0)
endfunction
private function Init takes nothing returns nothing
call CreateCustomConsole()
call UseCustomConsole(GetLocalPlayer(), 0)
endfunction
private function at0s takes nothing returns nothing
call Init()
call DestroyTimer(GetExpiredTimer())
endfunction
private function update takes nothing returns nothing
call BlzFrameSetVisible(customInventoryCoverParent, not BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, 0)))
endfunction
private function init_function takes nothing returns nothing
local integer index = 0
set index = 0
call AddCustomConsole(index, "ui\\console\\human\\humanuitile01")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile02")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile03")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile04")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile05")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile06")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-timeindicatorframe")
call AddCustomConsole(index, "ui\\console\\human\\humanuitile-inventorycover")
//call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
// offset this mostly is used to fit to the glowing orbs showing the houers
set x[index] = 0.0009
set y[index] = 0.0
set index = 1
call AddCustomConsole(index, "war3mapImported\\orderuitile01.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile02.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile03.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile04.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile05.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile06.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile-timeindicatorframe.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile-inventorycover.dds")
//call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
set x[index] = 0.0009
set y[index] = 0.0
set index = 2
call AddCustomConsole(index, "war3mapImported\\natureuitile01.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile02.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile03.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile04.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile05.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile06.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile-timeindicatorframe.dds")
call AddCustomConsole(index, "war3mapImported\\natureuitile-inventorycover.dds")
//call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
set x[index] = 0.0009
set y[index] = 0.0
set index = 3
call AddCustomConsole(index, "war3mapImported\\deathuitile01.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile02.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile03.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile04.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile05.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile06.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile-timeindicatorframe.dds")
call AddCustomConsole(index, "war3mapImported\\deathuitile-inventorycover.dds")
//call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
set x[index] = 0.0009
set y[index] = 0.0
set index = 4
call AddCustomConsole(index, "war3mapImported\\orderuitile01.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile02.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile03.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile04.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile05.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile06.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile-timeindicatorframe.dds")
call AddCustomConsole(index, "war3mapImported\\orderuitile-inventorycover.dds")
//call AddCustomConsole(index, "ReplaceableTextures\\CommandButtons\\BTNPeasant")
set x[index] = 0.0009
set y[index] = 0.0
if GetLocalizedString("REFORGED") == "REFORGED" then
call TimerStart(CreateTimer(), 1/32.0, true, function update)
endif
call TimerStart(CreateTimer(), 0, false, function at0s)
static if LIBRARY_FrameLoader then
call FrameLoaderAdd(function Init)
endif
endfunction
endlibrary
function Trig_Preload_Models_Actions takes nothing returns nothing
local effect model = AddSpecialEffect("war3mapImported\\Eternitys_Crown_1537.mdx", 0.0, 0.0)
call BlzSetSpecialEffectTimeScale(model, 1000)
call DestroyEffect(model)
set model = AddSpecialEffect("war3mapImported\\ZombiePlagueAOE", 0.0, 0.0)
call BlzSetSpecialEffectTimeScale(model, 1000)
call DestroyEffect(model)
endfunction
//===========================================================================
function InitTrig_Preload_Models takes nothing returns nothing
set gg_trg_Preload_Models = CreateTrigger( )
call TriggerAddAction( gg_trg_Preload_Models, function Trig_Preload_Models_Actions )
endfunction
globals
constant integer DEATH_STARTING_WORKER_COUNT = 3
endglobals
function Trig_Starting_Units_Death_Actions takes nothing returns nothing
local boolexpr goldMineFilter = Condition(function GoldMineFilter)
local group goldMines = CreateGroup()
local unit goldMine = null
local real x = GetPlayerStartLocationX(udg_Player_Temp)
local real y = GetPlayerStartLocationY(udg_Player_Temp)
local real unitX = x
local real unitY = y
local real angle = 0.0
local real dist = 0.0
local unit lastUnit = null
local integer index = 0
call CreateUnit(udg_Player_Temp, SB_NECROPOLIS, x, y, bj_UNIT_FACING)
call GroupEnumUnitsInRange(goldMines, x, y, 1000.0, goldMineFilter)
set goldMine = GroupPickClosestUnit(goldMines, x, y)
if (goldMine != null) then
set dist = DistanceBetweenPointsXY(x, y, GetUnitX(goldMine), GetUnitY(goldMine))
set angle = AngleBetweenPointsXY(x, y, GetUnitX(goldMine), GetUnitY(goldMine))
set unitX = PolarProjectionX(x, dist * 0.5, angle)
set unitY = PolarProjectionY(y, dist * 0.5, angle)
endif
//set lastUnit = CreateUnit(udg_Player_Temp, SB_NECROMANCER, unitX, unitY, bj_UNIT_FACING)
//call IssueImmediateOrder(lastUnit, "unroot")
loop
exitwhen index >= DEATH_STARTING_WORKER_COUNT
set angle = index * (360.0 / DEATH_STARTING_WORKER_COUNT)
call CreateUnit(udg_Player_Temp, SB_LOST_SOUL, PolarProjectionX(unitX, 75.0, angle), PolarProjectionY(unitY, 75.0, angle), bj_UNIT_FACING)
set index = index + 1
endloop
endfunction
//===========================================================================
function InitTrig_Starting_Units_Death takes nothing returns nothing
set gg_trg_Starting_Units_Death = CreateTrigger( )
call TriggerAddAction( gg_trg_Starting_Units_Death, function Trig_Starting_Units_Death_Actions )
endfunction
function Trig_Starting_Units_Nature_Actions takes nothing returns nothing
local player p = udg_Player_Temp
local real startX = GetPlayerStartLocationX(p)
local real startY = GetPlayerStartLocationY(p)
local unit hq = CreateUnit(p, SB_HOLD, startX, startY, bj_UNIT_FACING)
local boolexpr goldMineFilter = Condition(function GoldMineFilter)
local group nearbyMines = CreateGroup()
local unit pickedMine = null
local real startingUnitsCenterX = 0.0
local real startingUnitsCenterY = 0.0
local real placementX = 0.0
local real placementY = 0.0
local real angle = 0.0
local real dist = 0.0
local real index = 0
call GroupEnumUnitsInRange(nearbyMines, startX, startY, 1000.0, goldMineFilter)
set pickedMine = GroupPickClosestUnit(nearbyMines, startX, startY)
if (pickedMine != null) then
set dist = DistanceBetweenUnits(hq, pickedMine) * 0.5
set angle = AngleBetweenUnits(hq, pickedMine)
set startingUnitsCenterX = PolarProjectionX(startX, dist, angle)
set startingUnitsCenterY = PolarProjectionY(startY, dist, angle)
else
set startingUnitsCenterX = PolarProjectionX(startX, 250.0, bj_UNIT_FACING)
set startingUnitsCenterY = PolarProjectionY(startY, 250.0, bj_UNIT_FACING)
endif
set angle = AngleBetweenUnits(pickedMine, hq)
set placementX = PolarProjectionX(startingUnitsCenterX, 75.0, angle)
set placementY = PolarProjectionY(startingUnitsCenterY, 75.0, angle)
call CreateUnit(p, SB_DENDROID_TREEHERD, placementX, placementY, bj_UNIT_FACING)
set angle = AngleBetweenUnits(hq, pickedMine) + 60.0
set placementX = PolarProjectionX(startingUnitsCenterX, 75.0, angle)
set placementY = PolarProjectionY(startingUnitsCenterY, 75.0, angle)
call CreateUnit(p, SB_ELVEN_ARTISAN, startingUnitsCenterX, startingUnitsCenterY, bj_UNIT_FACING)
set angle = AngleBetweenUnits(hq, pickedMine) - 60.0
set placementX = PolarProjectionX(startingUnitsCenterX, 75.0, angle)
set placementY = PolarProjectionY(startingUnitsCenterY, 75.0, angle)
call CreateUnit(p, SB_ELVEN_ARTISAN, placementX, placementY, bj_UNIT_FACING)
if (GetPlayerController(p) == MAP_CONTROL_COMPUTER) then
call StartMeleeAI(p, "war3mapImported/SBNatureAI.ai")
//call StartNatureAIForPlayer(p)
endif
call DestroyGroup(nearbyMines)
call DestroyBoolExpr(goldMineFilter)
endfunction
//===========================================================================
function InitTrig_Starting_Units_Nature takes nothing returns nothing
set gg_trg_Starting_Units_Nature = CreateTrigger( )
call TriggerAddAction( gg_trg_Starting_Units_Nature, function Trig_Starting_Units_Nature_Actions )
endfunction
function SetRaceForPlayer takes integer playerNumber, integer raceNumber returns nothing
set udg_String_PlayerRaceName[playerNumber] = udg_String_RaceNames[raceNumber]
set udg_Int_Race[playerNumber] = raceNumber
endfunction
function SetAIPlayerRaceSelections takes nothing returns nothing
local integer playerNumber = 1
local player thisPlayer = null
loop
exitwhen playerNumber > GetBJMaxPlayers()
set thisPlayer = ConvertedPlayer(playerNumber)
if (GetPlayerSlotState(thisPlayer) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(thisPlayer) == MAP_CONTROL_COMPUTER) then
// For now set all AI players to order.
if(GetPlayerRace(thisPlayer) == RACE_NIGHTELF)then
call SetRaceForPlayer(playerNumber, udg_Int_RaceNum_Nature)
else
call SetRaceForPlayer(playerNumber, udg_Int_RaceNum_Order)
endif
endif
set playerNumber = playerNumber + 1
endloop
endfunction
function SetRaceMultiboardVisibility takes player whichPlayer, boolean flag returns nothing
local integer playerIndex = GetPlayerId(whichPlayer)
set udg_Bool_RaceMultiboardVisState[playerIndex] = flag
if (GetLocalPlayer() == whichPlayer) then
call MultiboardDisplay(udg_Multiboard_RaceSelection, flag)
endif
endfunction
function GetRaceMultiboardVisibility takes player whichPlayer returns boolean
local integer playerIndex = GetPlayerId(whichPlayer)
return udg_Bool_RaceMultiboardVisState[playerIndex]
endfunction
function SetRaceMultiboardVisibilityAll takes boolean flag returns nothing
local integer p = 0
loop
exitwhen p >= GetBJMaxPlayers()
set udg_Bool_RaceMultiboardVisState[p] = flag
set p = p + 1
endloop
call MultiboardDisplay(udg_Multiboard_RaceSelection, flag)
endfunction
function GetSelectionStatus takes integer raceIndex returns string
if (raceIndex > 0 and raceIndex <= udg_Int_RaceCount) then
return "|cff00c000Ready|r"
else
return "|cff808080Waiting...|r"
endif
endfunction
function SetRaceSelectionMultiboardRowForPlayer takes player p, string selection returns nothing
local integer playerNumber = GetConvertedPlayerId(p)
local string playerName = GetPlayerNameColored(p)
call MultiboardSetItemValueBJ(udg_Multiboard_RaceSelection, 1, playerNumber, playerName)
call MultiboardSetItemWidthBJ(udg_Multiboard_RaceSelection, 1, playerNumber, 12.0)
call MultiboardSetItemValueBJ(udg_Multiboard_RaceSelection, 2, playerNumber, selection)
call MultiboardSetItemWidthBJ(udg_Multiboard_RaceSelection, 2, playerNumber, 4.25)
endfunction
function SetRaceSelectionMultiboardRow takes nothing returns nothing
call SetRaceSelectionMultiboardRowForPlayer(GetEnumPlayer(), GetSelectionStatus(udg_Int_Race[GetConvertedPlayerId(GetEnumPlayer())]))
endfunction
function CreateRaceSelectionMultiboard takes nothing returns nothing
local force players = GetPlayingPlayers(false, false, false)
local integer playerCount = CountPlayersInForceBJ(players)
if (playerCount > 0) then
set udg_Multiboard_RaceSelection = CreateMultiboardBJ(2, playerCount, udg_String_RSMBTitle)
call MultiboardSetItemsStyle(udg_Multiboard_RaceSelection, true, false)
call ForForce(players, function SetRaceSelectionMultiboardRow)
call MultiboardMinimizeBJ(false, udg_Multiboard_RaceSelection)
call SetRaceMultiboardVisibilityAll(true)
endif
call DestroyForce(players)
endfunction
function CreateRaceMenu takes nothing returns nothing
local integer pIndex = 0
local player thisPlayer = null
local integer rIndex = 1
call DialogSetMessageBJ(udg_Dialog_RaceSelection, "Choose your alignment:")
loop
exitwhen rIndex > udg_Int_RaceCount
set udg_DialogButton_RaceSelection[rIndex] = DialogAddButtonBJ(udg_Dialog_RaceSelection, udg_String_RaceNames[rIndex])
set rIndex = rIndex + 1
endloop
set udg_DialogButton_RaceSelection[udg_Int_RaceNum_Random] = DialogAddButtonBJ(udg_Dialog_RaceSelection, udg_String_RaceNames[udg_Int_RaceNum_Random])
loop
exitwhen pIndex >= GetBJMaxPlayers()
set thisPlayer = Player(pIndex)
if (GetPlayerSlotState(thisPlayer) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(thisPlayer) == MAP_CONTROL_USER) then
call DialogDisplayBJ(true, udg_Dialog_RaceSelection, thisPlayer)
endif
set pIndex = pIndex + 1
endloop
endfunction
globals
constant real RACE_SELECTION_TEXT_DURATION = 15.0
endglobals
function AllPlayersReady takes nothing returns nothing
local integer playerNumber = 1
local player thisPlayer = null
call DisableTrigger(gg_trg_Race_Selection_Timer_Loop)
call MultiboardSetTitleText(udg_Multiboard_RaceSelection, udg_String_RSMBTitle)
call TriggerSleepAction( 1.00 )
call ClearTextMessages()
call DisplayTimedTextToForce( GetPlayersAll(), RACE_SELECTION_TEXT_DURATION, "|cffffcc00Welcome to Spellbringers, hosted by |cff00ccffhiveworkshop.com!|r|r" )
loop
exitwhen playerNumber > GetBJMaxPlayers()
set thisPlayer = ConvertedPlayer(playerNumber)
if (GetPlayerSlotState(thisPlayer) == PLAYER_SLOT_STATE_PLAYING) then
if (udg_Int_Race[playerNumber] <= 0) then // Random
set udg_Int_Race[playerNumber] = GetRandomInt(1, udg_Int_RaceCount)
endif
call SetRaceSelectionMultiboardRowForPlayer(thisPlayer, udg_String_PlayerRaceName[playerNumber])
call DisplayTimedTextToForce(GetPlayersAll(), RACE_SELECTION_TEXT_DURATION, " • " + GetPlayerNameColored(thisPlayer) + " has chosen " + udg_String_PlayerRaceName[playerNumber] + ".")
set udg_Player_Temp = thisPlayer
call ConditionalTriggerExecute(udg_Trigger_StartingUnits[udg_Int_Race[playerNumber]])
endif
set playerNumber = playerNumber + 1
endloop
call EnableTrigger(gg_trg_Hide_Race_Selection_Multiboard)
call BeginGameTimer()
call StartTimerBJ(udg_Timer_DestroyRSMultiboard, false, 10.0)
//call ConditionalTriggerExecute( gg_trg_Game_Clock_Initialization )
call MeleeInitVictoryDefeat()
endfunction
function AreAllPlayersReady takes nothing returns boolean
local integer playerNumber = 1
loop
exitwhen playerNumber > GetBJMaxPlayers()
if (GetPlayerSlotState(ConvertedPlayer(playerNumber)) == PLAYER_SLOT_STATE_PLAYING and udg_Int_Race[playerNumber] == -1) then
return false
endif
set playerNumber = playerNumber + 1
endloop
return true
endfunction
function Trig_Race_Selection_Actions takes nothing returns nothing
call SetAIPlayerRaceSelections()
call CreateRaceSelectionMultiboard()
if (not AreAllPlayersReady()) then
call CreateRaceMenu()
call EnableTrigger(gg_trg_Race_Selection_Timer_Loop)
call DisplayTextToForce( GetPlayersAll(), "|cffffcc00Waiting for all players to choose their alignments...|r" )
else
call AllPlayersReady()
endif
endfunction
//===========================================================================
function InitTrig_Race_Selection takes nothing returns nothing
set gg_trg_Race_Selection = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Race_Selection, 2.00 )
call TriggerAddAction( gg_trg_Race_Selection, function Trig_Race_Selection_Actions )
endfunction
globals
constant real RACE_SELECTION_TIMER_LOOP_INTERVAL = 1.0
endglobals
function Trig_Race_Selection_Timer_Loop_Expired takes nothing returns nothing
local integer playerNum = 1
local player thisPlayer = null
loop
exitwhen playerNum > GetBJMaxPlayers()
set thisPlayer = ConvertedPlayer(playerNum)
if (udg_Int_Race[playerNum] == -1) then
if (GetPlayerSlotState(thisPlayer) == PLAYER_SLOT_STATE_LEFT or GetPlayerSlotState(thisPlayer) == PLAYER_SLOT_STATE_PLAYING) then
call SetRaceForPlayer(playerNum, udg_Int_RaceNum_Random)
call DialogDisplayBJ(false, udg_Dialog_RaceSelection, thisPlayer)
endif
endif
set playerNum = playerNum + 1
endloop
call DisableTrigger(GetTriggeringTrigger())
call AllPlayersReady()
endfunction
function Trig_Race_Selection_Timer_Loop_Actions takes nothing returns nothing
local string mbTitle = udg_String_RSMBTitle + " (|cffffffff" + GetFormattedTimeString(udg_Real_RaceSelectionTime) + "|r)"
call MultiboardSetTitleText(udg_Multiboard_RaceSelection, mbTitle)
if (udg_Real_RaceSelectionTime > 0.0) then
set udg_Real_RaceSelectionTime = udg_Real_RaceSelectionTime - RACE_SELECTION_TIMER_LOOP_INTERVAL
else
call Trig_Race_Selection_Timer_Loop_Expired()
endif
endfunction
//===========================================================================
function InitTrig_Race_Selection_Timer_Loop takes nothing returns nothing
set gg_trg_Race_Selection_Timer_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Race_Selection_Timer_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Race_Selection_Timer_Loop, RACE_SELECTION_TIMER_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Race_Selection_Timer_Loop, function Trig_Race_Selection_Timer_Loop_Actions )
endfunction
function Trig_Race_Selection_Click_Actions takes nothing returns nothing
local integer rIndex = 0
local integer playerNumber = GetConvertedPlayerId(GetTriggerPlayer())
call DialogDisplayBJ(false, udg_Dialog_RaceSelection, GetTriggerPlayer())
loop
exitwhen rIndex > udg_Int_RaceCount
if (GetClickedButtonBJ() == udg_DialogButton_RaceSelection[rIndex]) then
call SetRaceForPlayer(playerNumber, rIndex)
call SetRaceSelectionMultiboardRowForPlayer(GetTriggerPlayer(), GetSelectionStatus(udg_Int_Race[playerNumber]))
exitwhen true
endif
set rIndex = rIndex + 1
endloop
if (AreAllPlayersReady()) then
call AllPlayersReady()
else
call DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, "Waiting for other players...")
endif
endfunction
//===========================================================================
function InitTrig_Race_Selection_Click takes nothing returns nothing
set gg_trg_Race_Selection_Click = CreateTrigger( )
call TriggerRegisterDialogEventBJ(gg_trg_Race_Selection_Click, udg_Dialog_RaceSelection)
call TriggerAddAction( gg_trg_Race_Selection_Click, function Trig_Race_Selection_Click_Actions )
endfunction
function Trig_Hide_Race_Selection_Multiboard_Actions takes nothing returns nothing
call SetRaceMultiboardVisibilityAll(false)
call CreateGameClock()
call DestroyTimer(udg_Timer_DestroyRSMultiboard)
call EnableTrigger(gg_trg_Toggle_Races_Multiboard)
call DisableTrigger(GetTriggeringTrigger())
endfunction
//===========================================================================
function InitTrig_Hide_Race_Selection_Multiboard takes nothing returns nothing
set gg_trg_Hide_Race_Selection_Multiboard = CreateTrigger( )
call DisableTrigger( gg_trg_Hide_Race_Selection_Multiboard )
call TriggerRegisterTimerExpireEventBJ( gg_trg_Hide_Race_Selection_Multiboard, udg_Timer_DestroyRSMultiboard )
call TriggerAddAction( gg_trg_Hide_Race_Selection_Multiboard, function Trig_Hide_Race_Selection_Multiboard_Actions )
endfunction
library ArmySystemCommon
// Determines whether a unit should be included in army commands. This should work fine by default,
// however, you may wish to add a way to force a unit to be in the army if it normally woudn't be, or
// vice versa.
public function IsArmyUnit takes unit whichUnit returns boolean
if (GetUnitDefaultMoveSpeed(whichUnit) <= 0.0) then
return false
elseif (GetUnitAbilityLevel(whichUnit, 'Aloc') > 0) then
return false
elseif (GetUnitAbilityLevel(whichUnit, SB_ARMY_TOGGLE_REMOVE) > 0) then
return true
elseif (IsUnitType(whichUnit, UNIT_TYPE_PEON)) then
return false
elseif (IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE)) then
return false
elseif (not (IsUnitType(whichUnit, UNIT_TYPE_MELEE_ATTACKER) or IsUnitType(whichUnit, UNIT_TYPE_RANGED_ATTACKER))) then
return false
elseif (GetUnitPropWindow(whichUnit) <= 0.0) then
return false
endif
return true
endfunction
endlibrary
library ArmySystemConfig initializer Init requires ArmyCommands, ArmyToggle
private function Init takes nothing returns nothing
// Determines which ability will cause army units to attack.
call ArmyCommands_SetAttackArmyAbility(SB_ATTACK_ARMY)
// Determines which ability will cause army units to move.
call ArmyCommands_SetMoveArmyAbility(SB_MOVE_ARMY)
// IMPORTANT CONFIG:
// -- What is a command bucket? --
// A command bucket is a way to group units together when issuing army commands.
// It works by grouping units of similar movement speeds together. The more buckets
// you have, the more responsive your commands will feel. However, more buckets will
// also increase the chance that your commands will cause units to bug out (because of an overload of commands.)
// Four or five should be enough, depending on how many units an army will likely contain.
// -- NOTE --
// Buckets must be added in order from slowest to fastest.
call ArmyCommands_AddCommandBucket(150.0) // Very slow
call ArmyCommands_AddCommandBucket(300.0) // Slow
call ArmyCommands_AddCommandBucket(450.0) // Average
call ArmyCommands_AddCommandBucket(600.0) // Fast
// When adding or removing a unit from an army via user input, these models can be added to the unit
// to identify which units have been added to or removed from the army.
call ArmySystem_SetAddedToArmyEffectModel("Abilities\\Spells\\ArmyStatus\\ArmyStatusAdded.mdl", "overhead")
call ArmySystem_SetRemovedFromArmyEffectModel("Abilities\\Spells\\ArmyStatus\\ArmyStatusRemoved.mdl", "overhead")
// Determines which ability can force a non-army unit into the army when activated.
call ArmyToggle_SetAddArmyAbility(SB_ARMY_TOGGLE_ADD, OrderId("defend"))
// Determines which ability will undo the above action.
call ArmyToggle_SetUnAddArmyAbility(SB_ARMY_TOGGLE_ADD, OrderId("undefend"))
// Determines which ability can force an army unit out of the army when activated.
call ArmyToggle_SetRemoveArmyAbility(SB_ARMY_TOGGLE_REMOVE, OrderId("defend"))
// Determines which ability will undo the above action.
call ArmyToggle_SetUnRemoveArmyAbility(SB_ARMY_TOGGLE_REMOVE, OrderId("undefend"))
endfunction
endlibrary
library ArmySystem initializer Init requires ArmySystemCommon
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_COUNTER
private constant key KEY_EFFECT
private string ADDED_EFFECT_MODEL = null
private string ADDED_EFFECT_AP = null
private string REMOVED_EFFECT_MODEL = null
private string REMOVED_EFFECT_AP = null
endglobals
// ************************************
// PRIVATE FUNCTIONS
// ************************************
private function AddArmyEffect takes unit whichUnit, string effectModel, string attachmentPoint returns effect
local effect vfx = LoadEffectHandle(HT, GetHandleId(whichUnit), KEY_EFFECT)
if (vfx == null) then
if (GetLocalPlayer() != GetOwningPlayer(whichUnit)) then
set effectModel = ""
endif
set vfx = AddSpecialEffectTarget(effectModel, whichUnit, attachmentPoint)
call SaveEffectHandle(HT, GetHandleId(whichUnit), KEY_EFFECT, vfx)
endif
return vfx
endfunction
private function DestroyArmyEffect takes unit whichUnit returns nothing
local effect vfx = LoadEffectHandle(HT, GetHandleId(whichUnit), KEY_EFFECT)
call DestroyEffect(vfx)
call RemoveSavedHandle(HT, GetHandleId(whichUnit), KEY_EFFECT)
endfunction
private function GetCounter takes unit whichUnit returns integer
return LoadInteger(HT, GetHandleId(whichUnit), KEY_COUNTER)
endfunction
private function ChangeCounter takes unit whichUnit, integer delta, boolean showEffect returns integer
local integer counter = GetCounter(whichUnit) + delta
if (counter == 0) then
call DestroyArmyEffect(whichUnit)
call RemoveSavedInteger(HT, GetHandleId(whichUnit), KEY_COUNTER)
else
call SaveInteger(HT, GetHandleId(whichUnit), KEY_COUNTER, counter)
if (showEffect and counter > 0) then
call AddArmyEffect(whichUnit, ADDED_EFFECT_MODEL, ADDED_EFFECT_AP)
elseif (showEffect and counter < 0) then
call AddArmyEffect(whichUnit, REMOVED_EFFECT_MODEL, REMOVED_EFFECT_AP)
endif
endif
return counter
endfunction
// ************************************
// PUBLIC API
// ************************************
public function SetAddedToArmyEffectModel takes string model, string attachmentPoint returns nothing
set ADDED_EFFECT_MODEL = model
set ADDED_EFFECT_AP = attachmentPoint
endfunction
public function SetRemovedFromArmyEffectModel takes string model, string attachmentPoint returns nothing
set REMOVED_EFFECT_MODEL = model
set REMOVED_EFFECT_AP = attachmentPoint
endfunction
public function IsUnitAddedToArmy takes unit whichUnit returns boolean
return GetCounter(whichUnit) > 0
endfunction
public function IsUnitRemovedFromArmy takes unit whichUnit returns boolean
return GetCounter(whichUnit) < 0
endfunction
public function AddUnitToArmy takes unit whichUnit, boolean showEffect returns nothing
call ChangeCounter(whichUnit, 1, showEffect)
endfunction
public function UnAddUnitToArmy takes unit whichUnit, boolean showEffect returns nothing
local integer counter = GetCounter(whichUnit)
if (counter > 0) then
call ChangeCounter(whichUnit, -1, showEffect)
endif
endfunction
public function RemoveUnitFromArmy takes unit whichUnit, boolean showEffect returns nothing
call ChangeCounter(whichUnit, -1, showEffect)
endfunction
public function UnRemoveUnitFromArmy takes unit whichUnit, boolean showEffect returns nothing
local integer counter = GetCounter(whichUnit)
if (counter < 0) then
call ChangeCounter(whichUnit, 1, showEffect)
endif
endfunction
public function GetUnitArmyCounter takes unit whichUnit returns integer
return GetCounter(whichUnit)
endfunction
// ************************************
// TRIGGERS
// ************************************
private function OnUnitDies takes nothing returns nothing
local unit dying = GetDyingUnit()
call DestroyArmyEffect(dying)
call FlushChildHashtable(HT, GetHandleId(dying))
endfunction
// ************************************
// INITIALIZATION
// ************************************
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, function OnUnitDies)
endfunction
endlibrary
library ArmyCommands initializer Init requires ArmySystem, ArmySystemCommon
globals
private integer ABILITY_ATTACK_ARMY = 0
private integer ABILITY_MOVE_ARMY = 0
private constant real array CB_MS_LIMITS
private constant group array COMMANDBUCKETS
private integer BUCKET_COUNT = 0
private constant integer array unitCounter
endglobals
// ************************************
// PUBLIC API
// ************************************
public function AddCommandBucket takes real msLimit returns nothing
set CB_MS_LIMITS[BUCKET_COUNT] = msLimit
set COMMANDBUCKETS[BUCKET_COUNT] = CreateGroup()
set BUCKET_COUNT = BUCKET_COUNT + 1
endfunction
public function SetAttackArmyAbility takes integer abilityId returns nothing
set ABILITY_ATTACK_ARMY = abilityId
endfunction
public function SetMoveArmyAbility takes integer abilityId returns nothing
set ABILITY_MOVE_ARMY = abilityId
endfunction
// ************************************
// PRIVATE FUNCTIONS
// ************************************
private function ArmyCommandFilter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitAliveBJ(filter)) then
return false
elseif (ArmySystem_IsUnitAddedToArmy(filter)) then
return true
elseif (not ArmySystemCommon_IsArmyUnit(filter)) then
return false
elseif (ArmySystem_IsUnitRemovedFromArmy(filter)) then
return false
endif
return true
endfunction
private function IsAttackOrder takes integer abilityId returns boolean
return abilityId == ABILITY_ATTACK_ARMY
endfunction
private function IsMoveOrder takes integer abilityId returns boolean
return abilityId == ABILITY_MOVE_ARMY
endfunction
private function ArmyCommandExecOrder takes group commandGroup, string order, real x, real y, widget target returns nothing
if (target != null) then
call GroupTargetOrder(commandGroup, order, target)
else
call GroupPointOrder(commandGroup, order, x, y)
endif
call GroupClear(commandGroup)
endfunction
private function ArmyCommandExecute takes player p, string order, real x, real y, widget target returns nothing
local group armyUnits = GetUnitsOfPlayerMatching(p, Condition(function ArmyCommandFilter))
local group commandUnits = null
local real ms = 0.0
local integer bucketIndex = 0
local unit pickedUnit = null
loop
exitwhen bucketIndex >= BUCKET_COUNT
set unitCounter[bucketIndex] = 0
call GroupClear(COMMANDBUCKETS[bucketIndex])
set bucketIndex = bucketIndex + 1
endloop
loop
set pickedUnit = FirstOfGroup(armyUnits)
exitwhen pickedUnit == null
call GroupRemoveUnit(armyUnits, pickedUnit)
set ms = GetUnitMoveSpeed(pickedUnit)
set bucketIndex = 0
loop
exitwhen bucketIndex >= BUCKET_COUNT
if (ms <= CB_MS_LIMITS[bucketIndex]) then
set commandUnits = COMMANDBUCKETS[bucketIndex]
exitwhen true
endif
set bucketIndex = bucketIndex + 1
endloop
set bucketIndex = IMinBJ(bucketIndex, BUCKET_COUNT - 1)
call GroupAddUnit(commandUnits, pickedUnit)
set unitCounter[bucketIndex] = unitCounter[bucketIndex] + 1
if (unitCounter[bucketIndex] >= 12) then
call ArmyCommandExecOrder(commandUnits, order, x, y, target)
set unitCounter[bucketIndex] = 0
endif
endloop
set bucketIndex = 0
loop
exitwhen bucketIndex >= BUCKET_COUNT
if (unitCounter[bucketIndex] > 0) then
call ArmyCommandExecOrder(COMMANDBUCKETS[bucketIndex], order, x, y, target)
set unitCounter[bucketIndex] = 0
endif
set bucketIndex = bucketIndex + 1
endloop
call DestroyGroup(armyUnits)
endfunction
// ************************************
// TRIGGERS
// ************************************
private function CommandConditions takes nothing returns boolean
local integer abilityId = GetSpellAbilityId()
return IsAttackOrder(abilityId) or IsMoveOrder(abilityId)
endfunction
private function CommandActions takes nothing returns nothing
local player p = GetOwningPlayer(GetSpellAbilityUnit())
local integer abilityId = GetSpellAbilityId()
local string order = null
local widget target = GetSpellTargetUnit()
if (target == null) then
set target = GetSpellTargetDestructable()
endif
if (IsAttackOrder(abilityId)) then
set order = "attack"
elseif (GetSpellTargetUnit() != null) then
set order = "patrol"
else
set order = "move"
endif
call ArmyCommandExecute(p, order, GetSpellTargetX(), GetSpellTargetY(), target)
endfunction
private function SmartCommandConditions takes nothing returns boolean
local integer orderId = GetIssuedOrderId()
return orderId == OrderId("smart") or orderId == OrderId("rally")
endfunction
private function SmartCommandActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local player p = GetOwningPlayer(ordered)
local widget target = GetOrderTarget()
if (GetUnitAbilityLevel(ordered, ABILITY_ATTACK_ARMY) > 0 and target != null) then
call ArmyCommandExecute(p, "smart", 0, 0, target)
call BlzPauseUnitEx(ordered, true)
call IssueImmediateOrder(ordered, "stop")
call BlzPauseUnitEx(ordered, false)
elseif (GetUnitAbilityLevel(ordered, ABILITY_MOVE_ARMY) > 0 and target == null) then
call ArmyCommandExecute(p, "smart", GetOrderPointX(), GetOrderPointY(), null)
call BlzPauseUnitEx(ordered, true)
call IssueImmediateOrder(ordered, "stop")
call BlzPauseUnitEx(ordered, false)
endif
endfunction
// ************************************
// INITIALIZATION
// ************************************
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition( function CommandConditions ))
call TriggerAddAction(t, function CommandActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition( function SmartCommandConditions ))
call TriggerAddAction(t, function SmartCommandActions)
endfunction
endlibrary
library ArmyToggle initializer Init requires ArmySystem, ArmySystemCommon
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_HOLDING_POSITION
private constant key KEY_CHANNELING
private integer ABILITY_ARMY_TOGGLE_ADD = 0
private integer ABILITY_ARMY_TOGGLE_REMOVE = 0
private integer ABILITY_ARMY_TOGGLE_UNADD = 0
private integer ABILITY_ARMY_TOGGLE_UNREMOVE = 0
private integer ORDER_ARMY_TOGGLE_ADD = 0
private integer ORDER_ARMY_TOGGLE_REMOVE = 0
private integer ORDER_ARMY_TOGGLE_UNADD = 0
private integer ORDER_ARMY_TOGGLE_UNREMOVE = 0
private integer ARMY_ADD_CALLBACK = 0
private integer ARMY_UNADD_CALLBACK = 0
private integer ARMY_REMOVE_CALLBACK = 0
private integer ARMY_UNREMOVE_CALLBACK = 0
endglobals
// ************************************
// PUBLIC API
// ************************************
public function interface UnitArmyCallback takes unit whichUnit returns nothing
public function SetAddArmyAbility takes integer abilityId, integer orderId returns nothing
set ABILITY_ARMY_TOGGLE_ADD = abilityId
set ORDER_ARMY_TOGGLE_ADD = orderId
endfunction
public function SetUnAddArmyAbility takes integer abilityId, integer orderId returns nothing
set ABILITY_ARMY_TOGGLE_UNADD = abilityId
set ORDER_ARMY_TOGGLE_UNADD = orderId
endfunction
public function SetRemoveArmyAbility takes integer abilityId, integer orderId returns nothing
set ABILITY_ARMY_TOGGLE_REMOVE = abilityId
set ORDER_ARMY_TOGGLE_REMOVE = orderId
endfunction
public function SetUnRemoveArmyAbility takes integer abilityId, integer orderId returns nothing
set ABILITY_ARMY_TOGGLE_UNREMOVE = abilityId
set ORDER_ARMY_TOGGLE_UNREMOVE = orderId
endfunction
public function RegisterAddToArmyCallback takes UnitArmyCallback callback returns nothing
set ARMY_ADD_CALLBACK = callback
endfunction
public function RegisterUnAddToArmyCallback takes UnitArmyCallback callback returns nothing
set ARMY_UNADD_CALLBACK = callback
endfunction
public function RegisterRemoveFromArmyCallback takes UnitArmyCallback callback returns nothing
set ARMY_REMOVE_CALLBACK = callback
endfunction
public function RegisterUnRemoveFromArmyCallback takes UnitArmyCallback callback returns nothing
set ARMY_UNREMOVE_CALLBACK = callback
endfunction
// ************************************
// TRIGGERS
// ************************************
private function ArmyToggleAddConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
if (IsUnitDeadBJ(ordered)) then
return false
elseif (GetIssuedOrderId() != ORDER_ARMY_TOGGLE_ADD) then
return false
elseif (GetUnitAbilityLevel(ordered, ABILITY_ARMY_TOGGLE_ADD) == 0) then
return false
endif
return true
endfunction
private function ArmyToggleAddActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local UnitArmyCallback callback = ARMY_ADD_CALLBACK
call ArmySystem_AddUnitToArmy(ordered, true)
if (callback != 0) then
call callback.evaluate(ordered)
endif
endfunction
private function ArmyToggleUnAddConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
if (IsUnitDeadBJ(ordered)) then
return false
elseif (GetIssuedOrderId() != ORDER_ARMY_TOGGLE_UNADD) then
return false
elseif (GetUnitAbilityLevel(ordered, ABILITY_ARMY_TOGGLE_UNADD) == 0) then
return false
endif
return true
endfunction
private function ArmyToggleUnAddActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local UnitArmyCallback callback = ARMY_UNADD_CALLBACK
call ArmySystem_UnAddUnitToArmy(ordered, true)
if (callback != 0) then
call callback.evaluate(ordered)
endif
endfunction
private function ArmyToggleRemoveConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
if (IsUnitDeadBJ(ordered)) then
return false
elseif (GetIssuedOrderId() != ORDER_ARMY_TOGGLE_REMOVE) then
return false
elseif (GetUnitAbilityLevel(ordered, ABILITY_ARMY_TOGGLE_REMOVE) == 0) then
return false
endif
return true
endfunction
private function ArmyToggleRemoveActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local UnitArmyCallback callback = ARMY_REMOVE_CALLBACK
call ArmySystem_RemoveUnitFromArmy(ordered, true)
if (callback != 0) then
call callback.evaluate(ordered)
endif
endfunction
private function ArmyToggleUnRemoveConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
if (IsUnitDeadBJ(ordered)) then
return false
elseif (GetIssuedOrderId() != ORDER_ARMY_TOGGLE_UNREMOVE) then
return false
elseif (GetUnitAbilityLevel(ordered, ABILITY_ARMY_TOGGLE_UNREMOVE) == 0) then
return false
endif
return true
endfunction
function ArmyToggleUnRemoveActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local UnitArmyCallback callback = ARMY_UNREMOVE_CALLBACK
call ArmySystem_UnRemoveUnitFromArmy(ordered, true)
if (callback != 0) then
call callback.evaluate(ordered)
endif
endfunction
private function HoldPositionConditions takes nothing returns boolean
return GetIssuedOrderId() == 851993 and not HaveSavedBoolean(HT, KEY_HOLDING_POSITION, GetHandleId(GetOrderedUnit()))
endfunction
private function HoldPositionActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
call ArmySystem_RemoveUnitFromArmy(GetOrderedUnit(), true)
call SaveBoolean(HT, KEY_HOLDING_POSITION, GetHandleId(ordered), true)
endfunction
private function ReturnToArmyConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
local integer orderId = GetIssuedOrderId()
return HaveSavedBoolean(HT, KEY_HOLDING_POSITION, GetHandleId(ordered)) and orderId != 851993 and orderId != ORDER_ARMY_TOGGLE_REMOVE and orderId != ORDER_ARMY_TOGGLE_UNREMOVE
endfunction
private function ReturnToArmyActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
call ArmySystem_UnRemoveUnitFromArmy(ordered, true)
call RemoveSavedBoolean(HT, KEY_HOLDING_POSITION, GetHandleId(ordered))
endfunction
private function SpellChannelConditions takes nothing returns boolean
local unit caster = GetSpellAbilityUnit()
return ArmySystem_IsUnitAddedToArmy(caster) or ArmySystemCommon_IsArmyUnit(caster)
endfunction
private function SpellChannelActions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call ArmySystem_RemoveUnitFromArmy(caster, false)
call SaveBoolean(HT, KEY_CHANNELING, GetHandleId(caster), true)
endfunction
private function SpellChannelStopConditions takes nothing returns boolean
local unit caster = GetSpellAbilityUnit()
return HaveSavedBoolean(HT, KEY_CHANNELING, GetHandleId(caster)) or ArmySystemCommon_IsArmyUnit(caster)
endfunction
private function SpellChannelStopActions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call ArmySystem_UnRemoveUnitFromArmy(caster, false)
call RemoveSavedHandle(HT, KEY_CHANNELING, GetHandleId(caster))
endfunction
private function UnitDiesActions takes nothing returns nothing
local unit dying = GetDyingUnit()
call RemoveSavedHandle(HT, KEY_CHANNELING, GetHandleId(dying))
call RemoveSavedHandle(HT, KEY_HOLDING_POSITION, GetHandleId(dying))
endfunction
// ************************************
// INITIALIZATION
// ************************************
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function ArmyToggleAddConditions))
call TriggerAddAction(t, function ArmyToggleAddActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function ArmyToggleUnAddConditions))
call TriggerAddAction(t, function ArmyToggleUnAddActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function ArmyToggleRemoveConditions))
call TriggerAddAction(t, function ArmyToggleRemoveActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function ArmyToggleUnRemoveConditions))
call TriggerAddAction(t, function ArmyToggleUnRemoveActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function HoldPositionConditions))
call TriggerAddAction(t, function HoldPositionActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition(function ReturnToArmyConditions))
call TriggerAddAction(t, function ReturnToArmyActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddCondition(t, Condition(function SpellChannelConditions))
call TriggerAddAction(t, function SpellChannelActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(t, Condition(function SpellChannelStopConditions))
call TriggerAddAction(t, function SpellChannelStopActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, function UnitDiesActions)
endfunction
endlibrary
scope BuildingSelectionHotkeys initializer Init
globals
private integer array SELECTED_UNIT_TYPES[4][10]
private oskeytype array HOTKEYS
private integer METAKEY_CTRL = 2
private integer METAKEY_CTRLSHIFT = 3
private integer PRESSED_KEY = 0
endglobals
private function interface UnitFilter takes unit whichUnit returns boolean
private function GetAllBuildingsOfType takes nothing returns boolean
local player whichPlayer = GetTriggerPlayer()
local unit u = GetFilterUnit()
local integer id = GetUnitTypeId(u)
local integer whichRace = udg_Int_Race[GetConvertedPlayerId(whichPlayer)]
local UnitFilter filter = SELECTED_UNIT_TYPES[whichRace][PRESSED_KEY]
return UnitAlive(u) and filter.evaluate(u)
endfunction
private function OnBuildingHotkeyPressed takes nothing returns nothing
local oskeytype pressedKeyType = BlzGetTriggerPlayerKey()
local player whichPlayer = GetTriggerPlayer()
local group g = CreateGroup()
local unit picked = null
local integer i = 0
loop
exitwhen i > 4
if pressedKeyType == HOTKEYS[i] then
set PRESSED_KEY = i
exitwhen true
endif
set i = i + 1
endloop
if (BlzGetTriggerPlayerMetaKey()) == METAKEY_CTRLSHIFT then
set PRESSED_KEY = PRESSED_KEY + 5
endif
call GroupEnumUnitsOfPlayer(g , whichPlayer , Condition(function GetAllBuildingsOfType))
if (BlzGroupGetSize(g) > 0) then
if (GetLocalPlayer() == whichPlayer) then
call ClearSelection()
endif
loop
set picked = FirstOfGroup(g)
exitwhen picked == null
if (GetLocalPlayer() == whichPlayer) then
call SelectUnit(picked, true)
endif
call GroupRemoveUnit(g, picked)
endloop
endif
call DestroyGroup(g)
set g = null
endfunction
private function IsHall takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_CITADEL or unitTypeId == SB_HOLD or unitTypeId == SB_NECROPOLIS or unitTypeId == SB_DARK_NEXUS
endfunction
private function IsPrimaryRax takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_BARRACKS or unitTypeId == SB_HALL_OF_WARRIORS
endfunction
private function IsSecondaryRax takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_WAR_FACTORY or unitTypeId == SB_HAVEN
endfunction
private function IsAirStructure takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_CELESTIAL_BEACON or unitTypeId == SB_CELESTIAL_GATEWAY or unitTypeId == SB_SKY_TOTEM or unitTypeId == SB_DREAD_SPIRE
endfunction
private function IsLumberMill takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_LUMBER_MILL or unitTypeId == SB_WAR_MILL
endfunction
private function IsHallOfElites takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_HALL_OF_ELITES
endfunction
private function IsCryptOrManor takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_CRYPT or unitTypeId == SB_MANOR
endfunction
private function IsPrimaryUpgradeStructure takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_BLACKSMITH or unitTypeId == SB_HALL_OF_SCHOLARS or unitTypeId == SB_GRAVEYARD
endfunction
private function IsChurch takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_CHURCH
endfunction
private function IsScoutTower takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_SCOUT_TOWER
endfunction
private function IsDendroidElder takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_DENDROID_ELDER
endfunction
private function IsDendroidChieftain takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_DENDROID_CHIEFTAIN
endfunction
private function IsProductionStructure takes unit whichUnit returns boolean
return IsPrimaryRax(whichUnit) or IsSecondaryRax(whichUnit) or IsAirStructure(whichUnit)
endfunction
private function IsAltar takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_ALTAR_OF_LIGHT or unitTypeId == SB_ALTAR_OF_NATURE or unitTypeId == SB_ALTAR_OF_DARKNESS
endfunction
private function IsIdleNecromancer takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
if (BlzGetUnitBooleanField(whichUnit, UNIT_BF_IS_A_BUILDING) == true) then
return false
endif
return unitTypeId == SB_NECROMANCER or unitTypeId == SB_NECROMANCER_LICH
endfunction
private function IsTrainingNecromancer takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
if (BlzGetUnitBooleanField(whichUnit, UNIT_BF_IS_A_BUILDING) == false) then
return false
endif
return unitTypeId == SB_NECROMANCER or unitTypeId == SB_NECROMANCER_LICH
endfunction
private function IsDeathProductionStructure takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
if (BlzGetUnitBooleanField(whichUnit, UNIT_BF_IS_A_BUILDING) == false) then
return false
endif
return unitTypeId == SB_NECROMANCER or unitTypeId == SB_NECROMANCER_LICH or unitTypeId == SB_DREAD_SPIRE
endfunction
private function IsVaultOfPhylacteries takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_VAULT_OF_PHYLACTERIES
endfunction
private function IsVileLaboratory takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_VILE_LABORATORY
endfunction
private function Init takes nothing returns nothing
local integer i = 0
local trigger trig = CreateTrigger()
loop
exitwhen i > bj_MAX_PLAYERS //Use whatever the best way is to loop through all players
if (IsPlayingPlayer(Player(i), true)) then
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_Q, METAKEY_CTRL, true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_W, METAKEY_CTRL, true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_E, METAKEY_CTRL, true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_R, METAKEY_CTRL, true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_T, METAKEY_CTRL, true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_Q, METAKEY_CTRLSHIFT , true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_W, METAKEY_CTRLSHIFT , true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_E, METAKEY_CTRLSHIFT , true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_R, METAKEY_CTRLSHIFT , true )
call BlzTriggerRegisterPlayerKeyEvent( trig , Player(i) , OSKEY_T, METAKEY_CTRLSHIFT , true )
endif
set i = i + 1
endloop
call TriggerAddAction( trig , function OnBuildingHotkeyPressed )
set HOTKEYS[0] = OSKEY_Q
set HOTKEYS[1] = OSKEY_W
set HOTKEYS[2] = OSKEY_E
set HOTKEYS[3] = OSKEY_R
set HOTKEYS[4] = OSKEY_T
set HOTKEYS[5] = OSKEY_Q
set HOTKEYS[6] = OSKEY_W
set HOTKEYS[7] = OSKEY_E
set HOTKEYS[8] = OSKEY_R
set HOTKEYS[9] = OSKEY_T
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][0] = IsHall
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][1] = IsPrimaryRax
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][2] = IsSecondaryRax
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][3] = IsAirStructure
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][4] = IsProductionStructure
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][5] = IsPrimaryUpgradeStructure
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][6] = IsLumberMill
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][7] = IsAltar
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][8] = IsChurch
set SELECTED_UNIT_TYPES[RACE_NUM_ORDER][9] = IsScoutTower
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][0] = IsHall
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][1] = IsPrimaryRax
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][2] = IsSecondaryRax
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][3] = IsAirStructure
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][4] = IsProductionStructure
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][5] = IsPrimaryUpgradeStructure
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][6] = IsHallOfElites
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][7] = IsAltar
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][8] = IsDendroidElder
set SELECTED_UNIT_TYPES[RACE_NUM_NATURE][9] = IsDendroidChieftain
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][0] = IsHall
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][1] = IsIdleNecromancer
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][2] = IsTrainingNecromancer
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][3] = IsAirStructure
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][4] = IsDeathProductionStructure
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][5] = IsPrimaryUpgradeStructure
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][6] = IsCryptOrManor
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][7] = IsAltar
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][8] = IsVileLaboratory
set SELECTED_UNIT_TYPES[RACE_NUM_DEATH][9] = IsVaultOfPhylacteries
endfunction
endscope
library GoldMineTracker initializer Init requires TimersPlus, EventSystem
globals
private constant hashtable HT_GOLD_MINE_TRACKER = InitHashtable()
private constant key KEY_GOLD_MINE
private constant key KEY_GOLD_MINE_WORKER
private constant real GOLD_MINE_OWNERSHIP_BUFFER = 2.0
private constant integer ORDER_HARVEST = 852018
private constant integer ORDER_SMART = 851971
private constant integer ORDER_SMART_FROM_RALLY = 851970
private constant integer ORDER_RESUME_HARVESTING = 852017
private constant integer GOLD_MINE_ABILITY = 'Agld'
private constant integer array HARVEST_GOLD_ABILITIES
private constant integer array RETURN_GOLD_ABILITIES
// Events
public Event OnBeforeWorkerAddedToMine = 0
public Event OnAfterWorkerAddedToMine = 0
public Event OnBeforeWorkerRemovedFromMine = 0
public Event OnAfterWorkerRemovedFromMine = 0
public Event OnMineGoldOrder = 0
public Event OnReturnGoldOrder = 0
// Mining State
public constant integer MINING_STATE_NONE = 0
public constant integer MINING_STATE_MINE = 1
public constant integer MINING_STATE_RETURN = 2
endglobals
private struct GoldMine
unit mine = null
group workers = null
player owner = null
IntTimer emptyTimer = 0
method onDestroy takes nothing returns nothing
call emptyTimer.destroy()
call DestroyGroup(workers)
call RemoveSavedInteger(HT_GOLD_MINE_TRACKER, GetHandleId(mine), KEY_GOLD_MINE)
endmethod
endstruct
private struct GoldMineWorker
unit mine = null
unit worker = null
integer miningState = MINING_STATE_NONE
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(HT_GOLD_MINE_TRACKER, GetHandleId(worker), KEY_GOLD_MINE_WORKER)
endmethod
endstruct
public struct MiningEvent
unit mine = null
unit worker = null
integer lastMiningState = 0
endstruct
private function CreateGoldMine takes unit mine returns GoldMine
local GoldMine gm = GoldMine.create()
set gm.mine = mine
set gm.workers = CreateGroup()
return gm
endfunction
private function CreateGoldMineWorker takes unit worker returns GoldMineWorker
local GoldMineWorker gmw = GoldMineWorker.create()
set gmw.worker = worker
set gmw.miningState = MINING_STATE_NONE
return gmw
endfunction
private function CreateEventData takes unit mine, unit worker, integer lastMiningState returns MiningEvent
local MiningEvent data = MiningEvent.create()
set data.mine = mine
set data.worker = worker
set data.lastMiningState = lastMiningState
return data
endfunction
private function FireEvent takes Event e, unit mine, unit worker, integer lastMiningState returns nothing
local MiningEvent data = 0
if (EventSystem_HasListeners(e)) then
set data = CreateEventData(mine, worker, lastMiningState)
call EventSystem_FireEvent(e, data)
call data.destroy()
endif
endfunction
private function GetGoldMineData takes unit mine returns GoldMine
return LoadInteger(HT_GOLD_MINE_TRACKER, GetHandleId(mine), KEY_GOLD_MINE)
endfunction
private function GetOrCreateGoldMineData takes unit mine returns GoldMine
local GoldMine data = GetGoldMineData(mine)
if (data == 0) then
set data = CreateGoldMine(mine)
call SaveInteger(HT_GOLD_MINE_TRACKER, GetHandleId(mine), KEY_GOLD_MINE, data)
endif
return data
endfunction
private function GetGoldMineWorkerData takes unit worker returns GoldMineWorker
return LoadInteger(HT_GOLD_MINE_TRACKER, GetHandleId(worker), KEY_GOLD_MINE_WORKER)
endfunction
private function GetOrCreateGoldMineWorkerData takes unit worker returns GoldMineWorker
local GoldMineWorker data = GetGoldMineWorkerData(worker)
if (data == 0) then
set data = CreateGoldMineWorker(worker)
call SaveInteger(HT_GOLD_MINE_TRACKER, GetHandleId(worker), KEY_GOLD_MINE_WORKER, data)
endif
return data
endfunction
private function OnGoldMineEmptied takes IntTimer it returns nothing
local GoldMine gm = it.owner
set gm.owner = null
set gm.emptyTimer = 0
endfunction
private function GoldMineSetOwner takes GoldMine gm, player owner returns nothing
if (owner != null) then
set gm.owner = owner
call gm.emptyTimer.destroy()
set gm.emptyTimer = 0
elseif (gm.owner != null) then
set gm.emptyTimer = CreateIntTimer(gm, true)
call StartTimerPlus(gm.emptyTimer, GOLD_MINE_OWNERSHIP_BUFFER, OnGoldMineEmptied)
endif
endfunction
private function GoldMineGetOwner takes unit mine returns player
local GoldMine data = GetGoldMineData(mine)
return data.owner
endfunction
private function GoldMineRemoveWorker takes unit mine, unit worker returns boolean
local GoldMine gm = GetGoldMineData(mine)
local GoldMineWorker gmw = GetGoldMineWorkerData(worker)
call FireEvent(OnBeforeWorkerRemovedFromMine, mine, worker, gmw.miningState)
if (GroupRemoveUnit(gm.workers, worker)) then
set gmw.mine = null
if (FirstOfGroup(gm.workers) == null) then
// Mine is empty
call GoldMineSetOwner(gm, null)
endif
call FireEvent(OnAfterWorkerRemovedFromMine, mine, worker, gmw.miningState)
return true
endif
return false
endfunction
private function GoldMineAddWorker takes unit mine, unit worker returns boolean
local GoldMine gm = GetOrCreateGoldMineData(mine)
local GoldMineWorker gmw = GetOrCreateGoldMineWorkerData(worker)
if (gmw.mine != mine) then
if (gmw.mine != null) then
call GoldMineRemoveWorker(mine, worker)
endif
call FireEvent(OnBeforeWorkerAddedToMine, mine, worker, gmw.miningState)
if (GroupAddUnit(gm.workers, worker)) then
set gmw.mine = mine
if (CountUnitsInGroup(gm.workers) == 1) then
call GoldMineSetOwner(gm, GetOwningPlayer(worker))
endif
call FireEvent(OnAfterWorkerAddedToMine, mine, worker, gmw.miningState)
return true
endif
endif
return false
endfunction
private function ReportMineOrder takes integer orderId, unit mine, unit worker returns nothing
local player owner = GoldMineGetOwner(mine)
local GoldMineWorker gmw = 0
local integer lastMiningState = 0
if (owner == null or owner == GetOwningPlayer(worker)) then
call GoldMineAddWorker(mine, worker)
set gmw = GetGoldMineWorkerData(worker)
set lastMiningState = gmw.miningState
// If the worker is "returning" gold, only change mining state on an actual harvest order.
if (lastMiningState != MINING_STATE_RETURN or orderId != ORDER_SMART) then
set gmw.miningState = MINING_STATE_MINE
endif
call FireEvent(OnMineGoldOrder, mine, worker, lastMiningState)
endif
endfunction
private function ReportReturnOrder takes integer orderId, unit worker returns nothing
local GoldMineWorker gmw = GetGoldMineWorkerData(worker)
local integer lastMiningState = 0
if (gmw != 0) then
set lastMiningState = gmw.miningState
if (lastMiningState != MINING_STATE_MINE or orderId != ORDER_SMART) then
set gmw.miningState = MINING_STATE_RETURN
endif
call FireEvent(OnReturnGoldOrder, gmw.mine, worker, lastMiningState)
endif
endfunction
private function ReportMineDestroyed takes GoldMine mine returns nothing
local unit worker = null
loop
set worker = FirstOfGroup(mine.workers)
exitwhen worker == null
call GoldMineRemoveWorker(mine.mine, worker)
endloop
call mine.destroy()
endfunction
private function IsGoldMine takes unit whichUnit returns boolean
return GetUnitAbilityLevel(whichUnit, GOLD_MINE_ABILITY) > 0
endfunction
private function IsGoldHarvester takes unit whichUnit returns boolean
local integer i = 0
loop
exitwhen HARVEST_GOLD_ABILITIES[i] == 0
if (GetUnitAbilityLevel(whichUnit, HARVEST_GOLD_ABILITIES[i]) > 0) then
return true
endif
set i = i + 1
endloop
return false
endfunction
private function IsGoldReturnUnit takes unit whichUnit returns boolean
local integer i = 0
loop
exitwhen RETURN_GOLD_ABILITIES[i] == 0
if (GetUnitAbilityLevel(whichUnit, RETURN_GOLD_ABILITIES[i]) > 0) then
return true
endif
set i = i + 1
endloop
return false
endfunction
private function IsHarvestOrder takes integer orderId, unit ordered, unit target returns boolean
if (orderId == ORDER_HARVEST or orderId == ORDER_SMART or orderId == ORDER_SMART_FROM_RALLY) then
return IsGoldMine(target) and IsGoldHarvester(ordered)
endif
return false
endfunction
private function IsReturnGoldOrder takes integer orderId, unit ordered, unit target returns boolean
if (orderId == ORDER_RESUME_HARVESTING) then
return true
elseif (orderId == ORDER_SMART and IsGoldReturnUnit(target)) then
return true
endif
return false
endfunction
// ****************************************
// PUBLIC API
// ****************************************
public function GetWorkerCount takes unit mine returns integer
local GoldMine data = GetGoldMineData(mine)
if (data != 0) then
return CountUnitsInGroup(data.workers)
endif
return 0
endfunction
public function GetMiningState takes unit worker returns integer
local GoldMineWorker gmw = GetGoldMineWorkerData(worker)
if (gmw != 0) then
return gmw.miningState
endif
return MINING_STATE_NONE
endfunction
// ****************************************
// TRIGGERS
// ****************************************
private function HarvestTriggerCondition takes nothing returns boolean
return IsHarvestOrder(GetIssuedOrderId(), GetOrderedUnit(), GetOrderTargetUnit())
endfunction
private function HarvestTriggerAction takes nothing returns nothing
local unit mine = GetOrderTargetUnit()
local unit harvester = GetOrderedUnit()
call ReportMineOrder(GetIssuedOrderId(), mine, harvester)
endfunction
private function NonHarvestTriggerCondition takes nothing returns boolean
return not IsHarvestOrder(GetIssuedOrderId(), GetOrderedUnit(), GetOrderTargetUnit())
endfunction
private function NonHarvestTriggerAction takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local GoldMineWorker gmw = GetGoldMineWorkerData(ordered)
if (gmw != 0 and gmw.mine != null) then
if (IsReturnGoldOrder(GetIssuedOrderId(), ordered, GetOrderTargetUnit())) then
call ReportReturnOrder(GetIssuedOrderId(), ordered)
else
call GoldMineRemoveWorker(gmw.mine, ordered)
endif
endif
endfunction
private function CreateHarvestTriggers takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition(function HarvestTriggerCondition))
call TriggerAddAction(t, function HarvestTriggerAction)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition(function NonHarvestTriggerCondition))
call TriggerAddAction(t, function NonHarvestTriggerAction)
endfunction
private function DeathTriggerCondition takes nothing returns boolean
local unit dying = GetDyingUnit()
if (GetGoldMineWorkerData(dying) != 0) then
return true
elseif (GetGoldMineData(dying) != 0) then
return true
endif
return false
endfunction
private function DeathTriggerAction takes nothing returns nothing
local unit dying = GetDyingUnit()
local GoldMine gm = 0
local GoldMineWorker gmw = GetGoldMineWorkerData(dying)
if (gmw != 0) then
call GoldMineRemoveWorker(gmw.mine, dying)
call gmw.destroy()
else
set gm = GetGoldMineData(dying)
if (gm != 0) then
call ReportMineDestroyed(gm)
endif
endif
endfunction
private function CreateDeathTriggers takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function DeathTriggerCondition))
call TriggerAddAction(t, function DeathTriggerAction)
endfunction
// ****************************************
// INITIALIZATION
// ****************************************
private function Init takes nothing returns nothing
set HARVEST_GOLD_ABILITIES[0] = SB_HARVEST_CHAOS_WEAK
set HARVEST_GOLD_ABILITIES[1] = SB_HARVEST_CHAOS_NORMAL
set HARVEST_GOLD_ABILITIES[2] = SB_HARVEST_GOLD_AND_LUMBER
set HARVEST_GOLD_ABILITIES[3] = SB_HARVEST_GOLD_AND_LUMBER_MAGIC
set HARVEST_GOLD_ABILITIES[4] = SB_HARVEST_GOLD_ONLY
set HARVEST_GOLD_ABILITIES[5] = SB_HARVEST_ORDER_SUPER_PEASANT
set RETURN_GOLD_ABILITIES[0] = SB_RETURN_GOLD
set RETURN_GOLD_ABILITIES[1] = SB_RETURN_GOLD_AND_LUMBER
set OnBeforeWorkerAddedToMine = EventSystem_Create()
set OnAfterWorkerAddedToMine = EventSystem_Create()
set OnBeforeWorkerRemovedFromMine = EventSystem_Create()
set OnAfterWorkerRemovedFromMine = EventSystem_Create()
set OnMineGoldOrder = EventSystem_Create()
set OnReturnGoldOrder = EventSystem_Create()
call CreateHarvestTriggers()
call CreateDeathTriggers()
endfunction
endlibrary
library EventSystem requires LinkedList
function interface EventHandler takes integer eventData returns nothing
struct Event
LinkedList_Int listeners = 0
method onDestroy takes nothing returns nothing
call DestroyLinkedList(listeners)
endmethod
endstruct
public function Create takes nothing returns Event
local Event ev = Event.create()
set ev.listeners = CreateLinkedList_Int()
return ev
endfunction
public function RegisterEventListener takes Event ev, EventHandler listener returns nothing
local LinkedListNode_Int node = LinkedListFindInt(ev.listeners, listener)
if (node == 0) then
call LinkedListAddLastInt(ev.listeners, listener)
endif
endfunction
public function UnregisterEventListener takes Event ev, EventHandler listener returns nothing
local LinkedListNode_Int node = LinkedListFindInt(ev.listeners, listener)
if (node != 0) then
call LinkedListDestroyNode(ev.listeners, node)
endif
endfunction
public function HasListeners takes Event ev returns boolean
return ev.listeners.count > 0
endfunction
public function FireEvent takes Event ev, integer input returns nothing
local LinkedListNode_Int node = LinkedListGetFirst(ev.listeners)
local EventHandler listener = 0
loop
exitwhen node == 0
set listener = node.value
if (listener != 0) then
call listener.evaluate(input)
endif
set node = node.next
endloop
endfunction
endlibrary
library Animate requires TimersPlus
function interface AnimationCallback takes IAnimation animation returns nothing
interface IAnimation
AnimationCallback updateCallback = 0
AnimationCallback endCallback = 0
IntTimer update = 0
endinterface
private function AnimationUpdate takes IntTimer it returns nothing
local IAnimation animation = it.owner
if (animation.updateCallback != 0) then
call animation.updateCallback.evaluate(animation)
endif
endfunction
private function AnimationExpires takes IntTimer it returns nothing
local IAnimation animation = it.owner
if (animation.endCallback != 0) then
call animation.endCallback.evaluate(animation)
endif
endfunction
function DestroyAnimation takes IAnimation animation returns nothing
call animation.update.destroy()
call animation.destroy()
endfunction
function PlayAnimationAll takes IAnimation animation, real duration, real interval, boolean oneShot, AnimationCallback update, AnimationCallback end returns nothing
set animation.updateCallback = update
set animation.endCallback = end
if (animation.update == 0) then
set animation.update = CreateIntTimer(animation, oneShot)
endif
call StartTimerPlusPeriodic(animation.update, duration, interval, AnimationUpdate, AnimationExpires)
endfunction
endlibrary
function GetUnitSize takes unit whichUnit returns real
if (not HaveSavedReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("START SCALE"))) then
return BlzGetUnitRealField(whichUnit, UNIT_RF_SCALING_VALUE)
else
return LoadReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("END SCALE"))
endif
endfunction
function SetUnitSizeOverTime takes unit whichUnit, real duration, real targetScale returns nothing
local real scale = GetUnitSize(whichUnit)
call SaveReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("START SCALE"), scale)
call SaveReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("END SCALE"), targetScale)
if (duration > 0) then
call SaveReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("DURATION"), duration)
call SaveReal(udg_HashTable_SizeBlending, GetHandleId(whichUnit), StringHash("TIMER"), 0.0)
call GroupAddUnit(udg_UnitGroup_SizeBlending, whichUnit)
call EnableTrigger(gg_trg_Size_Blending_Loop)
else
call SetUnitScale(whichUnit, targetScale, targetScale, targetScale)
endif
endfunction
function ChangeUnitSizeOverTime takes unit whichUnit, real duration, real sizeChangePct returns nothing
local real scale = GetUnitSize(whichUnit)
call SetUnitSizeOverTime(whichUnit, duration, scale + sizeChangePct)
endfunction
function ChangeUnitSize takes unit whichUnit, real sizeChangePct returns nothing
call ChangeUnitSizeOverTime(whichUnit, 0.0, sizeChangePct)
endfunction
globals
constant real SIZE_BLENDING_INTERVAL = 0.05
endglobals
function Trig_Size_Blending_Loop_Actions takes nothing returns nothing
local integer unitCount = BlzGroupGetSize(udg_UnitGroup_SizeBlending)
local integer index = unitCount - 1
local unit pickedUnit = null
local real time = 0.0
local real duration = 0.0
local real scale = 0.0
local real startScale = 0.0
local real endScale = 0.0
local real i = 0.0
if (unitCount > 0) then
call EnableTrigger(gg_trg_Size_Blending_Death)
loop
exitwhen index < 0
set pickedUnit = BlzGroupUnitAt(udg_UnitGroup_SizeBlending, index)
set time = LoadReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("TIMER")) + SIZE_BLENDING_INTERVAL
set duration = LoadReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("DURATION"))
set startScale = LoadReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("START SCALE"))
set endScale = LoadReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("END SCALE"))
set i = time / duration
if (time >= duration) then
set scale = endScale
call GroupRemoveUnit(udg_UnitGroup_SizeBlending, pickedUnit)
call RemoveSavedReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("TIMER"))
else
set scale = startScale + (endScale - startScale) * i
call SaveReal(udg_HashTable_SizeBlending, GetHandleId(pickedUnit), StringHash("TIMER"), time)
endif
call SetUnitScale(pickedUnit, scale, scale, scale)
set index = index - 1
endloop
else
call DisableTrigger(gg_trg_Size_Blending_Death)
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Size_Blending_Loop takes nothing returns nothing
set gg_trg_Size_Blending_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Size_Blending_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Size_Blending_Loop, SIZE_BLENDING_INTERVAL)
call TriggerAddAction( gg_trg_Size_Blending_Loop, function Trig_Size_Blending_Loop_Actions )
endfunction
library ColorBlending requires Color, TimersPlus
globals
private constant hashtable HT_COLOR_BLENDING = InitHashtable()
private constant key KEY_COLOR_DEFAULT
private constant key KEY_COLOR_BLEND
endglobals
private struct ColorBlend
unit target = null
Color start = 0
Color end = 0
real elapsed = 0.0
real duration = 0.0
real delay = 0.0
method onDestroy takes nothing returns nothing
call start.destroy()
call end.destroy()
endmethod
endstruct
function EndColorBlendForUnit takes unit whichUnit returns nothing
local IntTimer blendTimer = LoadInteger(HT_COLOR_BLENDING, GetHandleId(whichUnit), KEY_COLOR_BLEND)
local ColorBlend blend = blendTimer.owner
if (blend != 0) then
call SetUnitVertexColor(whichUnit, blend.end.r, blend.end.g, blend.end.b, blend.end.a)
endif
call blendTimer.destroy()
call blend.destroy()
call RemoveSavedInteger(HT_COLOR_BLENDING, GetHandleId(whichUnit), KEY_COLOR_BLEND)
endfunction
private function CreateColorBlend takes unit whichUnit, Color start, Color end, real duration, real delay returns ColorBlend
local ColorBlend cb = ColorBlend.create()
set cb.target = whichUnit
set cb.start = start
set cb.end = end
set cb.duration = duration
set cb.delay = delay
return cb
endfunction
private function UpdateColorBlend takes IntTimer it returns nothing
local ColorBlend blend = it.owner
local integer r = 0
local integer g = 0
local integer b = 0
local integer a = 0
local real i = 0.0
set blend.elapsed = blend.elapsed + TimerPlusGetElapsed(it)
if (blend.elapsed > blend.delay) then
set i = (blend.elapsed - blend.delay) / blend.duration
endif
set r = blend.start.r + R2I(i * (blend.end.r - blend.start.r))
set g = blend.start.g + R2I(i * (blend.end.g - blend.start.g))
set b = blend.start.b + R2I(i * (blend.end.b - blend.start.b))
set a = blend.start.a + R2I(i * (blend.end.a - blend.start.a))
call SetUnitVertexColor(blend.target, r, g, b, a)
endfunction
private function EndColorBlend takes IntTimer it returns nothing
local ColorBlend blend = it.owner
call EndColorBlendForUnit(blend.target)
endfunction
function FadeUnitColorOverTime takes unit whichUnit, real dur, real delay, Color startColor, Color endColor returns nothing
local integer unitHandle = GetHandleId(whichUnit)
local Color defaultColor = 0
local IntTimer blendTimer = LoadInteger(HT_COLOR_BLENDING, unitHandle, KEY_COLOR_BLEND)
local ColorBlend blend = blendTimer.owner
if (not HaveSavedInteger(HT_COLOR_BLENDING, unitHandle, KEY_COLOR_DEFAULT)) then
set defaultColor = GetUnitVertexColor(whichUnit)
call SaveInteger(HT_COLOR_BLENDING, unitHandle, KEY_COLOR_DEFAULT, defaultColor)
endif
if (blendTimer != 0) then
call blend.destroy()
call blendTimer.destroy()
endif
if (dur > 0) then
call SetUnitVertexColor(whichUnit, startColor.r, startColor.g, startColor.b, startColor.a)
set blend = CreateColorBlend(whichUnit, startColor, endColor, dur, delay)
set blendTimer = CreateIntTimer(blend, false)
call StartTimerPlusPeriodic(blendTimer, dur + delay, 0.01, UpdateColorBlend, EndColorBlend)
call SaveInteger(HT_COLOR_BLENDING, unitHandle, KEY_COLOR_BLEND, blendTimer)
else
call SetUnitVertexColor(whichUnit, endColor.r, endColor.g, endColor.b, endColor.a)
endif
endfunction
function ChangeUnitColorOverTime takes unit whichUnit, real dur, real delay, integer endR, integer endG, integer endB, integer endA returns nothing
local Color endColor = CreateColor(endR, endG, endB, endA)
call FadeUnitColorOverTime(whichUnit, dur, delay, GetUnitVertexColor(whichUnit), endColor)
endfunction
function RestoreUnitColorOverTime takes unit whichUnit, real dur, real delay returns nothing
local Color defaultColor = 0
if (HaveSavedInteger(HT_COLOR_BLENDING, GetHandleId(whichUnit), KEY_COLOR_DEFAULT)) then
set defaultColor = LoadInteger(HT_COLOR_BLENDING, GetHandleId(whichUnit), KEY_COLOR_DEFAULT)
call FadeUnitColorOverTime(whichUnit, dur, delay, GetUnitVertexColor(whichUnit), defaultColor)
endif
endfunction
function RestoreUnitColor takes unit whichUnit returns nothing
call RestoreUnitColorOverTime(whichUnit, 0.0, 0.0)
endfunction
function FadeUnitAlphaOverTime takes unit whichUnit, real dur, real delay, integer startA, integer endA returns nothing
local Color startColor = GetUnitVertexColor(whichUnit)
local Color endColor = GetUnitVertexColor(whichUnit)
set startColor.a = startA
set endColor.a = endA
call FadeUnitColorOverTime(whichUnit, dur, delay, startColor, endColor)
endfunction
function ChangeUnitAlphaOverTime takes unit whichUnit, real dur, real delay, integer endA returns nothing
local integer startA = BlzGetUnitIntegerField(whichUnit, UNIT_IF_TINTING_COLOR_ALPHA)
call FadeUnitAlphaOverTime(whichUnit, dur, delay, startA, endA)
endfunction
function ChangeUnitColor takes unit whichUnit, integer r, integer g, integer b, integer a returns nothing
call ChangeUnitColorOverTime(whichUnit, 0, 0, r, g, b, a)
endfunction
function ChangeUnitAlpha takes unit whichUnit, integer a returns nothing
call ChangeUnitAlphaOverTime(whichUnit, 0, 0, a)
endfunction
endlibrary
library LightningEffects requires Vectors
globals
private constant hashtable HT_LIGHTNING_EFFECTS = InitHashtable()
endglobals
struct UnitLeash
lightning bolt = null
unit unit1 = null
unit unit2 = null
vec3 unit1Offset = 0
vec3 unit2Offset = 0
real timeRemaining = 0.0
timer updateTimer = null
method onDestroy takes nothing returns nothing
call unit1Offset.destroy()
call unit2Offset.destroy()
call DestroyLightning(bolt)
call DestroyTimer(updateTimer)
endmethod
endstruct
private function UpdateUnitLeash takes nothing returns nothing
local timer t = GetExpiredTimer()
local UnitLeash leash = LoadInteger(HT_LIGHTNING_EFFECTS, GetHandleId(t), 0)
local vec3 offset1Rotated = VecRotateZ(leash.unit1Offset, GetUnitFacing(leash.unit1))
local vec3 offset2Rotated = VecRotateZ(leash.unit2Offset, GetUnitFacing(leash.unit2))
local vec3 pos1 = GetUnitVec(leash.unit1).add(offset1Rotated)
local vec3 pos2 = GetUnitVec(leash.unit2).add(offset2Rotated)
set leash.timeRemaining = leash.timeRemaining - TimerGetElapsed(t)
call MoveLightningEx(leash.bolt, true, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z)
if (leash.timeRemaining <= 0.0) then
call leash.destroy()
endif
call offset1Rotated.destroy()
call offset2Rotated.destroy()
call pos1.destroy()
call pos2.destroy()
endfunction
public function CreateLightningBetweenUnits takes unit unit1, unit unit2, vec3 unit1Offset, vec3 unit2Offset, string lightningType returns lightning
local vec3 offset1Rotated = VecRotateZ(unit1Offset, GetUnitFacing(unit1))
local vec3 offset2Rotated = VecRotateZ(unit2Offset, GetUnitFacing(unit2))
local vec3 pos1 = GetUnitVec(unit1).add(offset1Rotated)
local vec3 pos2 = GetUnitVec(unit2).add(offset2Rotated)
local lightning l = AddLightningEx(lightningType, true, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z)
call offset1Rotated.destroy()
call offset2Rotated.destroy()
call pos1.destroy()
call pos2.destroy()
return l
endfunction
public function CreateUnitLeash takes unit unit1, unit unit2, vec3 offset1, vec3 offset2, string lightningType, real updateInterval, real duration returns UnitLeash
local UnitLeash leash = UnitLeash.create()
set leash.bolt = CreateLightningBetweenUnits(unit1, unit2, offset1, offset2, lightningType)
set leash.unit1 = unit1
set leash.unit2 = unit2
set leash.unit1Offset = offset1
set leash.unit2Offset = offset2
set leash.timeRemaining = duration
set leash.updateTimer = CreateTimer()
call SaveInteger(HT_LIGHTNING_EFFECTS, GetHandleId(leash.updateTimer), 0, leash)
call TimerStart(leash.updateTimer, updateInterval, true, function UpdateUnitLeash)
return leash
endfunction
endlibrary
globals
LightningRing array LIGHTNING_RINGS
integer LIGHTNING_RINGS_COUNT = 0
constant real LIGHTNING_RINGS_UPDATE_INTERVAL = 0.03
constant integer LIGHTNING_STATE_BIRTH = 0
constant integer LIGHTNING_STATE_STAND = 1
constant integer LIGHTNING_STATE_DEATH = 2
constant integer LIGHTNING_STATE_DESTROYED = 3
endglobals
struct LightningRing
location origin
integer resolution
string lightningType
real radius
real birthTime
real deathTime
real timeLeft
integer lrIndex
integer state
static method create takes location whichLocation, integer resolution, string lightningType, real radius, real birthTime returns LightningRing
local LightningRing lr = LightningRing.allocate()
local integer i = 0
set lr.origin = whichLocation
set lr.resolution = resolution
set lr.lightningType = lightningType
set lr.radius = radius
set lr.birthTime = birthTime
set lr.timeLeft = birthTime
set lr.state = LIGHTNING_STATE_BIRTH
set lr.lrIndex = LIGHTNING_RINGS_COUNT
set LIGHTNING_RINGS[LIGHTNING_RINGS_COUNT] = lr
set LIGHTNING_RINGS_COUNT = LIGHTNING_RINGS_COUNT + 1
loop
exitwhen i >= resolution
call lr.CreateLightning(i)
set i = i + 1
endloop
if (birthTime <= 0.0) then
call lr.Update()
else
call EnableTrigger(gg_trg_Lightning_Ring_Loop)
endif
return lr
endmethod
public method GetState takes nothing returns integer
return state
endmethod
public method GetLightning takes integer index returns lightning
return LoadLightningHandle(udg_HashTable_SpecialEffects, this, index)
endmethod
public method Destroy takes nothing returns nothing
set timeLeft = deathTime
if (deathTime <= 0.0) then
set state = LIGHTNING_STATE_DESTROYED
else
set state = LIGHTNING_STATE_DEATH
endif
endmethod
public method Update takes nothing returns nothing
if (state == LIGHTNING_STATE_BIRTH) then
call UpdateBirth()
elseif (state == LIGHTNING_STATE_DEATH) then
call UpdateDeath()
endif
endmethod
private method CreateLightning takes integer index returns nothing
local real x = GetLocationX(origin)
local real y = GetLocationY(origin)
local lightning l = AddLightning(lightningType, true, x, y, x, y)
call SaveLightningHandle(udg_HashTable_SpecialEffects, this, index, l)
endmethod
private method DestroyLightning takes integer index returns nothing
local lightning l = LoadLightningHandle(udg_HashTable_SpecialEffects, this, index)
call DestroyLightningBJ(l)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, this, index)
endmethod
private method UpdateBirth takes nothing returns nothing
local real angleStep = 360.0 / resolution
local real r = radius
local lightning l = null
local integer i = 0
local real x1 = 0.0
local real y1 = 0.0
local real x2 = 0.0
local real y2 = 0.0
if (birthTime > 0) then
set r = RMinBJ(radius, radius * (birthTime - timeLeft) / birthTime)
endif
loop
exitwhen i >= resolution
set x1 = PolarProjectionX(GetLocationX(origin), r, angleStep * i)
set y1 = PolarProjectionY(GetLocationY(origin), r, angleStep * i)
set x2 = PolarProjectionX(GetLocationX(origin), r, angleStep * (i + 1))
set y2 = PolarProjectionY(GetLocationY(origin), r, angleStep * (i + 1))
set l = GetLightning(i)
call MoveLightning(l, true, x1, y1, x2, y2)
set i = i + 1
endloop
set timeLeft = timeLeft - LIGHTNING_RINGS_UPDATE_INTERVAL
if (timeLeft <= 0) then
set state = LIGHTNING_STATE_STAND
endif
endmethod
private method UpdateDeath takes nothing returns nothing
local integer i = 0
local lightning l = null
loop
exitwhen i >= resolution
set l = GetLightning(i)
call SetLightningColor(l, 1.0, 1.0, 1.0, RMaxBJ(0.0, timeLeft / deathTime))
set i = i + 1
endloop
set timeLeft = timeLeft - LIGHTNING_RINGS_UPDATE_INTERVAL
if (timeLeft <= 0) then
set state = LIGHTNING_STATE_DESTROYED
endif
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
call RemoveLocation(origin)
loop
exitwhen i >= resolution
call DestroyLightning(i)
set i = i + 1
endloop
set i = lrIndex
loop
exitwhen i >= LIGHTNING_RINGS_COUNT - 2
set LIGHTNING_RINGS[i] = LIGHTNING_RINGS[i + 1]
set LIGHTNING_RINGS[i].lrIndex = i
set i = i + 1
endloop
set LIGHTNING_RINGS[LIGHTNING_RINGS_COUNT - 1] = 0
set LIGHTNING_RINGS_COUNT = LIGHTNING_RINGS_COUNT - 1
endmethod
endstruct
function Trig_Lightning_Ring_Loop_Actions takes nothing returns nothing
local integer lrIndex = LIGHTNING_RINGS_COUNT - 1
local integer state = 0
loop
exitwhen lrIndex < 0
set state = LIGHTNING_RINGS[lrIndex].GetState()
if (state != LIGHTNING_STATE_DESTROYED) then
call LIGHTNING_RINGS[lrIndex].Update()
else
call LIGHTNING_RINGS[lrIndex].destroy()
endif
set lrIndex = lrIndex - 1
endloop
if (LIGHTNING_RINGS_COUNT <= 0) then
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Lightning_Ring_Loop takes nothing returns nothing
set gg_trg_Lightning_Ring_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Lightning_Ring_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Lightning_Ring_Loop, LIGHTNING_RINGS_UPDATE_INTERVAL)
call TriggerAddAction( gg_trg_Lightning_Ring_Loop, function Trig_Lightning_Ring_Loop_Actions )
endfunction
library OrderTracking initializer Init requires LinkedList
globals
private constant hashtable HT_ORDER_TRACKING = InitHashtable()
private constant key KEY_TRACKED_ORDER
private LinkedList_Int EVENT_HANDLERS_BEFORE_TRACK = 0
private LinkedList_Int EVENT_HANDLERS_AFTER_TRACK = 0
public integer EVENT_BEFORE_TRACK = 1
public integer EVENT_TRACK = 2
endglobals
public struct Order
integer orderId = 0
unit orderTargetUnit = null
destructable targetDestructable = null
real targetX = 0.0
real targetY = 0.0
endstruct
public struct TrackedOrder
Order lastOrder = 0
LinkedList_Int orderFilter = 0
endstruct
private function GetEventHandlers takes integer whichEvent returns LinkedList_Int
if (whichEvent == EVENT_BEFORE_TRACK) then
return EVENT_HANDLERS_BEFORE_TRACK
elseif (whichEvent == EVENT_TRACK) then
return EVENT_HANDLERS_AFTER_TRACK
endif
return 0
endfunction
public function interface EventHandler takes unit whichUnit, Order beforeTrack, Order afterTrack returns nothing
public function RegisterListener takes integer eventType, EventHandler handler returns nothing
local LinkedList_Int handlers = GetEventHandlers(eventType)
if (handlers != 0 and LinkedListFindInt(handlers, handler) == 0) then
call LinkedListAddLastInt(handlers, handler)
endif
endfunction
public function UnregisterListener takes integer eventType, EventHandler handler returns nothing
local LinkedList_Int handlers = GetEventHandlers(eventType)
local LinkedListNode_Int existing = 0
if (handlers != 0) then
set existing = LinkedListFindInt(handlers, handler)
if (existing != 0) then
call LinkedListDestroyNode(handlers, existing)
endif
endif
endfunction
private function FireEvent takes integer eventType, unit whichUnit, Order lastOrder, Order newOrder returns nothing
local LinkedList_Int handlers = GetEventHandlers(eventType)
local LinkedListNode_Int node = LinkedListGetFirst(handlers)
local EventHandler handler = 0
loop
exitwhen node == 0
set handler = node.value
call handler.evaluate(whichUnit, lastOrder, newOrder)
set node = node.next
endloop
endfunction
public function IsUnitTracked takes unit whichUnit returns boolean
return HaveSavedInteger(HT_ORDER_TRACKING, GetHandleId(whichUnit), KEY_TRACKED_ORDER)
endfunction
public function TrackUnit takes unit whichUnit returns nothing
local TrackedOrder to = 0
if (not IsUnitTracked(whichUnit)) then
set to = TrackedOrder.create()
set to.orderFilter = CreateLinkedList_Int()
call SaveInteger(HT_ORDER_TRACKING, GetHandleId(whichUnit), KEY_TRACKED_ORDER, to)
endif
endfunction
public function GetTrackedOrder takes unit whichUnit returns TrackedOrder
return LoadInteger(HT_ORDER_TRACKING, GetHandleId(whichUnit), KEY_TRACKED_ORDER)
endfunction
public function GetLastOrder takes unit whichUnit returns Order
local TrackedOrder to = GetTrackedOrder(whichUnit)
if (to != 0) then
return to.lastOrder
endif
return 0
endfunction
public function FilterOutOrder takes unit whichUnit, integer orderId returns nothing
local TrackedOrder to = GetTrackedOrder(whichUnit)
call LinkedListAddLastInt(to.orderFilter, orderId)
endfunction
public function SaveOrder takes unit whichUnit, integer orderId, unit targetUnit, destructable targetDestructable, real targetX, real targetY returns nothing
local TrackedOrder to = GetTrackedOrder(whichUnit)
local Order lastOrder = 0
local Order new = 0
if (LinkedListFindInt(to.orderFilter, orderId) == 0) then
set lastOrder = to.lastOrder
set new = Order.create()
set new.orderId = orderId
set new.orderTargetUnit = targetUnit
set new.targetDestructable = targetDestructable
set new.targetX = targetX
set new.targetY = targetY
call FireEvent(EVENT_TRACK, whichUnit, lastOrder, new)
set to.lastOrder = new
call lastOrder.destroy()
endif
endfunction
public function ExecuteOrder takes unit ordered, Order order returns boolean
if (order.orderId != 0) then
if (order.orderTargetUnit != null) then
return IssueTargetOrderById(ordered, order.orderId, order.orderTargetUnit)
elseif (order.targetDestructable != null) then
return IssueTargetOrderById(ordered, order.orderId, order.targetDestructable)
elseif (order.targetX != 0.0 and order.targetY != 0.0) then
return IssuePointOrderById(ordered, order.orderId, order.targetX, order.targetY)
endif
return IssueImmediateOrderById(ordered, order.orderId)
endif
return false
endfunction
private function Init takes nothing returns nothing
set EVENT_HANDLERS_BEFORE_TRACK = CreateLinkedList_Int()
set EVENT_HANDLERS_AFTER_TRACK = CreateLinkedList_Int()
endfunction
endlibrary
function Trig_Order_Tracking_Conditions takes nothing returns boolean
return OrderTracking_IsUnitTracked(GetOrderedUnit())
endfunction
function Trig_Order_Tracking_Actions takes nothing returns nothing
call OrderTracking_SaveOrder(GetOrderedUnit(), GetIssuedOrderId(), GetOrderTargetUnit(), GetOrderTargetDestructable(), GetOrderPointX(), GetOrderPointY())
endfunction
//===========================================================================
function InitTrig_Order_Tracking takes nothing returns nothing
set gg_trg_Order_Tracking = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Order_Tracking, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Order_Tracking, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Order_Tracking, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Order_Tracking, Condition( function Trig_Order_Tracking_Conditions ) )
call TriggerAddAction( gg_trg_Order_Tracking, function Trig_Order_Tracking_Actions )
endfunction
library FloatingText
function FloatTextAboveUnit takes unit whichUnit, string text, real size, real zOffset, real r, real g, real b, real a returns texttag
local texttag tt = CreateTextTag()
call SetTextTagText(tt, text, TextTagSize2Height(size))
call SetTextTagPosUnit(tt, whichUnit, zOffset)
call SetTextTagColor(tt, R2I(255 * r), R2I(255 * g), R2I(255 * b), R2I(255 * a))
call SetTextTagVisibility(tt, true)
return tt
endfunction
function FloatTextAboveUnitForPlayer takes unit whichUnit, player whichPlayer, string text, real size, real zOffset, real r, real g, real b, real a returns texttag
local force playerForce = GetForceOfPlayer(whichPlayer)
local texttag tt = FloatTextAboveUnit(whichUnit, text, size, zOffset, r, g, b, a)
call SetTextTagVisibility(tt, whichPlayer == GetLocalPlayer())
return tt
endfunction
function SetFloatingTextMovement takes texttag tt, real lifespan, real fadePoint, real velX, real velY returns nothing
call SetTextTagLifespan(tt, lifespan)
call SetTextTagFadepoint(tt, fadePoint)
call SetTextTagVelocity(tt, TextTagSpeed2Velocity(velX), TextTagSpeed2Velocity(velY))
call SetTextTagPermanent(tt, false)
endfunction
endlibrary
library TrainingQueue initializer Init requires LinkedList
globals
public constant integer TQ_EVENT_TYPE_TRAIN = 0
public constant integer TQ_EVENT_TYPE_FINISH = 1
public constant integer TQ_EVENT_TYPE_CANCEL = 2
private constant hashtable HT_TrainingQueue = InitHashtable()
private constant timer EVENT_QUEUE_TIMER = CreateTimer()
private constant key KEY_TRAINING_QUEUE
private LinkedList_Int TQ_EVENT_QUEUE = 0
private LinkedList_Int TQ_EVENT_HANDLERS_TRAIN = 0
private LinkedList_Int TQ_EVENT_HANDLERS_FINISH = 0
private LinkedList_Int TQ_EVENT_HANDLERS_CANCEL = 0
endglobals
public struct TrainingQueueEvent extends ILinkedListNode
player owningPlayer = null
integer unitTypeId = 0
group trainers = null
integer eventType = 0
method onDestroy takes nothing returns nothing
call DestroyGroup(trainers)
endmethod
endstruct
public function interface TrainingQueueEventHandler takes TrainingQueueEvent tqe returns nothing
private function Init takes nothing returns nothing
set TQ_EVENT_QUEUE = CreateLinkedList_Int()
set TQ_EVENT_HANDLERS_TRAIN = CreateLinkedList_Int()
set TQ_EVENT_HANDLERS_FINISH = CreateLinkedList_Int()
set TQ_EVENT_HANDLERS_CANCEL = CreateLinkedList_Int()
endfunction
public function GetTrainingQueue takes unit whichUnit returns LinkedList_Int
return LoadInteger(HT_TrainingQueue, GetHandleId(whichUnit), KEY_TRAINING_QUEUE)
endfunction
private function GetOrCreateTrainingQueue takes unit whichUnit returns LinkedList_Int
local LinkedList_Int queue = GetTrainingQueue(whichUnit)
if (queue == 0) then
set queue = CreateLinkedList_Int()
call SaveInteger(HT_TrainingQueue, GetHandleId(whichUnit), KEY_TRAINING_QUEUE, queue)
endif
return queue
endfunction
private function GetEventListeners takes integer tqEventType returns LinkedList_Int
if (tqEventType == TQ_EVENT_TYPE_TRAIN) then
return TQ_EVENT_HANDLERS_TRAIN
elseif (tqEventType == TQ_EVENT_TYPE_FINISH) then
return TQ_EVENT_HANDLERS_FINISH
elseif (tqEventType == TQ_EVENT_TYPE_CANCEL) then
return TQ_EVENT_HANDLERS_CANCEL
endif
return 0
endfunction
public function RegisterEvent takes integer tqEventType, TrainingQueueEventHandler handler returns nothing
local LinkedList_Int listeners = GetEventListeners(tqEventType)
if (listeners != 0) then
call LinkedListAddLastInt(listeners, handler)
endif
endfunction
public function UnregisterEvent takes integer tqEventType, TrainingQueueEventHandler handler returns nothing
local LinkedList_Int listeners = GetEventListeners(tqEventType)
local LinkedListNode_Int node = LinkedListGetFirst(listeners)
loop
exitwhen node == 0
if (node.value == handler) then
exitwhen true
endif
set node = node.next
endloop
if (node != 0) then
call LinkedListDestroyNode(listeners, node)
endif
endfunction
private function FlushEventQueue takes nothing returns nothing
local LinkedList_Int listeners = 0
local LinkedListNode_Int listenerNode = 0
local TrainingQueueEventHandler listener = 0
local TrainingQueueEvent tqe = 0
loop
set tqe = LinkedListGetLast(TQ_EVENT_QUEUE)
exitwhen tqe == 0
set listeners = GetEventListeners(tqe.eventType)
if (listeners != 0 and listeners.count > 0) then
set listenerNode = LinkedListGetFirst(listeners)
loop
exitwhen listenerNode == 0
set listener = listenerNode.value
call listener.evaluate(tqe)
set listenerNode = listenerNode.next
endloop
endif
call LinkedListDestroyLast(TQ_EVENT_QUEUE)
endloop
endfunction
private function IsEventEqual takes TrainingQueueEvent tqe, unit whichUnit, integer unitTypeId, integer tqEventType returns boolean
local player owner = GetOwningPlayer(whichUnit)
if (tqe.owningPlayer != owner) then
return false
elseif (tqe.unitTypeId != unitTypeId) then
return false
elseif (tqe.eventType != tqEventType) then
return false
elseif (IsUnitInGroup(whichUnit, tqe.trainers)) then
return false
endif
return true
endfunction
private function QueueTQEvent takes unit whichUnit, integer tqEventType returns nothing
local player owner = null
local TrainingQueueEvent tqe = 0
local integer unitTypeId = GetUnitTypeId(whichUnit)
local LinkedList_Int listeners = GetEventListeners(tqEventType)
if (listeners.count > 0) then
set owner = GetOwningPlayer(whichUnit)
set tqe = LinkedListGetLast(TQ_EVENT_QUEUE)
// Find a pending event of this type
loop
exitwhen tqe == 0
if (IsEventEqual(tqe, whichUnit, unitTypeId, tqEventType)) then
exitwhen true
endif
set tqe = tqe.prev
endloop
// No pending event found, create one
if (tqe == 0) then
set tqe = TrainingQueueEvent.create()
set tqe.owningPlayer = owner
set tqe.unitTypeId = unitTypeId
set tqe.trainers = CreateGroup()
set tqe.eventType = tqEventType
call LinkedListAddLast(TQ_EVENT_QUEUE, tqe)
endif
// Add this unit to the pending event
call GroupAddUnit(tqe.trainers, whichUnit)
// Flush the event queue next update
call TimerStart(EVENT_QUEUE_TIMER, 0.0, false, function FlushEventQueue)
endif
endfunction
public function HasSavedTrainingQueue takes unit whichUnit returns boolean
return HaveSavedInteger(HT_TrainingQueue, GetHandleId(whichUnit), KEY_TRAINING_QUEUE)
endfunction
public function GetQueueSize takes unit whichUnit returns integer
local LinkedList_Int queue = GetTrainingQueue(whichUnit)
if (queue != 0) then
return queue.count
endif
return 0
endfunction
public function AddToTrainingQueue takes unit whichUnit, integer unitTypeId returns integer
local LinkedList_Int queue = GetOrCreateTrainingQueue(whichUnit)
call LinkedListAddLastInt(queue, unitTypeId)
call QueueTQEvent(whichUnit, TQ_EVENT_TYPE_TRAIN)
return queue.count
endfunction
public function CancelFromTrainingQueue takes unit whichUnit returns integer
local LinkedList_Int queue = GetTrainingQueue(whichUnit)
if (queue != 0) then
call LinkedListDestroyLast(queue)
call QueueTQEvent(whichUnit, TQ_EVENT_TYPE_CANCEL)
return queue.count
endif
return 0
endfunction
public function RemoveFromTrainingQueueHead takes unit whichUnit returns integer
local LinkedList_Int queue = GetTrainingQueue(whichUnit)
if (queue != 0) then
call LinkedListDestroyFirst(queue)
call QueueTQEvent(whichUnit, TQ_EVENT_TYPE_FINISH)
return queue.count
endif
return 0
endfunction
endlibrary
function Trig_Training_Queue_Add_Conditions takes nothing returns boolean
local integer orderId = GetIssuedOrderId()
local integer goldCost = 0
local integer lumberCost = 0
local integer foodCost = 0
local player owner = null
if (not IsUnitType(GetOrderedUnit(), UNIT_TYPE_STRUCTURE)) then
return false
elseif (GetObjectName(orderId) == null or GetObjectName(orderId) == EMPTY_STRING or GetObjectName(orderId) == DEFAULT_STRING) then
return false
elseif (IsUnitIdType(orderId, UNIT_TYPE_STRUCTURE)) then
return false
else
set owner = GetOwningPlayer(GetOrderedUnit())
if (GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD) < GetUnitGoldCost(orderId)) then
return false
elseif (GetPlayerState(owner, PLAYER_STATE_RESOURCE_LUMBER) < GetUnitWoodCost(orderId)) then
return false
elseif (GetPlayerState(owner, PLAYER_STATE_RESOURCE_FOOD_CAP) - GetPlayerState(owner, PLAYER_STATE_RESOURCE_FOOD_USED) < GetFoodUsed(orderId)) then
if (TrainingQueue_GetQueueSize(GetOrderedUnit()) == 0) then
return false
endif
endif
endif
return true
endfunction
function Trig_Training_Queue_Add_Actions takes nothing returns nothing
call TrainingQueue_AddToTrainingQueue(GetOrderedUnit(), GetIssuedOrderId())
endfunction
//===========================================================================
function InitTrig_Training_Queue_Add takes nothing returns nothing
set gg_trg_Training_Queue_Add = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Training_Queue_Add, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Training_Queue_Add, Condition( function Trig_Training_Queue_Add_Conditions ) )
call TriggerAddAction( gg_trg_Training_Queue_Add, function Trig_Training_Queue_Add_Actions )
endfunction
function Trig_Training_Queue_Cancel_Conditions takes nothing returns boolean
return GetIssuedOrderId() == 851976 // Cancel
endfunction
function Trig_Training_Queue_Cancel_Actions takes nothing returns nothing
if (TrainingQueue_GetQueueSize(GetOrderedUnit()) > 0) then
call TrainingQueue_CancelFromTrainingQueue(GetOrderedUnit())
endif
endfunction
//===========================================================================
function InitTrig_Training_Queue_Cancel takes nothing returns nothing
set gg_trg_Training_Queue_Cancel = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Training_Queue_Cancel, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Training_Queue_Cancel, Condition( function Trig_Training_Queue_Cancel_Conditions ) )
call TriggerAddAction( gg_trg_Training_Queue_Cancel, function Trig_Training_Queue_Cancel_Actions )
endfunction
function Trig_Training_Queue_Finish_Conditions takes nothing returns boolean
return TrainingQueue_HasSavedTrainingQueue(GetTriggerUnit())
endfunction
function Trig_Training_Queue_Finish_Actions takes nothing returns nothing
call TrainingQueue_RemoveFromTrainingQueueHead(GetTriggerUnit())
endfunction
//===========================================================================
function InitTrig_Training_Queue_Finish takes nothing returns nothing
set gg_trg_Training_Queue_Finish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Training_Queue_Finish, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( gg_trg_Training_Queue_Finish, Condition( function Trig_Training_Queue_Finish_Conditions ) )
call TriggerAddAction( gg_trg_Training_Queue_Finish, function Trig_Training_Queue_Finish_Actions )
endfunction
library BetterTraining initializer Init requires TrainingQueue
private function OnTrainingQueueTrain takes TrainingQueue_TrainingQueueEvent tqe returns nothing
local integer minQueueSize = MAX_INTEGER
local integer queueSize = 0
local group trainers = null
local unit picked = null
if (GetPlayerController(tqe.owningPlayer) == MAP_CONTROL_USER) then
set trainers = CreateGroup()
call GroupAddGroup(tqe.trainers, trainers)
loop
set picked = FirstOfGroup(trainers)
exitwhen picked == null
set minQueueSize = IMinBJ(minQueueSize, TrainingQueue_GetQueueSize(picked))
call GroupRemoveUnit(trainers, picked)
endloop
call GroupAddGroup(tqe.trainers, trainers)
loop
set picked = FirstOfGroup(trainers)
exitwhen picked == null
set queueSize = TrainingQueue_GetQueueSize(picked)
if (queueSize > minQueueSize) then
call PauseUnit(picked, true)
call IssueImmediateOrder(picked, "stop")
call PauseUnit(picked, false)
//call IssueImmediateOrderById(picked, 851976) // Cancel
else
// Don't cancel this one, but cancel the rest of them
set minQueueSize = -1
endif
call GroupRemoveUnit(trainers, picked)
endloop
call DestroyGroup(trainers)
endif
endfunction
private function Init takes nothing returns nothing
call TrainingQueue_RegisterEvent(TrainingQueue_TQ_EVENT_TYPE_TRAIN, OnTrainingQueueTrain)
endfunction
endlibrary
function Trig_Debugging_THis_Actions takes nothing returns nothing
local group barracks = GetUnitsOfTypeIdAll('h002')
local unit picked = null
local texttag ft = null
loop
set picked = FirstOfGroup(barracks)
exitwhen picked == null
call CreateTextTagUnitBJ("0", picked, 100.0, 10, 100.0, 100.0, 100.0, 0)
call SetTextTagPermanentBJ( GetLastCreatedTextTag(), true )
call ShowTextTagForceBJ( true, GetLastCreatedTextTag(), GetPlayersAll())
call SaveTextTagHandle(udg_HashTable_UnitInfo, GetHandleId(picked), StringHash("TEST"), GetLastCreatedTextTag())
call GroupRemoveUnit(barracks, picked)
endloop
endfunction
//===========================================================================
function InitTrig_Debugging_THis takes nothing returns nothing
set gg_trg_Debugging_THis = CreateTrigger( )
call TriggerAddAction( gg_trg_Debugging_THis, function Trig_Debugging_THis_Actions )
endfunction
function Trig_More_debugging_Actions takes nothing returns nothing
local group barracks = GetUnitsOfTypeIdAll('h002')
local unit picked = null
local texttag ft = null
local LinkedList_Int queue = 0
loop
set picked = FirstOfGroup(barracks)
exitwhen picked == null
set queue = TrainingQueue_GetTrainingQueue(picked)
set ft = LoadTextTagHandle(udg_HashTable_UnitInfo, GetHandleId(picked), StringHash("TEST"))
call SetTextTagTextBJ(ft, I2S(queue.count) + ": " + LinkedListToString(queue), 10)
call GroupRemoveUnit(barracks, picked)
endloop
call DestroyGroup(barracks)
endfunction
//===========================================================================
function InitTrig_More_debugging takes nothing returns nothing
set gg_trg_More_debugging = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_More_debugging, 0.01 )
call TriggerAddAction( gg_trg_More_debugging, function Trig_More_debugging_Actions )
endfunction
globals
constant key KEY_REFUND_MANA
endglobals
function RefundAbilityCast_Condition takes nothing returns boolean
local integer abilityId = LoadInteger(udg_HashTable_ManaRefund, GetHandleId(GetTriggeringTrigger()), KEY_REFUND_MANA)
return GetSpellAbilityId() == abilityId
endfunction
function RefundAbilityCast_Action takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real manaCost = GetUnitAbilityIntegerLevelField(caster, GetSpellAbilityId(), ABILITY_ILF_MANA_COST)
call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) + manaCost)
call BlzEndUnitAbilityCooldown(caster, GetSpellAbilityId())
call RemoveSavedInteger(udg_HashTable_ManaRefund, GetHandleId(GetTriggeringTrigger()), KEY_REFUND_MANA)
call DestroyTrigger(GetTriggeringTrigger())
endfunction
function RefundAbilityCast takes unit caster, integer abilityId returns nothing
local trigger refundTrigger = CreateTrigger()
call SaveInteger(udg_HashTable_ManaRefund, GetHandleId(refundTrigger), KEY_REFUND_MANA, abilityId)
call TriggerRegisterUnitEvent(refundTrigger, caster, EVENT_UNIT_SPELL_ENDCAST)
call TriggerRegisterUnitEvent(refundTrigger, caster, EVENT_UNIT_SPELL_FINISH)
call TriggerAddCondition(refundTrigger, Condition(function RefundAbilityCast_Condition))
call TriggerAddAction(refundTrigger, function RefundAbilityCast_Action)
call IssueImmediateOrder(caster, "stop")
endfunction
function CreateDummyCaster takes player whichPlayer, real x, real y, integer abilityId, real duration returns unit
local unit dummy = CreateUnit(whichPlayer, SB_HIDDEN_CASTER, x, y, bj_UNIT_FACING)
call RemoveGuardPosition(dummy)
call UnitAddAbility(dummy, abilityId)
call UnitApplyTimedLife(dummy, SB_BUFF_TIMED_LIFE_GENERIC, duration)
return dummy
endfunction
function DummyCastInstantTimed takes player whichPlayer, real x, real y, integer abilityId, string order, real duration returns unit
local unit dummy = CreateDummyCaster(whichPlayer, x, y, abilityId, duration)
call IssueImmediateOrder(dummy, order)
return dummy
endfunction
function DummyCastInstant takes player whichPlayer, real x, real y, integer abilityId, string order returns unit
return DummyCastInstantTimed(whichPlayer, x, y, abilityId, order, 2.0)
endfunction
function DummyCastPoint takes player whichPlayer, real x, real y, real targetX, real targetY, integer abilityId, string order returns unit
local unit dummy = CreateDummyCaster(whichPlayer, x, y, abilityId, 2.0)
call IssuePointOrder(dummy, order, targetX, targetY)
return dummy
endfunction
function DummyCastUnit takes player whichPlayer, unit target, real x, real y, integer abilityId, string order returns unit
local unit dummy = CreateDummyCaster(whichPlayer, x, y, abilityId, 2.0)
call IssueTargetOrder(dummy, order, target)
return dummy
endfunction
library IntFilters
globals
integer CURRENT_INT_FILTER_INPUT = 0
real CURRENT_FILTER_AOE = 0.0
real CURRENT_FILTER_X = 0.0
real CURRENT_FILTER_Y = 0.0
IntCondition CURRENT_INT_FILTER = 0
constant real AOE_BUFFER = 128.0
endglobals
private function IsUnitInAOE takes unit whichUnit, real x, real y, real radius returns boolean
local real dx = x - GetUnitX(whichUnit)
local real dy = y - GetUnitY(whichUnit)
local real aoeSqr = Pow(radius + BlzGetUnitCollisionSize(whichUnit), 2)
return (dx * dx + dy * dy) <= aoeSqr
endfunction
private function IntFilterCallback takes nothing returns boolean
if (CURRENT_INT_FILTER != 0) then
return CURRENT_INT_FILTER.evaluate(CURRENT_INT_FILTER_INPUT)
endif
return true
endfunction
private function IntFilterCallbackAOE takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitInAOE(filter, CURRENT_FILTER_X, CURRENT_FILTER_Y, CURRENT_FILTER_AOE)) then
return false
else
return IntFilterCallback()
endif
endfunction
function GroupEnumUnitsInRangeInt takes group whichGroup, real x, real y, real radius, IntCondition filter, integer filterInput returns nothing
local boolexpr condition = Condition(function IntFilterCallback)
set CURRENT_INT_FILTER = filter
set CURRENT_INT_FILTER_INPUT = filterInput
call GroupEnumUnitsInRange(whichGroup, x, y, radius, condition)
call DestroyBoolExpr(condition)
endfunction
function GetUnitsInRangeInt takes real x, real y, real radius, IntCondition filter, integer filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInRangeInt(g, x, y, radius, filter, filterInput)
return g
endfunction
function GroupEnumUnitsInAOEInt takes group whichGroup, real x, real y, real aoe, IntCondition filter, integer filterInput returns nothing
local boolexpr condition = Condition(function IntFilterCallbackAOE)
set CURRENT_INT_FILTER = filter
set CURRENT_INT_FILTER_INPUT = filterInput
set CURRENT_FILTER_AOE = aoe
set CURRENT_FILTER_X = x
set CURRENT_FILTER_Y = y
call GroupEnumUnitsInRange(whichGroup, x, y, aoe + AOE_BUFFER, condition)
call DestroyBoolExpr(condition)
endfunction
function GroupEnumUnitsInAOEOfUnitInt takes group whichGroup, unit whichUnit, real aoe, IntCondition filter, integer filterInput returns nothing
call GroupEnumUnitsInAOEInt(whichGroup, GetUnitX(whichUnit), GetUnitY(whichUnit), aoe + BlzGetUnitCollisionSize(whichUnit), filter, filterInput)
endfunction
function GetUnitsInAOEInt takes real x, real y, real aoe, IntCondition filter, integer filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInAOEInt(g, x, y, aoe, filter, filterInput)
return g
endfunction
function GetUnitsInAOEOfUnitInt takes unit whichUnit, real aoe, IntCondition filter, integer filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInAOEOfUnitInt(g, whichUnit, aoe, filter, filterInput)
return g
endfunction
endlibrary
globals
unit CURRENT_UNIT_FILTER_INPUT = null
UnitCondition CURRENT_UNIT_FILTER = 0
endglobals
function UnitFilterCallback takes nothing returns boolean
if (CURRENT_UNIT_FILTER != 0) then
return CURRENT_UNIT_FILTER.evaluate(CURRENT_UNIT_FILTER_INPUT)
endif
return false
endfunction
function UnitFilterCallbackAOE takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitInAOE(filter, CURRENT_FILTER_X, CURRENT_FILTER_Y, CURRENT_FILTER_AOE)) then
return false
else
return UnitFilterCallback()
endif
endfunction
function GroupEnumUnitsInRangeUnit takes group whichGroup, real x, real y, real radius, UnitCondition filter, unit filterInput returns nothing
local boolexpr condition = Condition(function UnitFilterCallback)
set CURRENT_UNIT_FILTER = filter
set CURRENT_UNIT_FILTER_INPUT = filterInput
call GroupEnumUnitsInRange(whichGroup, x, y, radius, condition)
call DestroyBoolExpr(condition)
endfunction
function GetUnitsInRangeUnit takes real x, real y, real radius, UnitCondition filter, unit filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInRangeUnit(g, x, y, radius, filter, filterInput)
return g
endfunction
function GroupEnumUnitsInAOEUnit takes group whichGroup, real x, real y, real aoe, UnitCondition filter, unit filterInput returns nothing
set CURRENT_UNIT_FILTER = filter
set CURRENT_UNIT_FILTER_INPUT = filterInput
set CURRENT_FILTER_AOE = aoe
set CURRENT_FILTER_X = x
set CURRENT_FILTER_Y = y
call GroupEnumUnitsInRange(whichGroup, x, y, aoe + AOE_BUFFER, Condition(function UnitFilterCallbackAOE))
endfunction
function GroupEnumUnitsInAOEOfUnitUnit takes group whichGroup, unit whichUnit, real aoe, UnitCondition filter, unit filterInput returns nothing
call GroupEnumUnitsInAOEUnit(whichGroup, GetUnitX(whichUnit), GetUnitY(whichUnit), aoe + BlzGetUnitCollisionSize(whichUnit), filter, filterInput)
endfunction
function GetUnitsInAOEUnit takes real x, real y, real aoe, UnitCondition filter, unit filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInAOEUnit(g, x, y, aoe, filter, filterInput)
return g
endfunction
function GetUnitsInAOEOfUnitUnit takes unit whichUnit, real aoe, UnitCondition filter, unit filterInput returns group
local group g = CreateGroup()
call GroupEnumUnitsInAOEOfUnitUnit(g, whichUnit, aoe, filter, filterInput)
return g
endfunction
struct DumbTimer
real duration = 0.0
real elapsed = 0.0
endstruct
function CreateDumbTimer takes real duration returns DumbTimer
local DumbTimer t = DumbTimer.create()
set t.duration = duration
return t
endfunction
function UpdateDumbTimer takes DumbTimer t, real dt returns boolean
local boolean result = false
set t.elapsed = t.elapsed + dt
if (t.elapsed >= t.duration) then
set result = true
set t.elapsed = t.elapsed - t.duration
endif
return result
endfunction
library TimersPlus
globals
constant hashtable HT_TIMERS_PLUS = InitHashtable()
constant key TIMER_PLUS
endglobals
function interface TimerPlusCallback takes ITimerPlus t returns nothing
function OnDestroyTimerPlus takes ITimerPlus t returns nothing
call RemoveSavedInteger(HT_TIMERS_PLUS, TIMER_PLUS, GetHandleId(t.theTimer))
call DestroyTimerDialog(t.dialog)
call PauseTimer(t.theTimer)
call DestroyTimer(t.theTimer)
endfunction
function TimerPlusEndCallback takes nothing returns nothing
local ITimerPlus t = LoadInteger(HT_TIMERS_PLUS, TIMER_PLUS, GetHandleId(GetExpiredTimer()))
local TimerPlusCallback callbackEnd = t.callbackEnd
if (callbackEnd != 0) then
set t.callbackEnd = 0
call callbackEnd.evaluate(t)
endif
if (t.oneShot) then
call t.destroy()
endif
endfunction
function TimerPlusPeriodCallback takes nothing returns nothing
local ITimerPlus t = LoadInteger(HT_TIMERS_PLUS, TIMER_PLUS, GetHandleId(GetExpiredTimer()))
set t.duration = t.duration - t.period
if (t.callbackPeriodic != 0) then
call t.callbackPeriodic.execute(t)
endif
if (t.duration <= 0.0) then
if (t.callbackEnd != 0) then
call t.callbackEnd.evaluate(t)
endif
if (t.oneShot) then
call t.destroy()
endif
endif
endfunction
interface ITimerPlus
public timer theTimer = CreateTimer()
public boolean oneShot = false
public real duration = 0.0
public real period = 0.0
public timerdialog dialog = null
public TimerPlusCallback callbackEnd = 0
public TimerPlusCallback callbackPeriodic = 0
endinterface
function InitTimerPlus takes ITimerPlus t returns nothing
call SaveInteger(HT_TIMERS_PLUS, TIMER_PLUS, GetHandleId(t.theTimer), t)
endfunction
function CreateTimerPlusDialog takes ITimerPlus t, string label returns timerdialog
set t.dialog = CreateTimerDialogBJ(t.theTimer, label)
return t.dialog
endfunction
function DestroyTimerPlusDialog takes ITimerPlus t returns nothing
call DestroyTimerDialog(t.dialog)
endfunction
function StartTimerPlus takes ITimerPlus t, real dur, TimerPlusCallback callback returns nothing
set t.callbackEnd = callback
set t.duration = dur
call TimerStart(t.theTimer, t.duration, false, function TimerPlusEndCallback)
endfunction
function StartTimerPlusPeriodic takes ITimerPlus t, real dur, real interval, TimerPlusCallback periodicCallback, TimerPlusCallback endCallback returns nothing
set t.callbackEnd = endCallback
set t.callbackPeriodic = periodicCallback
set t.duration = dur
set t.period = interval
call TimerStart(t.theTimer, t.period, true, function TimerPlusPeriodCallback)
endfunction
function TimerPlusGetElapsed takes ITimerPlus t returns real
return TimerGetElapsed(t.theTimer)
endfunction
function PauseTimerPlus takes ITimerPlus t returns nothing
call PauseTimer(t.theTimer)
endfunction
function ResumeTimerPlus takes ITimerPlus t returns nothing
call ResumeTimer(t.theTimer)
endfunction
// ---------------------------------------------------
struct UnitTimer extends ITimerPlus
public unit owner = null
method onDestroy takes nothing returns nothing
call OnDestroyTimerPlus(this)
endmethod
endstruct
function CreateUnitTimer takes unit whichUnit, boolean oneShot returns UnitTimer
local UnitTimer t = UnitTimer.create()
set t.owner = whichUnit
set t.oneShot = oneShot
call InitTimerPlus(t)
return t
endfunction
// ---------------------------------------------------
struct DestructableTimer extends ITimerPlus
public destructable owner = null
method onDestroy takes nothing returns nothing
call OnDestroyTimerPlus(this)
endmethod
endstruct
function CreateDestructableTimer takes destructable whichDestructable, boolean oneShot returns DestructableTimer
local DestructableTimer t = DestructableTimer.create()
set t.owner = whichDestructable
set t.oneShot = oneShot
call InitTimerPlus(t)
return t
endfunction
// ---------------------------------------------------
struct EffectTimer extends ITimerPlus
public effect owner = null
method onDestroy takes nothing returns nothing
call OnDestroyTimerPlus(this)
endmethod
endstruct
function CreateEffectTimer takes effect whichEffect, boolean oneShot returns EffectTimer
local EffectTimer t = EffectTimer.create()
set t.owner = whichEffect
set t.oneShot = oneShot
call InitTimerPlus(t)
return t
endfunction
function OnSpecialEffectExpires takes EffectTimer t returns nothing
call DestroyEffect(t.owner)
endfunction
function AddSpecialEffectTimed takes string model, real x, real y, real duration returns effect
local effect e = AddSpecialEffect(model, x, y)
local EffectTimer et = CreateEffectTimer(e, true)
call StartTimerPlus(et, duration, OnSpecialEffectExpires)
return e
endfunction
// ---------------------------------------------------
struct IntTimer extends ITimerPlus
public integer owner = 0
method onDestroy takes nothing returns nothing
call OnDestroyTimerPlus(this)
endmethod
endstruct
function CreateIntTimer takes integer i, boolean oneShot returns UnitTimer
local IntTimer t = IntTimer.create()
set t.owner = i
set t.oneShot = oneShot
call InitTimerPlus(t)
return t
endfunction
function StartIntTimer takes IntTimer it, real dur, TimerPlusCallback callback returns nothing
call StartTimerPlus(it, dur, callback)
endfunction
function StartIntTimerPeriodic takes IntTimer it, real dur, real interval, TimerPlusCallback periodicCallback, TimerPlusCallback endCallback returns nothing
call StartTimerPlusPeriodic(it, dur, interval, periodicCallback, endCallback)
endfunction
endlibrary
globals
constant key KEY_SPELL_WAVE
constant real SPELL_WAVE_UPDATE_INTERVAL = 0.03
endglobals
function interface SpellWaveCallback takes SpellWave sw returns nothing
function interface SpellWaveFilterCallback takes SpellWave sw returns boolean
function interface SpellWaveOnHitCallback takes SpellWave sw, unit hit returns nothing
function SpellWavePeriod takes IntTimer it returns nothing
local SpellWave sw = it.owner
call sw.Update()
endfunction
struct SpellWave
unit owner = null
vec3 origin = 0
vec3 position = 0
vec3 direction = 0
real aoeStart = 0.0
real aoeEnd = 0.0
real distance = 0.0
real speed = 0.0
DumbTimer callbackPeriod = 0
SpellWaveFilterCallback targetFilter = 0
SpellWaveOnHitCallback onHit = 0
SpellWaveCallback periodCallback = 0
private IntTimer updateLoop = 0
private group unitsInAOE = CreateGroup()
private group unitsHit = CreateGroup()
static method create takes unit owner, real x, real y, real z returns SpellWave
local SpellWave sw = SpellWave.allocate()
set sw.owner = owner
set sw.origin = vec3.create(x, y, z)
set sw.position = vec3.create(x, y, z)
set sw.direction = vec3.create(0, 0, 0)
set sw.callbackPeriod = CreateDumbTimer(SPELL_WAVE_UPDATE_INTERVAL)
set sw.updateLoop = CreateIntTimer(sw, false)
return sw
endmethod
method SetDirection takes real yaw, real pitch returns nothing
local real yawRad = Deg2Rad(yaw)
local real pitchRad = Deg2Rad(pitch)
set direction.x = Cos(yawRad) * Cos(pitchRad)
set direction.y = Sin(yawRad) * Cos(pitchRad)
set direction.z = Sin(pitchRad)
endmethod
method GetCurrentDoneRatio takes nothing returns real
local real i = 1.0
if (distance > 0.0) then
set i = VecDistance(origin, position) / distance
endif
return i
endmethod
method CalculateAOE takes real i returns real
return (aoeEnd - aoeStart) * i + aoeStart
endmethod
method GetCurrentAOE takes nothing returns real
local real i = RMinBJ(GetCurrentDoneRatio(), 1.0)
return CalculateAOE(i)
endmethod
method HitUnit takes unit whichUnit returns nothing
call GroupAddUnit(unitsHit, whichUnit)
if (onHit != 0) then
call onHit.execute(this, whichUnit)
endif
endmethod
method HasUnitBeenHit takes unit whichUnit returns boolean
return IsUnitInGroup(whichUnit, unitsHit)
endmethod
method Begin takes nothing returns nothing
call position.copy(origin)
call StartTimerPlusPeriodic(updateLoop, 0.0, SPELL_WAVE_UPDATE_INTERVAL, SpellWavePeriod, 0)
endmethod
method Update takes nothing returns nothing
local real i = 0.0
local real aoe = 0.0
local unit pickedUnit = null
local vec3 translation = VecMultiply(direction, speed * SPELL_WAVE_UPDATE_INTERVAL)
call position.add(translation)
call translation.destroy()
set i = GetCurrentDoneRatio()
set aoe = CalculateAOE(i)
call GroupClear(unitsInAOE)
call GroupEnumUnitsInAOEInt(unitsInAOE, position.x, position.y, aoe, targetFilter, this)
loop
set pickedUnit = FirstOfGroup(unitsInAOE)
exitwhen pickedUnit == null
if (not HasUnitBeenHit(pickedUnit)) then
call HitUnit(pickedUnit)
endif
call GroupRemoveUnit(unitsInAOE, pickedUnit)
endloop
if (periodCallback != 0 and UpdateDumbTimer(callbackPeriod, SPELL_WAVE_UPDATE_INTERVAL)) then
call periodCallback.execute(this)
endif
if (i >= 1.0) then
call this.destroy()
endif
endmethod
method onDestroy takes nothing returns nothing
call origin.destroy()
call position.destroy()
call direction.destroy()
call updateLoop.destroy()
call DestroyGroup(unitsInAOE)
call DestroyGroup(unitsHit)
endmethod
endstruct
function interface PeriodicUnitAction takes unit whichUnit returns nothing
function interface PeriodicUnitCondition takes unit whichUnit returns boolean
struct PeriodicEffect
real time = 0.0
real tickDuration = 0.0
integer buffCode = 0
PeriodicUnitAction tickCallback = 0
PeriodicUnitCondition validityCallback = 0
endstruct
function ClearUnitPeriodicEffect takes unit whichUnit, integer index returns nothing
local integer unitId = GetHandleId(whichUnit)
local integer count = LoadInteger(udg_HashTable_DOTs, GetHandleId(whichUnit), StringHash("COUNT"))
local integer i = 0
local PeriodicEffect pEffect = 0
if (count <= 1 or index >= count) then
call FlushChildHashtable(udg_HashTable_DOTs, GetHandleId(whichUnit))
call GroupRemoveUnit(udg_UnitGroup_DOTs, whichUnit)
elseif (index >= 0) then
set i = index
loop
if (i >= count - 1) then
set pEffect = LoadInteger(udg_HashTable_DOTs, unitId, i)
call pEffect.destroy()
call RemoveSavedInteger(udg_HashTable_DOTs, unitId, count)
exitwhen true
endif
set pEffect = LoadInteger(udg_HashTable_DOTs, unitId, i + 1)
call SaveInteger(udg_HashTable_DOTs, unitId, i, pEffect)
set i = i + 1
endloop
call SaveInteger(udg_HashTable_DOTs, GetHandleId(whichUnit), StringHash("COUNT"), count - 1)
endif
endfunction
function GetUnitPeriodicEffectByBuff takes unit whichUnit, integer buffCode returns integer
local PeriodicEffect pEffect = 0
local integer count = LoadInteger(udg_HashTable_DOTs, GetHandleId(whichUnit), StringHash("COUNT"))
local integer i = 0
if (count > 0) then
loop
exitwhen i >= count
set pEffect = LoadInteger(udg_HashTable_DOTs, GetHandleId(whichUnit), i)
if (pEffect.buffCode == buffCode) then
return pEffect
exitwhen true
endif
set i = i + 1
endloop
endif
return -1
endfunction
function ClearUnitPeriodicEffectByBuff takes unit whichUnit, integer buffCode returns nothing
local integer i = GetUnitPeriodicEffectByBuff(whichUnit, buffCode)
if (i >= 0) then
call ClearUnitPeriodicEffect(whichUnit, i)
endif
endfunction
function AddUnitPeriodicEffectWithValidity takes unit whichUnit, integer buffCode, real tickDuration, PeriodicUnitAction tickCallback, PeriodicUnitCondition validityCallback returns nothing
local integer unitId = GetHandleId(whichUnit)
local integer count = 0
local PeriodicEffect pEffect = 0
local integer existingIndex = GetUnitPeriodicEffectByBuff(whichUnit, buffCode)
if (existingIndex >= 0) then
set pEffect = LoadInteger(udg_HashTable_DOTs, unitId, existingIndex)
set pEffect.tickDuration = tickDuration
set pEffect.tickCallback = tickCallback
set pEffect.validityCallback = validityCallback
else
set count = LoadInteger(udg_HashTable_DOTs, unitId, StringHash("COUNT"))
set pEffect = PeriodicEffect.create()
set pEffect.tickDuration = tickDuration
set pEffect.buffCode = buffCode
set pEffect.tickCallback = tickCallback
set pEffect.validityCallback = validityCallback
call SaveInteger(udg_HashTable_DOTs, unitId, count, pEffect)
call SaveInteger(udg_HashTable_DOTs, unitId, StringHash("COUNT"), count + 1)
endif
call GroupAddUnit(udg_UnitGroup_DOTs, whichUnit)
call EnableTrigger(gg_trg_Triggered_Periodic_Effects)
endfunction
function AddUnitPeriodicEffect takes unit whichUnit, integer buffCode, real tickDuration, PeriodicUnitAction tickCallback returns nothing
call AddUnitPeriodicEffectWithValidity(whichUnit, buffCode, tickDuration, tickCallback, 0)
endfunction
globals
constant real PERIODIC_EFFECTS_INTERVAL = 0.05
endglobals
function Trig_Triggered_Periodic_Effects_Validity takes unit whichUnit returns boolean
if (not IsUnitAliveBJ(whichUnit)) then
return false
elseif (BlzIsUnitInvulnerable(whichUnit)) then
return false
elseif (IsUnitType(whichUnit, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
return true
endfunction
function Trig_Triggered_Periodic_Effects_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_DOTs)
local integer unitIndex = size - 1
local unit pickedUnit = null
local integer count = 0
local integer pIndex = 0
local PeriodicEffect pEffect = 0
local PeriodicUnitCondition validity = 0
if (size > 0) then
loop
exitwhen unitIndex < 0
set pickedUnit = BlzGroupUnitAt(udg_UnitGroup_DOTs, unitIndex)
set count = LoadInteger(udg_HashTable_DOTs, GetHandleId(pickedUnit), StringHash("COUNT"))
set pIndex = count - 1
loop
exitwhen pIndex < 0
set pEffect = LoadInteger(udg_HashTable_DOTs, GetHandleId(pickedUnit), pIndex)
if (pEffect.validityCallback == 0) then
set validity = Trig_Triggered_Periodic_Effects_Validity
else
set validity = pEffect.validityCallback
endif
if (UnitHasBuffBJ(pickedUnit, pEffect.buffCode) and validity.evaluate(pickedUnit)) then
if (pEffect.time >= pEffect.tickDuration) then
call pEffect.tickCallback.evaluate(pickedUnit)
set pEffect.time = pEffect.time - pEffect.tickDuration
else
set pEffect.time = pEffect.time + PERIODIC_EFFECTS_INTERVAL
endif
else
call ClearUnitPeriodicEffect(pickedUnit, pIndex)
endif
set pIndex = pIndex - 1
endloop
set unitIndex = unitIndex - 1
endloop
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Triggered_Periodic_Effects takes nothing returns nothing
set gg_trg_Triggered_Periodic_Effects = CreateTrigger( )
call DisableTrigger( gg_trg_Triggered_Periodic_Effects )
call TriggerRegisterTimerEventPeriodic( gg_trg_Triggered_Periodic_Effects, PERIODIC_EFFECTS_INTERVAL)
call TriggerAddAction( gg_trg_Triggered_Periodic_Effects, function Trig_Triggered_Periodic_Effects_Actions )
endfunction
library Lifelink initializer Init
globals
private constant hashtable HT_LIFELINK = InitHashtable()
constant integer LIFELINK_NONE = 0
constant integer LIFELINK_KILL = 1
constant integer LIFELINK_REMOVE = 2
endglobals
private struct Lifelink
group kill = null
group remove = null
method onDestroy takes nothing returns nothing
call DestroyGroup(kill)
call DestroyGroup(remove)
endmethod
endstruct
private function GetLifelink takes unit whichUnit returns Lifelink
return LoadInteger(HT_LIFELINK, GetHandleId(whichUnit), 0)
endfunction
private function GetOrCreateLifelink takes unit whichUnit returns Lifelink
local Lifelink ll = GetLifelink(whichUnit)
if (ll == 0) then
set ll = Lifelink.create()
call SaveInteger(HT_LIFELINK, GetHandleId(whichUnit), 0, ll)
endif
return ll
endfunction
private function AddLifelinkedUnit takes Lifelink ll, unit whichUnit, integer lifelinkType returns nothing
if (lifelinkType == LIFELINK_KILL) then
if (ll.kill == null) then
set ll.kill = CreateGroup()
endif
call GroupAddUnit(ll.kill, whichUnit)
elseif (lifelinkType == LIFELINK_REMOVE) then
if (ll.remove == null) then
set ll.remove = CreateGroup()
endif
call GroupAddUnit(ll.remove, whichUnit)
endif
endfunction
function LifelinkUnits takes unit host, unit lifelinked, integer lifelinkType returns nothing
local Lifelink ll = GetOrCreateLifelink(host)
call AddLifelinkedUnit(ll, lifelinked, lifelinkType)
endfunction
function UnlifelinkUnits takes unit host, unit lifelinked returns nothing
local Lifelink ll = GetLifelink(host)
call GroupRemoveUnit(ll.kill, lifelinked)
call GroupRemoveUnit(ll.remove, lifelinked)
endfunction
// ****************************************
// TRIGGERS
// ****************************************
private function DeathTriggerCondition takes nothing returns boolean
return HaveSavedInteger(HT_LIFELINK, GetHandleId(GetDyingUnit()), 0)
endfunction
private function DeathTriggerAction takes nothing returns nothing
local Lifelink ll = GetLifelink(GetDyingUnit())
local unit picked = null
local group g = ll.kill
if (g != null) then
loop
set picked = FirstOfGroup(g)
exitwhen picked == null
call KillUnit(picked)
call GroupRemoveUnit(g, picked)
endloop
endif
set g = ll.remove
if (g != null) then
loop
set picked = FirstOfGroup(g)
exitwhen picked == null
call KillUnit(picked)
call RemoveUnit(picked)
call GroupRemoveUnit(g, picked)
endloop
endif
call ll.destroy()
call RemoveSavedInteger(HT_LIFELINK, GetHandleId(GetDyingUnit()), 0)
endfunction
// ****************************************
// INITIALIZATION
// ****************************************
private function Init takes nothing returns nothing
local trigger deathTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(deathTrigger, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(deathTrigger, Condition(function DeathTriggerCondition))
call TriggerAddAction(deathTrigger, function DeathTriggerAction)
endfunction
endlibrary
globals
LinkedList_Int FOLLOW_DUMMIES = 0
constant hashtable HT_FOLLOW_DUMMIES = InitHashtable()
constant key KEY_FOLLOW_DUMMY
constant key KEY_FOLLOW_DUMMY_TARGET
endglobals
function interface FollowDummyCallback takes unit target, unit dummy returns nothing
struct FollowDummy extends ILinkedListNode
unit target = null
unit dummy = null
FollowDummyCallback callback = 0
FollowDummyCallback onDestroyed = 0
endstruct
function AddFollowDummyWithCallback takes unit target, unit dummy, integer lifelinkType, FollowDummyCallback callback returns FollowDummy
local FollowDummy fd = FollowDummy.create()
set fd.target = target
set fd.dummy = dummy
set fd.callback = callback
if (FOLLOW_DUMMIES == 0) then
set FOLLOW_DUMMIES = CreateLinkedList_Int()
endif
call LinkedListAddLast(FOLLOW_DUMMIES, fd)
call SaveInteger(HT_FOLLOW_DUMMIES, GetHandleId(target), KEY_FOLLOW_DUMMY_TARGET, fd)
call SaveInteger(HT_FOLLOW_DUMMIES, GetHandleId(dummy), KEY_FOLLOW_DUMMY, fd)
if (lifelinkType != LIFELINK_NONE) then
call LifelinkUnits(target, dummy, lifelinkType)
endif
call EnableTrigger(gg_trg_Follow_Dummy_Loop)
return fd
endfunction
function AddFollowDummy takes unit target, unit dummy, integer lifelinkType returns nothing
call AddFollowDummyWithCallback(target, dummy, lifelinkType, 0)
endfunction
function GetFollowDummyFromTarget takes unit target returns FollowDummy
return LoadInteger(HT_FOLLOW_DUMMIES, GetHandleId(target), KEY_FOLLOW_DUMMY_TARGET)
endfunction
function GetFollowDummyFromDummy takes unit dummy returns FollowDummy
return LoadInteger(HT_FOLLOW_DUMMIES, GetHandleId(dummy), KEY_FOLLOW_DUMMY)
endfunction
function DestroyFollowDummy takes FollowDummy fd returns nothing
if (fd.onDestroyed != 0) then
call fd.onDestroyed.evaluate(fd.target, fd.dummy)
endif
call RemoveSavedInteger(HT_FOLLOW_DUMMIES, GetHandleId(fd.target), KEY_FOLLOW_DUMMY_TARGET)
call RemoveSavedInteger(HT_FOLLOW_DUMMIES, GetHandleId(fd.dummy), KEY_FOLLOW_DUMMY)
call UnlifelinkUnits(fd.target, fd.dummy)
call LinkedListRemove(FOLLOW_DUMMIES, fd)
call fd.destroy()
endfunction
globals
constant real FOLLOW_DUMMY_UPDATE_INTERVAL = 0.01
endglobals
function Trig_Follow_Dummy_Loop_Actions takes nothing returns nothing
local FollowDummy fd = LinkedListGetFirst(FOLLOW_DUMMIES)
local FollowDummy tempNode = 0
if (FOLLOW_DUMMIES.count > 0) then
loop
exitwhen fd == 0
if (UnitAlive(fd.target) and UnitAlive(fd.dummy)) then
call SetUnitPosition(fd.dummy, GetUnitX(fd.target), GetUnitY(fd.target))
if (IsUnitHidden(fd.target) and not IsUnitHidden(fd.dummy)) then
call ShowUnitHide(fd.dummy)
elseif (not IsUnitHidden(fd.target) and IsUnitHidden(fd.dummy)) then
call ShowUnitShow(fd.dummy)
endif
if (fd.callback != 0) then
call fd.callback.evaluate(fd.target, fd.dummy)
endif
set fd = fd.next
else
set tempNode = fd
set fd = fd.next
call DestroyFollowDummy(tempNode)
endif
endloop
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Follow_Dummy_Loop takes nothing returns nothing
set gg_trg_Follow_Dummy_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Follow_Dummy_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Follow_Dummy_Loop, FOLLOW_DUMMY_UPDATE_INTERVAL )
call TriggerAddAction( gg_trg_Follow_Dummy_Loop, function Trig_Follow_Dummy_Loop_Actions )
endfunction
library GatedAbilityTrigger initializer Init
globals
private GatedAbilityTrigger array GATS
private integer GAT_COUNT = 0
private integer ABILITY_ID = 0
endglobals
function interface GatedAbilityTriggerCallback takes unit u returns nothing
struct GatedAbilityTrigger
trigger t = null
integer abilityId = 0
integer techId = 0
group abilityUnits = null
GatedAbilityTriggerCallback onEnable = 0
GatedAbilityTriggerCallback onDisable = 0
endstruct
private function AddUnit takes GatedAbilityTrigger gat, unit whichUnit returns nothing
if (GroupAddUnit(gat.abilityUnits, whichUnit)) then
if (gat.techId == 0 or GetPlayerTechCount(GetOwningPlayer(whichUnit), gat.techId, true) > 0) then
call EnableTrigger(gat.t)
if (gat.onEnable != 0) then
call gat.onEnable.evaluate(whichUnit)
endif
endif
endif
endfunction
private function RemoveUnit takes GatedAbilityTrigger gat, unit whichUnit returns nothing
if (GroupRemoveUnit(gat.abilityUnits, whichUnit)) then
if (gat.onDisable != 0 and (gat.techId == 0 or GetPlayerTechCount(GetOwningPlayer(whichUnit), gat.techId, true) > 0)) then
call gat.onDisable.evaluate(whichUnit)
endif
endif
endfunction
private function ExecuteCallbackForGroup takes group g, GatedAbilityTriggerCallback callback returns nothing
local integer i = BlzGroupGetSize(g)
loop
set i = i - 1
exitwhen i < 0
call callback.evaluate(BlzGroupUnitAt(g, i))
endloop
endfunction
private function UnitsWithAbilityFilter takes nothing returns boolean
return GetUnitAbilityLevel(GetFilterUnit(), ABILITY_ID) > 0
endfunction
function GateAbilityTriggerAll takes trigger t, integer abilityId, integer techId, GatedAbilityTriggerCallback onEnable, GatedAbilityTriggerCallback onDisable returns GatedAbilityTrigger
local group units = null
local unit picked = null
local integer i = 0
local player p = null
local GatedAbilityTrigger g = GatedAbilityTrigger.create()
set ABILITY_ID = abilityId
set g.t = t
set g.abilityId = abilityId
set g.techId = techId
set g.abilityUnits = CreateGroup()
set g.onEnable = onEnable
set g.onDisable = onDisable
call GroupEnumUnitsInRect(g.abilityUnits, GetEntireMapRect(), Condition(function UnitsWithAbilityFilter))
set GATS[GAT_COUNT] = g
set GAT_COUNT = GAT_COUNT + 1
if (BlzGroupGetSize(g.abilityUnits) > 0) then
if (techId != 0) then
set i = bj_MAX_PLAYER_SLOTS
loop
set i = i - 1
exitwhen i < 0
if (GetPlayerTechCount(Player(i), techId, true) > 0) then
exitwhen true
endif
endloop
if (i < 0) then
call DisableTrigger(t)
elseif (onEnable != 0) then
call ExecuteCallbackForGroup(g.abilityUnits, onEnable)
endif
elseif (onEnable != 0) then
call ExecuteCallbackForGroup(g.abilityUnits, onEnable)
endif
else
call DisableTrigger(t)
endif
return g
endfunction
function GateAbilityTrigger takes trigger t, integer abilityId, integer techId returns GatedAbilityTrigger
return GateAbilityTriggerAll(t, abilityId, techId, 0, 0)
endfunction
private function UnitEnters takes nothing returns nothing
local unit entering = GetEnteringUnit()
local player p = GetOwningPlayer(entering)
local integer i = GAT_COUNT
local GatedAbilityTrigger gat = 0
loop
set i = i - 1
exitwhen i < 0
set gat = GATS[i]
if (GetUnitAbilityLevel(entering, gat.abilityId) > 0) then
call AddUnit(gat, entering)
endif
endloop
endfunction
private function UnitDies takes nothing returns nothing
local unit dying = GetDyingUnit()
local integer i = GAT_COUNT
local GatedAbilityTrigger gat = 0
if (not IsUnitType(dying, UNIT_TYPE_HERO)) then
loop
set i = i - 1
exitwhen i < 0
set gat = GATS[i]
if (GetUnitAbilityLevel(dying, gat.abilityId) > 0) then
call RemoveUnit(gat, dying)
endif
endloop
endif
endfunction
private function UnitResearchesTech takes nothing returns nothing
local unit researching = GetResearchingUnit()
local integer techId = GetResearched()
local integer i = GAT_COUNT
local GatedAbilityTrigger gat = 0
loop
set i = i - 1
exitwhen i < 0
set gat = GATS[i]
if (gat.techId == techId and BlzGroupGetSize(gat.abilityUnits) > 0) then
call EnableTrigger(gat.t)
if (gat.onEnable != 0) then
call ExecuteCallbackForGroup(gat.abilityUnits, gat.onEnable)
endif
endif
endloop
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterEnterRectSimple(t, GetEntireMapRect())
call TriggerAddAction(t, function UnitEnters)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t, function UnitDies)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddAction(t, function UnitResearchesTech)
endfunction
endlibrary
library TransportTracking initializer Init requires EventSystem
globals
private constant hashtable HT_TRANSPORTS = InitHashtable()
private constant key KEY_UNIT_TO_TRANSPORT
private constant key KEY_TRANSPORT_TO_UNITS
public Event OnUnitLoadedIntoTransport = 0
public Event OnUnitUnloadedFromTransport = 0
endglobals
struct TransportEvent
unit transport = null
unit cargo = null
endstruct
private function FireTransportEvent takes Event ev, unit transport, unit cargo returns nothing
local TransportEvent input = 0
if (EventSystem_HasListeners(ev)) then
set input = TransportEvent.create()
set input.transport = transport
set input.cargo = cargo
call EventSystem_FireEvent(ev, input)
call input.destroy()
endif
endfunction
function IsUnitLoadedIntoTransport takes unit whichUnit returns boolean
return HaveSavedHandle(HT_TRANSPORTS, GetHandleId(whichUnit), KEY_UNIT_TO_TRANSPORT)
endfunction
function GetTransportingUnit takes unit whichUnit returns unit
return LoadUnitHandle(HT_TRANSPORTS, GetHandleId(whichUnit), KEY_UNIT_TO_TRANSPORT)
endfunction
function GetLoadedUnits takes unit transport returns group
return LoadGroupHandle(HT_TRANSPORTS, GetHandleId(transport), KEY_TRANSPORT_TO_UNITS)
endfunction
private function GetOrCreateLoadedUnits takes unit transport returns group
local group loadedUnits = GetLoadedUnits(transport)
if (loadedUnits == null) then
set loadedUnits = CreateGroup()
call SaveGroupHandle(HT_TRANSPORTS, GetHandleId(transport), KEY_TRANSPORT_TO_UNITS, loadedUnits)
endif
return loadedUnits
endfunction
private function ReportUnitLoadedIntoTransport takes unit transport, unit loaded returns nothing
local group loadedUnits = GetOrCreateLoadedUnits(transport)
call GroupAddUnit(loadedUnits, loaded)
call SaveUnitHandle(HT_TRANSPORTS, GetHandleId(loaded), KEY_UNIT_TO_TRANSPORT, transport)
call FireTransportEvent(OnUnitLoadedIntoTransport, transport, loaded)
endfunction
private function ReportUnitUnloadedFromTransport takes unit transport, unit unloaded returns nothing
local group loadedUnits = GetLoadedUnits(transport)
if (GroupRemoveUnit(loadedUnits, unloaded)) then
call FireTransportEvent(OnUnitUnloadedFromTransport, transport, unloaded)
if (CountUnitsInGroup(loadedUnits) == 0) then
call DestroyGroup(loadedUnits)
call RemoveSavedHandle(HT_TRANSPORTS, GetHandleId(transport), KEY_TRANSPORT_TO_UNITS)
endif
call RemoveSavedHandle(HT_TRANSPORTS, GetHandleId(unloaded), KEY_UNIT_TO_TRANSPORT)
endif
endfunction
private function UnitLoadedActions takes nothing returns nothing
call ReportUnitLoadedIntoTransport(GetTransportUnit(), GetLoadedUnit())
endfunction
private function UnitUnloadedConditions takes nothing returns boolean
if (GetIssuedOrderId() != OrderId("stop")) then
return false
elseif (not IsUnitLoadedIntoTransport(GetOrderedUnit())) then
return false
endif
return true
endfunction
private function UnitUnloadedActions takes nothing returns nothing
local unit unloaded = GetOrderedUnit()
local unit transport = GetTransportingUnit(unloaded)
call ReportUnitUnloadedFromTransport(transport, unloaded)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_LOADED)
call TriggerAddAction(t, function UnitLoadedActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function UnitUnloadedConditions))
call TriggerAddAction(t, function UnitUnloadedActions)
set OnUnitLoadedIntoTransport = EventSystem_Create()
set OnUnitUnloadedFromTransport = EventSystem_Create()
endfunction
endlibrary
globals
constant integer SIM_MOVE_TYPE_SETXY = 0
constant integer SIM_MOVE_TYPE_SETPOS = 1
constant real SIM_MOVEMENT_UPDATE_INTERVAL = 0.01
endglobals
function interface SimMovementCallback takes SimMovement sim returns nothing
struct SimMovement
integer simMoveType = SIM_MOVE_TYPE_SETXY
unit mover = null
real originX = 0.0
real originY = 0.0
real targetX = 0.0
real targetY = 0.0
real speed = 0.0
real arc = 0.0
real flyHeightStart = 0.0
real flyHeightEnd = -1.0
SimMovementCallback onMove = 0
SimMovementCallback onFinish = 0
IntTimer update = 0
method onDestroy takes nothing returns nothing
if (onFinish != 0) then
call onFinish.evaluate(this)
endif
call update.destroy()
endmethod
endstruct
function SimMoveApplyArc takes SimMovement sim, real curX, real curY returns nothing
local real x = DistanceBetweenPointsXY(curX, curY, sim.targetX, sim.targetY)
local real d = DistanceBetweenPointsXY(sim.originX, sim.originY, sim.targetX, sim.targetY)
local real y = GetMissileHeight(sim.arc, d, x)
local real flyHeightOffset = 0.0
if (sim.flyHeightEnd != -1.0) then
set flyHeightOffset = (1.0 - DBZ(x, d, 0.0)) * (sim.flyHeightEnd - sim.flyHeightStart) + sim.flyHeightStart
endif
call SetUnitFlyHeight(sim.mover, y + flyHeightOffset, 0.0)
endfunction
function SimMoveUnit takes SimMovement sim, real x, real y returns nothing
if (sim.simMoveType == SIM_MOVE_TYPE_SETPOS) then
call SetUnitPosition(sim.mover, x, y)
else
call SetUnitX(sim.mover, x)
call SetUnitY(sim.mover, y)
endif
if (sim.arc != 0.0) then
call SimMoveApplyArc(sim, x, y)
endif
if (sim.onMove != 0) then
call sim.onMove.evaluate(sim)
endif
endfunction
function SimMovementUpdate takes IntTimer it returns nothing
local SimMovement sim = it.owner
local real delta = TimerPlusGetElapsed(it)
local real x = GetUnitX(sim.mover)
local real y = GetUnitY(sim.mover)
local real speed = sim.speed * delta
local real angle = AngleBetweenPointsXY(x, y, sim.targetX, sim.targetY)
local real dist = DistanceBetweenPointsXY(x, y, sim.targetX, sim.targetY)
local real nextX = PolarProjectionX(x, speed, angle)
local real nextY = PolarProjectionY(y, speed, angle)
if (dist > speed) then // and (IsUnitType(sim.mover, UNIT_TYPE_FLYING) or IsPointWalkable(nextX, nextY))) then
call SetUnitPathing(sim.mover, false)
call SimMoveUnit(sim, nextX, nextY)
else
// Unit is close enough to the target point
call SimMoveUnit(sim, sim.targetX, sim.targetY)
call SetUnitPathing(sim.mover, true)
call sim.destroy()
endif
endfunction
function CreateSimMovement takes unit whichUnit, real startX, real startY, real endX, real endY returns SimMovement
local SimMovement sim = SimMovement.create()
set sim.mover = whichUnit
set sim.originX = startX
set sim.originY = startY
set sim.targetX = endX
set sim.targetY = endY
set sim.update = CreateIntTimer(sim, false)
return sim
endfunction
function MoveUnitToPointAtSpeedParams takes SimMovement sim returns nothing
local location newTarget = null
if (not IsUnitType(sim.mover, UNIT_TYPE_FLYING)) then
if (sim.arc != 0.0 or sim.flyHeightEnd != -1.0) then
call EnableUnitFlyHeight(sim.mover)
endif
set newTarget = LineTraceWalkability(sim.originX, sim.originY, sim.targetX, sim.targetY, 32.0)
set sim.targetX = GetLocationX(newTarget)
set sim.targetY = GetLocationY(newTarget)
call RemoveLocation(newTarget)
endif
call StartIntTimerPeriodic(sim.update, 0.0, SIM_MOVEMENT_UPDATE_INTERVAL, SimMovementUpdate, 0)
endfunction
function MoveUnitToPointAtSpeedAll takes unit whichUnit, real targetX, real targetY, real speed, real arc, integer simMovementType, SimMovementCallback onMove, SimMovementCallback onFinished returns nothing
local SimMovement sim = CreateSimMovement(whichUnit, GetUnitX(whichUnit), GetUnitY(whichUnit), targetX, targetY)
set sim.simMoveType = simMovementType
set sim.speed = speed
set sim.arc = arc
set sim.flyHeightStart = GetUnitFlyHeight(whichUnit)
set sim.onMove = onMove
set sim.onFinish = onFinished
call MoveUnitToPointAtSpeedParams(sim)
endfunction
function MoveUnitToPointAtSpeedWithCallback takes unit whichUnit, real targetX, real targetY, real speed, SimMovementCallback onFinished returns nothing
call MoveUnitToPointAtSpeedAll(whichUnit, targetX, targetY, speed, 0.0, SIM_MOVE_TYPE_SETXY, 0, onFinished)
endfunction
function MoveUnitToPointAtSpeedXY takes unit whichUnit, real targetX, real targetY, real speed returns nothing
call MoveUnitToPointAtSpeedAll(whichUnit, targetX, targetY, speed, 0.0, SIM_MOVE_TYPE_SETXY, 0, 0)
endfunction
function MoveUnitToPointAtSpeed takes unit whichUnit, location targetLoc, real speed returns nothing
call MoveUnitToPointAtSpeedXY(whichUnit, GetLocationX(targetLoc), GetLocationY(targetLoc), speed)
endfunction
function AddMissileTarget takes unit target, unit caster, integer buffHandle, MissileHitCallback callback returns nothing
local integer targetHandle = GetHandleId(target)
local integer count = LoadInteger(udg_HashTable_Missiles, targetHandle, StringHash("COUNT"))
local integer index = count
call SaveUnitHandle(udg_HashTable_Missiles, targetHandle, StringHash("CASTER " + I2S(index)), caster)
call SaveInteger(udg_HashTable_Missiles, targetHandle, StringHash("BUFF " + I2S(index)), buffHandle)
call SaveInteger(udg_HashTable_Missiles, targetHandle, StringHash("ONHIT " + I2S(index)), callback)
call SaveInteger(udg_HashTable_Missiles, targetHandle, StringHash("COUNT"), count + 1)
call GroupAddUnit(udg_UnitGroup_MissileTargets, target)
call EnableTrigger(gg_trg_Triggered_Missile_Loop)
endfunction
function ClearMissileTarget takes unit whichUnit, integer index returns nothing
local integer unitHandle = GetHandleId(whichUnit)
local integer count = LoadInteger(udg_HashTable_Missiles, unitHandle, StringHash("COUNT"))
local integer i = 0
local integer tempBuff = 0
local MissileHitCallback tempCallback = 0
local unit tempCaster = null
call RemoveSavedInteger(udg_HashTable_Missiles, unitHandle, StringHash("BUFF " + I2S(index)))
call RemoveSavedInteger(udg_HashTable_Missiles, unitHandle, StringHash("ONHIT " + I2S(index)))
call RemoveSavedHandle(udg_HashTable_Missiles, unitHandle, StringHash("CASTER " + I2S(index)))
if (count == 1 or index >= count) then
call FlushChildHashtable(udg_HashTable_Missiles, unitHandle)
call GroupRemoveUnit(udg_UnitGroup_MissileTargets, whichUnit)
elseif (index >= 0) then
set i = index
loop
if (i >= count - 1) then
call RemoveSavedInteger(udg_HashTable_Missiles, unitHandle, StringHash("BUFF " + I2S(i)))
call RemoveSavedInteger(udg_HashTable_Missiles, unitHandle, StringHash("ONHIT " + I2S(i)))
call RemoveSavedHandle(udg_HashTable_Missiles, unitHandle, StringHash("CASTER " + I2S(i)))
exitwhen true
endif
set tempBuff = LoadInteger(udg_HashTable_Missiles, unitHandle, StringHash("BUFF " + I2S(i + 1)))
set tempCallback = LoadInteger(udg_HashTable_Missiles, unitHandle, StringHash("ONHIT " + I2S(i + 1)))
set tempCaster = LoadUnitHandle(udg_HashTable_Missiles, unitHandle, StringHash("CASTER " + I2S(i + 1)))
call SaveInteger(udg_HashTable_Missiles, unitHandle, StringHash("BUFF " + I2S(i)), tempBuff)
call SaveInteger(udg_HashTable_Missiles, unitHandle, StringHash("ONHIT " + I2S(i)), tempCallback)
call SaveUnitHandle(udg_HashTable_Missiles, unitHandle, StringHash("CASTER " + I2S(i)), tempCaster)
set i = i + 1
endloop
call SaveInteger(udg_HashTable_Missiles, unitHandle, StringHash("COUNT"), count - 1)
endif
endfunction
globals
constant real TRIGGERED_MISSILE_INTERVAL = 0.01
endglobals
function interface MissileHitCallback takes unit caster, unit target returns nothing
function IsInvalidMissileTarget takes unit whichUnit returns boolean
if (IsUnitAliveBJ(whichUnit) == false) then
return true
endif
if (IsUnitType(whichUnit, UNIT_TYPE_MAGIC_IMMUNE)) then
return true
endif
if (BlzIsUnitInvulnerable(whichUnit)) then
return true
endif
if (IsUnitHiddenBJ(whichUnit)) then
return true
endif
return false
endfunction
function Trig_Triggered_Missile_Loop_Actions takes nothing returns nothing
local integer groupCount = BlzGroupGetSize(udg_UnitGroup_MissileTargets)
local integer groupIndex = groupCount - 1
local integer missileCount = 0
local integer missileIndex = 0
local unit pickedUnit = null
local integer missileBuff = 0
local unit caster = null
local MissileHitCallback callback = 0
if (groupCount > 0) then
loop
exitwhen groupIndex < 0
set pickedUnit = BlzGroupUnitAt(udg_UnitGroup_MissileTargets, groupIndex)
set missileCount = LoadInteger(udg_HashTable_Missiles, GetHandleId(pickedUnit), StringHash("COUNT"))
if (missileCount > 0) then
set missileIndex = missileCount - 1
loop
exitwhen missileIndex < 0
set missileBuff = LoadInteger(udg_HashTable_Missiles, GetHandleId(pickedUnit), StringHash("BUFF " + I2S(missileIndex)))
// Check if the target is still valid
if (IsInvalidMissileTarget(pickedUnit)) then
call ClearMissileTarget(pickedUnit, missileIndex)
elseif UnitHasBuffBJ(pickedUnit, missileBuff) then
set caster = LoadUnitHandle(udg_HashTable_Missiles, GetHandleId(pickedUnit), StringHash("CASTER " + I2S(missileIndex)))
set callback = LoadInteger(udg_HashTable_Missiles, GetHandleId(pickedUnit), StringHash("ONHIT " + I2S(missileIndex)))
call callback.evaluate(caster, pickedUnit)
call ClearMissileTarget(pickedUnit, missileIndex)
endif
set missileIndex = missileIndex - 1
endloop
else
call GroupRemoveUnit(udg_UnitGroup_MissileTargets, pickedUnit)
endif
set groupIndex = groupIndex - 1
endloop
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Triggered_Missile_Loop takes nothing returns nothing
set gg_trg_Triggered_Missile_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Triggered_Missile_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Triggered_Missile_Loop, TRIGGERED_MISSILE_INTERVAL)
call TriggerAddAction( gg_trg_Triggered_Missile_Loop, function Trig_Triggered_Missile_Loop_Actions )
endfunction
globals
constant real MISSILE_UPDATE_INTERVAL = 0.01
endglobals
function interface MissileUpdateCallback takes IMissile missile, real dt returns boolean
function interface MissileDestroyCallback takes IMissile missile returns nothing
function OnDestroyMissile takes IMissile missile returns nothing
if (missile.destroyCallback != 0) then
call missile.destroyCallback.evaluate(missile)
endif
call DestroyEffect(missile.model)
call missile.visualPos.destroy()
call missile.velocity.destroy()
call missile.update.destroy()
call RemoveLocation(missile.actualPos)
endfunction
function MissileTimerLoop takes IntTimer missileTimer returns nothing
local IMissile missile = missileTimer.owner
local real dt = TimerPlusGetElapsed(missileTimer)
local boolean shouldDestroy = false
if (missile.updateLoop != 0) then
set shouldDestroy = missile.updateLoop.evaluate(missile, dt)
endif
if (missile.userUpdateCallback != 0) then
set missile.userUpdateElapsed = missile.userUpdateElapsed + dt
if (missile.userUpdateElapsed >= missile.userUpdateInterval) then
set shouldDestroy = missile.userUpdateCallback.evaluate(missile, dt) or shouldDestroy
set missile.userUpdateElapsed = missile.userUpdateElapsed - missile.userUpdateInterval
endif
endif
if (shouldDestroy) then
call missile.destroy()
endif
endfunction
function BaseMissileUpdate takes IMissile missile, real dt returns boolean
local vec3 delta = VecMultiply(missile.velocity, dt)
local vec3 deltaNorm = vec3.create(delta.x, delta.y, 0.0).normalize()
local real arcZOffset = GetMissileHeight(missile.arc, missile.range, missile.rangeRemaining)
local vec3 nextVisualPos = 0
call MoveLocation(missile.actualPos, GetLocationX(missile.actualPos) + delta.x, GetLocationY(missile.actualPos) + delta.y)
set nextVisualPos = GetLocVec(missile.actualPos).addZ(missile.zOffset + arcZOffset + delta.z)
call BlzSetSpecialEffectYaw(missile.model, VecYawRad(deltaNorm))
call BlzSetSpecialEffectPitch(missile.model, PitchBetweenVecsRad(missile.visualPos, nextVisualPos))
call BlzSetSpecialEffectPosition(missile.model, nextVisualPos.x, nextVisualPos.y, nextVisualPos.z)
set missile.visualPos = missile.visualPos.copy(nextVisualPos)
set missile.rangeRemaining = missile.rangeRemaining - delta.setZ(0.0).mag()
call delta.destroy()
call deltaNorm.destroy()
call nextVisualPos.destroy()
return missile.rangeRemaining <= 0.0
endfunction
interface IMissile
effect model = null
unit owner = null
location actualPos = null
real zOffset = 0.0
vec3 visualPos = 0
vec3 velocity = 0
real range = BIG_REAL
real rangeRemaining = 0.0
real arc = 0.0
real speed = 0.0
real userUpdateInterval = 0.0
real userUpdateElapsed = 0.0
MissileUpdateCallback updateLoop = 0
MissileUpdateCallback userUpdateCallback = 0
MissileDestroyCallback destroyCallback = 0
IntTimer update = 0
integer data = 0
endinterface
function InitMissile takes IMissile missile, string modelName, unit owner, real originX, real originY, real zOffset, real yawInRadians, real pitchInRadians returns nothing
set missile.model = AddSpecialEffect(modelName, originX, originY)
set missile.owner = owner
set missile.actualPos = Location(originX, originY)
set missile.visualPos = GetLocVec(missile.actualPos).addZ(zOffset)
set missile.zOffset = zOffset
call BlzSetSpecialEffectYaw(missile.model, yawInRadians)
call BlzSetSpecialEffectPitch(missile.model, pitchInRadians)
call BlzSetSpecialEffectZ(missile.model, missile.visualPos.z)
endfunction
function FireMissile takes IMissile missile, real speed, real range, real yawInRadians, real pitchInRadians, MissileUpdateCallback updateLoop, MissileDestroyCallback onDestroyed returns nothing
call BlzSetSpecialEffectYaw(missile.model, yawInRadians)
call BlzSetSpecialEffectPitch(missile.model, pitchInRadians)
set missile.velocity = VecDirection(yawInRadians, pitchInRadians).multiply(speed)
set missile.range = range
set missile.rangeRemaining = range
set missile.speed = speed
set missile.updateLoop = updateLoop
set missile.destroyCallback = onDestroyed
set missile.update = CreateIntTimer(missile, false)
call StartIntTimerPeriodic(missile.update, 0.0, MISSILE_UPDATE_INTERVAL, MissileTimerLoop, 0)
endfunction
function interface WaveMissileFilter takes WaveMissile missile, unit filter returns boolean
function interface WaveMissileOnHitCallback takes WaveMissile missle, unit hit returns nothing
function WaveMissileUpdate takes WaveMissile missile, real dt returns boolean
local real aoe = 0.0
local group nearbyUnits = null
local unit picked = null
local boolean result = BaseMissileUpdate.evaluate(missile, dt)
if (UpdateDumbTimer(missile.hitInterval, TimerPlusGetElapsed(missile.update))) then
set aoe = (missile.aoeEnd - missile.aoeStart) * (1 - (missile.rangeRemaining / missile.range)) + missile.aoeStart
set nearbyUnits = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(nearbyUnits, missile.actualPos, aoe, null)
loop
set picked = FirstOfGroup(nearbyUnits)
exitwhen picked == null
if (missile.filter != 0 and missile.onHit != 0) then
if (missile.multiHit or not IsUnitInGroup(picked, missile.allHit)) then
call GroupAddUnit(missile.allHit, picked)
if (missile.filter.evaluate(missile, picked)) then
call missile.onHit.execute(missile, picked)
endif
endif
endif
call GroupRemoveUnit(nearbyUnits, picked)
endloop
call DestroyGroup(nearbyUnits)
endif
return result
endfunction
struct WaveMissile extends IMissile
real aoeStart = 0.0
real aoeEnd = 0.0
boolean multiHit = false
group allHit = null
DumbTimer hitInterval = 0
WaveMissileFilter filter = 0
WaveMissileOnHitCallback onHit = 0
method onDestroy takes nothing returns nothing
call OnDestroyMissile(this)
call hitInterval.destroy()
call DestroyGroup(allHit)
endmethod
endstruct
function CreateWaveMissileYawPitch takes string modelName, unit owner, real originX, real originY, real originZ, real hitInterval, real yawInRadians, real pitchInRadians returns WaveMissile
local WaveMissile waveMissile = WaveMissile.create()
call InitMissile(waveMissile, modelName, owner, originX, originY, originZ, yawInRadians, pitchInRadians)
set waveMissile.hitInterval = CreateDumbTimer(hitInterval)
return waveMissile
endfunction
function CreateWaveMissileInterval takes string modelName, unit owner, real originX, real originY, real originZ, real hitInterval returns WaveMissile
return CreateWaveMissileYawPitch(modelName, owner, originX, originY, originZ, hitInterval, 0.0, 0.0)
endfunction
function CreateWaveMissile takes string modelName, unit owner, real originX, real originY, real originZ returns WaveMissile
return CreateWaveMissileYawPitch(modelName, owner, originX, originY, originZ, 0.0, 0.0, 0.0)
endfunction
function FireWaveMissile takes WaveMissile missile, real speed, real range, real yawInRadians, real pitchInRadians, real aoeStart, real aoeEnd, WaveMissileFilter filter, WaveMissileOnHitCallback onHit returns nothing
if (not missile.multiHit) then
set missile.allHit = CreateGroup()
endif
set missile.aoeStart = aoeStart
set missile.aoeEnd = aoeEnd
set missile.filter = filter
set missile.onHit = onHit
call FireMissile(missile, speed, range, yawInRadians, pitchInRadians, WaveMissileUpdate, 0)
endfunction
function interface PointMissileOnHitCallback takes PointMissile missile, real x, real y returns nothing
function PointMissileDestroyed takes PointMissile pm returns nothing
if (pm.onHit != 0) then
call pm.onHit.evaluate(pm, GetLocationX(pm.actualPos), GetLocationY(pm.actualPos))
endif
endfunction
struct PointMissile extends IMissile
PointMissileOnHitCallback onHit = 0
method onDestroy takes nothing returns nothing
call OnDestroyMissile(this)
endmethod
endstruct
function CreatePointMissile takes string modelName, unit owner, real originX, real originY, real zOffset, real yawInRadians, real pitchInRadians returns PointMissile
local PointMissile pointMissile = PointMissile.create()
call InitMissile(pointMissile, modelName, owner, originX, originY, zOffset, yawInRadians, pitchInRadians)
return pointMissile
endfunction
function FirePointMissile takes PointMissile missile, real speed, real targetX, real targetY, real targetZOffset, real arc, PointMissileOnHitCallback onHit returns nothing
local location targetLoc = Location(targetX, targetY)
local vec3 source = GetLocVec(missile.actualPos)
local vec3 target = GetLocVec(targetLoc).addZ(targetZOffset)
local real distance = DistanceBetweenPointsXY(source.x, source.y, target.x, target.y)
set missile.arc = arc
set missile.onHit = onHit
call FireMissile(missile, speed, distance, YawBetweenVecsRad(source, target), -PitchBetweenVecsRad(source, target), BaseMissileUpdate, PointMissileDestroyed)
call RemoveLocation(targetLoc)
call source.destroy()
call target.destroy()
endfunction
function interface TargetMissileOnHitCallback takes TargetMissile missile, real x, real y returns nothing
function TargetMissileDestroyed takes TargetMissile tm returns nothing
if (tm.onHit != 0) then
call tm.onHit.evaluate(tm, GetLocationX(tm.actualPos), GetLocationY(tm.actualPos))
endif
endfunction
function TargetMissileWithHomingUpdate takes TargetMissile missile, real dt returns boolean
local vec3 currentPos = GetLocVec(missile.actualPos)
local vec3 targetPos = GetUnitVec(missile.target).addZ(missile.targetZOffset)
local vec3 delta = VecSub(targetPos, currentPos)
local vec3 deltaNorm = vec3.create(delta.x, delta.y, 0.0).normalize()
local real rangeRemaining = DistanceBetweenPointsXY(currentPos.x, currentPos.y, targetPos.x, targetPos.y)
local real arcZOffset = GetMissileHeight(missile.arc, missile.range, rangeRemaining)
local real targetZOffset = missile.targetZOffset + GetUnitFlyHeight(missile.target)
local real zOffset = (1.0 - RMinBJ(DBZ(rangeRemaining, missile.range, 1.0), 1.0)) * (targetZOffset - missile.zOffset) + missile.zOffset + arcZOffset
local real speed = missile.speed * dt
local vec3 nextVisualPos = 0
local boolean hit = false
if (rangeRemaining <= speed) then
call MoveLocation(missile.actualPos, targetPos.x, targetPos.y)
set nextVisualPos = targetPos.dupe().addZ(arcZOffset)
set rangeRemaining = 0.0
set hit = true
else
call MoveLocation(missile.actualPos, currentPos.x + deltaNorm.x * speed, currentPos.y + deltaNorm.y * speed)
set nextVisualPos = GetLocVec(missile.actualPos).addZ(zOffset)
endif
call BlzSetSpecialEffectYaw(missile.model, VecYawRad(deltaNorm))
call BlzSetSpecialEffectPitch(missile.model, PitchBetweenVecsRad(missile.visualPos, nextVisualPos))
call BlzSetSpecialEffectPosition(missile.model, nextVisualPos.x, nextVisualPos.y, nextVisualPos.z)
set missile.rangeRemaining = rangeRemaining
set missile.visualPos = missile.visualPos.copy(nextVisualPos)
call currentPos.destroy()
call targetPos.destroy()
call delta.destroy()
call deltaNorm.destroy()
call nextVisualPos.destroy()
return hit
endfunction
struct TargetMissile extends IMissile
unit target = null
real targetZOffset = 0.0
TargetMissileOnHitCallback onHit = 0
method onDestroy takes nothing returns nothing
call OnDestroyMissile(this)
endmethod
endstruct
function CreateTargetMissileYawPitch takes string modelName, unit owner, real originX, real originY, real zOffset, real yawInRadians, real pitchInRadians returns TargetMissile
local TargetMissile targetMissile = TargetMissile.create()
call InitMissile(targetMissile, modelName, owner, originX, originY, GetUnitFlyHeight(owner) + zOffset, yawInRadians, pitchInRadians)
return targetMissile
endfunction
function CreateTargetMissile takes string modelName, unit owner, real originX, real originY, real zOffset returns TargetMissile
return CreateTargetMissileYawPitch(modelName, owner, originX, originY, zOffset, 0.0, 0.0)
endfunction
function FireTargetMissile takes TargetMissile missile, unit targetUnit, real speed, real arc, real zOffset, boolean enableHoming, TargetMissileOnHitCallback onHit returns nothing
local vec3 source = GetLocVec(missile.actualPos).addZ(missile.zOffset)
local vec3 target = GetUnitVec(targetUnit).addZ(zOffset)
local real distance = DistanceBetweenPointsXY(source.x, source.y, target.x, target.y)
local MissileUpdateCallback updateCallback = BaseMissileUpdate
set missile.target = targetUnit
set missile.arc = arc
set missile.onHit = onHit
set missile.targetZOffset = zOffset
if (enableHoming) then
set updateCallback = TargetMissileWithHomingUpdate
endif
call FireMissile(missile, speed, distance, YawBetweenVecsRad(source, target), -PitchBetweenVecsRad(source, target), updateCallback, TargetMissileDestroyed)
call source.destroy()
call target.destroy()
endfunction
function FireUnitAbilityTargetMissile takes unit whichUnit, unit target, integer abilityId, real projectileLaunchZOffset, real projectileHitZOffset, boolean enableHoming, TargetMissileOnHitCallback onHit returns TargetMissile
local string missileArt = GetUnitAbilityStringLevelField(whichUnit, abilityId, ABILITY_SLF_MISSILE_ART)
local real missileSpeed = GetUnitAbilityIntegerField(whichUnit, abilityId, ABILITY_IF_MISSILE_SPEED)
local real missileArc = GetUnitAbilityRealField(whichUnit, abilityId, ABILITY_RF_ARF_MISSILE_ARC)
local TargetMissile missile = CreateTargetMissile(missileArt, whichUnit, GetUnitX(whichUnit), GetUnitY(whichUnit), projectileLaunchZOffset)
call FireTargetMissile(missile, target, missileSpeed, missileArc, projectileHitZOffset, enableHoming, onHit)
return missile
endfunction
globals
key KEY_ITEMUNITS
endglobals
function interface OnCollectCallback takes unit itemUnit, unit collector returns nothing
function interface CollectionFilter takes unit itemUnit, unit filterUnit returns boolean
struct ItemUnitParams
group OrderedUnits = CreateGroup()
real CollectionRadius = 100.0
CollectionFilter CollectionFilter = 0
OnCollectCallback OnCollect = 0
method onDestroy takes nothing returns nothing
call DestroyGroup(OrderedUnits)
endmethod
endstruct
scope ItemUnit
public function AddItemUnit takes unit whichUnit, CollectionFilter filter, OnCollectCallback callback returns nothing
local ItemUnitParams params = ItemUnitParams.create()
set params.CollectionFilter = filter
set params.OnCollect = callback
call SaveInteger(G_ITEMUNIT_LOOKUP, GetHandleId(whichUnit), KEY_ITEMUNITS, params)
call GroupAddUnit(udg_UnitGroup_ItemUnits, whichUnit)
call EnableTrigger(gg_trg_ItemUnit_Loop)
call EnableTrigger(gg_trg_ItemUnit_Collect_Order)
call EnableTrigger(gg_trg_ItemUnit_Other_Order)
endfunction
endscope
function Trig_ItemUnit_Collect_Order_Conditions takes nothing returns boolean
if (not IsOrder(GetIssuedOrderId(), "smart")) then
return false
elseif (GetOrderTargetUnit() == null) then
return false
elseif (not IsUnitInGroup(GetOrderTargetUnit(), udg_UnitGroup_ItemUnits)) then
return false
endif
return true
endfunction
function Trig_ItemUnit_Collect_Order_Actions takes nothing returns nothing
local unit itemUnit = GetOrderTargetUnit()
local ItemUnitParams param = LoadInteger(G_ITEMUNIT_LOOKUP, GetHandleId(itemUnit), KEY_ITEMUNITS)
if (param.CollectionFilter != 0 and param.CollectionFilter.evaluate(itemUnit, GetOrderedUnit())) then
call SaveUnitHandle(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_ITEMUNITS, itemUnit)
call GroupAddUnit(param.OrderedUnits, GetOrderedUnit())
endif
endfunction
//===========================================================================
function InitTrig_ItemUnit_Collect_Order takes nothing returns nothing
set gg_trg_ItemUnit_Collect_Order = CreateTrigger( )
call DisableTrigger( gg_trg_ItemUnit_Collect_Order )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ItemUnit_Collect_Order, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_ItemUnit_Collect_Order, Condition( function Trig_ItemUnit_Collect_Order_Conditions ) )
call TriggerAddAction( gg_trg_ItemUnit_Collect_Order, function Trig_ItemUnit_Collect_Order_Actions )
endfunction
function Trig_ItemUnit_Other_Order_Conditions takes nothing returns boolean
if (not IsOrder(GetIssuedOrderId(), "smart")) then
return false
elseif (GetOrderTargetUnit() != null and IsUnitInGroup(GetOrderTargetUnit(), udg_UnitGroup_ItemUnits)) then
return false
endif
return true
endfunction
function Trig_ItemUnit_Other_Order_Actions takes nothing returns nothing
local unit itemUnit = LoadUnitHandle(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_ITEMUNITS)
local ItemUnitParams param = LoadInteger(G_ITEMUNIT_LOOKUP, GetHandleId(itemUnit), KEY_ITEMUNITS)
if (itemUnit != null) then
call RemoveSavedHandle(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_ITEMUNITS)
call GroupRemoveUnit(param.OrderedUnits, GetOrderedUnit())
endif
endfunction
//===========================================================================
function InitTrig_ItemUnit_Other_Order takes nothing returns nothing
set gg_trg_ItemUnit_Other_Order = CreateTrigger( )
call DisableTrigger( gg_trg_ItemUnit_Other_Order )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ItemUnit_Other_Order, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ItemUnit_Other_Order, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_ItemUnit_Other_Order, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_ItemUnit_Other_Order, Condition( function Trig_ItemUnit_Other_Order_Conditions ) )
call TriggerAddAction( gg_trg_ItemUnit_Other_Order, function Trig_ItemUnit_Other_Order_Actions )
endfunction
globals
constant real ITEM_UNIT_LOOP_INTERVAL = 0.25
constant hashtable G_ITEMUNIT_LOOKUP = InitHashtable()
endglobals
function Trig_ItemUnit_ClearOrderedUnit takes nothing returns nothing
call RemoveSavedHandle(udg_HashTable_UnitInfo, GetHandleId(GetEnumUnit()), KEY_ITEMUNITS)
endfunction
function Trig_ItemUnit_Loop takes nothing returns nothing
local unit itemUnit = GetEnumUnit()
local ItemUnitParams params = LoadInteger(G_ITEMUNIT_LOOKUP, GetHandleId(itemUnit), KEY_ITEMUNITS)
local integer size = BlzGroupGetSize(params.OrderedUnits)
local integer index = 0
local real dist = 0.0
local real minDist = BIG_REAL
local unit pickedUnit = null
local unit closestUnit = null
if (UnitAlive(itemUnit)) then
if (not IsUnitHidden(itemUnit)) then
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(params.OrderedUnits, index)
set dist = DistanceBetweenUnits(pickedUnit, itemUnit) - BlzGetUnitCollisionSize(pickedUnit) - BlzGetUnitCollisionSize(itemUnit)
if (dist <= params.CollectionRadius and dist < minDist) then
set minDist = dist
set closestUnit = pickedUnit
endif
set index = index + 1
endloop
if (closestUnit != null and params.OnCollect != 0) then
call params.OnCollect.execute(itemUnit, closestUnit)
endif
endif
else
call ForGroupBJ(params.OrderedUnits, function Trig_ItemUnit_ClearOrderedUnit)
call params.destroy()
call GroupRemoveUnit(udg_UnitGroup_ItemUnits, itemUnit)
call RemoveSavedInteger(G_ITEMUNIT_LOOKUP, GetHandleId(itemUnit), KEY_ITEMUNITS)
endif
endfunction
function Trig_ItemUnit_Loop_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_ItemUnits)
if (size > 0) then
call ForGroupBJ(udg_UnitGroup_ItemUnits, function Trig_ItemUnit_Loop)
else
call DisableTrigger(GetTriggeringTrigger())
call DisableTrigger(gg_trg_ItemUnit_Collect_Order)
call DisableTrigger(gg_trg_ItemUnit_Other_Order)
endif
endfunction
//===========================================================================
function InitTrig_ItemUnit_Loop takes nothing returns nothing
set gg_trg_ItemUnit_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_ItemUnit_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_ItemUnit_Loop, ITEM_UNIT_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_ItemUnit_Loop, function Trig_ItemUnit_Loop_Actions )
endfunction
globals
constant key KEY_BUFF_EFFECTS
endglobals
struct BuffEffect
integer BuffType = 0
string EffectModel = null
effect Effect = null
UnitFunc onBuffRemoved = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(Effect)
endmethod
endstruct
function AddBuffEffectWithCallback takes unit whichUnit, integer whichBuff, string attachmentPoint, string modelName, UnitFunc onBuffRemoved returns effect
local LinkedList_Int buffEffects = LoadInteger(udg_HashTable_SpecialEffects, GetHandleId(whichUnit), KEY_BUFF_EFFECTS)
local LinkedListNode_Int node = 0
local BuffEffect buffEffect = 0
if (buffEffects == 0) then
set buffEffects = CreateLinkedList_Int()
call SaveInteger(udg_HashTable_SpecialEffects, GetHandleId(whichUnit), KEY_BUFF_EFFECTS, buffEffects)
endif
set node = LinkedListGetFirst(buffEffects)
loop
exitwhen node == 0
set buffEffect = node.value
if (buffEffect.BuffType == whichBuff and buffEffect.EffectModel == modelName) then
return buffEffect.Effect
endif
set node = node.next
endloop
set buffEffect = BuffEffect.create()
set buffEffect.BuffType = whichBuff
set buffEffect.EffectModel = modelName
set buffEffect.Effect = AddSpecialEffectTargetUnitBJ(attachmentPoint, whichUnit, modelName)
set buffEffect.onBuffRemoved = onBuffRemoved
call LinkedListAddLastInt(buffEffects, buffEffect)
call GroupAddUnit(udg_UnitGroup_BuffEffects, whichUnit)
call EnableTrigger(gg_trg_Triggered_Buff_Effects)
return buffEffect.Effect
endfunction
function AddBuffEffect takes unit whichUnit, integer whichBuff, string attachmentPoint, string modelName returns effect
return AddBuffEffectWithCallback(whichUnit, whichBuff, attachmentPoint, modelName, 0)
endfunction
globals
constant real TRIGGERED_BUFF_EFFECT_INTERVAL = 0.25
endglobals
function Trig_Triggered_Buff_Effects_Loop takes nothing returns nothing
local LinkedList_Int buffEffects = LoadInteger(udg_HashTable_SpecialEffects, GetHandleId(GetEnumUnit()), KEY_BUFF_EFFECTS)
local LinkedListNode_Int node = LinkedListGetFirst(buffEffects)
local LinkedListNode_Int nextNode = 0
local BuffEffect buffEffect = 0
if (buffEffects.count > 0) then
loop
exitwhen node == 0
set buffEffect = node.value
if (not UnitHasBuffBJ(GetEnumUnit(), buffEffect.BuffType)) then
if (buffEffect.onBuffRemoved != 0) then
call buffEffect.onBuffRemoved.evaluate(GetEnumUnit())
endif
call buffEffect.destroy()
set nextNode = node.next
call LinkedListRemove(buffEffects, node)
call node.destroy()
set node = nextNode
else
set node = node.next
endif
endloop
else
call DestroyLinkedList(buffEffects)
call RemoveSavedInteger(udg_HashTable_SpecialEffects, GetHandleId(GetEnumUnit()), KEY_BUFF_EFFECTS)
call GroupRemoveUnit(udg_UnitGroup_BuffEffects, GetEnumUnit())
endif
endfunction
function Trig_Triggered_Buff_Effects_Actions takes nothing returns nothing
local integer count = BlzGroupGetSize(udg_UnitGroup_BuffEffects)
if (count > 0) then
call ForGroupBJ(udg_UnitGroup_BuffEffects, function Trig_Triggered_Buff_Effects_Loop)
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Triggered_Buff_Effects takes nothing returns nothing
set gg_trg_Triggered_Buff_Effects = CreateTrigger()
call DisableTrigger(gg_trg_Triggered_Buff_Effects)
call TriggerRegisterTimerEventPeriodic(gg_trg_Triggered_Buff_Effects, TRIGGERED_BUFF_EFFECT_INTERVAL)
call TriggerAddAction(gg_trg_Triggered_Buff_Effects, function Trig_Triggered_Buff_Effects_Actions)
endfunction
scope Buffs
globals
private constant hashtable HT = InitHashtable()
private constant real DEFAULT_UPDATE_INTERVAL = 0.25
endglobals
function interface BuffCallback takes IBuff b returns nothing
struct IBuff
unit host = null
integer buffId = 0
integer abilityId = 0
BuffCallback onUpdate = 0
BuffCallback onRemoved = 0
IntTimer updateTimer = 0
endstruct
private struct SimpleBuff extends IBuff
endstruct
function CreateSimpleBuff takes unit host returns IBuff
local SimpleBuff b = SimpleBuff.create()
set b.host = host
return b
endfunction
function DestroyBuff takes IBuff b returns nothing
if (b != 0) then
call UnitRemoveAbility(b.host, b.abilityId)
call UnitRemoveAbility(b.host, b.buffId)
call b.updateTimer.destroy()
if (b.onRemoved != 0) then
call b.onRemoved.evaluate(b)
endif
call RemoveSavedInteger(HT, GetHandleId(b.host), b.buffId)
call b.destroy()
endif
endfunction
private function OnBuffUpdate takes IntTimer it returns nothing
local IBuff b = it.owner
if (UnitHasAbility(b.host, b.buffId)) then
if (b.onUpdate != 0) then
call b.onUpdate.evaluate(b)
endif
else
call DestroyBuff(b)
endif
endfunction
function GetBuff takes unit host, integer buffId returns IBuff
return LoadInteger(HT, GetHandleId(host), buffId)
endfunction
function HasBuff takes unit host, integer buffId returns boolean
return UnitHasAbility(host, buffId)
endfunction
function TrackBuff takes IBuff b, integer buffId, real updateInterval, BuffCallback onRemoved, BuffCallback onUpdate returns nothing
local IBuff existing = GetBuff(b.host, buffId)
if (existing != 0) then
call DestroyBuff(existing)
endif
if (updateInterval <= 0.0) then
set updateInterval = DEFAULT_UPDATE_INTERVAL
endif
set b.buffId = buffId
set b.onUpdate = onUpdate
set b.onRemoved = onRemoved
set b.updateTimer = CreateIntTimer(b, false)
call StartTimerPlusPeriodic(b.updateTimer, 0.0, updateInterval, OnBuffUpdate, 0)
call SaveInteger(HT, GetHandleId(b.host), buffId, b)
endfunction
function DummyCastBuff takes IBuff b, player p, integer buffId, integer abilityId, string order returns unit
local unit dummy = null
call TrackBuff(b, buffId, DEFAULT_UPDATE_INTERVAL, b.onRemoved, b.onUpdate)
set dummy = DummyCastUnit(p, b.host, GetUnitX(b.host), GetUnitY(b.host), abilityId, order)
return dummy
endfunction
function DummyCastBuffAll takes IBuff b, player p, integer buffId, real updateInterval, integer abilityId, string order returns unit
local unit dummy = null
call TrackBuff(b, buffId, updateInterval, b.onRemoved, b.onUpdate)
set dummy = DummyCastUnit(p, b.host, GetUnitX(b.host), GetUnitY(b.host), abilityId, order)
return dummy
endfunction
endscope
globals
key KEY_TRIGGERED_AURA
endglobals
function interface EmitterUpdate takes group unitsInsideAura returns nothing
function interface EmitterCondition takes unit emitter returns boolean
struct TriggeredAuraParams
integer AuraKey = 0
real UpdateInterval = 1.0
real AreaOfEffect = 0.0
group AuraEmitters = null
ConditionFunc TargetFilter = 0
UnitFunc ApplyAuraEffect = 0
UnitFunc RemoveAuraEffect = 0
EmitterUpdate OnEmitterUpdate = 0
EmitterCondition IsEmitterValid = 0
method ToString takes nothing returns string
return "AuraKey: " + I2S(AuraKey) + ", UpdateInterval: " + R2S(UpdateInterval) + ", AreaOfEffect: " + R2S(AreaOfEffect) + ", AuraEmitters: " + I2S(GetHandleId(AuraEmitters))
endmethod
endstruct
scope TriggeredAura
globals
private unit CurrentEmitter = null
private TriggeredAuraParams CurrentParams = 0
private hashtable lookup = InitHashtable()
endglobals
public function GetEmitter takes nothing returns unit
return CurrentEmitter
endfunction
function IsEmitterValid takes unit emitter returns boolean
if (CurrentParams.IsEmitterValid != 0) then
return CurrentParams.IsEmitterValid.evaluate(emitter)
else
return UnitAlive(emitter)
endif
endfunction
function TargetFilter takes nothing returns boolean
if (CurrentParams.TargetFilter != 0) then
return CurrentParams.TargetFilter.evaluate()
endif
return false
endfunction
function ApplyEffect takes nothing returns nothing
if (CurrentParams.ApplyAuraEffect != 0) then
call CurrentParams.ApplyAuraEffect.execute(GetEnumUnit())
endif
endfunction
function RemoveEffect takes nothing returns nothing
if (CurrentParams.RemoveAuraEffect != 0) then
call CurrentParams.RemoveAuraEffect.execute(GetEnumUnit())
endif
endfunction
public function Loop takes nothing returns nothing
local TriggeredAuraParams params = LoadInteger(lookup, KEY_TRIGGERED_AURA, GetHandleId(GetTriggeringTrigger()))
local group unitsOutsideAura = CreateGroup()
local group unitsInsideAura = CreateGroup()
local group auraEmitters = params.AuraEmitters
local group lastAOE = null
local group currentAOE = null
local integer emitterCount = BlzGroupGetSize(auraEmitters)
local integer emitterIndex = emitterCount - 1
local integer unitCount = 0
local integer unitIndex = 0
local unit pickedUnit = null
local location emitterPos = null
local location unitPos = null
set CurrentParams = params
// Loop through all auraEmitters on the map
loop
exitwhen emitterIndex < 0
set CurrentEmitter = BlzGroupUnitAt(auraEmitters, emitterIndex)
set lastAOE = LoadGroupHandle(lookup, GetHandleId(CurrentEmitter), params.AuraKey)
if (IsEmitterValid(CurrentEmitter)) then
// Emitter is alive
set emitterPos = GetUnitLoc(CurrentEmitter)
set currentAOE = GetUnitsInRangeOfLocMatching(params.AreaOfEffect, emitterPos, Condition(function TargetFilter))
call GroupAddGroup(currentAOE, lastAOE)
set unitCount = BlzGroupGetSize(lastAOE)
set unitIndex = unitCount - 1
loop
exitwhen unitIndex < 0
set pickedUnit = BlzGroupUnitAt(lastAOE, unitIndex)
set unitPos = GetUnitLoc(pickedUnit)
if (not UnitAlive(pickedUnit) or DistanceBetweenPoints(emitterPos, unitPos) > params.AreaOfEffect) then
call GroupAddUnit(unitsOutsideAura, pickedUnit)
call GroupRemoveUnit(lastAOE, pickedUnit)
else
call GroupAddUnit(unitsInsideAura, pickedUnit)
endif
call RemoveLocation(unitPos)
set unitIndex = unitIndex - 1
endloop
call RemoveLocation(emitterPos)
call DestroyGroup(currentAOE)
if (params.OnEmitterUpdate != 0) then
call params.OnEmitterUpdate.execute(lastAOE)
endif
else
// Emitter is not alive
call ForGroupBJ(lastAOE, function RemoveEffect)
call GroupRemoveUnit(auraEmitters, CurrentEmitter)
call DestroyGroup(lastAOE)
endif
set emitterIndex = emitterIndex - 1
endloop
if (BlzGroupGetSize(auraEmitters) > 0) then
call ForGroupBJ(unitsInsideAura, function ApplyEffect)
call BlzGroupRemoveGroupFast(unitsInsideAura, unitsOutsideAura)
call ForGroupBJ(unitsOutsideAura, function RemoveEffect)
else
call DisableTrigger(GetTriggeringTrigger())
endif
call DestroyGroup(unitsInsideAura)
call DestroyGroup(unitsOutsideAura)
endfunction
public function Create takes TriggeredAuraParams params returns trigger
local trigger auraTrigger = CreateTrigger()
if (params.AuraEmitters == null) then
set params.AuraEmitters = CreateGroup()
endif
call DisableTrigger(auraTrigger)
call TriggerRegisterTimerEventPeriodic( auraTrigger, params.UpdateInterval)
call TriggerAddAction(auraTrigger, function TriggeredAura_Loop)
call SaveInteger(lookup, KEY_TRIGGERED_AURA, GetHandleId(auraTrigger), params)
return auraTrigger
endfunction
public function AddEmitter takes unit whichUnit, trigger auraLoop returns nothing
local location emitterPos = GetUnitLoc(whichUnit)
set CurrentParams = LoadInteger(lookup, KEY_TRIGGERED_AURA, GetHandleId(auraLoop))
set CurrentEmitter = whichUnit
call SaveGroupHandle(lookup, GetHandleId(whichUnit), CurrentParams.AuraKey, GetUnitsInRangeOfLocMatching(CurrentParams.AreaOfEffect, emitterPos, Condition(function TargetFilter)))
call GroupAddUnit(CurrentParams.AuraEmitters, whichUnit)
call EnableTrigger(auraLoop)
call RemoveLocation(emitterPos)
endfunction
public function RemoveEmitter takes unit whichUnit, trigger auraLoop returns nothing
local group lastEmitterAOE = null
set CurrentEmitter = whichUnit
set CurrentParams = LoadInteger(lookup, KEY_TRIGGERED_AURA, GetHandleId(auraLoop))
set lastEmitterAOE = LoadGroupHandle(lookup, GetHandleId(whichUnit), CurrentParams.AuraKey)
call ForGroupBJ(lastEmitterAOE, function RemoveEffect)
call GroupRemoveUnit(CurrentParams.AuraEmitters, whichUnit)
call DestroyGroup(lastEmitterAOE)
call RemoveSavedHandle(lookup, GetHandleId(whichUnit), CurrentParams.AuraKey)
endfunction
endscope
globals
constant key KEY_CONSTRUCTION_DUMMIES
constant key KEY_CONSTRUCTION_DUMMIES_ALPHA_CHANGED
endglobals
function AddConstructionDummyNoTransparency takes unit target, integer dummyUnitTypeId, real timeScale returns unit
local player p = GetOwningPlayer(target)
local unit dummy = CreateUnit(p, dummyUnitTypeId, GetUnitX(target), GetUnitY(target), GetUnitFacing(target))
local group constructionEffects = LoadGroupHandle(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES, GetHandleId(target))
if (constructionEffects == null) then
set constructionEffects = CreateGroup()
endif
call SetUnitAnimation(dummy, "birth")
call SetUnitTimeScale(dummy, timeScale)
call LifelinkUnits(target, dummy, LIFELINK_KILL)
call GroupAddUnit(constructionEffects, dummy)
call SaveGroupHandle(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES, GetHandleId(target), constructionEffects)
return dummy
endfunction
function AddConstructionDummy takes unit target, integer dummyUnitTypeId, real timeScaleBuffer returns unit
local unit dummy = AddConstructionDummyNoTransparency(target, dummyUnitTypeId, timeScaleBuffer)
call ChangeUnitAlpha(target, 0)
call SaveBoolean(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES_ALPHA_CHANGED, GetHandleId(target), true)
return dummy
endfunction
function RemoveConstructionDummies takes unit target returns nothing
local player p = GetOwningPlayer(target)
local group constructionEffects = LoadGroupHandle(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES, GetHandleId(target))
local unit pickedUnit = null
if (constructionEffects != null) then
loop
set pickedUnit = FirstOfGroup(constructionEffects)
exitwhen pickedUnit == null
call GroupRemoveUnit(constructionEffects, pickedUnit)
call RemoveUnit(pickedUnit)
endloop
call RemoveSavedHandle(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES, GetHandleId(target))
call DestroyGroup(constructionEffects)
endif
if (HaveSavedBoolean(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES_ALPHA_CHANGED, GetHandleId(target))) then
call RestoreUnitColor(target)
call RemoveSavedBoolean(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES_ALPHA_CHANGED, GetHandleId(target))
endif
endfunction
function Trig_Construction_Complete_Conditions takes nothing returns boolean
return HaveSavedHandle(udg_HashTable_ConstructionEffects, KEY_CONSTRUCTION_DUMMIES, GetHandleId(GetConstructedStructure()))
endfunction
function Trig_Construction_Complete_Actions takes nothing returns nothing
call RemoveConstructionDummies(GetConstructedStructure())
endfunction
//===========================================================================
function InitTrig_Construction_Complete takes nothing returns nothing
set gg_trg_Construction_Complete = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Construction_Complete, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
call TriggerAddCondition( gg_trg_Construction_Complete, Condition( function Trig_Construction_Complete_Conditions ) )
call TriggerAddAction( gg_trg_Construction_Complete, function Trig_Construction_Complete_Actions )
endfunction
globals
constant key KEY_SWARM_UNIT
constant key KEY_SWARM_TARGET
constant integer SWARM_UNIT_STATE_NONE = 0
constant integer SWARM_UNIT_STATE_ATTACK = 1
constant integer SWARM_UNIT_STATE_RETURN = 2
endglobals
function interface SwarmTargetFilter takes Swarm swarm, unit filterUnit returns boolean
//===========================================================================
struct SwarmMember
unit swarmUnit = null
unit targetUnit = null
location targetLoc = null
integer state = SWARM_UNIT_STATE_NONE
method SetStateAttack takes unit target returns nothing
call ClearTargets()
set targetUnit = target
set state = SWARM_UNIT_STATE_ATTACK
endmethod
method SetStateReturn takes location target returns nothing
call ClearTargets()
set targetLoc = target
set state = SWARM_UNIT_STATE_RETURN
endmethod
private method ClearTargets takes nothing returns nothing
if (targetUnit != null) then
call HashTableAddInteger(udg_HashTable_UnitInfo, GetHandleId(targetUnit), KEY_SWARM_TARGET, -1, true)
endif
set targetUnit = null
call RemoveLocation(targetLoc)
endmethod
method onDestroy takes nothing returns nothing
call ClearTargets()
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(swarmUnit), KEY_SWARM_UNIT)
call KillUnit(swarmUnit)
endmethod
endstruct
//===========================================================================
struct Swarm
unit host = null
LinkedList_Int members = 0
integer maxAttackersPerTarget = 0
real aoe = 0.0
SwarmTargetFilter targetFilter
method AddMember takes unit newMember returns nothing
call EnsureList()
call CreateMember(newMember)
endmethod
method AddMembers takes group newMembers returns nothing
local integer size = BlzGroupGetSize(newMembers)
local integer i = 0
local unit pickedUnit = null
call EnsureList()
loop
exitwhen i >= size
set pickedUnit = BlzGroupUnitAt(newMembers, i)
call CreateMember(pickedUnit)
set i = i + 1
endloop
endmethod
method RemoveMember takes SwarmMember member returns nothing
local integer i = 0
local SwarmMember sm = 0
local LinkedListNode_Int node = LinkedListGetFirst(members)
call EnsureList()
loop
exitwhen node == 0
set sm = node.value
if (sm == member) then
if (LinkedListRemove(members, node)) then
call node.destroy()
endif
exitwhen true
endif
set node = node.next
endloop
endmethod
private method EnsureList takes nothing returns nothing
if (members == 0) then
set members = CreateLinkedList_Int()
endif
endmethod
private method CreateMember takes unit whichUnit returns SwarmMember
local SwarmMember member = SwarmMember.create()
set member.swarmUnit = whichUnit
call LinkedListAddLastInt(members, member)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_SWARM_UNIT, member)
return member
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
local LinkedListNode_Int node = 0
local SwarmMember member = 0
// Remove this swarm from the global array
loop
exitwhen i >= SwarmsCount
if (udg_IntArr_Swarms[i] == this) then
loop
exitwhen i >= SwarmsCount - 1
set udg_IntArr_Swarms[i] = udg_IntArr_Swarms[i + 1]
set i = i + 1
endloop
set SwarmsCount = SwarmsCount - 1
exitwhen true
endif
set i = i + 1
endloop
// Destroy all of the swarm's members
loop
exitwhen members.count == 0
set node = LinkedListRemoveLast(members)
set member = node.value
call member.destroy()
call node.destroy()
endloop
call DestroyLinkedList(members)
call KillUnit(host)
endmethod
endstruct
globals
constant real SWARM_AOE_BUFFER = 150.0
integer SwarmsCount = 0
Swarm bj_currentSwarm = 0
group bj_swarmTargets = null
endglobals
//===========================================================================
function SetSwarmingEnabled takes boolean enable returns nothing
if (enable) then
call EnableTrigger(gg_trg_Swarm_Loop)
call EnableTrigger(gg_trg_Swarm_Orders)
else
call DisableTrigger(gg_trg_Swarm_Loop)
call DisableTrigger(gg_trg_Swarm_Orders)
endif
endfunction
//===========================================================================
function CreateSwarm takes unit host, real aoe, SwarmTargetFilter targetFilter returns Swarm
local Swarm swarm = Swarm.create()
set swarm.host = host
set swarm.aoe = aoe
set swarm.targetFilter = targetFilter
set udg_IntArr_Swarms[SwarmsCount] = swarm
set SwarmsCount = SwarmsCount + 1
call SetSwarmingEnabled(true)
return swarm
endfunction
//===========================================================================
function GetEnumSwarm takes nothing returns Swarm
return bj_currentSwarm
endfunction
function FindSwarmTargetFilter takes nothing returns boolean
local Swarm swarm = bj_currentSwarm
local unit filter = GetFilterUnit()
if (swarm.maxAttackersPerTarget > 0 and LoadInteger(udg_HashTable_UnitInfo, GetHandleId(filter), KEY_SWARM_TARGET) >= swarm.maxAttackersPerTarget) then
return false
elseif (swarm.targetFilter != 0) then
return swarm.targetFilter.evaluate(swarm, filter)
endif
return true
endfunction
//===========================================================================
function FindSwarmTarget takes Swarm swarm returns unit
if (bj_swarmTargets == null) then
set bj_swarmTargets = CreateGroup()
call GroupEnumUnitsInRange(bj_swarmTargets, GetUnitX(swarm.host), GetUnitY(swarm.host), swarm.aoe + SWARM_AOE_BUFFER, Condition(function FindSwarmTargetFilter))
endif
return GroupPickRandomUnit(bj_swarmTargets)
endfunction
//===========================================================================
function UpdateSwarmMember takes Swarm swarm, SwarmMember member returns nothing
local unit target = null
local location loc = null
local integer lastState = member.state
if (GetUnitCurrentOrder(member.swarmUnit) == 0) then
set target = FindSwarmTarget(swarm)
if (lastState != SWARM_UNIT_STATE_ATTACK and target != null) then
call member.SetStateAttack(target)
call IssueTargetOrder(member.swarmUnit, "attackonce", target)
call HashTableAddInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_SWARM_TARGET, 1, true)
else
set loc = RandomPointInCircle(GetUnitX(swarm.host), GetUnitY(swarm.host), swarm.aoe)
call member.SetStateReturn(loc)
call IssuePointOrderLoc(member.swarmUnit, "move", loc)
endif
endif
endfunction
//===========================================================================
function UpdateSwarm takes Swarm swarm returns nothing
local SwarmMember swarmMember = 0
local LinkedListNode_Int node = LinkedListGetFirst(swarm.members)
local LinkedListNode_Int nodeTemp = 0
set bj_currentSwarm = swarm
loop
exitwhen node == 0
set swarmMember = node.value
if (UnitAlive(swarmMember.swarmUnit)) then
call UpdateSwarmMember(swarm, swarmMember)
set node = node.next
elseif (LinkedListRemove(swarm.members, node)) then
call swarmMember.destroy()
set nodeTemp = node
set node = node.next
call nodeTemp.destroy()
endif
endloop
set bj_currentSwarm = 0
if (swarm.members.count <= 0) then
call swarm.destroy()
endif
call DestroyGroup(bj_swarmTargets)
set bj_swarmTargets = null
endfunction
globals
constant real SWARM_LOOP_INTERVAL = 0.1
endglobals
function Trig_Swarm_Loop_Actions takes nothing returns nothing
local integer index = SwarmsCount - 1
local integer shiftIndex = 0
local Swarm swarm = 0
loop
exitwhen index < 0
set swarm = udg_IntArr_Swarms[index]
if (UnitAlive(swarm.host)) then
call UpdateSwarm(swarm)
else
set shiftIndex = index
loop
exitwhen shiftIndex >= SwarmsCount - 1
set udg_IntArr_Swarms[shiftIndex] = udg_IntArr_Swarms[shiftIndex + 1]
set shiftIndex = shiftIndex + 1
endloop
set SwarmsCount = SwarmsCount - 1
call swarm.destroy()
endif
set index = index - 1
endloop
if (SwarmsCount == 0) then
call SetSwarmingEnabled(false)
endif
endfunction
//===========================================================================
function InitTrig_Swarm_Loop takes nothing returns nothing
set gg_trg_Swarm_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Swarm_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Swarm_Loop, SWARM_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Swarm_Loop, function Trig_Swarm_Loop_Actions )
endfunction
function Trig_Swarm_Orders_Conditions takes nothing returns boolean
local SwarmMember member = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_SWARM_UNIT)
return member != 0
endfunction
function Trig_Swarm_Orders_Actions takes nothing returns nothing
local SwarmMember member = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_SWARM_UNIT)
local integer order = GetIssuedOrderId()
local unit targetUnit = null
local location targetLoc = null
if (member.state == SWARM_UNIT_STATE_ATTACK) then
set targetUnit = GetOrderTargetUnit()
if (order != String2OrderIdBJ("attackonce") or targetUnit != member.targetUnit) then
call IssueTargetOrder(member.swarmUnit, "attackonce", member.targetUnit)
endif
else
set targetLoc = GetOrderPointLoc()
if (order != String2OrderIdBJ("move") or CompareLocationsBJ(targetLoc, member.targetLoc) == false) then
call IssuePointOrderLoc(member.swarmUnit, "move", member.targetLoc)
endif
endif
endfunction
//===========================================================================
function InitTrig_Swarm_Orders takes nothing returns nothing
set gg_trg_Swarm_Orders = CreateTrigger( )
call DisableTrigger( gg_trg_Swarm_Orders )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Swarm_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Swarm_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Swarm_Orders, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Swarm_Orders, Condition( function Trig_Swarm_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Swarm_Orders, function Trig_Swarm_Orders_Actions )
endfunction
globals
constant key KEY_EXILE
constant key KEY_UNEXILE
endglobals
function ExileUnit takes unit whichUnit, boolean flag returns nothing
if (flag) then
call IssueImmediateOrder(whichUnit, "stop")
endif
call PauseUnit(whichUnit, flag)
call ShowUnit(whichUnit, not flag)
call SetUnitInvulnerable(whichUnit, flag)
endfunction
function ExileUnitTimerCallback takes UnitTimer ut returns nothing
call ExileUnit(ut.owner, true)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(ut.owner), KEY_EXILE)
endfunction
function UnexileUnitTimerCallback takes UnitTimer ut returns nothing
call ExileUnit(ut.owner, false)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(ut.owner), KEY_UNEXILE)
endfunction
function ExileUnitIn takes unit whichUnit, real delay returns nothing
local UnitTimer ut = LoadInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_EXILE)
if (ut == 0) then
set ut = CreateUnitTimer(whichUnit, true)
call SaveInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_EXILE, ut)
endif
call StartTimerPlus(ut, delay, ExileUnitTimerCallback)
endfunction
function ShowUnitIn takes unit whichUnit, real delay returns nothing
local UnitTimer ut = LoadInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_UNEXILE)
if (ut == 0) then
set ut = CreateUnitTimer(whichUnit, true)
call SaveInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_UNEXILE, ut)
endif
call StartTimerPlus(ut, delay, UnexileUnitTimerCallback)
endfunction
library CustomAuras requires LinkedList
function interface CustomAuraCallback takes CustomAura aura, group unitsInAura returns nothing
function interface CustomAuraEmitterCallback takes CustomAuraEmitter emitter, group unitsInRange returns nothing
function interface UnitCallback takes unit whichUnit returns nothing
function interface CustomAuraCondition takes CustomAuraEmitter emitter returns boolean
globals
constant hashtable HT_CUSTOM_AURAS = InitHashtable()
constant key KEY_CUSTOM_AURA
constant key KEY_ADDED_THIS_LOOP
CustomAura CURRENT_AURA = 0
endglobals
struct CustomAura
public real updateInterval = 0.0
public group unitsInsideAura = null
public timer updateTimer = null
public UnitCallback unitEnterCallback = 0
public UnitCallback unitLeaveCallback = 0
public CustomAuraCondition targetFilter = 0
public CustomAuraCondition emitterValidFilter = 0
public CustomAuraCallback updateCallback = 0
public LinkedList_Int emitters = 0
static method create takes nothing returns CustomAura
local CustomAura ca = CustomAura.allocate()
set ca.unitsInsideAura = CreateGroup()
set ca.updateTimer = CreateTimer()
call SaveInteger(HT_CUSTOM_AURAS, GetHandleId(ca.updateTimer), KEY_CUSTOM_AURA, ca)
return ca
endmethod
method onDestroy takes nothing returns nothing
call DestroyGroup(unitsInsideAura)
call emitters.destroy()
call RemoveSavedInteger(HT_CUSTOM_AURAS, GetHandleId(updateTimer), KEY_CUSTOM_AURA)
call DestroyTimer(updateTimer)
endmethod
endstruct
public function CreateCustomAura takes real updateInterval, UnitCallback unitEnters, UnitCallback unitLeaves, CustomAuraCondition targetFilter, CustomAuraCondition emitterValidFilter, CustomAuraCallback updateCallback returns CustomAura
local CustomAura aura = CustomAura.create()
set aura.updateInterval = updateInterval
set aura.unitEnterCallback = unitEnters
set aura.unitLeaveCallback = unitLeaves
set aura.targetFilter = targetFilter
set aura.emitterValidFilter = emitterValidFilter
set aura.updateCallback = updateCallback
set aura.emitters = CreateLinkedList_Int()
return aura
endfunction
struct CustomAuraEmitter extends ILinkedListNode
public unit emitter = null
public real areaOfEffect = 0.0
public CustomAuraEmitterCallback updateCallback = 0
public integer data = 0
static method create takes nothing returns CustomAuraEmitter
local CustomAuraEmitter emitter = CustomAuraEmitter.allocate()
return emitter
endmethod
method onDestroy takes nothing returns nothing
endmethod
endstruct
private function IsEmitterValid takes CustomAuraEmitter emitter, CustomAura aura returns boolean
if (not UnitAlive(emitter.emitter)) then
return false
elseif (aura.emitterValidFilter != 0 and not aura.emitterValidFilter.evaluate(emitter)) then
return false
endif
return true
endfunction
private function SqrDistanceBetweenUnits takes unit u1, unit u2 returns real
local real dx = GetUnitX(u2) - GetUnitX(u1)
local real dy = GetUnitY(u2) - GetUnitY(u1)
return dx * dx + dy * dy
endfunction
private function AddUnit takes nothing returns nothing
local unit whichUnit = GetEnumUnit()
if (not HaveSavedBoolean(HT_CUSTOM_AURAS, GetHandleId(whichUnit), CURRENT_AURA)) then
if (CURRENT_AURA.unitEnterCallback != 0) then
call CURRENT_AURA.unitEnterCallback.evaluate(whichUnit)
endif
call SaveBoolean(HT_CUSTOM_AURAS, GetHandleId(whichUnit), CURRENT_AURA, true)
endif
endfunction
private function RemoveUnit takes nothing returns nothing
local unit whichUnit = GetEnumUnit()
if (CURRENT_AURA.unitLeaveCallback != 0) then
call CURRENT_AURA.unitLeaveCallback.evaluate(GetEnumUnit())
endif
call RemoveSavedBoolean(HT_CUSTOM_AURAS, GetHandleId(whichUnit), CURRENT_AURA)
endfunction
private function UpdateLoop takes nothing returns nothing
local timer expired = GetExpiredTimer()
local CustomAura aura = LoadInteger(HT_CUSTOM_AURAS, GetHandleId(expired), KEY_CUSTOM_AURA)
local CustomAuraEmitter emitter = LinkedListGetFirst(aura.emitters)
local CustomAuraEmitter temp = 0
local real sqrRadius = emitter.areaOfEffect * emitter.areaOfEffect
local group unitsOutsideAura = CreateGroup()
local group unitsInsideAura = CreateGroup()
local group currentAOE = null
local unit picked = null
set CURRENT_AURA = aura
call GroupAddGroup(aura.unitsInsideAura, unitsOutsideAura)
loop
exitwhen emitter == 0
if (IsEmitterValid(emitter, aura)) then
// Emitter is valid
set currentAOE = GetUnitsInAOEOfUnitInt(emitter.emitter, emitter.areaOfEffect, aura.targetFilter, emitter)
if (emitter.updateCallback != 0) then
call emitter.updateCallback.evaluate(emitter, currentAOE)
endif
loop
set picked = FirstOfGroup(currentAOE)
exitwhen picked == null
call GroupRemoveUnit(unitsOutsideAura, picked)
call GroupRemoveUnit(currentAOE, picked)
call GroupAddUnit(unitsInsideAura, picked)
endloop
call DestroyGroup(currentAOE)
set emitter = emitter.next
else
// Emitter is invalid
set temp = emitter.next
call LinkedListRemove(aura.emitters, emitter)
call emitter.destroy()
set emitter = temp
endif
endloop
call ForGroupBJ(unitsInsideAura, function AddUnit)
call ForGroupBJ(unitsOutsideAura, function RemoveUnit)
if (aura.updateCallback != 0) then
call aura.updateCallback.evaluate(aura, unitsInsideAura)
endif
call DestroyGroup(aura.unitsInsideAura)
set aura.unitsInsideAura = unitsInsideAura
if (aura.emitters.count == 0) then
call PauseTimer(aura.updateTimer)
endif
call DestroyGroup(unitsOutsideAura)
endfunction
public function AddEmitter takes unit whichUnit, CustomAura aura, real aoe returns CustomAuraEmitter
local CustomAuraEmitter emitter = CustomAuraEmitter.create()
set emitter.emitter = whichUnit
set emitter.areaOfEffect = aoe
call LinkedListAddFirst(aura.emitters, emitter)
if (aura.emitters.count == 1) then
call TimerStart(aura.updateTimer, aura.updateInterval, true, function UpdateLoop)
endif
return emitter
endfunction
endlibrary
library Races initializer Init requires MathUtil
globals
private integer array PLAYER_RACES
private Race array RACES
private integer NUM_RACES = 0
private integer NUM_RACES_SELECTABLE = 3
private constant real GOLD_MINE_RANGE = 1000.0
private constant real WORKER_RADIUS = 72.0
endglobals
function interface PlaceStartingUnitsAction takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
struct Race
string name = null
string colorString = null
string aiScript = null
integer spellbringerUnitTypeId = 0
PlaceStartingUnitsAction placeStartingUnitsAction = 0
endstruct
private function AddRace takes string name, string colorString, integer spellbringerUnitTypeId, PlaceStartingUnitsAction startingUnits, string aiScript returns Race
local Race r = Race.create()
set r.name = name
set r.colorString = colorString
set r.aiScript = aiScript
set r.spellbringerUnitTypeId = spellbringerUnitTypeId
set r.placeStartingUnitsAction = startingUnits
set RACES[NUM_RACES] = r
set NUM_RACES = NUM_RACES + 1
return r
endfunction
function PlayerSetRace takes player p, integer raceId returns nothing
set PLAYER_RACES[GetPlayerId(p)] = raceId
endfunction
function PlayerGetRaceId takes player p returns integer
return PLAYER_RACES[GetPlayerId(p)]
endfunction
private function PlaceStartingUnits takes player p returns nothing
local Race r = PlayerGetRaceId(p)
local location startLoc = GetPlayerStartLocationLoc(p)
local unit mine = MeleeFindNearestMine(startLoc, GOLD_MINE_RANGE)
local real workerCenterX = GetLocationX(startLoc)
local real workerCenterY = GetLocationY(startLoc) + WORKER_RADIUS * 1.5
if (mine != null) then
set workerCenterX = GetLocationX(startLoc) + (GetUnitX(mine) - GetLocationX(startLoc)) * 0.5
set workerCenterY = GetLocationY(startLoc) + (GetUnitY(mine) - GetLocationY(startLoc)) * 0.5
endif
call r.placeStartingUnitsAction.evaluate(p, startLoc, workerCenterX, workerCenterY)
call RemoveLocation(startLoc)
endfunction
private function PlaceStartingUnits_Order takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
local unit hall = CreateUnit(p, SB_CITADEL, GetLocationX(loc), GetLocationY(loc), bj_UNIT_FACING)
local integer numWorkers = 5
local real angle = 0.0
local real angleStart = 90.0
local real angleInterval = 360.0 / numWorkers
local real x = 0.0
local real y = 0.0
loop
set numWorkers = numWorkers - 1
exitwhen numWorkers < 0
set angle = angleStart + angleInterval * numWorkers
set x = PolarProjectionX(workerCenterX, WORKER_RADIUS, angle)
set y = PolarProjectionY(workerCenterY, WORKER_RADIUS, angle)
call CreateUnit(p, SB_PEASANT, x, y, bj_UNIT_FACING)
endloop
endfunction
private function PlaceStartingUnits_Nature takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
local unit hall = CreateUnit(p, SB_HOLD, GetLocationX(loc), GetLocationY(loc), bj_UNIT_FACING)
local integer numWorkers = 3
local real angle = 0.0
local real angleStart = AngleBetweenPointsXY(GetLocationX(loc), GetLocationY(loc), workerCenterX, workerCenterY)
local real angleInterval = 360.0 / numWorkers
local real x = 0.0
local real y = 0.0
loop
set numWorkers = numWorkers - 1
exitwhen numWorkers < 0
set angle = angleStart + angleInterval * numWorkers
set x = PolarProjectionX(workerCenterX, WORKER_RADIUS, angle)
set y = PolarProjectionY(workerCenterY, WORKER_RADIUS, angle)
if (numWorkers == 0) then
call CreateUnit(p, SB_DENDROID_TREEHERD, x, y, bj_UNIT_FACING)
else
call CreateUnit(p, SB_ELVEN_ARTISAN, x, y, bj_UNIT_FACING)
endif
endloop
endfunction
private function PlaceStartingUnits_Death takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
local unit hall = CreateUnit(p, SB_NECROPOLIS, GetLocationX(loc), GetLocationY(loc), bj_UNIT_FACING)
local integer numWorkers = 3
local real angle = 0.0
local real angleStart = 90.0
local real angleInterval = 360.0 / numWorkers
local real x = 0.0
local real y = 0.0
loop
set numWorkers = numWorkers - 1
exitwhen numWorkers < 0
set angle = angleStart + angleInterval * numWorkers
set x = PolarProjectionX(workerCenterX, WORKER_RADIUS, angle)
set y = PolarProjectionY(workerCenterY, WORKER_RADIUS, angle)
call CreateUnit(p, SB_LOST_SOUL, x, y, bj_UNIT_FACING)
endloop
endfunction
private function PlaceStartingUnits_Magic takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
local unit hall = CreateUnit(p, SB_SANCTUM, GetLocationX(loc), GetLocationY(loc), bj_UNIT_FACING)
local integer numWorkers = 5
local real angle = 0.0
local real angleStart = 90.0
local real angleInterval = 360.0 / numWorkers
local real x = 0.0
local real y = 0.0
loop
set numWorkers = numWorkers - 1
exitwhen numWorkers < 0
set angle = angleStart + angleInterval * numWorkers
set x = PolarProjectionX(workerCenterX, WORKER_RADIUS, angle)
set y = PolarProjectionY(workerCenterY, WORKER_RADIUS, angle)
call CreateUnit(p, SB_SHAPER, x, y, bj_UNIT_FACING)
endloop
endfunction
private function PlaceStartingUnits_Chaos takes player p, location loc, real workerCenterX, real workerCenterY returns nothing
local unit hall = CreateUnit(p, SB_FORTRESS, GetLocationX(loc), GetLocationY(loc), bj_UNIT_FACING)
local integer numWorkers = 5
local real angle = 0.0
local real angleStart = 90.0
local real angleInterval = 360.0 / numWorkers
local real x = 0.0
local real y = 0.0
loop
set numWorkers = numWorkers - 1
exitwhen numWorkers < 0
set angle = angleStart + angleInterval * numWorkers
set x = PolarProjectionX(workerCenterX, WORKER_RADIUS, angle)
set y = PolarProjectionY(workerCenterY, WORKER_RADIUS, angle)
call CreateUnit(p, SB_SLAVE, x, y, bj_UNIT_FACING)
endloop
call CreateUnit(p, 'n00G', workerCenterX, workerCenterY, bj_UNIT_FACING)
endfunction
private function Init takes nothing returns nothing
call AddRace("None", "|cffa4a4a4", 0, 0, null)
call AddRace("Order", "|cffffe428", 'H001', PlaceStartingUnits_Order, "war3mapImported/SBOrderAI.ai")
call AddRace("Nature", "|cff00b105", 'H016', PlaceStartingUnits_Nature, null)
call AddRace("Death", "|cff6d0065", 'H00A', PlaceStartingUnits_Death, null)
call AddRace("Magic", "|cff92b5ff", 'H008', PlaceStartingUnits_Magic, null)
call AddRace("Chaos", "|cffff4600", 0, PlaceStartingUnits_Chaos, null)
endfunction
endlibrary
library SpellbringerAlerts initializer Init requires PlayerColors
globals
private real MINIMAP_PING_DURATION = 2.0
private hashtable HT_SB_ALERTS = InitHashtable()
endglobals
private function PlaySBAlert takes player whichPlayer, Color pingColor, sound snd, real x, real y returns nothing
if (whichPlayer == GetLocalPlayer()) then
call PingMinimapEx(x, y, MINIMAP_PING_DURATION, pingColor.r, pingColor.g, pingColor.b, false)
call SetCameraQuickPosition(x, y)
call StartSound(snd)
endif
endfunction
private function PlaySBAlertForObserver takes player whichPlayer, player owner, sound snd, real x, real y returns nothing
local Color pc = PlayerColor(owner)
call PlaySBAlert(whichPlayer, pc, snd, x, y)
endfunction
private function PlaySBAlertForAlly takes player whichPlayer, player owner, sound snd, real x, real y returns nothing
local Color pc = PlayerColorToColor(PLAYER_COLOR_CYAN)
call PlaySBAlert(whichPlayer, pc, snd, x, y)
endfunction
private function PlaySBAlertForEnemy takes player whichPlayer, player owner, sound snd, real x, real y returns nothing
local Color pc = PlayerColorToColor(PLAYER_COLOR_RED)
call PlaySBAlert(whichPlayer, pc, snd, x, y)
endfunction
function PlaySBAlertAtPos takes player owner, real x, real y, integer abilityId returns nothing
local string audioCue = LoadStr(HT_SB_ALERTS, abilityId, 0)
local sound snd = CreateSound(audioCue, false, false, true, 12700, 12700, "DefaultEAXON")
local player p = null
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYERS
set p = Player(i)
if (p == owner) then
// Do nothing
elseif (not IsVisibleToPlayer(x, y, p)) then
// Do nothing
elseif (IsPlayerObserver(p)) then
call PlaySBAlertForObserver(p, owner, snd, x, y)
elseif (IsPlayerAlly(p, owner)) then
call PlaySBAlertForAlly(p, owner, snd, x, y)
elseif (IsPlayerEnemy(p, owner)) then
call PlaySBAlertForEnemy(p, owner, snd, x, y)
endif
set i = i + 1
endloop
call KillSoundWhenDone(snd)
endfunction
function PlaySBAlertOnUnit takes player owner, unit whichUnit, integer abilityId returns nothing
call PlaySBAlertAtPos(owner, GetUnitX(whichUnit), GetUnitY(whichUnit), abilityId)
endfunction
private function Init takes nothing returns nothing
call SaveStr(HT_SB_ALERTS, SB_DIVINE_INTERVENTION, 0, "Abilities\\Spells\\Human\\DivineShield\\DivineShield.flac")
call SaveStr(HT_SB_ALERTS, SB_SUMMON_SPIRIT_DWARVES, 0, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.flac")
call SaveStr(HT_SB_ALERTS, SB_GAVEL_OF_JUDGMENT, 0, "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTargetWaveNonLoop1.flac")
call SaveStr(HT_SB_ALERTS, SB_AVATAR_OF_COMMAND, 0, "Abilities\\Spells\\Human\\HolyBolt\\HolyBolt.flac")
call SaveStr(HT_SB_ALERTS, SB_BATTLE_STANDARD, 0, "Abilities\\Spells\\Orc\\HealingWave\\HealingWave.flac")
call SaveStr(HT_SB_ALERTS, SB_RESURRECTION, 0, "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.flac")
call SaveStr(HT_SB_ALERTS, SB_ROOTGRASP, 0, "Abilities\\Spells\\NightElf\\EntanglingRoots\\EntanglingRootsTarget1.flac")
call SaveStr(HT_SB_ALERTS, SB_ENTWINE, 0, "Abilities\\Spells\\NightElf\\Root\\Root.flac")
call SaveStr(HT_SB_ALERTS, SB_MURDER_OF_CROWS, 0, "Units\\NightElf\\DruidOfTheTalon\\DruidOfTheTalonDeathAlternate1.flac")
call SaveStr(HT_SB_ALERTS, SB_BEAST_WITHIN, 0, "Abilities\\Spells\\NightElf\\BattleRoar\\BattleRoar.flac")
call SaveStr(HT_SB_ALERTS, SB_CLOUD_OF_MIST, 0, "Abilities\\Spells\\Other\\BreathOfFrost\\BreathOfFrost1.flac")
call SaveStr(HT_SB_ALERTS, SB_CALL_GREAT_STAG, 0, "Abilities\\Spells\\NightElf\\Tranquility\\Tranquility.flac")
call SaveStr(HT_SB_ALERTS, SB_BRINK_OF_DEATH, 0, "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt1.flac")
call SaveStr(HT_SB_ALERTS, SB_ANIMATE_DEAD, 0, "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.flac")
call SaveStr(HT_SB_ALERTS, SB_UNHOLY_CROWN, 0, "Abilities\\Spells\\Demon\\SoulPreservation\\SoulPreservation.flac")
call SaveStr(HT_SB_ALERTS, SB_ZOMBIE_PLAGUE, 0, "Abilities\\Weapons\\MeatwagonMissile\\MeatwagonMissileHit1.flac")
call SaveStr(HT_SB_ALERTS, SB_DEATH_BEAM, 0, "Abilities\\Spells\\Other\\Parasite\\Parasite.flac")
endfunction
endlibrary
function CreateSBDummyDependency takes player p returns unit
local unit dummy = CreateUnit(p, SB_SPELLBRINGER_DUMMY_DEPENDENCY, GetRectMaxX(GetPlayableMapRect()), GetRectMaxY(GetPlayableMapRect()), 0.0)
set udg_Unit_SpellbringerDependency[GetPlayerId(p)] = dummy
return dummy
endfunction
function Trig_Spellbringer_Init_PlayerLoop takes nothing returns nothing
local integer raceNumber = 1
local integer SBCount = 0
local integer SBLevel = 0
local group spellbringers = null
local unit spellbringer = null
loop
exitwhen raceNumber > udg_Int_RaceCount
set SBLevel = GetSpellbringerLevelByTech(GetEnumPlayer(), raceNumber)
set spellbringers = GetUnitsOfPlayerAndTypeId(GetEnumPlayer(), udg_UnitType_Spellbringer[raceNumber])
loop
set spellbringer = FirstOfGroup(spellbringers)
exitwhen spellbringer == null
set SBCount = SBCount + 1
call SetHeroLevelBJ(spellbringer, SBLevel, false)
call SuspendHeroXP(spellbringer, true)
call GroupRemoveUnit(spellbringers, spellbringer)
endloop
if (SBCount > 0) then
call CreateSBDummyDependency(GetEnumPlayer())
endif
call DestroyGroup(spellbringers)
set raceNumber = raceNumber + 1
endloop
endfunction
function Trig_Spellbringer_Init_Actions takes nothing returns nothing
local force players = GetPlayingPlayers(false, true, true)
call ForForce(players, function Trig_Spellbringer_Init_PlayerLoop)
call DestroyForce(players)
endfunction
//===========================================================================
function InitTrig_Spellbringer_Init takes nothing returns nothing
set gg_trg_Spellbringer_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Spellbringer_Init, function Trig_Spellbringer_Init_Actions )
endfunction
function Trig_Spellbringer_Enter_Actions takes nothing returns nothing
local integer SBLevel = 0
local integer raceNumber = 1
local player owner = GetOwningPlayer(GetEnteringUnit())
loop
exitwhen raceNumber > udg_Int_RaceCount
if (GetUnitTypeId(GetEnteringUnit()) == udg_UnitType_Spellbringer[raceNumber]) then
set SBLevel = GetSpellbringerLevelByTech(owner, raceNumber)
call SetHeroLevelBJ(GetEnteringUnit(), SBLevel, false)
call SuspendHeroXP(GetEnteringUnit(), true)
exitwhen true
endif
set raceNumber = raceNumber + 1
endloop
endfunction
//===========================================================================
function InitTrig_Spellbringer_Enter takes nothing returns nothing
set gg_trg_Spellbringer_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Spellbringer_Enter, GetPlayableMapRect() )
call TriggerAddAction( gg_trg_Spellbringer_Enter, function Trig_Spellbringer_Enter_Actions )
endfunction
function Trig_Spellbringer_Construction_Complete_Conditions takes nothing returns boolean
local integer raceNumber = 1
local integer ownerIndex = GetPlayerId(GetOwningPlayer(GetConstructedStructure()))
loop
exitwhen raceNumber > udg_Int_RaceCount
if (GetUnitTypeId(GetConstructedStructure()) == udg_UnitType_Spellbringer[raceNumber]) then
return udg_Unit_SpellbringerDependency[ownerIndex] == null
endif
set raceNumber = raceNumber + 1
endloop
return false
endfunction
function Trig_Spellbringer_Construction_Complete_Actions takes nothing returns nothing
call CreateSBDummyDependency(GetOwningPlayer(GetConstructedStructure()))
endfunction
//===========================================================================
function InitTrig_Spellbringer_Construction_Complete takes nothing returns nothing
set gg_trg_Spellbringer_Construction_Complete = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spellbringer_Construction_Complete, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
call TriggerAddCondition(gg_trg_Spellbringer_Construction_Complete, Condition(function Trig_Spellbringer_Construction_Complete_Conditions))
call TriggerAddAction( gg_trg_Spellbringer_Construction_Complete, function Trig_Spellbringer_Construction_Complete_Actions )
endfunction
function Trig_Spellbringer_Death_Actions takes nothing returns nothing
local integer raceNumber = GetSpellbringerRace(GetDyingUnit())
local unit sb = null
if (raceNumber != -1) then
set sb = GetDyingUnit()
call KillUnit(CreateUnit(GetOwningPlayer(sb), udg_UnitType_SpellbringerDeath[raceNumber], GetUnitX(sb), GetUnitY(sb), bj_UNIT_FACING))
call RemoveUnit(sb)
if (CountSpellbringersForPlayer(GetOwningPlayer(sb)) <= 0) then
call RemoveUnit(udg_Unit_SpellbringerDependency[GetPlayerId(GetOwningPlayer(sb))])
endif
endif
endfunction
//===========================================================================
function InitTrig_Spellbringer_Death takes nothing returns nothing
set gg_trg_Spellbringer_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spellbringer_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Spellbringer_Death, function Trig_Spellbringer_Death_Actions )
endfunction
function Trig_Spellbringer_Research_Complete_Actions takes nothing returns nothing
local integer raceNumber = 1
local integer SBLevel = 0
local group spellbringers = null
local unit spellbringer = null
loop
exitwhen raceNumber > udg_Int_RaceCount
if (GetResearched() == udg_TechType_Level3SBSpell[raceNumber]) then
set SBLevel = 3
elseif (GetResearched() == udg_TechType_Level2SBSpell[raceNumber]) then
set SBLevel = 2
endif
if (SBLevel > 1) then
set spellbringers = GetUnitsOfPlayerAndTypeId(GetOwningPlayer(GetResearchingUnit()), udg_UnitType_Spellbringer[raceNumber])
loop
set spellbringer = FirstOfGroup(spellbringers)
exitwhen spellbringer == null
call SuspendHeroXP(spellbringer, false)
call SetHeroLevelBJ(spellbringer, SBLevel, true)
call SuspendHeroXP(spellbringer, true)
call GroupRemoveUnit(spellbringers, spellbringer)
endloop
exitwhen true
endif
set raceNumber = raceNumber + 1
endloop
endfunction
//===========================================================================
function InitTrig_Spellbringer_Research_Complete takes nothing returns nothing
set gg_trg_Spellbringer_Research_Complete = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spellbringer_Research_Complete, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddAction( gg_trg_Spellbringer_Research_Complete, function Trig_Spellbringer_Research_Complete_Actions )
endfunction
scope GenericUnsummon initializer Init
private function OnSpellEffect takes nothing returns nothing
call KillUnit(GetSpellAbilityUnit())
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_UNSUMMON_GENERIC, function OnSpellEffect)
endfunction
endscope
scope CargoHoldDeath initializer Init
private function OnUnitUnloadedFromTransport takes TransportEvent ev returns nothing
if (not UnitAlive(ev.transport) and UnitHasAbility(ev.transport, SB_CARGO_HOLD_DEATH)) then
call KillUnit(ev.cargo)
endif
endfunction
private function Init takes nothing returns nothing
call EventSystem_RegisterEventListener(TransportTracking_OnUnitUnloadedFromTransport, OnUnitUnloadedFromTransport)
endfunction
endscope
function InitEject takes unit whichUnit returns nothing
call OrderTracking_TrackUnit(whichUnit)
call OrderTracking_FilterOutOrder(whichUnit, String2OrderIdBJ("berserk"))
call BlzUnitDisableAbility(whichUnit, SB_EJECT, true, true)
endfunction
globals
constant key KEY_EJECT
endglobals
function Trig_Eject_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_EJECT
endfunction
function Trig_Eject_Unload_Unit takes unit transport returns boolean
local group transportedUnits = GetLoadedUnits(transport)
local unit dropped = FirstOfGroup(transportedUnits)
local OrderTracking_Order lastOrder = 0
if (dropped != null) then
set lastOrder = OrderTracking_GetLastOrder(transport)
call IssueTargetOrder(transport, "unload", dropped)
if (lastOrder.orderId != SB_ORDER_STOP) then
call OrderTracking_ExecuteOrder(transport, lastOrder)
endif
endif
return CountUnitsInGroup(transportedUnits) > 1
endfunction
function Trig_Eject_Update takes UnitTimer ut returns nothing
if (not Trig_Eject_Unload_Unit(ut.owner)) then
call ut.destroy()
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(ut.owner), KEY_EJECT)
endif
endfunction
function Trig_Eject_Actions takes nothing returns nothing
local unit transport = GetSpellAbilityUnit()
local real dropoffInterval = GetUnitAbilityRealLevelField(transport, SB_EJECT, ABILITY_RLF_DURATION_HERO)
local UnitTimer ejectTimer = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(transport), KEY_EJECT)
local boolean needTimer = Trig_Eject_Unload_Unit(transport)
if (needTimer) then
if (ejectTimer == 0) then
set ejectTimer = CreateUnitTimer(transport, false)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(transport), KEY_EJECT, ejectTimer)
endif
call StartTimerPlusPeriodic(ejectTimer, 0.0, dropoffInterval, Trig_Eject_Update, 0)
endif
endfunction
//===========================================================================
function InitTrig_Eject takes nothing returns nothing
set gg_trg_Eject = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Eject, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Eject, Condition( function Trig_Eject_Conditions ) )
call TriggerAddAction( gg_trg_Eject, function Trig_Eject_Actions )
endfunction
function Trig_Eject_Init_Actions takes nothing returns nothing
local group ejectors = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_EJECT)
local unit picked = null
loop
set picked = FirstOfGroup(ejectors)
exitwhen picked == null
call InitEject(picked)
call GroupRemoveUnit(ejectors, picked)
endloop
call DestroyGroup(ejectors)
endfunction
//===========================================================================
function InitTrig_Eject_Init takes nothing returns nothing
set gg_trg_Eject_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Eject_Init, function Trig_Eject_Init_Actions )
endfunction
function Trig_Eject_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_EJECT)
endfunction
function Trig_Eject_Enters_Actions takes nothing returns nothing
call InitEject(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Eject_Enters takes nothing returns nothing
set gg_trg_Eject_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Eject_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Eject_Enters, Condition( function Trig_Eject_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Eject_Enters, function Trig_Eject_Enters_Actions )
endfunction
function Trig_Eject_Loaded_Conditions takes nothing returns boolean
return UnitHasAbility(GetTransportUnit(), SB_EJECT)
endfunction
function Trig_Eject_Unit_Unloaded takes TransportEvent ev returns nothing
local unit transport = ev.transport
local unit unloaded = ev.cargo
local group transported = null
if (UnitHasAbility(transport, SB_EJECT)) then
set transported = GetLoadedUnits(transport)
if (CountUnitsInGroup(transported) == 0) then
call BlzUnitDisableAbility(transport, SB_EJECT, true, true)
endif
endif
endfunction
function Trig_Eject_Loaded_Actions takes nothing returns nothing
local unit transport = GetTransportUnit()
local group transported = GetLoadedUnits(transport)
if (CountUnitsInGroup(transported) == 1) then
call BlzUnitDisableAbility(transport, SB_EJECT, false, false)
endif
endfunction
//===========================================================================
function InitTrig_Eject_Loaded takes nothing returns nothing
set gg_trg_Eject_Loaded = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Eject_Loaded, EVENT_PLAYER_UNIT_LOADED )
call TriggerAddCondition( gg_trg_Eject_Loaded, Condition( function Trig_Eject_Loaded_Conditions ) )
call TriggerAddAction( gg_trg_Eject_Loaded, function Trig_Eject_Loaded_Actions )
call EventSystem_RegisterEventListener(TransportTracking_OnUnitUnloadedFromTransport, Trig_Eject_Unit_Unloaded)
endfunction
function Trig_Damage_Resistance_Conditions takes nothing returns boolean
return UnitHasAbility(BlzGetEventDamageTarget(), SB_DAMAGE_RESISTANCE)
endfunction
function Trig_Damage_Resistance_Actions takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local real damageMultiplier = 1.0 - GetUnitAbilityRealLevelField(damaged, SB_DAMAGE_RESISTANCE, ABILITY_RLF_CASTING_TIME)
call BlzSetEventDamage(GetEventDamage() * damageMultiplier)
endfunction
//===========================================================================
function InitTrig_Damage_Resistance takes nothing returns nothing
set gg_trg_Damage_Resistance = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Damage_Resistance, EVENT_PLAYER_UNIT_DAMAGING )
call TriggerAddCondition( gg_trg_Damage_Resistance, Condition( function Trig_Damage_Resistance_Conditions ) )
call TriggerAddAction( gg_trg_Damage_Resistance, function Trig_Damage_Resistance_Actions )
call GateAbilityTrigger(gg_trg_Damage_Resistance, SB_DAMAGE_RESISTANCE, 0)
endfunction
function Trig_Remove_Hero_Glow_Init_Actions takes nothing returns nothing
local group heroGlowUnits = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_NO_HERO_GLOW)
local unit picked = null
loop
set picked = FirstOfGroup(heroGlowUnits)
exitwhen picked == null
call BlzShowUnitTeamGlow(picked, false)
call GroupRemoveUnit(heroGlowUnits, picked)
endloop
call DestroyGroup(heroGlowUnits)
endfunction
//===========================================================================
function InitTrig_Remove_Hero_Glow_Init takes nothing returns nothing
set gg_trg_Remove_Hero_Glow_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Remove_Hero_Glow_Init, function Trig_Remove_Hero_Glow_Init_Actions )
endfunction
function Trig_Remove_Hero_Glow_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_NO_HERO_GLOW)
endfunction
function Trig_Remove_Hero_Glow_Enters_Actions takes nothing returns nothing
call BlzShowUnitTeamGlow(GetEnteringUnit(), false)
endfunction
//===========================================================================
function InitTrig_Remove_Hero_Glow_Enters takes nothing returns nothing
set gg_trg_Remove_Hero_Glow_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Remove_Hero_Glow_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Remove_Hero_Glow_Enters, Condition( function Trig_Remove_Hero_Glow_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Remove_Hero_Glow_Enters, function Trig_Remove_Hero_Glow_Enters_Actions )
endfunction
globals
constant hashtable HT_OFFERING = InitHashtable()
constant real OFFERING_COST_INCREASE = 0.0
endglobals
struct Offering
unit spellbringer = null
integer totalMana = 0
real duration = 0.0
effect specialEffect = null
IntTimer updateTimer = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(specialEffect)
endmethod
endstruct
function CreateOffering takes unit altar, unit spellbringer returns Offering
local string effectModel = GetUnitAbilityStringLevelField(altar, SB_OFFERING, ABILITY_SLF_TARGET)
local Offering o = Offering.create()
set o.spellbringer = spellbringer
set o.totalMana = GetUnitAbilityIntegerLevelField(altar, SB_OFFERING, ABILITY_ILF_MANA_COST)
set o.duration = GetUnitAbilityRealLevelField(altar, SB_OFFERING, ABILITY_RLF_DURATION_NORMAL)
set o.specialEffect = AddSpecialEffectTarget(effectModel, spellbringer, "origin")
set o.updateTimer = CreateIntTimer(o, true)
return o
endfunction
function GetOfferingCost takes player p returns integer
return LoadInteger(HT_OFFERING, GetHandleId(p), 0)
endfunction
function OfferingUpdate takes IntTimer it returns nothing
local Offering o = it.owner
local real mana = DBZ(o.totalMana, o.duration, o.totalMana)
call SetUnitState(o.spellbringer, UNIT_STATE_MANA, GetUnitState(o.spellbringer, UNIT_STATE_MANA) + mana)
endfunction
function OfferingExpires takes IntTimer it returns nothing
local Offering o = it.owner
call o.destroy()
endfunction
function OfferingCooldownExpires takes UnitTimer it returns nothing
local unit altar = it.owner
call UnitRemoveAbility(altar, SB_OFFERING_DUMMY)
call BlzUnitDisableAbility(altar, SB_OFFERING, false, false)
endfunction
function ActivateOffering takes unit altar returns nothing
local player p = GetOwningPlayer(altar)
local group spellbringers = GetPlayerSpellbringers(p)
local group altars = GetUnitsOfPlayerWithAbility(p, SB_OFFERING)
local integer cost = R2I(GetUnitAbilityIntegerLevelField(altar, SB_OFFERING, ABILITY_ILF_GOLD_COST_NDT1) + OFFERING_COST_INCREASE)
local real cooldown = GetUnitAbilityRealLevelField(altar, SB_OFFERING, ABILITY_RLF_COOLDOWN)
local real period = 0.0
local unit picked = null
local Offering o = 0
local UnitTimer cooldownTimer = CreateUnitTimer(altar, true)
call SaveInteger(HT_OFFERING, GetHandleId(p), 0, cost)
loop
set picked = FirstOfGroup(spellbringers)
exitwhen picked == null
set o = CreateOffering(altar, picked)
set period = GetUnitAbilityRealLevelField(altar, SB_OFFERING, ABILITY_RLF_DURATION_HERO)
call StartTimerPlusPeriodic(o.updateTimer, o.duration, period, OfferingUpdate, OfferingExpires)
call GroupRemoveUnit(spellbringers, picked)
endloop
loop
set picked = FirstOfGroup(altars)
exitwhen picked == null
call SetUnitAbilityIntegerLevelField(picked, SB_OFFERING, ABILITY_ILF_GOLD_COST_NDT1, cost)
call GroupRemoveUnit(altars, picked)
endloop
call BlzUnitDisableAbility(altar, SB_OFFERING, true, true)
call UnitAddAbility(altar, SB_OFFERING_DUMMY)
call BlzStartUnitAbilityCooldown(altar, SB_OFFERING_DUMMY, cooldown)
call StartTimerPlus(cooldownTimer, cooldown, OfferingCooldownExpires)
call DestroyGroup(spellbringers)
call DestroyGroup(altars)
endfunction
function Trig_Offering_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_OFFERING
endfunction
function Trig_Offering_Actions takes nothing returns nothing
call ActivateOffering(GetSpellAbilityUnit())
endfunction
//===========================================================================
function InitTrig_Offering takes nothing returns nothing
set gg_trg_Offering = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Offering, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Offering, Condition( function Trig_Offering_Conditions ) )
call TriggerAddAction( gg_trg_Offering, function Trig_Offering_Actions )
endfunction
function Trig_Offering_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_OFFERING)
endfunction
function Trig_Offering_Enters_Actions takes nothing returns nothing
local unit entering = GetEnteringUnit()
local integer cost = GetOfferingCost(GetOwningPlayer(entering))
if (cost != 0) then
call SetUnitAbilityIntegerLevelField(entering, SB_OFFERING, ABILITY_ILF_GOLD_COST_NDT1, cost)
endif
endfunction
//===========================================================================
function InitTrig_Offering_Enters takes nothing returns nothing
set gg_trg_Offering_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Offering_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Offering_Enters, Condition( function Trig_Offering_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Offering_Enters, function Trig_Offering_Enters_Actions )
endfunction
function Trig_Offering_Allow_While_Researching_Conditions takes nothing returns boolean
return UnitHasAbility(GetTriggerUnit(), SB_OFFERING) or UnitHasAbility(GetTriggerUnit(), SB_OFFERING_DUMMY)
endfunction
function Trig_Offering_Allow_While_Researching_Actions takes nothing returns nothing
call BlzUnitDisableAbility(GetTriggerUnit(), SB_OFFERING, false, false)
call BlzUnitDisableAbility(GetTriggerUnit(), SB_OFFERING_DUMMY, false, false)
call BlzUnitDisableAbility(GetTriggerUnit(), 1098081641, false, false)
endfunction
//===========================================================================
function InitTrig_Offering_Allow_While_Researching takes nothing returns nothing
set gg_trg_Offering_Allow_While_Researching = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Offering_Allow_While_Researching, EVENT_PLAYER_UNIT_TRAIN_START )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Offering_Allow_While_Researching, EVENT_PLAYER_UNIT_RESEARCH_START )
call TriggerAddAction( gg_trg_Offering_Allow_While_Researching, function Trig_Offering_Allow_While_Researching_Actions )
endfunction
function Trig_AutoFire_Abilities_Conditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
if (UnitHasAbility(damager, SB_BOMBARD)) then
return true
elseif (UnitHasAbility(damager, SB_BARRAGE)) then
return true
endif
return false
endfunction
function Trig_AutoFire_Abilities_Actions takes nothing returns nothing
if (BlzGetEventDamageType() == DAMAGE_TYPE_FIRE) then
call BlzSetEventAttackType(ATTACK_TYPE_CHAOS)
call BlzSetEventDamageType(DAMAGE_TYPE_NORMAL)
endif
if (UnitHasAbility(BlzGetEventDamageTarget(), SB_CLOUD_OF_MIST_EVASION)) then
call BlzSetEventDamage(0.0)
endif
endfunction
//===========================================================================
function InitTrig_AutoFire_Abilities takes nothing returns nothing
local integer playerNum = 0
set gg_trg_AutoFire_Abilities = CreateTrigger( )
loop
exitwhen playerNum >= GetBJMaxPlayers() + 4
call TriggerRegisterPlayerUnitEventSimple( gg_trg_AutoFire_Abilities, Player(playerNum), EVENT_PLAYER_UNIT_DAMAGING )
set playerNum = playerNum + 1
endloop
call TriggerAddCondition(gg_trg_AutoFire_Abilities, Condition(function Trig_AutoFire_Abilities_Conditions))
call TriggerAddAction( gg_trg_AutoFire_Abilities, function Trig_AutoFire_Abilities_Actions )
endfunction
globals
constant key KEY_WORKER_MODE
constant integer array WorkerModeAbilities
constant integer WorkerModeAbilitiesCount = 2
endglobals
function Trig_Worker_Mode_Constants_Actions takes nothing returns nothing
set WorkerModeAbilities[0] = SB_WORKER_MODE_DENDROID_TREEHERD
set WorkerModeAbilities[1] = SB_WORKER_MODE_SAPLING
endfunction
//===========================================================================
function InitTrig_Worker_Mode_Constants takes nothing returns nothing
set gg_trg_Worker_Mode_Constants = CreateTrigger( )
call TriggerAddAction( gg_trg_Worker_Mode_Constants, function Trig_Worker_Mode_Constants_Actions )
endfunction
struct OrderRecord
integer orderId
location targetLoc
widget targetWidget
static method create takes integer orderId, location targetLoc, widget orderTarget returns OrderRecord
local OrderRecord rec = OrderRecord.allocate()
set rec.orderId = orderId
set rec.targetLoc = targetLoc
set rec.targetWidget = orderTarget
return rec
endmethod
method SetValues takes integer orderId, location targetLoc, widget orderTarget returns OrderRecord
set this.orderId = orderId
set this.targetLoc = targetLoc
set this.targetWidget = orderTarget
return this
endmethod
method IssueOrder takes unit whichUnit returns boolean
local string order = OrderId2String(this.orderId)
if (this.targetWidget != null) then
return IssueTargetOrder(whichUnit, order, this.targetWidget)
elseif (this.targetLoc != null) then
return IssuePointOrderLoc(whichUnit, order, this.targetLoc)
else
return IssueImmediateOrder(whichUnit, order)
endif
endmethod
endstruct
function IsWorkerModeUnit takes unit whichUnit returns boolean
local integer index = 0
loop
exitwhen index >= WorkerModeAbilitiesCount
if (UnitHasAbility(whichUnit, WorkerModeAbilities[index])) then
return IsUnitType(whichUnit, UNIT_TYPE_PEON)
endif
set index = index + 1
endloop
return false
endfunction
function IsWarriorModeUnit takes unit whichUnit returns boolean
local integer index = 0
loop
exitwhen index >= WorkerModeAbilitiesCount
if (UnitHasAbility(whichUnit, WorkerModeAbilities[index])) then
return not IsUnitType(whichUnit, UNIT_TYPE_PEON)
endif
set index = index + 1
endloop
return false
endfunction
function IsWorkerModeAbility takes integer abilityId returns boolean
local integer index = 0
loop
exitwhen index >= WorkerModeAbilitiesCount
if (abilityId == WorkerModeAbilities[index]) then
return true
endif
set index = index + 1
endloop
return false
endfunction
function Trig_Worker_Mode_Cast_Conditions takes nothing returns boolean
return IsWorkerModeAbility(GetSpellAbilityId())
endfunction
function Trig_Worker_Mode_Cast_Actions takes nothing returns nothing
local OrderRecord lastOrder = LoadInteger(udg_HashTable_Orders, GetHandleId(GetSpellAbilityUnit()), KEY_WORKER_MODE)
call AddUnitAnimationProperties(GetSpellAbilityUnit(), "alternate", false)
if (lastOrder != 0) then
call IssueImmediateOrder(GetSpellAbilityUnit(), "stop")
call lastOrder.IssueOrder(GetSpellAbilityUnit())
endif
endfunction
//===========================================================================
function InitTrig_Worker_Mode_Cast takes nothing returns nothing
set gg_trg_Worker_Mode_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Worker_Mode_Cast, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Worker_Mode_Cast, Condition( function Trig_Worker_Mode_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Worker_Mode_Cast, function Trig_Worker_Mode_Cast_Actions )
endfunction
function Trig_Worker_Mode_Auto_Toggle_Conditions takes nothing returns boolean
return IsWarriorModeUnit(GetOrderedUnit()) or IsWorkerModeUnit(GetOrderedUnit())
endfunction
function Trig_Worker_Mode_Auto_Toggle_Actions takes nothing returns nothing
local integer order = GetIssuedOrderId()
local OrderRecord lastOrder = 0
// Save the issued order as our "last" order
if (not (IsOrder(order, "stop") or IsOrder(order, "bearform") or IsOrder(order, "unbearform"))) then
set lastOrder = LoadInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_WORKER_MODE)
if (lastOrder == 0) then
set lastOrder = OrderRecord.create(order, GetOrderPointLoc(), GetOrderTarget())
call SaveInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_WORKER_MODE, lastOrder)
else
call lastOrder.SetValues(order, GetOrderPointLoc(), GetOrderTarget())
endif
endif
// Switch to a worker if a warrior is given worker commands
if (IsWarriorModeUnit(GetOrderedUnit())) then
if (IsOrder(order, "harvest") or IsOrder(order, "resumeharvesting") or IsOrder(order, "autoharvestlumber")) then
call IssueImmediateOrder(GetOrderedUnit(), "unbearform")
elseif (IsOrder(order, "smart") and (UnitHasAbility(GetOrderTargetUnit(), SB_GOLD_MINE_ABILITY) or IsTree(GetOrderTargetDestructable()))) then
call IssueImmediateOrder(GetOrderedUnit(), "unbearform")
elseif (String2UnitIdBJ(OrderId2StringBJ(order)) != 0) then
call IssueImmediateOrder(GetOrderedUnit(), "unbearform")
endif
endif
endfunction
//===========================================================================
function InitTrig_Worker_Mode_Auto_Toggle takes nothing returns nothing
set gg_trg_Worker_Mode_Auto_Toggle = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Worker_Mode_Auto_Toggle, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Worker_Mode_Auto_Toggle, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Worker_Mode_Auto_Toggle, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition( gg_trg_Worker_Mode_Auto_Toggle, Condition( function Trig_Worker_Mode_Auto_Toggle_Conditions ) )
call TriggerAddAction( gg_trg_Worker_Mode_Auto_Toggle, function Trig_Worker_Mode_Auto_Toggle_Actions )
endfunction
function Trig_Worker_Mode_Attack_Conditions takes nothing returns boolean
if (not IsWorkerModeUnit(GetAttacker())) then
return false
elseif (not IsUnitEnemy(GetAttackedUnitBJ(), GetOwningPlayer(GetAttacker()))) then
return false
endif
return true
endfunction
function Trig_Worker_Mode_Attack_Actions takes nothing returns nothing
call IssueImmediateOrder(GetAttacker(), "bearform")
endfunction
//===========================================================================
function InitTrig_Worker_Mode_Attack takes nothing returns nothing
set gg_trg_Worker_Mode_Attack = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Worker_Mode_Attack, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_Worker_Mode_Attack, Condition( function Trig_Worker_Mode_Attack_Conditions ) )
call TriggerAddAction( gg_trg_Worker_Mode_Attack, function Trig_Worker_Mode_Attack_Actions )
endfunction
library CustomSounds initializer Init
globals
constant hashtable HT_CUSTOM_SOUNDS = InitHashtable()
endglobals
private function OnUnitReadyCondition takes nothing returns boolean
return HaveSavedHandle(HT_CUSTOM_SOUNDS, GetTrainedUnitType(), 0)
endfunction
private function OnUnitReady takes nothing returns nothing
local unit trained = GetTrainedUnit()
local sound snd = LoadSoundHandle(HT_CUSTOM_SOUNDS, GetTrainedUnitType(), 0)
if (GetLocalPlayer() == GetOwningPlayer(GetTrainedUnit())) then
if (not GetSoundIsPlaying(snd)) then
call SetSoundPosition(snd, GetUnitX(trained), GetUnitY(trained), BlzGetUnitZ(trained))
call StartSound(snd)
endif
endif
endfunction
private function CreateReadySound takes string soundPath returns sound
local sound snd = CreateSound(soundPath, false, true, true, 1, 1, "DefaultEAXON")
call SetSoundChannel(snd, AUDIO_CHANNEL_UNIT_READY)
call SetSoundDistanceCutoff(snd, 3000.0)
call SetSoundDistances(snd, 100000, 100000)
return snd
endfunction
private function Init takes nothing returns nothing
local sound snd = null
local trigger readySoundTrigger = CreateTrigger()
set snd = CreateReadySound("Units\\Human\\Uther\\UtherPissed4.flac")
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_ENFORCER, 0, snd)
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_CRUSADER, 0, snd)
set snd = CreateReadySound("Units\\Creeps\\Wendigo\\WendigoYesAttack1.flac")
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_ZOMBIE_BUILD_DUMMY, 0, snd)
set snd = CreateReadySound("Buildings\\NightElf\\AncientOfWonder\\AncientofWonderYesAttack1.flac")
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_TREEHERD, 0, snd)
set snd = CreateReadySound("Units\\Undead\\KelThuzadLich\\KelThuzadPissed3.flac")
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_PHANTOM_CARRIAGE, 0, snd)
set snd = CreateReadySound("Units\\Demon\\Infernal\\InfernalPissed2.flac")
call SaveSoundHandle(HT_CUSTOM_SOUNDS, SB_SHAPER, 0, snd)
call TriggerAddCondition(readySoundTrigger, Condition(function OnUnitReadyCondition))
call TriggerAddAction(readySoundTrigger, function OnUnitReady)
call TriggerRegisterAnyUnitEventBJ(readySoundTrigger, EVENT_PLAYER_UNIT_TRAIN_FINISH)
endfunction
endlibrary
scope GoldBoosting initializer Init
globals
private constant hashtable HT = InitHashtable()
endglobals
private struct GoldMineRate
unit mine = null
real lastCheck = 0.0
real mineWorkerSpeed = 0.0
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(HT, GetHandleId(mine), 0)
endmethod
endstruct
private function GetOrCreateGoldMineRate takes unit mine returns GoldMineRate
local GoldMineRate rate = LoadInteger(HT, GetHandleId(mine), 0)
if (rate == 0) then
set rate = GoldMineRate.create()
set rate.mine = mine
call SaveInteger(HT, GetHandleId(mine), 0, rate)
endif
return rate
endfunction
private function OnMineGoldOrder takes GoldMineTracker_MiningEvent ev returns nothing
local GoldMineRate rate = GetOrCreateGoldMineRate(ev.mine)
endfunction
private function OnReturnGoldMineOrder takes GoldMineTracker_MiningEvent ev returns nothing
local GoldMineRate rate = 0
local real thisInterval = 0.0
local real elapsed = 0.0
local real desiredInterval = 0.0
if (GetPlayerController(GetOwningPlayer(ev.worker)) == MAP_CONTROL_USER) then
set rate = GetOrCreateGoldMineRate(ev.mine)
set elapsed = GetElapsedGameTime()
set thisInterval = elapsed - rate.lastCheck
set rate.lastCheck = elapsed
set desiredInterval = DBZ(5.0, GoldMineTracker_GetWorkerCount(ev.mine), 5.0)
call DisplayTextToPlayer(Player(0), 0, 0, R2S(thisInterval))
call DisplayTextToPlayer(Player(0), 0, 0, R2S(GetUnitMoveSpeed(ev.worker)))
endif
endfunction
private function Init takes nothing returns nothing
call EventSystem_RegisterEventListener(GoldMineTracker_OnMineGoldOrder, OnMineGoldOrder)
call EventSystem_RegisterEventListener(GoldMineTracker_OnReturnGoldOrder, OnReturnGoldMineOrder)
endfunction
endscope
scope GoldBoosting initializer Init
globals
private constant hashtable HT_GOLD_BOOSTING = InitHashtable()
private constant integer WINDED_CORRECTION_CYCLES = 6
private constant real CYCLE_TIMEOUT = 15.0
private constant real MAX_LEEWAY = 4.25
private constant real LEEWAY_ORDER_PUNISHMENT = 1.5
private constant real MIN_CYCLE_TIME = 4.25
private constant real WINDED_MS = 100.0
endglobals
private struct MiningCycle
unit worker = null
real leeway = MAX_LEEWAY
integer correctionCounter = 0
boolean punishedThisCycle = false
IntTimer cycleTimer = 0
method onDestroy takes nothing returns nothing
call cycleTimer.destroy()
endmethod
endstruct
private function GetMiningCycle takes unit whichUnit returns MiningCycle
return LoadInteger(HT_GOLD_BOOSTING, GetHandleId(whichUnit), 0)
endfunction
private function GetOrCreateMiningCycle takes unit whichUnit returns MiningCycle
local MiningCycle cycle = GetMiningCycle(whichUnit)
if (cycle == 0) then
set cycle = MiningCycle.create()
set cycle.worker = whichUnit
set cycle.cycleTimer = CreateIntTimer(cycle, false)
call SaveInteger(HT_GOLD_BOOSTING, GetHandleId(whichUnit), 0, cycle)
endif
return cycle
endfunction
private function CycleTimerExpires takes IntTimer it returns nothing
local MiningCycle cycle = it.owner
call UnitRemoveAbility(cycle.worker, SB_WINDED)
call UnitRemoveAbility(cycle.worker, SB_BUFF_WINDED)
call SetUnitMoveSpeed(cycle.worker, GetUnitDefaultMoveSpeed(cycle.worker))
call RemoveSavedInteger(HT_GOLD_BOOSTING, GetHandleId(cycle.worker), 0)
call cycle.destroy()
endfunction
private function IsUnitWinded takes unit whichUnit returns boolean
return UnitHasAbility(whichUnit, SB_WINDED)
endfunction
private function UpdateGoldBoostCorrection takes unit whichUnit returns nothing
local MiningCycle cycle = GetOrCreateMiningCycle(whichUnit)
local real defaultMS = GetUnitDefaultMoveSpeed(whichUnit)
local real targetMS = 0.0
if (IsUnitWinded(whichUnit)) then
set cycle.correctionCounter = cycle.correctionCounter - 1
else
call UnitAddAbility(whichUnit, SB_WINDED)
set cycle.correctionCounter = WINDED_CORRECTION_CYCLES
call WriteReal("GOLD BOOSTING DETECTED FROM " + GetPlayerName(GetOwningPlayer(whichUnit)) + "|r. Cycle time was ", TimerPlusGetElapsed(cycle.cycleTimer))
endif
set targetMS = WINDED_MS + (defaultMS - WINDED_MS) * (1 - DBZ(cycle.correctionCounter, WINDED_CORRECTION_CYCLES, 1.0))
call SetUnitMoveSpeed(whichUnit, targetMS)
if (cycle.correctionCounter == 0) then
call UnitRemoveAbility(whichUnit, SB_WINDED)
call UnitRemoveBuffBJ(SB_BUFF_WINDED, whichUnit)
endif
endfunction
private function OnMineGoldOrder takes GoldMineTracker_MiningEvent ev returns nothing
local MiningCycle cycle = GetOrCreateMiningCycle(ev.worker)
local integer miningState = GoldMineTracker_GetMiningState(ev.worker)
local real cycleTime = 0.0
if (ev.lastMiningState != miningState) then
set cycleTime = TimerPlusGetElapsed(cycle.cycleTimer)
if (cycleTime > 0) then
if (IsUnitWinded(ev.worker) or cycleTime + cycle.leeway < MIN_CYCLE_TIME) then
call UpdateGoldBoostCorrection(ev.worker)
endif
set cycle.leeway = RClamp(cycle.leeway + (cycleTime - MIN_CYCLE_TIME), 0.0, MIN_CYCLE_TIME)
endif
call StartTimerPlus(cycle.cycleTimer, CYCLE_TIMEOUT, CycleTimerExpires)
set cycle.punishedThisCycle = false
elseif (not cycle.punishedThisCycle) then
set cycle.leeway = RMaxBJ(cycle.leeway - LEEWAY_ORDER_PUNISHMENT, 0.0)
set cycle.punishedThisCycle = true
endif
endfunction
private function OnReturnGoldMineOrder takes GoldMineTracker_MiningEvent ev returns nothing
local MiningCycle cycle = GetOrCreateMiningCycle(ev.worker)
if (ev.lastMiningState == GoldMineTracker_MINING_STATE_RETURN and not cycle.punishedThisCycle) then
set cycle.leeway = RMaxBJ(cycle.leeway - LEEWAY_ORDER_PUNISHMENT, 0.0)
set cycle.punishedThisCycle = true
endif
endfunction
private function Init takes nothing returns nothing
call EventSystem_RegisterEventListener(GoldMineTracker_OnMineGoldOrder, OnMineGoldOrder)
call EventSystem_RegisterEventListener(GoldMineTracker_OnReturnGoldOrder, OnReturnGoldMineOrder)
endfunction
endscope
scope ResearchAutocastAbilities initializer Init
globals
private hashtable HT = InitHashtable()
endglobals
private struct Entry
integer abilityId = 0
string order = null
endstruct
private function AddEntry takes integer abilityId, integer techId, string order returns nothing
local Entry e = Entry.create()
set e.abilityId = abilityId
set e.order = order
call SaveInteger(HT, techId, 0, e)
endfunction
private function ResearchConditions takes nothing returns boolean
local integer techId = GetResearched()
return HaveSavedInteger(HT, techId, 0)
endfunction
private function ResearchActions takes nothing returns nothing
local integer techId = GetResearched()
local Entry e = LoadInteger(HT, techId, 0)
local group units = GetUnitsOfPlayerWithAbility(GetOwningPlayer(GetResearchingUnit()), e.abilityId)
local unit picked = null
loop
set picked = FirstOfGroup(units)
exitwhen picked == null
call IssueImmediateOrder(picked, e.order)
call GroupRemoveUnit(units, picked)
endloop
call DestroyGroup(units)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddCondition(t, Condition(function ResearchConditions))
call TriggerAddAction(t, function ResearchActions)
call AddEntry(SB_PUTREFY, SB_TECH_PUTREFY, "frostarmoron")
call AddEntry(SB_BLIGHT_SHOT, SB_TECH_BLIGHT_SHOT, "flamingarrows")
call AddEntry(SB_HOLD_THE_LINE, SB_TECH_HOLD_THE_LINE, "phaseshifton")
endfunction
endscope
function Trig_Expansion_Markers_Removal_Conditions takes nothing returns boolean
return IsUnitType(GetEnteringUnit(), UNIT_TYPE_TOWNHALL)
endfunction
function Trig_Expansion_Markers_Removal_Actions takes nothing returns nothing
local group expansionMarkers = CreateGroup()
local unit picked = null
call GroupAddGroup(udg_UnitGroup_ExpansionMarkers, expansionMarkers)
loop
set picked = FirstOfGroup(expansionMarkers)
exitwhen picked == null
if (DistanceBetweenUnits(picked, GetEnteringUnit()) <= 1.0) then
exitwhen true
endif
call GroupRemoveUnit(expansionMarkers, picked)
endloop
if (picked != null) then
if (GetElapsedGameTime() > 1.0) then
call PlaySoundForPlayer("Sound\\Interface\\GoodJob.flac", GetOwningPlayer(GetEnteringUnit()))
endif
call RemoveUnit(picked)
endif
endfunction
//===========================================================================
function InitTrig_Expansion_Markers_Removal takes nothing returns nothing
set gg_trg_Expansion_Markers_Removal = CreateTrigger( )
call DisableTrigger( gg_trg_Expansion_Markers_Removal )
call TriggerRegisterEnterRectSimple( gg_trg_Expansion_Markers_Removal, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Expansion_Markers_Removal, Condition( function Trig_Expansion_Markers_Removal_Conditions ) )
call TriggerAddAction( gg_trg_Expansion_Markers_Removal, function Trig_Expansion_Markers_Removal_Actions )
endfunction
function Trig_No_Collision_Init_Filter takes nothing returns boolean
return GetUnitAbilityLevel(GetFilterUnit(), SB_NO_COLLISION) > 0
endfunction
function Trig_No_Collision_Init_Actions takes nothing returns nothing
local group ncUnits = GetUnitsInRectMatching(GetPlayableMapRect(), Condition(function Trig_No_Collision_Init_Filter))
local unit ncUnit = FirstOfGroup(ncUnits)
loop
exitwhen ncUnit == null
call SetUnitPathing(ncUnit, false)
call GroupRemoveUnit(ncUnits, ncUnit)
set ncUnit = FirstOfGroup(ncUnits)
endloop
call DestroyGroup(ncUnits)
endfunction
//===========================================================================
function InitTrig_No_Collision_Init takes nothing returns nothing
set gg_trg_No_Collision_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_No_Collision_Init, function Trig_No_Collision_Init_Actions )
endfunction
function Trig_No_Collision_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_NO_COLLISION)
endfunction
function Trig_No_Collision_Enters_Actions takes nothing returns nothing
call SetUnitPathing(GetEnteringUnit(), false)
endfunction
//===========================================================================
function InitTrig_No_Collision_Enters takes nothing returns nothing
set gg_trg_No_Collision_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_No_Collision_Enters, GetPlayableMapRect() )
call TriggerAddCondition(gg_trg_No_Collision_Enters, Condition(function Trig_No_Collision_Enters_Conditions))
call TriggerAddAction( gg_trg_No_Collision_Enters, function Trig_No_Collision_Enters_Actions )
endfunction
scope GoldMineEffects initializer Init
private function GoldMineWorkersChanged takes GoldMineTracker_MiningEvent ev returns nothing
local unit mine = ev.mine
local integer miningCount = GoldMineTracker_GetWorkerCount(mine)
call AddUnitAnimationProperties(mine, "upgrade", miningCount > 0)
call AddUnitAnimationProperties(mine, "first", miningCount == 1)
call AddUnitAnimationProperties(mine, "second", miningCount == 2)
call AddUnitAnimationProperties(mine, "third", miningCount == 3)
call AddUnitAnimationProperties(mine, "fourth", miningCount == 4)
call AddUnitAnimationProperties(mine, "fifth", miningCount == 5)
call AddUnitAnimationProperties(mine, "sixth", miningCount > 5)
if(miningCount >= 5)then
call UnitAddAbility(mine, 'Sfgm')
else
call UnitRemoveAbility(mine, 'Sfgm')
endif
endfunction
private function Init takes nothing returns nothing
call EventSystem_RegisterEventListener(GoldMineTracker_OnAfterWorkerAddedToMine, GoldMineWorkersChanged)
call EventSystem_RegisterEventListener(GoldMineTracker_OnAfterWorkerRemovedFromMine, GoldMineWorkersChanged)
endfunction
endscope
function Trig_Divine_Intervention_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_DIVINE_INTERVENTION
endfunction
function Trig_Divine_Intervention_Actions takes nothing returns nothing
call PlaySBAlertOnUnit(GetOwningPlayer(GetSpellAbilityUnit()), GetSpellTargetUnit(), GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Divine_Intervention takes nothing returns nothing
set gg_trg_Divine_Intervention = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Divine_Intervention, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Divine_Intervention, Condition( function Trig_Divine_Intervention_Conditions ) )
call TriggerAddAction( gg_trg_Divine_Intervention, function Trig_Divine_Intervention_Actions )
endfunction
function InitSpiritDwarf takes unit dwarf returns nothing
local effect cloud = AddSpecialEffectTarget("war3mapImported\\MistAura.mdx", dwarf, "origin")
call ChangeUnitColor(dwarf, 255, 255, 255, 180)
call BlzSetSpecialEffectAlpha( cloud, 100 )
call BlzSetSpecialEffectScale( cloud, 0.50 )
endfunction
function Trig_Spirit_Dwarf_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SUMMON_SPIRIT_DWARVES
endfunction
function Trig_Spirit_Dwarf_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local integer count = R2I(GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_HERO))
local integer index = 0
local real x = 0.0
local real y = 0.0
local real angleInterval = DBZ(360.0, count, 0.0)
local unit dwarf = null
loop
exitwhen index >= count
set x = PolarProjectionX(GetUnitX(target), BlzGetUnitCollisionSize(target) + 16.0, angleInterval * index)
set y = PolarProjectionY(GetUnitY(target), BlzGetUnitCollisionSize(target) + 16.0, angleInterval * index)
set dwarf = CreateUnit(GetOwningPlayer(caster), SB_SPIRIT_DWARF, x, y, AngleBetweenPointsXY(x, y, GetUnitX(target), GetUnitY(target)))
call UnitApplyTimedLife(dwarf, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call AddSpecialEffectOneShot("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", x, y)
if (IsUnitType(target, UNIT_TYPE_MECHANICAL) and GetUnitLifePercent(target) < 100.0) then
call IssueTargetOrder(dwarf, "repair", target)
else
call IssueTargetOrder(dwarf, "smart", target)
endif
set index = index + 1
endloop
call PlaySBAlertOnUnit(GetOwningPlayer(caster), target, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Spirit_Dwarf_Cast takes nothing returns nothing
set gg_trg_Spirit_Dwarf_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spirit_Dwarf_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spirit_Dwarf_Cast, Condition( function Trig_Spirit_Dwarf_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Spirit_Dwarf_Cast, function Trig_Spirit_Dwarf_Cast_Actions )
endfunction
function Trig_Spirit_Dwarf_Effects_Init_Loop takes nothing returns nothing
call InitSpiritDwarf(GetEnumUnit())
endfunction
function Trig_Spirit_Dwarf_Effects_Init_Actions takes nothing returns nothing
local group dwarves = GetUnitsOfTypeIdAll(SB_SPIRIT_DWARF)
call ForGroup(dwarves, function Trig_Spirit_Dwarf_Effects_Init_Loop)
call DestroyGroup(dwarves)
endfunction
//===========================================================================
function InitTrig_Spirit_Dwarf_Effects_Init takes nothing returns nothing
set gg_trg_Spirit_Dwarf_Effects_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Spirit_Dwarf_Effects_Init, function Trig_Spirit_Dwarf_Effects_Init_Actions )
endfunction
function Trig_Spirit_Dwarf_Effects_Enter_Conditions takes nothing returns boolean
return GetUnitTypeId(GetEnteringUnit()) == SB_SPIRIT_DWARF
endfunction
function Trig_Spirit_Dwarf_Effects_Enter_Actions takes nothing returns nothing
call InitSpiritDwarf(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Spirit_Dwarf_Effects_Enter takes nothing returns nothing
set gg_trg_Spirit_Dwarf_Effects_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Spirit_Dwarf_Effects_Enter, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Spirit_Dwarf_Effects_Enter, Condition( function Trig_Spirit_Dwarf_Effects_Enter_Conditions ) )
call TriggerAddAction( gg_trg_Spirit_Dwarf_Effects_Enter, function Trig_Spirit_Dwarf_Effects_Enter_Actions )
endfunction
function Trig_Spirit_Dwarf_Dies_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_SPIRIT_DWARF
endfunction
function Trig_Spirit_Dwarf_Dies_Actions takes nothing returns nothing
call AddSpecialEffectOneShot("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl", GetUnitX(GetDyingUnit()), GetUnitY(GetDyingUnit()))
call RemoveUnit(GetDyingUnit())
endfunction
//===========================================================================
function InitTrig_Spirit_Dwarf_Dies takes nothing returns nothing
set gg_trg_Spirit_Dwarf_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spirit_Dwarf_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Spirit_Dwarf_Dies, Condition( function Trig_Spirit_Dwarf_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Spirit_Dwarf_Dies, function Trig_Spirit_Dwarf_Dies_Actions )
endfunction
globals
constant real GAVEL_OF_JUDGMENT_UPDATE_INTERVAL = 0.01
constant real GAVEL_OF_JUDGMENT_HIT_DELAY = 0.8
constant real GAVEL_OF_JUDGMENT_FADE_IN_DURATION = 0.5
endglobals
struct GavelOfJudgment
unit host = null
player castingPlayer = null
location loc = null
real fadeDurationRemaining = GAVEL_OF_JUDGMENT_FADE_IN_DURATION
string hitModel = null
effect targetEffect = null
effect hitEffect = null
method onDestroy takes nothing returns nothing
call RemoveLocation(loc)
call DestroyEffect(targetEffect)
call DestroyEffect(hitEffect)
endmethod
endstruct
function CreateGavelOfJudgment takes unit caster, unit target returns GavelOfJudgment
local string targetModel = GetUnitAbilityStringLevelField(caster, SB_GAVEL_OF_JUDGMENT, ABILITY_SLF_EFFECT)
local GavelOfJudgment g = GavelOfJudgment.create()
set g.loc = GetUnitLoc(target)
set g.hitModel = GetUnitAbilityStringLevelField(caster, SB_GAVEL_OF_JUDGMENT, ABILITY_SLF_AREA_EFFECT)
set g.host = target
set g.castingPlayer = GetOwningPlayer(caster)
set g.targetEffect = AddSpecialEffectLoc(targetModel, g.loc)
call BlzPlaySpecialEffect(g.targetEffect, ANIM_TYPE_STAND)
call BlzSetSpecialEffectScale(g.targetEffect, 2.0)
call BlzSetSpecialEffectAlpha(g.targetEffect, 0)
return g
endfunction
function Trig_Judgment_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_GAVEL_OF_JUDGMENT
endfunction
function Trig_Judgment_Hit_Update takes IntTimer it returns nothing
local GavelOfJudgment gavel = it.owner
if (UnitAlive(gavel.host)) then
call MoveLocation(gavel.loc, GetUnitX(gavel.host), GetUnitY(gavel.host))
call BlzSetSpecialEffectX(gavel.targetEffect, GetLocationX(gavel.loc))
call BlzSetSpecialEffectY(gavel.targetEffect, GetLocationY(gavel.loc))
call BlzSetSpecialEffectZ(gavel.targetEffect, GetLocationZ(gavel.loc))
call BlzSetSpecialEffectX(gavel.hitEffect, GetLocationX(gavel.loc))
call BlzSetSpecialEffectY(gavel.hitEffect, GetLocationY(gavel.loc))
call BlzSetSpecialEffectZ(gavel.hitEffect, GetLocationZ(gavel.loc))
endif
endfunction
function Trig_Judgment_Hit takes IntTimer it returns nothing
local GavelOfJudgment gavel = it.owner
local unit dummy = DummyCastPoint(gavel.castingPlayer, GetLocationX(gavel.loc), GetLocationY(gavel.loc), GetLocationX(gavel.loc), GetLocationY(gavel.loc), SB_GAVEL_OF_JUDGMENT_HIDDEN_CASTER, "silence")
local real aoe = GetUnitAbilityRealLevelField(dummy, SB_GAVEL_OF_JUDGMENT_HIDDEN_CASTER, ABILITY_RLF_AREA_OF_EFFECT)
call TerrainDeformationRippleBJ(0.25, false, gavel.loc, aoe, aoe, 50.0, 0.125, aoe)
call it.destroy()
call gavel.destroy()
endfunction
function Trig_Judgment_Delay_Update takes IntTimer it returns nothing
local GavelOfJudgment gavel = it.owner
set gavel.fadeDurationRemaining = RMaxBJ(gavel.fadeDurationRemaining - TimerPlusGetElapsed(it), 0.0)
call BlzSetSpecialEffectAlpha(gavel.targetEffect, R2I((1.0 - DBZ(gavel.fadeDurationRemaining, GAVEL_OF_JUDGMENT_FADE_IN_DURATION, 1.0)) * 255))
if (UnitAlive(gavel.host)) then
call MoveLocation(gavel.loc, GetUnitX(gavel.host), GetUnitY(gavel.host))
call BlzSetSpecialEffectX(gavel.targetEffect, GetLocationX(gavel.loc))
call BlzSetSpecialEffectY(gavel.targetEffect, GetLocationY(gavel.loc))
call BlzSetSpecialEffectZ(gavel.targetEffect, GetLocationZ(gavel.loc))
endif
endfunction
function Trig_Judgment_Delay_Ends takes IntTimer it returns nothing
local GavelOfJudgment gavel = it.owner
set gavel.hitEffect = AddSpecialEffectLoc(gavel.hitModel, gavel.loc)
call StartTimerPlusPeriodic(it, GAVEL_OF_JUDGMENT_HIT_DELAY, GAVEL_OF_JUDGMENT_UPDATE_INTERVAL, Trig_Judgment_Hit_Update, Trig_Judgment_Hit)
endfunction
function Trig_Judgment_Actions takes nothing returns nothing
local GavelOfJudgment gavel = CreateGavelOfJudgment(GetSpellAbilityUnit(), GetSpellTargetUnit())
local real delay = GetUnitAbilityRealLevelField(GetSpellAbilityUnit(), GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local IntTimer t = CreateIntTimer(gavel, false)
call PlaySBAlertOnUnit(GetOwningPlayer(GetSpellAbilityUnit()), GetSpellTargetUnit(), GetSpellAbilityId())
call StartIntTimerPeriodic(t, delay, GAVEL_OF_JUDGMENT_UPDATE_INTERVAL, Trig_Judgment_Delay_Update, Trig_Judgment_Delay_Ends)
endfunction
//===========================================================================
function InitTrig_Judgment takes nothing returns nothing
set gg_trg_Judgment = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Judgment, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Judgment, Condition(function Trig_Judgment_Conditions))
call TriggerAddAction(gg_trg_Judgment, function Trig_Judgment_Actions)
endfunction
globals
constant key KEY_AVATAR_OF_COMMAND
endglobals
function Trig_Avatar_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SUMMON_AVATAR_OF_COMMAND
endfunction
function Trig_Avatar_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local unit avatar = null
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local string effectModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_SPECIAL)
call ExileUnit(target, true)
set avatar = CreateUnit(GetOwningPlayer(target), SB_AVATAR_OF_COMMAND, GetUnitX(target), GetUnitY(target), GetUnitFacing(target))
call AddSpecialEffectTargetOneShot(effectModel, avatar, "origin")
call UnitApplyTimedLife(avatar, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call SaveUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_AVATAR_OF_COMMAND, target)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), avatar, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Avatar_Cast takes nothing returns nothing
set gg_trg_Avatar_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Avatar_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Avatar_Cast, Condition( function Trig_Avatar_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Avatar_Cast, function Trig_Avatar_Cast_Actions )
endfunction
function Trig_Avatar_Death_Conditions takes nothing returns boolean
return HaveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(GetDyingUnit()), KEY_AVATAR_OF_COMMAND)
endfunction
function Trig_Avatar_Death_Actions takes nothing returns nothing
local unit avatar = GetDyingUnit()
local unit exiledUnit = LoadUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_AVATAR_OF_COMMAND)
if (exiledUnit != null) then
call SetUnitX(exiledUnit, GetUnitX(avatar))
call SetUnitY(exiledUnit, GetUnitY(avatar))
call ExileUnit(exiledUnit, false)
endif
call RemoveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_AVATAR_OF_COMMAND)
endfunction
//===========================================================================
function InitTrig_Avatar_Death takes nothing returns nothing
set gg_trg_Avatar_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Avatar_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Avatar_Death, Condition( function Trig_Avatar_Death_Conditions ) )
call TriggerAddAction( gg_trg_Avatar_Death, function Trig_Avatar_Death_Actions )
endfunction
globals
key KEY_BATTLE_STANDARD
endglobals
function Trig_Battle_Standard_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BATTLE_STANDARD
endfunction
function Trig_Battle_Standard_Cast_CollectionFilter takes unit flag, unit filter returns boolean
if (not IsUnitAlly(flag, GetOwningPlayer(filter))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Battle_Standard_Cast_OnCollectFlag takes unit flag, unit collector returns nothing
call UnitAddAbilityBJ(SB_BATTLE_STANDARD_AURA, collector)
call ShowUnitHide(flag)
call SaveUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(flag), KEY_BATTLE_STANDARD, collector)
call SaveUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(collector), KEY_BATTLE_STANDARD, flag)
endfunction
function Trig_Battle_Standard_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local unit flag = CreateUnit(GetOwningPlayer(caster), SB_BATTLE_STANDARD_UNIT, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
local real duration = GetUnitAbilityRealLevelField(caster, SB_BATTLE_STANDARD, ABILITY_RLF_DURATION_NORMAL)
call UnitApplyTimedLifeBJ(duration, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, flag)
call Trig_Battle_Standard_Cast_OnCollectFlag(flag, target)
call ItemUnit_AddItemUnit(flag, Trig_Battle_Standard_Cast_CollectionFilter, Trig_Battle_Standard_Cast_OnCollectFlag)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), target, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Battle_Standard_Cast takes nothing returns nothing
set gg_trg_Battle_Standard_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Battle_Standard_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Battle_Standard_Cast, Condition( function Trig_Battle_Standard_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Battle_Standard_Cast, function Trig_Battle_Standard_Cast_Actions )
endfunction
function Trig_Battle_Standard_Dies_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_BATTLE_STANDARD_UNIT
endfunction
function Trig_Battle_Standard_Dies_Actions takes nothing returns nothing
local unit flag = GetDyingUnit()
local unit flagCarrier = LoadUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(flag), KEY_BATTLE_STANDARD)
if (flagCarrier != null) then
call RemoveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(flag), KEY_BATTLE_STANDARD)
call RemoveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(flagCarrier), KEY_BATTLE_STANDARD)
if (UnitHasAbility(flagCarrier, SB_BATTLE_STANDARD_AURA)) then
call UnitRemoveAbility(flagCarrier, SB_BATTLE_STANDARD_AURA)
endif
endif
endfunction
//===========================================================================
function InitTrig_Battle_Standard_Dies takes nothing returns nothing
set gg_trg_Battle_Standard_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Battle_Standard_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Battle_Standard_Dies, Condition( function Trig_Battle_Standard_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Battle_Standard_Dies, function Trig_Battle_Standard_Dies_Actions )
endfunction
function Trig_Battle_Standard_Carrier_Dies_Conditions takes nothing returns boolean
return UnitHasAbility(GetDyingUnit(), SB_BATTLE_STANDARD_AURA)
endfunction
function Trig_Battle_Standard_Carrier_Dies_Actions takes nothing returns nothing
local unit flagCarrier = GetDyingUnit()
local unit flag = LoadUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(flagCarrier), KEY_BATTLE_STANDARD)
call SetUnitX(flag, GetUnitX(flagCarrier))
call SetUnitY(flag, GetUnitY(flagCarrier))
call ShowUnitShow(flag)
endfunction
//===========================================================================
function InitTrig_Battle_Standard_Carrier_Dies takes nothing returns nothing
set gg_trg_Battle_Standard_Carrier_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Battle_Standard_Carrier_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Battle_Standard_Carrier_Dies, Condition( function Trig_Battle_Standard_Carrier_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Battle_Standard_Carrier_Dies, function Trig_Battle_Standard_Carrier_Dies_Actions )
endfunction
function InitArchangelOfLife takes unit angel returns nothing
call ChangeUnitColor(angel, 255, 255, 128, 128)
endfunction
function Trig_Resurrection_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RESURRECTION
endfunction
function Trig_Resurrection_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local unit angel = CreateUnit(GetOwningPlayer(caster), SB_ARCHANGEL_OF_LIFE, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
call UnitApplyTimedLife(angel, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call AddSpecialEffectOneShot("Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl", GetUnitX(angel), GetUnitY(angel))
call PlaySBAlertOnUnit(GetOwningPlayer(caster), angel, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Resurrection_Cast takes nothing returns nothing
set gg_trg_Resurrection_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Resurrection_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Resurrection_Cast, Condition( function Trig_Resurrection_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Resurrection_Cast, function Trig_Resurrection_Cast_Actions )
endfunction
function Trig_Archangel_Init_Loop takes nothing returns nothing
call InitArchangelOfLife(GetEnumUnit())
endfunction
function Trig_Archangel_Init_Actions takes nothing returns nothing
local group angels = GetUnitsOfTypeIdAll(SB_ARCHANGEL_OF_LIFE)
call ForGroup(angels, function Trig_Archangel_Init_Loop)
call DestroyGroup(angels)
endfunction
//===========================================================================
function InitTrig_Archangel_Init takes nothing returns nothing
set gg_trg_Archangel_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Archangel_Init, function Trig_Archangel_Init_Actions )
endfunction
function Trig_Archangel_Enters_Conditions takes nothing returns boolean
return GetUnitTypeId(GetEnteringUnit()) == SB_ARCHANGEL_OF_LIFE
endfunction
function Trig_Archangel_Enters_Actions takes nothing returns nothing
call InitArchangelOfLife(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Archangel_Enters takes nothing returns nothing
set gg_trg_Archangel_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Archangel_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Archangel_Enters, Condition( function Trig_Archangel_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Archangel_Enters, function Trig_Archangel_Enters_Actions )
endfunction
function Trig_Archangel_Dies_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_ARCHANGEL_OF_LIFE
endfunction
function Trig_Archangel_Dies_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
local real deathTime = BlzGetUnitRealField(dying, UNIT_RF_DEATH_TIME)
if (GetKillingUnit() == null) then
call AddSpecialEffectOneShot("Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl", GetUnitX(dying), GetUnitY(dying))
call RemoveUnit(dying)
else
call SetUnitFlyHeight(dying, 0.0, BlzGetUnitRealField(dying, UNIT_RF_FLY_HEIGHT))
call ChangeUnitAlphaOverTime(dying, deathTime * 0.5, deathTime * 0.5, 0)
endif
endfunction
//===========================================================================
function InitTrig_Archangel_Dies takes nothing returns nothing
set gg_trg_Archangel_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Archangel_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Archangel_Dies, Condition( function Trig_Archangel_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Archangel_Dies, function Trig_Archangel_Dies_Actions )
endfunction
scope TowerShields initializer Init
private function BlockConditions takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
if (not UnitHasAbility(damaged, SB_TOWER_SHIELDS)) then
return false
elseif (BlzGetUnitAbilityCooldownRemaining(damaged, SB_TOWER_SHIELDS) > 0.0) then
return false
elseif (not IsUnitEnemy(damaged, GetOwningPlayer(damager))) then
return false
elseif (not (BlzGetEventIsAttack())) then
return false
elseif (GetEventDamage() <= 0) then
return false
endif
return true
endfunction
private function OnBlock takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
local string casterVfx = GetUnitAbilityStringLevelField(damaged, SB_TOWER_SHIELDS, ABILITY_SLF_CASTER)
local texttag ft = FloatTextAboveUnit(damaged, "Block!", 10.0, 0.0, 1.0, 0.0, 0.0, 1.0)
local integer level = GetUnitAbilityLevel(damaged, SB_TOWER_SHIELDS) - 1
local real cd = BlzGetUnitAbilityCooldown(damaged, SB_TOWER_SHIELDS, level)
local real damageReduction = GetUnitAbilityRealLevelField(damaged, SB_TOWER_SHIELDS, ABILITY_RLF_AREA_OF_EFFECT)
call BlzStartUnitAbilityCooldown(damaged, SB_TOWER_SHIELDS, cd)
call BlzSetEventDamage(RMax(GetEventDamage() - damageReduction, 0.0))
call AddSpecialEffectTargetOneShot(casterVfx, damaged, "origin")
call SetFloatingTextMovement(ft, 3, 1, 0.0, 72.0)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t, Condition(function BlockConditions))
call TriggerAddAction(t, function OnBlock)
call GateAbilityTrigger(t, SB_TOWER_SHIELDS, SB_TECH_TOWER_SHIELDS)
endfunction
endscope
scope Fortify initializer Init
globals
private constant hashtable HT = InitHashtable()
endglobals
private struct Fortify
integer spearCount = 0
real baseAttackCooldown = 0.0
endstruct
private function GetAttackIndex takes unit whichUnit returns integer
local player p = GetOwningPlayer(whichUnit)
if (PlayerHasTech(p, SB_TECH_SIEGE_SPEARS)) then
return 1
endif
return 0
endfunction
private function UpdateAttack takes unit spearTank, Fortify f returns nothing
local integer attackIndex = GetAttackIndex(spearTank)
local real cd = DBZ(f.baseAttackCooldown, f.spearCount, f.baseAttackCooldown)
call BlzSetUnitAttackCooldown(spearTank, cd, attackIndex)
if (f.spearCount > 0 and GetUnitTypeId(spearTank) != SB_SPEARTANK) then
call BlzSetUnitWeaponBooleanField(spearTank, UNIT_WEAPON_BF_ATTACKS_ENABLED, attackIndex, true)
else
call BlzSetUnitWeaponBooleanField(spearTank, UNIT_WEAPON_BF_ATTACKS_ENABLED, attackIndex, false)
endif
endfunction
private function AddAttacker takes unit spearTank returns nothing
local Fortify f = LoadInteger(HT, GetHandleId(spearTank), 0)
local integer attackIndex = GetAttackIndex(spearTank)
if (f == 0) then
set f = Fortify.create()
set f.baseAttackCooldown = BlzGetUnitAttackCooldown(spearTank, attackIndex)
call SaveInteger(HT, GetHandleId(spearTank), 0, f)
endif
set f.spearCount = f.spearCount + 1
call UpdateAttack(spearTank, f)
endfunction
private function RemoveAttacker takes unit spearTank returns nothing
local Fortify f = LoadInteger(HT, GetHandleId(spearTank), 0)
set f.spearCount = f.spearCount - 1
call UpdateAttack(spearTank, f)
if (f.spearCount == 0) then
call f.destroy()
call RemoveSavedInteger(HT, GetHandleId(spearTank), 0)
endif
endfunction
private function IsSpearman takes unit whichUnit returns boolean
return GetUnitTypeId(whichUnit) == SB_SPEARMAN or GetUnitTypeId(whichUnit) == SB_SPEARMAN_SIEGE_SPEARS
endfunction
private function OnUnitLoaded takes TransportEvent ev returns nothing
if (IsSpearman(ev.cargo) and UnitHasAbility(ev.transport, SB_FORTIFY)) then
call AddAttacker(ev.transport)
endif
endfunction
private function OnUnitUnloaded takes TransportEvent ev returns nothing
if (IsSpearman(ev.cargo) and UnitHasAbility(ev.transport, SB_FORTIFY)) then
call RemoveAttacker(ev.transport)
endif
endfunction
private function OnFortify takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local Fortify f = LoadInteger(HT, GetHandleId(caster), 0)
if (f != 0) then
call UpdateAttack(caster, f)
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call CreateSpellFinishTrigger(SB_FORTIFY, function OnFortify)
call EventSystem_RegisterEventListener(TransportTracking_OnUnitLoadedIntoTransport, OnUnitLoaded)
call EventSystem_RegisterEventListener(TransportTracking_OnUnitUnloadedFromTransport, OnUnitUnloaded)
endfunction
endscope
scope AscendDescend initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_DESCEND
private constant key KEY_SELECTED
endglobals
private function SaveSelection takes player p returns nothing
local group savedSelection = LoadGroupHandle(HT, KEY_SELECTED, GetHandleId(p))
if (savedSelection == null) then
set savedSelection = CreateGroup()
call SaveGroupHandle(HT, KEY_SELECTED, GetHandleId(p), savedSelection)
endif
call GroupEnumUnitsSelected(savedSelection, p, null)
endfunction
private function HasSavedSelection takes player p returns boolean
local group savedSelection = LoadGroupHandle(HT, KEY_SELECTED, GetHandleId(p))
local integer count = BlzGroupGetSize(savedSelection)
local integer i = 0
local unit picked = null
local boolean containsAirUnit = false
local boolean containsGroundUnit = false
if (savedSelection != null) then
loop
exitwhen i >= count or (containsAirUnit and containsGroundUnit)
set picked = BlzGroupUnitAt(savedSelection, i)
if (GetUnitTypeId(picked) == SB_ARCHON_AIR) then
set containsAirUnit = true
elseif (GetUnitTypeId(picked) == SB_ARCHON_GROUND) then
set containsGroundUnit = true
endif
set i = i + 1
endloop
endif
return containsAirUnit and containsGroundUnit
endfunction
private function DestroySavedSelection takes player p returns nothing
local group savedSelection = LoadGroupHandle(HT, KEY_SELECTED, GetHandleId(p))
call DestroyGroup(savedSelection)
call RemoveSavedHandle(HT, KEY_SELECTED, GetHandleId(p))
endfunction
private function RebuildSelection takes player p returns nothing
local group savedSelection = LoadGroupHandle(HT, KEY_SELECTED, GetHandleId(p))
local integer count = BlzGroupGetSize(savedSelection)
local integer i = 0
local unit picked = null
local boolean select = false
loop
set i = 0
loop
exitwhen i >= count
set picked = BlzGroupUnitAt(savedSelection, i)
if (GetUnitTypeId(picked) != SB_ARCHON_AIR and p == GetLocalPlayer()) then
call SelectUnit(picked, select)
endif
set i = i + 1
endloop
exitwhen select == true
set select = true
endloop
call DestroySavedSelection(p)
endfunction
private struct Descend
unit caster = null
location target = null
real speed = 0.0
real aoe = 0.0
string landingArt = null
string landingArt2 = null
effect descendEffect = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(HT, KEY_DESCEND, GetHandleId(caster))
call DestroyEffect(descendEffect)
call RemoveLocation(target)
call it.destroy()
set caster = null
set target = null
endmethod
endstruct
private function CreateDescend takes unit caster, real targetX, real targetY returns Descend
local string effectArt = GetUnitAbilityStringLevelField(caster, SB_DESCEND, ABILITY_SLF_MISSILE_ART)
local location target = LineTraceWalkabilityReverse(targetX, targetY, GetUnitX(caster), GetUnitY(caster), BlzGetUnitCollisionSize(caster))
local Descend d = Descend.create()
set d.caster = caster
set d.target = target
set d.speed = GetUnitAbilityIntegerField(caster, SB_DESCEND, ABILITY_IF_MISSILE_SPEED)
set d.aoe = GetUnitAbilityRealLevelField(caster, SB_DESCEND, ABILITY_RLF_AREA_OF_EFFECT)
set d.landingArt = GetUnitAbilityStringLevelField(caster, SB_DESCEND, ABILITY_SLF_AREA_EFFECT)
set d.landingArt2 = GetUnitAbilityStringLevelField(caster, SB_DESCEND, ABILITY_SLF_SPECIAL)
set d.descendEffect = AddSpecialEffectTarget(effectArt, caster, "origin")
set d.it = CreateIntTimer(d, false)
call SaveInteger(HT, KEY_DESCEND, GetHandleId(caster), d)
return d
endfunction
private function DescendTargetFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_ATTACKS_GROUND)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_PEON)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
return true
endfunction
private function DescendFinished takes Descend d returns nothing
local real x = GetUnitX(d.caster)
local real y = GetUnitY(d.caster)
local group hit = GetUnitsInAOEUnit(x, y, d.aoe, DescendTargetFilter, d.caster)
local integer count = BlzGroupGetSize(hit)
local unit picked = null
loop
set count = count - 1
exitwhen count < 0
set picked = BlzGroupUnitAt(hit, count)
call IssueTargetOrder(picked, "attack", d.caster)
endloop
call SetUnitTimeScale(d.caster, 1.0)
call AddSpecialEffectOneShotEx(d.landingArt, GetUnitX(d.caster), GetUnitY(d.caster), 0.0, DBZ(d.aoe, 250.0, 1.0), 1.0)
call AddSpecialEffectOneShotEx(d.landingArt2, GetUnitX(d.caster), GetUnitY(d.caster), 0.0, 2.0, 2.5)
call BlzStartUnitAbilityCooldown(d.caster, SB_ASCEND_DUMMY, BlzGetUnitAbilityCooldown(d.caster, SB_ASCEND_DUMMY, 0))
call SetUnitPathing(d.caster, true)
call DestroyGroup(hit)
call d.destroy()
endfunction
private function UpdateDescend takes IntTimer it returns nothing
local Descend d = it.owner
local real dt = TimerPlusGetElapsed(it)
local real dist = DistanceBetweenUnitAndPoint(d.caster, GetLocationX(d.target), GetLocationY(d.target))
local real angle = AngleBetweenPointsXY(GetUnitX(d.caster), GetUnitY(d.caster), GetLocationX(d.target), GetLocationY(d.target))
local real newX = 0.0
local real newY = 0.0
local real speed = d.speed * dt
local player owner = GetOwningPlayer(d.caster)
call BlzSetUnitFacingEx(d.caster, angle)
if (dist > speed) then
set newX = PolarProjectionX(GetUnitX(d.caster), speed, angle)
set newY = PolarProjectionY(GetUnitY(d.caster), speed, angle)
call SetUnitX(d.caster, newX)
call SetUnitY(d.caster, newY)
else
set newX = GetLocationX(d.target)
set newY = GetLocationY(d.target)
call SetUnitX(d.caster, newX)
call SetUnitY(d.caster, newY)
endif
if (GetUnitTypeId(d.caster) != SB_ARCHON_GROUND) then
call SaveSelection(owner)
else
call DescendFinished(d)
if (HasSavedSelection(owner)) then
call RebuildSelection(owner)
else
call DestroySavedSelection(owner)
endif
endif
endfunction
private function OnAscendBegin takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local Descend d = LoadInteger(HT, KEY_DESCEND, GetHandleId(caster))
if (d != 0) then
call SetUnitPathing(caster, false)
call StartTimerPlusPeriodic(d.it, 0.0, 0.01, UpdateDescend, 0)
endif
endfunction
private function OnTargetDescend takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local Descend d = CreateDescend(caster, targetX, targetY)
local real castRange = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_CAST_RANGE)
local real dist = DistanceBetweenUnitAndPoint(caster, GetLocationX(d.target), GetLocationY(d.target))
local real duration = DBZ(dist, d.speed, 0.0)
call SetUnitAbilityRealLevelField(caster, SB_ASCEND, ABILITY_RLF_DURATION_NORMAL, duration)
call SetUnitAbilityRealLevelField(caster, SB_ASCEND, ABILITY_RLF_ALTITUDE_ADJUSTMENT_DURATION, duration)
call SetUnitTimeScale(caster, DBZ(dist, castRange, 1.0))
call IssueImmediateOrderAfter(caster, "unravenform", 0.0)
endfunction
private function OnAscendDummy takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
call SetUnitAbilityRealLevelField(caster, SB_ASCEND, ABILITY_RLF_DURATION_NORMAL, duration)
call SetUnitAbilityRealLevelField(caster, SB_ASCEND, ABILITY_RLF_ALTITUDE_ADJUSTMENT_DURATION, duration)
call IssueImmediateOrderAfter(caster, "ravenform", 0.0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_ASCEND, function OnAscendBegin)
call CreateSpellEffectTrigger(SB_ASCEND_DUMMY, function OnAscendDummy)
call CreateSpellEffectTrigger(SB_DESCEND, function OnTargetDescend)
endfunction
endscope
function Trig_Cleave_Conditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
return UnitHasAbility(damager, SB_CLEAVE) and BlzGetEventDamageType() == DAMAGE_TYPE_ENHANCED
endfunction
function Trig_Cleave_Actions takes nothing returns nothing
call BlzSetEventDamageType(DAMAGE_TYPE_NORMAL)
endfunction
//===========================================================================
function InitTrig_Cleave takes nothing returns nothing
set gg_trg_Cleave = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Cleave, EVENT_PLAYER_UNIT_DAMAGING )
call TriggerAddCondition( gg_trg_Cleave, Condition( function Trig_Cleave_Conditions ) )
call TriggerAddAction( gg_trg_Cleave, function Trig_Cleave_Actions)
call GateAbilityTrigger(gg_trg_Cleave, SB_CLEAVE, SB_TECH_CLEAVE)
endfunction
function Trig_Taunt_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_TAUNT
endfunction
function Trig_Taunt_Filter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitEnemy(filter, GetOwningPlayer(caster))) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_MELEE_ATTACKER) and not IsUnitType(filter, UNIT_TYPE_RANGED_ATTACKER)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_PEON)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
endif
return true
endfunction
function Trig_Taunt_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local group unitsAffected = GetUnitsInAOEUnit(GetSpellTargetX(), GetSpellTargetY(), aoe, Trig_Taunt_Filter, caster)
local group batch = CreateGroup()
local unit picked = null
local integer count = 0
loop
set picked = FirstOfGroup(unitsAffected)
exitwhen picked == null
call GroupAddUnit(batch, picked)
set count = count + 1
if (count == 12) then
call GroupTargetOrder(batch, "attack", caster)
call GroupClear(batch)
endif
call AddSpecialEffectTargetOneShot("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe", picked, "overhead")
call GroupRemoveUnit(unitsAffected, picked)
endloop
if (count > 0) then
call GroupTargetOrder(batch, "attack", caster)
endif
call DestroyGroup(unitsAffected)
call DestroyGroup(batch)
endfunction
//===========================================================================
function InitTrig_Taunt takes nothing returns nothing
set gg_trg_Taunt = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Taunt, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Taunt, Condition(function Trig_Taunt_Conditions))
call TriggerAddAction(gg_trg_Taunt, function Trig_Taunt_Actions)
endfunction
function Trig_Blinding_Flash_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BLINDING_FLASH
endfunction
function Trig_Blinding_Flash_Actions takes nothing returns nothing
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
call DummyCastInstant(GetOwningPlayer(GetSpellAbilityUnit()), x, y, SB_BLINDING_FLASH_HIDDEN_CASTER, "howlofterror")
endfunction
//===========================================================================
function InitTrig_Blinding_Flash takes nothing returns nothing
set gg_trg_Blinding_Flash = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Blinding_Flash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Blinding_Flash, Condition( function Trig_Blinding_Flash_Conditions ) )
call TriggerAddAction( gg_trg_Blinding_Flash, function Trig_Blinding_Flash_Actions )
endfunction
scope OblivionVault
globals
private constant hashtable HT_OBLIVION_VAULT = InitHashtable()
private constant key KEY_OBLIVION_VAULT
endglobals
private struct OblivionVault
unit caster = null
unit target = null
unit vault = null
endstruct
private function OblivionVaultDies takes nothing returns nothing
local unit vault = GetDyingUnit()
local unit imprisoned = LoadUnitHandle(HT_OBLIVION_VAULT, GetHandleId(vault), 0)
call ExileUnit(imprisoned, false)
call UnitRemoveBuffBJ(SB_BUFF_OBLIVION_VAULT, imprisoned)
call UnitRemoveBuffBJ(SB_BUFF_OBLIVION_VAULT, imprisoned)
call UnitRemoveBuffBJ(SB_BUFF_OBLIVION_VAULT, imprisoned)
call SetUnitFlyHeight(vault, 0, GetUnitFlyHeight(vault) / 0.25)
call SetUnitFlyHeight(imprisoned, GetUnitDefaultFlyHeight(imprisoned), RAbsBJ(GetUnitDefaultFlyHeight(imprisoned) - GetUnitFlyHeight(imprisoned)) / 0.25)
call ChangeUnitAlphaOverTime(vault, 0.25, 0.0, 0)
call RestoreUnitColorOverTime(imprisoned, 0.25, 0.0)
call RemoveSavedHandle(HT_OBLIVION_VAULT, GetHandleId(vault), 0)
call DestroyTrigger(GetTriggeringTrigger())
endfunction
function OblivionVaultEffectEnds takes IntTimer it returns nothing
local OblivionVault ov = it.owner
local trigger vaultDiesTrigger = CreateTrigger()
local real x = GetUnitX(ov.target)
local real y = GetUnitY(ov.target)
local unit vault = null
call ExileUnit(ov.target, true)
call UnitShareVision(ov.vault, GetOwningPlayer(ov.caster), true)
call UnitShareVision(ov.vault, GetOwningPlayer(ov.caster), true)
call SaveUnitHandle(HT_OBLIVION_VAULT, GetHandleId(ov.vault), 0, ov.target)
call TriggerRegisterUnitEvent(vaultDiesTrigger, ov.vault, EVENT_UNIT_DEATH)
call TriggerAddAction(vaultDiesTrigger, function OblivionVaultDies)
call ov.destroy()
endfunction
function CreateOblivionVault takes unit caster, unit target returns nothing
local OblivionVault ov = OblivionVault.create()
local real duration = GetUnitAbilityRealLevelField(caster, SB_OBLIVION_VAULT, ABILITY_RLF_DURATION_NORMAL)
local IntTimer it = CreateIntTimer(ov, true)
set ov.caster = caster
set ov.target = target
set ov.vault = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), SB_OBLIVION_VAULT_UNIT, GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
call EnableUnitFlyHeight(target)
call SetUnitFlyHeight(target, 200.0, DBZ(200.0, duration, 0))
call ChangeUnitAlphaOverTime(target, duration, 0.0, 0)
call FadeUnitAlphaOverTime(ov.vault, duration, 0.0, 0, 255)
call ChangeUnitSize(ov.vault, 1.0)
call ChangeUnitSizeOverTime(ov.vault, duration, -1.0)
call StartTimerPlus(it, duration, OblivionVaultEffectEnds)
endfunction
endscope
function Trig_Oblivion_Vault_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_OBLIVION_VAULT
endfunction
function Trig_Oblivion_Vault_Actions takes nothing returns nothing
call CreateOblivionVault(GetSpellAbilityUnit(), GetSpellTargetUnit())
endfunction
//===========================================================================
function InitTrig_Oblivion_Vault takes nothing returns nothing
set gg_trg_Oblivion_Vault = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Oblivion_Vault, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Oblivion_Vault, Condition( function Trig_Oblivion_Vault_Conditions ) )
call TriggerAddAction( gg_trg_Oblivion_Vault, function Trig_Oblivion_Vault_Actions )
endfunction
scope ReleaseFalcon initializer Init
globals
private constant hashtable HT_FALCONS = InitHashtable()
private constant key KEY_FALCON_OWNER
private constant key KEY_FALCON_ORIGIN
private constant real FALCON_MAX_RANGE_INTERVAL = 0.5
private constant real FALCON_MAX_RANGE_SQR = 1800.0 * 1800.0
endglobals
// ****************************************
// TRIGGERS
// ****************************************
// FALCON RANGE TRIGGER
private function FalconUpdate takes UnitTimer ut returns nothing
local unit falcon = ut.owner
local location origin = null
if (UnitAlive(falcon)) then
set origin = LoadLocationHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_ORIGIN)
if (SqrDistanceBetweenPointsXY(GetUnitX(falcon), GetUnitY(falcon), GetLocationX(origin), GetLocationY(origin)) > FALCON_MAX_RANGE_SQR) then
call KillUnit(falcon)
call RemoveSavedHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_ORIGIN)
call ut.destroy()
endif
else
call RemoveSavedHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_ORIGIN)
call ut.destroy()
endif
endfunction
private function RangeTriggerConditions takes nothing returns boolean
local integer unitType = GetUnitTypeId(GetEnteringUnit())
return unitType == SB_FALCON or unitType == SB_FALCON_ATTACKER
endfunction
private function RangeTriggerActions takes nothing returns nothing
local unit falcon = GetEnteringUnit()
local UnitTimer ut = CreateUnitTimer(falcon, false)
call SaveLocationHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_ORIGIN, GetUnitLoc(falcon))
call StartTimerPlusPeriodic(ut, 0.0, FALCON_MAX_RANGE_INTERVAL, FalconUpdate, 0)
endfunction
private function CreateRangeTrigger takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterEnterRectSimple(t, GetEntireMapRect())
call TriggerAddCondition(t, Condition(function RangeTriggerConditions))
call TriggerAddAction(t, function RangeTriggerActions)
endfunction
// RELEASE FALCON TARGETED
private function ReleaseFalconTargetedConditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RELEASE_FALCON
endfunction
private function ReleaseFalconTargetedOnHit takes SimMovement sim returns nothing
local unit falcon = sim.mover
local unit caster = LoadUnitHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_OWNER)
local unit hiddenCaster = CreateUnit(GetOwningPlayer(falcon), SB_HIDDEN_CASTER_RELEASE_FALCON, GetUnitX(falcon), GetUnitY(falcon), bj_UNIT_FACING)
call UnitApplyTimedLife(hiddenCaster, SB_BUFF_TIMED_LIFE_GENERIC, 17.0)
call IssueImmediateOrder(hiddenCaster, "locustswarm")
call LifelinkUnits(caster, hiddenCaster, LIFELINK_KILL)
call RemoveSavedHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_OWNER)
call UnlifelinkUnits(caster, falcon)
call RemoveUnit(falcon)
endfunction
private function ReleaseFalconTargetedActions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real speed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local real angle = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), GetSpellTargetX(), GetSpellTargetY())
local real timeToTarget = DBZ(DistanceBetweenUnitAndPoint(caster, GetSpellTargetX(), GetSpellTargetY()), speed, 0.0)
local unit falcon = null
if (GetUnitAbilityLevel(caster, GetSpellAbilityId()) > 1) then
set falcon = CreateUnit(GetOwningPlayer(caster), SB_FALCON_ATTACKER, GetUnitX(caster), GetUnitY(caster), angle)
else
set falcon = CreateUnit(GetOwningPlayer(caster), SB_FALCON, GetUnitX(caster), GetUnitY(caster), angle)
endif
call SetUnitFlyHeight(falcon, 90.0, 0)
call SetUnitFlyHeight(falcon, GetUnitDefaultFlyHeight(falcon), DBZ(GetUnitDefaultFlyHeight(falcon) - 90.0, timeToTarget, 0.0))
call SaveUnitHandle(HT_FALCONS, GetHandleId(falcon), KEY_FALCON_OWNER, caster)
call LifelinkUnits(caster, falcon, LIFELINK_KILL)
call BlzSetUnitWeaponBooleanField(falcon, UNIT_WEAPON_BF_ATTACKS_ENABLED, 0, false)
call BlzSetUnitWeaponBooleanField(falcon, UNIT_WEAPON_BF_ATTACKS_ENABLED, 1, false)
call MoveUnitToPointAtSpeedAll(falcon, GetSpellTargetX(), GetSpellTargetY(), speed, 0.0, SIM_MOVE_TYPE_SETXY, 0, ReleaseFalconTargetedOnHit)
endfunction
private function CreateTargetedSpellTrigger takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function ReleaseFalconTargetedConditions ) )
call TriggerAddAction( t, function ReleaseFalconTargetedActions )
endfunction
// RELEASE FALCON UNTARGETED AUTOCAST
private function ReleaseFalconUntargetedAutocastConditions takes nothing returns boolean
local unit attacker = GetAttacker()
return UnitHasAbility(attacker, SB_RELEASE_FALCON_UNTARGETED) and BlzGetUnitAbilityCooldownRemaining(attacker, SB_RELEASE_FALCON_UNTARGETED) <= 0.0
endfunction
private function ReleaseFalconUntargetedAutocastActions takes nothing returns nothing
call IssueImmediateOrder(GetAttacker(), "locustswarm")
call BlzQueueTargetOrderById(GetAttacker(), SB_ORDER_ATTACK, GetTriggerUnit())
endfunction
private function CreateUntargetedAutocastTrigger takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition( function ReleaseFalconUntargetedAutocastConditions ) )
call TriggerAddAction( t, function ReleaseFalconUntargetedAutocastActions )
endfunction
// ****************************************
// INIT
// ****************************************
private function Init takes nothing returns nothing
call CreateRangeTrigger()
call CreateTargetedSpellTrigger()
call CreateUntargetedAutocastTrigger()
endfunction
endscope
function Trig_Farm_Bounty_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BOUNTY
endfunction
function Trig_Farm_Bounty_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, SB_BOUNTY, ABILITY_RLF_DURATION_NORMAL)
local real speed = GetUnitAbilityIntegerField(caster, SB_BOUNTY, ABILITY_IF_MISSILE_SPEED)
local real arc = GetUnitAbilityRealField(caster, SB_BOUNTY, ABILITY_RF_ARF_MISSILE_ARC)
local real aoe = GetUnitAbilityRealLevelField(caster, SB_BOUNTY, ABILITY_RLF_AREA_OF_EFFECT)
local real castRange = GetUnitAbilityRealLevelField(caster, SB_BOUNTY, ABILITY_RLF_CAST_RANGE)
local unit chicken = null
local integer unitCount = 3
local integer unitIndex = 0
local real offsetAngle = 0.0
local real srcX = 0.0
local real srcY = 0.0
local real x = 0.0
local real y = 0.0
loop
exitwhen unitIndex >= unitCount
set offsetAngle = GetRandomDirectionDeg()
set srcX = PolarProjectionX(GetUnitX(caster), aoe, offsetAngle)
set srcY = PolarProjectionY(GetUnitY(caster), aoe, offsetAngle)
set x = PolarProjectionX(srcX, castRange, offsetAngle)
set y = PolarProjectionY(srcY, castRange, offsetAngle)
set chicken = CreateUnit(GetOwningPlayer(caster), SB_CHICKEN, srcX, srcY, offsetAngle)
call SetUnitPathingSB(chicken, false)
call UnitApplyTimedLife(chicken, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call MoveUnitToPointAtSpeedAll(chicken, x, y, speed, arc, SIM_MOVE_TYPE_SETXY, 0, 0)
set unitIndex = unitIndex + 1
endloop
call PlaySoundAtPositionSB("Units\\Critters\\EasterChicken\\ChickenWhat1.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, srcX, srcY, 127.0)
endfunction
//===========================================================================
function InitTrig_Farm_Bounty takes nothing returns nothing
set gg_trg_Farm_Bounty = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Farm_Bounty, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Farm_Bounty, Condition( function Trig_Farm_Bounty_Conditions ) )
call TriggerAddAction( gg_trg_Farm_Bounty, function Trig_Farm_Bounty_Actions )
endfunction
globals
constant key KEY_CLOUD_COVER
endglobals
function AddCloudCoverEffect takes unit target returns nothing
local effect e = AddSpecialEffectTargetUnitBJ("origin", target, "war3mapImported/CloudCover.mdx")
call BlzSetSpecialEffectScale(e, 0.5)
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(target), KEY_CLOUD_COVER, e)
endfunction
function AddCloudCoverEffectEnum takes nothing returns nothing
call AddCloudCoverEffect(GetEnumUnit())
endfunction
function EnableCloudCoverTriggers takes boolean enable returns nothing
if (enable) then
call EnableTrigger(gg_trg_Cloud_Cover_On_Damaging)
call EnableTrigger(gg_trg_Cloud_Cover_Death)
else
call DisableTrigger(gg_trg_Cloud_Cover_On_Damaging)
call DisableTrigger(gg_trg_Cloud_Cover_Death)
endif
endfunction
function Trig_Cloud_Cover_Init_Actions takes nothing returns nothing
local integer i = 0
local integer playerCount = GetBJMaxPlayers() + 4
local player p = null
local group cloudCoverUnits = null
loop
exitwhen i >= playerCount
set p = Player(i)
if (PlayerHasTech(p, SB_CLOUD_COVER)) then
set cloudCoverUnits = GetUnitsOfPlayerWithAbility(p, SB_CLOUD_COVER)
call ForGroupBJ(cloudCoverUnits, function AddCloudCoverEffectEnum)
call GroupAddGroup(cloudCoverUnits, udg_UnitGroup_CloudCoverCasters)
if (CountUnitsInGroup(cloudCoverUnits) > 0) then
call EnableCloudCoverTriggers(true)
endif
call DestroyGroup(cloudCoverUnits)
endif
endloop
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_Init takes nothing returns nothing
set gg_trg_Cloud_Cover_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Cloud_Cover_Init, function Trig_Cloud_Cover_Init_Actions )
endfunction
function Trig_Cloud_Cover_Enter_Conditions takes nothing returns boolean
if (not UnitHasAbility(GetEnteringUnit(), SB_CLOUD_COVER)) then
return false
elseif (not PlayerHasTech(GetOwningPlayer(GetEnteringUnit()), SB_TECH_CLOUD_COVER)) then
return false
endif
return true
endfunction
function Trig_Cloud_Cover_Enter_Actions takes nothing returns nothing
call GroupAddUnit(udg_UnitGroup_CloudCoverCasters, GetEnteringUnit())
call AddCloudCoverEffect(GetEnteringUnit())
call EnableCloudCoverTriggers(true)
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_Enter takes nothing returns nothing
set gg_trg_Cloud_Cover_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Cloud_Cover_Enter, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Cloud_Cover_Enter, Condition( function Trig_Cloud_Cover_Enter_Conditions ) )
call TriggerAddAction( gg_trg_Cloud_Cover_Enter, function Trig_Cloud_Cover_Enter_Actions )
endfunction
function Trig_Cloud_Cover_Leave_Conditions takes nothing returns boolean
return IsUnitInGroup(GetLeavingUnit(), udg_UnitGroup_CloudCoverCasters)
endfunction
function Trig_Cloud_Cover_Leave_Actions takes nothing returns nothing
call GroupRemoveUnit(udg_UnitGroup_CloudCoverCasters, GetLeavingUnit())
if (CountUnitsInGroup(udg_UnitGroup_CloudCoverCasters) <= 0) then
call EnableCloudCoverTriggers(false)
endif
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_Leave takes nothing returns nothing
set gg_trg_Cloud_Cover_Leave = CreateTrigger( )
call TriggerRegisterLeaveRectSimple( gg_trg_Cloud_Cover_Leave, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Cloud_Cover_Leave, Condition( function Trig_Cloud_Cover_Leave_Conditions ) )
call TriggerAddAction( gg_trg_Cloud_Cover_Leave, function Trig_Cloud_Cover_Leave_Actions )
endfunction
function Trig_Cloud_Cover_Research_Conditions takes nothing returns boolean
return GetResearched() == SB_TECH_CLOUD_COVER
endfunction
function Trig_Cloud_Cover_Research_Actions takes nothing returns nothing
local group cloudCoverUnits = GetUnitsOfPlayerWithAbility(GetOwningPlayer(GetResearchingUnit()), SB_CLOUD_COVER)
if (CountUnitsInGroup(cloudCoverUnits) > 0) then
call GroupAddGroup(cloudCoverUnits, udg_UnitGroup_CloudCoverCasters)
call ForGroupBJ(cloudCoverUnits, function AddCloudCoverEffectEnum)
call EnableCloudCoverTriggers(true)
endif
call DestroyGroup(cloudCoverUnits)
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_Research takes nothing returns nothing
set gg_trg_Cloud_Cover_Research = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Cloud_Cover_Research, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddCondition( gg_trg_Cloud_Cover_Research, Condition( function Trig_Cloud_Cover_Research_Conditions ) )
call TriggerAddAction( gg_trg_Cloud_Cover_Research, function Trig_Cloud_Cover_Research_Actions )
endfunction
globals
constant real CLOUD_COVER_RANGE_THRESHOLD = 200.0
endglobals
function Trig_Cloud_Cover_On_Damaging_Conditions takes nothing returns boolean
if (not UnitHasAbility(BlzGetEventDamageTarget(), SB_CLOUD_COVER)) then
return false
elseif (not PlayerHasTech(GetOwningPlayer(BlzGetEventDamageTarget()), SB_TECH_CLOUD_COVER)) then
return false
elseif (not IsUnitType(GetEventDamageSource(), UNIT_TYPE_RANGED_ATTACKER)) then
return false
elseif (IsUnitType(GetEventDamageSource(), UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
function Trig_Cloud_Cover_On_Damaging_Actions takes nothing returns nothing
local unit damager = GetEventDamageSource()
local unit target = BlzGetEventDamageTarget()
local real maxReduction = GetUnitAbilityRealLevelField(target, SB_CLOUD_COVER, ABILITY_RLF_DAMAGE_MULTIPLIER_UNITS)
local real maxRange = GetUnitAbilityRealLevelField(target, SB_CLOUD_COVER, ABILITY_RLF_AREA_OF_EFFECT)
local real dist = DistanceBetweenUnits(damager, target)
local real totalReduction = RMinBJ(RMaxBJ((dist - CLOUD_COVER_RANGE_THRESHOLD) / (maxRange - CLOUD_COVER_RANGE_THRESHOLD), 0.0) * maxReduction, maxReduction)
call BlzSetEventDamage(GetEventDamage() * (1.0 - totalReduction))
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_On_Damaging takes nothing returns nothing
local integer playerNum = 0
set gg_trg_Cloud_Cover_On_Damaging = CreateTrigger()
call DisableTrigger(gg_trg_Cloud_Cover_On_Damaging)
loop
exitwhen playerNum >= GetBJMaxPlayers() + 4
call TriggerRegisterPlayerUnitEventSimple( gg_trg_Cloud_Cover_On_Damaging, Player(playerNum), EVENT_PLAYER_UNIT_DAMAGED)
set playerNum = playerNum + 1
endloop
call TriggerAddCondition( gg_trg_Cloud_Cover_On_Damaging, Condition( function Trig_Cloud_Cover_On_Damaging_Conditions ) )
call TriggerAddAction( gg_trg_Cloud_Cover_On_Damaging, function Trig_Cloud_Cover_On_Damaging_Actions )
endfunction
function Trig_Cloud_Cover_Death_Conditions takes nothing returns boolean
return UnitHasAbility(GetDyingUnit(), SB_CLOUD_COVER)
endfunction
function Trig_Cloud_Cover_Death_Actions takes nothing returns nothing
local effect e = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(GetDyingUnit()), KEY_CLOUD_COVER)
call DestroyEffect(e)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(GetDyingUnit()), KEY_CLOUD_COVER)
endfunction
//===========================================================================
function InitTrig_Cloud_Cover_Death takes nothing returns nothing
set gg_trg_Cloud_Cover_Death = CreateTrigger( )
call DisableTrigger(gg_trg_Cloud_Cover_Death)
call TriggerRegisterAnyUnitEventBJ( gg_trg_Cloud_Cover_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Cloud_Cover_Death, Condition( function Trig_Cloud_Cover_Death_Conditions ) )
call TriggerAddAction( gg_trg_Cloud_Cover_Death, function Trig_Cloud_Cover_Death_Actions )
endfunction
function Trig_Stand_Ground_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_STAND_GROUND
endfunction
function Trig_Stand_Ground_Actions takes nothing returns nothing
call IssueImmediateOrder(GetSpellAbilityUnit(), "holdposition")
endfunction
//===========================================================================
function InitTrig_Stand_Ground takes nothing returns nothing
set gg_trg_Stand_Ground = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Stand_Ground, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Stand_Ground, Condition( function Trig_Stand_Ground_Conditions ) )
call TriggerAddAction( gg_trg_Stand_Ground, function Trig_Stand_Ground_Actions )
endfunction
globals
constant key KEY_LOAD_GROUND
endglobals
function Trig_Steam_Roller_Orders_Conditions takes nothing returns boolean
return UnitHasAbility(GetOrderedUnit(), 'S003') and GetIssuedOrderId() != String2OrderIdBJ("load")
endfunction
function Trig_Steam_Roller_Orders_Actions takes nothing returns nothing
call SaveInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_LOAD_GROUND, GetIssuedOrderId())
endfunction
//===========================================================================
function InitTrig_Steam_Roller_Orders takes nothing returns nothing
set gg_trg_Steam_Roller_Orders = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Steam_Roller_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Steam_Roller_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Steam_Roller_Orders, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Steam_Roller_Orders, Condition( function Trig_Steam_Roller_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Steam_Roller_Orders, function Trig_Steam_Roller_Orders_Actions )
endfunction
function Trig_Steam_Roller_Load_Conditions takes nothing returns boolean
return UnitHasAbility(GetOrderedUnit(), 'S003') and GetIssuedOrderId() == String2OrderIdBJ("load")
endfunction
function Trig_Steam_Roller_Load_Actions takes nothing returns nothing
if (HaveSavedInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_LOAD_GROUND)) then
call IssueImmediateOrder(GetOrderedUnit(), "stop")
call RemoveSavedInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_LOAD_GROUND)
endif
endfunction
//===========================================================================
function InitTrig_Steam_Roller_Load takes nothing returns nothing
set gg_trg_Steam_Roller_Load = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Steam_Roller_Load, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( gg_trg_Steam_Roller_Load, Condition( function Trig_Steam_Roller_Load_Conditions ) )
call TriggerAddAction( gg_trg_Steam_Roller_Load, function Trig_Steam_Roller_Load_Actions )
endfunction
globals
CustomAura AURA_INTERDICTION = 0
constant real INTERDICTION_AURA_UPDATE_INTERVAL = 0.5
endglobals
function InterdictionAura_TargetFilter takes CustomAuraEmitter emitter returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitEnemy(filter, GetOwningPlayer(emitter.emitter))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (BlzGetUnitMaxMana(filter) <= 0) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function SetManaAbilitiesDisabled takes unit whichUnit, boolean disable returns nothing
local integer index = 0
local integer abilityId = 0
local integer level = 0
local ability a = null
loop
set a = BlzGetUnitAbilityByIndex(whichUnit, index)
exitwhen a == null
set abilityId = BlzGetAbilityId(a)
set level = GetUnitAbilityLevel(whichUnit, abilityId)
if (BlzGetUnitAbilityManaCost(whichUnit, abilityId, level - 1) > 0) then
call UnitDisableAbilitySB(whichUnit, abilityId, disable)
endif
set index = index + 1
endloop
endfunction
function InterdictionAura_UnitEnters takes unit whichUnit returns nothing
call SetManaAbilitiesDisabled(whichUnit, true)
call UnitAddAbility(whichUnit, SB_INTERDICTION_AURA_HIDDEN)
endfunction
function InterdictionAura_UnitLeaves takes unit whichUnit returns nothing
call UnitRemoveAbility(whichUnit, SB_INTERDICTION_AURA_HIDDEN)
call SetManaAbilitiesDisabled(whichUnit, false)
call UnitRemoveBuffBJ(SB_BUFF_INTERDICTION_AURA, whichUnit)
endfunction
function InitInterdictionAura takes nothing returns nothing
set AURA_INTERDICTION = CustomAuras_CreateCustomAura(INTERDICTION_AURA_UPDATE_INTERVAL, InterdictionAura_UnitEnters, InterdictionAura_UnitLeaves, InterdictionAura_TargetFilter, 0, 0)
endfunction
function Trig_Interdiction_Aura_Init_Actions takes nothing returns nothing
local group interdictors = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_INTERDICTION_AURA)
local real aoe = 0.0
local unit picked = null
loop
set picked = FirstOfGroup(interdictors)
exitwhen picked == null
set aoe = GetUnitAbilityRealLevelField(picked, SB_INTERDICTION_AURA, ABILITY_RLF_AREA_OF_EFFECT)
call CustomAuras_AddEmitter(picked, AURA_INTERDICTION, aoe)
call GroupRemoveUnit(interdictors, picked)
endloop
call DestroyGroup(interdictors)
endfunction
//===========================================================================
function InitTrig_Interdiction_Aura_Init takes nothing returns nothing
call InitInterdictionAura()
set gg_trg_Interdiction_Aura_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Interdiction_Aura_Init, function Trig_Interdiction_Aura_Init_Actions )
endfunction
function Trig_Interdiction_Aura_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_INTERDICTION_AURA)
endfunction
function Trig_Interdiction_Aura_Enters_Actions takes nothing returns nothing
local real aoe = GetUnitAbilityRealLevelField(GetEnteringUnit(), SB_INTERDICTION_AURA, ABILITY_RLF_AREA_OF_EFFECT)
call CustomAuras_AddEmitter(GetEnteringUnit(), AURA_INTERDICTION, aoe)
endfunction
//===========================================================================
function InitTrig_Interdiction_Aura_Enters takes nothing returns nothing
set gg_trg_Interdiction_Aura_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Interdiction_Aura_Enters, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Interdiction_Aura_Enters, Condition( function Trig_Interdiction_Aura_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Interdiction_Aura_Enters, function Trig_Interdiction_Aura_Enters_Actions )
endfunction
scope CelestialFire initializer Init
globals
private constant hashtable HT = InitHashtable()
endglobals
private struct CelestialFire
unit caster = null
real x = 0.0
real y = 0.0
real damagePerSec = 0.0
real buildingReduction = 0.0
real aoe = 0.0
effect areaEffect = null
IntTimer updateTimer = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(areaEffect)
call updateTimer.destroy()
call RemoveSavedInteger(HT, GetHandleId(caster), 0)
set caster = null
set areaEffect = null
endmethod
endstruct
private function TargetFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING) and not IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
private function UpdateCelestialFire takes IntTimer it returns nothing
local CelestialFire cf = it.owner
local real dt = TimerPlusGetElapsed(it)
local group nearby = GetUnitsInAOEUnit(cf.x, cf.y, cf.aoe, TargetFilter, cf.caster)
local integer size = BlzGroupGetSize(nearby)
local unit picked = null
loop
set size = size - 1
exitwhen size < 0
set picked = BlzGroupUnitAt(nearby, size)
if (IsUnitType(picked, UNIT_TYPE_STRUCTURE)) then
call UnitDamageTarget(cf.caster, picked, cf.damagePerSec * cf.buildingReduction * dt, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
else
call UnitDamageTarget(cf.caster, picked, cf.damagePerSec * dt, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
endif
endloop
call DummyCastPoint(GetOwningPlayer(cf.caster), cf.x, cf.y, cf.x, cf.y, SB_CELESTIAL_FIRE_HIDDEN_CASTER, "silence")
call DestroyGroup(nearby)
set picked = null
endfunction
private function OnChannelStop takes nothing returns nothing
local CelestialFire cf = LoadInteger(HT, GetHandleId(GetSpellAbilityUnit()), 0)
if (cf != 0) then
call cf.destroy()
endif
endfunction
private function OnChannelStart takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local CelestialFire cf = CelestialFire.create()
set cf.caster = caster
set cf.x = GetSpellTargetX()
set cf.y = GetSpellTargetY()
set cf.damagePerSec = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DAMAGE_HBZ2)
set cf.buildingReduction = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_BUILDING_REDUCTION_HBZ4)
set cf.aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
set cf.areaEffect = AddSpecialEffect(GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_AREA_EFFECT), cf.x, cf.y)
set cf.updateTimer = CreateIntTimer(cf, false)
call SaveInteger(HT, GetHandleId(caster), 0, cf)
call StartTimerPlusPeriodic(cf.updateTimer, 0.0, GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_CASTING_TIME), UpdateCelestialFire, 0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellChannelTrigger(SB_CELESTIAL_FIRE, function OnChannelStart)
call CreateSpellCancelTrigger(SB_CELESTIAL_FIRE, function OnChannelStop)
endfunction
endscope
library ReleaseFalconsAutocast initializer Init
globals
constant key KEY_RELEASE_FALCON
private hashtable HT_RELEASE_FALCONS_AUTOCAST = InitHashtable()
endglobals
public function IsEnabled takes player p returns boolean
return LoadBoolean(HT_RELEASE_FALCONS_AUTOCAST, GetHandleId(p), KEY_RELEASE_FALCON)
endfunction
public function Toggle takes player p, boolean enable returns nothing
call SetPlayerAbilityAvailable(p, SB_RELEASE_FALCON_AUTOCAST_ON, enable)
call SetPlayerAbilityAvailable(p, SB_RELEASE_FALCON_AUTOCAST_OFF, not enable)
call SaveBoolean(HT_RELEASE_FALCONS_AUTOCAST, GetHandleId(p), KEY_RELEASE_FALCON, enable)
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYERS
call Toggle(Player(i), true)
set i = i + 1
endloop
endfunction
endlibrary
function Trig_Release_Falcons_Autocast_Conditions takes nothing returns boolean
local unit attacker = GetAttacker()
local unit attacked = GetTriggerUnit()
local player p = GetOwningPlayer(attacker)
if (not UnitHasAbility(attacker, SB_RELEASE_FALCON)) then
return false
elseif (not IsUnitType(attacked, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitAlly(attacked, p)) then
return false
elseif (not PlayerHasTech(p, SB_TECH_FALCON_TRAINING)) then
return false
elseif (BlzGetUnitAbilityCooldownRemaining(attacker, SB_RELEASE_FALCON) > 0.0) then
return false
elseif (not ReleaseFalconsAutocast_IsEnabled(p)) then
return false
endif
return true
endfunction
function Trig_Release_Falcons_Autocast_Actions takes nothing returns nothing
local unit attacked = GetTriggerUnit()
call IssuePointOrder(GetAttacker(), "flare", GetUnitX(attacked), GetUnitY(attacked))
endfunction
//===========================================================================
function InitTrig_Release_Falcons_Autocast takes nothing returns nothing
set gg_trg_Release_Falcons_Autocast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Release_Falcons_Autocast, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_Release_Falcons_Autocast, Condition( function Trig_Release_Falcons_Autocast_Conditions ) )
call TriggerAddAction( gg_trg_Release_Falcons_Autocast, function Trig_Release_Falcons_Autocast_Actions )
endfunction
function Trig_Release_Falcons_Autocast_Toggle_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RELEASE_FALCON_AUTOCAST_ON or GetSpellAbilityId() == SB_RELEASE_FALCON_AUTOCAST_OFF
endfunction
function Trig_Release_Falcons_Autocast_Enable_Timer_Expires takes IntTimer it returns nothing
local player p = Player(it.owner)
call ReleaseFalconsAutocast_Toggle(p, true)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(p), KEY_RELEASE_FALCON)
endfunction
function Trig_Release_Falcons_Autocast_Disable_Timer_Expires takes IntTimer it returns nothing
local player p = Player(it.owner)
call ReleaseFalconsAutocast_Toggle(p, false)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(p), KEY_RELEASE_FALCON)
endfunction
function Trig_Release_Falcons_Autocast_Toggle_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetSpellAbilityUnit())
local boolean enableAutocast = false
local IntTimer toggleTimer = LoadInteger(udg_HashTable_Timers, GetHandleId(p), KEY_RELEASE_FALCON)
if (toggleTimer == 0) then
set toggleTimer = CreateIntTimer(GetPlayerId(p), true)
set enableAutocast = (GetSpellAbilityId() == SB_RELEASE_FALCON_AUTOCAST_OFF)
if (enableAutocast) then
call StartTimerPlus(toggleTimer, 0.0, Trig_Release_Falcons_Autocast_Enable_Timer_Expires)
else
call StartTimerPlus(toggleTimer, 0.0, Trig_Release_Falcons_Autocast_Disable_Timer_Expires)
endif
endif
endfunction
//===========================================================================
function InitTrig_Release_Falcons_Autocast_Toggle takes nothing returns nothing
set gg_trg_Release_Falcons_Autocast_Toggle = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Release_Falcons_Autocast_Toggle, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Release_Falcons_Autocast_Toggle, Condition( function Trig_Release_Falcons_Autocast_Toggle_Conditions ) )
call TriggerAddAction( gg_trg_Release_Falcons_Autocast_Toggle, function Trig_Release_Falcons_Autocast_Toggle_Actions )
endfunction
function Trig_Falcon_Training_Vision_Radius_Loop takes nothing returns nothing
local player p = GetEnumPlayer()
local integer techLevel = GetPlayerTechCount(p, SB_TECH_FALCON_TRAINING, false)
if (techLevel > 0) then
call SetPlayerTechResearched(p, SB_TECH_FALCON_TRAINING_HIDDEN, techLevel)
endif
endfunction
function Trig_Falcon_Training_Vision_Radius_Init_Actions takes nothing returns nothing
call ForForce(GetPlayersAll(), function Trig_Falcon_Training_Vision_Radius_Loop)
endfunction
//===========================================================================
function InitTrig_Falcon_Training_Vision_Radius_Init takes nothing returns nothing
set gg_trg_Falcon_Training_Vision_Radius_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Falcon_Training_Vision_Radius_Init, function Trig_Falcon_Training_Vision_Radius_Init_Actions )
endfunction
function Trig_Falcon_Training_Vision_Radius_Conditions takes nothing returns boolean
return GetResearched() == SB_TECH_FALCON_TRAINING
endfunction
function Trig_Falcon_Training_Vision_Radius_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
local integer techLevel = GetPlayerTechCount(p, GetResearched(), false)
call SetPlayerTechResearched(p, SB_TECH_FALCON_TRAINING_HIDDEN, techLevel)
endfunction
//===========================================================================
function InitTrig_Falcon_Training_Vision_Radius takes nothing returns nothing
set gg_trg_Falcon_Training_Vision_Radius = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Falcon_Training_Vision_Radius, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddCondition( gg_trg_Falcon_Training_Vision_Radius, Condition( function Trig_Falcon_Training_Vision_Radius_Conditions ) )
call TriggerAddAction( gg_trg_Falcon_Training_Vision_Radius, function Trig_Falcon_Training_Vision_Radius_Actions )
endfunction
function Trig_Select_Necromancers_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_FIND_FREE_NECROMANCERS or GetSpellAbilityId() == SB_FIND_RITUAL_NECROMANCERS
endfunction
function Trig_Select_Necromancers_GroupFilter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (GetUnitTypeId(filter) != SB_NECROMANCER and GetUnitTypeId(filter) != SB_NECROMANCER_LICH) then
return false
elseif (not IsUnitAliveBJ(filter)) then
return false
elseif (IsUnitHidden(filter)) then
return false
elseif (GetSpellAbilityId() == SB_FIND_FREE_NECROMANCERS and BlzGetUnitBooleanField(filter, UNIT_BF_IS_A_BUILDING)) then
return false
elseif (GetSpellAbilityId() == SB_FIND_RITUAL_NECROMANCERS and not BlzGetUnitBooleanField(filter, UNIT_BF_IS_A_BUILDING)) then
return false
endif
return true
endfunction
function Trig_Select_Necromancers_Actions takes nothing returns nothing
local player owner = GetOwningPlayer(GetSpellAbilityUnit())
local group necros = GetUnitsOfPlayerMatching(owner, Condition(function Trig_Select_Necromancers_GroupFilter))
local integer size = BlzGroupGetSize(necros)
local integer index = 0
local unit pickedUnit = null
local location unitPos = null
if (size > 0) then
call ClearSelectionForPlayer(owner)
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(necros, index)
set unitPos = GetUnitLoc(pickedUnit)
call SelectUnitAddForPlayer(pickedUnit, owner)
call PingMinimapLocForForceEx( GetForceOfPlayer(owner), unitPos, 2.00, bj_MINIMAPPINGSTYLE_SIMPLE, 100, 0.00, 100 )
call RemoveLocation(unitPos)
set index = index + 1
endloop
endif
call DestroyGroup(necros)
endfunction
//===========================================================================
function InitTrig_Select_Necromancers takes nothing returns nothing
set gg_trg_Select_Necromancers = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Select_Necromancers, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Select_Necromancers, Condition( function Trig_Select_Necromancers_Conditions ) )
call TriggerAddAction( gg_trg_Select_Necromancers, function Trig_Select_Necromancers_Actions )
endfunction
struct BrinkOfDeath
unit caster = null
unit target = null
real duration = 0.0
real interval = 0.25
real totalAmount = 0.0
IntTimer update = 0
method onDestroy takes nothing returns nothing
call update.destroy()
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_BRINK_OF_DEATH)
endmethod
endstruct
function CreateBrinkOfDeath takes unit caster, unit target returns BrinkOfDeath
local BrinkOfDeath bod = BrinkOfDeath.create()
set bod.caster = caster
set bod.target = target
set bod.duration = GetUnitAbilityRealLevelField(caster, SB_BRINK_OF_DEATH, ABILITY_RLF_DURATION_NORMAL)
set bod.update = CreateIntTimer(bod, false)
if (IsUnitNonNeutralAlly(target, GetOwningPlayer(caster))) then
set bod.totalAmount = -100.0
else
set bod.totalAmount = 75.0
endif
return bod
endfunction
function BrinkOfDeathUpdate takes IntTimer it returns nothing
local BrinkOfDeath bod = it.owner
local real damagePerSecond = bod.totalAmount / bod.duration * TimerPlusGetElapsed(it)
if (UnitAlive(bod.target) and UnitHasBuffBJ(bod.target, SB_BUFF_BRINK_OF_DEATH)) then
if (damagePerSecond < 0) then
call ChangeUnitState(bod.target, UNIT_STATE_LIFE, -damagePerSecond)
elseif (damagePerSecond > 0) then
set damagePerSecond = RMinBJ(damagePerSecond, GetUnitState(bod.target, UNIT_STATE_LIFE) - 1.0)
call UnitDamageTargetBJ(bod.caster, bod.target, damagePerSecond, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH)
endif
else
call bod.destroy()
endif
endfunction
globals
constant key KEY_BRINK_OF_DEATH
endglobals
function Trig_Brink_of_Death_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BRINK_OF_DEATH
endfunction
function Trig_Brink_of_Death_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local BrinkOfDeath bod = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_BRINK_OF_DEATH)
if (bod != null) then
call bod.destroy()
endif
set bod = CreateBrinkOfDeath(caster, target)
call StartTimerPlusPeriodic(bod.update, 0.0, bod.interval, BrinkOfDeathUpdate, 0)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_BRINK_OF_DEATH, bod)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), target, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Brink_of_Death takes nothing returns nothing
set gg_trg_Brink_of_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Brink_of_Death, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Brink_of_Death, Condition( function Trig_Brink_of_Death_Conditions ) )
call TriggerAddAction( gg_trg_Brink_of_Death, function Trig_Brink_of_Death_Actions )
endfunction
globals
constant key KEY_ECLIPSE
endglobals
function EclipseEnableInvisibility takes unit whichUnit, boolean enable returns nothing
local integer abilityId = SB_PERMANENT_INVISIBILITY_ECLIPSE
if (IsUnitType(whichUnit, UNIT_TYPE_PEON)) then
set abilityId = SB_PERMANENT_INVISIBILITY_ECLIPSE_NO_FADE
endif
if (enable) then
call UnitAddAbility(whichUnit, abilityId)
else
call UnitRemoveAbility(whichUnit, abilityId)
endif
endfunction
function EclipseRemoveDependency takes player p returns nothing
call RemoveUnit(udg_Unit_EclipseDependency[GetPlayerId(p)])
endfunction
function EclipseAddDependency takes player p returns nothing
set udg_Unit_EclipseDependency[GetPlayerId(p)] = CreateUnit(p, SB_ECLIPSE_DEPENDENCY, 0, 0, 0)
endfunction
function Trig_Eclipse_Starts_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ECLIPSE
endfunction
function Trig_Eclipse_Starts_PlayerLoop takes nothing returns nothing
local player p = GetEnumPlayer()
local group spirits = GetUnitsOfPlayerWithAbility(p, SB_SPIRIT)
local unit picked = null
loop
set picked = FirstOfGroup(spirits)
exitwhen picked == null
call EclipseEnableInvisibility(picked, true)
call GroupRemoveUnit(spirits, picked)
endloop
call EclipseRemoveDependency(p)
call EclipseAddDependency(p)
call DestroyGroup(spirits)
endfunction
function Trig_Eclipse_Starts_Actions takes nothing returns nothing
local force players = GetPlayingPlayers(false, true, true)
local real duration = GetUnitAbilityRealLevelField(GetSpellAbilityUnit(), SB_ECLIPSE, ABILITY_RLF_DURATION_NORMAL)
local string playerName = GetPlayerNameColored(GetOwningPlayer(GetSpellAbilityUnit()))
local timerdialog td = null
call ForForce(players, function Trig_Eclipse_Starts_PlayerLoop)
call StartTimerBJ(udg_Timer_Eclipse, false, duration)
set td = LoadTimerDialogHandle(udg_HashTable_Timers, GetHandleId(udg_Timer_Eclipse), KEY_ECLIPSE)
call DestroyTimerDialog(td)
set td = CreateTimerDialog(udg_Timer_Eclipse)
call TimerDialogSetTitle(td, "Eclipse (" + playerName + ")")
call SaveTimerDialogHandle(udg_HashTable_Timers, GetHandleId(udg_Timer_Eclipse), KEY_ECLIPSE, td)
call TimerDialogDisplay(td, true)
call PlayPitchedSound("Sound\\Time\\DuskWolf.flac", 127, 0.9)
call EnableTrigger(gg_trg_Eclipse_Unit_Enters)
call DestroyForce(players)
endfunction
//===========================================================================
function InitTrig_Eclipse_Starts takes nothing returns nothing
set gg_trg_Eclipse_Starts = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Eclipse_Starts, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Eclipse_Starts, Condition( function Trig_Eclipse_Starts_Conditions ) )
call TriggerAddAction( gg_trg_Eclipse_Starts, function Trig_Eclipse_Starts_Actions )
endfunction
function Trig_Eclipse_Unit_Enters_Conditions takes nothing returns boolean
return TimerGetRemaining(udg_Timer_Eclipse) > 0.0 and UnitHasAbility(GetEnteringUnit(), SB_SPIRIT)
endfunction
function Trig_Eclipse_Unit_Enters_Actions takes nothing returns nothing
call EclipseEnableInvisibility(GetEnteringUnit(), true)
endfunction
//===========================================================================
function InitTrig_Eclipse_Unit_Enters takes nothing returns nothing
set gg_trg_Eclipse_Unit_Enters = CreateTrigger( )
call DisableTrigger( gg_trg_Eclipse_Unit_Enters )
call TriggerRegisterEnterRectSimple( gg_trg_Eclipse_Unit_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Eclipse_Unit_Enters, Condition( function Trig_Eclipse_Unit_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Eclipse_Unit_Enters, function Trig_Eclipse_Unit_Enters_Actions )
endfunction
function Trig_Eclipse_Expires_PlayerLoop takes nothing returns nothing
local player p = GetEnumPlayer()
local group spirits = GetUnitsOfPlayerWithAbility(p, SB_SPIRIT)
local unit picked = null
loop
set picked = FirstOfGroup(spirits)
exitwhen picked == null
call EclipseEnableInvisibility(picked, false)
call GroupRemoveUnit(spirits, picked)
endloop
call EclipseRemoveDependency(p)
call DestroyGroup(spirits)
endfunction
function Trig_Eclipse_Expires_Actions takes nothing returns nothing
local force players = GetPlayingPlayers(false, true, true)
local timerdialog td = LoadTimerDialogHandle(udg_HashTable_Timers, GetHandleId(GetExpiredTimer()), KEY_ECLIPSE)
call ForForce(players, function Trig_Eclipse_Expires_PlayerLoop)
call DestroyTimerDialog(td)
call DisableTrigger(gg_trg_Eclipse_Unit_Enters)
call DestroyForce(players)
endfunction
//===========================================================================
function InitTrig_Eclipse_Expires takes nothing returns nothing
set gg_trg_Eclipse_Expires = CreateTrigger( )
call TriggerRegisterTimerExpireEventBJ( gg_trg_Eclipse_Expires, udg_Timer_Eclipse )
call TriggerAddAction( gg_trg_Eclipse_Expires, function Trig_Eclipse_Expires_Actions )
endfunction
function GetAnimateDeadMultiplier takes unit whichUnit, real bonus returns real
local integer foodCost = GetUnitFoodUsed(whichUnit)
return Pow(5.0 / foodCost, 1.5) * bonus + 1
endfunction
function FindAnimateDeadUnit takes group corpses, real x, real y returns unit
local group possibleTargets = CreateGroup()
local integer size = 0
local integer index = 0
local unit pickedUnit = null
local unit existingUnit = null
loop
set pickedUnit = FirstOfGroup(corpses)
exitwhen pickedUnit == null
set existingUnit = GetUnitInGroupOfType(possibleTargets, GetUnitTypeId(pickedUnit))
if (existingUnit == null) then
call GroupAddUnit(possibleTargets, pickedUnit)
elseif (SqrDistanceFromUnitToPoint(pickedUnit, x, y) < SqrDistanceFromUnitToPoint(existingUnit, x, y)) then
call GroupRemoveUnit(possibleTargets, existingUnit)
call GroupAddUnit(possibleTargets, existingUnit)
endif
call GroupRemoveUnit(corpses, pickedUnit)
endloop
set size = BlzGroupGetSize(possibleTargets)
set index = size
loop
exitwhen index <= 0 or size == 1
set pickedUnit = BlzGroupUnitAt(possibleTargets, index)
if (IsUnitType(pickedUnit, UNIT_TYPE_PEON)) then
call GroupRemoveUnit(possibleTargets, pickedUnit)
set size = size - 1
endif
set index = index - 1
endloop
set pickedUnit = GroupPickRandomUnit(possibleTargets)
call DestroyGroup(possibleTargets)
return pickedUnit
endfunction
function SetCasterAbilities takes unit whichUnit returns nothing
local integer typeId = GetUnitTypeId(whichUnit)
if (UnitHasAbility(whichUnit, SB_LEECH_SEED)) then
call UnitRemoveAbility(whichUnit, SB_LEECH_SEED)
call UnitAddAbility(whichUnit, SB_SEED_OF_CORRUPTION)
elseif (UnitHasAbility(whichUnit, SB_BLINDING_FLASH)) then
call UnitRemoveAbility(whichUnit, SB_BLINDING_FLASH)
call UnitAddAbility(whichUnit, SB_DARKNESS)
elseif (UnitHasAbility(whichUnit, SB_UNHOLY_BANNER)) then
call UnitRemoveAbility(whichUnit, SB_UNHOLY_BANNER)
call UnitAddAbility(whichUnit, SB_DEATH_WAVE)
endif
endfunction
function Trig_Animate_Dead_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ANIMATE_DEAD
endfunction
function Trig_Animate_Dead_Cast_Corpse_Filter takes nothing returns boolean
if (UnitAlive(GetFilterUnit())) then
return false
elseif (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(GetFilterUnit(), UNIT_TYPE_SUMMONED)) then
return false
elseif (not IsUnitType(GetFilterUnit(), UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitWard(GetFilterUnit())) then
return false
elseif (GetUnitFoodUsed(GetFilterUnit()) < 1) then
return false
endif
return true
endfunction
function Trig_Animate_Dead_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real aoe = GetUnitAbilityRealLevelField(caster, SB_ANIMATE_DEAD, ABILITY_RLF_AREA_OF_EFFECT)
local real duration = GetUnitAbilityRealLevelField(caster, SB_ANIMATE_DEAD, ABILITY_RLF_DURATION_NORMAL)
local group corpses = CreateGroup()
local integer soulHarvestAbilityLevel = 0
local unit reanimateTarget = null
local unit pickedUnit = null
local real hpMultiplier = 0.0
local real mpMultiplier = 0.0
local real damageMultiplier = 0.0
call GroupEnumUnitsInRange(corpses, GetSpellTargetX(), GetSpellTargetY(), aoe, Condition(function Trig_Animate_Dead_Cast_Corpse_Filter))
set reanimateTarget = FindAnimateDeadUnit(corpses, GetSpellTargetX(), GetSpellTargetY())
call DestroyGroup(corpses)
if (reanimateTarget != null) then
set hpMultiplier = GetAnimateDeadMultiplier(reanimateTarget, 0.62)
set mpMultiplier = GetAnimateDeadMultiplier(reanimateTarget, 0.62)
set damageMultiplier = GetAnimateDeadMultiplier(reanimateTarget, 0.25)
set soulHarvestAbilityLevel = GetSoulHarvestLevel(reanimateTarget)
set reanimateTarget = ReplaceUnitBJ(reanimateTarget, GetUnitTypeId(reanimateTarget), bj_UNIT_STATE_METHOD_MAXIMUM)
call SetUnitOwner(reanimateTarget, GetOwningPlayer(caster), true)
call SetUnitUseFood(reanimateTarget, false)
call UnitAddType(reanimateTarget, UNIT_TYPE_SUMMONED)
call UnitAddType(reanimateTarget, UNIT_TYPE_UNDEAD)
call UnitAddAbility(reanimateTarget, SB_ANIMATE_DEAD_VISUAL_EFFECT)
call BlzSetUnitMaxHP(reanimateTarget, R2I(GetUnitState(reanimateTarget, UNIT_STATE_MAX_LIFE) * hpMultiplier))
call BlzSetUnitMaxMana(reanimateTarget, R2I(GetUnitState(reanimateTarget, UNIT_STATE_MAX_MANA) * mpMultiplier))
call BlzSetUnitBaseDamage(reanimateTarget, R2I(BlzGetUnitBaseDamage(reanimateTarget, 0) * damageMultiplier), 0)
call BlzSetUnitBaseDamage(reanimateTarget, R2I(BlzGetUnitBaseDamage(reanimateTarget, 1) * damageMultiplier), 1)
call SetUnitLifePercentBJ(reanimateTarget, 100.0)
call SetUnitManaPercentBJ(reanimateTarget, 100.0)
if (soulHarvestAbilityLevel > 1) then
call Vampire_Soul_Harvest_AddLevels(reanimateTarget, soulHarvestAbilityLevel - 1)
endif
call SetCasterAbilities(reanimateTarget)
call UnitApplyTimedLife(reanimateTarget, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call ChangeUnitColor(reanimateTarget, 255, 128, 128, 255)
call ChangeUnitSize(reanimateTarget, 0.3)
call BlzSetUnitRealFieldBJ(reanimateTarget, UNIT_RF_SELECTION_SCALE, BlzGetUnitRealField(reanimateTarget, UNIT_RF_SELECTION_SCALE) * 1.25)
call AddSpecialEffectOneShot("Abilities\\Spells\\Demon\\SoulPreservation\\SoulPreservation.flac", GetUnitX(reanimateTarget), GetUnitY(reanimateTarget))
call PlaySBAlertOnUnit(GetOwningPlayer(caster), reanimateTarget, GetSpellAbilityId())
else
call DisplayError(GetOwningPlayer(caster), "No dead unit found for Animate Dead.")
call RefundAbilityCast(caster, GetSpellAbilityId())
endif
endfunction
//===========================================================================
function InitTrig_Animate_Dead_Cast takes nothing returns nothing
set gg_trg_Animate_Dead_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Animate_Dead_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Animate_Dead_Cast, Condition( function Trig_Animate_Dead_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Animate_Dead_Cast, function Trig_Animate_Dead_Cast_Actions )
endfunction
struct SeedOfCorruption
unit caster = null
unit target = null
real damagePct = 0.0
real damageInterval = 0.0
string deathEffectArt = null
string buffEffectArt = null
effect buffEffect = null
integer spawnedUnitTypeId = 0
integer spawnedUnitCount = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(buffEffect)
endmethod
endstruct
function CreateSeedOfCorruption takes unit caster, unit target returns SeedOfCorruption
local SeedOfCorruption ls = SeedOfCorruption.create()
set ls.caster = caster
set ls.target = target
set ls.damagePct = 0.15
set ls.damageInterval = 1.0
set ls.spawnedUnitTypeId = SB_ZOMBIE
set ls.spawnedUnitCount = 3
set ls.deathEffectArt = GetUnitAbilityStringLevelField(caster, SB_SEED_OF_CORRUPTION, ABILITY_SLF_SPECIAL)
set ls.buffEffectArt = "Abilities\\Spells\\Undead\\Cripple\\CrippleTarget.mdl"
return ls
endfunction
globals
constant key KEY_SEED_OF_CORRUPTION
endglobals
function Trig_Seed_of_Corruption_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SEED_OF_CORRUPTION
endfunction
function Trig_Seed_of_Corruption_Update takes IntTimer it returns nothing
local SeedOfCorruption ls = it.owner
local real damage = 0.0
if (UnitHasBuffBJ(ls.target, SB_BUFF_SEED_OF_CORRUPTION) and UnitAlive(ls.target)) then
set damage = GetUnitState(ls.target, UNIT_STATE_MAX_LIFE) * ls.damagePct
call UnitDamageTargetBJ(ls.caster, ls.target, damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH)
else
call RemoveSavedHandle(udg_HashTable_Timers, GetHandleId(ls.target), KEY_SEED_OF_CORRUPTION)
call it.destroy()
call ls.destroy()
endif
endfunction
function Trig_Seed_of_Corruption_Missile_Hit takes TargetMissile missile, real x, real y returns nothing
local SeedOfCorruption ls = missile.data
local SeedOfCorruption other = 0
local IntTimer it = LoadInteger(udg_HashTable_Timers, GetHandleId(missile.target), KEY_SEED_OF_CORRUPTION)
if (it == 0) then
set it = CreateIntTimer(ls, false)
call SaveInteger(udg_HashTable_Timers, GetHandleId(missile.target), KEY_SEED_OF_CORRUPTION, it)
endif
if (it.owner != ls) then
set other = it.owner
set it.owner = ls
call other.destroy()
endif
set ls.buffEffect = AddSpecialEffectTarget(ls.buffEffectArt, missile.target, "chest")
call StartTimerPlusPeriodic(it, 0.0, ls.damageInterval, Trig_Seed_of_Corruption_Update, 0)
endfunction
function Trig_Seed_of_Corruption_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local string missileArt = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_MISSILE_ART)
local real missileSpeed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local SeedOfCorruption ls = CreateSeedOfCorruption(caster, target)
local TargetMissile missile = CreateTargetMissile(missileArt, caster, GetUnitX(caster), GetUnitY(caster), 85.0)
set missile.data = ls
call FireTargetMissile(missile, target, missileSpeed, 0.0, 60.0, true, Trig_Seed_of_Corruption_Missile_Hit)
endfunction
//===========================================================================
function InitTrig_Seed_of_Corruption takes nothing returns nothing
set gg_trg_Seed_of_Corruption = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Seed_of_Corruption, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Seed_of_Corruption, Condition( function Trig_Seed_of_Corruption_Conditions ) )
call TriggerAddAction( gg_trg_Seed_of_Corruption, function Trig_Seed_of_Corruption_Actions )
endfunction
function Trig_Seed_of_Corruption_Unit_Dies_Conditions takes nothing returns boolean
return HaveSavedInteger(udg_HashTable_Timers, GetHandleId(GetDyingUnit()), KEY_SEED_OF_CORRUPTION)
endfunction
function Trig_Seed_of_Corruption_Unit_Dies_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
local IntTimer it = LoadInteger(udg_HashTable_Timers, GetHandleId(dying), KEY_SEED_OF_CORRUPTION)
local SeedOfCorruption ls = it.owner
local integer summonedUnitCount = ls.spawnedUnitCount
local unit summoned = null
call AddSpecialEffectOneShot(ls.deathEffectArt, GetUnitX(dying), GetUnitY(dying))
if (summonedUnitCount > 0) then
call PlaySoundAtPositionSB("Units\\Creeps\\Wendigo\\WendigoYesAttack1.flac", "SpellsEAX", 11, GetUnitX(dying), GetUnitY(dying), 100.0)
endif
loop
exitwhen summonedUnitCount <= 0
set summoned = CreateUnit(GetOwningPlayer(ls.caster), ls.spawnedUnitTypeId, GetUnitX(dying), GetUnitY(dying), GetUnitFacing(dying))
call AddSpecialEffectOneShot("Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl", GetUnitX(summoned), GetUnitY(summoned))
set summonedUnitCount = summonedUnitCount - 1
endloop
call ls.destroy()
call it.destroy()
endfunction
//===========================================================================
function InitTrig_Seed_of_Corruption_Unit_Dies takes nothing returns nothing
set gg_trg_Seed_of_Corruption_Unit_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Seed_of_Corruption_Unit_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Seed_of_Corruption_Unit_Dies, Condition( function Trig_Seed_of_Corruption_Unit_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Seed_of_Corruption_Unit_Dies, function Trig_Seed_of_Corruption_Unit_Dies_Actions )
endfunction
function Trig_Darkness_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_DARKNESS
endfunction
function Trig_Darkness_Actions takes nothing returns nothing
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
call DummyCastInstant(GetOwningPlayer(GetSpellAbilityUnit()), x, y, SB_DARKNESS_HIDDEN_CASTER, "howlofterror")
endfunction
//===========================================================================
function InitTrig_Darkness takes nothing returns nothing
set gg_trg_Darkness = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Darkness, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Darkness, Condition( function Trig_Darkness_Conditions ) )
call TriggerAddAction( gg_trg_Darkness, function Trig_Darkness_Actions )
endfunction
globals
constant real DEATH_WAVE_EFFECT_DENSITY = 0.04
endglobals
function Trig_Death_Wave_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_DEATH_WAVE
endfunction
function Trig_Death_Wave_Update takes SpellWave sw returns nothing
local real aoe = sw.GetCurrentAOE()
local integer numEffects = R2I(aoe * DEATH_WAVE_EFFECT_DENSITY)
local integer index = 0
local vec3 effectPos = vec3.create(0, 0, 0)
local real waveAngle = VecAngle(sw.direction)
local real halfPi = bj_PI * 0.5
local real angleIncrement = RDefaultIfZero(I2R(numEffects - 1), bj_PI / I2R(numEffects - 1), 0.0)
local real angle = 0.0
loop
exitwhen index >= numEffects
call effectPos.copy(sw.position)
set angle = Rad2Deg((waveAngle - halfPi) + (angleIncrement * index))
set effectPos.x = PolarProjectionX(effectPos.x, aoe * 0.5, angle)
set effectPos.y = PolarProjectionY(effectPos.y, aoe * 0.5, angle)
call AddSpecialEffectOneShot("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayTarget.mdl", effectPos.x, effectPos.y)
set index = index + 1
endloop
call SetBlight(GetOwningPlayer(sw.owner), sw.position.x, sw.position.y, aoe, true)
call effectPos.destroy()
endfunction
function Trig_Death_Wave_TargetFilter takes SpellWave sw returns boolean
local unit filter = GetFilterUnit()
if (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (filter == sw.owner) then
return false
elseif (not IsUnitAlly(filter, GetOwningPlayer(sw.owner))) then
if (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
endif
endif
return true
endfunction
function Trig_Death_Wave_OnHit takes SpellWave sw, unit hit returns nothing
local real pct = GetUnitAbilityRealLevelField(sw.owner, SB_DEATH_WAVE, ABILITY_RLF_DAMAGE_UCS1)
local real lifeChange = GetUnitState(hit, UNIT_STATE_MAX_LIFE) * pct
if (IsUnitAlly(hit, GetOwningPlayer(sw.owner))) then
call ChangeUnitState(hit, UNIT_STATE_LIFE, lifeChange)
call AddSpecialEffectTargetOneShot("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl", hit, "overhead")
else
call UnitDamageTarget(sw.owner, hit, lifeChange, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH, WEAPON_TYPE_WHOKNOWS)
call AddSpecialEffectTargetOneShot("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayDamage.mdl", hit, "overhead")
endif
endfunction
function Trig_Death_Wave_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real angle = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), GetSpellTargetX(), GetSpellTargetY())
local real startX = PolarProjectionX(GetUnitX(caster), BlzGetUnitCollisionSize(caster), angle)
local real startY = PolarProjectionY(GetUnitY(caster), BlzGetUnitCollisionSize(caster), angle)
local SpellWave sw = SpellWave.create(caster, startX, startY, 0.0)
set sw.aoeStart = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
set sw.aoeEnd = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_FINAL_AREA_UCS4)
set sw.distance = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DISTANCE_UCS3)
set sw.speed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
set sw.callbackPeriod.duration = 0.15
set sw.targetFilter = Trig_Death_Wave_TargetFilter
set sw.periodCallback = Trig_Death_Wave_Update
set sw.onHit = Trig_Death_Wave_OnHit
call sw.SetDirection(angle, 0.0)
call sw.Begin()
endfunction
//===========================================================================
function InitTrig_Death_Wave takes nothing returns nothing
set gg_trg_Death_Wave = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Death_Wave, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Death_Wave, Condition( function Trig_Death_Wave_Conditions ) )
call TriggerAddAction( gg_trg_Death_Wave, function Trig_Death_Wave_Actions )
endfunction
function Trig_Unholy_Crown_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_UNHOLY_CROWN
endfunction
function Trig_Unholy_Crown_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local real facing = GetUnitFacing(target)
local real hp = GetUnitState(target, UNIT_STATE_LIFE)
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local string effectModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_SPECIAL)
local unit summon = null
local texttag tt = null
call ShowUnitHide(target)
set summon = CreateUnit(GetOwningPlayer(target), SB_DEATH_KNIGHT, x, y, facing)
call SetUnitState(summon, UNIT_STATE_MANA, hp)
call UnitApplyTimedLife(summon, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call AddSpecialEffectTargetOneShot(effectModel, summon, "origin")
call PlaySoundAtPositionSB("Abilities\\Spells\\Other\\Parasite\\Parasite.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, GetUnitX(summon), GetUnitY(summon), 127)
set tt = FloatTextAboveUnitForPlayer(summon, GetOwningPlayer(summon), I2S(R2I(hp)) + "!", 10, 0.0, 0, 0.6, 0.9, 1)
call SetFloatingTextMovement(tt, 2.0, 1.0, 0.0, 16.0)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), summon, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Unholy_Crown takes nothing returns nothing
set gg_trg_Unholy_Crown = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unholy_Crown, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Unholy_Crown, Condition( function Trig_Unholy_Crown_Conditions ) )
call TriggerAddAction( gg_trg_Unholy_Crown, function Trig_Unholy_Crown_Actions )
endfunction
globals
constant real ZOMBIE_PLAGUE_UPDATE_INTERVAL = 0.1
constant key KEY_ZOMBIE_PLAGUE
endglobals
struct ZombiePlague
player buffOwner = null
unit target = null
real summonDelay = 0.0
boolean originalDecayable = false
IntTimer it = 0
method onDestroy takes nothing returns nothing
call BlzSetUnitBooleanField(target, UNIT_BF_DECAYABLE, originalDecayable)
call it.destroy()
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_ZOMBIE_PLAGUE)
endmethod
endstruct
function UpdateZombiePlague takes IntTimer it returns nothing
local ZombiePlague zp = it.owner
local unit tombstone = null
if (not UnitAlive(zp.target)) then
set tombstone = CreateUnit(zp.buffOwner, SB_SPECIAL_EFFECT_UNIT_ZOMBIE_PLAGUE, GetUnitX(zp.target), GetUnitY(zp.target), bj_UNIT_FACING)
call UnitApplyTimedLife(tombstone, SB_BUFF_TIMED_LIFE_GENERIC, zp.summonDelay)
call zp.destroy()
elseif (not UnitHasBuffBJ(zp.target, SB_BUFF_ZOMBIE_PLAGUE)) then
call zp.destroy()
endif
endfunction
function CreateZombiePlague takes unit caster, unit target returns ZombiePlague
local ZombiePlague zp = ZombiePlague.create()
set zp.buffOwner = GetOwningPlayer(caster)
set zp.target = target
set zp.summonDelay = GetUnitAbilityRealLevelField(caster, SB_ZOMBIE_PLAGUE, ABILITY_RLF_DURATION_HERO)
set zp.originalDecayable = BlzGetUnitBooleanField(target, UNIT_BF_DECAYABLE)
set zp.it = CreateIntTimer(zp, false)
call BlzSetUnitBooleanField(target, UNIT_BF_DECAYABLE, false)
call StartTimerPlusPeriodic(zp.it, 0.0, ZOMBIE_PLAGUE_UPDATE_INTERVAL, UpdateZombiePlague, 0)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_ZOMBIE_PLAGUE, zp)
return zp
endfunction
function GetZombiePlague takes unit whichUnit returns ZombiePlague
return LoadInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_ZOMBIE_PLAGUE)
endfunction
function Trig_Zombie_Plague_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ZOMBIE_PLAGUE
endfunction
function Trig_Zombie_Plague_Filter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitNonNeutralAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING) and not IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Zombie_Plague_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local player p = GetOwningPlayer(caster)
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local group hitUnits = null
local unit picked = null
local ZombiePlague zp = 0
call DummyCastInstant(p, x, y, SB_ZOMBIE_PLAGUE_HIDDEN_CASTER, "howlofterror")
set hitUnits = GetUnitsInAOEUnit(x, y, aoe, Trig_Zombie_Plague_Filter, caster)
loop
set picked = FirstOfGroup(hitUnits)
exitwhen picked == null
set zp = GetZombiePlague(picked)
if (zp != 0) then
call zp.destroy()
endif
set zp = CreateZombiePlague(caster, picked)
call GroupRemoveUnit(hitUnits, picked)
endloop
call PlaySBAlertAtPos(p, x, y, SB_ZOMBIE_PLAGUE)
call DestroyGroup(hitUnits)
endfunction
//===========================================================================
function InitTrig_Zombie_Plague_Cast takes nothing returns nothing
set gg_trg_Zombie_Plague_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Zombie_Plague_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Zombie_Plague_Cast, Condition( function Trig_Zombie_Plague_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Zombie_Plague_Cast, function Trig_Zombie_Plague_Cast_Actions )
endfunction
function Trig_Zombie_Plague_Tombstone_Expires_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_SPECIAL_EFFECT_UNIT_ZOMBIE_PLAGUE
endfunction
function Trig_Zombie_Plague_Tombstone_Expires_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
local unit zombie = CreateUnit(GetOwningPlayer(dying), SB_ZOMBIE, GetUnitX(dying), GetUnitY(dying), bj_UNIT_FACING)
call UnitRemoveAbility(zombie, SB_UNDYING)
call UnitApplyTimedLife(zombie, SB_BUFF_TIMED_LIFE_GENERIC, 60.0)
endfunction
//===========================================================================
function InitTrig_Zombie_Plague_Tombstone_Expires takes nothing returns nothing
set gg_trg_Zombie_Plague_Tombstone_Expires = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Zombie_Plague_Tombstone_Expires, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Zombie_Plague_Tombstone_Expires, Condition( function Trig_Zombie_Plague_Tombstone_Expires_Conditions ) )
call TriggerAddAction( gg_trg_Zombie_Plague_Tombstone_Expires, function Trig_Zombie_Plague_Tombstone_Expires_Actions )
endfunction
function InitBlackPyramid takes unit pyramid returns nothing
local unit dummy = null
//call SetUnitVertexColor(pyramid, 255, 255, 255, 0)
call SetUnitPathingSB(pyramid, false)
//set dummy = CreateUnit(GetOwningPlayer(pyramid), SB_SPECIAL_EFFECT_UNIT_PYRAMID, GetUnitX(pyramid), GetUnitX(pyramid), GetUnitFacing(pyramid))
//call SetUnitPathingSB(dummy, false)
//call AddFollowDummy(pyramid, dummy, LIFELINK_KILL)
call EnableTrigger(gg_trg_Black_Pyramid_Loop)
endfunction
function Trig_Black_Pyramid_Init_Loop takes nothing returns nothing
call InitBlackPyramid(GetEnumUnit())
endfunction
function Trig_Black_Pyramid_Init_Actions takes nothing returns nothing
set udg_UnitGroup_BlackPyramids = GetUnitsOfTypeIdAll(SB_BLACK_PYRAMID)
call ForGroupBJ( udg_UnitGroup_BlackPyramids, function Trig_Black_Pyramid_Init_Loop )
endfunction
//===========================================================================
function InitTrig_Black_Pyramid_Init takes nothing returns nothing
set gg_trg_Black_Pyramid_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Black_Pyramid_Init, function Trig_Black_Pyramid_Init_Actions )
endfunction
function Trig_Black_Pyramid_Enter_Conditions takes nothing returns boolean
return GetUnitTypeId(GetEnteringUnit()) == SB_BLACK_PYRAMID
endfunction
function Trig_Black_Pyramid_Enter_Actions takes nothing returns nothing
call GroupAddUnit(udg_UnitGroup_BlackPyramids, GetEnteringUnit())
call InitBlackPyramid(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Black_Pyramid_Enter takes nothing returns nothing
set gg_trg_Black_Pyramid_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Black_Pyramid_Enter, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Black_Pyramid_Enter, Condition( function Trig_Black_Pyramid_Enter_Conditions ) )
call TriggerAddAction( gg_trg_Black_Pyramid_Enter, function Trig_Black_Pyramid_Enter_Actions )
endfunction
function Trig_Black_Pyramid_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_DEATH_BEAM
endfunction
function Trig_Black_Pyramid_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real duration = GetUnitAbilityRealLevelField(caster, SB_DEATH_BEAM, ABILITY_RLF_DURATION_NORMAL)
local unit pyramid = CreateUnit(GetOwningPlayer(caster), SB_BLACK_PYRAMID, GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
call PlaySoundAtPositionSB("Abilities\\Spells\\Other\\Parasite\\Parasite.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, GetUnitX(pyramid), GetUnitY(pyramid), 127.0)
call UnitApplyTimedLife(pyramid, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call SelectUnitForPlayerSingle(pyramid, GetOwningPlayer(caster))
call PlaySBAlertOnUnit(GetOwningPlayer(caster), pyramid, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Black_Pyramid_Cast takes nothing returns nothing
set gg_trg_Black_Pyramid_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Black_Pyramid_Cast, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Black_Pyramid_Cast, Condition( function Trig_Black_Pyramid_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Black_Pyramid_Cast, function Trig_Black_Pyramid_Cast_Actions )
endfunction
globals
constant real BLACK_PYRAMID_LOOP_INTERVAL = 0.1
constant real BLACK_PYRAMID_BLIGHT_RADIUS = 128.0
endglobals
function Trig_Black_Pyramid_Loop_Loop takes nothing returns nothing
local unit pyramid = GetEnumUnit()
local location pyramidLoc = null
if (UnitAlive(pyramid)) then
set pyramidLoc = GetUnitLoc(pyramid)
call SetBlight(GetOwningPlayer(pyramid), GetUnitX(pyramid), GetUnitY(pyramid), BLACK_PYRAMID_BLIGHT_RADIUS, true)
call TerrainDeformationRippleBJ( 0.10, true, pyramidLoc, 150.00, 150.00, 32.00, 0.10, 150.00)
call RemoveLocation(pyramidLoc)
else
call GroupRemoveUnit(udg_UnitGroup_BlackPyramids, pyramid)
endif
endfunction
function Trig_Black_Pyramid_Loop_Actions takes nothing returns nothing
call ForGroup(udg_UnitGroup_BlackPyramids, function Trig_Black_Pyramid_Loop_Loop)
if (CountUnitsInGroup(udg_UnitGroup_BlackPyramids) <= 0) then
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Black_Pyramid_Loop takes nothing returns nothing
set gg_trg_Black_Pyramid_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Black_Pyramid_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Black_Pyramid_Loop, BLACK_PYRAMID_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Black_Pyramid_Loop, function Trig_Black_Pyramid_Loop_Actions )
endfunction
scope KissOfImmortality initializer Init
private struct KissOfImmortalityHeal extends IBuff
real healingRate = 0.0
string teleportTargetArt = null
string teleportToArt = null
endstruct
private function IsTownHall takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_TOWNHALL)
endfunction
private function IsBuilding takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
private function FindClosestNearbyTownHall takes unit whichUnit returns unit
local player whichPlayer = GetOwningPlayer(whichUnit)
local unit closest = null
local real closestDist = BIG_REAL
local real dist = 0.0
local integer size = 0
local group townHalls = CreateGroup()
call GroupEnumUnitsOfPlayer(townHalls, whichPlayer, Condition(function IsTownHall))
if (BlzGroupGetSize(townHalls) < 1) then
call GroupEnumUnitsOfPlayer(townHalls, whichPlayer, Condition(function IsBuilding))
endif
set closest = GroupPickClosestUnit(townHalls, GetUnitX(whichUnit), GetUnitY(whichUnit))
call DestroyGroup(townHalls)
return closest
endfunction
private function OnKissHealEnd takes KissOfImmortalityHeal heal returns nothing
local unit townHall = FindClosestNearbyTownHall(heal.host)
if (townHall != null) then
call AddSpecialEffectOneShot(heal.teleportTargetArt, GetUnitX(heal.host), GetUnitY(heal.host))
call SetUnitPosition(heal.host, GetUnitX(townHall), GetUnitY(townHall))
call AddSpecialEffectOneShot(heal.teleportToArt, GetUnitX(heal.host), GetUnitY(heal.host))
endif
endfunction
private function UpdateKissHeal takes KissOfImmortalityHeal heal returns nothing
local real maxHp = GetUnitState(heal.host, UNIT_STATE_MAX_LIFE)
local real healAmt = maxHp * heal.healingRate * TimerGetElapsed(GetExpiredTimer())
call SetUnitState(heal.host, UNIT_STATE_LIFE, GetUnitState(heal.host, UNIT_STATE_LIFE) + healAmt)
if (GetUnitState(heal.host, UNIT_STATE_LIFE) >= maxHp) then
call DestroyBuff(heal)
endif
endfunction
private function BeginKissHeal takes unit whichUnit returns nothing
local KissOfImmortalityHeal heal = KissOfImmortalityHeal.create()
local unit dummy = null
set heal.host = whichUnit
set heal.onUpdate = UpdateKissHeal
set heal.onRemoved = OnKissHealEnd
set dummy = DummyCastBuff(heal, GetOwningPlayer(whichUnit), SB_BUFF_KISS_OF_IMMORTALITY_HEAL, SB_KISS_OF_IMMORTALITY_HIDDEN_CASTER, "sleep")
set heal.healingRate = GetUnitAbilityRealLevelField(dummy, SB_KISS_OF_IMMORTALITY_HIDDEN_CASTER, ABILITY_RLF_AREA_OF_EFFECT)
set heal.teleportToArt = GetUnitAbilityStringLevelField(dummy, SB_KISS_OF_IMMORTALITY_HIDDEN_CASTER, ABILITY_SLF_AREA_EFFECT)
set heal.teleportTargetArt = GetUnitAbilityStringLevelField(dummy, SB_KISS_OF_IMMORTALITY_HIDDEN_CASTER, ABILITY_SLF_SPECIAL)
endfunction
private struct KissOfImmortalityShield extends IBuff
trigger damageTrigger = null
method onDestroy takes nothing returns nothing
call DestroyTrigger(damageTrigger)
endmethod
endstruct
private function IsLethalDamage takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
return GetEventDamage() >= GetUnitState(damaged, UNIT_STATE_LIFE)
endfunction
private function SaveUnit takes nothing returns nothing
local unit toSave = BlzGetEventDamageTarget()
if (UnitHasAbility(toSave, SB_BUFF_KISS_OF_IMMORTALITY)) then
call BeginKissHeal(toSave)
call UnitRemoveAbility(toSave,SB_BUFF_KISS_OF_IMMORTALITY)
endif
call BlzSetEventDamage(0.0)
endfunction
private function CreateKissOfImmortalityShield takes unit target returns KissOfImmortalityShield
local KissOfImmortalityShield k = KissOfImmortalityShield.create()
set k.host = target
set k.damageTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(k.damageTrigger, target, EVENT_UNIT_DAMAGED)
call TriggerAddCondition(k.damageTrigger, Condition(function IsLethalDamage))
call TriggerAddAction(k.damageTrigger, function SaveUnit)
return k
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local KissOfImmortalityShield k = CreateKissOfImmortalityShield(target)
call TrackBuff(k, SB_BUFF_KISS_OF_IMMORTALITY, 0.25, 0, 0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_KISS_OF_IMMORTALITY, function OnSpellEffect)
endfunction
endscope
scope SuicideAttack initializer Init
globals
private constant real FULL_DAMAGE_AOE_FACTOR = 0.25
private constant real MED_DAMAGE_AOE_FACTOR = 0.5
private constant real MED_DAMAGE_FACTOR = 0.5
private constant real SM_DAMAGE_FACTOR = 0.25
endglobals
private function AOEFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitAlive(filter)) then
return false
elseif (IsUnitNonNeutralAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
endif
return true
endfunction
private function IsSuicideAttack takes nothing returns boolean
local unit damager = GetEventDamageSource()
if (not UnitAlive(damager) or not IsUnitAlive(BlzGetEventDamageTarget())) then
return false
elseif (not UnitHasAbility(damager, SB_SUICIDE_ATTACK)) then
return false
elseif (not BlzGetEventIsAttack()) then
return false
endif
return true
endfunction
private function OnSuicideAttack takes nothing returns nothing
local unit damager = GetEventDamageSource()
local unit target = BlzGetEventDamageTarget()
local real fullAoe = GetUnitAbilityRealLevelField(damager, SB_SUICIDE_ATTACK, ABILITY_RLF_AREA_OF_EFFECT)
local real fullDamage = GetUnitDamageRoll(damager, 0)
local real damage = 0.0
local string art = GetUnitAbilityStringLevelField(damager, SB_SUICIDE_ATTACK, ABILITY_SLF_AREA_EFFECT)
local group nearby = null
local integer count = 0
call BlzSetEventDamage(0.0)
call KillUnit(damager)
set nearby = GetUnitsInAOEOfUnitUnit(damager, fullAoe, AOEFilter, damager)
if (IsUnitNonNeutralAlly(target, GetOwningPlayer(damager))) then
call GroupAddUnit(nearby, target)
endif
set count = BlzGroupGetSize(nearby)
loop
set count = count - 1
exitwhen count < 0
set target = BlzGroupUnitAt(nearby, count)
if (IsUnitInRange(damager, target, fullAoe * FULL_DAMAGE_AOE_FACTOR)) then
set damage = fullDamage
elseif (IsUnitInRange(damager, target, fullAoe * MED_DAMAGE_AOE_FACTOR)) then
set damage = fullDamage * MED_DAMAGE_FACTOR
else
set damage = fullDamage * SM_DAMAGE_FACTOR
endif
call UnitDamageTarget(damager, target, damage, false, false, BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
endloop
call AddSpecialEffectOneShotEx(art, GetUnitX(damager), GetUnitY(damager), GetUnitFlyHeight(damager), 1.0, 1.0)
call RemoveUnit(damager)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_DAMAGING, function IsSuicideAttack, function OnSuicideAttack)
call GateAbilityTrigger(t, SB_SUICIDE_ATTACK, 0)
endfunction
endscope
function Trig_Return_to_Haunt_Damaged_Conditions takes nothing returns boolean
return UnitHasAbility(BlzGetEventDamageTarget(), SB_RETURN_TO_HAUNT) and BlzGetEventIsAttack()
endfunction
function Trig_Return_to_Haunt_Damaged_Actions takes nothing returns nothing
call BlzStartUnitAbilityCooldown(BlzGetEventDamageTarget(), SB_RETURN_TO_HAUNT, 4.0)
endfunction
//===========================================================================
function InitTrig_Return_to_Haunt_Damaged takes nothing returns nothing
set gg_trg_Return_to_Haunt_Damaged = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Return_to_Haunt_Damaged, EVENT_PLAYER_UNIT_DAMAGED )
call TriggerAddCondition( gg_trg_Return_to_Haunt_Damaged, Condition( function Trig_Return_to_Haunt_Damaged_Conditions ) )
call TriggerAddAction( gg_trg_Return_to_Haunt_Damaged, function Trig_Return_to_Haunt_Damaged_Actions )
call GateAbilityTrigger(gg_trg_Return_to_Haunt_Damaged, SB_RETURN_TO_HAUNT, 0)
endfunction
scope UnholyBanner initializer Init
globals
private string SOUND_EFFECT = "Units\\Orc\\HealingWard\\PlaceAncestralGuardian.flac"
private real SOUND_EFFECT_PITCH = 0.65
endglobals
private function UnholyBannerPlaced takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real unblightedDuration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local unit banner = CreateUnit(GetOwningPlayer(caster), SB_UNHOLY_BANNER_UNIT, x, y, bj_UNIT_FACING)
if (IsPointBlighted(x, y)) then
call UnitAddAbility(banner, SB_BLIGHT_GROWTH_768)
else
call UnitApplyTimedLife(banner, SB_BUFF_TIMED_LIFE_GENERIC, unblightedDuration)
call SetUnitTimeScale(banner, 0.0)
endif
call PlayPitchedSoundAtPositionSB(SOUND_EFFECT, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 100.0, SOUND_EFFECT_PITCH)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_UNHOLY_BANNER, function UnholyBannerPlaced)
endfunction
endscope
function Trig_Carriage_Init_Actions takes nothing returns nothing
local group carriages = GetUnitsOfTypeIdAll(SB_PHANTOM_CARRIAGE)
local unit picked = null
loop
set picked = FirstOfGroup(carriages)
exitwhen carriages == null
call BlzUnitDisableAbility(picked, SB_CARGO_HOLD_PHANTOM_CARRIAGE, true, false)
call GroupRemoveUnit(carriages, picked)
endloop
call DestroyGroup(carriages)
endfunction
//===========================================================================
function InitTrig_Carriage_Init takes nothing returns nothing
set gg_trg_Carriage_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Carriage_Init, function Trig_Carriage_Init_Actions )
endfunction
function Trig_Carriage_Enters_Conditions takes nothing returns boolean
return GetUnitTypeId(GetEnteringUnit()) == SB_PHANTOM_CARRIAGE
endfunction
function Trig_Carriage_Enters_Actions takes nothing returns nothing
call BlzUnitDisableAbility(GetEnteringUnit(), SB_CARGO_HOLD_PHANTOM_CARRIAGE, true, false)
endfunction
//===========================================================================
function InitTrig_Carriage_Enters takes nothing returns nothing
set gg_trg_Carriage_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Carriage_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Carriage_Enters, Condition( function Trig_Carriage_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Carriage_Enters, function Trig_Carriage_Enters_Actions )
endfunction
function Trig_Carriage_Land_Command_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_LAND_DUMMY
endfunction
function Trig_Carriage_Land_Command_Actions takes nothing returns nothing
call IssueImmediateOrder(GetSpellAbilityUnit(), "stop")
call IssueImmediateOrderAfter(GetSpellAbilityUnit(), "ravenform", 0.001)
endfunction
//===========================================================================
function InitTrig_Carriage_Land_Command takes nothing returns nothing
set gg_trg_Carriage_Land_Command = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Carriage_Land_Command, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Carriage_Land_Command, Condition( function Trig_Carriage_Land_Command_Conditions ) )
call TriggerAddAction( gg_trg_Carriage_Land_Command, function Trig_Carriage_Land_Command_Actions )
endfunction
function Trig_Carriage_Land_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_LAND
endfunction
function Trig_Carriage_Land_Timer_Loop takes UnitTimer ut returns nothing
local unit carriage = ut.owner
if (GetUnitTypeId(carriage) == SB_PHANTOM_CARRIAGE_LANDED) then
call BlzUnitDisableAbility(carriage, SB_CARGO_HOLD_PHANTOM_CARRIAGE, false, false)
call IssueImmediateOrder(carriage, "unloadallinstant")
call ut.destroy()
endif
endfunction
function Trig_Carriage_Land_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local UnitTimer ut = 0
local integer unitTypeId = GetUnitTypeId(GetSpellAbilityUnit())
local real blightRadius = GetUnitAbilityRealLevelField(caster, SB_BLIGHT_GROWTH_512, ABILITY_RLF_AREA_OF_EFFECT)
if (unitTypeId == SB_PHANTOM_CARRIAGE) then
set ut = CreateUnitTimer(GetSpellAbilityUnit(), false)
call StartTimerPlusPeriodic(ut, 0.0, 0.05, Trig_Carriage_Land_Timer_Loop, 0)
else
call BlzUnitDisableAbility(caster, SB_CARGO_HOLD_PHANTOM_CARRIAGE, true, false)
call RepealBlight(GetOwningPlayer(caster), GetUnitX(caster), GetUnitY(caster), blightRadius)
endif
endfunction
//===========================================================================
function InitTrig_Carriage_Land takes nothing returns nothing
set gg_trg_Carriage_Land = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Carriage_Land, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Carriage_Land, Condition( function Trig_Carriage_Land_Conditions ) )
call TriggerAddAction( gg_trg_Carriage_Land, function Trig_Carriage_Land_Actions )
endfunction
scope Haunt initializer Init
private function OnMissileHit takes PointMissile missile, real x, real y returns nothing
local real duration = GetUnitAbilityRealLevelField(missile.owner, SB_HAUNT, ABILITY_RLF_DURATION_NORMAL)
local unit ward = CreateUnit(GetOwningPlayer(missile.owner), SB_UNIT_HAUNT, x, y, bj_UNIT_FACING)
call UnitApplyTimedLife(ward, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call SetUnitAnimation(ward, "birth")
call QueueUnitAnimation(ward, "stand")
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local string missileArt = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_MISSILE_ART)
local real missileSpeed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local real missileArc = GetUnitAbilityRealField(caster, GetSpellAbilityId(), ABILITY_RF_ARF_MISSILE_ARC)
local PointMissile missile = CreatePointMissile(missileArt, caster, GetUnitX(caster), GetUnitY(caster), 60.0, 0.0, 0.0)
call FirePointMissile(missile, missileSpeed, x, y, 0.0, missileArc, OnMissileHit)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_HAUNT, function OnSpellEffect)
endfunction
endscope
struct PlagueDive
unit caster = null
real initialDistance = 0.0
real initialFlyHeight = 0.0
real x = 0.0
real y = 0.0
real aoe = 0.0
real speed = 0.0
real arcFactor = 0.0
real damageInterval = 0.25
real damagePerSecond = 0.0
endstruct
struct PlagueBuff
unit host = null
real damagePerSecond = 0.0
endstruct
function CreatePlagueDive takes unit caster, real x, real y returns PlagueDive
local PlagueDive p = PlagueDive.create()
set p.caster = caster
set p.initialDistance = DistanceBetweenUnitAndPoint(caster, x, y)
set p.initialFlyHeight = GetUnitFlyHeight(caster)
set p.x = x
set p.y = y
set p.aoe = GetUnitAbilityRealLevelField(caster, SB_PLAGUE_DIVE, ABILITY_RLF_AREA_OF_EFFECT)
set p.speed = GetUnitAbilityIntegerField(caster, SB_PLAGUE_DIVE, ABILITY_IF_MISSILE_SPEED)
set p.arcFactor = GetUnitAbilityRealField(caster, SB_PLAGUE_DIVE, ABILITY_RF_ARF_MISSILE_ARC)
set p.damageInterval = GetUnitAbilityRealLevelField(caster, SB_PLAGUE_DIVE, ABILITY_RLF_DURATION_NORMAL)
set p.damagePerSecond = GetUnitAbilityRealLevelField(caster, SB_PLAGUE_DIVE, ABILITY_RLF_DAMAGE_HBZ2)
return p
endfunction
function CreatePlagueBuff takes unit host, real damagePerSecond returns PlagueBuff
local PlagueBuff pb = PlagueBuff.create()
set pb.host = host
set damagePerSecond = 0.0
return pb
endfunction
globals
constant key KEY_PLAGUE_DIVE
constant real PLAGUE_DIVE_AOE_BUFFER = 100.0
endglobals
function Trig_Plague_Dive_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_PLAGUE_DIVE
endfunction
function Trig_Plague_Dive_Explosion_Filter takes PlagueDive pd returns boolean
local unit filter = GetFilterUnit()
return UnitHasBuffBJ(filter, SB_BUFF_PLAGUE)
endfunction
function Trig_Plague_Dive_DOT takes IntTimer it returns nothing
local PlagueBuff pb = it.owner
local real damage = 0.0
if (UnitHasBuffBJ(pb.host, SB_BUFF_PLAGUE)) then
set damage = RMinBJ(pb.damagePerSecond, GetUnitState(pb.host, UNIT_STATE_LIFE) - 1.0)
call ChangeUnitState(pb.host, UNIT_STATE_LIFE, -damage)
else
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(pb.host), KEY_PLAGUE_DIVE)
call pb.destroy()
call it.destroy()
endif
endfunction
function Trig_Plague_Dive_Explosion takes IntTimer it returns nothing
local PlagueDive pd = it.owner
local PlagueBuff pb = 0
local UnitTimer dotTimer = 0
local group unitsInAoe = GetUnitsInAOEInt(pd.x, pd.y, pd.aoe + PLAGUE_DIVE_AOE_BUFFER, Trig_Plague_Dive_Explosion_Filter, pd)
local unit picked = null
loop
set picked = FirstOfGroup(unitsInAoe)
exitwhen picked == null
set dotTimer = LoadInteger(udg_HashTable_Timers, GetHandleId(picked), KEY_PLAGUE_DIVE)
if (dotTimer == 0) then
set pb = CreatePlagueBuff(picked, pd.damagePerSecond)
set dotTimer = CreateIntTimer(pb, false)
call SaveInteger(udg_HashTable_Timers, GetHandleId(picked), KEY_PLAGUE_DIVE, dotTimer)
endif
set pb.damagePerSecond = RMaxBJ(pb.damagePerSecond, pd.damagePerSecond)
call StartTimerPlusPeriodic(dotTimer, 0.0, pd.damageInterval, Trig_Plague_Dive_DOT, 0)
call GroupRemoveUnit(unitsInAoe, picked)
endloop
call DestroyGroup(unitsInAoe)
call pd.destroy()
endfunction
function Trig_Plague_Dive_Update takes IntTimer it returns nothing
local PlagueDive pd = it.owner
local real dist = DistanceBetweenUnitAndPoint(pd.caster, pd.x, pd.y)
local real speed = pd.speed * TimerPlusGetElapsed(it)
local real angle = AngleBetweenPointsXY(GetUnitX(pd.caster), GetUnitY(pd.caster), pd.x, pd.y)
local real x = 0.0
local real y = 0.0
local boolean done = false
local real f = 0.0
if (not UnitAlive(pd.caster)) then
call it.destroy()
call pd.destroy()
else
if (dist <= speed) then
set done = true
set speed = dist
endif
set x = PolarProjectionX(GetUnitX(pd.caster), speed, angle)
set y = PolarProjectionY(GetUnitY(pd.caster), speed, angle)
if (not RectContainsCoords(GetPlayableMapRect(), x, y)) then
set done = true
set x = GetUnitX(pd.caster)
set y = GetUnitY(pd.caster)
endif
set f = Pow(DBZ(dist, pd.initialDistance, 1.0), pd.arcFactor)
call SetUnitPosition(pd.caster, x, y)
call SetUnitFlyHeight(pd.caster, (pd.initialFlyHeight - 90.0) * f + 90.0, 0.0)
if (done) then
call DummyCastPoint(Player(PLAYER_NEUTRAL_PASSIVE), x, y, x, y, SB_PLAGUE_DIVE_EFFECT, "flamestrike")
call DummyCastInstant(GetOwningPlayer(pd.caster), x, y, SB_PLAGUE_DIVE_HIDDEN_CASTER, "howlofterror")
call KillUnit(pd.caster)
set it.oneShot = true
call StartTimerPlus(it, 0.0, Trig_Plague_Dive_Explosion)
endif
endif
endfunction
function Trig_Plague_Dive_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real updateInterval = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_HERO)
local PlagueDive pd = CreatePlagueDive(caster, GetSpellTargetX(), GetSpellTargetY())
local IntTimer it = CreateIntTimer(pd, false)
call StartTimerPlusPeriodic(it, 0.0, updateInterval, Trig_Plague_Dive_Update, 0)
endfunction
//===========================================================================
function InitTrig_Plague_Dive takes nothing returns nothing
set gg_trg_Plague_Dive = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Plague_Dive, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Plague_Dive, Condition( function Trig_Plague_Dive_Conditions ) )
call TriggerAddAction( gg_trg_Plague_Dive, function Trig_Plague_Dive_Actions )
endfunction
globals
constant key KEY_SWOOP
constant key KEY_SWOOP_2
constant real SWOOP_UPDATE_INTERVAL = 0.01
constant real SWOOP_ARC_FACTOR = 2
constant real SWOOP_SPEED = 1500
constant real SWOOP_RETURN_DISTANCE = 800
constant real SWOOP_MIN_FLY_HEIGHT = 90.0
endglobals
function SwoopUpdate takes IntTimer t returns nothing
local Swoop instance = LoadInteger(udg_HashTable_Timers, KEY_SWOOP, t)
call instance.updateCallback.evaluate(instance)
endfunction
struct Swoop
unit caster = null
unit target = null
location start = null
location end = null
real speed = 1500.0
real arcFactor = 2.0
real returnDistance = 800.0
real flyHeightStart = 0.0
real selectionCircleStart = 0.0
IntFunc updateCallback = 0
IntFunc endCallback = 0
IntTimer updateLoop = 0
static method create takes unit caster, unit target returns Swoop
local Swoop instance = Swoop.allocate()
set instance.caster = caster
set instance.target = target
set instance.start = GetUnitLoc(caster)
set instance.flyHeightStart = GetUnitFlyHeight(caster)
set instance.selectionCircleStart = BlzGetUnitRealField(caster, UNIT_RF_SELECTION_CIRCLE_HEIGHT)
set instance.updateLoop = CreateIntTimer(instance, false)
return instance
endmethod
method Start takes IntFunc update returns nothing
set updateCallback = update
call RemoveSavedHandle(udg_HashTable_Timers, KEY_SWOOP, updateLoop)
call SaveInteger(udg_HashTable_Timers, KEY_SWOOP, updateLoop, this)
call updateLoop.StartPeriodic(BIG_REAL, SWOOP_UPDATE_INTERVAL, SwoopUpdate, 0)
endmethod
method onDestroy takes nothing returns nothing
if (endCallback != 0) then
call endCallback.evaluate(this)
endif
call updateLoop.destroy()
call RemoveLocation(start)
call RemoveLocation(end)
call RemoveSavedInteger(udg_HashTable_Timers, KEY_SWOOP, updateLoop)
endmethod
endstruct
function Trig_Swoop_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SWOOP
endfunction
function Trig_Swoop_Loop takes Swoop swoop returns nothing
local unit caster = swoop.caster
local unit target = swoop.target
local location targetLoc = null
local real dist = 0.0
local real currentDist = 0.0
local real flyHeight = 0.0
local real x = 0.0
local real y = 0.0
local real speed = swoop.speed * SWOOP_UPDATE_INTERVAL
local real angle = 0.0
local real targetFlyHeight = SWOOP_MIN_FLY_HEIGHT
local real defaultFlyHeight = GetUnitDefaultFlyHeight(caster)
if (UnitAlive(caster) and target != null) then
set targetFlyHeight = RMinBJ(targetFlyHeight + GetUnitDefaultFlyHeight(target), defaultFlyHeight)
if (swoop.end == null) then
set targetLoc = GetUnitLoc(target)
set angle = AngleBetweenUnits(caster, target)
set dist = DistanceBetweenPoints(swoop.start, targetLoc)
set currentDist = DistanceBetweenUnits(caster, target)
if (currentDist > speed) then
set x = PolarProjectionX(GetUnitX(caster), speed, angle)
set y = PolarProjectionY(GetUnitY(caster), speed, angle)
set flyHeight = Pow(DBZ(currentDist, dist, 1), swoop.arcFactor) * (swoop.flyHeightStart - targetFlyHeight) + targetFlyHeight
call SetUnitX(caster, x)
call SetUnitY(caster, y)
call SetUnitPosition(caster, x, y)
call SetUnitFacing(caster, angle)
call SetUnitAnimation(caster, "walk")
call SetUnitFlyHeight(caster, flyHeight, 0)
else
call SetUnitPosition(caster, GetLocationX(targetLoc), GetLocationY(targetLoc))
call SetUnitFlyHeight(caster, targetFlyHeight, 0)
set angle = AngleBetweenPointsXY(GetLocationX(swoop.start), GetLocationY(swoop.start), GetUnitX(caster), GetUnitY(caster))
call RemoveLocation(swoop.start)
set swoop.start = GetUnitLoc(caster)
set swoop.end = PolarProjectionBJ(targetLoc, swoop.returnDistance, angle)
call AddSpecialEffectTargetOneShot("Abilities\\Weapons\\GargoyleMissile\\GargoyleMissile.mdl", target, "chest")
call UnitSimulateAttack(caster, target, 0)
endif
call RemoveLocation(targetLoc)
else
set angle = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), GetLocationX(swoop.end), GetLocationY(swoop.end))
set dist = DistanceBetweenPoints(swoop.start, swoop.end)
set currentDist = DistanceBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), GetLocationX(swoop.end), GetLocationY(swoop.end))
if (currentDist > speed) then
set x = PolarProjectionX(GetUnitX(caster), speed, angle)
set y = PolarProjectionY(GetUnitY(caster), speed, angle)
set flyHeight = Pow(1 - DBZ(currentDist, dist, 0), swoop.arcFactor) * (defaultFlyHeight - targetFlyHeight) + targetFlyHeight
call SetUnitPosition(caster, x, y)
call SetUnitFacing(caster, angle)
call SetUnitAnimation(caster, "walk")
call SetUnitFlyHeight(caster, flyHeight, 0)
else
call SetUnitPosition(caster, GetLocationX(swoop.end), GetLocationY(swoop.end))
call SetUnitFlyHeight(caster, defaultFlyHeight, 0)
call swoop.destroy()
endif
endif
else
call SetUnitFlyHeight(caster, defaultFlyHeight, 0.5)
call swoop.destroy()
endif
endfunction
function Trig_Swoop_End takes Swoop swoop returns nothing
local effect sfxLeft = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(swoop.caster), KEY_SWOOP)
local effect sfxRight = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(swoop.caster), KEY_SWOOP_2)
if (UnitAlive(swoop.caster)) then
call ResetUnitAnimation(swoop.caster)
endif
call DestroyEffect(sfxLeft)
call DestroyEffect(sfxRight)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(swoop.caster), KEY_SWOOP)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(swoop.caster), KEY_SWOOP_2)
endfunction
function Trig_Swoop_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local effect sfxLeft = AddSpecialEffectTarget(GetUnitAbilityStringLevelField(caster, SB_SWOOP, ABILITY_SLF_MISSILE_ART), caster, "hand left")
local effect sfxRight = AddSpecialEffectTarget(GetUnitAbilityStringLevelField(caster, SB_SWOOP, ABILITY_SLF_MISSILE_ART), caster, "hand right")
local Swoop swoop = Swoop.create(caster, GetSpellTargetUnit())
set swoop.speed = I2R(GetUnitAbilityIntegerField(caster, SB_SWOOP, ABILITY_IF_MISSILE_SPEED))
set swoop.arcFactor = GetUnitAbilityRealField(caster, SB_SWOOP, ABILITY_RF_ARF_MISSILE_ARC)
set swoop.returnDistance = GetUnitAbilityRealLevelField(caster, SB_SWOOP, ABILITY_RLF_AREA_OF_EFFECT)
set swoop.endCallback = Trig_Swoop_End
call swoop.Start(Trig_Swoop_Loop)
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(caster), KEY_SWOOP, sfxLeft)
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(caster), KEY_SWOOP_2, sfxRight)
endfunction
//===========================================================================
function InitTrig_Swoop takes nothing returns nothing
set gg_trg_Swoop = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Swoop, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Swoop, Condition( function Trig_Swoop_Conditions ) )
call TriggerAddAction( gg_trg_Swoop, function Trig_Swoop_Actions )
endfunction
globals
constant key KEY_BLIGHT_ARMOR
endglobals
globals
constant real Blight_ARMOR_LOOP_INTERVAL = 1.00
endglobals
function Trig_Blight_Armor_Loop_Loop takes nothing returns nothing
local unit necro = GetEnumUnit()
local effect sfx = null
local boolean blighted = IsPointBlighted(GetUnitX(necro), GetUnitY(necro))
if (blighted and GetUnitAbilityLevel(necro, SB_BLIGHT_ARMOR) < 2) then
call SetUnitAbilityLevel(necro, SB_BLIGHT_ARMOR, 2)
set sfx = AddSpecialEffectTargetUnitBJ("origin", necro, "war3mapImported\\BlightArmor.mdx")
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(necro), KEY_BLIGHT_ARMOR, sfx)
elseif (not blighted and GetUnitAbilityLevel(necro, SB_BLIGHT_ARMOR) > 1) then
call SetUnitAbilityLevel(necro, SB_BLIGHT_ARMOR, 1)
call UnitRemoveBuffBJ(SB_BUFF_BLIGHT_ARMOR, necro)
set sfx = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(necro), KEY_BLIGHT_ARMOR)
call DestroyEffect(sfx)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(necro), KEY_BLIGHT_ARMOR)
endif
endfunction
function Trig_Blight_Armor_Loop_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_BlightBonus)
if (size > 0) then
call ForGroupBJ(udg_UnitGroup_BlightBonus, function Trig_Blight_Armor_Loop_Loop)
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Blight_Armor_Loop takes nothing returns nothing
set gg_trg_Blight_Armor_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Blight_Armor_Loop)
call TriggerRegisterTimerEventPeriodic( gg_trg_Blight_Armor_Loop, Blight_ARMOR_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Blight_Armor_Loop, function Trig_Blight_Armor_Loop_Actions )
endfunction
globals
constant key KEY_ABSORB_LUMBER
endglobals
struct AbsorbLumber
unit harvester = null
real lumberStored = 0.0
destructable lastTree = null
boolean expired = false
boolean paused = false
IntTimer updateTimer = 0
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(udg_HashTable_Resources, GetHandleId(harvester), KEY_ABSORB_LUMBER)
call updateTimer.destroy()
endmethod
endstruct
function UnitHasAbsorbLumber takes unit whichUnit returns boolean
return UnitHasAbility(whichUnit, SB_ABSORB_LUMBER) or UnitHasAbility(whichUnit, SB_ABSORB_LUMBER_NECROPOLIS)
endfunction
function GetUnitAbsorbLumber takes unit whichUnit returns integer
if (UnitHasAbility(whichUnit, SB_ABSORB_LUMBER)) then
return SB_ABSORB_LUMBER
else
return SB_ABSORB_LUMBER_NECROPOLIS
endif
endfunction
function AbsorbLumberReturnLumber takes AbsorbLumber al returns nothing
local player p = GetOwningPlayer(al.harvester)
local force nonPlayerForce = GetAllPlayersExcept(p)
local integer lumberReturned = R2I(al.lumberStored)
local location loc = GetUnitLoc(al.harvester)
call AdjustPlayerStateBJ(lumberReturned, p, PLAYER_STATE_RESOURCE_LUMBER)
call AdjustPlayerStateBJ(lumberReturned, p, PLAYER_STATE_LUMBER_GATHERED)
set al.lumberStored = al.lumberStored - lumberReturned
call BlzUnitDisableAbility(al.harvester, SB_RETURN_RESOURCES_BLIGHT_FACTORY, true, true)
call CreateTextTagLocBJ( ( "+" + I2S(lumberReturned) ), loc, 400.00, 10, 0.00, 78.00, 31.25, 0 )
call SetTextTagPermanentBJ( GetLastCreatedTextTag(), false )
call ShowTextTagForceBJ( false, GetLastCreatedTextTag(), nonPlayerForce)
call SetTextTagVelocityBJ( GetLastCreatedTextTag(), 100.00, 90 )
call SetTextTagLifespanBJ( GetLastCreatedTextTag(), 3.00 )
call SetTextTagFadepointBJ( GetLastCreatedTextTag(), 2.00 )
call RemoveLocation(loc)
call DestroyForce(nonPlayerForce)
endfunction
function AbsorbLumberExpires takes AbsorbLumber al returns nothing
local player p = GetOwningPlayer(al.harvester)
local force playerForce = GetForceOfPlayer(p)
set al.expired = true
if (not IsUnitType(al.harvester, UNIT_TYPE_TOWNHALL)) then
call AddUnitAnimationProperties(al.harvester, "work", false)
endif
call DisplayTextToPlayer(p, 0, 0, "|cffffcc00A " + GetUnitName(al.harvester) + " has run out of trees to absorb.|r")
call PingMinimapForPlayer(p, GetUnitX(al.harvester), GetUnitY(al.harvester), 2.0)
call PingMinimapForForceEx(playerForce, GetUnitX(al.harvester), GetUnitY(al.harvester), 2.00, bj_MINIMAPPINGSTYLE_SIMPLE, 100, 100, 0)
call SetCameraQuickPositionForPlayer(p, GetUnitX(al.harvester), GetUnitY(al.harvester))
call PlaySoundForPlayer("Sound\\Destructibles\\TreeFall3.flac", p)
call DestroyForce(playerForce)
endfunction
function AbsorbLumberLoop takes IntTimer it returns nothing
local AbsorbLumber al = it.owner
local unit caster = al.harvester
local integer abilityId = GetUnitAbsorbLumber(caster)
local real damageToTree = 0.0
local real returnThreshold = 0.0
local real aoe = 0.0
local string vfx = null
if (al.paused) then
return
endif
if (UnitAlive(caster) and UnitHasAbsorbLumber(caster)) then
if (al.lastTree == null or IsDestructableDeadBJ(al.lastTree)) then
set aoe = GetUnitAbilityRealLevelField(caster, abilityId, ABILITY_RLF_AREA_OF_EFFECT)
set al.lastTree = GetRandomLivingTreeInRange(GetUnitX(caster), GetUnitY(caster), aoe)
endif
if (al.lastTree != null) then
set damageToTree = GetUnitAbilityRealLevelField(caster, abilityId, ABILITY_RLF_DISTRIBUTED_DAMAGE_FACTOR_NCA1)
set returnThreshold = GetUnitAbilityRealLevelField(caster, abilityId, ABILITY_RLF_CAST_RANGE)
set vfx = GetUnitAbilityStringLevelField(caster, abilityId, ABILITY_SLF_EFFECT)
call AddSpecialEffectOneShot(vfx, GetDestructableX(al.lastTree), GetDestructableY(al.lastTree))
call UnitDamageTarget(caster, al.lastTree, damageToTree, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
set al.lumberStored = al.lumberStored + damageToTree
if (not IsUnitType(al.harvester, UNIT_TYPE_TOWNHALL)) then
call AddUnitAnimationProperties(caster, "work", true)
endif
if (al.lumberStored >= returnThreshold) then
call AbsorbLumberReturnLumber(al)
elseif (al.lumberStored == damageToTree) then
call BlzUnitDisableAbility(caster, SB_RETURN_RESOURCES_BLIGHT_FACTORY, false, false)
endif
elseif (not al.expired) then
call AbsorbLumberExpires(al)
endif
else
call al.destroy()
endif
endfunction
function CreateAbsorbLumber takes unit whichUnit returns AbsorbLumber
local AbsorbLumber al = AbsorbLumber.create()
local integer abilityId = GetUnitAbsorbLumber(whichUnit)
local real interval = GetUnitAbilityRealLevelField(whichUnit, abilityId, ABILITY_RLF_DURATION_NORMAL)
set al.updateTimer = CreateIntTimer(al, false)
set al.harvester = whichUnit
call StartTimerPlusPeriodic(al.updateTimer, 0.0, interval, AbsorbLumberLoop, 0)
call SaveInteger(udg_HashTable_Resources, GetHandleId(whichUnit), KEY_ABSORB_LUMBER, al)
return al
endfunction
function Trig_Absorb_Lumber_Init_Filter takes nothing returns boolean
return UnitHasAbsorbLumber(GetFilterUnit())
endfunction
function Trig_Absorb_Lumber_Init_Actions takes nothing returns nothing
local group absorbLumberUnits = GetUnitsInRectMatching(GetEntireMapRect(), Condition(function Trig_Absorb_Lumber_Init_Filter))
local unit picked = null
loop
set picked = FirstOfGroup(absorbLumberUnits)
exitwhen picked == null
call CreateAbsorbLumber(picked)
call GroupRemoveUnit(absorbLumberUnits, picked)
endloop
call DestroyGroup(absorbLumberUnits)
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Init takes nothing returns nothing
set gg_trg_Absorb_Lumber_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Absorb_Lumber_Init, function Trig_Absorb_Lumber_Init_Actions )
endfunction
function Trig_Absorb_Lumber_Construction_Done_Conditions takes nothing returns boolean
return UnitHasAbsorbLumber(GetTriggerUnit())
endfunction
function Trig_Absorb_Lumber_Construction_Done_Actions takes nothing returns nothing
call CreateAbsorbLumber(GetTriggerUnit())
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Construction_Done takes nothing returns nothing
set gg_trg_Absorb_Lumber_Construction_Done = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Absorb_Lumber_Construction_Done, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH )
call TriggerAddCondition( gg_trg_Absorb_Lumber_Construction_Done, Condition( function Trig_Absorb_Lumber_Construction_Done_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Construction_Done, function Trig_Absorb_Lumber_Construction_Done_Actions )
endfunction
function Trig_Absorb_Lumber_Enters_Conditions takes nothing returns boolean
local unit entering = GetEnteringUnit()
return UnitHasAbsorbLumber(entering) and GetUnitLifePercent(entering) >= 100.0
endfunction
function Trig_Absorb_Lumber_Enters_Actions takes nothing returns nothing
call CreateAbsorbLumber(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Enters takes nothing returns nothing
set gg_trg_Absorb_Lumber_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple(gg_trg_Absorb_Lumber_Enters, GetEntireMapRect())
call TriggerAddCondition( gg_trg_Absorb_Lumber_Enters, Condition( function Trig_Absorb_Lumber_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Enters, function Trig_Absorb_Lumber_Enters_Actions )
endfunction
function Trig_Absorb_Lumber_Return_Resources_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RETURN_RESOURCES_BLIGHT_FACTORY
endfunction
function Trig_Absorb_Lumber_Return_Resources_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local AbsorbLumber instance = LoadInteger(udg_HashTable_Resources, GetHandleId(caster), KEY_ABSORB_LUMBER)
if (instance != 0 and instance.lumberStored >= 1.0) then
call AbsorbLumberReturnLumber(instance)
endif
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Return_Resources takes nothing returns nothing
set gg_trg_Absorb_Lumber_Return_Resources = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Absorb_Lumber_Return_Resources, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Absorb_Lumber_Return_Resources, Condition( function Trig_Absorb_Lumber_Return_Resources_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Return_Resources, function Trig_Absorb_Lumber_Return_Resources_Actions )
endfunction
function Trig_Absorb_Lumber_Upgrade_Start_Conditions takes nothing returns boolean
return UnitHasAbsorbLumber(GetTriggerUnit())
endfunction
function Trig_Absorb_Lumber_Upgrade_Start_Actions takes nothing returns nothing
local AbsorbLumber al = LoadInteger(udg_HashTable_Resources, GetHandleId(GetTriggerUnit()), KEY_ABSORB_LUMBER)
if (al != 0) then
set al.paused = true
endif
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Upgrade_Start takes nothing returns nothing
set gg_trg_Absorb_Lumber_Upgrade_Start = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Absorb_Lumber_Upgrade_Start, EVENT_PLAYER_UNIT_UPGRADE_START )
call TriggerAddCondition( gg_trg_Absorb_Lumber_Upgrade_Start, Condition( function Trig_Absorb_Lumber_Upgrade_Start_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Upgrade_Start, function Trig_Absorb_Lumber_Upgrade_Start_Actions )
endfunction
function Trig_Absorb_Lumber_Upgrade_Cancel_Conditions takes nothing returns boolean
return HaveSavedInteger(udg_HashTable_Resources, GetHandleId(GetTriggerUnit()), KEY_ABSORB_LUMBER)
endfunction
function Trig_Absorb_Lumber_Upgrade_Cancel_Actions takes nothing returns nothing
local AbsorbLumber al = LoadInteger(udg_HashTable_Resources, GetHandleId(GetTriggerUnit()), KEY_ABSORB_LUMBER)
if (al != 0) then
set al.paused = false
endif
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Upgrade_Cancel takes nothing returns nothing
set gg_trg_Absorb_Lumber_Upgrade_Cancel = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Absorb_Lumber_Upgrade_Cancel, EVENT_PLAYER_UNIT_UPGRADE_CANCEL)
call TriggerAddCondition( gg_trg_Absorb_Lumber_Upgrade_Cancel, Condition( function Trig_Absorb_Lumber_Upgrade_Cancel_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Upgrade_Cancel, function Trig_Absorb_Lumber_Upgrade_Cancel_Actions )
endfunction
function Trig_Absorb_Lumber_Upgrade_Finish_Conditions takes nothing returns boolean
return HaveSavedInteger(udg_HashTable_Resources, GetHandleId(GetTriggerUnit()), KEY_ABSORB_LUMBER)
endfunction
function Trig_Absorb_Lumber_Upgrade_Finish_Actions takes nothing returns nothing
local AbsorbLumber al = LoadInteger(udg_HashTable_Resources, GetHandleId(GetTriggerUnit()), KEY_ABSORB_LUMBER)
if (al != 0) then
call al.destroy()
endif
endfunction
//===========================================================================
function InitTrig_Absorb_Lumber_Upgrade_Finish takes nothing returns nothing
set gg_trg_Absorb_Lumber_Upgrade_Finish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Absorb_Lumber_Upgrade_Finish, EVENT_PLAYER_UNIT_UPGRADE_FINISH)
call TriggerAddCondition( gg_trg_Absorb_Lumber_Upgrade_Finish, Condition( function Trig_Absorb_Lumber_Upgrade_Finish_Conditions ) )
call TriggerAddAction( gg_trg_Absorb_Lumber_Upgrade_Finish, function Trig_Absorb_Lumber_Upgrade_Finish_Actions )
endfunction
scope HydePotionAoe initializer Init
private function TargetFilter takes unit hit returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitAlly(filter, GetOwningPlayer(hit))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_MELEE_ATTACKER) and not IsUnitType(filter, UNIT_TYPE_RANGED_ATTACKER)) then
return false
endif
if (IsUnitType(hit, UNIT_TYPE_FLYING) and IsUnitType(filter, UNIT_TYPE_FLYING)) then
return true
elseif (IsUnitType(hit, UNIT_TYPE_GROUND) and IsUnitType(filter, UNIT_TYPE_GROUND)) then
return true
endif
return false
endfunction
private function OnMissileHit takes TargetMissile missile, real x, real y returns nothing
local unit caster = missile.owner
local real aoe = missile.data
local group nearby = GetUnitsInAOEOfUnitUnit(missile.target, aoe, TargetFilter, missile.target)
local unit picked = null
local integer size = BlzGroupGetSize(nearby)
loop
set size = size - 1
exitwhen size < 0
set picked = BlzGroupUnitAt(nearby, size)
call DummyCastUnit(GetOwningPlayer(picked), picked, GetUnitX(picked), GetUnitY(picked), SB_HYDE_POTION_HIDDEN_CASTER, "bloodlust")
endloop
call DestroyGroup(nearby)
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local string missileArt = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_MISSILE_ART)
local real missileArc = GetUnitAbilityRealField(caster, GetSpellAbilityId(), ABILITY_RF_ARF_MISSILE_ARC)
local real missileSpeed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local TargetMissile missile = CreateTargetMissile(missileArt, caster, GetUnitX(caster), GetUnitY(caster), GetUnitFlyHeight(caster) + 60.0)
set missile.data = R2I(GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT))
call FireTargetMissile(missile, GetSpellTargetUnit(), missileSpeed, missileArc, 0.0, true, OnMissileHit)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_HYDE_POTION_AOE, function OnSpellEffect)
endfunction
endscope
globals
constant real ITS_ALIVE_UPDATE_INTERVAL = 0.03
constant real ITS_ALIVE_PULL_SPEED = 300.0
constant integer ITS_ALIVE_LR_RESOLUTION = 12
constant integer ITS_ALIVE_MAX_ZOMBIE_COUNT = 8
constant key KEY_ITS_ALIVE
endglobals
struct ItsAlive
real ringDuration
real golemLifespan
unit golem
group zombies
group paused
LightningRing lr
timer updateTimer
static method create takes unit golem returns ItsAlive
local ItsAlive ia = ItsAlive.allocate()
set ia.golem = golem
set ia.zombies = CreateGroup()
set ia.paused = CreateGroup()
set ia.updateTimer = CreateTimer()
call SaveInteger(udg_HashTable_Timers, GetHandleId(ia.updateTimer), KEY_ITS_ALIVE, ia)
return ia
endmethod
method onDestroy takes nothing returns nothing
call DestroyTimer(updateTimer)
call lr.destroy()
call DestroyGroup(zombies)
call DestroyGroup(paused)
endmethod
endstruct
function Trig_Its_Alive_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ITS_ALIVE
endfunction
function Trig_Its_Alive_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitHidden(filter)) then
return false
endif
return GetUnitTypeId(filter) == SB_ZOMBIE
endfunction
function Trig_Its_Alive_Finish takes ItsAlive instance returns nothing
local unit pickedUnit = null
loop
set pickedUnit = FirstOfGroup(instance.paused)
exitwhen pickedUnit == null
call PauseUnit(pickedUnit, false)
call SetUnitPathingSB(pickedUnit, true)
call GroupRemoveUnit(instance.paused, pickedUnit)
endloop
if (CountUnitsInGroup(instance.zombies) > 0) then
call ExileUnit(instance.golem, false)
call SetUnitPathingSB(instance.golem, true)
call UnitApplyTimedLife(instance.golem, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, instance.golemLifespan)
call SetUnitTimeScale(instance.golem, 1.0)
call DestroyEffect(AddSpecialEffectTargetUnitBJ("origin", instance.golem, "war3mapImported\\Effect_MadScientist_BoltImpactGreen.mdx"))
call instance.lr.Destroy()
call DestroyTimer(instance.updateTimer)
else
call RemoveUnit(instance.golem)
call instance.destroy()
endif
endfunction
function Trig_Its_Alive_Update takes nothing returns nothing
local ItsAlive instance = LoadInteger(udg_HashTable_Timers, GetHandleId(GetExpiredTimer()), KEY_ITS_ALIVE)
local boolexpr filter = null
local group nearbyUnits = null
local unit pickedUnit = null
local real speed = ITS_ALIVE_PULL_SPEED * ITS_ALIVE_UPDATE_INTERVAL
local location targetPoint = instance.lr.origin
local real angle = 0.0
local integer zombieCount = 0
set instance.ringDuration = instance.ringDuration - ITS_ALIVE_UPDATE_INTERVAL
if (instance.ringDuration > 0.0) then
set zombieCount = CountUnitsInGroup(instance.zombies)
set nearbyUnits = CreateGroup()
set filter = Condition(function Trig_Its_Alive_Filter)
call GroupEnumUnitsInRange(nearbyUnits, GetLocationX(targetPoint), GetLocationY(targetPoint), instance.lr.radius, filter)
loop
set pickedUnit = FirstOfGroup(nearbyUnits)
exitwhen pickedUnit == null or zombieCount >= ITS_ALIVE_MAX_ZOMBIE_COUNT
if (GetOwningPlayer(pickedUnit) == GetOwningPlayer(instance.golem)) then
if (DistanceFromUnitToPoint(pickedUnit, GetLocationX(targetPoint), GetLocationY(targetPoint)) > 10.0) then
set angle = AngleBetweenPointsXY(GetUnitX(pickedUnit), GetUnitY(pickedUnit), GetLocationX(targetPoint), GetLocationY(targetPoint))
call SetUnitPathingSB(pickedUnit, false)
call PauseUnit(pickedUnit, true)
call GroupAddUnit(instance.paused, pickedUnit)
call SetUnitX(pickedUnit, PolarProjectionX(GetUnitX(pickedUnit), speed, angle))
call SetUnitY(pickedUnit, PolarProjectionY(GetUnitY(pickedUnit), speed, angle))
else
call AddSpecialEffectOneShot("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl", GetUnitX(pickedUnit), GetUnitY(pickedUnit))
call GroupRemoveUnit(instance.paused, pickedUnit)
call GroupAddUnit(instance.zombies, pickedUnit)
call ExileUnit(pickedUnit, true)
call ShowUnitShow(instance.golem)
set zombieCount = zombieCount + 1
call BlzSetUnitName(instance.golem, "Flesh Golem (" + I2S(zombieCount) + ")")
call SetUnitX(instance.golem, GetLocationX(targetPoint))
call SetUnitY(instance.golem, GetLocationY(targetPoint))
if (zombieCount > 1) then
call ChangeUnitState(instance.golem, UNIT_STATE_MAX_LIFE, GetUnitState(pickedUnit, UNIT_STATE_MAX_LIFE))
call ChangeUnitState(instance.golem, UNIT_STATE_LIFE, GetUnitState(pickedUnit, UNIT_STATE_LIFE))
call BlzSetUnitBaseDamage(instance.golem, BlzGetUnitBaseDamage(instance.golem, 0) + BlzGetUnitBaseDamage(pickedUnit, 0) + BlzGetUnitDiceSides(instance.golem, 0), 0)
call BlzSetUnitRealField(instance.golem, UNIT_RF_SELECTION_SCALE, BlzGetUnitRealField(instance.golem, UNIT_RF_SELECTION_SCALE) + 0.19)
call ChangeUnitSize(instance.golem, 0.11)
else
call SetUnitState(instance.golem, UNIT_STATE_MAX_LIFE, GetUnitState(pickedUnit, UNIT_STATE_MAX_LIFE))
call SetUnitState(instance.golem, UNIT_STATE_LIFE, GetUnitState(pickedUnit, UNIT_STATE_LIFE))
call BlzSetUnitBaseDamage(instance.golem, BlzGetUnitBaseDamage(pickedUnit, 0) + BlzGetUnitDiceSides(pickedUnit, 0) - BlzGetUnitDiceSides(instance.golem, 0), 0)
endif
endif
endif
call GroupRemoveUnit(nearbyUnits, pickedUnit)
endloop
if (zombieCount >= ITS_ALIVE_MAX_ZOMBIE_COUNT) then
call Trig_Its_Alive_Finish(instance)
endif
call DestroyGroup(nearbyUnits)
call DestroyBoolExpr(filter)
else
call Trig_Its_Alive_Finish(instance)
endif
endfunction
function Trig_Its_Alive_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real aoe = GetUnitAbilityRealLevelField(caster, SB_ITS_ALIVE, ABILITY_RLF_AREA_OF_EFFECT)
local unit golem = CreateUnit(GetOwningPlayer(caster), SB_FLESH_GOLEM, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(caster))
local ItsAlive instance = ItsAlive.create(golem)
set instance.lr = LightningRing.create(GetSpellTargetLoc(), ITS_ALIVE_LR_RESOLUTION, SB_LIGHTNING_MANA_FLARE, aoe, 0.24)
set instance.lr.deathTime = 0.5
call SetUnitTimeScale(golem, 0.0)
call ExileUnit(golem, true)
call SetUnitPathingSB(golem, false)
set instance.ringDuration = GetUnitAbilityRealLevelField(caster, SB_ITS_ALIVE, ABILITY_RLF_DURATION_HERO)
set instance.golemLifespan = GetUnitAbilityRealLevelField(caster, SB_ITS_ALIVE, ABILITY_RLF_DURATION_NORMAL)
call TimerStart(instance.updateTimer, ITS_ALIVE_UPDATE_INTERVAL, true, function Trig_Its_Alive_Update)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(golem), KEY_ITS_ALIVE, instance)
endfunction
//===========================================================================
function InitTrig_Its_Alive_Cast takes nothing returns nothing
set gg_trg_Its_Alive_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Its_Alive_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Its_Alive_Cast, Condition( function Trig_Its_Alive_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Its_Alive_Cast, function Trig_Its_Alive_Cast_Actions )
endfunction
function Trig_Its_Alive_Death_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_FLESH_GOLEM
endfunction
function Trig_Its_Alive_Death_Actions takes nothing returns nothing
local unit golem = GetDyingUnit()
local ItsAlive instance = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(golem), KEY_ITS_ALIVE)
local effect deathEffect = null
local unit zombie = null
local location loc = null
local integer zombieCount = 0
loop
set zombie = FirstOfGroup(instance.zombies)
exitwhen zombie == null
call GroupRemoveUnit(instance.zombies, zombie)
call SetUnitX(zombie, GetUnitX(golem))
call SetUnitY(zombie, GetUnitY(golem))
call ExileUnit(zombie, false)
set zombie = ReplaceUnitBJ(zombie, SB_FLESHLESS_ZOMBIE, bj_UNIT_STATE_METHOD_RELATIVE)
set zombieCount = zombieCount + 1
set loc = GetUnitLoc(zombie)
call SetUnitFacing(zombie, GetRandomDirectionDeg())
call SetUnitAnimation(zombie, "birth")
call QueueUnitAnimation(zombie, "stand")
call MoveUnitToPointAtSpeed(zombie, PolarProjectionBJ(loc, GetRandomReal(50.0, 200.0), GetRandomDirectionDeg()), 900.0)
call RemoveLocation(loc)
endloop
set deathEffect = AddSpecialEffect("Units\\Undead\\Abomination\\AbominationExplosion.mdl", GetUnitX(golem), GetUnitY(golem))
call BlzSetSpecialEffectYaw(deathEffect, Deg2Rad(GetUnitFacing(golem)))
call BlzSetSpecialEffectScale(deathEffect, 0.48 + (0.11 * zombieCount))
call BlzSetSpecialEffectColor(deathEffect, BlzGetUnitIntegerField(golem, UNIT_IF_TINTING_COLOR_RED), BlzGetUnitIntegerField(golem, UNIT_IF_TINTING_COLOR_GREEN), BlzGetUnitIntegerField(golem, UNIT_IF_TINTING_COLOR_BLUE))
call DestroyEffect(deathEffect)
set deathEffect = AddSpecialEffect("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl", GetUnitX(golem), GetUnitY(golem))
call BlzSetSpecialEffectScale(deathEffect, 0.48 + (0.11 * zombieCount))
call DestroyEffect(deathEffect)
call RemoveUnit(golem)
call instance.destroy()
endfunction
//===========================================================================
function InitTrig_Its_Alive_Death takes nothing returns nothing
set gg_trg_Its_Alive_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Its_Alive_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Its_Alive_Death, Condition( function Trig_Its_Alive_Death_Conditions ) )
call TriggerAddAction( gg_trg_Its_Alive_Death, function Trig_Its_Alive_Death_Actions )
endfunction
globals
constant key KEY_UNDYING
constant real UNDYING_DELAY = 5.0
endglobals
function Trig_Undying_Death_Conditions takes nothing returns boolean
if (not UnitHasAbility(GetDyingUnit(), SB_UNDYING)) then
return false
elseif (not PlayerHasTech(GetOwningPlayer(GetDyingUnit()), SB_TECH_UNDYING)) then
return false
endif
return true
endfunction
function Trig_Undying_Death_SpawnGrave takes player p, real x, real y, real time, unit fakeZombie returns nothing
local unit grave = null
call TriggerSleepAction(time)
set grave = CreateUnit(p, SB_SPECIAL_EFFECT_UNIT_UNDYING, x, y, bj_UNIT_FACING)
call SetUnitAnimation(grave, "birth")
call UnitApplyTimedLife(grave, SB_BUFF_TIMED_LIFE_GENERIC, UNDYING_DELAY)
call SaveUnitHandle(udg_HashTable_SpecialEffects, GetHandleId(grave), KEY_UNDYING, fakeZombie)
endfunction
function Trig_Undying_Death_Actions takes nothing returns nothing
local unit zombie = GetDyingUnit()
local player p = GetOwningPlayer(zombie)
local real deathTime = BlzGetUnitRealField(zombie, UNIT_RF_DEATH_TIME)
local unit fakeZombie = CreateUnit(p, SB_SPECIAL_EFFECT_UNIT_ZOMBIE, GetUnitX(zombie), GetUnitY(zombie), GetUnitFacing(zombie))
call SetUnitAnimation(fakeZombie, "death")
call Trig_Undying_Death_SpawnGrave.execute(GetOwningPlayer(zombie), GetUnitX(zombie), GetUnitY(zombie), deathTime, fakeZombie)
call RemoveUnit(zombie)
endfunction
//===========================================================================
function InitTrig_Undying_Death takes nothing returns nothing
set gg_trg_Undying_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Undying_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Undying_Death, Condition( function Trig_Undying_Death_Conditions ) )
call TriggerAddAction( gg_trg_Undying_Death, function Trig_Undying_Death_Actions )
endfunction
function Trig_Undying_Expiration_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_SPECIAL_EFFECT_UNIT_UNDYING
endfunction
function Trig_Undying_Expiration_Actions takes nothing returns nothing
local unit grave = GetDyingUnit()
local unit fakeZombie = LoadUnitHandle(udg_HashTable_SpecialEffects, GetHandleId(grave), KEY_UNDYING)
local unit newZombie = CreateUnit(GetOwningPlayer(grave), SB_ZOMBIE, GetUnitX(grave), GetUnitY(grave), bj_UNIT_FACING)
call RemoveUnit(fakeZombie)
call SetUnitAnimation(grave, "death")
call SetUnitLifePercentBJ(newZombie, 40.00)
call UnitRemoveAbility(newZombie, SB_UNDYING)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl", newZombie, "origin"))
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(grave), KEY_UNDYING)
endfunction
//===========================================================================
function InitTrig_Undying_Expiration takes nothing returns nothing
set gg_trg_Undying_Expiration = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Undying_Expiration, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Undying_Expiration, Condition( function Trig_Undying_Expiration_Conditions ) )
call TriggerAddAction( gg_trg_Undying_Expiration, function Trig_Undying_Expiration_Actions )
endfunction
scope BloodGorge initializer Init
private function UnitEntersCondition takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_BLOOD_GORGE)
endfunction
private function UnitEntersAction takes nothing returns nothing
call BlzUnitDisableAbility(GetEnteringUnit(), SB_BLOOD_GORGE, true, false)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
local unit picked = null
local group units = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_BLOOD_GORGE)
set t = CreateTrigger()
call TriggerRegisterEnterRectSimple(t, GetEntireMapRect())
call TriggerAddCondition(t, Condition(function UnitEntersCondition))
call TriggerAddAction(t, function UnitEntersAction)
loop
set picked = FirstOfGroup(units)
exitwhen picked == null
call BlzUnitDisableAbility(picked, SB_BLOOD_GORGE, true, false)
call GroupRemoveUnit(units, picked)
endloop
call DestroyGroup(units)
endfunction
endscope
globals
constant real SOUL_HARVEST_SIZE_INCREASE = 0.02
constant integer SOUL_HARVEST_LIFE_BONUS = 0
constant real SOUL_HARVEST_AOE = 1000.0
constant integer BLOOD_GORGE_LEVEL_THRESHOLD = 11
endglobals
function GetSoulHarvestLevel takes unit whichUnit returns integer
return GetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST)
endfunction
function GetMaxSoulHarvestLevel takes unit whichUnit returns integer
if (GetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST) > 0) then
if (not PlayerHasTech(GetOwningPlayer(whichUnit), SB_TECH_SOUL_CONNOISSEUR)) then
return BLOOD_GORGE_LEVEL_THRESHOLD
endif
return BlzGetAbilityIntegerField(BlzGetUnitAbility(whichUnit, SB_SOUL_HARVEST), ABILITY_IF_LEVELS)
endif
return 0
endfunction
function GetSoulHarvestLevelsRemaining takes unit whichUnit returns integer
local integer soulHarvestLevel = GetSoulHarvestLevel(whichUnit)
if (soulHarvestLevel == 0) then
return 0
endif
return GetMaxSoulHarvestLevel(whichUnit) - soulHarvestLevel
endfunction
function ResetWalkRunSpeedDelayed takes unit whichUnit returns nothing
call TriggerSleepAction(0.01)
call BlzSetUnitRealField(whichUnit, UNIT_RF_ANIMATION_WALK_SPEED, 450.0)
call BlzSetUnitRealField(whichUnit, UNIT_RF_ANIMATION_RUN_SPEED, 450.0)
endfunction
function Vampire_Soul_Harvest_AddLevels takes unit whichUnit, integer levels returns nothing
local integer currentLevel = GetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST)
set levels = IMinBJ(GetSoulHarvestLevelsRemaining(whichUnit), levels)
if (currentLevel <= BLOOD_GORGE_LEVEL_THRESHOLD and currentLevel + levels > BLOOD_GORGE_LEVEL_THRESHOLD) then
call BlzUnitDisableAbility(whichUnit, SB_BLOOD_GORGE, false, false)
call SetUnitLifePercentBJ(whichUnit, 100.0)
call SetUnitSizeOverTime(whichUnit, 0.0, 1.0)
call ResetWalkRunSpeedDelayed.execute(whichUnit)
endif
call SetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST, currentLevel + levels)
call SetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST_DAMAGE_BONUS, GetUnitAbilityLevel(whichUnit, SB_SOUL_HARVEST_DAMAGE_BONUS) + levels)
call BlzSetUnitMaxHP(whichUnit, BlzGetUnitMaxHP(whichUnit) + SOUL_HARVEST_LIFE_BONUS * levels)
call ChangeUnitState(whichUnit, UNIT_STATE_LIFE, SOUL_HARVEST_LIFE_BONUS * levels)
call ChangeUnitSize(whichUnit, SOUL_HARVEST_SIZE_INCREASE * levels)
endfunction
function SoulHarvestAddSize takes unit whichUnit, integer levels returns nothing
call ChangeUnitSize(whichUnit, SOUL_HARVEST_SIZE_INCREASE * levels)
endfunction
function SoulHarvestComparer takes unit vamp1, unit vamp2 returns integer
local integer level1 = 0
local integer level2 = 0
local real dist1 = 0.0
local real dist2 = 0.0
if (vamp1 == GetKillingUnit()) then
return -1
elseif (vamp2 == GetKillingUnit()) then
return 1
else
set level1 = GetSoulHarvestLevel(vamp1)
set level2 = GetSoulHarvestLevel(vamp2)
if (level1 == level2) then
set dist1 = SqrDistanceBetweenUnits(vamp1, GetDyingUnit())
set dist2 = SqrDistanceBetweenUnits(vamp2, GetDyingUnit())
if (dist1 > dist2) then
return 1
elseif (dist2 > dist1) then
return -1
else
return 0
endif
endif
return level1 - level2
endif
endfunction
function Trig_Vampire_Soul_Harvest_AOE_Conditions takes nothing returns boolean
local unit dying = GetDyingUnit()
local unit killing = GetKillingUnit()
if (killing == null) then
return false
elseif (not IsPlayerEnemy(GetOwningPlayer(dying), GetOwningPlayer(killing))) then
return false
elseif (GetUnitFoodUsed(dying) == 0) then
return false
elseif (IsUnitType(dying, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(dying, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(dying, UNIT_TYPE_SUMMONED)) then
return false
elseif (IsUnitWard(dying)) then
return false
endif
return true
endfunction
function Trig_Vampire_Soul_Harvest_AOE_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
local integer soulHarvestLevel = GetSoulHarvestLevel(filter)
if (not UnitAlive(filter)) then
return false
elseif (GetSoulHarvestLevelsRemaining(filter) == 0) then
return false
endif
return true
endfunction
function Trig_Vampire_Soul_Harvest_AddLevels takes unit whichUnit, unit dying, integer levels returns nothing
call Vampire_Soul_Harvest_AddLevels(whichUnit, levels)
call AddSpecialEffectOneShot("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl", GetUnitX(dying), GetUnitY(dying))
if (GetUnitTypeId(whichUnit) != SB_VAMPIRE_BLOODFIEND) then
call AddSpecialEffectTargetOneShot("war3mapImported\\WarpDarkTarget.mdx", whichUnit, "origin")
else
call AddSpecialEffectTargetOneShot("war3mapImported\\WarpDarkTarget.mdx", whichUnit, "origin alternate")
endif
endfunction
function Trig_Vampire_Soul_Harvest_AOE_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
local unit killing = GetKillingUnit()
local group nearbySoulHarvesters = null
local boolexpr filter = null
local unit pickedUnit = null
local integer minLevel = MAX_INTEGER
local integer curLevel = 0
local real minSqrDist = BIG_REAL
local real curSqrDist = 0.0
local integer totalLevels = GetUnitFoodUsed(dying)
local integer levelsGranted = 0
local integer index = 0
local integer count = 0
if (GetSoulHarvestLevelsRemaining(killing) >= totalLevels) then
call Trig_Vampire_Soul_Harvest_AddLevels(killing, dying, totalLevels)
else
set nearbySoulHarvesters = CreateGroup()
set filter = Condition(function Trig_Vampire_Soul_Harvest_AOE_Filter)
call GroupEnumUnitsInRange(nearbySoulHarvesters, GetUnitX(dying), GetUnitY(dying), SOUL_HARVEST_AOE, filter)
set count = GroupSortDestructive(nearbySoulHarvesters, SoulHarvestComparer, 0)
set index = 0
loop
exitwhen index >= count or totalLevels < 1
set pickedUnit = QUICK_SORT_CONTAINER[index]
set levelsGranted = IMinBJ(totalLevels, GetSoulHarvestLevelsRemaining(pickedUnit))
call Trig_Vampire_Soul_Harvest_AddLevels(pickedUnit, dying, levelsGranted)
set totalLevels = totalLevels - levelsGranted
set index = index + 1
endloop
call DestroyGroup(nearbySoulHarvesters)
call DestroyBoolExpr(filter)
endif
endfunction
//===========================================================================
function InitTrig_Vampire_Soul_Harvest_AOE takes nothing returns nothing
set gg_trg_Vampire_Soul_Harvest_AOE = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Vampire_Soul_Harvest_AOE, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition(gg_trg_Vampire_Soul_Harvest_AOE, Condition(function Trig_Vampire_Soul_Harvest_AOE_Conditions))
call TriggerAddAction( gg_trg_Vampire_Soul_Harvest_AOE, function Trig_Vampire_Soul_Harvest_AOE_Actions )
call GateAbilityTrigger(gg_trg_Vampire_Soul_Harvest_AOE, SB_SOUL_HARVEST, 0)
endfunction
scope Putrefy initializer Init
globals
private group DISEASED = CreateGroup()
private constant real EXPLOSION_DAMAGE_BASE = 15.0
private constant real EXPLOSION_DAMAGE_PER_LEVEL = 2.0
endglobals
private struct Disease extends IBuff
real damagePerSecond = 1.0
endstruct
private function DiseaseLoop takes Disease d returns nothing
local real hpLost = RMinBJ(d.damagePerSecond, RMaxBJ(GetUnitState(d.host, UNIT_STATE_LIFE) - 1.0, 0.0))
call ChangeUnitState(d.host, UNIT_STATE_LIFE, -hpLost)
endfunction
private struct Putrefy extends IBuff
unit caster = null
real explosionAoe = 0.0
real explosionDamage = 0.0
string explosionArt = null
endstruct
private function PutrefyFilter takes Putrefy p returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitNonNeutralAlly(filter, GetOwningPlayer(p.caster))) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (IsUnitType(p.host, UNIT_TYPE_GROUND) != IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitType(p.host, UNIT_TYPE_FLYING) != IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
endif
return true
endfunction
private function PutrefyHitLoop takes Putrefy p returns nothing
local unit hit = GetEnumUnit()
local Disease d = GetBuff(hit, SB_BUFF_DISEASE)
if (d == 0) then
set d = Disease.create()
set d.host = hit
call TrackBuff(d, SB_BUFF_DISEASE, 1.0, 0, DiseaseLoop)
endif
endfunction
private function PutrefyPulse takes Putrefy p, real aoe returns group
local group hit = CreateGroup()
local unit dummy = CreateDummyCaster(GetOwningPlayer(p.caster), GetUnitX(p.host), GetUnitY(p.host), SB_PUTREFY_HIDDEN_CASTER, 1.0)
if (aoe != 0.0) then
call SetUnitAbilityRealLevelField(dummy, SB_PUTREFY_HIDDEN_CASTER, ABILITY_RLF_AREA_OF_EFFECT, aoe)
else
set aoe = GetUnitAbilityRealLevelField(dummy, SB_PUTREFY_HIDDEN_CASTER, ABILITY_RLF_AREA_OF_EFFECT)
endif
call IssueImmediateOrder(dummy, "roar")
call GroupEnumUnitsInAOEOfUnitInt(hit, dummy, aoe, PutrefyFilter, p)
call ForGroupInt(hit, PutrefyHitLoop, p)
return hit
endfunction
private function PutrefyUpdate takes Putrefy p returns nothing
local group hit = PutrefyPulse(p, 0.0)
call DestroyGroup(hit)
endfunction
private function CreatePutrefy takes unit caster, unit host returns Putrefy
local Putrefy p = Putrefy.create()
set p.caster = caster
set p.host = host
set p.explosionAoe = GetUnitAbilityRealLevelField(caster, SB_PUTREFY, ABILITY_RLF_AREA_OF_EFFECT)
set p.explosionDamage = EXPLOSION_DAMAGE_BASE + EXPLOSION_DAMAGE_PER_LEVEL * (GetUnitAbilityLevel(caster, SB_PUTREFY) - 1)
set p.explosionArt = GetUnitAbilityStringLevelField(caster, SB_PUTREFY, ABILITY_SLF_AREA_EFFECT)
return p
endfunction
private function PutrefyEnds takes Putrefy p returns nothing
call ChangeUnitSizeOverTime(p.host, 0.5, -0.2)
call RestoreUnitColorOverTime(p.host, 0.5, 0.0)
endfunction
private function PutrefyDeathConditions takes nothing returns boolean
return GetBuff(GetDyingUnit(), SB_BUFF_PUTREFY) != null
endfunction
private function PutrefyDeath takes nothing returns nothing
local unit dying = GetDyingUnit()
local Putrefy p = GetBuff(dying, SB_BUFF_PUTREFY)
local group hit = PutrefyPulse(p, p.explosionAoe)
local unit picked = null
call AddSpecialEffectOneShot(p.explosionArt, GetUnitX(dying), GetUnitY(dying))
loop
set picked = FirstOfGroup(hit)
exitwhen picked == null
call UnitDamageTargetBJ(p.caster, picked, p.explosionDamage, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DEATH)
call GroupRemoveUnit(hit, picked)
endloop
call DestroyGroup(hit)
call DestroyBuff(p)
endfunction
private function PutrefyCastCondition takes nothing returns boolean
return GetSpellAbilityId() == SB_PUTREFY
endfunction
private function PutrefyCastEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local Putrefy p = CreatePutrefy(caster, target)
local integer r = IMaxBJ(0, BlzGetUnitIntegerField(target, UNIT_IF_TINTING_COLOR_RED) - 75)
local integer g = IMaxBJ(0, BlzGetUnitIntegerField(target, UNIT_IF_TINTING_COLOR_GREEN))
local integer b = IMaxBJ(0, BlzGetUnitIntegerField(target, UNIT_IF_TINTING_COLOR_BLUE) - 75)
local integer a = IMaxBJ(0, BlzGetUnitIntegerField(target, UNIT_IF_TINTING_COLOR_ALPHA))
call TrackBuff(p, SB_BUFF_PUTREFY, 1.0, PutrefyEnds, PutrefyUpdate)
call ChangeUnitSizeOverTime(target, 0.5, 0.2)
call ChangeUnitColorOverTime(target, 0.5, 0.0, r, g, b, a)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function PutrefyCastCondition))
call TriggerAddAction(t, function PutrefyCastEffect)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function PutrefyDeathConditions))
call TriggerAddAction(t, function PutrefyDeath)
endfunction
endscope
scope Obliterate initializer Init
globals
private constant real MEDIUM_DAMAGE_FACTOR = 0.5
private constant real MEDIUM_DAMAGE_AOE_FACTOR = 0.5
private constant real SMALL_DAMAGE_FACTOR = 0.25
private constant real SMALL_DAMAGE_AOE_FACTOR = 0.75
endglobals
private struct Obliterate
real aoe = 0.0
real x = 0.0
real y = 0.0
real damage = 0.0
effect targetingIndicator = null
method onDestroy takes nothing returns nothing
call DestroyEffect(targetingIndicator)
endmethod
endstruct
private function CreateObliterate takes unit caster, real x, real y returns PointMissile
local string missileArt = GetUnitAbilityStringLevelField(caster, SB_OBLITERATE, ABILITY_SLF_MISSILE_ART)
local string targetingArt = GetUnitAbilityStringLevelField(caster, SB_OBLITERATE, ABILITY_SLF_SPECIAL)
local PointMissile missile = 0
local Obliterate o = Obliterate.create()
set o.aoe = GetUnitAbilityRealLevelField(caster, SB_OBLITERATE, ABILITY_RLF_AREA_OF_EFFECT)
set o.x = x
set o.y = y
set o.damage = GetUnitAbilityRealLevelField(caster, SB_OBLITERATE, ABILITY_RLF_DAMAGE_HBZ2)
set o.targetingIndicator = AddSpecialEffect(targetingArt, x, y)
set missile = CreatePointMissile(missileArt, caster, GetUnitX(caster), GetUnitY(caster), 120.0, 0.0, 0.0)
set missile.data = o
return missile
endfunction
private function TargetFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
return true
endfunction
private function OnMissileHit takes PointMissile missile, real x, real y returns nothing
local unit caster = missile.owner
local Obliterate o = missile.data
local real aoe = o.aoe
local real mediumDamageAoe = aoe * MEDIUM_DAMAGE_AOE_FACTOR
local real smallDamageAoe = aoe * SMALL_DAMAGE_AOE_FACTOR
local real dist = 0.0
local real damage = 0.0
local group targets = GetUnitsInAOEUnit(x, y, aoe, TargetFilter, caster)
local unit picked = null
loop
set picked = FirstOfGroup(targets)
exitwhen picked == null
set dist = DistanceFromUnitToPoint(picked, x, y)
if (dist <= mediumDamageAoe) then
set damage = o.damage
elseif (dist <= smallDamageAoe) then
set damage = o.damage * MEDIUM_DAMAGE_FACTOR
else
set damage = o.damage * SMALL_DAMAGE_FACTOR
endif
call UnitDamageTargetBJ(caster, picked, damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH)
call GroupRemoveUnit(targets, picked)
endloop
call o.destroy()
call DestroyGroup(targets)
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real missileSpeed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local real missileArc = GetUnitAbilityRealField(caster, GetSpellAbilityId(), ABILITY_RF_ARF_MISSILE_ARC)
local PointMissile missile = CreateObliterate(caster, x, y)
call FirePointMissile(missile, missileSpeed, x, y, 0.0, missileArc, OnMissileHit)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_OBLITERATE, function OnSpellEffect)
endfunction
endscope
function Trig_Recall_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RECALL
endfunction
function Trig_Recall_Cast_ShouldInclude takes unit whichUnit, real areaOfEffect, location unitPos, location targetLoc returns boolean
if (whichUnit == GetSpellAbilityUnit()) then
return false
elseif (not IsUnitAliveBJ(whichUnit)) then
return false
elseif (GetOwningPlayer(whichUnit) != GetOwningPlayer(GetSpellAbilityUnit())) then
return false
elseif (IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE) and GetUnitAbilityLevel(whichUnit, SB_NECROMANCER_UPROOT) <= 0) then
return false
elseif (IsUnitHidden(whichUnit)) then
return false
elseif (IsUnitWard(whichUnit)) then
return false
elseif (DistanceBetweenPoints(unitPos, targetLoc) > areaOfEffect + BlzGetUnitCollisionSize(whichUnit)) then
return false
endif
return true
endfunction
function Trig_Recall_Cast_Actions takes nothing returns nothing
local ability cast = BlzGetUnitAbility(GetSpellAbilityUnit(), SB_RECALL)
local location targetLoc = GetSpellTargetLoc()
local location casterLoc = GetUnitLoc(GetSpellAbilityUnit())
local real aoe = BlzGetAbilityRealLevelField(cast, ABILITY_RLF_AREA_OF_EFFECT, GetUnitAbilityLevel(GetSpellAbilityUnit(), SB_RECALL) - 1)
local group unitsNearTarget = GetUnitsInRangeOfLocAll(aoe, targetLoc)
local integer size = BlzGroupGetSize(unitsNearTarget)
local integer index = size - 1
local unit pickedUnit = null
local location pos = null
local effect sfx = null
local RecallInstance recall = 0
loop
exitwhen index < 0
set pickedUnit = BlzGroupUnitAt(unitsNearTarget, index)
set pos = GetUnitLoc(pickedUnit)
if (Trig_Recall_Cast_ShouldInclude(pickedUnit, aoe, pos, targetLoc)) then
call PauseUnit(pickedUnit, true)
set sfx = AddSpecialEffectTargetUnitBJ("origin", pickedUnit, "Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl")
call SaveReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET DISTANCE"), RMaxBJ(BlzGetUnitCollisionSize(pickedUnit) + BlzGetUnitCollisionSize(GetSpellAbilityUnit()), DistanceBetweenPoints(targetLoc, pos)))
call SaveReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET ANGLE"), AngleBetweenPoints(targetLoc, pos))
if (HaveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET"))) then
call DestroyEffect(LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET")))
endif
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET"), sfx)
else
set size = size - 1
call GroupRemoveUnit(unitsNearTarget, pickedUnit)
endif
call RemoveLocation(pos)
set index = index - 1
endloop
if (size > 0) then
set recall = RecallInstance.create()
set recall.caster = GetSpellAbilityUnit()
set recall.units = unitsNearTarget
set recall.casterEffect = AddSpecialEffectLoc("war3mapImported\\Void Teleport Green To.mdx", casterLoc)
set recall.casterSplat = CreateUbersplatBJ(casterLoc, "UDSU", 100.0, 100.0, 100.0, 0.0, false, false)
call SetUbersplatRenderAlways(recall.casterSplat, true)
set udg_IntArr_RecallInstances[udg_Int_RecallInstanceCount] = recall
set udg_Int_RecallInstanceCount = udg_Int_RecallInstanceCount + 1
call EnableTrigger(gg_trg_Recall_Unit_Dies)
call EnableTrigger(gg_trg_Recall_Loop)
else
call DestroyGroup(unitsNearTarget)
endif
call RemoveLocation(targetLoc)
call RemoveLocation(casterLoc)
endfunction
//===========================================================================
function InitTrig_Recall_Cast takes nothing returns nothing
set gg_trg_Recall_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Recall_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Recall_Cast, Condition( function Trig_Recall_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Recall_Cast, function Trig_Recall_Cast_Actions )
endfunction
function Trig_Recall_Global_Cooldown_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_RECALL
endfunction
function Trig_Recall_Global_Cooldown_Actions takes nothing returns nothing
local group allRecallUnits = GetUnitsOfPlayerWithAbility(GetOwningPlayer(GetSpellAbilityUnit()), GetSpellAbilityId())
local unit picked = null
loop
set picked = FirstOfGroup(allRecallUnits)
exitwhen picked == null
if (picked != GetSpellAbilityUnit()) then
call BlzStartUnitAbilityCooldown(picked, GetSpellAbilityId(), GetUnitAbilityRealLevelField(picked, GetSpellAbilityId(), ABILITY_RLF_COOLDOWN))
call SetUnitState(picked, UNIT_STATE_MANA, 0.0)
endif
call GroupRemoveUnit(allRecallUnits, picked)
endloop
endfunction
//===========================================================================
function InitTrig_Recall_Global_Cooldown takes nothing returns nothing
set gg_trg_Recall_Global_Cooldown = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Recall_Global_Cooldown, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Recall_Global_Cooldown, Condition( function Trig_Recall_Global_Cooldown_Conditions ) )
call TriggerAddAction( gg_trg_Recall_Global_Cooldown, function Trig_Recall_Global_Cooldown_Actions )
endfunction
function Trig_Recall_Unit_Dies_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
if (HaveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(dying), StringHash("RECALL TARGET"))) then
call DestroyEffect(LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(dying), StringHash("RECALL TARGET")))
endif
endfunction
//===========================================================================
function InitTrig_Recall_Unit_Dies takes nothing returns nothing
set gg_trg_Recall_Unit_Dies = CreateTrigger()
call DisableTrigger(gg_trg_Recall_Unit_Dies)
call TriggerRegisterAnyUnitEventBJ( gg_trg_Recall_Unit_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( gg_trg_Recall_Unit_Dies, function Trig_Recall_Unit_Dies_Actions )
endfunction
globals
constant real RECALL_LOOP_INTERVAL = 0.5
constant real RECALL_DELAY = 4.0
endglobals
function Trig_Recall_Loop_RemoveRecallInstance takes integer index returns nothing
set index = index + 1
loop
exitwhen index >= udg_Int_RecallInstanceCount
set udg_IntArr_RecallInstances[index - 1] = udg_IntArr_RecallInstances[index]
set index = index + 1
endloop
set udg_Int_RecallInstanceCount = udg_Int_RecallInstanceCount - 1
set udg_IntArr_RecallInstances[udg_Int_RecallInstanceCount] = 0
endfunction
function Trig_Recall_Loop_ExecuteRecall takes RecallInstance recall returns nothing
local integer size = BlzGroupGetSize(recall.units)
local integer index = 0
local unit pickedUnit = null
local location casterPos = GetUnitLoc(recall.caster)
local location unitPos = null
local location targetPos = null
local real dist = 0.0
local real angle = 0.0
local effect sfx = null
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(recall.units, index)
set sfx = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET"))
call DestroyEffect(sfx)
if (UnitAlive(pickedUnit)) then
set dist = LoadReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET DISTANCE"))
set angle = LoadReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET ANGLE"))
set targetPos = PolarProjectionBJ(casterPos, dist, angle)
set unitPos = GetUnitLoc(pickedUnit)
set sfx = AddSpecialEffectLoc("war3mapImported\\Void Teleport Green Target.mdx", unitPos)
call DestroyEffect(sfx)
set sfx = AddSpecialEffectLoc("war3mapImported\\Void Teleport Green Target.mdx", targetPos)
call DestroyEffect(sfx)
call SetUnitPositionLoc(pickedUnit, targetPos)
call PauseUnit(pickedUnit, false)
call RemoveLocation(targetPos)
call RemoveLocation(unitPos)
endif
call RemoveSavedReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET DISTANCE"))
call RemoveSavedReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET ANGLE"))
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET"))
set index = index + 1
endloop
call DestroyEffect(recall.casterEffect)
call DestroyUbersplat(recall.casterSplat)
call RemoveLocation(casterPos)
endfunction
function Trig_Recall_Loop_CancelRecall takes RecallInstance recall returns nothing
local integer size = BlzGroupGetSize(recall.units)
local integer index = 0
local unit pickedUnit = null
loop
exitwhen index >= size
set pickedUnit = BlzGroupUnitAt(recall.units, index)
call PauseUnit(pickedUnit, false)
call DestroyEffect(LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET")))
call RemoveSavedReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET DISTANCE"))
call RemoveSavedReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("RECALL OFFSET ANGLE"))
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(pickedUnit), StringHash("RECALL TARGET"))
set index = index + 1
endloop
call DestroyEffect(recall.casterEffect)
call DestroyUbersplat(recall.casterSplat)
endfunction
function Trig_Recall_Loop_Actions takes nothing returns nothing
local integer index = udg_Int_RecallInstanceCount - 1
local RecallInstance recall = 0
if (udg_Int_RecallInstanceCount > 0) then
loop
exitwhen index < 0
set recall = udg_IntArr_RecallInstances[index]
if (recall.caster != null and IsUnitAliveBJ(recall.caster)) then
if (recall.time >= RECALL_DELAY) then
call Trig_Recall_Loop_ExecuteRecall(recall)
call Trig_Recall_Loop_RemoveRecallInstance(index)
call DestroyGroup(recall.units)
call recall.destroy()
else
set recall.time = recall.time + RECALL_LOOP_INTERVAL
endif
else
call Trig_Recall_Loop_CancelRecall(recall)
call Trig_Recall_Loop_RemoveRecallInstance(index)
call DestroyGroup(recall.units)
call recall.destroy()
endif
set index = index - 1
endloop
else
call DisableTrigger(gg_trg_Recall_Unit_Dies)
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Recall_Loop takes nothing returns nothing
set gg_trg_Recall_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Recall_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Recall_Loop, RECALL_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Recall_Loop, function Trig_Recall_Loop_Actions )
endfunction
function Trig_Recall_Allow_While_Training_Conditions takes nothing returns boolean
return UnitHasAbility(GetTriggerUnit(), SB_RECALL)
endfunction
function Trig_Recall_Allow_While_Training_Actions takes nothing returns nothing
call BlzUnitDisableAbility(GetTriggerUnit(), SB_RECALL, false, false)
endfunction
//===========================================================================
function InitTrig_Recall_Allow_While_Training takes nothing returns nothing
set gg_trg_Recall_Allow_While_Training = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Recall_Allow_While_Training, EVENT_PLAYER_UNIT_TRAIN_START )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Recall_Allow_While_Training, EVENT_PLAYER_UNIT_RESEARCH_START )
call TriggerAddAction( gg_trg_Recall_Allow_While_Training, function Trig_Recall_Allow_While_Training_Actions )
endfunction
globals
constant integer DEVOURING_SWARM_MAX_ATTACKERS = 1
endglobals
function Trig_Devouring_Swarm_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_DEVOURING_SWARM
endfunction
function Trig_Devouring_Swarm_Cast_TargetFilter takes Swarm swarm, unit filter returns boolean
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitEnemy(filter, GetOwningPlayer(swarm.host))) then
return false
elseif (not IsUnitVisible(filter, GetOwningPlayer(swarm.host))) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Devouring_Swarm_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local player p = GetOwningPlayer(caster)
local integer unitCount = R2I(GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_HERO))
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local unit host = CreateUnit(p, SB_SPECIAL_EFFECT_UNIT_DEVOURING_SWARM, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
local Swarm swarm = CreateSwarm(host, aoe, Trig_Devouring_Swarm_Cast_TargetFilter)
local unit bat = null
local integer i = 0
loop
exitwhen i >= unitCount
set bat = CreateUnit(p, SB_SWARM_BAT, GetSpellTargetX(), GetSpellTargetY(), GetRandomReal(0, 360))
call UnitApplyTimedLife(bat, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call swarm.AddMember(bat)
set i = i + 1
endloop
set swarm.maxAttackersPerTarget = DEVOURING_SWARM_MAX_ATTACKERS
call SetUnitAnimation(host, "birth")
call QueueUnitAnimation(host, "stand")
call UnitApplyTimedLife(host, SB_BUFF_TIMED_LIFE_GENERIC, duration)
endfunction
//===========================================================================
function InitTrig_Devouring_Swarm_Cast takes nothing returns nothing
set gg_trg_Devouring_Swarm_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Devouring_Swarm_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Devouring_Swarm_Cast, Condition( function Trig_Devouring_Swarm_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Devouring_Swarm_Cast, function Trig_Devouring_Swarm_Cast_Actions )
endfunction
scope Pyre initializer Init
globals
private hashtable HT = InitHashtable()
private LinkedList_Int PYRES = 0
private key KEY_CASTER_TO_SPELL
private key KEY_UNITS_HIT
private trigger PYRE_LOOP = null
private real PYRE_UPDATE_INTERVAL = 0.5
private real AREA_EFFECT_SCALE_BASE = 225.0
private real AREA_EFFECT_TIME_SCALE = 1.0
private real AREA_EFFECT_INTERVAL = 1.0
private real MANA_COST_PER_SECOND = 5.0
private string WARNING_SOUND = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeTargetWaveNonLoop1.flac"
private real WARNING_SOUND_PITCH = 2.0
private string CHANNEL_SOUND = "Abilities\\Spells\\Orc\\LiquidFire\\TrollBatriderLiquidFire1.flac"
private string UBERSPLAT_TYPE = "USMA"
endglobals
private struct Pyre extends ILinkedListNode
unit caster = null
real x = 0.0
real y = 0.0
real aoe = 0.0
real damagePerSecond = 0.0
integer manaPerFriendlyKill = 0
string areaArt = null
string sacArt = null
effect targetingEffect = null
effect areaEffect = null
fogmodifier visibility = null
ubersplat splat = null
sound snd = null
method onDestroy takes nothing returns nothing
call DestroyFogModifier(visibility)
call DestroyEffect(targetingEffect)
call DestroyEffect(areaEffect)
call DestroyUbersplat(splat)
call StopSound(snd, false, false)
call RemoveSavedInteger(HT, GetHandleId(caster), KEY_CASTER_TO_SPELL)
endmethod
endstruct
private function GetPyre takes unit caster returns Pyre
return LoadInteger(HT, GetHandleId(caster), KEY_CASTER_TO_SPELL)
endfunction
private function GetOrCreatePyre takes unit caster, real x, real y returns Pyre
local Pyre p = GetPyre(caster)
if (p != 0) then
call LinkedListRemove(PYRES, p)
call p.destroy()
endif
set p = Pyre.create()
set p.caster = caster
set p.x = x
set p.y = y
set p.aoe = GetUnitAbilityRealLevelField(caster, SB_PYRE, ABILITY_RLF_AREA_OF_EFFECT)
set p.damagePerSecond = GetUnitAbilityRealLevelField(caster, SB_PYRE, ABILITY_RLF_DURATION_HERO)
set p.manaPerFriendlyKill = R2I(GetUnitAbilityRealLevelField(caster, SB_PYRE, ABILITY_RLF_DURATION_NORMAL))
set p.sacArt = GetUnitAbilityStringLevelField(caster, SB_PYRE, ABILITY_SLF_MISSILE_ART)
set p.areaArt = GetUnitAbilityStringLevelField(caster, SB_PYRE, ABILITY_SLF_AREA_EFFECT)
call SaveInteger(HT, GetHandleId(caster), KEY_CASTER_TO_SPELL, p)
return p
endfunction
private function DestroyPyreGetNext takes Pyre p returns Pyre
local Pyre next = p.next
call LinkedListDestroyNode(PYRES, p)
return next
endfunction
private function PyreTargetFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (HaveSavedBoolean(HT, KEY_UNITS_HIT, GetHandleId(filter))) then
return false
endif
return true
endfunction
private function CreateAreaEffect takes Pyre p returns effect
local effect areaEffect = AddSpecialEffect(p.areaArt, p.x, p.y)
call BlzSetSpecialEffectScale(areaEffect, p.aoe / AREA_EFFECT_SCALE_BASE)
call BlzSetSpecialEffectTimeScale(areaEffect, AREA_EFFECT_TIME_SCALE)
return areaEffect
endfunction
private function PyreKillFriendly takes Pyre pyre, unit whichUnit returns nothing
if (not UnitAlive(whichUnit) and whichUnit != pyre.caster and GetOwningPlayer(pyre.caster) == GetOwningPlayer(whichUnit)) then
call AddSpecialEffectOneShot(pyre.sacArt, GetUnitX(whichUnit), GetUnitY(whichUnit))
call ChangeUnitState(pyre.caster, UNIT_STATE_MANA, pyre.manaPerFriendlyKill)
endif
endfunction
private function PyreLoop takes nothing returns nothing
local Pyre p = LinkedListGetFirst(PYRES)
local unit picked = null
local group hit = CreateGroup()
local real manaCost = MANA_COST_PER_SECOND * PYRE_UPDATE_INTERVAL
if (p != 0) then
loop
exitwhen p == 0
if (GetUnitState(p.caster, UNIT_STATE_MANA) >= manaCost) then
call ChangeUnitState(p.caster, UNIT_STATE_MANA, -manaCost)
call GroupEnumUnitsInAOEUnit(hit, p.x, p.y, p.aoe, PyreTargetFilter, p.caster)
loop
set picked = FirstOfGroup(hit)
exitwhen picked == null
call SaveBoolean(HT, KEY_UNITS_HIT, GetHandleId(picked), true)
call UnitDamageTarget(p.caster, picked, p.damagePerSecond * PYRE_UPDATE_INTERVAL, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
call PyreKillFriendly(p, picked)
call GroupRemoveUnit(hit, picked)
endloop
set p = p.next
else
call IssueImmediateOrder(p.caster, "stop")
set p = DestroyPyreGetNext(p)
endif
endloop
else
call DisableTrigger(GetTriggeringTrigger())
endif
call FlushChildHashtable(HT, KEY_UNITS_HIT)
call DestroyGroup(hit)
endfunction
private function PyreEffectBegins takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real interval = PYRE_UPDATE_INTERVAL
local Pyre p = GetPyre(caster)
if (p != 0) then
set p.visibility = CreateFogModifierRadius(GetOwningPlayer(caster), FOG_OF_WAR_VISIBLE, p.x, p.y, p.aoe * 1.5, true, false)
call FogModifierStart(p.visibility)
set p.snd = CreateSound(CHANNEL_SOUND, true, true, true, 1, 1, "SpellsEAX")
call SetSoundChannel(p.snd, AUDIO_CHANNEL_ANIMATIONS)
call SetSoundPosition(p.snd, p.x, p.y, 0.0)
call SetSoundVolumeBJ(p.snd, 100.0)
call StartSound(p.snd)
set p.areaEffect = CreateAreaEffect(p)
call LinkedListAddLast(PYRES, p)
call EnableTrigger(PYRE_LOOP)
endif
endfunction
private function PyreCancel takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local Pyre p = GetPyre(caster)
if (p != 0) then
call LinkedListRemove(PYRES, p)
call p.destroy()
endif
call ResetUnitAnimation(caster)
call SetUnitTimeScale(caster, 1.0)
endfunction
private function PyreChannel takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real castingTime = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_CASTING_TIME)
local Pyre p = GetOrCreatePyre(caster, GetSpellTargetX(), GetSpellTargetY())
local string targetArt = GetUnitAbilityStringLevelField(caster, SB_PYRE, ABILITY_SLF_SPECIAL)
set p.targetingEffect = AddSpecialEffect(targetArt, p.x, p.y)
call BlzSetSpecialEffectColorByPlayer(p.targetingEffect, GetOwningPlayer(caster))
call BlzSetSpecialEffectScale(p.targetingEffect, p.aoe / AREA_EFFECT_SCALE_BASE)
call SetUnitAnimationByIndexDelayedWithTimeScale(caster, 4, 0.01, DBZ(0.5, castingTime, 1.0))
call PlayPitchedSoundAtPositionSB(WARNING_SOUND, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, p.x, p.y, 200.0, WARNING_SOUND_PITCH)
endfunction
private function Init takes nothing returns nothing
set PYRES = CreateLinkedList_Int()
call CreateSpellChannelTrigger(SB_PYRE, function PyreChannel)
call CreateSpellCancelTrigger(SB_PYRE, function PyreCancel)
call CreateSpellEffectTrigger(SB_PYRE, function PyreEffectBegins)
set PYRE_LOOP = CreateTrigger()
call DisableTrigger(PYRE_LOOP)
call TriggerRegisterTimerEventPeriodic(PYRE_LOOP, PYRE_UPDATE_INTERVAL)
call TriggerAddAction(PYRE_LOOP, function PyreLoop)
endfunction
endscope
scope SoulCapture initializer Init
globals
private constant hashtable HT = InitHashtable()
private GatedAbilityTrigger DEATH_TRIGGER = 0
endglobals
private struct SoulCapture
unit whichUnit = null
integer manaRestored = 0
real inCombatDuration = 0.0
real manaDegen = 0.0
endstruct
private function CreateSoulCapture takes unit capturer, integer manaRestored returns SoulCapture
local SoulCapture sc = SoulCapture.create()
set sc.whichUnit = capturer
set sc.manaRestored = manaRestored
set sc.inCombatDuration = GetUnitAbilityRealLevelField(capturer, SB_SOUL_CAPTURE, ABILITY_RLF_DURATION_NORMAL)
return sc
endfunction
private function OnManaPauseTimerExpires takes IntTimer it returns nothing
local SoulCapture sc = it.owner
call BlzSetUnitRealField(sc.whichUnit, UNIT_RF_MANA_REGENERATION, sc.manaDegen)
call RemoveSavedInteger(HT, GetHandleId(sc.whichUnit), 0)
call sc.destroy()
endfunction
private function StartManaPauseTimer takes unit whichUnit, SoulCapture sc returns nothing
local IntTimer it = LoadInteger(HT, GetHandleId(whichUnit), 0)
if (it == 0) then
set it = CreateIntTimer(sc, true)
set sc.manaDegen = BlzGetUnitRealField(whichUnit, UNIT_RF_MANA_REGENERATION)
call SaveInteger(HT, GetHandleId(whichUnit), 0, it)
else
call sc.destroy()
set sc = it.owner
endif
call BlzSetUnitRealField(whichUnit, UNIT_RF_MANA_REGENERATION, 0.0)
call StartTimerPlus(it, sc.inCombatDuration, OnManaPauseTimerExpires)
endfunction
private function UnitDiesFilter takes nothing returns boolean
local unit dying = GetDyingUnit()
if (IsUnitType(dying, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(dying, UNIT_TYPE_MECHANICAL)) then
return false
elseif (GetUnitFoodUsed(dying) < 1) then
return false
endif
return true
endfunction
private function OnMissileHit takes TargetMissile missile, real x, real y returns nothing
local SoulCapture sc = missile.data
local string hitArt = GetUnitAbilityStringLevelField(missile.owner, SB_SOUL_CAPTURE, ABILITY_SLF_SPECIAL)
call ChangeUnitState(missile.target, UNIT_STATE_MANA, sc.manaRestored)
call AddSpecialEffectTargetOneShot(hitArt, missile.target, "origin")
call StartManaPauseTimer(missile.owner, sc)
endfunction
private function OnUnitDies takes nothing returns nothing
local unit dying = GetDyingUnit()
local unit capturer = null
local real aoe = 0.0
local integer manaRestored = 0
local SoulCapture sc = 0
local string missileArt = null
local real missileSpeed = 0.0
local real missileArc = 0.0
local TargetMissile missile = 0
local integer size = BlzGroupGetSize(DEATH_TRIGGER.abilityUnits)
loop
set size = size - 1
exitwhen size < 0
set capturer = BlzGroupUnitAt(DEATH_TRIGGER.abilityUnits, size)
if (UnitAlive(capturer)) then
set aoe = GetUnitAbilityRealLevelField(capturer, SB_SOUL_CAPTURE, ABILITY_RLF_AREA_OF_EFFECT)
if (SqrDistanceBetweenUnits(capturer, dying) <= aoe * aoe) then
set manaRestored = GetUnitAbilityIntegerLevelField(capturer, SB_SOUL_CAPTURE, ABILITY_ILF_MANA_COST) * GetUnitFoodUsed(dying)
if (manaRestored > 0) then
set sc = CreateSoulCapture(capturer, manaRestored)
set missileArt = GetUnitAbilityStringLevelField(capturer, SB_SOUL_CAPTURE, ABILITY_SLF_MISSILE_ART)
set missileArc = GetUnitAbilityRealField(capturer, SB_SOUL_CAPTURE, ABILITY_RF_ARF_MISSILE_ARC)
set missileSpeed = GetUnitAbilityIntegerField(capturer, SB_SOUL_CAPTURE, ABILITY_IF_MISSILE_SPEED)
set missile = CreateTargetMissile(missileArt, capturer, GetUnitX(dying), GetUnitY(dying), 0.0)
set missile.data = sc
call FireTargetMissile(missile, capturer, missileSpeed, missileArc, 75.0, true, OnMissileHit)
endif
endif
endif
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function UnitDiesFilter))
call TriggerAddAction(t, function OnUnitDies)
set DEATH_TRIGGER = GateAbilityTrigger(t, SB_SOUL_CAPTURE, 0)
endfunction
endscope
scope EldritchGaze initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_BUFF
private constant key KEY_ATTACK_TIMER
endglobals
private struct EldritchGaze
unit host = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call UnitRemoveAbility(host, SB_ELDRITCH_GAZE_HIDDEN)
call UnitRemoveAbility(host, SB_BUFF_ELDRITCH_GAZE)
call RemoveSavedInteger(HT, GetHandleId(host), KEY_BUFF)
endmethod
endstruct
private function GetGaze takes unit whichUnit returns EldritchGaze
local EldritchGaze gaze = LoadInteger(HT, GetHandleId(whichUnit), KEY_BUFF)
if (gaze == 0) then
set gaze = EldritchGaze.create()
set gaze.host = whichUnit
set gaze.it = CreateIntTimer(gaze, true)
call UnitAddAbility(whichUnit, SB_ELDRITCH_GAZE_HIDDEN)
call SaveInteger(HT, GetHandleId(whichUnit), KEY_BUFF, gaze)
endif
return gaze
endfunction
private function GetGazeTimer takes unit whichUnit returns UnitTimer
local UnitTimer ut = LoadInteger(HT, GetHandleId(whichUnit), KEY_ATTACK_TIMER)
if (ut == null) then
set ut = CreateUnitTimer(whichUnit, true)
call SaveInteger(HT, GetHandleId(whichUnit), KEY_ATTACK_TIMER, ut)
endif
return ut
endfunction
private function OnGazeExpires takes IntTimer it returns nothing
local EldritchGaze gaze = it.owner
call gaze.destroy()
endfunction
private function OnGazeTimerExpires takes UnitTimer ut returns nothing
call RemoveSavedInteger(HT, GetHandleId(ut.owner), KEY_ATTACK_TIMER)
endfunction
private function OnDamagedConditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
if (not BlzGetEventIsAttack()) then
return false
elseif (not UnitHasAbility(damager, SB_ELDRITCH_GAZE)) then
return false
elseif (not PlayerHasTech(GetOwningPlayer(damager), SB_TECH_ELDRITCH_GAZE)) then
return false
//elseif (IsUnitType(damaged, UNIT_TYPE_STRUCTURE)) then
//return false
elseif (IsUnitType(damaged, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
return true
endfunction
private function OnDamagedActions takes nothing returns nothing
local unit damager = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
local real duration = GetUnitAbilityRealLevelField(damager, SB_ELDRITCH_GAZE, ABILITY_RLF_DURATION_NORMAL)
local real slowPerSec = GetUnitAbilityRealLevelField(damager, SB_ELDRITCH_GAZE, ABILITY_RLF_AREA_OF_EFFECT)
local real maxSlow = GetUnitAbilityRealLevelField(damager, SB_ELDRITCH_GAZE, ABILITY_RLF_CAST_RANGE)
local EldritchGaze gaze = GetGaze(damaged)
local UnitTimer ut = GetGazeTimer(damager)
local real dt = TimerPlusGetElapsed(ut)
local real currentSlow = -GetUnitAbilityRealLevelField(damaged, SB_ELDRITCH_GAZE_HIDDEN, ABILITY_RLF_MOVEMENT_SPEED_FACTOR_SLO1)
if (dt == 0.0) then
set dt = 1.0
endif
set currentSlow = RMinBJ(currentSlow + slowPerSec * dt, maxSlow)
call SetUnitAbilityRealLevelField(damaged, SB_ELDRITCH_GAZE_HIDDEN, ABILITY_RLF_MOVEMENT_SPEED_FACTOR_SLO1, -currentSlow)
call SetUnitAbilityRealLevelField(damaged, SB_ELDRITCH_GAZE_HIDDEN, ABILITY_RLF_ATTACK_SPEED_FACTOR_SLO2, -currentSlow)
call BlzUnitDisableAbility(damaged, SB_ELDRITCH_GAZE_HIDDEN, true, true)
call BlzUnitDisableAbility(damaged, SB_ELDRITCH_GAZE_HIDDEN, false, false)
call StartTimerPlus(gaze.it, duration, OnGazeExpires)
call StartTimerPlus(ut, 1.0, OnGazeTimerExpires)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t, Condition(function OnDamagedConditions))
call TriggerAddAction(t, function OnDamagedActions)
endfunction
endscope
scope EyeBeam initializer Init
globals
private constant hashtable HT = InitHashtable()
endglobals
private struct EyeBeam
unit owner = null
unit target = null
real defaultAttackCooldown = 0.0
real defaultDamagePoint = 0.0
real defaultAttackRange = 0.0
real beamAttackCooldown = 0.0
IntTimer it = 0
boolean beamIsActive = false
method onDestroy takes nothing returns nothing
call it.destroy()
endmethod
endstruct
private function InitEyeBeam takes unit whichUnit returns nothing
local EyeBeam eb = EyeBeam.create()
set eb.owner = whichUnit
set eb.defaultDamagePoint = BlzGetUnitWeaponRealField(whichUnit, UNIT_WEAPON_RF_ATTACK_DAMAGE_POINT, 0)
set eb.defaultAttackCooldown = BlzGetUnitWeaponRealField(whichUnit, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0)
set eb.defaultAttackRange = GetUnitAttackRange(whichUnit, 0)
set eb.beamAttackCooldown = GetUnitAbilityRealLevelField(whichUnit, SB_EYE_BEAM, ABILITY_RLF_DURATION_NORMAL)
set eb.it = CreateIntTimer(eb, false)
call SaveInteger(HT, GetHandleId(whichUnit), 0, eb)
endfunction
private function GetEyeBeam takes unit whichUnit returns EyeBeam
return LoadInteger(HT, GetHandleId(whichUnit), 0)
endfunction
private function CooldownTimerExpires takes IntTimer it returns nothing
local EyeBeam eb = it.owner
set eb.beamIsActive = false
set eb.target = null
call BlzSetUnitWeaponRealField(eb.owner, UNIT_WEAPON_RF_ATTACK_DAMAGE_POINT, 0, eb.defaultDamagePoint)
call BlzSetUnitWeaponRealField(eb.owner, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0, eb.defaultAttackCooldown)
call SetUnitAttackRange(eb.owner, 0, eb.defaultAttackRange)
call AddUnitAnimationProperties(eb.owner, "gold", false)
endfunction
private function StartupTimerExpires takes IntTimer it returns nothing
local EyeBeam eb = it.owner
set eb.beamIsActive = true
call BlzSetUnitWeaponRealField(eb.owner, UNIT_WEAPON_RF_ATTACK_DAMAGE_POINT, 0, 0.0)
call BlzSetUnitWeaponRealField(eb.owner, UNIT_WEAPON_RF_ATTACK_BASE_COOLDOWN, 0, eb.beamAttackCooldown)
call SetUnitAttackRange(eb.owner, 0, GetUnitAbilityRealLevelField(eb.owner, SB_EYE_BEAM, ABILITY_RLF_CAST_RANGE))
call AddUnitAnimationProperties(eb.owner, "gold", true)
call StartTimerPlus(eb.it, 0.25, CooldownTimerExpires)
endfunction
private function StartupTimerUpdate takes IntTimer it returns nothing
local EyeBeam eb = it.owner
if (UnitAlive(eb.target)) then
call BlzSetUnitFacingEx(eb.owner, AngleBetweenUnits(eb.owner, eb.target))
else
call StartTimerPlus(eb.it, eb.beamAttackCooldown + 0.325, CooldownTimerExpires)
endif
endfunction
private function OnAttackConditions takes nothing returns boolean
local unit attacker = GetAttacker()
return UnitHasAbility(attacker, SB_EYE_BEAM)
endfunction
private function OnAttackActions takes nothing returns nothing
local unit attacker = GetAttacker()
local EyeBeam eb = GetEyeBeam(attacker)
set eb.target = GetTriggerUnit()
if (eb.beamIsActive) then
call StartTimerPlus(eb.it, eb.beamAttackCooldown + 0.325, CooldownTimerExpires)
else
call StartTimerPlusPeriodic(eb.it, eb.defaultDamagePoint, 0.01, StartupTimerUpdate, StartupTimerExpires)
endif
endfunction
private function OnDamageConditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
if (not UnitHasAbility(damager, SB_EYE_BEAM)) then
return false
elseif (not BlzGetEventIsAttack()) then
return false
endif
return true
endfunction
private function OnDamageActions takes nothing returns nothing
local unit damager = GetEventDamageSource()
local EyeBeam eb = GetEyeBeam(damager)
local real damage = DBZ(GetEventDamage(), eb.defaultAttackCooldown, GetEventDamage()) * eb.beamAttackCooldown
call BlzSetEventDamage(damage)
endfunction
private function OnUnitEntersConditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_EYE_BEAM)
endfunction
private function OnUnitEntersActions takes nothing returns nothing
call InitEyeBeam(GetEnteringUnit())
endfunction
private function OnUnitDiesConditions takes nothing returns boolean
return HaveSavedInteger(HT, GetHandleId(GetDyingUnit()), 0)
endfunction
private function OnUnitDiesActions takes nothing returns nothing
local EyeBeam eb = GetEyeBeam(GetDyingUnit())
if (eb != 0) then
call eb.destroy()
call RemoveSavedInteger(HT, GetHandleId(GetDyingUnit()), 0)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = null
local group eyeBeamers = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_EYE_BEAM)
local unit picked = null
set t = CreateTrigger()
call TriggerRegisterEnterRectSimple(t, GetEntireMapRect())
call TriggerAddCondition(t, Condition(function OnUnitEntersConditions))
call TriggerAddAction(t, function OnUnitEntersActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(t, Condition(function OnAttackConditions))
call TriggerAddAction(t, function OnAttackActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t, Condition(function OnDamageConditions))
call TriggerAddAction(t, function OnDamageActions)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function OnUnitDiesConditions))
call TriggerAddAction(t, function OnUnitDiesActions)
loop
set picked = FirstOfGroup(eyeBeamers)
exitwhen picked == null
call InitEyeBeam(picked)
call GroupRemoveUnit(eyeBeamers, picked)
endloop
call DestroyGroup(eyeBeamers)
endfunction
endscope
scope SpectralShot initializer Init
globals
private hashtable HT = InitHashtable()
endglobals
private function OnSpectralShotEnds takes IBuff b returns nothing
local integer p = 0
loop
exitwhen p >= bj_MAX_PLAYERS
if (HaveSavedInteger(HT, GetHandleId(b.host), p)) then
call UnitShareVision(b.host, Player(p), false)
endif
set p = p + 1
endloop
call FlushChildHashtable(HT, GetHandleId(b.host))
endfunction
private function SpectralShotConditions takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
if (not UnitHasAbility(damager, SB_SPECTRAL_SHOT)) then
return false
elseif (HaveSavedInteger(HT, GetHandleId(damaged), GetPlayerId(GetOwningPlayer(damager)))) then
return false
elseif (not UnitHasAbility(damaged, SB_BUFF_SPECTRAL_SHOT)) then
return false
elseif (not UnitAlive(damaged)) then
return false
endif
return true
endfunction
private function OnSpectralShotDamage takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
local IBuff b = CreateSimpleBuff(damaged)
call UnitShareVision(damaged, GetOwningPlayer(damager), true)
call SaveInteger(HT, GetHandleId(damaged), GetPlayerId(GetOwningPlayer(damager)), b)
call TrackBuff(b, SB_BUFF_SPECTRAL_SHOT, 0.5, OnSpectralShotEnds, 0)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_DAMAGED, function SpectralShotConditions, function OnSpectralShotDamage)
call GateAbilityTrigger(t, SB_SPECTRAL_SHOT, 0)
endfunction
endscope
function Trig_Construction_Effect_Blight_Factory_Conditions takes nothing returns boolean
return GetUnitTypeId(GetConstructingStructure()) == SB_BLIGHT_FACTORY
endfunction
function Trig_Construction_Effect_Blight_Factory_Actions takes nothing returns nothing
call AddConstructionDummyNoTransparency(GetConstructingStructure(), SB_CONSTRUCTION_DUMMY_BLIGHT_FACTORY, 3.0)
endfunction
//===========================================================================
function InitTrig_Construction_Effect_Blight_Factory takes nothing returns nothing
set gg_trg_Construction_Effect_Blight_Factory = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Construction_Effect_Blight_Factory, EVENT_PLAYER_UNIT_CONSTRUCT_START )
call TriggerAddCondition( gg_trg_Construction_Effect_Blight_Factory, Condition( function Trig_Construction_Effect_Blight_Factory_Conditions ) )
call TriggerAddAction( gg_trg_Construction_Effect_Blight_Factory, function Trig_Construction_Effect_Blight_Factory_Actions )
endfunction
function Trig_Load_Dummy_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_LOAD_PHANTOM_CARRIAGE_DUMMY
endfunction
function Trig_Load_Dummy_Actions takes nothing returns nothing
call IssueImmediateOrder(GetSpellAbilityUnit(), "ravenform")
endfunction
//===========================================================================
function InitTrig_Load_Dummy takes nothing returns nothing
set gg_trg_Load_Dummy = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Load_Dummy, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Load_Dummy, Condition( function Trig_Load_Dummy_Conditions ) )
call TriggerAddAction( gg_trg_Load_Dummy, function Trig_Load_Dummy_Actions )
endfunction
function Trig_Dark_Nexus_Init_Loop takes nothing returns nothing
local player p = GetEnumPlayer()
local boolean hasTech = PlayerHasTech(p, SB_TECH_DARK_NEXUS)
call SetPlayerUnitAvailableBJ(SB_NECROPOLIS, not hasTech, p)
call SetPlayerUnitAvailableBJ(SB_DARK_NEXUS, hasTech, p)
endfunction
function Trig_Dark_Nexus_Init_Actions takes nothing returns nothing
call ForForce(GetPlayersAll(), function Trig_Dark_Nexus_Init_Loop)
endfunction
//===========================================================================
function InitTrig_Dark_Nexus_Init takes nothing returns nothing
set gg_trg_Dark_Nexus_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Dark_Nexus_Init, function Trig_Dark_Nexus_Init_Actions )
endfunction
function Trig_Dark_Nexus_Research_Finished_Conditions takes nothing returns boolean
return GetResearched() == SB_TECH_DARK_NEXUS
endfunction
function Trig_Dark_Nexus_Research_Finished_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
call SetPlayerUnitAvailableBJ(SB_NECROPOLIS, false, p)
call SetPlayerUnitAvailableBJ(SB_DARK_NEXUS, true, p)
endfunction
//===========================================================================
function InitTrig_Dark_Nexus_Research_Finished takes nothing returns nothing
set gg_trg_Dark_Nexus_Research_Finished = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Dark_Nexus_Research_Finished, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddCondition( gg_trg_Dark_Nexus_Research_Finished, Condition( function Trig_Dark_Nexus_Research_Finished_Conditions ) )
call TriggerAddAction( gg_trg_Dark_Nexus_Research_Finished, function Trig_Dark_Nexus_Research_Finished_Actions )
endfunction
function IsSummoningRitual takes integer abilityId returns boolean
return abilityId == SB_START_SUMMONING_RITUAL or abilityId == SB_STOP_SUMMONING_RITUAL
endfunction
function SetNecroRitual takes unit whichUnit returns nothing
local boolean isABuilding = BlzGetUnitBooleanField(whichUnit, UNIT_BF_IS_A_BUILDING)
local integer abilityIdForCooldown = 0
call SaveBoolean(udg_HashTable_UnitInfo, GetHandleId(whichUnit), StringHash("IS_A_BUILDING"), isABuilding)
if (isABuilding) then
call UnitRemoveAbility(whichUnit, SB_START_SUMMONING_RITUAL)
call UnitAddAbility(whichUnit, SB_STOP_SUMMONING_RITUAL)
call BlzUnitDisableAbility(whichUnit, SB_STOP_SUMMONING_RITUAL, false, false)
set abilityIdForCooldown = SB_STOP_SUMMONING_RITUAL
call UnitRemoveAbility(whichUnit, SB_ARMY_TOGGLE_ADD)
call UnitAddAbility(whichUnit, SB_SUMMONING_RITUAL_EFFECT)
else
call UnitRemoveAbility(whichUnit, SB_STOP_SUMMONING_RITUAL)
call UnitAddAbility(whichUnit, SB_START_SUMMONING_RITUAL)
call UnitAddAbility(whichUnit, SB_ARMY_TOGGLE_ADD)
call BlzUnitDisableAbility(whichUnit, SB_START_SUMMONING_RITUAL, false, false)
call BlzUnitDisableAbility(whichUnit, SB_LICH_UPGRADE, false, false)
set abilityIdForCooldown = SB_START_SUMMONING_RITUAL
call UnitRemoveAbility(whichUnit, SB_SUMMONING_RITUAL_EFFECT)
call BlzUnitDisableAbility(whichUnit, SB_UNHOLY_BANNER, false, false)
call BlzUnitDisableAbility(whichUnit, SB_NECRO_RESTORE, false, false)
call BlzUnitDisableAbility(whichUnit, SB_SUMMONING_RITUAL_EFFECT, true, true)
call BlzUnitDisableAbility(whichUnit, SB_UD_BUILD, false, false)
call BlzUnitDisableAbility(whichUnit, SB_ARMY_TOGGLE_ADD, false, false)
endif
call BlzStartUnitAbilityCooldown(whichUnit, abilityIdForCooldown, BlzGetAbilityCooldown(abilityIdForCooldown, 1))
endfunction
function NecroExecuteOrder takes unit whichUnit returns nothing
local string order = LoadStr(udg_HashTable_Orders, GetHandleId(whichUnit), StringHash("ORDER"))
local location orderLoc = null
local unit orderUnit = null
local integer unitTypeId = String2UnitIdBJ(order)
if (unitTypeId != 0) then
set orderLoc = LoadLocationHandle(udg_HashTable_Orders, GetHandleId(whichUnit), StringHash("ORDER TARGET"))
if (orderLoc != null) then
call IssueBuildOrderByIdLocBJ(whichUnit, unitTypeId, orderLoc)
call FlushChildHashtable(udg_HashTable_Orders, GetHandleId(whichUnit))
endif
elseif (order == "restoration") then
set orderUnit = LoadUnitHandle(udg_HashTable_Orders, GetHandleId(whichUnit), StringHash("ORDER TARGET"))
if (orderUnit != null) then
call IssueTargetOrder(whichUnit, order, orderUnit)
call FlushChildHashtable(udg_HashTable_Orders, GetHandleId(whichUnit))
endif
endif
endfunction
function Trig_Necromancer_Init_Actions takes nothing returns nothing
local group necros = GetUnitsOfTypeIdAll(SB_NECROMANCER)
local group liches = GetUnitsOfTypeIdAll(SB_NECROMANCER_LICH)
local unit pickedUnit = null
loop
set pickedUnit = FirstOfGroup(necros)
exitwhen pickedUnit == null
call SetNecroRitual(pickedUnit)
call GroupRemoveUnit(necros, pickedUnit)
endloop
loop
set pickedUnit = FirstOfGroup(liches)
exitwhen pickedUnit == null
call SetNecroRitual(pickedUnit)
call GroupRemoveUnit(liches, pickedUnit)
endloop
call DestroyGroup(necros)
call DestroyGroup(liches)
endfunction
//===========================================================================
function InitTrig_Necromancer_Init takes nothing returns nothing
set gg_trg_Necromancer_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Necromancer_Init, function Trig_Necromancer_Init_Actions )
endfunction
function Trig_Necromancer_Enter_Conditions takes nothing returns boolean
local integer unitTypeId = GetUnitTypeId(GetEnteringUnit())
return unitTypeId == SB_NECROMANCER or unitTypeId == SB_NECROMANCER_LICH
endfunction
function Trig_Necromancer_Enter_Actions takes nothing returns nothing
call SetNecroRitual(GetEnteringUnit())
endfunction
//===========================================================================
function InitTrig_Necromancer_Enter takes nothing returns nothing
set gg_trg_Necromancer_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Necromancer_Enter, GetPlayableMapRect() )
call TriggerAddCondition(gg_trg_Necromancer_Enter, Condition(function Trig_Necromancer_Enter_Conditions))
call TriggerAddAction( gg_trg_Necromancer_Enter, function Trig_Necromancer_Enter_Actions )
endfunction
function Trig_Necromancer_Train_Conditions takes nothing returns boolean
local integer unitTypeId = GetUnitTypeId(GetTrainedUnit())
return unitTypeId == SB_NECROMANCER or unitTypeId == SB_NECROMANCER_LICH
endfunction
function Trig_Necromancer_Train_Actions takes nothing returns nothing
call IssueImmediateOrderBJ(GetTrainedUnit(), "unroot" )
endfunction
//===========================================================================
function InitTrig_Necromancer_Train takes nothing returns nothing
set gg_trg_Necromancer_Train = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Necromancer_Train, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( gg_trg_Necromancer_Train, Condition( function Trig_Necromancer_Train_Conditions ) )
call TriggerAddAction( gg_trg_Necromancer_Train, function Trig_Necromancer_Train_Actions )
endfunction
function Trig_Necromancer_Toggle_Summoning_Ritual_Conditions takes nothing returns boolean
return IsSummoningRitual(GetSpellAbilityId())
endfunction
function Trig_Necromancer_Toggle_Summoning_Ritual_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local location casterPos = null
if (GetSpellAbilityId() == SB_START_SUMMONING_RITUAL or GetSpellAbilityId() == SB_START_SUMMONING_RITUAL_LICH) then
set casterPos = GetUnitLoc(caster)
call SaveReal(udg_HashTable_UnitInfo, GetHandleId(caster), StringHash("FACING"), GetUnitFacing(caster))
call BlzSetUnitFacingEx(caster, bj_UNIT_FACING)
call IssuePointOrderLoc(caster, "root", casterPos)
call RemoveLocation(casterPos)
else
call ClearUnitTrainingQueue(caster)
call IssueImmediateOrder(caster, "unroot")
endif
call GroupAddUnit(udg_UnitGroup_TransformingNecros, caster)
call EnableTrigger(gg_trg_Necromancer_Ritual_Root_Loop)
endfunction
//===========================================================================
function InitTrig_Necromancer_Toggle_Summoning_Ritual takes nothing returns nothing
set gg_trg_Necromancer_Toggle_Summoning_Ritual = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Necromancer_Toggle_Summoning_Ritual, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Necromancer_Toggle_Summoning_Ritual, Condition( function Trig_Necromancer_Toggle_Summoning_Ritual_Conditions ) )
call TriggerAddAction( gg_trg_Necromancer_Toggle_Summoning_Ritual, function Trig_Necromancer_Toggle_Summoning_Ritual_Actions )
endfunction
function Trig_Necromancer_Ritual_Root_Loop_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_TransformingNecros)
local integer index = size - 1
local unit pickedUnit = null
local boolean wasABuilding = false
local boolean isABuilding = false
local effect sfx = null
if (size > 0) then
loop
exitwhen index < 0
set pickedUnit = BlzGroupUnitAt(udg_UnitGroup_TransformingNecros, index)
if (IsUnitAliveBJ(pickedUnit)) then
set wasABuilding = LoadBoolean(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("IS_A_BUILDING"))
set isABuilding = BlzGetUnitBooleanField(pickedUnit, UNIT_BF_IS_A_BUILDING)
if (wasABuilding and not isABuilding) then
call SetNecroRitual(pickedUnit)
call NecroExecuteOrder(pickedUnit)
call GroupRemoveUnit(udg_UnitGroup_TransformingNecros, pickedUnit)
set sfx = AddSpecialEffectTargetUnitBJ("origin", pickedUnit, "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl")
call DestroyEffect(sfx)
elseif (not wasABuilding and isABuilding) then
call SetNecroRitual(pickedUnit)
call GroupRemoveUnit(udg_UnitGroup_TransformingNecros, pickedUnit)
call RemoveSavedReal(udg_HashTable_UnitInfo, GetHandleId(pickedUnit), StringHash("FACING"))
set sfx = AddSpecialEffectTargetUnitBJ("origin", pickedUnit, "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl")
call DestroyEffect(sfx)
call SetUnitAnimation(pickedUnit, "spell")
call QueueUnitAnimation(pickedUnit, "stand")
endif
else
call GroupRemoveUnit(udg_UnitGroup_TransformingNecros, pickedUnit)
endif
set index = index - 1
endloop
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Necromancer_Ritual_Root_Loop takes nothing returns nothing
set gg_trg_Necromancer_Ritual_Root_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Necromancer_Ritual_Root_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Necromancer_Ritual_Root_Loop, 0.01 )
call TriggerAddAction( gg_trg_Necromancer_Ritual_Root_Loop, function Trig_Necromancer_Ritual_Root_Loop_Actions )
endfunction
globals
constant real BLIGHT_REPEAL_REDUCTION_AMOUNT = 32.0
constant real BLIGHT_REPEAL_UPDATE_INTERVAL = 0.32
endglobals
function BlightRepealTimerLoop takes IntTimer it returns nothing
local BlightRepeal br = it.owner
local boolean end = false
set br.lastRadius = br.lastRadius + BLIGHT_REPEAL_REDUCTION_AMOUNT
if (br.lastRadius >= br.totalRadius) then
set br.lastRadius = br.totalRadius
set end = true
endif
call SetBlight(br.p, br.x, br.y, br.lastRadius, false)
if (end) then
call br.destroy()
endif
endfunction
struct BlightRepeal
player p = null
real x = 0.0
real y = 0.0
real lastRadius = 0.0
real totalRadius = 0.0
IntTimer tick = 0
public static method create takes player p, real x, real y, real radius returns BlightRepeal
local BlightRepeal b = BlightRepeal.allocate()
set b.p = p
set b.x = x
set b.y = y
set b.lastRadius = 0.0
set b.totalRadius = radius
set b.tick = CreateIntTimer(b, false)
return b
endmethod
public method Start takes nothing returns nothing
call StartTimerPlusPeriodic(tick, 0.0, BLIGHT_REPEAL_UPDATE_INTERVAL, BlightRepealTimerLoop, 0)
//call tick.StartPeriodic(0.0, BLIGHT_REPEAL_UPDATE_INTERVAL, BlightRepealTimerLoop, 0)
endmethod
method onDestroy takes nothing returns nothing
call tick.destroy()
endmethod
endstruct
function RepealBlight takes player p, real x, real y, real radius returns BlightRepeal
local BlightRepeal br = BlightRepeal.create(p, x, y, radius)
call br.Start()
return br
endfunction
function Trig_Blight_Growth_Death_Conditions takes nothing returns boolean
local unit dying = GetDyingUnit()
if (UnitHasAbility(dying, SB_BLIGHT_GROWTH_512) or UnitHasAbility(dying, SB_BLIGHT_GROWTH_768) or UnitHasAbility(dying, SB_BLIGHT_GROWTH_960)) then
return not IsUnitInGroup(dying, udg_UnitGroup_UnderConstruction)
endif
return false
endfunction
function Trig_Blight_Growth_Death_Actions takes nothing returns nothing
local unit dying = GetDyingUnit()
local real aoe = 0.0
if (UnitHasAbility(dying, SB_BLIGHT_GROWTH_512)) then
set aoe = 512.0
endif
if (UnitHasAbility(dying, SB_BLIGHT_GROWTH_768)) then
set aoe = 768.0
endif
if (UnitHasAbility(dying, SB_BLIGHT_GROWTH_960)) then
set aoe = 960.0
endif
call RepealBlight(GetOwningPlayer(dying), GetUnitX(dying), GetUnitY(dying), aoe)
endfunction
//===========================================================================
function InitTrig_Blight_Growth_Death takes nothing returns nothing
set gg_trg_Blight_Growth_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Blight_Growth_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Blight_Growth_Death, Condition( function Trig_Blight_Growth_Death_Conditions ) )
call TriggerAddAction( gg_trg_Blight_Growth_Death, function Trig_Blight_Growth_Death_Actions )
endfunction
scope WildGrowthSB initializer Init
globals
private constant real TREE_COLLISION_RADIUS = 48.0
private constant real TREE_SCALE = 0.75
private constant string SOUND_EFFECT = "Abilities\\Spells\\NightElf\\Uproot\\Uproot.flac"
endglobals
private function IsOwnTree takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
return GetUnitTypeId(damaged) == SB_WILD_GROWTH_UNIT and IsUnitNonNeutralAlly(damager, GetOwningPlayer(damaged))
endfunction
private function OnDamageOwnTree takes nothing returns nothing
call KillUnit(BlzGetEventDamageTarget())
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local real birthTime = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_HERO)
local real circ = bj_PI * 2 * aoe
local integer count = R2I(circ / 48.0 / 2)
local integer index = 0
local real thisX = 0.0
local real thisY = 0.0
local real rad = 0.0
local unit tree = null
if (count > 0) then
set rad = 0.0
loop
exitwhen index >= count
set thisX = x + aoe * Cos(rad)
set thisY = y + aoe * Sin(rad)
set tree = CreateUnit(GetOwningPlayer(caster), SB_WILD_GROWTH_UNIT, thisX, thisY, GetRandomDirectionDeg())
call SetUnitPathing(tree, false)
call SetUnitPositionExact(tree, thisX, thisY)
call SetUnitPathing(tree, true)
call UnitApplyTimedLife(tree, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call ChangeUnitSize(tree, -1.0)
call ChangeUnitSizeOverTime(tree, birthTime, TREE_SCALE)
set rad = rad + bj_PI * 2 / count
set index = index + 1
endloop
call PlayPitchedSoundAtPositionSB(SOUND_EFFECT, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 100.0, 1.0)
endif
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_WILD_GROWTH_SB, function OnSpellEffect)
call CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_DAMAGED, function IsOwnTree, function OnDamageOwnTree)
endfunction
endscope
function Trig_Grasping_Vines_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ROOTGRASP
endfunction
function Trig_Grasping_Vines_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
if (IsUnitType(target, UNIT_TYPE_FLYING) and not IsUnitType(target, UNIT_TYPE_GROUND)) then
call DummyCastUnit(GetOwningPlayer(target), target, GetUnitX(target), GetUnitY(target), SB_ROOTGRASP_AIR, "cripple")
else
call DummyCastUnit(GetOwningPlayer(target), target, GetUnitX(target), GetUnitY(target), SB_ROOTGRASP_GROUND, "ensnare")
endif
call PlaySBAlertOnUnit(GetOwningPlayer(caster), target, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Grasping_Vines takes nothing returns nothing
set gg_trg_Grasping_Vines = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Grasping_Vines, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Grasping_Vines, Condition( function Trig_Grasping_Vines_Conditions ) )
call TriggerAddAction( gg_trg_Grasping_Vines, function Trig_Grasping_Vines_Actions )
endfunction
globals
constant real SPIRIT_OWL_MOVEMENT_INTERVAL = 0.01
constant real SPIRIT_OWL_ANIMATION_BASE = 400.0
endglobals
struct SpiritOwl
unit owl = null
real minSpeedFactor = 0.0
real maxSpeed = 0.0
real innerAoe = 0.0
real outerAoe = 0.0
real targetX = 0.0
real targetY = 0.0
vec3 direction = 0
method onDestroy takes nothing returns nothing
call direction.destroy()
endmethod
endstruct
function CreateSpiritOwl takes unit caster, real targetX, real targetY returns SpiritOwl
local real speedChangeDuration = GetUnitAbilityRealLevelField(caster, SB_SPIRIT_OWL, ABILITY_RLF_DURATION_NORMAL)
local SpiritOwl so = SpiritOwl.create()
set so.owl = CreateUnit(GetOwningPlayer(caster), SB_SPIRIT_OWL_UNIT, GetUnitX(caster), GetUnitY(caster), bj_UNIT_FACING)
set so.minSpeedFactor = GetUnitAbilityRealField(caster, SB_SPIRIT_OWL, ABILITY_RF_ARF_MISSILE_ARC)
set so.maxSpeed = GetUnitAbilityIntegerField(caster, SB_SPIRIT_OWL, ABILITY_IF_MISSILE_SPEED)
set so.innerAoe = GetUnitAbilityRealLevelField(caster, SB_SPIRIT_OWL, ABILITY_RLF_DURATION_HERO)
set so.outerAoe = GetUnitAbilityRealLevelField(caster, SB_SPIRIT_OWL, ABILITY_RLF_AREA_OF_EFFECT)
set so.targetX = targetX
set so.targetY = targetY
set so.direction = vec3.create(targetX - GetUnitX(caster), targetY - GetUnitY(caster), 0).normalize()
call SetUnitTimeScale(so.owl, so.maxSpeed / SPIRIT_OWL_ANIMATION_BASE)
call SetUnitAnimationByIndex(so.owl, 0)
call UnitRemoveAbility(so.owl, 'Amov')
return so
endfunction
function SpiritOwlUpdate takes IntTimer it returns nothing
local SpiritOwl so = it.owner
local unit owl = so.owl
local real distToTarget = DistanceBetweenUnitAndPoint(owl, so.targetX, so.targetY)
local real speed = so.maxSpeed
local real speedFactor = 0.0
local vec3 next = GetUnitVec(owl)
if (distToTarget <= so.outerAoe) then
set speedFactor = (1 - DBZ(RMaxBJ(distToTarget - so.innerAoe, 0), so.outerAoe - so.innerAoe, 1.0)) * so.minSpeedFactor
set speed = speed * (1 - speedFactor)
endif
call SetUnitTimeScale(so.owl, speed / SPIRIT_OWL_ANIMATION_BASE)
call SetUnitFacing(owl, VecAngle(so.direction))
set next.x = next.x + so.direction.x * speed * TimerPlusGetElapsed(it)
set next.y = next.y + so.direction.y * speed * TimerPlusGetElapsed(it)
if (RectContainsCoords(GetPlayableMapRect(), next.x, next.y)) then
call SetUnitX(owl, next.x)
call SetUnitY(owl, next.y)
else
call SetUnitTimeScale(so.owl, 1.0)
call ResetUnitAnimation(owl)
call KillUnit(owl)
call so.destroy()
call it.destroy()
endif
call next.destroy()
endfunction
function Trig_Spirit_Owl_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SPIRIT_OWL
endfunction
function Trig_Spirit_Owl_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local SpiritOwl so = CreateSpiritOwl(caster, GetSpellTargetX(), GetSpellTargetY())
local IntTimer owlUpdate = CreateIntTimer(so, false)
call StartTimerPlusPeriodic(owlUpdate, 0.0, SPIRIT_OWL_MOVEMENT_INTERVAL, SpiritOwlUpdate, 0)
endfunction
//===========================================================================
function InitTrig_Spirit_Owl takes nothing returns nothing
set gg_trg_Spirit_Owl = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spirit_Owl, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spirit_Owl, Condition( function Trig_Spirit_Owl_Conditions ) )
call TriggerAddAction( gg_trg_Spirit_Owl, function Trig_Spirit_Owl_Actions )
endfunction
scope Entwine initializer Init
globals
private hashtable HT = InitHashtable()
private constant integer PLANT_COUNT = 4
private constant real PLANT_ANGLE_START = bj_PI * 0.25
private constant real PLANT_OFFSET = 64.0
private constant real ENTWINE_COLLISION_BASE = 72.0
private constant real ENTWINE_SCALE_BASE = 1.5
endglobals
private struct Entwine extends IBuff
effect entwineEffect = null
group createdUnits = null
real hpPerSec = 0.0
method onDestroy takes nothing returns nothing
local integer i = BlzGroupGetSize(createdUnits)
loop
set i = i - 1
exitwhen i < 0
call KillUnit(BlzGroupUnitAt(createdUnits, i))
endloop
call DestroyEffect(entwineEffect)
call DestroyGroup(createdUnits)
endmethod
endstruct
private function UpdateEntwine takes Entwine e returns nothing
local real dt = TimerPlusGetElapsed(e.updateTimer)
call ChangeUnitState(e.host, UNIT_STATE_LIFE, e.hpPerSec * dt)
endfunction
private function CreateEntwine takes unit caster, unit target returns Entwine
local integer plantIndex = 0
local string effectArt = GetUnitAbilityStringLevelField(caster, SB_ENTWINE, ABILITY_SLF_SPECIAL)
local real x = 0.0
local real y = 0.0
local real rad = 0.0
local real dist = 0.0
local unit plant = null
local Entwine e = Entwine.create()
set e.host = target
set e.createdUnits = CreateGroup()
set e.hpPerSec = GetUnitAbilityRealLevelField(caster, SB_ENTWINE, ABILITY_RLF_AREA_OF_EFFECT)
set e.entwineEffect = AddSpecialEffect(effectArt, GetUnitX(target), GetUnitY(target))
call BlzSetSpecialEffectColor(e.entwineEffect, 80, 255, 80)
call BlzSetSpecialEffectScale(e.entwineEffect, ENTWINE_SCALE_BASE)
call SetUnitPathingSB(target, false)
loop
exitwhen plantIndex >= PLANT_COUNT
set dist = BlzGetUnitCollisionSize(target) + PLANT_OFFSET
set rad = (bj_PI * 2 / PLANT_COUNT) * plantIndex + PLANT_ANGLE_START
set x = GetUnitXExact(target) + Cos(rad) * dist
set y = GetUnitYExact(target) + Sin(rad) * dist
set plant = CreateUnit(GetOwningPlayer(target), SB_SPITTER_PLANT, x, y, rad * bj_RADTODEG)
call SetUnitPathing(plant, false)
call SetUnitPositionExact(plant, x, y)
call SetUnitAnimation(plant, "birth")
call QueueUnitAnimation(plant, "stand")
call GroupAddUnit(e.createdUnits, plant)
set plantIndex = plantIndex + 1
endloop
call SetUnitPathingSB(target, true)
call TrackBuff(e, SB_BUFF_ENTWINE, 0.5, 0, UpdateEntwine)
return e
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
if (IsUnitInGroup(target, udg_UnitGroup_UnderConstruction)) then
call RefundAbilityCast(caster, SB_ENTWINE)
call DisplayError(GetOwningPlayer(caster), "Unable to target buildings that are under construction.")
else
call CreateEntwine(caster, target)
endif
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_ENTWINE, function OnSpellEffect)
endfunction
endscope
function Trig_Entwine_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ENTWINE
endfunction
function Trig_Entwine_Cast_Actions takes nothing returns nothing
local player owner = GetOwningPlayer(GetSpellAbilityUnit())
local unit target = GetSpellTargetUnit()
local location targetPoint = GetUnitLoc(target)
local location attackerPoint = null
local unit spawned = null
local real duration = 0
local integer attackerCount = 4
if (IsUnitInGroup(target, udg_UnitGroup_UnderConstruction)) then
call SaveReal(udg_HashTable_ManaRefund, GetHandleId(GetSpellAbilityUnit()), StringHash("ENTWINE"), BlzGetAbilityManaCost(SB_ENTWINE, GetUnitAbilityLevel(GetSpellAbilityUnit(), SB_ENTWINE) - 1))
call IssueImmediateOrder(GetSpellAbilityUnit(), "stop")
else
set spawned = CreateUnitAtLoc(owner, SB_SPECIAL_EFFECT_UNIT_ENTWINE, targetPoint, bj_UNIT_FACING)
set duration = BlzGetAbilityRealLevelField(BlzGetUnitAbility(GetSpellAbilityUnit(), GetSpellAbilityId()), ABILITY_RLF_ARMOR_DURATION, GetUnitAbilityLevelSwapped(GetSpellAbilityId(), GetSpellAbilityUnit()) - 1 )
call SetUnitPathingSB(spawned, false)
call SetUnitX(spawned, GetLocationX(targetPoint))
call SetUnitY(spawned, GetLocationY(targetPoint))
call UnitApplyTimedLife(spawned, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call SetUnitAnimation(spawned, "birth" )
call QueueUnitAnimation(spawned, "stand")
call LifelinkUnits(target, spawned, LIFELINK_KILL)
loop
exitwhen attackerCount <= 0
set attackerPoint = PolarProjectionBJ(targetPoint, BlzGetUnitCollisionSize(target) + 32.0, 90.0 * I2R(attackerCount - 1) + 45.0)
set spawned = CreateUnitAtLoc(owner, SB_SPITTER_PLANT, attackerPoint, AngleBetweenPoints(targetPoint, attackerPoint))
call SetUnitPathingSB(spawned, false)
call SetUnitX(spawned, GetLocationX(attackerPoint))
call SetUnitY(spawned, GetLocationY(attackerPoint))
call UnitApplyTimedLife(spawned, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call SetUnitAnimation(spawned, "birth" )
call QueueUnitAnimation(spawned, "stand")
call LifelinkUnits(target, spawned, LIFELINK_KILL)
call RemoveLocation(attackerPoint)
set attackerCount = attackerCount - 1
endloop
call GroupAddUnit(udg_UnitGroup_Entwine, target)
call PlaySBAlertOnUnit(owner, target, GetSpellAbilityId())
call EnableTrigger(gg_trg_Entwine_Loop)
endif
call RemoveLocation(targetPoint)
endfunction
//===========================================================================
function InitTrig_Entwine_Cast takes nothing returns nothing
set gg_trg_Entwine_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Entwine_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Entwine_Cast, Condition( function Trig_Entwine_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Entwine_Cast, function Trig_Entwine_Cast_Actions )
endfunction
globals
constant real ENTWINE_LOOP_INTERVAL = 1.0
endglobals
function Trig_Entwine_Loop_UnitLoop takes nothing returns nothing
local unit building = GetEnumUnit()
if (IsUnitAliveBJ(building) and UnitHasBuffBJ(building, SB_BUFF_ENTWINE)) then
call SetUnitLifeBJ(building, GetUnitState(building, UNIT_STATE_LIFE) + 5.00)
else
call GroupRemoveUnit(udg_UnitGroup_Entwine, building)
endif
endfunction
function Trig_Entwine_Loop_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_Entwine)
if (size > 0) then
call ForGroupBJ(udg_UnitGroup_Entwine, function Trig_Entwine_Loop_UnitLoop)
else
call DisableTrigger( GetTriggeringTrigger() )
endif
endfunction
//===========================================================================
function InitTrig_Entwine_Loop takes nothing returns nothing
set gg_trg_Entwine_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Entwine_Loop )
call TriggerRegisterTimerEventPeriodic(gg_trg_Entwine_Loop, ENTWINE_LOOP_INTERVAL)
call TriggerAddAction( gg_trg_Entwine_Loop, function Trig_Entwine_Loop_Actions )
endfunction
function Trig_Entwine_Failed_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ENTWINE
endfunction
function Trig_Entwine_Failed_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real manaRefund = LoadReal(udg_HashTable_ManaRefund, GetHandleId(caster), StringHash("ENTWINE"))
if (manaRefund > 0) then
call SetUnitManaBJ(caster, GetUnitState(caster, UNIT_STATE_MANA) + manaRefund)
call BlzEndUnitAbilityCooldown(caster, SB_ENTWINE)
call FlushChildHashtable(udg_HashTable_ManaRefund, GetHandleId(caster))
call DisplayTextToPlayer(GetOwningPlayer(caster), 0, 0, "|cffffcc00Unable to target buildings that are under construction.|r")
if (GetOwningPlayer(caster) == GetLocalPlayer()) then
call PlaySoundBJ(gg_snd_Error)
endif
endif
endfunction
//===========================================================================
function InitTrig_Entwine_Failed takes nothing returns nothing
set gg_trg_Entwine_Failed = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Entwine_Failed, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Entwine_Failed, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition( gg_trg_Entwine_Failed, Condition( function Trig_Entwine_Failed_Conditions ) )
call TriggerAddAction( gg_trg_Entwine_Failed, function Trig_Entwine_Failed_Actions )
endfunction
function Trig_Murder_of_Crows_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_MURDER_OF_CROWS
endfunction
function Trig_Murder_of_Crows_Find_Target_Filter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitNonNeutralAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Murder_of_Crows_Additional_Filter takes group g returns nothing
local integer size = BlzGroupGetSize(g)
local integer index = 0
local boolean airUnitsPresent = false
local boolean groundUnitsPresent = false
local unit picked = null
loop
exitwhen index >= size or (airUnitsPresent and groundUnitsPresent)
set picked = BlzGroupUnitAt(g, index)
if (IsUnitType(picked, UNIT_TYPE_FLYING)) then
set airUnitsPresent = true
else
set groundUnitsPresent = true
endif
set index = index + 1
endloop
if (airUnitsPresent and groundUnitsPresent) then
set index = size
loop
exitwhen index < 0
set picked = BlzGroupUnitAt(g, index)
if (IsUnitType(picked, UNIT_TYPE_FLYING)) then
call GroupRemoveUnit(g, picked)
endif
set index = index - 1
endloop
endif
endfunction
function Trig_Murder_of_Crows_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local string effectModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_SPECIAL)
local string targetModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_TARGET)
local integer dummyAbility = SB_MURDER_OF_CROWS_HIDDEN_CASTER_GROUND
local real x = 0.0
local real y = 0.0
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local unit hiddenCaster = null
local group nearby = null
if (target == null) then
set nearby = GetUnitsInAOEUnit(GetSpellTargetX(), GetSpellTargetY(), aoe, Trig_Murder_of_Crows_Find_Target_Filter, caster)
call Trig_Murder_of_Crows_Additional_Filter(nearby)
set target = GroupPickClosestUnit(nearby, GetSpellTargetX(), GetSpellTargetY())
call DestroyGroup(nearby)
if (target != null) then
call AddSpecialEffectTargetOneShot(targetModel, target, "origin")
endif
endif
if (target != null) then
set x = GetUnitX(target)
set y = GetUnitY(target)
if (IsUnitType(GetSpellTargetUnit(), UNIT_TYPE_FLYING) and not IsUnitType(GetSpellTargetUnit(), UNIT_TYPE_STRUCTURE)) then
set dummyAbility = SB_MURDER_OF_CROWS_HIDDEN_CASTER_AIR
endif
set hiddenCaster = DummyCastInstantTimed(GetOwningPlayer(GetSpellAbilityUnit()), x, y, dummyAbility, "locustswarm", 13.0)
call AddSpecialEffectOneShot(effectModel, x, y)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), target, GetSpellAbilityId())
else
call DisplayError(GetOwningPlayer(caster), "Must target a friendly unit.")
call RefundAbilityCast(caster, GetSpellAbilityId())
call IssueImmediateOrder(caster, "stop")
endif
endfunction
//===========================================================================
function InitTrig_Murder_of_Crows_Cast takes nothing returns nothing
set gg_trg_Murder_of_Crows_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Murder_of_Crows_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Murder_of_Crows_Cast, Condition( function Trig_Murder_of_Crows_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Murder_of_Crows_Cast, function Trig_Murder_of_Crows_Cast_Actions )
endfunction
function Trig_Murder_of_Crows_Blind_Effect_Conditions takes nothing returns boolean
local integer unitType = GetUnitTypeId(GetAttacker())
return unitType == SB_CROW or unitType == SB_CROW_AIR
endfunction
function Trig_Murder_of_Crows_Blind_Effect_Actions takes nothing returns nothing
local unit hit = GetTriggerUnit()
call DummyCastUnit(GetOwningPlayer(hit), hit, GetUnitX(hit), GetUnitY(hit), SB_BLIND_HIDDEN_CASTER, "cripple")
endfunction
//===========================================================================
function InitTrig_Murder_of_Crows_Blind_Effect takes nothing returns nothing
set gg_trg_Murder_of_Crows_Blind_Effect = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Murder_of_Crows_Blind_Effect, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_Murder_of_Crows_Blind_Effect, Condition( function Trig_Murder_of_Crows_Blind_Effect_Conditions ) )
call TriggerAddAction( gg_trg_Murder_of_Crows_Blind_Effect, function Trig_Murder_of_Crows_Blind_Effect_Actions )
endfunction
function Trig_Murder_of_Crows_Sound_Effect_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_MURDER_OF_CROWS_HIDDEN_CASTER_GROUND or GetSpellAbilityId() == SB_MURDER_OF_CROWS_HIDDEN_CASTER_AIR
endfunction
function Trig_Murder_of_Crows_Sound_Effect_Actions takes nothing returns nothing
local location pos = GetUnitLoc(GetSpellAbilityUnit())
call PlaySoundAtPointSB("Units\\NightElf\\DruidOfTheTalon\\DruidOfTheTalonDeathAlternate1.flac", "SpellsEAX", 11, pos, 100.0)
call RemoveLocation(pos)
endfunction
//===========================================================================
function InitTrig_Murder_of_Crows_Sound_Effect takes nothing returns nothing
set gg_trg_Murder_of_Crows_Sound_Effect = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Murder_of_Crows_Sound_Effect, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Murder_of_Crows_Sound_Effect, Condition(function Trig_Murder_of_Crows_Sound_Effect_Conditions) )
call TriggerAddAction( gg_trg_Murder_of_Crows_Sound_Effect, function Trig_Murder_of_Crows_Sound_Effect_Actions )
endfunction
globals
constant key KEY_BEAST_WITHIN
endglobals
function Trig_Beast_Within_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BEAST_WITHIN
endfunction
function Trig_Beast_Within_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local unit avatar = null
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local string effectModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_SPECIAL)
call ExileUnit(target, true)
set avatar = CreateUnit(GetOwningPlayer(target), SB_T_REX, GetUnitX(target), GetUnitY(target), GetUnitFacing(target))
call AddSpecialEffectTargetOneShot(effectModel, avatar, "origin")
call UnitApplyTimedLife(avatar, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call SaveUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_BEAST_WITHIN, target)
call PlaySBAlertOnUnit(GetOwningPlayer(caster), avatar, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Beast_Within_Cast takes nothing returns nothing
set gg_trg_Beast_Within_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Beast_Within_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Beast_Within_Cast, Condition( function Trig_Beast_Within_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Beast_Within_Cast, function Trig_Beast_Within_Cast_Actions )
endfunction
function Trig_Beast_Within_Death_Conditions takes nothing returns boolean
return HaveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(GetDyingUnit()), KEY_BEAST_WITHIN)
endfunction
function Trig_Beast_Within_Death_Actions takes nothing returns nothing
local unit avatar = GetDyingUnit()
local unit exiledUnit = LoadUnitHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_BEAST_WITHIN)
if (exiledUnit != null) then
call SetUnitX(exiledUnit, GetUnitX(avatar))
call SetUnitY(exiledUnit, GetUnitY(avatar))
call ExileUnit(exiledUnit, false)
endif
call RemoveSavedHandle(udg_HashTable_UnitOwnership, GetHandleId(avatar), KEY_BEAST_WITHIN)
endfunction
//===========================================================================
function InitTrig_Beast_Within_Death takes nothing returns nothing
set gg_trg_Beast_Within_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Beast_Within_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Beast_Within_Death, Condition( function Trig_Beast_Within_Death_Conditions ) )
call TriggerAddAction( gg_trg_Beast_Within_Death, function Trig_Beast_Within_Death_Actions )
endfunction
scope CloudOfMist initializer Init
globals
private constant hashtable HT = InitHashtable()
private CustomAura CLOUD_OF_MIST = 0
endglobals
private function CloudedUnitDamaged takes nothing returns nothing
local unit damager = GetEventDamageSource()
local texttag tt = null
if (BlzGetEventIsAttack() and GetEventDamage() > 0.0) then
set tt = FloatTextAboveUnit(damager, "miss!", 10.0, 0.0, 1.0, 0.0, 0.0, 1.0)
call SetFloatingTextMovement(tt, 3.0, 1.0, 0.0, 54.0)
call BlzSetEventWeaponType(WEAPON_TYPE_WHOKNOWS)
endif
call BlzSetEventDamage(0.0)
endfunction
private function TargetFilter takes CustomAuraEmitter emitter returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
private function UnitEntersCloud takes unit whichUnit returns nothing
local trigger damageTrigger = LoadTriggerHandle(HT, GetHandleId(whichUnit), 0)
if (damageTrigger == null) then
set damageTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(damageTrigger, whichUnit, EVENT_UNIT_DAMAGED)
call TriggerAddAction(damageTrigger, function CloudedUnitDamaged)
call SaveTriggerHandle(HT, GetHandleId(whichUnit), 0, damageTrigger)
endif
endfunction
private function UnitLeavesCloud takes unit whichUnit returns nothing
local trigger damageTrigger = LoadTriggerHandle(HT, GetHandleId(whichUnit), 0)
if (damageTrigger != null) then
call DestroyTrigger(damageTrigger)
call RemoveSavedHandle(HT, GetHandleId(whichUnit), 0)
endif
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local player p = GetOwningPlayer(caster)
local real duration = GetUnitAbilityRealLevelField(caster, SB_CLOUD_OF_MIST, ABILITY_RLF_DURATION_NORMAL)
local real aoe = GetUnitAbilityRealLevelField(caster, SB_CLOUD_OF_MIST, ABILITY_RLF_AREA_OF_EFFECT)
local unit cloud = CreateUnit(p, SB_SPECIAL_EFFECT_UNIT_CLOUD_OF_MIST, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
call PlaySoundAtPositionSB("Abilities\\Spells\\Other\\BreathOfFrost\\BreathOfFrost1.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, GetUnitX(cloud), GetUnitY(cloud), 127.0)
call UnitApplyTimedLife(cloud, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call CustomAuras_AddEmitter(cloud, CLOUD_OF_MIST, aoe)
call PlaySBAlertAtPos(p, GetSpellTargetX(), GetSpellTargetY(), GetSpellAbilityId())
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_CLOUD_OF_MIST, function OnSpellEffect)
set CLOUD_OF_MIST = CustomAuras_CreateCustomAura(0.5, UnitEntersCloud, UnitLeavesCloud, TargetFilter, 0, 0)
endfunction
endscope
function Trig_Great_Stag_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_CALL_GREAT_STAG
endfunction
function Trig_Great_Stag_Cast_Actions takes nothing returns nothing
local unit stag = CreateUnit(GetOwningPlayer(GetSpellAbilityUnit()), SB_GREAT_STAG, GetSpellTargetX(), GetSpellTargetY(), 225.0)
local real duration = GetUnitAbilityRealLevelField(GetSpellAbilityUnit(), GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
call UnitApplyTimedLife(stag, SB_BUFF_TIMED_LIFE_WATER_ELEMENTAL, duration)
call SetUnitAnimation(stag, "birth")
call QueueUnitAnimation(stag, "stand")
call PlaySBAlertOnUnit(GetOwningPlayer(GetSpellAbilityUnit()), stag, GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Great_Stag_Cast takes nothing returns nothing
set gg_trg_Great_Stag_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Great_Stag_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Great_Stag_Cast, Condition( function Trig_Great_Stag_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Great_Stag_Cast, function Trig_Great_Stag_Cast_Actions )
endfunction
function Trig_Great_Stag_Dies_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_GREAT_STAG
endfunction
function Trig_Great_Stag_Dies_Actions takes nothing returns nothing
local real deathTime = BlzGetUnitRealField(GetDyingUnit(), UNIT_RF_DEATH_TIME)
call ChangeUnitAlphaOverTime(GetDyingUnit(), deathTime * 0.5, deathTime * 0.5, 0)
endfunction
//===========================================================================
function InitTrig_Great_Stag_Dies takes nothing returns nothing
set gg_trg_Great_Stag_Dies = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Great_Stag_Dies, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Great_Stag_Dies, Condition( function Trig_Great_Stag_Dies_Conditions ) )
call TriggerAddAction( gg_trg_Great_Stag_Dies, function Trig_Great_Stag_Dies_Actions )
endfunction
scope EagleEye initializer Init
globals
private constant real RANGE_MAX_MELEE = 128.0
private constant string SOUND_EFFECT = "Units\\Creeps\\WarEagle\\HawkReady1.flac"
endglobals
private struct EagleEye extends IBuff
real acquireRangeIncrease = 0.0
real rangeIncrease0 = 0.0
real rangeIncrease1 = 0.0
real visionIncrease = 0.0
method onDestroy takes nothing returns nothing
call SetUnitAttackRange(host, 1, GetUnitAttackRange(host, 1) - rangeIncrease1)
call SetUnitAttackRange(host, 0, GetUnitAttackRange(host, 0) - rangeIncrease0)
call SetUnitAcquireRange(host, GetUnitAcquireRange(host) - acquireRangeIncrease)
call BlzSetUnitRealField(host, UNIT_RF_SIGHT_RADIUS, BlzGetUnitRealField(host, UNIT_RF_SIGHT_RADIUS) - visionIncrease)
endmethod
endstruct
private function CreateEagleEye takes unit caster, unit target returns EagleEye
local real meleeFactor = GetUnitAbilityRealField(caster, SB_EAGLE_EYE, ABILITY_RF_ARF_MISSILE_ARC)
local EagleEye ee = EagleEye.create()
set ee.host = target
set ee.rangeIncrease0 = I2R(GetUnitAbilityIntegerField(caster, SB_EAGLE_EYE, ABILITY_IF_MISSILE_SPEED))
set ee.rangeIncrease1 = ee.rangeIncrease0
set ee.acquireRangeIncrease = RMax(ee.rangeIncrease0, ee.rangeIncrease1)
set ee.visionIncrease = GetUnitAbilityRealLevelField(caster, SB_EAGLE_EYE, ABILITY_RLF_AREA_OF_EFFECT)
if (GetUnitAttackRange(target, 0) <= RANGE_MAX_MELEE) then
set ee.rangeIncrease0 = ee.rangeIncrease0 * meleeFactor
endif
if (GetUnitAttackRange(target, 1) <= RANGE_MAX_MELEE) then
set ee.rangeIncrease1 = ee.rangeIncrease1 * meleeFactor
endif
call BlzSetUnitRealField(target, UNIT_RF_SIGHT_RADIUS, BlzGetUnitRealField(target, UNIT_RF_SIGHT_RADIUS) + ee.visionIncrease)
call SetUnitAcquireRange(target, GetUnitAcquireRange(target) + ee.acquireRangeIncrease)
call SetUnitAttackRange(target, 0, GetUnitAttackRange(target, 0) + ee.rangeIncrease0)
call SetUnitAttackRange(target, 1, GetUnitAttackRange(target, 1) + ee.rangeIncrease1)
call TrackBuff(ee, SB_BUFF_EAGLE_EYE, 0.5, 0, 0)
return ee
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
call CreateEagleEye(caster, target)
call PlaySoundAtPositionSB(SOUND_EFFECT, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, GetUnitX(target), GetUnitY(target), 100.0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_EAGLE_EYE, function OnSpellEffect)
endfunction
endscope
scope HoldTheLine initializer Init
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call DummyCastUnit(GetOwningPlayer(caster), caster, GetUnitX(caster), GetUnitY(caster), SB_HOLD_THE_LINE_HIDDEN_CASTER, "innerfire")
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_HOLD_THE_LINE, function OnSpellEffect)
endfunction
endscope
scope Saplings
globals
private constant real SAPLING_UPDATE_INTERVAL = 1.0
private constant string SAPLING_SPAWN_EFFECT_MODEL = "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"
endglobals
private struct Sapling
unit sapling = null
real hpLossPerSec = 0.0
endstruct
private function UpdateSapling takes IntTimer it returns nothing
local Sapling data = it.owner
if (UnitAlive(data.sapling)) then
if (not BlzIsUnitInvulnerable(data.sapling)) then
call ChangeUnitState(data.sapling, UNIT_STATE_LIFE, -data.hpLossPerSec * TimerPlusGetElapsed(it))
endif
else
call it.destroy()
call data.destroy()
endif
endfunction
function SpawnSapling takes player p, real duration, real x, real y, real facing, boolean workerMode returns unit
local Sapling data = Sapling.create()
local IntTimer it = CreateIntTimer(data, false)
local integer unitTypeId = SB_SAPLING_WARRIOR_MODE
if (workerMode) then
set unitTypeId = SB_SAPLING
endif
set data.sapling = CreateUnit(p, unitTypeId, x, y, facing)
set data.hpLossPerSec = DBZ(BlzGetUnitMaxHP(data.sapling), duration, 0.0)
call AddSpecialEffectOneShot(SAPLING_SPAWN_EFFECT_MODEL, x, y)
call StartTimerPlusPeriodic(it, 0.0, SAPLING_UPDATE_INTERVAL, UpdateSapling, 0)
return data.sapling
endfunction
function SpawnSaplings takes player p, integer count, real duration, real x, real y, real facing, boolean workerMode returns group
local group result = CreateGroup()
local unit sapling = null
local integer i = 0
loop
exitwhen i >= count
set sapling = SpawnSapling(p, duration, x, y, facing, workerMode)
call GroupAddUnit(result, sapling)
set i = i + 1
endloop
return result
endfunction
endscope
function Trig_Camoflage_Init_Actions takes nothing returns nothing
local group unitsWithCamo = GetUnitsInRectWithAbility(GetEntireMapRect(), SB_CAMOFLAGE)
local unit picked = null
loop
set picked = FirstOfGroup(unitsWithCamo)
exitwhen picked == null
call BlzUnitDisableAbility(picked, SB_CAMOFLAGE, true, true)
call UnitAddAbility(picked, SB_CAMOFLAGE_DUMMY)
call GroupRemoveUnit(unitsWithCamo, picked)
endloop
call DestroyGroup(unitsWithCamo)
endfunction
//===========================================================================
function InitTrig_Camoflage_Init takes nothing returns nothing
set gg_trg_Camoflage_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Camoflage_Init, function Trig_Camoflage_Init_Actions )
endfunction
function Trig_Camoflage_Enters_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_CAMOFLAGE)
endfunction
function Trig_Camoflage_Enters_Actions takes nothing returns nothing
call BlzUnitDisableAbility(GetEnteringUnit(), SB_CAMOFLAGE, true, true)
call UnitAddAbility(GetEnteringUnit(), SB_CAMOFLAGE_DUMMY)
endfunction
//===========================================================================
function InitTrig_Camoflage_Enters takes nothing returns nothing
set gg_trg_Camoflage_Enters = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Camoflage_Enters, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Camoflage_Enters, Condition( function Trig_Camoflage_Enters_Conditions ) )
call TriggerAddAction( gg_trg_Camoflage_Enters, function Trig_Camoflage_Enters_Actions )
endfunction
globals
constant key KEY_CAMOFLAGE
endglobals
function Trig_Camoflage_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_CAMOFLAGE_DUMMY
endfunction
function Trig_Camoflage_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call BlzUnitDisableAbility(caster, SB_CAMOFLAGE_DUMMY, true, true)
call BlzUnitDisableAbility(caster, SB_CAMOFLAGE, false, false)
call IssueImmediateOrderById(caster, SB_ORDER_AMBUSH)
call SaveBoolean(udg_HashTable_UnitInfo, GetHandleId(caster), KEY_CAMOFLAGE, true)
call ArmySystem_RemoveUnitFromArmy(caster, false)
endfunction
//===========================================================================
function InitTrig_Camoflage_Cast takes nothing returns nothing
set gg_trg_Camoflage_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Camoflage_Cast, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Camoflage_Cast, Condition( function Trig_Camoflage_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Camoflage_Cast, function Trig_Camoflage_Cast_Actions )
endfunction
function Trig_Camoflage_End_Conditions takes nothing returns boolean
return HaveSavedBoolean(udg_HashTable_UnitInfo, GetHandleId(GetOrderedUnit()), KEY_CAMOFLAGE) and GetIssuedOrderId() != SB_ORDER_AMBUSH
endfunction
function Trig_Camoflage_End_Actions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
call ArmySystem_UnRemoveUnitFromArmy(ordered, false)
call BlzUnitDisableAbility(ordered, SB_CAMOFLAGE_DUMMY, false, false)
call BlzUnitDisableAbility(ordered, SB_CAMOFLAGE, true, true)
call RemoveSavedBoolean(udg_HashTable_UnitInfo, GetHandleId(ordered), KEY_CAMOFLAGE)
endfunction
//===========================================================================
function InitTrig_Camoflage_End takes nothing returns nothing
set gg_trg_Camoflage_End = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Camoflage_End, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Camoflage_End, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Camoflage_End, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Camoflage_End, Condition( function Trig_Camoflage_End_Conditions ) )
call TriggerAddAction( gg_trg_Camoflage_End, function Trig_Camoflage_End_Actions )
endfunction
function Trig_Camoflage_Damaged_Conditions takes nothing returns boolean
return UnitHasAbility(BlzGetEventDamageTarget(), SB_CAMOFLAGE_DUMMY) and BlzGetEventIsAttack()
endfunction
function Trig_Camoflage_Damaged_Actions takes nothing returns nothing
call BlzStartUnitAbilityCooldown(BlzGetEventDamageTarget(), SB_CAMOFLAGE_DUMMY, 4.0)
call BlzStartUnitAbilityCooldown(BlzGetEventDamageTarget(), SB_CAMOFLAGE, 4.0)
endfunction
//===========================================================================
function InitTrig_Camoflage_Damaged takes nothing returns nothing
set gg_trg_Camoflage_Damaged = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Camoflage_Damaged, EVENT_PLAYER_UNIT_DAMAGED )
call TriggerAddCondition( gg_trg_Camoflage_Damaged, Condition( function Trig_Camoflage_Damaged_Conditions ) )
call TriggerAddAction( gg_trg_Camoflage_Damaged, function Trig_Camoflage_Damaged_Actions )
call GateAbilityTrigger(gg_trg_Camoflage_Damaged, SB_CAMOFLAGE_DUMMY, 0)
endfunction
scope AcidSwoop initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant real SWOOP_UPDATE_INTERVAL = 0.01
private constant real SWOOP_MIN_FLY_HEIGHT = 90.0
private constant string SOUND_EFFECT = "Units/Undead/FrostWyrm/FrostwyrmYesAttack3.flac"
endglobals
struct AcidSwoop
unit caster = null
real targetX = 0.0
real targetY = 0.0
location start = null
location end = null
real speed = 0.0
real arcFactor = 0.0
real returnDistance = 0.0
real flyHeightStart = 0.0
real selectionCircleStart = 0.0
real damageAoe = 0.0
real damage = 0.0
string areaArt = null
string hitArt = null
effect vfxLeft = null
effect vfxRight = null
DumbTimer damageInterval = 0
IntTimer updateLoop = 0
method onDestroy takes nothing returns nothing
if (UnitAlive(caster)) then
call ResetUnitAnimation(caster)
endif
call DestroyEffect(vfxLeft)
call DestroyEffect(vfxRight)
call damageInterval.destroy()
call updateLoop.destroy()
call RemoveLocation(start)
call RemoveLocation(end)
call RemoveSavedInteger(HT, GetHandleId(caster), 0)
set caster = null
endmethod
endstruct
private function CreateSwoop takes unit caster, real x, real y returns AcidSwoop
local real castRange = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_RLF_CAST_RANGE)
local real angle = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), x, y)
local AcidSwoop instance = LoadInteger(HT, GetHandleId(caster), 0)
if (instance != 0) then
call instance.destroy()
endif
set instance = AcidSwoop.create()
set instance.caster = caster
set instance.targetX = PolarProjectionX(GetUnitX(caster), castRange, angle)
set instance.targetY = PolarProjectionY(GetUnitY(caster), castRange, angle)
set instance.start = GetUnitLoc(caster)
set instance.flyHeightStart = GetUnitFlyHeight(caster)
set instance.selectionCircleStart = BlzGetUnitRealField(caster, UNIT_RF_SELECTION_CIRCLE_HEIGHT)
set instance.speed = GetUnitAbilityIntegerField(caster, SB_ACID_BREATH_SWOOP, ABILITY_IF_MISSILE_SPEED)
set instance.arcFactor = GetUnitAbilityRealField(caster, SB_ACID_BREATH_SWOOP, ABILITY_RF_ARF_MISSILE_ARC)
set instance.returnDistance = castRange
set instance.areaArt = GetUnitAbilityStringLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_SLF_AREA_EFFECT)
set instance.hitArt = GetUnitAbilityStringLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_SLF_SPECIAL)
set instance.damageAoe = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_RLF_AREA_OF_EFFECT)
set instance.damage = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_RLF_DURATION_HERO)
set instance.damageInterval = CreateDumbTimer(GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_RLF_DURATION_NORMAL))
set instance.updateLoop = CreateIntTimer(instance, false)
set instance.vfxLeft = AddSpecialEffectTarget(GetUnitAbilityStringLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_SLF_MISSILE_ART), caster, "hand left")
set instance.vfxRight = AddSpecialEffectTarget(GetUnitAbilityStringLevelField(caster, SB_ACID_BREATH_SWOOP, ABILITY_SLF_MISSILE_ART), caster, "hand right")
call SaveInteger(HT, GetHandleId(caster), 0, instance)
return instance
endfunction
private function DamageFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
endif
return true
endfunction
private function UpdateSwoop takes IntTimer it returns nothing
local AcidSwoop swoop = it.owner
local unit caster = swoop.caster
local location targetLoc = null
local real dist = 0.0
local real currentDist = 0.0
local real flyHeight = 0.0
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local real speed = swoop.speed * TimerPlusGetElapsed(it)
local real angle = 0.0
local real defaultFlyHeight = GetUnitDefaultFlyHeight(caster)
local real targetFlyHeight = RMin(SWOOP_MIN_FLY_HEIGHT, defaultFlyHeight)
local group aoeTargets = null
local unit picked = null
local integer aoeCount = 0
local rect map = GetPlayableMapRect()
local boolean doAOE = true
local boolean end = false
if (UnitAlive(caster)) then
if (swoop.end == null) then
set angle = AngleBetweenPointsXY(x, y, swoop.targetX, swoop.targetY)
set dist = DistanceBetweenPointsXY(GetLocationX(swoop.start), GetLocationY(swoop.start), swoop.targetX, swoop.targetY)
set currentDist = DistanceBetweenPointsXY(x, y, swoop.targetX, swoop.targetY)
if (currentDist > speed) then
set x = PolarProjectionX(x, speed, angle)
set y = PolarProjectionY(y, speed, angle)
if (RectContainsCoords(map, x, y)) then
set flyHeight = Pow(DBZ(currentDist, dist, 1), swoop.arcFactor) * (swoop.flyHeightStart - targetFlyHeight) + targetFlyHeight
call SetUnitX(caster, x)
call SetUnitY(caster, y)
call SetUnitPosition(caster, x, y)
call SetUnitFacing(caster, angle)
call SetUnitAnimation(caster, "walk")
call SetUnitFlyHeight(caster, flyHeight, 0)
else
set end = true
endif
elseif (RectContainsCoords(map, swoop.targetX, swoop.targetY)) then
call SetUnitPosition(caster, swoop.targetX, swoop.targetY)
call SetUnitFlyHeight(caster, targetFlyHeight, 0)
set angle = AngleBetweenPointsXY(GetLocationX(swoop.start), GetLocationY(swoop.start), x, y)
call RemoveLocation(swoop.start)
set swoop.start = GetUnitLoc(caster)
set swoop.end = Location(PolarProjectionX(swoop.targetX, swoop.returnDistance, angle), PolarProjectionY(swoop.targetY, swoop.returnDistance, angle))
else
set end = true
endif
else
set angle = AngleBetweenPointsXY(x, y, GetLocationX(swoop.end), GetLocationY(swoop.end))
set dist = DistanceBetweenPoints(swoop.start, swoop.end)
set currentDist = DistanceBetweenPointsXY(x, y, GetLocationX(swoop.end), GetLocationY(swoop.end))
if (currentDist > speed) then
set x = PolarProjectionX(x, speed, angle)
set y = PolarProjectionY(y, speed, angle)
if (RectContainsCoords(map, x, y)) then
set flyHeight = Pow(1 - DBZ(currentDist, dist, 0), swoop.arcFactor) * (defaultFlyHeight - targetFlyHeight) + targetFlyHeight
call SetUnitPosition(caster, x, y)
call SetUnitFacing(caster, angle)
call SetUnitAnimation(caster, "walk")
call SetUnitFlyHeight(caster, flyHeight, 0)
else
set end = true
endif
elseif (RectContainsCoords(map, GetLocationX(swoop.end), GetLocationY(swoop.end))) then
call SetUnitPosition(caster, GetLocationX(swoop.end), GetLocationY(swoop.end))
call SetUnitFlyHeight(caster, defaultFlyHeight, 0)
call swoop.destroy()
set doAOE = false
else
set end = true
endif
endif
if (UpdateDumbTimer(swoop.damageInterval, TimerPlusGetElapsed(it)) and doAOE and not end) then
set x = PolarProjectionX(x, swoop.damageAoe + BlzGetUnitCollisionSize(caster), angle)
set y = PolarProjectionY(y, swoop.damageAoe + BlzGetUnitCollisionSize(caster), angle)
call AddSpecialEffectOneShot(swoop.areaArt, x, y)
set aoeTargets = GetUnitsInAOEUnit(x, y, swoop.damageAoe, DamageFilter, caster)
set aoeCount = BlzGroupGetSize(aoeTargets)
loop
set aoeCount = aoeCount - 1
exitwhen aoeCount < 0
set picked = BlzGroupUnitAt(aoeTargets, aoeCount)
call AddSpecialEffectTargetOneShot(swoop.hitArt, picked, "chest")
call DummyCastUnit(GetOwningPlayer(caster), picked, GetUnitX(picked), GetUnitY(picked), SB_ACID_BREATH_HIDDEN_CASTER_GROUND, "acidbomb")
call UnitDamageTarget(caster, picked, swoop.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ACID, WEAPON_TYPE_WHOKNOWS)
endloop
call DestroyGroup(aoeTargets)
set picked = null
endif
else
set end = true
endif
if (end) then
call SetUnitFlyHeight(caster, defaultFlyHeight, 0.5)
call swoop.destroy()
endif
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local AcidSwoop swoop = CreateSwoop(caster, GetSpellTargetX(), GetSpellTargetY())
call StartTimerPlusPeriodic(swoop.updateLoop, 0.0, SWOOP_UPDATE_INTERVAL, UpdateSwoop, 0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_ACID_BREATH_SWOOP, function OnSpellEffect)
endfunction
endscope
scope ThornsArmor initializer Init
private struct ThornsArmor extends IBuff
integer hpGained = 0
real damageReturned = 0.0
string hitEffect = null
trigger damageTrigger = null
method onDestroy takes nothing returns nothing
call DestroyTrigger(damageTrigger)
call BlzSetUnitMaxHP(host, BlzGetUnitMaxHP(host) - hpGained)
endmethod
endstruct
private function ThornsArmorDamageCondition takes nothing returns boolean
local unit damager = GetEventDamageSource()
if (not IsUnitType(damager, UNIT_TYPE_MELEE_ATTACKER)) then
return false
elseif (not BlzGetEventIsAttack()) then
return false
elseif (IsUnitType(damager, UNIT_TYPE_RANGED_ATTACKER) and BlzGetEventAttackType() != ATTACK_TYPE_MELEE) then
return false
endif
return true
endfunction
private function OnThornsArmorTargetDamaged takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local unit damager = GetEventDamageSource()
local ThornsArmor ta = GetBuff(damaged, SB_BUFF_THORNS_ARMOR)
if (ta != null) then
call AddSpecialEffectTargetOneShot(ta.hitEffect, damager, "chest")
call UnitDamageTarget(damaged, damager, ta.damageReturned, false, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
endfunction
private function CreateThornsArmor takes unit caster, unit target returns ThornsArmor
local ThornsArmor ta = ThornsArmor.create()
set ta = ThornsArmor.create()
set ta.host = target
set ta.hpGained = R2I(GetUnitAbilityRealField(caster, SB_THORNS_ARMOR, ABILITY_RF_ARF_MISSILE_ARC))
set ta.damageReturned = GetUnitAbilityRealLevelField(caster, SB_THORNS_ARMOR, ABILITY_RLF_AREA_OF_EFFECT)
set ta.hitEffect = GetUnitAbilityStringLevelField(caster, SB_THORNS_ARMOR, ABILITY_SLF_SPECIAL)
set ta.damageTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(ta.damageTrigger, target, EVENT_UNIT_DAMAGED)
call TriggerAddCondition(ta.damageTrigger, Condition(function ThornsArmorDamageCondition))
call TriggerAddAction(ta.damageTrigger, function OnThornsArmorTargetDamaged)
call BlzSetUnitMaxHP(target, BlzGetUnitMaxHP(target) + ta.hpGained)
call SetUnitState(target, UNIT_STATE_LIFE, GetUnitState(target, UNIT_STATE_LIFE) + ta.hpGained)
call TrackBuff(ta, SB_BUFF_THORNS_ARMOR, 0.5, 0, 0)
return ta
endfunction
private function OnSpellEffect takes nothing returns nothing
call CreateThornsArmor(GetSpellAbilityUnit(), GetSpellTargetUnit())
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_THORNS_ARMOR, function OnSpellEffect)
endfunction
endscope
globals
key KEY_HARVEST
endglobals
function Trig_Spawn_Sapling_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SPAWN_SAPLING_STRUCTURES or GetSpellAbilityId() == SB_SPAWN_SAPLING_UNITS
endfunction
function Trig_Spawn_Sapling_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit targetUnit = GetSpellTargetUnit()
local destructable casterHarvestTarget = null
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local real targetX = 0.0
local real targetY = 0.0
local real x = 0.0
local real y = 0.0
local real dist = 0.0
local real angle = 0.0
local group spawnedUnits = null
local integer saplingCount = GetUnitAbilityLevel(caster, GetSpellAbilityId())
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local boolean isWorker = false
if (IsUnitType(caster, UNIT_TYPE_PEON) or IsUnitType(caster, UNIT_TYPE_STRUCTURE)) then
set isWorker = true
endif
//set duration = duration * DBZ(GetUnitState(caster, UNIT_STATE_MANA), BlzGetUnitMaxMana(caster), 1.0)
//call SetUnitState(caster, UNIT_STATE_MANA, 0.0)
if (targetUnit != null) then
// Spell was cast targeting a unit
set targetX = GetUnitX(targetUnit)
set targetY = GetUnitY(targetUnit)
set dist = RMinBJ(100.0, DistanceBetweenPointsXY(casterX, casterY, targetX, targetY))
set angle = AngleBetweenPointsXY(casterX, casterY, targetX, targetY)
set x = PolarProjectionX(casterX, dist, angle)
set y = PolarProjectionY(casterY, dist, angle)
set spawnedUnits = SpawnSaplings(GetOwningPlayer(caster), saplingCount, duration, x, y, angle, isWorker)
call GroupTargetOrder(spawnedUnits, "smart", targetUnit)
else
// Spell was cast targeting a point
set targetX = GetSpellTargetX()
set targetY = GetSpellTargetY()
set dist = RMinBJ(100.0, DistanceBetweenPointsXY(casterX, casterY, targetX, targetY))
set angle = AngleBetweenPointsXY(casterX, casterY, targetX, targetY)
set x = PolarProjectionX(casterX, dist, angle)
set y = PolarProjectionY(casterY, dist, angle)
if (IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)) then
set x = casterX
set y = casterY
endif
set spawnedUnits = SpawnSaplings(GetOwningPlayer(caster), saplingCount, duration, x, y, angle, isWorker)
call GroupPointOrder(spawnedUnits, "attack", targetX, targetY)
endif
call PlaySoundAtPositionSB("Units\\Creeps\\CorruptedEnt\\EntReady1.flac", "SpellsEAX", 11, casterX, casterY, 100.0)
set casterHarvestTarget = LoadDestructableHandle(udg_HashTable_Orders, GetHandleId(caster), KEY_HARVEST)
if (casterHarvestTarget != null) then
call IssueImmediateOrderAfter(caster, "autoharvestlumber", 0.01)
endif
call DestroyGroup(spawnedUnits)
endfunction
//===========================================================================
function InitTrig_Spawn_Sapling_Cast takes nothing returns nothing
set gg_trg_Spawn_Sapling_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Sapling_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spawn_Sapling_Cast, Condition( function Trig_Spawn_Sapling_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Spawn_Sapling_Cast, function Trig_Spawn_Sapling_Cast_Actions )
endfunction
function Trig_Spawn_Sapling_Orders_Conditions takes nothing returns boolean
return UnitHasAbility(GetOrderedUnit(), SB_SPAWN_SAPLING_STRUCTURES) or UnitHasAbility(GetOrderedUnit(), SB_SPAWN_SAPLING_UNITS)
endfunction
function Trig_Spawn_Sapling_Orders_Actions takes nothing returns nothing
local integer order = GetIssuedOrderId()
local destructable targetDestructable = GetOrderTargetDestructable()
if ((IsOrder(order, "harvest") or IsOrder(order, "smart")) and IsTree(targetDestructable)) then
call SaveDestructableHandle(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_HARVEST, targetDestructable)
elseif (not IsOrder(order, "parasite") and not IsOrder(order, "resumeharvesting") and not IsOrder(order, "bearform") and not IsOrder(order, "unbearform") and not(IsOrder(order, "smart") and GetUnitTypeId(GetOrderTargetUnit()) == SB_GOLD_MINE)) then
call RemoveSavedHandle(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_HARVEST)
endif
endfunction
//===========================================================================
function InitTrig_Spawn_Sapling_Orders takes nothing returns nothing
set gg_trg_Spawn_Sapling_Orders = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Sapling_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Sapling_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Sapling_Orders, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Spawn_Sapling_Orders, Condition( function Trig_Spawn_Sapling_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Spawn_Sapling_Orders, function Trig_Spawn_Sapling_Orders_Actions )
endfunction
function Trig_Spawn_Sapling_Train_Conditions takes nothing returns boolean
if (GetUnitTypeId(GetTrainedUnit()) != SB_DENDROID_TREEHERD ) then
return false
endif
if (GetUnitRallyDestructable(GetTriggerUnit()) == null) then
return false
endif
if (not IsTree(GetUnitRallyDestructable(GetTriggerUnit()))) then
return false
endif
return true
endfunction
function Trig_Spawn_Sapling_Train_Actions takes nothing returns nothing
call IssueTargetDestructableOrder( GetTrainedUnit(), "harvest", GetUnitRallyDestructable(GetTriggerUnit()))
endfunction
//===========================================================================
function InitTrig_Spawn_Sapling_Train takes nothing returns nothing
set gg_trg_Spawn_Sapling_Train = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spawn_Sapling_Train, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( gg_trg_Spawn_Sapling_Train, Condition( function Trig_Spawn_Sapling_Train_Conditions ) )
call TriggerAddAction( gg_trg_Spawn_Sapling_Train, function Trig_Spawn_Sapling_Train_Actions )
endfunction
globals
constant key KEY_NULL_BOMB
endglobals
struct NullBomb
unit target = null
unit caster = null
unit effectUnit = null
real aoe = 0.0
timer delayTimer = null
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_NULL_BOMB)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(delayTimer), KEY_NULL_BOMB)
call DestroyTimer(delayTimer)
endmethod
endstruct
function Trig_Null_Bomb_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_NULL_BOMB
endfunction
function Trig_Null_Bomb_Detonate_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (GetUnitState(filter, UNIT_STATE_MAX_MANA) <= 0) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
endif
return true
endfunction
function Trig_Null_Bomb_Detonate takes nothing returns nothing
local timer delayTimer = GetExpiredTimer()
local NullBomb bomb = LoadInteger(udg_HashTable_Timers, GetHandleId(delayTimer), KEY_NULL_BOMB)
local group nearbyUnits = CreateGroup()
local unit pickedUnit = null
local effect explosion = null
if (UnitHasBuffBJ(bomb.target, SB_BUFF_NULL_BOMB) and UnitAlive(bomb.target)) then
set explosion = AddSpecialEffect("war3mapImported\\NullBomb.mdx", GetUnitX(bomb.target), GetUnitY(bomb.target))
call BlzSetSpecialEffectZ(explosion, 160.0 + BlzGetUnitZ(bomb.target) + GetUnitFlyHeight(bomb.target))
call DestroyEffect(explosion)
call GroupEnumUnitsInRange(nearbyUnits, GetUnitX(bomb.target), GetUnitY(bomb.target), bomb.aoe + udg_Real_MaxCollisionSize, Condition(function Trig_Null_Bomb_Detonate_Filter))
loop
set pickedUnit = FirstOfGroup(nearbyUnits)
exitwhen pickedUnit == null
if (not IsUnitAlly(pickedUnit, GetOwningPlayer(bomb.caster))) then
if (DistanceBetweenUnits(bomb.target, pickedUnit) - BlzGetUnitCollisionSize(pickedUnit) <= bomb.aoe) then
call ChangeUnitState(pickedUnit, UNIT_STATE_MANA, -200)
endif
endif
call GroupRemoveUnit(nearbyUnits, pickedUnit)
endloop
endif
call DestroyGroup(nearbyUnits)
call bomb.destroy()
endfunction
function Trig_Null_Bomb_Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
local real delay = GetUnitAbilityRealLevelField(GetSpellAbilityUnit(), GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local NullBomb bomb = LoadInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_NULL_BOMB)
if (bomb == 0) then
set bomb = NullBomb.create()
set bomb.target = target
//set bomb.effectUnit = CreateUnit(GetOwningPlayer(target), SB_SPECIAL_EFFECT_UNIT_NULL_BOMB, GetUnitX(target), GetUnitY(target), bj_UNIT_FACING)
set bomb.delayTimer = CreateTimer()
call AddFollowDummy(bomb.target, bomb.effectUnit, LIFELINK_KILL)
call SetUnitAnimation(bomb.effectUnit, "birth")
call QueueUnitAnimation(bomb.effectUnit, "stand")
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(target), KEY_NULL_BOMB, bomb)
call SaveInteger(udg_HashTable_Timers, GetHandleId(bomb.delayTimer), KEY_NULL_BOMB, bomb)
endif
set bomb.caster = GetSpellAbilityUnit()
set bomb.aoe = GetUnitAbilityRealLevelField(GetSpellAbilityUnit(), GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
//call SetUnitScale(bomb.effectUnit, 1.0, 1.0, 1.0)
//call ChangeUnitSizeOverTime(bomb.effectUnit, delay, 1.0)
call TimerStart(bomb.delayTimer, delay, false, function Trig_Null_Bomb_Detonate)
endfunction
//===========================================================================
function InitTrig_Null_Bomb takes nothing returns nothing
set gg_trg_Null_Bomb = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Null_Bomb, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Null_Bomb, Condition( function Trig_Null_Bomb_Conditions ) )
call TriggerAddAction( gg_trg_Null_Bomb, function Trig_Null_Bomb_Actions )
endfunction
scope Whirlwind initializer Init
globals
private constant hashtable HT = InitHashtable()
endglobals
struct Whirlwind
unit target = null
integer originalTargetedAs = 0
effect sfx = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call BlzSetSpecialEffectTimeScale(sfx, 3.0)
call DestroyEffect(sfx)
call it.destroy()
call RemoveSavedInteger(HT, GetHandleId(target), 0)
endmethod
endstruct
private function GetWhirlwind takes unit target returns Whirlwind
return LoadInteger(HT, GetHandleId(target), 0)
endfunction
private function CreateWhirlwind takes unit caster, unit target returns Whirlwind
local string effectArt = GetUnitAbilityStringLevelField(caster, SB_WHIRLWIND, ABILITY_SLF_SPECIAL)
local integer targetedAs = BlzGetUnitIntegerField(target, UNIT_IF_TARGETED_AS)
local integer newTargetedAs = BlzBitXor(BlzBitOr(targetedAs, GetHandleId(TARGET_FLAG_AIR)), GetHandleId(TARGET_FLAG_GROUND))
local Whirlwind ww = Whirlwind.create()
set ww.target = target
set ww.originalTargetedAs = targetedAs
set ww.sfx = AddSpecialEffect(effectArt, GetUnitX(target), GetUnitY(target))
set ww.it = CreateIntTimer(ww, false)
call EnableUnitFlyHeight(target)
call SetUnitFlyHeight(target, 300.0, 500.0)
call BlzSetUnitIntegerField(target, UNIT_IF_TARGETED_AS, newTargetedAs)
call BlzUnitDisableAbility(target, 'Aatk', true, false)
call SaveInteger(HT, GetHandleId(target), 0, ww)
return ww
endfunction
function WhirlwindUpdate takes IntTimer it returns nothing
local Whirlwind ww = it.owner
if (UnitHasAbility(ww.target, SB_BUFF_WHIRLWIND)) then
call BlzSetSpecialEffectX(ww.sfx, GetUnitX(ww.target))
call BlzSetSpecialEffectY(ww.sfx, GetUnitY(ww.target))
else
call SetUnitFlyHeight(ww.target, GetUnitDefaultFlyHeight(ww.target), 1600.0)
call BlzSetUnitIntegerField(ww.target, UNIT_IF_TARGETED_AS, ww.originalTargetedAs)
call BlzUnitDisableAbility(ww.target, 'Aatk', false, false)
call ww.destroy()
endif
endfunction
function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local integer targetedAs = BlzGetUnitIntegerField(target, UNIT_IF_TARGETED_AS)
local integer newTargetedAs = BlzBitXor(BlzBitOr(targetedAs, GetHandleId(TARGET_FLAG_AIR)), GetHandleId(TARGET_FLAG_GROUND))
local Whirlwind ww = GetWhirlwind(target)
if (ww == 0) then
set ww = CreateWhirlwind(caster, target)
endif
call StartTimerPlusPeriodic(ww.it, 0.0, 0.01, WhirlwindUpdate, 0)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_WHIRLWIND, function OnSpellEffect)
endfunction
endscope
scope Soothe
struct Soothe
unit target = null
real lastHp = 0.0
real hpPerSec = 0.0
IntTimer updateTimer = 0
method onDestroy takes nothing returns nothing
call UnitRemoveAbility(target, SB_SOOTHE_HIDDEN)
call UnitRemoveBuffBJ(SB_BUFF_SOOTHE, target)
call updateTimer.destroy()
endmethod
endstruct
private function SootheAOEFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(caster)) then
return false
elseif (not IsUnitAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (GetUnitLifePercent(filter) >= 100.0) then
return false
elseif (IsUnitType(caster, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(caster, UNIT_TYPE_STRUCTURE)) then
return false
elseif (UnitHasBuffBJ(filter, SB_BUFF_SOOTHE)) then
return false
endif
return true
endfunction
private function CostComparer takes unit a, unit b returns integer
local real aPct = GetUnitLifePercent(a)
local real bPct = GetUnitLifePercent(b)
if (aPct > bPct) then
return 1
elseif (aPct < bPct) then
return -1
else
return 0
endif
endfunction
private function SootheUpdate takes IntTimer it returns nothing
local Soothe soothe = it.owner
local real currentHp = GetUnitState(soothe.target, UNIT_STATE_LIFE)
if (not UnitAlive(soothe.target)) then
call soothe.destroy()
elseif (currentHp >= BlzGetUnitMaxHP(soothe.target)) then
call soothe.destroy()
elseif (currentHp < soothe.lastHp) then
call soothe.destroy()
else
call ChangeUnitState(soothe.target, UNIT_STATE_LIFE, soothe.hpPerSec * TimerPlusGetElapsed(it))
set soothe.lastHp = GetUnitState(soothe.target, UNIT_STATE_LIFE)
endif
endfunction
function CreateSoothe takes unit caster, real x, real y returns nothing
local Soothe soothe = 0
local real aoe = GetUnitAbilityRealLevelField(caster, SB_SOOTHE, ABILITY_RLF_AREA_OF_EFFECT)
local real interval = GetUnitAbilityRealLevelField(caster, SB_SOOTHE, ABILITY_RLF_DURATION_NORMAL)
local real hpPerSec = GetUnitAbilityRealLevelField(caster, SB_SOOTHE, ABILITY_RLF_DURATION_HERO)
local group unitsInAOE = GetUnitsInRangeUnit(x, y, aoe, SootheAOEFilter, caster)
local integer manaCost = GetUnitAbilityIntegerLevelField(caster, SB_SOOTHE, ABILITY_ILF_MANA_COST)
local integer maxUnits = R2I(GetUnitState(caster, UNIT_STATE_MANA) / manaCost)
local integer i = 0
local integer count = IMinBJ(CountUnitsInGroup(unitsInAOE), maxUnits)
local unit picked = null
if (count > 0) then
call GroupSortDestructive(unitsInAOE, CostComparer, 0)
loop
exitwhen i >= count
set picked = QUICK_SORT_CONTAINER[i]
set soothe = Soothe.create()
set soothe.target = picked
set soothe.lastHp = GetUnitState(picked, UNIT_STATE_LIFE)
set soothe.hpPerSec = hpPerSec
set soothe.updateTimer = CreateIntTimer(soothe, false)
call StartTimerPlusPeriodic(soothe.updateTimer, 0.0, interval, SootheUpdate, 0)
call UnitAddAbility(picked, SB_SOOTHE_HIDDEN)
set i = i + 1
endloop
call ChangeUnitState(caster, UNIT_STATE_MANA, (count - 1) * -manaCost)
endif
call DestroyGroup(unitsInAOE)
endfunction
endscope
function Trig_Soothe_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SOOTHE
endfunction
function Trig_Soothe_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call CreateSoothe(caster, GetSpellTargetX(), GetSpellTargetY())
endfunction
//===========================================================================
function InitTrig_Soothe takes nothing returns nothing
set gg_trg_Soothe = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Soothe, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Soothe, Condition( function Trig_Soothe_Conditions ) )
call TriggerAddAction( gg_trg_Soothe, function Trig_Soothe_Actions )
endfunction
globals
constant key KEY_SLURP
constant real SNATCH_DAMAGE = 30.0
constant real SNATCH_HEALING_FACTOR = 1.0
constant real SNATCH_DELAY = 0.01
constant real SNATCH_UPDATE_INTERVAL = 0.01
constant real SNATCH_FLY_HEIGHT_RETURN_TIME = 1.0
endglobals
struct Snatch
unit caster = null
unit target = null
UnitLeash tongue = 0
real speed = 0.0
real startX = 0.0
real startY = 0.0
real startingFlyHeight = 0.0
real sinkTime = 0.0
real sinkTimeElapsed = 0.0
method onDestroy takes nothing returns nothing
call SetUnitPropWindow(target, GetUnitDefaultPropWindow(target))
call SetUnitFlyHeight(target, GetUnitDefaultFlyHeight(target), GetUnitDefaultFlyHeight(target) * SNATCH_FLY_HEIGHT_RETURN_TIME)
call tongue.destroy()
endmethod
endstruct
function UpdateSnatch takes IntTimer it returns nothing
local Snatch s = it.owner
local unit caster = s.caster
local unit target = s.target
local real speed = s.speed * TimerPlusGetElapsed(it)
local real distance = 0.0
local real distanceRemaining = 0.0
local real angle = AngleBetweenUnits(caster, target)
local real height = 0.0
local real targetX = PolarProjectionX(GetUnitX(caster), 90.0 + BlzGetUnitCollisionSize(target), angle)
local real targetY = PolarProjectionY(GetUnitY(caster), 90.0 + BlzGetUnitCollisionSize(target), angle)
set s.sinkTimeElapsed = s.sinkTimeElapsed + TimerPlusGetElapsed(it)
set height = s.startingFlyHeight * (1 - (s.sinkTimeElapsed / s.sinkTime))
call SetUnitFlyHeightBJ(target, height, 0.0)
if (UnitAlive(caster) and target != null) then
set distance = DistanceBetweenUnitAndPoint(target, targetX, targetY)
set distanceRemaining = RMaxBJ(distance, speed)
if (distance <= speed) then
call SetUnitPathingSB(target, true)
call SetUnitX(target, targetX)
call SetUnitY(target, targetY)
call s.destroy()
call it.destroy()
else
set angle = AngleBetweenUnits(target, caster)
set targetX = PolarProjectionX(GetUnitX(target), speed, angle)
set targetY = PolarProjectionY(GetUnitY(target), speed, angle)
call SetUnitPathingSB(target, false)
call SetUnitX(target, targetX)
call SetUnitY(target, targetY)
endif
else
call s.destroy()
call it.destroy()
endif
endfunction
function CreateSnatch takes unit caster, unit target returns Snatch
local Snatch snatch = Snatch.create()
set snatch.caster = caster
set snatch.target = target
set snatch.tongue = LightningEffects_CreateUnitLeash(caster, target, vec3.create(90, 0.0, 60.0), vec3.create(0, 0, 60.0), "DRAL", 0.01, BIG_REAL)
set snatch.speed = GetUnitAbilityRealLevelField(caster, SB_SLURP, ABILITY_RLF_AREA_OF_EFFECT)
set snatch.startX = GetUnitX(target)
set snatch.startY = GetUnitY(target)
set snatch.startingFlyHeight = GetUnitFlyHeight(target)
set snatch.sinkTime = (DistanceBetweenUnits(snatch.caster, snatch.target) / snatch.speed) + SNATCH_DELAY
set snatch.sinkTimeElapsed = 0.0
call SetUnitPropWindow(target, 0.0)
return snatch
endfunction
function Trig_Snatch_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SLURP
endfunction
function Trig_Snatch_Delayed takes IntTimer it returns nothing
local Snatch snatch = it.owner
call SetUnitX(snatch.target, snatch.startX)
call SetUnitY(snatch.target, snatch.startY)
call UnitDamageTargetBJ(snatch.caster, snatch.target, SNATCH_DAMAGE, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL)
call ChangeUnitState(snatch.caster, UNIT_STATE_LIFE, SNATCH_DAMAGE * SNATCH_HEALING_FACTOR)
//call AddSpecialEffectTargetOneShot("Doodads\\Dungeon\\Terrain\\EggSack\\EggSack1.mdl", snatch.target, "chest")
call StartTimerPlusPeriodic(it, 0.0, SNATCH_UPDATE_INTERVAL, UpdateSnatch, 0)
endfunction
function Trig_Snatch_Actions takes nothing returns nothing
local Snatch snatch = CreateSnatch(GetSpellAbilityUnit(), GetSpellTargetUnit())
local IntTimer delay = CreateIntTimer(snatch, false)
call SetUnitPathingSB(snatch.target, false)
call SetUnitAbilityRealLevelField(snatch.caster, GetSpellAbilityId(), ABILITY_RLF_AIR_UNIT_LOWER_DURATION, snatch.sinkTime)
call StartTimerPlus(delay, SNATCH_DELAY, Trig_Snatch_Delayed)
endfunction
//===========================================================================
function InitTrig_Snatch takes nothing returns nothing
set gg_trg_Snatch = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Snatch, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Snatch, Condition( function Trig_Snatch_Conditions ) )
call TriggerAddAction( gg_trg_Snatch, function Trig_Snatch_Actions )
endfunction
function Trig_Slurp_Research_Conditions takes nothing returns boolean
return GetResearched() == SB_TECH_SLURP
endfunction
function Trig_Slurp_Research_Actions takes nothing returns nothing
local group slurpers = GetUnitsOfPlayerWithAbility(GetOwningPlayer(GetResearchingUnit()), SB_SLURP)
local unit picked = null
loop
set picked = FirstOfGroup(slurpers)
exitwhen picked == null
call IssueImmediateOrder(picked, "webon")
call GroupRemoveUnit(slurpers, picked)
endloop
call DestroyGroup(slurpers)
endfunction
//===========================================================================
function InitTrig_Slurp_Research takes nothing returns nothing
set gg_trg_Slurp_Research = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Slurp_Research, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddCondition( gg_trg_Slurp_Research, Condition( function Trig_Slurp_Research_Conditions ) )
call TriggerAddAction( gg_trg_Slurp_Research, function Trig_Slurp_Research_Actions )
endfunction
function Trig_Slurp_Track_Autocast_Init_Loop takes nothing returns nothing
local group toads = null
local unit picked = null
if (PlayerHasTech(GetEnumPlayer(), SB_TECH_SLURP)) then
set toads = GetUnitsOfPlayerWithAbility(GetEnumPlayer(), SB_SLURP)
loop
set picked = FirstOfGroup(toads)
exitwhen picked == null
call SaveBoolean(udg_HashTable_Autocast, GetHandleId(picked), KEY_SLURP, true)
call GroupRemoveUnit(toads, picked)
endloop
call DestroyGroup(toads)
endif
endfunction
function Trig_Slurp_Track_Autocast_Init_Actions takes nothing returns nothing
local force players = GetPlayingPlayers(false, true, false)
call ForForce(players, function Trig_Slurp_Track_Autocast_Init_Loop)
call DestroyForce(players)
endfunction
//===========================================================================
function InitTrig_Slurp_Track_Autocast_Init takes nothing returns nothing
set gg_trg_Slurp_Track_Autocast_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Slurp_Track_Autocast_Init, function Trig_Slurp_Track_Autocast_Init_Actions )
endfunction
function Trig_Slurp_Track_Autocast_Order_Conditions takes nothing returns boolean
return GetIssuedOrderId() == String2OrderIdBJ("webon") or GetIssuedOrderId() == String2OrderIdBJ("weboff")
endfunction
function Trig_Slurp_Track_Autocast_Order_Actions takes nothing returns nothing
if (GetIssuedOrderId() == String2OrderIdBJ("webon")) then
call SaveBoolean(udg_HashTable_Autocast, GetHandleId(GetOrderedUnit()), KEY_SLURP, true)
else
call RemoveSavedBoolean(udg_HashTable_Autocast, GetHandleId(GetOrderedUnit()), KEY_SLURP)
endif
endfunction
//===========================================================================
function InitTrig_Slurp_Track_Autocast_Order takes nothing returns nothing
set gg_trg_Slurp_Track_Autocast_Order = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Slurp_Track_Autocast_Order, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Slurp_Track_Autocast_Order, Condition( function Trig_Slurp_Track_Autocast_Order_Conditions ) )
call TriggerAddAction( gg_trg_Slurp_Track_Autocast_Order, function Trig_Slurp_Track_Autocast_Order_Actions )
endfunction
function Trig_Slurp_Track_Autocast_Cleanup_Conditions takes nothing returns boolean
return HaveSavedBoolean(udg_HashTable_Autocast, GetHandleId(GetDyingUnit()), KEY_SLURP)
endfunction
function Trig_Slurp_Track_Autocast_Cleanup_Actions takes nothing returns nothing
call RemoveSavedBoolean(udg_HashTable_Autocast, GetHandleId(GetDyingUnit()), KEY_SLURP)
endfunction
//===========================================================================
function InitTrig_Slurp_Track_Autocast_Cleanup takes nothing returns nothing
set gg_trg_Slurp_Track_Autocast_Cleanup = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Slurp_Track_Autocast_Cleanup, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Slurp_Track_Autocast_Cleanup, Condition( function Trig_Slurp_Track_Autocast_Cleanup_Conditions ) )
call TriggerAddAction( gg_trg_Slurp_Track_Autocast_Cleanup, function Trig_Slurp_Track_Autocast_Cleanup_Actions )
endfunction
function Trig_Leap_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_LEAP
endfunction
function Trig_Leap_Cast_OnMove takes SimMovement sim returns nothing
call SetUnitAnimationByIndex(sim.mover, 9)
endfunction
function Trig_Leap_Cast_Knockback_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (GetUnitDefaultMoveSpeed(filter) <= 0.0) then
return false
endif
return true
endfunction
function Trig_Leap_Cast_Slurp_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MECHANICAL)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (not IsUnitEnemy(filter, udg_Player_Temp)) then
return false
elseif (not IsUnitVisible(filter, udg_Player_Temp)) then
return false
endif
return true
endfunction
function Trig_Leap_Cast_Slurp_Filter2 takes unit whichUnit returns boolean
return not HaveSavedHandle(udg_HashTable_TargetToCaster, GetHandleId(whichUnit), KEY_SLURP)
endfunction
function Trig_Leap_Cast_Finished takes SimMovement sim returns nothing
local unit whichUnit = sim.mover
local group nearbyUnits = CreateGroup()
local unit pickedUnit = null
local real leaperX = GetUnitX(whichUnit)
local real leaperY = GetUnitY(whichUnit)
local real targetX = 0.0
local real targetY = 0.0
local real dist = 0.0
local real angle = 0.0
call IssueImmediateOrder(whichUnit, "stop")
call BlzSetUnitIntegerFieldBJ(whichUnit, UNIT_IF_MOVE_TYPE, GetHandleId(MOVE_TYPE_FOOT))
call SetUnitTimeScale(whichUnit, 1.0)
call ResetUnitAnimation(whichUnit)
call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl", GetUnitX(whichUnit), GetUnitY(whichUnit)))
call GroupEnumUnitsInRange(nearbyUnits, GetUnitX(whichUnit), GetUnitY(whichUnit), BlzGetUnitCollisionSize(whichUnit), function Trig_Leap_Cast_Knockback_Filter)
loop
set pickedUnit = FirstOfGroup(nearbyUnits)
exitwhen pickedUnit == null
if (pickedUnit != whichUnit) then
set dist = BlzGetUnitCollisionSize(whichUnit) + BlzGetUnitCollisionSize(pickedUnit) - DistanceBetweenUnits(pickedUnit, whichUnit)
set angle = AngleBetweenUnits(whichUnit, pickedUnit)
set targetX = PolarProjectionX(GetUnitX(pickedUnit), dist, angle)
set targetY = PolarProjectionY(GetUnitY(pickedUnit), dist, angle)
call MoveUnitToPointAtSpeedXY(pickedUnit, targetX, targetY, 900.0)
endif
call GroupRemoveUnit(nearbyUnits, pickedUnit)
endloop
call GroupClear(nearbyUnits)
call UnitRemoveSlows(whichUnit)
if (HaveSavedBoolean(udg_HashTable_Autocast, GetHandleId(whichUnit), KEY_SLURP)) then
set udg_Player_Temp = GetOwningPlayer(whichUnit)
set dist = GetUnitAbilityRealLevelField(whichUnit, SB_SLURP, ABILITY_RLF_CAST_RANGE)
call GroupEnumUnitsInRange(nearbyUnits, leaperX, leaperY, dist, Condition(function Trig_Leap_Cast_Slurp_Filter))
set pickedUnit = GroupPickClosestUnitMatching(nearbyUnits, leaperX, leaperY, Trig_Leap_Cast_Slurp_Filter2)
if (pickedUnit != null) then
call IssueImmediateOrder(whichUnit, "stop")
call IssueTargetOrderBJ(whichUnit, "web", pickedUnit)
endif
endif
call DestroyGroup(nearbyUnits)
endfunction
function Trig_Leap_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real originX = GetUnitX(caster)
local real originY = GetUnitY(caster)
local real maxRange = GetUnitAbilityRealLevelField(caster, SB_LEAP, ABILITY_RLF_MAXIMUM_RANGE)
local real angle = AngleBetweenPointsXY(originX, originY, GetSpellTargetX(), GetSpellTargetY())
local real dist = RMinBJ(maxRange, DistanceBetweenPointsXY(originX, originY, GetSpellTargetX(), GetSpellTargetY()))
local real targetX = PolarProjectionX(originX, dist, angle)
local real targetY = PolarProjectionY(originY, dist, angle)
local real speed = 2000.0
local real arc = BlzGetAbilityRealField(BlzGetUnitAbility(caster, SB_LEAP), ABILITY_RF_ARF_MISSILE_ARC)
local real time = DistanceBetweenPointsXY(originX, originY, targetX, targetY) / speed
local effect launchEffect = null
call BlzStartUnitAbilityCooldown(caster, SB_LEAP, BlzGetAbilityCooldown(SB_LEAP, GetUnitAbilityLevel(caster, SB_LEAP) - 1))
call BlzSetUnitFacingEx(caster, AngleBetweenPointsXY(originX, originY, targetX, targetY))
call IssueImmediateOrder(caster, "stop")
call SetUnitTimeScale(caster, 1 / time)
call SetUnitAnimationByIndex(caster, 9)
set launchEffect = AddSpecialEffect("war3mapImported\\SandWaveDamage.mdl", originX, originY)
call BlzSetSpecialEffectScale(launchEffect, 2.0)
call BlzSetSpecialEffectZ(launchEffect, BlzGetUnitZ(caster) - 95.0)
call DestroyEffect(launchEffect)
call BlzSetUnitIntegerFieldBJ(caster, UNIT_IF_MOVE_TYPE, GetHandleId(MOVE_TYPE_FLY))
call MoveUnitToPointAtSpeedAll(caster, targetX, targetY, speed, arc, SIM_MOVE_TYPE_SETXY, Trig_Leap_Cast_OnMove, Trig_Leap_Cast_Finished)
endfunction
//===========================================================================
function InitTrig_Leap takes nothing returns nothing
set gg_trg_Leap = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Leap, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Leap, Condition( function Trig_Leap_Conditions ) )
call TriggerAddAction( gg_trg_Leap, function Trig_Leap_Actions )
endfunction
function Trig_Trample_Init_Loop takes nothing returns nothing
call IssueImmediateOrder(GetEnumUnit(), "windwalk")
endfunction
function Trig_Trample_Init_Actions takes nothing returns nothing
set udg_UnitGroup_Trample = GetUnitsInRectMatching(GetPlayableMapRect(), UnitsWithAbilityFilter(SB_TRAMPLE))
if (BlzGroupGetSize(udg_UnitGroup_Trample) > 0) then
call ForGroup(udg_UnitGroup_Trample, function Trig_Trample_Init_Loop)
call EnableTrigger(gg_trg_Trample_Loop)
endif
endfunction
//===========================================================================
function InitTrig_Trample_Init takes nothing returns nothing
set gg_trg_Trample_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Trample_Init, function Trig_Trample_Init_Actions )
endfunction
function Trig_Trample_Enter_Conditions takes nothing returns boolean
return UnitHasAbility(GetEnteringUnit(), SB_TRAMPLE)
endfunction
function Trig_Trample_Enter_Actions takes nothing returns nothing
call GroupAddUnit(udg_UnitGroup_Trample, GetEnteringUnit())
call IssueImmediateOrder(GetEnteringUnit(), "windwalk")
call EnableTrigger(gg_trg_Trample_Loop)
endfunction
//===========================================================================
function InitTrig_Trample_Enter takes nothing returns nothing
set gg_trg_Trample_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Trample_Enter, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_Trample_Enter, Condition( function Trig_Trample_Enter_Conditions ) )
call TriggerAddAction( gg_trg_Trample_Enter, function Trig_Trample_Enter_Actions )
endfunction
globals
constant real TRAMPLE_LOOP_INTERVAL = 0.05
endglobals
function Trig_Trample_Loop_Trampled_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not IsUnitAliveBJ(filter)) then
return false
elseif (IsUnitAlly(filter, GetOwningPlayer(GetEnumUnit()))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Trample_Loop_Tramplers_Loop takes nothing returns nothing
local unit trampler = GetEnumUnit()
local location lastLoc = LoadLocationHandle(udg_HashTable_UnitInfo, GetHandleId(trampler), StringHash("TRAMPLE LAST LOCATION"))
local real aoe = 0.0
local group trampled = null
local unit pickedUnit = null
local real moveAngle = 0.0
local real maxPushDist = 0.0
local real dist = 0.0
local real x = 0.0
local real y = 0.0
if (IsUnitAliveBJ(trampler)) then
if (GetLocationX(lastLoc) != GetUnitX(trampler) or GetLocationY(lastLoc) != GetUnitY(trampler)) then
set trampled = CreateGroup()
set aoe = GetUnitAbilityRealLevelField(trampler, SB_TRAMPLE, ABILITY_RLF_AREA_OF_EFFECT) + BlzGetUnitCollisionSize(trampler)
set maxPushDist = GetUnitAbilityRealLevelField(trampler, SB_TRAMPLE, ABILITY_RLF_CAST_RANGE) * TRAMPLE_LOOP_INTERVAL
call GroupEnumUnitsInRange(trampled, GetUnitX(trampler), GetUnitY(trampler), aoe + udg_Real_MaxCollisionSize, Condition(function Trig_Trample_Loop_Trampled_Filter))
loop
set pickedUnit = FirstOfGroup(trampled)
exitwhen pickedUnit == null
set dist = DistanceBetweenUnits(trampler, pickedUnit)
if (dist < BlzGetUnitCollisionSize(pickedUnit) + aoe) then
set moveAngle = AngleBetweenUnits(trampler, pickedUnit)
set dist = RMinBJ(maxPushDist, BlzGetUnitCollisionSize(pickedUnit) + aoe - dist)
set x = PolarProjectionX(GetUnitX(pickedUnit), dist, moveAngle)
set y = PolarProjectionY(GetUnitY(pickedUnit), dist, moveAngle)
if (not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)) then
call SetUnitX(pickedUnit, x)
call SetUnitY(pickedUnit, y)
endif
endif
call GroupRemoveUnit(trampled, pickedUnit)
endloop
call DestroyGroup(trampled)
endif
call SaveLocationHandle(udg_HashTable_UnitInfo, GetHandleId(trampler), StringHash("TRAMPLE LAST LOCATION"), GetUnitLoc(trampler))
else
call GroupRemoveUnit(udg_UnitGroup_Trample, trampler)
call RemoveSavedHandle(udg_HashTable_UnitInfo, GetHandleId(trampler), StringHash("TRAMPLE LAST LOCATION"))
endif
call RemoveLocation(lastLoc)
endfunction
function Trig_Trample_Loop_Tramplers_Filter takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), SB_TRAMPLE)
endfunction
function Trig_Trample_Loop_Actions takes nothing returns nothing
local integer size = BlzGroupGetSize(udg_UnitGroup_Trample)
if (size > 0) then
call ForGroupBJ(udg_UnitGroup_Trample, function Trig_Trample_Loop_Tramplers_Loop)
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Trample_Loop takes nothing returns nothing
set gg_trg_Trample_Loop = CreateTrigger( )
//call DisableTrigger( gg_trg_Trample_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Trample_Loop, TRAMPLE_LOOP_INTERVAL )
call TriggerAddAction( gg_trg_Trample_Loop, function Trig_Trample_Loop_Actions )
endfunction
function Trig_Tail_Whip_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_TAIL_WHIP
endfunction
function Trig_Tail_Whip_TargetFilter takes SpellWave sw returns boolean
local unit caster = sw.owner
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (BlzGetUnitBooleanField(filter, UNIT_BF_IS_A_BUILDING)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (GetUnitMoveSpeed(filter) <= 0.0) then
return false
endif
return true
endfunction
function Trig_Tail_Whip_OnHit takes SpellWave sw, unit hit returns nothing
local real damage = GetUnitAbilityRealLevelField(sw.owner, SB_TAIL_WHIP, ABILITY_RLF_DAMAGE_UCS1)
local real slowDur = GetUnitAbilityRealLevelField(sw.owner, SB_TAIL_WHIP, ABILITY_RLF_DURATION_NORMAL)
local real distance = GetUnitAbilityRealLevelField(sw.owner, SB_TAIL_WHIP, ABILITY_RLF_DISTANCE_UCS3)
local real speed = I2R(GetUnitAbilityIntegerField(sw.owner, SB_TAIL_WHIP, ABILITY_IF_MISSILE_SPEED))
local real arc = GetUnitAbilityRealField(sw.owner, SB_TAIL_WHIP, ABILITY_RF_ARF_MISSILE_ARC)
local real angleBack = AngleBetweenPointsXY(sw.origin.x, sw.origin.y, GetUnitX(sw.owner), GetUnitY(sw.owner))
local real sourceX = PolarProjectionX(GetUnitX(sw.owner), 200.0, angleBack)
local real sourceY = PolarProjectionY(GetUnitY(sw.owner), 200.0, angleBack)
local real fanAngle = AngleBetweenPointsXY(sourceX, sourceY, GetUnitX(hit), GetUnitY(hit))
local real targetX = PolarProjectionX(GetUnitX(hit), distance, fanAngle)
local real targetY = PolarProjectionY(GetUnitY(hit), distance, fanAngle)
if (IsUnitType(hit, UNIT_TYPE_MECHANICAL)) then
call AddSpecialEffectTargetOneShot("war3mapImported\\Dust.mdl", hit, "chest")
else
call AddSpecialEffectTargetOneShot("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", hit, "chest")
endif
call UnitDamageTargetBJ(sw.owner, hit, damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL)
call UnitApplyFakeBuff(hit, SB_TAIL_WHIP_SLOW, SB_BUFF_TAIL_WHIP, slowDur)
call MoveUnitToPointAtSpeedAll(hit, targetX, targetY, speed, arc, SIM_MOVE_TYPE_SETXY, 0, 0)
endfunction
function Trig_Tail_Whip_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real aoe = GetUnitAbilityRealLevelField(caster, SB_TAIL_WHIP, ABILITY_RLF_AREA_OF_EFFECT)
local real sourceX = GetUnitX(caster)
local real sourceY = GetUnitY(caster)
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local real angle = AngleBetweenPointsXY(sourceX, sourceY, targetX, targetY)
local real x = PolarProjectionX(sourceX, 128.0, angle)
local real y = PolarProjectionY(sourceY, 128.0, angle)
local SpellWave wave = SpellWave.create(caster, x, y, 0.0)
set wave.targetFilter = Trig_Tail_Whip_TargetFilter
set wave.onHit = Trig_Tail_Whip_OnHit
set wave.aoeStart = aoe
set wave.aoeEnd = aoe
call wave.SetDirection(angle, 0)
call wave.Begin()
endfunction
//===========================================================================
function InitTrig_Tail_Whip takes nothing returns nothing
set gg_trg_Tail_Whip = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Tail_Whip, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Tail_Whip, Condition( function Trig_Tail_Whip_Conditions ) )
call TriggerAddAction( gg_trg_Tail_Whip, function Trig_Tail_Whip_Actions )
endfunction
globals
constant key KEY_SPIN_WEB
endglobals
struct SpinWeb
unit caster = null
effect specialEffect = null
method onDestroy takes nothing returns nothing
call BlzSetSpecialEffectAlpha(specialEffect, 0)
call DestroyEffect(specialEffect)
call RemoveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(caster), KEY_SPIN_WEB)
endmethod
endstruct
function CreateSpinWeb takes unit caster returns SpinWeb
local real morphDuration = GetUnitAbilityRealLevelField(caster, SB_SPIN_WEB, ABILITY_RLF_DURATION_NORMAL)
local string effectModel = GetUnitAbilityStringLevelField(caster, SB_SPIN_WEB, ABILITY_SLF_EFFECT)
local SpinWeb sw = SpinWeb.create()
set sw.caster = caster
set sw.specialEffect = AddSpecialEffect(effectModel, GetUnitX(caster), GetUnitY(caster))
call BlzSetSpecialEffectScale(sw.specialEffect, 2.0)
call BlzSetSpecialEffectAlpha(sw.specialEffect, 96)
call BlzSetSpecialEffectTimeScale(sw.specialEffect, DBZ(0.5, morphDuration, 1.0))
call BlzPlaySpecialEffect(sw.specialEffect, ANIM_TYPE_BIRTH)
call SaveInteger(udg_HashTable_UnitInfo, GetHandleId(caster), KEY_SPIN_WEB, sw)
return sw
endfunction
function GetSpunWeb takes unit whichUnit returns SpinWeb
return LoadInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_SPIN_WEB)
endfunction
function HasSpunWeb takes unit whichUnit returns boolean
return HaveSavedInteger(udg_HashTable_UnitInfo, GetHandleId(whichUnit), KEY_SPIN_WEB)
endfunction
function Trig_Spin_Web_Begin_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SPIN_WEB
endfunction
function Trig_Spin_Web_Begin_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local SpinWeb web = 0
call SetUnitAnimationByIndex(caster, 1)
if (GetUnitTypeId(caster) == SB_BLIGHT_WIDOW) then
set web = CreateSpinWeb(caster)
else
set web = GetSpunWeb(caster)
call BlzSetSpecialEffectTimeScale(web.specialEffect, DBZ(0.66, GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL), 1.0))
call BlzPlaySpecialEffect(web.specialEffect, ANIM_TYPE_DEATH)
endif
endfunction
//===========================================================================
function InitTrig_Spin_Web_Begin takes nothing returns nothing
set gg_trg_Spin_Web_Begin = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spin_Web_Begin, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Spin_Web_Begin, Condition( function Trig_Spin_Web_Begin_Conditions ) )
call TriggerAddAction( gg_trg_Spin_Web_Begin, function Trig_Spin_Web_Begin_Actions )
endfunction
function Trig_Spin_Web_Stop_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_SPIN_WEB
endfunction
function Trig_Spin_Web_Stop_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local SpinWeb web = GetSpunWeb(caster)
call ResetUnitAnimation(caster)
if (GetUnitTypeId(caster) == SB_BLIGHT_WIDOW) then
call BlzPlaySpecialEffect(web.specialEffect, ANIM_TYPE_DEATH)
call web.destroy()
else
call BlzPlaySpecialEffect(web.specialEffect, ANIM_TYPE_STAND)
endif
endfunction
//===========================================================================
function InitTrig_Spin_Web_Stop takes nothing returns nothing
set gg_trg_Spin_Web_Stop = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spin_Web_Stop, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition( gg_trg_Spin_Web_Stop, Condition( function Trig_Spin_Web_Stop_Conditions ) )
call TriggerAddAction( gg_trg_Spin_Web_Stop, function Trig_Spin_Web_Stop_Actions )
endfunction
function Trig_Spin_Web_Death_Conditions takes nothing returns boolean
return HasSpunWeb(GetDyingUnit())
endfunction
function Trig_Spin_Web_Death_Actions takes nothing returns nothing
local SpinWeb web = GetSpunWeb(GetDyingUnit())
local effect sfx = web.specialEffect
set web.specialEffect = null
call DestroyEffect(sfx)
call web.destroy()
endfunction
//===========================================================================
function InitTrig_Spin_Web_Death takes nothing returns nothing
set gg_trg_Spin_Web_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spin_Web_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Spin_Web_Death, Condition( function Trig_Spin_Web_Death_Conditions ) )
call TriggerAddAction( gg_trg_Spin_Web_Death, function Trig_Spin_Web_Death_Actions )
endfunction
scope ViperStrike initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_VIPER_STRIKE
private constant key KEY_VIPER_STRIKE_WAIT
endglobals
private function GetViperStrikeMinDist takes unit caster, unit target returns real
return BlzGetUnitCollisionSize(caster) + BlzGetUnitCollisionSize(target) + BlzGetUnitWeaponRealField(caster, UNIT_WEAPON_RF_ATTACK_RANGE, 0)
endfunction
private struct ViperStrike
unit caster = null
unit target = null
real speed = 0.0
real bufferTime = 0.0
boolean inBuffer = false
effect dashEffect = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call it.destroy()
call DestroyEffect(dashEffect)
call RemoveSavedInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE)
endmethod
endstruct
private function GetViperStrike takes unit caster returns ViperStrike
return LoadInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE)
endfunction
private function CreateViperStrike takes unit caster, unit target returns ViperStrike
local string dashArt = GetUnitAbilityStringLevelField(caster, SB_VIPER_STRIKE, ABILITY_SLF_SPECIAL)
local ViperStrike vs = GetViperStrike(caster)
if (vs != 0) then
call vs.destroy()
endif
set vs = ViperStrike.create()
set vs.caster = caster
set vs.target = target
set vs.speed = GetUnitAbilityIntegerField(caster, SB_VIPER_STRIKE, ABILITY_IF_MISSILE_SPEED)
set vs.bufferTime = BlzGetUnitWeaponRealField(caster, UNIT_WEAPON_RF_ATTACK_DAMAGE_POINT, 0)
set vs.dashEffect = AddSpecialEffectTarget(dashArt, caster, "origin")
set vs.it = CreateIntTimer(vs, false)
call SaveInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE, vs)
return vs
endfunction
private function ViperStrikeUpdate takes IntTimer it returns nothing
local ViperStrike vs = it.owner
local real minDist = GetViperStrikeMinDist(vs.caster, vs.target)
local real distSqr = SqrDistanceBetweenUnits(vs.caster, vs.target)
local real angle = AngleBetweenUnits(vs.caster, vs.target)
local real speed = vs.speed * TimerPlusGetElapsed(it)
local real x = 0.0
local real y = 0.0
if (not vs.inBuffer and distSqr + speed * speed > minDist * minDist) then
set x = PolarProjectionX(GetUnitX(vs.caster), speed, angle)
set y = PolarProjectionY(GetUnitY(vs.caster), speed, angle)
else
set x = PolarProjectionX(GetUnitX(vs.target), minDist, angle + 180.0)
set y = PolarProjectionY(GetUnitY(vs.target), minDist, angle + 180.0)
set vs.inBuffer = true
set vs.bufferTime = vs.bufferTime - TimerPlusGetElapsed(it)
endif
call SetUnitX(vs.caster, x)
call SetUnitY(vs.caster, y)
if (vs.bufferTime <= 0.0) then
call vs.destroy()
endif
endfunction
private struct ViperStrikeWait
unit caster = null
unit target = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call it.destroy()
call RemoveSavedInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE_WAIT)
endmethod
endstruct
private function GetViperStrikeWait takes unit caster returns ViperStrikeWait
return LoadInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE_WAIT)
endfunction
private function CreateViperStrikeWait takes unit caster, unit target returns ViperStrikeWait
local ViperStrikeWait vs = ViperStrikeWait.create()
set vs.caster = caster
set vs.target = target
set vs.it = CreateIntTimer(vs, false)
call SaveInteger(HT, GetHandleId(caster), KEY_VIPER_STRIKE_WAIT, vs)
return vs
endfunction
private function GetOrCreateViperStrikeWait takes unit caster, unit target returns ViperStrikeWait
local ViperStrikeWait vs = GetViperStrikeWait(caster)
if (vs == 0) then
set vs = CreateViperStrikeWait(caster, target)
endif
set vs.target = target
return vs
endfunction
private function ViperStrikeWaitUpdate takes IntTimer it returns nothing
local ViperStrikeWait vs = it.owner
local real rangeBuffer = 0.0
local real minDist = 0.0
if (UnitAlive(vs.caster) and UnitAlive(vs.target)) then
if (BlzGetUnitAbilityCooldownRemaining(vs.caster, SB_VIPER_STRIKE) <= 0.0) then
set rangeBuffer = GetUnitAbilityRealLevelField(vs.caster, SB_VIPER_STRIKE, ABILITY_RLF_AREA_OF_EFFECT)
set minDist = BlzGetUnitCollisionSize(vs.caster) + BlzGetUnitCollisionSize(vs.target) + rangeBuffer
if (SqrDistanceBetweenUnits(vs.caster, vs.target) > minDist * minDist) then
call IssueTargetOrder(vs.caster, "faeriefire", vs.target)
endif
endif
call StartTimerPlus(it, 0.5, ViperStrikeWaitUpdate)
else
call vs.destroy()
endif
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real minDist = GetViperStrikeMinDist(caster, target)
local ViperStrike vs = 0
if (SqrDistanceBetweenUnits(caster, target) > minDist * minDist) then
set vs = CreateViperStrike(caster, target)
call StartTimerPlusPeriodic(vs.it, 0.0, 0.01, ViperStrikeUpdate, 0)
endif
call BlzQueueTargetOrderById(caster, SB_ORDER_SMART, target)
endfunction
private function OrderConditions takes nothing returns boolean
local unit ordered = GetOrderedUnit()
local unit target = GetOrderTargetUnit()
local integer orderId = GetIssuedOrderId()
if (orderId == OrderId("faeriefire")) then
return false
elseif (not UnitHasAbility(ordered, SB_VIPER_STRIKE)) then
return false
endif
return true
endfunction
private function OrderActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local unit target = GetOrderTargetUnit()
local integer orderId = GetIssuedOrderId()
local ViperStrikeWait vs = 0
if (orderId == SB_ORDER_SMART and not IsUnitNonNeutralAlly(target, GetOwningPlayer(ordered)) and IsUnitType(target, UNIT_TYPE_FLYING)) then
set vs = GetOrCreateViperStrikeWait(ordered, target)
call StartTimerPlus(vs.it, 0.0, ViperStrikeWaitUpdate)
else
set vs = GetViperStrikeWait(ordered)
if (vs != 0) then
call vs.destroy()
endif
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition(function OrderConditions))
call TriggerAddAction(t, function OrderActions)
call CreateSpellEffectTrigger(SB_VIPER_STRIKE, function OnSpellEffect)
endfunction
endscope
globals
constant key KEY_FLICKER
endglobals
struct Flicker
unit flickerer = null
effect vfx = null
method onDestroy takes nothing returns nothing
call DestroyEffect(vfx)
endmethod
endstruct
function CreateFlicker takes unit caster returns Flicker
local string effectModel = GetUnitAbilityStringLevelField(caster, SB_FLICKER, ABILITY_SLF_TARGET)
local Flicker f = Flicker.create()
set f.flickerer = caster
set f.vfx = AddSpecialEffectTarget(effectModel, caster, "origin")
return f
endfunction
function Trig_Flicker_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_FLICKER
endfunction
function Trig_Flicker_Expires takes IntTimer it returns nothing
local Flicker flicker = it.owner
call UnitRemoveAbility(flicker.flickerer, SB_PERMANENT_INVISIBILITY_FLICKER)
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(flicker.flickerer), KEY_FLICKER)
call flicker.destroy()
endfunction
function Trig_Flicker_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, SB_FLICKER, ABILITY_RLF_AREA_OF_EFFECT)
local Flicker f = 0
local IntTimer it = LoadInteger(udg_HashTable_Timers, GetHandleId(caster), KEY_FLICKER)
call UnitAddAbility(caster, SB_PERMANENT_INVISIBILITY_FLICKER)
if (it == 0) then
set f = CreateFlicker(caster)
set it = CreateIntTimer(f, true)
call SaveInteger(udg_HashTable_Timers, GetHandleId(caster), KEY_FLICKER, it)
endif
call StartTimerPlus(it, duration, Trig_Flicker_Expires)
endfunction
//===========================================================================
function InitTrig_Flicker takes nothing returns nothing
set gg_trg_Flicker = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Flicker, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Flicker, Condition( function Trig_Flicker_Conditions ) )
call TriggerAddAction( gg_trg_Flicker, function Trig_Flicker_Actions )
endfunction
function Trig_Acid_Breath_Conditions takes nothing returns boolean
local unit damageSource = GetEventDamageSource()
local unit damageTarget = BlzGetEventDamageTarget()
if (not BlzGetEventIsAttack()) then
return false
elseif (not UnitHasAbility(damageSource, SB_ACID_BREATH)) then
return false
elseif (GetEventDamage() <= 0) then
return false
elseif (not UnitAlive(damageTarget)) then
return false
elseif (BlzGetEventAttackType() == ATTACK_TYPE_NORMAL) then
return false
elseif (IsUnitAlly(damageTarget, GetOwningPlayer(damageSource))) then
return false
elseif (IsUnitType(damageTarget, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(damageTarget)) then
return false
endif
return true
endfunction
function Trig_Acid_Breath_Actions takes nothing returns nothing
local unit damageSource = GetEventDamageSource()
local unit damageTarget = BlzGetEventDamageTarget()
local integer abilId = SB_ACID_BREATH_HIDDEN_CASTER_GROUND
if (IsUnitType(damageTarget, UNIT_TYPE_FLYING)) then
set abilId = SB_ACID_BREATH_HIDDEN_CASTER_AIR
endif
call DummyCastUnit(GetOwningPlayer(damageSource), damageTarget, GetUnitX(damageTarget), GetUnitY(damageTarget), abilId, "acidbomb")
endfunction
//===========================================================================
function InitTrig_Acid_Breath takes nothing returns nothing
local integer playerNum = 0
set gg_trg_Acid_Breath = CreateTrigger( )
call DisableTrigger( gg_trg_Acid_Breath )
loop
exitwhen playerNum >= GetBJMaxPlayers() + 4
call TriggerRegisterPlayerUnitEventSimple( gg_trg_Acid_Breath, Player(playerNum), EVENT_PLAYER_UNIT_DAMAGED)
set playerNum = playerNum + 1
endloop
call TriggerAddCondition( gg_trg_Acid_Breath, Condition( function Trig_Acid_Breath_Conditions ) )
call TriggerAddAction( gg_trg_Acid_Breath, function Trig_Acid_Breath_Actions )
call GateAbilityTrigger(gg_trg_Acid_Breath, SB_ACID_BREATH, SB_TECH_ACID_BREATH)
endfunction
scope AcidBreath initializer Init
globals
private constant real EFFECT_SCALING_FACTOR = 200.0
endglobals
private struct AcidBreath
real damage = 0.0
real aoeStart = 0.0
real aoeEnd = 0.0
string aoeArt = null
endstruct
private function CreateAcidBreath takes unit caster returns AcidBreath
local AcidBreath ab = AcidBreath.create()
set ab.damage = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_CS, ABILITY_RLF_DAMAGE_UCS1)
set ab.aoeStart = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_CS, ABILITY_RLF_AREA_OF_EFFECT)
set ab.aoeEnd = GetUnitAbilityRealLevelField(caster, SB_ACID_BREATH_CS, ABILITY_RLF_FINAL_AREA_UCS4)
set ab.aoeArt = GetUnitAbilityStringLevelField(caster, SB_ACID_BREATH_CS, ABILITY_SLF_AREA_EFFECT)
return ab
endfunction
private function MissileFilter takes WaveMissile missile, unit filter returns boolean
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitType(filter, UNIT_TYPE_GROUND)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
endif
return true
endfunction
private function OnMissileUpdate takes WaveMissile missile, real dt returns boolean
local AcidBreath ab = missile.data
local real aoe = (ab.aoeEnd - ab.aoeStart) * (missile.rangeRemaining / missile.range) + ab.aoeStart
local real effectScale = aoe / EFFECT_SCALING_FACTOR
call AddSpecialEffectOneShotEx(ab.aoeArt, GetLocationX(missile.actualPos), GetLocationY(missile.actualPos), 0.0, effectScale, 1.0)
return false
endfunction
private function OnMissileHit takes WaveMissile missile, unit hit returns nothing
local AcidBreath ac = missile.data
call UnitDamageTarget(missile.owner, hit, ac.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_ACID, WEAPON_TYPE_WHOKNOWS)
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local real missileSpeed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local real range = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DISTANCE_UCS3)
local real interval = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local real yaw = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), targetX, targetY) * bj_DEGTORAD
local AcidBreath ab = CreateAcidBreath(caster)
local WaveMissile missile = CreateWaveMissileInterval(null, caster, GetUnitX(caster), GetUnitY(caster), BlzGetUnitZ(caster), interval)
set missile.data = ab
set missile.multiHit = true
set missile.userUpdateCallback = OnMissileUpdate
set missile.userUpdateInterval = interval
call FireWaveMissile(missile, missileSpeed, range, yaw, 0.0, ab.aoeStart, ab.aoeEnd, MissileFilter, OnMissileHit)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_ACID_BREATH_CS, function OnSpellEffect)
endfunction
endscope
function Trig_Couatl_Ground_Attack_Conditions takes nothing returns boolean
if (GetUnitAbilityLevel(GetOrderedUnit(), SB_TOGGLE_GROUND_ATTACK) > 0) then
return GetIssuedOrderIdBJ() == String2OrderIdBJ("defend") or GetIssuedOrderIdBJ() == String2OrderIdBJ("undefend")
endif
return false
endfunction
function Trig_Couatl_Ground_Attack_Actions takes nothing returns nothing
if (GetIssuedOrderIdBJ() == String2OrderIdBJ("defend")) then
call BlzSetUnitWeaponBooleanField(GetOrderedUnit(), UNIT_WEAPON_BF_ATTACKS_ENABLED, 1, false)
else
call BlzSetUnitWeaponBooleanField(GetOrderedUnit(), UNIT_WEAPON_BF_ATTACKS_ENABLED, 1, true)
endif
endfunction
//===========================================================================
function InitTrig_Couatl_Ground_Attack takes nothing returns nothing
set gg_trg_Couatl_Ground_Attack = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Couatl_Ground_Attack, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition(gg_trg_Couatl_Ground_Attack, Condition(function Trig_Couatl_Ground_Attack_Conditions))
call TriggerAddAction( gg_trg_Couatl_Ground_Attack, function Trig_Couatl_Ground_Attack_Actions )
endfunction
scope LeechSeed initializer Init
struct LeechSeed
unit caster = null
unit target = null
real aoe = 0.0
real damage = 0.0
real damageInterval = 0.0
real missileSpeed = 0.0
real remaining = 0.0
real lastX = 0.0
real lastY = 0.0
string missileArt = null
string deathEffectArt = null
string buffEffectArt = null
effect buffEffect = null
integer spawnedUnitTypeId = 0
integer spawnedUnitCount = 0
integer updateCallback = 0
IntTimer it = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(buffEffect)
call it.destroy()
set caster = null
set target = null
set buffEffect = null
endmethod
endstruct
private function CreateLeechSeed takes unit caster, unit target returns LeechSeed
local LeechSeed ls = LeechSeed.create()
set ls.caster = caster
set ls.target = target
set ls.aoe = GetUnitAbilityRealLevelField(caster, SB_LEECH_SEED, ABILITY_RLF_AREA_OF_EFFECT)
set ls.damage = 5.0
set ls.damageInterval = 1.0
set ls.missileSpeed = GetUnitAbilityIntegerField(caster, SB_LEECH_SEED, ABILITY_IF_MISSILE_SPEED)
set ls.remaining = GetUnitAbilityRealLevelField(caster, SB_LEECH_SEED, ABILITY_RLF_DURATION_NORMAL)
set ls.lastX = GetUnitX(target)
set ls.lastY = GetUnitY(target)
set ls.spawnedUnitTypeId = SB_SAPLING_WARRIOR_MODE
set ls.spawnedUnitCount = 1
set ls.missileArt = GetUnitAbilityStringLevelField(caster, SB_LEECH_SEED, ABILITY_SLF_MISSILE_ART)
set ls.deathEffectArt = GetUnitAbilityStringLevelField(caster, SB_LEECH_SEED, ABILITY_SLF_SPECIAL)
set ls.buffEffectArt = "war3mapImported\\LeechSeedTarget.mdx"
set ls.it = CreateIntTimer(ls, false)
return ls
endfunction
private function LeechSeedBounceFilter takes LeechSeed ls returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitEnemy(filter, GetOwningPlayer(ls.caster))) then
return false
elseif (UnitHasBuffBJ(filter, SB_BUFF_LEECH_SEED)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MECHANICAL)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
private function OnMissileHit takes TargetMissile missile, real x, real y returns nothing
local LeechSeed ls = missile.data
if (UnitHasBuffBJ(ls.target, SB_BUFF_LEECH_SEED)) then
set ls.buffEffect = AddSpecialEffectTarget(ls.buffEffectArt, missile.target, "chest")
call StartTimerPlusPeriodic(ls.it, 0.0, ls.damageInterval, ls.updateCallback, 0)
else
call ls.destroy()
endif
endfunction
private function BounceLeechSeed takes LeechSeed ls returns nothing
local unit dying = ls.target
local integer summonedUnitCount = ls.spawnedUnitCount
local unit summoned = null
local group nearbyEnemies = null
local unit picked = null
local unit dummy = null
local TargetMissile missile = 0
local real x = GetUnitX(dying)
local real y = GetUnitY(dying)
if (GetUnitTypeId(dying) == 0) then
set x = ls.lastX
set y = ls.lastY
set nearbyEnemies = GetUnitsInAOEInt(x, y, ls.aoe, LeechSeedBounceFilter, ls)
else
set nearbyEnemies = GetUnitsInAOEOfUnitInt(dying, ls.aoe, LeechSeedBounceFilter, ls)
endif
call AddSpecialEffectOneShot(ls.deathEffectArt, x, y)
if (summonedUnitCount > 0) then
call PlaySoundAtPositionSB("Units\\Creeps\\CorruptedEnt\\EntReady1.flac", "SpellsEAX", 11, x, y, 100.0)
endif
loop
exitwhen summonedUnitCount <= 0
set summoned = SpawnSapling(GetOwningPlayer(ls.caster), 45.0, x, y, bj_UNIT_FACING, false)
set summonedUnitCount = summonedUnitCount - 1
endloop
call DestroyEffect(ls.buffEffect)
set picked = GroupPickRandomUnit(nearbyEnemies)
if (picked != null and ls.remaining > 0.0) then
set ls.target = picked
set missile = CreateTargetMissile(ls.missileArt, ls.caster, x, y, 85.0)
set missile.data = ls
call FireTargetMissile(missile, picked, ls.missileSpeed, 0.0, 60.0, true, OnMissileHit)
set dummy = CreateDummyCaster(GetOwningPlayer(ls.target), GetUnitX(ls.target), GetUnitY(ls.target), SB_LEECH_SEED_HIDDEN_CASTER, 1.0)
call SetUnitAbilityRealLevelField(dummy, SB_LEECH_SEED_HIDDEN_CASTER, ABILITY_RLF_DURATION_NORMAL, ls.remaining)
call IssueTargetOrder(dummy, "slow", ls.target)
else
call ls.destroy()
endif
endfunction
private function UpdateLeechSeed takes IntTimer it returns nothing
local LeechSeed ls = it.owner
if (not UnitAlive(ls.target)) then
call PauseTimerPlus(ls.it)
call BounceLeechSeed(ls)
elseif (UnitHasBuffBJ(ls.target, SB_BUFF_LEECH_SEED)) then
set ls.remaining = ls.remaining - TimerPlusGetElapsed(it)
set ls.lastX = GetUnitX(ls.target)
set ls.lastY = GetUnitY(ls.target)
call UnitDamageTarget(ls.caster, ls.target, ls.damage, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_PLANT, WEAPON_TYPE_WHOKNOWS)
else
call ls.destroy()
endif
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local LeechSeed ls = CreateLeechSeed(caster, target)
local TargetMissile missile = CreateTargetMissile(ls.missileArt, caster, GetUnitX(caster), GetUnitY(caster), 85.0)
set missile.data = ls
set ls.updateCallback = UpdateLeechSeed
call FireTargetMissile(missile, target, ls.missileSpeed, 0.0, 60.0, true, OnMissileHit)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateSpellEffectTrigger(SB_LEECH_SEED, function OnSpellEffect)
endfunction
endscope
scope WildGrowth initializer Init
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real rads = Atan2(y - GetUnitY(caster), x - GetUnitX(caster)) + bj_PI * 0.5
local real dist = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT) * 2.0
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local integer count = R2I(GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_HERO))
local integer index = 0
local real thisX = 0.0
local real thisY = 0.0
local real thisDist = 0.0
local real distInterval = 0.0
local unit tree = null
if (count > 0) then
set distInterval = dist / count
loop
exitwhen index >= count
set thisDist = -(dist * 0.5) + distInterval * index + distInterval * 0.5
set thisX = x + thisDist * Cos(rads)
set thisY = y + thisDist * Sin(rads)
set tree = CreateUnit(GetOwningPlayer(caster), SB_WILD_GROWTH_UNIT, thisX, thisY, GetRandomDirectionDeg())
call SetUnitPathing(tree, false)
call SetUnitPosition(tree, thisX, thisY)
call SetUnitPathing(tree, true)
call UnitApplyTimedLife(tree, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call ChangeUnitSize(tree, -1.0)
call ChangeUnitSizeOverTime(tree, 0.25, 1.0)
set index = index + 1
endloop
endif
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_WILD_GROWTH, function OnSpellEffect)
endfunction
endscope
function Trig_Elder_Treeherds_Sapling_HP_Loop takes nothing returns nothing
local player p = GetEnumPlayer()
local integer techLevel = GetPlayerTechCount(p, SB_TECH_ELDER_TREEHERDS, false)
if (techLevel > 0) then
call SetPlayerTechResearched(p, SB_TECH_ELDER_TREEHERDS_HIDDEN, techLevel)
endif
endfunction
function Trig_Elder_Treeherds_Sapling_HP_Init_Actions takes nothing returns nothing
call ForForce(GetPlayersAll(), function Trig_Elder_Treeherds_Sapling_HP_Loop)
endfunction
//===========================================================================
function InitTrig_Elder_Treeherds_Sapling_HP_Init takes nothing returns nothing
set gg_trg_Elder_Treeherds_Sapling_HP_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Elder_Treeherds_Sapling_HP_Init, function Trig_Elder_Treeherds_Sapling_HP_Init_Actions )
endfunction
function Trig_Elder_Treeherds_Sapling_HP_Conditions takes nothing returns boolean
return GetResearched() == SB_TECH_ELDER_TREEHERDS
endfunction
function Trig_Elder_Treeherds_Sapling_HP_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
local integer techLevel = GetPlayerTechCount(p, GetResearched(), false)
call SetPlayerTechResearched(p, SB_TECH_ELDER_TREEHERDS_HIDDEN, techLevel)
endfunction
//===========================================================================
function InitTrig_Elder_Treeherds_Sapling_HP takes nothing returns nothing
set gg_trg_Elder_Treeherds_Sapling_HP = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Elder_Treeherds_Sapling_HP, EVENT_PLAYER_UNIT_RESEARCH_FINISH )
call TriggerAddCondition( gg_trg_Elder_Treeherds_Sapling_HP, Condition( function Trig_Elder_Treeherds_Sapling_HP_Conditions ) )
call TriggerAddAction( gg_trg_Elder_Treeherds_Sapling_HP, function Trig_Elder_Treeherds_Sapling_HP_Actions )
endfunction
function Trig_Taskmaster_Conditions takes nothing returns boolean
local integer order = GetIssuedOrderId()
if (GetUnitTypeId(GetOrderedUnit()) != SB_SLAVE) then
return false
elseif ((IsOrder(order, "smart") or IsOrder(order, "harvest")) and UnitHasAbility(GetOrderTargetUnit(), SB_GOLD_MINE_ABILITY)) then
return true
// elseif (IsOrder(order, "resumeharvesting") or IsOrder(order, "autoharvestlumber")) then
// return true
endif
return false
endfunction
function Trig_Taskmaster_Actions takes nothing returns nothing
local unit slave = GetOrderedUnit()
local boolean reorder = false
if (UnitHasAbility(slave, SB_HARVEST_CHAOS_WEAK) and UnitHasBuffBJ(slave, SB_BUFF_TASKMASTER)) then
call UnitRemoveAbility(slave, SB_HARVEST_CHAOS_WEAK)
call UnitAddAbility(slave, SB_HARVEST_CHAOS_NORMAL)
set reorder = true
elseif (UnitHasAbility(slave, SB_HARVEST_CHAOS_NORMAL) and not UnitHasBuffBJ(slave, SB_BUFF_TASKMASTER)) then
call UnitRemoveAbility(slave, SB_HARVEST_CHAOS_NORMAL)
call UnitAddAbility(slave, SB_HARVEST_CHAOS_WEAK)
set reorder = true
endif
if (reorder) then
if (GetOrderTargetUnit() != null) then
call IssueTargetOrder(slave, OrderId2String(GetIssuedOrderId()), GetOrderTarget())
else
call IssueImmediateOrder(slave, OrderId2String(GetIssuedOrderId()))
endif
endif
endfunction
//===========================================================================
function InitTrig_Taskmaster takes nothing returns nothing
set gg_trg_Taskmaster = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_Taskmaster, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
//call TriggerRegisterAnyUnitEventBJ(gg_trg_Taskmaster, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(gg_trg_Taskmaster, Condition(function Trig_Taskmaster_Conditions))
call TriggerAddAction( gg_trg_Taskmaster, function Trig_Taskmaster_Actions )
endfunction
function Trig_Lash_of_the_Whip_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_LASH_OF_THE_WHIP
endfunction
function Trig_Lash_of_the_Whip_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
call DummyCastUnit(GetOwningPlayer(caster), target, GetUnitX(caster), GetUnitY(caster), SB_LASH_OF_THE_WHIP_HIDDEN_CASTER, "fingerofdeath")
call PlaySoundAtPositionSB("Units\\Orc\\Peon\\PeonYes3.flac", "SpellsEAX", 11, GetUnitX(target), GetUnitY(target), 100.0)
call UnitDamageTargetBJ(caster, target, 15.0, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL)
endfunction
//===========================================================================
function InitTrig_Lash_of_the_Whip takes nothing returns nothing
set gg_trg_Lash_of_the_Whip = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Lash_of_the_Whip, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Lash_of_the_Whip, Condition( function Trig_Lash_of_the_Whip_Conditions ) )
call TriggerAddAction( gg_trg_Lash_of_the_Whip, function Trig_Lash_of_the_Whip_Actions )
endfunction
globals
constant real BURNING_BLOOD_EXPLOSION_RADIUS = 150.0
constant real BURNING_BLOOD_EXPLOSION_DAMAGE = 50.0
endglobals
function Trig_Burning_Blood_Death_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == SB_BURNING_BLOOD_EXPLOSION
endfunction
function Trig_Burning_Blood_Death_Explosion_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
local boolean isFlier = IsUnitType(GetDyingUnit(), UNIT_TYPE_FLYING)
if (isFlier != IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Burning_Blood_Death_Actions takes nothing returns nothing
local unit explosion = GetDyingUnit()
local group explosionVictims = CreateGroup()
local unit pickedUnit = null
call GroupEnumUnitsInRange(explosionVictims, GetUnitX(explosion), GetUnitY(explosion), 150.0, Condition(function Trig_Burning_Blood_Death_Explosion_Filter))
loop
set pickedUnit = FirstOfGroup(explosionVictims)
exitwhen pickedUnit == null
call UnitDamageTargetBJ(explosion, pickedUnit, BURNING_BLOOD_EXPLOSION_DAMAGE, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE)
call GroupRemoveUnit(explosionVictims, pickedUnit)
endloop
call DestroyGroup(explosionVictims)
endfunction
//===========================================================================
function InitTrig_Burning_Blood_Death takes nothing returns nothing
set gg_trg_Burning_Blood_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Burning_Blood_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Burning_Blood_Death, Condition( function Trig_Burning_Blood_Death_Conditions ) )
call TriggerAddAction( gg_trg_Burning_Blood_Death, function Trig_Burning_Blood_Death_Actions )
endfunction
globals
constant integer WALL_OF_FLAME_LENGTH = 5
constant real WALL_OF_FLAME_ENTITY_DISTANCE = 150.0
endglobals
function Trig_Wall_of_Fire_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_WALL_OF_FIRE
endfunction
function Trig_Wall_of_Fire_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local player p = GetOwningPlayer(caster)
local real duration = GetUnitAbilityRealLevelField(caster, SB_WALL_OF_FIRE, ABILITY_RLF_DURATION_NORMAL)
local location casterLoc = GetUnitLoc(caster)
local location targetLoc = GetSpellTargetLoc()
local real angle = AngleBetweenPoints(casterLoc, targetLoc) + 90.0
local location startLoc = PolarProjectionBJ(targetLoc, WALL_OF_FLAME_ENTITY_DISTANCE * WALL_OF_FLAME_LENGTH * 0.5, angle)
local location nextLoc = null
local unit flame = null
local integer i = 0
loop
exitwhen i >= WALL_OF_FLAME_LENGTH
set nextLoc = PolarProjectionBJ(startLoc, WALL_OF_FLAME_ENTITY_DISTANCE * i, angle + 180)
set flame = CreateUnitAtLoc(p, SB_SPECIAL_EFFECT_UNIT_WALL_OF_FIRE, nextLoc, bj_UNIT_FACING)
call UnitApplyTimedLife(flame, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call RemoveLocation(nextLoc)
set i = i + 1
endloop
call RemoveLocation(casterLoc)
call RemoveLocation(targetLoc)
call RemoveLocation(startLoc)
endfunction
//===========================================================================
function InitTrig_Wall_of_Fire_Cast takes nothing returns nothing
set gg_trg_Wall_of_Fire_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wall_of_Fire_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Wall_of_Fire_Cast, Condition( function Trig_Wall_of_Fire_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Wall_of_Fire_Cast, function Trig_Wall_of_Fire_Cast_Actions )
endfunction
scope ArcanePulse initializer Init
private struct ArcanePulse
unit caster = null
unit whichUnit = null
real damage = 0.0
real aoe = 0.0
string explosionArt = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
set whichUnit = null
set caster = null
call it.destroy()
endmethod
endstruct
private function OnUpdate takes IntTimer it returns nothing
local ArcanePulse ph = it.owner
local real effectHeight = BlzGetUnitZ(ph.whichUnit)
local integer abilityId = SB_ARCANE_PULSE_EXPLOSION_GROUND
local unit dummy = null
if (not UnitAlive(ph.whichUnit) or not UnitHasBuffBJ(ph.whichUnit, SB_BUFF_ARCANE_PULSE)) then
if (IsUnitType(ph.whichUnit, UNIT_TYPE_FLYING)) then
set effectHeight = effectHeight + GetUnitFlyHeight(ph.whichUnit)
set abilityId = SB_ARCANE_PULSE_EXPLOSION_AIR
endif
call AddSpecialEffectOneShotWithZ(ph.explosionArt, GetUnitX(ph.whichUnit), GetUnitY(ph.whichUnit), effectHeight)
set dummy = CreateDummyCaster(GetOwningPlayer(ph.caster), GetUnitX(ph.whichUnit), GetUnitY(ph.whichUnit), abilityId, 1.0)
call SetUnitAbilityRealLevelField(dummy, abilityId, ABILITY_RLF_AREA_OF_EFFECT, ph.aoe)
call SetUnitAbilityRealLevelField(dummy, abilityId, ABILITY_RLF_DAMAGE_WRS1, ph.damage)
call IssueImmediateOrder(dummy, "stomp")
call ph.destroy()
endif
endfunction
private function CreateArcanePulse takes unit caster, unit target returns ArcanePulse
local real duration = GetUnitAbilityRealLevelField(caster, SB_ARCANE_PULSE, ABILITY_RLF_DURATION_NORMAL)
local ArcanePulse ph = ArcanePulse.create()
local unit dummy = CreateDummyCaster(GetOwningPlayer(target), GetUnitX(target), GetUnitY(target), SB_ARCANE_PULSE_BUFF, 1.0)
set ph.caster = caster
set ph.whichUnit = target
set ph.aoe = GetUnitAbilityRealLevelField(caster, SB_ARCANE_PULSE, ABILITY_RLF_AREA_OF_EFFECT)
set ph.damage = GetUnitAbilityRealLevelField(caster, SB_ARCANE_PULSE, ABILITY_RLF_DURATION_HERO)
set ph.explosionArt = GetUnitAbilityStringLevelField(caster, SB_ARCANE_PULSE, ABILITY_SLF_SPECIAL)
set ph.it = CreateIntTimer(ph, false)
call SetUnitAbilityRealLevelField(dummy, SB_ARCANE_PULSE_BUFF, ABILITY_RLF_DURATION_NORMAL, duration)
call SetUnitAbilityRealLevelField(dummy, SB_ARCANE_PULSE_BUFF, ABILITY_RLF_DURATION_HERO, duration)
call IssueTargetOrder(dummy, "bloodlust", target)
call StartTimerPlusPeriodic(ph.it, 0.0, 0.1, OnUpdate, 0)
return ph
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
call CreateArcanePulse(caster, target)
if (GetOwningPlayer(caster) == GetOwningPlayer(target)) then
call ClearSelectionForPlayer(GetOwningPlayer(caster))
call SelectUnitAddForPlayer(target, GetOwningPlayer(caster))
endif
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_ARCANE_PULSE, function OnSpellEffect)
endfunction
endscope
scope MindVision initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant string SOUND_EFFECT = "Abilities\\Spells\\Orc\\EtherealForm\\SpiritWalkerMorph.flac"
endglobals
private struct MindVision
player owner = null
group affected = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call DestroyGroup(affected)
call it.destroy()
endmethod
endstruct
private function TargetFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitNonNeutralAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
return true
endfunction
private function MindVisionUpdate takes IntTimer it returns nothing
local MindVision mv = it.owner
local integer numUnits = BlzGroupGetSize(mv.affected)
local integer unitsRemaining = 0
local unit picked = null
loop
set numUnits = numUnits - 1
exitwhen numUnits < 0
set picked = BlzGroupUnitAt(mv.affected, numUnits)
if (UnitAlive(picked) and GetUnitAbilityLevel(picked, SB_BUFF_MIND_VISION) > 0) then
set unitsRemaining = unitsRemaining + 1
call UnitShareVision(picked, mv.owner, true)
else
call UnitShareVision(picked, mv.owner, false)
call GroupRemoveUnit(mv.affected, picked)
endif
endloop
if (unitsRemaining <= 0) then
call mv.destroy()
endif
endfunction
private function OnDummySpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local player p = GetOwningPlayer(caster)
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)
local group affected = GetUnitsInAOEOfUnitUnit(caster, aoe, TargetFilter, caster)
local integer size = BlzGroupGetSize(affected)
local MindVision mv = 0
if (size > 0) then
set mv = mv.create()
set mv.owner = p
set mv.affected = affected
set mv.it = CreateIntTimer(mv, false)
call StartTimerPlusPeriodic(mv.it, 0.0, 0.01, MindVisionUpdate, 0)
endif
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real dummyDuration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DURATION_NORMAL)
local real dummyVision = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local player p = GetOwningPlayer(caster)
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real scale = DBZ(dummyVision, 128.0, 1.0)
local unit dummy = CreateUnit(p, SB_MIND_VISION_DUMMY, x, y, bj_UNIT_FACING)
local fogmodifier fm = CreateFogModifierRadius(p, FOG_OF_WAR_VISIBLE, x, y, dummyVision, true, false)
call FogModifierStart(fm)
call SetUnitPathing(dummy, false)
call SetUnitPosition(dummy, x, y)
call SetUnitScale(dummy, scale, scale, scale)
call UnitApplyTimedLife(dummy, SB_BUFF_TIMED_LIFE_GENERIC, dummyDuration)
call IssueImmediateOrderById(dummy, SB_ORDER_MIND_VISION_AOE)
call SaveFogModifierHandle(HT, GetHandleId(dummy), 0, fm)
call SetUnitAnimation(dummy, "birth")
call PlayPitchedSoundAtPositionSB(SOUND_EFFECT, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 100.0, 0.8)
endfunction
private function IsDummy takes nothing returns boolean
return HaveSavedHandle(HT, GetHandleId(GetTriggerUnit()), 0)
endfunction
private function OnDummyDies takes nothing returns nothing
local unit dummy = GetDyingUnit()
local fogmodifier fm = LoadFogModifierHandle(HT, GetHandleId(dummy), 0)
call FogModifierStop(fm)
call DestroyFogModifier(fm)
call RemoveSavedHandle(HT, GetHandleId(dummy), 0)
endfunction
private function Init takes nothing returns nothing
call CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_DEATH, function IsDummy, function OnDummyDies)
call CreateSpellEffectTrigger(SB_MIND_VISION, function OnSpellEffect)
call CreateSpellEffectTrigger(SB_MIND_VISION_DUMMY_CAST, function OnDummySpellEffect)
endfunction
endscope
scope TitanicInvocation initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant string BIRTH_SOUND = "Units\\Undead\\HeroCryptLord\\NerubianCryptLordReady1.flac"
endglobals
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local string birthEffect = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_AREA_EFFECT)
local unit target = GetSpellTargetUnit()
local player p = GetOwningPlayer(target)
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local real facing = GetUnitFacing(target)
local unit titan = null
call ExileUnit(target, true)
set titan = CreateUnit(p, SB_FROST_TITAN, x, y, facing)
call SaveUnitHandle(HT, GetHandleId(titan), 0, target)
call UnitApplyTimedLife(titan, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call AddSpecialEffectOneShot(birthEffect, x, y)
call PlayPitchedSoundAtPositionSB(BIRTH_SOUND, "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 100.0, 0.9)
endfunction
private function IsTitan takes nothing returns boolean
return HaveSavedHandle(HT, GetHandleId(GetTriggerUnit()), 0)
endfunction
private function OnTitanDies takes nothing returns nothing
local unit titan = GetDyingUnit()
local unit host = LoadUnitHandle(HT, GetHandleId(titan), 0)
call SetUnitX(host, GetUnitX(titan))
call SetUnitY(host, GetUnitY(titan))
call ExileUnit(host, false)
call RemoveSavedHandle(HT, GetHandleId(titan), 0)
endfunction
private function Init takes nothing returns nothing
call CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_DEATH, function IsTitan, function OnTitanDies)
call CreateSpellEffectTrigger(SB_TITANIC_INVOCATION, function OnSpellEffect)
endfunction
endscope
scope Blizzard initializer Init
globals
private constant key KEY_BLIZZARD
private trigger BLIZZARD_LOOP = null
private constant real BLIZZARD_AOE = 800.0
private constant real BLIZZARD_SCALING_FACTOR = 200.0
private constant real BLIZZARD_UPDATE_INTERVAL = 0.5
endglobals
struct Blizzard
unit target = null
effect vfx = null
method onDestroy takes nothing returns nothing
call DestroyEffect(vfx)
call TriggeredAura_RemoveEmitter(target, BLIZZARD_LOOP)
endmethod
endstruct
function CreateBlizzard takes unit caster, unit target returns Blizzard
local string areaArt = GetUnitAbilityStringLevelField(caster, SB_BLIZZARD, ABILITY_SLF_AREA_EFFECT)
local real targetX = GetUnitX(target)
local real targetY = GetUnitY(target)
local real rectSize = BLIZZARD_AOE * 0.75
local Blizzard blizzard = Blizzard.create()
set blizzard.target = target
set blizzard.vfx = AddSpecialEffect(areaArt, GetUnitX(target), GetUnitY(target))
call BlzSetSpecialEffectScale(blizzard.vfx, BLIZZARD_AOE / BLIZZARD_SCALING_FACTOR)
call TriggeredAura_AddEmitter(target, BLIZZARD_LOOP)
return blizzard
endfunction
function IsBlizzardCasterValid takes unit emitter returns boolean
return UnitAlive(emitter)
endfunction
function BlizzardUpdate takes IntTimer it returns nothing
local Blizzard blizzard = it.owner
if (not UnitAlive(blizzard.target)) then
call blizzard.destroy()
call it.destroy()
endif
endfunction
function BlizzardConcludes takes IntTimer it returns nothing
local Blizzard blizzard = it.owner
call blizzard.destroy()
endfunction
function BlizzardActions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local Blizzard blizzard = CreateBlizzard(caster, target)
local IntTimer it = CreateIntTimer(blizzard, true)
local real duration = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_ARMOR_DURATION)
call StartTimerPlusPeriodic(it, duration, BLIZZARD_UPDATE_INTERVAL, BlizzardUpdate, BlizzardConcludes)
endfunction
function BlizzardTargetFilter takes nothing returns boolean
local unit target = GetFilterUnit()
if (not IsUnitAliveBJ(target)) then
return false
elseif (IsUnitAlly(target, GetOwningPlayer(TriggeredAura_GetEmitter()))) then
return false
elseif (IsUnitType(target, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(target)) then
return false
endif
return true
endfunction
function BlizzardApplyEffect takes unit whichUnit returns nothing
if (not UnitHasAbility(whichUnit, SB_BLIZZARD_SLOW_ABILITY)) then
call UnitAddAbility(whichUnit, SB_BLIZZARD_SLOW_ABILITY)
call ChangeUnitColorOverTime(whichUnit, 0.5, 0.0, 190, 190, 255, 255)
endif
endfunction
function BlizzardRemoveEffect takes unit whichUnit returns nothing
call UnitRemoveAbility(whichUnit, SB_BLIZZARD_SLOW_ABILITY)
call RestoreUnitColorOverTime(whichUnit, 0.5, 0.0)
endfunction
private function Init takes nothing returns nothing
local TriggeredAuraParams params = TriggeredAuraParams.create()
set params.AuraKey = KEY_BLIZZARD
set params.UpdateInterval = BLIZZARD_UPDATE_INTERVAL
set params.AreaOfEffect = BLIZZARD_AOE
set params.ApplyAuraEffect = BlizzardApplyEffect
set params.RemoveAuraEffect = BlizzardRemoveEffect
set params.TargetFilter = BlizzardTargetFilter
set params.IsEmitterValid = IsBlizzardCasterValid
set BLIZZARD_LOOP = TriggeredAura_Create(params)
call CreateSpellEffectTrigger(SB_BLIZZARD, function BlizzardActions)
endfunction
endscope
globals
constant hashtable HT_TIME_WARP = InitHashtable()
constant integer TIME_WARP_DATA_POINTS = 5
constant key KEY_TIME_WARP
endglobals
struct TimeWarpSnapshot extends ILinkedListNode
real posX = 0.0
real posY = 0.0
real facing = 0.0
real life = 0.0
real mana = 0.0
integer orderId = 0
real orderTargetX = 0.0
real orderTargetY = 0.0
widget orderTargetObject = null
endstruct
function CreateTimeWarpSnapshot takes unit whichUnit returns TimeWarpSnapshot
local TimeWarpSnapshot snapshot = TimeWarpSnapshot.create()
set snapshot.posX = GetUnitX(whichUnit)
set snapshot.posY = GetUnitY(whichUnit)
set snapshot.facing = GetUnitFacing(whichUnit)
set snapshot.life = GetUnitState(whichUnit, UNIT_STATE_LIFE)
set snapshot.mana = GetUnitState(whichUnit, UNIT_STATE_MANA)
return snapshot
endfunction
function GetTimeWarpData takes unit whichUnit returns LinkedList_Int
return LoadInteger(HT_TIME_WARP, GetHandleId(whichUnit), KEY_TIME_WARP)
endfunction
function GetOrCreateTimeWarpData takes unit whichUnit returns LinkedList_Int
local LinkedList_Int list = GetTimeWarpData(whichUnit)
if (list == 0) then
set list = CreateLinkedList_Int()
call SaveInteger(HT_TIME_WARP, GetHandleId(whichUnit), KEY_TIME_WARP, list)
endif
return list
endfunction
function DeleteTimeWarpData takes unit whichUnit returns nothing
call RemoveSavedHandle(HT_TIME_WARP, GetHandleId(whichUnit), KEY_TIME_WARP)
endfunction
function TimeWarpTakeSnapshot takes unit whichUnit returns nothing
local LinkedList_Int list = GetOrCreateTimeWarpData(whichUnit)
local TimeWarpSnapshot ss = CreateTimeWarpSnapshot(whichUnit)
call LinkedListAddLast(list, ss)
loop
exitwhen list.count <= TIME_WARP_DATA_POINTS
call LinkedListDestroyFirst(list)
endloop
endfunction
function TimeWarpShowUnitAndIssueOrder takes IntTimer it returns nothing
local SavedOrder savedOrder = it.owner
call ExileUnit(savedOrder.whichUnit, false)
call SetUnitUseFood(savedOrder.whichUnit, true)
call IssueSavedOrder(savedOrder.whichUnit, savedOrder)
call savedOrder.destroy()
call RemoveSavedInteger(udg_HashTable_Timers, GetHandleId(savedOrder.whichUnit), KEY_EXILE)
endfunction
function TimeWarpShowUnitDelayed takes unit whichUnit, TimeWarpSnapshot snapshot, real delay returns nothing
local IntTimer it = LoadInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_EXILE)
local SavedOrder savedOrder = CreateSavedOrder(snapshot.orderId, snapshot.orderTargetObject, snapshot.orderTargetX, snapshot.orderTargetY)
local SavedOrder prev = 0
set savedOrder.whichUnit = whichUnit
if (it == 0) then
set it = CreateIntTimer(savedOrder, true)
call SaveInteger(udg_HashTable_Timers, GetHandleId(whichUnit), KEY_EXILE, it)
else
set prev = it.owner
set it.owner = savedOrder
call prev.destroy()
endif
call StartIntTimer(it, delay, TimeWarpShowUnitAndIssueOrder)
endfunction
function ApplyTimeWarp takes unit whichUnit returns nothing
local LinkedList_Int list = GetTimeWarpData(whichUnit)
local TimeWarpSnapshot snapshot = LinkedListGetFirst(list)
if (list != 0 and snapshot != 0) then
call SetUnitX(whichUnit, snapshot.posX)
call SetUnitY(whichUnit, snapshot.posY)
call BlzSetUnitFacingEx(whichUnit, snapshot.facing)
call SetUnitLifeBJ(whichUnit, snapshot.life)
call SetUnitManaBJ(whichUnit, snapshot.mana)
if (list.count < TIME_WARP_DATA_POINTS) then
call ExileUnit(whichUnit, true)
call SetUnitUseFood(whichUnit, false)
call TimeWarpShowUnitDelayed(whichUnit, snapshot, (TIME_WARP_DATA_POINTS - list.count) * TIME_WARP_UPDATE_INTERVAL)
endif
if (snapshot.orderId != 0) then
if (snapshot.orderTargetObject != null) then
call IssueTargetOrderById(whichUnit, snapshot.orderId, snapshot.orderTargetObject)
elseif (snapshot.orderTargetX != 0.0 and snapshot.orderTargetY != 0.0) then
call IssuePointOrderById(whichUnit, snapshot.orderId, snapshot.orderTargetX, snapshot.orderTargetY)
else
call IssueImmediateOrderById(whichUnit, snapshot.orderId)
endif
endif
endif
endfunction
globals
constant real TIME_WARP_UPDATE_INTERVAL = 1.5
constant group GROUP_TIME_WARP = CreateGroup()
force TIME_WARP_PLAYERS = null
boolexpr TIME_WARP_CONDITION = null
boolean TIME_WARP_CAPTURE_ENABLED = true
endglobals
function Trig_Time_Warp_Loop_Conditions takes nothing returns boolean
return TIME_WARP_CAPTURE_ENABLED
endfunction
function Trig_Time_Warp_Player_Loop takes nothing returns nothing
local group playerUnits = GetUnitsOfPlayerMatching(GetEnumPlayer(), TIME_WARP_CONDITION)
local unit picked = null
loop
set picked = FirstOfGroup(playerUnits)
exitwhen picked == null
call TimeWarpTakeSnapshot(picked)
call GroupRemoveUnit(playerUnits, picked)
endloop
call DestroyGroup(playerUnits)
endfunction
function Trig_Time_Warp_Loop_Filter takes nothing returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (BlzGetUnitBooleanField(filter, UNIT_BF_IS_A_BUILDING)) then
return false
elseif (UnitHasAbility(filter, SB_LOCUST)) then
return false
endif
return true
endfunction
function Trig_Time_Warp_Loop_Actions takes nothing returns nothing
local unit picked = null
local LinkedList_Int list = 0
local integer pIndex = 0
if (TIME_WARP_PLAYERS == null) then
set TIME_WARP_PLAYERS = GetPlayingPlayers(false, true, true)
endif
if (TIME_WARP_CONDITION == null) then
set TIME_WARP_CONDITION = Condition(function Trig_Time_Warp_Loop_Filter)
endif
call ForForce(TIME_WARP_PLAYERS, function Trig_Time_Warp_Player_Loop)
endfunction
//===========================================================================
function InitTrig_Time_Warp_Loop takes nothing returns nothing
set gg_trg_Time_Warp_Loop = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_Time_Warp_Loop, TIME_WARP_UPDATE_INTERVAL)
call TriggerAddCondition( gg_trg_Time_Warp_Loop, Condition(function Trig_Time_Warp_Loop_Conditions))
call TriggerAddAction( gg_trg_Time_Warp_Loop, function Trig_Time_Warp_Loop_Actions )
call GateAbilityTrigger(gg_trg_Time_Warp_Loop, SB_TIME_WARP, 0)
endfunction
function Trig_Time_Warp_Orders_Conditions takes nothing returns boolean
return GetTimeWarpData(GetOrderedUnit()) != 0
endfunction
function Trig_Time_Warp_Orders_Actions takes nothing returns nothing
local LinkedList_Int list = GetTimeWarpData(GetOrderedUnit())
local TimeWarpSnapshot latestSnapshot = LinkedListGetLast(list)
set latestSnapshot.orderId = GetIssuedOrderId()
set latestSnapshot.orderTargetX = GetOrderPointX()
set latestSnapshot.orderTargetY = GetOrderPointY()
set latestSnapshot.orderTargetObject = GetOrderTarget()
endfunction
//===========================================================================
function InitTrig_Time_Warp_Orders takes nothing returns nothing
set gg_trg_Time_Warp_Orders = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Time_Warp_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Time_Warp_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Time_Warp_Orders, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Time_Warp_Orders, Condition( function Trig_Time_Warp_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Time_Warp_Orders, function Trig_Time_Warp_Orders_Actions )
call GateAbilityTrigger(gg_trg_Time_Warp_Orders, SB_TIME_WARP, 0)
endfunction
function Trig_Time_Warp_Death_Conditions takes nothing returns boolean
return GetTimeWarpData(GetDyingUnit()) != 0
endfunction
function Trig_Time_Warp_Death_Actions takes nothing returns nothing
call DeleteTimeWarpData(GetDyingUnit())
endfunction
//===========================================================================
function InitTrig_Time_Warp_Death takes nothing returns nothing
set gg_trg_Time_Warp_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Time_Warp_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Time_Warp_Death, Condition( function Trig_Time_Warp_Death_Conditions ) )
call TriggerAddAction( gg_trg_Time_Warp_Death, function Trig_Time_Warp_Death_Actions )
endfunction
function Trig_Time_Warp_Leave_Conditions takes nothing returns boolean
return GetTimeWarpData(GetLeavingUnit()) != 0
endfunction
function Trig_Time_Warp_Leave_Actions takes nothing returns nothing
call DeleteTimeWarpData(GetLeavingUnit())
endfunction
//===========================================================================
function InitTrig_Time_Warp_Leave takes nothing returns nothing
set gg_trg_Time_Warp_Leave = CreateTrigger( )
call TriggerRegisterLeaveRectSimple( gg_trg_Time_Warp_Leave, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Time_Warp_Leave, Condition( function Trig_Time_Warp_Leave_Conditions ) )
call TriggerAddAction( gg_trg_Time_Warp_Leave, function Trig_Time_Warp_Leave_Actions )
endfunction
function Trig_Time_Warp_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_TIME_WARP
endfunction
function Trig_Time_Warp_Cast_PlayEffect takes string effectModel, unit whichUnit, string attachmentPoint returns nothing
local real x = GetUnitX(whichUnit)
local real y = GetUnitY(whichUnit)
if (not IsUnitHidden(whichUnit) and x != 0.0 and y != 0.0) then
if (attachmentPoint != null) then
call AddSpecialEffectTargetOneShot(effectModel, whichUnit, attachmentPoint)
else
call AddSpecialEffectOneShot(effectModel, x, y)
endif
endif
endfunction
function Trig_Time_Warp_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local string beforeEffect = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_EFFECT)
local string afterEffect = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_AREA_EFFECT)
local real x = GetUnitX(target)
local real y = GetUnitY(target)
call Trig_Time_Warp_Cast_PlayEffect(beforeEffect, target, null)
call ApplyTimeWarp(target)
call Trig_Time_Warp_Cast_PlayEffect(afterEffect, target, "origin")
call PlayPitchedSoundAtPositionSB("Abilities\\Spells\\Human\\InnerFire\\InnerFireBirth.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 127, 2.0)
endfunction
//===========================================================================
function InitTrig_Time_Warp_Cast takes nothing returns nothing
set gg_trg_Time_Warp_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Time_Warp_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Time_Warp_Cast, Condition( function Trig_Time_Warp_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Time_Warp_Cast, function Trig_Time_Warp_Cast_Actions )
endfunction
struct ChainLightning
unit caster = null
unit current = null
real aoe = 0.0
real delay = 0.0
real damage = 0.0
string targetModel = null
string hitModel = null
effect targetEffect = null
UnitLeash lightningEffect = 0
IntTimer delayTimer = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(targetEffect)
call delayTimer.destroy()
endmethod
endstruct
function CreateChainLightning takes unit caster, unit target returns ChainLightning
local ChainLightning cl = ChainLightning.create()
set cl.caster = caster
set cl.current = target
set cl.aoe = GetUnitAbilityRealLevelField(caster, SB_CHAIN_LIGHTNING, ABILITY_RLF_AREA_OF_EFFECT)
set cl.delay = GetUnitAbilityRealLevelField(caster, SB_CHAIN_LIGHTNING, ABILITY_RLF_DURATION_NORMAL)
set cl.damage = GetUnitAbilityRealLevelField(caster, SB_CHAIN_LIGHTNING, ABILITY_RLF_DURATION_HERO)
set cl.targetModel = GetUnitAbilityStringLevelField(caster, SB_CHAIN_LIGHTNING, ABILITY_SLF_SPECIAL)
set cl.hitModel = GetUnitAbilityStringLevelField(caster, SB_CHAIN_LIGHTNING, ABILITY_SLF_EFFECT)
set cl.delayTimer = CreateIntTimer(cl, false)
return cl
endfunction
function ChainLightningTargetFilter takes ChainLightning cl returns boolean
local unit filter = GetFilterUnit()
if (filter == cl.current) then
return false
elseif (not UnitAlive(filter)) then
return false
elseif (IsUnitNonNeutralAlly(filter, GetOwningPlayer(cl.caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
endif
return true
endfunction
function GetChainLightningTarget takes ChainLightning cl returns unit
local group nearbyUnits = GetUnitsInAOEOfUnitInt(cl.current, cl.aoe, ChainLightningTargetFilter, cl)
local unit picked = GroupPickClosestUnit(nearbyUnits, GetUnitX(cl.current), GetUnitY(cl.current))
call DestroyGroup(nearbyUnits)
return picked
endfunction
function ChainLightningHit takes ChainLightning cl, unit hit returns nothing
if (cl.lightningEffect != 0) then
call cl.lightningEffect.destroy()
endif
call DestroyEffect(cl.targetEffect)
set cl.targetEffect = AddSpecialEffectTarget(cl.targetModel, hit, "origin")
set cl.lightningEffect = LightningEffects_CreateUnitLeash(cl.current, hit, vec3.create(0, 0, 60), vec3.create(0, 0, 60), "CLPB", 0.01, 0.5)
call AddSpecialEffectTargetOneShot(cl.hitModel, hit, "origin")
call UnitDamageTargetBJ(cl.caster, hit, cl.damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING)
set cl.current = hit
call StartTimerPlus(cl.delayTimer, cl.delay, ChainLightningBounceReady)
endfunction
function ChainLightningBounceReady takes IntTimer it returns nothing
local ChainLightning cl = it.owner
local unit picked = GetChainLightningTarget(cl)
if (picked != null) then
call ChainLightningHit(cl, picked)
else
call cl.destroy()
endif
endfunction
function Trig_Chain_Lightning_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_CHAIN_LIGHTNING
endfunction
function Trig_Chain_Lightning_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local ChainLightning cl = CreateChainLightning(caster, target)
local unit nearbyTarget = GetChainLightningTarget(cl)
if (nearbyTarget != null) then
call AddSpecialEffectTargetOneShot(cl.hitModel, target, "origin")
call ChainLightningHit(cl, nearbyTarget)
else
call DisplayError(GetOwningPlayer(caster), "No nearby targets found.")
call RefundAbilityCast(caster, GetSpellAbilityId())
endif
endfunction
//===========================================================================
function InitTrig_Chain_Lightning_Cast takes nothing returns nothing
set gg_trg_Chain_Lightning_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Chain_Lightning_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Chain_Lightning_Cast, Condition( function Trig_Chain_Lightning_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Chain_Lightning_Cast, function Trig_Chain_Lightning_Cast_Actions )
endfunction
scope ArcaneRiddle initializer Init
private function IsArcaneRiddleTech takes nothing returns boolean
return GetResearched() == SB_TECH_ARCANE_RIDDLE
endfunction
private function ArcaneRiddleResearched takes nothing returns nothing
local group unitsWithAbility = GetUnitsOfPlayerWithAbility(GetOwningPlayer(GetResearchingUnit()), SB_ARCANE_RIDDLE)
local integer size = BlzGroupGetSize(unitsWithAbility)
loop
set size = size - 1
exitwhen size < 0
call BlzUnitDisableAbility(BlzGroupUnitAt(unitsWithAbility, size), SB_ARCANE_RIDDLE, false, false)
endloop
endfunction
private function InitArcaneRiddle takes unit whichUnit returns nothing
if (not PlayerHasTech(GetOwningPlayer(whichUnit), SB_TECH_ARCANE_RIDDLE)) then
call BlzUnitDisableAbility(whichUnit, SB_ARCANE_RIDDLE, true, true)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddCondition(t, Condition(function IsArcaneRiddleTech))
call TriggerAddAction(t, function ArcaneRiddleResearched)
call InitAbility(SB_ARCANE_RIDDLE, InitArcaneRiddle)
endfunction
endscope
scope LightningStrike initializer Init
private function AOEFilter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
private function OnSpellEffect takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real aoeSmall = 35.0
local real buildingReduction = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_BUILDING_REDUCTION_HBZ4)
local real aoeLarge = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local real bigDamage = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DAMAGE_HBZ2)
local real smallDamage = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_DAMAGE_PER_SECOND_HBZ5)
local string areaArt = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_AREA_EFFECT)
local string hitArt = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_SPECIAL)
local group unitsInAoe = GetUnitsInAOEUnit(x, y, aoeLarge, AOEFilter, caster)
local real armor = 0
local integer size = BlzGroupGetSize(unitsInAoe)
local unit picked = null
local real damageDealt = 0.0
local real colSize = 0.0
call AddSpecialEffectOneShotEx(areaArt, x, y, 0.0, 0.5, 1.0)
loop
set size = size - 1
exitwhen size < 0
set picked = BlzGroupUnitAt(unitsInAoe, size)
set damageDealt = smallDamage
set armor = BlzGetUnitArmor(picked)
set colSize = BlzGetUnitCollisionSize(picked)
if (SqrDistanceBetweenPointsXY(GetUnitX(picked), GetUnitY(picked), x, y) <= (aoeSmall + colSize) * (aoeSmall + colSize)) then
set damageDealt = bigDamage
endif
if (IsUnitType(picked, UNIT_TYPE_STRUCTURE)) then
set damageDealt = damageDealt * buildingReduction
endif
if (armor != 0) then
set damageDealt = damageDealt * (1.0 - (0.06 * armor) / (1 + 0.06 * armor))
endif
call AddSpecialEffectTargetOneShot(hitArt, picked, "chest")
call UnitDamageTarget(caster, picked, damageDealt, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_LIGHTNING, WEAPON_TYPE_WHOKNOWS)
endloop
call DestroyGroup(unitsInAoe)
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(SB_LIGHTNING_STRIKE, function OnSpellEffect)
endfunction
endscope
globals
constant key KEY_ILLUSION
endglobals
function Trig_Illusion_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ILLUSION
endfunction
function Trig_Illusion_Cast_Filter takes unit caster returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitAlly(filter, GetOwningPlayer(caster))) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitIllusion(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Illusion_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local group unitsInAOE = GetUnitsInAOEUnit(GetSpellTargetX(), GetSpellTargetY(), aoe, Trig_Illusion_Cast_Filter, caster)
local unit picked = null
loop
set picked = FirstOfGroup(unitsInAOE)
exitwhen picked == null
if (not UnitHasAbility(picked, SB_ILLUSION_HIDDEN)) then
call UnitAddAbility(picked, SB_ILLUSION_HIDDEN)
endif
call SaveBoolean(udg_HashTable_UnitInfo, GetHandleId(picked), KEY_ILLUSION, true)
call IssueImmediateOrder(picked, "mirrorimage")
call GroupRemoveUnit(unitsInAOE, picked)
endloop
call DestroyGroup(unitsInAOE)
endfunction
//===========================================================================
function InitTrig_Illusion_Cast takes nothing returns nothing
set gg_trg_Illusion_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Illusion_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Illusion_Cast, Condition( function Trig_Illusion_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Illusion_Cast, function Trig_Illusion_Cast_Actions )
endfunction
function Trig_Illusion_Spawn_Conditions takes nothing returns boolean
return IsUnitIllusion(GetSummonedUnit()) and HaveSavedBoolean(udg_HashTable_UnitInfo, GetHandleId(GetSummoningUnit()), KEY_ILLUSION)
endfunction
function Trig_Illusion_Spawn_Actions takes nothing returns nothing
local unit summoning = GetSummoningUnit()
local unit summoned = GetSummonedUnit()
local real x = GetUnitX(summoned)
local real y = GetUnitY(summoned)
local unit dummy = DummyCastUnit(GetOwningPlayer(summoning), summoned, x, y, SB_ILLUSION_HIDDEN_CASTER, "")
call SaveUnitHandle(udg_HashTable_TargetToCaster, GetHandleId(dummy), KEY_ILLUSION, summoned)
call IssueTargetOrderById(dummy, 852274, summoned)
call RemoveSavedBoolean(udg_HashTable_UnitInfo, GetHandleId(summoning), KEY_ILLUSION)
endfunction
//===========================================================================
function InitTrig_Illusion_Spawn takes nothing returns nothing
set gg_trg_Illusion_Spawn = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Illusion_Spawn, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_Illusion_Spawn, Condition( function Trig_Illusion_Spawn_Conditions ) )
call TriggerAddAction( gg_trg_Illusion_Spawn, function Trig_Illusion_Spawn_Actions )
endfunction
function Trig_Illusion_Replace_Conditions takes nothing returns boolean
return IsUnitIllusion(GetSummonedUnit()) and HaveSavedHandle(udg_HashTable_TargetToCaster, GetHandleId(GetSummoningUnit()), KEY_ILLUSION)
endfunction
function Trig_Illusion_Replace_Actions takes nothing returns nothing
local unit summoned = GetSummonedUnit()
local unit summoning = GetSummoningUnit()
local unit replaced = LoadUnitHandle(udg_HashTable_TargetToCaster, GetHandleId(summoning), KEY_ILLUSION)
local real x = GetUnitX(replaced)
local real y = GetUnitY(replaced)
call RemoveUnit(replaced)
call SetUnitX(summoned, x)
call SetUnitY(summoned, y)
call RemoveSavedHandle(udg_HashTable_TargetToCaster, GetHandleId(summoning), KEY_ILLUSION)
endfunction
//===========================================================================
function InitTrig_Illusion_Replace takes nothing returns nothing
set gg_trg_Illusion_Replace = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Illusion_Replace, EVENT_PLAYER_UNIT_SUMMON )
call TriggerAddCondition( gg_trg_Illusion_Replace, Condition( function Trig_Illusion_Replace_Conditions ) )
call TriggerAddAction( gg_trg_Illusion_Replace, function Trig_Illusion_Replace_Actions )
endfunction
function Trig_Illusion_Hidden_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ILLUSION_HIDDEN
endfunction
function Trig_Illusion_Hidden_Cast_Actions takes nothing returns nothing
call UnitRemoveAbility(GetSpellAbilityUnit(), GetSpellAbilityId())
endfunction
//===========================================================================
function InitTrig_Illusion_Hidden_Cast takes nothing returns nothing
set gg_trg_Illusion_Hidden_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Illusion_Hidden_Cast, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Illusion_Hidden_Cast, Condition( function Trig_Illusion_Hidden_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Illusion_Hidden_Cast, function Trig_Illusion_Hidden_Cast_Actions )
endfunction
scope Stormrage initializer Init
private function OnTransformBeginBegin takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
call SetUnitAbilityRealLevelField(caster, SB_STORMRAGE, ABILITY_RLF_DURATION_NORMAL, 0.0)
call SetUnitAbilityRealLevelField(caster, SB_STORMRAGE, ABILITY_RLF_ALTITUDE_ADJUSTMENT_DURATION, 0.5)
endfunction
private function OnTransformBeginFinish takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local string effectArt = GetUnitAbilityStringLevelField(caster, SB_STORMRAGE_DUMMY, ABILITY_SLF_SPECIAL)
call IssueImmediateOrder(caster, "ravenform")
endfunction
private function OnTransformEndBegin takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
if (IsUnitType(caster, UNIT_TYPE_FLYING)) then
call SetUnitAbilityRealLevelField(caster, SB_STORMRAGE, ABILITY_RLF_DURATION_NORMAL, 1.5)
call SetUnitAbilityRealLevelField(caster, SB_STORMRAGE, ABILITY_RLF_ALTITUDE_ADJUSTMENT_DURATION, 1.5)
endif
endfunction
private function Init takes nothing returns nothing
call CreateSpellBeginTrigger(SB_STORMRAGE_DUMMY, function OnTransformBeginBegin)
call CreateSpellFinishTrigger(SB_STORMRAGE_DUMMY, function OnTransformBeginFinish)
call CreateSpellBeginTrigger(SB_STORMRAGE, function OnTransformEndBegin)
endfunction
endscope
scope BurstAttack initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant key KEY_BURST_ATTACK
endglobals
struct BurstAttack
unit whichUnit = null
integer attackCounter = 0
real baseAttackCooldown = 0.0
IntTimer resetTimer = 0
method onDestroy takes nothing returns nothing
set whichUnit = null
call resetTimer.destroy()
endmethod
endstruct
function CreateBurstAttack takes unit whichUnit returns BurstAttack
local BurstAttack b = BurstAttack.create()
set b.whichUnit = whichUnit
set b.baseAttackCooldown = BlzGetUnitAttackCooldown(whichUnit, 0)
set b.resetTimer = CreateUnitTimer(whichUnit, false)
return b
endfunction
private function BurstAttack_OnEnable takes unit whichUnit returns nothing
local BurstAttack b = CreateBurstAttack(whichUnit)
call SaveInteger(HT, GetHandleId(whichUnit), KEY_BURST_ATTACK, b)
endfunction
private function BurstAttack_OnDisable takes unit whichUnit returns nothing
local BurstAttack b = LoadInteger(HT, GetHandleId(whichUnit), KEY_BURST_ATTACK)
call b.destroy()
call RemoveSavedInteger(HT, GetHandleId(whichUnit), KEY_BURST_ATTACK)
endfunction
private function ResetBurstAttack takes IntTimer it returns nothing
local BurstAttack b = it.owner
set b.attackCounter = 0
endfunction
private function BurstAttackConditions takes nothing returns boolean
return UnitHasAbility(GetAttacker(), SB_BURST_ATTACK) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_FLYING)
endfunction
private function BurstAttackActions takes nothing returns nothing
local unit attacker = GetAttacker()
local BurstAttack b = LoadInteger(HT, GetHandleId(attacker), KEY_BURST_ATTACK)
local integer attacksPerBurst = R2I(GetUnitAbilityRealLevelField(attacker, SB_BURST_ATTACK, ABILITY_RLF_CASTING_TIME))
local real cooldown = GetUnitAbilityRealLevelField(attacker, SB_BURST_ATTACK, ABILITY_RLF_COOLDOWN)
set b.attackCounter = b.attackCounter + 1
if (b.attackCounter >= attacksPerBurst) then
call BlzSetUnitAttackCooldown(attacker, cooldown, 0)
set b.attackCounter = 0
else
call BlzSetUnitAttackCooldown(attacker, b.baseAttackCooldown, 0)
call StartTimerPlus(b.resetTimer, cooldown, ResetBurstAttack)
endif
endfunction
private function Init takes nothing returns nothing
local GatedAbilityTrigger gat = 0
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddCondition(t, Condition(function BurstAttackConditions))
call TriggerAddAction(t, function BurstAttackActions)
set gat = GateAbilityTriggerAll(t, SB_BURST_ATTACK, 0, BurstAttack_OnEnable, BurstAttack_OnDisable)
endfunction
endscope
scope Spellburn initializer Init
globals
private constant real SPELLBURN_MULTIPLIER = 1.30
endglobals
private function IsMagicOrSpellDamage takes nothing returns boolean
local attacktype attackType = BlzGetEventAttackType()
local damagetype damageType = BlzGetEventDamageType()
if (attackType == ATTACK_TYPE_MAGIC or attackType == ATTACK_TYPE_NORMAL) then
return true
elseif (damageType == DAMAGE_TYPE_ACID) then
return true
elseif (damageType == DAMAGE_TYPE_COLD) then
return true
elseif (damageType == DAMAGE_TYPE_DEATH) then
return true
elseif (damageType == DAMAGE_TYPE_DIVINE) then
return true
elseif (damageType == DAMAGE_TYPE_FIRE) then
return true
elseif (damageType == DAMAGE_TYPE_LIGHTNING) then
return true
elseif (damageType == DAMAGE_TYPE_MAGIC) then
return true
elseif (damageType == DAMAGE_TYPE_MIND) then
return true
elseif (damageType == DAMAGE_TYPE_PLANT) then
return true
elseif (damageType == DAMAGE_TYPE_SONIC) then
return true
endif
return false
endfunction
private function SpellburnDamagingConditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
if (GetUnitAbilityLevel(damaged, SB_BUFF_SPELLBURN) == 0) then
return false
elseif (not IsMagicOrSpellDamage()) then
return false
elseif (GetEventDamage() <= 0.0) then
return false
endif
return true
endfunction
private function SpellburnActions takes nothing returns nothing
local real damage = GetEventDamage()
call BlzSetEventDamage(damage * SPELLBURN_MULTIPLIER)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t, Condition(function SpellburnDamagingConditions))
call TriggerAddAction(t, function SpellburnActions)
call GateAbilityTrigger(t, SB_ARCANE_RIDDLE, SB_TECH_ARCANE_RIDDLE)
endfunction
endscope
scope Kundalini initializer Init
private struct Kundalini
unit whichUnit = null
real healingPerSecond = 0.0
real manaPerHitPoint = 0.0
string healArt = null
effect healEffect = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call DestroyEffect(healEffect)
call it.destroy()
endmethod
endstruct
private function UpdateKundalini takes IntTimer it returns nothing
local Kundalini k = it.owner
local real unitLife = GetUnitState(k.whichUnit, UNIT_STATE_LIFE)
local real unitMaxLife = GetUnitState(k.whichUnit, UNIT_STATE_MAX_LIFE)
local real hpRestored = RMin(k.healingPerSecond * TimerPlusGetElapsed(it), unitMaxLife - unitLife)
local real manaConsumed = hpRestored * k.manaPerHitPoint
if (not UnitAlive(k.whichUnit)) then
call k.destroy()
elseif (unitLife < unitMaxLife and GetUnitState(k.whichUnit, UNIT_STATE_MANA) >= manaConsumed) then
call ChangeUnitState(k.whichUnit, UNIT_STATE_MANA, -manaConsumed)
call ChangeUnitState(k.whichUnit, UNIT_STATE_LIFE, hpRestored)
if (k.healEffect == null) then
set k.healEffect = AddSpecialEffectTarget(k.healArt, k.whichUnit, "origin")
endif
elseif (k.healEffect != null) then
call DestroyEffect(k.healEffect)
set k.healEffect = null
endif
endfunction
private function CreateKundalini takes unit whichUnit returns nothing
local real healingInterval = GetUnitAbilityRealLevelField(whichUnit, SB_KUNDALINI, ABILITY_RLF_DURATION_NORMAL)
local Kundalini k = Kundalini.create()
set k.whichUnit = whichUnit
set k.healingPerSecond = GetUnitAbilityRealLevelField(whichUnit, SB_KUNDALINI, ABILITY_RLF_AREA_OF_EFFECT)
set k.manaPerHitPoint = GetUnitAbilityIntegerLevelField(whichUnit, SB_KUNDALINI, ABILITY_ILF_MANA_COST)
set k.healArt = GetUnitAbilityStringLevelField(whichUnit, SB_KUNDALINI, ABILITY_SLF_SPECIAL)
set k.it = CreateIntTimer(k, false)
call StartTimerPlusPeriodic(k.it, 0.0, healingInterval, UpdateKundalini, 0)
endfunction
private function Init takes nothing returns nothing
call GateAbilityTriggerAll(null, SB_KUNDALINI, 0, CreateKundalini, 0)
endfunction
endscope
scope ManaBattery initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant real MANA_BATTERY_INTERVAL = 1.0
private constant real MANA_COST_FACTOR = 0.33334
private constant key KEY_MB_TARGET
private constant string RESTORE_MANA_EFFECT = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"
private constant string SOUND_EFFECT = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouch.flac"
private timer MB_TIMER = null
private group MB_CASTERS = CreateGroup()
endglobals
private function TargetFilter takes unit emitter returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (not IsUnitNonNeutralAlly(filter, GetOwningPlayer(emitter))) then
return false
elseif (BlzGetUnitMaxMana(filter) <= 0) then
return false
elseif (GetUnitAbilityLevel(filter, SB_MANA_BATTERY) > 0) then
return false
elseif (GetUnitState(filter, UNIT_STATE_MANA) >= BlzGetUnitMaxMana(filter)) then
return false
elseif (HaveSavedHandle(HT, KEY_MB_TARGET, GetHandleId(filter))) then
return false
endif
return true
endfunction
private function UpdateManaBattery takes nothing returns nothing
local integer emitters = BlzGroupGetSize(MB_CASTERS)
local integer targets = 0
local unit emitter = null
local unit target = null
local group nearby = CreateGroup()
local real aoe = 0.0
local real maxManaRestored = 0.0
local real manaRestored = 0.0
local integer maxTargets = 0
call FlushChildHashtable(HT, KEY_MB_TARGET)
loop
set emitters = emitters - 1
exitwhen emitters < 0
set emitter = BlzGroupUnitAt(MB_CASTERS, emitters)
if (UnitAlive(emitter) and UnitHasAbility(emitter, SB_BUFF_MANA_BATTERY)) then
set aoe = GetUnitAbilityRealLevelField(emitter, SB_MANA_BATTERY, ABILITY_RLF_AREA_OF_EFFECT)
set maxTargets = R2I(GetUnitAbilityRealLevelField(emitter, SB_MANA_BATTERY, ABILITY_RLF_CAST_RANGE) + 0.5)
set maxManaRestored = GetUnitAbilityRealLevelField(emitter, SB_MANA_BATTERY, ABILITY_RLF_DAMAGE_PER_INTERVAL)
if (GetUnitState(emitter, UNIT_STATE_MANA) >= maxManaRestored * MANA_COST_FACTOR) then
call GroupEnumUnitsInAOEOfUnitUnit(nearby, emitter, aoe, TargetFilter, emitter)
set targets = IMin(BlzGroupGetSize(nearby), maxTargets)
if (targets > 0) then
call PlaySoundAtPositionSB(SOUND_EFFECT, "SpellsEAX", AUDIO_CHANNEL_BIRTH, GetUnitX(emitter), GetUnitY(emitter), 50.0)
endif
loop
set targets = targets - 1
exitwhen targets < 0 or maxTargets < 0 or GetUnitState(emitter, UNIT_STATE_MANA) < maxManaRestored * MANA_COST_FACTOR
set target = BlzGroupUnitAt(nearby, targets)
set manaRestored = RMin(maxManaRestored, BlzGetUnitMaxMana(target) - GetUnitState(target, UNIT_STATE_MANA))
if (manaRestored >= 1.0) then
call SaveUnitHandle(HT, KEY_MB_TARGET, GetHandleId(target), emitter)
call ChangeUnitState(emitter, UNIT_STATE_MANA, -manaRestored * MANA_COST_FACTOR)
call ChangeUnitState(target, UNIT_STATE_MANA, manaRestored)
call DestroyEffect(AddSpecialEffectTarget(RESTORE_MANA_EFFECT, target, "overhead"))
endif
endloop
endif
else
call GroupRemoveUnit(MB_CASTERS, emitter)
endif
endloop
endfunction
private function AddManaBatteryEmitter takes unit emitter returns nothing
call GroupAddUnit(MB_CASTERS, emitter)
if (MB_TIMER == null) then
set MB_TIMER = CreateTimer()
call TimerStart(MB_TIMER, MANA_BATTERY_INTERVAL, true, function UpdateManaBattery)
endif
endfunction
private function RemoveManaBatteryEmitter takes unit emitter returns nothing
call GroupRemoveUnit(MB_CASTERS, emitter)
endfunction
private function IsManaBatteryCaster takes nothing returns boolean
return UnitHasAbility(GetFilterUnit(), SB_BUFF_MANA_BATTERY)
endfunction
private function IsManaBatteryUnit takes nothing returns boolean
return UnitHasAbility(GetTriggerUnit(), SB_BUFF_MANA_BATTERY)
endfunction
private function IsManaBatteryActivate takes nothing returns boolean
return GetIssuedOrderId() == SB_ORDER_ACTIVATE_MANA_BATTERY
endfunction
private function IsManaBatteryDeactivate takes nothing returns boolean
return GetIssuedOrderId() == SB_ORDER_DEACTIVATE_MANA_BATTERY
endfunction
private function OnManaBatteryEnabled takes nothing returns nothing
local unit caster = GetTriggerUnit()
call AddManaBatteryEmitter(caster)
endfunction
private function OnManaBatteryDisabled takes nothing returns nothing
local unit caster = GetTriggerUnit()
call RemoveManaBatteryEmitter(caster)
endfunction
private function InitManaBatteries takes nothing returns nothing
call GroupEnumUnitsInRect(MB_CASTERS, GetEntireMapRect(), Condition(function IsManaBatteryCaster))
if (CountUnitsInGroup(MB_CASTERS) > 0) then
set MB_TIMER = CreateTimer()
call TimerStart(MB_TIMER, MANA_BATTERY_INTERVAL, true, function UpdateManaBattery)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(t, Condition(function IsManaBatteryUnit))
call TriggerAddAction(t, function OnManaBatteryEnabled)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function IsManaBatteryActivate))
call TriggerAddAction(t, function OnManaBatteryEnabled)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(t, Condition(function IsManaBatteryDeactivate))
call TriggerAddAction(t, function OnManaBatteryDisabled)
call GroupEnumUnitsInRect(MB_CASTERS, GetEntireMapRect(), Condition(function IsManaBatteryCaster))
if (CountUnitsInGroup(MB_CASTERS) > 0) then
set MB_TIMER = CreateTimer()
call TimerStart(MB_TIMER, MANA_BATTERY_INTERVAL, true, function UpdateManaBattery)
endif
endfunction
endscope
globals
constant real BLACK_HOLE_UPDATE_INTERVAL = 0.01
constant real BLACK_HOLE_EJECTION_SPEED = 2400.0
constant key KEY_BLACK_HOLE
CustomAura BLACK_HOLE_AURA = 0
endglobals
struct BlackHole
real x = 0.0
real y = 0.0
real aoe = 0.0
real gravity = 0.0
group suckedIn = null
method onDestroy takes nothing returns nothing
call DestroyGroup(suckedIn)
endmethod
endstruct
struct BlackHoleEjection
unit whichUnit = null
real x = 0.0
real y = 0.0
real speed = 0.0
endstruct
function GetBlackHoleFromEmitter takes unit emitter returns BlackHole
return LoadInteger(udg_HashTable_Auras, GetHandleId(emitter), KEY_BLACK_HOLE)
endfunction
function BlackHoleUpdate takes CustomAuraEmitter emitter, group unitsAffected returns nothing
local BlackHole bh = GetBlackHoleFromEmitter(emitter.emitter)
local group unitsInRange = CreateGroup()
local unit picked = null
local real dist = 0.0
local real angle = 0.0
local real factor = 0.0
local real f = 0.0
call GroupAddGroup(unitsAffected, unitsInRange)
loop
set picked = FirstOfGroup(unitsInRange)
exitwhen picked == null
set dist = DistanceBetweenUnits(picked, emitter.emitter)
set angle = AngleBetweenUnits(picked, emitter.emitter)
set factor = Pow(1.0 - DBZ(dist, bh.aoe, 0.0), 3.0)
set f = RMinBJ(dist, factor * bh.gravity * BLACK_HOLE_UPDATE_INTERVAL)
call SetUnitX(picked, PolarProjectionX(GetUnitX(picked), f, angle + factor))
call SetUnitY(picked, PolarProjectionY(GetUnitY(picked), f, angle + factor))
//call SetUnitSizeOverTime(picked, 0.0, 1.0 - factor)
if (dist <= 10.0) then
call GroupAddUnit(bh.suckedIn, picked)
call ExileUnit(picked, true)
endif
call GroupRemoveUnit(unitsInRange, picked)
endloop
call DestroyGroup(unitsInRange)
endfunction
function EjectBlackHoleUnit takes IntTimer it returns nothing
local BlackHoleEjection bhe = it.owner
call ExileUnit(bhe.whichUnit, false)
if (bhe.speed > 0.0) then
call MoveUnitToPointAtSpeedXY(bhe.whichUnit, bhe.x, bhe.y, bhe.speed)
else
call SetUnitX(bhe.whichUnit, bhe.x)
call SetUnitY(bhe.whichUnit, bhe.y)
endif
call bhe.destroy()
endfunction
function EjectBlackHole takes BlackHole bh returns nothing
local integer count = CountUnitsInGroup(bh.suckedIn)
local real x = 0.0
local real y = 0.0
local real dist = 0.0
local real angle = 0.0
local real angleInterval = DBZ(360.0, count, 0)
local real speed = 0.0
local real factor = 0.0
local real delay = 0.0
local BlackHoleEjection ejection = 0
local IntTimer t = 0
local integer index = 0
local unit picked = null
loop
set picked = FirstOfGroup(bh.suckedIn)
exitwhen picked == null
set factor = I2R(index) / count
set dist = GetRandomReal(bh.aoe * 0.3, bh.aoe * 0.7)
set speed = (dist / bh.aoe) * BLACK_HOLE_EJECTION_SPEED
set angle = index * angleInterval
set ejection = BlackHoleEjection.create()
set ejection.whichUnit = picked
set ejection.x = PolarProjectionX(GetUnitX(picked), dist, angle)
set ejection.y = PolarProjectionY(GetUnitY(picked), dist, angle)
set ejection.speed = speed
set delay = index * 0.03
set t = CreateIntTimer(ejection, true)
call StartTimerPlus(t, delay, EjectBlackHoleUnit)
call GroupRemoveUnit(bh.suckedIn, picked)
set index = index + 1
endloop
endfunction
function CreateBlackHole takes unit caster, real x, real y returns BlackHole
local real duration = GetUnitAbilityRealLevelField(caster, SB_BLACK_HOLE, ABILITY_RLF_DURATION_NORMAL)
local unit emitter = CreateUnit(GetOwningPlayer(caster), SB_SPECIAL_EFFECT_UNIT_BLACK_HOLE, x, y, bj_UNIT_FACING)
local real aoe = GetUnitAbilityRealLevelField(caster, SB_BLACK_HOLE, ABILITY_RLF_AREA_OF_EFFECT)
local CustomAuraEmitter customAuraEmitter = CustomAuras_AddEmitter(emitter, BLACK_HOLE_AURA, aoe)
local BlackHole bh = BlackHole.create()
set bh.x = x
set bh.y = y
set bh.aoe = aoe
set bh.gravity = GetUnitAbilityIntegerField(caster, SB_BLACK_HOLE, ABILITY_IF_MISSILE_SPEED)
set bh.suckedIn = CreateGroup()
set customAuraEmitter.updateCallback = BlackHoleUpdate
call SetUnitAnimation(emitter, "birth")
call QueueUnitAnimation(emitter, "stand")
call SaveInteger(udg_HashTable_Auras, GetHandleId(emitter), KEY_BLACK_HOLE, bh)
call UnitApplyTimedLife(emitter, SB_BUFF_TIMED_LIFE_GENERIC, duration)
return bh
endfunction
function Trig_Black_Hole_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_BLACK_HOLE
endfunction
function Trig_Black_Hole_Filter takes CustomAuraEmitter emitter returns boolean
local unit filter = GetFilterUnit()
if (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (IsUnitWard(filter)) then
return false
elseif (GetHandleId(filter) == 0) then
return false
endif
return true
endfunction
function Trig_Black_Hole_UnitEnters takes unit whichUnit returns nothing
call SetUnitPathingSB(whichUnit, false)
endfunction
function Trig_Black_Hole_UnitExits takes unit whichUnit returns nothing
call SetUnitPathingSB(whichUnit, true)
endfunction
function Trig_Black_Hole_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local BlackHole bh = CreateBlackHole(caster, GetSpellTargetX(), GetSpellTargetY())
endfunction
//===========================================================================
function InitTrig_Black_Hole takes nothing returns nothing
set gg_trg_Black_Hole = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( gg_trg_Black_Hole, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Black_Hole, Condition( function Trig_Black_Hole_Conditions ) )
call TriggerAddAction( gg_trg_Black_Hole, function Trig_Black_Hole_Actions )
set BLACK_HOLE_AURA = CustomAuras_CreateCustomAura(BLACK_HOLE_UPDATE_INTERVAL, Trig_Black_Hole_UnitEnters, Trig_Black_Hole_UnitExits, Trig_Black_Hole_Filter, 0, 0)
endfunction
function Trig_Black_Hole_Death_Conditions takes nothing returns boolean
return GetBlackHoleFromEmitter(GetDyingUnit()) != 0
endfunction
function Trig_Black_Hole_Death_Actions takes nothing returns nothing
local BlackHole bh = GetBlackHoleFromEmitter(GetDyingUnit())
call EjectBlackHole(bh)
call RemoveSavedInteger(udg_HashTable_Auras, GetHandleId(GetDyingUnit()), KEY_BLACK_HOLE)
call bh.destroy()
endfunction
//===========================================================================
function InitTrig_Black_Hole_Death takes nothing returns nothing
set gg_trg_Black_Hole_Death = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Black_Hole_Death, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Black_Hole_Death, Condition( function Trig_Black_Hole_Death_Conditions ) )
call TriggerAddAction( gg_trg_Black_Hole_Death, function Trig_Black_Hole_Death_Actions )
endfunction
globals
constant key KEY_IMMOLATE
endglobals
function Trig_Immolate_Cast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_IMMOLATE
endfunction
function Trig_Immolate_Expires takes unit whichUnit returns nothing
local SavedOrder order = LoadInteger(udg_HashTable_Orders, GetHandleId(whichUnit), KEY_IMMOLATE)
call BlzUnitDisableAbility(whichUnit, 'Aatk', false, false)
call order.destroy()
call RemoveSavedInteger(udg_HashTable_Orders, GetHandleId(whichUnit), KEY_IMMOLATE)
endfunction
function Trig_Immolate_Cast_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local real angle = AngleBetweenUnits(caster, target)
local real distance = GetUnitAbilityRealLevelField(caster, SB_IMMOLATE, ABILITY_RLF_AREA_OF_EFFECT)
local real targetX = PolarProjectionX(GetUnitX(target), distance, angle)
local real targetY = PolarProjectionY(GetUnitY(target), distance, angle)
local SavedOrder order = CreateSavedOrder(String2OrderIdBJ("move"), null, targetX, targetY)
if (not UnitHasBuffBJ(target, SB_IMMOLATE)) then
call BlzUnitDisableAbility(target, 'Aatk', true, false)
endif
call IssueSavedOrder(target, order)
call SaveInteger(udg_HashTable_Orders, GetHandleId(target), KEY_IMMOLATE, order)
call AddBuffEffectWithCallback(target, SB_BUFF_IMMOLATE, "", "", Trig_Immolate_Expires)
endfunction
//===========================================================================
function InitTrig_Immolate_Cast takes nothing returns nothing
set gg_trg_Immolate_Cast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Immolate_Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Immolate_Cast, Condition( function Trig_Immolate_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Immolate_Cast, function Trig_Immolate_Cast_Actions )
endfunction
function Trig_Immolate_Orders_Conditions takes nothing returns boolean
return UnitHasBuffBJ(GetOrderedUnit(), SB_BUFF_IMMOLATE) and HaveSavedInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_IMMOLATE)
endfunction
function Trig_Immolate_Orders_Actions takes nothing returns nothing
local SavedOrder order = LoadInteger(udg_HashTable_Orders, GetHandleId(GetOrderedUnit()), KEY_IMMOLATE)
if (not IsOrderEqual(order, GetIssuedOrderId(), GetOrderTarget(), GetOrderPointX(), GetOrderPointY())) then
call IssueSavedOrder(GetOrderedUnit(), order)
endif
endfunction
//===========================================================================
function InitTrig_Immolate_Orders takes nothing returns nothing
set gg_trg_Immolate_Orders = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Immolate_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Immolate_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Immolate_Orders, EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddCondition( gg_trg_Immolate_Orders, Condition( function Trig_Immolate_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Immolate_Orders, function Trig_Immolate_Orders_Actions )
endfunction
function Trig_Freeze_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_FREEZETHAW
endfunction
function Trig_Freeze_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local effect vfx = null
if (GetUnitTypeId(caster) == SB_WATER_ELEMENTAL) then
set vfx = AddSpecialEffect("Abilities\\Spells\\Other\\FrostBolt\\FrostBoltMissile.mdl", GetUnitX(caster), GetUnitY(caster))
call BlzSetSpecialEffectScale(vfx, 2.0)
call BlzSetSpecialEffectZ(vfx, BlzGetUnitZ(caster) + 64.0)
else
set vfx = AddSpecialEffect("Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl", GetUnitX(caster), GetUnitY(caster))
call BlzSetSpecialEffectScale(vfx, 0.8)
endif
call DestroyEffect(vfx)
set vfx = null
set caster = null
endfunction
//===========================================================================
function InitTrig_Freeze takes nothing returns nothing
set gg_trg_Freeze = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Freeze, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Freeze, Condition( function Trig_Freeze_Conditions ) )
call TriggerAddAction( gg_trg_Freeze, function Trig_Freeze_Actions )
endfunction
struct TractorBeam
unit caster = null
unit target = null
real minDist = 0.0
real dragSpeed = 0.0
endstruct
function CreateTractorBeam takes unit caster, unit target returns TractorBeam
local TractorBeam tb = TractorBeam.create()
set tb.caster = caster
set tb.target = target
set tb.minDist = GetUnitAbilityRealLevelField(caster, SB_TRACTOR_BEAM, ABILITY_RLF_AREA_OF_EFFECT)
set tb.dragSpeed = GetUnitAbilityIntegerField(caster, SB_TRACTOR_BEAM, ABILITY_IF_MISSILE_SPEED)
return tb
endfunction
globals
constant real TRACTOR_BEAM_UPDATE_INTERVAL = 0.01
endglobals
function Trig_Tractor_Beam_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_TRACTOR_BEAM
endfunction
function Trig_Tractor_Beam_Update takes IntTimer it returns nothing
local TractorBeam tb = it.owner
local real speed = tb.dragSpeed * TRACTOR_BEAM_UPDATE_INTERVAL
local real newX = 0.0
local real newY = 0.0
local real angle = 0.0
local real dist = 0.0
if (UnitHasBuffBJ(tb.target, SB_BUFF_TRACTOR_BEAM)) then
set dist = DistanceBetweenUnits(tb.caster, tb.target) - BlzGetUnitCollisionSize(tb.caster) - BlzGetUnitCollisionSize(tb.target)
if (dist > tb.minDist) then
set dist = RMinBJ(dist, speed)
set angle = AngleBetweenUnits(tb.target, tb.caster)
set newX = PolarProjectionX(GetUnitX(tb.target), dist, angle)
set newY = PolarProjectionY(GetUnitY(tb.target), dist, angle)
if (IsPointWalkable(newX, newY)) then
call SetUnitX(tb.target, newX)
call SetUnitY(tb.target, newY)
endif
endif
else
call tb.destroy()
call it.destroy()
endif
endfunction
function Trig_Tractor_Beam_Actions takes nothing returns nothing
local TractorBeam tb = CreateTractorBeam(GetSpellAbilityUnit(), GetSpellTargetUnit())
local IntTimer it = CreateIntTimer(tb, false)
call StartIntTimerPeriodic(it, 0.0, TRACTOR_BEAM_UPDATE_INTERVAL, Trig_Tractor_Beam_Update, 0)
endfunction
//===========================================================================
function InitTrig_Tractor_Beam takes nothing returns nothing
set gg_trg_Tractor_Beam = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Tractor_Beam, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Tractor_Beam, Condition( function Trig_Tractor_Beam_Conditions ) )
call TriggerAddAction( gg_trg_Tractor_Beam, function Trig_Tractor_Beam_Actions )
endfunction
globals
constant key KEY_MANA_SHIELD
GatedAbilityTrigger GAT_MANA_SHIELD = 0
endglobals
function Trig_Mana_Shield_Conditions takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
if (not UnitHasAbility(damaged, SB_MANA_SHIELD)) then
return false
elseif (GetEventDamage() <= 0.0) then
return false
endif
return true
endfunction
function Trig_Mana_Shield_Update takes unit whichUnit returns nothing
local real bufferManaRequired = GetUnitAbilityRealLevelField(whichUnit, SB_MANA_SHIELD, ABILITY_RLF_CASTING_TIME)
local real unitMana = GetUnitState(whichUnit, UNIT_STATE_MANA)
local effect manaShieldEffect = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(whichUnit), KEY_MANA_SHIELD)
local boolean remove = false
if (not UnitAlive(whichUnit)) then
set remove = true
elseif (manaShieldEffect != null and unitMana < bufferManaRequired) then
set remove = true
elseif (manaShieldEffect == null and unitMana >= bufferManaRequired) then
set manaShieldEffect = AddSpecialEffectTarget(GetUnitAbilityStringLevelField(whichUnit, SB_MANA_SHIELD, ABILITY_SLF_CASTER), whichUnit, "overhead")
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(whichUnit), KEY_MANA_SHIELD, manaShieldEffect)
endif
if (remove) then
call BlzSetSpecialEffectAlpha(manaShieldEffect, 0)
call DestroyEffect(manaShieldEffect)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(whichUnit), KEY_MANA_SHIELD)
endif
call EnableTrigger(gg_trg_Mana_Shield_Loop)
endfunction
function Trig_Mana_Shield_Actions takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local real damage = GetEventDamage()
local real damageReduction = GetUnitAbilityRealLevelField(damaged, SB_MANA_SHIELD, ABILITY_RLF_CAST_RANGE)
local integer manaPerDamage = GetUnitAbilityIntegerLevelField(damaged, SB_MANA_SHIELD, ABILITY_ILF_MANA_COST)
local real damageReduced = damage * damageReduction
local real cost = damageReduced * manaPerDamage
local real mana = GetUnitState(damaged, UNIT_STATE_MANA)
call BlzSetEventDamage(damage - (damageReduced * RMinBJ(mana / cost, 1.0)))
call ChangeUnitState(damaged, UNIT_STATE_MANA, -cost)
endfunction
//===========================================================================
function InitTrig_Mana_Shield takes nothing returns nothing
set gg_trg_Mana_Shield = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Mana_Shield, EVENT_PLAYER_UNIT_DAMAGING )
call TriggerAddCondition( gg_trg_Mana_Shield, Condition( function Trig_Mana_Shield_Conditions ) )
call TriggerAddAction( gg_trg_Mana_Shield, function Trig_Mana_Shield_Actions )
set GAT_MANA_SHIELD = GateAbilityTriggerAll(gg_trg_Mana_Shield, SB_MANA_SHIELD, SB_TECH_MANA_SHIELD, Trig_Mana_Shield_Update, 0)
endfunction
function Trig_Mana_Shield_Loop_Loop takes nothing returns nothing
local unit picked = GetEnumUnit()
call Trig_Mana_Shield_Update(picked)
endfunction
function Trig_Mana_Shield_Loop_Actions takes nothing returns nothing
local integer count = CountUnitsInGroup(GAT_MANA_SHIELD.abilityUnits)
if (count > 0) then
call ForGroup(GAT_MANA_SHIELD.abilityUnits, function Trig_Mana_Shield_Loop_Loop)
else
call DisableTrigger(GetTriggeringTrigger())
endif
endfunction
//===========================================================================
function InitTrig_Mana_Shield_Loop takes nothing returns nothing
set gg_trg_Mana_Shield_Loop = CreateTrigger( )
call DisableTrigger( gg_trg_Mana_Shield_Loop )
call TriggerRegisterTimerEventPeriodic( gg_trg_Mana_Shield_Loop, 1.00 )
call TriggerAddAction( gg_trg_Mana_Shield_Loop, function Trig_Mana_Shield_Loop_Actions )
endfunction
globals
constant key KEY_WAVEFORM
endglobals
function Trig_Waveform_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_WAVEFORM
endfunction
function Trig_Waveform_Finished takes SimMovement sim returns nothing
local effect vfx = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(sim.mover), KEY_WAVEFORM)
call ResetUnitAnimation(sim.mover)
call SetUnitTimeScale(sim.mover, 1.0)
call SetUnitPosition(sim.mover, GetUnitX(sim.mover), GetUnitY(sim.mover))
call DestroyEffect(vfx)
call RemoveSavedHandle(udg_HashTable_SpecialEffects, GetHandleId(sim.mover), KEY_WAVEFORM)
endfunction
function Trig_Waveform_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real maxDist = GetUnitAbilityRealLevelField(caster, SB_WAVEFORM, ABILITY_RLF_AREA_OF_EFFECT)
local real dist = RMinBJ(maxDist, DistanceBetweenUnitAndPoint(caster, GetSpellTargetX(), GetSpellTargetY()))
local real angle = AngleBetweenPointsXY(GetUnitX(caster), GetUnitY(caster), GetSpellTargetX(), GetSpellTargetY())
local real targetX = PolarProjectionX(GetUnitX(caster), dist, angle)
local real targetY = PolarProjectionY(GetUnitY(caster), dist, angle)
local real speed = GetUnitAbilityIntegerField(caster, GetSpellAbilityId(), ABILITY_IF_MISSILE_SPEED)
local string effectModel = GetUnitAbilityStringLevelField(caster, SB_WAVEFORM, ABILITY_SLF_MISSILE_ART)
local effect vfx = LoadEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(caster), KEY_WAVEFORM)
local SimMovement sim = CreateSimMovement(caster, GetUnitX(caster), GetUnitY(caster), targetX, targetY)
set sim.speed = speed
set sim.onFinish = Trig_Waveform_Finished
set sim.simMoveType = SIM_MOVE_TYPE_SETPOS
if (vfx != null) then
call DestroyEffect(vfx)
endif
set vfx = AddSpecialEffectTarget(effectModel, caster, "chest")
call SaveEffectHandle(udg_HashTable_SpecialEffects, GetHandleId(caster), KEY_WAVEFORM, vfx)
call BlzSetUnitFacingEx(caster, angle)
call SetUnitTimeScale(caster, 5.0)
call SetUnitAnimationByIndexDelayed(caster, 8, 0.001)
call MoveUnitToPointAtSpeedParams(sim)
endfunction
//===========================================================================
function InitTrig_Waveform takes nothing returns nothing
set gg_trg_Waveform = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Waveform, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Waveform, Condition( function Trig_Waveform_Conditions ) )
call TriggerAddAction( gg_trg_Waveform, function Trig_Waveform_Actions )
endfunction
function Trig_Overclock_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_OVERCLOCK and not UnitHasBuffBJ(GetSpellTargetUnit(), SB_BUFF_OVERCLOCK)
endfunction
function Trig_Overclock_Ends takes unit whichUnit returns nothing
call BlzSetUnitMaxHP(whichUnit, BlzGetUnitMaxHP(whichUnit) - 60)
endfunction
function Trig_Overclock_Actions takes nothing returns nothing
local unit target = GetSpellTargetUnit()
call BlzSetUnitMaxHP(target, BlzGetUnitMaxHP(target) + 60)
call SetUnitLifeBJ(target, GetUnitState(target, UNIT_STATE_LIFE) + 60)
call AddBuffEffectWithCallback(target, SB_BUFF_OVERCLOCK, "", "", Trig_Overclock_Ends)
endfunction
//===========================================================================
function InitTrig_Overclock takes nothing returns nothing
set gg_trg_Overclock = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Overclock, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Overclock, Condition( function Trig_Overclock_Conditions ) )
call TriggerAddAction( gg_trg_Overclock, function Trig_Overclock_Actions )
endfunction
globals
constant key KEY_WIND_BARRIER
constant real WIND_BARRIER_DAMAGE_REDUCTION = 0.35
constant integer WIND_BARRIER_MANA_COST_PER_HIT = 2
CustomAura AURA_WIND_BARRIER = 0
endglobals
function WindBarrierTargetFilter takes CustomAuraEmitter emitter returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_STRUCTURE)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function UnitEntersWindBarrier takes unit whichUnit returns nothing
call ChangeUnitAlphaOverTime(whichUnit, 0.5, 0.0, 190)
call SaveBoolean(udg_HashTable_Auras, GetHandleId(whichUnit), KEY_WIND_BARRIER, true)
endfunction
function UnitLeavesWindBarrier takes unit whichUnit returns nothing
call RestoreUnitColorOverTime(whichUnit, 0.5, 0.0)
call RemoveSavedBoolean(udg_HashTable_Auras, GetHandleId(whichUnit), KEY_WIND_BARRIER)
if (AURA_WIND_BARRIER.emitters.count <= 0) then
call DisableTrigger(gg_trg_Wind_Barrier_Damage_Reduction)
endif
endfunction
function Trig_Wind_Barrier_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_WIND_BARRIER
endfunction
function Trig_Wind_Barrier_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real duration = GetUnitAbilityRealLevelField(caster, SB_WIND_BARRIER, ABILITY_RLF_DURATION_NORMAL)
local real aoe = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_AREA_OF_EFFECT)
local unit emitter = CreateUnit(GetOwningPlayer(caster), SB_SPECIAL_EFFECT_UNIT_WIND_BARRIER, GetSpellTargetX(), GetSpellTargetY(), bj_UNIT_FACING)
call CustomAuras_AddEmitter(emitter, AURA_WIND_BARRIER, aoe)
call SetUnitScale(emitter, aoe / 600.0, aoe / 600.0, aoe / 600.0)
call UnitApplyTimedLife(emitter, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call EnableTrigger(gg_trg_Wind_Barrier_Damage_Reduction)
endfunction
//===========================================================================
function InitTrig_Wind_Barrier takes nothing returns nothing
set gg_trg_Wind_Barrier = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wind_Barrier, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Wind_Barrier, Condition( function Trig_Wind_Barrier_Conditions ) )
call TriggerAddAction( gg_trg_Wind_Barrier, function Trig_Wind_Barrier_Actions )
set AURA_WIND_BARRIER = CustomAuras_CreateCustomAura(0.25, UnitEntersWindBarrier, UnitLeavesWindBarrier, WindBarrierTargetFilter, 0, 0)
endfunction
function Trig_Wind_Barrier_Damage_Reduction_Conditions takes nothing returns boolean
local unit damaged = BlzGetEventDamageTarget()
if (not HaveSavedBoolean(udg_HashTable_Auras, GetHandleId(damaged), KEY_WIND_BARRIER)) then
return false
elseif (GetEventDamage() <= 0.0) then
return false
elseif (BlzGetEventAttackType() != ATTACK_TYPE_PIERCE) then
return false
endif
return true
endfunction
function Trig_Wind_Barrier_Damage_Reduction_Actions takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local real damage = GetEventDamage()
call BlzSetEventDamage(damage * (1.0 - WIND_BARRIER_DAMAGE_REDUCTION))
call AddSpecialEffectTargetOneShot("Abilities\\Weapons\\SorceressMissile\\SorceressMissile.mdl", damaged, "chest")
endfunction
//===========================================================================
function InitTrig_Wind_Barrier_Damage_Reduction takes nothing returns nothing
set gg_trg_Wind_Barrier_Damage_Reduction = CreateTrigger( )
call DisableTrigger( gg_trg_Wind_Barrier_Damage_Reduction )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wind_Barrier_Damage_Reduction, EVENT_PLAYER_UNIT_DAMAGING )
call TriggerAddCondition( gg_trg_Wind_Barrier_Damage_Reduction, Condition( function Trig_Wind_Barrier_Damage_Reduction_Conditions ) )
call TriggerAddAction( gg_trg_Wind_Barrier_Damage_Reduction, function Trig_Wind_Barrier_Damage_Reduction_Actions )
endfunction
struct Meteor
unit caster = null
real targetX = 0.0
real targetY = 0.0
real aoe = 0.0
real damage = 0.0
real buildingDamageFactor = 0.0
effect targetingEffect = null
method onDestroy takes nothing returns nothing
call DestroyEffect(targetingEffect)
endmethod
endstruct
function CreateMeteor takes unit caster, real x, real y returns Meteor
local string targetModel = GetUnitAbilityStringLevelField(caster, SB_METEOR, ABILITY_SLF_TARGET)
local Meteor m = Meteor.create()
set m.caster = caster
set m.targetX = x
set m.targetY = y
set m.aoe = GetUnitAbilityRealLevelField(caster, SB_METEOR, ABILITY_RLF_AREA_OF_EFFECT)
set m.damage = GetUnitAbilityRealLevelField(caster, SB_METEOR, ABILITY_RLF_FULL_DAMAGE_DEALT)
set m.buildingDamageFactor = GetUnitAbilityRealLevelField(caster, SB_METEOR, ABILITY_RLF_BUILDING_REDUCTION_HFS5)
set m.targetingEffect = AddSpecialEffect(targetModel, x, y)
call BlzSetSpecialEffectScale(m.targetingEffect, m.aoe / 120.0)
return m
endfunction
globals
constant key KEY_METEOR
endglobals
function Trig_Meteor_Begin_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_METEOR
endfunction
function Trig_Meteor_Begin_Actions takes nothing returns nothing
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local Meteor meteor = CreateMeteor(GetSpellAbilityUnit(), x, y)
call PlaySoundAtPositionSB("Abilities\\Spells\\NightElf\\Starfall\\StarfallCaster1.flac", "SpellsEAX", AUDIO_CHANNEL_ANIMATIONS, x, y, 127.0)
call SaveInteger(udg_HashTable_TargetToCaster, GetHandleId(GetSpellAbilityUnit()), KEY_METEOR, meteor)
endfunction
//===========================================================================
function InitTrig_Meteor_Begin takes nothing returns nothing
set gg_trg_Meteor_Begin = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Meteor_Begin, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
call TriggerAddCondition( gg_trg_Meteor_Begin, Condition( function Trig_Meteor_Begin_Conditions ) )
call TriggerAddAction( gg_trg_Meteor_Begin, function Trig_Meteor_Begin_Actions )
endfunction
function Trig_Meteor_Cancel_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_METEOR
endfunction
function Trig_Meteor_Cancel_Actions takes nothing returns nothing
local Meteor meteor = LoadInteger(udg_HashTable_TargetToCaster, GetHandleId(GetSpellAbilityUnit()), KEY_METEOR)
call RemoveSavedHandle(udg_HashTable_TargetToCaster, GetHandleId(GetSpellAbilityUnit()), KEY_METEOR)
call meteor.destroy()
endfunction
//===========================================================================
function InitTrig_Meteor_Cancel takes nothing returns nothing
set gg_trg_Meteor_Cancel = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Meteor_Cancel, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition( gg_trg_Meteor_Cancel, Condition( function Trig_Meteor_Cancel_Conditions ) )
call TriggerAddAction( gg_trg_Meteor_Cancel, function Trig_Meteor_Cancel_Actions )
endfunction
function Trig_Meteor_Finish_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_METEOR
endfunction
function Trig_Meteor_Hit_Filter takes Meteor meteor returns boolean
local unit filter = GetFilterUnit()
if (not UnitAlive(filter)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_FLYING)) then
return false
elseif (IsUnitType(filter, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
elseif (BlzIsUnitInvulnerable(filter)) then
return false
elseif (IsUnitWard(filter)) then
return false
endif
return true
endfunction
function Trig_Meteor_Hit takes IntTimer it returns nothing
local Meteor meteor = it.owner
local string hitEffect = GetUnitAbilityStringLevelField(meteor.caster, SB_METEOR, ABILITY_SLF_AREA_EFFECT)
local group hit = GetUnitsInAOEInt(meteor.targetX, meteor.targetY, meteor.aoe, Trig_Meteor_Hit_Filter, meteor)
local unit picked = null
loop
set picked = FirstOfGroup(hit)
exitwhen picked == null
if (IsUnitType(picked, UNIT_TYPE_STRUCTURE)) then
call UnitDamageTargetBJ(meteor.caster, picked, meteor.damage * meteor.buildingDamageFactor, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC)
else
call UnitDamageTargetBJ(meteor.caster, picked, meteor.damage, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC)
endif
call GroupRemoveUnit(hit, picked)
endloop
call TerrainDeformCrater(meteor.targetX, meteor.targetY, meteor.aoe, 15.0, 50, true)
call AddSpecialEffectOneShot(hitEffect, meteor.targetX, meteor.targetY)
call DestroyGroup(hit)
call meteor.destroy()
endfunction
function Trig_Meteor_Finish_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local string effectModel = GetUnitAbilityStringLevelField(caster, GetSpellAbilityId(), ABILITY_SLF_MISSILE_ART)
local real delay = GetUnitAbilityRealLevelField(caster, GetSpellAbilityId(), ABILITY_RLF_FULL_DAMAGE_INTERVAL)
local Meteor meteor = LoadInteger(udg_HashTable_TargetToCaster, GetHandleId(caster), KEY_METEOR)
local IntTimer delayTimer = CreateIntTimer(meteor, true)
local effect vfx = AddSpecialEffect(effectModel, meteor.targetX, meteor.targetY)
call StartTimerPlus(delayTimer, delay, Trig_Meteor_Hit)
call BlzSetSpecialEffectScale(vfx, 2.0)
call BlzSetSpecialEffectTimeScale(vfx, DBZ(0.77, delay, 1.0))
call DestroyEffect(vfx)
endfunction
//===========================================================================
function InitTrig_Meteor_Finish takes nothing returns nothing
set gg_trg_Meteor_Finish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Meteor_Finish, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Meteor_Finish, Condition( function Trig_Meteor_Finish_Conditions ) )
call TriggerAddAction( gg_trg_Meteor_Finish, function Trig_Meteor_Finish_Actions )
endfunction
function Trig_Oust_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_OUST
endfunction
function Trig_Oust_TownHallFilter takes nothing returns boolean
local unit filter = GetFilterUnit()
return UnitAlive(filter) and IsUnitType(filter, UNIT_TYPE_TOWNHALL)
endfunction
function Trig_Oust_BuildingFilter takes nothing returns boolean
local unit filter = GetFilterUnit()
return UnitAlive(filter) and IsUnitType(filter, UNIT_TYPE_STRUCTURE)
endfunction
function Trig_Oust_AfterDelay takes unit target returns nothing
local boolexpr townHallFilter = Condition(function Trig_Oust_TownHallFilter)
local boolexpr buildingFilter = null
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local real angle = 0.0
local real dist = 0.0
local group townHalls = GetUnitsOfPlayerMatching(GetOwningPlayer(target), townHallFilter)
local unit furthest = GroupPickFurthestUnit(townHalls, x, y)
if (furthest == null) then
set buildingFilter = Condition(function Trig_Oust_BuildingFilter)
call GroupEnumUnitsOfPlayer(townHalls, GetOwningPlayer(target), buildingFilter)
set furthest = GroupPickFurthestUnit(townHalls, x, y)
call DestroyBoolExpr(buildingFilter)
endif
if (furthest != null) then
set dist = BlzGetUnitCollisionSize(target) + BlzGetUnitCollisionSize(furthest) + 10.0
set angle = AngleBetweenUnits(furthest, target)
call AddSpecialEffectOneShot("war3mapImported\\Void Teleport Caster.mdx", x, y)
set x = PolarProjectionX(GetUnitX(furthest), dist, angle)
set y = PolarProjectionY(GetUnitY(furthest), dist, angle)
call SetUnitPosition(target, x, y)
call AddSpecialEffectTargetOneShot("war3mapImported\\Void Teleport To.mdx", target, "origin")
endif
call DestroyBoolExpr(townHallFilter)
call DestroyGroup(townHalls)
endfunction
function Trig_Oust_Actions takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
call AddBuffEffectWithCallback(target, SB_BUFF_OUST, "", "", Trig_Oust_AfterDelay)
endfunction
//===========================================================================
function InitTrig_Oust takes nothing returns nothing
set gg_trg_Oust = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Oust, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Oust, Condition( function Trig_Oust_Conditions ) )
call TriggerAddAction( gg_trg_Oust, function Trig_Oust_Actions )
endfunction
scope TakeForm
globals
private constant hashtable HT_TAKE_FORM = InitHashtable()
private constant real TAKE_FORM_UPDATE_INTERVAL = 0.01
private constant real TAKE_FORM_SCALE_FACTOR = 0.03
endglobals
struct TakeForm
unit changeling = null
unit controlDummy = null
trigger damagingTrigger = null
trigger orderTrigger = null
IntTimer update = 0
method onDestroy takes nothing returns nothing
call DestroyTrigger(damagingTrigger)
call DestroyTrigger(orderTrigger)
call RemoveSavedHandle(HT_TAKE_FORM, GetHandleId(changeling), 0)
call RemoveSavedHandle(HT_TAKE_FORM, GetHandleId(controlDummy), 0)
call update.destroy()
endmethod
endstruct
private function TakeFormOnDamagingActions takes nothing returns nothing
local unit damaging = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
local TakeForm tf = LoadInteger(HT_TAKE_FORM, GetHandleId(damaging), 0)
if (tf != 0) then
call BlzSetEventDamage(0.0)
else
set tf = LoadInteger(HT_TAKE_FORM, GetHandleId(damaged), 0)
if (tf != 0) then
call BlzSetEventDamage(GetEventDamage() * 2.0)
endif
endif
endfunction
private function TakeFormUpdate takes IntTimer it returns nothing
local TakeForm tf = it.owner
if (UnitAlive(tf.changeling) and UnitAlive(tf.controlDummy)) then
call SetUnitPathingSB(tf.controlDummy, false)
call SetUnitX(tf.controlDummy, GetUnitX(tf.changeling))
call SetUnitY(tf.controlDummy, GetUnitY(tf.changeling))
else
call KillUnit(tf.changeling)
call KillUnit(tf.controlDummy)
call tf.destroy()
endif
endfunction
private function TakeFormOrderConditions takes nothing returns boolean
return GetIssuedOrderId() != SB_ORDER_STUNNED
endfunction
private function TakeFormOrderActions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local TakeForm tf = LoadInteger(HT_TAKE_FORM, GetHandleId(ordered), 0)
if (tf != 0) then
if (GetOrderTarget() != null) then
call IssueTargetOrderById(tf.changeling, GetIssuedOrderId(), GetOrderTarget())
elseif (GetOrderPointX() != 0.0 and GetOrderPointY() != 0.0) then
call IssuePointOrderById(tf.changeling, GetIssuedOrderId(), GetOrderPointX(), GetOrderPointY())
else
call IssueImmediateOrderById(tf.changeling, GetIssuedOrderId())
endif
call BlzUnitClearOrders(ordered, false)
endif
endfunction
function CreateTakeForm takes unit caster, unit target returns TakeForm
local player p = GetOwningPlayer(caster)
local real duration = GetUnitAbilityRealLevelField(caster, SB_TAKE_FORM, ABILITY_RLF_AREA_OF_EFFECT)
local TakeForm tf = TakeForm.create()
set tf.changeling = ReplaceUnitBJ(caster, GetUnitTypeId(target), bj_UNIT_STATE_METHOD_DEFAULTS)
set tf.damagingTrigger = CreateTrigger()
set tf.orderTrigger = CreateTrigger()
set tf.update = CreateIntTimer(tf, false)
call SetUnitOwner(tf.changeling, GetOwningPlayer(target), true)
call UnitShareVision(tf.changeling, p, true)
if (GetLocalPlayer() == p) then
call SetUnitVertexColor(tf.changeling, 0, 0, 200, 200)
endif
set tf.controlDummy = CreateUnit(p, SB_CHANGELING_CONTROL_DUMMY, GetUnitX(tf.changeling), GetUnitY(tf.changeling), GetUnitFacing(tf.changeling))
call ChangeUnitSizeOverTime(tf.controlDummy, 0.5, TAKE_FORM_SCALE_FACTOR * BlzGetUnitCollisionSize(tf.changeling))
call SetUnitPathingSB(tf.controlDummy, false)
call UnitApplyTimedLife(tf.controlDummy, SB_BUFF_TIMED_LIFE_GENERIC, duration)
call TriggerAddAction(tf.damagingTrigger, function TakeFormOnDamagingActions)
call TriggerRegisterUnitEvent(tf.damagingTrigger, tf.changeling, EVENT_UNIT_DAMAGING)
call TriggerAddCondition(tf.orderTrigger, Condition(function TakeFormOrderConditions))
call TriggerAddAction(tf.orderTrigger, function TakeFormOrderActions)
call TriggerRegisterUnitEvent(tf.orderTrigger, tf.controlDummy, EVENT_UNIT_ISSUED_ORDER)
call TriggerRegisterUnitEvent(tf.orderTrigger, tf.controlDummy, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(tf.orderTrigger, tf.controlDummy, EVENT_UNIT_ISSUED_TARGET_ORDER)
call StartIntTimerPeriodic(tf.update, 0.0, TAKE_FORM_UPDATE_INTERVAL, TakeFormUpdate, 0)
call SaveInteger(HT_TAKE_FORM, GetHandleId(tf.changeling), 0, tf)
call SaveInteger(HT_TAKE_FORM, GetHandleId(tf.controlDummy), 0, tf)
return tf
endfunction
endscope
function Trig_Take_Form_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_TAKE_FORM
endfunction
function Trig_Take_Form_Actions takes nothing returns nothing
local TakeForm tf = CreateTakeForm(GetSpellAbilityUnit(), GetSpellTargetUnit())
endfunction
//===========================================================================
function InitTrig_Take_Form takes nothing returns nothing
set gg_trg_Take_Form = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Take_Form, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Take_Form, Condition( function Trig_Take_Form_Conditions ) )
call TriggerAddAction( gg_trg_Take_Form, function Trig_Take_Form_Actions )
endfunction
scope ThreeWishes initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant integer ABILITY_WISH = 'A02R'
private constant integer LEVEL_POWER = 0
private constant integer LEVEL_WEALTH = 1
private constant integer LEVEL_LIFE = 2
private constant integer array BUFFS
private constant integer BUFF_COUNT = 3
private LinkedList_Int RANDOM_CONTAINER = 0
endglobals
private struct Wealth
unit host = null
real resourceRate = 0.0
string deathArt = null
IntTimer it = 0
method onDestroy takes nothing returns nothing
call RemoveSavedInteger(HT, GetHandleId(host), 0)
call it.destroy()
set host = null
set deathArt = null
endmethod
endstruct
private function UpdateWealth takes IntTimer it returns nothing
local Wealth w = it.owner
local player p = GetOwningPlayer(w.host)
local integer gold = 0
local integer lumber = 0
local integer unitTypeId = 0
local texttag tt = null
local real zOffset = 0.0
if (not UnitAlive(w.host)) then
set unitTypeId = GetUnitTypeId(w.host)
set gold = R2I(GetUnitGoldCost(unitTypeId) * w.resourceRate + 0.5)
set lumber = R2I(GetUnitWoodCost(unitTypeId) * w.resourceRate + 0.5)
call AddSpecialEffectTargetOneShot(w.deathArt, w.host, "origin")
if (lumber > 0) then
set tt = FloatTextAboveUnitForPlayer(w.host, p, "+" + I2S(lumber), 10.0, 0.0, 0.0, 0.78, 0.31, 1.0)
call SetFloatingTextMovement(tt, 2.0, 1.0, 0.0, 54.0)
call AdjustPlayerStateBJ(lumber, p, PLAYER_STATE_RESOURCE_LUMBER)
set zOffset = 80.0
endif
if (gold > 0) then
set tt = FloatTextAboveUnitForPlayer(w.host, p, "+" + I2S(gold), 10.0, zOffset, 1.0, 0.86, 0.0, 1.0)
call SetFloatingTextMovement(tt, 2.0, 1.0, 0.0, 54.0)
call AdjustPlayerStateBJ(gold, p, PLAYER_STATE_RESOURCE_GOLD)
endif
call w.destroy()
elseif (not UnitHasBuffBJ(w.host, BUFFS[LEVEL_WEALTH])) then
call w.destroy()
endif
endfunction
private function OnWishDelayed takes UnitTimer ut returns nothing
local unit caster = ut.owner
local integer level = GetRandomInt(1, GetUnitAbilityIntegerField(caster, ABILITY_WISH, ABILITY_IF_LEVELS))
call SetUnitAbilityLevel(caster, ABILITY_WISH, level)
endfunction
private function OnWish takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local UnitTimer ut = CreateUnitTimer(caster, true)
local Wealth w = 0
call StartTimerPlus(ut, 0.01, OnWishDelayed)
if (GetUnitAbilityLevel(caster, GetSpellAbilityId()) == LEVEL_WEALTH + 1) then
set w = LoadInteger(HT, GetHandleId(target), 0)
if (w == 0) then
set w = Wealth.create()
set w.host = GetSpellTargetUnit()
set w.resourceRate = BlzGetAbilityRealLevelField(GetSpellAbility(), ABILITY_RLF_AREA_OF_EFFECT, LEVEL_WEALTH)
set w.deathArt = BlzGetAbilityStringLevelField(GetSpellAbility(), ABILITY_SLF_SPECIAL, LEVEL_WEALTH)
set w.it = CreateIntTimer(w, false)
call SaveInteger(HT, GetHandleId(target), 0, w)
endif
call StartTimerPlusPeriodic(w.it, 0.0, 0.25, UpdateWealth, 0)
endif
endfunction
private function IsWishOrder takes nothing returns boolean
local unit ordered = GetOrderedUnit()
return UnitHasAbility(ordered, ABILITY_WISH) and GetIssuedOrderId() == SB_ORDER_WISH
endfunction
private function OnWishOrder takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local unit target = GetOrderTargetUnit()
local integer i = 0
local LinkedListNode_Int node = 0
loop
exitwhen i >= BUFF_COUNT
if (GetUnitAbilityLevel(target, BUFFS[i]) == 0) then
call LinkedListAddLastInt(RANDOM_CONTAINER, i + 1)
endif
set i = i + 1
endloop
if (RANDOM_CONTAINER.count > 0) then
set i = GetRandomInt(0, RANDOM_CONTAINER.count - 1)
set node = LinkedListGetAtIndex(RANDOM_CONTAINER, i)
call SetUnitAbilityLevel(ordered, ABILITY_WISH, node.value)
loop
exitwhen RANDOM_CONTAINER.count <= 0
call LinkedListDestroyFirst(RANDOM_CONTAINER)
endloop
endif
endfunction
private function Init takes nothing returns nothing
set RANDOM_CONTAINER = CreateLinkedList_Int()
set BUFFS[LEVEL_POWER] = 'B01R'
set BUFFS[LEVEL_WEALTH] = 'B01V'
set BUFFS[LEVEL_LIFE] = 'B01O'
call CreateAnyUnitTrigger(EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER, function IsWishOrder, function OnWishOrder)
call CreateSpellEffectTrigger(ABILITY_WISH, function OnWish)
endfunction
endscope
scope HurlBoulder initializer Init
globals
private constant integer ABILITY_HURL_BOULDER = 'Amhb'
private constant integer ABILITY_DUMMY_CAST = 'dchb'
endglobals
private function OnHurlBoulder takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
call DummyCastUnit(GetOwningPlayer(caster), target, GetUnitX(caster), GetUnitY(caster), ABILITY_DUMMY_CAST, "creepthunderbolt")
endfunction
private function Init takes nothing returns nothing
call CreateSpellEffectTrigger(ABILITY_HURL_BOULDER, function OnHurlBoulder)
endfunction
endscope
scope MagicStructure initializer Init
globals
private constant hashtable HT = InitHashtable()
private constant integer ABILITY_MAGIC_STRUCTURE = 'Abld'
private constant string BUILD_EFFECT_ART = "war3mapImported\\SBArcaneBirth.MDX"
private constant string DEATH_EFFECT_ART = "war3mapImported\\SBArcaneDeath.MDX"
endglobals
struct MagicConstruction
unit whichUnit = null
effect specialEffect = null
real damageTaken = 0.0
real lastConstructionPct = 0.0
trigger damageTrigger = null
IntTimer updateTimer = 0
method onDestroy takes nothing returns nothing
call SetUnitVertexColor(whichUnit, 255, 255, 255, 255)
call updateTimer.destroy()
call RemoveSavedInteger(HT, GetHandleId(whichUnit), 0)
call BlzSetSpecialEffectTimeScale(specialEffect, 10000.0)
call DestroyEffect(specialEffect)
call DestroyTrigger(damageTrigger)
endmethod
endstruct
private function UpdateMagicBuild takes IntTimer it returns nothing
local MagicConstruction mc = it.owner
local unit whichUnit = mc.whichUnit
local real maxHp = BlzGetUnitMaxHP(whichUnit)
local real currentHp = GetUnitState(whichUnit, UNIT_STATE_LIFE)
local real virtualHp = 0.0
local real constructionPct = 0.0
local integer color = 0
if (UnitAlive(whichUnit)) then
set virtualHp = currentHp + mc.damageTaken - maxHp * 0.1
set constructionPct = DBZ(virtualHp, maxHp * 0.9, 1.0)
if (constructionPct < 1.0) then
set color = IMin(R2I((255.0 * EaseIn(constructionPct, 2.0)) + 0.5), 255)
call SetUnitVertexColor(whichUnit, color, color, 255, color)
if (constructionPct > mc.lastConstructionPct) then
call BlzSetSpecialEffectTimeScale(mc.specialEffect, DBZ(60.0, GetUnitBuildTime(GetUnitTypeId(whichUnit)), 1.0))
else
call BlzSetSpecialEffectTimeScale(mc.specialEffect, 0.0)
endif
else
call mc.destroy()
endif
set mc.lastConstructionPct = constructionPct
else
call mc.destroy()
endif
endfunction
private function OnUnitDamaged takes nothing returns nothing
local unit damaged = BlzGetEventDamageTarget()
local MagicConstruction mc = LoadInteger(HT, GetHandleId(damaged), 0)
local real amount = GetEventDamage()
if (mc != 0) then
set mc.damageTaken = mc.damageTaken + amount
else
call DestroyTrigger(GetTriggeringTrigger())
endif
endfunction
private function TriggerUnitIsMagicStructure takes nothing returns boolean
return GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_MAGIC_STRUCTURE) > 0
endfunction
private function OnConstruction takes nothing returns nothing
local unit structure = GetConstructingStructure()
local MagicConstruction mc = MagicConstruction.create()
local real buildTime = GetUnitBuildTime(GetUnitTypeId(structure))
local real collisionSize = BlzGetUnitCollisionSize(structure)
set mc.whichUnit = structure
set mc.specialEffect = AddSpecialEffect(BUILD_EFFECT_ART, GetUnitX(structure), GetUnitY(structure))
set mc.updateTimer = CreateIntTimer(mc, false)
set mc.damageTrigger = CreateTrigger()
call BlzSetSpecialEffectTimeScale(mc.specialEffect, DBZ(60.0, buildTime, 1.0))
call BlzSetSpecialEffectScale(mc.specialEffect, collisionSize / 144.0)
call TriggerRegisterUnitEvent(mc.damageTrigger, structure, EVENT_UNIT_DAMAGED)
call TriggerAddAction(mc.damageTrigger, function OnUnitDamaged)
call SetUnitVertexColor(structure, 0, 0, 0, 0)
call SaveInteger(HT, GetHandleId(structure), 0, mc)
call StartTimerPlusPeriodic(mc.updateTimer, 0.0, 0.01, UpdateMagicBuild, 0)
endfunction
private function OnConstructionDone takes nothing returns nothing
local unit structure = GetConstructedStructure()
local MagicConstruction mc = LoadInteger(HT, GetHandleId(structure), 0)
if (mc != 0) then
call mc.destroy()
endif
endfunction
private function OnDeath takes nothing returns nothing
local unit dying = GetDyingUnit()
local real collisionSize = BlzGetUnitCollisionSize(dying)
local MagicConstruction mc = LoadInteger(HT, GetHandleId(dying), 0)
if (mc != 0) then
call mc.destroy()
endif
call AddSpecialEffectOneShotEx(DEATH_EFFECT_ART, GetUnitX(dying), GetUnitY(dying), 20.0, DBZ(collisionSize, 64.0, 1.0), 1.0)
call SetUnitTimeScale(dying, 10000.0)
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_START)
call TriggerAddCondition(t, Condition(function TriggerUnitIsMagicStructure))
call TriggerAddAction(t, function OnConstruction)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(t, Condition(function TriggerUnitIsMagicStructure))
call TriggerAddAction(t, function OnConstructionDone)
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function TriggerUnitIsMagicStructure))
call TriggerAddAction(t, function OnDeath)
endfunction
endscope
scope ShaperAnimations initializer Init
private function IsAttackOrder takes nothing returns boolean
local unit targetUnit = GetOrderTargetUnit()
local integer orderId = GetIssuedOrderId()
if (orderId == SB_ORDER_ATTACK) then
return true
elseif (orderId == SB_ORDER_SMART and targetUnit != null) then
return IsUnitEnemy(targetUnit, GetOwningPlayer(GetOrderedUnit()))
endif
return false
endfunction
private function IsShaper takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == SB_SHAPER or GetUnitTypeId(GetTriggerUnit()) == SB_SHAPELING
endfunction
private function OnOrder takes nothing returns nothing
local unit ordered = GetOrderedUnit()
call AddUnitAnimationProperties(ordered, "alternate", IsAttackOrder())
endfunction
private function Init takes nothing returns nothing
local trigger t = null
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(t, Condition(function IsShaper))
call TriggerAddAction(t, function OnOrder)
endfunction
endscope
function IsMagicHall takes unit whichUnit returns boolean
local integer unitTypeId = GetUnitTypeId(whichUnit)
return unitTypeId == SB_MAGIC_HALL or unitTypeId == SB_MAGIC_HALL_2
endfunction
function UpdateTinkerLimitFilter takes nothing returns boolean
return IsMagicHall(GetFilterUnit())
endfunction
function UpdateTinkerLimit takes player p returns integer
local boolexpr filter = Condition(function UpdateTinkerLimitFilter)
local integer hallCount = 0
local group halls = GetUnitsOfPlayerMatching(p, filter)
local unit picked = null
loop
set picked = FirstOfGroup(halls)
exitwhen picked == null
if (UnitAlive(picked) and not (GetUnitTypeId(picked) == SB_MAGIC_HALL and IsUnitInGroup(picked, udg_UnitGroup_UnderConstruction))) then
set hallCount = hallCount + 1
endif
call GroupRemoveUnit(halls, picked)
endloop
call SetPlayerTechMaxAllowed(p, SB_SHAPER, hallCount)
call DestroyGroup(halls)
call DestroyBoolExpr(filter)
return hallCount
endfunction
function Trig_Tinker_Limit_Init_Loop takes nothing returns nothing
call UpdateTinkerLimit(GetEnumPlayer())
endfunction
function Trig_Shaper_Limit_Init_Actions takes nothing returns nothing
local force players = GetPlayingPlayers(false, true, true)
call ForForce(players, function Trig_Tinker_Limit_Init_Loop)
call DestroyForce(players)
endfunction
//===========================================================================
function InitTrig_Shaper_Limit_Init takes nothing returns nothing
set gg_trg_Shaper_Limit_Init = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Shaper_Limit_Init, 0.00 )
call TriggerAddAction( gg_trg_Shaper_Limit_Init, function Trig_Shaper_Limit_Init_Actions )
endfunction
function Trig_Shaper_Limit_Enter_Conditions takes nothing returns boolean
return IsMagicHall(GetEnteringUnit())
endfunction
function Trig_Shaper_Limit_Enter_Actions takes nothing returns nothing
call UpdateTinkerLimit(GetOwningPlayer(GetEnteringUnit()))
endfunction
//===========================================================================
function InitTrig_Shaper_Limit_Enter takes nothing returns nothing
set gg_trg_Shaper_Limit_Enter = CreateTrigger( )
call TriggerRegisterEnterRectSimple( gg_trg_Shaper_Limit_Enter, GetEntireMapRect() )
call TriggerAddCondition( gg_trg_Shaper_Limit_Enter, Condition( function Trig_Shaper_Limit_Enter_Conditions ) )
call TriggerAddAction( gg_trg_Shaper_Limit_Enter, function Trig_Shaper_Limit_Enter_Actions )
endfunction
function Trig_Shaper_Limit_Construction_Conditions takes nothing returns boolean
return IsMagicHall(GetConstructedStructure())
endfunction
function Trig_Shaper_Limit_Construction_Actions takes nothing returns nothing
call UpdateTinkerLimit(GetOwningPlayer(GetConstructedStructure()))
endfunction
//===========================================================================
function InitTrig_Shaper_Limit_Construction takes nothing returns nothing
set gg_trg_Shaper_Limit_Construction = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(gg_trg_Shaper_Limit_Construction, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition( gg_trg_Shaper_Limit_Construction, Condition( function Trig_Shaper_Limit_Construction_Conditions ) )
call TriggerAddAction( gg_trg_Shaper_Limit_Construction, function Trig_Shaper_Limit_Construction_Actions )
endfunction
function Trig_Shaper_Limit_Leave_Conditions takes nothing returns boolean
return IsMagicHall(GetTriggerUnit())
endfunction
function Trig_Shaper_Limit_Leave_Actions takes nothing returns nothing
call UpdateTinkerLimit(GetOwningPlayer(GetTriggerUnit()))
endfunction
//===========================================================================
function InitTrig_Shaper_Limit_Leave takes nothing returns nothing
set gg_trg_Shaper_Limit_Leave = CreateTrigger( )
call TriggerRegisterLeaveRectSimple( gg_trg_Shaper_Limit_Leave, GetPlayableMapRect() )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Shaper_Limit_Leave, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Shaper_Limit_Leave, Condition( function Trig_Shaper_Limit_Leave_Conditions ) )
call TriggerAddAction( gg_trg_Shaper_Limit_Leave, function Trig_Shaper_Limit_Leave_Actions )
endfunction
globals
constant key KEY_UNIT_SELL_UNITS
constant key KEY_UNIT_SELL_UNITS_WORKER
endglobals
function Trig_Unit_Sell_Units_Orders_Conditions takes nothing returns boolean
return UnitHasAbility(GetOrderedUnit(), SB_UNIT_SELL_UNITS)
endfunction
function Trig_Unit_Sell_Units_Orders_Actions takes nothing returns nothing
local unit ordered = GetOrderedUnit()
local widget target = GetOrderTarget()
local integer orderId = GetIssuedOrderId()
local SavedOrder order = 0
local SavedOrder workerOrder = 0
if (target != null) then
set order = CreateSavedTargetOrder(orderId, target)
if (orderId != String2OrderIdBJ("resumeharvesting")) then
set workerOrder = CreateSavedTargetOrder(orderId, target)
endif
else
set order = CreateSavedPointOrder(orderId, GetOrderPointX(), GetOrderPointY())
set workerOrder = CreateSavedPointOrder(orderId, GetOrderPointX(), GetOrderPointY())
endif
call SaveInteger(udg_HashTable_Orders, GetHandleId(ordered), KEY_UNIT_SELL_UNITS, order)
if (workerOrder != 0) then
call SaveInteger(udg_HashTable_Orders, GetHandleId(ordered), KEY_UNIT_SELL_UNITS_WORKER, workerOrder)
endif
endfunction
//===========================================================================
function InitTrig_Unit_Sell_Units_Orders takes nothing returns nothing
set gg_trg_Unit_Sell_Units_Orders = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Sell_Units_Orders, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Sell_Units_Orders, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerAddCondition( gg_trg_Unit_Sell_Units_Orders, Condition( function Trig_Unit_Sell_Units_Orders_Conditions ) )
call TriggerAddAction( gg_trg_Unit_Sell_Units_Orders, function Trig_Unit_Sell_Units_Orders_Actions )
endfunction
function Trig_Unit_Sell_Units_Sell_Conditions takes nothing returns boolean
return UnitHasAbility(GetSellingUnit(), SB_UNIT_SELL_UNITS) and GetUnitCurrentOrder(GetSellingUnit()) != 0
endfunction
function Trig_Unit_Sell_Units_Sell_Actions takes nothing returns nothing
local unit selling = GetSellingUnit()
local unit sold = GetSoldUnit()
local real distance = GetUnitAbilityRealLevelField(selling, SB_UNIT_SELL_UNITS, ABILITY_RLF_CAST_RANGE)
local real time = GetUnitAbilityRealLevelField(selling, SB_UNIT_SELL_UNITS, ABILITY_RLF_CASTING_TIME)
local real speed = distance / time
local real angle = 0.0
local SavedOrder lastOrder = LoadInteger(udg_HashTable_Orders, GetHandleId(selling), KEY_UNIT_SELL_UNITS)
local SavedOrder workerOrder = LoadInteger(udg_HashTable_Orders, GetHandleId(selling), KEY_UNIT_SELL_UNITS_WORKER)
call IssueImmediateOrder(selling, "stop")
if (lastOrder != 0) then
call IssueSavedOrderDelayed.execute(selling, lastOrder, 0.001)
endif
if (workerOrder != 0 and lastOrder != 0 and lastOrder.orderId == workerOrder.orderId) then
call IssueSavedOrder(sold, workerOrder)
//if (workerOrder.orderType != ORDER_TYPE_IMMEDIATE) then
// set angle = AngleBetweenPointsXY(GetUnitX(sold), GetUnitY(sold), GetSavedOrderTargetX(workerOrder), GetSavedOrderTargetY(workerOrder))
//set distance = RMinBJ(distance, DistanceBetweenPointsXY(GetUnitX(selling), GetUnitY(selling), GetSavedOrderTargetX(workerOrder), GetSavedOrderTargetY(workerOrder)))
//if (distance > 0.0) then
// call SetUnitX(sold, GetUnitX(sold))
//call SetUnitY(sold, GetUnitY(sold))
//call MoveUnitToPointAtSpeedXY(sold, PolarProjectionX(GetUnitX(sold), distance, angle), PolarProjectionY(GetUnitY(sold), distance, angle), speed)
//endif
//endif
endif
call SetUnitAnimation(selling, "spell")
//call QueueUnitAnimation(selling, "stand")
endfunction
//===========================================================================
function InitTrig_Unit_Sell_Units_Sell takes nothing returns nothing
set gg_trg_Unit_Sell_Units_Sell = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Unit_Sell_Units_Sell, EVENT_PLAYER_UNIT_SELL )
call TriggerAddCondition( gg_trg_Unit_Sell_Units_Sell, Condition( function Trig_Unit_Sell_Units_Sell_Conditions ) )
call TriggerAddAction( gg_trg_Unit_Sell_Units_Sell, function Trig_Unit_Sell_Units_Sell_Actions )
endfunction
function StartNatureAIForPlayer takes player p returns nothing
call EnableTrigger(gg_trg_AI_Treeherd_Sapling_Mine)
call StartMeleeAI(p, "war3mapImported/SBNatureAI.ai" )
endfunction
function Trig_AI_Treeherd_Sapling_Mine_Conditions takes nothing returns boolean
if (GetUnitTypeId(GetTriggerUnit()) != SB_DENDROID_TREEHERD) then
return false
elseif (GetPlayerController(GetOwningPlayer(GetTriggerUnit())) != MAP_CONTROL_COMPUTER) then
return false
endif
return true
endfunction
function Trig_AI_Treeherd_Sapling_Mine_Actions takes nothing returns nothing
local unit treeherd = GetTriggerUnit()
local group nearbyMines = CreateGroup()
local unit mine = null
call GroupEnumUnitsInRange(nearbyMines, GetUnitX(treeherd), GetUnitY(treeherd), 1000.0, Condition(function GoldMineFilter))
loop
set mine = FirstOfGroup(nearbyMines)
exitwhen mine == null
if (GetUnitsMiningMine(mine) < 5) then
exitwhen true
endif
call GroupRemoveUnit(nearbyMines, mine)
set mine = null
endloop
if (mine != null) then
call IssueTargetOrderBJ(treeherd, "parasite", mine)
endif
endfunction
//===========================================================================
function InitTrig_AI_Treeherd_Sapling_Mine takes nothing returns nothing
set gg_trg_AI_Treeherd_Sapling_Mine = CreateTrigger( )
call DisableTrigger(gg_trg_AI_Treeherd_Sapling_Mine)
call TriggerRegisterEnterRectSimple( gg_trg_AI_Treeherd_Sapling_Mine, GetPlayableMapRect() )
call TriggerAddCondition( gg_trg_AI_Treeherd_Sapling_Mine, Condition( function Trig_AI_Treeherd_Sapling_Mine_Conditions ) )
call TriggerAddAction( gg_trg_AI_Treeherd_Sapling_Mine, function Trig_AI_Treeherd_Sapling_Mine_Actions )
endfunction
library ElapsedTimer
globals
private multiboard GAME_CLOCK = null
private timer TIMER = CreateTimer()
private real INTERVAL = 0.01
private real ELAPSED = 0.0
endglobals
private function GetFormattedTimeString takes real time returns string
local integer seconds = R2I(ModuloReal(time, 60.0))
local integer minutes = R2I(ModuloReal(time / 60.0, 60.0))
local integer hours = R2I(time / 3600.00)
local string timeFormat = ""
if (hours > 0) then
set timeFormat = timeFormat + I2S(hours) + ":"
if (minutes < 10) then
set timeFormat = timeFormat + "0"
endif
endif
set timeFormat = timeFormat + I2S(minutes) + ":"
if (seconds < 10) then
set timeFormat = timeFormat + "0"
endif
set timeFormat = timeFormat + I2S(seconds)
return timeFormat
endfunction
private function ElapsedTimeCallback takes nothing returns nothing
set ELAPSED = ELAPSED + TimerGetElapsed(GetExpiredTimer())
endfunction
private function MultiboardUpdateCallback takes nothing returns nothing
call MultiboardSetItemValueBJ(GAME_CLOCK, 1, 1, GetFormattedTimeString(ELAPSED))
endfunction
function CreateGameClock takes nothing returns multiboard
local trigger timerUpdateTrigger = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(timerUpdateTrigger, 1.0)
call TriggerAddAction(timerUpdateTrigger, function MultiboardUpdateCallback)
set GAME_CLOCK = CreateMultiboardBJ(1, 1, "Game Clock")
call MultiboardSetItemStyleBJ( GAME_CLOCK, 1, 1, true, false )
call MultiboardSetItemValueBJ( GAME_CLOCK, 1, 1, GetFormattedTimeString(ELAPSED) )
call MultiboardSetItemWidthBJ( GAME_CLOCK, 1, 1, 8.0)
return GAME_CLOCK
endfunction
function BeginGameTimer takes nothing returns nothing
call TimerStart(TIMER, INTERVAL, true, function ElapsedTimeCallback)
endfunction
function GetElapsedGameTime takes nothing returns real
return ELAPSED
endfunction
endlibrary
function Trig_Toggle_Races_Multiboard_Actions takes nothing returns nothing
local boolean isVisible = GetRaceMultiboardVisibility(GetTriggerPlayer())
call SetRaceMultiboardVisibility(GetTriggerPlayer(), not isVisible)
endfunction
//===========================================================================
function InitTrig_Toggle_Races_Multiboard takes nothing returns nothing
local integer p = 0
set gg_trg_Toggle_Races_Multiboard = CreateTrigger( )
call DisableTrigger(gg_trg_Toggle_Races_Multiboard)
loop
exitwhen p >= GetBJMaxPlayers()
if (IsPlayingPlayer(Player(p), true)) then
call TriggerRegisterPlayerChatEvent( gg_trg_Toggle_Races_Multiboard, Player(p), "-alignments", true )
endif
set p = p + 1
endloop
call TriggerAddAction( gg_trg_Toggle_Races_Multiboard, function Trig_Toggle_Races_Multiboard_Actions )
endfunction
function Trig_DebugAbilities_Func001A takes nothing returns nothing
local unit picked = GetEnumUnit()
local integer abilityId = 0
local integer index = 0
local ability a = null
loop
set a = BlzGetUnitAbilityByIndex(picked, index)
exitwhen a == null
set abilityId = BlzGetAbilityId(a)
call WriteInt(GetAbilityName(abilityId) + ": ", abilityId)
call Write(BlzGetAbilityIcon(abilityId))
call Write("--------------------------------------")
set index = index + 1
endloop
endfunction
function Trig_DebugAbilities_Actions takes nothing returns nothing
call ForGroupBJ( GetUnitsSelectedAll(Player(0)), function Trig_DebugAbilities_Func001A )
endfunction
//===========================================================================
function InitTrig_DebugAbilities takes nothing returns nothing
set gg_trg_DebugAbilities = CreateTrigger( )
call DisableTrigger( gg_trg_DebugAbilities )
call TriggerRegisterPlayerChatEvent( gg_trg_DebugAbilities, Player(0), "-abilities", true )
call TriggerAddAction( gg_trg_DebugAbilities, function Trig_DebugAbilities_Actions )
endfunction
function Trig_DebugOrder_Actions takes nothing returns nothing
local integer orderId = GetIssuedOrderId()
local unit ordered = GetOrderedUnit()
local unit target = GetOrderTargetUnit()
call Write("Str: " + OrderId2String(orderId) + ", ID: " + I2S(orderId) + ", Src: " + GetUnitName(ordered) + ", Trg: " + GetUnitName(target))
endfunction
//===========================================================================
function InitTrig_DebugOrder takes nothing returns nothing
set gg_trg_DebugOrder = CreateTrigger( )
call DisableTrigger( gg_trg_DebugOrder )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_DebugOrder, Player(0), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_DebugOrder, Player(0), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_DebugOrder, Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER )
call TriggerAddAction( gg_trg_DebugOrder, function Trig_DebugOrder_Actions )
endfunction
globals
integer array GoldHistory[10]
integer GoldHistoryIndex = 0
integer LastGoldTotal = 0
endglobals
function Trig_DebugGoldPerSecond_Actions takes nothing returns nothing
local integer playerGold = GetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD)
local integer index = 0
local real gps = 0.0
set GoldHistory[GoldHistoryIndex] = playerGold - LastGoldTotal
set GoldHistoryIndex = ModuloInteger(GoldHistoryIndex + 1, 10)
set LastGoldTotal = playerGold
loop
exitwhen index >= 10
set gps = gps + GoldHistory[index]
set index = index + 1
endloop
set gps = gps / 10
call WriteReal("GPS: ", gps)
endfunction
//===========================================================================
function InitTrig_DebugGoldPerSecond takes nothing returns nothing
set gg_trg_DebugGoldPerSecond = CreateTrigger( )
call TriggerRegisterTimerEventPeriodic( gg_trg_DebugGoldPerSecond, 1.00 )
call DisableTrigger(gg_trg_DebugGoldPerSecond)
call TriggerAddAction( gg_trg_DebugGoldPerSecond, function Trig_DebugGoldPerSecond_Actions )
endfunction
function Trig_DebugDamaging_Conditions takes nothing returns boolean
local unit damager = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
return GetOwningPlayer(damager) == Player(0) or GetOwningPlayer(damaged) == Player(0)
endfunction
function Trig_DebugDamaging_Actions takes nothing returns nothing
local unit damager = GetEventDamageSource()
local unit damaged = BlzGetEventDamageTarget()
local real damage = GetEventDamage()
local damagetype dt = BlzGetEventDamageType()
local attacktype at = BlzGetEventAttackType()
call Write(GetUnitName(damager) + " damaging " + GetUnitName(damaged) + ", dealing " + R2S(damage) + " damage of damage type " + I2S(GetHandleId(dt)) + " and attack type " + I2S(GetHandleId(at)))
endfunction
//===========================================================================
function InitTrig_DebugDamaging takes nothing returns nothing
set gg_trg_DebugDamaging = CreateTrigger( )
call DisableTrigger(gg_trg_DebugDamaging)
call TriggerRegisterAnyUnitEventBJ( gg_trg_DebugDamaging, EVENT_PLAYER_UNIT_DAMAGING )
call TriggerAddCondition( gg_trg_DebugDamaging, Condition( function Trig_DebugDamaging_Conditions ) )
call TriggerAddAction( gg_trg_DebugDamaging, function Trig_DebugDamaging_Actions )
endfunction
function Trig_DebugAnimations_Actions takes nothing returns nothing
local integer index = S2I(SubString(GetEventPlayerChatString(), 8,10))
local group selected = GetUnitsSelectedAll(GetTriggerPlayer())
local unit picked = null
call WriteInt("Setting animation index to ", index)
loop
set picked = FirstOfGroup(selected)
exitwhen picked == null
if (index == -1) then
call ResetUnitAnimation(picked)
else
call SetUnitAnimationByIndex(picked, index)
endif
endloop
call DestroyGroup(selected)
endfunction
//===========================================================================
function InitTrig_DebugAnimations takes nothing returns nothing
set gg_trg_DebugAnimations = CreateTrigger( )
call DisableTrigger( gg_trg_DebugAnimations )
call TriggerRegisterPlayerChatEvent(gg_trg_DebugAnimations, Player(0), "-aindex", false)
call TriggerAddAction( gg_trg_DebugAnimations, function Trig_DebugAnimations_Actions )
endfunction
function Trig_DebugRange_Actions takes nothing returns nothing
local integer index = S2I(SubString(GetEventPlayerChatString(), 5,6))
local integer range = S2I(SubString(GetEventPlayerChatString(), 7,11))
local group selected = GetUnitsSelectedAll(GetTriggerPlayer())
local unit picked = null
loop
set picked = FirstOfGroup(selected)
exitwhen picked == null
if (range != 0) then
call BlzSetUnitWeaponRealField(picked, UNIT_WEAPON_RF_ATTACK_RANGE, index + 1, I2R(range))
endif
call WriteReal("Attack range at index " + I2S(index) + " for " + GetUnitName(picked) + ": ", BlzGetUnitWeaponRealField(picked, UNIT_WEAPON_RF_ATTACK_RANGE, index))
call GroupRemoveUnit(selected, picked)
endloop
call DestroyGroup(selected)
endfunction
//===========================================================================
function InitTrig_DebugRange takes nothing returns nothing
set gg_trg_DebugRange = CreateTrigger( )
call DisableTrigger( gg_trg_DebugRange )
call TriggerRegisterPlayerChatEvent(gg_trg_DebugRange, Player(0), "-rng", false)
call TriggerAddAction( gg_trg_DebugRange, function Trig_DebugRange_Actions )
endfunction