Name | Type | is_array | initial_value |
AbsorcionCaster | unit | No | |
AbsorcionDamage | real | No | |
AbsorcionFX | effect | No | |
AbsorcionGroup | group | No | |
AbsorcionMana | integer | No | |
AddTimedAbility_Buff | buffcode | Yes | |
AddTimedAbility_C | integer | Yes | |
AddTimedAbility_IDX | integer | Yes | |
AddTimedAbility_Skill | abilcode | Yes | |
AddTimedAbility_T | real | Yes | |
AddTimedAbility_Unit | unit | Yes | |
AddTimedAbilitySYS_Buff | buffcode | No | |
AddTimedAbilitySYS_Level | integer | No | |
AddTimedAbilitySYS_Skill | abilcode | No | |
AddTimedAbilitySYS_Tiempo | real | No | |
AddTimedAbilitySYS_Unit | unit | No | |
AfterDamageEvent | real | No | |
AfterDamageEvent_Copy | real | No | |
AgilityStoreBlue | unit | Yes | |
AgilityStoreRed | unit | Yes | |
AI_AttackinHero | boolean | Yes | |
AI_AttackinStructure | boolean | Yes | |
AI_Farming | boolean | Yes | |
AI_FarminJungle | boolean | Yes | |
AI_Group | group | Yes | |
AI_Hero | unit | Yes | |
AI_Kitting | boolean | Yes | |
AI_RetreatPoint | location | No | |
AI_SearchRune | boolean | Yes | |
AI_UnderAttack | boolean | Yes | |
All_Items_Given | boolean | Yes | |
AllianceBottonGroup | group | Yes | |
AllianceMidGroup | group | Yes | |
AllianceTopGroup | group | Yes | |
AmountRandomHeroesLeft | integer | No | |
AncienofDeathEReward | integer | No | |
AncienofDeathGReward | integer | No | |
AncienofDeathUpgrade | integer | No | 1 |
AncienofLifeEReward | integer | No | |
AncienofLifeGReward | integer | No | |
AncienofLifeUpgrade | integer | No | 1 |
AncientCamp | group | Yes | |
AncientofDeath | unit | No | |
AncientofDeathFase | integer | No | |
AncientofDeathItem | item | Yes | |
AncientofDeathSpawn | rect | No | |
AncientofLife | unit | No | |
AncientofLifeFase | integer | No | |
AncientofLifeItem | item | Yes | |
AncientofLifeSpawn | rect | No | |
AncientType1 | unitcode | No | |
AncientType1Resurrection | timer | No | |
AncientType2 | unitcode | No | |
AncientType2Resurrection | timer | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
AofDUnterAttack | boolean | No | |
AofLUnderAttack | boolean | 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 | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
ArmoryBluePoint | location | No | |
ArmoryRedPoint | location | No | |
ArrayReal | real | Yes | |
ArrayUnit | unit | Yes | |
AssistGold | integer | No | |
AssistPlayer | integer | No | |
AtaqueParasma | boolean | Yes | false |
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 | |
AttackBase | location | Yes | |
AttackPoint | location | Yes | |
AttackTypeDebugStr | string | Yes | |
AuraDebuffArea | real | No | |
automaticClean | boolean | No | |
Autosave_Interval | real | No | |
AvailableHeroes | unitcode | Yes | |
B_Caster | unit | No | |
B_Point | location | No | |
Barrera_Group | group | No | |
Barrera_Magica | integer | Yes | |
BarreraCaster | unit | Yes | |
Base | location | Yes | |
BaseExperience | integer | No | 100 |
BaseHeroPoll | group | No | |
BaseV | location | Yes | |
BC_Point | location | No | |
BlazePlayer | player | No | Player06 |
BloodthornTarget | unit | No | |
BloodthronDamageStore | real | Yes | |
BLUE_CantidadMelee | integer | Yes | 3 |
BLUE_CantidadRango | integer | Yes | 1 |
BLUE_Grupos | group | Yes | |
BLUE_Spawn | location | Yes | |
BLUE_TipoUnidad_ASEDIO | unitcode | Yes | |
BLUE_TipoUnidad_MELEE | unitcode | Yes | |
BLUE_TipoUnidad_RANGO | unitcode | Yes | |
BM_EQUIP | integer | Yes | |
BM_SKIN_1 | integer | Yes | |
BM_SKIN_2 | integer | Yes | |
BM_SKIN_3 | integer | Yes | |
BotasTranquilasTimer | real | Yes | |
BottomDireGroup | group | No | |
BottomRadiantGroup | group | No | |
BottonLane | boolean | Yes | |
BountyGold | integer | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
CasterUnit | unit | No | |
CatchTarget | unit | No | |
CEvBlock | boolean | Yes | |
CEvNext | integer | Yes | |
CEvPrev | integer | Yes | |
CEvSpecial | boolean | Yes | |
CEvUnloadTimer | timer | No | |
CF_EQUIP | integer | Yes | |
CF_SKIN_1 | integer | Yes | |
CF_SKIN_2 | integer | Yes | |
CF_SKIN_3 | integer | Yes | |
CF_SKIN_4 | integer | Yes | |
CF_SKIN_5 | integer | Yes | |
CL_EQUIP | integer | Yes | |
CL_SKIN_1 | integer | Yes | |
CL_SKIN_2 | integer | Yes | |
ClearDamageEvent | trigger | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
CooldownNuevo | real | Yes | |
CooldownReducido | real | Yes | |
CooldwonBase | real | Yes | |
CoreDire | unit | No | |
CoreRadiant | unit | No | |
CorrupcionUnit | unit | Yes | |
CountdownAllPick | timer | No | |
Courier_DistanceToHero | real | Yes | |
Courier_EndTransfer | group | No | |
Courier_Group | group | No | |
Courier_Integer | integer | No | |
Courier_LoopInteger | integer | No | |
Courier_Owning_Player | player | No | |
Courier_TempPoint | location | No | |
Courier_Transfering | unit | Yes | |
Courier_Transfering2 | group | No | |
CourierSpawn | location | Yes | |
CreepCampAncient | rect | Yes | |
CreepCampLarge | rect | Yes | |
CreepCampMedium | rect | Yes | |
CreepCampSmall | rect | Yes | |
CreeptoCreep | unit | Yes | |
CrimsonCaster | unit | No | |
CrimsonGroup | group | No | |
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 | |
DAMAGE_UfgarkUlt | real | No | |
DamageBlockingAbility | abilcode | No | |
DamageEvent | real | No | |
DamageEvent_Copy | real | No | |
DamageEventAmount | real | No | |
DamageEventAmount_Copy | 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 | |
DamageEventOverride_Copy | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventPrevAmt_Copy | real | No | |
DamageEventSource | unit | No | |
DamageEventSource_Copy | unit | No | |
DamageEventsWasted | integer | No | |
DamageEventTarget | unit | No | |
DamageEventTarget_Copy | unit | No | |
DamageEventTrigger | trigger | No | |
DamageEventType | integer | No | |
DamageEventType_Copy | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageModifierEvent_Copy | real | No | |
DamageOverTime_A | real | Yes | |
DamageOverTime_AC | integer | Yes | |
DamageOverTime_AT | attacktype | Yes | |
DamageOverTime_B | boolean | Yes | |
DamageOverTime_BC | boolean | Yes | |
DamageOverTime_C | integer | Yes | |
DamageOverTime_D | real | Yes | |
DamageOverTime_DT | damagetype | Yes | |
DamageOverTime_G | group | No | |
DamageOverTime_I | real | Yes | |
DamageOverTime_IDX | integer | Yes | |
DamageOverTime_P | location | No | |
DamageOverTime_T | real | Yes | |
DamageOverTime_UnitO | unit | Yes | |
DamageOverTime_UnitT | unit | Yes | |
DamageOverTimeSYS_AoE | real | No | |
DamageOverTimeSYS_AttkType | attacktype | No | |
DamageOverTimeSYS_Bool | boolean | No | |
DamageOverTimeSYS_Damage | real | No | |
DamageOverTimeSYS_DmgType | damagetype | No | |
DamageOverTimeSYS_IntervaloDmg | real | No | |
DamageOverTimeSYS_Tiempo | real | No | |
DamageOverTimeSYS_TipoObjetivo | boolean | No | |
DamageOverTimeSYS_UnitOwner | unit | No | |
DamageOverTimeSYS_UnitTarget | unit | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeBlocked_Copy | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeCriticalStrike_Copy | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeExplosive_Copy | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypeHeal_Copy | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DamageTypeReduced_Copy | integer | No | |
DBottomBaseTower1 | unit | No | |
DBottomBaseTower2 | unit | No | |
DBottomBaseTower3 | unit | No | |
DBottomBaseTower4 | unit | No | |
DCoreTower1 | unit | No | |
DCoreTower2 | unit | No | |
DeadHeroLevel | integer | No | |
DeathEvent | real | No | |
DeathWindowAllies | timerdialog | Yes | |
DebilidadMagicaGroup | group | No | |
decisionCooldown | real | 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 | |
DEffigy1 | unit | No | |
DEffigy2 | unit | No | |
DEffigy3 | unit | No | |
DEffigy4 | unit | No | |
DEffigy5 | unit | No | |
DEffigy6 | unit | No | |
DEvAbility | abilcode | No | |
DEvAbilityTemp | abilcode | No | |
DEvBlock | boolean | Yes | |
DEvList | integer | Yes | |
DEvRemoved | boolean | Yes | |
DEvTimer | timer | No | |
DisperserTarget | unit | Yes | |
DK_EQUIP | integer | Yes | |
DK_SKIN_1 | integer | Yes | |
DK_SKIN_2 | integer | Yes | |
DK_SKIN_3 | integer | Yes | |
DMegaCreepsON | boolean | No | |
DMeleBarrak1 | unit | No | |
DMeleBarrak2 | unit | No | |
DMeleBarrak3 | unit | No | |
DmgDuration | real | No | |
DmgEvLife | real | No | |
DmgEvPrevLife | real | No | |
DmgEvRecursionLevel | integer | No | |
DmgEvRecursionN | integer | No | |
DmgEvRunning | boolean | No | |
DmgEvStarted | boolean | No | |
DmgEvTimer | timer | No | |
DmgEvTrig | trigger | No | |
DmgEvUnit | unit | No | |
DmgSize | real | No | |
DmgStr | string | No | |
DMidBaseTower1 | unit | No | |
DMidBaseTower2 | unit | No | |
DMidBaseTower3 | unit | No | |
DMidBaseTower4 | unit | No | |
DominatedUnitLive | boolean | Yes | |
DominationUnit | unit | Yes | |
DoNotClearNext | boolean | No | |
DP_Area | group | No | |
DP_Caster | unit | No | |
DP_FX | effect | No | |
DP_Point | location | No | |
DRangeBarrak1 | unit | No | |
DRangeBarrak2 | unit | No | |
DRangeBarrak3 | unit | No | |
DShrine | unit | No | |
DTopBaseTower1 | unit | No | |
DTopBaseTower2 | unit | No | |
DTopBaseTower3 | unit | No | |
DTopBaseTower4 | unit | No | |
DUMMY_CASTER_ID | unitcode | No | |
DUMMY_ID | unitcode | No | |
DummyUnit | unit | No | |
DyingHero | unit | Yes | |
DyingPlayer | integer | No | |
EarnedExperience | integer | No | |
EmberFx | effect | No | |
EnemyBaseLocation | location | Yes | |
EnhancedDamageTarget | unit | No | |
Equipo | force | Yes | |
Eslarc | unit | No | |
finish | boolean | No | |
FL_SKIN_1 | integer | Yes | |
FL_SKIN_2 | integer | Yes | |
FL_SKIN_3 | integer | Yes | |
FL_SKIN_4 | integer | Yes | |
FN_EQUIP | integer | Yes | |
FoK_Ability_Damage | abilcode | No | |
FoK_Caster | unit | No | |
FoK_Level | integer | No | |
FoK_Owner | player | No | |
FoK_Position | location | No | |
FoK_Target_Point | location | No | |
Found_Index | integer | No | |
Found_Range | integer | No | |
Fristbloodgiven | boolean | No | |
FS_Location | location | No | |
FS_Target | unit | No | |
FWGroup | group | No | |
FWID | integer | No | |
GameCountdown | timer | No | |
GameCountdownWindow | timerdialog | No | |
GameTime | real | No | |
GB_Caster | unit | No | |
GB_FX | effect | No | |
GB_HPDamage | real | No | |
GB_MaxHp | integer | No | |
GB_Roll | integer | No | |
GB_Target | unit | No | |
GenericTimer | timer | No | |
get_boolean | boolean | Yes | |
get_destructible | destructable | Yes | |
get_effect | effect | Yes | |
get_group | group | Yes | |
get_integer | integer | Yes | |
get_player | player | Yes | |
get_point | location | Yes | |
get_real | real | Yes | |
get_unit | unit | Yes | |
GI_Count | integer | No | |
GI_Grass | unit | Yes | |
GI_GrassGroup | group | No | |
GI_GrassRadius | real | No | |
GI_GrassUnitType | unitcode | No | |
GI_Index | integer | No | |
GI_InvisGroup | group | No | |
GOLDEFFECT | effect | No | |
GoldString | string | No | |
group | group | No | |
GuardiaIntergerA | integer | Yes | |
GuardiaIntergerB | integer | Yes | |
H_EQUIP | integer | Yes | |
H_SKIN_1 | integer | Yes | |
H_SKIN_2 | integer | Yes | |
HASHASSIST | hashtable | No | |
hashtable | hashtable | No | |
HASSUPPORT | hashtable | No | |
heal_amount | real | No | |
heal_check | boolean | No | |
HEAL_CHECK_INTERVAL | real | No | |
heal_count | integer | No | |
heal_diff | real | No | |
heal_exitwhen | integer | No | |
heal_indexRef | integer | Yes | |
heal_indices | integer | Yes | |
heal_inSys | boolean | Yes | |
heal_integer | integer | No | |
heal_lastLife | real | Yes | |
heal_life | real | No | |
heal_regen | real | Yes | |
heal_source | unit | No | |
heal_target | unit | No | |
HEAL_THRESHOLD | real | No | |
heal_timer | timer | No | |
HealEvent | real | No | |
HealingSpell | abilcode | Yes | |
Hero | unit | Yes | |
Hero1 | unit | No | UnitNull |
Hero10 | unit | No | UnitNull |
Hero10Lvl | integer | No | |
Hero10Type | unitcode | No | |
Hero1Lvl | integer | No | |
Hero1Type | unitcode | No | |
Hero2 | unit | No | UnitNull |
Hero2Lvl | integer | No | |
Hero2Type | unitcode | No | |
Hero3 | unit | No | UnitNull |
Hero3Lvl | integer | No | |
Hero3Type | unitcode | No | |
Hero4 | unit | No | UnitNull |
Hero4Lvl | integer | No | |
Hero4Type | unitcode | No | |
Hero5 | unit | No | UnitNull |
Hero5Lvl | integer | No | |
Hero5Type | unitcode | No | |
Hero6 | unit | No | UnitNull |
Hero6Lvl | integer | No | |
Hero6Type | unitcode | No | |
Hero7 | unit | No | UnitNull |
Hero7Lvl | integer | No | |
Hero7Type | unitcode | No | |
Hero8 | unit | No | UnitNull |
Hero8Lvl | integer | No | |
Hero8Type | unitcode | No | |
Hero9 | unit | No | UnitNull |
Hero9Lvl | integer | No | |
Hero9Type | unitcode | No | |
Hero_Random | unitcode | Yes | |
HeroDummy | unit | Yes | |
HeroesSelected | group | No | |
HeroIsDeadT | timer | Yes | |
HeroIsDeadW | timerdialog | Yes | |
HeroLevel | integer | Yes | |
HeroLevelExperience | integer | No | |
HeroList | integer | No | |
HeroPlayer | unit | Yes | |
HeroPoll | unitcode | Yes | |
HeroStrengthStore2 | unit | No | |
HitMultiplier | integer | Yes | |
HolyBoltArea | group | No | |
HolyBoltCaster | unit | No | |
HolyBoltPoint | location | No | |
HolyBoltTarget | unit | No | |
HordeBottonGroup | group | Yes | |
HordeMidGroup | group | Yes | |
HordeTopGroup | group | Yes | |
instanceCount | integer | No | |
integer | integer | No | |
integer2 | integer | No | |
integer3 | integer | No | |
Integer_TowerRangeIndex | integer | No | |
IntelligenceStoreBlue | unit | Yes | |
IntelligenceStoreRed | unit | Yes | |
isAttackingRoshan | boolean | Yes | |
isCreeping | boolean | Yes | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
IsDamageSpell_Copy | boolean | No | |
isDefendingBase | boolean | Yes | |
isEngaging | boolean | Yes | |
isFarming | boolean | Yes | |
isFountainSafe | boolean | Yes | |
isGanking | boolean | Yes | |
isHealing | boolean | Yes | |
isKiting | boolean | Yes | |
isRetreating | boolean | Yes | |
IsUnitAlive | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
Item_CanBeDisassemble | boolean | Yes | |
Item_Check | integer | No | |
Item_Count | integer | No | |
Item_CustomValue | integer | No | |
Item_DisassembleAbility | abilcode | No | |
Item_DisassembleEffect | string | No | |
Item_DisassemblePoint | location | Yes | |
Item_Effect | string | No | |
Item_EnableOS | boolean | No | |
Item_Fake | itemcode | Yes | |
Item_Given | item | No | |
Item_LoopA | integervar | No | |
Item_LoopB | integervar | No | |
Item_LoopC | integervar | No | |
Item_Mat1 | itemcode | Yes | |
Item_Mat1Amount | integer | Yes | |
Item_Mat2 | itemcode | Yes | |
Item_Mat2Amount | integer | Yes | |
Item_Mat3 | itemcode | Yes | |
Item_Mat3Amount | integer | Yes | |
Item_Mat4 | itemcode | Yes | |
Item_Mat4Amount | integer | Yes | |
Item_Mat5 | itemcode | Yes | |
Item_Mat5Amount | integer | Yes | |
Item_MatMax | integer | Yes | |
Item_Max | integer | No | |
Item_Owner | player | Yes | |
Item_OwneredItem | item | Yes | |
Item_OwnershipException | group | No | |
Item_Point | location | Yes | |
Item_Real | itemcode | Yes | |
Item_RecipeMax | integer | No | |
Item_Result | itemcode | Yes | |
Item_ToGive | item | No | |
ItemRandomizer | integer | No | |
ItemRune | itemcode | Yes | |
JungleCampLocations | location | Yes | |
KEMPY_Punto | location | No | |
KillCount | integer | Yes | |
KillingPlayer | integer | No | |
KillingPlayerP | player | No | |
Killstreak | integer | Yes | |
KillStreakGold | integer | Yes | |
KillTimer | timer | Yes | |
KillTimerWindow | real | No | |
LargeCamp | group | Yes | |
LasHitPlayer | player | No | |
LasKillTime | real | Yes | |
LastCreatedUnit | unit | No | |
LastDamageHP | real | No | |
LastDmgPrevAmount | real | Yes | |
LastDmgPrevType | integer | Yes | |
LastDmgSource | unit | Yes | |
LastDmgTarget | unit | Yes | |
LastDmgValue | real | Yes | |
LastDmgWasSpell | boolean | Yes | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
LG_EQUIP | integer | Yes | |
LG_SKIN_1 | integer | Yes | |
LG_SKIN_2 | integer | Yes | |
limit | integer | No | |
LK_EQUIP | integer | Yes | |
LK_SKIN_1 | integer | Yes | |
LK_SKIN_2 | integer | Yes | |
LK_SKIN_3 | integer | Yes | |
LLuvia | weathereffect | No | |
LocalFiles_WarningMessage | string | No | |
LOOP | integervar | No | |
LuzTenueEscudo | integer | Yes | |
LuzTenueGroup | group | No | |
LuzTenueTarget | unit | Yes | |
MaelstromDummy | integer | No | |
MagicShield | integer | Yes | |
Manacost | integer | No | |
ManacostReal | real | No | |
MapName | string | No | |
MaxHealth | real | Yes | |
MaxManaBonus | integer | No | |
MaxManaDMG | real | No | |
MDMG_Resistance | real | No | |
MedallonGroup | group | No | |
MedallonSanto | item | Yes | |
MediumCamp | group | Yes | |
MidDireGroup | group | No | |
MidLane | boolean | Yes | |
MidRadiantGroup | group | No | |
Misha | unit | No | |
MK_EQUIP | integer | Yes | |
MK_SKIN_1 | integer | Yes | |
MK_SKIN_2 | integer | Yes | |
MK_SKIN_3 | integer | Yes | |
MK_SKIN_4 | integer | Yes | |
MMRCalculation | real | No | |
MMRDifference | real | No | |
MMRLossers | integer | No | |
MMRWinners | integer | No | |
MR_Unit | unit | No | |
mui_boolean | boolean | Yes | |
mui_destructible | destructable | Yes | |
mui_effect | effect | Yes | |
mui_group | group | Yes | |
mui_integer | integer | Yes | |
mui_player | player | Yes | |
mui_point | location | Yes | |
mui_real | real | Yes | |
mui_unit | unit | Yes | |
mui_used_booleans | integer | Yes | |
mui_used_destructibles | integer | Yes | |
mui_used_effects | integer | Yes | |
mui_used_groups | integer | Yes | |
mui_used_integers | integer | Yes | |
mui_used_players | integer | Yes | |
mui_used_points | integer | Yes | |
mui_used_reals | integer | Yes | |
mui_used_units | integer | Yes | |
MultiboardB | multiboard | No | |
MultiboardS | multiboard | No | |
MultiKillCount | integer | Yes | |
MyriadC_Ability | abilcode | No | |
MyriadC_AT | attacktype | No | |
MyriadC_CasterUnit | unit | No | |
MyriadC_CrystalDamage | real | Yes | |
MyriadC_CrystalFreezeDur | real | Yes | |
MyriadC_CrystalLaunch | integer | No | |
MyriadC_CrystalLaunched | integer | Yes | |
MyriadC_CrystalPerWave | integer | Yes | |
MyriadC_CrystalRainDuration | real | Yes | |
MyriadC_DamageArea | real | Yes | |
MyriadC_DelayCrystalImpact | real | Yes | |
MyriadC_DelayPerWave | real | Yes | |
MyriadC_DT | damagetype | No | |
MyriadC_FieldSFX | string | No | |
MyriadC_FieldSFXAreaFactor | real | No | |
MyriadC_FreezeSFX | string | No | |
MyriadC_FreezeSFXAttachPoint | string | No | |
MyriadC_ImpactSFX | string | No | |
MyriadC_InitialDelay | real | Yes | |
MyriadC_Level | integer | No | |
MyriadC_MaxCrystal | integer | Yes | |
MyriadC_RainArea | real | Yes | |
MyriadC_RainSFX | string | No | |
MyriadC_RainSFXAreaFactor | real | No | |
MyriadC_TargetGroup | group | No | |
MyriadC_TargetUnit | unit | No | |
MyriadC_TargetValid | boolean | No | |
Neblina | weathereffect | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageOverride | boolean | No | |
NextDamageType | integer | No | |
NextDamageType_Copy | integer | No | |
NextDamageWeaponT | integer | No | |
NextHealAmount | real | No | |
NextHealSource | unit | No | |
NextHealTarget | unit | No | |
NextItemsSecret | unit | Yes | |
NextRainDelay | real | No | |
NorthRune | item | No | |
NullTalismanMana | integer | Yes | |
OA_Caster | unit | No | |
OA_Timer | timer | No | |
OceanicAttackTarget | unit | No | |
OLEADAS_Reloj | timer | Yes | |
OnCooldown | boolean | Yes | |
OnDamageEvent | real | No | |
OrchidDamageStore | real | Yes | |
OrchidTarget | unit | No | |
OverheadNames | effect | Yes | |
P_CURRENCY | integer | Yes | |
ParasmaUser | unit | Yes | |
PCourier | unit | Yes | |
PG_Active_Users | force | No | |
PG_All_Users | force | No | |
PG_Leavers | force | No | |
Pipa_Aura_Group | group | No | |
player | player | No | |
Player1 | player | No | Player01 |
Player10 | player | No | Player11 |
Player2 | player | No | Player02 |
Player3 | player | No | Player03 |
Player4 | player | No | Player04 |
Player5 | player | No | Player05 |
Player6 | player | No | Player07 |
Player7 | player | No | Player08 |
Player8 | player | No | Player09 |
Player9 | player | No | Player10 |
player_force | force | No | |
Player_MMR | integer | Yes | |
Player_Transfering | force | No | |
PlayerAssist | integer | Yes | |
PlayerColor | string | Yes | |
PlayerDeaths | integer | Yes | |
PlayerHasSelected | boolean | Yes | |
PlayerIndex | integer | No | |
PlayerKills | integer | Yes | |
PlayerName | string | Yes | |
PlayerRow | integer | No | |
PlayerTeam | integer | No | |
PlayerValue | integer | No | |
PN | integer | No | |
Point_TowerRange | location | No | |
PointAbsorcion | location | No | |
PointRune | location | Yes | |
PowerStoreBlue | unit | Yes | |
PowerStoreRed | unit | Yes | |
PreDamageEvent | real | No | |
ProtectTarget | unit | Yes | |
ProtegerEscudo | integer | Yes | |
PUNTO_ATK | location | Yes | |
PUNTO_Base | location | Yes | |
Punto_Externo | location | No | |
Punto_Externo2 | location | No | |
RadiantUnit | unit | Yes | |
RainCooldown | real | No | |
RainDuration | real | No | |
Raining | boolean | No | |
RandomHero | unitcode | No | |
Randomizer | integer | No | |
RandomRainTime | real | No | |
RandomVarMaelstrom | integer | No | |
RBottomBaseTower1 | unit | No | |
RBottomBaseTower2 | unit | No | |
RBottomBaseTower3 | unit | No | |
RBottomBaseTower4 | unit | No | |
RCoreTower1 | unit | No | |
RCoreTower2 | unit | No | |
Real_Externo | real | No | |
Real_TotalTowerRange | real | No | |
Reals_CollisionSize | real | Yes | |
Reals_TowerRangeSize | real | Yes | |
RecoverTranquilBoots | boolean | Yes | |
recycle | integer | No | |
recycleNext | integer | Yes | |
RED_CantidadMelee | integer | Yes | 3 |
RED_CantidadRango | integer | Yes | 1 |
RED_Grupos | group | Yes | |
RED_Spawn | location | Yes | |
RED_TipoUnidad_ASEDIO | unitcode | Yes | |
RED_TipoUnidad_MELEE | unitcode | Yes | |
RED_TipoUnidad_RANGO | unitcode | Yes | |
REffigy1 | unit | No | |
REffigy2 | unit | No | |
REffigy3 | unit | No | |
REffigy4 | unit | No | |
REffigy5 | unit | No | |
REffigy6 | unit | No | |
regen_buildup | real | Yes | |
REGEN_EVENT_INTERVAL | real | No | |
REGEN_STRENGTH_VALUE | real | No | |
REGEN_THRESHOLD | real | No | |
regen_timeleft | real | Yes | |
RemoveDamageEvent | boolean | No | |
Reporting | boolean | No | |
ReportLife | real | No | |
Reserve_Circle | unit | Yes | |
ResurrectionCountdown | timer | Yes | |
ResurrectionTimer | timer | Yes | |
ResurrectionTimerW | timerdialog | Yes | |
RevivialInterger | integer | Yes | |
Reward | integer | No | |
RMegaCreepsON | boolean | No | |
RMeleBarrak1 | unit | No | |
RMeleBarrak2 | unit | No | |
RMeleBarrak3 | unit | No | |
RMidBaseTower1 | unit | No | |
RMidBaseTower2 | unit | No | |
RMidBaseTower3 | unit | No | |
RMidBaseTower4 | unit | No | |
RomperUnit | unit | Yes | |
RRangeBarrak1 | unit | No | |
RRangeBarrak2 | unit | No | |
RRangeBarrak3 | unit | No | |
RShrine | unit | No | |
RTopBaseTower1 | unit | No | |
RTopBaseTower2 | unit | No | |
RTopBaseTower3 | unit | No | |
RTopBaseTower4 | unit | No | |
SacredShield_Ability | abilcode | No | |
SacredShield_Duration | real | Yes | |
SacredShield_Group | group | No | |
SacredShield_Index | integer | No | |
SacredShield_IntMultiplier | real | Yes | |
SacredShield_Level | integer | No | |
SacredShield_RemDuration | real | Yes | |
SacredShield_RemVal | real | Yes | |
SacredShield_SFX | string | No | |
SacredShield_SFXAttach | string | No | |
SacredShield_SpcEffect | effect | Yes | |
SacredShield_Timeout | real | No | |
SacredShield_Timer | timer | No | |
SacredShield_Unit | unit | No | |
SafeFountainLocation | location | Yes | |
SafeLocation | location | Yes | |
Save_Loop_A | integer | No | |
Save_Loop_B | integer | No | |
SaveCount | integer | No | |
SaveCurrentSlot | integer | Yes | |
SaveLoadEvent | real | No | |
SaveLoadEvent_Code | string | No | |
SaveLoadEvent_Player | player | No | |
SaveLoadEvent_PN | integer | No | |
SaveMaxValue | integer | Yes | |
SavePlayerLoading | boolean | Yes | |
SaveTempInt | integer | No | |
SaveTempString | string | No | |
SaveValue | integer | Yes | |
SelecctionCircle | unit | Yes | |
SelectedHeroesGroup | group | No | |
set_boolean | boolean | Yes | |
set_destructible | destructable | Yes | |
set_effect | effect | Yes | |
set_group | group | Yes | |
set_integer | integer | Yes | |
set_player | player | Yes | |
set_point | location | Yes | |
set_real | real | Yes | |
set_unit | unit | Yes | |
SFX | effect | Yes | |
ShadowFX | effect | No | |
ShadowFX1 | effect | No | |
ShineShield | integer | Yes | |
ShineTarget | unit | Yes | |
ShinteTimer | timer | No | |
Skill | abilcode | No | |
Skill_Copy | ability | No | |
SKIN_FX_P | location | No | |
SKIN_SHOP | unit | Yes | |
SmallCamp | group | Yes | |
SourceDamageEvent | real | No | |
SouthRune | item | No | |
SpellDamageAbility | abilcode | No | |
SprayCaster | unit | No | |
SS_Roll | integer | No | |
SS_Target | unit | No | |
StormPlayer | player | No | Player00 |
Streak | integer | No | |
StreakGold | integer | No | |
StrengthStoreBlue | unit | Yes | |
StrengthStoreRed | unit | Yes | |
string | string | No | |
string2 | string | No | |
StunSnippet__AttachPoint | string | No | |
StunSnippet__Duration | real | No | |
StunSnippet__SFX | string | No | |
StunSnippet__StunnedUnit | unit | No | |
StunSnippet_CurrentUnit | unit | No | |
StunSnippet_DEFAULTAttachPoint | string | No | |
StunSnippet_DEFAULTSFX | string | No | |
StunSnippet_OnEventEnd | trigger | No | |
StunSnippet_OnEventLoop | trigger | No | |
StunSnippet_OnEventStart | trigger | No | |
StunSnippet_TEnd | trigger | No | |
StunSnippet_TLoop | trigger | No | |
StunSnippet_TRegister | trigger | No | |
StunSnippet_TStart | trigger | No | |
SUP_Default_AfectaAereas | boolean | No | |
SUP_Default_AfectaEstructuras | boolean | No | |
SUP_Default_AfectaInmuneAMagia | boolean | No | |
SUP_Default_AfectaInvisibles | boolean | No | |
SUP_Default_Altura_Final | real | No | |
SUP_Default_Altura_Inicial | real | No | |
SUP_Default_AoE | real | No | |
SUP_Default_AoE_Final | real | No | |
SUP_Default_Arco | real | No | |
SUP_Default_CuraAliados | boolean | No | |
SUP_Default_CuracionAoE | real | No | |
SUP_Default_CuracionTarget | real | No | |
SUP_Default_DamageAoE | real | No | |
SUP_Default_DamageTarget | real | No | |
SUP_Default_DamageType | attacktype | No | |
SUP_Default_DaniaAliados | boolean | No | |
SUP_Default_DummyBlue | real | No | |
SUP_Default_DummyGreen | real | No | |
SUP_Default_DummyRed | real | No | |
SUP_Default_DummySize | real | No | |
SUP_Default_DummyTransparency | real | No | |
SUP_Default_IgnorarReduccion | boolean | No | |
SUP_Default_Model | string | No | |
SUP_Default_OnAoEHit_Model | string | No | |
SUP_Default_OnTargetHit_Model | string | No | |
SUP_Default_OrderString | string | No | |
SUP_Default_SetTargetAlChocar | boolean | No | |
SUP_Default_Speed | real | No | |
SUP_Default_TerminarAlChocar | boolean | No | |
SUP_Get_Caster | unit | No | |
SUP_Local_Altura | real | No | |
SUP_Local_Angle | real | No | |
SUP_Local_Angle_Z | real | No | |
SUP_Local_Booleana_Auxiliar | boolean | No | |
SUP_Local_DifAltura | real | No | |
SUP_Local_Distancia | real | No | |
SUP_Local_EsAfectada | boolean | No | |
SUP_Local_ForLoop | integer | No | |
SUP_Local_Group | group | No | |
SUP_Local_Jugador | player | No | |
SUP_Local_Point | location | No | |
SUP_Local_Point2 | location | No | |
SUP_Local_Real_Auxiliar | real | No | |
SUP_Private_AfectaAereas | boolean | Yes | |
SUP_Private_AfectaEstructuras | boolean | Yes | |
SUP_Private_AfectaInmuneAMagia | boolean | Yes | |
SUP_Private_AfectaInvisibles | boolean | Yes | |
SUP_Private_AoE | real | Yes | |
SUP_Private_AoE_Final | real | Yes | |
SUP_Private_Arco | real | Yes | |
SUP_Private_Caster | unit | Yes | |
SUP_Private_CuraAliados | boolean | Yes | |
SUP_Private_CuracionAoE | real | Yes | |
SUP_Private_CuracionTarget | real | Yes | |
SUP_Private_DamageAoE | real | Yes | |
SUP_Private_DamageStyle | damagetype | Yes | |
SUP_Private_DamageTarget | real | Yes | |
SUP_Private_DamageType | attacktype | Yes | |
SUP_Private_DaniaAliados | boolean | Yes | |
SUP_Private_Dummy | unit | Yes | |
SUP_Private_Dummy_Z | real | Yes | |
SUP_Private_DummyAbility | abilcode | Yes | |
SUP_Private_DummyAbilNivel | integer | Yes | |
SUP_Private_Effect | effect | Yes | |
SUP_Private_Enteros | integer | Yes | |
SUP_Private_Group | group | Yes | |
SUP_Private_IsActive | boolean | Yes | |
SUP_Private_OnAoEHit_Model | string | Yes | |
SUP_Private_OnTargetHit_Model | string | Yes | |
SUP_Private_OrderString | string | Yes | |
SUP_Private_SetTargetOnLoop | boolean | Yes | |
SUP_Private_Speed | real | Yes | |
SUP_Private_SpeedZ | real | Yes | |
SUP_Private_Target | unit | Yes | |
SUP_Private_TargetPoint | location | Yes | |
SUP_Private_TerminarAlChocar | boolean | Yes | |
SUP_Private_Time | real | Yes | |
SUP_Private_ZTarget | real | Yes | |
SUP_Set_AfectaAereas | boolean | No | |
SUP_Set_AfectaEstructuras | boolean | No | |
SUP_Set_AfectaInmuneAMagia | boolean | No | |
SUP_Set_AfectaInvisibles | boolean | No | |
SUP_Set_Altura_Final | real | No | |
SUP_Set_Altura_Inicial | real | No | |
SUP_Set_AoE | real | No | |
SUP_Set_AoE_Final | real | No | |
SUP_Set_Arco | real | No | |
SUP_Set_Caster | unit | No | |
SUP_Set_CuraAliados | boolean | No | |
SUP_Set_CuracionAoE | real | No | |
SUP_Set_CuracionTarget | real | No | |
SUP_Set_DamageAoE | real | No | |
SUP_Set_DamageTarget | real | No | |
SUP_Set_DamageType | attacktype | No | |
SUP_Set_DaniaAliados | boolean | No | |
SUP_Set_DummyAbility | abilcode | No | |
SUP_Set_DummyAbilNivel | integer | No | |
SUP_Set_DummyBlue | real | No | |
SUP_Set_DummyGreen | real | No | |
SUP_Set_DummyRed | real | No | |
SUP_Set_DummySize | real | No | |
SUP_Set_DummyTransparency | real | No | |
SUP_Set_IgnorarReduccion | boolean | No | |
SUP_Set_Model | string | No | |
SUP_Set_OnAoEHit_Model | string | No | |
SUP_Set_OnTargetHit_Model | string | No | |
SUP_Set_OrderString | string | No | |
SUP_Set_PuntoInicial | location | No | |
SUP_Set_PuntoObjetivo | location | No | |
SUP_Set_SetTargetAlChocar | boolean | No | |
SUP_Set_Speed | real | No | |
SUP_Set_Target | unit | No | |
SUP_Set_TerminarAlChocar | boolean | No | |
TargetUnit | unit | No | |
TarrasqueGrup | group | No | |
TarrasqueRegen | real | Yes | |
TavernHero | unitcode | No | |
TavernRegion | rect | No | |
TB_Area | location | No | |
TB_Grupo | group | No | |
Team | force | Yes | |
Team1MMR | integer | No | |
Team2MMR | integer | No | |
Teleport | effect | Yes | |
TELL__AllocDuration | real | No | |
TELL__AllocLoopTimer | real | No | |
TELL__Duration | real | No | |
TELL__Index | integer | No | |
TELL__LoopTimer | real | No | |
TELL_Duration | real | Yes | |
TELL_InitializationFinish | real | No | |
TELL_Instance | integer | No | |
TELL_InstanceIterator | integer | No | |
TELL_Last | integer | No | |
TELL_MaxIndex | integer | No | |
TELL_Next | integer | Yes | |
TELL_OnEventDealloc | trigger | Yes | |
TELL_OnEventLoop | trigger | Yes | |
TELL_OnEventLoopDuration | real | Yes | |
TELL_OnEventLoopTimer | real | Yes | |
TELL_Prev | integer | Yes | |
TELL_RecycleSize | integer | No | |
TELL_RecycleStack | integer | Yes | |
TELL_RegisterID | integer | No | |
TELL_TempID | integer | No | |
TELL_Timer | timer | No | |
TELL_TimerTIMEOUT | real | No | |
TELL_TriggerEmptyEvent | trigger | No | |
TELL_TriggerLoop | trigger | No | |
TELL_TriggerRegister | trigger | No | |
TELLDebugMode | boolean | No | |
TELLDuration | real | No | |
TELLOnEventAlloc | trigger | No | |
TELLOnEventDealloc | trigger | No | |
TELLOnEventLoop | trigger | No | |
TELLOnEventLoopTimer | real | No | |
TempAIGroup | group | Yes | |
TempForce | force | No | |
TempGroup | group | No | |
TempGroup2 | integer | No | |
TempGroup_Spray | group | No | |
TempGroup_Totem | group | No | |
TempGroup_Tranquilidad | group | No | |
TempInt | integer | No | |
TempInteger | integer | No | |
TempItem | item | No | |
TempLoc | location | No | |
TemPoint_Spray | location | No | |
TemPoint_Totem | location | No | |
TempPlayer | player | No | |
TempPoint | location | No | |
TempReal | real | No | |
TempReal2 | real | No | |
TempUnit | unit | No | |
TempUnit_Copy | unit | No | |
TidalChase | group | No | |
timeout | real | No | |
TIMER_ASSIST | integer | No | |
TIMER_SUPPORT | integer | No | |
TimerRevival | real | No | |
TopDireGroup | group | No | |
TopLane | boolean | Yes | |
TopRadiantGroup | group | No | |
TotemCaster | unit | No | |
TP_Caster | unit | No | |
TP_FX | effect | No | |
TP_Timer | timer | No | |
TPpoint | location | Yes | |
Tranquil_Caster | unit | No | |
Transport_Active | boolean | No | |
Tree | destructable | Yes | |
TreeFX | effect | Yes | |
TreeIndex01 | integer | No | |
TreeIndex02 | integer | No | |
TreesCoundown | timer | No | |
TreeTempPoint | location | No | |
trigger | trigger | No | |
TriggeringPlayer | player | Yes | |
TriggeringPlayerValue | integer | No | |
TriggeringUnit | unit | No | |
TSE__ActiveIndex | integer | No | |
TSE__Point | location | No | |
TSE__RemainingDuration | real | No | |
TSE__SourceUnit | unit | No | |
TSE__SpecialEffect | effect | No | |
TSE__TargetUnit | unit | No | |
TSE_CTimer | timer | No | |
TSE_EmptyEvent | trigger | No | |
TSE_I_ActiveInstance | boolean | Yes | |
TSE_I_ChanneledOrderID | string | Yes | |
TSE_I_Effect | effect | Yes | |
TSE_I_IsChanneling | boolean | Yes | |
TSE_I_LockInstance | boolean | Yes | |
TSE_I_LoopDuration | real | Yes | |
TSE_I_OnEndEvent | trigger | Yes | |
TSE_I_OnLoopEvent | trigger | Yes | |
TSE_I_OnLoopTimer | real | Yes | |
TSE_I_Point | location | Yes | |
TSE_I_RemainingDuration | real | Yes | |
TSE_I_SourceUnit | unit | Yes | |
TSE_I_SourceUnitAliveCheck | boolean | Yes | |
TSE_I_TargetUnit | unit | Yes | |
TSE_I_TargetUnitAliveCheck | boolean | Yes | |
TSE_I_UnitAliveCheck | boolean | Yes | |
TSE_Index | integer | No | |
TSE_LoopTrigger | trigger | No | |
TSE_MaxCheckOver | boolean | No | |
TSE_MaxIndex | integer | No | |
TSE_MaxRecursion | integer | No | |
TSE_Recursion | integer | No | |
TSE_RegisterTrigger | trigger | No | |
TSE_ReplacementIndex | integer | No | |
TSE_ReplacementIndexFound | boolean | No | |
TSE_TIMEOUT | real | No | |
TSEAttachPoint | string | No | |
TSEChanneledOrderID | string | No | |
TSEDuration | real | No | |
TSEEffectName | string | No | |
TSELL__ActiveIndex | integer | No | |
TSELL__AllocActiveIndex | integer | No | |
TSELL__AllocInteger | integer | No | |
TSELL__AllocLoopTimer | real | No | |
TSELL__AllocPoint | location | No | |
TSELL__AllocRemainingDuration | real | No | |
TSELL__AllocSourceUnit | unit | No | |
TSELL__AllocSpecialEffect | effect | No | |
TSELL__AllocTargetUnit | unit | No | |
TSELL__Integer | integer | No | |
TSELL__LoopTimer | real | No | |
TSELL__Point | location | No | |
TSELL__RemainingDuration | real | No | |
TSELL__SourceUnit | unit | No | |
TSELL__SpecialEffect | effect | No | |
TSELL__TargetUnit | unit | No | |
TSELL_AttachPoint | string | No | |
TSELL_ChanneledOrderID | string | No | |
TSELL_DebugMode | boolean | No | |
TSELL_Duration | real | No | |
TSELL_EffectName | string | No | |
TSELL_EmptyEvent | trigger | No | |
TSELL_I_ChanneledOrderID | string | Yes | |
TSELL_I_Integer | integer | Yes | |
TSELL_I_IsChanneling | boolean | Yes | |
TSELL_I_OnEndEvent | trigger | Yes | |
TSELL_I_OnLoopEvent | trigger | Yes | |
TSELL_I_OnLoopTimer | real | Yes | |
TSELL_I_Point | location | Yes | |
TSELL_I_SourceUnit | unit | Yes | |
TSELL_I_SourceUnitAliveCheck | boolean | Yes | |
TSELL_I_SpecialEffect | effect | Yes | |
TSELL_I_TargetUnit | unit | Yes | |
TSELL_I_TargetUnitAliveCheck | boolean | Yes | |
TSELL_Index | integer | No | |
TSELL_Integer | integer | No | |
TSELL_MaxIndex | integer | No | |
TSELL_OnEventAllocate | trigger | No | |
TSELL_OnEventDeallocate | trigger | No | |
TSELL_OnEventLoop | trigger | No | |
TSELL_Point | location | No | |
TSELL_Scale | real | No | |
TSELL_SourceUnit | unit | No | |
TSELL_SourceUnitAliveCheck | boolean | No | |
TSELL_TargetUnit | unit | No | |
TSELL_TargetUnitAliveCheck | boolean | No | |
TSELL_TimerForLoop | real | No | |
TSELL_TriggerAllocation | trigger | No | |
TSELL_TriggerDeallocation | trigger | No | |
TSELL_TriggerLoop | trigger | No | |
TSELL_TriggerRegister | trigger | No | |
TSELockInstance | boolean | No | |
TSEOnEndEvent | trigger | No | |
TSEOnIndexEvent | trigger | No | |
TSEOnLoopEvent | trigger | No | |
TSEOnLoopTimer | real | No | |
TSEPoint | location | No | |
TSEScale | real | No | |
TSESourceUnit | unit | No | |
TSESourceUnitAliveCheck | boolean | No | |
TSETargetUnit | unit | No | |
TSETargetUnitAliveCheck | boolean | No | |
TSEUnit | unit | No | |
TSEUnitAliveCheck | boolean | No | |
UDex | integer | No | |
UDex_Copy | integer | No | |
UDexGen | integer | No | |
UDexGen_Copy | integer | No | |
UDexNext | integer | Yes | |
UDexNext_Copy | integer | Yes | |
UDexPrev | integer | Yes | |
UDexPrev_Copy | integer | Yes | |
UDexRecycle | integer | No | |
UDexRecycle_Copy | integer | No | |
UDexUnits | unit | Yes | |
UDexUnits_Copy | unit | Yes | |
UDexWasted | integer | No | |
UDexWasted_Copy | integer | No | |
Ufgark_C | unit | No | |
Ufgark_P | location | No | |
UG_Heroes | group | Yes | |
unit | unit | No | |
unit2 | unit | No | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
UnitDamageRegistered | boolean | Yes | |
UnitIndexerEnabled | boolean | No | |
UnitIndexerEnabled_Copy | boolean | No | |
UnitIndexEvent | real | No | |
UnitIndexEvent_Copy | real | No | |
UnitIndexLock | integer | Yes | |
UnitIndexLock_Copy | integer | Yes | |
UnitTypeEvent | real | No | |
UnitTypes_TowerRange | unitcode | Yes | |
UnselecctedHeroesGroup | group | No | |
used_booleans | integer | No | |
used_destructibles | integer | No | |
used_effects | integer | No | |
used_groups | integer | No | |
used_integers | integer | No | |
used_players | integer | No | |
used_points | integer | No | |
used_reals | integer | No | |
used_units | integer | No | |
User | string | No | |
Usuario | string | Yes | |
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 | |
WH_Point | location | No | |
WORLD_BORDER_MAX_X | real | No | |
WORLD_BORDER_MAX_Y | real | No | |
WORLD_BORDER_MIN_X | real | No | |
WORLD_BORDER_MIN_Y | real | No | |
WORLD_BORDER_WIDTH | real | No | |
WR_FX | effect | No | |
Your_Courier_FirstPoint | location | Yes | |
Your_HeroTempPoint | location | No | |
YourCourier | unit | Yes | |
YourHero | unit | Yes | |
ZeroDamageEvent | real | No |
library SaveHelperLib initializer Init requires SyncHelper, PlayerUtils, SaveFile
// Uses GUI variables from the "Save Init" trigger. You can modify these functions to use your own variables.
private keyword SaveHelperInit
struct SaveHelper extends array
static method IsUserLoading takes User user returns boolean
return udg_SavePlayerLoading[user.id]
endmethod
static method SetUserLoading takes User user, boolean flag returns nothing
set udg_SavePlayerLoading[user.id] = flag
endmethod
static method SetSaveSlot takes User user, integer slot returns nothing
set udg_SaveCurrentSlot[user.id] = slot
endmethod
static method GetMapName takes nothing returns string
return udg_MapName
endmethod
static method GUILoadNext takes nothing returns nothing
set udg_SaveValue[udg_SaveCount] = Savecode(udg_SaveTempInt).Decode(udg_SaveMaxValue[udg_SaveCount])
endmethod
endstruct
private function LoadSaveSlot_OnLoad takes nothing returns nothing
local player p = GetTriggerPlayer()
local string prefix = BlzGetTriggerSyncPrefix()
local string data = BlzGetTriggerSyncData()
local User user = User[p]
call SaveHelper.SetUserLoading(user, false)
set udg_SaveLoadEvent_Code = data
set udg_SaveLoadEvent_Player = p
set udg_SaveLoadEvent = 1.
set udg_SaveLoadEvent = -1
endfunction
function LoadSaveSlot takes player p, integer slot returns nothing
local SaveFile savefile = SaveFile(slot)
local string s
local User user = User[p]
if (SaveHelper.IsUserLoading(user)) then
call DisplayTextToPlayer(p, 0, 0, "Please wait while your MMR syncs.")
else
set s = savefile.getData()
if s != null then
if (GetLocalPlayer() == p) then
call SyncString(s)
endif
call ClearTextMessages()
call DisplayTimedTextToPlayer(p, 0, 0, 15, "Synchronizing with other players...")
call SaveHelper.SetSaveSlot(user, slot)
else
call DisplayTimedTextToPlayer(p, 0, 0, 12, "The file |cff00ff00Saved|r could not be found.")
endif
endif
endfunction
private function Init takes nothing returns nothing
call OnSyncString(function LoadSaveSlot_OnLoad)
endfunction
endlibrary
library SyncHelper
globals
public constant string SYNC_PREFIX = "S"
endglobals
private keyword INITS
private struct Sync extends array
static trigger Trigger = CreateTrigger()
implement INITS
endstruct
function SyncString takes string s returns boolean
return BlzSendSyncData(SYNC_PREFIX, s)
endfunction
function OnSyncString takes code func returns triggeraction
return TriggerAddAction(Sync.Trigger, func)
endfunction
function RemoveSyncString takes triggeraction t returns nothing
call TriggerRemoveAction(Sync.Trigger, t)
endfunction
private module INITS
private static method onInit takes nothing returns nothing
local integer i = 0
loop
call BlzTriggerRegisterPlayerSyncEvent(.Trigger, Player(i), SYNC_PREFIX, false)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
endmethod
endmodule
endlibrary
library SaveFile requires FileIO
private keyword SaveFileInit
struct SaveFile extends array
static constant string ManualPath = "Manual"
static constant string InvalidPath = "Unknown"
static constant integer MIN = 1
static constant integer MAX = 12
private File file
static method operator Folder takes nothing returns string
return udg_MapName
endmethod
static method getPath takes integer slot returns string
if (slot == 0) then
return .Folder + "\\SaveSlot_" + .InvalidPath + ".pld"
elseif (slot > 0 and (slot < .MIN or slot > .MAX)) then
return .Folder + "\\SaveSlot_" + .InvalidPath + ".pld"
elseif (slot < 0) then
return .Folder + "\\SaveSlot_" + .ManualPath + ".pld"
endif
return .Folder + "\\SaveSlot_" + I2S(slot) + ".pld"
endmethod
static method create takes player p, string title, integer slot, string data returns thistype
if (GetLocalPlayer() == p) then
call FileIO_Write(.getPath(slot), title + "\n" + data)
endif
return slot
endmethod
static method clear takes player p, integer slot returns thistype
if (GetLocalPlayer() == p) then
call FileIO_Write(.getPath(slot), "")
endif
return slot
endmethod
static method exists takes integer slot returns boolean // async
return FileIO_Read(.getPath(slot)) != null
endmethod
method getLines takes integer line, boolean includePrevious returns string // async
local string contents = FileIO_Read(.getPath(this))
local integer len = StringLength(contents)
local string char = null
local string buffer = ""
local integer curLine = 0
local integer i = 0
loop
exitwhen i > len
set char = SubString(contents, i, i + 1)
if (char == "\n") then
set curLine = curLine + 1
if (curLine > line) then
return buffer
endif
if (not includePrevious) then
set buffer = ""
endif
else
set buffer = buffer + char
endif
set i = i + 1
endloop
if (curLine == line) then
return buffer
endif
return null
endmethod
method getLine takes integer line returns string // async
return .getLines(line, false)
endmethod
method getTitle takes nothing returns string // async
return .getLines(0, false)
endmethod
method getData takes nothing returns string // async
return .getLines(1, false)
endmethod
implement SaveFileInit
endstruct
private module SaveFileInit
private static method onInit takes nothing returns nothing
//set thistype.Folder = udg_MapName
endmethod
endmodule
endlibrary
library FileIO
/***************************************************************
*
* v1.1.0, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* Provides functionality to read and write files.
* _________________________________________________________________________
* 1. Requirements
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - Patch 1.29 or higher.
* - JassHelper (vJASS)
* _________________________________________________________________________
* 2. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it.
* _________________________________________________________________________
* 3. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct File extends array
*
* static constant integer AbilityCount
* static constant integer PreloadLimit
*
* readonly static boolean ReadEnabled
* readonly static integer Counter
* readonly static integer array List
*
* static method open takes string filename returns File
* static method create takes string filename returns File
*
* ---------
*
* method write takes string value returns File
* method read takes nothing returns string
*
* method readEx takes boolean close returns string
* method readAndClose takes nothing returns string
* method readBuffer takes nothing returns string
* method writeBuffer takes string contents returns nothing
* method appendBuffer takes string contents returns nothing
*
* method close takes nothing returns nothing
*
* public function Write takes string filename, string contents returns nothing
* public function Read takes string filename returns string
*
***************************************************************/
globals
// Enable this if you want to allow the system to read files generated in patch 1.30 or below.
// NOTE: For this to work properly you must edit the 'Amls' ability and change the levels to 2
// as well as typing something in "Level 2 - Text - Tooltip - Normal" text field.
//
// Enabling this will also cause the system to treat files written with .write("") as empty files.
//
// This setting is really only intended for those who were already using the system in their map
// prior to patch 1.31 and want to keep old files created with this system to still work.
private constant boolean BACKWARDS_COMPATABILITY = true
endglobals
private keyword FileInit
struct File extends array
static constant integer AbilityCount = 10
static constant integer PreloadLimit = 200
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList
readonly static boolean ReadEnabled
readonly string filename
private string buffer
static method open takes string filename returns thistype
local thistype this = .List[0]
if (this == 0) then
set this = Counter + 1
set Counter = this
else
set .List[0] = .List[this]
endif
set this.filename = filename
set this.buffer = null
debug if (this >= JASS_MAX_ARRAY_SIZE) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") WARNING: Maximum instance limit " + I2S(JASS_MAX_ARRAY_SIZE) + " reached.")
debug endif
return this
endmethod
// This is used to detect invalid characters which aren't supported in preload files.
static if (DEBUG_MODE) then
private static method validateInput takes string contents returns string
local integer i = 0
local integer l = StringLength(contents)
local string ch = ""
loop
exitwhen i >= l
set ch = SubString(contents, i, i + 1)
if (ch == "\\") then
return ch
elseif (ch == "\"") then
return ch
endif
set i = i + 1
endloop
return null
endmethod
endif
method write takes string contents returns thistype
local integer i = 0
local integer c = 0
local integer len = StringLength(contents)
local integer lev = 0
local string prefix = "-" // this is used to signify an empty string vs a null one
local string chunk
debug if (.validateInput(contents) != null) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: Invalid character |cffffcc00" + .validateInput(contents) + "|r")
debug return this
debug endif
set this.buffer = null
// Check if the string is empty. If null, the contents will be cleared.
if (contents == "") then
set len = len + 1
endif
// Begin to generate the file
call PreloadGenClear()
call PreloadGenStart()
loop
exitwhen i >= len
debug if (c >= .AbilityCount) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: String exceeds maximum length (" + I2S(.AbilityCount * .PreloadLimit) + ").|r")
debug endif
set lev = 0
static if (BACKWARDS_COMPATABILITY) then
if (c == 0) then
set lev = 1
set prefix = ""
else
set prefix = "-"
endif
endif
set chunk = SubString(contents, i, i + .PreloadLimit)
call Preload("\" )\ncall BlzSetAbilityTooltip(" + I2S(.AbilityList[c]) + ", \"" + prefix + chunk + "\", " + I2S(lev) + ")\n//")
set i = i + .PreloadLimit
set c = c + 1
endloop
call Preload("\" )\nendfunction\nfunction a takes nothing returns nothing\n //")
call PreloadGenEnd(this.filename)
return this
endmethod
method clear takes nothing returns thistype
return this.write(null)
endmethod
private method readPreload takes nothing returns string
local integer i = 0
local integer lev = 0
local string array original
local string chunk = ""
local string output = ""
loop
exitwhen i == .AbilityCount
set original[i] = BlzGetAbilityTooltip(.AbilityList[i], 0)
set i = i + 1
endloop
// Execute the preload file
call Preloader(this.filename)
// Read the output
set i = 0
loop
exitwhen i == .AbilityCount
set lev = 0
// Read from ability index 1 instead of 0 if
// backwards compatability is enabled
static if (BACKWARDS_COMPATABILITY) then
if (i == 0) then
set lev = 1
endif
endif
// Make sure the tooltip has changed
set chunk = BlzGetAbilityTooltip(.AbilityList[i], lev)
if (chunk == original[i]) then
if (i == 0 and output == "") then
return null // empty file
endif
return output
endif
// Check if the file is an empty string or null
static if not (BACKWARDS_COMPATABILITY) then
if (i == 0) then
if (SubString(chunk, 0, 1) != "-") then
return null // empty file
endif
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
endif
// Remove the prefix
if (i > 0) then
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
// Restore the tooltip and append the chunk
call BlzSetAbilityTooltip(.AbilityList[i], original[i], lev)
set output = output + chunk
set i = i + 1
endloop
return output
endmethod
method close takes nothing returns nothing
if (this.buffer != null) then
call .write(.readPreload() + this.buffer)
set this.buffer = null
endif
set .List[this] = .List[0]
set .List[0] = this
endmethod
method readEx takes boolean close returns string
local string output = .readPreload()
local string buf = this.buffer
if (close) then
call this.close()
endif
if (output == null) then
return buf
endif
if (buf != null) then
set output = output + buf
endif
return output
endmethod
method read takes nothing returns string
return .readEx(false)
endmethod
method readAndClose takes nothing returns string
return .readEx(true)
endmethod
method appendBuffer takes string contents returns thistype
set .buffer = .buffer + contents
return this
endmethod
method readBuffer takes nothing returns string
return .buffer
endmethod
method writeBuffer takes string contents returns nothing
set .buffer = contents
endmethod
static method create takes string filename returns thistype
return .open(filename).write("")
endmethod
implement FileInit
endstruct
private module FileInit
private static method onInit takes nothing returns nothing
local string originalTooltip
// We can't use a single ability with multiple levels because
// tooltips return the first level's value if the value hasn't
// been set. This way we don't need to edit any object editor data.
set File.AbilityList[0] = 'Amls'
set File.AbilityList[1] = 'Aroc'
set File.AbilityList[2] = 'Amic'
set File.AbilityList[3] = 'Amil'
set File.AbilityList[4] = 'Aclf'
set File.AbilityList[5] = 'Acmg'
set File.AbilityList[6] = 'Adef'
set File.AbilityList[7] = 'Adis'
set File.AbilityList[8] = 'Afbt'
set File.AbilityList[9] = 'Afbk'
// Backwards compatability check
static if (BACKWARDS_COMPATABILITY) then
static if (DEBUG_MODE) then
set originalTooltip = BlzGetAbilityTooltip(File.AbilityList[0], 1)
call BlzSetAbilityTooltip(File.AbilityList[0], SCOPE_PREFIX, 1)
if (BlzGetAbilityTooltip(File.AbilityList[0], 1) == originalTooltip) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO WARNING: Backward compatibility enabled but \"" + GetObjectName(File.AbilityList[0]) + "\" It is not configured correctly.|r")
endif
endif
endif
// Read check
set File.ReadEnabled = File.open("FileTester.pld").write(SCOPE_PREFIX).readAndClose() == SCOPE_PREFIX
endmethod
endmodule
public function Write takes string filename, string contents returns nothing
call File.open(filename).write(contents).close()
endfunction
public function Read takes string filename returns string
return File.open(filename).readEx(true)
endfunction
endlibrary
library PlayerUtils
/**************************************************************
*
* v1.2.9 by TriggerHappy
*
* This library provides a struct which caches data about players
* as well as provides functionality for manipulating player colors.
*
* Constants
* ------------------
*
* force FORCE_PLAYING - Player group of everyone who is playing.
*
* Struct API
* -------------------
* struct User
*
* static method fromIndex takes integer i returns User
* static method fromLocal takes nothing returns User
* static method fromPlaying takes integer id returns User
*
* static method operator [] takes integer id returns User
* static method operator count takes nothing returns integer
*
* method operator name takes nothing returns string
* method operator name= takes string name returns nothing
* method operator color takes nothing returns playercolor
* method operator color= takes playercolor c returns nothing
* method operator defaultColor takes nothing returns playercolor
* method operator hex takes nothing returns string
* method operator nameColored takes nothing returns string
*
* method toPlayer takes nothing returns player
* method colorUnits takes playercolor c returns nothing
*
* readonly string originalName
* readonly boolean isPlaying
* readonly static player Local
* readonly static integer LocalId
* readonly static integer AmountPlaying
* readonly static playercolor array Color
* readonly static player array PlayingPlayer
*
**************************************************************/
globals
// automatically change unit colors when changing player color
private constant boolean AUTO_COLOR_UNITS = true
// use an array for name / color lookups (instead of function calls)
private constant boolean ARRAY_LOOKUP = false
// this only applies if ARRAY_LOOKUP is true
private constant boolean HOOK_SAFETY = false // disable for speed, but only use the struct to change name/color safely
constant force FORCE_PLAYING = CreateForce()
private string array Name
private string array Hex
private string array OriginalHex
private playercolor array CurrentColor
endglobals
private keyword PlayerUtilsInit
struct User extends array
static constant integer NULL = bj_MAX_PLAYER_SLOTS
readonly player handle
readonly integer id
readonly thistype next
readonly thistype prev
readonly string originalName
readonly boolean isPlaying
readonly static thistype first
readonly static thistype last
readonly static player Local
readonly static integer LocalId
readonly static integer AmountPlaying = 0
readonly static playercolor array Color
static if not (LIBRARY_GroupUtils) then
readonly static group ENUM_GROUP = CreateGroup()
endif
private static thistype array PlayingPlayer
private static integer array PlayingPlayerIndex
// similar to Player(#)
static method fromIndex takes integer i returns thistype
return thistype(i)
endmethod
// similar to GetLocalPlayer
static method fromLocal takes nothing returns thistype
return thistype(thistype.LocalId)
endmethod
// access active players array
static method fromPlaying takes integer index returns thistype
return PlayingPlayer[index]
endmethod
static method operator [] takes player p returns thistype
return thistype(GetPlayerId(p))
endmethod
method toPlayer takes nothing returns player
return this.handle
endmethod
method operator name takes nothing returns string
static if (ARRAY_LOOKUP) then
return Name[this]
else
return GetPlayerName(this.handle)
endif
endmethod
method operator name= takes string newName returns nothing
call SetPlayerName(this.handle, newName)
static if (ARRAY_LOOKUP) then
static if not (HOOK_SAFETY) then
set Name[this] = newName
endif
endif
endmethod
method operator color takes nothing returns playercolor
static if (ARRAY_LOOKUP) then
return CurrentColor[this]
else
return GetPlayerColor(this.handle)
endif
endmethod
method operator hex takes nothing returns string
return OriginalHex[GetHandleId(this.color)]
endmethod
method operator color= takes playercolor c returns nothing
call SetPlayerColor(this.handle, c)
static if (ARRAY_LOOKUP) then
set CurrentColor[this] = c
static if not (HOOK_SAFETY) then
static if (AUTO_COLOR_UNITS) then
call this.colorUnits(color)
endif
endif
endif
endmethod
method operator defaultColor takes nothing returns playercolor
return Color[this]
endmethod
method operator nameColored takes nothing returns string
return hex + this.name + "|r"
endmethod
method colorUnits takes playercolor c returns nothing
local unit u
call GroupEnumUnitsOfPlayer(ENUM_GROUP, this.handle, null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen u == null
call SetUnitColor(u, c)
call GroupRemoveUnit(ENUM_GROUP, u)
endloop
endmethod
static method onLeave takes nothing returns boolean
local thistype p = thistype[GetTriggerPlayer()]
local integer i = .PlayingPlayerIndex[p.id]
// clean up
call ForceRemovePlayer(FORCE_PLAYING, p.toPlayer())
// recycle index
set .AmountPlaying = .AmountPlaying - 1
set .PlayingPlayerIndex[i] = .PlayingPlayerIndex[.AmountPlaying]
set .PlayingPlayer[i] = .PlayingPlayer[.AmountPlaying]
if (.AmountPlaying == 1) then
set p.prev.next = User.NULL
set p.next.prev = User.NULL
else
set p.prev.next = p.next
set p.next.prev = p.prev
endif
set .last = .PlayingPlayer[.AmountPlaying]
set p.isPlaying = false
return false
endmethod
implement PlayerUtilsInit
endstruct
private module PlayerUtilsInit
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local thistype p
set thistype.Local = GetLocalPlayer()
set thistype.LocalId = GetPlayerId(thistype.Local)
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
set thistype.first = User.NULL
loop
exitwhen i == bj_MAX_PLAYERS
set p = User(i)
set p.handle = Player(i)
set p.id = i
set thistype.Color[i] = GetPlayerColor(p.handle)
set CurrentColor[i] = thistype.Color[i]
if (GetPlayerController(p.handle) == MAP_CONTROL_USER and GetPlayerSlotState(p.handle) == PLAYER_SLOT_STATE_PLAYING) then
set .PlayingPlayer[AmountPlaying] = p
set .PlayingPlayerIndex[i] = .AmountPlaying
set .last = i
if (.first == User.NULL) then
set .first = i
set User(i).next = User.NULL
set User(i).prev = User.NULL
else
set User(i).prev = PlayingPlayer[AmountPlaying-1].id
set PlayingPlayer[AmountPlaying-1].next = User(i)
set User(i).next = User.NULL
endif
set p.isPlaying = true
call TriggerRegisterPlayerEvent(t, p.handle, EVENT_PLAYER_LEAVE)
call ForceAddPlayer(FORCE_PLAYING, p.handle)
set Hex[p] = OriginalHex[GetHandleId(thistype.Color[i])]
set .AmountPlaying = .AmountPlaying + 1
endif
set Name[p] = GetPlayerName(p.handle)
set p.originalName=Name[p]
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function thistype.onLeave))
endmethod
endmodule
//===========================================================================
static if (ARRAY_LOOKUP) then
static if (HOOK_SAFETY) then
private function SetPlayerNameHook takes player whichPlayer, string name returns nothing
set Name[GetPlayerId(whichPlayer)] = name
endfunction
private function SetPlayerColorHook takes player whichPlayer, playercolor color returns nothing
local User p = User[whichPlayer]
set Hex[p] = OriginalHex[GetHandleId(color)]
set CurrentColor[p] = color
static if (AUTO_COLOR_UNITS) then
call p.colorUnits(color)
endif
endfunction
hook SetPlayerName SetPlayerNameHook
hook SetPlayerColor SetPlayerColorHook
endif
endif
endlibrary
library Savecode requires BigNum
private constant function uppercolor takes nothing returns string
return "|cffff0000"
endfunction
private constant function lowercolor takes nothing returns string
return "|cff00ff00"
endfunction
private constant function numcolor takes nothing returns string
return "|cff0000ff"
endfunction
private function player_charset takes nothing returns string
return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
endfunction
private function player_charsetlen takes nothing returns integer
return StringLength(player_charset())
endfunction
private function charset takes nothing returns string
return "!#$%&'()*+,-.0123456789:;=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}`"
endfunction
private function charsetlen takes nothing returns integer
return StringLength(charset())
endfunction
private function BASE takes nothing returns integer
return charsetlen()
endfunction
private constant function HASHN takes nothing returns integer
return 5000 //1./HASHN() is the probability of a random code being valid
endfunction
private constant function MAXINT takes nothing returns integer
return 2147483647
endfunction
private function player_chartoi takes string c returns integer
local integer i = 0
local string cs = player_charset()
local integer len = player_charsetlen()
loop
exitwhen i>=len or c == SubString(cs,i,i+1)
set i = i + 1
endloop
return i
endfunction
private function chartoi takes string c returns integer
local integer i = 0
local string cs = charset()
local integer len = charsetlen()
loop
exitwhen i>=len or c == SubString(cs,i,i+1)
set i = i + 1
endloop
return i
endfunction
private function itochar takes integer i returns string
return SubString(charset(),i,i+1)
endfunction
//You probably want to use a different char set for this
//Also, use a hash that doesn't suck so much
private function scommhash takes string s returns integer
local integer array count
local integer i = 0
local integer len = StringLength(s)
local integer x
set s = StringCase(s,true)
loop
exitwhen i >= len
set x = player_chartoi(SubString(s,i,i+1))
set count[x] = count[x] + 1
set i = i + 1
endloop
set i = 0
set len = player_charsetlen()
set x = 0
loop
exitwhen i>= len
set x = count[i]*count[i]*i+count[i]*x+x+199
// call BJDebugMsg(I2S(x)+" "+I2S(count[i]))
// call TriggerSleepAction(0.)
set i = i + 1
endloop
if x < 0 then
set x = -x
endif
return x
endfunction
private function modb takes integer x returns integer
if x >= BASE() then
return x - BASE()
elseif x < 0 then
return x + BASE()
else
return x
endif
endfunction
struct Savecode
real digits //logarithmic approximation
BigNum bignum
static method create takes nothing returns Savecode
local Savecode sc = Savecode.allocate()
set sc.digits = 0.
set sc.bignum = BigNum.create(BASE())
return sc
endmethod
method onDestroy takes nothing returns nothing
call .bignum.destroy()
endmethod
method Encode takes integer val, integer max returns nothing
set .digits = .digits + log(max+1,BASE())
call .bignum.MulSmall(max+1)
call .bignum.AddSmall(val)
endmethod
method Decode takes integer max returns integer
return .bignum.DivSmall(max+1)
endmethod
method IsEmpty takes nothing returns boolean
return .bignum.IsZero()
endmethod
method Length takes nothing returns real
return .digits
endmethod
method Clean takes nothing returns nothing
call .bignum.Clean()
endmethod
//These functions get too intimate with BigNum_l
method Pad takes nothing returns nothing
local BigNum_l cur = .bignum.list
local BigNum_l prev
local integer maxlen = R2I(1.0 + .Length())
loop
exitwhen cur == 0
set prev = cur
set cur = cur.next
set maxlen = maxlen - 1
endloop
loop
exitwhen maxlen <= 0
set prev.next = BigNum_l.create()
set prev = prev.next
set maxlen = maxlen - 1
endloop
endmethod
method ToString takes nothing returns string
local BigNum_l cur = .bignum.list
local string s = ""
loop
exitwhen cur == 0
set s = itochar(cur.leaf) + s
set cur = cur.next
endloop
return s
endmethod
method FromString takes string s returns nothing
local integer i = StringLength(s)-1
local BigNum_l cur = BigNum_l.create()
set .bignum.list = cur
loop
set cur.leaf = chartoi(SubString(s,i,i+1))
exitwhen i <= 0
set cur.next = BigNum_l.create()
set cur = cur.next
set i = i - 1
endloop
endmethod
method Hash takes nothing returns integer
local integer hash = 0
local integer x
local BigNum_l cur = .bignum.list
loop
exitwhen cur == 0
set x = cur.leaf
set hash = ModuloInteger(hash+79*hash/(x+1) + 293*x/(1+hash - (hash/BASE())*BASE()) + 479,HASHN())
set cur = cur.next
endloop
return hash
endmethod
//this is not cryptographic which is fine for this application
//sign = 1 is forward
//sign = -1 is backward
method Obfuscate takes integer key, integer sign returns nothing
local integer seed = GetRandomInt(0,MAXINT())
local integer advance
local integer x
local BigNum_l cur = .bignum.list
if sign == -1 then
call SetRandomSeed(.bignum.LastDigit())
set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
set x = cur.leaf
endif
call SetRandomSeed(key)
loop
exitwhen cur == 0
if sign == -1 then
set advance = cur.leaf
endif
set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
if sign == 1 then
set advance = cur.leaf
endif
set advance = advance + GetRandomInt(0,BASE()-1)
call SetRandomSeed(advance)
set x = cur.leaf
set cur = cur.next
endloop
if sign == 1 then
call SetRandomSeed(x)
set .bignum.list.leaf = modb(.bignum.list.leaf + sign*GetRandomInt(0,BASE()-1))
endif
call SetRandomSeed(seed)
endmethod
method Dump takes nothing returns nothing
local BigNum_l cur = .bignum.list
local string s = ""
set s = "max: "+R2S(.digits)
loop
exitwhen cur == 0
set s = I2S(cur.leaf)+" "+s
set cur = cur.next
endloop
call BJDebugMsg(s)
endmethod
method Save takes player p, integer loadtype returns string
local integer key = scommhash(GetPlayerName(p))+loadtype*73
local string s
local integer hash
call .Clean()
set hash = .Hash()
call .Encode(hash,HASHN())
call .Clean()
/////////////////////// Save code information. Comment out next two lines in implementation
//call BJDebugMsg("Expected length: " +I2S(R2I(1.0+.Length())))
//call BJDebugMsg("Room left in last char: "+R2S(1.-ModuloReal((.Length()),1)))
///////////////////////
call .Pad()
call .Obfuscate(key,1)
return .ToString()
endmethod
method Load takes player p, string s, integer loadtype returns boolean
local integer ikey = scommhash(GetPlayerName(p))+loadtype*73
local integer inputhash
call .FromString(s)
call .Obfuscate(ikey,-1)
set inputhash = .Decode(HASHN())
call .Clean()
return inputhash == .Hash()
endmethod
endstruct
private function isupper takes string c returns boolean
return c == StringCase(c,true)
endfunction
private function ischar takes string c returns boolean
return S2I(c) == 0 and c!= "0"
endfunction
private function chartype takes string c returns integer
if(ischar(c)) then
if isupper(c) then
return 0
else
return 1
endif
else
return 2
endif
endfunction
private function testchar takes string c returns nothing
if(ischar(c)) then
if isupper(c) then
call BJDebugMsg(c+" isupper")
else
call BJDebugMsg(c+" islower")
endif
else
call BJDebugMsg(c+ " isnumber")
endif
endfunction
public function colorize takes string s returns string
local string out = ""
local integer i = 0
local integer len = StringLength(s)
local integer ctype
local string c
loop
exitwhen i >= len
set c = SubString(s,i,i+1)
set ctype = chartype(c)
if ctype == 0 then
set out = out + uppercolor()+c+"|r"
elseif ctype == 1 then
set out = out + lowercolor()+c+"|r"
else
set out = out + numcolor()+c+"|r"
endif
set i = i + 1
endloop
return out
endfunction
private function prop_Savecode takes nothing returns boolean
local string s
local Savecode loadcode
//--- Data you want to save ---
local integer medal1 = 10
local integer medal2 = 3
local integer medalmax = 13
local integer XP = 1337
local integer XPmax = 1000000
local Savecode savecode = Savecode.create()
call SetPlayerName(Player(0),"yomp")
call SetPlayerName(Player(1),"fruitcup")
call savecode.Encode(medal1,medalmax)
call savecode.Encode(medal2,medalmax)
call savecode.Encode(XP,XPmax)
//--- Savecode_save generates the savecode for a specific player ---
set s = savecode.Save(Player(0),1)
call savecode.destroy()
// call BJDebugMsg("Savecode: " + Savecode_colorize(s))
//--- User writes down code, inputs again ---
set loadcode = Savecode.create()
if loadcode.Load(Player(0),s,1) then
// call BJDebugMsg("load ok")
else
call BJDebugMsg("load failed")
return false
endif
//Must decode in reverse order of encodes
// load object : max value that data can take
if XP != loadcode.Decode(XPmax) then
return false
elseif medal2 != loadcode.Decode(medalmax) then
return false
elseif medal1 != loadcode.Decode(medalmax) then
return false
endif
call loadcode.destroy()
return true
endfunction
endlibrary
//===========================================================================
function InitTrig_save_system takes nothing returns nothing
endfunction
library BigNum
//prefer algebraic approach because of real subtraction issues
function log takes real y, real base returns real
local real x
local real factor = 1.0
local real logy = 0.0
local real sign = 1.0
if(y < 0.) then
return 0.0
endif
if(y < 1.) then
set y = 1.0/y
set sign = -1.0
endif
//Chop out powers of the base
loop
exitwhen y < 1.0001 //decrease this ( bounded below by 1) to improve precision
if(y > base) then
set y = y / base
set logy = logy + factor
else
set base = SquareRoot(base) //If you use just one base a lot, precompute its squareroots
set factor = factor / 2.
endif
endloop
return sign*logy
endfunction
struct BigNum_l
integer leaf
BigNum_l next
debug static integer nalloc = 0
static method create takes nothing returns BigNum_l
local BigNum_l bl = BigNum_l.allocate()
set bl.next = 0
set bl.leaf = 0
debug set BigNum_l.nalloc = BigNum_l.nalloc + 1
return bl
endmethod
method onDestroy takes nothing returns nothing
debug set BigNum_l.nalloc = BigNum_l.nalloc - 1
endmethod
//true: want destroy
method Clean takes nothing returns boolean
if .next == 0 and .leaf == 0 then
return true
elseif .next != 0 and .next.Clean() then
call .next.destroy()
set .next = 0
return .leaf == 0
else
return false
endif
endmethod
method DivSmall takes integer base, integer denom returns integer
local integer quotient
local integer remainder = 0
local integer num
if .next != 0 then
set remainder = .next.DivSmall(base,denom)
endif
set num = .leaf + remainder*base
set quotient = num/denom
set remainder = num - quotient*denom
set .leaf = quotient
return remainder
endmethod
endstruct
struct BigNum
BigNum_l list
integer base
static method create takes integer base returns BigNum
local BigNum b = BigNum.allocate()
set b.list = 0
set b.base = base
return b
endmethod
method onDestroy takes nothing returns nothing
local BigNum_l cur = .list
local BigNum_l next
loop
exitwhen cur == 0
set next = cur.next
call cur.destroy()
set cur = next
endloop
endmethod
method IsZero takes nothing returns boolean
local BigNum_l cur = .list
loop
exitwhen cur == 0
if cur.leaf != 0 then
return false
endif
set cur = cur.next
endloop
return true
endmethod
method Dump takes nothing returns nothing
local BigNum_l cur = .list
local string s = ""
loop
exitwhen cur == 0
set s = I2S(cur.leaf)+" "+s
set cur = cur.next
endloop
call BJDebugMsg(s)
endmethod
method Clean takes nothing returns nothing
local BigNum_l cur = .list
call cur.Clean()
endmethod
//fails if bignum is null
//BASE() + carry must be less than MAXINT()
method AddSmall takes integer carry returns nothing
local BigNum_l next
local BigNum_l cur = .list
local integer sum
if cur == 0 then
set cur = BigNum_l.create()
set .list = cur
endif
loop
exitwhen carry == 0
set sum = cur.leaf + carry
set carry = sum / .base
set sum = sum - carry*.base
set cur.leaf = sum
if cur.next == 0 then
set cur.next = BigNum_l.create()
endif
set cur = cur.next
endloop
endmethod
//x*BASE() must be less than MAXINT()
method MulSmall takes integer x returns nothing
local BigNum_l cur = .list
local integer product
local integer remainder
local integer carry = 0
loop
exitwhen cur == 0 and carry == 0
set product = x * cur.leaf + carry
set carry = product/.base
set remainder = product - carry*.base
set cur.leaf = remainder
if cur.next == 0 and carry != 0 then
set cur.next = BigNum_l.create()
endif
set cur = cur.next
endloop
endmethod
//Returns remainder
method DivSmall takes integer denom returns integer
return .list.DivSmall(.base,denom)
endmethod
method LastDigit takes nothing returns integer
local BigNum_l cur = .list
local BigNum_l next
loop
set next = cur.next
exitwhen next == 0
set cur = next
endloop
return cur.leaf
endmethod
endstruct
private function prop_Allocator1 takes nothing returns boolean
local BigNum b1
local BigNum b2
set b1 = BigNum.create(37)
call b1.destroy()
set b2 = BigNum.create(37)
call b2.destroy()
return b1 == b2
endfunction
private function prop_Allocator2 takes nothing returns boolean
local BigNum b1
local boolean b = false
set b1 = BigNum.create(37)
call b1.AddSmall(17)
call b1.MulSmall(19)
debug if BigNum_l.nalloc < 1 then
debug return false
debug endif
call b1.destroy()
debug set b = BigNum_l.nalloc == 0
return b
endfunction
private function prop_Arith takes nothing returns boolean
local BigNum b1
set b1 = BigNum.create(37)
call b1.AddSmall(73)
call b1.MulSmall(39)
call b1.AddSmall(17)
//n = 2864
if b1.DivSmall(100) != 64 then
return false
elseif b1.DivSmall(7) != 0 then
return false
elseif b1.IsZero() then
return false
elseif b1.DivSmall(3) != 1 then
return false
elseif b1.DivSmall(3) != 1 then
return false
elseif not b1.IsZero() then
return false
endif
return true
endfunction
endlibrary
//===========================================================================
function InitTrig_bignum_lib takes nothing returns nothing
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Mathematical Functions **
// ** ————————————— **
// ** **
// ** Functions used instead of BJs to calculate some values **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library Math
function GetDistance takes real ax, real ay, real bx, real by returns real
return SquareRoot((bx-ax)*(bx-ax)+(by-ay)*(by-ay))
endfunction
function PolarProjectionx takes real ax, real dist, real angle returns real
return ax + dist * Cos(angle)
endfunction
function PolarProjectiony takes real ay, real dist, real angle returns real
return ay + dist * Sin(angle)
endfunction
function GetAngle takes real ax, real ay, real bx, real by returns real
return Atan2(by-ay, bx-ax)
endfunction
function RAbs takes real a returns real
if (a >= 0) then
return a
else
return -a
endif
endfunction
function AntiLeak takes nothing returns boolean
return true
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//Functions used to handle timers. Credits to Vexorian and Captain Griffen
//Check http://www.wc3c.net/showthread.php?t=89072 for more informations
library HandleTimers
globals
private timer array timers
private integer N = 0
endglobals
function NewTimer takes nothing returns timer
if (N==0) then
return CreateTimer()
endif
set N=N-1
return timers[N]
endfunction
function ReleaseTimer takes timer t returns nothing
call PauseTimer(t)
if (N==8191) 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
set timers[N]=t
set N=N+1
endif
endfunction
function TimerAttach takes timer t, real time, real value, code func returns nothing
call TimerStart(t, value, false, null)
call PauseTimer(t)
call TimerStart(t, time, false, func)
endfunction
// ONLY call on an expired timer.
function GetTimerInt takes timer t returns integer
return R2I(TimerGetRemaining(t) + 0.5)
endfunction
endlibrary
//TESH.scrollpos=25
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Check Pathability Function **
// ** ————————————— **
// ** **
// ** A Function that checks if a unit can walk over a certain area **
// ** (Ignores other units but not buildings, trees and other obstacles) **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library Walkable initializer init requires ChargeConfig, Math
globals
unit pathchecker
rect pathrect
filterfunc truefilter
endglobals
function HideItems takes nothing returns nothing
call SetItemVisible(GetEnumItem(), false)
endfunction
function UnHideItems takes nothing returns nothing
call SetItemVisible(GetEnumItem(), true)
endfunction
function IsPointWalkable takes real x, real y returns boolean
local boolean b
call SetUnitPosition(pathchecker,x,y)
set b=((GetUnitX(pathchecker)-x)*(GetUnitX(pathchecker)-x)+((GetUnitY(pathchecker)-y)*(GetUnitY(pathchecker)-y))<=1)
if (b==false) then
call MoveRectTo(pathrect, x, y)
call EnumItemsInRect(pathrect,truefilter,function HideItems)
call SetUnitPosition(pathchecker,x,y)
set b=((GetUnitX(pathchecker)-x)*(GetUnitX(pathchecker)-x)+((GetUnitY(pathchecker)-y)*(GetUnitY(pathchecker)-y))<=1)
call EnumItemsInRect(pathrect,truefilter,function UnHideItems)
endif
return b
endfunction
function init takes nothing returns nothing
local real x = GetRectMinX(bj_mapInitialPlayableArea)
local real y = GetRectMinY(bj_mapInitialPlayableArea)
set pathrect=Rect(x,y,x+200.00,y+200.00)
set pathchecker=CreateUnit( Player(PLAYER_NEUTRAL_PASSIVE), PATHCHECKERID, 0, 0, 0)
set truefilter=Filter(function AntiLeak)
call UnitAddAbility(pathchecker, SPELLPATHID)
call IssueImmediateOrder( pathchecker, "windwalk" )
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Knockback initializer Init requires HandleTimers, Walkable
// **************************************************************************
// ** **
// ** Knockback(Ex) **
// ** ————————————— **
// ** **
// ** A function made for efficient knockbacking **
// ** **
// ** By: Silvenon **
// ** **
// **************************************************************************
//=======================================//
//Credits to PitzerMike for this function//
//=======================================//
private function TreeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local boolean i = IsDestructableInvulnerable(d)
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMYID, GetWidgetX(d), GetWidgetY(d), 0)
local boolean result = false
call UnitAddAbility(u, 'Ahrl')
if i then
call SetDestructableInvulnerable(d, false)
endif
set result = IssueTargetOrder(u, "harvest", d)
call RemoveUnit(u)
if i then
call SetDestructableInvulnerable(d, true)
endif
set u = null
set d = null
return result
endfunction
//===========================================================================
globals
private timer Tim = CreateTimer()
private integer Total = 0
private boolexpr Cond = null
private integer array Ar
private boolean array BoolAr
private real MAX_X
private real MAX_Y
private real MIN_X
private real MIN_Y
endglobals
private constant function Interval takes nothing returns real
return 0.04
endfunction
private function KillTree takes nothing returns nothing
if BoolAr[0] then
call KillDestructable(GetEnumDestructable())
else
set BoolAr[1] = true
endif
endfunction
public struct Data
unit u
real d1
real d2
real sin
real cos
real r
string s = ""
effect e = null
static method create takes unit u, integer q, real d, real a, real r, integer t, string s, string p returns Data
local Data dat = Data.allocate()
set dat.u = u
set dat.d1 = 2 * d / (q + 1)
set dat.d2 = dat.d1 / q
set dat.sin = Sin(a)
set dat.cos = Cos(a)
set dat.r = r
if s != "" and s != null then
if t == 2 then
if p != "" and p != null then
set dat.e = AddSpecialEffectTarget(s, u, p)
else
set dat.e = AddSpecialEffectTarget(s, u, "chest")
endif
elseif t == 1 then
set dat.s = s
endif
endif
call SetUnitPosition(u, GetUnitX(u), GetUnitY(u))
call PauseUnit(u, true)
if Total == 0 then
call TimerStart(Tim, Interval(), true, function Data.Execute)
endif
set Total = Total + 1
set Ar[Total - 1] = dat
return dat
endmethod
static method Execute takes nothing returns nothing
local Data dat
local integer i = 0
local real x
local real y
local rect r
local real rad
loop
exitwhen i >= Total
set dat = Ar[i]
if dat.s != "" and dat.s != null then
set x = GetUnitX(dat.u)
set y = GetUnitY(dat.u)
call DestroyEffect(AddSpecialEffect(dat.s, x, y))
set x = x + dat.d1 * dat.cos
set y = y + dat.d1 * dat.sin
else
set x = GetUnitX(dat.u) + dat.d1 * dat.cos
set y = GetUnitY(dat.u) + dat.d1 * dat.sin
endif
if dat.r != 0 then
set BoolAr[0] = dat.r > 0
set rad = dat.r
if not BoolAr[0] then
set rad = rad * (-1)
endif
set r = Rect(x - rad, y - rad, x + rad, y + rad)
call EnumDestructablesInRect(r, Cond, function KillTree)
call RemoveRect(r)
set r = null
endif
if (x < MAX_X and y < MAX_Y and x > MIN_X and y > MIN_Y) and not BoolAr[1] and (IsPointWalkable(x, y)) then
call SetUnitX(dat.u, x)
call SetUnitY(dat.u, y)
endif
set dat.d1 = dat.d1 - dat.d2
if dat.d1 <= 0 or (x > MAX_X or y > MAX_Y or x < MIN_X or y < MIN_Y) or BoolAr[1] or not(IsPointWalkable(x, y)) then
set Ar[i] = Ar[Total - 1]
set Total = Total - 1
call dat.destroy()
endif
set i = i + 1
endloop
if Total == 0 then
call PauseTimer(Tim)
endif
endmethod
method onDestroy takes nothing returns nothing
if .e != null then
call DestroyEffect(.e)
endif
call PauseUnit(.u, false)
set BoolAr[0] = false
set BoolAr[1] = false
endmethod
endstruct
function KnockbackEx takes unit u, real d, real a, real w, real r, integer t, string s, string p returns nothing
call Data.create(u, R2I(w / Interval()), d, a, r, t, s, p)
endfunction
function Knockback takes unit u, real d, real a, real w returns nothing
call Data.create(u, R2I(w / Interval()), d, a, 0, 0, "", "")
endfunction
private function Init takes nothing returns nothing
set Cond = Filter(function TreeFilter)
set BoolAr[0] = false
set BoolAr[1] = false
set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea) - 64
set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea) - 64
set MIN_X = GetRectMinX(bj_mapInitialPlayableArea) + 64
set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea) + 64
endfunction
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 4.1.0.1.
One map, one hashtable. Welcome to NewTable 4.1.0.1
This newest iteration of Table introduces the new HashTable struct.
You can now instantiate HashTables which enables the use of large
parent and large child keys, just like a standard hashtable. Previously,
the user would have to instantiate a Table to do this on their own which -
while doable - is something the user should not have to do if I can add it
to this resource myself (especially if they are inexperienced).
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//New textmacro to allow table.integer[] syntax for compatibility with textmacros that might desire it.
//! runtextmacro NEW_ARRAY_BASIC("Integer", "Integer", "integer")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement integerm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key) //return this.integer[key]
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb) //set this.integer[key] = tb
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key) //return this.integer.has(key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key) //call this.integer.remove(key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
//NEW: Added in Table 4.0. A fairly simple struct but allows you to do more
//than that which was previously possible.
struct HashTable extends array
//Enables myHash[parentKey][childKey] syntax.
//Basically, it creates a Table in the place of the parent key if
//it didn't already get created earlier.
method operator [] takes integer index returns Table
local Table t = Table(this)[index]
if t == 0 then
set t = Table.create()
set Table(this)[index] = t //whoops! Forgot that line. I'm out of practice!
endif
return t
endmethod
//You need to call this on each parent key that you used if you
//intend to destroy the HashTable or simply no longer need that key.
method remove takes integer index returns nothing
local Table t = Table(this)[index]
if t != 0 then
call t.destroy()
call Table(this).remove(index)
endif
endmethod
//Added in version 4.1
method has takes integer index returns boolean
return Table(this).has(index)
endmethod
//HashTables are just fancy Table indices.
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
//Like I said above...
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
endlibrary
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.1
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
library Shop requires Table, RegisterPlayerUnitEvent, Components
/* --------------------------------------- Shop v1.0 --------------------------------------- */
// Credits:
// Taysen: FDF file and A2S function
// Bribe: Table library
// Magtheridon: RegisterPlayerUnitEvent library
// Hate: Frame border effects
/* -------------------------------------- By Chopinski ------------------------------------- */
/* ----------------------------------------------------------------------------------------- */
/* Configuration */
/* ----------------------------------------------------------------------------------------- */
globals
// Main window
private constant real X = 0.0
private constant real Y = 0.56
private constant real WIDTH = 0.8
private constant real HEIGHT = 0.4
private constant real TOOLBAR_BUTTON_SIZE = 0.02
private constant integer ROWS = 5
private constant integer COLUMNS = 13
private constant integer DETAILED_ROWS = 5
private constant integer DETAILED_COLUMNS = 8
private constant string CLOSE_ICON = "ui\\widgets\\battlenet\\chaticons\\bnet-squelch"
private constant string CLEAR_ICON = "ReplaceableTextures\\CommandButtons\\BTNCancel.blp"
private constant string HELP_ICON = "UI\\Widgets\\EscMenu\\Human\\quest-unknown.blp"
private constant string LOGIC_ICON = "ReplaceableTextures\\CommandButtons\\BTNMagicalSentry.blp"
private constant string UNDO_ICON = "ReplaceableTextures\\CommandButtons\\BTNReplay-Loop.blp"
private constant string DISMANTLE_ICON = "UI\\Feedback\\Resources\\ResourceUpkeep.blp"
// Buyer Panel
private constant real BUYER_WIDTH = WIDTH/2
private constant real BUYER_HEIGHT = 0.08
private constant real BUYER_SIZE = 0.032
private constant real BUYER_GAP = 0.04
private constant real BUYER_SHIFT_BUTTON_SIZE = 0.012
private constant integer BUYER_COUNT = 8
private constant string BUYER_RIGHT = "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedDown.blp"
private constant string BUYER_LEFT = "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedUp.blp"
// Inventory Panel
private constant real INVENTORY_WIDTH = 0.23780
private constant real INVENTORY_HEIGHT = 0.03740
private constant real INVENTORY_SIZE = 0.031
private constant real INVENTORY_GAP = 0.04
private constant integer INVENTORY_COUNT = 6
private constant string INVENTORY_TEXTURE = "Inventory.blp"
// Details window
private constant real DETAIL_WIDTH = 0.3125
private constant real DETAIL_HEIGHT = HEIGHT
private constant integer DETAIL_USED_COUNT = 6
private constant real DETAIL_BUTTON_SIZE = 0.035
private constant real DETAIL_BUTTON_GAP = 0.044
private constant real DETAIL_CLOSE_BUTTON_SIZE = 0.02
private constant real DETAIL_SHIFT_BUTTON_SIZE = 0.012
private constant string USED_RIGHT = "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedDown.blp"
private constant string USED_LEFT = "ReplaceableTextures\\CommandButtons\\BTNReplay-SpeedUp.blp"
// When true, a click in a component in the
// detail panel will detail the clicked component
private constant boolean DETAIL_COMPONENT = false
// Side Panels
private constant real SIDE_WIDTH = 0.075
private constant real SIDE_HEIGHT = HEIGHT
private constant real EDIT_WIDTH = 0.15
private constant real EDIT_HEIGHT = 0.0285
// Category and Favorite buttons
private constant integer CATEGORY_COUNT = 13
private constant real CATEGORY_SIZE = 0.02750
private constant real CATEGORY_GAP = 0.0
// Favorite key
// LSHIT, LCONTROL are buggy on KeyDown event,
// complain to blizzard, not me
private constant oskeytype FAVORITE_KEY = OSKEY_TAB
// Item slots
private constant real SLOT_WIDTH = 0.04
private constant real SLOT_HEIGHT = 0.05
private constant real ITEM_SIZE = 0.04
private constant real GOLD_SIZE = 0.01
private constant real COST_WIDTH = 0.045
private constant real COST_HEIGHT = 0.01
private constant real COST_SCALE = 0.8
private constant real SLOT_GAP_X = 0.018
private constant real SLOT_GAP_Y = 0.022
private constant string GOLD_ICON = "UI\\Feedback\\Resources\\ResourceGold.blp"
// Selected item highlight
private constant string ITEM_HIGHLIGHT = "neon_sprite.mdx"
private constant real HIGHLIGHT_WIDTH = 0.00001
private constant real HIGHLIGHT_HEIGHT = 0.00001
private constant real HIGHLIGHT_SCALE = 0.75
private constant real HIGHLIGHT_XOFFSET = -0.0052
private constant real HIGHLIGHT_YOFFSET = -0.0048
// Tagged item highlight
private constant string TAG_HIGHLIGHT = "crystallid_sprite.mdx"
private constant real TAG_HIGHLIGHT_WIDTH = 0.00001
private constant real TAG_HIGHLIGHT_HEIGHT = 0.00001
private constant real TAG_HIGHLIGHT_SCALE = 0.75
private constant real TAG_HIGHLIGHT_XOFFSET = -0.0052
private constant real TAG_HIGHLIGHT_YOFFSET = -0.0048
// Scroll
private constant real SCROLL_DELAY = 0.01
// Update time
private constant real UPDATE_PERIOD = 0.33
// Buy / Sell sound, model and scale
private constant string SPRITE_MODEL = "UI\\Feedback\\GoldCredit\\GoldCredit.mdl"
private constant real SPRITE_SCALE = 0.0005
private constant string SUCCESS_SOUND = "war3mapImported\\Ui_buy.mp3"
private constant string ERROR_SOUND = "Sound\\Interface\\Error.wav"
// Dont touch
private HashTable table
endglobals
/* ----------------------------------------------------------------------------------------- */
/* JASS API */
/* ----------------------------------------------------------------------------------------- */
function CreateShop takes integer id, real aoe, real returnRate returns nothing
call Shop.create(id, aoe, returnRate)
endfunction
function ShopAddCategory takes integer id, string icon, string description returns integer
return Shop.addCategory(id, icon, description)
endfunction
function ShopAddItem takes integer id, integer itemId, integer categories returns nothing
call Shop.addItem(id, itemId, categories)
endfunction
function ItemAddComponents takes integer whichItem, integer a, integer b, integer c, integer d, integer e returns nothing
call Item.addComponents(whichItem, a, b, c, d, e)
endfunction
function UnitHasItemOfType takes unit u, integer id returns boolean
return Item.hasType(u, id)
endfunction
function UnitCountItemOfType takes unit u, integer id returns integer
return Item.countType(u, id)
endfunction
function ShopFilter takes unit u, player owner, unit shop returns boolean
return IsUnitOwnedByPlayer(u, owner) and UnitInventorySize(u) > 0 and not IsUnitType(u, UNIT_TYPE_DEAD) and not IsUnitPaused(u) and not IsUnitIllusion(u) and not IsUnitHidden(u)
endfunction
function A2S takes integer id returns string
local string chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
local string s = ""
local integer min = ' '
local integer i
if id >= min then
loop
exitwhen id == 0
set i = ModuloInteger(id, 256) - min
set s = SubString(chars, i, i + 1) + s
set id = id / 256
endloop
endif
return s
endfunction
/* ----------------------------------------------------------------------------------------- */
/* System */
/* ----------------------------------------------------------------------------------------- */
struct Item
private static unit shop
private static rect rect
private static trigger trigger = CreateTrigger()
private static player player = Player(bj_PLAYER_NEUTRAL_EXTRA)
readonly static Table itempool
readonly static HashTable unit
private integer componentCount
string name
string icon
string tooltip
integer id
integer gold
integer charges
integer categories
Table component
Table counter
Table relation
method destroy takes nothing returns nothing
call component.destroy()
call relation.destroy()
call counter.destroy()
call deallocate()
endmethod
method operator components takes nothing returns integer
return componentCount
endmethod
method count takes integer id returns integer
return counter[id]
endmethod
static method get takes integer id returns thistype
return itempool[id]
endmethod
private static method save takes integer id, integer comp returns nothing
local thistype this
local thistype part
local integer i = 0
if comp > 0 and comp != id then
set this = create(id, 0)
set part = create(comp, 0)
set component[componentCount] = comp
set componentCount = componentCount + 1
set counter[comp] = counter[comp] + 1
loop
exitwhen part.relation[i] == id
if not part.relation.has(i) then
set part.relation[i] = id
exitwhen true
endif
set i = i + 1
endloop
endif
endmethod
static method addComponents takes integer id, integer a, integer b, integer c, integer d, integer e returns nothing
local thistype this
if id > 0 then
set this = create(id, 0)
set componentCount = 0
call component.flush()
call counter.flush()
call save(id, a)
call save(id, b)
call save(id, c)
call save(id, d)
call save(id, e)
endif
endmethod
static method cost takes integer id returns integer
local integer old
call AddItemToStock(shop, id, 1, 1)
call SetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD, 9999999)
set old = GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD)
call IssueNeutralImmediateOrderById(player, shop, id)
call RemoveItemFromStock(shop, id)
call EnumItemsInRect(rect, null, function thistype.clear)
return old - GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD)
endmethod
private static method clear takes nothing returns nothing
call RemoveItem(GetEnumItem())
endmethod
static method hasType takes unit u, integer id returns boolean
return unit[GetHandleId(u)][id] > 0
endmethod
static method countType takes unit u, integer id returns integer
return unit[GetHandleId(u)][id]
endmethod
static method create takes integer id, integer category returns thistype
local thistype this
local item i
if itempool.has(id) then
set this = itempool[id]
if category > 0 then
set categories = category
endif
return this
else
set i = CreateItem(id, 0, 0)
if i != null then
set this = thistype.allocate()
set .id = id
set categories = category
set name = GetItemName(i)
set icon = BlzGetItemIconPath(i)
set tooltip = BlzGetItemExtendedTooltip(i)
set charges = GetItemCharges(i)
if charges == 0 then
set charges = 1
endif
set gold = cost(id)
set componentCount = 0
set component = Table.create()
set counter = Table.create()
set relation = Table.create()
set itempool[id] = this
call RemoveItem(i)
set i = null
return this
else
return 0
endif
endif
endmethod
private static method onPickup takes nothing returns nothing
local integer u = GetHandleId(GetManipulatingUnit())
local integer i = GetItemTypeId(GetManipulatedItem())
set unit[u][i] = unit[u][i] + 1
endmethod
private static method onDrop takes nothing returns nothing
local integer u = GetHandleId(GetManipulatingUnit())
local integer i = GetItemTypeId(GetManipulatedItem())
set unit[u][i] = unit[u][i] - 1
endmethod
private static method onInit takes nothing returns nothing
set rect = Rect(0, 0, 0, 0)
set itempool = Table.create()
set unit = HashTable.create()
set shop = CreateUnit(player, 'nmrk', 0, 0, 0)
call SetRect(rect, GetUnitX(shop) - 1000, GetUnitY(shop) - 1000, GetUnitX(shop) + 1000, GetUnitY(shop) + 1000)
call UnitAddAbility(shop, 'AInv')
call IssueNeutralTargetOrder(player, shop, "smart", shop)
call ShowUnit(shop, false)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.onPickup)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
struct Slot
private boolean isVisible
private real xPos
private real yPos
readonly framehandle parent
readonly framehandle slot
readonly framehandle gold
readonly framehandle cost
Item item
Button button
method operator x= takes real newX returns nothing
set xPos = newX
call BlzFrameClearAllPoints(slot)
call BlzFrameSetPoint(slot, FRAMEPOINT_TOPLEFT, parent, FRAMEPOINT_TOPLEFT, xPos, yPos)
endmethod
method operator x takes nothing returns real
return xPos
endmethod
method operator y= takes real newY returns nothing
set yPos = newY
call BlzFrameClearAllPoints(slot)
call BlzFrameSetPoint(slot, FRAMEPOINT_TOPLEFT, parent, FRAMEPOINT_TOPLEFT, xPos, yPos)
endmethod
method operator y takes nothing returns real
return yPos
endmethod
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
call BlzFrameSetVisible(slot, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method operator onClick= takes code c returns nothing
set button.onClick = c
endmethod
method operator onScroll= takes code c returns nothing
set button.onScroll = c
endmethod
method operator onRightClick= takes code c returns nothing
set button.onRightClick = c
endmethod
method operator onDoubleClick= takes code c returns nothing
set button.onDoubleClick = c
endmethod
method destroy takes nothing returns nothing
call BlzDestroyFrame(cost)
call BlzDestroyFrame(gold)
call BlzDestroyFrame(slot)
call button.destroy()
call deallocate()
set slot = null
set gold = null
set cost = null
set parent = null
endmethod
static method create takes framehandle parent, Item i, real x, real y, framepointtype point, boolean simpleTooltip returns thistype
local thistype this = thistype.allocate()
set item = i
set xPos = x
set yPos = y
set .parent = parent
set slot = BlzCreateFrameByType("FRAME", "", parent, "", 0)
set gold = BlzCreateFrameByType("BACKDROP", "", slot, "", 0)
set cost = BlzCreateFrameByType("TEXT", "", gold, "", 0)
set button = Button.create(slot, ITEM_SIZE, ITEM_SIZE, 0, 0, simpleTooltip)
set button.tooltip.point = point
call BlzFrameSetPoint(slot, FRAMEPOINT_TOPLEFT, parent, FRAMEPOINT_TOPLEFT, x, y)
call BlzFrameSetSize(slot, SLOT_WIDTH, SLOT_HEIGHT)
call BlzFrameSetPoint(gold, FRAMEPOINT_TOPLEFT, slot, FRAMEPOINT_TOPLEFT, 0.0000, - 0.040000)
call BlzFrameSetSize(gold, GOLD_SIZE, GOLD_SIZE)
call BlzFrameSetTexture(gold, GOLD_ICON, 0, true)
call BlzFrameSetPoint(cost, FRAMEPOINT_TOPLEFT, gold, FRAMEPOINT_TOPLEFT, 0.013250, - 0.0019300)
call BlzFrameSetSize(cost, COST_WIDTH, COST_HEIGHT)
call BlzFrameSetEnable(cost, false)
call BlzFrameSetScale(cost, COST_SCALE)
call BlzFrameSetTextAlignment(cost, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_LEFT)
if item != 0 then
set button.icon = item.icon
set button.tooltip.text = item.tooltip
set button.tooltip.name = item.name
set button.tooltip.icon = item.icon
call BlzFrameSetText(cost, "|cffFFCC00" + I2S(item.gold) + "|r")
endif
return this
endmethod
endstruct
private struct ShopSlot extends Slot
Shop shop
Slot next
Slot prev
Slot right
Slot left
integer row
integer column
method destroy takes nothing returns nothing
call table.remove(GetHandleId(button.frame))
call deallocate()
endmethod
method move takes integer row, integer column returns nothing
set .row = row
set .column = column
set x = 0.030000 + ((SLOT_WIDTH + SLOT_GAP_X) * column)
set y = - (0.030000 + ((SLOT_HEIGHT + SLOT_GAP_Y) * row))
call update()
endmethod
method update takes nothing returns nothing
if column <= (shop.columns / 2) and row < 3 then
set button.tooltip.point = FRAMEPOINT_TOPLEFT
elseif column >= ((shop.columns / 2) + 1) and row < 3 then
set button.tooltip.point = FRAMEPOINT_TOPRIGHT
elseif column <= (shop.columns / 2) and row >= 3 then
set button.tooltip.point = FRAMEPOINT_BOTTOMLEFT
else
set button.tooltip.point = FRAMEPOINT_BOTTOMRIGHT
endif
endmethod
static method create takes Shop shop, Item i, integer row, integer column returns thistype
local thistype this = thistype.allocate(shop.main, i, 0.030000 + ((SLOT_WIDTH + SLOT_GAP_X) * column), - (0.030000 + ((SLOT_HEIGHT + SLOT_GAP_Y) * row)), FRAMEPOINT_TOPLEFT, false)
set .shop = shop
set next = 0
set prev = 0
set right = 0
set left = 0
set .row = row
set .column = column
set onClick = function thistype.onClicked
set onScroll = function thistype.onScrolled
set onDoubleClick = function thistype.onDoubleClicked
set onRightClick = function thistype.onRightClicked
set table[GetHandleId(button.frame)][0] = this
call update()
return this
endmethod
static method onScrolled takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
if GetLocalPlayer() == GetTriggerPlayer() then
call shop.scroll(BlzGetTriggerFrameValue() < 0)
endif
endif
endmethod
static method onClicked takes nothing returns nothing
local player p = GetTriggerPlayer()
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer id = GetPlayerId(p)
if this != 0 then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
if Shop.tag[id] then
call shop.favorites.add(item, p)
else
call shop.detail(item, p)
// if GetLocalPlayer() == p then
// if shop.lastClicked[id] != 0 then
// call Button(shop.lastClicked[id]).display(null, 0, 0, 0, null, null, 0, 0)
// endif
// call button.display(ITEM_HIGHLIGHT, HIGHLIGHT_WIDTH, HIGHLIGHT_HEIGHT, HIGHLIGHT_SCALE, FRAMEPOINT_BOTTOMLEFT, FRAMEPOINT_BOTTOMLEFT, HIGHLIGHT_XOFFSET, HIGHLIGHT_YOFFSET)
// set shop.lastClicked[id] = button
// endif
endif
endif
set p = null
set frame = null
endmethod
static method onDoubleClicked takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
if shop.buy(item, GetTriggerPlayer()) then
if GetLocalPlayer() == GetTriggerPlayer() then
call button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
endif
endmethod
static method onRightClicked takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
if shop.buy(item, GetTriggerPlayer()) then
if GetLocalPlayer() == GetTriggerPlayer() then
call button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
endif
endmethod
endstruct
private struct Transaction
private integer index
Shop shop
Item item
unit unit
player player
string type
integer gold
Table component
method destroy takes nothing returns nothing
call component.destroy()
call deallocate()
set unit = null
set player = null
endmethod
method rollback takes nothing returns nothing
local integer i = 0
local integer j = 0
local integer id = GetPlayerId(player)
if IsUnitInGroup(unit, shop.group[id]) then
if type == "buy" then
if UnitHasItemOfType(unit, item.id) then
loop
exitwhen i == UnitInventorySize(unit)
if GetItemTypeId(UnitItemInSlot(unit, i)) == item.id then
call RemoveItem(UnitItemInSlot(unit, i))
exitwhen true
endif
set i = i + 1
endloop
set i = 0
loop
exitwhen i == index
call UnitAddItemById(unit, Item(component[i]).id)
set i = i + 1
endloop
call SetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD) + gold)
if not GetSoundIsPlaying(shop.success) then
call StartSoundForPlayerBJ(player, shop.success)
endif
else
if not GetSoundIsPlaying(shop.error) then
call StartSoundForPlayerBJ(player, shop.error)
endif
endif
elseif type == "sell" then
call UnitAddItemById(unit, item.id)
call SetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD) - gold)
if not GetSoundIsPlaying(shop.success) then
call StartSoundForPlayerBJ(player, shop.success)
endif
else
loop
exitwhen i == item.components
set j = 0
loop
exitwhen j == UnitInventorySize(unit)
if GetItemTypeId(UnitItemInSlot(unit, j)) == Item.get(item.component[i]).id then
call RemoveItem(UnitItemInSlot(unit, j))
exitwhen true
endif
set j = j + 1
endloop
set i = i + 1
endloop
call UnitAddItemById(unit, item.id)
if not GetSoundIsPlaying(shop.success) then
call StartSoundForPlayerBJ(player, shop.success)
endif
endif
else
if not GetSoundIsPlaying(shop.error) then
call StartSoundForPlayerBJ(player, shop.error)
endif
endif
set shop.transactionCount[id] = shop.transactionCount[id] - 1
call shop.transaction[id].remove(shop.transactionCount[id])
call destroy()
endmethod
method add takes Item i returns nothing
if i != 0 then
set component[index] = i
set index = index + 1
endif
endmethod
static method create takes Shop shop, unit u, Item i, string transaction returns thistype
local thistype this = thistype.allocate()
set item = i
set unit = u
set .shop = shop
set type = transaction
set index = 0
set player = GetOwningPlayer(u)
set component = Table.create()
return this
endmethod
endstruct
private struct Detail
readonly static trigger trigger = CreateTrigger()
private boolean isVisible
Shop shop
Table item
Table main
Table center
Table left1
Table left2
Table right1
Table right2
Table count
HashTable used
HashTable button
Button close
Button left
Button right
framehandle frame
framehandle tooltip
framehandle topSeparator
framehandle bottomSeparator
framehandle usedIn
framehandle scrollFrame
framehandle horizontalRight
framehandle horizontalLeft
framehandle verticalMain
framehandle verticalCenter
framehandle verticalLeft1
framehandle verticalLeft2
framehandle verticalRight1
framehandle verticalRight2
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
call BlzFrameSetVisible(frame, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local integer j = 0
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call table.remove(GetHandleId(Slot(main[i]).button.frame))
call table.remove(GetHandleId(Slot(center[i]).button.frame))
call table.remove(GetHandleId(Slot(left1[i]).button.frame))
call table.remove(GetHandleId(Slot(left2[i]).button.frame))
call table.remove(GetHandleId(Slot(right1[i]).button.frame))
call table.remove(GetHandleId(Slot(right2[i]).button.frame))
call Slot(main[i]).destroy()
call Slot(center[i]).destroy()
call Slot(left1[i]).destroy()
call Slot(left2[i]).destroy()
call Slot(right1[i]).destroy()
call Slot(right2[i]).destroy()
set j = 0
loop
exitwhen j == DETAIL_USED_COUNT
call table.remove(GetHandleId(Button(button[i][j]).frame))
call Button(button[i][j]).destroy()
set j = j + 1
endloop
call button.remove(i)
call used.remove(i)
set i = i + 1
endloop
call main.destroy()
call center.destroy()
call left1.destroy()
call left2.destroy()
call right1.destroy()
call right2.destroy()
call count.destroy()
call item.destroy()
call used.destroy()
call button.destroy()
call BlzDestroyFrame(topSeparator)
call BlzDestroyFrame(bottomSeparator)
call BlzDestroyFrame(usedIn)
call BlzDestroyFrame(scrollFrame)
call BlzDestroyFrame(horizontalRight)
call BlzDestroyFrame(horizontalLeft)
call BlzDestroyFrame(verticalMain)
call BlzDestroyFrame(verticalCenter)
call BlzDestroyFrame(verticalLeft1)
call BlzDestroyFrame(verticalLeft2)
call BlzDestroyFrame(verticalRight1)
call BlzDestroyFrame(verticalRight2)
call BlzDestroyFrame(tooltip)
call BlzDestroyFrame(frame)
call deallocate()
set frame = null
set tooltip = null
set topSeparator = null
set bottomSeparator = null
set usedIn = null
set scrollFrame = null
set horizontalRight = null
set horizontalLeft = null
set verticalMain = null
set verticalCenter = null
set verticalLeft1 = null
set verticalLeft2 = null
set verticalRight1 = null
set verticalRight2 = null
endmethod
method update takes framehandle frame, framepointtype point, framehandle parent, framepointtype relative, real width, real height, real x, real y, boolean visible returns nothing
if visible then
call BlzFrameClearAllPoints(frame)
call BlzFrameSetPoint(frame, point, parent, relative, x, y)
call BlzFrameSetSize(frame, width, height)
endif
call BlzFrameSetVisible(frame, visible)
endmethod
method shift takes boolean left, player p returns nothing
local Item i
local integer j
local integer id = GetPlayerId(p)
if left then
if Item(item[id]).relation.has(count[id]) and count[id] >= DETAIL_USED_COUNT then
set j = 0
loop
exitwhen j == DETAIL_USED_COUNT - 1
set used[id][j] = used[id][j + 1]
if GetLocalPlayer() == p then
set Button(button[id][j]).icon = Item(used[id][j]).icon
set Button(button[id][j]).tooltip.text = Item(used[id][j]).tooltip
set Button(button[id][j]).tooltip.name = Item(used[id][j]).name
set Button(button[id][j]).tooltip.icon = Item(used[id][j]).icon
set Button(button[id][j]).available = shop.has(Item(used[id][j]).id)
set Button(button[id][j]).visible = true
endif
set j = j + 1
endloop
set i = Item.get(Item(item[id]).relation[count[id]])
if i != 0 then
set count[id] = count[id] + 1
set used[id][j] = i
if GetLocalPlayer() == p then
set Button(button[id][j]).icon = i.icon
set Button(button[id][j]).tooltip.text = i.tooltip
set Button(button[id][j]).tooltip.name = i.name
set Button(button[id][j]).tooltip.icon = i.icon
set Button(button[id][j]).available = shop.has(i.id)
set Button(button[id][j]).visible = true
endif
endif
endif
else
if count.integer[id] > DETAIL_USED_COUNT then
set j = DETAIL_USED_COUNT - 1
loop
exitwhen j == 0
set used[id][j] = used[id][j - 1]
if GetLocalPlayer() == p then
set Button(button[id][j]).icon = Item(used[id][j]).icon
set Button(button[id][j]).tooltip.text = Item(used[id][j]).tooltip
set Button(button[id][j]).tooltip.name = Item(used[id][j]).name
set Button(button[id][j]).tooltip.icon = Item(used[id][j]).icon
set Button(button[id][j]).available = shop.has(Item(used[id][j]).id)
set Button(button[id][j]).visible = true
endif
set j = j - 1
endloop
set i = Item.get(Item(item[id]).relation[count[id] - DETAIL_USED_COUNT - 1])
if i != 0 then
set count[id] = count[id] - 1
set used[id][j] = i
if GetLocalPlayer() == p then
set Button(button[id][j]).icon = i.icon
set Button(button[id][j]).tooltip.text = i.tooltip
set Button(button[id][j]).tooltip.name = i.name
set Button(button[id][j]).tooltip.icon = i.icon
set Button(button[id][j]).available = shop.has(i.id)
set Button(button[id][j]).visible = true
endif
endif
endif
endif
endmethod
method showUsed takes player p returns nothing
local Item i
local integer j = 0
local integer id = GetPlayerId(p)
if GetLocalPlayer() == p then
loop
exitwhen j == DETAIL_USED_COUNT
set Button(button[id][j]).visible = false
set j = j + 1
endloop
endif
set j = 0
loop
exitwhen not Item(item[id]).relation.has(j) or j == DETAIL_USED_COUNT
set i = Item.get(Item(item[id]).relation[j])
if i != 0 then
set used[id][j] = i
if GetLocalPlayer() == p then
set Button(button[id][count[id]]).icon = i.icon
set Button(button[id][count[id]]).tooltip.text = i.tooltip
set Button(button[id][count[id]]).tooltip.name = i.name
set Button(button[id][count[id]]).tooltip.icon = i.icon
set Button(button[id][count[id]]).visible = true
set Button(button[id][count[id]]).available = shop.has(i.id)
endif
set count[id] = count[id] + 1
endif
set j = j + 1
endloop
endmethod
method refresh takes player p returns nothing
local integer id = GetPlayerId(p)
if isVisible and item[id] != 0 then
call show(item[id], p)
endif
endmethod
method show takes Item i, player p returns nothing
local Item component
local Slot slot
local integer j = 0
local integer k = 0
local integer cost
local integer id = GetPlayerId(p)
local Table counter = Table.create()
if i != 0 then
set item[id] = i
set count[id] = 0
set cost = i.gold
set Slot(main[id]).item = i
call showUsed(p)
if i.components > 0 then
loop
exitwhen j == i.components or k == 5
set component = Item.get(i.component[j])
if component != 0 then
if i.components == 1 then
set slot = center[id]
if GetLocalPlayer() == p then
set Slot(left1[id]).visible = false
set Slot(left2[id]).visible = false
set Slot(right1[id]).visible = false
set Slot(right2[id]).visible = false
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.13625, - 0.10200, true)
call update(verticalMain, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.082500, true)
call update(verticalCenter, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.092500, true)
call BlzFrameSetVisible(horizontalLeft, false)
call BlzFrameSetVisible(horizontalRight, false)
call BlzFrameSetVisible(verticalLeft1, false)
call BlzFrameSetVisible(verticalLeft2, false)
call BlzFrameSetVisible(verticalRight1, false)
call BlzFrameSetVisible(verticalRight2, false)
endif
elseif i.components == 2 then
if j == 0 then
set slot = left1[id]
if GetLocalPlayer() == p then
set Slot(center[id]).visible = false
set Slot(left2[id]).visible = false
set Slot(right2[id]).visible = false
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.087250, - 0.10200, true)
call update(verticalMain, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.082500, true)
call update(horizontalLeft, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.048, 0.001, 0.10700, - 0.091500, true)
call update(verticalLeft1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.10700, - 0.092500, true)
call BlzFrameSetVisible(verticalCenter, false)
call BlzFrameSetVisible(verticalLeft2, false)
endif
else
set slot = right1[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.18525, - 0.10200, true)
call update(horizontalRight, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.048, 0.001, 0.15700, - 0.091500, true)
call update(verticalRight1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.20500, - 0.092500, true)
call BlzFrameSetVisible(verticalRight2, false)
endif
endif
elseif i.components == 3 then
if j == 0 then
set slot = left2[id]
if GetLocalPlayer() == p then
set Slot(left1[id]).visible = false
set Slot(right1[id]).visible = false
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.038250, - 0.10200, true)
call update(verticalMain, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.082500, true)
call update(horizontalLeft, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.057000, - 0.091500, true)
call update(verticalLeft2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.057000, - 0.092500, true)
call BlzFrameSetVisible(verticalLeft1, false)
endif
elseif j == 1 then
set slot = center[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.13625, - 0.10200, true)
call update(verticalCenter, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.092500, true)
endif
else
set slot = right2[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.23425, - 0.10200, true)
call update(horizontalRight, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.15700, - 0.091500, true)
call update(verticalRight2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.25600, - 0.092500, true)
call BlzFrameSetVisible(verticalRight1, false)
endif
endif
elseif i.components == 4 then
if j == 0 then
set slot = left2[id]
if GetLocalPlayer() == p then
set Slot(right2[id]).visible = false
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.038250, - 0.10200, true)
call update(verticalMain, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.082500, true)
call update(horizontalLeft, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.057000, - 0.091500, true)
call update(verticalLeft2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.057000, - 0.092500, true)
endif
elseif j == 1 then
set slot = left1[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.10350, - 0.10200, true)
call update(verticalLeft1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.12250, - 0.092500, true)
endif
elseif j == 2 then
set slot = center[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.16875, - 0.10200, true)
call update(verticalRight1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.18950, - 0.092500, true)
call BlzFrameSetVisible(verticalCenter, false)
endif
else
set slot = right1[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.23400, - 0.10200, true)
call update(horizontalRight, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.15700, - 0.091500, true)
call update(verticalRight2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.25600, - 0.092500, true)
endif
endif
else
if j == 0 then
set slot = left2[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.038250, - 0.10200, true)
call update(verticalMain, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.082500, true)
call update(horizontalLeft, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.057000, - 0.091500, true)
call update(verticalLeft2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.057000, - 0.092500, true)
endif
elseif j == 1 then
set slot = left1[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.087250, - 0.10200, true)
call update(verticalLeft1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.10700, - 0.092500, true)
endif
elseif j == 2 then
set slot = center[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.13625, - 0.10200, true)
call update(verticalCenter, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.15600, - 0.092500, true)
endif
elseif j == 3 then
set slot = right1[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.18525, - 0.10200, true)
call update(verticalRight1, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.20500, - 0.092500, true)
endif
else
set slot = right2[id]
if GetLocalPlayer() == p then
call update(slot.slot, FRAMEPOINT_TOPLEFT, slot.parent, FRAMEPOINT_TOPLEFT, SLOT_WIDTH, SLOT_HEIGHT, 0.23425, - 0.10200, true)
call update(horizontalRight, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.1, 0.001, 0.15700, - 0.091500, true)
call update(verticalRight2, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.001, 0.01, 0.25600, - 0.092500, true)
endif
endif
endif
set slot.item = component
set slot.button.icon = component.icon
set slot.button.tooltip.text = component.tooltip
set slot.button.tooltip.name = component.name
set slot.button.tooltip.icon = component.icon
set slot.button.available = shop.has(component.id)
call BlzFrameSetText(slot.cost, "|cffFFCC00" + I2S(component.gold) + "|r")
if shop.buyer.selected.unit[id] != null then
if UnitHasItemOfType(shop.buyer.selected.unit[id], component.id) then
if UnitCountItemOfType(shop.buyer.selected.unit[id], component.id) >= i.count(component.id) then
set slot.button.checked = true
else
set counter[component.id] = counter[component.id] + 1
set slot.button.checked = counter[component.id] <= UnitCountItemOfType(shop.buyer.selected.unit[id], component.id)
endif
else
set slot.button.checked = false
endif
else
set slot.button.checked = false
endif
if slot.button.checked then
set cost = cost - component.gold
endif
if GetLocalPlayer() == p then
set slot.visible = true
endif
set j = j + 1
endif
set k = k + 1
endloop
else
if GetLocalPlayer() == p then
set Slot(center[id]).visible = false
set Slot(left1[id]).visible = false
set Slot(left2[id]).visible = false
set Slot(right1[id]).visible = false
set Slot(right2[id]).visible = false
call BlzFrameSetVisible(horizontalLeft, false)
call BlzFrameSetVisible(horizontalRight, false)
call BlzFrameSetVisible(verticalMain, false)
call BlzFrameSetVisible(verticalCenter, false)
call BlzFrameSetVisible(verticalLeft1, false)
call BlzFrameSetVisible(verticalLeft2, false)
call BlzFrameSetVisible(verticalRight1, false)
call BlzFrameSetVisible(verticalRight2, false)
endif
endif
set Slot(main[id]).button.icon = i.icon
set Slot(main[id]).button.tooltip.text = i.tooltip
set Slot(main[id]).button.tooltip.name = i.name
set Slot(main[id]).button.tooltip.icon = i.icon
set Slot(main[id]).button.available = shop.has(i.id)
if GetLocalPlayer() == p then
call BlzFrameSetText(Slot(main[id]).cost, "|cffFFCC00" + I2S(cost) + "|r")
call BlzFrameSetText(tooltip, i.tooltip)
set visible = true
endif
endif
call counter.destroy()
endmethod
static method create takes Shop shop returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer j
set .shop = shop
set isVisible = false
set item = Table.create()
set count = Table.create()
set main = Table.create()
set center = Table.create()
set left1 = Table.create()
set left2 = Table.create()
set right1 = Table.create()
set right2 = Table.create()
set used = HashTable.create()
set button = HashTable.create()
set frame = BlzCreateFrame("EscMenuBackdrop", shop.main, 0, 0)
set topSeparator = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set bottomSeparator = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set tooltip = BlzCreateFrame("DescriptionArea", frame, 0, 0)
set horizontalLeft = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set horizontalRight = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalMain = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalCenter = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalLeft1 = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalLeft2 = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalRight1 = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set verticalRight2 = BlzCreateFrameByType("BACKDROP", "", frame, "", 0)
set scrollFrame = BlzCreateFrameByType("BUTTON", "", frame, "", 0)
set usedIn = BlzCreateFrameByType("TEXT", "", scrollFrame, "", 0)
set close = Button.create(frame, DETAIL_CLOSE_BUTTON_SIZE, DETAIL_CLOSE_BUTTON_SIZE, 0.26676, - 0.025000, true)
set close.icon = CLOSE_ICON
set close.onClick = function thistype.onClick
set close.tooltip.text = "Close"
set left = Button.create(scrollFrame, DETAIL_SHIFT_BUTTON_SIZE, DETAIL_SHIFT_BUTTON_SIZE, 0.0050000, - 0.0025000, true)
set left.icon = USED_LEFT
set left.onClick = function thistype.onClick
set left.tooltip.text = "Scroll Left"
set right = Button.create(scrollFrame, DETAIL_SHIFT_BUTTON_SIZE, DETAIL_SHIFT_BUTTON_SIZE, 0.24800, - 0.0025000, true)
set right.icon = USED_RIGHT
set right.onClick = function thistype.onClick
set right.tooltip.text = "Scroll Right"
set table[GetHandleId(close.frame)][0] = this
set table[GetHandleId(left.frame)][0] = this
set table[GetHandleId(right.frame)][0] = this
set table[GetHandleId(scrollFrame)][0] = this
call BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, shop.main, FRAMEPOINT_TOPLEFT, WIDTH - DETAIL_WIDTH, 0.0000)
call BlzFrameSetPoint(scrollFrame, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.022500, - 0.31550)
call BlzFrameSetPoint(topSeparator, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.027500, - 0.15585)
call BlzFrameSetPoint(bottomSeparator, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.027500, - 0.31585)
call BlzFrameSetPoint(usedIn, FRAMEPOINT_TOPLEFT, scrollFrame, FRAMEPOINT_TOPLEFT, 0.11500, - 0.0025000)
call BlzFrameSetPoint(tooltip, FRAMEPOINT_TOPLEFT, frame, FRAMEPOINT_TOPLEFT, 0.027500, - 0.15950)
call BlzFrameSetSize(frame, DETAIL_WIDTH, DETAIL_HEIGHT)
call BlzFrameSetSize(scrollFrame, 0.26750, 0.06100)
call BlzFrameSetSize(topSeparator, 0.255, 0.001)
call BlzFrameSetSize(bottomSeparator, 0.255, 0.001)
call BlzFrameSetSize(usedIn, 0.04, 0.012)
call BlzFrameSetSize(tooltip, 0.31, 0.16)
call BlzFrameSetText(tooltip, "")
call BlzFrameSetText(usedIn, "|cffFFCC00 Used in|r")
call BlzFrameSetEnable(usedIn, false)
call BlzFrameSetScale(usedIn, 1.00)
call BlzFrameSetTextAlignment(usedIn, TEXT_JUSTIFY_TOP, TEXT_JUSTIFY_LEFT)
call BlzFrameSetTexture(bottomSeparator, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(topSeparator, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(horizontalLeft, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(horizontalRight, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalMain, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalCenter, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalLeft1, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalLeft2, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalRight1, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzFrameSetTexture(verticalRight2, "replaceabletextures\\teamcolor\\teamcolor08", 0, true)
call BlzTriggerRegisterFrameEvent(trigger, scrollFrame, FRAMEEVENT_MOUSE_WHEEL)
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
set main[i] = Slot.create(frame, 0, 0.13625, - 0.030000, FRAMEPOINT_TOPRIGHT, false)
set Slot(main[i]).visible = GetLocalPlayer() == Player(i)
set Slot(main[i]).onClick = function thistype.onClick
set Slot(main[i]).onRightClick = function thistype.onRightClick
set Slot(main[i]).onDoubleClick = function thistype.onDoubleClick
set center[i] = Slot.create(frame, 0, 0.13625, - 0.10200, FRAMEPOINT_TOPRIGHT, false)
set Slot(center[i]).visible = false
set Slot(center[i]).onClick = function thistype.onClick
set Slot(center[i]).onRightClick = function thistype.onRightClick
set Slot(center[i]).onDoubleClick = function thistype.onDoubleClick
set left1[i] = Slot.create(frame, 0, 0.087250, - 0.10200, FRAMEPOINT_TOPRIGHT, false)
set Slot(left1[i]).visible = false
set Slot(left1[i]).onClick = function thistype.onClick
set Slot(left1[i]).onRightClick = function thistype.onRightClick
set Slot(left1[i]).onDoubleClick = function thistype.onDoubleClick
set left2[i] = Slot.create(frame, 0, 0.038250, - 0.10200, FRAMEPOINT_TOPRIGHT, false)
set Slot(left2[i]).visible = false
set Slot(left2[i]).onClick = function thistype.onClick
set Slot(left2[i]).onRightClick = function thistype.onRightClick
set Slot(left2[i]).onDoubleClick = function thistype.onDoubleClick
set right1[i] = Slot.create(frame, 0, 0.18525, - 0.10200, FRAMEPOINT_TOPRIGHT, false)
set Slot(right1[i]).visible = false
set Slot(right1[i]).onClick = function thistype.onClick
set Slot(right1[i]).onRightClick = function thistype.onRightClick
set Slot(right1[i]).onDoubleClick = function thistype.onDoubleClick
set right2[i] = Slot.create(frame, 0, 0.23425, - 0.10200, FRAMEPOINT_TOPRIGHT, false)
set Slot(right2[i]).visible = false
set Slot(right2[i]).onClick = function thistype.onClick
set Slot(right2[i]).onRightClick = function thistype.onRightClick
set Slot(right2[i]).onDoubleClick = function thistype.onDoubleClick
set table[GetHandleId(Slot(main[i]).button.frame)][0] = this
set table[GetHandleId(Slot(center[i]).button.frame)][0] = this
set table[GetHandleId(Slot(left1[i]).button.frame)][0] = this
set table[GetHandleId(Slot(left2[i]).button.frame)][0] = this
set table[GetHandleId(Slot(right1[i]).button.frame)][0] = this
set table[GetHandleId(Slot(right2[i]).button.frame)][0] = this
loop
exitwhen j == DETAIL_USED_COUNT
set button[i][j] = Button.create(scrollFrame, DETAIL_BUTTON_SIZE, DETAIL_BUTTON_SIZE, 0.0050000 + DETAIL_BUTTON_GAP*j, - 0.019500, false)
set Button(button[i][j]).onClick = function thistype.onClick
set Button(button[i][j]).onScroll = function thistype.onScroll
set Button(button[i][j]).onRightClick = function thistype.onRightClick
set Button(button[i][j]).tooltip.point = FRAMEPOINT_BOTTOMRIGHT
set Button(button[i][j]).visible = false
set table[GetHandleId(Button(button[i][j]).frame)][0] = this
set table[GetHandleId(Button(button[i][j]).frame)][1] = j
set j = j + 1
endloop
set i = i + 1
endloop
call BlzFrameSetVisible(frame, false)
return this
endmethod
static method onScroll takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
call shift(BlzGetTriggerFrameValue() < 0, GetTriggerPlayer())
endif
endmethod
static method onClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(GetTriggerPlayer())
if this != 0 then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
if frame == close.frame then
call shop.detail(0, GetTriggerPlayer())
elseif frame == left.frame then
call shift(false, GetTriggerPlayer())
elseif frame == right.frame then
call shift(true, GetTriggerPlayer())
elseif frame == Slot(center[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(center[id]).item, GetTriggerPlayer())
else
static if DETAIL_COMPONENT then
call shop.detail(Slot(center[id]).item, GetTriggerPlayer())
endif
endif
elseif frame == Slot(left1[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(left1[id]).item, GetTriggerPlayer())
else
static if DETAIL_COMPONENT then
call shop.detail(Slot(left1[id]).item, GetTriggerPlayer())
endif
endif
elseif frame == Slot(left2[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(left2[id]).item, GetTriggerPlayer())
else
static if DETAIL_COMPONENT then
call shop.detail(Slot(left2[id]).item, GetTriggerPlayer())
endif
endif
elseif frame == Slot(right1[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(right1[id]).item, GetTriggerPlayer())
else
static if DETAIL_COMPONENT then
call shop.detail(Slot(right1[id]).item, GetTriggerPlayer())
endif
endif
elseif frame == Slot(right2[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(right2[id]).item, GetTriggerPlayer())
else
static if DETAIL_COMPONENT then
call shop.detail(Slot(right2[id]).item, GetTriggerPlayer())
endif
endif
elseif frame != Slot(main[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(used[id][i], GetTriggerPlayer())
else
call shop.detail(used[id][i], GetTriggerPlayer())
endif
elseif frame == Slot(main[id]).button.frame then
if Shop.tag[id] then
call shop.favorites.add(Slot(main[id]).item, GetTriggerPlayer())
else
call shop.select(Slot(main[id]).item, GetTriggerPlayer())
endif
endif
endif
set frame = null
endmethod
static method onRightClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(p)
if this != 0 then
if frame == Slot(main[id]).button.frame then
if shop.buy(Slot(main[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(main[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(center[id]).button.frame then
if shop.buy(Slot(center[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(center[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(left1[id]).button.frame then
if shop.buy(Slot(left1[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(left1[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(left2[id]).button.frame then
if shop.buy(Slot(left2[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(left2[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(right1[id]).button.frame then
if shop.buy(Slot(right1[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(right1[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(right2[id]).button.frame then
if shop.buy(Slot(right2[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(right2[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
else
if shop.buy(used[id][i], p) then
if GetLocalPlayer() == p then
call Button(button[id][i]).play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
endif
endif
set p =null
set frame = null
endmethod
static method onDoubleClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(p)
if this != 0 then
if frame == Slot(main[id]).button.frame then
if shop.buy(Slot(main[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(main[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(center[id]).button.frame then
if shop.buy(Slot(center[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(center[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(left1[id]).button.frame then
if shop.buy(Slot(left1[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(left1[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(left2[id]).button.frame then
if shop.buy(Slot(left2[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(left2[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(right1[id]).button.frame then
if shop.buy(Slot(right1[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(right1[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
elseif frame == Slot(right2[id]).button.frame then
if shop.buy(Slot(right2[id]).item, p) then
if GetLocalPlayer() == p then
call Slot(right2[id]).button.play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
else
if shop.buy(used[id][i], p) then
if GetLocalPlayer() == p then
call Button(button[id][i]).play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
endif
endif
set p =null
set frame = null
endmethod
static method onInit takes nothing returns nothing
call TriggerAddAction(trigger, function thistype.onScroll)
endmethod
endstruct
private struct Inventory
private boolean isVisible
Shop shop
framehandle frame
framehandle scrollFrame
Table selected
HashTable item
HashTable button
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
call BlzFrameSetVisible(frame, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local integer j
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
loop
exitwhen j == INVENTORY_COUNT
call table.remove(GetHandleId(Button(button[i][j]).frame))
call Button(button[i][j]).destroy()
set j = j + 1
endloop
call button.remove(i)
call item.remove(i)
set i = i + 1
endloop
call BlzDestroyFrame(frame)
call BlzDestroyFrame(scrollFrame)
call selected.destroy()
call button.destroy()
call item.destroy()
call deallocate()
set frame = null
set scrollFrame = null
endmethod
method move takes framepointtype point, framehandle relative, framepointtype relativePoint returns nothing
call BlzFrameClearAllPoints(frame)
call BlzFrameSetPoint(frame, point, relative, relativePoint, 0, 0)
endmethod
method show takes unit u returns nothing
local item i
local integer j = 0
local integer id = GetPlayerId(GetOwningPlayer(u))
if u != null then
loop
exitwhen j == INVENTORY_COUNT
set i = UnitItemInSlot(u, j)
if i != null then
set item[id][j] = Item.get(GetItemTypeId(i))
if GetLocalPlayer() == GetOwningPlayer(u) then
set Button(button[id][j]).icon = Item(item[id][j]).icon
set Button(button[id][j]).tooltip.icon = Item(item[id][j]).icon
set Button(button[id][j]).tooltip.name = Item(item[id][j]).name
set Button(button[id][j]).tooltip.text = Item(item[id][j]).tooltip
set Button(button[id][j]).visible = true
endif
else
set item[id][j] = 0
if GetLocalPlayer() == GetOwningPlayer(u) then
set Button(button[id][j]).visible = false
endif
endif
set j = j + 1
endloop
else
loop
exitwhen j == INVENTORY_COUNT
set item[id][j] = 0
if GetLocalPlayer() == GetOwningPlayer(u) then
set Button(button[id][j]).visible = false
endif
set j = j + 1
endloop
endif
set i = null
endmethod
static method create takes Shop shop returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer j = 0
set .shop = shop
set isVisible = true
set selected = Table.create()
set item = HashTable.create()
set button = HashTable.create()
set frame = BlzCreateFrameByType("BACKDROP", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
set scrollFrame = BlzCreateFrameByType("BUTTON", "", frame, "", 0)
call BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, shop.buyer.frame, FRAMEPOINT_TOPLEFT, 0, 0)
call BlzFrameSetSize(frame, INVENTORY_WIDTH, INVENTORY_HEIGHT)
call BlzFrameSetTexture(frame, INVENTORY_TEXTURE, 0, false)
call BlzFrameSetAllPoints(scrollFrame, frame)
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
loop
exitwhen j == INVENTORY_COUNT
set button[i][j] = Button.create(scrollFrame, INVENTORY_SIZE, INVENTORY_SIZE, 0.0033700 + INVENTORY_GAP*j, - 0.0037500, false)
set Button(button[i][j]).tooltip.point = FRAMEPOINT_BOTTOM
set Button(button[i][j]).onClick = function thistype.onClick
set Button(button[i][j]).onDoubleClick = function thistype.onDoubleClick
set Button(button[i][j]).onRightClick = function thistype.onRightClick
set Button(button[i][j]).visible = false
set table[GetHandleId(Button(button[i][j]).frame)][0] = this
set table[GetHandleId(Button(button[i][j]).frame)][1] = j
set j = j + 1
endloop
set i = i + 1
endloop
return this
endmethod
static method onClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
if this != 0 then
set selected[GetPlayerId(GetTriggerPlayer())] = i
endif
set frame = null
endmethod
static method onDoubleClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(p)
if this != 0 then
if shop.sell(item[id][i], p, i) then
call show(shop.buyer.selected.unit[id])
endif
endif
set p = null
set frame = null
endmethod
static method onRightClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(p)
if this != 0 then
if shop.sell(item[id][i], p, i) then
call show(shop.buyer.selected.unit[id])
endif
endif
set p = null
set frame = null
endmethod
endstruct
private struct Buyer
private static Table current
readonly static trigger trigger = CreateTrigger()
private boolean isVisible
Shop shop
Inventory inventory
Button left
Button right
Table last
Table index
Table size
Table selected
HashTable button
HashTable unit
framehandle frame
framehandle scrollFrame
method operator visible= takes boolean visibility returns nothing
local integer i = 0
local integer id = GetPlayerId(GetLocalPlayer())
set isVisible = visibility
set inventory.visible = visibility
if isVisible then
loop
exitwhen i == BUYER_COUNT
if unit[id].unit[i] == selected.unit[id] then
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
exitwhen true
endif
set i = i + 1
endloop
endif
call BlzFrameSetVisible(frame, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local integer j
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
loop
exitwhen j == BUYER_COUNT
call table.remove(GetHandleId(Button(button[i][j]).frame))
call Button(button[i][j]).destroy()
set j = j + 1
endloop
call button.remove(i)
call unit.remove(i)
set i = i + 1
endloop
call BlzDestroyFrame(frame)
call BlzDestroyFrame(scrollFrame)
call button.destroy()
call unit.destroy()
call last.destroy()
call index.destroy()
call size.destroy()
call selected.destroy()
call left.destroy()
call right.destroy()
call inventory.destroy()
call deallocate()
set frame = null
set scrollFrame = null
endmethod
method shift takes boolean left, player p returns nothing
local integer id = GetPlayerId(p)
local boolean flag = false
local integer i
local unit u
if left then
if (index[id] + 1 + BUYER_COUNT) <= size[id] and size[id] > 0 then
set index[id] = index[id] + 1
set i = 0
loop
exitwhen i == BUYER_COUNT - 1
set unit[id].unit[i] = unit[id].unit[i + 1]
if GetLocalPlayer() == p then
set Button(button[id][i]).icon = Button(button[id][i + 1]).icon
set Button(button[id][i]).tooltip.text = Button(button[id][i + 1]).tooltip.text
set Button(button[id][i]).highlighted = selected.unit[id] == unit[id].unit[i]
set Button(button[id][i]).visible = true
if Button(button[id][i]).highlighted then
set flag = true
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
endif
endif
set i = i + 1
endloop
set u = BlzGroupUnitAt(shop.group[id], index[id] + BUYER_COUNT)
if u != null then
set unit[id].unit[i] = u
if GetLocalPlayer() == p then
set Button(button[id][i]).icon = BlzGetAbilityIcon(GetUnitTypeId(u))
set Button(button[id][i]).tooltip.text = GetUnitName(u)
set Button(button[id][i]).visible = true
set Button(button[id][i]).highlighted = selected.unit[id] == unit[id].unit[i]
if Button(button[id][i]).highlighted then
set flag = true
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
endif
endif
endif
if GetLocalPlayer() == p then
set inventory.visible = flag
endif
endif
else
if index[id] - 1 >= 0 and size[id] > 0 then
set index[id] = index[id] - 1
set i = BUYER_COUNT - 1
loop
exitwhen i == 0
set unit[id].unit[i] = unit[id].unit[i - 1]
if GetLocalPlayer() == p then
set Button(button[id][i]).icon = Button(button[id][i - 1]).icon
set Button(button[id][i]).tooltip.text = Button(button[id][i - 1]).tooltip.text
set Button(button[id][i]).highlighted = selected.unit[id] == unit[id].unit[i]
set Button(button[id][i]).visible = true
if Button(button[id][i]).highlighted then
set flag = true
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
endif
endif
set i = i - 1
endloop
set u = BlzGroupUnitAt(shop.group[id], index[id])
if u != null then
set unit[id].unit[i] = u
if GetLocalPlayer() == p then
set Button(button[id][i]).icon = BlzGetAbilityIcon(GetUnitTypeId(u))
set Button(button[id][i]).tooltip.text = GetUnitName(u)
set Button(button[id][i]).visible = true
set Button(button[id][i]).highlighted = selected.unit[id] == unit[id].unit[i]
if Button(button[id][i]).highlighted then
set flag = true
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
endif
endif
endif
if GetLocalPlayer() == p then
set inventory.visible = flag
endif
endif
endif
endmethod
method update takes group g, integer id returns nothing
local integer i = 0
local integer j
local unit u
set size[id] = BlzGroupGetSize(g)
if size[id] > 0 then
if (index.integer[id] + BUYER_COUNT) > size.integer[id] then
set index[id] = 0
endif
if not IsUnitInGroup(selected.unit[id], g) then
set index[id] = 0
call current.remove(GetHandleId(selected.unit[id]))
set selected.unit[id] = FirstOfGroup(g)
set current[GetHandleId(selected.unit[id])] = this
call IssueNeutralTargetOrder(Player(id), shop.current[id], "smart", selected.unit[id])
call inventory.show(selected.unit[id])
if GetLocalPlayer() == Player(id) then
call inventory.move(FRAMEPOINT_TOP, Button(button[id][0]).frame, FRAMEPOINT_BOTTOM)
call shop.details.refresh(Player(id))
endif
endif
set j = index[id]
loop
exitwhen i == BUYER_COUNT
if j >= size[id] then
set unit[id].unit[i] = null
if GetLocalPlayer() == Player(id) then
set Button(button[id][i]).visible = false
endif
else
set u = BlzGroupUnitAt(g, j)
set unit[id].unit[i] = u
if selected.unit[id] == u then
set last[id] = button[id][i]
endif
if GetLocalPlayer() == Player(id) then
set Button(button[id][i]).icon = BlzGetAbilityIcon(GetUnitTypeId(u))
set Button(button[id][i]).tooltip.text = GetUnitName(u)
set Button(button[id][i]).highlighted = selected.unit[id] == u
set Button(button[id][i]).visible = true
if Button(button[id][i]).highlighted then
set inventory.visible = true
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
endif
endif
set j = j + 1
endif
set i = i + 1
endloop
else
call current.remove(GetHandleId(selected.unit[id]))
set index[id] = 0
call selected.unit.remove(id)
if GetLocalPlayer() == Player(id) then
set inventory.visible = false
loop
exitwhen i == BUYER_COUNT
set unit[id].unit[i] = null
set Button(button[id][i]).highlighted = false
set Button(button[id][i]).visible = false
set i = i + 1
endloop
call shop.details.refresh(Player(id))
endif
endif
endmethod
static method create takes Shop shop returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer j = 0
set .shop = shop
set isVisible = true
set last = Table.create()
set size = Table.create()
set index = Table.create()
set selected = Table.create()
set button = HashTable.create()
set unit = HashTable.create()
set frame = BlzCreateFrame("EscMenuBackdrop", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
set scrollFrame = BlzCreateFrameByType("BUTTON", "", frame, "", 0)
set left = Button.create(scrollFrame, BUYER_SHIFT_BUTTON_SIZE, BUYER_SHIFT_BUTTON_SIZE, 0.027500, - 0.032500, true)
set left.onClick = function thistype.onClick
set left.icon = BUYER_LEFT
set left.tooltip.text = "Scroll Left"
set right = Button.create(scrollFrame, BUYER_SHIFT_BUTTON_SIZE, BUYER_SHIFT_BUTTON_SIZE, 0.36350, - 0.032500, true)
set right.onClick = function thistype.onClick
set right.icon = BUYER_RIGHT
set right.tooltip.text = "Scroll Right"
set inventory = Inventory.create(shop)
set table[GetHandleId(left.frame)][0] = this
set table[GetHandleId(right.frame)][0] = this
set table[GetHandleId(scrollFrame)][0] = this
call BlzFrameSetPoint(frame, FRAMEPOINT_TOP, shop.base, FRAMEPOINT_BOTTOM, 0, 0.02750)
call BlzFrameSetSize(frame, BUYER_WIDTH, BUYER_HEIGHT)
call BlzFrameSetAllPoints(scrollFrame, frame)
call BlzTriggerRegisterFrameEvent(trigger, scrollFrame, FRAMEEVENT_MOUSE_WHEEL)
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
loop
exitwhen j == BUYER_COUNT
set button[i][j] = Button.create(scrollFrame, BUYER_SIZE, BUYER_SIZE, 0.045000 + BUYER_GAP*j, - 0.023000, true)
set Button(button[i][j]).onClick = function thistype.onClick
set Button(button[i][j]).onScroll = function thistype.onScroll
set Button(button[i][j]).visible = false
set table[GetHandleId(Button(button[i][j]).frame)][0] = this
set table[GetHandleId(Button(button[i][j]).frame)][1] = j
set j = j + 1
endloop
set i = i + 1
endloop
return this
endmethod
static method onScroll takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
call shift(BlzGetTriggerFrameValue() < 0, GetTriggerPlayer())
endif
endmethod
static method onClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(GetTriggerPlayer())
if this != 0 then
if frame == left.frame then
call shift(false, GetTriggerPlayer())
elseif frame == right.frame then
call shift(true, GetTriggerPlayer())
else
call current.remove(GetHandleId(selected.unit[id]))
set selected.unit[id] = unit[id].unit[i]
set current[GetHandleId(selected.unit[id])] = this
call IssueNeutralTargetOrder(GetTriggerPlayer(), shop.current[id], "smart", selected.unit[id])
call inventory.show(selected.unit[id])
call inventory.selected.remove(id)
if GetLocalPlayer() == GetTriggerPlayer() then
set Button(last[id]).highlighted = false
set Button(button[id][i]).highlighted = true
set last[id] = button[id][i]
call inventory.move(FRAMEPOINT_TOP, Button(button[id][i]).frame, FRAMEPOINT_BOTTOM)
call shop.details.refresh(GetTriggerPlayer())
endif
endif
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
endif
set frame = null
endmethod
private static method onPickup takes nothing returns nothing
local unit u = GetManipulatingUnit()
local integer i = GetPlayerId(GetOwningPlayer(u))
local thistype this = current[GetHandleId(u)]
if this != 0 then
if shop.current[i] != null then
if selected.unit[i] == u and IsUnitInRange(u, shop.current[i], shop.aoe) then
call inventory.show(u)
call shop.details.refresh(GetOwningPlayer(u))
endif
endif
endif
set u = null
endmethod
private static method onDrop takes nothing returns nothing
local unit u = GetManipulatingUnit()
local integer i = GetPlayerId(GetOwningPlayer(u))
local thistype this = current[GetHandleId(u)]
if this != 0 then
if shop.current[i] != null then
if selected.unit[i] == u and IsUnitInRange(u, shop.current[i], shop.aoe) then
call shop.details.refresh(GetOwningPlayer(u))
endif
endif
endif
set u = null
endmethod
static method onInit takes nothing returns nothing
set current = Table.create()
call TriggerAddAction(trigger, function thistype.onScroll)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.onPickup)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.onDrop)
endmethod
endstruct
private struct Favorites
Shop shop
Table count
HashTable item
HashTable button
method destroy takes nothing returns nothing
local integer i = 0
local integer j
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
loop
exitwhen j == CATEGORY_COUNT
call table.remove(GetHandleId(Button(button[i][j]).frame))
call Button(button[i][j]).destroy()
set j = j + 1
endloop
call button.remove(i)
call item.remove(i)
set i = i + 1
endloop
call count.destroy()
call item.destroy()
call button.destroy()
call deallocate()
endmethod
method has takes integer id, player p returns boolean
local integer i = 0
local integer pid = GetPlayerId(p)
loop
exitwhen i > count.integer[pid]
if Item(item[pid][i]).id == id then
return true
endif
set i = i + 1
endloop
return false
endmethod
method clear takes player p returns nothing
local integer id = GetPlayerId(p)
loop
exitwhen count[id] == -1
if GetLocalPlayer() == p then
set Button(button[id][count[id]]).visible = false
call ShopSlot(table[shop][Item(item[id][count[id]]).id]).button.tag(null, 0, 0, 0, null, null, 0, 0)
endif
set count[id] = count[id] - 1
endloop
endmethod
method remove takes integer i, player p returns nothing
local integer id = GetPlayerId(p)
if GetLocalPlayer() == p then
call ShopSlot(table[shop][Item(item[id][i]).id]).button.tag(null, 0, 0, 0, null, null, 0, 0)
endif
loop
exitwhen i >= count[id]
set item[id][i] = item[id][i + 1]
if GetLocalPlayer() == p then
set Button(button[id][i]).icon = Item(item[id][i]).icon
set Button(button[id][i]).tooltip.text = Item(item[id][i]).tooltip
set Button(button[id][i]).tooltip.name = Item(item[id][i]).name
set Button(button[id][i]).tooltip.icon = Item(item[id][i]).icon
endif
set i = i + 1
endloop
if GetLocalPlayer() == p then
set Button(button[id][count[id]]).visible = false
endif
set count[id] = count[id] - 1
endmethod
method add takes Item i, player p returns nothing
local integer id = GetPlayerId(p)
if count.integer[id] < CATEGORY_COUNT - 1 then
if not has(i.id, p) then
set count[id] = count[id] + 1
set item[id][count[id]] = i
if GetLocalPlayer() == p then
set Button(button[id][count[id]]).icon = i.icon
set Button(button[id][count[id]]).tooltip.text = i.tooltip
set Button(button[id][count[id]]).tooltip.name = i.name
set Button(button[id][count[id]]).tooltip.icon = i.icon
set Button(button[id][count[id]]).visible = true
call ShopSlot(table[shop][i.id]).button.tag(TAG_HIGHLIGHT, TAG_HIGHLIGHT_WIDTH, TAG_HIGHLIGHT_HEIGHT, TAG_HIGHLIGHT_SCALE, FRAMEPOINT_BOTTOMLEFT, FRAMEPOINT_BOTTOMLEFT, TAG_HIGHLIGHT_XOFFSET, TAG_HIGHLIGHT_YOFFSET)
endif
endif
endif
endmethod
static method create takes Shop shop returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local integer j
set .shop = shop
set count = Table.create()
set item = HashTable.create()
set button = HashTable.create()
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set j = 0
set count[i] = -1
loop
exitwhen j == CATEGORY_COUNT
set button[i][j] = Button.create(shop.rightPanel, CATEGORY_SIZE, CATEGORY_SIZE, 0.023750, - (0.021500 + CATEGORY_SIZE*j + CATEGORY_GAP), false)
set Button(button[i][j]).visible = false
set Button(button[i][j]).onClick = function thistype.onClick
set Button(button[i][j]).onDoubleClick = function thistype.onDoubleClick
set Button(button[i][j]).tooltip.point = FRAMEPOINT_TOPRIGHT
set table[GetHandleId(Button(button[i][j]).frame)][0] = this
set table[GetHandleId(Button(button[i][j]).frame)][1] = j
if j > 6 then
set Button(button[i][j]).tooltip.point = FRAMEPOINT_BOTTOMRIGHT
endif
set j = j + 1
endloop
set i = i + 1
endloop
return this
endmethod
static method onClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(GetTriggerPlayer())
if this != 0 then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
if Shop.tag[id] then
call remove(i, GetTriggerPlayer())
else
call shop.detail(item[id][i], GetTriggerPlayer())
endif
endif
set frame = null
endmethod
static method onDoubleClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local player p = GetTriggerPlayer()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
local integer id = GetPlayerId(p)
if this != 0 then
if shop.buy(item[id][i], p) then
if GetLocalPlayer() == p then
call Button(button[id][i]).play(SPRITE_MODEL, SPRITE_SCALE, 0)
endif
endif
endif
set p = null
set frame = null
endmethod
endstruct
private struct Category
Shop shop
integer count
integer active
boolean andLogic
integer array value[CATEGORY_COUNT]
Button array button[CATEGORY_COUNT]
method destroy takes nothing returns nothing
loop
exitwhen count == -1
call table.remove(GetHandleId(button[count].frame))
call button[count].destroy()
set count = count - 1
endloop
call deallocate()
endmethod
method clear takes nothing returns nothing
local integer i = 0
set active = 0
loop
exitwhen i == CATEGORY_COUNT
set button[i].enabled = false
set i = i + 1
endloop
call shop.filter(active, andLogic)
endmethod
method add takes string icon, string description returns integer
if count < CATEGORY_COUNT then
set count = count + 1
set value[count] = R2I(Pow(2, count))
set button[count] = Button.create(shop.leftPanel, CATEGORY_SIZE, CATEGORY_SIZE, 0.023750, - (0.021500 + CATEGORY_SIZE*count + CATEGORY_GAP), true)
set button[count].icon = icon
set button[count].enabled = false
set button[count].onClick = function thistype.onClick
set button[count].tooltip.text = description
set table[GetHandleId(button[count].frame)][0] = this
set table[GetHandleId(button[count].frame)][1] = count
return value[count]
else
call BJDebugMsg("Maximum number os categories reached.")
endif
return 0
endmethod
static method create takes Shop shop returns thistype
local thistype this = thistype.allocate()
set count = -1
set active = 0
set andLogic = true
set .shop = shop
return this
endmethod
static method onClick takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local integer i = table[GetHandleId(frame)][1]
if this != 0 then
if GetLocalPlayer() == GetTriggerPlayer() then
set button[i].enabled = not button[i].enabled
if button[i].enabled then
set active = active + value[i]
else
set active = active - value[i]
endif
call shop.filter(active, andLogic)
endif
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
endif
set frame = null
endmethod
endstruct
struct Shop
private static trigger trigger = CreateTrigger()
private static trigger search = CreateTrigger()
private static trigger keyPress = CreateTrigger()
private static trigger escPressed = CreateTrigger()
private static timer update = CreateTimer()
private static integer count = -1
private static HashTable itempool
readonly static sound success
readonly static sound error
readonly static sound array noGold
readonly static group array group
readonly static timer array timer
readonly static boolean array canScroll
readonly static boolean array tag
readonly static unit array current
private boolean isVisible
readonly framehandle base
readonly framehandle main
readonly framehandle edit
readonly framehandle leftPanel
readonly framehandle rightPanel
readonly Category category
readonly Favorites favorites
readonly Detail details
readonly Buyer buyer
readonly Button close
readonly Button break
readonly Button revert
readonly Button logic
readonly Button clearCategory
readonly Button clearFavorites
readonly ShopSlot first
readonly ShopSlot last
readonly ShopSlot head
readonly ShopSlot tail
readonly integer id
readonly integer index
readonly integer size
readonly integer rows
readonly integer columns
readonly boolean detailed
readonly real aoe
readonly real tax
Table lastClicked
HashTable transaction
Table transactionCount
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
set buyer.visible = visibility
if not visibility then
set buyer.index = 0
else
if details.visible then
call details.refresh(GetLocalPlayer())
endif
endif
call BlzFrameSetVisible(base, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method destroy takes nothing returns nothing
local integer i = 0
local ShopSlot slot = itempool[this][0]
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call transaction[i].flush()
set i = i + 1
endloop
loop
exitwhen slot == 0
call slot.destroy()
set slot = slot.next
endloop
call table.remove(id)
call table.remove(this)
call itempool.remove(this)
call BlzDestroyFrame(rightPanel)
call BlzDestroyFrame(leftPanel)
call BlzDestroyFrame(main)
call BlzDestroyFrame(base)
call lastClicked.destroy()
call transaction.destroy()
call transactionCount.destroy()
call break.destroy()
call revert.destroy()
call category.destroy()
call favorites.destroy()
call details.destroy()
call buyer.destroy()
call deallocate()
set base = null
set main = null
set leftPanel = null
set rightPanel = null
endmethod
method buy takes Item i, player p returns boolean
local unit u
local item new
local Item component
local Transaction t
local integer cost
local integer gold
local integer j = 0
local integer k = 0
local integer id = GetPlayerId(p)
local boolean canBuy = false
local Table counter = Table.create()
if i != 0 and buyer.selected.unit.has(id) then
if has(i.id) then
set canBuy = true
set u = buyer.selected.unit[id]
set gold = GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)
set cost = i.gold
if i.components > 0 then
loop
exitwhen j == i.components or not canBuy
set component = Item.get(i.component[j])
if UnitHasItemOfType(u, component.id) and counter.integer[component.id] < UnitCountItemOfType(u, component.id) then
set cost = cost - component.gold
set counter[component.id] = counter[component.id] + 1
else
set canBuy = has(component.id)
endif
set j = j + 1
endloop
endif
if canBuy and gold >= cost then
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, gold - cost)
set t = Transaction.create(this, u, i, "buy")
set t.gold = cost
set j = 0
if i.components > 0 then
loop
exitwhen j == i.components
set k = 0
loop
exitwhen k == UnitInventorySize(u)
if GetItemTypeId(UnitItemInSlot(u, k)) == i.component[j] then
call t.add(Item.get(GetItemTypeId(UnitItemInSlot(u, k))))
call RemoveItem(UnitItemInSlot(u, k))
exitwhen true
endif
set k = k + 1
endloop
set j = j + 1
endloop
endif
set transaction[id][transactionCount[id]] = t
set transactionCount[id] = transactionCount[id] + 1
set new = CreateItem(i.id, GetUnitX(u), GetUnitY(u))
if not UnitAddItem(u, new) then
call IssueTargetItemOrder(u, "smart", new)
endif
if not GetSoundIsPlaying(success) then
call StartSoundForPlayerBJ(p, success)
endif
call buyer.inventory.show(u)
call details.refresh(p)
else
set canBuy = false
if gold < cost then
if not GetSoundIsPlaying(noGold[GetHandleId(GetPlayerRace(p))]) then
call StartSoundForPlayerBJ(p, noGold[GetHandleId(GetPlayerRace(p))])
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
call counter.destroy()
set new = null
return canBuy
endmethod
method sell takes Item i, player p, integer slot returns boolean
local unit u
local Transaction t
local integer cost
local integer gold
local integer charges
local integer id = GetPlayerId(p)
local boolean sold = false
if i != 0 and buyer.selected.unit.has(id) then
set u = buyer.selected.unit[id]
set charges = GetItemCharges(UnitItemInSlot(u, slot))
if charges == 0 then
set charges = 1
endif
set gold = GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)
set cost = R2I(R2I(i.gold / i.charges) * charges * tax)
if GetItemTypeId(UnitItemInSlot(u, slot)) == i.id then
set sold = true
set t = Transaction.create(this, u, i, "sell")
set t.gold = cost
set transaction[id][transactionCount[id]] = t
set transactionCount[id] = transactionCount[id] + 1
call RemoveItem(UnitItemInSlot(u, slot))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, gold + cost)
call buyer.inventory.show(u)
call details.refresh(p)
endif
if not GetSoundIsPlaying(success) then
call StartSoundForPlayerBJ(p, success)
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
return sold
endmethod
method dismantle takes Item i, player p, integer slot returns nothing
local unit u
local Transaction t
local integer slots = 0
local integer j = 0
local integer id = GetPlayerId(p)
if i != 0 and buyer.selected.unit.has(id) then
if i.components > 0 then
set u = buyer.selected.unit[id]
loop
exitwhen j == UnitInventorySize(u)
if UnitItemInSlot(u, j) == null then
set slots = slots + 1
endif
set j = j + 1
endloop
if (slots + 1) >= i.components then
set j = 0
set t = Transaction.create(this, u, i, "dismantle")
set transaction[id][transactionCount[id]] = t
set transactionCount[id] = transactionCount[id] + 1
call RemoveItem(UnitItemInSlot(u, slot))
loop
exitwhen j == i.components
call UnitAddItemById(u, Item.get(i.component[j]).id)
set j = j + 1
endloop
if not GetSoundIsPlaying(success) then
call StartSoundForPlayerBJ(p, success)
endif
call buyer.inventory.show(u)
call details.refresh(p)
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
set u = null
endmethod
method undo takes player p returns nothing
local integer id = GetPlayerId(p)
if transactionCount[id] > 0 then
call Transaction(transaction[id][transactionCount[id] - 1]).rollback()
call buyer.inventory.show(buyer.selected.unit[id])
call details.refresh(p)
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
endmethod
method scroll takes boolean down returns nothing
local ShopSlot slot = first
if (down and tail != last) or (not down and head != first) then
loop
exitwhen slot == 0
if down then
call slot.move(slot.row - 1, slot.column)
else
call slot.move(slot.row + 1, slot.column)
endif
set slot.visible = slot.row >= 0 and slot.row <= rows - 1 and slot.column >= 0 and slot.column <= columns - 1
if slot.row == 0 and slot.column == 0 then
set head = slot
endif
if (slot.row == rows - 1 and slot.column == columns - 1) or (slot == last and slot.visible) then
set tail = slot
endif
set slot = slot.right
endloop
endif
endmethod
method filter takes integer categories, boolean andLogic returns nothing
local ShopSlot slot = itempool[this][0]
local string text = BlzFrameGetText(edit)
local boolean process
local integer i = -1
set size = 0
set first = 0
set last = 0
set head = 0
set tail = 0
loop
exitwhen slot == 0
if andLogic then
set process = categories == 0 or BlzBitAnd(slot.item.categories, categories) >= categories
else
set process = categories == 0 or BlzBitAnd(slot.item.categories, categories) > 0
endif
if text != "" and text != null then
set process = process and find(StringCase(slot.item.name, false), StringCase(text, false))
endif
if process then
set i = i + 1
set size = size + 1
call slot.move(R2I(i/columns), ModuloInteger(i, columns))
set slot.visible = slot.row >= 0 and slot.row <= rows - 1 and slot.column >= 0 and slot.column <= columns - 1
if i > 0 then
set slot.left = last
set last.right = slot
else
set first = slot
set head = first
endif
if slot.visible then
set tail = slot
endif
set last = slot
else
set slot.visible = false
endif
set slot = slot.next
endloop
endmethod
method select takes Item i, player p returns nothing
local integer id = GetPlayerId(p)
if i != 0 and GetLocalPlayer() == p then
if lastClicked[id] != 0 then
call Button(lastClicked[id]).display(null, 0, 0, 0, null, null, 0, 0)
endif
set lastClicked[id] = ShopSlot(table[this][i.id]).button
call Button(lastClicked[id]).display(ITEM_HIGHLIGHT, HIGHLIGHT_WIDTH, HIGHLIGHT_HEIGHT, HIGHLIGHT_SCALE, FRAMEPOINT_BOTTOMLEFT, FRAMEPOINT_BOTTOMLEFT, HIGHLIGHT_XOFFSET, HIGHLIGHT_YOFFSET)
endif
endmethod
method detail takes Item i, player p returns nothing
if i != 0 then
if GetLocalPlayer() == p then
set rows = DETAILED_ROWS
set columns = DETAILED_COLUMNS
if not detailed then
set detailed = true
call filter(category.active, category.andLogic)
endif
endif
call select(i, p)
call details.show(i, p)
else
if GetLocalPlayer() == p then
set rows = ROWS
set columns = COLUMNS
set detailed = false
set details.visible = false
call filter(category.active, category.andLogic)
endif
endif
endmethod
method has takes integer id returns boolean
return table[this].has(id)
endmethod
method clearTransactions takes player p returns nothing
local integer i = 0
local integer id = GetPlayerId(p)
loop
exitwhen i == transactionCount[id]
call Transaction(transaction[id][i]).destroy()
set i = i + 1
endloop
set transactionCount[id] = 0
call transaction[id].flush()
endmethod
private method find takes string source, string target returns boolean
local integer sourceLength = StringLength(source)
local integer targetLenght = StringLength(target)
local integer i = 0
if targetLenght <= sourceLength then
loop
exitwhen i > sourceLength - targetLenght
if SubString(source, i, i + targetLenght) == target then
return true
endif
set i = i + 1
endloop
endif
return false
endmethod
static method addCategory takes integer id, string icon, string description returns integer
local thistype this = table[id][0]
if this != 0 then
return category.add(icon, description)
endif
return 0
endmethod
static method addItem takes integer id, integer itemId, integer categories returns nothing
local thistype this = table[id][0]
local ShopSlot slot
local Item i
if this != 0 then
if not table[this].has(itemId) then
set i = Item.create(itemId, categories)
if i != 0 then
set size = size + 1
set index = index + 1
set slot = ShopSlot.create(this, i, R2I(index/COLUMNS), ModuloInteger(index, COLUMNS))
set slot.visible = slot.row >= 0 and slot.row <= ROWS - 1 and slot.column >= 0 and slot.column <= COLUMNS - 1
if index > 0 then
set slot.prev = last
set slot.left = last
set last.next = slot
set last.right = slot
else
set first = slot
set head = slot
endif
if slot.visible then
set tail = slot
endif
set last = slot
set table[this][itemId] = slot
set itempool[this][index] = slot
else
call BJDebugMsg("Invalid item code: " + A2S(itemId))
endif
else
call BJDebugMsg("The item " + GetObjectName(itemId) + " is already registered for the shop " + GetObjectName(id))
endif
endif
endmethod
static method create takes integer id, real aoe, real returnRate returns thistype
local thistype this
local integer i = 0
if not table[id].has(0) then
set this = thistype.allocate()
set .id = id
set .aoe = aoe
set tax = returnRate
set first = 0
set last = 0
set head = 0
set tail = 0
set size = 0
set index = -1
set rows = ROWS
set columns = COLUMNS
set count = count + 1
set detailed = false
set lastClicked = Table.create()
set transactionCount = Table.create()
set transaction = HashTable.create()
set base = BlzCreateFrame("EscMenuBackdrop", BlzGetFrameByName("ConsoleUIBackdrop", 0), 0, 0)
set main = BlzCreateFrameByType("BUTTON", "main", base, "", 0)
set edit = BlzCreateFrame("EscMenuEditBoxTemplate", main, 0, 0)
set leftPanel = BlzCreateFrame("EscMenuBackdrop", base, 0, 0)
set rightPanel = BlzCreateFrame("EscMenuBackdrop", base, 0, 0)
set category = Category.create(this)
set favorites = Favorites.create(this)
set details = Detail.create(this)
set buyer = Buyer.create(this)
set close = Button.create(main, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, (WIDTH - 2*TOOLBAR_BUTTON_SIZE), 0.015000, true)
set close.icon = CLOSE_ICON
set close.onClick = function thistype.onClose
set close.tooltip.text = "Close"
set break = Button.create(main, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, (WIDTH - 2*TOOLBAR_BUTTON_SIZE - 0.0205), 0.015000, true)
set break.icon = DISMANTLE_ICON
set break.onClick = function thistype.onDismantle
set break.tooltip.text = "Dismantle"
set revert = Button.create(main, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, (WIDTH - 2*TOOLBAR_BUTTON_SIZE - 0.0410), 0.015000, true)
set revert.icon = UNDO_ICON
set revert.onClick = function thistype.onUndo
set revert.tooltip.text = "Undo"
set clearCategory = Button.create(leftPanel, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, 0.028000, 0.015000, true)
set clearCategory.icon = CLEAR_ICON
set clearCategory.onClick = function thistype.onClear
set clearCategory.tooltip.text = "Clear Category"
set clearFavorites = Button.create(rightPanel, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, 0.027000, 0.015000, true)
set clearFavorites.icon = CLEAR_ICON
set clearFavorites.onClick = function thistype.onClear
set clearFavorites.tooltip.text = "Clear Favorites"
set logic = Button.create(leftPanel, TOOLBAR_BUTTON_SIZE, TOOLBAR_BUTTON_SIZE, 0.049000, 0.015000, true)
set logic.icon = LOGIC_ICON
set logic.onClick = function thistype.onLogic
set logic.enabled = false
set logic.tooltip.text = "AND Logic"
set table[id][0] = this
set table[GetHandleId(main)][0] = this
set table[GetHandleId(close.frame)][0] = this
set table[GetHandleId(break.frame)][0] = this
set table[GetHandleId(revert.frame)][0] = this
set table[GetHandleId(clearCategory.frame)][0] = this
set table[GetHandleId(clearFavorites.frame)][0] = this
set table[GetHandleId(logic.frame)][0] = this
set table[GetHandleId(edit)][0] = this
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set timer[i] = CreateTimer()
set group[i] = CreateGroup()
set canScroll[i] = true
set table[GetHandleId(Player(i))][id] = this
set table[GetHandleId(Player(i))][count] = id
set i = i + 1
endloop
call BlzFrameSetAbsPoint(base, FRAMEPOINT_TOPLEFT, X, Y)
call BlzFrameSetSize(base, WIDTH, HEIGHT)
call BlzFrameSetPoint(main, FRAMEPOINT_TOPLEFT, base, FRAMEPOINT_TOPLEFT, 0.0000, 0.0000)
call BlzFrameSetSize(main, WIDTH, HEIGHT)
call BlzFrameSetPoint(edit, FRAMEPOINT_TOPLEFT, main, FRAMEPOINT_TOPLEFT, 0.021000, 0.020000)
call BlzFrameSetSize(edit, EDIT_WIDTH, EDIT_HEIGHT)
call BlzFrameSetPoint(leftPanel, FRAMEPOINT_TOPLEFT, base, FRAMEPOINT_TOPLEFT, -0.04800, 0.0000)
call BlzFrameSetSize(leftPanel, SIDE_WIDTH, SIDE_HEIGHT)
call BlzFrameSetPoint(rightPanel, FRAMEPOINT_TOPLEFT, base, FRAMEPOINT_TOPLEFT, (WIDTH - 0.027), 0.0000)
call BlzFrameSetSize(rightPanel, SIDE_WIDTH, SIDE_HEIGHT)
call BlzTriggerRegisterFrameEvent(trigger, main, FRAMEEVENT_MOUSE_WHEEL)
call BlzTriggerRegisterFrameEvent(search, edit, FRAMEEVENT_EDITBOX_TEXT_CHANGED)
set visible = false
endif
return this
endmethod
private static method onExpire takes nothing returns nothing
set canScroll[GetPlayerId(GetLocalPlayer())] = true
endmethod
private static method onPeriod takes nothing returns nothing
local thistype this
local unit shop
local unit u
local group g
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set g = CreateGroup()
set shop = current[i]
set this = table[GetUnitTypeId(shop)][0]
if this != 0 then
call GroupClear(group[i])
call GroupEnumUnitsInRange(g, GetUnitX(shop), GetUnitY(shop), aoe, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if ShopFilter(u, Player(i), shop) then
call GroupAddUnit(group[i], u)
endif
call GroupRemoveUnit(g, u)
endloop
call buyer.update(group[i], i)
endif
call DestroyGroup(g)
set i = i + 1
endloop
set g = null
set shop = null
endmethod
private static method onSearch takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
if GetLocalPlayer() == GetTriggerPlayer() then
call filter(category.active, category.andLogic)
endif
endif
endmethod
private static method onLogic takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
if this != 0 then
if GetLocalPlayer() == GetTriggerPlayer() then
set logic.enabled = not logic.enabled
set category.andLogic = not category.andLogic
if category.andLogic then
set logic.tooltip.text = "AND Logic"
else
set logic.tooltip.text = "OR Logic"
endif
call filter(category.active, category.andLogic)
endif
call BlzFrameSetEnable(logic.frame, false)
call BlzFrameSetEnable(logic.frame, true)
endif
endmethod
private static method onClear takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
if this != 0 then
if frame == clearCategory.frame then
if GetLocalPlayer() == GetTriggerPlayer() then
call category.clear()
endif
else
call favorites.clear(GetTriggerPlayer())
endif
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
endif
set frame = null
endmethod
private static method onClose takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if this != 0 then
if GetLocalPlayer() == p then
set visible = false
endif
set current[id] = null
call clearTransactions(p)
endif
set p = null
endmethod
private static method onDismantle takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if this != 0 then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
if buyer.inventory.selected.has(id) then
call dismantle(Item(buyer.inventory.item[id][buyer.inventory.selected[id]]), p, buyer.inventory.selected[id])
else
if not GetSoundIsPlaying(error) then
call StartSoundForPlayerBJ(p, error)
endif
endif
endif
set p = null
set frame = null
endmethod
private static method onUndo takes nothing returns nothing
local framehandle frame = BlzGetTriggerFrame()
local thistype this = table[GetHandleId(frame)][0]
if this != 0 then
call BlzFrameSetEnable(frame, false)
call BlzFrameSetEnable(frame, true)
call undo(GetTriggerPlayer())
endif
set frame = null
endmethod
private static method onScroll takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())][0]
local integer i = GetPlayerId(GetLocalPlayer())
if this != 0 then
if GetLocalPlayer() == GetTriggerPlayer() then
if canScroll[i] then
if SCROLL_DELAY > 0 then
set canScroll[i] = false
endif
call scroll(BlzGetTriggerFrameValue() < 0)
endif
endif
endif
if SCROLL_DELAY > 0 then
call TimerStart(timer[i], TimerGetRemaining(timer[i]), false, function thistype.onExpire)
endif
endmethod
private static method onSelect takes nothing returns nothing
local thistype this = table[GetUnitTypeId(GetTriggerUnit())][0]
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
if this != 0 then
if GetLocalPlayer() == p then
set visible = GetTriggerEventId() == EVENT_PLAYER_UNIT_SELECTED
endif
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SELECTED then
set current[id] = GetTriggerUnit()
call buyer.inventory.show(buyer.selected.unit[id])
else
set current[id] = null
call clearTransactions(p)
endif
endif
set p = null
endmethod
private static method onKey takes nothing returns nothing
set tag[GetPlayerId(GetTriggerPlayer())] = BlzGetTriggerPlayerIsKeyDown()
endmethod
private static method onEsc takes nothing returns nothing
local thistype this
local player p = GetTriggerPlayer()
local integer i = 0
local integer id = GetHandleId(p)
loop
exitwhen i > count
set this = table[id][table[id][i]]
if this != 0 then
if GetLocalPlayer() == p then
set visible = false
endif
set current[GetPlayerId(p)] = null
call clearTransactions(p)
endif
set i = i + 1
endloop
set p = null
endmethod
private static method onInit takes nothing returns nothing
local integer i = 0
local integer id
set table = HashTable.create()
set itempool = HashTable.create()
set success = CreateSound(SUCCESS_SOUND, false, false, false, 10, 10, "")
call SetSoundDuration(success, 1600)
set error = CreateSound(ERROR_SOUND, false, false, false, 10, 10, "")
call SetSoundDuration(error, 614)
set id = GetHandleId(RACE_HUMAN)
set noGold[id] = CreateSound("Sound\\Interface\\Warning\\Human\\KnightNoGold1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(noGold[id], "NoGoldHuman")
call SetSoundDuration(noGold[id], 1618)
set id = GetHandleId(RACE_ORC)
set noGold[id] = CreateSound("Sound\\Interface\\Warning\\Orc\\GruntNoGold1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(noGold[id], "NoGoldOrc")
call SetSoundDuration(noGold[id], 1450)
set id = GetHandleId(RACE_NIGHTELF)
set noGold[id] = CreateSound("Sound\\Interface\\Warning\\NightElf\\SentinelNoGold1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(noGold[id], "NoGoldNightElf")
call SetSoundDuration(noGold[id], 1229)
set id = GetHandleId(RACE_UNDEAD)
set noGold[id] = CreateSound("Sound\\Interface\\Warning\\Undead\\NecromancerNoGold1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(noGold[id], "NoGoldUndead")
call SetSoundDuration(noGold[id], 2005)
set id = GetHandleId(ConvertRace(11))
set noGold[id] = CreateSound("Sound\\Interface\\Warning\\Naga\\NagaNoGold1.wav", false, false, false, 10, 10, "")
call SetSoundParamsFromLabel(noGold[id], "NoGoldNaga")
call SetSoundDuration(noGold[id], 2690)
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set tag[i] = false
call BlzTriggerRegisterPlayerKeyEvent(keyPress, Player(i), FAVORITE_KEY, 0, true)
call BlzTriggerRegisterPlayerKeyEvent(keyPress, Player(i), FAVORITE_KEY, 0, false)
call TriggerRegisterPlayerEventEndCinematic(escPressed, Player(i))
set i = i + 1
endloop
call BlzLoadTOCFile("Shop.toc")
call TimerStart(update, UPDATE_PERIOD, true, function thistype.onPeriod)
call TriggerAddAction(trigger, function thistype.onScroll)
call TriggerAddCondition(search, Condition(function thistype.onSearch))
call TriggerAddCondition(keyPress, Condition(function thistype.onKey))
call TriggerAddCondition(escPressed, Condition(function thistype.onEsc))
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function thistype.onSelect)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DESELECTED, function thistype.onSelect)
endmethod
endstruct
endlibrary
library Components requires Table
/* ------------------------------------ Components v1.0 ------------------------------------ */
// Credits:
// Taysen: FDF file
// Bribe: Table library
/* -------------------------------------- By Chopinski ------------------------------------- */
/* ----------------------------------------------------------------------------------------- */
/* Configuration */
/* ----------------------------------------------------------------------------------------- */
globals
private constant real TOOLTIP_SIZE = 0.2
private constant real SCROLL_DELAY = 0.01
private constant real DOUBLE_CLICK_DELAY = 0.25
private constant string HIGHLIGHT = "UI\\Widgets\\Glues\\GlueScreen-Button-KeyboardHighlight"
private constant string CHECKED_BUTTON = "UI\\Widgets\\EscMenu\\Human\\checkbox-check.blp"
private constant string UNAVAILABLE_BUTTON = "ui\\widgets\\battlenet\\chaticons\\bnet-squelch"
endglobals
/* ----------------------------------------------------------------------------------------- */
/* System */
/* ----------------------------------------------------------------------------------------- */
struct Tooltip
private framehandle box
private framehandle line
private framehandle tooltip
private framehandle iconFrame
private framehandle nameFrame
private framehandle parent
private framepointtype pointType
private real widthSize
private string texture
private boolean isVisible
private boolean simple
readonly framehandle frame
method operator text= takes string description returns nothing
call BlzFrameSetText(tooltip, description)
endmethod
method operator text takes nothing returns string
return BlzFrameGetText(tooltip)
endmethod
method operator name= takes string newName returns nothing
call BlzFrameSetText(nameFrame, newName)
endmethod
method operator name takes nothing returns string
return BlzFrameGetText(nameFrame)
endmethod
method operator icon= takes string texture returns nothing
set .texture = texture
call BlzFrameSetTexture(iconFrame, texture, 0, false)
endmethod
method operator icon takes nothing returns string
return texture
endmethod
method operator width= takes real newWidth returns nothing
set widthSize = newWidth
if not simple then
call BlzFrameClearAllPoints(tooltip)
call BlzFrameSetSize(tooltip, newWidth, 0)
endif
endmethod
method operator width takes nothing returns real
return widthSize
endmethod
method operator point= takes framepointtype newPoint returns nothing
set pointType = newPoint
if not simple then
call BlzFrameClearAllPoints(tooltip)
if newPoint == FRAMEPOINT_TOPLEFT then
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_TOPRIGHT, 0.005, -0.05)
elseif newPoint == FRAMEPOINT_TOPRIGHT then
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_TOPLEFT, -0.005, -0.05)
elseif newPoint == FRAMEPOINT_BOTTOMLEFT then
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_BOTTOMRIGHT, 0.005, 0.0)
elseif newPoint == FRAMEPOINT_BOTTOM then
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_TOP, 0.0, 0.005)
elseif newPoint == FRAMEPOINT_TOP then
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_BOTTOM, 0.0, -0.05)
else
call BlzFrameSetPoint(tooltip, newPoint, parent, FRAMEPOINT_BOTTOMLEFT, -0.005, 0.0)
endif
endif
endmethod
method operator point takes nothing returns framepointtype
return pointType
endmethod
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
call BlzFrameSetVisible(box, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method destroy takes nothing returns nothing
call BlzDestroyFrame(nameFrame)
call BlzDestroyFrame(iconFrame)
call BlzDestroyFrame(tooltip)
call BlzDestroyFrame(line)
call BlzDestroyFrame(box)
call BlzDestroyFrame(frame)
call deallocate()
set frame = null
set box = null
set line = null
set tooltip = null
set iconFrame = null
set nameFrame = null
set pointType = null
set parent = null
endmethod
static method create takes framehandle owner, real width, framepointtype point, boolean simpleTooltip returns thistype
local thistype this = thistype.allocate()
set parent = owner
set simple = simpleTooltip
set widthSize = width
set pointType = point
set isVisible = true
if simpleTooltip then
set frame = BlzCreateFrameByType("FRAME", "", owner, "", 0)
set box = BlzCreateFrame("Leaderboard", frame, 0, 0)
set tooltip = BlzCreateFrameByType("TEXT", "", box, "", 0)
call BlzFrameSetPoint(tooltip, FRAMEPOINT_BOTTOM, owner, FRAMEPOINT_TOP, 0, 0.008)
call BlzFrameSetPoint(box, FRAMEPOINT_TOPLEFT, tooltip, FRAMEPOINT_TOPLEFT, -0.008, 0.008)
call BlzFrameSetPoint(box, FRAMEPOINT_BOTTOMRIGHT, tooltip, FRAMEPOINT_BOTTOMRIGHT, 0.008, -0.008)
else
set frame = BlzCreateFrame("TooltipBoxFrame", owner, 0, 0)
set box = BlzGetFrameByName("TooltipBox", 0)
set line = BlzGetFrameByName("TooltipSeperator", 0)
set tooltip = BlzGetFrameByName("TooltipText", 0)
set iconFrame = BlzGetFrameByName("TooltipIcon", 0)
set nameFrame = BlzGetFrameByName("TooltipName", 0)
if point == FRAMEPOINT_TOPLEFT then
call BlzFrameSetPoint(tooltip, point, owner, FRAMEPOINT_TOPRIGHT, 0.005, -0.05)
elseif point == FRAMEPOINT_TOPRIGHT then
call BlzFrameSetPoint(tooltip, point, owner, FRAMEPOINT_TOPLEFT, -0.005, -0.05)
elseif point == FRAMEPOINT_BOTTOMLEFT then
call BlzFrameSetPoint(tooltip, point, owner, FRAMEPOINT_BOTTOMRIGHT, 0.005, 0.0)
else
call BlzFrameSetPoint(tooltip, point, owner, FRAMEPOINT_BOTTOMLEFT, -0.005, 0.0)
endif
call BlzFrameSetPoint(box, FRAMEPOINT_TOPLEFT, iconFrame, FRAMEPOINT_TOPLEFT, -0.005, 0.005)
call BlzFrameSetPoint(box, FRAMEPOINT_BOTTOMRIGHT, tooltip, FRAMEPOINT_BOTTOMRIGHT, 0.005, -0.005)
call BlzFrameSetSize(tooltip, width, 0)
endif
return this
endmethod
endstruct
struct Button
private static trigger clicked = CreateTrigger()
private static trigger scrolled = CreateTrigger()
private static trigger rightClicked = CreateTrigger()
private static timer double = CreateTimer()
private static timer array timer
private static boolean array canScroll
private static Table table
private static HashTable doubleTime
private static HashTable time
private trigger click
private trigger scroll
private trigger doubleClick
private trigger rightClick
private framehandle iconFrame
private framehandle availableFrame
private framehandle checkedFrame
private framehandle highlightFrame
private framehandle spriteFrame
private framehandle displayFrame
private framehandle tagFrame
private framehandle parent
private boolean isVisible
private boolean isAvailable
private boolean isChecked
private boolean isHighlighted
private boolean isEnabled
private string texture
private real widhtSize
private real heightSize
private real xPos
private real yPos
readonly framehandle frame
Tooltip tooltip
method operator x= takes real newX returns nothing
set xPos = newX
call BlzFrameClearAllPoints(iconFrame)
call BlzFrameSetPoint(iconFrame, FRAMEPOINT_TOPLEFT, parent, FRAMEPOINT_TOPLEFT, xPos, yPos)
endmethod
method operator x takes nothing returns real
return xPos
endmethod
method operator y= takes real newY returns nothing
set yPos = newY
call BlzFrameClearAllPoints(iconFrame)
call BlzFrameSetPoint(iconFrame, FRAMEPOINT_TOPLEFT, parent, FRAMEPOINT_TOPLEFT, xPos, yPos)
endmethod
method operator y takes nothing returns real
return yPos
endmethod
method operator icon= takes string texture returns nothing
set .texture = texture
call BlzFrameSetTexture(iconFrame, texture, 0, true)
endmethod
method operator icon takes nothing returns string
return texture
endmethod
method operator width= takes real newWidth returns nothing
set widhtSize = newWidth
call BlzFrameClearAllPoints(iconFrame)
call BlzFrameSetSize(iconFrame, newWidth, heightSize)
endmethod
method operator width takes nothing returns real
return widhtSize
endmethod
method operator height= takes real newHeight returns nothing
set heightSize = newHeight
call BlzFrameClearAllPoints(iconFrame)
call BlzFrameSetSize(iconFrame, widhtSize, newHeight)
endmethod
method operator height takes nothing returns real
return heightSize
endmethod
method operator visible= takes boolean visibility returns nothing
set isVisible = visibility
call BlzFrameSetVisible(iconFrame, visibility)
endmethod
method operator visible takes nothing returns boolean
return isVisible
endmethod
method operator available= takes boolean flag returns nothing
set isAvailable = flag
if flag then
call BlzFrameSetVisible(availableFrame, false)
else
call BlzFrameSetVisible(availableFrame, true)
call BlzFrameSetTexture(availableFrame, UNAVAILABLE_BUTTON, 0, true)
endif
endmethod
method operator available takes nothing returns boolean
return isAvailable
endmethod
method operator checked= takes boolean flag returns nothing
set isChecked = flag
if flag then
call BlzFrameSetVisible(checkedFrame, true)
call BlzFrameSetTexture(checkedFrame, CHECKED_BUTTON, 0, true)
else
call BlzFrameSetVisible(checkedFrame, false)
endif
endmethod
method operator checked takes nothing returns boolean
return isChecked
endmethod
method operator highlighted= takes boolean flag returns nothing
set isHighlighted = flag
if flag then
call BlzFrameSetVisible(highlightFrame, true)
call BlzFrameSetTexture(highlightFrame, HIGHLIGHT, 0, true)
else
call BlzFrameSetVisible(highlightFrame, false)
endif
endmethod
method operator highlighted takes nothing returns boolean
return isHighlighted
endmethod
method operator enabled= takes boolean flag returns nothing
local string t = texture
set isEnabled = flag
if not flag then
if SubString(t, 34, 35) == "\\" then
set t = SubString(t, 0, 34) + "Disabled\\DIS" + SubString(t, 35, StringLength(t))
endif
endif
call BlzFrameSetTexture(iconFrame, t, 0, true)
endmethod
method operator enabled takes nothing returns boolean
return isEnabled
endmethod
method operator onClick= takes code c returns nothing
call DestroyTrigger(click)
set click = null
if c != null then
set click = CreateTrigger()
call TriggerAddCondition(click, Condition(c))
endif
endmethod
method operator onScroll= takes code c returns nothing
call DestroyTrigger(scroll)
set scroll = null
if c != null then
set scroll = CreateTrigger()
call TriggerAddCondition(scroll, Condition(c))
endif
endmethod
method operator onDoubleClick= takes code c returns nothing
call DestroyTrigger(doubleClick)
set doubleClick = null
if c != null then
set doubleClick = CreateTrigger()
call TriggerAddCondition(doubleClick, Condition(c))
endif
endmethod
method operator onRightClick= takes code c returns nothing
call DestroyTrigger(rightClick)
set rightClick = null
if c != null then
set rightClick = CreateTrigger()
call TriggerAddCondition(rightClick, Condition(c))
endif
endmethod
method destroy takes nothing returns nothing
call table.remove(GetHandleId(frame))
call DestroyTrigger(click)
call DestroyTrigger(scroll)
call DestroyTrigger(doubleClick)
call DestroyTrigger(rightClick)
call BlzDestroyFrame(displayFrame)
call BlzDestroyFrame(spriteFrame)
call BlzDestroyFrame(tagFrame)
call BlzDestroyFrame(frame)
call BlzDestroyFrame(iconFrame)
call BlzDestroyFrame(availableFrame)
call BlzDestroyFrame(checkedFrame)
call tooltip.destroy()
call deallocate()
set availableFrame = null
set checkedFrame = null
set spriteFrame = null
set displayFrame = null
set iconFrame = null
set tagFrame = null
set doubleClick = null
set rightClick = null
set parent = null
set scroll = null
set frame = null
set click = null
endmethod
method play takes string model, real scale, integer animation returns nothing
if model != "" and model != null then
call BlzFrameClearAllPoints(spriteFrame)
call BlzFrameSetPoint(spriteFrame, FRAMEPOINT_CENTER, frame, FRAMEPOINT_CENTER, 0, 0)
call BlzFrameSetSize(spriteFrame, widhtSize, heightSize)
call BlzFrameSetModel(spriteFrame, model, 0)
call BlzFrameSetScale(spriteFrame, scale)
call BlzFrameSetSpriteAnimate(spriteFrame, animation, 0)
endif
endmethod
method display takes string model, real width, real height, real scale, framepointtype point, framepointtype relativePoint, real offsetX, real offsetY returns nothing
if model != "" and model != null then
call BlzFrameClearAllPoints(displayFrame)
call BlzFrameSetPoint(displayFrame, point, frame, relativePoint, offsetX, offsetY)
call BlzFrameSetSize(displayFrame, width, height)
call BlzFrameSetScale(displayFrame, scale)
call BlzFrameSetModel(displayFrame, model, 0)
call BlzFrameSetVisible(displayFrame, true)
else
call BlzFrameSetVisible(displayFrame, false)
endif
endmethod
method tag takes string model, real width, real height, real scale, framepointtype point, framepointtype relativePoint, real offsetX, real offsetY returns nothing
if model != "" and model != null then
call BlzFrameClearAllPoints(tagFrame)
call BlzFrameSetPoint(tagFrame, point, frame, relativePoint, offsetX, offsetY)
call BlzFrameSetSize(tagFrame, width, height)
call BlzFrameSetScale(tagFrame, scale)
call BlzFrameSetModel(tagFrame, model, 0)
call BlzFrameSetVisible(tagFrame, true)
else
call BlzFrameSetVisible(tagFrame, false)
endif
endmethod
static method create takes framehandle owner, real width, real height, real x, real y, boolean simpleTooltip returns thistype
local thistype this = thistype.allocate()
local integer i = 0
set parent = owner
set xPos = x
set yPos = y
set widhtSize = width
set heightSize = height
set isVisible = true
set isAvailable = true
set isChecked = false
set isHighlighted = false
set iconFrame = BlzCreateFrameByType("BACKDROP", "", owner, "", 0)
set availableFrame = BlzCreateFrameByType("BACKDROP", "", iconFrame, "", 0)
set checkedFrame = BlzCreateFrameByType("BACKDROP", "", iconFrame, "", 0)
set highlightFrame = BlzCreateFrame("HighlightFrame", iconFrame, 0, 0)
set frame = BlzCreateFrame("IconButtonTemplate", iconFrame, 0, 0)
set displayFrame = BlzCreateFrameByType("SPRITE", "", frame, "WarCraftIIILogo", 0)
set tagFrame = BlzCreateFrameByType("SPRITE", "", frame, "WarCraftIIILogo", 0)
set spriteFrame = BlzCreateFrameByType("SPRITE", "", frame, "", 0)
set tooltip = Tooltip.create(frame, TOOLTIP_SIZE, FRAMEPOINT_TOPLEFT, simpleTooltip)
set table[GetHandleId(frame)] = this
call BlzFrameSetPoint(iconFrame, FRAMEPOINT_TOPLEFT, owner, FRAMEPOINT_TOPLEFT, x, y)
call BlzFrameSetSize(iconFrame, width, height)
call BlzFrameSetAllPoints(frame, iconFrame)
call BlzFrameSetTooltip(frame, tooltip.frame)
call BlzFrameSetAllPoints(availableFrame, iconFrame)
call BlzFrameSetVisible(availableFrame, false)
call BlzFrameSetAllPoints(checkedFrame, iconFrame)
call BlzFrameSetVisible(checkedFrame, false)
call BlzFrameSetPoint(highlightFrame, FRAMEPOINT_TOPLEFT, iconFrame, FRAMEPOINT_TOPLEFT, - 0.0040000, 0.0045000)
call BlzFrameSetSize(highlightFrame, width + 0.0085, height + 0.0085)
call BlzFrameSetVisible(highlightFrame, false)
call BlzTriggerRegisterFrameEvent(clicked, frame, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(scrolled, frame, FRAMEEVENT_MOUSE_WHEEL)
call BlzTriggerRegisterFrameEvent(rightClicked, frame, FRAMEEVENT_MOUSE_UP)
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set timer[i] = CreateTimer()
set canScroll[i] = true
set i = i + 1
endloop
return this
endmethod
private static method onExpire takes nothing returns nothing
set canScroll[GetPlayerId(GetLocalPlayer())] = true
endmethod
private static method onScrolled takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())]
local integer i = GetPlayerId(GetLocalPlayer())
if this != 0 then
if canScroll[i] and scroll != null then
if SCROLL_DELAY > 0 then
set canScroll[i] = false
endif
call TriggerEvaluate(scroll)
endif
endif
if SCROLL_DELAY > 0 then
call TimerStart(timer[i], TimerGetRemaining(timer[i]), false, function thistype.onExpire)
endif
endmethod
private static method onRightClicked takes nothing returns nothing
local thistype this = table[GetHandleId(BlzGetTriggerFrame())]
if this != 0 then
if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT and rightClick != null then
call TriggerEvaluate(rightClick)
endif
endif
endmethod
private static method onClicked takes nothing returns nothing
local integer i = GetPlayerId(GetTriggerPlayer())
local integer j = GetHandleId(BlzGetTriggerFrame())
local thistype this = table[j]
if this != 0 then
set time[i].real[j] = TimerGetElapsed(double)
if click != null then
call TriggerEvaluate(click)
endif
if time[i].real[j] - doubleTime[i].real[j] <= DOUBLE_CLICK_DELAY then
set doubleTime[i][j] = 0
if doubleClick != null then
call TriggerEvaluate(doubleClick)
endif
else
set doubleTime[i].real[j] = time[i].real[j]
endif
endif
endmethod
private static method onInit takes nothing returns nothing
set table = Table.create()
set time = HashTable.create()
set doubleTime = HashTable.create()
call TimerStart(double, 9999999999, false, null)
call TriggerAddAction(clicked, function thistype.onClicked)
call TriggerAddAction(scrolled, function thistype.onScrolled)
call TriggerAddAction(rightClicked, function thistype.onRightClicked)
endmethod
endstruct
endlibrary
scope Test
struct Items
static constant integer ANILLO = 'I000'
static constant integer ANILLO_DE_TARRASQUE = 'I001'
static constant integer ANILLO_DE_PROTECCION = 'I002'
static constant integer ANILLO_DE_REGENERACION = 'I003'
static constant integer ANILLO_DE_SALUD = 'I004'
static constant integer ANILLO_DEL_ALMA = 'I01V'
static constant integer AMPLIFICADOR_DE_ENERGIA = 'I01C'
static constant integer BANDA_DE_PIEL_ELFICA = 'I00F'
static constant integer BASTON_DE_HECHICERIA = 'I005'
static constant integer BASTON_DEL_OLVIDO = 'I026'
static constant integer BASTON_MISTICO = 'I01L'
static constant integer BOTAS_ARCANAS = 'I02E'
static constant integer BOTAS_DE_FASE = 'I027'
static constant integer BOTAS_DE_VELOCIDAD = 'I006'
static constant integer CANTO_DEL_AGUILA = 'I01K'
static constant integer CAPA = 'I007'
static constant integer CINTURON_DE_FUERZA = 'I008'
static constant integer CLAYMORE = 'I009'
static constant integer CORONA = 'I00A'
static constant integer COTA_DE_MALLA = 'I00B'
static constant integer COTA_DE_METAL = 'I01D'
static constant integer CUERNO_DE_LA_ABUNDANCIA = 'I00Q'
static constant integer DAGA_PARPADEANTE = 'I01R'
static constant integer DIADEMA = 'I00C'
static constant integer ENCAJE_DE_VIENTO = 'I00D'
static constant integer ESPADAS_DE_ATAQUE = 'I00E'
static constant integer ESPADA_DE_HALCON = 'I01O'
static constant integer FILO_DEMONIACO = 'I01G'
static constant integer FRAGMENTO_DE_LUNA = 'I01S'
static constant integer GUANTELETES_DE_FUERZA = 'I00G'
static constant integer GUANTES_DE_PRISA = 'I00H'
static constant integer HACHA_DE_OGRO = 'I00I'
static constant integer HIPERPIEDRA = 'I01H'
static constant integer HOJA_DE_PRONTITUD = 'I00J'
static constant integer JABALINA = 'I00K'
static constant integer MANDOBLE = 'I00L'
static constant integer MANO_DE_MIDAS = 'I01W'
static constant integer MANTO_DE_INTELIGENCIA = 'I00M'
static constant integer MARTILLO_DE_MITHRIL = 'I00N'
static constant integer MASCARA_DE_LA_LOCURA = 'I02A'
static constant integer MASCARA_DE_SABIO = 'I00O'
static constant integer MASCARA_MORBIDA = 'I00P'
static constant integer MASCARA_VUDU = 'I01B'
static constant integer NUDILLOS_BLIZT = 'I00R'
static constant integer ORBE_DE_CORROSION = 'I02B'
static constant integer ORBE_DE_VENENO = 'I00S'
static constant integer ORBE_DEFINITIVO = 'I01N'
static constant integer PAVE = 'I02H'
static constant integer PERSEVERANCIA = 'I01T'
static constant integer PIEDRA_DE_LA_PLAGA = 'I00T'
static constant integer PISADAS_POTENTES = 'I02C'
static constant integer PISADAS_POTENTES_A = 'I01U'
static constant integer PISADAS_POTENTES_F = 'I02D'
static constant integer PISADAS_POTENTES_I = 'I028'
static constant integer POTENCIADOR_DE_PUNTOS = 'I01I'
static constant integer POTENCIADOR_DE_VITALIDAD = 'I01F'
static constant integer RELIQUIA_SAGRADA = 'I01E'
static constant integer SAQUEADOR = 'I01M'
static constant integer LA_OFRENDA_DE_VLADIMIR = 'I02J'
static constant integer SOMBRERO_MULLIDO = 'I00U'
static constant integer TALISMAN_DE_EVASION = 'I01J'
static constant integer TIARA_DE_ELUNE = 'I00V'
static constant integer TUNICA_DE_LOS_MAGOS = 'I00W'
static constant integer YELMO_DE_LA_VOLUNTAD_DE_HIERRO = 'I00X'
static constant integer YELMO_DEL_SENOR_SUPREMO = 'I01P'
static constant integer YELMO_DEL_DOMINADOR = 'I029'
static constant integer ZAPATILLAS_DE_AGILIDAD = 'I00Y'
static constant integer AMULETO_DE_SOMBRA = 'I00Z'
static constant integer CETRO_FANTASMA = 'I010'
static constant integer CLARIDAD = 'I01A'
static constant integer ESPADA_SOFOCANTE = 'I011'
static constant integer FUEGO_DE_HADAS = 'I012'
static constant integer GOTAS_DE_LLUVIA_INFUNDIDAS = 'I013'
static constant integer GRANADA_DE_SANGRE = 'I014'
static constant integer LA_JOYA_DE_LA_VISION_VERDADERA = 'I015'
static constant integer MANGO_ENCANTADO = 'I016'
static constant integer MEDALLON_SAGRADO = 'I02G'
static constant integer PALO_MAGICO = 'I019'
static constant integer PERGAMINO_DEL_PORTAL_DE_LA_CUIDAD = 'stwp'
static constant integer RAMA_DE_HIERRO = 'I017'
static constant integer TAMBOR_DE_RESISTENCIA = 'I02F'
static constant integer TANGO = 'I018'
static constant integer VARITA_MAGICA = 'I01X'
static constant integer VASIJA_ESPIRITUAL = 'I02I'
static constant integer OBSERVADOR = 'wswd'
static constant integer POLVO_DE_APARIENCIA = 'I02K'
static constant integer UNGUENTO_CURATIVO = 'I02L'
static constant integer BOTAS_DE_RODAMIENTO = 'I02M'
static constant integer GREBAS_DE_GUARDIAN = 'I02N'
static constant integer MECANISMO = 'I02O'
static constant integer PIEDRA_DEL_VACIO = 'I02P'
static constant integer BOTAS_DE_VIAJE = 'I02Q'
static constant integer BOTAS_DE_VIAJE2 = 'I02R'
static constant integer PIPA_DE_LA_PERSPICACIA = 'I02S'
static constant integer URNA_DE_LAS_SOMBRAS = 'I02T'
static constant integer ANILLO_DE_BASILIUS = 'I02U'
static constant integer ESCUDO = 'I02V'
static constant integer TUNICA = 'I02W'
static constant integer BOTAS_TRANQUILAS = 'I02X'
static constant integer PARASMA = 'I02Z'
static constant integer LENTE_DE_ETER = 'I030'
static constant integer DAGON1 = 'I031'
static constant integer DAGON2 = 'I032'
static constant integer DAGON3 = 'I033'
static constant integer DAGON4 = 'I034'
static constant integer DAGON5 = 'I035'
static constant integer CAPA_DE_DESTELLOS = 'I036'
static constant integer MALLA_DE_CUCHILLAS = 'I03U'
static constant integer BARRA_DEL_REY_NEGRO = 'I03W'
static constant integer VARA_DE_ARAJ = 'I03Y'
static constant integer SANGE_Y_YASHA = 'I040'
static constant integer SANGE = 'I041'
static constant integer YASHA = 'I043'
static constant integer DESTRUCTOR_DE_CALAVERAS = 'I045'
static constant integer VANGUARDIA = 'I047'
static constant integer ESPADA_ABISAL = 'I048'
static constant integer BRAZALETE = 'I04A'
static constant integer TALISMAN_NULO = 'I04D'
static constant integer BANDA_ESPECTRO = 'I04G'
static constant integer CRISTALICA = 'I04J'
static constant integer DEDALO = 'I04L'
static constant integer GUARDIA_CARMESI = 'I04N'
static constant integer ESPADA_DE_BRUJA = 'I04P'
static constant integer CORAZA_DE_ASALTO = 'I04S'
static constant integer ESPADA_DE_SOMBRA = 'I04U'
static constant integer NUCLEO_DE_OCTARINA = 'I04V'
static constant integer POTENCIADOR_DE_ALMA = 'I04W'
static constant integer FURIA_DE_BATALLA = 'I04X'
static constant integer VELO_DE_LA_DISCORDIA = 'I050'
static constant integer DESOLADORA = 'I052'
static constant integer CORAZON_DE_TARRASQUE = 'I053'
static constant integer ESTILO_MANTA = 'I056'
static constant integer CETRO_EUL = 'I059'
static constant integer VARA_DEL_VIENTO = 'I058'
static constant integer GUADANA_DE_VYSE = 'I05A'
static constant integer MARIPOSA = 'I05B'
static constant integer DIFUSAL = 'I05F'
static constant integer DISPERSER = 'I05H'
static constant integer FORCE_STAFF = 'I05I'
static constant integer ORCHID = 'I05L'
static constant integer REFRESHER = 'I05M'
static constant integer SHIVAS = 'I05N'
static constant integer ORBE_DE_LOTO = 'I05R'
static constant integer ESPINA_DE_SANGRE = 'I05T'
static constant integer ESFERA_DE_LINKENS = 'I05V'
static constant integer CRESTA_SOLAR = 'I01Q'
static constant integer RECETA_BOTAS_DE_VIAJE = 'I037'
static constant integer RECETA_YELMO_DOMINADOR = 'I038'
static constant integer RECETA_YELMO_SENOR = 'I039'
static constant integer RECETA_ANILLO_ALMA = 'I03A'
static constant integer RECETA_ESPADA_HALCON = 'I03B'
static constant integer RECETA_VARITA_MAGICA = 'I03C'
static constant integer RECETA_MIDAS = 'I03D'
static constant integer RECETA_BOTAS_ARCANAS = 'I03E'
static constant integer RECETA_GREBAS_GUARDIANAS = 'I03F'
static constant integer RECETA_VASIJA = 'I03G'
static constant integer RECETA_RODAMIENTO = 'I03H'
static constant integer RECETA_TUNICA = 'I03I'
static constant integer RECETA_PAVE = 'I03J'
static constant integer RECETA_ESCUDO = 'I03J'
static constant integer RECETA_PIPA = 'I03M'
static constant integer RECETA_URNA = 'I03N'
static constant integer RECETA_TAMBOR = 'I03O'
static constant integer RECETA_MECANISMO = 'I03P'
static constant integer RECETA_BASILIO = 'I03Q'
static constant integer RECETA_LENTE = 'I03R'
static constant integer RECETA_DAGON = 'I03S'
static constant integer RECETA_DESTELLOS = 'I03T'
static constant integer RECETA_CUCHILLAS = 'I03V'
static constant integer RECETA_BKB = 'I03X'
static constant integer RECETA_ARAJ = 'I03Z'
static constant integer RECETA_SANGE = 'I042'
static constant integer RECETA_YASHA = 'I044'
static constant integer RECETA_DESTRUCTOR = 'I046'
static constant integer RECETA_ABISAL = 'I049'
static constant integer RECETA_BRAZALETE = 'I04C'
static constant integer RECETA_TALISMAN_NULO = 'I04E'
static constant integer RECETA_BANDA_ESPECTRO = 'I04I'
static constant integer RECETA_CRISTALICA = 'I04K'
static constant integer RECETA_DEDALO = 'I04M'
static constant integer RECETA_CARMESI = 'I04O'
static constant integer RECETA_BRUJA = 'I04Q'
static constant integer RECETA_PARASMA = 'I04R'
static constant integer RECETA_CORAZA_ASALTO = 'I04T'
static constant integer RECETA_BATALLA_FURIA = 'I04Y'
static constant integer RECETA_VELO = 'I051'
static constant integer RECETA_MEDALLON_SAGRADO = 'I03L'
static constant integer RECETA_TARRASQUE = 'I055'
static constant integer RECETA_MANTA = 'I057'
static constant integer RECETA_EUL = 'I05C'
static constant integer RECETA_VIENTO = 'I05D'
static constant integer RECETA_GUADANA = 'I05E'
static constant integer RECETA_DIFUSAL = 'I05G'
static constant integer RECETA_DISPERSER = 'I05J'
static constant integer RECETA_FORCE_STAFF = 'I05K'
static constant integer RECETA_ORCHID = 'I05O'
static constant integer RECETA_REFRESHER = 'I05P'
static constant integer RECETA_SHIVAS = 'I05Q'
static constant integer RECETA_LOTO = 'I05S'
static constant integer RECETA_BLOODTHORN = 'I05U'
static constant integer RECETA_LINKENS = 'I05W'
static constant integer RECETA_CRESTA_SOLAR = 'I054'
private static method configure takes nothing returns nothing
call ItemAddComponents(ANILLO_DEL_ALMA, ANILLO_DE_PROTECCION, GUANTELETES_DE_FUERZA, GUANTELETES_DE_FUERZA, RECETA_ANILLO_ALMA, 0)
call ItemAddComponents(BASTON_DEL_OLVIDO, NUDILLOS_BLIZT, TUNICA_DE_LOS_MAGOS, MASCARA_DE_SABIO, 0, 0)
call ItemAddComponents(BOTAS_ARCANAS, BOTAS_DE_VELOCIDAD, ANILLO_DE_BASILIUS, RECETA_BOTAS_ARCANAS, 0, 0)
call ItemAddComponents(BOTAS_DE_FASE, BOTAS_DE_VELOCIDAD, COTA_DE_MALLA, ESPADAS_DE_ATAQUE, 0, 0)
call ItemAddComponents(VARITA_MAGICA, PALO_MAGICO, RAMA_DE_HIERRO, RAMA_DE_HIERRO, RECETA_VARITA_MAGICA, 0)
call ItemAddComponents(MANO_DE_MIDAS, GUANTES_DE_PRISA, RECETA_MIDAS, 0, 0, 0)
call ItemAddComponents(PISADAS_POTENTES_I, BOTAS_DE_VELOCIDAD, GUANTES_DE_PRISA, TUNICA_DE_LOS_MAGOS, 0, 0)
call ItemAddComponents(YELMO_DEL_DOMINADOR, YELMO_DE_LA_VOLUNTAD_DE_HIERRO, DIADEMA, RECETA_YELMO_DOMINADOR, 0, 0)
call ItemAddComponents(ORBE_DE_CORROSION, ORBE_DE_VENENO, ANILLO_DE_PROTECCION, GUANTES_DE_PRISA, 0, 0)
call ItemAddComponents(PISADAS_POTENTES, BOTAS_DE_VELOCIDAD, GUANTES_DE_PRISA, CINTURON_DE_FUERZA, 0, 0)
call ItemAddComponents(PISADAS_POTENTES_F, BOTAS_DE_VELOCIDAD, GUANTES_DE_PRISA, CINTURON_DE_FUERZA, 0, 0)
call ItemAddComponents(ESPADA_DE_HALCON, SOMBRERO_MULLIDO, MASCARA_DE_SABIO, ESPADAS_DE_ATAQUE, RECETA_ESPADA_HALCON, 0)
call ItemAddComponents(YELMO_DEL_SENOR_SUPREMO, YELMO_DEL_DOMINADOR, ORBE_DEFINITIVO, RECETA_YELMO_SENOR, 0, 0)
call ItemAddComponents(FRAGMENTO_DE_LUNA, HIPERPIEDRA, HIPERPIEDRA, 0, 0, 0)
call ItemAddComponents(PERSEVERANCIA, ANILLO_DE_SALUD, PIEDRA_DEL_VACIO, 0, 0, 0)
call ItemAddComponents(PISADAS_POTENTES_A, BOTAS_DE_VELOCIDAD, GUANTES_DE_PRISA, BANDA_DE_PIEL_ELFICA, 0, 0)
call ItemAddComponents(TAMBOR_DE_RESISTENCIA, TUNICA_DE_LOS_MAGOS, CINTURON_DE_FUERZA, ENCAJE_DE_VIENTO, RECETA_TAMBOR, 0)
call ItemAddComponents(MEDALLON_SAGRADO, DIADEMA, VARITA_MAGICA, RECETA_MEDALLON_SAGRADO, 0, 0)
call ItemAddComponents(PAVE, AMPLIFICADOR_DE_ENERGIA, ANILLO_DE_PROTECCION, SOMBRERO_MULLIDO, 0, 0)
call ItemAddComponents(BOTAS_DE_VIAJE, BOTAS_DE_VELOCIDAD, RECETA_BOTAS_DE_VIAJE, 0, 0, 0)
call ItemAddComponents(BOTAS_DE_VIAJE2, BOTAS_DE_VIAJE, RECETA_BOTAS_DE_VIAJE, 0, 0, 0)
call ItemAddComponents(URNA_DE_LAS_SOMBRAS, MASCARA_DE_SABIO, SOMBRERO_MULLIDO, ANILLO_DE_PROTECCION, RECETA_URNA, 0)
call ItemAddComponents(VASIJA_ESPIRITUAL, URNA_DE_LAS_SOMBRAS, CORONA, POTENCIADOR_DE_VITALIDAD, RECETA_VASIJA, 0)
call ItemAddComponents(ANILLO_DE_BASILIUS, MASCARA_DE_SABIO, RECETA_BASILIO, 0, 0, 0)
call ItemAddComponents(ESCUDO, ANILLO_DE_PROTECCION, RECETA_ESCUDO, 0, 0, 0)
call ItemAddComponents(LA_OFRENDA_DE_VLADIMIR, ESCUDO, ANILLO_DE_BASILIUS, MASCARA_MORBIDA, ESPADAS_DE_ATAQUE, 0)
call ItemAddComponents(TUNICA, ANILLO_DE_REGENERACION, RECETA_TUNICA, 0, 0, 0)
call ItemAddComponents(MECANISMO, TUNICA, COTA_DE_MALLA, RECETA_MECANISMO, 0, 0)
call ItemAddComponents(GREBAS_DE_GUARDIAN, MECANISMO, BOTAS_ARCANAS, ESCUDO, RECETA_GREBAS_GUARDIANAS, 0)
call ItemAddComponents(BOTAS_TRANQUILAS, BOTAS_DE_VELOCIDAD, ENCAJE_DE_VIENTO, ANILLO_DE_REGENERACION, 0, 0)
call ItemAddComponents(BOTAS_DE_RODAMIENTO, BOTAS_TRANQUILAS, TAMBOR_DE_RESISTENCIA, RECETA_RODAMIENTO, 0, 0)
call ItemAddComponents(LENTE_DE_ETER, AMPLIFICADOR_DE_ENERGIA, PIEDRA_DEL_VACIO, RECETA_LENTE, 0, 0)
call ItemAddComponents(DAGON1, DIADEMA, MASCARA_VUDU, RECETA_DAGON, 0, 0)
call ItemAddComponents(DAGON2, DAGON1, RECETA_DAGON, 0, 0, 0)
call ItemAddComponents(DAGON3, DAGON2, RECETA_DAGON, 0, 0, 0)
call ItemAddComponents(DAGON4, DAGON3, RECETA_DAGON, 0, 0, 0)
call ItemAddComponents(DAGON5, DAGON4, RECETA_DAGON, 0, 0, 0)
call ItemAddComponents(CAPA_DE_DESTELLOS, AMULETO_DE_SOMBRA, CAPA, RECETA_DESTELLOS, 0, 0)
call ItemAddComponents(PAVE, AMPLIFICADOR_DE_ENERGIA, ANILLO_DE_PROTECCION, SOMBRERO_MULLIDO, RECETA_PAVE, 0)
call ItemAddComponents(PIPA_DE_LA_PERSPICACIA, CAPA, TUNICA, ANILLO_DE_TARRASQUE, RECETA_PIPA, 0)
call ItemAddComponents(MALLA_DE_CUCHILLAS, MANDOBLE, COTA_DE_MALLA, RECETA_CUCHILLAS, 0, 0)
call ItemAddComponents(BARRA_DEL_REY_NEGRO, HACHA_DE_OGRO, MARTILLO_DE_MITHRIL, RECETA_BKB, 0, 0)
call ItemAddComponents(VARA_DE_ARAJ, BASTON_DE_HECHICERIA, POTENCIADOR_DE_VITALIDAD, RECETA_ARAJ, 0, 0)
call ItemAddComponents(SANGE, HACHA_DE_OGRO, CINTURON_DE_FUERZA, RECETA_SANGE, 0, 0)
call ItemAddComponents(YASHA, HOJA_DE_PRONTITUD, BANDA_DE_PIEL_ELFICA, RECETA_YASHA, 0, 0)
call ItemAddComponents(SANGE_Y_YASHA, YASHA, SANGE, 0, 0, 0)
call ItemAddComponents(DESTRUCTOR_DE_CALAVERAS, MARTILLO_DE_MITHRIL, CINTURON_DE_FUERZA, RECETA_DESTRUCTOR, 0, 0)
call ItemAddComponents(VANGUARDIA, ANILLO_DE_SALUD, POTENCIADOR_DE_VITALIDAD, 0, 0, 0)
call ItemAddComponents(ESPADA_ABISAL, DESTRUCTOR_DE_CALAVERAS, VANGUARDIA, RECETA_ABISAL, 0, 0)
call ItemAddComponents(BRAZALETE, ANILLO, GUANTELETES_DE_FUERZA, RECETA_BRAZALETE, 0, 0)
call ItemAddComponents(TALISMAN_NULO, ANILLO, MANTO_DE_INTELIGENCIA, RECETA_TALISMAN_NULO, 0, 0)
call ItemAddComponents(BANDA_ESPECTRO, ANILLO, ZAPATILLAS_DE_AGILIDAD, RECETA_BANDA_ESPECTRO, 0, 0)
call ItemAddComponents(MASCARA_DE_LA_LOCURA, MASCARA_MORBIDA, MANDOBLE, 0, 0, 0)
call ItemAddComponents(CRISTALICA, CLAYMORE, ESPADAS_DE_ATAQUE, RECETA_CRISTALICA, 0, 0)
call ItemAddComponents(DEDALO, CRISTALICA, FILO_DEMONIACO, RECETA_DEDALO, 0, 0)
call ItemAddComponents(GUARDIA_CARMESI, VANGUARDIA, YELMO_DE_LA_VOLUNTAD_DE_HIERRO, RECETA_CARMESI, 0, 0)
call ItemAddComponents(PARASMA, ESPADA_DE_BRUJA, BASTON_MISTICO, RECETA_PARASMA, 0, 0)
call ItemAddComponents(ESPADA_DE_BRUJA, BASTON_DEL_OLVIDO, COTA_DE_MALLA, RECETA_BRUJA, 0, 0)
call ItemAddComponents(CORAZA_DE_ASALTO, COTA_DE_METAL,HIPERPIEDRA, ESCUDO, RECETA_CORAZA_ASALTO, 0)
call ItemAddComponents(ESPADA_DE_SOMBRA, AMULETO_DE_SOMBRA, NUDILLOS_BLIZT, MANDOBLE, 0, 0)
call ItemAddComponents(FURIA_DE_BATALLA, MANDOBLE, CLAYMORE, CUERNO_DE_LA_ABUNDANCIA, ESPADA_SOFOCANTE, RECETA_BATALLA_FURIA)
call ItemAddComponents(NUCLEO_DE_OCTARINA, TIARA_DE_ELUNE, POTENCIADOR_DE_ALMA, 0, 0, 0)
call ItemAddComponents(POTENCIADOR_DE_ALMA, POTENCIADOR_DE_VITALIDAD, AMPLIFICADOR_DE_ENERGIA, POTENCIADOR_DE_PUNTOS, 0, 0)
call ItemAddComponents(VELO_DE_LA_DISCORDIA, YELMO_DE_LA_VOLUNTAD_DE_HIERRO, CORONA, RECETA_VELO, 0, 0)
call ItemAddComponents(DESOLADORA, MARTILLO_DE_MITHRIL, MARTILLO_DE_MITHRIL, PIEDRA_DE_LA_PLAGA, 0, 0)
call ItemAddComponents(CORAZON_DE_TARRASQUE, ANILLO_DE_TARRASQUE, SAQUEADOR, RECETA_TARRASQUE, 0, 0)
call ItemAddComponents(ESTILO_MANTA, YASHA, DIADEMA, RECETA_MANTA, 0, 0)
call ItemAddComponents(CETRO_EUL, BASTON_DE_HECHICERIA, PIEDRA_DEL_VACIO, ENCAJE_DE_VIENTO, RECETA_EUL, 0)
call ItemAddComponents(VARA_DEL_VIENTO, CETRO_EUL, BASTON_MISTICO, RECETA_VIENTO, 0, 0)
call ItemAddComponents(GUADANA_DE_VYSE, BASTON_MISTICO, TIARA_DE_ELUNE, RECETA_GUADANA, 0, 0)
call ItemAddComponents(MARIPOSA, CANTO_DEL_AGUILA, TALISMAN_DE_EVASION, CLAYMORE, 0, 0)
call ItemAddComponents(DIFUSAL, HOJA_DE_PRONTITUD, TUNICA_DE_LOS_MAGOS, RECETA_DIFUSAL, 0, 0)
call ItemAddComponents(DISPERSER, DIFUSAL, CANTO_DEL_AGUILA, RECETA_DISPERSER, 0, 0)
call ItemAddComponents(FORCE_STAFF, BASTON_DE_HECHICERIA, SOMBRERO_MULLIDO, RECETA_FORCE_STAFF, 0, 0)
call ItemAddComponents(ORCHID, BASTON_DEL_OLVIDO, CUERNO_DE_LA_ABUNDANCIA, RECETA_ORCHID, 0, 0)
call ItemAddComponents(REFRESHER, CUERNO_DE_LA_ABUNDANCIA, ANILLO_DE_TARRASQUE, TIARA_DE_ELUNE, RECETA_REFRESHER, 0)
call ItemAddComponents(SHIVAS, VELO_DE_LA_DISCORDIA, COTA_DE_METAL, RECETA_SHIVAS, 0, 0)
call ItemAddComponents(ORBE_DE_LOTO, PERSEVERANCIA, COTA_DE_METAL, AMPLIFICADOR_DE_ENERGIA, RECETA_LOTO, 0)
call ItemAddComponents(ESPINA_DE_SANGRE, ORCHID, JABALINA, HIPERPIEDRA, RECETA_BLOODTHORN, 0)
call ItemAddComponents(ESFERA_DE_LINKENS, ORBE_DEFINITIVO, PERSEVERANCIA, RECETA_LINKENS, 0, 0)
call ItemAddComponents(CRESTA_SOLAR, PAVE, CORONA, ENCAJE_DE_VIENTO, RECETA_CRESTA_SOLAR, 0)
endmethod
static method create takes integer shop, real aoe, real tax returns thistype
local integer consumibles
local integer atributos
local integer agilidad
local integer inteligencia
local integer fuerza
local integer ofensivos
local integer defensivos
local integer soporte
local integer magicos
local integer auras
local integer movimiento
local integer control
local integer regeneracion
local integer Recetas
call CreateShop(shop, aoe, tax)
set consumibles = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNPotionOfClarity.blp", "Consumables")
set atributos = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNCirclet.blp", "Attributes")
set agilidad = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNSlippersofAgility.blp", "Agility")
set inteligencia = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNMantleofIntelligence.blp", "Intelligence")
set fuerza = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNGauntletsOfOgrePower.blp", "Strength")
set ofensivos = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNClawsOfAttack.blp", "Offensive")
set defensivos = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNRingGreen.blp", "Defensives")
set soporte = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNDrum.blp", "Support")
set magicos = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNStaffOfTeleportation.blp", "Magical")
set auras = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNDarkSummoning.blp", "Auras")
set movimiento = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNBootsofSpeed.blp", "Movement")
set control = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNScepterOfMastery.blp", "Control")
set regeneracion = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNHeal.blp", "Regeneration")
set Recetas = ShopAddCategory(shop, "ReplaceableTextures\\CommandButtons\\BTNCancel.blp", "Recipes")
call ShopAddItem(shop, ANILLO, atributos)
call ShopAddItem(shop, AMULETO_DE_SOMBRA, magicos)
call ShopAddItem(shop, ANILLO_DE_BASILIUS, auras + soporte)
call ShopAddItem(shop, ANILLO_DE_PROTECCION, defensivos)
call ShopAddItem(shop, ANILLO_DE_REGENERACION, regeneracion)
call ShopAddItem(shop, ANILLO_DE_SALUD, defensivos)
call ShopAddItem(shop, ANILLO_DEL_ALMA, magicos + fuerza)
call ShopAddItem(shop, BANDA_DE_PIEL_ELFICA, agilidad)
call ShopAddItem(shop, BANDA_ESPECTRO, agilidad + atributos)
call ShopAddItem(shop, BARRA_DEL_REY_NEGRO, magicos + defensivos)
call ShopAddItem(shop, FORCE_STAFF, inteligencia + magicos)
call ShopAddItem(shop, BASTON_DE_HECHICERIA, inteligencia)
call ShopAddItem(shop, BASTON_DEL_OLVIDO, inteligencia + regeneracion + atributos)
call ShopAddItem(shop, BOTAS_ARCANAS, movimiento + soporte + magicos)
call ShopAddItem(shop, BOTAS_DE_FASE, movimiento + ofensivos + magicos)
call ShopAddItem(shop, BOTAS_DE_RODAMIENTO, movimiento + soporte + magicos + auras)
call ShopAddItem(shop, BOTAS_TRANQUILAS, movimiento + magicos)
call ShopAddItem(shop, BOTAS_DE_VELOCIDAD, movimiento)
call ShopAddItem(shop, BOTAS_DE_VIAJE, movimiento + magicos)
call ShopAddItem(shop, BOTAS_DE_VIAJE2, movimiento + magicos)
call ShopAddItem(shop, BRAZALETE, fuerza + atributos)
call ShopAddItem(shop, CAPA, defensivos)
call ShopAddItem(shop, CAPA_DE_DESTELLOS, magicos + soporte + defensivos)
call ShopAddItem(shop, CETRO_EUL, magicos + inteligencia + regeneracion + movimiento + control)
call ShopAddItem(shop, CETRO_FANTASMA, magicos + atributos + control)
call ShopAddItem(shop, CRESTA_SOLAR, defensivos + magicos + atributos + movimiento)
call ShopAddItem(shop, CRISTALICA, ofensivos)
call ShopAddItem(shop, CINTURON_DE_FUERZA, fuerza)
call ShopAddItem(shop, CLARIDAD, consumibles)
call ShopAddItem(shop, CLAYMORE, ofensivos)
call ShopAddItem(shop, CORONA, atributos)
call ShopAddItem(shop, CORAZA_DE_ASALTO, auras + defensivos)
call ShopAddItem(shop, CORAZON_DE_TARRASQUE, regeneracion + fuerza)
call ShopAddItem(shop, COTA_DE_MALLA, defensivos)
call ShopAddItem(shop, DAGA_PARPADEANTE, magicos)
call ShopAddItem(shop, DAGON1, magicos)
call ShopAddItem(shop, DAGON2, magicos)
call ShopAddItem(shop, DAGON3, magicos)
call ShopAddItem(shop, DAGON4, magicos)
call ShopAddItem(shop, DAGON5, magicos)
call ShopAddItem(shop, DESOLADORA, ofensivos)
call ShopAddItem(shop, DESTRUCTOR_DE_CALAVERAS, ofensivos + control)
call ShopAddItem(shop, DEDALO, ofensivos)
call ShopAddItem(shop, DIADEMA, atributos)
call ShopAddItem(shop, DIFUSAL, agilidad + inteligencia + ofensivos + magicos)
call ShopAddItem(shop, DISPERSER, agilidad + inteligencia + ofensivos + magicos)
call ShopAddItem(shop, ESCUDO, auras + defensivos + soporte)
call ShopAddItem(shop, ESPADA_SOFOCANTE, magicos)
call ShopAddItem(shop, ESTILO_MANTA, atributos + movimiento + magicos)
call ShopAddItem(shop, ENCAJE_DE_VIENTO, movimiento)
call ShopAddItem(shop, ESPADAS_DE_ATAQUE, ofensivos)
call ShopAddItem(shop, ESPADA_DE_BRUJA, inteligencia + regeneracion + ofensivos)
call ShopAddItem(shop, ESPADA_DE_SOMBRA, ofensivos + magicos)
call ShopAddItem(shop, ESPADA_ABISAL, control + ofensivos + magicos)
call ShopAddItem(shop, ESPADA_DE_HALCON, defensivos + ofensivos + regeneracion)
call ShopAddItem(shop, ESPINA_DE_SANGRE, ofensivos + regeneracion + magicos + control)
call ShopAddItem(shop, ESFERA_DE_LINKENS, defensivos + atributos + magicos + regeneracion)
call ShopAddItem(shop, FRAGMENTO_DE_LUNA, ofensivos + magicos)
call ShopAddItem(shop, FUEGO_DE_HADAS, consumibles + ofensivos)
call ShopAddItem(shop, FURIA_DE_BATALLA, ofensivos + control)
call ShopAddItem(shop, GOTAS_DE_LLUVIA_INFUNDIDAS, consumibles + regeneracion)
call ShopAddItem(shop, GUADANA_DE_VYSE, regeneracion + inteligencia + control + magicos)
call ShopAddItem(shop, GRANADA_DE_SANGRE, consumibles + control)
call ShopAddItem(shop, GREBAS_DE_GUARDIAN, movimiento + soporte + auras + magicos)
call ShopAddItem(shop, GUANTELETES_DE_FUERZA, fuerza)
call ShopAddItem(shop, GUANTES_DE_PRISA, atributos)
call ShopAddItem(shop, GUARDIA_CARMESI, defensivos + magicos + regeneracion)
call ShopAddItem(shop, HACHA_DE_OGRO, fuerza)
call ShopAddItem(shop, HOJA_DE_PRONTITUD, agilidad)
call ShopAddItem(shop, JABALINA, ofensivos)
call ShopAddItem(shop, MANDOBLE, ofensivos)
call ShopAddItem(shop, MANGO_ENCANTADO, consumibles + regeneracion)
call ShopAddItem(shop, MANO_DE_MIDAS, atributos + magicos)
call ShopAddItem(shop, MANTO_DE_INTELIGENCIA, inteligencia)
call ShopAddItem(shop, MARIPOSA, ofensivos + agilidad)
call ShopAddItem(shop, MALLA_DE_CUCHILLAS, defensivos + magicos)
call ShopAddItem(shop, MARTILLO_DE_MITHRIL, ofensivos)
call ShopAddItem(shop, MASCARA_DE_LA_LOCURA, ofensivos + magicos)
call ShopAddItem(shop, MASCARA_DE_SABIO, regeneracion)
call ShopAddItem(shop, MASCARA_MORBIDA, ofensivos + regeneracion)
call ShopAddItem(shop, MASCARA_VUDU, regeneracion + magicos)
call ShopAddItem(shop, MECANISMO, soporte + auras + magicos)
call ShopAddItem(shop, MEDALLON_SAGRADO, atributos + soporte + magicos)
call ShopAddItem(shop, NUCLEO_DE_OCTARINA, atributos + ofensivos + magicos)
call ShopAddItem(shop, NUDILLOS_BLIZT, atributos)
call ShopAddItem(shop, LA_JOYA_DE_LA_VISION_VERDADERA, magicos)
call ShopAddItem(shop, LA_OFRENDA_DE_VLADIMIR, ofensivos + soporte + auras)
call ShopAddItem(shop, LENTE_DE_ETER, ofensivos + regeneracion)
call ShopAddItem(shop, OBSERVADOR, consumibles)
call ShopAddItem(shop, ORBE_DE_CORROSION, ofensivos + magicos)
call ShopAddItem(shop, ORBE_DE_VENENO, ofensivos + magicos)
call ShopAddItem(shop, ORBE_DE_LOTO, defensivos + regeneracion + magicos)
call ShopAddItem(shop, ORCHID, inteligencia + magicos + regeneracion + ofensivos + atributos + control)
call ShopAddItem(shop, PARASMA, ofensivos + magicos + inteligencia)
call ShopAddItem(shop, PALO_MAGICO, magicos)
call ShopAddItem(shop, PAVE, defensivos + soporte + magicos)
call ShopAddItem(shop, PERGAMINO_DEL_PORTAL_DE_LA_CUIDAD, consumibles)
call ShopAddItem(shop, PERSEVERANCIA, regeneracion)
call ShopAddItem(shop, PIEDRA_DE_LA_PLAGA, ofensivos)
call ShopAddItem(shop, PIEDRA_DEL_VACIO, regeneracion)
call ShopAddItem(shop, PIPA_DE_LA_PERSPICACIA, soporte + auras + defensivos + magicos)
call ShopAddItem(shop, PISADAS_POTENTES, movimiento + atributos)
call ShopAddItem(shop, PISADAS_POTENTES_A, movimiento + agilidad)
call ShopAddItem(shop, PISADAS_POTENTES_F, movimiento + fuerza)
call ShopAddItem(shop, PISADAS_POTENTES_I, movimiento + inteligencia)
call ShopAddItem(shop, POTENCIADOR_DE_ALMA, defensivos)
call ShopAddItem(shop, POLVO_DE_APARIENCIA, consumibles)
call ShopAddItem(shop, RAMA_DE_HIERRO, atributos + magicos)
call ShopAddItem(shop, REFRESHER, regeneracion + magicos + ofensivos)
call ShopAddItem(shop, SANGE, fuerza + ofensivos)
call ShopAddItem(shop, SOMBRERO_MULLIDO, defensivos)
call ShopAddItem(shop, SANGE_Y_YASHA, agilidad + fuerza + atributos + ofensivos)
call ShopAddItem(shop, SHIVAS, atributos + regeneracion + defensivos + magicos + auras)
call ShopAddItem(shop, TAMBOR_DE_RESISTENCIA, soporte + auras + magicos)
call ShopAddItem(shop, TANGO, consumibles)
call ShopAddItem(shop, TALISMAN_NULO, inteligencia + atributos)
call ShopAddItem(shop, TUNICA, regeneracion + auras + soporte)
call ShopAddItem(shop, TUNICA_DE_LOS_MAGOS, inteligencia)
call ShopAddItem(shop, UNGUENTO_CURATIVO, consumibles)
call ShopAddItem(shop, URNA_DE_LAS_SOMBRAS, regeneracion + defensivos + soporte + magicos)
call ShopAddItem(shop, VANGUARDIA, defensivos + regeneracion + magicos)
call ShopAddItem(shop, VARA_DE_ARAJ, inteligencia + soporte + magicos)
call ShopAddItem(shop, VARA_DEL_VIENTO, inteligencia + control + magicos + regeneracion + movimiento)
call ShopAddItem(shop, VARITA_MAGICA, atributos + magicos)
call ShopAddItem(shop, VASIJA_ESPIRITUAL, regeneracion + defensivos + soporte + magicos)
call ShopAddItem(shop, VELO_DE_LA_DISCORDIA, defensivos + regeneracion + magicos + atributos)
call ShopAddItem(shop, YASHA, agilidad + movimiento)
call ShopAddItem(shop, YELMO_DE_LA_VOLUNTAD_DE_HIERRO, defensivos)
call ShopAddItem(shop, YELMO_DEL_SENOR_SUPREMO, control + atributos)
call ShopAddItem(shop, YELMO_DEL_DOMINADOR, control + atributos)
call ShopAddItem(shop, ZAPATILLAS_DE_AGILIDAD, agilidad)
call ShopAddItem(shop, RECETA_BOTAS_DE_VIAJE, Recetas)
call ShopAddItem(shop, RECETA_YELMO_DOMINADOR, Recetas)
call ShopAddItem(shop, RECETA_YELMO_SENOR, Recetas)
call ShopAddItem(shop, RECETA_ANILLO_ALMA, Recetas)
call ShopAddItem(shop, RECETA_ESPADA_HALCON, Recetas)
call ShopAddItem(shop, RECETA_VARITA_MAGICA, Recetas)
call ShopAddItem(shop, RECETA_MIDAS, Recetas)
call ShopAddItem(shop, RECETA_BOTAS_ARCANAS, Recetas)
call ShopAddItem(shop, RECETA_GREBAS_GUARDIANAS, Recetas)
call ShopAddItem(shop, RECETA_VASIJA, Recetas)
call ShopAddItem(shop, RECETA_RODAMIENTO, Recetas)
call ShopAddItem(shop, RECETA_TUNICA, Recetas)
call ShopAddItem(shop, RECETA_PAVE, Recetas)
call ShopAddItem(shop, RECETA_ESCUDO, Recetas)
call ShopAddItem(shop, RECETA_URNA, Recetas)
call ShopAddItem(shop, RECETA_TAMBOR, Recetas)
call ShopAddItem(shop, RECETA_MECANISMO, Recetas)
call ShopAddItem(shop, RECETA_BASILIO, Recetas)
call ShopAddItem(shop, RECETA_LENTE, Recetas)
call ShopAddItem(shop, RECETA_DAGON, Recetas)
call ShopAddItem(shop, RECETA_DESTELLOS, Recetas)
call ShopAddItem(shop, RECETA_CUCHILLAS, Recetas)
call ShopAddItem(shop, RECETA_BKB, Recetas)
call ShopAddItem(shop, RECETA_ARAJ, Recetas)
call ShopAddItem(shop, RECETA_SANGE, Recetas)
call ShopAddItem(shop, RECETA_YASHA, Recetas)
call ShopAddItem(shop, RECETA_DESTRUCTOR, Recetas)
call ShopAddItem(shop, RECETA_ABISAL, Recetas)
call ShopAddItem(shop, RECETA_BRAZALETE, Recetas)
call ShopAddItem(shop, RECETA_TALISMAN_NULO, Recetas)
call ShopAddItem(shop, RECETA_BANDA_ESPECTRO, Recetas)
call ShopAddItem(shop, RECETA_CRISTALICA, Recetas)
call ShopAddItem(shop, RECETA_DEDALO, Recetas)
call ShopAddItem(shop, RECETA_CARMESI, Recetas)
call ShopAddItem(shop, RECETA_BRUJA, Recetas)
call ShopAddItem(shop, RECETA_PARASMA, Recetas)
call ShopAddItem(shop, RECETA_CORAZA_ASALTO, Recetas)
call ShopAddItem(shop, RECETA_PIPA, Recetas)
call ShopAddItem(shop, RECETA_BATALLA_FURIA, Recetas)
call ShopAddItem(shop, RECETA_VELO, Recetas)
call ShopAddItem(shop, RECETA_MEDALLON_SAGRADO, Recetas)
call ShopAddItem(shop, RECETA_TARRASQUE, Recetas)
call ShopAddItem(shop, RECETA_MANTA, Recetas)
call ShopAddItem(shop, RECETA_EUL, Recetas)
call ShopAddItem(shop, RECETA_VIENTO, Recetas)
call ShopAddItem(shop, RECETA_GUADANA, Recetas)
call ShopAddItem(shop, RECETA_DIFUSAL, Recetas)
call ShopAddItem(shop, RECETA_DISPERSER, Recetas)
call ShopAddItem(shop, RECETA_FORCE_STAFF, Recetas)
call ShopAddItem(shop, RECETA_REFRESHER, Recetas)
call ShopAddItem(shop, RECETA_SHIVAS, Recetas)
call ShopAddItem(shop, RECETA_ORCHID, Recetas)
call ShopAddItem(shop, RECETA_LOTO, Recetas)
call ShopAddItem(shop, RECETA_BLOODTHORN, Recetas)
call ShopAddItem(shop, RECETA_LINKENS, Recetas)
call ShopAddItem(shop, RECETA_CRESTA_SOLAR, Recetas)
return 0
endmethod
private static method onInit takes nothing returns nothing
call configure()
call create('n00A', 1000, 0.5)
call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, 0)
// call BlzFrameSetAlpha(BlzGetFrameByName("SimpleInventoryCover", 0), 0)
// call BlzFrameSetScale(BlzGetFrameByName("InventoryText", 0), 0.0001)
// call BlzFrameSetAbsPoint(BlzGetFrameByName("ConsoleUI", 0), FRAMEPOINT_TOPLEFT, 0.0, 0.633)
// call BlzFrameSetVisible(BlzGetFrameByName("ResourceBarFrame", 0), false)
// call BlzFrameSetVisible(BlzGetFrameByName("UpperButtonBarFrame", 0), false)
// call BlzFrameSetVisible(BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7), false)
// call BlzFrameSetVisible(BlzFrameGetChild(BlzFrameGetChild(BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 5),0), false)
// call BlzFrameSetParent(BlzGetFrameByName("MiniMapFrame", 0), BlzGetFrameByName("ConsoleUIBackdrop", 0))
// call BlzFrameSetVisible(BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT, 0), false)
endmethod
endstruct
endscope
//TESH.scrollpos=-1
//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 = 'dumm'
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
library xefx initializer init requires xebasic
//**************************************************
// xefx 0.6
// --------
// Recommended: ARGB (adds ARGBrecolor method)
// For your movable fx needs
//
//**************************************************
//==================================================
globals
private constant integer MAX_INSTANCES = 8190 //change accordingly.
private constant real RECYCLE_DELAY = 4.0
//recycling, in order to show the effect correctly, must wait some time before
//removing the unit.
private timer recycler
private timer NOW
endglobals
private struct recyclebin extends array
unit u
real schedule
static recyclebin end=0
static recyclebin begin=0
static method Recycle takes nothing returns nothing
call RemoveUnit(.begin.u) //this unit is private, systems shouldn't mess with it.
set .begin.u=null
set .begin=recyclebin(integer(.begin)+1)
if(.begin==.end) then
set .begin=0
set .end=0
else
call TimerStart(recycler, .begin.schedule-TimerGetElapsed(NOW), false, function recyclebin.Recycle)
endif
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
set NOW=CreateTimer()
call TimerStart(NOW,43200,true,null)
endfunction
struct xefx[MAX_INSTANCES]
public integer tag=0
private unit dummy
private effect fx=null
private real zang=0.0
private integer r=255
private integer g=255
private integer b=255
private integer a=255
private integer abil=0
static method create takes real x, real y, real facing returns xefx
local xefx this=xefx.allocate()
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
return this
endmethod
method operator owner takes nothing returns player
return GetOwningPlayer(this.dummy)
endmethod
method operator owner= takes player p returns nothing
call SetUnitOwner(this.dummy,p,false)
endmethod
method operator teamcolor= takes playercolor c returns nothing
call SetUnitColor(this.dummy,c)
endmethod
method operator scale= takes real value returns nothing
call SetUnitScale(this.dummy,value,value,value)
endmethod
//! textmacro XEFX_colorstuff takes colorname, colorvar
method operator $colorname$ takes nothing returns integer
return this.$colorvar$
endmethod
method operator $colorname$= takes integer value returns nothing
set this.$colorvar$=value
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
//! endtextmacro
//! runtextmacro XEFX_colorstuff("red","r")
//! runtextmacro XEFX_colorstuff("green","g")
//! runtextmacro XEFX_colorstuff("blue","b")
//! runtextmacro XEFX_colorstuff("alpha","a")
method recolor takes integer r, integer g , integer b, integer a returns nothing
set this.r=r
set this.g=g
set this.b=b
set this.a=a
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
implement optional ARGBrecolor
method operator abilityid takes nothing returns integer
return this.abil
endmethod
method operator abilityid= takes integer a returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(a!=0) then
call UnitAddAbility(this.dummy,a)
endif
set this.abil=a
endmethod
method flash takes string fx returns nothing
call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
endmethod
method operator xyangle takes nothing returns real
return GetUnitFacing(this.dummy)*bj_DEGTORAD
endmethod
method operator xyangle= takes real value returns nothing
call SetUnitFacing(this.dummy,value*bj_RADTODEG)
endmethod
method operator zangle takes nothing returns real
return this.zang
endmethod
method operator zangle= takes real value returns nothing
local integer i=R2I(value*bj_RADTODEG+90.5)
set this.zang=value
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(this.dummy, i )
endmethod
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method operator z= takes real value returns nothing
call SetUnitFlyHeight(this.dummy,value,0)
endmethod
method operator x= takes real value returns nothing
call SetUnitX(this.dummy,value)
endmethod
method operator y= takes real value returns nothing
call SetUnitY(this.dummy,value)
endmethod
method operator fxpath= takes string newpath returns nothing
if (this.fx!=null) then
call DestroyEffect(this.fx)
endif
if (newpath=="") then
set this.fx=null
else
set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
endif
endmethod
private method onDestroy takes nothing returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(this.fx!=null) then
call DestroyEffect(this.fx)
set this.fx=null
endif
if (recyclebin.end==MAX_INSTANCES) then
call TimerStart(recycler,0,false,function recyclebin.Recycle)
call ExplodeUnitBJ(this.dummy)
else
set recyclebin.end.u=this.dummy
set recyclebin.end.schedule=TimerGetElapsed(NOW)+RECYCLE_DELAY
set recyclebin.end= recyclebin( integer(recyclebin.end)+1)
if( recyclebin.end==1) then
call TimerStart(recycler, RECYCLE_DELAY, false, function recyclebin.Recycle)
endif
call SetUnitOwner(this.dummy,Player(15),false)
endif
set this.dummy=null
endmethod
endstruct
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* 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.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer2() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer2(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.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer2 takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer2 takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) 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: ReleaseTimer2: 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
set hasht = InitHashtable()
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library GroupUtils
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a simple implementation of a stack for groups that need to
//* be in the user's control for greater than an instant of time. Additionally,
//* this library provides a single, global group variable for use with user-end
//* enumerations. It is important to note that users should not be calling
//* DestroyGroup() on the global group, since then it may not exist for when it
//* it is next needed.
//*
//* The group stack removes the need for destroying groups and replaces it with
//* a recycling method.
//* function NewGroup takes nothing returns group
//* function ReleaseGroup takes group g returns boolean
//* function GroupRefresh takes group g returns nothing
//*
//* NewGroup grabs a currently unused group from the stack or creates one if the
//* stack is empty. You can use this group however you'd like, but always
//* remember to call ReleaseGroup on it when you are done with it. If you don't
//* release it, it will 'leak' and your stack may eventually overflow if you
//* keep doing that.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hash table. 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.
//*
globals
//* Group for use with all instant enumerations
group ENUM_GROUP = CreateGroup()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Assorted constants
private constant integer MAX_HANDLE_COUNT = 408000
private constant integer MIN_HANDLE_ID = 0x100000
//* Arrays and counter for the group stack
private group array Groups
private integer array Status[MAX_HANDLE_COUNT]
private integer Count = 0
endglobals
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
set Status[GetHandleId(Groups[Count])-MIN_HANDLE_ID] = 1
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer stat = Status[GetHandleId(g)-MIN_HANDLE_ID]
local boolean b = true
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Null groups cannot be released")
set b = false
elseif stat == 0 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Group not part of stack")
set b = false
elseif stat == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Groups cannot be multiply released")
set b = false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Max groups achieved, destroying group")
call DestroyGroup(g)
set b = false
else
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
set Status[GetHandleId(g)-MIN_HANDLE_ID] = 2
endif
return b
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//==============================================================================
// PUI -- Perfect Unit Indexing by Cohadar -- v5.1
//==============================================================================
//
// PURPOUSE:
// * Extending UnitUserData()
// * This is basically perfect hashing algorithm for units
//
// HOW TO USE:
// * You have only one function at your disposal GetUnitIndex(unit)
// It will return a unique index for each unit in range 1..8190
//
// * What you will do with that index is all up to you
// Of course using global arrays is the most obvious choice
// Advanced jassers will think of a couple of more clever ones ofc.
//
// * There are also 2 textmacros available at the end of library code
// They can be used for easier attaching to units
// PUI for structs
// PUI_PROPERTY for unit, integer, real, boolean and string variables
//
// PROS:
// * You can use any number of systems that previously could not work together
// because they all required exclusive access of UnitUserData()
//
// * You can also use this to attach spell data structs to casters
//
// * There are no SetUnitIndex() or ClearUnitIndex() functions here
// Each unit gets assigned one index that cannot be changed
// That index will be automatically recycled when unit is removed from the game.
//
// CONS:
// * This system uses UnitUserData() itself
// That means that if you want to use PUI you must recode
// any other system that uses UnitUserData() to use GetUnitIndex() instead
//
// * If you use UnitIndex for arrays of non-native types (timers, effects and similar)
// you must check if timer on that index already exists before you create a new one.
// This can happen if GetUnitIndex() assigns a recycled index (index of some dead and removed unit)
// to the newly created unit for which you intended to use timer for
//
// * All in all this is not a sys for newbies, it gives great power,
// but it requires knowledge and carefull handling
//
// DETAILS:
// * System is using unit array to keep track of all units with an index.
// Array is periodically checked for removed units,
// when removed unit is found, index is recycled.
// Indexes have "decay time" to prevent bugs
// caused by attaching to "Can't Raise, Does not decay" type units,
// or by using RemoveUnit() function
//
// SYSTEM COMMANDS: (debug mode only, red player only)
//
// * type -pui to display indexes of currently selected units
// * type -puistats to display some stats
//
// THANKS TO:
// * Vexorian - for his help with PUI textmacro
//
// HOW TO IMPORT:
// * Just create a trigger named PUI
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library PUI initializer Init
//==============================================================================
globals
//-----------------------------------------------
private constant real INDEX_DECAY_TIME = 5. // seconds
//-----------------------------------------------
private constant real PERIOD = 0.03125 // 32 fps
//-----------------------------------------------
private constant integer DECAY_TICKS = R2I(INDEX_DECAY_TIME/PERIOD)
//-----------------------------------------------
private integer array Indexz
private unit array Unitz
private integer array Decayz
private integer array Tickz
private integer maxindex = 0
private integer topindex = 0
private integer decayindex = 0
private integer checker = 0
private integer decayer = 0
private integer tick = 0
endglobals
//==============================================================================
private function PeriodicRecycler takes nothing returns boolean
local integer temp
set tick = tick + 1
if topindex > decayindex then
set checker = checker + 1
if checker > topindex then
set checker = decayindex + 1
endif
if (GetUnitUserData(Unitz[checker])==0) then
set decayindex = decayindex + 1
set Unitz[checker] = Unitz[decayindex]
// swap(checker, decayindex)
set temp = Indexz[checker]
set Indexz[checker] = Indexz[decayindex]
set Indexz[decayindex] = temp
set Decayz[decayindex] = DECAY_TICKS
set Tickz[decayindex] = tick
endif
endif
if decayindex > 0 then
set decayer = decayer + 1
if decayer > decayindex then
set decayer = 1
endif
set Decayz[decayer] = Decayz[decayer] - (tick-Tickz[decayer])
if Decayz[decayer] > 0 then
set Tickz[decayer] = tick
else
// swap(decayer, decayindex)
set temp = Indexz[decayer]
set Indexz[decayer] = Indexz[decayindex]
set Indexz[decayindex] = temp
set Unitz[decayindex] = Unitz[topindex]
// swap(decayindex, topindex)
set temp = Indexz[decayindex]
set Indexz[decayindex] = Indexz[topindex]
set Indexz[topindex] = temp
set decayindex = decayindex - 1
set topindex = topindex - 1
endif
endif
return false
endfunction
//==============================================================================
// Main and only function exported by this library
//==============================================================================
function GetUnitIndex takes unit whichUnit returns integer
local integer index
debug if whichUnit == null then
debug call BJDebugMsg("|c00FF0000ERROR: PUI - Index requested for null unit")
debug return 0
debug endif
set index = GetUnitUserData(whichUnit)
if index == 0 then
set topindex = topindex + 1
if topindex > maxindex then
set maxindex = topindex
set Indexz[topindex] = topindex
endif
set index = Indexz[topindex]
set Unitz[topindex] = whichUnit
call SetUnitUserData(whichUnit, index)
set index = GetUnitUserData(whichUnit)
// this happens when requesting unit index for removed unit
debug if index == 0 then
debug call BJDebugMsg("|c00FFCC00WARNING: PUI - Bad unit handle")
debug endif
//debug call BJDebugMsg("|c00FFCC00PUI: Index assigned #" + I2S(index))
endif
return index
endfunction
//==============================================================================
private function DisplayStats takes nothing returns nothing
call BJDebugMsg("=============================================")
call BJDebugMsg("Biggest index ever = " + I2S(maxindex))
call BJDebugMsg("Indexes in use = " + I2S(topindex-decayindex))
call BJDebugMsg("Decaying indexes = " + I2S(decayindex))
call BJDebugMsg("Released indexes = " + I2S(maxindex-topindex))
call BJDebugMsg("=============================================")
endfunction
//===========================================================================
private function DisplaySelectedEnum takes nothing returns nothing
call BJDebugMsg( "PUI(" + ( GetUnitName(GetEnumUnit()) + ( ") = " + I2S(GetUnitUserData(GetEnumUnit())) ) ) )
endfunction
//===========================================================================
private function DisplaySelected takes nothing returns nothing
local group g = CreateGroup()
call SyncSelections()
call GroupEnumUnitsSelected(g, Player(0), null)
call ForGroup(g, function DisplaySelectedEnum)
call DestroyGroup(g)
set g = null
endfunction
//==============================================================================
private function Init takes nothing returns nothing
local trigger trig
set trig = CreateTrigger()
call TriggerRegisterTimerEvent( trig, PERIOD, true )
call TriggerAddCondition( trig, Condition(function PeriodicRecycler) )
debug set trig = CreateTrigger()
debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-pui", true )
debug call TriggerAddAction( trig, function DisplaySelected )
debug set trig = CreateTrigger()
debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-puistats", true )
debug call TriggerAddAction( trig, function DisplayStats )
endfunction
endlibrary
//===========================================================================
// Allowed PUI_PROPERTY TYPES are: unit, integer, real, boolean, string
// Do NOT put handles that need to be destroyed here (timer, trigger, ...)
// Instead put them in a struct and use PUI textmacro
//===========================================================================
//! textmacro PUI_PROPERTY takes VISIBILITY, TYPE, NAME, DEFAULT
$VISIBILITY$ struct $NAME$
private static unit array pui_unit
private static $TYPE$ array pui_data
//-----------------------------------------------------------------------
// Returns default value when first time used
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns $TYPE$
local integer pui = GetUnitIndex(whichUnit)
if .pui_unit[pui] != whichUnit then
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = $DEFAULT$
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, $TYPE$ whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
endmethod
endstruct
//! endtextmacro
//===========================================================================
// Never destroy PUI structs directly.
// Use .release() instead, will call .destroy()
//===========================================================================
//! textmacro PUI
private static unit array pui_unit
private static integer array pui_data
private static integer array pui_id
//-----------------------------------------------------------------------
// Returns zero if no struct is attached to unit
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns integer
local integer pui = GetUnitIndex(whichUnit)
if .pui_data[pui] != 0 then
if .pui_unit[pui] != whichUnit then
// recycled handle detected
call .destroy(.pui_data[pui])
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endif
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
// This will overwrite already attached struct if any
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, integer whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
if .pui_data[pui] != 0 then
call .destroy(.pui_data[pui])
endif
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
set .pui_id[whichData] = pui
endmethod
//-----------------------------------------------------------------------
// If you do not call release struct will be destroyed when unit handle gets recycled
//-----------------------------------------------------------------------
method release takes nothing returns nothing
local integer pui= .pui_id[integer(this)]
call .destroy()
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endmethod
//! endtextmacro
library PauseUnitEx /*
--------------
*/ requires /*
--------------
--------------------
*/ optional Table /*
--------------------
Link: "hiveworkshop.com/forums/showthread.php?t=188084"
--------------------
| PauseUnitEx |
| - MyPad |
--------------------
A simple snippet that grants additional functionality
to BlzPauseUnitEx that mimics PauseUnit
---------
| API |
---------
function PauseUnitEx(unit whichUnit, boolean flag)
- Internally calls BlzPauseUnitEx
function IsUnitPausedEx(unit whichUnit) -> boolean
- Checks if the unit is paused.
- This does not return accurate values when
BlzPauseUnitEx is called directly.
function GetUnitPauseExCounter(unit whichUnit) -> integer
- Returns the pause counter of the unit.
function SetUnitPauseExCounter(unit whichUnit, integer new)
- Sets the pause counter of the unit to the
new value. Internally calls BlzPauseUnitEx
when appropriate.
- Time Complexity: O(n)
*/
private module PauseM
static if LIBRARY_Table then
static Table map = 0
private static method onInit takes nothing returns nothing
set thistype.map = Table.create()
endmethod
else
static hashtable map = InitHashtable()
endif
static method getPauseCounter takes unit whichUnit returns integer
local integer counter = 0
local integer unitId = GetHandleId(whichUnit)
static if LIBRARY_Table then
set counter = map[unitId]
else
set counter = LoadInteger(map, 0, unitId)
endif
return counter
endmethod
static method pauseUnit takes unit whichUnit, boolean flag returns nothing
local integer counter = thistype.getPauseCounter(whichUnit)
local integer unitId = GetHandleId(whichUnit)
local integer incr = IntegerTertiaryOp(flag, 1, -1)
set counter = counter + incr
static if LIBRARY_Table then
set map[unitId] = counter
else
call SaveInteger(map, 0, unitId, counter)
endif
call BlzPauseUnitEx(whichUnit, flag)
endmethod
static method isPaused takes unit whichUnit returns boolean
local integer counter = thistype.getPauseCounter(whichUnit)
return counter > 0
endmethod
static method setPauseCounter takes unit whichUnit, integer new returns nothing
local integer counter = thistype.getPauseCounter(whichUnit)
local integer sign = 0
local integer unitId = GetHandleId(whichUnit)
local boolean flag = false
if new < counter then
set sign = -1
set flag = false
elseif new > counter then
set sign = 1
set flag = true
endif
loop
exitwhen counter == new
set counter = counter + sign
call BlzPauseUnitEx(whichUnit, flag)
endloop
static if LIBRARY_Table then
set map[unitId] = counter
else
call SaveInteger(map, 0, unitId, counter)
endif
endmethod
endmodule
private struct Pause extends array
implement PauseM
endstruct
function PauseUnitEx takes unit whichUnit, boolean flag returns nothing
call Pause.pauseUnit(whichUnit, flag)
endfunction
function SetUnitPauseExCounter takes unit whichUnit, integer new returns nothing
call Pause.setPauseCounter(whichUnit, new)
endfunction
function IsUnitPausedEx takes unit whichUnit returns boolean
return Pause.isPaused(whichUnit)
endfunction
function GetUnitPauseExCounter takes unit whichUnit returns integer
return Pause.getPauseCounter(whichUnit)
endfunction
endlibrary
library RemoveEffect
//Destroying an effect always plays its death animation and any associated sounds.
//This library fixes it in a simple way: move the effect to a location where nobody can see or hear it.
//By Pyrogasm, additional help by Bribe
//v1.1
globals
private real SAFE_X = -3900.
private real SAFE_Y = 3900.
private real SAFE_Z = -1000.
private real TIMESCALE = 10. //doesn't really matter what this is but we set it to > 0 so the animations actually finish
endglobals
function RemoveEffect takes effect e returns nothing
call BlzSetSpecialEffectAlpha(e, 255)
call BlzSetSpecialEffectZ(e, SAFE_Z)
call BlzSetSpecialEffectPosition(e, SAFE_X, SAFE_Y, SAFE_Z)
call BlzSetSpecialEffectTimeScale(e, TIMESCALE)
call DestroyEffect(e)
endfunction
endlibrary
//Place these functions at map header (Jass) or in a library/module (vJass)
function CreateTimedEffectOnUnit takes string mdl, unit target, string attach, real duration returns nothing
set udg_TSELL_EffectName = mdl
set udg_TSELL_TargetUnit = target
set udg_TSELL_AttachPoint = attach
set udg_TSELL_Duration = duration
call ConditionalTriggerExecute( udg_TSELL_TriggerRegister )
endfunction
function CreateTimedEffectOnLoc takes string mdl, real x, real y, real duration returns nothing
set udg_TSELL_EffectName = mdl
set udg_TSELL_Point = Location(x,y)
set udg_TSELL_Duration = duration
call ConditionalTriggerExecute( udg_TSELL_TriggerRegister )
endfunction
//TESH.scrollpos=1
//TESH.alwaysfold=0
// allocator
// thanks nestharus/vexorian c:
function MUI_CreateInstance takes nothing returns integer
local integer instance
if ( udg_recycle == 0 ) then
set udg_instanceCount = udg_instanceCount + 1
set instance = udg_instanceCount
else
set instance = udg_recycle
set udg_recycle = udg_recycleNext[udg_recycle]
endif
// reserving space
set instance = instance * udg_limit
return instance
endfunction
// deallocator
// thanks nestharus/vexorian c:
function MUI_RecycleInstance takes integer instance returns nothing
set instance = instance / udg_limit
set udg_recycleNext[instance] = udg_recycle
set udg_recycle = instance
endfunction
function MUI_ShowOverLimitError takes nothing returns nothing
call BJDebugMsg("No puedes guardar mas de " + I2S(udg_limit) + ". Si necesitas mas, modifica la variable limit.\nYou can't save more than " + I2S(udg_limit) + ". If you need more, modify the variable called 'limit'")
endfunction
// private
function MUI_SaveUnits takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_unit[instance + i] = udg_set_unit[i]
set udg_set_unit[i] = null
exitwhen i == udg_used_units
set i = i + 1
endloop
set udg_mui_used_units[instance] = udg_used_units
endfunction
// private
function MUI_SaveReals takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_real[instance + i] = udg_set_real[i]
set udg_set_real[i] = 0.
exitwhen i == udg_used_reals
set i = i + 1
endloop
set udg_mui_used_reals[instance] = udg_used_reals
endfunction
// private
function MUI_SavePlayers takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_player[instance + i] = udg_set_player[i]
set udg_set_player[i] = null
exitwhen i == udg_used_players
set i = i + 1
endloop
set udg_mui_used_players[instance] = udg_used_players
endfunction
// private
function MUI_SavePoints takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_point[instance + i] = udg_set_point[i]
set udg_set_point[i] = null
exitwhen i == udg_used_points
set i = i + 1
endloop
set udg_mui_used_points[instance] = udg_used_points
endfunction
// private
function MUI_SaveEffects takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_effect[instance + i] = udg_set_effect[i]
set udg_set_effect[i] = null
exitwhen i == udg_used_effects
set i = i + 1
endloop
set udg_mui_used_effects[instance] = udg_used_effects
endfunction
// private
function MUI_SaveIntegers takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_integer[instance + i] = udg_set_integer[i]
set udg_set_integer[i] = 0
exitwhen i == udg_used_integers
set i = i + 1
endloop
set udg_mui_used_integers[instance] = udg_used_integers
endfunction
// private
function MUI_SaveUnitGroups takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_group[instance + i] = udg_set_group[i]
set udg_set_group[i] = null
exitwhen i == udg_used_groups
set i = i + 1
endloop
set udg_mui_used_groups[instance] = udg_used_groups
endfunction
// private
function MUI_SaveBooleans takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_boolean[instance + i] = udg_set_boolean[i]
set udg_set_boolean[i] = false
exitwhen i == udg_used_booleans
set i = i + 1
endloop
set udg_mui_used_booleans[instance] = udg_used_booleans
endfunction
// private
function MUI_SaveDestructibles takes integer instance returns nothing
local integer i = 1
loop
set udg_mui_destructible[instance + i] = udg_set_destructible[i]
set udg_set_destructible[i] = null
exitwhen i == udg_used_destructibles
set i = i + 1
endloop
set udg_mui_used_destructibles[instance] = udg_used_destructibles
endfunction
// private
function MUI_Periodic takes nothing returns nothing
local timer expiredTimer = GetExpiredTimer()
local integer expiredTimerId = GetHandleId(expiredTimer)
local integer instance = LoadInteger(udg_hashtable, expiredTimerId, 0)
local integer i
// avoid recursion problems
local unit array prevGetUnit
local real array prevGetReal
local player array prevGetPlayer
local location array prevGetPoint
local effect array prevGetEffect
local integer array prevGetInteger
local group array prevGetGroup
local boolean array prevGetBoolean
local destructable array prevGetDestructible
local boolean prevAutomaticClean = udg_automaticClean
local boolean prevFinish = udg_finish
// unit
if ( udg_mui_used_units[instance] > 0 ) then
set i = 1
loop
set prevGetUnit[i] = udg_get_unit[i]
set udg_get_unit[i] = udg_mui_unit[instance + i]
exitwhen i == udg_mui_used_units[instance]
set i = i + 1
endloop
endif
// real
if ( udg_mui_used_reals[instance] > 0 ) then
set i = 1
loop
set prevGetReal[i] = udg_get_real[i]
set udg_get_real[i] = udg_mui_real[instance + i]
exitwhen i == udg_mui_used_reals[instance]
set i = i + 1
endloop
endif
// player
if ( udg_mui_used_players[instance] > 0 ) then
set i = 1
loop
set prevGetPlayer[i] = udg_get_player[i]
set udg_get_player[i] = udg_mui_player[instance + i]
exitwhen i == udg_mui_used_players[instance]
set i = i + 1
endloop
endif
// location
if ( udg_mui_used_points[instance] > 0 ) then
set i = 1
loop
set prevGetPoint[i] = udg_get_point[i]
set udg_get_point[i] = udg_mui_point[instance + i]
exitwhen i == udg_mui_used_points[instance]
set i = i + 1
endloop
endif
// effect
if ( udg_mui_used_effects[instance] > 0 ) then
set i = 1
loop
set prevGetEffect[i] = udg_get_effect[i]
set udg_get_effect[i] = udg_mui_effect[instance + i]
exitwhen i == udg_mui_used_effects[instance]
set i = i + 1
endloop
endif
// integer
if ( udg_mui_used_integers[instance] > 0 ) then
set i = 1
loop
set prevGetInteger[i] = udg_get_integer[i]
set udg_get_integer[i] = udg_mui_integer[instance + i]
exitwhen i == udg_mui_used_integers[instance]
set i = i + 1
endloop
endif
// group
if ( udg_mui_used_groups[instance] > 0 ) then
set i = 1
loop
set prevGetGroup[i] = udg_get_group[i]
set udg_get_group[i] = udg_mui_group[instance + i]
exitwhen i == udg_mui_used_groups[instance]
set i = i + 1
endloop
endif
// boolean
if ( udg_mui_used_booleans[instance] > 0 ) then
set i = 1
loop
set prevGetBoolean[i] = udg_get_boolean[i]
set udg_get_boolean[i] = udg_mui_boolean[instance + i]
exitwhen i == udg_mui_used_booleans[instance]
set i = i + 1
endloop
endif
// destructible
if ( udg_mui_used_destructibles[instance] > 0 ) then
set i = 1
loop
set prevGetDestructible[i] = udg_get_destructible[i]
set udg_get_destructible[i] = udg_mui_destructible[instance + i]
exitwhen i == udg_mui_used_destructibles[instance]
set i = i + 1
endloop
endif
call TriggerExecute(LoadTriggerHandle(udg_hashtable, expiredTimerId, 1))
// unit
if ( udg_mui_used_units[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
set udg_mui_unit[instance + i] = null
else
set udg_mui_unit[instance + i] = udg_get_unit[i]
endif
set udg_get_unit[i] = prevGetUnit[i]
set prevGetUnit[i] = null
exitwhen i == udg_mui_used_units[instance]
set i = i + 1
endloop
endif
// real
if ( udg_mui_used_reals[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
set udg_mui_real[instance + i] = 0.
else
set udg_mui_real[instance + i] = udg_get_real[i]
endif
set udg_get_real[i] = prevGetReal[i]
exitwhen i == udg_mui_used_reals[instance]
set i = i + 1
endloop
endif
// player
if ( udg_mui_used_players[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
set udg_mui_player[instance + i] = null
else
set udg_mui_player[instance + i] = udg_get_player[i]
endif
set udg_get_player[i] = prevGetPlayer[i]
set prevGetPlayer[i] = null
exitwhen i == udg_mui_used_players[instance]
set i = i + 1
endloop
endif
// location
if ( udg_mui_used_points[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
if ( udg_automaticClean ) then
call RemoveLocation(udg_mui_point[instance + i])
call RemoveLocation(udg_get_point[i])
endif
set udg_mui_point[instance + i] = null
else
if ( udg_mui_point[instance + i] != udg_get_point[i] ) then
call RemoveLocation(udg_mui_point[instance + i])
set udg_mui_point[instance + i] = udg_get_point[i]
endif
endif
set udg_get_point[i] = prevGetPoint[i]
set prevGetPoint[i] = null
exitwhen i == udg_mui_used_points[instance]
set i = i + 1
endloop
endif
// effect
if ( udg_mui_used_effects[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
if ( udg_automaticClean ) then
call DestroyEffect(udg_mui_effect[instance + i])
call DestroyEffect(udg_get_effect[i])
endif
set udg_mui_effect[instance + i] = null
else
if ( udg_mui_effect[instance + i] != udg_get_effect[i] ) then
call DestroyEffect(udg_mui_effect[instance + i])
set udg_mui_effect[instance + i] = udg_get_effect[i]
endif
endif
set udg_get_effect[i] = prevGetEffect[i]
set prevGetEffect[i] = null
exitwhen i == udg_mui_used_effects[instance]
set i = i + 1
endloop
endif
// integer
if ( udg_mui_used_integers[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
set udg_mui_integer[instance + i] = 0
else
set udg_mui_integer[instance + i] = udg_get_integer[i]
endif
set udg_get_integer[i] = prevGetInteger[i]
exitwhen i == udg_mui_used_integers[instance]
set i = i + 1
endloop
endif
// groups
if ( udg_mui_used_groups[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
if ( udg_automaticClean ) then
call DestroyGroup(udg_mui_group[instance + i])
call DestroyGroup(udg_get_group[i])
endif
set udg_mui_group[instance + i] = null
else
if ( udg_mui_group[instance + i] != udg_get_group[i] ) then
call DestroyGroup(udg_mui_group[instance + i])
set udg_mui_group[instance + i] = udg_get_group[i]
endif
endif
set udg_get_group[i] = prevGetGroup[i]
set prevGetGroup[i] = null
exitwhen i == udg_mui_used_groups[instance]
set i = i + 1
endloop
endif
// boolean
if ( udg_mui_used_booleans[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
set udg_mui_boolean[instance + i] = false
else
set udg_mui_boolean[instance + i] = udg_get_boolean[i]
endif
set udg_get_boolean[i] = prevGetBoolean[i]
exitwhen i == udg_mui_used_booleans[instance]
set i = i + 1
endloop
endif
// destructible
if ( udg_mui_used_destructibles[instance] > 0 ) then
set i = 1
loop
if ( udg_finish ) then
if ( udg_automaticClean ) then
call RemoveDestructable(udg_mui_destructible[instance + i])
call RemoveDestructable(udg_get_destructible[instance + i])
endif
set udg_mui_destructible[instance + i] = null
else
set udg_mui_destructible[instance + i] = udg_get_destructible[i]
endif
set udg_get_destructible[i] = prevGetDestructible[i]
exitwhen i == udg_mui_used_destructibles[instance]
set i = i + 1
endloop
endif
if ( udg_finish ) then
set udg_mui_used_units[instance] = 0
set udg_mui_used_reals[instance] = 0
set udg_mui_used_players[instance] = 0
set udg_mui_used_points[instance] = 0
set udg_mui_used_effects[instance] = 0
set udg_mui_used_integers[instance] = 0
set udg_mui_used_groups[instance] = 0
set udg_mui_used_booleans[instance] = 0
set udg_mui_used_destructibles[instance] = 0
call MUI_RecycleInstance(instance)
call FlushChildHashtable(udg_hashtable, expiredTimerId)
call PauseTimer(expiredTimer)
call DestroyTimer(expiredTimer)
endif
set udg_automaticClean = prevAutomaticClean
set udg_finish = prevFinish
set expiredTimer = null
endfunction
// private
function MUI_OnTimeoutChange takes nothing returns nothing
local timer periodicTimer = CreateTimer()
local integer instance = MUI_CreateInstance()
// units
if ( udg_used_units > 0 ) then
if ( udg_used_units > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveUnits(instance)
set udg_used_units = 0
endif
endif
// reals
if ( udg_used_reals > 0 ) then
if ( udg_used_reals > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveReals(instance)
set udg_used_reals = 0
endif
endif
// players
if ( udg_used_players > 0 ) then
if ( udg_used_players > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SavePlayers(instance)
set udg_used_players = 0
endif
endif
// points
if ( udg_used_points > 0 ) then
if ( udg_used_points > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SavePoints(instance)
set udg_used_points = 0
endif
endif
// effects
if ( udg_used_effects > 0 ) then
if ( udg_used_effects > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveEffects(instance)
set udg_used_effects = 0
endif
endif
// integers
if ( udg_used_integers > 0 ) then
if ( udg_used_integers > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveIntegers(instance)
set udg_used_integers = 0
endif
endif
// groups
if ( udg_used_groups > 0 ) then
if ( udg_used_groups > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveUnitGroups(instance)
set udg_used_groups = 0
endif
endif
// boolean
if ( udg_used_booleans > 0 ) then
if ( udg_used_booleans > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveBooleans(instance)
set udg_used_booleans = 0
endif
endif
// destructibles
if ( udg_used_destructibles > 0 ) then
if ( udg_used_destructibles > udg_limit ) then
call MUI_ShowOverLimitError()
else
call MUI_SaveDestructibles(instance)
set udg_used_destructibles = 0
endif
endif
call SaveInteger(udg_hashtable, GetHandleId(periodicTimer), 0, instance)
call SaveTriggerHandle(udg_hashtable, GetHandleId(periodicTimer), 1, udg_trigger)
call TimerStart(periodicTimer, udg_timeout, true, function MUI_Periodic)
set udg_timeout = 0.
set udg_trigger = null
set periodicTimer = null
endfunction
// initializer
function InitTrig_MUI takes nothing returns nothing
set gg_trg_MUI = CreateTrigger()
set udg_hashtable = InitHashtable()
call TriggerRegisterVariableEvent(gg_trg_MUI, "udg_timeout", GREATER_THAN, 0)
call TriggerAddAction(gg_trg_MUI, function MUI_OnTimeoutChange)
endfunction
//TESH.scrollpos=23
//TESH.alwaysfold=0
function SetUnitFacingZ takes unit u, real radians returns nothing
local integer i=R2I(radians*bj_RADTODEG+90.5)
// call SaveReal(WPSS_HASH, GetHandleId(u), StringHash("AngleZ"), radians)
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(u, i)
endfunction
function GetUnitZ takes unit u returns real
local location p = GetUnitLoc(u)
local real r = GetLocationZ(p)+GetUnitFlyHeight(u)
call RemoveLocation(p)
set p = null
return r
endfunction
function SetPointInBorders takes location l returns nothing
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real nx = x
local real ny = y
if x > udg_WORLD_BORDER_MAX_X then
set nx = udg_WORLD_BORDER_MAX_X
elseif x < udg_WORLD_BORDER_MIN_X then
set nx = udg_WORLD_BORDER_MIN_X
endif
if y > udg_WORLD_BORDER_MAX_Y then
set ny = udg_WORLD_BORDER_MAX_Y
elseif y < udg_WORLD_BORDER_MIN_Y then
set ny = udg_WORLD_BORDER_MIN_Y
endif
call MoveLocation(l,nx,ny)
endfunction
function Trig_Utilidad_SUP_Actions takes nothing returns nothing
//call BJDebugMsg("KILL")
endfunction
function Trig_Utilidad_SUP_Conditions takes nothing returns boolean
if GetUnitTypeId(GetTriggerUnit())==udg_DUMMY_ID then
call Trig_Utilidad_SUP_Actions()
endif
return FALSE
endfunction
function InitTrig_Utilidad_SUP takes nothing returns nothing
local trigger t=CreateTrigger()
//call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
//call TriggerAddCondition( t, Condition( function Trig_Utilidad_SUP_Conditions ) )
set t =null
endfunction
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//Credits:
// - Blaxor for the inspiration
// - cohadar for his PUI library
// - Rising_Dusk for his GroupUtils library
// - Vexorian for JassHelper and TimerUtils
// - PipeDream for Grimoire and all his help with spirals
// - PitzerMike for JassNewGenPack
// - SFilip for TESH
// How to import:
// - Copy the code into a trigger on your map, adjust the constants below (especially AID) and youre done.
// - Note that you have to copy over the required libraries as well
library FireSpiral uses TimerUtils, GroupUtils, PUI, xefx
globals
private constant integer AID = 'A001' // rawcode of the triggering abiltiy (press Ctrl+D to display the rawcode of objects, in the object editor)
private constant real FX_INTERVAL = 0.05 // effects are spawned in this interval
private constant string FIRE_FX = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl" // this is the effect the spiral consits of
private constant real FIRE_FX_RADIUS = 24. // collision size of the beforementioned effect
private constant real FIRE_FX_SCALE = 1. // scale of beforementioned effect
private real array FIRE_DMG // Units receive this much damage per second
private constant real FIRE_DMG_RADIUS = 96 // this is the radius in which units around the effects get receive damage
private constant real FIRE_DMG_TICK = 1. // this is the granulation of damage
private constant string FIRE_DMG_FX = "Environment\\LargeBuildingFire\\LargeBuildingFire2.mdl" // this is the effect spawned on units receiving damage by the spiral
private constant string FIRE_DMG_FX_ATTPT = "head" // this is the attachmentpoint where the beforementioned effect gets attached to
private constant real FIRE_DMG_FX_STAY = 1. // the beforementioned effect stays on units this long after they receive no more damage
private constant attacktype FIRE_DMG_ATTACKTYPE = ATTACK_TYPE_NORMAL // attacktype of the damage units receive
private constant damagetype FIRE_DMG_DAMAGETYPE = DAMAGE_TYPE_MAGIC // damagetype of the damage units receive
private real array SPIRAL_INITIAL_RADIUS // initial radius of the spiral
private real array SPIRAL_END_RADIUS // radius of the spiral
private real array SPIRAL_CIRCLES // how often does a spiral reach ((angle) modulo (2*PI))==0
private integer array SPIRAL_ENDINGS // number of spirals spawned
private real array DURATION // Duration of the spiral after all effects have been spawned
private constant integer MAX_FIRE_FX_PER_INSTANCE = 255
endglobals
private function SetUpFIRE_DMG takes nothing returns nothing
set FIRE_DMG[1]=150.
set FIRE_DMG[2]=200.
set FIRE_DMG[3]=250.
endfunction
private function SetUpSPIRAL_INITIAL_RADIUS takes nothing returns nothing
set SPIRAL_INITIAL_RADIUS[1]=100
set SPIRAL_INITIAL_RADIUS[2]=150
set SPIRAL_INITIAL_RADIUS[3]=200
endfunction
private function SetUpSPIRAL_END_RADIUS takes nothing returns nothing
set SPIRAL_END_RADIUS[1]=600.
set SPIRAL_END_RADIUS[2]=700.
set SPIRAL_END_RADIUS[3]=800.
endfunction
private function SetUpSPIRAL_CIRCLES takes nothing returns nothing
set SPIRAL_CIRCLES[1]=0.6
set SPIRAL_CIRCLES[2]=0.8
set SPIRAL_CIRCLES[3]=1.0
endfunction
private function SetUpSPIRAL_ENDINGS takes nothing returns nothing
set SPIRAL_ENDINGS[1]=3
set SPIRAL_ENDINGS[2]=4
set SPIRAL_ENDINGS[3]=5
endfunction
private function SetUpDURATION takes nothing returns nothing
set DURATION[1]=10.
set DURATION[2]=15.
set DURATION[3]=20.
endfunction
// proxy functions
// if you want to use formulae, edit these
private function Fire_Dmg takes integer level returns real
return FIRE_DMG[level]
endfunction
private function Spiral_Initial_Radius takes integer level returns real
return SPIRAL_INITIAL_RADIUS[level]
endfunction
private function Spiral_End_Radius takes integer level returns real
return SPIRAL_END_RADIUS[level]
endfunction
private function Spiral_Circles takes integer level returns real
return SPIRAL_CIRCLES[level]
endfunction
private function Spiral_Endings takes integer level returns integer
return SPIRAL_ENDINGS[level]
endfunction
private function Duration takes integer level returns real
return DURATION[level]
endfunction
// I wouldnt edit anything below this line, if i were you
private struct Data
unit c
integer level
integer i
timer t
real x
real y
real a
real b
real f
real d
integer fxcount=0
xefx array FX[MAX_FIRE_FX_PER_INSTANCE]
real array FXX[MAX_FIRE_FX_PER_INSTANCE]
real array FXY[MAX_FIRE_FX_PER_INSTANCE]
static Data array Structs
static integer Count=0
static timer T=CreateTimer()
static Data tmps
static boolexpr FireDmg
static timer array ImmoT
static effect array ImmoFX
static method ImmoCallback takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer i=GetTimerData(t)
call DestroyEffect(Data.ImmoFX[i])
set Data.ImmoFX[i]=null
call ReleaseTimer2(t)
endmethod
static method FireDmgFunc takes nothing returns boolean
local unit u=GetFilterUnit()
local integer i
local integer j=0
local timer t
local boolean b=false
if IsUnitEnemy(u, GetOwningPlayer(Data.tmps.c)) and IsUnitType(u, UNIT_TYPE_DEAD)==false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false then
loop
exitwhen j>=Data.tmps.fxcount
if (((Data.tmps.FXX[j]-GetUnitX(u))*(Data.tmps.FXX[j]-GetUnitX(u)))+((Data.tmps.FXY[j]-GetUnitY(u))*(Data.tmps.FXY[j]-GetUnitY(u))))<=FIRE_DMG_RADIUS*FIRE_DMG_RADIUS then
set b=true
exitwhen true
endif
set j=j+1
endloop
if b then
call UnitDamageTarget(Data.tmps.c, u, Fire_Dmg(Data.tmps.level)*FIRE_DMG_TICK, false, false, FIRE_DMG_ATTACKTYPE, FIRE_DMG_DAMAGETYPE, WEAPON_TYPE_WHOKNOWS)
set i=GetUnitIndex(u)
if Data.ImmoFX[i]==null then
set Data.ImmoFX[i]=AddSpecialEffectTarget(FIRE_DMG_FX, u, FIRE_DMG_FX_ATTPT)
set t=NewTimer2()
call SetTimerData(t, i)
call TimerStart(t, FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
set Data.ImmoT[i]=t
else
call TimerStart(Data.ImmoT[i], FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
endif
endif
endif
set u=null
return false
endmethod
method onDestroy takes nothing returns nothing
set .c=null
call ReleaseTimer2(.t)
set Data.Count=Data.Count-1
set Data.Structs[.i]=Data.Structs[Data.Count]
set Data.Structs[.i].i=.i
if Data.Count==0 then
call PauseTimer(Data.T)
endif
endmethod
static method EndingCB takes nothing returns nothing
local Data s=GetTimerData(GetExpiredTimer())
local integer i=0
loop
exitwhen i>=Spiral_Endings(s.level)
set s.fxcount=s.fxcount-1
call s.FX[s.fxcount].destroy()
set i=i+1
endloop
if s.fxcount<=0 then
call s.destroy()
endif
endmethod
static method Ending takes nothing returns nothing
call TimerStart(GetExpiredTimer(), FX_INTERVAL, true, function Data.EndingCB)
endmethod
static method SpawnCB takes nothing returns nothing
local Data s=GetTimerData(GetExpiredTimer())
local integer i=0
local real d=2*bj_PI/Spiral_Endings(s.level)
local real f=s.a+(bj_PI/2)
loop
exitwhen i>=Spiral_Endings(s.level)
debug if s.fxcount>=MAX_FIRE_FX_PER_INSTANCE then
debug call BJDebugMsg("FireSpiral: Array overflow! Try increasing MAX_FIRE_FX_PER_INSTANCE!")
debug exitwhen true
debug endif
set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
set s.FX[s.fxcount].fxpath=FIRE_FX
set s.FX[s.fxcount].scale=FIRE_FX_SCALE
set s.fxcount=s.fxcount+1
set i=i+1
endloop
set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
set s.d=s.b*s.a
if s.d>Spiral_End_Radius(s.level) then
call TimerStart(s.t, Duration(s.level), false, function Data.Ending)
endif
endmethod
static method Callback takes nothing returns nothing
local integer i=Data.Count-1
loop
exitwhen i<0
set Data.tmps=Data.Structs[i]
call GroupEnumUnitsInRange(ENUM_GROUP, Data.tmps.x, Data.tmps.y, Spiral_End_Radius(Data.tmps.level)+FIRE_DMG_RADIUS, Data.FireDmg)
call GroupClear(ENUM_GROUP)
set i=i-1
endloop
endmethod
static method Cond takes nothing returns boolean
return GetSpellAbilityId()==AID
endmethod
static method Create takes nothing returns nothing
local Data s=Data.allocate()
local real d
local integer i=0
local real f
set s.c=GetTriggerUnit()
set s.level=GetUnitAbilityLevel(s.c, AID)
set s.t=NewTimer2()
set s.f=GetUnitFacing(s.c)*bj_DEGTORAD
set s.x=GetUnitX(s.c)
set s.y=GetUnitY(s.c)
set s.b=(Spiral_End_Radius(s.level)-Spiral_Initial_Radius(s.level))/(2*bj_PI*Spiral_Circles(s.level))
set s.d=Spiral_Initial_Radius(s.level)
set s.a=s.d/s.b
set d=2*bj_PI/Spiral_Endings(s.level)
set f=s.a+(bj_PI/2)
loop
exitwhen i>=Spiral_Endings(s.level)
set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
set s.FX[s.fxcount].fxpath=FIRE_FX
set s.FX[s.fxcount].scale=FIRE_FX_SCALE
set s.fxcount=s.fxcount+1
set i=i+1
endloop
if s.d==0 then
set s.a=2*FIRE_FX_RADIUS/s.b
else
set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
endif
set s.d=s.b*s.a
call SetTimerData(s.t, s)
call TimerStart(s.t, FX_INTERVAL, true, function Data.SpawnCB)
set Data.Structs[Data.Count]=s
set s.i=Data.Count
if Data.Count==0 then
call TimerStart(Data.T, FIRE_DMG_TICK, true, function Data.Callback)
endif
set Data.Count=Data.Count+1
endmethod
static method onInit takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, function Data.Create)
call TriggerAddCondition(t, Condition(function Data.Cond))
set Data.FireDmg=Condition(function Data.FireDmgFunc)
call SetUpFIRE_DMG()
call SetUpSPIRAL_INITIAL_RADIUS()
call SetUpSPIRAL_END_RADIUS()
call SetUpSPIRAL_CIRCLES()
call SetUpSPIRAL_ENDINGS()
call SetUpDURATION()
endmethod
endstruct
endlibrary
//TESH.scrollpos=70
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Charge **
// ** ————————————— **
// ** **
// ** A simple Charge Spell **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library ChargeConfig
globals
//CHECK THE CHARGEEXEC TRIGGER FOR MORE OPTIONS
//ID CONFIGURATIONS FOR SPELLS AND DUMMY UNITS
//ID of the Charge spell
constant integer SPELLID = 'A042'
//ID of the dummy unit used for the attack at the end of the charge. Set this to 0 for no unit
constant integer DUMMYID = 'e004'
//ID of the spell to be casted by the dummy unit once the charge is complete (Has to be a spell with
//a Target). Set this to 0 for no spell. The Spell effect depends on the level of the Charge Spell
//So it's advisable to set the number of levels of this spell at the same value of the level of the
//Charge Spell
constant integer DUMMYSPELLID = 'A040'
//Order String for the spell to be casted by the dummy unit
constant string SPELLORDERID = "thunderbolt"
//SPECIAL EFFECTS CONFIGURATION
//You can set this to a non existand model (or change the code of the spell) if you don't want that
//effect
//Special Effect attached on the unit (in this example it will look like a red trail)
constant string ATTACHEDEFFECT = "war3mapImported\\Valiant Charge Holy.mdx"
//Special Effect created by the unit while walking
constant string WALKEFFECT = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
//Special Effect used at the end of the Charge
constant string ENDINGEFFECT = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
//NUMERICAL SETTINGS
//Charge Starting Speed
constant real STARTSPEED = 20.00
//Max Speed that can be reached by the Caster unit while charging
constant real MAXSPEED = 100.00
//Damage Dealt at the end of the Charge (0 for no damage). DEPENDS ON LEVEL
constant real CHARGEDAMAGE = 60.00
//Minimum Distance at where a unit can Charge (0 for no min distance)
//Make sure the dummy spell has a longer distance than this
constant real MINDISTANCE = 300.00
//Maximum Distance at where a unit can Charge (0 for no max distance)
//This is mainly used to interrupt the charge if the target unit gets teleported somewhere else
//Make sure the dummy spell has a distance equal or less than this number
constant real MAXDISTANCE = 800.00
//KNOCKBACK SETTINGS
//Theese settings refer to the Knock trigger which is not made by me but by Silvenon. If you want
//to know more about this script, got to
//http://www.hiveworkshop.com/forums/jass-functions-413/knockback-unit-35545/
//Special Effect created by the knockback
constant string KNOCKEFFECT = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
//The Distance of the Knockback effect. DEPENDS ON LEVEL
constant real KNOCKDISTANCE = 10.00
//The Duration of the Knockback effect
constant real KNOCKDURATION = 0.5
//Tree Destroying effect
//If you want trees destroyed behind your target while he's knocked back, then set this to true
//Otherwise set this to false. See the Knock Trigger for more configuration options
constant boolean KNOCKTREECHECK = true
//Knockback Effect
//This is the effect played on the Knocked Back Unit. If you set this to 0 then no effect will be played
//If you set this to 1 then the effect set on the KnockEffect() function is played as a periodic effect
//If you set this to 2 then the effect will be attached on the unit and destroyed once the knocback ends
constant integer KNOCKPLAYEFFECT = 1
//Attachement point of the effect played during the knockback. Default is "chest"
constant string KNOCKATTACH = "foot"
//You may want to check the ChargeExec trigger for more Configuration Options
//PATCCHECKER SETTINGS
//ID of the dummy unit used for the path checker function (has to be an invulnerable locusted unit with No model)
constant integer PATHCHECKERID = 'e005'
//ID of the permanent windwalk spell used for the path checker function
constant integer SPELLPATHID = 'A041'
endglobals
function KnockTree takes nothing returns real
if (KNOCKTREECHECK==true) then
return 150.00
endif
return 0.00
endfunction
endlibrary
//TESH.scrollpos=248
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Charge **
// ** ————————————— **
// ** **
// ** A simple Charge Spell **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library ChargeExec requires Knockback
struct ChargeLoop
private real ChargeTargetx
private real ChargeTargety
private real ChargeEndx
private real ChargeEndy
private real ChargeLocx
private real ChargeLocy
private real ChargeNextx
private real ChargeNexty
private unit ChargeTarget
private unit ChargeCaster
private real ChargeAngle
private real ChargeDistance
private effect ChargeEffect
private timer ChargeTimer
private boolean ChargeCond = false
private integer SpellLvl
//START OF CONFIGURATION METHODS
//With this method you can set the "acceleration rate" (Physicists Forgive me) of the charge.
//You can use any kind of numeric function (for example this.ChargeDistance * 2.00 will double
//The speed at every loop)
private method ChangeDistance takes nothing returns real
return this.ChargeDistance + 1.00
endmethod
//END OF CONFIGURATION METHODS
//START OF CUSTOMIZABLE METHODS
//This method sets the conditions when to activate the AlmostCharge method. In particular
//You may be interested in changing the distance at where the condition is true.
//In this Example it will be activated when the Caster is 16x times the Charge Speed Far away
//From the target
private method AlmostChargeCond takes nothing returns boolean
return ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) < ( this.ChargeDistance * 16.00 )) and this.ChargeCond == false)
endmethod
//Actions to take when the Charge is almost completed. In this example the caster will play
//The slam animation (Being a Blademaster, it will jump in the air while attacking)
private method AlmostCharge takes nothing returns nothing
set this.ChargeCond = true
call SetUnitTimeScale( this.ChargeCaster, 2.00 )
call SetUnitAnimation( this.ChargeCaster, "slam" )
call QueueUnitAnimation( this.ChargeCaster, "stand")
endmethod
//Actions to take when the Caster reaches its target and the charge is completed.
//In this example the target unit will be stunned and you will see a Thunderclap effect on the ground
private method CompleteCharge takes nothing returns nothing
local effect tempEffect
local unit dummy
local real angle=GetAngle(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy)
set this.ChargeLocx = this.ChargeNextx
set this.ChargeLocy = this.ChargeNexty
set this.ChargeNextx = PolarProjectionx(this.ChargeLocx, this.ChargeDistance, this.ChargeAngle)
set this.ChargeNexty = PolarProjectiony(this.ChargeLocy, this.ChargeDistance, this.ChargeAngle)
call DestroyEffect(AddSpecialEffect( WALKEFFECT, this.ChargeLocx, this.ChargeLocy ))
call SetUnitX( this.ChargeCaster, this.ChargeEndx )
call SetUnitY( this.ChargeCaster, this.ChargeEndy )
set dummy = CreateUnit( GetOwningPlayer(this.ChargeCaster), DUMMYID, this.ChargeLocx, this.ChargeLocy, 0 )
call UnitAddAbility( dummy, DUMMYSPELLID )
call SetUnitAbilityLevel(dummy, DUMMYSPELLID, this.SpellLvl)
call IssueTargetOrder( dummy, SPELLORDERID, this.ChargeTarget )
call UnitApplyTimedLife( dummy, 'BTLF', 1.00)
call DestroyEffect(AddSpecialEffect( ENDINGEFFECT, this.ChargeLocx, this.ChargeLocy ))
call UnitDamageTarget( this.ChargeCaster, this.ChargeTarget, CHARGEDAMAGE*this.SpellLvl, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS )
call PauseUnit( this.ChargeCaster, false )
//This is the Knockback effect, see the Knock Trigger for more customization options
call KnockbackEx(this.ChargeTarget, KNOCKDISTANCE*this.SpellLvl, angle, KNOCKDURATION, KnockTree(), KNOCKPLAYEFFECT, KNOCKEFFECT, KNOCKATTACH)
call IssueTargetOrder( this.ChargeCaster, "attack", this.ChargeTarget )
set dummy = null
endmethod
//What to do during the charge, the unit is moved, an effect is placed on the ground and
//the charging speed is increased
private method ContinueCharge takes nothing returns nothing
call DestroyEffect(AddSpecialEffect( WALKEFFECT, this.ChargeLocx, this.ChargeLocy ))
call SetUnitX(this.ChargeCaster, this.ChargeNextx)
call SetUnitY(this.ChargeCaster, this.ChargeNexty)
call SetUnitFacing(this.ChargeCaster, bj_RADTODEG * GetAngle(this.ChargeNextx, this.ChargeNexty, this.ChargeTargetx, this.ChargeTargety))
set this.ChargeLocx = this.ChargeNextx
set this.ChargeLocy = this.ChargeNexty
set this.ChargeNextx = PolarProjectionx(this.ChargeLocx, this.ChargeDistance, this.ChargeAngle)
set this.ChargeNexty = PolarProjectiony(this.ChargeLocy, this.ChargeDistance, this.ChargeAngle)
if (this.ChargeDistance <= MAXSPEED) then
set this.ChargeDistance = this.ChangeDistance()
endif
endmethod
//END OF CUSTOMIZABLE METHODS
//START OF OTHER METHODS
//This is the main method executed during the charge
public static method ChargeActions takes nothing returns nothing
local ChargeLoop l=GetTimerInt(GetExpiredTimer())
set l.ChargeTargetx = GetUnitX(l.ChargeTarget)
set l.ChargeTargety = GetUnitY(l.ChargeTarget)
set l.ChargeEndx = PolarProjectionx(l.ChargeTargetx, 100.00, GetAngle(l.ChargeTargetx, l.ChargeTargety, l.ChargeLocx, l.ChargeLocy))
set l.ChargeEndy = PolarProjectiony(l.ChargeTargety, 100.00, GetAngle(l.ChargeTargetx, l.ChargeTargety, l.ChargeLocx, l.ChargeLocy))
set l.ChargeAngle = GetAngle(l.ChargeLocx, l.ChargeLocy, l.ChargeEndx, l.ChargeEndy)
if ( l.AlmostChargeCond() ) then
//What to do when the caster is about to reach the target
call l.AlmostCharge()
endif
//If the Target gets too far away (by teleportation, for example) then stops the Charge
if ( GetDistance(l.ChargeLocx, l.ChargeLocy, l.ChargeEndx, l.ChargeEndy) >= MAXDISTANCE and (MAXDISTANCE != 0.00) ) then
call l.StopCharge()
endif
if ( l.ChargeConditions() ) then
//If the unit hasn't reached the target yet, then execute this
call l.ContinueCharge()
call TimerAttach(l.ChargeTimer,0.03,l,function ChargeLoop.ChargeActions)
else
if ( l.ChargeCompleted() ) then
//What to do if the charge is succesfully completed
call l.CompleteCharge()
endif
call l.StopCharge()
endif
endmethod
//Actions to take once the Charge is being stopped (either because it wasn't possible to complete
//the charge or because the caster reached its target)
private method StopCharge takes nothing returns nothing
set this.ChargeCond = false
call SetUnitPathing(this.ChargeCaster, true)
call PauseUnit(this.ChargeCaster, false)
call SetUnitAnimation(this.ChargeCaster, "stand")
call SetUnitTimeScale(this.ChargeCaster, 1.00)
call DestroyEffect(this.ChargeEffect)
call this.destroy()
endmethod
private method ChargeCompleted takes nothing returns boolean
if ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) <= this.ChargeDistance*1.10) and IsPointWalkable(this.ChargeNextx, this.ChargeNexty)) then
if ((IsTerrainPathable(this.ChargeNextx, this.ChargeNexty, PATHING_TYPE_WALKABILITY) == false ) and ( (GetUnitState(this.ChargeTarget, UNIT_STATE_LIFE)<=0) == false )) then
if(((GetUnitState(this.ChargeCaster, UNIT_STATE_LIFE) <= 0) == false)) then
return true
endif
endif
endif
return false
endmethod
private method ChargeConditions takes nothing returns boolean
if ((GetDistance(this.ChargeLocx, this.ChargeLocy, this.ChargeEndx, this.ChargeEndy) > this.ChargeDistance*1.10) and IsPointWalkable(this.ChargeNextx, this.ChargeNexty)) then
if ((IsTerrainPathable(this.ChargeNextx, this.ChargeNexty, PATHING_TYPE_WALKABILITY) == false ) and ( (GetUnitState(this.ChargeTarget, UNIT_STATE_LIFE)<=0) == false )) then
if(((GetUnitState(this.ChargeCaster, UNIT_STATE_LIFE) <= 0) == false)) then
return true
endif
endif
endif
return false
endmethod
private method onDestroy takes nothing returns nothing
call ReleaseTimer(this.ChargeTimer)
set this.ChargeTarget = null
set this.ChargeCaster = null
set this.ChargeEffect = null
endmethod
static method create takes real pChargeTargetx, real pChargeTargety, real pChargeEndx, real pChargeEndy, real pChargeLocx, real pChargeLocy, real pChargeNextx, real pChargeNexty, unit pChargeTarget, unit pChargeCaster, real pChargeAngle, real pChargeDistance, effect pChargeEffect, timer pChargeTimer returns ChargeLoop
local ChargeLoop l = ChargeLoop.allocate()
set l.ChargeTargetx = pChargeTargetx
set l.ChargeTargety = pChargeTargety
set l.ChargeEndx = pChargeEndx
set l.ChargeEndy = pChargeEndy
set l.ChargeLocx = pChargeLocx
set l.ChargeLocy = pChargeLocy
set l.ChargeNextx = pChargeNextx
set l.ChargeNexty = pChargeNexty
set l.ChargeTarget = pChargeTarget
set l.ChargeCaster = pChargeCaster
set l.ChargeAngle = pChargeAngle
set l.ChargeDistance = pChargeDistance
set l.ChargeEffect = pChargeEffect
set l.ChargeTimer = pChargeTimer
set l.SpellLvl = GetUnitAbilityLevel(l.ChargeCaster, SPELLID)
return l
endmethod
//END OF OTHER METHODS
endstruct
endlibrary
//TRIGGER OF THE CHARGE SPELL
scope Charge initializer InitTrig
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == SPELLID
endfunction
private function CheckActions takes nothing returns nothing
local real ChargeLocx = GetUnitX(GetTriggerUnit())
local real ChargeLocy = GetUnitY(GetTriggerUnit())
local real ChargeEndx = GetUnitX(GetSpellTargetUnit())
local real ChargeEndy = GetUnitY(GetSpellTargetUnit())
local sound s
if ( GetDistance(ChargeLocx, ChargeLocy, ChargeEndx, ChargeEndy) <= (MINDISTANCE) ) then
call DisplayTextToPlayer( GetOwningPlayer(GetTriggerUnit()), 0, 0, "|cffFFCC00El objetivo está demasiado cerca!|r" )
set s = CreateSound("Sound\\Interface\\Error.wav", false, false, true, 12700, 12700, "")
call StartSound(s)
call KillSoundWhenDone(s)
set s = null
call IssueImmediateOrder( GetTriggerUnit(), "stop" )
endif
endfunction
private function InitActions takes nothing returns nothing
local timer ChargeTimer = NewTimer()
local effect ChargeEffect
local unit ChargeCaster = GetTriggerUnit()
local unit ChargeTarget = GetSpellTargetUnit()
local real ChargeDistance = STARTSPEED
local real ChargeLocx = GetUnitX(ChargeCaster)
local real ChargeLocy = GetUnitY(ChargeCaster)
local real ChargeTargetx = GetUnitX(ChargeTarget)
local real ChargeTargety = GetUnitY(ChargeTarget)
local real ChargeEndx = PolarProjectionx(ChargeTargetx, 100.00, GetAngle(ChargeTargetx, ChargeTargety, ChargeLocx, ChargeLocy))
local real ChargeEndy = PolarProjectiony(ChargeTargety, 100.00, GetAngle(ChargeTargetx, ChargeTargety, ChargeLocx, ChargeLocy))
local real ChargeAngle = GetAngle(ChargeLocx, ChargeLocy, ChargeEndx, ChargeEndy)
local real ChargeNextx = PolarProjectionx(ChargeLocx, ChargeDistance, ChargeAngle)
local real ChargeNexty = PolarProjectiony(ChargeLocy, ChargeDistance, ChargeAngle)
local ChargeLoop stru
set ChargeEffect = AddSpecialEffectTarget(ATTACHEDEFFECT, ChargeCaster, "origin" )
set stru = ChargeLoop.create(ChargeTargetx, ChargeTargety, ChargeEndx, ChargeEndy, ChargeLocx, ChargeLocy, ChargeNextx, ChargeNexty, ChargeTarget, ChargeCaster, ChargeAngle, ChargeDistance, ChargeEffect, ChargeTimer)
call SetUnitPathing(ChargeCaster, false)
call SetUnitTimeScale(ChargeCaster, 3)
call IssueImmediateOrder(ChargeCaster, "stop" )
call PauseUnit(ChargeCaster, true)
call SetUnitAnimationByIndex(ChargeCaster,6)
call TimerAttach(ChargeTimer,0,stru,function ChargeLoop.ChargeActions)
set ChargeTimer = null
set ChargeEffect = null
set ChargeCaster = null
set ChargeTarget = null
endfunction
private function InitTrig takes nothing returns nothing
local trigger ChargeCheck = CreateTrigger()
local trigger ChargeInit = CreateTrigger()
local filterfunc f = Filter(function AntiLeak)
local integer i = 0
loop
exitwhen i == 16
call TriggerRegisterPlayerUnitEvent(ChargeCheck,Player(i),EVENT_PLAYER_UNIT_SPELL_CAST,truefilter)
call TriggerRegisterPlayerUnitEvent(ChargeInit,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,truefilter)
set i = i + 1
endloop
call TriggerAddCondition(ChargeCheck, Condition(function Conditions))
call TriggerAddAction(ChargeCheck, function CheckActions)
call TriggerAddCondition(ChargeInit, Condition(function Conditions))
call TriggerAddAction(ChargeInit, function InitActions)
set ChargeCheck = null
set ChargeInit = null
set f = null
endfunction
endscope
/*
vJass Damage Engine 5.A.0.0
This update enables compatibility with AttackIndexer.
*/
/*
JASS API:
struct Damage extends array
readonly static unit source // udg_DamageEventSource in real-time
readonly static unit target // udg_DamageEventTarget in real-time
static real amount // udg_DamageEventAmount in real-time
readonly unit sourceUnit // udg_DamageEventSource by index
readonly unit targetUnit // udg_DamageEventTarget by index
real damage // udg_DamageEventAmount by index
readonly real prevAmt // udg_DamageEventPrevAmt by index
attacktype attackType // udg_DamageEventAttackT by index
damagetype damageType // udg_DamageEventDamageT by index
weapontype weaponType // udg_DamageEventWeaponT by index
integer userType // udg_DamageEventType by index
readonly boolean isAttack // udg_IsDamageAttack by index
readonly boolean isCode // udg_IsDamageCode by index
readonly boolean isMelee // udg_IsDamageMelee by index
readonly boolean isRanged // udg_IsDamageRanged by index
readonly boolean isSpell // udg_IsDamageSpell by index
real armorPierced // udg_DamageEventArmorPierced by index
integer armorType // udg_DamageEventArmorT by index
integer defenseType // udg_DamageEventDefenseT by index
readonly integer eFilter
Set to false to disable the damage event triggers or to true to reverse that:
static boolean operator enabled
Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
Will automatically cause the damage to be registered as Code damage.
static method apply takes
unit source,
unit target,
real amount,
boolean isAttack,
boolean isRanged,
attacktype at,
damagetype dt,
weapontype wt
returns Damage
A simplified version of the above function that autofills each boolean, attacktype and weapontype.
static method applySpell takes
unit src,
unit tgt,
real amt,
damagetype dt
returns Damage
A different variation of the above which autofills the "isAttack" boolean
and populates damagetype as DAMAGE_TYPE_NORMAL.
static method applyAttack takes
unit src,
unit tgt,
real amt,
boolean ranged,
attacktype at,
weapontype wt
returns Damage
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- integer DamageEngine_FILTER_ATTACK
- integer DamageEngine_FILTER_MELEE
- integer DamageEngine_FILTER_OTHER
- integer DamageEngine_FILTER_RANGED
- integer DamageEngine_FILTER_SPELL
- integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
Alternatively, vJass users can set these instead. Just be mindful to set the variable
"configured" to true after settings these:
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
method configure takes nothing returns nothing
The string in the aruments below requires the following API:
"" for standard damage event
"Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method registerTrigger takes
trigger whichTrig,
string var,
real value
returns nothing
static method unregister takes
trigger whichTrig,
string eventName,
real value,
boolean reset
returns boolean
static method getIndex takes
trigger fromTrigger,
string eventName,
real value
returns integer
If you already have the index of the trigger you want to unregister:
method unregisterByIndex takes
boolean reset
returns boolean
Converts a code argument to a trigger, while checking if the same code had already been registered before.
Use it via DamageTrigger[function MyCallbackFunction]
static method operator [] takes
code callback
returns trigger
The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister:
function TriggerRegisterDamageEngineEx takes
trigger whichTrig,
string eventName,
real value,
integer opId
returns nothing
function TriggerRegisterDamageEngine takes
trigger whichTrig,
string eventName,
real value
returns nothing
function RegisterDamageEngineEx takes
code callback,
string eventName,
real value,
integer opId
returns nothing
function RegisterDamageEngine takes
code callback,
string eventName,
real value
returns nothing
*/
//===========================================================================
library DamageEngine requires optional AttackIndexer
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or SourceDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE = true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
/*
When manually-enabled recursion is enabled via DamageEngine_inception,
the engine will never go deeper than MAX_RECURSIVE_TOLERANCE:
*/
private constant integer MAX_RECURSIVE_TOLERANCE = 16
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case M$ ever changes this, it'll be a quick fix here.
private timer async = null
private boolean timerStarted = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean isNotNativeRecursiveDamage = true
private boolean waitingForDamageEventToRun = false
private boolean array attacksImmune
private boolean array damagesImmune
//Primary triggers used to handle all damage events.
private trigger damagingTrigger = null
private trigger damagedTrigger = null
private trigger recursiveTrigger = null //Catches, stores recursive events
/*
These variables coincide with Blizzard's "limitop" type definitions
so as to enable GUI users with some performance perks - however,
these optimizations need to be tested
*/
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
/*
When true, it allows your trigger to go recursively up to
MAX_RECURSIVE_TOLERANCE (if needed). It must be set before dealing damage.
*/
public boolean inception = false
private boolean callbacksInProgress = false
private integer recursiveCallbackDepth = 0
private group recursionSources = null
private group recursionTargets = null
private boolean recursiveCallbaksInProgress = false
private boolean nativeEventsCompleted = false
private boolean atLeastOneLethalDamageEventRegistered = false
// Struct members made private to this library.
private keyword run
private keyword trigFrozen
private keyword ownRecursiveDepth
private keyword manualRecursionRequested
endglobals
native UnitAlive takes unit u returns boolean
//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
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfig" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
//Added in 5.8:
boolean udg_RemoveDamageEvent //Allow GUI users to more fully unregister a damage event trigger. Can only be used from within a damage event (of any kind).
integer udg_DamageFilterSourceA
integer udg_DamageFilterTargetA //Check if a source or target have a specific ability (will overwrite any source or target buff check, I need to use this because GUI differentiates ability ID and buff ID)
integer udg_DamageFilterSourceI
integer udg_DamageFilterTargetI //Check if a source or target have a specific type of item
integer udg_DamageFilterSourceC
integer udg_DamageFilterTargetC //Classification of source/target (e.g. hero, treant, ward)
//Added in 5.9
real udg_SourceDamageEvent //Like AOEDamageEvent, fires each time the source unit has finished dealing damage, but doesn't care if the damage hit multiple units.
real udg_PreDamageEvent //Like DamageModifierEvent 3.99 or less, except can be any real value.
real udg_ArmorDamageEvent //Like DamageModifierEvent 4.00 or more, except can be any real value.
real udg_OnDamageEvent //Like DamageEvent equal to 1.00 or some non-zero/non-2 value, except can be any real value.
real udg_ZeroDamageEvent //Like DamageEvent equal to 0.00 or 2.00, except can be any real value.
*/
struct DamageTrigger extends array
static method checkItem takes unit u, integer id returns boolean
local integer i
if IsUnitType(u, UNIT_TYPE_HERO) then
set i = UnitInventorySize(u)
loop
exitwhen i <= 0
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == id then
return true
endif
endloop
endif
return false
endmethod
/*
Map makers should probably not use these filters,
unless someone tests performance to see
if such an ugly hack is even worth it.
*/
method checkConfig takes nothing returns boolean
//call BJDebugMsg("Checking configuration")
if this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif this.failChance > 0.00 and GetRandomReal(0.00, 1.00) <= this.failChance then
elseif this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceItem != 0 and not .checkItem(udg_DamageEventSource, this.sourceItem) then
elseif this.targetItem != 0 and not .checkItem(udg_DamageEventTarget, this.targetItem) then
elseif this.sourceClass >= 0 and not IsUnitType(udg_DamageEventSource, ConvertUnitType(this.sourceClass)) then
elseif this.targetClass >= 0 and not IsUnitType(udg_DamageEventTarget, ConvertUnitType(this.targetClass)) then
elseif udg_DamageEventAmount >= this.damageMin then
//call BJDebugMsg("Configuration passed")
return true
endif
//call BJDebugMsg("Checking failed")
return false
endmethod
//The below variables are to be treated as constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean usingGUI
private thistype next
private trigger rootTrig
//The below variables are to be treated as private
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer ownRecursiveDepth //How deep the user recursion currently is.
boolean manualRecursionRequested //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent triggers.
//configuration variables:
boolean configured
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
integer sourceItem
integer targetItem
integer sourceClass
integer targetClass
real damageMin
real failChance
integer attackType
integer damageType
integer userType
// getter:
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
// setter:
method operator runChance= takes real chance returns nothing
set this.failChance = 1.00 - chance
endmethod
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceItem = udg_DamageFilterSourceI
set this.targetItem = udg_DamageFilterTargetI
set this.sourceClass = udg_DamageFilterSourceC
set this.targetClass = udg_DamageFilterTargetC
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set this.failChance = 1.00 - (udg_DamageFilterRunChance - udg_DamageFilterFailChance)
if udg_DamageFilterSourceA > 0 then
set this.sourceBuff = udg_DamageFilterSourceA
set udg_DamageFilterSourceA = 0
else
set this.sourceBuff = udg_DamageFilterSourceB
endif
if udg_DamageFilterTargetA > 0 then
set this.targetBuff = udg_DamageFilterTargetA
set udg_DamageFilterTargetA = 0
else
set this.targetBuff = udg_DamageFilterTargetB
endif
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
//These handles can have a valid value of 0, so we need to distinguish them.
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterSourceI = 0
set udg_DamageFilterTargetI = 0
set udg_DamageFilterMinAmount = 0.00
set udg_DamageFilterFailChance = 0.00
set udg_DamageFilterRunChance = 1.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
//! runtextmacro optional ATTACK_INDEXER_GUI_VARS()
static if USE_MELEE_RANGE then
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if (var == "udg_DamageModifierEvent" and root < 4) or var == "udg_PreDamageEvent" then
set root = MOD
elseif var == "udg_DamageModifierEvent" or var == "udg_ArmorDamageEvent" then
set root = SHIELD
elseif (var == "udg_DamageEvent" and root == 2 or root == 0) or var == "udg_ZeroDamageEvent" then
set root = ZERO
elseif var == "udg_DamageEvent" or var == "udg_OnDamageEvent" then
set root = DAMAGE
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" or var == "udg_SourceDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer opId returns nothing
set this = this * FILTER_MAX
if opId == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if opId == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + opId] = true
endif
endif
endmethod
static method registerVerbose takes /*
*/ trigger whichTrig, /*
*/ string var, /*
*/ real lbs, /*
*/ boolean GUI, /*
*/ integer filt /*
*/ returns thistype
local thistype index = getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
//allows GUI to register multiple different types of Damage filters to the same trigger
set filters[lastRegistered*FILTER_MAX + filt] = true
return 0
endif
set atLeastOneLethalDamageEventRegistered = /*
*/ atLeastOneLethalDamageEventRegistered or index == LETHAL
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
//they will probably bug out with class types as well, so I should add them, just in case:
set id.sourceClass = -1
set id.targetClass = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes /*
*/ trigger t, /*
*/ string eventName, /*
*/ real lbs /*
*/ returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
method unregisterByIndex takes boolean reset returns boolean
if this == 0 then
return false
endif
set prev.next = this.next
set trigIndexStack[this] = trigIndexStack[0]
set trigIndexStack[0] = this
if reset then
call this.configure()
set this.configured = false
call thistype(this*FILTER_MAX).toggleAllFilters(false)
endif
return true
endmethod
static method unregister takes /*
*/ trigger t, /*
*/ string eventName, /*
*/ real lbs, /*
*/ boolean reset /*
*/ returns boolean
return getIndex(t, eventName, lbs).unregisterByIndex(reset)
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif
if callbacksInProgress then
return
endif
set callbacksInProgress = true
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
call EnableTrigger(recursiveTrigger)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif
set eventIndex = this
if (not this.trigFrozen) and /*
*/ filters[this*FILTER_MAX + d.eFilter] and /*
*/ IsTriggerEnabled(this.rootTrig) and /*
*/ ((not this.configured) or (this.checkConfig())) and /*
*/ (cat != AOE or udg_DamageEventAOE > 1 or this.eventStr == "udg_SourceDamageEvent") /*
*/ then
static if USE_GUI then
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
if udg_RemoveDamageEvent then
set udg_RemoveDamageEvent = false
call this.unregisterByIndex(true)
endif
endif
endif
endloop
static if USE_GUI then
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else
call setGUIFromStruct(false)
endif
//call BJDebugMsg("End of event running")
call DisableTrigger(recursiveTrigger)
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set callbacksInProgress = false
endmethod
/*
Used by RegisterDamageEngineEx to create triggers behind-the-scenes,
allowing the user to simply pass the function they want to execute.
*/
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code callback returns trigger
local integer i = 0
local boolexpr b = Filter(callback)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit
readonly unit targetUnit
real damage
readonly real prevAmt
attacktype attackType
damagetype damageType
weapontype weaponType
integer userType
readonly boolean isAttack
readonly boolean isCode
readonly boolean isSpell
static if USE_MELEE_RANGE then
readonly boolean isMelee //stores udg_IsDamageMelee
endif
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if not (pierce == 0.00) then //Changed from != to not == due to bug reported by BLOKKADE
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif
static if USE_EXTRA then
private static method onAOEEnd takes nothing returns nothing
call DamageTrigger.AOE.run()
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif
private static method afterDamage takes nothing returns nothing
if udg_DamageEventDamageT != 0 and not (udg_DamageEventPrevAmt == 0.00) then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method runDamagingEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(recursionSources, udg_DamageEventSource)
call GroupAddUnit(recursionTargets, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
// Using not == instead of !=; the idea is to eliminate floating point bugs when two numbers are very close to 0,
// because JASS uses a less-strict comparison for checking if a number is equal than when it is unequal.
if not (udg_DamageEventAmount == 0.00) then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then
call DamageTrigger.setGUIFromStruct(false)
endif
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then
call this.setArmor(false)
endif
return false
endif
return true //return value is based on whether the event is a 0 damage event (true) or not (false).
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.ownRecursiveDepth = 0
endloop
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set recursiveCallbaksInProgress = false
set damageStack = 0
set prepped = 0
set callbacksInProgress = false
set recursiveCallbackDepth = 0
call GroupClear(recursionSources)
call GroupClear(recursionTargets)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method runAfterDamageEvents takes nothing returns nothing
local Damage i = 0
local integer exit
if nativeEventsCompleted then
set nativeEventsCompleted = false
call afterDamage()
endif
if isNotNativeRecursiveDamage and not recursiveCallbaksInProgress then
if damageStack != 0 then
set recursiveCallbaksInProgress = true
loop
/*
Use two loops. The outer loop handles all normal event
execution, while the inner loop intelligently handles
recursive execution (when it's used).
*/
set recursiveCallbackDepth = recursiveCallbackDepth + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then
// We don't need to trigger `damagingTrigger` itself, so just call its handler directly.
call prepped.runDamagingEvents(false)
if prepped.damage > 0.00 then
call DisableTrigger(damagingTrigger) // Disallow `damagingTrigger` because we only want `damageTrigger` to run.
call EnableTrigger(damagedTrigger) // Re-enable `damagedTrigger` in case the user forgot to do so.
set waitingForDamageEventToRun = true
call UnitDamageTarget( /*
*/ prepped.sourceUnit, /*
*/ prepped.targetUnit, /*
*/ prepped.damage, /*
*/ prepped.isAttack, /*
*/ prepped.isRanged, /*
*/ prepped.attackType, /*
*/ prepped.damageType, /*
*/ prepped.weaponType /*
*/ )
else
if udg_DamageEventDamageT != 0 then
//No native events run at all in this case
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
/*
No need for BlzSetEventDamage/UnitDamageTarget here,
because we can safely adjust the unit's life instead.
*/
call SetWidgetLife( /*
*/ prepped.targetUnit, /*
*/ GetWidgetLife(prepped.targetUnit) - prepped.damage /*
*/ )
endif
static if USE_ARMOR_MOD then
call prepped.setArmor(true)
endif
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then
call Damage.index.setArmor(true)
endif
set isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
set waitingForDamageEventToRun = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set nativeEventsCompleted = true
endif
call runAfterDamageEvents()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if callbacksInProgress then
call EnableTrigger(recursiveTrigger)
else
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
endif
else
if callbacksInProgress then
call DisableTrigger(recursiveTrigger)
else
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(damagingTrigger)
endmethod
private static boolean threadCompleted = false
private static method asyncCallbackSafeCallback takes nothing returns nothing
if waitingForDamageEventToRun then
/*
This means that WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
*/
call failsafeClear()
else
set isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
call runAfterDamageEvents()
endif
static if USE_EXTRA then
call onAOEEnd()
endif
set threadCompleted = true
endmethod
private static method asyncCallback takes nothing returns nothing
set callbacksInProgress = false
set Damage.enabled = true
/*
Open a new thread in case of a thread crash during callback.
*/
call ForForce(bj_FORCE_PLAYER[0], function thistype.asyncCallbackSafeCallback)
if not threadCompleted then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set threadCompleted = false
endif
set Damage.count = 0
set Damage.index = 0
set timerStarted = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
local DamageTrigger currentIndex
if not (this.damage == 0.00) then
set currentIndex = DamageTrigger.eventIndex
set this.recursiveTrig = currentIndex
if not this.isCode then
/*
If the recursive damage trigger is executed, this can only
mean that the user has manually dealt damage from a trigger.
Hence flag the damage as being 'code' if they didn't already
manually do this.
*/
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or /*
*/ currentIndex.manualRecursionRequested
if recursiveCallbaksInProgress and /*
*/ IsUnitInGroup(this.sourceUnit, recursionSources) and /*
*/ IsUnitInGroup(this.targetUnit, recursionTargets) /*
*/ then
if not inception then
set currentIndex.trigFrozen = true
elseif not currentIndex.trigFrozen then
set currentIndex.manualRecursionRequested = true
if currentIndex.ownRecursiveDepth < recursiveCallbackDepth then
set currentIndex.ownRecursiveDepth = /*
*/ currentIndex.ownRecursiveDepth + 1
if currentIndex.ownRecursiveDepth >= MAX_RECURSIVE_TOLERANCE then
set currentIndex.trigFrozen = true
endif
endif
endif
endif
// push the reference to the top of the damage stack.
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " ownRecursiveDepth: " + I2S(currentIndex.ownRecursiveDepth) + " recursiveCallbackDepth: " + I2S(recursiveCallbackDepth))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif
endmethod
static method create takes /*
*/ unit src, /*
*/ unit tgt, /*
*/ real amt, /*
*/ boolean isAttack, /*
*/ attacktype at, /*
*/ damagetype dt, /*
*/ weapontype wt /*
*/ returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.damageType = dt
set d.attackType = at
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or isAttack
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = thistype.create( /*
*/ GetEventDamageSource(), /*
*/ GetTriggerUnit(), /*
*/ GetEventDamage(), /*
*/ BlzGetEventIsAttack(), /*
*/ BlzGetEventAttackType(), /*
*/ BlzGetEventDamageType(), /*
*/ BlzGetEventWeaponType() /*
*/ )
set d.isCode = udg_NextDamageType != 0 or /*
*/ udg_NextDamageIsAttack or /*
*/ udg_NextDamageIsRanged or /*
*/ udg_NextDamageIsMelee or /*
*/ d.damageType == DAMAGE_TYPE_MIND or /*
*/ udg_NextDamageWeaponT != 0 or /*
*/ (d.damageType == DAMAGE_TYPE_UNKNOWN and not (d.damage == 0.00))
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
// Added in version 5.A in order to allow an optional external
// Attack Indexer system to reset the event weapon type to normal.
//! runtextmacro optional ATTACK_INDEXER_ADJUSTMENTS()
static if USE_MELEE_RANGE then
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
// Melee units always play a sound when damaging in WC3,
// so this is an easy check.
set d.isMelee = d.weaponType != null
// In the case where a unit is both ranged and melee,
// the ranged attack plays no sound.
set d.isRanged = not d.isMelee
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then
// Spells are neither melee nor ranged.
set d.isMelee = false
set d.isRanged = false
endif
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursiveDamageCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamagingCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if timerStarted then
if waitingForDamageEventToRun then
//WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or /*
*/ d.damageType == DAMAGE_TYPE_DEFENSIVE or /*
*/ d.damageType == DAMAGE_TYPE_PLANT /*
*/ then
set waitingForDamageEventToRun = false
set lastInstance = Damage.index
set isNotNativeRecursiveDamage = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call runAfterDamageEvents() //wrap up any previous damage index
endif
static if USE_EXTRA then
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget = d.targetUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif
else
call TimerStart(async, 0.00, false, function Damage.asyncCallback)
set timerStarted = true
static if USE_EXTRA then
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif
endif
static if USE_EXTRA then
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif
if d.runDamagingEvents(true) then
call DamageTrigger.ZERO.run()
set isNotNativeRecursiveDamage = true
call runAfterDamageEvents()
endif
set waitingForDamageEventToRun = lastInstance == 0 or /*
*/ attacksImmune[udg_DamageEventAttackT] or /*
*/ damagesImmune[udg_DamageEventDamageT] or /*
*/ not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamagedCallback takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif callbacksInProgress or d.prevAmt == 0.00 then
return false
elseif waitingForDamageEventToRun then
set waitingForDamageEventToRun = false
else
/*
This should only happen for native recursive WarCraft 3 damage
such as Spirit Link, Thorns Aura, or Spiked Carapace / Barricades.
*/
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
/*
Since the native recursive damage has now wrapped up, we can resume
handling events as normal at this point. This means that the original
target that the DAMAGING event was triggered for is now finally getting
its DAMAGED event.
*/
set isNotNativeRecursiveDamage = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then
call d.setArmor(true)
endif
static if USE_SCALING then
if not (udg_DamageEventAmount == 0.00) and not (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
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = /*
*/ udg_DamageEventAmount / udg_DamageEventPrevAmt
endif
endif
endif
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then
set udg_DamageEventAmount = d.damage
endif
static if USE_LETHAL then
if atLeastOneLethalDamageEventRegistered or udg_DamageEventType < 0 then
set udg_LethalDamageHP = /*
*/ GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if atLeastOneLethalDamageEventRegistered then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = /*
*/ GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and /*
*/ udg_LethalDamageHP <= DEATH_VAL /*
*/ then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif
static if USE_SCALING then
if udg_DamageEventPrevAmt == 0.00 or /*
*/ udg_DamageScalingWC3 == 0.00 /*
*/ then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = /*
*/ udg_DamageEventAmount / udg_DamageEventPrevAmt / udg_DamageScalingWC3
endif
endif
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set nativeEventsCompleted = true
if udg_DamageEventAmount == 0.00 then
call runAfterDamageEvents()
endif
// This return statement was needed years ago to avoid potential crashes on Mac.
// I am not sure if that's still a thing.
return false
endmethod
static method apply takes /*
*/ unit src, /*
*/ unit tgt, /*
*/ real amt, /*
*/ boolean a, /*
*/ boolean r, /*
*/ attacktype at, /*
*/ damagetype dt, /*
*/ weapontype wt /*
*/ returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if callbacksInProgress then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call runAfterDamageEvents()
endif
call clearNexts()
return d
endmethod
static method applySpell takes /*
*/ unit src, /*
*/ unit tgt, /*
*/ real amt, /*
*/ damagetype dt /*
*/ returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes /*
*/ unit src, /*
*/ unit tgt, /*
*/ real amt, /*
*/ boolean ranged, /*
*/ attacktype at, /*
*/ weapontype wt /*
*/ returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
/*
This part is the most critical to get things kicked off. All the code we've seen up until now
is related to event handling, trigger assignment, edge cases, etc. But it's the following that
is really quite esesntial for any damage engine - not just this one.
*/
private static method onInit takes nothing returns nothing
set async = CreateTimer()
set recursionSources = CreateGroup()
set recursionTargets = CreateGroup()
set damagingTrigger = CreateTrigger()
set damagedTrigger = CreateTrigger()
set recursiveTrigger = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(damagingTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(damagingTrigger, Filter(function Damage.onDamagingCallback))
call TriggerRegisterAnyUnitEventBJ(damagedTrigger, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(damagedTrigger, Filter(function Damage.onDamagedCallback))
//For recursion
call TriggerRegisterAnyUnitEventBJ(recursiveTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(recursiveTrigger, Filter(function Damage.onRecursiveDamageCallback))
call DisableTrigger(recursiveTrigger) //starts disabled. Will be enabled during recursive event handling.
/*
For preventing Thorns/Defensive glitch.
Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
*/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
// Called from the GUI configuration trigger once the assignments are in place.
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"
// Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
/*
In-game World Editor doesn't allow Attack Type and Damage Type comparisons.
Therefore, I need to code them as integers into GUI
*/
set udg_ATTACK_TYPE_SPELLS = 0
set udg_ATTACK_TYPE_NORMAL = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
// -
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
/*
The below variables don't affect damage amount, but do affect the sound played
They also give important information about the type of attack used.
They can differentiate between ranged and melee for units who are both
*/
set udg_WEAPON_TYPE_NONE = 0
// Metal Light/Medium/Heavy
set udg_WEAPON_TYPE_ML_CHOP = 1
set udg_WEAPON_TYPE_MM_CHOP = 2
set udg_WEAPON_TYPE_MH_CHOP = 3
set udg_WEAPON_TYPE_ML_SLICE = 4
set udg_WEAPON_TYPE_MM_SLICE = 5
set udg_WEAPON_TYPE_MH_SLICE = 6
set udg_WEAPON_TYPE_MM_BASH = 7
set udg_WEAPON_TYPE_MH_BASH = 8
set udg_WEAPON_TYPE_MM_STAB = 9
set udg_WEAPON_TYPE_MH_STAB = 10
// Wood Light/Medium/Heavy
set udg_WEAPON_TYPE_WL_SLICE = 11
set udg_WEAPON_TYPE_WM_SLICE = 12
set udg_WEAPON_TYPE_WH_SLICE = 13
set udg_WEAPON_TYPE_WL_BASH = 14
set udg_WEAPON_TYPE_WM_BASH = 15
set udg_WEAPON_TYPE_WH_BASH = 16
set udg_WEAPON_TYPE_WL_STAB = 17
set udg_WEAPON_TYPE_WM_STAB = 18
// Claw Light/Medium/Heavy
set udg_WEAPON_TYPE_CL_SLICE = 19
set udg_WEAPON_TYPE_CM_SLICE = 20
set udg_WEAPON_TYPE_CH_SLICE = 21
// Axe Medium
set udg_WEAPON_TYPE_AM_CHOP = 22
// Rock Heavy
set udg_WEAPON_TYPE_RH_BASH = 23
/*
Since GUI still doesn't provide Defense Type and Armor Types,
I needed to include the below:
*/
set udg_ARMOR_TYPE_NONE = 0
set udg_ARMOR_TYPE_FLESH = 1
set udg_ARMOR_TYPE_METAL = 2
set udg_ARMOR_TYPE_WOOD = 3
set udg_ARMOR_TYPE_ETHEREAL = 4
set udg_ARMOR_TYPE_STONE = 5
set udg_DEFENSE_TYPE_LIGHT = 0
set udg_DEFENSE_TYPE_MEDIUM = 1
set udg_DEFENSE_TYPE_HEAVY = 2
set udg_DEFENSE_TYPE_FORTIFIED = 3
set udg_DEFENSE_TYPE_NORMAL = 4
set udg_DEFENSE_TYPE_HERO = 5
set udg_DEFENSE_TYPE_DIVINE = 6
set udg_DEFENSE_TYPE_UNARMORED = 7
/*
The remaining stuff is an ugly 'optimization' that I did a long
time ago, thinking that it would improve performance for GUI users
by not having so many different triggerconditions evaluating per
damage event. I am not sure if it even worked; in Lua it might
perform worse, but in vJass it remains to be tested.
*/
set udg_UNIT_CLASS_HERO = 0
set udg_UNIT_CLASS_DEAD = 1
set udg_UNIT_CLASS_STRUCTURE = 2
set udg_UNIT_CLASS_FLYING = 3
set udg_UNIT_CLASS_GROUND = 4
set udg_UNIT_CLASS_ATTACKS_FLYING = 5
set udg_UNIT_CLASS_ATTACKS_GROUND = 6
set udg_UNIT_CLASS_MELEE = 7
set udg_UNIT_CLASS_RANGED = 8
set udg_UNIT_CLASS_GIANT = 9
set udg_UNIT_CLASS_SUMMONED = 10
set udg_UNIT_CLASS_STUNNED = 11
set udg_UNIT_CLASS_PLAGUED = 12
set udg_UNIT_CLASS_SNARED = 13
set udg_UNIT_CLASS_UNDEAD = 14
set udg_UNIT_CLASS_MECHANICAL = 15
set udg_UNIT_CLASS_PEON = 16
set udg_UNIT_CLASS_SAPPER = 17
set udg_UNIT_CLASS_TOWNHALL = 18
set udg_UNIT_CLASS_ANCIENT = 19
set udg_UNIT_CLASS_TAUREN = 20
set udg_UNIT_CLASS_POISONED = 21
set udg_UNIT_CLASS_POLYMORPHED = 22
set udg_UNIT_CLASS_SLEEPING = 23
set udg_UNIT_CLASS_RESISTANT = 24
set udg_UNIT_CLASS_ETHEREAL = 25
set udg_UNIT_CLASS_MAGIC_IMMUNE = 26
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterRunChance = 1.00
endfunction
public function RegisterFromHook takes /*
*/ trigger whichTrig, /*
*/ string var, /*
*/ limitop op, /*
*/ real value /*
*/ returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes /*
*/ trigger whichTrig, /*
*/ string eventName, /*
*/ real value, /*
*/ integer opId /*
*/ returns DamageTrigger
return DamageTrigger.registerVerbose( /*
*/ whichTrig, /*
*/ DamageTrigger.getVerboseStr(eventName), /*
*/ value, /*
*/ false, /*
*/ opId /*
*/ )
endfunction
function TriggerRegisterDamageEngine takes /*
*/ trigger whichTrig, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value, /*
*/ integer opId /*
*/ returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[callback], eventName, value, opId)
endfunction
//Similar to TriggerRegisterDamageEvent, but takes code instead of trigger as the first argument.
function RegisterDamageEngine takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return RegisterDamageEngineEx(callback, eventName, value, FILTER_OTHER)
endfunction
/*
The below macros are for GUI to tap into more powerful vJass event filtering:
*/
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
endif
if not DamageTrigger.eventIndex.checkConfig() then
return
endif
//! endtextmacro
endlibrary
// Arcing Text Tag v1.0.2.0 by Maker with added API by Bribe and features proposed by Ugabunda and Kusanagi Kuro
//
// Added API in 1.0.1.0:
// public static ArcingTextTag lastCreated
// - Get the last created ArcingTextTag
// public real scaling
// - Set the size ratio of the texttag - 1.00 is the default
// public real timeScaling
// - Set the duration ratio of the texttag - 1.00 is the default
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 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 real scale
private real timeScale
public static thistype lastCreated = 0
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = Sin(bj_PI*(.t / timeScale))
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)*.scale)
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 createEx takes string s, unit u, real duration, real size, player p 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 .scale = size
set .timeScale = RMaxBJ(duration, 0.001)
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
if IsUnitVisible(u, p) then
set .tt = CreateTextTag()
call SetTextTagPermanent(.tt, false)
call SetTextTagLifespan(.tt, TIME_LIFE*duration)
call SetTextTagFadepoint(.tt, TIME_FADE*duration)
call SetTextTagText(.tt, s, SIZE_MIN*size)
call SetTextTagPos(.tt, .x, .y, Z_OFFSET)
else
set .tt = null
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
set .lastCreated = this
return this
endmethod
public static method create takes string s, unit u returns thistype
return thistype.createEx(s, u, TIME_LIFE, 1.00, GetLocalPlayer())
endmethod
endstruct
endlibrary
//////////////////////////////////////////////////////////////////////
// Frozen Blast by 1)ark_NiTe //
// Originally made for Against the Darkness //
// //
// r = angle that wave will be fired towards //
// //
// Notes: //
// //
// 1. Change the spells and dummy units rawcodes in the constants. //
// 2. Damage/duration data can be changed by accessing the spells //
// in the object editor //
// a.) Damage for each Frozen Blast Wave is modified in the //
// Frozen Blast (Actual Ability). //
// b.) Cooldown/spell description is modified in the Frozen //
// Blast (Dummy Ability). //
//////////////////////////////////////////////////////////////////////
//==================================================================================================================================
// Start of constants. These provide the user with easier implementing//changing of the spell's rawcodes. All of these can be changed.
//==================================================================================================================================
constant function Frozen_Blast_ID takes nothing returns integer
return 'A0CM' // Frozen Blast actual ability rawcode. This is the spell that will be cast by a dummy unit.
endfunction
constant function Frozen_Blast_Dummy_ID takes nothing returns integer
return 'A0CO' // Frozen Blast dummy ability rawcode. This is the spell that the Hero will use.
endfunction
constant function Slow_ID takes nothing returns integer
return 'A0CN' // Slow (Frozen Blast) rawcode.
endfunction
constant function Dummy_ID takes nothing returns integer
return 'h00R' // Dummy unit rawcode
endfunction
//==================================================================================================================================
//End of constants. Do not touch anything below this if you are unfamiliar with JASS.
//==================================================================================================================================
//==================================================================================================================================
//Spell conditions.
//==================================================================================================================================
function Trig_Blast_Conditions takes nothing returns boolean
return GetSpellAbilityId() == Frozen_Blast_Dummy_ID()
endfunction
//==================================================================================================================================
//Filter function grouping enemies to be slowed.
//==================================================================================================================================
function Slow_Filter takes nothing returns boolean
return IsPlayerEnemy(GetOwningPlayer(GetTriggerUnit()), GetOwningPlayer(GetFilterUnit())) == true
endfunction
//==================================================================================================================================
//Spell actions. Main block of coding
//==================================================================================================================================
function Trig_Blast_Actions takes nothing returns nothing
//Locals are declared
local unit t = GetTriggerUnit()
local real px = GetWidgetX(t)
local real py = GetWidgetY(t)
local real qx
local real qy
local unit array d
local unit array u
local unit e
local group g = CreateGroup()
local real r = 0.00
local integer i = 0
local integer z = 0
local integer l = GetUnitAbilityLevel(t, Frozen_Blast_Dummy_ID())
//Frozen Blasts are created. A blast occurs every 30 degrees out around the Hero 12 times (360 degrees).
loop
exitwhen i == 12
set i = i + 1
set r = r + .52359
set d[i] = CreateUnit(GetOwningPlayer(t), Dummy_ID(), px, py, 250.0)
call UnitAddAbility(d[i], Frozen_Blast_ID())
call SetUnitAbilityLevel(t, Frozen_Blast_ID(), l)
call UnitApplyTimedLife(d[i], 'BTLF', 1.00)
set qx = px + 300 * Cos(r)
set qy = py + 300 * Sin(r)
call IssuePointOrder (d[i], "carrionswarm", qx, qy)
set d[i] = null
endloop
call GroupEnumUnitsInRange(g, px, py, 900.00, Condition(function Slow_Filter))
set i = 0
set z = CountUnitsInGroup(g)
//Dummy units cast Slow (Frozen Blast) on the units in the area
loop
exitwhen i >= z
set i = i + 1
set u[i] = FirstOfGroup(g)
call GroupRemoveUnit( g, u[i] )
set e = CreateUnit(GetOwningPlayer(t), Dummy_ID(), px, py, 250.0)
call UnitApplyTimedLife(e, 'BTLF', 1.00)
call UnitAddAbility(e, Slow_ID())
call IssueTargetOrder(e, "slow", u[i])
set u[i] = null
endloop
set e = null
set t = null
endfunction
function AntiLeaker takes nothing returns boolean
return true
endfunction
//===========================================================================
function InitTrig_Explosion_artica takes nothing returns nothing
local trigger t = CreateTrigger( )
local filterfunc f = Filter(function AntiLeaker)
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, f)
set i = i + 1
exitwhen i == 16
endloop
call TriggerAddCondition(t, Condition( function Trig_Blast_Conditions ) )
call TriggerAddAction(t, function Trig_Blast_Actions )
call DestroyFilter(f)
set f = null
set t = null
endfunction