Name | Type | is_array | initial_value |
AAngle | real | Yes | |
Abilityshop1 | unit | No | |
Abilityshop2 | unit | No | |
Abilityshop3 | unit | No | |
Abilityshop4 | unit | No | |
Abilityshop5 | unit | No | |
ACaster | unit | Yes | |
ACasterPoint | location | Yes | |
ACount | integer | No | |
ADamage | real | Yes | |
ADistance | real | Yes | |
AfterDamageEvent | real | No | |
AG_Ability | abilcode | No | |
AG_AffectedUnit | unit | No | |
AG_AffectedUnitPosition | location | No | |
AG_Angle | real | Yes | |
AG_AttackType | attacktype | No | |
AG_Caster | unit | Yes | |
AG_CurrentIndex | integervar | No | |
AG_CurrentSpeed | real | Yes | |
AG_DamageType | damagetype | No | |
AG_DestroyTree | boolean | No | |
AG_DistanceCounter | real | Yes | |
AG_Dummy | unit | Yes | |
AG_DummyAbility | abilcode | No | |
AG_DummyCaster | unit | No | |
AG_DummyPosition | location | No | |
AG_DummyType | unitcode | No | |
AG_DummyX | real | No | |
AG_DummyY | real | No | |
AG_EffectScale | real | No | |
AG_ExplosionEffect | string | No | |
AG_GrenadeColor | real | Yes | |
AG_GrenadeEffect | string | No | |
AG_GrenadeEffectHandler | effect | Yes | |
AG_GrenadeSize | real | Yes | |
AG_GrenadeTransparency | real | Yes | |
AG_ImpactDamage | real | Yes | |
AG_Index | integer | No | |
AG_Level | integer | Yes | |
AG_MaxHeight | real | Yes | |
AG_Radius | real | Yes | |
AG_Speed | real | Yes | |
AG_Tree | destructable | No | |
AG_TreeDestroyer | unit | No | |
AHas | boolean | Yes | |
AIndex | integer | No | |
AInteger | integervar | No | |
ALastRecycled | integer | No | |
AMax | integer | No | |
AMaxDistance | real | Yes | |
AMove | real | Yes | |
Angle | real | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
Aplayer | force | No | |
APORAR | dialog | No | |
APORARbutt | button | Yes | |
ARecycledList | integer | Yes | |
ark | effect | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorTypeDebugStr | string | Yes | |
AscentHeight | real | No | |
AscentSpeed | real | No | |
ATarget | unit | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
Beast_Attack_Ability_Level | integer | No | |
Beast_Attack_Atribute | integer | No | |
Beast_Attack_Base_Offset | real | No | |
Beast_Attack_Base_Radius | real | No | |
Beast_Attack_Bonus_Offset | real | No | |
Beast_Attack_Bonus_Radius | real | No | |
Beast_Attack_Caster | unit | No | |
Beast_Attack_Damage_Group | group | No | |
Beast_Attack_Damage_Location | location | No | |
Beast_Attack_Damage_Multiplier | real | No | |
Beast_Attack_Destroy_Trees | boolean | No | |
Beast_Attack_Destroy_Trees_SE | string | No | |
Beast_Attack_Destruct_Kill_AoE | real | No | |
Beast_Attack_Direction | real | No | |
Beast_Attack_KB_Angle | real | No | |
Beast_Attack_KB_Base_Distance | real | No | |
Beast_Attack_KB_Bonus_Distance | real | No | |
Beast_Attack_KB_Group | group | No | |
Beast_Attack_KB_LocI | location | No | |
Beast_Attack_KB_LocII | location | No | |
Beast_Attack_KB_LocIII | location | No | |
Beast_Attack_KB_Minim_Distance | real | No | |
Beast_Attack_KB_Special_Effect | string | No | |
Beast_Attack_KB_Speed | real | No | |
Beast_Attack_KB_Total_Distance | real | No | |
Beast_Attack_Knock_Back_on | boolean | No | |
Beast_Attack_Location | location | No | |
Beast_Attack_LocationII | location | No | |
Beast_Attack_Random_Distance | boolean | No | |
Beast_Attack_Table | hashtable | No | |
Beast_Attack_Total_Damage | real | No | |
Beast_Attack_Total_Offset | real | No | |
Beast_Attack_Total_Radius | real | No | |
BOSS | unit | No | |
BOSS2 | unit | No | |
BOSS3 | unit | No | |
BOSS4 | unit | No | |
BT | integervar | No | |
BT_Closed | boolean | Yes | |
BT_Damage | real | Yes | |
BT_Duration | real | Yes | |
BT_Group | group | No | |
BT_Hero | unit | Yes | |
BT_Interval | real | Yes | |
BT_IntervalCheck | real | Yes | |
BT_Level | integer | Yes | |
BT_On | boolean | Yes | |
BT_Point | location | Yes | |
BT_Skip | integer | No | |
BT_Target | unit | Yes | |
BT_Times | integer | No | |
BT_Trap | unit | Yes | |
BUS_Loc | location | No | |
BUS_MapMaxX | real | No | |
BUS_MapMaxY | real | No | |
BUS_MapMinX | real | No | |
BUS_MapMinY | real | No | |
BUS_Rect | rect | No | |
BUS_Stunner | unit | No | |
BUS_TreeChecker | unit | No | |
BUSK_CurrentEffect | effect | Yes | |
BUSK_CurrentHeight | real | Yes | |
BUSK_KnockbackX | real | Yes | |
BUSK_KnockbackY | real | Yes | |
BUSK_KnockbackZ | real | Yes | |
BUSK_NextNode | integer | Yes | |
BUSK_NodeNumber | integer | No | |
BUSK_PrevNode | integer | Yes | |
BUSK_RecyclableNodes | integer | No | |
BUSK_RecycleNodes | integer | Yes | |
BUSK_ReturnHeight | real | Yes | |
BUSK_Timer | timer | No | |
BUSK_TreeCounter | integer | No | |
BUSK_Unit | unit | Yes | |
BUSK_UnitType | boolean | Yes | |
CB_angle | real | No | |
CB_attacked_loc | location | No | |
CB_attacker | unit | No | |
CB_attacking_loc | location | No | |
CB_BOOOM | boolean | No | |
CB_chance_to_knockback | integer | Yes | |
CB_defender | unit | No | |
CB_distance | real | No | |
CB_distance_setup | real | Yes | |
CB_effectOnCast | string | No | |
CB_effectOnLoop | string | No | |
CB_group | group | No | |
CB_hash | hashtable | No | |
CB_temp_unit | unit | No | |
CB_temploc | location | No | |
CB_temploc_2 | location | No | |
CB_time | real | No | |
CCSS_3rdPersonCamMode | boolean | No | |
CCSS_AddUnitHeightToCamera | boolean | No | |
CCSS_AlignmentLeft | boolean | No | |
CCSS_AngleOfAttackDefault | real | No | |
CCSS_AngleOfAttackEnabled | boolean | No | |
CCSS_AngleOfAttackMax | real | No | |
CCSS_AngleOfAttackMin | real | No | |
CCSS_AngleOfAttackShow | boolean | No | |
CCSS_AngleOfAttackStep | real | No | |
CCSS_CamUpdateInterval | real | No | |
CCSS_CheckBoxShow | boolean | No | |
CCSS_CheckBoxText | string | No | |
CCSS_CheckBoxTextOnLeft | boolean | No | |
CCSS_DistanceDefault | real | No | |
CCSS_DistanceEnabled | boolean | No | |
CCSS_DistanceMax | real | No | |
CCSS_DistanceMin | real | No | |
CCSS_DistanceShow | boolean | No | |
CCSS_DistanceStep | real | No | |
CCSS_HeightDefault | real | No | |
CCSS_HeightEnabled | boolean | No | |
CCSS_HeightMax | real | No | |
CCSS_HeightMin | real | No | |
CCSS_HeightShow | boolean | No | |
CCSS_HeightStep | real | No | |
CCSS_HorizontalArrowMoveLimit | real | No | |
CCSS_HorizontalReturnSpeed | real | No | |
CCSS_HorizontalSpeed | real | No | |
CCSS_InvertHorizontalMovement | boolean | No | |
CCSS_InvertVerticalMovement | boolean | No | |
CCSS_PositionCheckBoxX | real | No | |
CCSS_PositionCheckBoxY | real | No | |
CCSS_PositionSlidersX | real | No | |
CCSS_PositionSlidersY | real | No | |
CCSS_ResetButtonSizeX | real | No | |
CCSS_ResetButtonSizeY | real | No | |
CCSS_ResetButtonText | string | No | |
CCSS_RotationDefault | real | No | |
CCSS_RotationEnabled | boolean | No | |
CCSS_RotationMax | real | No | |
CCSS_RotationMin | real | No | |
CCSS_RotationShow | boolean | No | |
CCSS_RotationStep | real | No | |
CCSS_SButton180Turn | boolean | No | |
CCSS_SButtonOrder | string | No | |
CCSS_ShowValues | boolean | No | |
CCSS_SliderGap | real | No | |
CCSS_TargetUnit | unit | Yes | |
CCSS_UseArrowKeys | boolean | No | |
CCSS_UseNumpadKeys | boolean | No | |
CCSS_UseWASDKeys | boolean | No | |
CCSS_VerticalReturnSpeed | real | No | |
CCSS_VerticalSpeed | real | No | |
CCSS_WASDMoveMinDistance | real | No | |
CCSS_WASDMoveOrderInterval | real | No | |
CCSS_WASDMoveSpeedModifier | real | No | |
CCSS_WASDStationaryTurnSpeed | real | No | |
CCSS_WASDTurnSpeed | real | No | |
CCSS_XButton180Turn | boolean | No | |
CE_Ability_Level | integer | No | |
CE_Area_of_Effect | real | No | |
CE_Base_Damage | real | No | |
CE_Caster | unit | No | |
CE_Damage_Group | group | No | |
CE_Destroy_Trees | boolean | No | |
CE_Knock_Angle | real | No | |
CE_Knock_Distance | real | No | |
CE_Knock_Group | group | No | |
CE_Knock_Loc1 | location | No | |
CE_Knock_Loc2 | location | No | |
CE_Knock_Speed | real | No | |
CE_Knocktable | hashtable | No | |
CE_Location | location | No | |
CE_Location2 | location | No | |
CE_Pathing_On | boolean | No | |
CE_Special_Effect | effect | No | |
CE_Special_Effect1 | effect | No | |
CE_Total_Damage | real | No | |
CL_AbilityLevel | integer | Yes | |
CL_AOE | real | Yes | |
CL_Caster | unit | Yes | |
CL_Count | integer | Yes | |
CL_Damage | integer | Yes | |
CL_FirstTarget | boolean | Yes | |
CL_Group | group | Yes | |
CL_Loc | location | Yes | |
CL_Player | player | Yes | |
CL_Slashes | integer | Yes | |
CL_Special | effect | Yes | |
CL_Target | unit | Yes | |
CL_Victim | unit | Yes | |
CLAnimation | string | No | |
CLAnimationIndex | integer | No | |
CLAnimationSpeed | real | No | |
CLAttach | string | No | |
CLAttachment | string | No | |
CLDamage | real | Yes | |
CLDuration | real | No | |
CleanedItem | item | Yes | |
CLEffect | string | No | |
CLMaxSlashes | integer | Yes | |
CLMinimumDistance | real | No | |
CLSFX | string | No | |
CLSlashInterval | integer | No | |
CLSpeed | real | No | |
CLSpellLevel | integer | Yes | |
CLTransparency | real | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
Count | integer | No | |
CP_HiddenItems | item | Yes | |
CP_HiddenItemsIndex | integer | No | |
CP_Item | item | No | |
CP_PointIsWalkable | boolean | No | |
CP_Rect | rect | No | |
Creep_Point | location | Yes | |
Damage | real | Yes | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DashCaster | unit | Yes | |
DashDamage | real | Yes | |
DashDistance | integer | Yes | |
DashGroup1 | group | No | |
DashGroup2 | group | No | |
DashGroup3 | group | No | |
DashInteger | integer | Yes | |
DashPoint3 | location | Yes | |
DashPoint4 | location | Yes | |
DashPoint5 | location | Yes | |
DashReal1 | real | Yes | |
DashReal2 | real | Yes | |
DashSpeed | real | Yes | |
DC_caster | unit | Yes | |
DC_damage | real | Yes | |
DC_duration | integer | Yes | |
DC_effect | string | Yes | |
DC_integer | integer | Yes | |
DC_lightning | lightning | Yes | |
DC_pointcaster | location | Yes | |
DC_pointtarget | location | Yes | |
DC_target | unit | Yes | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
Delay | real | Yes | |
Dexterity | integer | Yes | |
Difficulty | dialog | No | |
DifficultyButt | button | Yes | |
Dipper_Phases | integer | Yes | |
Distance | real | No | |
DmgStr | string | No | |
DummyEffect | abilcode | No | |
DummySkill | abilcode | No | |
DummyUnit | unitcode | No | |
Duration | real | Yes | |
EnhancedDamageTarget | unit | No | |
ExplosionLayersBase | integer | No | |
ExplosionLayersPerlevel | integer | No | |
ExplosionProjectileHeightMutli | real | No | |
ExplosionRadius | real | No | |
ExplosionRadiusCurrent | real | No | |
ExplosionSidesBase | integer | No | |
ExplosionSidesPerLevel | integer | No | |
EyBe_Config_Ability | abilcode | Yes | |
EyBe_Config_Ability_Order_ID | string | No | |
EyBe_Config_D_Type | unitcode | No | |
EyBe_Config_Damage | real | Yes | |
EyBe_Config_Damage_Bonus | real | Yes | |
EyBe_Config_Duration | real | Yes | |
EyBe_Config_Duration_Slow | real | Yes | |
EyBe_Config_Effect_Path | string | Yes | |
EyBe_Config_End_P_Offset | real | No | |
EyBe_Config_Height | real | Yes | |
EyBe_Config_Lightning_Type | lightningtype | No | |
EyBe_Config_Margin | real | No | |
EyBe_Config_Periodic | real | No | |
EyBe_Config_Range | real | No | |
EyBe_Config_Slow | real | Yes | |
EyBe_Config_Speed | real | Yes | |
EyBe_Config_Tick | real | No | |
EyBe_Config_Width | real | Yes | |
EyBe_Damage | real | Yes | |
EyBe_Duration | real | Yes | |
EyBe_Duration_Slow | real | Yes | |
EyBe_Index | integer | No | |
EyBe_Lightning | lightning | Yes | |
EyBe_Loop | integer | No | |
EyBe_LvL | integer | No | |
EyBe_MouseX | real | No | |
EyBe_MouseX_Prev | real | Yes | |
EyBe_MouseY | real | No | |
EyBe_MouseY_Prev | real | Yes | |
EyBe_Owner | player | Yes | |
EyBe_Point | location | Yes | |
EyBe_Point_Node | effect | Yes | |
EyBe_Point_Z_Height | real | Yes | |
EyBe_Real | real | Yes | |
EyBe_Slow | real | Yes | |
EyBe_Spef | effect | No | |
EyBe_Tar_Angle | real | No | |
EyBe_Tick | real | Yes | |
EyBe_Unit | unit | Yes | |
EyBe_Unit_Caster | unit | Yes | |
EyBe_Unit_Dummy | unit | No | |
EyBe_UnitC_Angle | real | Yes | |
EyBe_Width | real | Yes | |
EyBe_XYZ | real | Yes | |
EyBe_XYZ2 | real | Yes | |
FB_Ability | abilcode | No | |
FB_Attack_Type | attacktype | No | |
FB_Condition | boolean | Yes | |
FB_DAbility | abilcode | No | |
FB_Damage_Type | damagetype | No | |
FB_Dummy_Type | unitcode | No | |
FB_Fireball_AoE | real | Yes | |
FB_Fireball_Collision | real | Yes | |
FB_Fireball_Damage | real | Yes | |
FB_Fireball_Effect | string | No | |
FB_Fireball_Explosion_Type | integer | Yes | |
FB_Fireball_Height | real | Yes | |
FB_Fireball_Hit | boolean | No | |
FB_Fireball_Model | string | No | |
FB_Fireball_Scale | real | Yes | |
FB_Fireball_Speed | real | Yes | |
FB_Fireballs_AoE | real | Yes | |
FB_Fireballs_Collision | real | Yes | |
FB_Fireballs_Damage | real | Yes | |
FB_Fireballs_Distance | real | Yes | |
FB_Fireballs_Effect | string | No | |
FB_Fireballs_Explosion_Type | integer | Yes | |
FB_Fireballs_Height | real | Yes | |
FB_Fireballs_Hit | boolean | No | |
FB_Fireballs_Model | string | No | |
FB_Fireballs_Number | integer | Yes | |
FB_Fireballs_Scale | real | Yes | |
FB_Fireballs_Speed | real | Yes | |
FB_Group | group | No | |
FB_Handle_Id | integer | No | |
FB_Harvest_Order | string | No | |
FB_Harvester | unit | No | |
FB_Hashtable | hashtable | No | |
FB_Interval | real | No | |
FB_Kill_Trees | boolean | No | |
FB_Level | integer | No | |
FB_Loop | integervar | No | |
FB_Owner | player | No | |
FB_Real | real | Yes | |
FB_SFX | effect | No | |
FB_Spawn_Distance | real | No | |
FB_TempUnit | unit | Yes | |
FB_Tree | destructable | No | |
FC_Ability | abilcode | No | |
FC_Angle_Real | real | No | |
FC_Attack_Type | attacktype | No | |
FC_Base_Damage | real | No | |
FC_BetterFPS | boolean | No | |
FC_Buff | buffcode | No | |
FC_Critical | boolean | No | |
FC_CriticalChanceBase | real | No | |
FC_CriticalChanceLvl | real | No | |
FC_CriticalMultiplier | real | No | |
FC_Damage | real | No | |
FC_Damage_Air | boolean | No | |
FC_Damage_Building | boolean | No | |
FC_Damage_Ground | boolean | No | |
FC_Damage_Heroes | boolean | No | |
FC_Damage_Immune | boolean | No | |
FC_Damage_Mechanical | boolean | No | |
FC_Damage_Type | damagetype | No | |
FC_DestroyTrees | boolean | No | |
FC_Destructable | destructable | No | |
FC_Distance | real | No | |
FC_DummyAbility | abilcode | No | |
FC_DummyType | unitcode | No | |
FC_Effect_Timer | real | No | |
FC_Effect_Timer_Instance | real | No | |
FC_Group | group | No | |
FC_HandleDummyType | unitcode | No | |
FC_Hashtable | hashtable | No | |
FC_i | integervar | No | |
FC_i2 | integervar | No | |
FC_i3 | integervar | No | |
FC_Level_Damage | real | No | |
FC_MaxDistance | real | No | |
FC_MaxDistanceBase | real | No | |
FC_MaxDistanceLevel | real | No | |
FC_RangeofDamageBase | real | No | |
FC_RangeofDamageLevel | real | No | |
FC_RangeofDamageTreesBase | real | No | |
FC_RangeofDamageTreesLevel | real | No | |
FC_SFX | string | No | |
FC_SFX_Damage_Trees | string | No | |
FC_SFX_Damage_Unit | string | No | |
FC_Speed_Base | real | No | |
FC_Speed_Level | real | No | |
FC_TmpCaster | unit | No | |
FC_TmpDummy | unit | No | |
FC_TmpHandle | handle | No | |
FC_TmpHandleDummy | unit | No | |
FC_TmpInt | integer | No | |
FC_TmpInt2 | integer | No | |
FC_TmpPoint | location | No | |
FC_TmpPoint2 | location | No | |
FC_TreeRemover | unit | No | |
FC_TreeRemoverType | unitcode | No | |
FC_X | real | No | |
FC_Y | real | No | |
FlareSegmentGroup | group | No | |
FlareStarHash | hashtable | No | |
Game | dialog | No | |
Gamebutton | button | Yes | |
Gamescleared | integer | No | |
HA_Caster | unit | No | |
HA_DamageDealt | real | No | |
HA_DamageTaken | real | No | |
HA_Point | location | No | |
HA_Target | unit | No | |
HASH | hashtable | No | |
Hash2 | hashtable | No | |
HeroAll | unitcode | Yes | |
HeroEffect | abilcode | No | |
HeronumberAll | integer | No | |
HeroSelectorEvent | real | No | |
HeroSelectorEventIsRandom | boolean | No | |
HeroSelectorEventPlayer | player | No | |
HeroSelectorEventUnit | unit | No | |
HeroSelectorEventUnitCode | unitcode | No | |
HeroSelectorRandomOnly | unitcode | Yes | |
HeroSelectorUnitCode | unitcode | Yes | |
InfiniteSlashesAngle | real | Yes | |
InfiniteSlashesBol1 | boolean | Yes | |
InfiniteSlashesBol2 | boolean | Yes | |
InfiniteSlashesCaster | unit | Yes | |
InfiniteSlashesCasterLoc | location | No | |
InfiniteSlashesCasterLoc2 | location | No | |
InfiniteSlashesCount1 | integer | Yes | |
InfiniteSlashesCount2 | integer | Yes | |
InfiniteSlashesDistance | real | Yes | |
InfiniteSlashesIndex | integer | No | |
InfiniteSlashesLoop | integervar | No | |
InfiniteSlashesMui | integer | No | |
InfiniteSlashesSFX | effect | Yes | |
InfiniteSlashesTarget | unit | Yes | |
InfiniteSlashesTargetLoc | location | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
ItemCleanupFlag | boolean | No | |
ItemCleanupTimer | timer | No | |
ItemsToClean | integer | No | |
JB | integervar | No | |
JB_Angle | real | Yes | |
JB_AoE | real | Yes | |
JB_Colision | real | Yes | |
JB_Damage | real | Yes | |
JB_Distance | real | Yes | |
JB_Group | group | No | |
JB_Height | real | Yes | |
JB_Hero | unit | Yes | |
JB_Level | integer | Yes | |
JB_MaxDistance | real | Yes | |
JB_Missile | unit | Yes | |
JB_Off | boolean | Yes | |
JB_Parabola | real | Yes | |
JB_Point | location | Yes | |
JB_Skip | integer | No | |
JB_Speed | real | Yes | |
JB_Times | integer | No | |
KB | integervar | No | |
KB3D_Accel | real | No | |
KB3D_AllowOutSiding | boolean | No | |
KB3D_Angle | real | No | |
KB3D_AoE | real | No | |
KB3D_AoEDamage | real | No | |
KB3D_AoEEndDamage | real | No | |
KB3D_AoEKB | boolean | No | |
KB3D_AoEKB_Power | real | No | |
KB3D_Arc | real | No | |
KB3D_AttackType | attacktype | No | |
KB3D_Counter | integer | No | |
KB3D_D_ALLY | boolean | No | |
KB3D_D_MAGIC_IMMINUE | boolean | No | |
KB3D_D_MECHANICAL | boolean | No | |
KB3D_D_STRUCTURE | boolean | No | |
KB3D_Damager | unit | No | |
KB3D_DamageType | damagetype | No | |
KB3D_DestroyTree | boolean | No | |
KB3D_DisableUnit | boolean | No | |
KB3D_EndFx | string | No | |
KB3D_EndwhenDead | boolean | No | |
KB3D_EndWhenHit | boolean | No | |
KB3D_FaceAngle | boolean | No | |
KB3D_Fx | string | No | |
KB3D_Fx_Attach | string | No | |
KB3D_GroundDamage | boolean | No | |
KB3D_Group | group | No | |
KB3D_HA | hashtable | No | |
KB3D_Harvester | unit | No | |
KB3D_iKB | boolean | No | |
KB3D_ImpactDamage | real | No | |
KB3D_Instances | integer | No | |
KB3D_KBTarget | boolean | No | |
KB3D_KillatEnd | boolean | No | |
KB3D_KillatTime | real | No | |
KB3D_KillifOutSider | boolean | No | |
KB3D_KillWhenHit | boolean | No | |
KB3D_LineDamage | real | No | |
KB3D_LoopDamage | real | No | |
KB3D_Range | real | No | |
KB3D_Reals | real | Yes | |
KB3D_Registration | trigger | No | |
KB3D_Speed | real | No | |
KB3D_StopTime | real | No | |
KB3D_TargetDamage | real | No | |
KB3D_Targeted_Unit | unit | No | |
KB3D_Time | real | No | |
KB3D_Timer | timer | No | |
KB3D_TrailFx | string | No | |
KB3D_Unit | unit | No | |
KB3D_UnpathableStop | boolean | No | |
KB3D_Zoffset | real | No | |
KB_Angle | real | Yes | |
KB_Angle_Copy | real | Yes | |
KB_Casters | unit | Yes | |
KB_CountBuffs | integer | No | |
KB_DestroyTrees | boolean | Yes | |
KB_Distance | real | Yes | |
KB_Effects_1 | string | Yes | |
KB_Effects_2 | string | Yes | |
KB_GeneralIntegers | integer | Yes | |
KB_KnockbackedUnits | group | No | |
KB_Levels | integer | Yes | |
KB_MaxDistance | real | Yes | |
KB_Off | boolean | Yes | |
KB_Point | location | Yes | |
KB_ReachedDistance | real | Yes | |
KB_ReducedReal | real | No | |
KB_ReduceSpeedReal | real | Yes | |
KB_Skip | integer | No | |
KB_Spam | integer | Yes | |
KB_SpecificSpeed | real | Yes | |
KB_Speed | real | Yes | |
KB_StartPositions | location | Yes | |
KB_Target | unit | Yes | |
KB_TempPoint | location | Yes | |
KB_TempReal | real | No | |
KB_Times | integer | No | |
KB_TotalKnockUnits | integer | No | |
KB_Units | unit | Yes | |
KBA_Caster | unit | No | |
KBA_DestroyTrees | boolean | No | |
KBA_DistancePerLevel | real | No | |
KBA_Level | integer | No | |
KBA_SpecialEffects | string | Yes | |
KBA_Speed | real | No | |
KBA_StartingPosition | location | No | |
KBA_TargetUnit | unit | No | |
Kill_Count | integer | Yes | |
KSHash | hashtable | No | |
LC_Cloud | unit | No | |
LC_TimerN | integer | No | |
LC_Timers | timer | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LG_angle | real | Yes | |
LG_angleSet | boolean | Yes | |
LG_caster | unit | Yes | |
LG_casterPoint | location | No | |
LG_castingGroup | group | No | |
LG_damagedGroup | group | Yes | |
LG_dummy | unit | Yes | |
LG_dummyEffect | string | No | |
LG_dummyReached | boolean | Yes | |
LG_effectDelay | real | No | |
LG_effectDelayCount | real | Yes | |
LG_index1 | integer | Yes | |
LG_index2 | integer | No | |
LG_index3 | integervar | No | |
LG_indexMax | integer | No | |
LG_indexSize | integer | No | |
LG_isStillMoving | boolean | Yes | |
LG_landingDamage | real | Yes | |
LG_landingDamageAoE | real | No | |
LG_landingEffect | string | No | |
LG_lightning | lightning | Yes | |
LG_lightningHeight | real | No | |
LG_lineDamage | real | Yes | |
LG_lineDamageAoE | real | No | |
LG_moveSpeed | real | No | |
LG_pullAcceleration | real | No | |
LG_pullDelay | real | Yes | |
LG_pulledEffect | string | No | |
LG_pulledEnemies | integer | Yes | |
LG_pulledEnemiesAlong | boolean | No | |
LG_pulledGroup | group | Yes | |
LG_pullSpeed | real | Yes | |
LG_shockedEffect | string | No | |
LG_spell | abilcode | No | |
LG_spellEnd | boolean | Yes | |
LG_targetRect | rect | Yes | |
LH | integervar | No | |
LHAngleFour | real | No | |
LHAngleOne | real | No | |
LHAngleThree | real | No | |
LHAngleTwo | real | No | |
LHCaster | unit | Yes | |
LHCasterGroup | group | Yes | |
LHCasterPoint | location | No | |
LHDamage | real | Yes | |
LHDamageGroup | group | Yes | |
LHFly | real | No | |
LHIndex | integer | Yes | |
LHPlayer | player | Yes | |
LHReject | unit | Yes | |
LHRejectGroup | group | Yes | |
LHRejectPoint | location | Yes | |
LHSize | real | No | |
LHSpiralFour | unit | No | |
LHSpiralOne | unit | No | |
LHSpiralPointFour | location | No | |
LHSpiralPointOne | location | No | |
LHSpiralPointThree | location | No | |
LHSpiralPointTwo | location | No | |
LHSpiralThree | unit | No | |
LHSpiralTwo | unit | No | |
LHSpire | unit | No | |
LHSpireFly | real | No | |
LHTarget | unit | No | |
LHThunder | unit | No | |
LHThunderFly | real | No | |
LHTimer | real | Yes | |
Lightning | lightning | Yes | |
Loop | integervar | No | |
LP_Angle | real | Yes | |
LP_Caster | unit | Yes | |
LP_Dummy | unit | Yes | |
LP_DummyGroup | group | Yes | |
LP_DummyPoint | location | Yes | |
LP_Integer | integer | Yes | |
LP_Lightning | lightning | Yes | |
LP_Location | location | Yes | |
LP_Location2 | location | Yes | |
LP_NonStrike | group | Yes | |
LP_PickedUnit | unit | Yes | |
LP_PositionPickedUnit | location | Yes | |
LP_Strike | group | Yes | |
LP_Tick | integer | Yes | |
LS_Caster | unit | Yes | |
LS_DamageHeal | real | Yes | |
LS_Dummy | unit | No | |
LS_Duration | integer | Yes | |
LS_EffectCaster | string | Yes | |
LS_EffectTarget | string | Yes | |
LS_GeneralInteger | integer | No | |
LS_Groups | group | Yes | |
LS_integer | integer | Yes | |
LS_Target | unit | Yes | |
LS_TempPoint | location | Yes | |
LSE_Destructable | destructable | Yes | |
LSE_DestructableCounter | integer | No | |
LSE_GetDestructables | trigger | No | |
LSE_GetItems | trigger | No | |
LSE_GetUnits | trigger | No | |
LSE_Group | group | No | |
LSE_Item | item | Yes | |
LSE_ItemCounter | integer | No | |
LSE_Loc_1 | location | No | |
LSE_Loc_2 | location | No | |
LSE_Offset | real | No | |
LSE_Rect | rect | No | |
LW_Angle1 | real | Yes | |
LW_Angle2 | real | No | |
LW_Angle2Saved | real | No | |
LW_AoE1 | real | Yes | |
LW_AoE2 | real | No | |
LW_AoE3 | real | No | |
LW_Caster | unit | Yes | |
LW_Check | boolean | Yes | |
LW_Count | integer | No | |
LW_CurrentDistance | real | Yes | |
LW_Damage1 | real | Yes | |
LW_Damage2 | real | Yes | |
LW_Distance | real | Yes | |
LW_Dummy | unit | No | |
LW_Effect1 | string | No | |
LW_Effect2 | string | No | |
LW_Index1 | integer | No | |
LW_Index2 | integer | No | |
LW_Index3 | integervar | No | |
LW_Integer | integervar | Yes | |
LW_Lightning | lightning | Yes | |
LW_Multiplier | real | No | |
LW_Point1 | location | Yes | |
LW_Point2 | location | No | |
LW_Point3 | location | No | |
LW_Point4 | location | No | |
LW_Real1 | real | Yes | |
LW_Real2 | real | No | |
LW_Speed | real | No | |
LW_Speed2 | real | No | |
LW_XY | location | No | |
LW_Z1 | real | No | |
LW_Z2 | real | No | |
Max_Index | integer | No | |
MC_Angle | real | Yes | |
MC_AngleAdjust | real | Yes | |
MC_AngleLimit | real | Yes | |
MC_AOE | real | Yes | |
MC_CleaveScale | real | Yes | |
MC_Delay | real | Yes | |
MC_DelayReset | real | Yes | |
MC_Division | real | Yes | |
MC_EffectDistance | real | Yes | |
MC_HealthDamage | real | Yes | |
MC_KnockbackForce | real | Yes | |
MC_ManaDamage | real | Yes | |
MC_NextNode | integer | Yes | |
MC_NodeNumber | integer | No | |
MC_Player | player | Yes | |
MC_PrevNode | integer | Yes | |
MC_RecyclableNodes | integer | No | |
MC_RecycleNodes | integer | Yes | |
MC_TempGroup | group | No | |
MC_Timer | timer | No | |
MC_Unit | unit | Yes | |
MEB_Angle | real | No | |
MEB_Bomb | unitcode | No | |
MEB_Bombs | group | No | |
MEB_BurnAoe | real | No | |
MEB_BurnDamageBase | real | No | |
MEB_BurnDamagePerLevel | real | No | |
MEB_DamageBase | real | No | |
MEB_DamagePerLevel | real | No | |
MEB_DistanceIncrease | real | No | |
MEB_DurationBase | real | No | |
MEB_DurationPerLevel | real | No | |
MEB_ExplosionAOEBase | real | No | |
MEB_ExplosionAOPerLevel | real | No | |
MEB_Hash | hashtable | No | |
MEB_I | integervar | No | |
MEB_KnockbackDetriment | real | No | |
MEB_KnockbackStrengthBase | real | No | |
MEB_KnockbackStrengthPerLevel | real | No | |
MEB_Lightning | string | No | |
MEB_LightningHeight | real | No | |
MEB_MagneticAOEBase | real | No | |
MEB_MagneticAOEPerLevel | real | No | |
MEB_MagneticStrengthBase | real | No | |
MEB_MagneticStrengthPerLevel | real | No | |
MEB_ManaDamageBase | real | No | |
MEB_ManaDamagePerLevel | real | No | |
MEB_ManaToHealthDamageBase | real | No | |
MEB_ManaToHealthDamagePerLevel | real | No | |
MEB_RockSmash | real | No | |
MEB_SFXDeath | string | No | |
MEB_SFXKnockback | string | No | |
MEB_SFXSpawn | string | No | |
MEB_SidesBase | integer | No | |
MEB_SidesPerLevel | integer | No | |
MEB_Speed | real | No | |
MEB_Spell | abilcode | No | |
MEB_StartDistance | real | No | |
MEB_Tail | unitcode | No | |
MEB_TailDurationBase | real | No | |
MEB_TailDurationPerLevel | real | No | |
MEB_TempGroup | group | No | |
MEB_TempI | integer | No | |
MEB_TempLightning | lightning | No | |
MEB_TempPoint | location | No | |
MEB_TempPoint2 | location | No | |
MEB_TempPoint3 | location | No | |
MEB_TempReal | real | No | |
MEB_TempReal2 | real | No | |
MEB_TempU | unit | No | |
MEB_TreeChecker | unit | No | |
MEB_TreeDestroyArea | real | No | |
MEB_TreeKill | boolean | No | |
MEB_U | unit | No | |
MEB_UHandle | integer | No | |
MEB_UHandleC | integer | No | |
MUI_1 | integer | No | |
MUI_2 | integer | Yes | |
MUI_3 | integervar | No | |
NextDamageType | integer | No | |
PB | integervar | No | |
PB_Damage | real | Yes | |
PB_DebugGroup | group | Yes | |
PB_Group | group | Yes | |
PB_Hero | unit | Yes | |
PB_Level | integer | Yes | |
PB_Point | location | Yes | |
PB_Skip | integer | No | |
PB_Times | integer | No | |
PhantomPhase_AT | attacktype | No | |
PhantomPhase_Damage | real | Yes | |
PhantomPhase_DT | damagetype | No | |
PhantomPhase_PhaseOneDuration | real | Yes | |
PhantomPhase_SFX_Attached | string | No | |
PhantomPhase_SFX_AttachPoint | string | No | |
PhantomPhase_SFX_AttachPointT | string | No | |
PhantomPhase_SFX_Retreat | string | No | |
PhantomPhase_SFX_Targeted | string | No | |
PhantomPhase_SFX_TargetSFX | effect | Yes | |
PhantomPhase_SFX_TelSpot | string | No | |
PhantomPhase_Spot | location | Yes | |
PhantomPhase_Teleported | boolean | Yes | |
Player1 | unit | No | |
Player2 | unit | No | |
Player3 | unit | No | |
Player4 | unit | No | |
Player5 | unit | No | |
PlayerHeroes | group | No | |
Playernumber | integer | No | |
Players | force | No | |
Presence_Ability_Aura | abilcode | Yes | |
Presence_Ability_Change | abilcode | No | |
Presence_Buff | buffcode | Yes | |
Presence_Caster | unit | No | |
Presence_Handle | handle | No | |
Presence_Hash | hashtable | No | |
Presence_Index_Add | integer | No | |
Presence_Index_Remove | integer | No | |
Presence_Level | integer | No | |
ProjectileSpeed | real | No | |
PWAngle | real | Yes | |
PWCaster | unit | Yes | |
PWCasterPoint | location | Yes | |
PWCount | integer | No | |
PWDamage | real | Yes | |
PWDistance | real | Yes | |
PWDMGGroup | group | Yes | |
PWHas | boolean | Yes | |
PWIndex | integer | No | |
PWInteger | integer | No | |
PWLastRecycled | integer | No | |
PWMax | integer | No | |
PWMaxDistance | real | Yes | |
PWPhoenix | unit | Yes | |
PWRecycledList | integer | Yes | |
PWTargetPoint | location | Yes | |
RB_player_max | integer | No | |
RB_temppoint | location | Yes | |
RB_tempunit | unit | No | |
ReportLife | real | No | |
RS_Animation_Speed | real | No | |
RS_Attack_Type | attacktype | No | |
RS_Caster | unit | Yes | |
RS_Current_Index | integer | No | |
RS_Damage | real | Yes | |
RS_Damage_Type | damagetype | No | |
RS_Effect | string | Yes | |
RS_Index | integer | Yes | |
RS_Index_Size | integer | No | |
RS_Level | integer | No | |
RS_Loop | integervar | No | |
RS_Max_Index | integer | No | |
RS_Slashes | integer | Yes | |
RS_Target | unit | Yes | |
RS_Transparency | real | No | |
RS_Weapon_Effect | effect | Yes | |
RSCaster | unit | Yes | |
RSCount | integer | No | |
RSDamage | real | Yes | |
RSDistance | real | Yes | |
RSEffectDelayer | integer | Yes | |
RSHas | boolean | Yes | |
RSIndex | integer | No | |
RSInteger | integer | No | |
RSLastRecycled | integer | No | |
RSMax | integer | No | |
RSRecycledList | integer | Yes | |
RSRemaining | integer | Yes | |
RSTarget | unit | Yes | |
SB | integervar | No | |
SB_Angle | real | Yes | |
SB_AOE | real | Yes | |
SB_Bomb | unit | Yes | |
SB_Boolean | boolean | Yes | |
SB_Colision | real | Yes | |
SB_CurrentScale | real | Yes | |
SB_Damage | real | Yes | |
SB_Distance | real | Yes | |
SB_DistanceCheck | real | Yes | |
SB_FT_Count | real | Yes | |
SB_FTValue | integer | Yes | |
SB_Group | group | No | |
SB_Height | real | Yes | |
SB_Hero | unit | Yes | |
SB_Level | integer | Yes | |
SB_Loc | location | Yes | |
SB_Loop | integervar | No | |
SB_MaxDistance | real | Yes | |
SB_MaxScale | real | Yes | |
SB_Missile | unit | Yes | |
SB_On | boolean | Yes | |
SB_Parabola | real | Yes | |
SB_Point | location | Yes | |
SB_Projectile | unit | Yes | |
SB_SFX | effect | Yes | |
SB_Skip | integer | No | |
SB_Speed | real | Yes | |
SB_Sticked | boolean | Yes | |
SB_Target | unit | Yes | |
SB_Timer | real | Yes | |
SB_Times | integer | No | |
SB_TrgtPoint | location | Yes | |
SF_Ability | abilcode | No | |
SF_Blast_AttackType | attacktype | No | |
SF_Blast_DamageStructures | boolean | No | |
SF_Blast_DamageType | damagetype | No | |
SF_Blast_KB_Acceleration | real | Yes | |
SF_Blast_KB_Damage | real | Yes | |
SF_Blast_KB_DestroyTrees | boolean | No | |
SF_Blast_KB_Effect | string | No | |
SF_Blast_KB_EffectAttach | string | No | |
SF_Blast_KB_Range | real | Yes | |
SF_Blast_KB_Speed | real | Yes | |
SF_Blast_KB_Z_Height | real | Yes | |
SF_Blast_KnockbackUnits | boolean | No | |
SF_Blast_PickedUnit | unit | No | |
SF_BlastDamage | real | Yes | |
SF_BlastDummy | unit | No | |
SF_BlastEffect | string | No | |
SF_BlastGroup | group | No | |
SF_BlastPickedUnitPosition | location | No | |
SF_BlastRadius | real | Yes | |
SF_BlastScaleRatio | real | No | |
SF_Caster | unit | Yes | |
SF_CasterPosition | location | No | |
SF_CurrentIndex | integervar | No | |
SF_DistanceCounter | real | Yes | |
SF_FlameStrikeAbility | abilcode | No | |
SF_FlameStrikeDummy | unit | No | |
SF_Level | integer | Yes | |
SF_MaxIndex | integer | No | |
SF_PFPickedUnitsFx | string | No | |
SF_PFPickedUnitsFxAttach | string | No | |
SF_Player | player | Yes | |
SF_PrimaryFirebalFxHandler | effect | Yes | |
SF_PrimaryFireballAngle | real | Yes | |
SF_PrimaryFireballAttackType | attacktype | No | |
SF_PrimaryFireballCollision | real | Yes | |
SF_PrimaryFireballDamage | real | Yes | |
SF_PrimaryFireballDamageType | damagetype | No | |
SF_PrimaryFireballDistance | real | Yes | |
SF_PrimaryFireballDummy | unit | Yes | |
SF_PrimaryFireballGroup | group | No | |
SF_PrimaryFireballHeight | real | Yes | |
SF_PrimaryFireballModel | string | No | |
SF_PrimaryFireballMovement | location | No | |
SF_PrimaryFireballPickedUnits | unit | No | |
SF_PrimaryFireballPosition | location | No | |
SF_PrimaryFireballSize | real | Yes | |
SF_PrimaryFireballSpeed | real | Yes | |
SF_PrimarySplitEffect | string | No | |
SF_SecondaryFBAcceleration | real | Yes | |
SF_SecondaryFBDamageStructure | boolean | No | |
SF_SecondaryFBDestroyTrees | boolean | No | |
SF_SecondaryFireballAngle | real | Yes | |
SF_SecondaryFireballAttackType | attacktype | No | |
SF_SecondaryFireballBlastFx | string | No | |
SF_SecondaryFireballCollision | real | Yes | |
SF_SecondaryFireballDamage | real | Yes | |
SF_SecondaryFireballDamageType | damagetype | No | |
SF_SecondaryFireballDummy | unit | No | |
SF_SecondaryFireballDurCounter | real | Yes | |
SF_SecondaryFireballModel | string | No | |
SF_SecondaryFireballRange | real | Yes | |
SF_SecondaryFireballReleaseDur | real | Yes | |
SF_SecondaryFireballSize | real | Yes | |
SF_SecondaryFireballSpeed | real | Yes | |
SF_TargetLocation | location | No | |
SF_TertiaryFBAcceleration | real | Yes | |
SF_TertiaryFireballAmount | integer | Yes | |
SF_TertiaryFireballAngle | real | No | |
SF_TertiaryFireballAttackType | attacktype | No | |
SF_TertiaryFireballBlastEffect | string | No | |
SF_TertiaryFireballCollision | real | Yes | |
SF_TertiaryFireballDamage | real | Yes | |
SF_TertiaryFireballDamageType | damagetype | No | |
SF_TertiaryFireballDestroyTree | boolean | No | |
SF_TertiaryFireballDummy | unit | No | |
SF_TertiaryFireballInt | integervar | No | |
SF_TertiaryFireballLocation | location | No | |
SF_TertiaryFireballModel | string | No | |
SF_TertiaryFireballRange | real | Yes | |
SF_TertiaryFireballRotation | boolean | No | |
SF_TertiaryFireballSize | real | Yes | |
SF_TertiaryFireballSpeed | real | Yes | |
SF_VexorianDummyType | unitcode | No | |
Spell__Ability | abilcode | No | |
Spell__AutoAddTargets | boolean | No | |
Spell__BuffAbility | abilcode | No | |
Spell__BuffOrder | ordercode | No | |
Spell__Caster | unit | No | |
Spell__CasterOwner | player | No | |
Spell__CastPoint | location | No | |
Spell__Channeling | boolean | No | |
Spell__Completed | boolean | No | |
Spell__DummyOwner | player | No | |
Spell__DummyType | unitcode | No | |
Spell__Duration | real | No | |
Spell__DurationPerLevel | real | No | |
Spell__Expired | boolean | No | |
Spell__Filter_AllowAlly | boolean | No | |
Spell__Filter_AllowDead | boolean | No | |
Spell__Filter_AllowEnemy | boolean | No | |
Spell__Filter_AllowFlying | boolean | No | |
Spell__Filter_AllowHero | boolean | No | |
Spell__Filter_AllowLiving | boolean | No | |
Spell__Filter_AllowMagicImmune | boolean | No | |
Spell__Filter_AllowMechanical | boolean | No | |
Spell__Filter_AllowNonHero | boolean | No | |
Spell__Filter_AllowStructure | boolean | No | |
Spell__Hash | hashtable | No | |
Spell__Index | integer | No | |
Spell__InRange | real | No | |
Spell__InRangeCount | integer | No | |
Spell__InRangeGroup | group | No | |
Spell__InRangeMax | integer | No | |
Spell__InRangePoint | location | No | |
Spell__InRangeUnit | unit | No | |
Spell__InRangeUnits | unit | Yes | |
Spell__Interval | real | No | |
Spell__Level | integer | No | |
Spell__LevelMultiplier | real | No | |
Spell__Running | boolean | No | |
Spell__StartDuration | boolean | No | |
Spell__Target | unit | No | |
Spell__TargetGroup | group | No | |
Spell__TargetPoint | location | No | |
Spell__Time | real | No | |
Spell__Trigger_InRangeFilter | trigger | No | |
Spell__Trigger_OnCast | trigger | No | |
Spell__Trigger_OnChannel | trigger | No | |
Spell__Trigger_OnEffect | trigger | No | |
Spell__Trigger_OnFinish | trigger | No | |
Spell__Trigger_OnLoop | trigger | No | |
Spell__UseTargetGroup | boolean | No | |
Spell__WakeTargets | boolean | No | |
Spell_i_Abil | abilcode | Yes | |
Spell_i_AllowAlly | boolean | Yes | |
Spell_i_AllowDead | boolean | Yes | |
Spell_i_AllowEnemy | boolean | Yes | |
Spell_i_AllowFlying | boolean | Yes | |
Spell_i_AllowHero | boolean | Yes | |
Spell_i_AllowLiving | boolean | Yes | |
Spell_i_AllowMagicImmune | boolean | Yes | |
Spell_i_AllowMechanical | boolean | Yes | |
Spell_i_AllowNonHero | boolean | Yes | |
Spell_i_AllowStructure | boolean | Yes | |
Spell_i_AutoAddTargets | boolean | Yes | |
Spell_i_BuffAbil | abilcode | Yes | |
Spell_i_BuffOrder | ordercode | Yes | |
Spell_i_Caster | unit | Yes | |
Spell_i_Channeling | boolean | Yes | |
Spell_i_Completed | boolean | Yes | |
Spell_i_Duration | real | Yes | |
Spell_i_EventType | integer | Yes | |
Spell_i_GroupN | integer | No | |
Spell_i_GroupStack | group | Yes | |
Spell_i_Head | integer | Yes | |
Spell_i_InRangeFilter | trigger | Yes | |
Spell_i_Instances | integer | No | |
Spell_i_LastTime | real | Yes | |
Spell_i_Level | integer | Yes | |
Spell_i_Linked | boolean | Yes | |
Spell_i_OnCastStack | trigger | Yes | |
Spell_i_OnChannelStack | trigger | Yes | |
Spell_i_OnEffectStack | trigger | Yes | |
Spell_i_OnFinishStack | trigger | Yes | |
Spell_i_OnLoopStack | trigger | Yes | |
Spell_i_PreloadDummy | unit | No | |
Spell_i_Recycle | integer | No | |
Spell_i_RecycleList | integer | Yes | |
Spell_i_Stack | integer | Yes | |
Spell_i_StackN | integer | No | |
Spell_i_StackRef | integer | Yes | |
Spell_i_Target | unit | Yes | |
Spell_i_TargetGroup | group | Yes | |
Spell_i_TargetX | real | Yes | |
Spell_i_TargetY | real | Yes | |
Spell_i_Time | real | Yes | |
Spell_i_Timer | timer | No | |
Spell_i_UseTG | boolean | Yes | |
SpinSpeed | real | No | |
SpreadSpeed | real | No | |
SSCaster | unit | Yes | |
SSCount | integer | No | |
SSDamage | real | Yes | |
SSDelay | real | Yes | |
SSDummyGroup | group | Yes | |
SSDuration | real | Yes | |
SSHas | boolean | Yes | |
SSIndex | integer | No | |
SSInteger | integervar | No | |
SSLastRecycled | integer | No | |
SSMax | integer | No | |
SSRecycledList | integer | Yes | |
SSTarget | unit | Yes | |
Star_Loop | integervar | No | |
Star_Loop_2 | integervar | No | |
StarSegmentAOEDamageBase | real | No | |
StarSegmentAOEDamagePerlevel | real | No | |
StarSidesBase | integer | No | |
StarSidesPerLevel | integer | No | |
StarSize | real | No | |
TDS | integervar | No | |
TDS_Damage | real | Yes | |
TDS_Hero | unit | Yes | |
TDS_On | boolean | Yes | |
TDS_Skip | integer | No | |
TDS_Target | unit | Yes | |
TDS_Time | real | Yes | |
TDS_Times | integer | No | |
Temp | integer | No | |
Temp_Integer | integer | No | |
Temp_Point | location | No | |
Temp_Point2 | location | No | |
TempGroup | group | No | |
TempGroup_Copy | group | No | |
TempInt | integer | No | |
TempInt_AKA | integer | No | |
tempInteger | integer | No | |
TempLoc | location | No | |
TempLoc2 | location | No | |
TempLoc2_AKA | location | No | |
TempLoc3 | location | No | |
TempLoc_AKA | location | No | |
TempLoc_Copy | location | No | |
tempPlayerGroup | force | No | |
TempPoint | location | No | |
tempPoint | location | No | |
tempPoint2 | location | No | |
TempPoint2 | location | No | |
TempPoint3 | location | No | |
tempPoint3 | location | No | |
tempReal | real | No | |
tempUnit | unit | No | |
TempUnit | unit | No | |
TempUnit_AKA | unit | No | |
TEXTBOSSRUSH | texttag | No | |
TEXTFINALBOSS | texttag | No | |
TEXTGAME | texttag | No | |
TEXTPVP | texttag | No | |
TEXTRANDOMIZER | texttag | No | |
TEXTSECRETBOSS | texttag | No | |
Tier1boss | unitcode | Yes | |
Tier1enemy | unitcode | Yes | |
Tier2boss | unitcode | Yes | |
Tier2enemy | unitcode | Yes | |
Tier3bossmajor | unitcode | Yes | |
Tier3enemy | unitcode | Yes | |
Tier4boss | unitcode | Yes | |
Tier4enemy | unitcode | Yes | |
Tier5boss | unitcode | Yes | |
Tier5enemy | unitcode | Yes | |
Tier6bossmajor2 | unitcode | Yes | |
Tier6enemy | unitcode | Yes | |
Tier7boss | unitcode | Yes | |
Tier8boss | unitcode | Yes | |
Tier9finalboss | unitcode | Yes | |
Tiersideboss | unitcode | Yes | |
Timestamp | timer | No | |
TRdummyh | unit | No | |
TRhash | hashtable | No | |
TRindexD | integer | No | |
TRindexN | integer | No | |
TRisEnabled | boolean | No | |
TRtimers | timer | Yes | |
TRtrig | trigger | No | |
u | unit | No | |
UHandle | integer | No | |
Unit1 | unit | No | |
Unit2 | unit | No | |
Waves | timer | No | |
WavesWin | timerdialog | No | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
X | real | Yes | |
Y | real | Yes |
library TeamViewer
//TeamViewer 1.3
//Plugin for HeroSelector by Tasyen
//It shows the selection of Teams in groups
//Default setup could be suited for 2 team games
//API
// TeamViewerDestroy()
// destroys Frames created by TeamViewer
// TeamViewerInit()
// creates Frames of TeamViewer, normaly should be called at the end of HeroSelectors Init
globals
private boolean ShowNonAllies = true //show non allies
private boolean UpdateNonAllies = false //update the image of non allies when the select or pick
//position when ShowNonAllies = false or when a TeamPos is not set
//how big are the Faces
private real ButtonSize = 0.03
private integer ButtonAlphaSelected = 150
private string ButtonDefaultIcon = "UI\\Widgets\\EscMenu\\Human\\quest-unknown.blp"
private real CategoryButtonSize = 0.015 //size of the CategoryButtons below an players name
private real CategoryButtonGap = 0.002 // space between 2 CategoryButtons
//used when ShowNonAllies = true
//warcraft 3 Teams start with 0
private real array TeamPosX
private real array TeamPosY
private real array TeamPosGapY
private boolean array TeamPosLeft2Right
private boolean array HasPicked
private framehandle array playerParentFrame
private framehandle array playerFaceButton
private framehandle array playerFaceIcon
private framehandle array playerFaceIconDisabled
private framehandle array playerFaceTooltip
private framehandle array playerFaceName
private framehandle array LastTeamFaceButton
//2D
private framehandle array playerCategoryIcon
private framehandle array playerCategoryButton
private framehandle array playerCategoryTooltip
private string array OriginalHex
endglobals
function TeamViewerSetup takes nothing returns nothing
set TeamPosX[0] = 0.02
set TeamPosY[0] = 0.5
set TeamPosGapY[0] = 0.015
set TeamPosLeft2Right[0] = true
set TeamPosX[1] = 0.75
set TeamPosY[1] = 0.5
set TeamPosGapY[1] = 0.015
set TeamPosLeft2Right[1] = false
//player_Color is Copied from TriggerHappy
set OriginalHex[0] = "|cffff0303"
set OriginalHex[1] = "|cff0042ff"
set OriginalHex[2] = "|cff1ce6b9"
set OriginalHex[3] = "|cff540081"
set OriginalHex[4] = "|cfffffc01"
set OriginalHex[5] = "|cfffe8a0e"
set OriginalHex[6] = "|cff20c000"
set OriginalHex[7] = "|cffe55bb0"
set OriginalHex[8] = "|cff959697"
set OriginalHex[9] = "|cff7ebff1"
set OriginalHex[10] = "|cff106246"
set OriginalHex[11] = "|cff4e2a04"
if (bj_MAX_PLAYERS > 12) then
set OriginalHex[12] = "|cff9B0000"
set OriginalHex[13] = "|cff0000C3"
set OriginalHex[14] = "|cff00EAFF"
set OriginalHex[15] = "|cffBE00FE"
set OriginalHex[16] = "|cffEBCD87"
set OriginalHex[17] = "|cffF8A48B"
set OriginalHex[18] = "|cffBFFF80"
set OriginalHex[19] = "|cffDCB9EB"
set OriginalHex[20] = "|cff282828"
set OriginalHex[21] = "|cffEBF0FF"
set OriginalHex[22] = "|cff00781E"
set OriginalHex[23] = "|cffA46F33"
endif
endfunction
function TeamViewerDestroy takes nothing returns nothing
local player p
local integer playerIndex = 0
local integer buttonIndex
local integer categoryButtonIndex
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
call BlzDestroyFrame(playerFaceButton[playerIndex])
call BlzDestroyFrame(playerFaceName[playerIndex])
call BlzDestroyFrame(playerFaceIcon[playerIndex])
call BlzDestroyFrame(playerFaceIconDisabled[playerIndex])
call BlzDestroyFrame(playerFaceTooltip[playerIndex])
call BlzDestroyFrame(playerParentFrame[playerIndex])
set playerFaceButton[playerIndex] = null
set playerFaceName[playerIndex] = null
set playerFaceIcon[playerIndex] = null
set playerFaceIconDisabled[playerIndex] = null
set playerFaceTooltip[playerIndex] = null
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
call BlzDestroyFrame(playerCategoryButton[categoryButtonIndex])
call BlzDestroyFrame(playerCategoryIcon[categoryButtonIndex])
call BlzDestroyFrame(playerCategoryTooltip[categoryButtonIndex])
set playerCategoryButton[categoryButtonIndex] = null
set playerCategoryIcon[categoryButtonIndex] = null
set playerCategoryTooltip[categoryButtonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
endif
set playerIndex = playerIndex + 1
endloop
endfunction
private function PosFirstFrame takes framehandle movingFrame, framehandle relativFrame, boolean left2Right returns nothing
if left2Right then
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPLEFT, relativFrame, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
else
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_TOPRIGHT, relativFrame, FRAMEPOINT_BOTTOMLEFT, 0, 0)
endif
endfunction
private function PosFrame takes framehandle movingFrame, framehandle relativFrame, boolean left2Right returns nothing
if left2Right then
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_LEFT, relativFrame, FRAMEPOINT_RIGHT, CategoryButtonGap, 0)
else
call BlzFrameSetPoint(movingFrame, FRAMEPOINT_RIGHT, relativFrame, FRAMEPOINT_LEFT, -CategoryButtonGap, 0)
endif
endfunction
function TeamViewerInit takes nothing returns nothing
local player p
local integer playerIndex = 0
local integer teamNr
local boolean left2Right = false
local integer createContext
local integer buttonIndex
local integer categoryButtonIndex
call TeamViewerSetup()
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
set teamNr = GetPlayerTeam(p)
set createContext = 1000 + playerIndex
set playerParentFrame[playerIndex] = BlzCreateFrameByType("FRAME", "TeamViewerPlayerFrame", HeroSelectorBox, "", createContext)
set playerFaceButton[playerIndex] = BlzCreateFrame("HeroSelectorButton", playerParentFrame[playerIndex], 0, createContext)
set playerFaceName[playerIndex] = BlzCreateFrame("HeroSelectorTitle", playerParentFrame[playerIndex], 0, createContext) // do not the buttons child, else it is affected by Alpha change
set playerFaceIcon[playerIndex] = BlzGetFrameByName("HeroSelectorButtonIcon", createContext)
set playerFaceIconDisabled[playerIndex] = BlzGetFrameByName("HeroSelectorButtonIconDisabled", createContext)
set playerFaceTooltip[playerIndex] = BlzCreateFrame("HeroSelectorText", playerFaceButton[playerIndex], 0, createContext)
if ShowNonAllies then
set left2Right = TeamPosLeft2Right[teamNr]
else
set left2Right = TeamPosLeft2Right[0]
endif
call BlzFrameSetSize(playerFaceButton[playerIndex], ButtonSize, ButtonSize)
if LastTeamFaceButton[teamNr] == null then
if ShowNonAllies then
call BlzFrameSetAbsPoint(playerFaceButton[playerIndex], FRAMEPOINT_BOTTOMLEFT, TeamPosX[teamNr], TeamPosY[teamNr])
else
call BlzFrameSetAbsPoint(playerFaceButton[playerIndex], FRAMEPOINT_BOTTOMLEFT, TeamPosX[0], TeamPosY[0])
endif
else
call BlzFrameSetPoint(playerFaceButton[playerIndex], FRAMEPOINT_TOPLEFT, LastTeamFaceButton[teamNr], FRAMEPOINT_BOTTOMLEFT, 0, -TeamPosGapY[teamNr])
endif
set LastTeamFaceButton[teamNr] = playerFaceButton[playerIndex]
call PosFrame(playerFaceName[playerIndex], playerFaceButton[playerIndex], left2Right)
if left2Right then
call BlzFrameSetPoint(playerFaceTooltip[playerIndex], FRAMEPOINT_BOTTOMLEFT, playerFaceButton[playerIndex], FRAMEPOINT_TOPLEFT, 0, 0)
else
call BlzFrameSetPoint(playerFaceTooltip[playerIndex], FRAMEPOINT_BOTTOMRIGHT, playerFaceButton[playerIndex], FRAMEPOINT_TOPRIGHT, 0, 0)
endif
call BlzFrameSetText(playerFaceName[playerIndex], OriginalHex[GetPlayerId(p)] + GetPlayerName(p))
call BlzFrameSetTooltip(playerFaceButton[playerIndex], playerFaceTooltip[playerIndex])
call BlzFrameSetTexture(playerFaceIcon[playerIndex], ButtonDefaultIcon, 0, true)
//print("Pre HeroSelector.Category")
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
//print("playerIndex",key)
set playerCategoryButton[categoryButtonIndex] = BlzCreateFrameByType("BUTTON", "", playerParentFrame[playerIndex], "", 0)
set playerCategoryIcon[categoryButtonIndex] = BlzCreateFrameByType("BACKDROP", "", playerCategoryButton[categoryButtonIndex], "", 0)
set playerCategoryTooltip[categoryButtonIndex] = BlzCreateFrame("HeroSelectorText", playerCategoryButton[categoryButtonIndex], 0, categoryButtonIndex)
call BlzFrameSetText(playerCategoryTooltip[categoryButtonIndex], BlzFrameGetText(HeroSelector_CategoryTooltipFrame[buttonIndex]))
call BlzFrameSetTooltip( playerCategoryButton[categoryButtonIndex], playerCategoryTooltip[categoryButtonIndex])
call BlzFrameSetAllPoints(playerCategoryIcon[categoryButtonIndex], playerCategoryButton[categoryButtonIndex])
call BlzFrameSetPoint(playerCategoryTooltip[categoryButtonIndex], FRAMEPOINT_BOTTOM, playerCategoryButton[categoryButtonIndex], FRAMEPOINT_TOP, 0, 0)
call BlzFrameSetSize( playerCategoryButton[categoryButtonIndex], 0.015, 0.015)
call BlzFrameSetTexture(playerCategoryIcon[categoryButtonIndex], HeroSelector_CategoryTexture[buttonIndex], 0, true)
call BlzFrameSetVisible( playerCategoryButton[categoryButtonIndex], false)
set buttonIndex = buttonIndex + 1
endloop
//When showning only allies, hide non allies
if not ShowNonAllies and not IsPlayerAlly(p, GetLocalPlayer()) then
call BlzFrameSetVisible(playerParentFrame[playerIndex], false)
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function TeamViewerButtonSelected takes player p, integer unitCode returns nothing
local integer playerIndex = GetPlayerId(p)
local integer teamNr = GetPlayerTeam(p)
local framehandle prevCategoryButton = null
local integer category = 1
local boolean left2Right = false
local integer unitCodeIndex = LoadInteger(HeroSelector_Hash, unitCode, 0)
local integer unitCategory = HeroSelector_HeroCategory[unitCodeIndex]
local integer categoryButtonIndex
local integer buttonIndex = 1
if not HasPicked[playerIndex] then
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetText(playerFaceTooltip[playerIndex], GetObjectName(unitCode))
call BlzFrameSetTexture(playerFaceIcon[playerIndex], BlzGetAbilityIcon(unitCode), 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], ButtonAlphaSelected)
if ShowNonAllies then
set left2Right = TeamPosLeft2Right[teamNr]
else
set left2Right = TeamPosLeft2Right[0]
endif
loop
exitwhen buttonIndex > HeroSelector_CategoryButtonCount
set categoryButtonIndex = playerIndex*1000 + buttonIndex
call BlzFrameClearAllPoints(playerCategoryButton[categoryButtonIndex])
if BlzBitAnd(category, unitCategory) > 0 then
call BlzFrameSetVisible(playerCategoryButton[categoryButtonIndex], true)
if prevCategoryButton == null then
call PosFirstFrame(playerCategoryButton[categoryButtonIndex], playerFaceButton[playerIndex], left2Right)
else
call PosFrame(playerCategoryButton[categoryButtonIndex], prevCategoryButton, left2Right)
endif
set prevCategoryButton = playerCategoryButton[categoryButtonIndex]
else
call BlzFrameSetVisible(playerCategoryButton[categoryButtonIndex], false)
endif
set category = category + category
set buttonIndex = buttonIndex + 1
endloop
endif
endif
set prevCategoryButton = null
endfunction
function TeamViewerUnitCreated takes player p, unit u, boolean isRandom returns nothing
local integer playerIndex = GetPlayerId(p)
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetTexture(playerFaceIcon[playerIndex], BlzGetAbilityIcon(GetUnitTypeId(u)), 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], 255)
endif
set HasPicked[playerIndex] = true
endfunction
function TeamViewerRepick takes unit u, player p returns nothing
local integer playerIndex = GetPlayerId(p)
if UpdateNonAllies or IsPlayerAlly(GetLocalPlayer(), p) then
call BlzFrameSetTexture(playerFaceIcon[playerIndex], ButtonDefaultIcon, 0, true)
call BlzFrameSetAlpha(playerFaceButton[playerIndex], 255)
endif
set HasPicked[playerIndex] = false
endfunction
endlibrary
library HeroInfo
// 11
//Plugin for by Tasyen
//This Creates a TextDisplay which displays the name and the Extended tooltip of selected units
globals
private framehandle TextDisplay
private string DescHeroNamePrefix = "|cffffcc00" //added before the Units Name
private string DescHeroNameSufix = "|r" //added after the units Name
private real TextAreaSizeX = 0.32
private real TextAreaSizeY = 0.25
private real TextAreaOffsetX = 0.0
private real TextAreaOffsetY = 0.0
private framepointtype TextAreaPoint = FRAMEPOINT_TOPLEFT //pos the Tooltip with which Point
private framepointtype TextAreaRelativePoint = FRAMEPOINT_TOPRIGHT //pos the Tooltip to which Point of the Relative
private boolean TextAreaRelativeGame = false //(false) relativ to box, (true) relativ to GameUI
endglobals
function HeroInfoDestroy takes nothing returns nothing
call BlzDestroyFrame(TextDisplay)
set TextDisplay = null
endfunction
function HeroInfoInit takes nothing returns nothing
set TextDisplay = BlzCreateFrame("HeroSelectorTextArea", HeroSelectorBox, 0, 0)
call BlzFrameSetSize(TextDisplay , TextAreaSizeX, TextAreaSizeY)
if not TextAreaRelativeGame then
call BlzFrameSetPoint(TextDisplay, TextAreaPoint, HeroSelectorBox, TextAreaRelativePoint, TextAreaOffsetX, TextAreaOffsetY)
else
call BlzFrameSetPoint(TextDisplay, TextAreaPoint, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), TextAreaRelativePoint, TextAreaOffsetX, TextAreaOffsetY)
endif
endfunction
function HeroInfoButtonSelected takes player p, integer unitCode returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetText(TextDisplay, DescHeroNamePrefix + GetObjectName(unitCode) + DescHeroNameSufix)
call BlzFrameAddText(TextDisplay, BlzGetAbilityExtendedTooltip(unitCode,0))
endif
endfunction
endlibrary
library HeroSelector
//HeroSelector V1.3.0
//API
//=====
//HeroSelectorForcePick()
//HeroSelectorForcePickPlayer(player p)
//HeroSelectorForcePickRace(race r)
//HeroSelectorForcePickTeam(integer teamNr)
//HeroSelectorForceRandom()
//HeroSelectorForceRandomRace(race r)
//HeroSelectorForceRandomTeam(integer teamNr)
//HeroSelectorDoPick(player p)
//HeroSelectorDoRandom(player p)
//HeroSelectorShow(boolean flag)
//HeroSelectorShowForce(boolean flag, force f)
//HeroSelectorShowRace(boolean flag, race r)
//HeroSelectorShowPlayer(boolean flag, player p)
//HeroSelectorShowTeam(boolean flag, integer teamNr)
//HeroSelectorEnableBan(boolean flag)
//HeroSelectorEnableBanRace
//HeroSelectorEnableBanTeam
//HeroSelectorEnableBanPlayer
//HeroSelectorEnableBanForce
//HeroSelectorEnablePick(boolean flag)
//HeroSelectorEnablePickForce
//HeroSelectorEnablePickPlayer
//HeroSelectorEnablePickTeam
//HeroSelectorEnablePickRace
//HeroSelectorRollOption(player p, boolean includeRandomOnly, integer exculdedIndex, integer category) returns integer
//HeroSelectorCounterChangeUnitCode(integer unitCode, integer add, player p)
//HeroSelectorEnableButtonIndex(integer unitCode, integer buttonIndex)
//HeroSelectorDisableButtonIndex(integer buttonIndex, integer teamNr)
//HeroSelectorButtonRequirementDone(integer unitCode, player p) returns boolean
//HeroSelectorDeselectButton(integer buttonIndex)
//HeroSelectorAddUnit(integer unitCode, boolean onlyRandom)
//HeroSelectorAddUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitCategory(integer unitCode, integer category)
//HeroSelectorSetUnitReqPlayer(integer unitCode, player p)
//HeroSelectorSetUnitReqRace(integer unitCode, race r)
//HeroSelectorSetUnitReqForce(integer unitCode, force f)
//HeroSelectorSetUnitReqTeam(integer unitCode, integer teamNr)
//HeroSelectorSetFrameText(framehandle frame, string text)
//HeroSelectorSetFrameTextPlayer
//HeroSelectorSetFrameTextForce
//HeroSelectorSetFrameTextTeam
//HeroSelectorSetFrameTextRace
//HeroSelectorSetTitleText(string text)
//HeroSelectorSetTitleTextRace
//HeroSelectorSetTitleTextPlayer
//HeroSelectorSetTitleTextForce
//HeroSelectorSetTitleTextTeam
//HeroSelectorSetBanButtonText
//HeroSelectorSetBanButtonTextPlayer
//HeroSelectorSetBanButtonTextRace
//HeroSelectorSetBanButtonTextForce
//HeroSelectorSetBanButtonTextTeam
//HeroSelectorSetRandomButtonText
//HeroSelectorSetRandomButtonTextPlayer
//HeroSelectorSetRandomButtonTextForce
//HeroSelectorSetRandomButtonTextTeam
//HeroSelectorSetRandomButtonTextRace
//HeroSelectorSetAcceptButtonText
//HeroSelectorSetAcceptButtonTextPlayer
//HeroSelectorSetAcceptButtonTextForce
//HeroSelectorSetAcceptButtonTextTeam
//HeroSelectorSetAcceptButtonTextRace
//HeroSelectorAddCategory(string icon, string text) //should only be used before the category Buttons are created
//HeroSelectorGetDisabledIcon(string iconPath)
//HeroSelectorUpdate()
//=====
globals
//Setup
//Box
private string BoxFrameName = "EscMenuBackdrop" //this is the background box being created
private real BoxPosX = 0.3
private real BoxPosY = 0.4
private framepointtype BoxPosPoint = FRAMEPOINT_CENTER
private boolean AutoShow = true //(true) shows the box and the Selection at 0.0 for all players
//Unique Picks
private integer UnitCount = 1 //each hero is in total allowed to be picked this amount of times (includes random, repicking allows a hero again).
private integer UnitCountPerTeam = 1 //Each Team is allowed to pick this amount of each unitType
//Ban
private boolean DelayBanUntilPick = false //(true) baning will not be applied instantly, instead it is applied when HeroSelectorEnablePick is called the next time.
//Category
private boolean CategoryAffectRandom = true //(false) random will not care about selected category
private boolean CategoryMultiSelect = false //(false) deselect other category when selecting one, (true) can selected multiple categories and all heroes having any of them are not filtered.
private real CategorySize = 0.02 //the size of the Category Button
private real CategorySpaceX = 0.0010 //space between 2 category Buttons, it is meant to need only one line of Categoryy Buttons.
private integer CategoryFilteredAlpha = 45 // Alpha value of Heroes being filtered by unselected categories
private boolean CategoryAutoDetectHero = true // Will create and remove added Heroes to read and setup the Category for the primary Attribute Str(4) Agi(8) Int(16)
//Icon path, tooltip Text (tries to localize)
//Indicator
private framehandle IndicatorSelected
private string IndicatorPathPick = "UI\\Feedback\\Autocast\\UI-ModalButtonOn.mdl" //this model is used by the indicator during picking
private string IndicatorPathBan = "war3mapImported\\HeroSelectorBan.mdl" //this model is used by the indicator during baning
//Grid
private real SpaceBetweenX = 0.010 //space between 2 buttons in one row
private real SpaceBetweenY = 0.010 //space between 2 rows
private integer ButtonColCount = 2 //amount of buttons in one row
private integer ButtonRowCount = 4 //amount of rows
private boolean ChainedButtons = true //(true) connect to the previous button/ or row, (false) have a offset to the box topLeft in this moving a button has no effect on other buttons.
//Button
private real ButtonSize = 0.06 //size of each button
private boolean ButtonBlendAll = false //(true) when a hero icon uses transparenzy
private string EmptyButtonPath = "UI\\Widgets\\EscMenu\\Human\\blank-background.blp"
//Ban Button
private string BanButtonTextPrefix = "|cffcf2084" //Prefix Text for the Ban Button
private string BanButtonText = "CHAT_ACTION_BAN" //tries to get a Localized String
private real BanButtonSizeX = 0.13
private real BanButtonSizeY = 0.03
//Accept Button
private string AcceptButtonTextPrefix = ""
private string AcceptButtonText = "ACCEPT"
private real AcceptButtonSizeX = 0.085
private real AcceptButtonSizeY = 0.03
private boolean AcceptButtonIsShown = true
private framepointtype AcceptButtonAnchor = FRAMEPOINT_BOTTOMRIGHT //places the Accept button with which Point to the bottom, with right he is at the left
//Random Button
private string RandomButtonTextPrefix = ""
private string RandomButtonText = "RANDOM" //tries Localizing
private real RandomButtonSizeX = 0.085
private real RandomButtonSizeY = 0.03
private boolean RandomButtonIsShown = true
private framepointtype RandomButtonAnchor = FRAMEPOINT_BOTTOMLEFT
private boolean RandomButtonPick = false //(true) pressing the random button will pick the option. (false) pressing the random button will select a button, random only heroes can not be selected, but that does not matter. This weak random and randomonly should not be combined.
//Tooltip
private string TooltipPrefix = "|cffffcc00"
private real TooltipOffsetX = 0
private real TooltipOffsetY = 0
private framepointtype TooltipPoint = FRAMEPOINT_BOTTOM //pos the Tooltip with which Point
private framepointtype TooltipRelativePoint = FRAMEPOINT_TOP //pos the Tooltip to which Point of the Relative
private boolean TooltipRelativIsBox = false //(true) use the box as anchor, (false) use the button as anchor
//System variables, Do not touch
public integer HeroButtonCount = ButtonRowCount*ButtonColCount
private trigger CategoryClickTrigger = CreateTrigger()
private trigger AcceptButtonTrigger = CreateTrigger()
private trigger BanButtonTrigger = CreateTrigger()
private trigger RandomButtonTrigger = CreateTrigger()
private framehandle BanButton
private framehandle AcceptButton
private framehandle RandomButton
private player array DelayBanPlayer
private integer array DelayBanUnitCode
private integer DelayBanCount = 0
public framehandle array CategoryButton
public framehandle array CategoryIconFrame
public framehandle array CategoryTooltipFrame
public string array CategoryText
public string array CategoryTexture
public string array CategoryTextureDisabled
private integer array CategoryButtonValue
public integer CategoryButtonCount = 0
private integer array UsedTeamNr
private integer UsedTeamNrCount = 0
private integer ButtonHeroCount = 0
private integer array ButtonHeroUnitCode
private integer array HeroTotalCount
public integer array HeroCategory
private integer array HeroRegType
private player array HeroRegPlayer
private force array HeroRegForce
private integer array HeroRegTeam
private race array HeroRegRace
private integer HeroCount = 0
private integer array HeroUnitCode
private integer array HeroButtonIndex
public hashtable Hash = InitHashtable()
framehandle HeroSelectorBox
private framehandle HeroSelectorBoxTitle
private integer array HeroButtonUnitCode
private integer HeroButtonUnitCodeCount = 0
private framehandle array HeroButtonIcon
private framehandle array HeroButtonIconDisabled
private framehandle array HeroButtonTooltip
private framehandle array HeroButtonFrame
private trigger HeroButtonClickTrigger = CreateTrigger()
private integer array PlayerSelectedButtonIndex
private integer array PlayerSelectedCategory
private integer array PlayerLastSelectedCategoryIndex
endglobals
private function AutoDetectCategory takes integer unitCode returns integer
local integer value = 0
local unit u
local integer primaryAttribute
if IsUnitIdType(unitCode, UNIT_TYPE_MELEE_ATTACKER) then
set value = 1
elseif IsUnitIdType(unitCode, UNIT_TYPE_RANGED_ATTACKER) then
set value = 2
endif
if CategoryAutoDetectHero and IsUnitIdType(unitCode, UNIT_TYPE_HERO) then
set u = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), unitCode, 0, 0, 270)
set primaryAttribute = BlzGetUnitIntegerField(u, UNIT_IF_PRIMARY_ATTRIBUTE)
call RemoveUnit(u)
set u = null
if ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_STR then
set value = value + 4
elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_AGI then
set value = value + 8
elseif ConvertHeroAttribute(primaryAttribute) == HERO_ATTRIBUTE_INT then
set value = value + 16
endif
endif
return value
endfunction
private function GetBorderSize takes nothing returns real
if GetPlayerRace(GetLocalPlayer()) == RACE_HUMAN then
return 0.025
elseif GetPlayerRace(GetLocalPlayer()) == RACE_ORC then
return 0.029
elseif GetPlayerRace(GetLocalPlayer()) == RACE_UNDEAD then
return 0.035
elseif GetPlayerRace(GetLocalPlayer()) == RACE_NIGHTELF then
return 0.035
elseif GetPlayerRace(GetLocalPlayer()) == RACE_DEMON then
return 0.024
else
return 0.0
endif
endfunction
function HeroSelectorDestroy takes nothing returns nothing
local integer buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
call BlzDestroyFrame(HeroButtonIcon[buttonIndex])
call BlzDestroyFrame(HeroButtonIconDisabled[buttonIndex])
call BlzDestroyFrame(HeroButtonFrame[buttonIndex])
call BlzDestroyFrame(HeroButtonTooltip[buttonIndex])
set HeroButtonTooltip[buttonIndex] = null
set HeroButtonFrame[buttonIndex] = null
set HeroButtonIcon[buttonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
set buttonIndex = 1
loop
exitwhen buttonIndex > CategoryButtonCount
call BlzDestroyFrame(CategoryButton[buttonIndex])
call BlzDestroyFrame(CategoryIconFrame[buttonIndex])
call BlzDestroyFrame(CategoryTooltipFrame[buttonIndex])
set CategoryButton[buttonIndex] = null
set CategoryIconFrame[buttonIndex] = null
set CategoryTooltipFrame[buttonIndex] = null
set buttonIndex = buttonIndex + 1
endloop
call BlzDestroyFrame(HeroSelectorBox)
call BlzDestroyFrame(HeroSelectorBoxTitle)
call BlzDestroyFrame(BanButton)
call BlzDestroyFrame(RandomButton)
call BlzDestroyFrame(AcceptButton)
call BlzDestroyFrame(IndicatorSelected)
set HeroSelectorBox = null
set HeroSelectorBoxTitle = null
set BanButton = null
set RandomButton = null
set AcceptButton = null
set IndicatorSelected = null
call DestroyTrigger(CategoryClickTrigger)
call DestroyTrigger(BanButtonTrigger)
call DestroyTrigger(RandomButtonTrigger)
call DestroyTrigger(HeroButtonClickTrigger)
set CategoryClickTrigger = null
set BanButtonTrigger = null
set RandomButtonTrigger = null
set HeroButtonClickTrigger = null
endfunction
//=====
//code start
//=====
function HeroSelectorGetDisabledIcon takes string icon returns string
//ReplaceableTextures\CommandButtons\BTNHeroPaladin.tga -> ReplaceableTextures\CommandButtonsDisabled\DISBTNHeroPaladin.tga
if SubString(icon, 34, 35) != "\\" then
return icon
endif //this string has not enough chars return it
//string.len(icon) < 34 then return icon end //this string has not enough chars return it
return SubString(icon, 0, 34) + "Disabled\\DIS" + SubString(icon, 35, StringLength(icon))
endfunction
function HeroSelectorAddCategory takes string icon, string text returns nothing
//adds an data category construct
set CategoryButtonCount = CategoryButtonCount + 1
set CategoryText[CategoryButtonCount] = text
set CategoryTexture[CategoryButtonCount] = icon
set CategoryTextureDisabled[CategoryButtonCount] = HeroSelectorGetDisabledIcon(icon)
if CategoryButtonCount > 1 then
set CategoryButtonValue[CategoryButtonCount] = CategoryButtonValue[CategoryButtonCount - 1]*2
else
set CategoryButtonValue[CategoryButtonCount] = 1
endif
endfunction
function HeroSelectorSetFrameText takes framehandle frame, string text returns nothing
call BlzFrameSetText(frame, text)
endfunction
function HeroSelectorSetFrameTextPlayer takes framehandle frame, string text, player p returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextTeam takes framehandle frame, string text, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextRace takes framehandle frame, string text, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetFrameTextForce takes framehandle frame, string text, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call BlzFrameSetText(frame, text)
endif
endfunction
function HeroSelectorSetTitleText takes string text returns nothing
call HeroSelectorSetFrameText(HeroSelectorBoxTitle, text)
endfunction
function HeroSelectorSetTitleTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetTitleTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(HeroSelectorBoxTitle, text, who)
endfunction
function HeroSelectorSetBanButtonText takes string text returns nothing
call HeroSelectorSetFrameText(BanButton, text)
endfunction
function HeroSelectorSetBanButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(BanButton, text, who)
endfunction
function HeroSelectorSetBanButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(BanButton, text, who)
endfunction
function HeroSelectorSetRandomButtonText takes string text returns nothing
call HeroSelectorSetFrameText(RandomButton, text)
endfunction
function HeroSelectorSetRandomButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(RandomButton, text, who)
endfunction
function HeroSelectorSetRandomButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(RandomButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonText takes string text returns nothing
call HeroSelectorSetFrameText(AcceptButton, text)
endfunction
function HeroSelectorSetAcceptButtonTextPlayer takes string text, player who returns nothing
call HeroSelectorSetFrameTextPlayer(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextForce takes string text, force who returns nothing
call HeroSelectorSetFrameTextForce(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextTeam takes string text, integer who returns nothing
call HeroSelectorSetFrameTextTeam(AcceptButton, text, who)
endfunction
function HeroSelectorSetAcceptButtonTextRace takes string text, race who returns nothing
call HeroSelectorSetFrameTextRace(AcceptButton, text, who)
endfunction
function HeroSelectorSetUnitCategory takes integer unitCode, integer category returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroCategory[index] = category
endfunction
function HeroSelectorAddUnitCategory takes integer unitCode, integer category returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroCategory[index] = BlzBitOr(category, HeroCategory[index])
endfunction
function HeroSelectorDeselectButton takes integer buttonIndex returns nothing
local integer playerIndex = 0
if buttonIndex > 0 then
if PlayerSelectedButtonIndex[GetPlayerId(GetLocalPlayer())] == buttonIndex then
call BlzFrameSetVisible(IndicatorSelected, false)
endif
loop
exitwhen playerIndex == GetBJMaxPlayers()
if PlayerSelectedButtonIndex[playerIndex] == buttonIndex then
set PlayerSelectedButtonIndex[playerIndex] = 0
endif
set playerIndex = playerIndex + 1
endloop
else
loop
exitwhen playerIndex == GetBJMaxPlayers()
set PlayerSelectedButtonIndex[playerIndex] = 0
set playerIndex = playerIndex + 1
endloop
call BlzFrameSetVisible(IndicatorSelected, false)
endif
endfunction
function HeroSelectorSetUnitReqRace takes integer unitCode, race r returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 1
set HeroRegRace[index] = r
endfunction
function HeroSelectorSetUnitReqForce takes integer unitCode, force f returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 4
set HeroRegForce[index] = f
endfunction
function HeroSelectorSetUnitReqPlayer takes integer unitCode, player p returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 3
set HeroRegPlayer[index] = p
endfunction
function HeroSelectorSetUnitReqTeam takes integer unitCode, integer teamNr returns nothing
local integer index = LoadInteger(Hash, unitCode, 0)
set HeroRegType[index] = 2
set HeroRegTeam[index] = teamNr
endfunction
function HeroSelectorButtonRequirementDone takes integer unitCode, player p returns boolean
//true when no requirement is set or the requirment call is successful
local integer index = LoadInteger(Hash, unitCode, 0)
if HeroRegType[index] == 0 then //no requirement
return true
elseif HeroRegType[index] == 1 and HeroRegRace[index] == GetPlayerRace(p) then
return true
elseif HeroRegType[index] == 2 and HeroRegTeam[index] == GetPlayerTeam(p) then
return true
elseif HeroRegType[index] == 3 and HeroRegPlayer[index] == p then
return true
elseif HeroRegType[index] == 4 and BlzForceHasPlayer(HeroRegForce[index], p) then
return true
endif
return false
endfunction
function HeroSelectorDisableButtonIndex takes integer buttonIndex, integer teamNr returns nothing
local integer playerIndex = 0
if buttonIndex > 0 then
if teamNr == -1 or teamNr == GetPlayerTeam(GetLocalPlayer()) then
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
endif
if PlayerSelectedButtonIndex[GetPlayerId(GetLocalPlayer())] == buttonIndex then
call BlzFrameSetVisible(IndicatorSelected, false)
endif
//deselect this Button from all players or the team
loop
exitwhen playerIndex == GetBJMaxPlayers()
if (teamNr == -1 or teamNr == GetPlayerTeam(Player(playerIndex))) and PlayerSelectedButtonIndex[playerIndex] == buttonIndex then
set PlayerSelectedButtonIndex[playerIndex] = 0
endif
set playerIndex = playerIndex + 1
endloop
endif
endfunction
function HeroSelectorEnableButtonIndex takes integer unitCode, integer buttonIndex returns nothing
if buttonIndex > 0 then
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], true and HeroSelectorButtonRequirementDone(unitCode, GetLocalPlayer()))
endif
endfunction
function HeroSelectorCounterChangeUnitCode takes integer unitCode, integer add, player p returns nothing
local integer unitCodeIndex = LoadInteger(Hash, unitCode, 0)
local integer buttonIndex = HeroButtonIndex[unitCodeIndex]
local integer teamNr = GetPlayerTeam(p)
local integer teamKey = StringHash("TeamCount"+I2S(teamNr))
set HeroTotalCount[unitCodeIndex] = HeroTotalCount[unitCodeIndex] + add
call SaveInteger(Hash, unitCode, teamKey, LoadInteger(Hash, unitCode, teamKey) + add)
if HeroTotalCount[unitCodeIndex] >= UnitCount then
//disable for all
call HeroSelectorDisableButtonIndex(buttonIndex, -1)
else
//enable for all
call HeroSelectorEnableButtonIndex(unitCode, buttonIndex)
if LoadInteger(Hash, unitCode, teamKey) >= UnitCountPerTeam then
//disable for this team
call HeroSelectorDisableButtonIndex(buttonIndex, teamNr)
endif
endif
endfunction
function HeroSelectorRollOption takes player p, boolean includeRandomOnly, integer exculdedIndex, integer category returns integer
local integer teamNr = GetPlayerTeam(p)
local integer array options
local integer optionCount = 0
local integer teamKey = StringHash("TeamCount"+I2S(teamNr))
local boolean allowed
local integer index = 1
local integer unitCode
local integer unitCodeIndex
loop
exitwhen index > HeroCount
set unitCode = HeroUnitCode[index]
set unitCodeIndex = LoadInteger(Hash, unitCode, 0)
set allowed = true
//total limited reached?
if HeroTotalCount[unitCodeIndex] >= UnitCount then
set allowed = false
//print(GetObjectName(unitCode))
//print("rejected total limit")
endif
//team limited reached?
if allowed and LoadInteger(Hash, unitCode, teamKey) >= UnitCountPerTeam then
//print(GetObjectName(unitCode))
//print("rejected team limit")
set allowed = false
endif
//allow randomOnly?
if allowed and not includeRandomOnly and HeroButtonIndex[unitCodeIndex] == 0 then
//print(GetObjectName(unitCode))
//print("rejected random only")
set allowed = false
endif
//this index is excluded? This can make sure you get another button.
if allowed and HeroButtonIndex[unitCodeIndex] > 0 and HeroButtonIndex[unitCodeIndex] == exculdedIndex then
//print(GetObjectName(unitCode))
//print("rejected exclude")
set allowed = false
endif
//fullfills the requirement?
if allowed and not HeroSelectorButtonRequirementDone(unitCode, p) then
//print(GetObjectName(unitCode))
//print("rejected requirement")
set allowed = false
endif
//when having an given an category only allow options having that category atleast partly
if allowed and category > 0 and BlzBitAnd(category, HeroCategory[unitCodeIndex]) == 0 then
//print(GetObjectName(unitCode))
//print(" rejected category", category, HeroSelector.UnitData[unitCode].Category)
set allowed = false
endif
if allowed then
set optionCount = optionCount + 1
set options[optionCount] = unitCode
endif
set index = index + 1
endloop
//nothing is allwoed?
if optionCount == 0 then
return 0
else
return options[GetRandomInt(1, optionCount)]
endif
endfunction
function HeroSelectorEnablePickDelayBanAction takes nothing returns nothing
loop
exitwhen DelayBanCount <= 0
call HeroSelectorCounterChangeUnitCode(DelayBanUnitCode[DelayBanCount], UnitCount + 1, DelayBanPlayer[DelayBanCount])
set DelayBanCount = DelayBanCount - 1
endloop
endfunction
function HeroSelectorEnablePickAction takes boolean flag returns nothing
call BlzFrameSetVisible(AcceptButton, true and AcceptButtonIsShown)
call BlzFrameSetVisible(RandomButton, true and RandomButtonIsShown)
call BlzFrameSetVisible(BanButton, false)
call BlzFrameSetEnable(AcceptButton, flag)
call BlzFrameSetEnable(RandomButton, flag)
call BlzFrameSetModel(IndicatorSelected, IndicatorPathPick, 0)
endfunction
function HeroSelectorEnablePick takes boolean flag returns nothing
call HeroSelectorEnablePickDelayBanAction()
call HeroSelectorEnablePickAction(flag)
endfunction
function HeroSelectorEnablePickPlayer takes boolean flag, player p returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetLocalPlayer() == p then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickTeam takes boolean flag, integer teamNr returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickRace takes boolean flag, race r returns nothing
call HeroSelectorEnablePickDelayBanAction()
if GetPlayerRace(GetLocalPlayer()) == r then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnablePickForce takes boolean flag, force f returns nothing
call HeroSelectorEnablePickDelayBanAction()
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call HeroSelectorEnablePickAction(flag)
endif
endfunction
function HeroSelectorEnableBanPlayerAction takes boolean flag returns nothing
call BlzFrameSetVisible(AcceptButton, false)
call BlzFrameSetVisible(RandomButton, false)
call BlzFrameSetVisible(BanButton, true)
call BlzFrameSetEnable(BanButton, flag)
call BlzFrameSetModel(IndicatorSelected, IndicatorPathBan, 0)
endfunction
function HeroSelectorEnableBanPlayer takes boolean flag, player p returns nothing
if GetLocalPlayer() == p then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanForce takes boolean flag, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanTeam takes boolean flag, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBanRace takes boolean flag, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call HeroSelectorEnableBanPlayerAction(flag)
endif
endfunction
function HeroSelectorEnableBan takes boolean flag returns nothing
call HeroSelectorEnableBanPlayerAction(flag)
endfunction
function HeroSelectorframeLoseFocus takes framehandle frame returns nothing
if BlzFrameGetEnable(frame) then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
endif
endfunction
function HeroSelectorUpdate takes nothing returns nothing
local integer buttonIndex = 1
local integer unitCodeIndex
local integer teamNr
local integer teamIndex = 1
local integer teamKey
loop
exitwhen buttonIndex > HeroButtonCount
//have data for this button?
if HeroButtonUnitCode[buttonIndex] > 0 then
set unitCodeIndex = LoadInteger(Hash, HeroButtonUnitCode[buttonIndex],0)
if HeroTotalCount[unitCodeIndex] >= UnitCount then
//disable for all
call HeroSelectorDisableButtonIndex(buttonIndex, -1)
else
//enable for all
call HeroSelectorEnableButtonIndex(HeroButtonUnitCode[buttonIndex], buttonIndex)
loop
exitwhen teamIndex > UsedTeamNrCount
set teamNr = UsedTeamNr[teamIndex]
set teamKey = StringHash("TeamCount"+I2S(teamNr))
if LoadInteger(Hash, HeroButtonUnitCode[buttonIndex], teamKey) >= UnitCountPerTeam then
//disable for this team
call HeroSelectorDisableButtonIndex(buttonIndex, teamNr)
endif
set teamIndex = teamIndex + 1
endloop
endif
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex]), 0, ButtonBlendAll)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], HeroSelectorGetDisabledIcon(BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex])), 0, ButtonBlendAll)
call BlzFrameSetText(HeroButtonTooltip[buttonIndex], TooltipPrefix + GetObjectName(HeroButtonUnitCode[buttonIndex]))
else
//no, make it unclickable and empty
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], EmptyButtonPath, 0, true)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], EmptyButtonPath, 0, true)
endif
set buttonIndex = buttonIndex + 1
endloop
endfunction
function HeroSelectorShowFramePlayer takes framehandle frame, boolean flag, player p returns nothing
if GetLocalPlayer() == p then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameForce takes framehandle frame, boolean flag, force f returns nothing
if BlzForceHasPlayer(f, GetLocalPlayer()) then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameTeam takes framehandle frame, boolean flag, integer teamNr returns nothing
if GetPlayerTeam(GetLocalPlayer()) == teamNr then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowFrameRace takes framehandle frame, boolean flag, race r returns nothing
if GetPlayerRace(GetLocalPlayer()) == r then
call BlzFrameSetVisible(frame, flag)
endif
endfunction
function HeroSelectorShowPlayer takes boolean flag, player who returns nothing
call HeroSelectorShowFramePlayer(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowTeam takes boolean flag, integer who returns nothing
call HeroSelectorShowFrameTeam(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowRace takes boolean flag, race who returns nothing
call HeroSelectorShowFrameRace(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShowForce takes boolean flag, force who returns nothing
call HeroSelectorShowFrameForce(HeroSelectorBox, flag, who)
endfunction
function HeroSelectorShow takes boolean flag returns nothing
call BlzFrameSetVisible(HeroSelectorBox, flag)
endfunction
function HeroSelectorAddUnit takes integer unitCode, boolean onlyRandom returns nothing
//no unitCode => empty field
if unitCode == 0 then
set ButtonHeroCount = ButtonHeroCount + 1
else
//Such an object Exist? not unique?
if GetObjectName(unitCode) == "" or HaveSavedBoolean(Hash, unitCode, 0) then
return
endif
set HeroCount = HeroCount + 1
set HeroUnitCode[HeroCount] = unitCode
call SaveBoolean(Hash, unitCode, 0, true)
call SaveInteger(Hash, unitCode, 0, HeroCount)
set HeroCategory[HeroCount] = AutoDetectCategory(unitCode)
if not onlyRandom then
set ButtonHeroCount = ButtonHeroCount + 1
set HeroButtonIndex[HeroCount] = ButtonHeroCount
set ButtonHeroUnitCode[ButtonHeroCount] = unitCode
endif
endif
endfunction
function HeroSelectorDoRandom takes player p returns nothing
local integer category = 0
local integer unitCode
local unit u
if CategoryAffectRandom then
set category = PlayerSelectedCategory[GetPlayerId(p)]
endif
set unitCode = HeroSelectorRollOption(p, true, 0, category)
if unitCode == 0 then
return
endif
set u = CreateUnit(p, unitCode, 0, 0, 0)
call HeroSelectorCounterChangeUnitCode(unitCode, 1, p)
set udg_HeroSelectorEventUnit = u
set udg_HeroSelectorEventIsRandom = true
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 1.0
set udg_HeroSelectorEvent = 0.0
set u = null
endfunction
function HeroSelectorDoPick takes player p returns boolean
local integer unitCode
local unit u
//pick what currently is selected, returns true on success returns false when something went wrong,
local integer buttonIndex = PlayerSelectedButtonIndex[GetPlayerId(p)]
if buttonIndex <= 0 then
return false
endif //reject nothing selected
set unitCode = HeroButtonUnitCode[buttonIndex]
set u = CreateUnit(p, unitCode, 0, 0, 0)
call HeroSelectorCounterChangeUnitCode(unitCode, 1, p)
set udg_HeroSelectorEventUnit = u
set udg_HeroSelectorEventIsRandom = false
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 1.0
set udg_HeroSelectorEvent = 0.0
set u = null
return true
endfunction
function HeroSelectorForceRandom takes nothing returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
call HeroSelectorDoRandom(p)
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForceRandomTeam takes integer who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerTeam(p) == who then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForceRandomRace takes race who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerRace(p) == who then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
set p = null
endfunction
function HeroSelectorForcePick takes nothing returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickTeam takes integer who returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerTeam(p) == who then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickRace takes race r returns nothing
//this is a wrapper for doRandom allowing different dataTypes
local player p
local integer playerIndex = 0
loop
exitwhen playerIndex == GetBJMaxPlayers()
set p = Player(playerIndex)
if GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
if GetPlayerRace(p) == r then
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endif
endif
set playerIndex = playerIndex + 1
endloop
endfunction
function HeroSelectorForcePickPlayer takes player p returns nothing
if not HeroSelectorDoPick(p) then
call HeroSelectorDoRandom(p)
endif
endfunction
function HeroSelectorActionPressHeroButton takes nothing returns nothing
local framehandle fh = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local integer buttonIndex = LoadInteger(Hash, GetHandleId(fh), 0)
local integer unitCode = HeroButtonUnitCode[buttonIndex]
set PlayerSelectedButtonIndex[GetPlayerId(p)] = buttonIndex
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if GetLocalPlayer() == p then
call BlzFrameSetVisible(IndicatorSelected, true)
call BlzFrameSetPoint(IndicatorSelected, FRAMEPOINT_TOPLEFT, fh, FRAMEPOINT_TOPLEFT, -0.001, 0.001)
call BlzFrameSetPoint(IndicatorSelected, FRAMEPOINT_BOTTOMRIGHT, fh, FRAMEPOINT_BOTTOMRIGHT, -0.0012, -0.0016)
endif
set udg_HeroSelectorEventUnit = null
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 2.0
set udg_HeroSelectorEvent = 0.0
set fh = null
set p = null
endfunction
function HeroSelectorActionRandomButton takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer unitCode
local integer unitCodeIndex
local integer buttonIndex
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if RandomButtonPick then
call HeroSelectorDoRandom(p)
else
set unitCode = HeroSelectorRollOption(p, false, PlayerSelectedButtonIndex[playerIndex], PlayerSelectedCategory[playerIndex])
if unitCode > 0 and GetLocalPlayer() == p then
set unitCodeIndex = LoadInteger(Hash, unitCode, 0)
set buttonIndex = HeroButtonIndex[unitCodeIndex]
call BlzFrameClick(HeroButtonFrame[buttonIndex])
endif
endif
set p = null
endfunction
function HeroSelectorActionAcceptButton takes nothing returns nothing
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
call HeroSelectorDoPick(GetTriggerPlayer())
endfunction
function HeroSelectorActionBanButton takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer buttonIndex = PlayerSelectedButtonIndex[playerIndex]
local integer unitCode = HeroButtonUnitCode[buttonIndex]
call HeroSelectorframeLoseFocus(BlzGetTriggerFrame())
if buttonIndex > 0 then
if not DelayBanUntilPick then
call HeroSelectorCounterChangeUnitCode(unitCode, UnitCount + 1, p)
else
set DelayBanCount = DelayBanCount + 1
set DelayBanPlayer[DelayBanCount] = p
set DelayBanUnitCode[DelayBanCount] = unitCode
endif
set udg_HeroSelectorEventUnit = null
set udg_HeroSelectorEventUnitCode = unitCode
set udg_HeroSelectorEventPlayer = p
set udg_HeroSelectorEvent = 0.0
set udg_HeroSelectorEvent = 3.0
set udg_HeroSelectorEvent = 0.0
endif
set p = null
endfunction
function HeroSelectorActionCategoryButton takes nothing returns nothing
local integer buttonIndex
local framehandle fh = BlzGetTriggerFrame()
local integer categoryIndex = LoadInteger(Hash, GetHandleId(fh), 0)
local integer lastCategoryIndex
local player p = GetTriggerPlayer()
local integer playerIndex = GetPlayerId(p)
local integer unitCodeIndex
call HeroSelectorframeLoseFocus(fh)
//has this category already?
if BlzBitAnd(PlayerSelectedCategory[playerIndex], CategoryButtonValue[categoryIndex]) != 0 then
//yes, unable
set PlayerSelectedCategory[playerIndex] = PlayerSelectedCategory[playerIndex] - CategoryButtonValue[categoryIndex]
if GetLocalPlayer() == p then
call BlzFrameSetTexture(CategoryIconFrame[categoryIndex], CategoryTextureDisabled[categoryIndex], 0, true)
endif
else
if not CategoryMultiSelect and PlayerSelectedCategory[playerIndex] != 0 then
set lastCategoryIndex = PlayerLastSelectedCategoryIndex[playerIndex]
call BlzFrameSetTexture(CategoryIconFrame[lastCategoryIndex], CategoryTextureDisabled[lastCategoryIndex], 0, true)
set PlayerSelectedCategory[playerIndex] = 0
endif
//no, enable
set PlayerSelectedCategory[playerIndex] = PlayerSelectedCategory[playerIndex] + CategoryButtonValue[categoryIndex]
if GetLocalPlayer() == p then
call BlzFrameSetTexture(CategoryIconFrame[categoryIndex], CategoryTexture[categoryIndex], 0, true)
endif
set PlayerLastSelectedCategoryIndex[playerIndex] = categoryIndex
endif
if GetLocalPlayer() == p then
//update all buttons
//buttons not having at least 1 selected category becomes partly transparent
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
if HeroButtonUnitCode[buttonIndex] > 0 then
set unitCodeIndex = LoadInteger(Hash, HeroButtonUnitCode[buttonIndex],0)
if PlayerSelectedCategory[playerIndex] == 0 or BlzBitAnd(HeroCategory[unitCodeIndex], PlayerSelectedCategory[playerIndex]) > 0 then
call BlzFrameSetAlpha(HeroButtonFrame[buttonIndex], 255)
else
call BlzFrameSetAlpha(HeroButtonFrame[buttonIndex], CategoryFilteredAlpha)
endif
endif
set buttonIndex = buttonIndex + 1
endloop
endif
set fh = null
set p = null
endfunction
function HeroSelectorInit takes nothing returns nothing
local integer buttonIndex
local real titleSize = 0.015
local real borderSize = GetBorderSize()
local integer colCount = ButtonColCount
local integer rowCount = ButtonRowCount
local framehandle box = BlzCreateFrame(BoxFrameName, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
local integer rowRemaining = colCount
local real y = -borderSize - titleSize - 0.0125 - CategorySize
local real x = borderSize
local integer playerIndex = 0
local integer teamIndexLoop
local integer teamNr
call ExecuteFunc("HeroSelectorAction_InitHeroes")
call BlzLoadTOCFile("war3mapImported\\HeroSelector.toc") //ex/import also "HeroSelector.fdf"
//for key, value in ipairs(HeroSelector.UnitData)
//do
// print(key, ('>I4'):pack(value), GetObjectName(value))
//end
//find all Teams in usage
loop
exitwhen playerIndex == GetBJMaxPlayers()
set teamNr = GetPlayerTeam(Player(playerIndex))
if teamNr != -1 then
set teamIndexLoop = UsedTeamNrCount
loop
exitwhen teamIndexLoop == 0
exitwhen UsedTeamNr[teamIndexLoop] == teamNr
set teamIndexLoop = teamIndexLoop - 1
endloop
if teamIndexLoop == 0 then
set UsedTeamNrCount = UsedTeamNrCount + 1
set UsedTeamNr[UsedTeamNrCount] = teamNr
endif
endif
set playerIndex = playerIndex + 1
endloop
call TriggerAddAction(HeroButtonClickTrigger, function HeroSelectorActionPressHeroButton)
set HeroSelectorBoxTitle = BlzCreateFrame("HeroSelectorTitle", box, 0, 0)
set IndicatorSelected = BlzCreateFrameByType("SPRITE", "MyHeroIndikator", box, "", 0)
set HeroSelectorBox = box
call BlzFrameSetModel(IndicatorSelected, IndicatorPathPick, 0)
call BlzFrameSetScale(IndicatorSelected, ButtonSize/0.036) //scale the model to the button size.
call BlzFrameSetVisible(IndicatorSelected, false)
call BlzFrameSetAbsPoint(box, BoxPosPoint, BoxPosX, BoxPosY)
call BlzFrameSetSize(box, borderSize*2 + ButtonSize*colCount + SpaceBetweenX*(colCount-1), borderSize*2 + ButtonSize*rowCount + SpaceBetweenY*(rowCount - 1) + titleSize + CategorySize + 0.0145)
call BlzFrameSetPoint(HeroSelectorBoxTitle, FRAMEPOINT_TOP, box, FRAMEPOINT_TOP, 0, -borderSize)
call BlzFrameSetText(HeroSelectorBoxTitle, "Hero Selection")
if colCount*rowCount < ButtonHeroCount then
call BJDebugMsg("FieldCount:"+ I2S(colCount*rowCount) + "HeroCount" + I2S(ButtonHeroCount))
endif
set buttonIndex = 1
loop
exitwhen buttonIndex > HeroButtonCount
set HeroButtonFrame[buttonIndex] = BlzCreateFrame("HeroSelectorButton", box, 0, buttonIndex)
set HeroButtonIcon[buttonIndex] = BlzGetFrameByName("HeroSelectorButtonIcon", buttonIndex)
set HeroButtonIconDisabled[buttonIndex] = BlzGetFrameByName("HeroSelectorButtonIconDisabled", buttonIndex)
set HeroButtonUnitCode[buttonIndex] = ButtonHeroUnitCode[buttonIndex]
call SaveInteger(Hash, GetHandleId(HeroButtonFrame[buttonIndex]), 0, buttonIndex)
set HeroButtonTooltip[buttonIndex] = BlzCreateFrame("HeroSelectorText", box, 0, buttonIndex)
call BlzFrameSetTooltip(HeroButtonFrame[buttonIndex], HeroButtonTooltip[buttonIndex])
if not TooltipRelativIsBox then
call BlzFrameSetPoint(HeroButtonTooltip[buttonIndex], TooltipPoint, HeroButtonFrame[buttonIndex], TooltipRelativePoint, TooltipOffsetX ,TooltipOffsetY)
else
call BlzFrameSetPoint(HeroButtonTooltip[buttonIndex], TooltipPoint, box, TooltipRelativePoint, TooltipOffsetX ,TooltipOffsetY)
endif
call BlzTriggerRegisterFrameEvent(HeroButtonClickTrigger, HeroButtonFrame[buttonIndex], FRAMEEVENT_CONTROL_CLICK)
call BlzFrameSetSize(HeroButtonFrame[buttonIndex], ButtonSize, ButtonSize)
if HeroButtonUnitCode[buttonIndex] > 0 then
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex]), 0, ButtonBlendAll)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], HeroSelectorGetDisabledIcon(BlzGetAbilityIcon(HeroButtonUnitCode[buttonIndex])), 0, ButtonBlendAll)
call BlzFrameSetText(HeroButtonTooltip[buttonIndex], TooltipPrefix + GetObjectName(HeroButtonUnitCode[buttonIndex]))
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], HeroSelectorButtonRequirementDone(HeroButtonUnitCode[buttonIndex], GetLocalPlayer()))
else
call BlzFrameSetEnable(HeroButtonFrame[buttonIndex], false)
call BlzFrameSetTexture(HeroButtonIcon[buttonIndex], EmptyButtonPath, 0, true)
call BlzFrameSetTexture(HeroButtonIconDisabled[buttonIndex], EmptyButtonPath, 0, true)
endif
if ChainedButtons then //buttons are connected to the previous one or the previous row
if buttonIndex == 1 then
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, borderSize, y)
elseif rowRemaining <= 0 then
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, HeroButtonFrame[buttonIndex - colCount], FRAMEPOINT_BOTTOMLEFT, 0, -SpaceBetweenY)
set rowRemaining = colCount
else
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_LEFT, HeroButtonFrame[buttonIndex - 1], FRAMEPOINT_RIGHT, SpaceBetweenX, 0)
endif
else //buttons have an offset to the TopLeft of the box
if rowRemaining <= 0 then
set x = borderSize
set rowRemaining = colCount
set y = y - SpaceBetweenY - ButtonSize
elseif buttonIndex != 1 then
set x = x + ButtonSize + SpaceBetweenX
endif
call BlzFrameSetPoint(HeroButtonFrame[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, x, y)
endif
set rowRemaining = rowRemaining - 1
set buttonIndex = buttonIndex + 1
endloop
set y = -borderSize - titleSize - 0.0105
set x = borderSize
//create category buttons added before the box was created
set buttonIndex = 1
loop
exitwhen buttonIndex > CategoryButtonCount
set CategoryButton[buttonIndex] = BlzCreateFrameByType("BUTTON", "", box, "", 0)
set CategoryIconFrame[buttonIndex] = BlzCreateFrameByType("BACKDROP", "", box, "", 0)
set CategoryTooltipFrame[buttonIndex] = BlzCreateFrame("HeroSelectorText", box, 0, buttonIndex)
call BlzFrameSetText(CategoryTooltipFrame[buttonIndex], GetLocalizedString(CategoryText[buttonIndex]))
call BlzFrameSetPoint(CategoryTooltipFrame[buttonIndex], FRAMEPOINT_BOTTOM, CategoryButton[buttonIndex], FRAMEPOINT_TOP, 0, 0)
call BlzFrameSetTooltip(CategoryButton[buttonIndex], CategoryTooltipFrame[buttonIndex])
call BlzFrameSetAllPoints(CategoryIconFrame[buttonIndex], CategoryButton[buttonIndex])
call BlzFrameSetSize(CategoryButton[buttonIndex], CategorySize, CategorySize)
call BlzFrameSetTexture(CategoryIconFrame[buttonIndex], CategoryTextureDisabled[buttonIndex], 0, true)
call BlzTriggerRegisterFrameEvent(CategoryClickTrigger, CategoryButton[buttonIndex], FRAMEEVENT_CONTROL_CLICK)
if buttonIndex == 1 then
call BlzFrameSetPoint(CategoryButton[buttonIndex], FRAMEPOINT_TOPLEFT, box, FRAMEPOINT_TOPLEFT, x, y)
else
call BlzFrameSetPoint(CategoryButton[buttonIndex], FRAMEPOINT_LEFT, CategoryButton[buttonIndex - 1], FRAMEPOINT_RIGHT, CategorySpaceX, 0)
endif
call SaveInteger(Hash, GetHandleId(CategoryButton[buttonIndex]), 0, buttonIndex)
set buttonIndex = buttonIndex + 1
endloop
call TriggerAddAction(CategoryClickTrigger, function HeroSelectorActionCategoryButton)
set AcceptButton = BlzCreateFrameByType("GLUETEXTBUTTON", "OKButton", box, "ScriptDialogButton", 0)
set RandomButton = BlzCreateFrameByType("GLUETEXTBUTTON", "RandomButton", box, "ScriptDialogButton", 0)
set BanButton = BlzCreateFrameByType("GLUETEXTBUTTON", "BanButton", box, "ScriptDialogButton", 0)
call TriggerAddAction(AcceptButtonTrigger, function HeroSelectorActionAcceptButton)
call TriggerAddAction(RandomButtonTrigger, function HeroSelectorActionRandomButton)
call TriggerAddAction(BanButtonTrigger, function HeroSelectorActionBanButton)
call BlzTriggerRegisterFrameEvent(AcceptButtonTrigger, AcceptButton, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(RandomButtonTrigger, RandomButton, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(BanButtonTrigger, BanButton, FRAMEEVENT_CONTROL_CLICK)
call BlzFrameSetSize(AcceptButton, AcceptButtonSizeX, AcceptButtonSizeY)
call BlzFrameSetSize(RandomButton, RandomButtonSizeX, RandomButtonSizeY)
call BlzFrameSetSize(BanButton, BanButtonSizeX, BanButtonSizeY)
//OK, READY, ACCEPT
call BlzFrameSetText(AcceptButton, AcceptButtonTextPrefix + GetLocalizedString(AcceptButtonText))
call BlzFrameSetText(RandomButton, RandomButtonTextPrefix + GetLocalizedString(RandomButtonText))
call BlzFrameSetText(BanButton, BanButtonTextPrefix + GetLocalizedString(BanButtonText))
call BlzFrameSetPoint(AcceptButton, AcceptButtonAnchor, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetPoint(RandomButton, RandomButtonAnchor, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetPoint(BanButton, FRAMEPOINT_BOTTOM, box, FRAMEPOINT_BOTTOM, 0, 0)
call BlzFrameSetVisible(BanButton, false)
call BlzFrameSetVisible(AcceptButton, AcceptButtonIsShown)
call BlzFrameSetVisible(RandomButton, RandomButtonIsShown)
if not AutoShow then
call BlzFrameSetVisible(box, false)
endif
call ExecuteFunc("HeroInfoInit")
call ExecuteFunc("TeamViewerInit")
endfunction
endlibrary
library HeroSelectorAction initializer Init uses HeroSelector, TeamViewer, HeroInfo
//HeroSelectorAction V1.2.1
//what happens to the unit beeing picked, player is the one having pressed the button
function HeroSelectorUnitCreated takes nothing returns nothing
local player p = udg_HeroSelectorEventPlayer
local unit u = udg_HeroSelectorEventUnit
local boolean isRandom = udg_HeroSelectorEventIsRandom
set bj_lastCreatedUnit = u
if isRandom then
//randomed
else
//picked
endif
call SetUnitPosition(u, GetPlayerStartLocationX(p), GetPlayerStartLocationY(p))
if p == Player(1) then
endif
call TeamViewerUnitCreated(p, u, isRandom)
call PanCameraToTimedForPlayer(p, GetUnitX(u), GetUnitY(u),0)
call SelectUnitForPlayerSingle(u, p)
call HeroSelectorEnablePickPlayer(false, p) //only one pick for this player
set p = null
set u = null
endfunction
//happens when the banButton is pressed, player is the one having pressed the button
function HeroSelectorUnitBaned takes nothing returns nothing
local player p = udg_HeroSelectorEventPlayer
local integer unitCode = udg_HeroSelectorEventUnitCode
call HeroSelectorEnableBanPlayer(false, p) //only one ban
set p = null
endfunction
function HeroSelectorButtonSelected takes nothing returns nothing
//player who pressed the button
//unitCode the unitCode selected
//this is not picked.
local player p = udg_HeroSelectorEventPlayer
local integer unitCode = udg_HeroSelectorEventUnitCode
call HeroInfoButtonSelected(p, unitCode)
call TeamViewerButtonSelected(p, unitCode)
set p = null
endfunction
function HeroSelectorRepick takes unit u returns nothing
local integer unitCode
local player p = GetOwningPlayer(u)
call UnitRemoveBuffsBJ(bj_REMOVEBUFFS_ALL, u) //this is done to undo metamorph
set unitCode = GetUnitTypeId(u)
if unitCode == 0 then
return
endif
call HeroSelectorCounterChangeUnitCode(unitCode, -1, p)
call HeroSelectorShowPlayer(true, p)
call HeroSelectorEnablePickPlayer(true, p)
call TeamViewerRepick(u, p)
call RemoveUnit(u)
endfunction
//This runs before the box is created with that the system has the needed data right when it is needed.
//you can add units somewhere else but it is done after the box was created you have to use the update function to update the textures of shown buttons
public function InitHeroes takes nothing returns nothing
//create categories setuped in config
local integer index
local integer categoryMelee = 1 //autodetected
local integer categoryRanged = 2 //autodetected
local integer categoryStr = 4
local integer categoryAgi = 8
local integer categoryInt = 16
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSteelMelee", "MELEE") //1, automatic detected when adding an unit
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNHumanMissileUpOne", "Ranged") //2, automatic detected when adding an unit
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower", "STRENGTH") //4
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNSlippersOfAgility", "AGILITY") //8
call HeroSelectorAddCategory("ReplaceableTextures\\CommandButtons\\BTNMantleOfIntelligence", "INTELLECT") //16
//read GUI, when the variable exist
set index = 1
//add from index 1 all random only heroes
loop
exitwhen udg_HeroSelectorRandomOnly[index] == 0
call HeroSelectorAddUnit(udg_HeroSelectorRandomOnly[index], true)
set index = index + 1
endloop
set index = 1
//copy the setuped field
loop
exitwhen index > HeroSelector_HeroButtonCount
call HeroSelectorAddUnit(udg_HeroSelectorUnitCode[index], false)
set index = index + 1
endloop
//adding further units when using the GUI Array does not make much sense, except you would add rows.
call HeroSelectorAddUnit('Hgam', true) //antonidas is an only random Hero that can only be randomed by team 0 (for users 1).
call HeroSelectorAddUnit('Eevi', true) //evil Illidan is an only random Hero that can only be randomed by team 1 (for users 2).
//Adds requirments
//when you have a ban phase it might be better to add the requirments after the ban phase is over, otherwise one can only ban own options.
//human only work for human, as nightelf only for Nightelf
call HeroSelectorSetUnitReqRace('Hpal', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hamg', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hblm', RACE_HUMAN)
call HeroSelectorSetUnitReqRace('Hmkg', RACE_HUMAN)
//call HeroSelectorSetUnitReqRace('Ofar', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Oshd', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Otch', RACE_ORC)
//call HeroSelectorSetUnitReqRace('Obla', RACE_ORC)
call HeroSelectorSetUnitReqRace('Emoo', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Edem', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Ekee', RACE_NIGHTELF)
call HeroSelectorSetUnitReqRace('Ewar', RACE_NIGHTELF)
//call HeroSelectorSetUnitReqRace('Udea', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Ulic', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Udre', RACE_UNDEAD)
//call HeroSelectorSetUnitReqRace('Ucrl', RACE_UNDEAD)
endfunction
private function Init takes nothing returns nothing
local trigger trig
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 2.0 )
call TriggerAddAction(trig, function HeroSelectorButtonSelected)
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 1.0 )
call TriggerAddAction(trig, function HeroSelectorUnitCreated)
set trig = CreateTrigger()
call TriggerRegisterVariableEvent(trig, "udg_HeroSelectorEvent", EQUAL, 3.0 )
call TriggerAddAction(trig, function HeroSelectorUnitBaned)
endfunction
endlibrary
// Arcing Text Tag v1.0.0.3 by Maker
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.018 // Minimum size of text
private constant real SIZE_BONUS = 0.012 // Text size increase
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 50 // Height above unit
private constant real Z_OFFSET_BON = 50 // How much extra height the text gains
private constant real VELOCITY = 2 // How fast the text move in x/y plane
private constant real ANGLE = bj_PI/2 // Movement angle of the text. Does not apply if
// ANGLE_RND is true
private constant boolean ANGLE_RND = true // Is the angle random or fixed
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real ah // arc height
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*.t)
set .t = .t - 0.03125
set .x = .x + .ac
set .y = .y + .as
call SetTextTagPos(.tt, .x, .y, Z_OFFSET + Z_OFFSET_BON * p)
call SetTextTagText(.tt, .s, SIZE_MIN + SIZE_BONUS * p)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method create takes string s, unit u returns thistype
local thistype this = rn[0]
static if ANGLE_RND then
local real a = GetRandomReal(0, 2*bj_PI)
else
local real a = ANGLE
endif
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set .s = s
set .x = GetUnitX(u)
set .y = GetUnitY(u)
set .t = TIME_LIFE
set .as = Sin(a)*VELOCITY
set .ac = Cos(a)*VELOCITY
set .ah = 0.
if IsUnitVisible(u, GetLocalPlayer()) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE)
call SetTextTagFadepoint(.tt, TIME_FADE)
call SetTextTagText(.tt, s, SIZE_MIN)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
return this
endmethod
endstruct
endlibrary
//===========================================================================
//
// Damage Engine 5.5.0.0 - update requires copying of the Damage Engine folder.
//
//===========================================================================
library DamageEngine initializer Init
globals
private timer alarm = CreateTimer()
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private boolean canKick = true
private boolean totem = false
private real lastAmount = 0.00
private real lastPrevAmt = 0.00
private integer lastType = 0
private boolean lastCode = false
private real lastPierced = 0.00
private integer armorType = 0
private integer lastArmor = 0
private boolean lastAttack = false
private integer lastPrevArmor = 0
private integer defenseType = 0
private integer lastDefense = 0
private integer lastPrevDefense = 0
//Stuff to track recursive UnitDamageTarget calls.
private boolean eventsRun = false
private boolean kicking = false
private integer damageStack = 0
private unit array sourceStack
private unit array targetStack
private real array amountStack
private attacktype array attackTStack
private damagetype array damageTStack
private weapontype array weaponTStack
private integer array userTrigStack
private integer array typeStack
//Added in 5.4 to silently eliminate infinite recursion.
private integer userTrigs = 9
private integer eventTrig = 0
private integer array nextTrig
private trigger array userTrig
private boolean array trigFrozen
//Added/re-tooled in 5.4.1 to allow forced recursion (for advanced users only).
private constant integer LIMBO = 16 //Recursion will never go deeper than LIMBO.
private integer array levelsDeep //How deep the user recursion currently is.
public boolean inception = false //You must set DamageEngine_inception = true before dealing damage to utlize this.
//When true, it allows your trigger to potentially go recursive up to LIMBO.
private boolean dreaming = false
private boolean array inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
private integer sleepLevel = 0
private group proclusGlobal = CreateGroup() //track sources of recursion
private group fischerMorrow = CreateGroup() //track targets of recursion
//Improves readability in the code to have these as named constants.
private constant integer MOD_EVENT = 1
private constant integer SHIELD_EVENT = 4
private constant integer DAMAGE_EVENT = 5
private constant integer ZERO_EVENT = 6
private constant integer AFTER_EVENT = 7
private constant integer LETHAL_EVENT = 8
private constant integer AOE_EVENT = 9
//private string crashStr = ""
endglobals
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
*/
private function RunTrigs takes integer i returns nothing
local integer cat = i
if dreaming then
//call BJDebugMsg("Tried to run triggers while triggers were already running.")
return
endif
set dreaming = true
//call BJDebugMsg("Start of event running")
loop
set i = nextTrig[i]
exitwhen i == 0
exitwhen cat == MOD_EVENT and (udg_DamageEventOverride or udg_DamageEventType*udg_DamageEventType == 4)
exitwhen cat == SHIELD_EVENT and udg_DamageEventAmount <= 0.00
exitwhen cat == LETHAL_EVENT and udg_LethalDamageHP > 0.405
//set crashStr = "Bout to inspect " + I2S(i)
if not trigFrozen[i] and IsTriggerEnabled(userTrig[i]) then
set eventTrig = i
//set crashStr = "Bout to evaluate " + I2S(i)
if TriggerEvaluate(userTrig[i]) then
//set crashStr = "Bout to execute " + I2S(i)
call TriggerExecute(userTrig[i])
endif
//set crashStr = "Ran " + I2S(i)
//call BJDebugMsg("Ran " + I2S(i))
//if not (udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 or udg_DamageEventAmount == 0.00) then
// if cat == MOD_EVENT then
// set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
// elseif cat == SHIELD_EVENT then
// set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
// endif
//elseif udg_DamageEventPrevAmt == 0.00 then
// call BJDebugMsg("Prev amount 0.00 and User Amount " + R2S(udg_DamageEventAmount))
//elseif udg_DamageEventAmount == 0.00 then
// call BJDebugMsg("User amount 0.00 and Prev Amount " + R2S(udg_DamageEventPrevAmt))
//elseif udg_DamageScalingWC3 == 0.00 then
// call BJDebugMsg("WC3 amount somehow 0.00")
//endif
//set crashStr = "Filtered " + I2S(i)
//elseif i > 9 then
// if trigFrozen[i] then
// call BJDebugMsg("User Trigger is frozen")
// else
// call BJDebugMsg("User Trigger is off")
// endif
endif
endloop
//call BJDebugMsg("End of event running")
set dreaming = false
endfunction
private function OnAOEEnd takes nothing returns nothing
if udg_DamageEventAOE > 1 then
call RunTrigs(AOE_EVENT)
set udg_DamageEventAOE = 1
endif
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endfunction
private function AfterDamage takes nothing returns nothing
if udg_DamageEventPrevAmt != 0.00 and udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(AFTER_EVENT)
endif
endfunction
private function Finish takes nothing returns nothing
local integer i = 0
local integer exit
if eventsRun then
//call BJDebugMsg("events ran")
set eventsRun = false
call AfterDamage()
endif
if canKick and not kicking then
//call BJDebugMsg("can kick")
if damageStack > 0 then
set kicking = true
//call BJDebugMsg("Clearing queued damage instances: " + I2S(damageStack))
loop
set exit = damageStack
set sleepLevel = sleepLevel + 1
loop
set udg_NextDamageType = typeStack[i]
//call BJDebugMsg("Stacking on " + R2S(amountStack[i]))
call UnitDamageTarget(sourceStack[i], targetStack[i], amountStack[i], true, false, attackTStack[i], damageTStack[i], weaponTStack[i])
call AfterDamage()
set i = i + 1 //Need to loop bottom to top to make sure damage order is preserved.
exitwhen i == exit
endloop
//call BJDebugMsg("Exit at: " + I2S(i))
exitwhen i == damageStack
endloop
//call BJDebugMsg("Terminate at at: " + I2S(i))
set sleepLevel = 0
loop
set i = i - 1
set trigFrozen[userTrigStack[i]] = false //Only re-enable recursive triggers AFTER all damage is dealt.
set levelsDeep[userTrigStack[i]] = 0 //Reset this stuff if the user tried some nonsense
exitwhen i == 0
endloop
//call BJDebugMsg("Cleared queued damage instances: " + I2S(damageStack))
set damageStack = 0 //Can only be set after all the damage has successfully ended.
set kicking = false
endif
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//elseif kicking then
// call BJDebugMsg("Somehow still kicking")
//else
// call BJDebugMsg("Cannot kick")
endif
endfunction
private function ResetArmor takes nothing returns nothing
if udg_DamageEventArmorPierced != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + udg_DamageEventArmorPierced)
endif
if armorType != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, armorType) //revert changes made to the damage instance
endif
if defenseType != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, defenseType)
endif
endfunction
private function FailsafeClear takes nothing returns nothing
//call BJDebugMsg("Damage from " + GetUnitName(udg_DamageEventSource) + " to " + GetUnitName(udg_DamageEventTarget) + " has been messing up Damage Engine.")
//call BJDebugMsg(R2S(udg_DamageEventAmount) + " " + " " + R2S(udg_DamageEventPrevAmt) + " " + udg_AttackTypeDebugStr[udg_DamageEventAttackT] + " " + udg_DamageTypeDebugStr[udg_DamageEventDamageT])
call ResetArmor()
set canKick = true
set totem = false
set udg_DamageEventAmount = 0.00
set udg_DamageScalingWC3 = 0.00
if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(DAMAGE_EVENT) //Run the normal on-damage event based on this failure.
set eventsRun = true //Run the normal after-damage event based on this failure.
endif
call Finish()
endfunction
private function WakeUp takes nothing returns nothing
set alarmSet = false //The timer has expired. Flag off to allow it to be restarted when needed.
//if dreaming then
// set dreaming= false
// call BJDebugMsg("Timer set dreaming to False")
// call BJDebugMsg(crashStr)
//endif
if totem then
//Something went wrong somewhere; the WarCraft 3 engine didn't run the DAMAGED event despite running the DAMAGING event.
call FailsafeClear()
else
if not canKick and damageStack > 0 then
//call BJDebugMsg("Damage Engine recursion deployment was failing with application of: " + R2S(udg_DamageEventAmount))
set canKick = true
endif
call Finish() //Wrap up any outstanding damage instance
endif
call OnAOEEnd() //Reset things so they don't perpetuate for AoE/Level target detection
set udg_DamageEventPrevAmt = 0.00 //Added in 5.4.2.1 to try to squash the Cold Arrows glitch (failed to do it)
endfunction
private function CalibrateMR takes nothing returns nothing
set udg_IsDamageMelee = false
set udg_IsDamageRanged = false
set udg_IsDamageSpell = udg_DamageEventAttackT == 0 and not udg_IsDamageAttack
if udg_DamageEventDamageT == udg_DAMAGE_TYPE_NORMAL and not udg_IsDamageSpell then //This damage type is the only one that can get reduced by armor.
set udg_IsDamageMelee = IsUnitType(udg_DamageEventSource, UNIT_TYPE_MELEE_ATTACKER)
set udg_IsDamageRanged = IsUnitType(udg_DamageEventSource, UNIT_TYPE_RANGED_ATTACKER)
if udg_IsDamageMelee and udg_IsDamageRanged then
set udg_IsDamageMelee = udg_DamageEventWeaponT > 0// Melee units play a sound when damaging
set udg_IsDamageRanged = not udg_IsDamageMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif // The Huntress has a melee sound for her ranged projectile, however it is only an issue
endif //if she also had a melee attack, because by default she is only UNIT_TYPE_RANGED_ATTACKER.
endfunction
private function OnPreDamage takes nothing returns boolean
local unit src = GetEventDamageSource()
local unit tgt = GetTriggerUnit()
local real amt = GetEventDamage()
local attacktype at = BlzGetEventAttackType()
local damagetype dt = BlzGetEventDamageType()
local weapontype wt = BlzGetEventWeaponType()
//call BJDebugMsg("First damage event running")
if dreaming then
//call BJDebugMsg("Dreaming")
if amt != 0.00 then
//Store recursive damage into a queue from index "damageStack" (0-15)
//This damage will be fired after the current damage instance has wrapped up its events.
//This damage can only be caused by triggers.
set amountStack[damageStack] = amt
set sourceStack[damageStack] = src
set targetStack[damageStack] = tgt
set attackTStack[damageStack] = at
set damageTStack[damageStack] = dt
set weaponTStack[damageStack] = wt
set userTrigStack[damageStack] = eventTrig
if udg_NextDamageType == 0 then
set typeStack[damageStack] = udg_DamageTypeCode
else
set typeStack[damageStack] = udg_NextDamageType
endif
//Next block added in 5.4.1 to allow *some* control over whether recursion should kick
//in. Also it's important to track whether the source and target were both involved at
//some earlier point, so this is a more accurate and lenient method than before.
set inception = inception or inceptionTrig[eventTrig]
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
if kicking and IsUnitInGroup(src, proclusGlobal) and IsUnitInGroup(tgt, fischerMorrow) then
if inception and not trigFrozen[eventTrig] then
set inceptionTrig[eventTrig] = true
if levelsDeep[eventTrig] < sleepLevel then
set levelsDeep[eventTrig] = levelsDeep[eventTrig] + 1
if levelsDeep[eventTrig] >= LIMBO then
set trigFrozen[eventTrig] = true
endif
endif
else
set trigFrozen[eventTrig] = true
endif
endif
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(levelsDeep[eventTrig]) + " sleepLevel: " + I2S(sleepLevel))
call BlzSetEventDamage(0.00) //queue the damage instance instead of letting it run recursively
endif
else
if not kicking then
//Added 25 July 2017 to detect AOE damage or multiple single-target damage
if alarmSet then
if totem then
if dt != DAMAGE_TYPE_SPIRIT_LINK and dt != DAMAGE_TYPE_DEFENSIVE and dt != DAMAGE_TYPE_PLANT then
//if 'totem' is still set and it's not due to spirit link distribution or defense retaliation,
//the next function must be called as a debug. This reverts an issue I created in patch 5.1.3.
call FailsafeClear()
else
set totem = false
set lastAmount = udg_DamageEventAmount
set lastPrevAmt = udg_DamageEventPrevAmt //Store the actual pre-armor value.
set lastType = udg_DamageEventType //also store the damage type.
set lastCode = udg_IsDamageCode //store this as well.
set lastAttack = udg_IsDamageAttack //Added after this new Reforged native.
set lastArmor = udg_DamageEventArmorT
set lastPrevArmor = armorType
set lastDefense = udg_DamageEventDefenseT
set lastPrevDefense = defenseType
set lastPierced = udg_DamageEventArmorPierced
set canKick = false
endif
else
call Finish()
endif
if src != udg_AOEDamageSource then //Source has damaged more than once
call OnAOEEnd() //New damage source - unflag everything
set udg_AOEDamageSource = src
elseif tgt == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1 //The number of times the same unit was hit.
elseif not IsUnitInGroup(tgt, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1 //Multiple targets hit by this source - flag as AOE
endif
else
call TimerStart(alarm, 0.00, false, function WakeUp)
set alarmSet = true
set udg_AOEDamageSource = src
set udg_EnhancedDamageTarget= tgt
endif
call GroupAddUnit(udg_DamageEventAOEGroup, tgt)
endif
set udg_DamageEventType = udg_NextDamageType
set udg_IsDamageCode = udg_NextDamageType != 0
set udg_IsDamageAttack = BlzGetEventIsAttack()
set udg_DamageEventOverride = dt == null //Got rid of NextDamageOverride in 5.1 for simplicity
set udg_DamageEventPrevAmt = amt
set udg_DamageEventSource = src
set udg_DamageEventTarget = tgt
set udg_DamageEventAmount = amt
set udg_DamageEventAttackT = GetHandleId(at)
set udg_DamageEventDamageT = GetHandleId(dt)
set udg_DamageEventWeaponT = GetHandleId(wt)
call CalibrateMR() //Set Melee and Ranged settings.
set udg_DamageEventArmorT = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE) //Introduced in Damage Engine 5.2.0.0
set udg_DamageEventDefenseT = BlzGetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE)
set armorType = udg_DamageEventArmorT
set defenseType = udg_DamageEventDefenseT
set udg_DamageEventArmorPierced = 0.00
set udg_DamageScalingUser = 1.00
set udg_DamageScalingWC3 = 1.00
if amt != 0.00 then
if not udg_DamageEventOverride then
call RunTrigs(MOD_EVENT)
//All events have run and the pre-damage amount is finalized.
call BlzSetEventAttackType(ConvertAttackType(udg_DamageEventAttackT))
call BlzSetEventDamageType(ConvertDamageType(udg_DamageEventDamageT))
call BlzSetEventWeaponType(ConvertWeaponType(udg_DamageEventWeaponT))
if udg_DamageEventArmorPierced != 0.00 then
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) - udg_DamageEventArmorPierced)
endif
if armorType != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, udg_DamageEventArmorT) //Introduced in Damage Engine 5.2.0.0
endif
if defenseType != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, udg_DamageEventDefenseT) //Introduced in Damage Engine 5.2.0.0
endif
call BlzSetEventDamage(udg_DamageEventAmount)
endif
//call BJDebugMsg("Ready to deal " + R2S(udg_DamageEventAmount))
set totem = true
else
call RunTrigs(ZERO_EVENT)
set canKick = true
call Finish()
endif
endif
set src = null
set tgt = null
set inception = false
set udg_NextDamageType = 0
return false
endfunction
//The traditional on-damage response, where armor reduction has already been factored in.
private function OnDamage takes nothing returns boolean
local real r = GetEventDamage()
//call BJDebugMsg("Second damage event running")
if dreaming or udg_DamageEventPrevAmt == 0.00 then
//if dreaming then
// call BJDebugMsg("Dreaming")
//else
// call BJDebugMsg("Prev amount is zero")
//endif
return false
endif
if totem then
set totem = false //This should be the case in almost all circumstances
else
call AfterDamage() //Wrap up the outstanding damage instance
set canKick = true
//Unfortunately, Spirit Link and Thorns Aura/Spiked Carapace fire the DAMAGED event out of sequence with the DAMAGING event,
//so I have to re-generate a buncha stuff here.
set udg_DamageEventSource = GetEventDamageSource()
set udg_DamageEventTarget = GetTriggerUnit()
set udg_DamageEventAmount = lastAmount
set udg_DamageEventPrevAmt = lastPrevAmt
set udg_DamageEventAttackT = GetHandleId(BlzGetEventAttackType())
set udg_DamageEventDamageT = GetHandleId(BlzGetEventDamageType())
set udg_DamageEventWeaponT = GetHandleId(BlzGetEventWeaponType())
set udg_DamageEventType = lastType
set udg_IsDamageAttack = lastAttack
set udg_IsDamageCode = lastCode
set udg_DamageEventArmorT = lastArmor
set udg_DamageEventDefenseT = lastDefense
set udg_DamageEventArmorPierced = lastPierced
set armorType = lastPrevArmor
set defenseType = lastPrevDefense
call CalibrateMR() //Apply melee/ranged settings once again.
endif
call ResetArmor()
if udg_DamageEventAmount != 0.00 and r != 0.00 then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
set udg_DamageScalingUser = udg_DamageEventAmount / udg_DamageEventPrevAmt
endif
set udg_DamageEventAmount = udg_DamageEventAmount*udg_DamageScalingWC3
if udg_DamageEventAmount > 0.00 then
//This event is used for custom shields which have a limited hit point value
//The shield here kicks in after armor, so it acts like extra hit points.
call RunTrigs(SHIELD_EVENT)
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= 0.405 then
call RunTrigs(LETHAL_EVENT) //Added 10 May 2019 to detect and potentially prevent lethal damage. Instead of
//modifying the damage, you need to modify LethalDamageHP instead (the final HP of the unit).
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
if udg_DamageEventType < 0 and udg_LethalDamageHP <= 0.405 then
call SetUnitExploded(udg_DamageEventTarget, true) //Explosive damage types should blow up the target.
endif
endif
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
call BlzSetEventDamage(udg_DamageEventAmount) //Apply the final damage amount.
if udg_DamageEventDamageT != udg_DAMAGE_TYPE_UNKNOWN then
call RunTrigs(DAMAGE_EVENT)
endif
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call Finish()
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGED) //Thanks to this I no longer have to create an event for every unit in the map.
call TriggerAddCondition(trig, Filter(function OnDamage))
set trig = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DAMAGING) //The new 1.31 event which fires before damage.
call TriggerAddCondition(trig, Filter(function OnPreDamage))
set trig = null
endfunction
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
endfunction
//This function exists mainly to make it easier to switch from another DDS, like PDD.
function UnitDamageTargetEx takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns boolean
if udg_NextDamageType == 0 then
set udg_NextDamageType = udg_DamageTypeCode
endif
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
return dreaming
endfunction
public function SetupEvent takes trigger whichTrig, string var, integer index returns nothing
local integer max = 1
local integer off = 0
local integer exit = 0
local integer i
if var == "udg_DamageModifierEvent" then //MOD_EVENT 1-4 -> Events 1-4
if index < 3 then
set exit = index + 1
endif
if nextTrig[1] == 0 then
set nextTrig[1] = 2
set nextTrig[2] = 3
set trigFrozen[2] = true
set trigFrozen[3] = true
endif
set max = 4
elseif var == "udg_DamageEvent" then //DAMAGE_EVENT 1,2 -> Events 5,6
set max = 2
set off = 4
elseif var == "udg_AfterDamageEvent" then //AFTER_EVENT -> Event 7
set off = 6
elseif var == "udg_LethalDamageEvent" then //LETHAL_EVENT -> Event 8
set off = 7
elseif var == "udg_AOEDamageEvent" then //AOE_EVENT -> Event 9
set off = 8
else
return
endif
set i = IMaxBJ(IMinBJ(index, max), 1) + off
//call BJDebugMsg("Root index: " + I2S(i))
loop
set index = i
set i = nextTrig[i]
exitwhen i == exit
endloop
set userTrigs = userTrigs + 1 //User list runs from index 10 and up
set nextTrig[index] = userTrigs
set nextTrig[userTrigs] = exit
set userTrig[userTrigs] = whichTrig
//call BJDebugMsg("Registered " + I2S(userTrigs) + " to " + I2S(index))
endfunction
private function PreSetup takes trigger whichTrig, string var, limitop op, real value returns nothing
call SetupEvent(whichTrig, var, R2I(value))
endfunction
hook TriggerRegisterVariableEvent PreSetup
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
library ValueIndexing initializer Init
//===========================================================================
// Information:
//==============
// This is a library that allows you to get unique hashvalues for any number you like.
// This also gives the option to be directly added to the struct, so you will have this syntax:
// set Data['some'] = anyValue
//
// But you could also do it with table, right?
// Well that's correct, but in many cases this is faster;
// It is proven that LoadInteger is much faster than SaveInteger.
// When you apply new data to a normal table, SaveInteger is used.
// This system only uses SaveInteger if it hasn't created a hash yet.
//
// But the bad thing is that you should remove the hashvalues after a while, since
// there is a limit of 8191 unique hashnumbers. Also this is not available as a struct,
// just as a module.
//===========================================================================
// FAQ:
// ====
//
// 1. We have a maximum of 8190 possible hashes. And there's no clearHash function.
// Won't this break after a while?
//
// Answer: No, it won't. If the number of hahes reach a critical point, all hashes
// that have been in the game for longer than HASH_DECAY_TIME seconds will
// be removed then.
//
//===========================================================================
globals
private constant real HASH_DECAY_TIME = 500.
private constant integer CLEAR_HASH_COUNT = 8190
endglobals
globals
private hashtable HashTable = InitHashtable()
private integer HashNumber = 0
private integer array HashData
private integer array HashHash
private integer array HashPlace
private real array CreationTime
private integer TempHashNumber = 0
private integer array TempHashHash
private integer array TempHashPlace
private integer array TempHashData
private real array TempCreationTime
private integer LastHashedValue = 0
private integer LastIndex = 0
private real GameTime = 0.
private timer GameTimeTimer = CreateTimer()
private constant real GAMETIME_TIMER_INTERVAL = 30.
private constant integer key = 0
endglobals
private function GetElapsedGameTime takes nothing returns real
return GameTime + TimerGetElapsed(GameTimeTimer)
endfunction
private function UpdateGameTime takes nothing returns nothing
set GameTime = GameTime + GAMETIME_TIMER_INTERVAL
endfunction
// Well, the method to do this that I use in my automatic memory leak destroyer
// is much more efficient, but I think that's not iportant in this library,
// because old Hashes are destroyed very rarely.
private function DestroyHashes takes nothing returns nothing
local real gt = GetElapsedGameTime
local Index ind
// Well, due to the nature of this system, the looking of the code sucks.
loop
exitwhen HashNumber == 0
if gt - CreationTime[HashNumber] > HASH_DECAY_TIME then
set ind = HashHash[HashNumber]
call ind.destroy()
call RemoveSavedInteger(HashTable,key,HashData[HashNumber])
else
set TempHashNumber = TempHashNumber + 1
set TempHashData[TempHashNumber] = HashData[HashNumber]
set TempHashHash[TempHashNumber] = HashHash[HashNumber]
set TempHashPlace[TempHashNumber] = HashPlace[HashNumber]
set TempCreationTime[TempHashNumber] = CreationTime[HashNumber]
endif
set HashData[HashNumber] = 0
set HashHash[HashNumber] = 0
set HashPlace[HashNumber] = 0
set CreationTime[HashNumber] = 0.
set HashNumber = HashNumber - 1
endloop
loop
exitwhen TempHashNumber == 0
set HashNumber = HashNumber + 1
set HashData[HashNumber] = TempHashData[TempHashNumber]
set HashHash[HashNumber] = TempHashHash[TempHashNumber]
set HashPlace[HashNumber] = TempHashPlace[TempHashNumber]
set TempHashData[TempHashNumber] = 0
set TempHashNumber = TempHashNumber - 1
endloop
endfunction
struct Index
static method GetHash takes integer value returns integer
local integer int = LoadInteger(HashTable,key,value)
if int == 0 then
set int = Index.create()
call SaveInteger(HashTable,key,value,int)
set HashNumber = HashNumber + 1
set HashPlace[int] = HashNumber
set HashData[HashNumber] = value
set HashHash[HashNumber] = int
set CreationTime[HashNumber] = GetElapsedGameTime()
if HashNumber >= CLEAR_HASH_COUNT then
call DestroyHashes()
endif
endif
set LastHashedValue = value
set LastIndex = int
return int
endmethod
endstruct
function ProtectHash takes integer value returns nothing
if value == LastHashedValue then
set CreationTime[HashPlace[LastIndex]] = 999999999.
else
set CreationTime[HashPlace[Index.GetHash(value)]] = 999999999.
endif
endfunction
function GetValueIndex takes integer value returns integer
return Index.GetHash(value)
endfunction
private function Init takes nothing returns nothing
call TimerStart(GameTimeTimer,GAMETIME_TIMER_INTERVAL,true,function UpdateGameTime)
endfunction
module ValueIndexing
static integer array Data
static method operator []= takes integer i, integer equals returns nothing
set .Data[Index.GetHash(i)] = equals
endmethod
static method operator [] takes integer i returns thistype
return .Data[Index.GetHash(i)]
endmethod
endmodule
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.0
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
//=============================================================
// initialize it all.
//
private static method onInit takes nothing returns nothing
set ht = InitHashtable()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=437
//TESH.alwaysfold=0
library MemoryLeakHelper initializer Init requires Table
// ==================================
// Give credits to Mr.Malte when used!
//===========================================================================
// Information:
//==============
//
// There are things called 'memory Leaks'. When you create a group or use a location
// without destroying it, you will cause lag that stays in the whole game.
// If you implement this library into your map it will automatically fix a big part
// of those memory leaks, so reduce the lag extremely.
// This should mainfully be used by GUI-users because the system is designed for them.
//
// Of course no system can work totally automatically.
// But there is only one thing you have to do in order to prevent bugs:
// If you make groups or locations that have to be filled for more than CLEAN_UP_INTERVAL seconds
// you have to save them with the code:
//
// call ProtectHandle(XXX)
//
// Where XXX is filled with your variable. Otherwise that variable gets destroyed
// automatically. You can also fill in XXX with
//
// GetLastCaughtHandle()
//
// But if you save the things in a variable, I'd recommend to directly put the
// variable into the brackets. Note: GUI variables have the prefix 'udg_' in JASS.
//
// This gives the 'Do Nothing' function in GUI a sense!
// When you call DoNothing, all data that were caught by this system
// will be destroyed in CLEAN_UP_INTERVAL seconds, ignoring how big
// the number of caught handles is. This will not work, if the system is
// already cleaning up.
//===========================================================================
// Implementation:
//===============
//
// The easiest thing is to directly implement this thing into your map, when you start making
// it, so you don't have to look over your globals and use ProtectHandle on them.
// These are the steps you have to do to clear the memory leaks:
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// http://www.wc3c.net/showthread.php?t=90999
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// http://www.wc3c.net/showthread.php?t=101246
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//
// Note: Instead of doing 2 and 3 you can also copy and paste the folder 'MemoryLeakHelper'
// from the example map.
//===========================================================================
// How bad are memory leaks?
//==========================
// If you don't remove memory leaks, they suck memory:
//
// Location: 0.361 kb
// Group: 0.62 kb + 0.040 kb for each unit in the group.
// Effect: 11.631 kb
//
// Both, locations and groups are used very frequently. So when you don't fix those memory leaks,
// you will experience lag.
// When you want to see, how useful this is for your map, implement it
// and write 'call DisplayLeaks()' into a custom script that is fired when
// they game ends.
//===========================================================================
// Changelog:
//===========
// v1.00 --- first version
// v1.01 --- able to detect special effects, too now.
// v1.02 --- made the system safer and reduced the number of variables to protect greatly.
// v1.03 --- Gave a sense to 'DoNothing'* GUI function and made the Pass Data part
// more accurate, so the time until data get destroyed are much more explicit
// now.
// v1.04 --- Added the very important constant MAX_LEAK_INSTANCES
//
// *if you don't want it to be hooked, comment line 350.
//===========================================================================
// FAQ:
// ====
// 1. Why don't you hook functions like GetLocationX or the ForGroup without BJ?
//
// Answer: Well, in jass you would never destroy groups, rather have one global group
// and clear/recycle it. But GUI always creates new groups with the functions.
// So actually, jass groups don't have to be destroyed.
// And special effects are mostly instantly destroyed and locations are never used.
// So I don't want to endanger breaking jass systems, I rather make it for GUI, where it is
// really useful and neccessary
//
// 2. Why should I protect my variables instead of killing my leaks?
//
// Answer: In GUI, unitgroup effect and location variables are actually just used
// for destroying stuff. It is rare that you really want to keep the groups.
// So in fact, it is like one-hundred times less frequent that you want to keep
// your data instead of destroying it.
//
// 3. I can't use jass. How can this system be useful for me?
//
// Answer: This system works mainly automatically; You just have to use jass very rarely (and then a simple function).
// The functions you need are:
//
// ProtectVariable(udg_###)
// GetLastCaughtHandle()
//
// where ProtectVariable saves something you want to keep from getting destroyed. Just replace ### with your
// variable name. NOTE: You don't have to protect the variable, when you want to keep the data inside less than
// CLEAN_UP_INTERVAL seconds.
//
// and where GetLastCaughtHandle responses to the handle* that was used lastly.
// That can be for example the point where you just spawned a unit.
//
// * 'handle' means a specialeffect, a location or a unitgroup
//
// 4. If you give functions like 'DelayMMH', why don't you add functions like 'Disable/EnableMMH'?
//
// Answer: Well, I want to protect the user. You do not need Disable/Enable functions.
// To me the danger is too big, that you forget to activate it again or do
// something like that. DelayMMH is totally enough if you don't want this system
// to affect the code that comes next. Also that prevents, that there are
// spells like 'Trojan Horses' that get too much access to this and can
// change it's infrastructure.
//
//===========================================================================
// Functions:
//==========
// ProtectHandle : Saves a handle from getting destroyed
// ProtectVariable : Same.
// DoNothing() : Destroys all data caught by the system right now in X seconds.
// DelayMMD() : Stops the system working until the trigger ends/next wait *
//
// * This is as fast as an automatic memory leak destroyer can get. Why should
// you want to disable the system? Because it offers the possibilty to make things
// more efficient. I don't want to say, this is unefficient, because it is not.
// But this will destroy leaks like 10% slower.
//
//===========================================================================
globals
// The system fires when you do something that creates a leak.
// The data that cause leak are saved in a variable then.
// And every CLEAN_UP_INTERVAL seconds those data are destroyed.
// This shouldn't be too high, or too low.
private constant real CLEAN_UP_INTERVAL = 120.
// If this is set to true, the system will work more slowly (but you wont notice)
// and count, how much memory this system was able to save.
// This value is display by the function DisplayLeaks() then.
// WARNING: This sucks a lot of performance. I would ONLY use it when you want
// to test, if this is useful for your map. Later set it to false.
private constant boolean DISPLAY_SAVED_MEMORY = false
// The Data are only cleaned up, when that many handles were caught
private constant integer MIN_LEAK_NUMBER = 1750
// How often are data passed to the destroyer?
// Leaks stay for a random time between CLEAN_UP_INTERVAL and CLEAN_UP_INTERVAL+PASS_INTERVAL
// in the game
private constant real PASS_INTERVAL = 2.5
// Memory leaks occur pretty frequently. When a leak is caught it is saved in
// an array. But the array can't have more than MAX_LEAK_INSTANCES instances, so
// if more than MAX_LEAK_INSTANCES memory leaks occur during a destroy interval,
// the system fails.
private constant integer MAX_LEAK_INSTANCES = 60000
endglobals
globals
private HandleTable IndexData
private HandleTable IsSaved
//! textmacro MemoryLeakVars takes NAME, TYPE
private integer Caught$NAME$Leaks = 0
private $TYPE$ array $NAME$LeakData[MAX_LEAK_INSTANCES]
private integer $NAME$DestroyCount = 0
private $TYPE$ array $NAME$DestroyData[MAX_LEAK_INSTANCES]
//! endtextmacro
//! runtextmacro MemoryLeakVars("Location","location")
//! runtextmacro MemoryLeakVars("Effect","effect")
//! runtextmacro MemoryLeakVars("Group","group")
private integer DestroyedLeaks = 0
private integer CaughtLeaks = 0
private integer DestroyedLeaksUser = 0
private handle LastCaught
private timer PassTimer = CreateTimer()
private timer CleanTimer = CreateTimer()
private timer DelayTimer = CreateTimer()
private boolean IsDestroying = false
private real SavedMemory = 0.
private real LastCheckedGroupMemoryUsage = 0.
private boolean DestroyThreadRunning = false
private boolean Disabled = false
// These values were found out in a big leak test by gekko.
private constant real LOCATION_MEMORY_USAGE = 0.361
private constant real GROUP_MEMORY_USAGE = 0.62
private constant real GROUP_UNIT_MEMORY_USAGE = 0.040
private constant real EFFECT_MEMORY_USAGE = 11.631
private constant real REMOVED_EFFECT_MEMORY_USAGE = 0.066
endglobals
// ======================================
// ============= Basic Code =============
// ======================================
function GetLastCaughtHandle takes nothing returns handle
return LastCaught
endfunction
function ProtectHandle takes handle h returns nothing
set IsSaved[h] = 1
endfunction
function ProtectVariable takes handle h returns nothing
set IsSaved[h] = 1
endfunction
private function EnableMMH takes nothing returns nothing
set Disabled = false
endfunction
function DelayMMH takes nothing returns nothing
set Disabled = true
call TimerStart(DelayTimer,0.00,false,function EnableMMH)
endfunction
function DisplayLeaks takes nothing returns nothing
call ClearTextMessages()
call BJDebugMsg("======= MemoryLeakHelper =======")
call BJDebugMsg("Destroyed Leaks: "+I2S(DestroyedLeaks))
call BJDebugMsg("Destroyed Leaks by user: "+I2S(DestroyedLeaksUser))
call BJDebugMsg("Percentage System: "+R2S(I2R(DestroyedLeaks)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Percentage User: "+R2S(I2R(DestroyedLeaksUser)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Leaks until next destroy: "+I2S(MIN_LEAK_NUMBER-CaughtLeaks))
call BJDebugMsg(" === In Destroy Queue === ")
call BJDebugMsg(" Group Leaks: "+I2S(GroupDestroyCount))
call BJDebugMsg(" Location Leaks: "+I2S(LocationDestroyCount))
call BJDebugMsg(" Effect Leaks: "+I2S(EffectDestroyCount))
call BJDebugMsg(" === Not in Destroy Queue yet === ")
call BJDebugMsg(" Group Leaks: "+I2S(CaughtGroupLeaks))
call BJDebugMsg(" Location Leaks: "+I2S(CaughtLocationLeaks))
call BJDebugMsg(" Effect Leaks: "+I2S(CaughtEffectLeaks))
call BJDebugMsg("Time until next PassSequence: "+I2S(R2I(TimerGetRemaining(PassTimer)+0.5))+" seconds.")
call BJDebugMsg(" ")
if DISPLAY_SAVED_MEMORY then
call BJDebugMsg("All in all the MemoryLeakHelper could release "+R2S(SavedMemory)+" kb of memory.")
endif
call BJDebugMsg("================================")
endfunction
private function GroupGetMemoryUsageEnum takes nothing returns nothing
set LastCheckedGroupMemoryUsage = LastCheckedGroupMemoryUsage + GROUP_UNIT_MEMORY_USAGE
endfunction
function GroupGetMemoryUsage takes group g returns real
set LastCheckedGroupMemoryUsage = 0.
call ForGroup(g,function GroupGetMemoryUsageEnum)
return LastCheckedGroupMemoryUsage + GROUP_MEMORY_USAGE
endfunction
//! textmacro ResponseOnLeak takes NAME, VALUE
private function Catch$NAME$ takes $VALUE$ l returns nothing
set LastCaught = l
if Disabled then
return
elseif Caught$NAME$Leaks == MAX_LEAK_INSTANCES then
debug call BJDebugMsg("MemoryLeakHelper: Failed to store leak because of size limitations")
return
endif
if IndexData.exists(l) == false then
//call BJDebugMsg("Caught $NAME$")
set Caught$NAME$Leaks = Caught$NAME$Leaks + 1
set $NAME$LeakData[Caught$NAME$Leaks] = l
set IndexData[l] = Caught$NAME$Leaks
endif
endfunction
private function AddTo$NAME$DestroyQueue takes $VALUE$ l returns nothing
set $NAME$DestroyCount = $NAME$DestroyCount + 1
set $NAME$DestroyData[$NAME$DestroyCount] = l
set IndexData[l] = $NAME$DestroyCount*-1 // Put his to negative, so we know that this is used in the DestroyQueue now.
endfunction
private function Release$NAME$ takes $VALUE$ l returns nothing
local integer index
if IsDestroying == false and IndexData.exists(l) then
set index = IndexData[l]
// If this is true, the index wasn't put to a destroy queue yet.
if index > 0 then
set $NAME$LeakData[index] = $NAME$LeakData[Caught$NAME$Leaks]
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
else
set index = index * -1
set $NAME$DestroyData[index] = $NAME$DestroyData[$NAME$DestroyCount]
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endif
call IndexData.flush(l)
set DestroyedLeaksUser = DestroyedLeaksUser + 1
endif
endfunction
//! endtextmacro
//! runtextmacro ResponseOnLeak("Location","location")
//! runtextmacro ResponseOnLeak("Group","group")
//! runtextmacro ResponseOnLeak("Effect","effect")
private function DestroyMemoryLeaks takes nothing returns nothing
set IsDestroying = true
//call BJDebugMsg("DESTROYING Memory Leaks")
//! textmacro DestroyLeaks takes NAME, DESTROYCALL, MEMORYUSAGE
set DestroyedLeaks = DestroyedLeaks + $NAME$DestroyCount
loop
exitwhen $NAME$DestroyCount == 0
if DISPLAY_SAVED_MEMORY then
set SavedMemory = SavedMemory + $MEMORYUSAGE$
endif
call $DESTROYCALL$($NAME$DestroyData[$NAME$DestroyCount])
call IndexData.flush($NAME$DestroyData[$NAME$DestroyCount])
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endloop
//! endtextmacro
//! runtextmacro DestroyLeaks ("Group","DestroyGroup","GroupGetMemoryUsage(GroupDestroyData[GroupDestroyCount])")
//! runtextmacro DestroyLeaks ("Location","RemoveLocation","LOCATION_MEMORY_USAGE")
//! runtextmacro DestroyLeaks ("Effect","DestroyEffect","EFFECT_MEMORY_USAGE")
set IsDestroying = false
set DestroyThreadRunning = false
//call StartPassTimer.execute() // Strange. This causes bugs sometimes and the function isn't called
// This is slower, but safe.
call ExecuteFunc("StartPassTimer")
endfunction
function StartDestroyThread takes nothing returns nothing
if DestroyThreadRunning == false then
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
call PauseTimer(PassTimer)
endif
endfunction
hook DoNothing StartDestroyThread
// We want that the user doesn't have to protect too many variables, but all the variables that are filled longer
// than CLEAN_UP_INTERVAL seconds. But what, when the handle thing is put into the destroy stack and the next destroy is
// in 5 seconds, because the last one was 15 seconds ago? We can simply avoid something like that by using a 2-step-system
// that goes sure, the handle is only destroyed when it passed the CLEAN_UP_INTERVAL twice.
// Having two kinds of variables is simply easier and more efficient than having another variable that refers to
// how many times the handle passed the timer; If it isn't passed/cleared in the Interval then, we can't loop
// that easily through the data and we'd have to fix gaps later; That would suck a lot of performacne.
private function PassMemoryLeaks takes nothing returns nothing
//call BJDebugMsg("PassMemoryLeaks")
//! textmacro PassLeaks takes NAME
set CaughtLeaks = CaughtLeaks + Caught$NAME$Leaks
//call BJDebugMsg("Caught $NAME$s: "+I2S(Caught$NAME$Leaks))
loop
exitwhen Caught$NAME$Leaks < 1
if IsSaved.exists($NAME$LeakData[Caught$NAME$Leaks]) == false and $NAME$LeakData[Caught$NAME$Leaks] != null then
call AddTo$NAME$DestroyQueue($NAME$LeakData[Caught$NAME$Leaks])
endif
set $NAME$LeakData[Caught$NAME$Leaks] = null
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
endloop
//! endtextmacro
//! runtextmacro PassLeaks ("Group")
//! runtextmacro PassLeaks ("Location")
//! runtextmacro PassLeaks ("Effect")
if CaughtLeaks > MIN_LEAK_NUMBER then
set CaughtLeaks = 0
//call BJDebugMsg("Caught Leaks: "+I2S(MIN_LEAK_NUMBER))
//call BJDebugMsg("Now start Destroy Timer")
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
// We have to pause this timer a bit; Otherwise it would break the CLEAN_UP_INTERVAL rule.
call PauseTimer(PassTimer)
endif
endfunction
// =================================
// ============= Usage =============
// =================================
private function PP takes location source, real dist, real angle returns nothing
call CatchLocation(source)
endfunction
private function CU takes integer count, integer unitId, player p, location l, real face returns nothing
call CatchLocation(l)
endfunction
private function IPO takes unit k, string order, location l returns nothing
call CatchLocation(l)
endfunction
private function SUP takes unit who, location l returns nothing
call CatchLocation(l)
endfunction
private function SUF takes unit who, location l, real dur returns nothing
call CatchLocation(l)
endfunction
private function GUR takes real radius, location l, boolexpr filter returns nothing
call CatchLocation(l)
endfunction
private function CUF takes integer count, integer unitId, player whichPlayer, location loc, location lookAt returns nothing
call CatchLocation(loc)
call CatchLocation(lookAt)
endfunction
hook PolarProjectionBJ PP
hook CreateNUnitsAtLoc CU
hook CreateNUnitsAtLocFacingLocBJ CUF
hook IssuePointOrderLocBJ IPO
hook SetUnitPositionLoc SUP
hook SetUnitFacingToFaceLocTimed SUF
hook GetUnitsInRangeOfLocMatching GUR
hook RemoveLocation ReleaseLocation
private function FG takes group g, code callback returns nothing
call CatchGroup(g)
endfunction
hook ForGroupBJ FG // :D This should catch all GUI usages for groups.
hook GroupPickRandomUnit CatchGroup
hook CountUnitsInGroup CatchGroup
hook DestroyGroup ReleaseGroup
private function ASETU takes string bla, widget d, string blu returns nothing
// We can not catch THIS effect, but the effect that was created before.
// So we can destroy all SpecialEffects excpet one.
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
private function ASE takes location where, string modelName returns nothing
call CatchLocation(where)
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
hook AddSpecialEffectLocBJ ASE
hook AddSpecialEffectTargetUnitBJ ASETU
hook DestroyEffect ReleaseEffect
hook DestroyEffectBJ ReleaseEffect
// When I want to make the timer run the PassMemoryLeaks things, I have to use an .execute command which requires an extra func.
function StartPassTimer takes nothing returns nothing
//call BJDebugMsg("Restarting PassTimer")
call TimerStart(PassTimer,PASS_INTERVAL,true,function PassMemoryLeaks)
endfunction
private function Init takes nothing returns nothing
set IndexData = HandleTable.create()
set IsSaved = HandleTable.create()
call StartPassTimer()
endfunction
endlibrary
library CombinedCameraSliderSystem
//----------------------------------------------\\
// \\
// Version 1.2 \\
// Written by Sabe / Sabeximus#2923 \\
// \\
//----------------------------------------------\\
globals
private framehandle sliderDistance
private framehandle sliderDistanceLabel
private framehandle sliderAngleOfAttack
private framehandle sliderAngleOfAttackLabel
private framehandle sliderRotation
private framehandle sliderRotationLabel
private framehandle sliderHeight
private framehandle sliderHeightLabel
private framehandle resetButton
private framehandle sliderAbove
private framepointtype framepointVerticalMain
private framepointtype framepointVerticalSecondary
private framepointtype framepointCornerMain
private framepointtype framepointCheckboxMain
private framepointtype framepointCheckboxSecondary
private boolean array leftArrowIsDown
private boolean array upArrowIsDown
private boolean array downArrowIsDown
private boolean array rightArrowIsDown
private boolean array wKeyIsDown
private boolean array aKeyIsDown
private boolean array sKeyIsDown
private boolean array dKeyIsDown
private boolean array xKeyIsDown
private real array horizontalChange
private real array verticalChange
private real array xTarget
private real array yTarget
private real array forward
private real array sideways
private real array orderDelay
private real array fullTurnDelay
private boolean debugMode = false
endglobals
private function LoadToc takes string s returns nothing
if not BlzLoadTOCFile(s) then
call BJDebugMsg("|cffff0000Failed to Load: " + s + "|r \nYou need to import the |cffffcc00templates.toc|r file.")
endif
endfunction
private function UpdateCam takes nothing returns nothing
local integer i = GetPlayerId(GetEnumPlayer())
local unit u = udg_CCSS_TargetUnit[i + 1]
local real facing = GetUnitFacing(u)
local real moveSpeed = GetUnitMoveSpeed(u)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real hDir = 0
local real vDir = 0
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_TARGET_DISTANCE, BlzFrameGetValue(sliderDistance), udg_CCSS_CamUpdateInterval)
if (udg_CCSS_3rdPersonCamMode) then // Check if Third Person Camera mode is enabled
if (((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys)) and (u != null)) then // Unit WASD control. Obviously, run these only if the WASD keys are enabled and there is a Target Unit
if (wKeyIsDown[i]) then
set forward[i] = 1
else
set forward[i] = 0
endif
if (aKeyIsDown[i]) then
set sideways[i] = sideways[i] - 1
endif
if (dKeyIsDown[i]) then
set sideways[i] = sideways[i] + 1
endif
set xTarget[i] = x
set yTarget[i] = y
if ((moveSpeed / udg_CCSS_WASDMoveSpeedModifier) < udg_CCSS_WASDMoveMinDistance) then
set moveSpeed = udg_CCSS_WASDMoveMinDistance
else
set moveSpeed = moveSpeed / udg_CCSS_WASDMoveSpeedModifier
endif
if (forward[i] == 1) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing)) * (moveSpeed)
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing)) * (moveSpeed)
if (sideways[i] < 0) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 90)) * udg_CCSS_WASDTurnSpeed
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
if (sideways[i] > 0) then
set xTarget[i] = xTarget[i] + Cos(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
set yTarget[i] = yTarget[i] + Sin(Deg2Rad(facing + 270)) * udg_CCSS_WASDTurnSpeed
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
else
if (sideways[i] == -1) then
call SetUnitFacing(u, facing + (udg_CCSS_WASDStationaryTurnSpeed))
set sideways[i] = 0
endif
if (sideways[i] == 1) then
call SetUnitFacing(u, facing - (udg_CCSS_WASDStationaryTurnSpeed))
set sideways[i] = 0
endif
if (udg_CCSS_SButtonOrder != "") then
if (sKeyIsDown[i]) then
call IssueImmediateOrder(u, udg_CCSS_SButtonOrder)
endif
endif
set fullTurnDelay[i] = fullTurnDelay[i] - udg_CCSS_CamUpdateInterval
if (fullTurnDelay[i] <= 0) then
if (udg_CCSS_SButton180Turn) then
if (sKeyIsDown[i]) then
set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
call SetUnitFacing(u, facing - 180)
endif
endif
if (udg_CCSS_XButton180Turn) then
if (xKeyIsDown[i]) then
set fullTurnDelay[i] = udg_CCSS_CamUpdateInterval * 10
call SetUnitFacing(u, facing - 180)
endif
endif
endif
endif
set orderDelay[i] = orderDelay[i] - udg_CCSS_WASDMoveOrderInterval
if (orderDelay[i] <= 0) then
set orderDelay[i] = 1
if ((forward[i] != 0) or (sideways[i] != 0)) then
call IssuePointOrder(u, "move", xTarget[i], yTarget[i])
set sideways[i] = 0
endif
endif
endif
if (udg_CCSS_UseArrowKeys) then // Only run these if the Arrow Keys are used
// Horizontal Key Register
if (leftArrowIsDown[i]) then
if (udg_CCSS_InvertHorizontalMovement) then
if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir - 1
endif
else
if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir + 1
endif
endif
endif
if (rightArrowIsDown[i]) then
if (udg_CCSS_InvertHorizontalMovement) then
if (horizontalChange[i] - (udg_CCSS_HorizontalSpeed * 3) < udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir + 1
endif
else
if (horizontalChange[i] + (udg_CCSS_HorizontalSpeed * 3) > -udg_CCSS_HorizontalArrowMoveLimit) then
set hDir = hDir - 1
endif
endif
endif
set horizontalChange[i] = horizontalChange[i] + (hDir * udg_CCSS_HorizontalSpeed)
if ((hDir == 0) and (horizontalChange[i] != 0)) then
if (horizontalChange[i] > 0) then
set horizontalChange[i] = horizontalChange[i] - (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
if (horizontalChange[i] < udg_CCSS_HorizontalSpeed) then
set horizontalChange[i] = 0
endif
else
set horizontalChange[i] = horizontalChange[i] + (udg_CCSS_HorizontalSpeed * udg_CCSS_HorizontalReturnSpeed)
if (horizontalChange[i] > udg_CCSS_HorizontalSpeed) then
set horizontalChange[i] = 0
endif
endif
endif
// Vertical Key Register
if (upArrowIsDown[i]) then
if (udg_CCSS_InvertVerticalMovement) then
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
set vDir = vDir - 1
endif
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then // Don't allow the number to grow if camera had stopped at the limit
set vDir = vDir + 1
endif
endif
endif
if (downArrowIsDown[i]) then
if (udg_CCSS_InvertVerticalMovement) then
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] - (udg_CCSS_HorizontalSpeed * 2)) < (udg_CCSS_AngleOfAttackMax)) then
set vDir = vDir + 1
endif
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i] + (udg_CCSS_HorizontalSpeed * 2)) > (udg_CCSS_AngleOfAttackMin)) then
set vDir = vDir - 1
endif
endif
endif
set verticalChange[i] = verticalChange[i] + (vDir * udg_CCSS_VerticalSpeed)
if ((vDir == 0) and (verticalChange[i] != 0)) then
if (verticalChange[i] > 0) then
set verticalChange[i] = verticalChange[i] - (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
if (verticalChange[i] < udg_CCSS_VerticalSpeed) then
set verticalChange[i] = 0
endif
else
set verticalChange[i] = verticalChange[i] + (udg_CCSS_VerticalSpeed * udg_CCSS_VerticalReturnSpeed)
if (verticalChange[i] > udg_CCSS_VerticalSpeed) then
set verticalChange[i] = 0
endif
endif
endif
endif
// Apply arrow key changes
if (u != null) then // Check if our player has a Target Unit
// Horizontal
if (horizontalChange[i] > udg_CCSS_HorizontalArrowMoveLimit) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval) // Prevent camera from rolling around the unit forever
else
if (horizontalChange[i] < -udg_CCSS_HorizontalArrowMoveLimit) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing - udg_CCSS_HorizontalArrowMoveLimit, udg_CCSS_CamUpdateInterval)
else
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, facing + horizontalChange[i], udg_CCSS_CamUpdateInterval)
endif
endif
if (GetLocalPlayer() == Player(i)) then // Lock the rotation bar. Purely cosmetic, can be removed if, for example, causes desync problems. (The bar won't affect rotation even if not locked)
call BlzFrameSetEnable(sliderRotation, false)
endif
// Vertical
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) > (udg_CCSS_AngleOfAttackMax)) then // Prevent camera from overstepping angle of attack slider maximum and minimum.
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMax, udg_CCSS_CamUpdateInterval)
else
if ((BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i]) < (udg_CCSS_AngleOfAttackMin)) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, udg_CCSS_AngleOfAttackMin, udg_CCSS_CamUpdateInterval)
else
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack) + verticalChange[i], udg_CCSS_CamUpdateInterval)
endif
endif
// Add Unit Height to Camera
if (udg_CCSS_AddUnitHeightToCamera) then
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight) + GetUnitFlyHeight(u), udg_CCSS_CamUpdateInterval)
endif
else // If doesn't have Target Unit
// Horizontal
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 Because I want the default rotation angle (90) to be zero for simplicity's sake
if ((GetLocalPlayer() == GetEnumPlayer()) and (udg_CCSS_RotationEnabled)) then
call BlzFrameSetEnable(sliderRotation, true)
endif
// Vertical
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)
// Height
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
endif
else // Only run this if 3rdPC mode is not used
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ROTATION, BlzFrameGetValue(sliderRotation) + 90, udg_CCSS_CamUpdateInterval) // +90 so that 0 on the slider is the default WC3 angle
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ANGLE_OF_ATTACK, BlzFrameGetValue(sliderAngleOfAttack), udg_CCSS_CamUpdateInterval)
call SetCameraFieldForPlayer(Player(i), CAMERA_FIELD_ZOFFSET, BlzFrameGetValue(sliderHeight), udg_CCSS_CamUpdateInterval)
endif
set u = null
endfunction
private function HumanPlayersPlaying takes nothing returns boolean
if (GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER) and (GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING) then
return true
else
return false
endif
endfunction
private function PreUpdateCam takes nothing returns nothing
local force f = GetPlayersMatching(Condition(function HumanPlayersPlaying)) // No point in picking computer players
call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
call BlzFrameSetEnable(sliderRotation, udg_CCSS_DistanceEnabled)
call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
if (udg_CCSS_ShowValues) then
call BlzFrameSetText(sliderDistanceLabel, "Distance: " + R2SW(BlzFrameGetValue(sliderDistance), 1, 1))
call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle: " + R2SW(BlzFrameGetValue(sliderAngleOfAttack), 1, 1))
call BlzFrameSetText(sliderRotationLabel, "Rotation: " + R2SW(BlzFrameGetValue(sliderRotation), 1, 1))
call BlzFrameSetText(sliderHeightLabel, "Height: " + R2SW(BlzFrameGetValue(sliderHeight), 1, 1))
else
call BlzFrameSetText(sliderDistanceLabel, "Distance")
call BlzFrameSetText(sliderAngleOfAttackLabel, "Angle")
call BlzFrameSetText(sliderRotationLabel, "Rotation")
call BlzFrameSetText(sliderHeightLabel, "Height")
endif
call ForForce(f, function UpdateCam)
call DestroyForce(f)
endfunction
private function CreateSliders takes nothing returns nothing
local real labelGap
set sliderDistance = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
set sliderDistanceLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderDistance, 0, 0)
set sliderAngleOfAttack = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 1)
set sliderAngleOfAttackLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderAngleOfAttack, 0, 0)
set sliderRotation = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 2)
set sliderRotationLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderRotation, 0, 0)
set sliderHeight = BlzCreateFrame("EscMenuSliderTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 3)
set sliderHeightLabel = BlzCreateFrame("EscMenuLabelTextTemplate", sliderHeight, 0, 0)
set sliderAbove = null
if (udg_CCSS_PositionSlidersX >= 8) then
set udg_CCSS_PositionSlidersX = 0.8
else
if (udg_CCSS_PositionSlidersX < 0) then
set udg_CCSS_PositionSlidersX = 0
else
set udg_CCSS_PositionSlidersX = udg_CCSS_PositionSlidersX / 10 // GUI only allows 2 decimals for reals, so this way I can get 3 decimals for JASS
endif
endif
if (udg_CCSS_PositionSlidersY >= 6) then
set udg_CCSS_PositionSlidersY = 0.6
else
if (udg_CCSS_PositionSlidersY < 0) then
set udg_CCSS_PositionSlidersY = 0
else
set udg_CCSS_PositionSlidersY = udg_CCSS_PositionSlidersY / 10
endif
endif
set udg_CCSS_SliderGap = udg_CCSS_SliderGap / 10
if (udg_CCSS_AlignmentLeft) then
set framepointVerticalMain = FRAMEPOINT_LEFT
set framepointVerticalSecondary = FRAMEPOINT_RIGHT
set framepointCornerMain = FRAMEPOINT_TOPLEFT
set labelGap = 0.005
else
set framepointVerticalMain = FRAMEPOINT_RIGHT
set framepointVerticalSecondary = FRAMEPOINT_LEFT
set framepointCornerMain = FRAMEPOINT_TOPRIGHT
set labelGap = -0.005
endif
//Distance Slider options
call BlzFrameSetAbsPoint(sliderDistance, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
call BlzFrameSetPoint(sliderDistanceLabel, framepointVerticalMain, sliderDistance, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderDistance, udg_CCSS_DistanceMin, udg_CCSS_DistanceMax)
call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
call BlzFrameSetStepSize(sliderDistance, udg_CCSS_DistanceStep)
call BlzFrameSetEnable(sliderDistance, udg_CCSS_DistanceEnabled)
if (udg_CCSS_DistanceShow) then
set sliderAbove = sliderDistance
endif
call BlzFrameSetVisible(sliderDistance, false)
//Angle of Attack Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderAngleOfAttack, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderAngleOfAttack, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderAngleOfAttackLabel, framepointVerticalMain, sliderAngleOfAttack, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackMin, udg_CCSS_AngleOfAttackMax)
call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
call BlzFrameSetStepSize(sliderAngleOfAttack, udg_CCSS_AngleOfAttackStep)
call BlzFrameSetEnable(sliderAngleOfAttack, udg_CCSS_AngleOfAttackEnabled)
if (udg_CCSS_AngleOfAttackShow) then
set sliderAbove = sliderAngleOfAttack
endif
call BlzFrameSetVisible(sliderAngleOfAttack, false)
//Rotation Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderRotation, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderRotation, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderRotationLabel, framepointVerticalMain, sliderRotation, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderRotation, udg_CCSS_RotationMin, udg_CCSS_RotationMax)
call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
call BlzFrameSetStepSize(sliderRotation, udg_CCSS_RotationStep)
call BlzFrameSetEnable(sliderRotation, udg_CCSS_RotationEnabled)
if (udg_CCSS_RotationShow) then
set sliderAbove = sliderRotation
endif
call BlzFrameSetVisible(sliderRotation, false)
//Height Slider options
if (sliderAbove != null) then
call BlzFrameSetPoint(sliderHeight, FRAMEPOINT_TOPLEFT, sliderAbove, FRAMEPOINT_BOTTOMLEFT, 0, -udg_CCSS_SliderGap)
else
call BlzFrameSetAbsPoint(sliderHeight, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetPoint(sliderHeightLabel, framepointVerticalMain, sliderHeight, framepointVerticalSecondary, labelGap, 0)
call BlzFrameSetMinMaxValue(sliderHeight, udg_CCSS_HeightMin, udg_CCSS_HeightMax)
call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
call BlzFrameSetStepSize(sliderHeight, udg_CCSS_HeightStep)
call BlzFrameSetEnable(sliderHeight, udg_CCSS_HeightEnabled)
if (udg_CCSS_HeightShow) then
set sliderAbove = sliderHeight
endif
call BlzFrameSetVisible(sliderHeight, false)
endfunction
private function ResetSliders takes nothing returns nothing
if GetLocalPlayer() == GetTriggerPlayer() then
call BlzFrameSetValue(sliderDistance, udg_CCSS_DistanceDefault)
call BlzFrameSetValue(sliderAngleOfAttack, udg_CCSS_AngleOfAttackDefault)
call BlzFrameSetValue(sliderRotation, udg_CCSS_RotationDefault)
call BlzFrameSetValue(sliderHeight, udg_CCSS_HeightDefault)
endif
call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
call BlzFrameSetEnable(BlzGetTriggerFrame(), true)
endfunction
private function CreateResetButton takes nothing returns nothing
local trigger t = CreateTrigger()
set resetButton = BlzCreateFrame("ScriptDialogButton", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
set udg_CCSS_ResetButtonSizeX = udg_CCSS_ResetButtonSizeX / 10
set udg_CCSS_ResetButtonSizeY = udg_CCSS_ResetButtonSizeY / 10
if (sliderAbove != null) then
call BlzFrameSetPoint(resetButton, framepointCornerMain, sliderAbove, framepointVerticalMain, 0, -(udg_CCSS_SliderGap * 2))
else
call BlzFrameSetAbsPoint(resetButton, framepointVerticalMain, udg_CCSS_PositionSlidersX, udg_CCSS_PositionSlidersY)
endif
call BlzFrameSetSize(resetButton, udg_CCSS_ResetButtonSizeX, udg_CCSS_ResetButtonSizeY)
call BlzFrameSetText(resetButton, udg_CCSS_ResetButtonText)
call BlzFrameSetVisible(resetButton, false)
call TriggerAddAction(t, function ResetSliders)
call BlzTriggerRegisterFrameEvent(t, resetButton, FRAMEEVENT_CONTROL_CLICK)
endfunction
private function CheckBoxLockSliders takes nothing returns nothing
local boolean b = (BlzGetTriggerFrameEvent() == FRAMEEVENT_CHECKBOX_CHECKED)
if GetLocalPlayer() == GetTriggerPlayer() then
if (udg_CCSS_DistanceShow) then
call BlzFrameSetVisible(sliderDistance, b)
endif
if (udg_CCSS_AngleOfAttackShow) then
call BlzFrameSetVisible(sliderAngleOfAttack, b)
endif
if (udg_CCSS_RotationShow) then
call BlzFrameSetVisible(sliderRotation, b)
endif
if (udg_CCSS_HeightShow) then
call BlzFrameSetVisible(sliderHeight, b)
endif
call BlzFrameSetVisible(resetButton, b)
endif
endfunction
private function CreateCheckbox takes nothing returns nothing
local trigger t = CreateTrigger()
local framehandle fh = BlzCreateFrame("QuestCheckBox", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
local framehandle label = BlzCreateFrame("EscMenuLabelTextTemplate", fh, 0, 0)
local real labelGap
if (udg_CCSS_PositionCheckBoxX >= 8) then
set udg_CCSS_PositionCheckBoxX = 0.8
else
if (udg_CCSS_PositionCheckBoxX < 0) then
set udg_CCSS_PositionCheckBoxX = 0
else
set udg_CCSS_PositionCheckBoxX = udg_CCSS_PositionCheckBoxX / 10
endif
endif
if (udg_CCSS_PositionCheckBoxY >= 6) then
set udg_CCSS_PositionCheckBoxY = 0.6
else
if (udg_CCSS_PositionCheckBoxY < 0) then
set udg_CCSS_PositionCheckBoxY = 0
else
set udg_CCSS_PositionCheckBoxY = udg_CCSS_PositionCheckBoxY / 10
endif
endif
if (udg_CCSS_CheckBoxTextOnLeft) then
set framepointCheckboxMain = FRAMEPOINT_RIGHT
set framepointCheckboxSecondary = FRAMEPOINT_LEFT
set labelGap = -0.005
else
set framepointCheckboxMain = FRAMEPOINT_LEFT
set framepointCheckboxSecondary = FRAMEPOINT_RIGHT
set labelGap = 0.005
endif
call BlzFrameSetPoint(label, framepointCheckboxMain, fh, framepointCheckboxSecondary, labelGap, 0)
call BlzFrameSetAbsPoint(fh, framepointCheckboxMain, udg_CCSS_PositionCheckBoxX, udg_CCSS_PositionCheckBoxY)
call BlzFrameSetText(label, udg_CCSS_CheckBoxText)
call BlzFrameSetVisible(fh, udg_CCSS_CheckBoxShow)
call TriggerAddAction(t, function CheckBoxLockSliders)
call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_CHECKED)
call BlzTriggerRegisterFrameEvent(t, fh, FRAMEEVENT_CHECKBOX_UNCHECKED)
endfunction
// Arrow keys
private function LeftArrowPress takes nothing returns nothing
set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function LeftArrowRelease takes nothing returns nothing
set leftArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function UpArrowPress takes nothing returns nothing
set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function UpArrowRelease takes nothing returns nothing
set upArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function DownArrowPress takes nothing returns nothing
set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function DownArrowRelease takes nothing returns nothing
set downArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function RightArrowPress takes nothing returns nothing
set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = true
endfunction
private function RightArrowRelease takes nothing returns nothing
set rightArrowIsDown[GetPlayerId(GetTriggerPlayer())] = false
endfunction
private function ArrowKeyListeners takes nothing returns nothing
local trigger tLp = CreateTrigger()
local trigger tUp = CreateTrigger()
local trigger tDp = CreateTrigger()
local trigger tRp = CreateTrigger()
local trigger tLr = CreateTrigger()
local trigger tUr = CreateTrigger()
local trigger tDr = CreateTrigger()
local trigger tRr = CreateTrigger()
local integer i
set i = 0
loop
call TriggerRegisterPlayerKeyEventBJ(tLp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_LEFT)
call TriggerRegisterPlayerKeyEventBJ(tLr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_LEFT)
call TriggerRegisterPlayerKeyEventBJ(tUp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_UP)
call TriggerRegisterPlayerKeyEventBJ(tUr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_UP)
call TriggerRegisterPlayerKeyEventBJ(tDp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_DOWN)
call TriggerRegisterPlayerKeyEventBJ(tDr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_DOWN)
call TriggerRegisterPlayerKeyEventBJ(tRp, Player(i), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_RIGHT)
call TriggerRegisterPlayerKeyEventBJ(tRr, Player(i), bj_KEYEVENTTYPE_RELEASE, bj_KEYEVENTKEY_RIGHT)
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(tLp, function LeftArrowPress)
call TriggerAddAction(tLr, function LeftArrowRelease)
call TriggerAddAction(tUp, function UpArrowPress)
call TriggerAddAction(tUr, function UpArrowRelease)
call TriggerAddAction(tDp, function DownArrowPress)
call TriggerAddAction(tDr, function DownArrowRelease)
call TriggerAddAction(tRp, function RightArrowPress)
call TriggerAddAction(tRr, function RightArrowRelease)
endfunction
// WASD keys
private function WKey takes nothing returns nothing
set wKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("W is pressed")
else
call BJDebugMsg("W is released")
endif
endif
endfunction
private function AKey takes nothing returns nothing
set aKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("A is pressed")
else
call BJDebugMsg("A is released")
endif
endif
endfunction
private function SKey takes nothing returns nothing
set sKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("S is pressed")
else
call BJDebugMsg("S is released")
endif
endif
endfunction
private function DKey takes nothing returns nothing
set dKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("D is pressed")
else
call BJDebugMsg("D is released")
endif
endif
endfunction
private function XKey takes nothing returns nothing
set xKeyIsDown[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
if (debugMode) then
if BlzGetTriggerPlayerIsKeyDown() then
call BJDebugMsg("X is pressed")
else
call BJDebugMsg("X is released")
endif
endif
endfunction
private function WASDKeyListeners takes nothing returns nothing
local trigger tWp = CreateTrigger()
local trigger tAp = CreateTrigger()
local trigger tSp = CreateTrigger()
local trigger tDp = CreateTrigger()
local trigger tWr = CreateTrigger()
local trigger tAr = CreateTrigger()
local trigger tSr = CreateTrigger()
local trigger tDr = CreateTrigger()
local trigger tXp = CreateTrigger()
local trigger tXr = CreateTrigger()
local integer i
set i = 0
loop
if (udg_CCSS_UseNumpadKeys) then
call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_NUMPAD8, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_NUMPAD8, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_NUMPAD4, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_NUMPAD4, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_NUMPAD5, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_NUMPAD5, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_NUMPAD6, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_NUMPAD6, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_NUMPAD2, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_NUMPAD2, 0, false)
else
call BlzTriggerRegisterPlayerKeyEvent(tWp, Player(i), OSKEY_W, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tWr, Player(i), OSKEY_W, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tAp, Player(i), OSKEY_A, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tAr, Player(i), OSKEY_A, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tSp, Player(i), OSKEY_S, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tSr, Player(i), OSKEY_S, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tDp, Player(i), OSKEY_D, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tDr, Player(i), OSKEY_D, 0, false)
call BlzTriggerRegisterPlayerKeyEvent(tXp, Player(i), OSKEY_X, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(tXr, Player(i), OSKEY_X, 0, false)
endif
set orderDelay[i] = 0
set fullTurnDelay[i] = 0
set i = i + 1
exitwhen i > bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(tWp, function WKey)
call TriggerAddAction(tWr, function WKey)
call TriggerAddAction(tAp, function AKey)
call TriggerAddAction(tAr, function AKey)
call TriggerAddAction(tSp, function SKey)
call TriggerAddAction(tSr, function SKey)
call TriggerAddAction(tDp, function DKey)
call TriggerAddAction(tDr, function DKey)
call TriggerAddAction(tXp, function XKey)
call TriggerAddAction(tXr, function XKey)
endfunction
//=============================================================================
function CreateCamControl takes nothing returns nothing
call LoadToc("war3mapimported\\templates.toc")
call CreateSliders()
call CreateCheckbox()
call CreateResetButton()
if ((udg_CCSS_3rdPersonCamMode) and (udg_CCSS_UseArrowKeys)) then // If 3rd Person Cam and Arrow keys aren't enabled, don't bother to create triggers for listening the keys
call ArrowKeyListeners()
endif
if ((udg_CCSS_3rdPersonCamMode) and ((udg_CCSS_UseWASDKeys) or (udg_CCSS_UseNumpadKeys))) then
call WASDKeyListeners()
endif
call TimerStart(CreateTimer(), udg_CCSS_CamUpdateInterval, true, function PreUpdateCam)
set debugMode = false // Turn true for testing purposes
endfunction
endlibrary
//TESH.scrollpos=64
//TESH.alwaysfold=0
// ---------------------------------------------------------
// ABILITY LEVEL UP SYSTEM
// CREATED BY -KOBAS- ON REQUEST
// VERSION 2.0
// ---------------------------------------------------------
function ItemSystemSetup takes nothing returns nothing
local integer ItemId
set udg_KSHash = InitHashtable()
set ItemId = 'I000' //FOR ITEM -> 'I000'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A008') //Ability Id
set ItemId = 'I001' //FOR ITEM -> 'I001'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A000') //Ability Id
set ItemId = 'I002' //FOR ITEM -> 'I002'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A002') //Ability Id
set ItemId = 'I003' //FOR ITEM -> 'I003'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00C') //Ability Id
set ItemId = 'I005' //FOR ITEM -> 'I005'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A007') //Ability Id
set ItemId = 'I004' //FOR ITEM -> 'I004'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00B') //Ability Id
set ItemId = 'I008' //FOR ITEM -> 'I008'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00A') //Ability Id
set ItemId = 'I007' //FOR ITEM -> 'I007'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A004') //Ability Id
set ItemId = 'I006' //FOR ITEM -> 'I006'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A003') //Ability Id
set ItemId = 'I00A' //FOR ITEM -> 'I00A'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A005') //Ability Id
set ItemId = 'I00B' //FOR ITEM -> 'I00B'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A060') //Ability Id
set ItemId = 'I009' //FOR ITEM -> 'I009'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A001') //Ability Id
set ItemId = 'I00D' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00L') //Ability Id
set ItemId = 'I00E' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00E') //Ability Id
set ItemId = 'I00C' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00J') //Ability Id
set ItemId = 'I00F' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00H') //Ability Id
set ItemId = 'I00H' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00K') //Ability Id
set ItemId = 'I00G' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00F') //Ability Id
set ItemId = 'I00K' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00M') //Ability Id
set ItemId = 'I00J' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00G') //Ability Id
set ItemId = 'I00I' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00I') //Ability Id
set ItemId = 'I00N' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00Q') //Ability Id
set ItemId = 'I00L' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00P') //Ability Id
set ItemId = 'I00M' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A00O') //Ability Id
set ItemId = 'I01B' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A02V') //Ability Id
set ItemId = 'I01C' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A030') //Ability Id
set ItemId = 'I01A' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'S000') //Ability Id
set ItemId = 'I01D' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A037') //Ability Id
set ItemId = 'I01E' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A031') //Ability Id
set ItemId = 'I01F' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A033') //Ability Id
set ItemId = 'I01G' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03B') //Ability Id
set ItemId = 'I01H' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A02W') //Ability Id
set ItemId = 'I01I' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03A') //Ability Id
set ItemId = 'I01J' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A038') //Ability Id
set ItemId = 'I01K' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A035') //Ability Id
set ItemId = 'I01L' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03C') //Ability Id
set ItemId = 'I01M' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03F') //Ability Id
set ItemId = 'I01N' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A02X') //Ability Id
set ItemId = 'I01O' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03J') //Ability Id
set ItemId = 'I01P' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03E') //Ability Id
set ItemId = 'I01Q' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A02Y') //Ability Id
set ItemId = 'I01R' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03H') //Ability Id
set ItemId = 'I01U' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03G') //Ability Id
set ItemId = 'I01S' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03I') //Ability Id
set ItemId = 'I01T' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03D') //Ability Id
set ItemId = 'I01V' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03P') //Ability Id
set ItemId = 'I01W' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03O') //Ability Id
set ItemId = 'I01X' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03K') //Ability Id
set ItemId = 'I01Z' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03Y') //Ability Id
set ItemId = 'I020' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03U') //Ability Id
set ItemId = 'I01Y' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A040') //Ability Id
set ItemId = 'I022' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03Q') //Ability Id
set ItemId = 'I021' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03R') //Ability Id
set ItemId = 'I023' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03S') //Ability Id
set ItemId = 'I024' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03V') //Ability Id
set ItemId = 'I025' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03T') //Ability Id
set ItemId = 'I026' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03Z') //Ability Id
set ItemId = 'I027' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03W') //Ability Id
set ItemId = 'I028' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A042') //Ability Id
set ItemId = 'I029' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A03X') //Ability Id
set ItemId = 'I02A' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04W') //Ability Id
set ItemId = 'I02B' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04J') //Ability Id
set ItemId = 'I02C' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04I') //Ability Id
set ItemId = 'I02F' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04H') //Ability Id
set ItemId = 'I02E' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04K') //Ability Id
set ItemId = 'I02D' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04P') //Ability Id
set ItemId = 'I02G' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04L') //Ability Id
set ItemId = 'I02H' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04Q') //Ability Id
set ItemId = 'I02I' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04N') //Ability Id
set ItemId = 'I02J' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04V') //Ability Id
set ItemId = 'I02K' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04S') //Ability Id
set ItemId = 'I02L' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04T') //Ability Id
set ItemId = 'I02M' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A050') //Ability Id
set ItemId = 'I02O' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A052') //Ability Id
set ItemId = 'I02N' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04X') //Ability Id
set ItemId = 'I02P' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A054') //Ability Id
set ItemId = 'I02Q' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04Z') //Ability Id
set ItemId = 'I02R' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A056') //Ability Id
set ItemId = 'I02S' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A055') //Ability Id
set ItemId = 'I02U' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05F') //Ability Id
set ItemId = 'I02T' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A04Y') //Ability Id
set ItemId = 'I02V' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A053') //Ability Id
set ItemId = 'I02W' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A057') //Ability Id
set ItemId = 'I02X' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05C') //Ability Id
set ItemId = 'I02Y' //FOR ITEM -> 'I00D'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05H') //Ability Id
set ItemId = 'I02Z' //FOR ITEM -> 'I00E'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05Q') //Ability Id
set ItemId = 'I030' //FOR ITEM -> 'I00C'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 1 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 10 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 1 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05P') //Ability Id
set ItemId = 'I031' //FOR ITEM -> 'I00F'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05G') //Ability Id
set ItemId = 'I032' //FOR ITEM -> 'I00H'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05W') //Ability Id
set ItemId = 'I033' //FOR ITEM -> 'I00G'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 5 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 8 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 2 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05X') //Ability Id
set ItemId = 'I034' //FOR ITEM -> 'I00K'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05K') //Ability Id
set ItemId = 'I035' //FOR ITEM -> 'I00J'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05L') //Ability Id
set ItemId = 'I036' //FOR ITEM -> 'I00I'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 10 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 5 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 3 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05N') //Ability Id
set ItemId = 'I037' //FOR ITEM -> 'I00N'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05A') //Ability Id
set ItemId = 'I038' //FOR ITEM -> 'I00L'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05Z') //Ability Id
set ItemId = 'I039' //FOR ITEM -> 'I00M'
call SaveInteger(udg_KSHash, ItemId, 0, 0 ) //Required Agility
call SaveInteger(udg_KSHash, ItemId, 1, 0 ) //Required Intelligence
call SaveInteger(udg_KSHash, ItemId, 2, 0 ) //Required Strength
call SaveInteger(udg_KSHash, ItemId, 3, 25 ) //Required Level
call SaveInteger(udg_KSHash, ItemId, 4, 3 ) //Ability Max Level
call SaveInteger(udg_KSHash, ItemId, 5, 0 ) //Item Gold Cost
call SaveInteger(udg_KSHash, ItemId, 6, 4 ) //Item Lumber Cost
call SaveInteger(udg_KSHash, ItemId, 7, 'A05Y') //Ability Id
// ---------------------------------------------------------
// HERE YOU CAN EDIT MSG DISPLAYED TO PLAYER
// ---------------------------------------------------------
call SaveStr(udg_KSHash, 0, 0, "Ability is already max level") //MSG Shown when unit has already ability level set to max
call SaveStr(udg_KSHash, 0, 1, "Your Stats are low") //MSG Shown when unit don't have required stats
call SaveStr(udg_KSHash, 0, 2, "Your Level is low") //MSG Shown when unit don't have required level
// ---------------------------------------------------------
// HERE YOU CAN EDIT SPECIAL EFFECTS DISPLAYED TO PLAYERS
// ---------------------------------------------------------
call SaveStr(udg_KSHash, 1, 0, "Abilities\\Spells\\Orc\\AncestralSpirit\\AncestralSpiritCaster.mdl") //Special Effect path: Learn ability
call SaveStr(udg_KSHash, 1, 1, "Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualCaster.mdl") //Special Effect path: level up ability
call SaveStr(udg_KSHash, 1, 2, "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl") //Special Effect path: Error
// ---------------------------------------------------------
endfunction
function ItemSystemCleanUp takes integer id, integer i returns nothing
call SetPlayerState( GetTriggerPlayer(), PLAYER_STATE_RESOURCE_LUMBER, ( GetPlayerState( GetTriggerPlayer() ,PLAYER_STATE_RESOURCE_LUMBER) + LoadInteger(udg_KSHash, id, 6) ) ) // We add lumber back to player
call SetPlayerState( GetTriggerPlayer(), PLAYER_STATE_RESOURCE_GOLD, ( GetPlayerState( GetTriggerPlayer() ,PLAYER_STATE_RESOURCE_GOLD) + LoadInteger(udg_KSHash, id, 5) ) ) // We add gold back to player
call DisplayTextToPlayer(GetTriggerPlayer(), 0, 0, LoadStr(udg_KSHash, 0, i))
call DestroyEffect(AddSpecialEffect(LoadStr(udg_KSHash, 1, 2),GetUnitX(GetTriggerUnit()),GetUnitY(GetTriggerUnit())))
endfunction
function ItemSystem takes nothing returns nothing
local integer ItemId = GetItemTypeId(GetManipulatedItem())
local unit u = GetTriggerUnit()
// ---------------------------------------------------------
// NO NEED TO BE CHANGED
// ---------------------------------------------------------
if GetHeroLevel(u) >= LoadInteger(udg_KSHash, ItemId, 3) then
if GetHeroAgi(u, false) >= LoadInteger(udg_KSHash, ItemId, 0) and GetHeroInt(u, false) >= LoadInteger(udg_KSHash, ItemId, 1) and GetHeroStr(u, false) >= LoadInteger(udg_KSHash, ItemId, 2) then
if GetUnitAbilityLevel(u, LoadInteger(udg_KSHash, ItemId, 7)) == 0 then
call UnitAddAbility(u, LoadInteger(udg_KSHash, ItemId, 7))
call UnitMakeAbilityPermanent(u,true, LoadInteger(udg_KSHash, ItemId, 7))
call DestroyEffect(AddSpecialEffect(LoadStr(udg_KSHash, 1, 0),GetUnitX(u),GetUnitY(u)))
elseif GetUnitAbilityLevel(u, LoadInteger(udg_KSHash, ItemId, 7)) == LoadInteger(udg_KSHash, ItemId, 4) then
call ItemSystemCleanUp(ItemId, 0)
else
call IncUnitAbilityLevel(u, LoadInteger(udg_KSHash, ItemId, 7))
call DestroyEffect(AddSpecialEffect(LoadStr(udg_KSHash, 1, 1),GetUnitX(u),GetUnitY(u)))
endif
else
call ItemSystemCleanUp(ItemId, 1)
endif
else
call ItemSystemCleanUp(ItemId, 2)
endif
call SetWidgetLife(GetManipulatedItem(),0.406)
set u = null
endfunction
// ---------------------------------------------------------
// BJ BELOW WILL TRIGGER THIS FOR ANY PLAYER SO NO NEED FOR
// CORRECTIONS, OFC EDIT IT IN CASE YOU USE THIS FOR 1 PLAYER
// EXAMPLE FOR PLAYER RED:
// TriggerRegisterPlayerUnitEvent(gg_trg_Kobas_System, player(0), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
// ---------------------------------------------------------
function InitTrig_Kobas_System takes nothing returns nothing
set gg_trg_Kobas_System = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Kobas_System, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddAction( gg_trg_Kobas_System, function ItemSystem )
call ItemSystemSetup()
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
//Spell Name: Lightning Cloud v2.0
//Made by: Mckill2009
//NOTE:
//- To all of you who are thinking that this is a rip-off dota's Razor's ultimate spell
// well, you are wrong, I even dont know that spell coz I really dont play DotA
//===HOW TO USE:
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- The trigger name MUST be >>> InitTrig_LightningCloud (see the name below)
//- Copy ALL that is written here and overwrite the existing texts in the custom text
//- Copy the Dummy/custom abilities/buffs etc... to your object editor
//- Make sure you inputed the correct raw codes of the base spell/buffs/dummy etc...
//- If your raw code is different, you MUST CHANGE IT...
//- You can view the raw codes by pressing CTRL+B in the object editor
//- Examples of raw codes are 'A000', 'h000' etc...
//===REQUIRED VARIABLES:
//- HASH = Hashtable
//- LC_Cloud = Unit
//- LC_TimerN - Integer
//- LC_Timers - Timer Array
//===CONFIGURABLES:
constant function LC_SpellId takes nothing returns integer
return 'A04N' //Raw code for the Hero ability
endfunction
constant function LC_DummySpellId takes nothing returns integer
return 'A04M' //Raw code for the Lightning Strike ability
endfunction
constant function LC_CloudUnit takes nothing returns integer
return 'h00O' //Raw code for the Cloud Unit
endfunction
constant function LC_Damage takes integer i returns real
return i * 200. //This is the ability level multiply by base damage
endfunction
constant function LC_Range takes nothing returns real
return 500. //Maximum range is 3000 or you can adjust it via object editor
endfunction
constant function LC_Duration takes nothing returns real
return 20. //This is the duration of the cloud and spell
endfunction
constant function LC_TimerSpeed takes nothing returns real
return 0.05
endfunction
constant function LC_ATT takes nothing returns attacktype
return ATTACK_TYPE_MAGIC
endfunction
constant function LC_DAM takes nothing returns damagetype
return DAMAGE_TYPE_LIGHTNING
endfunction
//===END OF CONFIGURABLES===
function LC_RTimer takes timer t returns nothing
if t != null then
call PauseTimer(t)
set udg_LC_Timers[udg_LC_TimerN] = t
set udg_LC_TimerN = udg_LC_TimerN + 1
endif
endfunction
//and get a timer
function LC_NTimer takes nothing returns timer
if udg_LC_TimerN == 0 then
return CreateTimer()
endif
set udg_LC_TimerN = udg_LC_TimerN - 1
return udg_LC_Timers[udg_LC_TimerN]
endfunction
function LC_FilterThem takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(udg_LC_Cloud)) and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false
set u = null
return b
endfunction
function LC_Loop takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer parent = GetHandleId(t)
local integer cloudkey
local unit caster = LoadUnitHandle(udg_HASH, parent, 1)
local unit cloud = LoadUnitHandle(udg_HASH, parent, 2)
local real dur = LoadReal(udg_HASH, parent, 3)
local real range = LoadReal(udg_HASH, parent, 4)
set cloudkey = GetHandleId(cloud)
set udg_LC_Cloud = cloud //should be transfered to a global variable
if dur > 0 and GetWidgetLife(caster) > 0.405 then
call SaveReal(udg_HASH, parent, 3 , dur - LC_TimerSpeed())
call SetUnitX(cloud, GetUnitX(caster))
call SetUnitY(cloud, GetUnitY(caster))
call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(cloud), GetUnitY(cloud), range, Filter(function LC_FilterThem))
call IssueTargetOrder(cloud, "chainlightning" , FirstOfGroup(bj_lastCreatedGroup)) //852119
else
call UnitApplyTimedLife(cloud, 'BTLF', 0.01)
call LC_RTimer(t)
call FlushChildHashtable(udg_HASH, parent)
call FlushChildHashtable(udg_HASH, cloudkey)
endif
set t = null
set cloud = null
set caster = null
endfunction
function LC_Cast takes nothing returns boolean
local timer t
local unit caster
local unit cloud
local integer cloudkey
local integer parent
local integer abilitylevel
if GetSpellAbilityId()==LC_SpellId() then
set caster = GetTriggerUnit()
set abilitylevel = GetUnitAbilityLevel(caster, LC_SpellId())
set t = LC_NTimer()
set parent = GetHandleId(t)
set cloud = CreateUnit(GetTriggerPlayer(), LC_CloudUnit() , GetUnitX(caster), GetUnitY(caster), 0)
set cloudkey = GetHandleId(cloud)
//===This portion saves the caster so that he will deal damage, not the cloud
call SaveUnitHandle(udg_HASH, cloudkey, 1, caster)
call SaveReal(udg_HASH, cloudkey, 2 , LC_Damage(abilitylevel))
//===This portion saves the caster/cloud/duration and range
call SaveUnitHandle(udg_HASH, parent, 1, caster)
call SaveUnitHandle(udg_HASH, parent, 2, cloud)
call SaveReal(udg_HASH, parent, 3, LC_Duration()) //See Function
call SaveReal(udg_HASH, parent, 4, LC_Range()) //See Function
call TimerStart(t, LC_TimerSpeed(), true, function LC_Loop)
elseif GetSpellAbilityId()==LC_DummySpellId() then
set cloudkey = GetHandleId(GetTriggerUnit())
call UnitDamageTarget(LoadUnitHandle(udg_HASH, cloudkey, 1), GetSpellTargetUnit(), LoadReal(udg_HASH, cloudkey, 2), false, false, LC_ATT(), LC_DAM(), null)
endif
set t = null
set caster = null
set cloud = null
return false
endfunction
function InitTrig_LightningCloud takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function LC_Cast))
set udg_HASH = InitHashtable()
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
///////////////////////////////////////////////////////////////////
//==============================================================
// LIGHTNINGS 1.5
// eubz
//============================================================== //
//This is a very simple spell but could be useful for maps.
//
//THANKS TO:
// Luorax, iAyanami, and Adiktuz
//==============================================================
//WHAT THIS SPELL DO:
//Creates lightnings around a target that deals damage
//to its sorrounding units which are enemies of the caster.
//Level 1 - 50 damage, 250 AoE
//Level 2 - 100 damage, 500 AoE
//Level 3 - 150 damage, 750 AoE
//==============================================================
//
//HOW TO IMPORT:
//1. copy all these codes into your map OR copy the trigger labeled Lightning.
//2. create an ability for this spell or just copy the custom ability in this map for this spell.
//
//==============================================================
///////////////////////////////////////////////////////////////////////////////////
//==============================================================
library Lightnings initializer Init
//==========================================================
//THE GLOBALS BELOW CAN BE CONFIGURED=======================
globals
private constant real DAMAGE = 750 //the damage dealt (you can set this)
private constant real AREA_OF_EFFECT = 200 //how large is the lightning AoE(you can set this)
private constant string SFX = "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl" //the SFX model path
private constant integer ABIL_CODE = 'A04L' //the ability ID
private constant attacktype A_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype D_TYPE = DAMAGE_TYPE_NORMAL
endglobals
//END OF CONFIGURATIONS======================================
constant native UnitAlive takes unit id returns boolean
private constant function areaEffect takes integer level returns real
return AREA_OF_EFFECT*level
endfunction
private constant function damageInflict takes integer level returns real
return DAMAGE*level
endfunction
private constant function GetFilter takes unit caster, unit u returns boolean
return IsUnitEnemy((u),GetOwningPlayer(caster))/*
*/and UnitAlive(u)/*
*/and not IsUnitType((u), UNIT_TYPE_STRUCTURE)/*
*/and not IsUnitType((u), UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//============================================================================
private function lightningsConditions takes nothing returns boolean
return GetSpellAbilityId() == ABIL_CODE
endfunction
//===========================================================================
//from here, we'll start the real lightning spell
globals
private group g = bj_lastCreatedGroup
endglobals
private function lightningActions takes nothing returns nothing
local real damage
local real d
local unit caster
local unit target
local real x
local real y
local unit u
local integer level
set caster = GetTriggerUnit()
set target = GetSpellTargetUnit()
set x = GetUnitX(target)
set y = GetUnitY(target)
set level = GetUnitAbilityLevel(caster, ABIL_CODE)
set d = areaEffect(level)
set damage = damageInflict(level)
call GroupEnumUnitsInRange(g, x, y, d, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if GetFilter(caster, u) then
call UnitDamageTarget(caster,u,damage,true,false,A_TYPE,D_TYPE,null)
endif
call GroupRemoveUnit(g, u)
endloop
set caster = null
set target = null
if d > 0 then
loop
set d = d - 10
exitwhen d < 0
call DestroyEffect(AddSpecialEffect(SFX,x+d*Cos(d+50*bj_DEGTORAD),y+d*Sin(d+50*bj_DEGTORAD)))
endloop
endif
endfunction
private function Init takes nothing returns nothing
local trigger L
set L = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( L, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( L, Condition( function lightningsConditions ) )
call TriggerAddAction( L, function lightningActions )
endfunction
endlibrary
//====================================================================
//Code by eubz//
//TESH.scrollpos=0
//TESH.alwaysfold=0
How to import:
/* 1. Copy OW_Dummy unit */
/* 2. Copy Omega Wave trigger */
/* 3. Copy Omega Wave ability */
/* 4. Change the ABILCODE in the Omega Wave trigger to match the raw code */
/* of your ability. You can check the raw codes by hitting Ctrl + D */
/* in the object editor */
/* 5. Change the DUMMYTYPE in the Omega Wave trigger to match the raw code */
/* of your dummy unit. */
/* 6. Change the ORDERID to match the order id of your ability's order id */
/* In GUI you can get the order id with */
/* Custom script: call BJDebugMsg(I2S(OrderId("channel"))) */
/* Change the channel to whatever you have in Data - Base order id */
//TESH.scrollpos=44
//TESH.alwaysfold=0
/*~~~~~~~~~~~~~~~~~ OMEGA WAVE v1.04 by Maker ~~~~~~~~~~~~~~~~~~~~~*/
/* |
| Creates rotating circles around the caster. Part of the circle |
| damages and part destroys mana. |
| */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
scope OmegaWave initializer Omega_Wave
globals
private constant integer ABILCODE = 'A03P'
private constant integer DUMMY_TYPE = 'h00J'
private constant integer ORDERID = 852600
// Of how many lightnings the circle consist
private constant integer LIGHTNINGS = 20
// How many of the lightnings do not cause damage
// They drain mana instead
private constant integer MANA_LIGHTNINGS = 0
// How many circle waves there are
private constant integer WAVES = 4
// How many more waves per ability level. Does not apply at lvl 1
private constant integer WAVES_BONUS = 2
// How often a new circle is spawned
// Match this with Data - Art duration
// in object editor
private constant real INTERVAL = 1
// Height offset from ground
private constant real HEIGHT = 60.
// How fast the circle expands
private constant real SPEED = 5.
// Initial radius of the circle
private constant real INIT_DIST = 32.
// Circle position update interval
private constant real TIMEOUT = 0.03
// How far the circle expands
private constant real MAX_OFFSET = 400.
// Base damage per second
private constant real DMG_BASE = 2000. * TIMEOUT
// Bonus damage per ability level per second.
// Does not apply at level 1
private constant real DMG_BONUS = 1000. * TIMEOUT
// How much mana is destroyed per second
private constant real MANA_BASE = 40. * TIMEOUT
// BOnus mana destroyed per ability level per second.
// Does not apply at level 1
private constant real MANA_BONUS = 20. * TIMEOUT
// How wide the lightning is. Used for detecting
// collision with units
private constant real LIGHTNING_WIDTH = 28.
// Does the circle rotate
private constant boolean ROTATES = true
// Min and max speed for the rotation
private constant real MIN_ROT_SPD = 15 * TIMEOUT * bj_DEGTORAD
private constant real MAX_ROT_SPD = 30 * TIMEOUT * bj_DEGTORAD
// Lightning types
private constant string TYPESAFE = "AFOD"
private constant string TYPEDANGER = "AFOD"
// RGB values of the mana lightnings, adjusts colour
// Adjust the first 255 between 0 and 255
private constant real MRED = 255. / 255.
private constant real MGREEN = 255. / 255.
private constant real MBLUE = 255. / 255.
// RGB values of the health lightnings, adjusts colour
private constant real HRED = 255. / 255.
private constant real HGREEN = 255. / 255.
private constant real HBLUE = 255. / 255.
// Transparency of the lightnings
private constant real MALPHA = 1.
private constant real HALPHA = 1.
// Effect when damaging lightning hits
private constant string DMG_EFFECT = "Abilities\\Spells\\Items\\OrbCorruption\\OrbCorruptionMissile.mdl"
// Effect when mana destroying lightning hits
private constant string MANA_EFFECT = "Abilities\\Spells\\Items\\OrbCorruption\\OrbCorruptionMissile.mdl"
// Attack- and damage types
private constant attacktype ATKTYPE = ATTACK_TYPE_NORMAL
private constant damagetype DMGTYPE = DAMAGE_TYPE_NORMAL
/*~~~~~~~~~~~~~ Global variables, don't change these ~~~~~~~~~~~~~*/
private real r1
private real r2
private real r3
private real r4
private real r5
private real r6
private real r7
private player plr
private unit un
private integer casts = 0
private location l1 = Location(0,0)
private location l2 = Location(0,0)
private group grp1 = CreateGroup()
private group grp2 = CreateGroup()
private group casters = CreateGroup()
private timer tmr = CreateTimer()
private hashtable hash = InitHashtable()
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
endglobals
/*~The hash functions return the child hash integer for hashtable~*/
private constant function HashCircles takes nothing returns integer
return 1
endfunction
private constant function HashActiveCircles takes nothing returns integer
return 2
endfunction
private constant function HashTime takes nothing returns integer
return 3
endfunction
private constant function HashInterval takes nothing returns integer
return 4
endfunction
private constant function HashDamage takes nothing returns integer
return 5
endfunction
private constant function HashSafeWidth takes nothing returns integer
return 6
endfunction
private constant function HashWaves takes nothing returns integer
return 7
endfunction
private constant function HashFirstFree takes nothing returns integer
return 8
endfunction
private constant function HashFirst takes nothing returns integer
return 9
endfunction
private constant function HashLast takes nothing returns integer
return 10
endfunction
private constant function HashMana takes nothing returns integer
return 11
endfunction
private function HashAngle takes integer value returns integer
return 10 * LIGHTNINGS + value
endfunction
private function HashDist takes integer value returns integer
return 20 * LIGHTNINGS + value
endfunction
private function HashDestroyed takes integer value returns integer
return 30 * LIGHTNINGS + value
endfunction
private function HashSafeAngle takes integer value returns integer
return 40 * LIGHTNINGS + value
endfunction
private function HashRotSpeed takes integer value returns integer
return 50 * LIGHTNINGS + value
endfunction
private function HashRotDir takes integer value returns integer
return 60 * LIGHTNINGS + value
endfunction
private function HashDummy takes integer value1, integer value2 returns integer
return 1000 * LIGHTNINGS + value1 * 100 + value2
endfunction
private function HashLightning takes integer value1, integer value2 returns integer
return 5000 * LIGHTNINGS + value1 * 100 + value2
endfunction
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~Deals damage to units~~~~~~~~~~~~~~~~~~~~~*/
private function Pick_Filter_2 takes nothing returns boolean
local unit u = GetFilterUnit()
if not(IsUnitInGroup(u, grp1)) and /*
*/ IsUnitEnemy(u, plr) and /*
*/ GetWidgetLife(u) > 0.405 and /*
*/ GetUnitFlyHeight(u) < HEIGHT then
if Cos(r1 - Atan2(GetUnitY(u) - r4, GetUnitX(u) - r3)) < r7 then
call UnitDamageTarget(un, u, r5, false, true, ATKTYPE, DMGTYPE, null)
call DestroyEffect(AddSpecialEffectTarget(DMG_EFFECT, u, "chest"))
elseif GetUnitState(u, UNIT_STATE_MANA) > 0 then
call DestroyEffect(AddSpecialEffectTarget(MANA_EFFECT, u, "chest"))
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) - r6)
endif
endif
set u = null
return FALSE
endfunction
private function Pick_Filter_1 takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), plr)
endfunction
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~Adds an expanding circle for the caster~~~~~~~~~~~~*/
private function Add_Circle takes unit u, integer ID returns nothing
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real angle = GetRandomReal(-bj_PI, bj_PI)
local real x1
local real y1
local real x2
local real y2
local integer i = 0
local integer first = LoadInteger(hash, ID, HashFirst())
local integer last = LoadInteger(hash, ID, HashLast())
local integer free = LoadInteger(hash, ID, HashFirstFree())
local integer circles = LoadInteger(hash, ID, HashCircles())
local integer waves = LoadInteger(hash, ID, HashWaves())
local lightning l
// Saves the angle where the first lightning starts from
call SaveReal(hash, ID, HashAngle(free), angle)
// Saves the angle at the center of the safe lightnings
call SaveReal(hash, ID, HashSafeAngle(free), angle + (I2R(MANA_LIGHTNINGS) / I2R(LIGHTNINGS))* bj_PI)
// Randomizes the rotation angle
if ROTATES then
if GetRandomInt(1,2) == 1 then
call SaveReal(hash, ID, HashRotDir(free), 1)
else
call SaveReal(hash, ID, HashRotDir(free), -1)
endif
endif
// The loop creates a circle of lightnings and
// dummies around the caster
loop
set x1 = x + INIT_DIST * Cos(angle)
set y1 = y + INIT_DIST * Sin(angle)
set angle = angle + 2 * bj_PI / LIGHTNINGS
set x2 = x + INIT_DIST * Cos(angle)
set y2 = y + INIT_DIST * Sin(angle)
if i < MANA_LIGHTNINGS then
set l = AddLightningEx(TYPESAFE , true , x1 , y1 , HEIGHT , x2 , y2 , HEIGHT)
call SetLightningColor(l, MRED, MGREEN, MBLUE, MALPHA)
else
set l = AddLightningEx(TYPEDANGER , true , x1 , y1 , HEIGHT , x2 , y2 , HEIGHT)
call SetLightningColor(l, HRED, HGREEN, HBLUE, HALPHA)
endif
set bj_lastCreatedUnit = CreateUnit(Player(15), DUMMY_TYPE, x1, y1, angle*bj_RADTODEG)
call SetUnitFlyHeight(bj_lastCreatedUnit, HEIGHT, 0)
// Remove Move ability from dummy so it won't try to return
// to the pointwhere it was created at
call UnitRemoveAbility(bj_lastCreatedUnit, 'Amov')
call SaveUnitHandle(hash, ID, HashDummy(free,i), bj_lastCreatedUnit)
call SaveLightningHandle(hash, ID, HashLightning(free,i), l)
set i = i + 1
exitwhen i >= LIGHTNINGS
endloop
// Saves the distance of the circle from the caster
call SaveReal(hash, ID, HashDist(free), INIT_DIST)
call SaveBoolean(hash, ID, HashDestroyed(free), false)
call SaveInteger(hash, ID, HashCircles(), circles + 1)
call SaveInteger(hash, ID, HashFirstFree(), free + 1)
call SaveInteger(hash, ID, HashActiveCircles(), LoadInteger(hash, ID, HashActiveCircles()) + 1)
call SaveReal(hash, ID, HashRotSpeed(free), GetRandomReal(MIN_ROT_SPD, MAX_ROT_SPD))
// Update the smallest index to loop through
if free < first then
call SaveInteger(hash, ID, HashFirst(), free + 1)
endif
// Update the largest index to loop through
if free > last then
call SaveInteger(hash, ID, HashLast(), free)
endif
set l = null
endfunction
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
private function Loop takes nothing returns nothing
local unit u = GetEnumUnit()
local integer ID = GetHandleId(u)
local integer i = 0
local integer j = LoadInteger(hash, ID, HashFirst())
local integer k = 1
local integer oid = GetUnitCurrentOrder(u)
local integer free = LoadInteger(hash, ID, HashFirstFree())
local integer circles = LoadInteger(hash, ID, HashCircles())
local integer activeCircles = LoadInteger(hash, ID, HashActiveCircles())
local integer maxloop = LoadInteger(hash, ID, HashLast())
local real time = LoadReal(hash, ID, HashTime())+ TIMEOUT
local real interv = LoadReal(hash, ID, HashInterval()) + TIMEOUT
local real rotdir
local real offset
local real angle
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x1
local real x2
local real y1
local real y2
local unit dummy
local lightning l
// Caster must be alive, waves left to cast and at least one active circle
if not(IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0) and (circles < LoadInteger(hash, ID, HashWaves()) or activeCircles != 0) and oid == ORDERID then
loop
set rotdir = LoadReal(hash, ID, HashRotDir(j))
set angle = LoadReal(hash, ID, HashAngle(j))
set offset = LoadReal(hash, ID, HashDist(j)) + SPEED
// Has the circle not reached max dist
if offset < MAX_OFFSET then
set i = 0
loop
set x1 = x + offset * Cos(angle)
set y1 = y + offset * Sin(angle)
set angle = angle + 2 * bj_PI / LIGHTNINGS
set x2 = x + offset * Cos(angle)
set y2 = y + offset * Sin(angle)
call MoveLocation(l1, x1, y1)
call MoveLocation(l2, x2, y2)
set l = LoadLightningHandle(hash, ID, HashLightning(j,i))
// Makes the lightnings to "flow" the right direction
if rotdir == 1 then
call MoveLightningEx(l, false, x2, y2, HEIGHT + GetLocationZ(l2), x1, y1, HEIGHT + GetLocationZ(l1))
else
call MoveLightningEx(l, false, x1, y1, HEIGHT + GetLocationZ(l1), x2, y2, HEIGHT + GetLocationZ(l2))
endif
set dummy = LoadUnitHandle(hash, ID, HashDummy(j,i))
call SetUnitX(dummy, x1)
call SetUnitY(dummy, y1)
set i = i + 1
exitwhen i > LIGHTNINGS
endloop
set l = null
set dummy = null
set un = u
set plr = GetOwningPlayer(u)
set r1 = LoadReal(hash, ID, HashSafeAngle(j))
set r2 = LoadReal(hash, ID, HashSafeWidth())
set r7 = Cos(r2)
set r3 = x
set r4 = y
set r5 = LoadReal(hash, ID, HashDamage())
set r6 = LoadReal(hash, ID, HashMana())
call GroupEnumUnitsInRange(grp1, x, y, offset - LIGHTNING_WIDTH, function Pick_Filter_1)
call GroupEnumUnitsInRange(grp2, x, y, offset + LIGHTNING_WIDTH, function Pick_Filter_2)
call SaveReal(hash, ID, HashDist(j), offset)
// Updates the rotation angle and the safe angle
static if ROTATES then
call SaveReal(hash, ID, HashAngle(j), LoadReal(hash, ID, HashAngle(j)) + LoadReal(hash, ID, HashRotSpeed(j)) * LoadReal(hash, ID, HashRotDir(j)))
call SaveReal(hash, ID, HashSafeAngle(j), LoadReal(hash, ID, HashAngle(j)) + r2)
endif
else
// Checks whether the circle has been destroyed already or not
if LoadBoolean(hash, ID, HashDestroyed(j)) != true then
// The loop destroys all dummies and lightnings of the circle
set k = 0
loop
// Checks that the lightning exists, can produce fatal error without this check
if HaveSavedHandle(hash, ID, HashLightning(j,k)) then
call DestroyLightning(LoadLightningHandle(hash, ID, HashLightning(j,k)))
call UnitApplyTimedLife(LoadUnitHandle(hash, ID, HashDummy(j,k)), 1 , 0.01)
call RemoveSavedHandle(hash, ID, HashLightning(j,k))
endif
set k = k + 1
exitwhen k > LIGHTNINGS
endloop
// Marks the circle as been destroyed
call SaveBoolean(hash, ID, HashDestroyed(j), true)
// Reduces the number of active circles for the caster
call SaveInteger(hash, ID, HashActiveCircles(), activeCircles - 1)
// Updates the first free index
if j < free then
call SaveInteger(hash, ID, HashFirstFree(), j)
endif
endif
endif
set j = j + 1
exitwhen j > maxloop
endloop
// Updates the interval time used for creating a new circle
call SaveReal(hash, ID, HashTime(), interv)
if circles < LoadInteger(hash, ID, HashWaves()) then
if interv >= INTERVAL then
call Add_Circle(u, ID)
call SaveReal(hash, ID, HashInterval(), 0)
else
call SaveReal(hash, ID, HashInterval(), interv)
endif
endif
else
loop
set k = 0
loop
if HaveSavedHandle(hash, ID, HashLightning(j,k)) then
call DestroyLightning(LoadLightningHandle(hash, ID, HashLightning(j,k)))
call UnitApplyTimedLife(LoadUnitHandle(hash, ID, HashDummy(j,k)), 1 , 0.01)
endif
set k = k + 1
exitwhen k > LIGHTNINGS
endloop
set j = j + 1
exitwhen j > maxloop
endloop
call GroupRemoveUnit(casters, u)
if oid == ORDERID then
call IssueImmediateOrder(u, "stop")
endif
call FlushChildHashtable(hash, ID)
set casts = casts - 1
if casts == 0 then
call PauseTimer(tmr)
endif
endif
set u = null
endfunction
private function Timer_Expire takes nothing returns nothing
call ForGroup(casters, function Loop)
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer ID = GetHandleId(u)
local integer level = GetUnitAbilityLevel(u, ABILCODE) - 1
/*~~~ 0 value doesn't need to be saved but I do it to remember ~~~*/
/*~~~~~~~~~~~~~~~ the things that need to be saved ~~~~~~~~~~~~~~~*/
// call SaveReal(hash, ID, HashTime(), 0)
// call SaveReal(hash, ID, HashInterval(), 0)
// call SaveInteger(hash, ID, HashLast(), 0)
// call SaveInteger(hash, ID, HashFirst(), 0)
// call SaveInteger(hash, ID, HashCircles(), 0)
// call SaveInteger(hash, ID, HashFirstFree(), 0)
// call SaveInteger(hash, ID, HashActiveCircles(), 0)
call SaveInteger(hash, ID, HashWaves(), WAVES + WAVES_BONUS * level)
call SaveReal(hash, ID, HashDamage(), DMG_BASE + DMG_BONUS * level)
call SaveReal(hash, ID, HashMana(), MANA_BASE + MANA_BONUS * level)
call SaveReal(hash, ID, HashSafeWidth(), I2R(MANA_LIGHTNINGS) / I2R(LIGHTNINGS)* bj_PI)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
call Add_Circle(u, ID)
call GroupAddUnit(casters, u)
if casts == 0 then
call TimerStart(tmr , TIMEOUT , true , function Timer_Expire)
endif
set casts = casts + 1
set u = null
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILCODE
endfunction
private function Omega_Wave takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(t, function Conditions )
call TriggerAddAction(t, function Actions )
endfunction
endscope
library MouseUtils
/*
-------------------
MouseUtils
- MyPad
1.0.2.2
-------------------
----------------------------------------------------------------------------
A simple snippet that allows one to
conveniently use the mouse natives
as they were meant to be...
-------------------
| API |
-------------------
struct UserMouse extends array
static method operator [] (player p) -> thistype
- Returns the player's id + 1
static method getCurEventType() -> integer
- Returns the custom event that got executed.
method operator player -> player
- Returns Player(this - 1)
readonly real mouseX
readonly real mouseY
- Returns the current mouse coordinates.
readonly method operator isMouseClicked -> boolean
- Determines whether any mouse key has been clicked,
and will return true on the first mouse key.
method isMouseButtonClicked(mousebuttontype mouseButton)
- Returns true if the mouse button hasn't been
released yet.
method setMousePos(real x, y) (introduced in 1.0.2.2)
- Sets the mouse position for a given player.
static method registerCode(code c, integer ev) -> triggercondition
- Lets code run upon the execution of a certain event.
- Returns a triggercondition that can be removed later.
static method unregisterCallback(triggercondition trgHndl, integer ev)
- Removes a generated triggercondition from the trigger.
functions:
GetPlayerMouseX(player p) -> real
GetPlayerMouseY(player p) -> real
- Returns the coordinates of the mouse of the player.
OnMouseEvent(code func, integer eventId) -> triggercondition
- See UserMouse.registerCode
GetMouseEventType() -> integer
- See UserMouse.getCurEventType
UnregisterMouseCallback(triggercondition t, integer eventId)
- See UserMouse.unregisterCallback
SetUserMousePos(player p, real x, real y)
- See UserMouse.setMousePos
Unique Global Constants:
IMPL_LOCK (Introduced in v.1.0.2.2)
- Enables or disables the lock option
-------------------
| Credits |
-------------------
- Pyrogasm for pointing out a comparison logic flaw
in operator isMouseClicked.
- Illidan(Evil)X for the useful enum handles that
grant more functionality to this snippet.
- TriggerHappy for the suggestion to include
associated events and callbacks to this snippet.
- Quilnez for pointing out a bug related to the
method isMouseButtonClicked not working as intended
in certain situations.
----------------------------------------------------------------------------
*/
// Arbitrary constants
globals
constant integer EVENT_MOUSE_UP = 1024
constant integer EVENT_MOUSE_DOWN = 2048
constant integer EVENT_MOUSE_MOVE = 3072
private constant boolean IMPL_LOCK = false
endglobals
private module Init
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
struct UserMouse extends array
static if IMPL_LOCK then
// Determines the minimum interval that a mouse move event detector
// will be deactivated. (Globally-based)
// You can configure it to any amount you like.
private static constant real INTERVAL = 0.031250000
// Determines how many times a mouse move event detector can fire
// before being deactivated. (locally-based)
// You can configure this to any integer value. (Preferably positive)
private static constant integer MOUSE_COUNT_MAX = 16
// Determines the amount to be deducted from mouseEventCount
// per INTERVAL. Runs independently of resetTimer
private static constant integer MOUSE_COUNT_LOSS = 8
private static constant boolean IS_INSTANT = INTERVAL <= 0.
endif
private static integer currentEventType = 0
private static integer updateCount = 0
private static trigger stateDetector = null
static if IMPL_LOCK and not IS_INSTANT then
private static timer resetTimer = null
endif
private static trigger array evTrigger
private static integer array mouseButtonStack
static if IMPL_LOCK and not IS_INSTANT then
private integer mouseEventCount
private timer mouseEventReductor
endif
private thistype next
private thistype prev
private thistype resetNext
private thistype resetPrev
private trigger posDetector
private integer mouseClickCount
readonly real mouseX
readonly real mouseY
// Converts the enum type mousebuttontype into an integer
private static method toIndex takes mousebuttontype mouseButton returns integer
return GetHandleId(mouseButton)
endmethod
static method getCurEventType takes nothing returns integer
return currentEventType
endmethod
static method operator [] takes player p returns thistype
if thistype(GetPlayerId(p) + 1).posDetector != null then
return GetPlayerId(p) + 1
endif
return 0
endmethod
method operator player takes nothing returns player
return Player(this - 1)
endmethod
method operator isMouseClicked takes nothing returns boolean
return .mouseClickCount > 0
endmethod
method isMouseButtonClicked takes mousebuttontype mouseButton returns boolean
return UserMouse.mouseButtonStack[(this - 1)*3 + UserMouse.toIndex(mouseButton)] > 0
endmethod
method setMousePos takes integer x, integer y returns nothing
if GetLocalPlayer() == this.player then
call BlzSetMousePos(x, y)
endif
endmethod
static if IMPL_LOCK then
private static method getMouseEventReductor takes timer t returns thistype
local thistype this = thistype(0).next
loop
exitwhen this.mouseEventReductor == t or this == 0
set this = this.next
endloop
return this
endmethod
private static method onMouseUpdateListener takes nothing returns nothing
local thistype this = thistype(0).resetNext
set updateCount = 0
loop
exitwhen this == 0
set updateCount = updateCount + 1
set this.mouseEventCount = 0
call EnableTrigger(this.posDetector)
set this.resetNext.resetPrev = this.resetPrev
set this.resetPrev.resetNext = this.resetNext
set this = this.resetNext
endloop
if updateCount > 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
else
call onMouseUpdateListener()
endif
else
static if not IS_INSTANT then
call TimerStart(resetTimer, 0.00, false, null)
call PauseTimer(resetTimer)
endif
endif
endmethod
private static method onMouseReductListener takes nothing returns nothing
local thistype this = getMouseEventReductor(GetExpiredTimer())
if this.mouseEventCount <= 0 then
call PauseTimer(this.mouseEventReductor)
else
set this.mouseEventCount = IMaxBJ(this.mouseEventCount - MOUSE_COUNT_LOSS, 0)
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endmethod
endif
private static method onMouseUpOrDown takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local integer index = (this - 1)*3 + UserMouse.toIndex(BlzGetTriggerPlayerMouseButton())
local boolean releaseFlag = false
if GetTriggerEventId() == EVENT_PLAYER_MOUSE_DOWN then
set this.mouseClickCount = IMinBJ(this.mouseClickCount + 1, 3)
set releaseFlag = UserMouse.mouseButtonStack[index] <= 0
set UserMouse.mouseButtonStack[index] = IMinBJ(UserMouse.mouseButtonStack[index] + 1, 1)
if releaseFlag then
set currentEventType = EVENT_MOUSE_DOWN
call TriggerEvaluate(evTrigger[EVENT_MOUSE_DOWN])
endif
else
set this.mouseClickCount = IMaxBJ(this.mouseClickCount - 1, 0)
set releaseFlag = UserMouse.mouseButtonStack[index] > 0
set UserMouse.mouseButtonStack[index] = IMaxBJ(UserMouse.mouseButtonStack[index] - 1, 0)
if releaseFlag then
set currentEventType = EVENT_MOUSE_UP
call TriggerEvaluate(evTrigger[EVENT_MOUSE_UP])
endif
endif
endmethod
private static method onMouseMove takes nothing returns nothing
local thistype this = thistype[GetTriggerPlayer()]
local boolean started = false
set this.mouseX = BlzGetTriggerPlayerMouseX()
set this.mouseY = BlzGetTriggerPlayerMouseY()
static if IMPL_LOCK then
set this.mouseEventCount = this.mouseEventCount + 1
if this.mouseEventCount <= 1 then
call TimerStart(this.mouseEventReductor, INTERVAL, false, function thistype.onMouseReductListener)
endif
endif
set currentEventType = EVENT_MOUSE_MOVE
call TriggerEvaluate(evTrigger[EVENT_MOUSE_MOVE])
static if IMPL_LOCK then
if this.mouseEventCount >= thistype.MOUSE_COUNT_MAX then
call DisableTrigger(this.posDetector)
if thistype(0).resetNext == 0 then
static if not IS_INSTANT then
call TimerStart(resetTimer, INTERVAL, false, function thistype.onMouseUpdateListener)
// Mouse event reductor should be paused
else
set started = true
endif
call PauseTimer(this.mouseEventReductor)
endif
set this.resetNext = 0
set this.resetPrev = this.resetNext.resetPrev
set this.resetPrev.resetNext = this
set this.resetNext.resetPrev = this
if started then
call onMouseUpdateListener()
endif
endif
endif
endmethod
private static method init takes nothing returns nothing
local thistype this = 1
local player p = this.player
static if IMPL_LOCK and not IS_INSTANT then
set resetTimer = CreateTimer()
endif
set stateDetector = CreateTrigger()
set evTrigger[EVENT_MOUSE_UP] = CreateTrigger()
set evTrigger[EVENT_MOUSE_DOWN] = CreateTrigger()
set evTrigger[EVENT_MOUSE_MOVE] = CreateTrigger()
call TriggerAddCondition( stateDetector, Condition(function thistype.onMouseUpOrDown))
loop
exitwhen integer(this) > bj_MAX_PLAYER_SLOTS
if GetPlayerController(p) == MAP_CONTROL_USER and GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING then
set this.next = 0
set this.prev = thistype(0).prev
set thistype(0).prev.next = this
set thistype(0).prev = this
set this.posDetector = CreateTrigger()
static if IMPL_LOCK and not IS_INSTANT then
set this.mouseEventReductor = CreateTimer()
endif
call TriggerRegisterPlayerEvent( this.posDetector, p, EVENT_PLAYER_MOUSE_MOVE )
call TriggerAddCondition( this.posDetector, Condition(function thistype.onMouseMove))
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_UP )
call TriggerRegisterPlayerEvent( stateDetector, p, EVENT_PLAYER_MOUSE_DOWN )
endif
set this = this + 1
set p = this.player
endloop
endmethod
static method registerCode takes code handlerFunc, integer eventId returns triggercondition
return TriggerAddCondition(evTrigger[eventId], Condition(handlerFunc))
endmethod
static method unregisterCallback takes triggercondition whichHandler, integer eventId returns nothing
call TriggerRemoveCondition(evTrigger[eventId], whichHandler)
endmethod
implement Init
endstruct
function GetPlayerMouseX takes player p returns real
return UserMouse[p].mouseX
endfunction
function GetPlayerMouseY takes player p returns real
return UserMouse[p].mouseY
endfunction
function OnMouseEvent takes code func, integer eventId returns triggercondition
return UserMouse.registerCode(func, eventId)
endfunction
function GetMouseEventType takes nothing returns integer
return UserMouse.getCurEventType()
endfunction
function UnregisterMouseCallback takes triggercondition whichHandler, integer eventId returns nothing
call UserMouse.unregisterCallback(whichHandler, eventId)
endfunction
function SetUserMousePos takes player p, integer x, integer y returns nothing
call UserMouse[p].setMousePos(x, y)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library LineSegmentEnumeration /* v2.1a -- hiveworkshop.com/threads/line-segment-enumeration-v1-1.286552/
Information
¯¯¯¯¯¯¯¯¯¯¯
Allows to enumerate widgets inside a line segment with an offset.
So basicly it will result in a rect, but which is also allowed to be rotated.
Mechanics
¯¯¯¯¯¯¯¯¯
(Issue:)
The problem with normal jass rects is that they aren't defined by 4 points, but only by 4 values: x/y -min/max.
The result is that a jass rect is never rotated, so it's always paralel to the x/y axis.
But when we draw a line from point A to point B we might also create a non-axix-parelel rect, and then
we can't use the normal rect natives from jass anymore to find out if a point is inside the rect.
(Solution:)
To solve this problem the system does following:
jass rect: rectangular defined by 4 values (axis paralel)
custom rect: the real rectangular that is defined by user (not axis parelel)
1. Create a big jass rect that is big enough so we can ensure to enum all widgets that are potentialy inside our custom rect. (Enum_Group)
This Enum_Group will contain all wanted units, but may also contain not wanted units.
2. We rotate the custom rect around Point B, by angle "theta", so it gets now a normal, non-rotated rect. (axis parelel)
3. We loop through Enum_Group, and rotate all widget's coordinates also by the same "theta" value around Point B.
4. Now what happened is that the custom rect was manipulated so it got axis parelel. And we also used the same maths
to manipulate the x/y coordinate of our widgets, so the relation between the custom rect and the widget is still the very same.
But what we can do now is to use native jass logics to check if the widget is within the bounds of the rotated custom rect
with only comparing it's x/y coordinates with the rect's x/y -min/max coodinates.
Note: this approach is not the most performant one, but it doesn't work with custom types. So if you already work with for example
struct rects or other polygons, and you care for trigomnomig orientation you can write straight forward functions to check if a point
is inside a quadrilateral, as standalone function.
*/
// --- API ---
//! novjass
struct LineSegment
static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset returns nothing
static method EnumDestructables takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated destructables you have access to:
static integer DestructableCounter // starts with index "0"
static destructable array Destructable
static method EnumItems takes real ax, real ay, real bx, real by, real offset returns nothing
// after enumerated items you have access to:
static integer ItemCounter // starts with index "0"
static destructable array Item
//! endnovjass
// ==== End API ====
struct LineSegment extends array
private static constant rect RECT = Rect(0, 0, 0, 0)
private static constant group GROUP = CreateGroup()
public static method EnumUnits takes group whichgroup, real ax, real ay, real bx, real by, real offset returns nothing
local real angle = Atan2(by - ay, bx - ax)
local real theta = ModuloReal(angle, bj_PI/2)
local real thetaSin
local real thetaCos
local unit u
local real x
local real y
local real x_new
local real y_new
local real maxX
local real maxY
local real minX
local real minY
local real x1
local real y1
local real x2
local real y2
local real x3
local real y3
local real x4
local real y4
// Enum all potential units
if ax > bx then
set maxX = ax + offset
set minX = bx - offset
else
set maxX = bx + offset
set minX = ax - offset
endif
if ay > by then
set maxY = ay + offset
set minY = by - offset
else
set maxY = by + offset
set minY = ay - offset
endif
call SetRect(RECT, minX, minY, maxX, maxY)
call GroupEnumUnitsInRect(GROUP, RECT, null)
// Create and rotate rect around point B, so it gets unrotated
set angle = angle - theta
set angle = angle*-1
set thetaSin = Sin(-theta)
set thetaCos = Cos(-theta)
set x_new = (ax-bx)*thetaCos - (ay-by)*thetaSin + bx
set y_new = (ax-bx)*thetaSin + (ay-by)*thetaCos + by
set x1 = x_new + offset*Cos(angle - bj_PI*0.5)
set y1 = y_new + offset*Sin(angle - bj_PI*0.5)
set x2 = x_new + offset*Cos(angle + bj_PI*0.5)
set y2 = y_new + offset*Sin(angle + bj_PI*0.5)
set x3 = bx + offset*Cos(angle - bj_PI*0.5)
set y3 = by + offset*Sin(angle - bj_PI*0.5)
set x4 = bx + offset*Cos(angle + bj_PI*0.5)
set y4 = by + offset*Sin(angle + bj_PI*0.5)
// define max/min values of the new non-rotated rect
if x1 > x2 then
set maxX = RMaxBJ(x1, x3)
set minX = RMinBJ(x2, x4)
else
set maxX = RMaxBJ(x2, x4)
set minX = RMinBJ(x1, x3)
endif
if y1 > y2 then
set maxY = RMaxBJ(y1, y3)
set minY = RMinBJ(y2, y4)
else
set maxY = RMaxBJ(y2, y4)
set minY = RMinBJ(y1, y3)
endif
// enum through all tracked units, rotate it around B, and check if it's inside bounds
call GroupClear(whichgroup)
loop
set u = FirstOfGroup(GROUP)
exitwhen u == null
set x = GetUnitX(u)
set y = GetUnitY(u)
set x_new = (x-bx)*thetaCos - (y-by)*thetaSin + bx
set y_new = (x-bx)*thetaSin + (y-by)*thetaCos + by
if x_new >= minX and x_new <= maxX and y_new >= minY and y_new <= maxY then
call GroupAddUnit(whichgroup, u)
endif
call GroupRemoveUnit(GROUP, u)
endloop
endmethod
//! textmacro LSE_WIDGET takes TYPE, NAME
private static integer $NAME$Counter_p = -1
private static $TYPE$ array $NAME$_p
public static integer $NAME$Counter = -1
public static $TYPE$ array $NAME$
private static method on$NAME$Filter takes nothing returns nothing
set $NAME$Counter_p = $NAME$Counter_p + 1
set $NAME$_p[$NAME$Counter_p] = GetEnum$NAME$()
endmethod
public static method Enum$NAME$s takes real ax, real ay, real bx, real by, real offset returns nothing
local real angle = Atan2(by - ay, bx - ax)
local real theta = ModuloReal(angle, bj_PI/2)
local real thetaSin
local real thetaCos
local $TYPE$ t
local real x
local real y
local real x_new
local real y_new
local real maxX
local real maxY
local real minX
local real minY
local real x1
local real y1
local real x2
local real y2
local real x3
local real y3
local real x4
local real y4
// Enum all potential widgets
if ax > bx then
set maxX = ax + offset
set minX = bx - offset
else
set maxX = bx + offset
set minX = ax - offset
endif
if ay > by then
set maxY = ay + offset
set minY = by - offset
else
set maxY = by + offset
set minY = ay - offset
endif
call SetRect(RECT, minX, minY, maxX, maxY)
set $NAME$Counter_p = -1
call Enum$NAME$sInRect(RECT, null, function thistype.on$NAME$Filter)
// Create and rotate rect around point B, so it gets unrotated
set angle = angle - theta
set angle = angle*-1
set thetaSin = Sin(-theta)
set thetaCos = Cos(-theta)
set x_new = (ax-bx)*thetaCos - (ay-by)*thetaSin + bx
set y_new = (ax-bx)*thetaSin + (ay-by)*thetaCos + by
set x1 = x_new + offset*Cos(angle - bj_PI*0.5)
set y1 = y_new + offset*Sin(angle - bj_PI*0.5)
set x2 = x_new + offset*Cos(angle + bj_PI*0.5)
set y2 = y_new + offset*Sin(angle + bj_PI*0.5)
set x3 = bx + offset*Cos(angle - bj_PI*0.5)
set y3 = by + offset*Sin(angle - bj_PI*0.5)
set x4 = bx + offset*Cos(angle + bj_PI*0.5)
set y4 = by + offset*Sin(angle + bj_PI*0.5)
// define max/min values of the new non-rotated rect
if x1 > x2 then
set maxX = RMaxBJ(x1, x3)
set minX = RMinBJ(x2, x4)
else
set maxX = RMaxBJ(x2, x4)
set minX = RMinBJ(x1, x3)
endif
if y1 > y2 then
set maxY = RMaxBJ(y1, y3)
set minY = RMinBJ(y2, y4)
else
set maxY = RMaxBJ(y2, y4)
set minY = RMinBJ(y1, y3)
endif
// enum through all tracked widgets, rotate it around B, and check if it's inside bounds
set $NAME$Counter = -1
loop
exitwhen $NAME$Counter_p < 0
set t = $NAME$_p[$NAME$Counter_p]
set x = Get$NAME$X(t)
set y = Get$NAME$Y(t)
set x_new = (x-bx)*thetaCos - (y-by)*thetaSin + bx
set y_new = (x-bx)*thetaSin + (y-by)*thetaCos + by
if x_new >= minX and x_new <= maxX and y_new >= minY and y_new <= maxY then
set $NAME$Counter = $NAME$Counter + 1
set $NAME$[$NAME$Counter] = t
endif
set $NAME$_p[$NAME$Counter_p] = null
set $NAME$Counter_p = $NAME$Counter_p - 1
endloop
endmethod
//! endtextmacro
//! runtextmacro LSE_WIDGET("destructable", "Destructable")
//! runtextmacro LSE_WIDGET("item", "Item")
endstruct
endlibrary
//TESH.scrollpos=126
//TESH.alwaysfold=0
library LineSegmentEnumeration
globals
unit array units
private constant group GROUP = CreateGroup()
private constant rect RECT = Rect(0, 0, 0, 0)
endglobals
function EnumUnitsInLineSegment takes group whichgroup, real ax, real ay, real bx, real by, real offset returns nothing
local real angle = Atan2(by - ay, bx - ax)
local real theta = ModuloReal(angle, bj_PI/2)
local real thetaSin
local real thetaCos
local rect r
local unit u
local real x
local real y
local real x_new
local real y_new
local real maxX
local real maxY
local real minX
local real minY
local real x1
local real y1
local real x2
local real y2
local real x3
local real y3
local real x4
local real y4
if ax > bx then
set maxX = ax + offset
set minX = bx - offset
else
set maxX = bx + offset
set minX = ax - offset
endif
if ay > by then
set maxY = ay + offset
set minY = by - offset
else
set maxY = by + offset
set minY = ay - offset
endif
call SetRect(RECT, minX, minY, maxX, maxY)
call GroupEnumUnitsInRect(GROUP, RECT, null)
call SetUnitX(units[4], maxX)
call SetUnitY(units[4], maxY)
call SetUnitX(units[5], maxX)
call SetUnitY(units[5], minY)
call SetUnitX(units[6], minX)
call SetUnitY(units[6], maxY)
call SetUnitX(units[7], minX)
call SetUnitY(units[7], minY)
call ClearTextMessages()
call BJDebugMsg("angle: " + R2S(angle*bj_RADTODEG))
call BJDebugMsg("theta: " + R2S(theta*bj_RADTODEG))
set angle = angle - theta
set angle = angle*-1
set thetaSin = Sin(-theta)
set thetaCos = Cos(-theta)
call BJDebugMsg("angle fixed: " + R2S(angle*bj_RADTODEG))
set x_new = (ax-bx)*thetaCos - (ay-by)*thetaSin + bx
set y_new = (ax-bx)*thetaSin + (ay-by)*thetaCos + by
set x1 = x_new + offset*Cos(angle - bj_PI*0.5)
set y1 = y_new + offset*Sin(angle - bj_PI*0.5)
set x2 = x_new + offset*Cos(angle + bj_PI*0.5)
set y2 = y_new + offset*Sin(angle + bj_PI*0.5)
set x3 = bx + offset*Cos(angle - bj_PI*0.5)
set y3 = by + offset*Sin(angle - bj_PI*0.5)
set x4 = bx + offset*Cos(angle + bj_PI*0.5)
set y4 = by + offset*Sin(angle + bj_PI*0.5)
if x1 > x2 then
set maxX = RMaxBJ(x1, x3)
set minX = RMinBJ(x2, x4)
else
set maxX = RMaxBJ(x2, x4)
set minX = RMinBJ(x1, x3)
endif
if y1 > y2 then
set maxY = RMaxBJ(y1, y3)
set minY = RMinBJ(y2, y4)
else
set maxY = RMaxBJ(y2, y4)
set minY = RMinBJ(y1, y3)
endif
call SetUnitX(units[0], x1)
call SetUnitY(units[0], y1)
call SetUnitX(units[1], x2)
call SetUnitY(units[1], y2)
call SetUnitX(units[2], x3)
call SetUnitY(units[2], y3)
call SetUnitX(units[3], x4)
call SetUnitY(units[3], y4)
// ================== ===
call GroupClear(whichgroup)
loop
set u = FirstOfGroup(GROUP)
exitwhen u == null
if GetOwningPlayer(u) != GetLocalPlayer() then
set x = GetUnitX(u)
set y = GetUnitY(u)
set x_new = (x-bx)*thetaCos - (y-by)*thetaSin + bx
set y_new = (x-bx)*thetaSin + (y-by)*thetaCos + by
if x_new >= minX and x_new <= maxX and y_new >= minY and y_new <= maxY then
call GroupAddUnit(whichgroup, u)
endif
endif
call GroupRemoveUnit(GROUP, u)
endloop
endfunction
function Trig_LSE_Run_Units_Actions takes nothing returns nothing
call EnumUnitsInLineSegment(udg_LSE_Group, GetLocationX(udg_LSE_Loc_1), GetLocationY(udg_LSE_Loc_1), GetLocationX(udg_LSE_Loc_2), GetLocationY(udg_LSE_Loc_2), udg_LSE_Offset)
endfunction
//===========================================================================
function InitTrig_LSE_backup takes nothing returns nothing
set gg_trg_LSE_backup = CreateTrigger( )
set units[0] = CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 0)
set units[1] = CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 0)
set units[2] = CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 0)
set units[3] = CreateUnit(GetLocalPlayer(), 'hfoo', 0, 0, 0)
set units[4] = CreateUnit(GetLocalPlayer(), 'hpea', 0, 0, 0)
set units[5] = CreateUnit(GetLocalPlayer(), 'hpea', 0, 0, 0)
set units[6] = CreateUnit(GetLocalPlayer(), 'hpea', 0, 0, 0)
set units[7] = CreateUnit(GetLocalPlayer(), 'hpea', 0, 0, 0)
call UnitAddAbility(units[0], 'Aeth')
call UnitAddAbility(units[1], 'Aeth')
call UnitAddAbility(units[2], 'Aeth')
call UnitAddAbility(units[3], 'Aeth')
call UnitAddAbility(units[4], 'Aeth')
call UnitAddAbility(units[5], 'Aeth')
call UnitAddAbility(units[6], 'Aeth')
call UnitAddAbility(units[7], 'Aeth')
call TriggerAddAction( gg_trg_LSE_backup, function Trig_LSE_Run_Units_Actions )
endfunction
endlibrary
//TESH.scrollpos=5
//TESH.alwaysfold=0
library LineSegmentEnumerationGUI uses LineSegmentEnumeration /* v2.0
*/
private struct LineSegmentGUI extends array
private static method GetUnits takes nothing returns nothing
call LineSegment.EnumUnits(udg_LSE_Group, GetLocationX(udg_LSE_Loc_1), GetLocationY(udg_LSE_Loc_1), GetLocationX(udg_LSE_Loc_2), GetLocationY(udg_LSE_Loc_2), udg_LSE_Offset)
endmethod
private static method GetDestructables takes nothing returns nothing
call LineSegment.EnumDestructables(GetLocationX(udg_LSE_Loc_1), GetLocationY(udg_LSE_Loc_1), GetLocationX(udg_LSE_Loc_2), GetLocationY(udg_LSE_Loc_2), udg_LSE_Offset)
set udg_LSE_DestructableCounter = -1
loop
exitwhen LineSegment.DestructableCounter < 0
set udg_LSE_DestructableCounter = udg_LSE_DestructableCounter + 1
set udg_LSE_Destructable[udg_LSE_DestructableCounter] = LineSegment.Destructable[LineSegment.DestructableCounter]
set LineSegment.DestructableCounter = LineSegment.DestructableCounter - 1
endloop
endmethod
private static method GetItems takes nothing returns nothing
call LineSegment.EnumItems(GetLocationX(udg_LSE_Loc_1), GetLocationY(udg_LSE_Loc_1), GetLocationX(udg_LSE_Loc_2), GetLocationY(udg_LSE_Loc_2), udg_LSE_Offset)
set udg_LSE_ItemCounter = -1
loop
exitwhen LineSegment.ItemCounter < 0
set udg_LSE_ItemCounter = udg_LSE_ItemCounter + 1
set udg_LSE_Item[udg_LSE_ItemCounter] = LineSegment.Item[LineSegment.ItemCounter]
set LineSegment.ItemCounter = LineSegment.ItemCounter - 1
endloop
endmethod
private static method onInit takes nothing returns nothing
set udg_LSE_GetUnits = CreateTrigger()
set udg_LSE_GetDestructables = CreateTrigger()
set udg_LSE_GetItems = CreateTrigger()
call TriggerAddAction(udg_LSE_GetUnits, function thistype.GetUnits)
call TriggerAddAction(udg_LSE_GetDestructables, function thistype.GetDestructables)
call TriggerAddAction(udg_LSE_GetItems, function thistype.GetItems)
endmethod
endstruct
endlibrary
//TESH.scrollpos=186
//TESH.alwaysfold=0
scope StaticFieldA
native UnitAlive takes unit id returns boolean
globals
private constant real FPS = 0.0312500
private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
private constant integer SPELL_ID = 'A02X'
private constant string LIGHTNING_ID = "MBUR"
private constant real LIGHTNING_RED = 1.
private constant real LIGHTNING_GREEN = 0.25
private constant real LIGHTNING_BLUE = 1.
private constant real LIGHTNING_ALPHA = 1.
private constant real DURATION = 1.0
private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
endglobals
private constant function MaxDamage takes integer level returns real
return 100.*level
endfunction
private constant function MinDamage takes integer level returns real
return 75.*level
endfunction
private constant function Aoe takes integer level returns real
return 400 + 50.*level
endfunction
private function UnitFilter takes player source, unit targ returns boolean
return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//! textmacro_once STATIC_FIELD_ALLOC
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
//! endtextmacro
private struct Caster extends array
real x
real y
real temp
thistype prev
thistype next
static integer count
static timer period
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.temp = this.temp - FPS
if this.temp <= 0 then
call DestroyEffect(AddSpecialEffect(MODEL_PATH, this.x, this.y))
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method add takes real x, real y returns nothing
local thistype this
//! runtextmacro STATIC_FIELD_ALLOC()
set this.x = x
set this.y = y
set this.temp = DURATION
endmethod
static method onInit takes nothing returns nothing
set count = 0
set period = CreateTimer()
endmethod
endstruct
private struct SF extends array
unit targ
unit cast
lightning light
real dmg
real cx
real cy
real cz
real tx
real ty
real x
real y
real z
integer steps
thistype prev
thistype next
static integer count
static timer period
static group g
static location loc
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
call DestroyLightning(this.light)
call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
set this.light = null
set this.cast = null
set this.targ = null
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.tx = this.tx+this.x
set this.ty = this.ty+this.y
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
if IsTerrainWalkable(this.tx, this.ty) then
call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetUnitX(this.targ, this.tx)
call SetUnitY(this.targ, this.ty)
endif
set this.steps = this.steps - 1
if this.steps == 0 then
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method cond takes nothing returns boolean
local thistype this
local integer lvl
local real angle
local unit u
local unit v
local real x
local real y
local player p
local real dist
if GetSpellAbilityId() == SPELL_ID then
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set p = GetOwningPlayer(u)
set lvl = GetUnitAbilityLevel(u, SPELL_ID)
call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
loop
set v = FirstOfGroup(g)
exitwhen v == null
call GroupRemoveUnit(g,v)
if UnitFilter(p,v) then
//! runtextmacro STATIC_FIELD_ALLOC()
set this.cast = u
set this.targ = v
set this.cx = x
set this.cy = y
set this.tx = GetUnitX(v)
set this.ty = GetUnitY(v)
set angle = Atan2(this.ty-y, this.tx-x)
set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
set this.dmg = MinDamage(lvl) + (dist/Aoe(lvl))*(MaxDamage(lvl)-MinDamage(lvl))
set this.x = -(dist/DURATION)*FPS*Cos(angle)
set this.y = -(dist/DURATION)*FPS*Sin(angle)
call MoveLocation(loc, x, y)
set this.cz = GetLocationZ(loc) + 20
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
set this.steps = R2I(DURATION/FPS)
call SetUnitPropWindow(this.targ, 0)
endif
endloop
call Caster.add(x,y)
set u = null
set p = null
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
call Preload(MODEL_PATH)
set count = 0
set period = CreateTimer()
set g = CreateGroup()
set loc = Location(0,0)
set t = null
endmethod
endstruct
endscope
//TESH.scrollpos=135
//TESH.alwaysfold=0
scope StaticFieldE
//native UnitAlive takes unit id returns boolean
globals
private constant real FPS = 0.0312500
private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
private constant integer SPELL_ID = 'A02Y'
private constant string LIGHTNING_ID = "AFOD"
private constant real LIGHTNING_RED = 1
private constant real LIGHTNING_GREEN = 0.25
private constant real LIGHTNING_BLUE = 0.255
private constant real LIGHTNING_ALPHA = 1.
private constant real DURATION = 0.5
private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
private constant real SPEED = 1000.
endglobals
private constant function MaxDamage takes integer level returns real
return 300.*level
endfunction
private constant function MinDamage takes integer level returns real
return 250.*level
endfunction
private constant function Aoe takes integer level returns real
return 400 + 100.*level
endfunction
private function UnitFilter takes player source, unit targ returns boolean
return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//! textmacro_once STATIC_FIELD_ALLOC
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
//! endtextmacro
private struct SF extends array
unit targ
unit cast
lightning light
real dmg
real cx
real cy
real cz
real tx
real ty
real x
real y
real z
integer steps
thistype prev
thistype next
static integer count
static timer period
static group g
static location loc
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
call DestroyLightning(this.light)
call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
set this.light = null
set this.cast = null
set this.targ = null
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.tx = this.tx+this.x
set this.ty = this.ty+this.y
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
if IsTerrainWalkable(this.tx, this.ty) then
call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetUnitX(this.targ, this.tx)
call SetUnitY(this.targ, this.ty)
endif
set this.steps = this.steps - 1
if this.steps == 0 then
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method cond takes nothing returns boolean
local thistype this
local integer lvl
local real angle
local unit u
local unit v
local real x
local real y
local player p
local real dist
if GetSpellAbilityId() == SPELL_ID then
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set p = GetOwningPlayer(u)
set lvl = GetUnitAbilityLevel(u, SPELL_ID)
call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
call DestroyEffect(AddSpecialEffect(MODEL_PATH, x, y))
loop
set v = FirstOfGroup(g)
exitwhen v == null
call GroupRemoveUnit(g,v)
if UnitFilter(p,v) then
//! runtextmacro STATIC_FIELD_ALLOC()
set this.cast = u
set this.targ = v
set this.cx = x
set this.cy = y
set this.tx = GetUnitX(v)
set this.ty = GetUnitY(v)
set angle = Atan2(this.ty-y, this.tx-x)
set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
set this.dmg = MinDamage(lvl) + (1-(dist/Aoe(lvl)))*(MaxDamage(lvl)-MinDamage(lvl))
set this.x = SPEED*FPS*Cos(angle)
set this.y = SPEED*FPS*Sin(angle)
call MoveLocation(loc, x, y)
set this.cz = GetLocationZ(loc)
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
set this.steps = R2I(DURATION/FPS)
call SetUnitPropWindow(this.targ, 0)
endif
endloop
set u = null
set p = null
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
call Preload(MODEL_PATH)
set count = 0
set period = CreateTimer()
set g = CreateGroup()
set loc = Location(0,0)
set t = null
endmethod
endstruct
endscope
//TESH.scrollpos=67
//TESH.alwaysfold=0
*Spell Name: Acid Grenade [ GUI MUI ] v1.1 = Removed some stuffs and merged some.
*Spell Author/Creator: by jakeZinc.
*Spell Version: v1.1 = * Removed some unneeded variables, used local variables,
* Global variable are now reduced
* Merged the variable creator and configuration trigger.
*Spell Purpose: It can be used in modern maps, this is acid grenade that will
bring acidics in the enemy armies. It is greatly reducing their
armors and slowing them. It is AoE Spell so it will reduce some enemies at
the same time.
*Spell Idea: None
*Spell Requested: None
*Spell Features v1.1 = * Multi- Unit Instanceabilty ( MUI Spell )
* Lagless
* Leakless ( Expecting Fixes )
* Configurable
How to Import/Install:
=Preparing for import=
Go to:
File
Preferences
General
Check the box labelled ''Automatically create unknown variables while pasting trigger data''
=Speeding up import of object data-
Go to:
Window
make sure the 'brush list' is unchecked.
You can swap between my map and your map.
=Main importing=
Difficuly in Importing:
"Easy" = 1 to 3 Copy - Paste Required
"Medium" = 4 to 6 Copy - Paste Required
"Hard" = 7 above, Copy - Paste Required
Spell Importing Difficulty: 'Medium'
In order of importing: Copy --> Paste to your Map.
Object Data (OE) - Spell - Acid Grenade
Object Data (OE) - Spell - Acid Grenade ( Dummy Ability )
Object Data (OE) - Buff - Acid Grenade
Object Data (OE) - Unit - Acid Grenade ( Dummy ).
Trigger Data (TE) - Folder - Acid Grenade [ GUI ] v1.1.
Import ( F12 ) Dummy.mdl by Vexorian
* Notes:
Note #1: Make sure to Configure the " AG Configuration " trigger in the AG_Ability, AG_DummyType, AG_DummyAbility
Note #2: If the spell give you error about " X, Y, MX and MY thing " pls copy the " AG Variable Creator " trigger.
Note #3: Go to OE ( Object Editor ) --> Abilities --> Acid Grenade ( Dummy Ability ), Set the buff of the Acid
Grenade ( Dummy Ability ) to Acid Grenade Buff, you must done this because it is important.
Note #4: After you import the spell to your map then click the save button in your map then delete the
"AG Variable Creator"
Note #5: If the spell is now working without issue then go to Note #6
Note #6: ~~Enjoy the Spell!!! ( you can delete the README File after this )
=Modification=
All Modifications should be done in the Configuration Trigger, each configuration is explained and elaborated.
//==========================================================================================================================================
Pls Give credits if you use this spell in your map.
Credits: emjl3r ( For the Spell Map Template )
Credits: Vexorian ( Dummy.mdl )
Sincerely,
jakeZinc
//TESH.scrollpos=0
//TESH.alwaysfold=0
*Spell Name: Splitting Fireball v1.0 = Initial Upload
*Spell Author/Creator: by jakeZinc.
*Spell Version: v1.0 = * Initial Released
*Spell Purpose: After the Eruption spell ( fire ultimate spell of FireLord ), Now Ive got idea about
aggresive fire skill of FireLord and I called it Splitting Fireball. The caster will
release a primary fireball, travels to the target location. While traveling, it will spliting
a secondary fireballs in backwards that can damage enemies in a line every second. When the primary fireball
impact to the target location, it will cause a massive knockback to the nearby enemy units and
the primary fireball will split up to mini fireballs. Causing a flamestrike to the target location.
Useful in reducing waves of the enemies in the line in 1 shot.
*Spell Idea: None.
*Spell Requested: None.
*Spell Features v1.0 = * Multi- Unit Instanceabilty ( MUI Spell )
* Leakless
* Readability
* Well Documented
* Indexed Array
+ KB3D System
How to Import/Install:
=Preparing for import=
Go to:
File
Preferences
General
Check the box labelled ''Automatically create unknown variables while pasting trigger data''
=Speeding up import of object data-
Go to:
Window
make sure the 'brush list' is unchecked.
You can swap between my map and your map.
=Main importing=
Difficuly in Importing:
"Easy" = 1 to 3 Copy - Paste Required
"Medium" = 4 to 6 Copy - Paste Required
"Hard" = 7 above, Copy - Paste Required
Spell Importing Difficulty: 'Medium'
In order of importing: Copy --> Paste to your Map.
Object Editor - Abilities - Splitting Fireball.
Object Editor - Abilities - Splitting Fireball ( FlameStrikeDummy )
Object Editor - Units - SF Vexorian Dummy ( Dummy Unit )
Trigger Editor - Folder - SF - Splitting Fireball v1.0
Trigger Editor - Folder - Knockback 3D v1.6.X. ( Not needed if you have already one )
Import/Export Files:
You must import the dummy model by Vexorian in Import Manager ( F12 )
* Notes:
Note #1: Make sure to Configure the " SP Configuration " trigger in the SF_Ability and SF_VexorianDummyType.
Note #2: IF your map has already KnockBack 3D System then dont copy the KnockBack 3D System.
Note #3: If the impact or fireball model effect didnt show up in the spell then make sure that
you copy the "SF Vexorian Dummy" in your map and make sure you import the Dummy Model by Vexorian.
Note #4: Report to the Author If you found a bug or tell the author if the spell is not working.
Note #5: The spell will work if you follow the notes and the Main Importing Instructions.
Note #6: Enjoy
=Modification=
All Modifications should be done in the Configuration Trigger, each configuration is explained and elaborated.
//==========================================================================================================================================
Pls Give credits if you use this spell in your map.
Credits: Vexorian ( Dummy.mdl )
Credits: Jad ( KB3D System v1.6.X )
Sincerely,
jakeZinc
//TESH.scrollpos=90
//TESH.alwaysfold=0
/////////////////////////////////////////////////////////////////////////////
// //
// Knock-Back 3D v. 1.6.X [JASS - GUI] //
// by JAD aka DotCa //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// System Informations: //
// //
// The System is a well performing, ultra-purpose knockback (see uses //
// below ) Coded in JASS making it possible for all users to take //
// advantage of it, and GUI friendly to use, see Examples in the triggers //
// above //
// Configurations have default values: //
// //
// - KB3D_EndWhenDead ==> TRUE by default //
// - KB3D_UnpathaableStop ==> TRUE by default //
// - KB3D_iKB ==> TRUE by default //
// - KB3D_AttackType ==> ATTACK_TYPE_NORMAL by default //
// - KB3D_DamageType ==> DAMAGE_TYPE_MAGIC by default //
// - KB3D_AoEKB_Power ==> 1.00 by default //
// - Other Booleans are FALSE by default //
// //
// The System also uses Always positive values for some configurations //
// to not make the knockback go worng, those configurations are: //
// //
// "KB3D_Range" - "KB3D_Speed" - "KB3D_ZOffset" - "KB3D_AoE" //
// //
/////////////////////////////////////////////////////////////////////////////
// //
// iKB, intelligent KB informations: //
// //
// iKB, makes some features in KB3D act intelligently, those features: //
// //
// -Range: usually always positive, it will be available in negative //
// values, it will, if negative, flip the Angle (+180 d) //
// -Speed, usually always positive, it will be available in negative //
// values, it will act normally, just the KBed unit will //
// move backward if the current speed is negative //
// -Damages: //
// AoEEndDamage, AoEDamage, LineDamage, ImpactDamage, TargetDamage //
// //
// All those values ^ will turn intelligent, by this, it means //
// that if the Target of the Damage is not in approximative //
// height (Z) of the KBed Unit, the damage won't occure //
// -AoEKB, usually KBs all units in the AoE, it will choose only //
// Units that are close to it by the height, Z offset //
// //
/////////////////////////////////////////////////////////////////////////////
// //
// System Requirements: Basic WE - (NONE) //
// //
// The System uses implemented CheckWalkability System by PurgeandFire //
// You "can" remove the initialization trigger of PnF's System since //
// it is directly implemented in the System, all will work fine with or //
// without removing your Initializer trigger //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// Credits: //
// //
// *WEHZ & TS Helpers Group for helping in Script Fixes //
// *Barry the Moose for helping in main codes and fixes //
// *PurgeandFire for his CheckWalkability System //
// *Vexorian / Nestharus for the GetCollision function //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// How to Import? //
// //
// 1. Check that Create Unknown Variables is ticked in your WE Settings //
// 2. Copy the Paste this Trigger //
// 3. Congratulations, the System is now implemented in your map //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// How to Use? //
// //
// 1. There are 5 Examples of use in the KB3D Example Folder //
// 2. Documentations are there in each of the 5 examples to help you //
// 3. The KB3D System is an Ultra-Purpose System where you can use it for://
// -Projectiles, the system supports homing so a projectile is easy //
// -Jump, the System's smoothness in the fly is useful for a jump spell//
// -And of course, a 2D Knock-Back //
// -And More depending on your imagination //
// //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// //
// Bug Reports - Feedbacks //
// //
// * We count on you to report bugs in the system, also telling the source//
// * Feedbacks about the system are much appreciated //
// * We mostly hope suggestions about enhancements for the System //
// //
/////////////////////////////////////////////////////////////////////////////
function SaveAttackTypeHandle takes hashtable hash, integer parentKey, integer childKey, attacktype at returns nothing
call SaveInteger(hash, parentKey, childKey, GetHandleId(at))
endfunction
function LoadAttackTypeHandle takes hashtable hash, integer parentKey, integer childKey returns attacktype
return ConvertAttackType(LoadInteger(hash, parentKey, childKey))
endfunction
function SaveDamageTypeHandle takes hashtable hash, integer parentKey, integer childKey, damagetype dt returns nothing
call SaveInteger(hash, parentKey, childKey, GetHandleId(dt))
endfunction
function LoadDamageTypeHandle takes hashtable hash, integer parentKey, integer childKey returns damagetype
return ConvertDamageType(LoadInteger(hash, parentKey, childKey))
endfunction
function KB3D_AlwaysNeg takes real R returns real//Used for redering some values always lower than 0
if R > 0 then
return -R
endif
return R
endfunction
function KB3D_AlwaysPos takes real R returns real//Used for redering some values always higher than 0
if R < 0 then
return -R
endif
return R
endfunction
function KB3D_InBetween takes real Min, real R, real Max returns real//Used to maintain values between 2 others
if R < Min then
return Min
elseif R > Max then
return Max
endif
return R
endfunction
function KB3D_IsInBetween takes real Min, real R, real Max returns boolean//Used to maintain values between 2 others
return R > Min and R < Max
endfunction
function KB3D_Approx takes unit U, unit U2, integer Loop returns boolean
local real r = LoadReal(udg_KB3D_HA, 29, Loop) / 2
local real r1 = GetUnitFlyHeight(U2)
return KB3D_IsInBetween(r1-r, GetUnitFlyHeight(U), r1+r)
endfunction
function KB3D_Filter takes unit U, unit U1, integer Loop returns boolean
if IsUnitType(U, UNIT_TYPE_DEAD) then
else
if not(LoadBoolean(udg_KB3D_HA, 48, Loop)) and ( IsUnitType(U, UNIT_TYPE_STRUCTURE)) then
return false
endif
if not(LoadBoolean(udg_KB3D_HA, 49, Loop)) and ( IsUnitType(U, UNIT_TYPE_MECHANICAL)) then
return false
endif
if not(LoadBoolean(udg_KB3D_HA, 50, Loop)) and ( IsUnitType(U, UNIT_TYPE_MAGIC_IMMUNE)) then
return false
endif
if not(LoadBoolean(udg_KB3D_HA, 51, Loop)) and ( IsUnitAlly(U, GetOwningPlayer(U1))) then
return false
endif
return true
endif
return false
endfunction
function KB3D_RegisterUnitCollision takes unit u, real x, real y, integer i returns real //Somehow a library for UnitCollision function
local real l = 0
local real h = 300
local real m = 150
local real nm
loop
if (IsUnitInRangeXY(u, x+m, y, 0)) then
set l = m
else
set h = m
endif
set nm = (l+h)/2
exitwhen nm+.001 > m and nm-.001 < m
set m = nm
endloop
set m = R2I(m*10)/10.
call SaveReal( udg_KB3D_HA, 16, GetUnitTypeId(u), m )
return m
endfunction
function KB3D_GetUnitCollision takes unit u returns real//Used to know the collision of a unit //Credits to Netharus// converted by malhorne
local integer i = GetUnitTypeId(u)
if HaveSavedReal( udg_KB3D_HA, 16, i) then
return LoadReal(udg_KB3D_HA, 16, i)
endif
return KB3D_RegisterUnitCollision(u, GetUnitX(u), GetUnitY(u), i)
endfunction
function KB3D_Tree_Check takes destructable D returns boolean //Checks if a destructable is a tree
return (IssueTargetOrder( udg_KB3D_Harvester, "harvest", D ) and (IssueImmediateOrder(udg_KB3D_Harvester, "stop")) )
endfunction
function KB3D_KillEnumDest takes nothing returns nothing //Function used in Enumeration loop
local destructable D = GetEnumDestructable()
if GetWidgetLife(D)>0 and ( KB3D_Tree_Check(D) ) and (GetUnitFlyHeight(LoadUnitHandle(udg_KB3D_HA, 0, R2I(udg_KB3D_Reals[0]))) < GetDestructableOccluderHeight(D)) then
call KillDestructable(D)
set D = null
endif
endfunction
function KB3D_CircleTreeKill takes real radius, real x, real y returns nothing//To destroy trees around the unit
local rect r = Rect(x-radius, y-radius, x+radius, y+radius)
call EnumDestructablesInRect(r, null, function KB3D_KillEnumDest)
call RemoveRect(r)
set r = null
endfunction
function KB3D_CW_Loop takes nothing returns nothing//function for item group loop for Check Walkability System
if IsItemVisible(GetEnumItem()) then
set udg_CP_HiddenItems[udg_CP_HiddenItemsIndex] = GetEnumItem()
call SetItemVisible(udg_CP_HiddenItems[udg_CP_HiddenItemsIndex], false)
set udg_CP_HiddenItemsIndex = ( udg_CP_HiddenItemsIndex + 1 )
endif
endfunction
function KB3D_CW takes real x, real y returns boolean//Check Walkability System by PnF
local real x2 = 0
local real y2 = 0
call MoveRectTo(udg_CP_Rect, x, y)
call EnumItemsInRect(udg_CP_Rect, null, function KB3D_CW_Loop )
call SetItemPosition(udg_CP_Item, x, y)
set x2 = GetWidgetX(udg_CP_Item)
set y2 = GetWidgetY(udg_CP_Item)
call SetItemVisible(udg_CP_Item, false)
loop
exitwhen udg_CP_HiddenItemsIndex <= 0
set udg_CP_HiddenItemsIndex = udg_CP_HiddenItemsIndex - 1
call SetItemVisible(udg_CP_HiddenItems[udg_CP_HiddenItemsIndex], true)
set udg_CP_HiddenItems[udg_CP_HiddenItemsIndex] = null
endloop
return (((x2-x)*(x2-x) + (y2-y)*(y2-y) <= 100) and (not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)))
endfunction
function KB3D_ClearInstance takes integer i returns nothing
local integer x = 0
call DestroyGroup(LoadGroupHandle(udg_KB3D_HA, 27, i))
loop
exitwhen x > 100
call RemoveSavedHandle(udg_KB3D_HA, x, i)
call SaveReal(udg_KB3D_HA, x, i, 0)
set x = x +1
endloop
endfunction
function MoveUnit_3D takes unit U, real x, real y, real z, real MaxZ, boolean P, boolean OS, boolean KiOS returns nothing
call SetUnitFlyHeight(U, KB3D_InBetween(GetUnitDefaultFlyHeight(U), z, 9999), 0)
if ( not(P) or ( KB3D_CW(x, y) ) or (OS) ) then
if (OS) then
call SetUnitX(U, KB3D_InBetween(udg_KB3D_Reals[6], x, udg_KB3D_Reals[5]))
call SetUnitY(U, KB3D_InBetween(udg_KB3D_Reals[8], y, udg_KB3D_Reals[7]))
if (KiOS) and (not(KB3D_IsInBetween(udg_KB3D_Reals[2], x, udg_KB3D_Reals[1])) or not(KB3D_IsInBetween(udg_KB3D_Reals[4], x, udg_KB3D_Reals[3]))) then
call KillUnit(U)
endif
else
call SetUnitX(U, KB3D_InBetween(udg_KB3D_Reals[2], x, udg_KB3D_Reals[1]))
call SetUnitY(U, KB3D_InBetween(udg_KB3D_Reals[4], y, udg_KB3D_Reals[3]))
endif
endif
endfunction
function KB3D_LineDamageLoop takes nothing returns boolean
local unit U = GetFilterUnit()
local integer Loop = R2I(udg_KB3D_Reals[0])
local unit Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
local attacktype AType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
local damagetype DType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
local real LineD = LoadReal(udg_KB3D_HA, 28, Loop)
local unit U1 = LoadUnitHandle(udg_KB3D_HA, 0, Loop)
local group G = LoadGroupHandle(udg_KB3D_HA, 27, Loop)
if KB3D_Filter(U, U1, Loop) and not ( IsUnitInGroup(U, G) ) then
call GroupAddUnit(G, U)
if not(LoadBoolean(udg_KB3D_HA, 44, Loop)) then
call UnitDamageTarget(Damager, U, LineD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
elseif KB3D_Approx(U, U1, Loop) then
call UnitDamageTarget(Damager, U, LineD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
endif
endif
set G = null
set U = null
set U1 = null
set Damager = null
set AType = null
set DType = null
return false
endfunction
function KB3D_AoEDamageLoop takes nothing returns boolean
local unit U = GetFilterUnit()
local integer Loop = R2I(udg_KB3D_Reals[0])
local unit Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
local attacktype AType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
local damagetype DType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
local real AoED = LoadReal(udg_KB3D_HA, 32, Loop)
local unit U1 = LoadUnitHandle(udg_KB3D_HA, 0, Loop)
if KB3D_Filter(U, U1, Loop) then
if not(LoadBoolean(udg_KB3D_HA, 44, Loop)) then
call UnitDamageTarget(Damager, U, AoED * 0.031250000, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
elseif KB3D_Approx(U, U1, Loop) then
call UnitDamageTarget(Damager, U, AoED * 0.031250000, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
endif
endif
set U = null
set U1 = null
set Damager = null
set AType = null
set DType = null
return false
endfunction
function KB3D_AoEEndDamage takes nothing returns boolean
local unit U = GetFilterUnit()
local integer Loop = R2I(udg_KB3D_Reals[0])
local unit Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
local attacktype AType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
local damagetype DType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
local real D = LoadReal(udg_KB3D_HA, 38, Loop)
local unit U1 = LoadUnitHandle(udg_KB3D_HA, 0, Loop)
if KB3D_Filter(U, U1, Loop) then
if not(LoadBoolean(udg_KB3D_HA, 44, Loop)) then
call UnitDamageTarget(Damager, U, D, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
elseif KB3D_Approx(U, U1, Loop) then
call UnitDamageTarget(Damager, U, D, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
endif
endif
set U = null
set U1 = null
set Damager = null
set AType = null
set DType = null
return false
endfunction
function KB3D_GiveKBto takes unit U1, unit U2, integer Loop returns nothing
set udg_KB3D_AoEEndDamage = LoadReal(udg_KB3D_HA, 38, Loop)
set udg_KB3D_EndwhenDead = LoadBoolean(udg_KB3D_HA, 35, Loop)
set udg_KB3D_Accel = -2000
set udg_KB3D_AllowOutSiding = LoadBoolean(udg_KB3D_HA, 34, Loop)
set udg_KB3D_Angle = (LoadReal(udg_KB3D_HA, 5, Loop)*180/3.14159)
set udg_KB3D_AoE = LoadReal(udg_KB3D_HA, 29, Loop)
set udg_KB3D_AoEDamage = LoadReal(udg_KB3D_HA, 32, Loop)
set udg_KB3D_AttackType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
set udg_KB3D_DamageType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
set udg_KB3D_Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
set udg_KB3D_DestroyTree = LoadBoolean(udg_KB3D_HA, 8, Loop)
set udg_KB3D_DisableUnit = LoadBoolean(udg_KB3D_HA, 6, Loop)
set udg_KB3D_FaceAngle = LoadBoolean(udg_KB3D_HA, 31, Loop)
set udg_KB3D_Fx = LoadStr(udg_KB3D_HA, 9, Loop)
set udg_KB3D_Fx_Attach = LoadStr(udg_KB3D_HA, 10, Loop)
set udg_KB3D_ImpactDamage = LoadReal(udg_KB3D_HA, 17, Loop)
set udg_KB3D_LineDamage = LoadReal(udg_KB3D_HA, 28, Loop)
set udg_KB3D_LoopDamage = LoadReal(udg_KB3D_HA, 18, Loop)/0.031250000
set udg_KB3D_Range = 99999
set udg_KB3D_Speed = LoadReal(udg_KB3D_HA, 2, Loop)/0.031250000
set udg_KB3D_Unit = U1
set udg_KB3D_Zoffset = LoadReal(udg_KB3D_HA, 3, Loop)-GetUnitDefaultFlyHeight(U2) / 1.85
call TriggerEvaluate( udg_KB3D_Registration )
endfunction
function KB3D_AoEGiveKBto takes unit U1, unit U2, integer Loop returns nothing
local real x1 = GetUnitX(U1)
local real y1 = GetUnitY(U1)
local real x2 = GetUnitX(U2)
local real y2 = GetUnitY(U2)
local real P = LoadReal(udg_KB3D_HA, 43, Loop)
set udg_KB3D_AoE = LoadReal(udg_KB3D_HA, 29, Loop)
set udg_KB3D_EndwhenDead = LoadBoolean(udg_KB3D_HA, 35, Loop)
set udg_KB3D_Accel = -550*P
set udg_KB3D_AllowOutSiding = LoadBoolean(udg_KB3D_HA, 34, Loop)
set udg_KB3D_Angle = Atan2(y1 - y2, x1 - x2)*180/3.14159
set udg_KB3D_AoEDamage = LoadReal(udg_KB3D_HA, 32, Loop)
set udg_KB3D_AttackType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
set udg_KB3D_DamageType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
set udg_KB3D_Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
set udg_KB3D_DestroyTree = LoadBoolean(udg_KB3D_HA, 8, Loop)
set udg_KB3D_DisableUnit = LoadBoolean(udg_KB3D_HA, 6, Loop)
set udg_KB3D_FaceAngle = LoadBoolean(udg_KB3D_HA, 31, Loop)
set udg_KB3D_Fx = LoadStr(udg_KB3D_HA, 9, Loop)
set udg_KB3D_Fx_Attach = LoadStr(udg_KB3D_HA, 10, Loop)
set udg_KB3D_ImpactDamage = LoadReal(udg_KB3D_HA, 17, Loop)
set udg_KB3D_LineDamage = LoadReal(udg_KB3D_HA, 28, Loop)
set udg_KB3D_LoopDamage = LoadReal(udg_KB3D_HA, 18, Loop)/0.031250000
set udg_KB3D_Range = 9999
set udg_KB3D_Speed = udg_KB3D_AoE*2*P
set udg_KB3D_Unit = U1
set udg_KB3D_Zoffset = 1.5*(udg_KB3D_AoE - SquareRoot(x2 * x1 + y2 * y1)*3.14159/180)*P
call TriggerEvaluate( udg_KB3D_Registration )
endfunction
function KB3D_AoEKB takes nothing returns boolean
local unit U = GetFilterUnit()
local integer Loop = R2I(udg_KB3D_Reals[0])
local unit U1 = LoadUnitHandle(udg_KB3D_HA, 0, Loop)
local real r
if KB3D_Filter(U, U1, Loop) then
if not(LoadBoolean(udg_KB3D_HA, 44, Loop)) then
call KB3D_AoEGiveKBto(U, U1, Loop)
elseif KB3D_Approx(U, U1, Loop) then
call KB3D_AoEGiveKBto(U, U1, Loop)
endif
endif
set U = null
set U1 = null
return false
endfunction
function KB3D_Loop takes integer Loop returns nothing//Main Trigger Loop
//Create all the nessesary locals
local unit U = LoadUnitHandle(udg_KB3D_HA, 0, Loop)
local real X = GetWidgetX(U)
local real Y = GetWidgetY(U)
local real Z = GetUnitFlyHeight(U)
local real x
local real y
local real z
local real Range = LoadReal(udg_KB3D_HA, 1, Loop)
local real Speed = LoadReal(udg_KB3D_HA, 2, Loop)
local real Zoffset = LoadReal(udg_KB3D_HA, 3, Loop)
local real Accel = LoadReal(udg_KB3D_HA, 4, Loop)
local real Angle
local real ZSpeed = LoadReal(udg_KB3D_HA, 12, Loop)
local real ZAccel = LoadReal(udg_KB3D_HA, 13, Loop)
local real ImpactD = LoadReal(udg_KB3D_HA, 17, Loop)
local real LoopD = LoadReal(udg_KB3D_HA, 18, Loop)
local real TargetD = LoadReal(udg_KB3D_HA, 19, Loop)
local real LineD = LoadReal(udg_KB3D_HA, 28, Loop)
local real AoE = LoadReal(udg_KB3D_HA, 29, Loop)
local real ZT = LoadReal(udg_KB3D_HA, 26, Loop)
local real AoED = LoadReal(udg_KB3D_HA, 32, Loop)
local real Time = LoadReal(udg_KB3D_HA, 41, Loop) + 0.031250000
local real KillatTime = LoadReal(udg_KB3D_HA, 36, Loop)
local real StopTime = LoadReal(udg_KB3D_HA, 37, Loop)
local real AoEEndDamage = LoadReal(udg_KB3D_HA, 38, Loop)
local unit Target = LoadUnitHandle(udg_KB3D_HA, 5, Loop)
local unit Damager = LoadUnitHandle(udg_KB3D_HA, 22, Loop)
local boolean DisableUnit = LoadBoolean(udg_KB3D_HA, 6, Loop)
local boolean UnpathableStop = LoadBoolean(udg_KB3D_HA, 7, Loop)
local boolean DestroyTree = LoadBoolean(udg_KB3D_HA, 8, Loop)
local boolean KillWhenHit = LoadBoolean(udg_KB3D_HA, 24, Loop)
local boolean EndWhenHit = LoadBoolean(udg_KB3D_HA, 25, Loop)
local boolean KiOS = LoadBoolean(udg_KB3D_HA, 33, Loop)
local boolean OS = LoadBoolean(udg_KB3D_HA, 34, Loop)
local boolean B = false
local boolean b = false
local boolean b1
local boolean EndwhenDead = LoadBoolean(udg_KB3D_HA, 35, Loop)
local boolean KBTarget = LoadBoolean(udg_KB3D_HA, 39, Loop)
local boolean AoEKB = LoadBoolean(udg_KB3D_HA, 40, Loop)
local boolean KillatEnd = LoadBoolean(udg_KB3D_HA, 46, Loop)
local boolean GroundDamage = LoadBoolean(udg_KB3D_HA, 47, Loop)
local string Fx = LoadStr(udg_KB3D_HA, 9, Loop)
local string Attach = LoadStr(udg_KB3D_HA, 10, Loop)
local string EndFx = LoadStr(udg_KB3D_HA, 42, Loop)
local attacktype AType = LoadAttackTypeHandle(udg_KB3D_HA, 20, Loop)
local damagetype DType = LoadDamageTypeHandle(udg_KB3D_HA, 21, Loop)
local group g
//end of locals
//Loop Damage Execution
if not (LoopD == 0) and not (Damager == null ) then
call UnitDamageTarget(Damager, U, LoopD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
endif
//Calculate the Angle
if ( Target == null ) then
set Angle = LoadReal(udg_KB3D_HA, 5, Loop) + LoadReal(udg_KB3D_HA, 30, Loop)//if there is no unit target
else
set Angle = Atan2(GetUnitY(Target) - Y, GetUnitX(Target) - X)//if there is a unit target
endif
//Make Unit Face Angle
if LoadBoolean(udg_KB3D_HA, 31, Loop) then
call SetUnitFacing(U, Angle * (180 / 3.14159))
endif
//Calculate 3D coordinates
set Speed = Speed + ( Accel )//Increase the KB speed depending on the Acceleration
set Range = Range - ( KB3D_AlwaysPos(Speed) )//Decrease distance traveled
set ZSpeed = ZSpeed + ( ZAccel )//change the fly changing rate //Acceleration is for smoothness
set x = X + ( Speed * Cos(Angle) )//new X location of the KBed unit
set y = Y + ( Speed * Sin(Angle) )//new Y location of the KBed unit
set z = Z + ( ZSpeed * 0.031250000 )//new Z Offset of the KBed unit
set ZT = ZT + ( ZSpeed * 0.031250000 )//Total Height Changings
//Move the unit according to the X, Y, Z
call MoveUnit_3D(U, x, y, z, Zoffset, UnpathableStop, OS, KiOS)
//Destroy Trees around the Unit depending on the unit's Collision Size
if (DestroyTree) then
set udg_KB3D_Reals[0] = I2R(Loop)
call KB3D_CircleTreeKill( KB3D_InBetween(100, 4 * KB3D_GetUnitCollision(U), 500), x, y )
endif
//Create the Effect on the unit
if not (Fx == "") then
if ( z > 20 ) then
if not (Attach == "") then
call DestroyEffect(AddSpecialEffectTarget(Fx, U, Attach))//attach the effect on the unit if he is flying
endif
else
call DestroyEffect(AddSpecialEffect(Fx, x, y))//create the effect on his location if he is not flying
endif
endif
//Initiate Impact Damage
if ( (UnpathableStop) and not ( KB3D_CW(x, y) ) ) and (not (ImpactD == 0) and not (Damager == null ) ) then//if the terrain is unpathable or if unpathable stop is disabled then..
if ( KB3D_CW(x, y) ) then
call SaveBoolean(udg_KB3D_HA, 23, Loop, true)
endif
if ( LoadBoolean(udg_KB3D_HA, 23, Loop) ) then
call UnitDamageTarget(Damager, U, ImpactD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)//Apply Impact Damage to the unit
call SaveBoolean(udg_KB3D_HA, 23, Loop, false)
endif
endif
//Initiate Line Damage
if not(LineD == 0) and not(Damager == null) and not(AoE == 0) then
set g = CreateGroup()
set udg_KB3D_Reals[0] = I2R(Loop)
call GroupEnumUnitsInRange(udg_KB3D_Group, x, y, KB3D_AlwaysPos(AoE), Filter(function KB3D_LineDamageLoop))
call DestroyGroup(g)
set g = null
endif
//Initiate AoE Damage
if not(AoED == 0) and not(Damager == null) and not(AoE == 0) then
set g = CreateGroup()
set udg_KB3D_Reals[0] = I2R(Loop)
call GroupEnumUnitsInRange(udg_KB3D_Group, x, y, KB3D_AlwaysPos(AoE), Filter(function KB3D_AoEDamageLoop))
call DestroyGroup(g)
set g = null
endif
//Disable the unit partially
if ( DisableUnit ) then
call SetUnitPropWindow(U, 0)
call SetUnitTurnSpeed(U, 0)
endif
//Initiate Target-Related Actions
if not(Target == null) then
if (SquareRoot ( ( GetWidgetX(Target) - x ) * ( GetWidgetX(Target) - x ) + ( GetWidgetY(Target) - y ) * ( GetWidgetY(Target) - y ) ) < Speed) then//when the target and the unit are close
if not (TargetD == 0) and not(Damager == null) then//Damage the Target
call UnitDamageTarget(Damager, Target, TargetD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
call SaveReal(udg_KB3D_HA, 19, Loop, 0)
endif
if KBTarget then//KB the Target
call KB3D_GiveKBto(Target, U, Loop)
call SaveBoolean( udg_KB3D_HA, 39, udg_KB3D_Counter, false )
endif
if (KillWhenHit) then//Kill the Unit
call KillUnit(U)
endif
if (EndWhenHit) then//End the KB
call SaveReal(udg_KB3D_HA, 4, Loop, KB3D_AlwaysNeg(Speed))
call SaveReal(udg_KB3D_HA, 3, Loop, GetUnitFlyHeight(U) - ZT)
endif
endif
endif
//Kill the Unit at the time
if not(KillatTime == 0) and ( Time > KillatTime ) then
call KillUnit(U)
endif
//Save Changes in the Hashtable
call SaveReal(udg_KB3D_HA, 1, Loop, Range)
call SaveReal(udg_KB3D_HA, 2, Loop, Speed)
call SaveReal(udg_KB3D_HA, 5, Loop, Angle)
call SaveReal(udg_KB3D_HA, 12, Loop, ZSpeed)
call SaveReal(udg_KB3D_HA, 26, Loop, ZT)
call SaveReal(udg_KB3D_HA, 41, Loop, Time)
//set B to if Stop time is exceeded
set B = ( not(StopTime == 0) and ( Time > StopTime ) )
//iKB interference
set b1 = LoadBoolean(udg_KB3D_HA, 45, Loop) and (Speed <= 0)
//Inititate End of the KB
if ( b1 or ( Range <= 0 ) or ( B ) ) then
call SaveBoolean(udg_KB3D_HA, 100, Loop, false)
set udg_KB3D_Instances = udg_KB3D_Instances - 1
if IsUnitType(U, UNIT_TYPE_DEAD) then
call SetUnitFlyHeight(U, GetUnitDefaultFlyHeight(U), 750 )
endif
call SetUnitPropWindow(U, LoadReal(udg_KB3D_HA, 15, Loop)*3.14159/180)
call SetUnitTurnSpeed(U, GetUnitDefaultTurnSpeed(U))
if HaveSavedHandle(udg_KB3D_HA, 14, Loop) then
call DestroyEffect(LoadEffectHandle(udg_KB3D_HA, 14, Loop))
endif
set b = true
elseif IsUnitType(U, UNIT_TYPE_DEAD) and (EndwhenDead) then
call SaveBoolean(udg_KB3D_HA, 100, Loop, false)
set udg_KB3D_Instances = udg_KB3D_Instances - 1
if IsUnitType(U, UNIT_TYPE_DEAD) then
call SetUnitFlyHeight(U, GetUnitDefaultFlyHeight(U), 750 )
endif
call SetUnitPropWindow(U, LoadReal(udg_KB3D_HA, 15, Loop)*3.14159/180)
call SetUnitTurnSpeed(U, GetUnitDefaultTurnSpeed(U))
if HaveSavedHandle(udg_KB3D_HA, 14, Loop) then
call DestroyEffect(LoadEffectHandle(udg_KB3D_HA, 14, Loop))
endif
set b = true
endif
//variable b refers to if the KB has ended
//AoE damage at the end of the KB
if (b) and not(AoEEndDamage == 0) and not(Damager == null) and not(AoE == 0) then
set g = CreateGroup()
set udg_KB3D_Reals[0] = I2R(Loop)
call GroupEnumUnitsInRange(udg_KB3D_Group, x, y, KB3D_AlwaysPos(AoE), Filter(function KB3D_AoEEndDamage))
call DestroyGroup(g)
set g = null
endif
//AoE Knock-back at the end of the KB
if (b) and (AoEKB) and not(AoE == 0) then
set g = CreateGroup()
set udg_KB3D_Reals[0] = I2R(Loop)
call GroupEnumUnitsInRange(udg_KB3D_Group, x, y, KB3D_AlwaysPos(AoE), Filter(function KB3D_AoEKB))
call DestroyGroup(g)
set g = null
endif
//Create End Effect
if b and not(EndFx == "") then
if ( z > 20 ) and not (Attach == "") then
call DestroyEffect(AddSpecialEffectTarget(EndFx, U, Attach))//attach the effect on the unit if he is flying
else
call DestroyEffect(AddSpecialEffect(EndFx, x, y))//create the effect on his location if he is not flying
endif
endif
//Ground Damage
if b and GroundDamage and not(ImpactD == 0) and z < 75 and not(Damager == null) then
call UnitDamageTarget(Damager, U, ImpactD, true, false, AType, DType, WEAPON_TYPE_WHOKNOWS)
endif
//Kill at End
if b and (KillatEnd) then
call KillUnit(U)
endif
//Clear Instance
if b then
call KB3D_ClearInstance(Loop)
endif
//Clear locals
set U = null
set Target = null
set Damager = null
endfunction
function KB3D_Loop_Actions takes nothing returns nothing//loop triggerer
local integer x = 0
loop
exitwhen x >= udg_KB3D_Counter
set x = x + 1
if ( LoadBoolean(udg_KB3D_HA, 100, x) ) then
call KB3D_Loop(x)
endif
endloop
if ( udg_KB3D_Instances == 0 ) then
set udg_KB3D_Counter = 0
call PauseTimer(udg_KB3D_Timer)
endif
endfunction
function KB3D_Registration takes nothing returns boolean//register an instance in the System
local real Time
local real R
local real R1
set udg_KB3D_Arc = KB3D_InBetween(-10, udg_KB3D_Arc, 10)
set udg_KB3D_AoEKB_Power = KB3D_InBetween(0.01, udg_KB3D_AoEKB_Power, 3)
if IsUnitType(udg_KB3D_Unit, UNIT_TYPE_FLYING) then
set udg_KB3D_UnpathableStop = false
endif
if (udg_KB3D_iKB) and udg_KB3D_Range < 0 then
if ( udg_KB3D_Targeted_Unit == null ) then
set udg_KB3D_Angle = udg_KB3D_Angle + 180
else
set udg_KB3D_Speed = -1*(udg_KB3D_Speed)
endif
endif
set udg_KB3D_Range = KB3D_InBetween(0.0000001, KB3D_AlwaysPos(udg_KB3D_Range), KB3D_AlwaysPos(udg_KB3D_Range))
if (udg_KB3D_iKB) and udg_KB3D_Speed < 0 then
set udg_KB3D_Speed = KB3D_InBetween(udg_KB3D_Speed, udg_KB3D_Speed, -0.01)
else
set udg_KB3D_Speed = KB3D_InBetween(0.01, KB3D_AlwaysPos(udg_KB3D_Speed), KB3D_AlwaysPos(udg_KB3D_Speed))
endif
set udg_KB3D_Counter = udg_KB3D_Counter + 1
set udg_KB3D_Instances = udg_KB3D_Instances + 1
set udg_KB3D_Zoffset = (1.85 * KB3D_AlwaysPos(udg_KB3D_Zoffset)) + GetUnitDefaultFlyHeight(udg_KB3D_Unit)
set udg_KB3D_StopTime = KB3D_AlwaysPos(udg_KB3D_StopTime)
set udg_KB3D_KillatTime = KB3D_AlwaysPos(udg_KB3D_KillatTime)
set udg_KB3D_AoE = KB3D_AlwaysPos(udg_KB3D_AoE)
call SaveUnitHandle( udg_KB3D_HA, 0, udg_KB3D_Counter, udg_KB3D_Unit )
call SaveReal( udg_KB3D_HA, 1, udg_KB3D_Counter, udg_KB3D_Range )
call SaveReal( udg_KB3D_HA, 2, udg_KB3D_Counter, udg_KB3D_Speed * 0.031250000 )
call SaveReal( udg_KB3D_HA, 4, udg_KB3D_Counter, udg_KB3D_Accel * 0.031250000 * 0.031250000 )
if ( udg_KB3D_Targeted_Unit == null ) then
call SaveReal( udg_KB3D_HA, 5, udg_KB3D_Counter, udg_KB3D_Angle * 3.14159 / 180 )
else
call SaveUnitHandle( udg_KB3D_HA, 5, udg_KB3D_Counter, udg_KB3D_Targeted_Unit )
endif
call SaveBoolean( udg_KB3D_HA, 6, udg_KB3D_Counter, udg_KB3D_DisableUnit )
call SaveBoolean( udg_KB3D_HA, 7, udg_KB3D_Counter, udg_KB3D_UnpathableStop )
call SaveBoolean( udg_KB3D_HA, 8, udg_KB3D_Counter, udg_KB3D_DestroyTree )
call SaveStr( udg_KB3D_HA, 9, udg_KB3D_Counter, udg_KB3D_Fx )
call SaveStr( udg_KB3D_HA, 10, udg_KB3D_Counter, udg_KB3D_Fx_Attach )
set udg_KB3D_Speed = KB3D_InBetween(0.01, KB3D_AlwaysPos(udg_KB3D_Speed), KB3D_AlwaysPos(udg_KB3D_Speed))
if ( udg_KB3D_Accel == 0.00 ) then
set Time = udg_KB3D_Range / (udg_KB3D_Speed)//calculating time for the knockback if Acceleration = 0
else
if ( udg_KB3D_Accel > 0 ) then
set Time = (( -2*(udg_KB3D_Speed) + SquareRoot((4*udg_KB3D_Speed) + (8*udg_KB3D_Accel*udg_KB3D_Range ) ) / (2*udg_KB3D_Accel) ))//calculating time for the knockback if Acceleration > 0
endif
if ( udg_KB3D_Accel < 0 ) then
set R = ( - 1 * (udg_KB3D_Speed) / udg_KB3D_Accel )
set R1 = (0.5 * udg_KB3D_Accel * R * R) + ((udg_KB3D_Speed) * R)
if R1 < udg_KB3D_Range then
set Time = R//calculating time for the knockback if Acceleration < 0 and if the speed will be = 0 before reaching max range
else
set Time = KB3D_AlwaysPos(( -2*(udg_KB3D_Speed) + SquareRoot(KB3D_AlwaysPos((4*(udg_KB3D_Speed)*(udg_KB3D_Speed)) + (8*udg_KB3D_Accel*udg_KB3D_Range) )) ) / (2*udg_KB3D_Accel) )//calculating time for the knockback if Acceleration < 0 and if the speed will be > 0 before reaching max range
endif
endif
endif
call SaveReal( udg_KB3D_HA, 11, udg_KB3D_Counter, Time )
call SaveBoolean( udg_KB3D_HA, 100, udg_KB3D_Counter, true )
if UnitAddAbility(udg_KB3D_Unit, 'Amrf') then
call UnitRemoveAbility(udg_KB3D_Unit, 'Amrf')
endif
call SaveReal( udg_KB3D_HA, 3, udg_KB3D_Counter, udg_KB3D_Zoffset )
call SaveReal( udg_KB3D_HA, 12, udg_KB3D_Counter, (udg_KB3D_Zoffset / ( Time / 2)) )
call SaveReal( udg_KB3D_HA, 13, udg_KB3D_Counter, ( -1 * udg_KB3D_Zoffset / ( Time / 2) ) / ( Time / 2) * 0.031250000 )
if not (udg_KB3D_TrailFx == "") and not (udg_KB3D_Fx_Attach == "") then
call SaveEffectHandle(udg_KB3D_HA, 14, udg_KB3D_Counter, AddSpecialEffectTarget(udg_KB3D_TrailFx, udg_KB3D_Unit, udg_KB3D_Fx_Attach))
endif
call SaveReal( udg_KB3D_HA, 15, udg_KB3D_Counter, GetUnitDefaultPropWindow(udg_KB3D_Unit) )
call SaveReal( udg_KB3D_HA, 17, udg_KB3D_Counter, udg_KB3D_ImpactDamage )
call SaveReal( udg_KB3D_HA, 18, udg_KB3D_Counter, udg_KB3D_LoopDamage * 0.031250000 )
call SaveReal( udg_KB3D_HA, 19, udg_KB3D_Counter, udg_KB3D_TargetDamage )
call SaveAttackTypeHandle( udg_KB3D_HA, 20, udg_KB3D_Counter, udg_KB3D_AttackType )
call SaveDamageTypeHandle( udg_KB3D_HA, 21, udg_KB3D_Counter, udg_KB3D_DamageType )
call SaveUnitHandle( udg_KB3D_HA, 22, udg_KB3D_Counter, udg_KB3D_Damager )
call SaveBoolean( udg_KB3D_HA, 23, udg_KB3D_Counter, true )
call SaveBoolean( udg_KB3D_HA, 24, udg_KB3D_Counter, udg_KB3D_KillWhenHit )
set udg_KB3D_EndWhenHit = udg_KB3D_KillWhenHit
call SaveBoolean( udg_KB3D_HA, 25, udg_KB3D_Counter, udg_KB3D_EndWhenHit )
call SaveGroupHandle(udg_KB3D_HA, 27, udg_KB3D_Counter, CreateGroup() )
call SaveReal( udg_KB3D_HA, 28, udg_KB3D_Counter, udg_KB3D_LineDamage )
call SaveReal( udg_KB3D_HA, 29, udg_KB3D_Counter, KB3D_AlwaysPos(udg_KB3D_AoE) )
call SaveReal( udg_KB3D_HA, 30, udg_KB3D_Counter, udg_KB3D_Arc * (3.14159/180) )
call SaveBoolean( udg_KB3D_HA, 31, udg_KB3D_Counter, udg_KB3D_FaceAngle )
call SaveReal( udg_KB3D_HA, 32, udg_KB3D_Counter, udg_KB3D_AoEDamage )
call SaveBoolean( udg_KB3D_HA, 33, udg_KB3D_Counter, udg_KB3D_KillifOutSider )
set udg_KB3D_AllowOutSiding = udg_KB3D_KillifOutSider
call SaveBoolean( udg_KB3D_HA, 34, udg_KB3D_Counter, udg_KB3D_AllowOutSiding )
set udg_KB3D_EndwhenDead = udg_KB3D_KillatTime > udg_KB3D_StopTime
call SaveBoolean( udg_KB3D_HA, 35, udg_KB3D_Counter, udg_KB3D_EndwhenDead )
call SaveReal( udg_KB3D_HA, 36, udg_KB3D_Counter, udg_KB3D_KillatTime )
call SaveReal( udg_KB3D_HA, 37, udg_KB3D_Counter, udg_KB3D_StopTime )
call SaveReal( udg_KB3D_HA, 38, udg_KB3D_Counter, udg_KB3D_AoEEndDamage )
call SaveBoolean( udg_KB3D_HA, 39, udg_KB3D_Counter, udg_KB3D_KBTarget )
call SaveBoolean( udg_KB3D_HA, 40, udg_KB3D_Counter, udg_KB3D_AoEKB )
//41 used
call SaveStr(udg_KB3D_HA, 42, udg_KB3D_Counter, udg_KB3D_EndFx )
call SaveReal( udg_KB3D_HA, 43, udg_KB3D_Counter, udg_KB3D_AoEKB_Power )
call SaveBoolean( udg_KB3D_HA, 44, udg_KB3D_Counter, udg_KB3D_iKB )
call SaveBoolean( udg_KB3D_HA, 45, udg_KB3D_Counter, udg_KB3D_Speed>0 )
call SaveBoolean( udg_KB3D_HA, 46, udg_KB3D_Counter, udg_KB3D_KillatEnd )
call SaveBoolean( udg_KB3D_HA, 47, udg_KB3D_Counter, udg_KB3D_GroundDamage )
call SaveBoolean( udg_KB3D_HA, 48, udg_KB3D_Counter, udg_KB3D_D_STRUCTURE )
call SaveBoolean( udg_KB3D_HA, 49, udg_KB3D_Counter, udg_KB3D_D_MECHANICAL )
call SaveBoolean( udg_KB3D_HA, 50, udg_KB3D_Counter, udg_KB3D_D_MAGIC_IMMINUE )
call SaveBoolean( udg_KB3D_HA, 51, udg_KB3D_Counter, udg_KB3D_D_ALLY )
//Nulling
set udg_KB3D_D_STRUCTURE = false
set udg_KB3D_D_MECHANICAL = false
set udg_KB3D_D_ALLY = false
set udg_KB3D_D_MAGIC_IMMINUE = false
set udg_KB3D_Accel = 0.00
set udg_KB3D_AllowOutSiding = false
set udg_KB3D_Angle = 0.00
set udg_KB3D_AoE = 0.00
set udg_KB3D_Arc = 0.00
set udg_KB3D_AoEDamage = 0.00
set udg_KB3D_AttackType = ATTACK_TYPE_NORMAL
set udg_KB3D_DamageType = DAMAGE_TYPE_MAGIC
set udg_KB3D_Damager = null
set udg_KB3D_DestroyTree = false
set udg_KB3D_DisableUnit = false
set udg_KB3D_EndWhenHit = false
set udg_KB3D_Fx = ""
set udg_KB3D_EndFx = ""
set udg_KB3D_Fx_Attach = ""
set udg_KB3D_ImpactDamage = 0.00
set udg_KB3D_KillWhenHit = false
set udg_KB3D_FaceAngle = false
set udg_KB3D_KillifOutSider = false
set udg_KB3D_LineDamage = 0.00
set udg_KB3D_LoopDamage = 0.00
set udg_KB3D_Range = 0.00
set udg_KB3D_Speed = 0.00
set udg_KB3D_TargetDamage = 0.00
set udg_KB3D_Targeted_Unit = null
set udg_KB3D_TrailFx = ""
set udg_KB3D_Unit = null
set udg_KB3D_UnpathableStop = true
set udg_KB3D_Zoffset = 0.00
set udg_KB3D_AoEEndDamage = 0.00
set udg_KB3D_AoEKB = false
set udg_KB3D_EndwhenDead = true
set udg_KB3D_KBTarget = false
set udg_KB3D_StopTime = 0.00
set udg_KB3D_KillatTime = 0.00
set udg_KB3D_AoEKB_Power = 1.00
set udg_KB3D_iKB = true
set udg_KB3D_KillatEnd = false
set udg_KB3D_GroundDamage = false
if ( udg_KB3D_Counter == 1 ) then
call TimerStart(udg_KB3D_Timer, 0.031250000, true, function KB3D_Loop_Actions )
endif
set udg_KB3D_Time = Time
return false
endfunction
//===========================================================================
function InitTrig_KB3D takes nothing returns nothing
////////REGISTRATION
set udg_KB3D_Registration = CreateTrigger( )
call TriggerAddCondition( udg_KB3D_Registration, Condition(function KB3D_Registration) )
set udg_KB3D_Harvester = CreateUnit(Player(15), 'hpea', 0, 0, 0)
call ShowUnit(udg_KB3D_Harvester, false)
call UnitAddAbility(udg_KB3D_Harvester, 'Aloc')
set udg_KB3D_HA = InitHashtable()
////////Check Walkability System by PnF
set udg_CP_Rect = Rect(0, 0, 128.00, 128.00)
set udg_CP_Item = CreateItem('wtlg', 0, 0)
call SetItemVisible( udg_CP_Item, false )
////////InitReals
set udg_KB3D_Reals[1] = GetRectMaxX(bj_mapInitialPlayableArea)
set udg_KB3D_Reals[2] = GetRectMinX(bj_mapInitialPlayableArea)
set udg_KB3D_Reals[3] = GetRectMaxY(bj_mapInitialPlayableArea)
set udg_KB3D_Reals[4] = GetRectMinY(bj_mapInitialPlayableArea)
set udg_KB3D_Reals[5] = GetRectMaxX(GetWorldBounds())
set udg_KB3D_Reals[6] = GetRectMinX(GetWorldBounds())
set udg_KB3D_Reals[7] = GetRectMaxY(GetWorldBounds())
set udg_KB3D_Reals[8] = GetRectMinY(GetWorldBounds())
//Initiate Default Values
set udg_KB3D_Accel = 0.00
set udg_KB3D_AllowOutSiding = false
set udg_KB3D_Angle = 0.00
set udg_KB3D_AoE = 0.00
set udg_KB3D_Arc = 0.00
set udg_KB3D_AoEDamage = 0.00
set udg_KB3D_AttackType = ATTACK_TYPE_NORMAL
set udg_KB3D_DamageType = DAMAGE_TYPE_MAGIC
set udg_KB3D_Damager = null
set udg_KB3D_DestroyTree = false
set udg_KB3D_DisableUnit = false
set udg_KB3D_EndWhenHit = false
set udg_KB3D_Fx = ""
set udg_KB3D_EndFx = ""
set udg_KB3D_Fx_Attach = ""
set udg_KB3D_ImpactDamage = 0.00
set udg_KB3D_KillWhenHit = false
set udg_KB3D_FaceAngle = false
set udg_KB3D_KillifOutSider = false
set udg_KB3D_LineDamage = 0.00
set udg_KB3D_LoopDamage = 0.00
set udg_KB3D_Range = 0.00
set udg_KB3D_Speed = 0.00
set udg_KB3D_TargetDamage = 0.00
set udg_KB3D_Targeted_Unit = null
set udg_KB3D_TrailFx = ""
set udg_KB3D_Unit = null
set udg_KB3D_UnpathableStop = true
set udg_KB3D_iKB = true
set udg_KB3D_iKB = true
set udg_KB3D_Zoffset = 0.00
set udg_KB3D_AoEEndDamage = 0.00
set udg_KB3D_AoEKB = false
set udg_KB3D_EndwhenDead = true
set udg_KB3D_KBTarget = false
set udg_KB3D_StopTime = 0.00
set udg_KB3D_KillatTime = 0.00
set udg_KB3D_KillatEnd = false
set udg_KB3D_AoEKB_Power = 1.00
set udg_KB3D_GroundDamage = false
set udg_KB3D_D_ALLY = false
set udg_KB3D_D_STRUCTURE = false
set udg_KB3D_D_MECHANICAL = false
set udg_KB3D_D_MAGIC_IMMINUE = false
endfunction
//TESH.scrollpos=183
//TESH.alwaysfold=0
scope DistantFieldA
//native UnitAlive takes unit id returns boolean
globals
private constant real FPS = 0.0312500
private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
private constant integer SPELL_ID = 'A02V'
private constant string LIGHTNING_ID = "DRAM"
private constant real LIGHTNING_RED = 0.15
private constant real LIGHTNING_GREEN = 0.45
private constant real LIGHTNING_BLUE = 1.
private constant real LIGHTNING_ALPHA = 1.
private constant real DURATION = 1.25
private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
endglobals
private constant function MaxDamage takes integer level returns real
return 150.*level
endfunction
private constant function MinDamage takes integer level returns real
return 75.*level
endfunction
private constant function Aoe takes integer level returns real
return 400 + 50.*level
endfunction
private function UnitFilter takes player source, unit targ returns boolean
return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//! textmacro_once STATIC_FIELD_ALLOC
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
//! endtextmacro
private struct Caster extends array
real x
real y
real temp
thistype prev
thistype next
static integer count
static timer period
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.temp = this.temp - FPS
if this.temp <= 0 then
call DestroyEffect(AddSpecialEffect(MODEL_PATH, this.x, this.y))
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method add takes real x, real y returns nothing
local thistype this
//! runtextmacro STATIC_FIELD_ALLOC()
set this.x = x
set this.y = y
set this.temp = DURATION
endmethod
static method onInit takes nothing returns nothing
set count = 0
set period = CreateTimer()
endmethod
endstruct
private struct SF extends array
unit targ
unit cast
lightning light
real dmg
real cx
real cy
real cz
real tx
real ty
real x
real y
real z
integer steps
thistype prev
thistype next
static integer count
static timer period
static group g
static location loc
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
call DestroyLightning(this.light)
call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
set this.light = null
set this.cast = null
set this.targ = null
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.tx = this.tx+this.x
set this.ty = this.ty+this.y
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
if IsTerrainWalkable(this.tx, this.ty) then
call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetUnitX(this.targ, this.tx)
call SetUnitY(this.targ, this.ty)
endif
set this.steps = this.steps - 1
if this.steps == 0 then
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method cond takes nothing returns boolean
local thistype this
local integer lvl
local real angle
local unit u
local unit v
local real x
local real y
local player p
local real dist
if GetSpellAbilityId() == SPELL_ID then
set u = GetTriggerUnit()
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set p = GetOwningPlayer(u)
set lvl = GetUnitAbilityLevel(u, SPELL_ID)
call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
loop
set v = FirstOfGroup(g)
exitwhen v == null
call GroupRemoveUnit(g,v)
if UnitFilter(p,v) then
//! runtextmacro STATIC_FIELD_ALLOC()
set this.cast = u
set this.targ = v
set this.cx = x
set this.cy = y
set this.tx = GetUnitX(v)
set this.ty = GetUnitY(v)
set angle = Atan2(this.ty-y, this.tx-x)
set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
set this.dmg = MinDamage(lvl) + (dist/Aoe(lvl))*(MaxDamage(lvl)-MinDamage(lvl))
set this.x = -(dist/DURATION)*FPS*Cos(angle)
set this.y = -(dist/DURATION)*FPS*Sin(angle)
call MoveLocation(loc, x, y)
set this.cz = GetLocationZ(loc) + 20
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
set this.steps = R2I(DURATION/FPS)
call SetUnitPropWindow(this.targ, 0)
endif
endloop
call Caster.add(x,y)
set u = null
set p = null
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
call Preload(MODEL_PATH)
set count = 0
set period = CreateTimer()
set g = CreateGroup()
set loc = Location(0,0)
set t = null
endmethod
endstruct
endscope
//TESH.scrollpos=139
//TESH.alwaysfold=0
scope DistantFieldE
//native UnitAlive takes unit id returns boolean
globals
private constant real FPS = 0.0312500
private constant string MODEL_PATH = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
private constant integer SPELL_ID = 'A02W'
private constant string LIGHTNING_ID = "DRAL"
private constant real LIGHTNING_RED = 0.45
private constant real LIGHTNING_GREEN = 1.
private constant real LIGHTNING_BLUE = 0.15
private constant real LIGHTNING_ALPHA = 1.5
private constant real DURATION = 1.0
private constant attacktype A_TYPE = ATTACK_TYPE_MAGIC
private constant damagetype D_TYPE = DAMAGE_TYPE_MAGIC
private constant real SPEED = 400.
endglobals
private constant function MaxDamage takes integer level returns real
return 500.*level
endfunction
private constant function MinDamage takes integer level returns real
return 300.*level
endfunction
private constant function Aoe takes integer level returns real
return 400 + 50.*level
endfunction
private function UnitFilter takes player source, unit targ returns boolean
return IsUnitEnemy(targ, source) and UnitAlive(targ) and not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
//! textmacro_once STATIC_FIELD_ALLOC
if thistype(0).prev == 0 then
set count = count + 1
set this = count
else
set this = thistype(0).prev
set thistype(0).prev = thistype(0).prev.prev
endif
if thistype(0).next == 0 then
call TimerStart(period, FPS, true, function thistype.periodic)
else
set thistype(0).next.prev = this
endif
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
//! endtextmacro
private struct SF extends array
unit targ
unit cast
lightning light
real dmg
real cx
real cy
real cz
real tx
real ty
real x
real y
real z
integer steps
thistype prev
thistype next
static integer count
static timer period
static group g
static location loc
method destroy takes nothing returns nothing
if this.next != 0 then
set this.next.prev = this.prev
endif
set this.prev.next = this.next
set this.prev = thistype(0).prev
set thistype(0).prev = this
if thistype(0).next == 0 then
call PauseTimer(period)
endif
call UnitDamageTarget(this.cast, this.targ, this.dmg, true, false, A_TYPE, D_TYPE, null)
call DestroyLightning(this.light)
call SetUnitPropWindow(this.targ, GetUnitDefaultPropWindow(this.targ)*bj_DEGTORAD)
set this.light = null
set this.cast = null
set this.targ = null
endmethod
static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
loop
exitwhen this == 0
set this.tx = this.tx+this.x
set this.ty = this.ty+this.y
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(this.targ)
if IsTerrainWalkable(this.tx, this.ty) then
call MoveLightningEx(this.light, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetUnitX(this.targ, this.tx)
call SetUnitY(this.targ, this.ty)
endif
set this.steps = this.steps - 1
if this.steps == 0 then
call this.destroy()
endif
set this = this.next
endloop
endmethod
static method cond takes nothing returns boolean
local thistype this
local integer lvl
local real angle
local unit u
local unit v
local real x
local real y
local player p
local real dist
if GetSpellAbilityId() == SPELL_ID then
set u = GetTriggerUnit()
set x = GetSpellTargetX()
set y = GetSpellTargetY()
set p = GetOwningPlayer(u)
set lvl = GetUnitAbilityLevel(u, SPELL_ID)
call GroupEnumUnitsInRange(g, x, y, Aoe(lvl), null)
call DestroyEffect(AddSpecialEffect(MODEL_PATH, x, y))
loop
set v = FirstOfGroup(g)
exitwhen v == null
call GroupRemoveUnit(g,v)
if UnitFilter(p,v) then
//! runtextmacro STATIC_FIELD_ALLOC()
set this.cast = u
set this.targ = v
set this.cx = x
set this.cy = y
set this.tx = GetUnitX(v)
set this.ty = GetUnitY(v)
set angle = Atan2(this.ty-y, this.tx-x)
set dist = SquareRoot((this.tx-x)*(this.tx-x) + (this.ty-y)*(this.ty-y))
set this.dmg = MinDamage(lvl) + (1-(dist/Aoe(lvl)))*(MaxDamage(lvl)-MinDamage(lvl))
set this.x = SPEED*FPS*Cos(angle)
set this.y = SPEED*FPS*Sin(angle)
call MoveLocation(loc, x, y)
set this.cz = GetLocationZ(loc) + 20
call MoveLocation(loc, this.tx, this.ty)
set this.z = GetLocationZ(loc) + 20 + GetUnitFlyHeight(v)
set this.light = AddLightningEx(LIGHTNING_ID, true, this.cx, this.cy, this.cz, this.tx, this.ty, this.z)
call SetLightningColor(this.light, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, LIGHTNING_ALPHA)
set this.steps = R2I(DURATION/FPS)
call SetUnitPropWindow(this.targ, 0)
endif
endloop
set u = null
set p = null
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.cond))
call Preload(MODEL_PATH)
set count = 0
set period = CreateTimer()
set g = CreateGroup()
set loc = Location(0,0)
set t = null
endmethod
endstruct
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//* > function IsTerrainDeepWater takes real x, real y returns boolean
//* > function IsTerrainShallowWater takes real x, real y returns boolean
//* > function IsTerrainLand takes real x, real y returns boolean
//* > function IsTerrainPlatform takes real x, real y returns boolean
//* > function IsTerrainWalkable takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//* [real] TerrainPathability_X
//* [real] TerrainPathability_Y
//*
globals
private constant real MAX_RANGE = 10.
private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals
globals
private item Item = null
private rect Find = null
private item array Hid
private integer HidMax = 0
public real X = 0.
public real Y = 0.
endglobals
function IsTerrainDeepWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
private function HideItem takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
set Hid[HidMax] = GetEnumItem()
call SetItemVisible(Hid[HidMax], false)
set HidMax = HidMax + 1
endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
//Hide any items in the area to avoid conflicts with our item
call MoveRectTo(Find, x, y)
call EnumItemsInRect(Find ,null, function HideItem)
//Try to move the test item and get its coords
call SetItemPosition(Item, x, y) //Unhides the item
set X = GetItemX(Item)
set Y = GetItemY(Item)
static if LIBRARY_IsTerrainWalkable then
//This is for compatibility with the IsTerrainWalkable library
set IsTerrainWalkable_X = X
set IsTerrainWalkable_Y = Y
endif
call SetItemVisible(Item, false)//Hide it again
//Unhide any items hidden at the start
loop
exitwhen HidMax <= 0
set HidMax = HidMax - 1
call SetItemVisible(Hid[HidMax], true)
set Hid[HidMax] = null
endloop
//Return walkability
return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
private function Init takes nothing returns nothing
set Find = Rect(0., 0., 128., 128.)
set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
call SetItemVisible(Item, false)
endfunction
endlibrary
//TESH.scrollpos=44
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Heights
globals
private location loc = Location( 0.00, 0.00 )
endglobals
function GetFloorHeight takes real x, real y returns real
call MoveLocation( loc, x, y )
return GetLocationZ( loc )
endfunction
function GetUnitZ takes unit whichUnit returns real
local real z = ( GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ) + GetUnitFlyHeight( whichUnit ) )
set whichUnit = null
return z
endfunction
function SetUnitZ takes unit whichUnit, real z returns nothing
local boolean whichUnitHasNotAmrf = ( GetUnitAbilityLevel( whichUnit, 'Amrf' ) <= 0 ) and IsUnitType(whichUnit, UNIT_TYPE_FLYING) == false
if ( whichUnitHasNotAmrf ) then
call UnitAddAbility( whichUnit, 'Amrf' )
endif
call SetUnitFlyHeight( whichUnit, z - GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ), 0.00 )
if ( whichUnitHasNotAmrf ) then
call UnitRemoveAbility( whichUnit, 'Amrf' )
endif
set whichUnit = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ShadowVortex initializer init
//*************************************************************************************************************//
// ShadowVortex v0.01 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// Heights by cedi //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Shadow
private keyword Main
private keyword Missile
globals
//ID of the spell
private constant integer SPELL_ID = 'A00M'
//ID of your dummy
private constant integer DUMMY_ID = 'h007'
//Amount of shadows created each time.
private constant integer SHADOW_COUNT = 8
//Amount of missiles created in the nova.
private constant integer MISSILE_COUNT = 24
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//Time between the nova and the absorbing
private constant real SHADOW_NOVA_INT = 0.30
//Speed of the shadows. In wc3 ms.
private constant real SPEED = 400.00
//Interval of picking
private constant real PICK_INT = 0.10
//Floating height of the shadows.
private constant real SHADOW_HEIGHT = 50.00
//Speed of the rotating in angle per second.
private constant real ANGLE_CHANGE = 120.00
//Start Height
private constant real START_Z = 500.00
//Start distance
private constant real SHADOW_DISTANCE = 350.00
//Min Dist
private constant real SHADOW_MIN_DIST = 5.00
//Interval of the shadow creation.
private constant real SHADOW_INTERVAL = 0.5
//On Damage sfx
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
//Model of the shadows.
private constant string SHADOW_MODEL = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
//SYSTEM
private Shadow SHADOW
private Main MAIN
private Missile MISSILE
private group GROUP = CreateGroup()
endglobals
private function DAMAGE takes integer level returns real
return 500.00 + 500.00 * level
endfunction
private function AOE takes integer level returns real
return 55.00 + 5.00 * level
endfunction
private function RANGE takes integer level returns real
return 500.00 + 100.00 * level
endfunction
private function NEEDED takes integer level returns integer
return 8 + 4 * level
endfunction
private function HIT_FUNC takes Missile m, unit target returns nothing
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction
private function MissileControl takes nothing returns nothing
set MISSILE = GetTimerData( GetExpiredTimer() )
call MISSILE.control()
endfunction
private function ShadowControl takes nothing returns nothing
set SHADOW = GetTimerData( GetExpiredTimer() )
call SHADOW.control()
endfunction
private function MainControl takes nothing returns nothing
set MAIN = GetTimerData( GetExpiredTimer() )
call MAIN.control()
endfunction
private struct Missile
unit caster = null
unit u = null
integer level = 1
real vx = 0.00
real vy = 0.00
real range = 0.00
real maxrange = 0.00
real x = 0.00
real y = 0.00
real interval = 0.00
effect model = null
timer t = null
group g = null
private method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( GROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( GROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call GroupAddUnit( .g, u )
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
endif
endif
call GroupRemoveUnit( GROUP, u )
set u = null
endloop
endmethod
method onDestroy takes nothing returns nothing
set .caster = null
call DestroyEffect( .model )
set .model = null
call KillUnit( .u )
set .u = null
call ReleaseTimer( .t )
set .t = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .u ) <= 0.405 then
call .destroy()
return
endif
set .range = .range - SPEED * TIMER_INTERVAL
if .range <= 0.00 then
call .destroy()
return
endif
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .u, .x )
call SetUnitY( .u, .y )
set .interval = .interval + TIMER_INTERVAL
if .interval >= PICK_INT then
set .interval = 0.00
call .pick()
endif
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
set angle = angle * bj_DEGTORAD
set .caster = m.caster
set .level = m.level
set .vx = Cos( angle ) * SPEED * TIMER_INTERVAL
set .vy = Sin( angle ) * SPEED * TIMER_INTERVAL
set .x = GetUnitX( .caster ) + .vx
set .y = GetUnitY( .caster ) + .vy
set .range = RANGE( .level )
set .maxrange = .range
set .u = CreateUnit( GetOwningPlayer( .caster ), DUMMY_ID, .x, .y, angle * bj_RADTODEG )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .t = NewTimer()
set .g = CreateGroup()
call SetUnitZ( .u, SHADOW_HEIGHT )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MissileControl )
return this
endmethod
endstruct
private struct Shadow
Main main = 0
unit caster = null
unit u = null
real distance = 0.00
real angle = 0.00
real z = 0.00
effect model = null
timer t = null
method control takes nothing returns nothing
local real x
local real y
local real z
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
return
endif
set .angle = .angle + ANGLE_CHANGE * TIMER_INTERVAL
set .distance = .distance - SPEED * TIMER_INTERVAL
if .distance <= 0.00 then
call .destroy()
return
endif
set x = GetUnitX( .caster ) + Cos( .angle * bj_DEGTORAD ) * .distance
set y = GetUnitY( .caster ) + Sin( .angle * bj_DEGTORAD ) * .distance
set z = ParabolaZ2( GetUnitZ( .caster ), .z, START_Z / 2.00, SHADOW_DISTANCE, .distance )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
call SetUnitZ( .u, z )
if IsUnitInRange( .u, .main.caster, SHADOW_MIN_DIST ) then
call .main.addCharge()
call .destroy()
endif
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect( .model )
set .model = null
call ReleaseTimer( .t )
set .t = null
call KillUnit( .u )
set .u = null
set .caster = null
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
local real x = GetUnitX( m.caster )
local real y = GetUnitY( m.caster )
set .main = m
set .distance = SHADOW_DISTANCE
set .angle = angle
set .t = NewTimer()
set x = x + Cos( angle * bj_DEGTORAD ) * .distance
set y = y + Sin( angle * bj_DEGTORAD ) * .distance
set .u = CreateUnit( GetOwningPlayer( m.caster ), DUMMY_ID, x, y, 0.00 )
call SetUnitZ( .u, START_Z )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .caster = m.caster
set .z = GetUnitZ( .u )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function ShadowControl )
return this
endmethod
endstruct
private struct Main
unit caster = null
integer level = 1
integer needed = 0
real interval = 0.00
timer t = null
boolean enough = false
method addCharge takes nothing returns nothing
set .needed = .needed - 1
if .needed <= 0 then
set .enough = true
set .interval = SHADOW_NOVA_INT
endif
endmethod
method newShadows takes nothing returns nothing
local integer i = 0
local real r = 360.00 / SHADOW_COUNT
loop
exitwhen i > SHADOW_COUNT
call Shadow.create( this, r * i )
set i = i + 1
endloop
endmethod
method nova takes nothing returns nothing
local integer i = 0
local real r = 360.00 / MISSILE_COUNT
loop
exitwhen i > MISSILE_COUNT
call Missile.create( this, r * i )
set i = i + 1
endloop
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
endif
set .interval = .interval - TIMER_INTERVAL
if not .enough then
if .interval <= 0.00 then
call .newShadows()
set .interval = SHADOW_INTERVAL
endif
else
if .interval <= 0.00 then
call .nova()
call .destroy()
endif
endif
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .needed = NEEDED( .level )
set .t = NewTimer()
set .interval = SHADOW_INTERVAL
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MainControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit() )
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function IsSpell ) )
set t = null
endfunction
endscope
function SpellIndexGetVars takes integer i returns nothing
set udg_Spell__Ability = udg_Spell_i_Abil[udg_Spell_i_Head[i]]
set udg_Spell__Index = i
set udg_Spell__Caster = udg_Spell_i_Caster[i]
set udg_Spell__CasterOwner = GetOwningPlayer(udg_Spell__Caster)
set udg_Spell__Level = udg_Spell_i_Level[i]
set udg_Spell__LevelMultiplier = udg_Spell__Level //Spell__LevelMultiplier is a real variable.
set udg_Spell__Target = udg_Spell_i_Target[i]
//Magic to ensure the locations never leak.
call MoveLocation(udg_Spell__CastPoint, GetUnitX(udg_Spell__Caster), GetUnitY(udg_Spell__Caster))
if udg_Spell__Target == null then
call MoveLocation(udg_Spell__TargetPoint, udg_Spell_i_TargetX[i], udg_Spell_i_TargetY[i])
else
call MoveLocation(udg_Spell__TargetPoint, GetUnitX(udg_Spell__Target), GetUnitY(udg_Spell__Target))
endif
set udg_Spell__TargetGroup = udg_Spell_i_TargetGroup[i]
set udg_Spell__Completed = udg_Spell_i_Completed[i]
set udg_Spell__Channeling = udg_Spell_i_Channeling[i]
endfunction
function SpellSetFilters takes integer i returns nothing
set udg_Spell_i_AllowEnemy[i] = udg_Spell__Filter_AllowEnemy
set udg_Spell_i_AllowAlly[i] = udg_Spell__Filter_AllowAlly
set udg_Spell_i_AllowDead[i] = udg_Spell__Filter_AllowDead
set udg_Spell_i_AllowLiving[i] = udg_Spell__Filter_AllowLiving
set udg_Spell_i_AllowMagicImmune[i] = udg_Spell__Filter_AllowMagicImmune
set udg_Spell_i_AllowMechanical[i] = udg_Spell__Filter_AllowMechanical
set udg_Spell_i_AllowStructure[i] = udg_Spell__Filter_AllowStructure
set udg_Spell_i_AllowFlying[i] = udg_Spell__Filter_AllowFlying
set udg_Spell_i_AllowHero[i] = udg_Spell__Filter_AllowHero
set udg_Spell_i_AllowNonHero[i] = udg_Spell__Filter_AllowNonHero
endfunction
function SpellIndexDestroy takes integer i returns nothing
local integer indexOf
local integer index
if udg_Spell_i_RecycleList[i] >= 0 then
return
endif
//If the caster is still channeling on the spell, don't destroy until it's finished:
if not udg_Spell_i_Channeling[i] then
set index = udg_Spell_i_Head[i]
set udg_Spell_i_RecycleList[i] = udg_Spell_i_Recycle
set udg_Spell_i_Recycle = i
//Reset things to defaults:
set udg_Spell_i_Time[i] = 0.00
set udg_Spell_i_LastTime[i] = 0.00
set udg_Spell_i_Duration[i] = 0.00
set udg_Spell_i_Completed[i] = false
set udg_Spell_i_Caster[i] = null
set udg_Spell_i_Target[i] = null
set udg_Spell_i_OnLoopStack[i] = null
//Recycle any applicable target unit group.
if udg_Spell_i_TargetGroup[i] != null then
call GroupClear(udg_Spell_i_TargetGroup[i])
set udg_Spell_i_GroupStack[udg_Spell_i_GroupN] = udg_Spell_i_TargetGroup[i]
set udg_Spell_i_GroupN = udg_Spell_i_GroupN + 1
set udg_Spell_i_TargetGroup[i] = null
endif
//Clear any user-specified data in the hashtable:
call FlushChildHashtable(udg_Spell__Hash, i)
//call BJDebugMsg("Destroying index: " + I2S(i))
endif
set indexOf = udg_Spell_i_StackRef[i]
if indexOf >= 0 then
set index = udg_Spell_i_StackN - 1
set udg_Spell_i_StackN = index
set udg_Spell_i_StackRef[udg_Spell_i_Stack[index]] = indexOf
set udg_Spell_i_Stack[indexOf] = udg_Spell_i_Stack[index]
if index == 0 then
//If no more spells require the timer, pause it.
call PauseTimer(udg_Spell_i_Timer)
endif
set udg_Spell_i_StackRef[i] = -1
endif
endfunction
function SpellTriggerExecute takes integer i, trigger t returns real
local real d = udg_Spell_i_Duration[i]
local boolean b = false
set udg_Spell__Duration = d
set udg_Spell__Time = 0.00
if t != null then
set udg_Spell__Trigger_OnLoop = null
set udg_Spell__Expired = d <= 0.00 //If the duration is <= 0, the spell has expired.
call SpellIndexGetVars(i)
if TriggerEvaluate(t) then
call TriggerExecute(t)
endif
if udg_Spell__Trigger_OnLoop != null then
set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
endif
//The remaining lines in this function process the duration specified by the user.
if udg_Spell__StartDuration then
set udg_Spell__StartDuration = false
set udg_Spell__Duration = udg_Spell_i_Duration[udg_Spell_i_Head[i]] + udg_Spell_i_LastTime[udg_Spell_i_Head[i]]*udg_Spell__LevelMultiplier
elseif (udg_Spell__Expired and d > 0.00) or (udg_Spell__Duration <= 0.00) then
set udg_Spell__Duration = 0.00
return udg_Spell__Time
//The user manually expired the spell or the spell duration ended on its own.
endif
if d != udg_Spell__Duration then
//A new duration has been assigned
set d = udg_Spell__Duration
set b = true
endif
set udg_Spell__Duration = 0.00
if udg_Spell__Time == 0.00 then
if udg_Spell_i_LastTime[i] == 0.00 then
if udg_Spell_i_Time[udg_Spell_i_Head[i]] > 0.00 then
//The user specified a default interval to follow:
set udg_Spell__Time = udg_Spell_i_Time[udg_Spell_i_Head[i]]
else
//Set the spell time to the minimum.
set udg_Spell__Time = udg_Spell__Interval
endif
else
//Otherwise, set it to what it was before.
set udg_Spell__Time = udg_Spell_i_LastTime[i]
endif
//else, the user is specifying a new time for the spell.
endif
set udg_Spell_i_LastTime[i] = udg_Spell__Time //Whatever the case, remember this time for next time.
if b then
//The duration was just assigned
set udg_Spell_i_Duration[i] = d
else
//The duration has been ongoing
set udg_Spell_i_Duration[i] = d - udg_Spell__Time
endif
endif
return udg_Spell__Time
endfunction
//===========================================================================
// Runs every Spell__Interval seconds and handles all of the timed events.
//
function SpellTimerLoop takes nothing returns nothing
local integer i = udg_Spell_i_StackN
local integer node
local real time
set udg_Spell__Running = true
//Run stack top to bottom to avoid skipping slots when destroying.
loop
set i = i - 1
exitwhen i < 0
set node = udg_Spell_i_Stack[i]
set time = udg_Spell_i_Time[node] - udg_Spell__Interval
if time <= 0.00 then
set time = SpellTriggerExecute(node, udg_Spell_i_OnLoopStack[node])
endif
if time <= 0.00 then
call SpellIndexDestroy(node)
else
set udg_Spell_i_Time[node] = time
endif
endloop
set udg_Spell__Running = false
endfunction
//===========================================================================
// This is the meat of the system as it handles the event responses.
//
function RunSpellEvent takes nothing returns boolean
local boolean b
local integer aid = GetSpellAbilityId()
local integer head = LoadInteger(udg_Spell__Hash, 0, aid)
local integer i
local integer id
local trigger t
local playerunitevent eid
if head == 0 then
//Nothing for this ability has been registered. Skip the sequence.
return false
endif
set eid = ConvertPlayerUnitEvent(GetHandleId(GetTriggerEventId()))
set udg_Spell__Caster = GetTriggerUnit()
set id = GetHandleId(udg_Spell__Caster)
set i = LoadInteger(udg_Spell__Hash, aid, id)
if i == 0 then
//This block will almost always happen with the OnChannel event. In the
//case of Charge Gold and Lumber, only an OnEffect event will run.
set i = udg_Spell_i_Recycle
if i == 0 then
//Create a new, unique index
set i = udg_Spell_i_Instances + 1
set udg_Spell_i_Instances = i
else
//Repurpose an existing one
set udg_Spell_i_Recycle = udg_Spell_i_RecycleList[i]
endif
//call BJDebugMsg("Creating index: " + I2S(i))
set udg_Spell_i_RecycleList[i] = -1
set udg_Spell_i_StackRef[i] = -1
set udg_Spell_i_Head[i] = head
if eid == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
set udg_Spell_i_Channeling[i] = true
call SaveInteger(udg_Spell__Hash, aid, id, i)
set t = udg_Spell_i_OnChannelStack[head]
else //eid == EVENT_PLAYER_UNIT_SPELL_EFFECT
set t = udg_Spell_i_OnEffectStack[head]
endif
set udg_Spell_i_Caster[i] = udg_Spell__Caster
set udg_Spell_i_Level[i] = GetUnitAbilityLevel(udg_Spell__Caster, aid)
set udg_Spell_i_Target[i] = GetSpellTargetUnit()
set udg_Spell_i_TargetX[i] = GetSpellTargetX()
set udg_Spell_i_TargetY[i] = GetSpellTargetY()
set udg_Spell_i_OnLoopStack[i] = udg_Spell_i_OnLoopStack[head]
if udg_Spell_i_UseTG[head] then
//Get a recycled unit group or create a new one.
set id = udg_Spell_i_GroupN - 1
if id >= 0 then
set udg_Spell_i_GroupN = id
set udg_Spell_i_TargetGroup[i] = udg_Spell_i_GroupStack[id]
else
set udg_Spell_i_TargetGroup[i] = CreateGroup()
endif
endif
elseif eid == EVENT_PLAYER_UNIT_SPELL_CAST then
set t = udg_Spell_i_OnCastStack[head]
elseif eid == EVENT_PLAYER_UNIT_SPELL_EFFECT then
set t = udg_Spell_i_OnEffectStack[head]
elseif eid == EVENT_PLAYER_UNIT_SPELL_FINISH then
set udg_Spell_i_Completed[i] = true
return true
else //eid == EVENT_PLAYER_UNIT_SPELL_ENDCAST
set udg_Spell_i_Channeling[i] = false
call RemoveSavedInteger(udg_Spell__Hash, aid, id)
set t = udg_Spell_i_OnFinishStack[head]
endif
if SpellTriggerExecute(i, t) > 0.00 then
//Set the spell time to the user-specified one.
set udg_Spell_i_Time[i] = udg_Spell__Time
if udg_Spell_i_StackRef[i] < 0 then
//Allocate the spell index onto the loop stack.
set aid = udg_Spell_i_StackN
set udg_Spell_i_Stack[aid] = i
set udg_Spell_i_StackRef[i] = aid
set udg_Spell_i_StackN = aid + 1
if aid == 0 then
//If this is the first spell index using the timer, start it up:
call TimerStart(udg_Spell_i_Timer, udg_Spell__Interval, true, function SpellTimerLoop)
endif
endif
elseif (not udg_Spell_i_Channeling[i]) and (t != null or udg_Spell_i_Time[i] <= 0.00) then
call SpellIndexDestroy(i)
endif
set t = null
return true
endfunction
//This function is invoked if an event was launched recursively by another event's callback.
function RunPreSpellEvent takes nothing returns nothing
local integer i = udg_Spell__Index
local real time = udg_Spell__Time
local real d = udg_Spell__Duration
local boolean expired = udg_Spell__Expired
if udg_Spell__Trigger_OnLoop != null then
set udg_Spell_i_OnLoopStack[i] = udg_Spell__Trigger_OnLoop
endif
if RunSpellEvent() then
set udg_Spell__Time = time
set udg_Spell__Duration = d
set udg_Spell__Expired = expired
call SpellIndexGetVars(i)
endif
endfunction
//===========================================================================
// Base function of the system: runs when an ability event does something.
//
function SpellSystemEvent takes nothing returns boolean
if udg_Spell__Running then
call RunPreSpellEvent()
else
set udg_Spell__Running = true
call RunSpellEvent()
set udg_Spell__Running = false
endif
return false
endfunction
//===========================================================================
// Set Spell__Ability to your spell's ability
// Set Spell__Trigger_OnChannel/Cast/Effect/Finish/Loop to any trigger(s) you
// want to automatically run.
//
// GUI-friendly: Run Spell System <gen> (ignoring conditions)
//
function SpellSystemRegister takes nothing returns nothing
local integer aid = udg_Spell__Ability
local integer head = udg_Spell_i_Instances + 1
if HaveSavedInteger(udg_Spell__Hash, 0, aid) or aid == 0 then
//The system rejects duplicate or unassigned abilities.
return
endif
set udg_Spell_i_Instances = head
set udg_Spell_i_Abil[head] = aid
//Preload the ability on dummy unit to help prevent first-instance lag
call UnitAddAbility(udg_Spell_i_PreloadDummy, aid)
//Save head index to the spell ability so it be referenced later.
call SaveInteger(udg_Spell__Hash, 0, aid, head)
//Set any applicable event triggers.
set udg_Spell_i_OnChannelStack[head]= udg_Spell__Trigger_OnChannel
set udg_Spell_i_OnCastStack[head] = udg_Spell__Trigger_OnCast
set udg_Spell_i_OnEffectStack[head] = udg_Spell__Trigger_OnEffect
set udg_Spell_i_OnFinishStack[head] = udg_Spell__Trigger_OnFinish
set udg_Spell_i_OnLoopStack[head] = udg_Spell__Trigger_OnLoop
set udg_Spell_i_InRangeFilter[head] = udg_Spell__Trigger_InRangeFilter
//Set any customized filter variables:
call SpellSetFilters(head)
//Tell the system to automatically create target groups, if needed
set udg_Spell_i_AutoAddTargets[head] = udg_Spell__AutoAddTargets
set udg_Spell_i_UseTG[head] = udg_Spell__UseTargetGroup or udg_Spell__AutoAddTargets
//Handle automatic buff assignment
set udg_Spell_i_BuffAbil[head] = udg_Spell__BuffAbility
set udg_Spell_i_BuffOrder[head] = udg_Spell__BuffOrder
//Set the default time sequences if a duration is used:
set udg_Spell_i_Time[head] = udg_Spell__Time
set udg_Spell_i_Duration[head] = udg_Spell__Duration
set udg_Spell_i_LastTime[head] = udg_Spell__DurationPerLevel
//Set variables back to their defaults:
set udg_Spell__Trigger_OnChannel = null
set udg_Spell__Trigger_OnCast = null
set udg_Spell__Trigger_OnEffect = null
set udg_Spell__Trigger_OnFinish = null
set udg_Spell__Trigger_OnLoop = null
set udg_Spell__Trigger_InRangeFilter= null
set udg_Spell__AutoAddTargets = false
set udg_Spell__UseTargetGroup = false
set udg_Spell__Time = 0.00
set udg_Spell__Duration = 0.00
set udg_Spell__DurationPerLevel = 0.00
set udg_Spell__BuffAbility = 0
set udg_Spell__BuffOrder = 0
set udg_Spell__Filter_AllowEnemy = udg_Spell_i_AllowEnemy[0]
set udg_Spell__Filter_AllowAlly = udg_Spell_i_AllowAlly[0]
set udg_Spell__Filter_AllowDead = udg_Spell_i_AllowDead[0]
set udg_Spell__Filter_AllowMagicImmune = udg_Spell_i_AllowMagicImmune[0]
set udg_Spell__Filter_AllowMechanical = udg_Spell_i_AllowMechanical[0]
set udg_Spell__Filter_AllowStructure = udg_Spell_i_AllowStructure[0]
set udg_Spell__Filter_AllowFlying = udg_Spell_i_AllowFlying[0]
set udg_Spell__Filter_AllowHero = udg_Spell_i_AllowHero[0]
set udg_Spell__Filter_AllowNonHero = udg_Spell_i_AllowNonHero[0]
set udg_Spell__Filter_AllowLiving = udg_Spell_i_AllowLiving[0]
endfunction
function SpellFilterCompare takes boolean is, boolean yes, boolean no returns boolean
return (is and yes) or ((not is) and no)
endfunction
//===========================================================================
// Before calling this function, set Spell__InRangePoint to whatever point
// you need, THEN set Spell__InRange to the radius you need. The system will
// enumerate the units matching the configured filter and fill them into
// Spell_InRangeGroup.
//
function SpellGroupUnitsInRange takes nothing returns boolean
local integer i = udg_Spell_i_Head[udg_Spell__Index]
local integer j = 0
local unit u
local real padding = 64.00
if udg_Spell_i_AllowStructure[i] then
//A normal unit can only have up to size 64.00 collision, but if the
//user needs to check for structures we need a padding big enough for
//the "fattest" ones: Tier 3 town halls.
set padding = 197.00
endif
call GroupEnumUnitsInRangeOfLoc(udg_Spell__InRangeGroup, udg_Spell__InRangePoint, udg_Spell__InRange + padding, null)
loop
set u = FirstOfGroup(udg_Spell__InRangeGroup)
exitwhen u == null
call GroupRemoveUnit(udg_Spell__InRangeGroup, u)
loop
exitwhen udg_Spell_i_AutoAddTargets[i] and IsUnitInGroup(u, udg_Spell__TargetGroup)
exitwhen not IsUnitInRangeLoc(u, udg_Spell__InRangePoint, udg_Spell__InRange)
exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_DEAD), udg_Spell_i_AllowDead[i], udg_Spell_i_AllowLiving[i])
exitwhen not SpellFilterCompare(IsUnitAlly(u, udg_Spell__CasterOwner), udg_Spell_i_AllowAlly[i], udg_Spell_i_AllowEnemy[i])
exitwhen not SpellFilterCompare(IsUnitType(u, UNIT_TYPE_HERO) or IsUnitType(u, UNIT_TYPE_RESISTANT), udg_Spell_i_AllowHero[i], udg_Spell_i_AllowNonHero[i])
exitwhen IsUnitType(u, UNIT_TYPE_STRUCTURE) and not udg_Spell_i_AllowStructure[i]
exitwhen IsUnitType(u, UNIT_TYPE_FLYING) and not udg_Spell_i_AllowFlying[i]
exitwhen IsUnitType(u, UNIT_TYPE_MECHANICAL) and not udg_Spell_i_AllowMechanical[i]
exitwhen IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) and not udg_Spell_i_AllowMagicImmune[i]
set udg_Spell__InRangeUnit = u
//Run the user's designated filter, if one exists.
exitwhen udg_Spell_i_InRangeFilter[i] != null and not TriggerEvaluate(udg_Spell_i_InRangeFilter[i])
set j = j + 1
set udg_Spell__InRangeUnits[j] = u
exitwhen true
endloop
endloop
if j > udg_Spell__InRangeMax and udg_Spell__InRangeMax > 0 then
//The user has defined a maximum number of units allowed in the group.
//Remove a random unit until the total does not exceed capacity.
loop
set i = GetRandomInt(1, j)
set udg_Spell__InRangeUnits[i] = udg_Spell__InRangeUnits[j]
set j = j - 1
exitwhen j == udg_Spell__InRangeMax
endloop
endif
set udg_Spell__InRangeCount = j
set udg_Spell__InRangeMax = 0
set udg_Spell__InRange = 0.00
set i = udg_Spell_i_Head[udg_Spell__Index]
loop
exitwhen j == 0
set u = udg_Spell__InRangeUnits[j]
call GroupAddUnit(udg_Spell__InRangeGroup, u)
if udg_Spell_i_AutoAddTargets[i] then
call GroupAddUnit(udg_Spell__TargetGroup, u)
endif
if udg_Spell__WakeTargets and UnitIsSleeping(u) then
call UnitWakeUp(u)
endif
if udg_Spell_i_BuffAbil[i] != 0 and udg_Spell_i_BuffOrder[i] != 0 then
//Auto-buff units added to group:
call UnitAddAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
call IssueTargetOrderById(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffOrder[i], u)
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_BuffAbil[i])
endif
set j = j - 1
endloop
set u = null
return false
endfunction
function SpellPreloadEnd takes nothing returns nothing
local integer i = udg_Spell_i_Instances
loop
exitwhen i == 0
//Remove preloaded abilities so they don't interfere with orders
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, udg_Spell_i_Abil[udg_Spell_i_Head[i]])
set i = i - 1
endloop
endfunction
//===========================================================================
function InitTrig_Spell_System takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS
local player p
local trigger t
if gg_trg_Spell_System != null then
//A JASS function call already initialized the system.
return
endif
//This runs before map init events so the hashtable is ready before then.
set udg_Spell__Hash = InitHashtable()
//Initialize these two locations which will never get removed
set udg_Spell__CastPoint = Location(0, 0)
set udg_Spell__TargetPoint = Location(0, 0)
//Recycle existing unit groups into the recycle stack to avoid needing to destroy any extras.
set udg_Spell_i_GroupStack[2] = udg_Spell__TargetGroup
set udg_Spell_i_GroupStack[3] = udg_Spell_i_TargetGroup[0]
set udg_Spell_i_GroupStack[4] = udg_Spell_i_TargetGroup[1]
set udg_Spell_i_GroupN = 5 //There are already five valid unit groups thanks to Variable Editor.
set t = CreateTrigger()
call TriggerRegisterVariableEvent(t, "udg_Spell__InRange", GREATER_THAN, 0.00)
call TriggerAddCondition(t, Filter(function SpellGroupUnitsInRange))
set t = CreateTrigger()
call TriggerAddCondition(t, Filter(function SpellSystemEvent))
loop
set i = i - 1
set p = Player(i)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_CAST, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_FINISH, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
exitwhen i == 0
endloop
set p = null
set t = null
//Run the configuration trigger so its variables are ready before the
//map initialization events run.
call TriggerExecute(gg_trg_Spell_System_Config)
call SpellSetFilters(0)
//Create this trigger so it's GUI-friendly.
set gg_trg_Spell_System = CreateTrigger()
call TriggerAddAction(gg_trg_Spell_System, function SpellSystemRegister)
set gg_trg_Spell_System_Config = gg_trg_Spell_System //In case the user accidentally picks this one
//Create a dummy unit for preloading abilities and casting buffs.
set udg_Spell_i_PreloadDummy = CreateUnit(udg_Spell__DummyOwner, udg_Spell__DummyType, 0, 0, 0)
//Start the timer to remove its abilities:
call TimerStart(udg_Spell_i_Timer, 0.00, false, function SpellPreloadEnd)
call UnitRemoveAbility(udg_Spell_i_PreloadDummy, 'Amov') //Force it to never move to cast spells
endfunction
//TESH.scrollpos=6
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=21
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'e000'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
//TESH.scrollpos=164
//TESH.alwaysfold=0
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.8
// --------
// For all your damage and targetting needs.
//
//************************************************************************
//===========================================================================================================
globals
private constant integer MAX_SUB_OPTIONS = 3
private constant real FACTOR_TEST_DAMAGE = 0.01
// a low damage to do on units to test their damage factors for specific
// attacktype/damagetype combos.
// You'll need something as high as 20.0 to make it work well with armor resistances.
// (Yes, you read it correctly, 20 ...
//
// If you use such a large value, there may be conflicts with some things relying on damage
// (ie they are not away of the isDummyDamage tag that xedamage posseses.) which may be quite bad if you think about it...
// then maybe it is better to change it to 0.01 ... then will work fine, just fine - but it will generally ignore armor -
// I am leaving it as 0.01 by default, because honestly, I'd rather make it ignore armor than have a lot of people sending me
// rants about how they detect 20.0 damage where none is visible...
private constant real MAX_DAMAGE_FACTOR = 3.00
// The maximum damage factor in the map. I think 3 is fine.
//=======================================================
private constant real EPSILON = 0.000000001
private unit dmger
private constant integer MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
endglobals
private keyword structInit
struct xedamage[MAX_SPACE]
//----
// fields and methods for a xedamage object, they aid determining valid targets and special
// damage factor conditions.
//
// Notice the default values.
//
boolean damageSelf = false // the damage and factor methods usually have a source unit parameter
// xedamage would consider this unit as immune unless you set damageSelf to true
boolean damageAllies = false // Alliance dependent target options.
boolean damageEnemies = true // *
boolean damageNeutral = true // *
boolean ranged = true // Is the attack ranged? This has some effect on the AI of the affected units
// true by default, you may not really need to modify this.
boolean visibleOnly = false // Should only units that are visible for source unit's owner be affected?
boolean deadOnly = false // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
boolean alsoDead = false // Should even corpses and alive units be considered?
boolean damageTrees = false //Also damage destructables? Notice this is used only in certain methods.
//AOE for example targets a circle, so it can affect the destructables
//in that circle, a custom spell using xedamage for targetting configuration
//could also have an if-then-else implemented so it can verify if it is true
//then affect trees manually.
//
// Damage type stuff:
// .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
// .atype : the "attacktype" , deals with armor.
// .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
//
// Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
//
damagetype dtype = DAMAGE_TYPE_UNIVERSAL
attacktype atype = ATTACK_TYPE_NORMAL
weapontype wtype = WEAPON_TYPE_WHOKNOWS
//
// Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
// variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
// a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
// you can use it in a way similar to Rising_Dusk's damage system.
//
integer tag = 0
//
// if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
// damage.
boolean forceDamage = false
//
// Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
// field allows you to do such thing.
//
real allyfactor = 1.0
//
// field: .exception = SOME_UNIT_TYPE
// This field adds an exception unittype (classification), if the unit belongs to this unittype it will
// be ignored.
//
method operator exception= takes unittype ut returns nothing
set this.use_ex=true
set this.ex_ut=ut
endmethod
//
// field: .required = SOME_UNIT_TYPE
// This field adds a required unittype (classification), if the unit does not belong to this unittype
// it will be ignored.
//
method operator required= takes unittype ut returns nothing
set this.use_req=true
set this.req_ut=ut
endmethod
private boolean use_ex = false
private unittype ex_ut = null
private boolean use_req = false
private unittype req_ut = null
private unittype array fct[MAX_SUB_OPTIONS]
private real array fc[MAX_SUB_OPTIONS]
private integer fcn=0
//
// method .factor(SOME_UNIT_TYPE, factor)
// You might call factor() if you wish to specify a special damage factor for a certain classification,
// for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
//
method factor takes unittype ut, real fc returns nothing
if(this.fcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
return
endif
set this.fct[this.fcn] = ut
set this.fc[this.fcn] = fc
set this.fcn = this.fcn+1
endmethod
private integer array abifct[MAX_SUB_OPTIONS]
private real array abifc[MAX_SUB_OPTIONS]
private integer abifcn=0
//
// method .abilityFactor('abil', factor)
// You might call abilityFactor() if you wish to specify a special damage factor for units that have a
// certain ability/buff.
// for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
// damage than usual.
//
method abilityFactor takes integer abilityId, real fc returns nothing
if(this.abifcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
return
endif
set this.abifct[this.abifcn] = abilityId
set this.abifc[this.abifcn] = fc
set this.abifcn = this.abifcn+1
endmethod
private boolean usefx = false
private string fxpath
private string fxattach
//
// method .useSpecialEffect("effect\\path.mdl", "origin")
// Makes it add (and destroy) an effect when damage is performed.
//
method useSpecialEffect takes string path, string attach returns nothing
set this.usefx = true
set this.fxpath=path
set this.fxattach=attach
endmethod
//********************************************************************
//* Now, the usage stuff:
//*
//================================================================================
// static method xedamage.isInUse() will return true during a unit damaged
// event in case this damage was caused by xedamage, in this case, you can
// read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
// to be able to recognize what sort of damage was done.
//
readonly static damagetype CurrentDamageType=null
readonly static attacktype CurrentAttackType=null
readonly static integer CurrentDamageTag =0
private static integer inUse = 0
static method isInUse takes nothing returns boolean
return (inUse>0) //inline friendly.
endmethod
readonly static boolean isDummyDamage = false
//========================================================================================================
// This function calculates the damage factor caused by a certain attack and damage
// type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
//
static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
local real fc = FACTOR_TEST_DAMAGE
//Since a unit is in that point, we don't need checks.
call SetUnitX(dmger,GetUnitX(u))
call SetUnitY(dmger,GetUnitY(u))
call SetUnitOwner(dmger,GetOwningPlayer(u),false)
set r=hp
if (hp< FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR) then
call SetWidgetLife(u, hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR )
set r = hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR
set fc = GetWidgetLife(u)-hp + EPSILON
endif
set isDummyDamage = true
call UnitDamageTarget(dmger,u, fc ,false,false,a,d,null)
static if DEBUG_MODE then
if IsUnitType(u, UNIT_TYPE_DEAD) and (hp>0.405) then
call BJDebugMsg("xedamage: For some reason, the unit being tested by getDamageTypeFactor has died. Verify MAX_DAMAGE_FACTOR is set to a correct value. ")
endif
endif
set isDummyDamage = false
call SetUnitOwner(dmger,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u)) / fc
endif
call SetWidgetLife(u,hp)
return r
endmethod
private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
local player p=GetOwningPlayer(source)
local boolean allied=IsUnitAlly(target,p)
local boolean enemy =IsUnitEnemy(target,p)
local boolean neutral=allied
local real f
local real negf=1.0
local integer i
if(this.damageAllies != this.damageNeutral) then
set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
//I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
// it neutral.
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
set allied= allied and not(neutral)
endif
if (not this.damageAllies) and allied then
return 0.0
elseif (not this.damageEnemies) and enemy then
return 0.0
elseif( (not this.damageSelf) and (source==target) ) then
return 0.0
elseif (not this.damageNeutral) and neutral then
return 0.0
elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
return 0.0
elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
return 0.0
elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
endif
set f=1.0
if ( IsUnitAlly(target,p) ) then
set f=f*this.allyfactor
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
if (this.use_req and not IsUnitType(target,this.req_ut)) then
return 0.0
endif
set i=.fcn-1
loop
exitwhen (i<0)
if( IsUnitType(target, this.fct[i] ) ) then
set f=f*this.fc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set i=.abifcn-1
loop
exitwhen (i<0)
if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
set f=f*this.abifc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set f=f*negf
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
if( this.forceDamage or not usetypes ) then
return f
endif
set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
return f
endmethod
//====================================================================
// With this you might decide if a unit is a valid target for a spell.
//
method getTargetFactor takes unit source, unit target returns real
return this.getTargetFactorCore(source,target,true)
endmethod
//======================================================================
// a little better, I guess
//
method allowedTarget takes unit source, unit target returns boolean
return (this.getTargetFactorCore(source,target,false)!=0.0)
endmethod
//=======================================================================
// performs damage to the target unit, for unit 'source'.
//
method damageTarget takes unit source, unit target, real damage returns boolean
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local real f = this.getTargetFactorCore(source,target,false)
local real pl
if(f!=0.0) then
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set pl=GetWidgetLife(target)
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
if(pl != GetWidgetLife(target) ) then
if(usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
return true
endif
endif
return false
endmethod
//=======================================================================================
// The same as damageTarget, but it forces a specific damage value, good if you already
// know the target.
//
method damageTargetForceValue takes unit source, unit target, real damage returns nothing
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
if( usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
set .inUse = .inUse +1
call UnitDamageTarget(source,target, damage, true, .ranged, null, null, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
endmethod
//=====================================================================================
// Notice: this will not Destroy the group, but it will certainly empty the group.
//
method damageGroup takes unit source, group targetGroup, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local unit target
local real f
local integer count=0
local real hp
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
loop
set target=FirstOfGroup(targetGroup)
exitwhen (target==null)
call GroupRemoveUnit(targetGroup,target)
set f= this.getTargetFactorCore(source,target,false)
if (f!=0.0) then
set count=count+1
if(usefx) then
set hp = GetWidgetLife(target)
endif
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
if(usefx and (hp > GetWidgetLife(target)) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
endloop
set .inUse = .inUse -1
set .CurrentDamageTag=tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return count
endmethod
private static xedamage instance
private integer countAOE
private unit sourceAOE
private real AOEx
private real AOEy
private real AOEradius
private real AOEdamage
private static boolexpr filterAOE
private static boolexpr filterDestAOE
private static group enumgroup
private static rect AOERect
private static method damageAOE_Enum takes nothing returns boolean
local unit target=GetFilterUnit()
local xedamage this=.instance //adopting a instance.
local real f
local real hp
if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
set target=null
return false
endif
set f=.getTargetFactorCore(.sourceAOE, target, false)
if(f!=0.0) then
set .countAOE=.countAOE+1
if(this.usefx) then
set hp =GetWidgetLife(target)
endif
call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
if(this.usefx and (hp > GetWidgetLife(target) ) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
private static method damageAOE_DestructablesEnum takes nothing returns boolean
local destructable target=GetFilterDestructable()
local xedamage this=.instance //adopting a instance.
local real dx=.AOEx-GetDestructableX(target)
local real dy=.AOEy-GetDestructableY(target)
if( dx*dx + dy*dy >= .AOEradius+EPSILON ) then
set target=null
return false
endif
set .countAOE=.countAOE+1
if(.usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
//==========================================================================================
// will affect trees if damageTrees is true!
//
method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius
set .AOEy=y
set .AOEdamage=damage
call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
set .AOEradius=.AOEradius*.AOEradius
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
endif
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return .countAOE
endmethod
method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//==========================================================================================
// only affects trees, ignores damageTrees
//
method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius*radius
set .AOEy=y
set .AOEdamage=damage
//if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
//endif
return .countAOE
endmethod
method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//'friend' with the library init
static method structInit takes nothing returns nothing
set .AOERect= Rect(0,0,0,0)
set .filterAOE= Condition(function xedamage.damageAOE_Enum)
set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
set .enumgroup = CreateGroup()
endmethod
endstruct
private function init takes nothing returns nothing
set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 0.,0.,0.)
call UnitAddAbility(dmger,'Aloc')
call xedamage.structInit()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ShadowAttack requires TimerUtils, GroupUtils, xedamage
//===============================================================================================
// shadow attack v1.00 by scorpion182
// requires: TimerUtils, xedamage by Vexorian
// GroupUtils by RisingDusk
//
// optional: BoundSentinel by Vexorian (use it if you don't want your hero stuck outside the map bound)
//
//===============================================================================================
globals
private keyword data
//-----------------------CALIBRATION SECTION-----------------------------------------------------
//spell id
private constant integer SPELL_ID = 'A00A'
//shadow trail unit id
private constant integer SHADOW_TRAIL = 'h003'
//shadow number
private constant integer MAX_SHADOW = 12
//attack animation index
private constant integer ANIMATION_INDEX = 1
//walk animation index
private constant integer ATTACK_AN_INDEX = 5
//collision distance
private constant real COLLISION_DIST = 75.
//spell order id
private constant string ORDER_ID = "blizzard"
//image special effect
private constant string IMAGE_FX = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"
//on-damage effect
private constant string ON_DAMAGE_FX = "Úbilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//on-damage effect attachment point
private constant string DAMAGE_ATTCH = "chest"
//preload effect?
private constant boolean PRELOAD_FX = true
endglobals
//do damage each hit
private constant function GetDamage takes integer lvl returns real
return 200. + lvl * 200
endfunction
//attack interval
private constant function GetAttackInterval takes integer lvl returns real
return 1. + lvl * 0
endfunction
//maximum number target per level
private constant function GetTargetNum takes integer lvl returns integer
return 4 + lvl * 2
endfunction
//rotation speed
private constant function GetAngleSpeed takes integer lvl returns real
return .03 + lvl * 0.
endfunction
//caster movement speed
private constant function GetSpeed takes integer lvl returns real
return 500. * XE_ANIMATION_PERIOD + lvl * 0
endfunction
//shadow number
private constant function GetShadowNum takes integer lvl returns integer
return 2 + lvl * 2
endfunction
//area of effect
private constant function GetDistance takes integer lvl returns real
return 450. + lvl * 0
endfunction
//filter the target
private function IsValidTarget takes unit u, data s returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE)==false and IsUnitEnemy(u,GetOwningPlayer(s.caster))==true and IsUnitVisible(u,GetOwningPlayer(s.caster))==true
endfunction
//damage options must match the target filter
private function DamageOptions takes xedamage spellDamage returns nothing
set spellDamage.dtype=DAMAGE_TYPE_UNIVERSAL
set spellDamage.atype=ATTACK_TYPE_NORMAL
set spellDamage.exception=UNIT_TYPE_STRUCTURE
set spellDamage.visibleOnly=true
endfunction
//----------------------END OF CALIBRATION-------------------------------------------------------
globals
private xedamage xed
private constant real A = 2 * bj_PI
endglobals
private struct shadow
unit array shadow[MAX_SHADOW]
real array angle[MAX_SHADOW]
boolean array show[MAX_SHADOW]
group victim
unit target = null
boolean sets = false
boolean attack = false
boolean ready = false
boolean back = false
boolean inpos = false
real interval = 0
real cap = 0
real ag = 0
integer idx = 0
integer num = 0
integer n = 0
integer pos = 0
unit caster
timer t
integer lvl
real cx
real cy
private static thistype temp
static method create takes unit c, real x, real y returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local real a
set .caster = c
set .t = NewTimer()
set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
set .victim = NewGroup()
set .cap = A
set .cx = x
set .cy = y
loop
exitwhen i == GetShadowNum(.lvl)
set a = i * A / GetShadowNum(.lvl)
set .shadow[i] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, x, y, a)
set .angle[i] = a
call SetUnitTimeScale(.shadow[i], 2.)
call SetUnitColor(.shadow[i], PLAYER_COLOR_LIGHT_GRAY)
call SetUnitVertexColor(.shadow[i], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[i], ANIMATION_INDEX)
call ShowUnit(.shadow[i], false)
set i = i + 1
endloop
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop)
return this
endmethod
//i don't know why i can't detect locust unit, so i reverse it
static method IsCaster takes nothing returns boolean
local unit u = GetFilterUnit()
if u==temp.caster and not temp.sets then
set temp.pos = temp.idx
set temp.sets = true
call RemoveUnit(temp.shadow[temp.idx])
set temp.shadow[temp.idx] = temp.caster
set temp.show[temp.idx] = true
set temp.num = temp.num + 1
endif
set u = null
return false
endmethod
static method IsTarget takes nothing returns boolean
local unit u = GetFilterUnit()
if temp.target == null and IsValidTarget(u, temp) and not IsUnitInGroup(u, temp.victim) then
set temp.target = u
set temp.n = temp.n + 1
set temp.attack = true
call GroupAddUnit(temp.victim, u)
endif
set u = null
return false
endmethod
static method onLoop takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local integer i = 0
local real dx
local real dy
local real dis
local real angle
if GetUnitCurrentOrder(.caster) == OrderId(ORDER_ID) then
set temp = this
if .ready then
if .back then
set .interval = .interval + XE_ANIMATION_PERIOD
if .interval > GetAttackInterval(.lvl) then
set .interval = 0.
set .back = false
set .shadow [.pos] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, GetUnitX(.caster), GetUnitY(.caster), GetUnitFacing(.caster))
call SetUnitTimeScale(.shadow[.pos], 2.)
call SetUnitColor(.shadow[.pos], PLAYER_COLOR_LIGHT_GRAY)
call SetUnitVertexColor(.shadow[.pos], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[.pos], ANIMATION_INDEX)
call UnitAddAbility(.shadow[.pos], 'Aloc')
call GroupClear(.victim)
endif
endif
if not .attack and .target == null and .n < GetTargetNum(.lvl) and not .back then
call GroupEnumUnitsInRange(ENUM_GROUP, .cx, .cy, GetDistance(.lvl), function thistype.IsTarget)
if .n == 0 and .target == null and not .inpos then
set .inpos = true
call RemoveUnit(.shadow[.pos])
set .shadow[.pos] = .caster
set .show[.pos] = true
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
if .n >= 1 and .target == null then
set .ready = false
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
elseif .attack and .target!=null then
set dx = GetUnitX(.target) - GetUnitX(.caster)
set dy = GetUnitY(.target) - GetUnitY(.caster)
set dis = SquareRoot(dx * dx + dy * dy)
set angle = Atan2(dy, dx)
if dis > COLLISION_DIST and IsUnitInRangeXY(.target, .cx, .cy, GetDistance(.lvl)) then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
call xed.damageTarget(.caster,.target,GetDamage(.lvl))
set .attack = false
set .target = null
call SetUnitAnimationByIndex(.caster, ATTACK_AN_INDEX)
endif
elseif .n == GetTargetNum (.lvl) then
set .ready = false
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
else
if .num == GetShadowNum(.lvl) then
set dx = GetUnitX(.shadow[.pos]) - GetUnitX(.caster)
set dy = GetUnitY(.shadow[.pos]) - GetUnitY(.caster)
set dis = SquareRoot(dx * dx + dy * dy)
set angle = Atan2(dy, dx)
if dis > 215. then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
if not .back then
set .back = true
set .ready = true
set .attack = false
set .inpos = false
set .n = 0
set .target = null
set .pos = .pos - 1
if .pos < 0 then
set .pos = GetShadowNum(.lvl) - 1
endif
call RemoveUnit(.shadow[.pos])
set .shadow[.pos] = .caster
set .show[.pos] = true
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
endif
endif
endif
if .sets and .ag > .cap then
set temp.idx = temp.idx - 1
if temp.idx < 0 then
set temp.idx = GetShadowNum(.lvl) - 1
endif
set .ag = 0
if not .show[.idx] then
set .num = .num + 1
if .num > GetShadowNum(.lvl) then
set .num = GetShadowNum(.lvl)
endif
if .num == GetShadowNum(.lvl) then
set .ready = true
set .shadow [.pos] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, GetUnitX(.caster), GetUnitY(.caster), GetUnitFacing(.caster))
call SetUnitTimeScale(.shadow[.pos], 2.)
call SetUnitColor(.shadow[.pos], PLAYER_COLOR_LIGHT_GRAY)
call SetUnitVertexColor(.shadow[.pos], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[.pos], ANIMATION_INDEX)
call UnitAddAbility(.shadow[.pos], 'Aloc')
endif
set .show[.idx] = true
call ShowUnit(.shadow[.idx], true)
call UnitAddAbility(.shadow[.idx], 'Aloc')
call DestroyEffect(AddSpecialEffectTarget(IMAGE_FX, .shadow[.idx], "origin"))
endif
endif
loop
exitwhen i == GetShadowNum(.lvl)
if not .sets then
call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(.shadow[i]), GetUnitY(.shadow[i]), COLLISION_DIST, function thistype.IsCaster)
set .idx = i
endif
set .ag = .ag + GetAngleSpeed(.lvl)
set .angle[i] = .angle[i] + GetAngleSpeed(.lvl)
call SetUnitX(.shadow[i], .cx + GetDistance(.lvl) * Cos(.angle[i]))
call SetUnitY(.shadow[i], .cy + GetDistance(.lvl) * Sin(.angle[i]))
call SetUnitFacing(.shadow[i], .angle[i] * bj_RADTODEG + 90. )
set i = i + 1
endloop
else
call .destroy()
endif
endmethod
private method onDestroy takes nothing returns nothing
local integer i = 0
call ReleaseTimer(.t)
call ReleaseGroup(.victim)
call SetUnitTimeScale(.caster, 1.)
loop
exitwhen i == GetShadowNum(.lvl)
set .show[i] = false
if .shadow[i] != .caster then
call SetUnitExploded(.shadow[i], true)
call KillUnit(.shadow[i])
endif
set i = i + 1
endloop
endmethod
endstruct
private struct data
unit caster
timer t
real tx
real ty
integer lvl
real cx
real cy
static method create takes unit c, real x, real y returns thistype
local thistype this = thistype.allocate()
local real angle = bj_RADTODEG * Atan2(y - GetUnitY(c), x - GetUnitX(c))
set .cx = x
set .cy = y
set .caster = c
set .t = NewTimer()
set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
set .tx = x + GetDistance(.lvl) * Cos(angle)
set .ty = y + GetDistance(.lvl) * Sin(angle)
call SetUnitFacing(.caster, angle)
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
call SetUnitTimeScale(.caster, 2.)
return this
endmethod
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
endmethod
static method onLoop takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local real dx = .tx - GetUnitX(.caster)
local real dy = .ty - GetUnitY(.caster)
local real dis = SquareRoot(dx * dx + dy * dy)
local real angle = Atan2(dy, dx)
local shadow s
if dis > COLLISION_DIST and GetUnitCurrentOrder(.caster) == OrderId(ORDER_ID) then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
call .destroy()
set s = shadow.create(.caster, .cx, .cy)
endif
endmethod
static method SpellEffect takes nothing returns boolean
local thistype this
local unit u = GetTriggerUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
if GetSpellAbilityId() == SPELL_ID then
set this = thistype.create(u, x, y)
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop)
endif
set u = null
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.SpellEffect))
//init xedamage
set xed=xedamage.create()
call DamageOptions(xed)
call xed.useSpecialEffect(ON_DAMAGE_FX, DAMAGE_ATTCH)
//preload fx
static if PRELOAD_FX then
call Preload(IMAGE_FX)
call Preload(ON_DAMAGE_FX)
endif
endmethod
endstruct
endlibrary
library Railgun requires TimerUtils
//==================================================================================================
//---------------------------------Railgun-----by-Insanity_AI---------------------------------------
//==================================================================================================
/*/* DISCLAIMER: This spell visually works better on 1.30 PTR */*/
/*/* Primarily because of BlzGetLocalUnitZ() working properly there... */*/
//
// Setup: Create a Railgun ability and modify trigger spell condition.
// Create a dummy unit for trajectory visualizaton.
// Make sure to match those objectIDs with configuration settings in here:
// Primarily in SpellCondition() and in the Visuals category; VISUALIZATION_ID
/* Make sure that you have a /*/*Unit Indexer*/*/ in your map.
*/
// A bit of configuration info:
// You can edit in the Configuration Section just down below.
// Each configurable function or variable has a little comment describing what it does.
// There are also functions that are responsible for damaging units, killing destructables,
// And blacklisting them, those are all at your disposal.
// I added a lot of visual configuration, I'm pretty sure you can use things like GetTriggerUnit()
// in there, so I'm pretty sure that alone opens a lot of doors and posibilities.
//
// About the damage:
// At the moment it deals percentage of target's max health.
// The damage is stacked on the target depending on how close they're to the beam,
// which is determined by the RADIUS.
// It goes up from 0% to 90%(in configuration) depending on how close the target is
// to the beam.
//
// Limitation:
// It will shoot through terrain hills, so I'd suggest using some sort of pathingblockers
// ... that is, unless you don't want this intended interaction (or lack of.)
//
// Modifications:
// Cast time, cooldown and mana cost is edited in the object editor,
// as for the other things, they're editable right here.
//
//==================================================================================================
globals
private real array angle
private real array offsetZ
private group array visualizers
private lightning array beam
private real array fadeOutDuration
private real array fadeOutRate
private real array fadeOutPeriod
private boolean array stopPoint
private trigger cast = CreateTrigger()
private trigger stop = CreateTrigger()
private trigger fire = CreateTrigger()
private boolexpr destructFilter = null
private boolexpr unitFilter = null
private boolexpr castFunction = null
private boolexpr stopFunction = null
private boolexpr fireFunction = null
endglobals
/*-----------------------------------------------------------------------------*/
/*========================Configuration Section================================*/
/*-----------------------------------------------------------------------------*/
//A little foreword; All of these functions have access to GetTriggerUnit() and GetSpellAbilityId(),
//and with such, opens many customization options.
//No need for have the library twice to make 2 different spells, is what I am saying.
private function SpellCondition takes nothing returns boolean
return (GetSpellAbilityId() == 'A006')
endfunction
private function GetRange takes nothing returns real
//Range to where the railgun shoots
return 2000.00
endfunction
private function GetRadius takes nothing returns real
//Railgun's visualizer area check for destructables and units
return 200.00
endfunction
private function GetBeamStepDistance takes nothing returns real
//Distance-step to check for beam's object blockers
//Eg. A tree.
return 40.00
endfunction
/*/*/*----------------------------------------------------------------------*/*/*/
/*/*/*===========================Visuals====================================*/*/*/
/*/*/*----------------------------------------------------------------------*/*/*/
globals
//UnitID of Railgun Trajectory visualization
private integer VISUALIZATION_ID = 'n000'
private integer VISUALIZATION_PLAYER = PLAYER_NEUTRAL_PASSIVE
private string VISUAL_HIT_MODEL = "Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl"
//Aka, how many lightnings does 1 beam contain, stacked up on 1 another.
private integer MAXLIGHTNINGCOUNT = 25
//- After a lot of thinking, I decided to put this back into variable form, because having multiple spells
//with different lightningcounts, would cause interference in the lightning array.
endglobals
private function FadeOut takes nothing returns boolean
//Would you like the railgun beam to fade out rather than just dissapear
return true
endfunction
private function GetBeamDuration takes nothing returns real
//Time before the railgun beam is removed from the map
//I should note that you shouldn't cast another beam from the same unit, until this time has passed
//So, set spell cooldown accordingly
return 0.3
endfunction
private function GetFadeOutPeriod takes nothing returns real
//In what intervals will it apply the fade out rate
return 0.05
endfunction
private function GetFadeOutRate takes nothing returns real
//By how much does the beam fade out per period,
//(remember lightning colour, including alpha channel, goes from 0.00 to 1.00)
//also if duration is lower than period, the beam will just dissapear instead, regardless if you have FadeOut as true.
return 0.2
endfunction
private function GetVisualizationDistance takes nothing returns real
//Distance between each of the visualization lights
return 200.00
endfunction
private function GetLightningName takes nothing returns string
// Change beam's lightning model, would suggest vanilla DRAM, DRAL, DRAB and LEAS models
//Other models don't retain a "beam" sort of structure.
return "DRAL"
endfunction
private function SetBeamColor takes lightning beam returns nothing
//The real values are by order: Red, Green, Blue, Alpha
//And take values from 0.00 to 1.00, apparently.
//Now this won't change the beam to actual color, but just reduce the amount of colour the lightning
//model already has. If you're unsatisfied with the results this gives you, try a different model.
call SetLightningColor(beam,1.00,0.75,0.75,0.75)
set beam = null
endfunction
private function GetLightningVisualHeightOffset takes nothing returns real
//Visual Z offset for the lightning.
return 60.00
endfunction
private function GetCastAnimation takes nothing returns string
//Used when the caster is prepearing to fire
return "stand channel"
endfunction
private function GetFireAnimation takes nothing returns string
//Used when caster is firing
return "spell,four"
endfunction
private function GetStandAnimation takes nothing returns string
//Queued after firing
return "stand"
endfunction
/*/*/*----------------------------------------------------------------------*/*/*/
/*/*/*=====================End of Visuals===================================*/*/*/
/*/*/*----------------------------------------------------------------------*/*/*/
private function UnitBlacklist takes nothing returns boolean
//Any unit or unit-type you want it to be immune to this? You can add it here.
return true
endfunction
private function DamageVictims takes real squaredDistance returns nothing
//Function responsible for damaging units, you can edit this however you'd like.
//squaredDistance is the distance of the unit from the beam... squared.
local unit target = GetEnumUnit()
local unit caster = GetTriggerUnit()
local real maxRangeSquared = Pow(GetRadius(),2)
local real damage
if(target != caster)then
set damage = (maxRangeSquared - squaredDistance)/maxRangeSquared
if damage > 0.50 then
set damage = 0.50
endif
set damage = damage * GetUnitState(target,UNIT_STATE_MAX_LIFE)
call UnitDamageTarget(caster,target,damage,true,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNKNOWN,WEAPON_TYPE_WHOKNOWS)
call DestroyEffect(AddSpecialEffectTarget(VISUAL_HIT_MODEL,target,"chest"))
endif
set target = null
set caster = null
endfunction
private function DestructableBlacklist takes nothing returns boolean
//Any additions you'd like to add here?
local integer destructType = GetDestructableTypeId(GetFilterDestructable())
//if the destructable is alive and is not a pathblocker of any kind.
if GetDestructableLife(GetFilterDestructable()) <= 0 then
return false
endif
set stopPoint[GetUnitUserData(GetTriggerUnit())] = true
return not((destructType == 'YTlb') or (destructType == 'YTab') or (destructType == 'YTpb') or (destructType == 'YTfb'))
endfunction
private function DestructSearchAndDestroy takes nothing returns nothing
//How destructables are being destroyed.
call SetDestructableLife(GetEnumDestructable(), 0.00)
endfunction
/*-----------------------------------------------------------------------------*/
/*===================End of configuration section==============================*/
/*-----------------------------------------------------------------------------*/
private function CheckUnitTarget takes nothing returns nothing
local unit target = GetEnumUnit()
local real targetX = GetUnitX(target)
local real targetY = GetUnitY(target)
local unit caster = GetTriggerUnit()
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local integer casterData = GetUnitUserData(caster)
local real maxRangeSquared = Pow(GetRadius(),2)
local real angleT = Atan2(targetY-casterY,targetX-casterX) - angle[casterData]
local real targetDistance
//Ignore units that are behind the caster.
if not(angleT < bj_PI/2 and angleT > -bj_PI/2) then
set target = null
set caster = null
return
endif
//A slightly modified Distance between a line and a point formula
//Ax + By + C = 0 => -ax + y + b = 0 from y = ax - b, where a = tan(angle) and b = a(x1) - y1
//Formula: |Ax + By + C|/Sqrt(A^2 + B^2)=> ((-ax + y + b)^2)/(a^2 + 1)
set angleT = Tan(angle[casterData])
set targetDistance = Pow(-angleT*targetX + targetY + angleT*casterX - casterY,2)/(Pow(angleT,2) + 1)
if targetDistance > maxRangeSquared then
set target = null
set caster = null
return
endif
//If it checks out, damage it
call DamageVictims(targetDistance)
set target = null
set caster = null
endfunction
private function GetVisualizationStopIndex takes nothing returns integer
return R2I(GetRange()/GetVisualizationDistance())
endfunction
private function GetBeamStopIndex takes nothing returns integer
return R2I(GetRange()/GetBeamStepDistance())
endfunction
private function Cast takes nothing returns nothing
local unit caster = GetTriggerUnit()
local rect destructCheckRect = Rect(0,0,0,0)
local unit visualizer = null
local group visualizerGroup = CreateGroup()
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local real casterZ = BlzGetLocalUnitZ(caster)
local real targetX = GetSpellTargetX()
local real targetY = GetSpellTargetY()
local real targetZ
local real range = GetRange()
local real visualDistance = GetVisualizationDistance()
local real radius = GetRadius()
local integer iteration = 1
local integer iterationEnd = GetVisualizationStopIndex()
local integer casterData = GetUnitUserData(caster)
local real offsetX
local real offsetY
call SetUnitAnimation(caster, GetCastAnimation())
set angle[casterData] = Atan2(targetY-casterY,targetX-casterX)
set offsetX = visualDistance*Cos(angle[casterData])
set offsetY = visualDistance*Sin(angle[casterData])
set visualizers[casterData] = CreateGroup()
set stopPoint[casterData] = false
loop
exitwhen iteration > iterationEnd
set targetX = casterX + offsetX*I2R(iteration)
set targetY = casterY + offsetY*I2R(iteration)
set visualizer = CreateUnit(Player(VISUALIZATION_PLAYER),VISUALIZATION_ID,targetX,targetY,angle[casterData])
call GroupAddUnit(visualizerGroup,visualizer)
call SetRect(destructCheckRect,targetX-radius,targetY-radius,targetX+radius,targetY+radius)
call EnumDestructablesInRect(destructCheckRect,destructFilter, null)
exitwhen stopPoint[casterData]
set iteration = iteration +1
endloop
set targetZ = BlzGetLocalUnitZ(visualizer)
set offsetZ[casterData] = (targetZ - casterZ)/range
set iteration = 1
loop
set visualizer = FirstOfGroup(visualizerGroup)
exitwhen visualizer == null
call UnitAddAbility(visualizer,'Amrf')
call SetUnitFlyHeight(visualizer,offsetZ[casterData] * I2R(iteration) + casterZ - BlzGetLocalUnitZ(visualizer) ,0.00)
call UnitRemoveAbility(visualizer,'Amrf')
set iteration = iteration + 1
call GroupRemoveUnit(visualizerGroup,visualizer)
call GroupAddUnit(visualizers[casterData],visualizer)
endloop
call RemoveRect(destructCheckRect)
call DestroyGroup(visualizerGroup)
set visualizerGroup = null
set visualizer = null
set caster = null
set destructCheckRect = null
endfunction
private function Stop takes nothing returns nothing
//in case the caster stops casting the railgun
local integer casterData = GetUnitUserData(GetTriggerUnit())
local unit dummy = null
loop
set dummy = FirstOfGroup(visualizers[casterData])
exitwhen (dummy == null)
call GroupRemoveUnit(visualizers[casterData],dummy)
call RemoveUnit(dummy)
endloop
call DestroyGroup(visualizers[casterData])
set dummy = null
set visualizers[casterData] = null
endfunction
private function FireCleanup takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer casterData = GetTimerData(t)
local integer iteration = 0
local integer endIteration = MAXLIGHTNINGCOUNT
loop
exitwhen iteration >= endIteration
call DestroyLightning(beam[casterData*endIteration + iteration])
set iteration = iteration + 1
endloop
call ReleaseTimer(t)
set t = null
endfunction
private function FireFadeOut takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer casterData = GetTimerData(t)
local integer iteration = 0
local integer endIteration = MAXLIGHTNINGCOUNT
local lightning localBeam = null
set fadeOutDuration[casterData] = fadeOutDuration[casterData] - fadeOutPeriod[casterData]
if fadeOutDuration[casterData] <= 0.00 then
call PauseTimer(t)
call FireCleanup()
endif
loop
exitwhen iteration >= endIteration
set localBeam = beam[casterData*endIteration+iteration]
call SetLightningColor(localBeam, GetLightningColorR(localBeam),GetLightningColorG(localBeam),GetLightningColorB(localBeam),GetLightningColorA(localBeam)- fadeOutRate[casterData])
set iteration = iteration + 1
endloop
set t = null
set localBeam = null
endfunction
private function Fire takes nothing returns nothing
local unit caster = GetTriggerUnit()
local integer casterData = GetUnitUserData(caster)
local timer t = NewTimerEx(casterData)
local rect multipurposeRect = Rect(0,0,0,0)
local group victims = CreateGroup()
local real lightningZOffset = GetLightningVisualHeightOffset()
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local real casterZ = BlzGetLocalUnitZ(caster) + lightningZOffset
local real stepDistance = GetBeamStepDistance()
local real radius = GetRadius()
local string lightningName = GetLightningName()
local real offsetX = stepDistance*Cos(angle[casterData])
local real offsetY = stepDistance*Sin(angle[casterData])
local real rectX
local real rectY
local integer iteration = 0
local integer endIteration = MAXLIGHTNINGCOUNT
local real targetX
local real targetY
local real targetZ
set stopPoint[casterData] = false
//visual appeal
call SetUnitAnimation(caster, GetFireAnimation())
call QueueUnitAnimation(caster, GetStandAnimation())
loop
exitwhen iteration >= endIteration
set beam[casterData*endIteration + iteration] = AddLightningEx(lightningName ,true ,casterX,casterY ,0.00 ,casterX + 1.00,casterY + 1.00,0.00)
set iteration = iteration + 1
endloop
set iteration = 1
set endIteration = GetBeamStopIndex()
loop
exitwhen iteration >= endIteration
set targetX = casterX + offsetX*I2R(iteration)
set targetY = casterY + offsetY*I2R(iteration)
call SetRect(multipurposeRect,targetX-radius,targetY-radius,targetX+radius,targetY+radius)
call EnumDestructablesInRect(multipurposeRect,destructFilter, function DestructSearchAndDestroy)
exitwhen stopPoint[casterData]
set iteration = iteration +1
endloop
//OffsetX/Y is no longer used, so I'll repurpose them here!
set offsetX = targetX
set offsetY = targetY
set rectX = casterX
set rectY = casterY
if targetX > casterX then
set offsetX = casterX
set rectX = targetX
endif
if targetY > casterY then
set offsetY = casterY
set rectY = targetY
endif
call SetRect(multipurposeRect,offsetX-radius,offsetY-radius,rectX+radius,rectY+radius)
call GroupEnumUnitsInRect(victims,multipurposeRect,unitFilter)
call ForGroup(victims, function CheckUnitTarget)
set targetZ = casterZ + offsetZ[casterData]*R2I(iteration)*stepDistance
set iteration = 0
set endIteration = MAXLIGHTNINGCOUNT
loop
exitwhen iteration >= endIteration
call MoveLightningEx(beam[casterData*endIteration + iteration],true,targetX,targetY,targetZ,casterX,casterY,casterZ)
call SetBeamColor(beam[casterData*endIteration + iteration])
set iteration = iteration + 1
endloop
if FadeOut() then
set fadeOutDuration[casterData] = GetBeamDuration()
set fadeOutRate[casterData] = GetFadeOutRate()
set fadeOutPeriod[casterData] = GetFadeOutPeriod()
call TimerStart(t,GetFadeOutPeriod(),true,function FireFadeOut)
else
call TimerStart(t,GetBeamDuration(),false,function FireCleanup)
endif
call DestroyGroup(victims)
call RemoveRect(multipurposeRect)
set caster = null
set multipurposeRect = null
set victims = null
set t = null
endfunction
private function Cast_Wrapper takes nothing returns boolean
if SpellCondition() then
call Cast()
return true
endif
return false
endfunction
private function Stop_Wrapper takes nothing returns boolean
if SpellCondition() then
call Stop()
return true
endif
return false
endfunction
private function Fire_Wrapper takes nothing returns boolean
if SpellCondition() then
call Fire()
return true
endif
return false
endfunction
//================================================================================
function InitTrig_Railgun takes nothing returns nothing
//this is so that the system knows when to stop the railgun. Value depends on 3 pre-set constants.
set destructFilter = Filter(function DestructableBlacklist)
set unitFilter = Filter(function UnitBlacklist)
set castFunction = Condition(function Cast_Wrapper)
set stopFunction = Condition(function Stop_Wrapper)
set fireFunction = Condition(function Fire_Wrapper)
//Cast the Railgun
call TriggerRegisterAnyUnitEventBJ(cast, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddCondition(cast, castFunction)
//Stop the Railgun
call TriggerRegisterAnyUnitEventBJ(stop, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition(stop, stopFunction)
//Be the... no wait, Fire the Railgun
call TriggerRegisterAnyUnitEventBJ(fire, EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(fire, fireFunction)
call Preload(VISUAL_HIT_MODEL)
endfunction
endlibrary
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary