//TESH.scrollpos=0
//TESH.alwaysfold=0
function Revive_Hero takes unit REVIVEUNIT, integer TIMEREVIVE returns nothing
local unit x = REVIVEUNIT
local integer t = TIMEREVIVE
local real tt = 1.0
loop
exitwhen t <= 0
call DisplayTextToPlayer(GetOwningPlayer(x), 0, 0, "You will revive in " + I2S(t) + " seconds.")
set t = t - 1
call TriggerSleepAction(tt)
endloop
call ReviveHeroLoc( x, GetRectCenter(gg_rct_Region_056), true )
if GetPlayerController(GetOwningPlayer(x)) == MAP_CONTROL_COMPUTER then
call SetEngageUnit(x)
endif
set x = null
endfunction
function Texttag_Create takes string TEXTTAG_TEXT, real TEXTTAG_LOCATION_X, real TEXTTAG_LOCATION_Y, integer TEXTTAG_ALPHA_RED, integer TEXTTAG_ALPHA_GREEN, integer TEXTTAG_ALPHA_BLUE, integer TEXTTAG_ALPHA_ALPHA returns nothing
local texttag te = CreateTextTag()
local string text = TEXTTAG_TEXT
local real x = TEXTTAG_LOCATION_X
local real y = TEXTTAG_LOCATION_Y
local integer red = TEXTTAG_ALPHA_RED
local integer green = TEXTTAG_ALPHA_GREEN
local integer blue = TEXTTAG_ALPHA_BLUE
local integer alpha = TEXTTAG_ALPHA_ALPHA
call SetTextTagText(te, text, 0.024)
call SetTextTagPos(te, x, y, 0.00)
call SetTextTagColor(te, red, green, blue, alpha)
call SetTextTagVelocity(te, 0, 0.04)
call SetTextTagVisibility(te, true)
call SetTextTagFadepoint(te, 2)
call SetTextTagLifespan(te, 5)
call SetTextTagPermanent(te, false)
set te = null
endfunction
Name | Type | is_array | initial_value |
AbilityLevel | real | No | |
AIGamble | integer | No | |
AIHERO | integer | No | |
AIProcess | integer | Yes | |
AllPlayer | force | No | |
Ally_Status | integer | Yes | |
AM | unit | No | |
angle | real | Yes | |
AOEPPA | unit | No | |
AOEPPAdmg | unit | No | |
AOESM | location | No | |
AOESNS | location | No | |
AOESNSMU | unit | No | |
AOESSOD | location | No | |
AOESWW | location | No | |
ArchimondeGroup | group | No | |
ArrowCount | real | No | |
ArrowCountPerLevel | real | No | |
ArrowDamage | real | No | |
ArrowHashtable | hashtable | No | |
attacker_multi | unit | Yes | |
BF_Caster_Group | group | No | |
BF_Flame_Group | group | No | |
BF_Hash | hashtable | No | |
BF_Reals | real | Yes | |
BlastArrowAOE | real | No | |
BreakingGround | effect | No | |
BSLoc | location | Yes | |
BSP | location | No | |
Caster | unit | No | |
CasterOfAOESHS | unit | No | |
CasterP | unit | No | |
Casters | group | No | |
CenterCamp | group | No | |
ChargeCaster | unit | No | |
ChargeTarget | unit | No | |
CLCaster | unit | No | |
CLCount | integer | No | |
CLDummy | unit | No | |
CLEANGROUP | group | No | |
CLEANTEMP | unit | No | |
CLFacing | real | No | |
CLGroup | group | No | |
CLLevel | integer | No | |
CLMaxCount | integer | No | |
CLOwner | player | No | |
CLPosition | location | No | |
CLTable | hashtable | No | |
CLTempPoint | location | No | |
CLTempUnit | unit | No | |
Computer_Allies | integer | Yes | |
CSACP | location | No | |
CSUS | unit | No | |
CurrentFlyingHeight | real | No | |
DAC | unit | No | |
DamagePerArrow | real | No | |
DAT | unit | No | |
DEBUG | boolean | No | |
DEBUG_Gold | integer | No | |
DEBUG_GoldN | integer | No | |
DefeatStrings | string | Yes | |
DetonateAll | group | No | |
Drain_Caster | unit | Yes | |
Drain_Interval | integer | Yes | |
Drain_Life_Lightning | lightning | Yes | |
Drain_Life_Max | integer | No | |
Drain_Max | integer | No | |
Drain_Range | real | Yes | |
Drain_Targets | group | Yes | |
Drain_Value | real | Yes | |
dummyAOESSS | unit | No | |
Duration | integer | Yes | |
Duration2 | integer | Yes | |
Dust_int | integer | No | |
Earth_quakeeffect_multi | effect | Yes | |
effect_multi | effect | Yes | |
Enemies | group | No | |
ExtraStreak_Chcker | boolean | Yes | |
ExtraStreak_Kills | integer | Yes | |
ExtraStreak_Sounds | sound | Yes | |
ExtraStreak_Strings | string | Yes | |
ExtraStreak_Timer | integer | Yes | |
ExtraStreakInt | integervar | No | |
Eye_Angle | real | No | |
FireArt | effect | No | |
FireCaster | unit | No | |
FleeingBolts | group | No | |
Flying_unit | group | No | |
FOB1 | unit | No | |
FOB2 | unit | No | |
FOB3 | unit | No | |
FoK_Ability_Level | integer | No | |
FoK_Angle | real | No | |
FoK_Base_Damage | real | No | |
FoK_Caster | unit | No | |
FoK_Damage_Group | group | No | |
FoK_Detection_Area | real | No | |
FoK_Distance | real | No | |
FoK_Dummy_Group | group | No | |
FoK_Facing | real | No | |
FoK_Knives_Count | integer | No | |
FoK_Loc1 | location | No | |
FoK_Loc2 | location | No | |
FoK_Loc3 | location | No | |
FoK_Loc4 | location | No | |
FoK_Random_Movement | boolean | No | |
FoK_Random_Path | boolean | No | |
FoK_Speed | real | No | |
FoK_Spiral_Angle | real | No | |
FoK_Table | hashtable | No | |
FoK_Total_Damage | real | No | |
GETLVL | integer | No | |
HandleID | integer | No | |
HASH | hashtable | No | |
Hashtable | hashtable | No | |
Heroes | unit | Yes | |
HEROREWGROUP | group | No | |
i | integervar | No | |
i2 | integer | No | |
ice1 | unit | No | |
ice2 | unit | No | |
ice3 | unit | No | |
ice4 | unit | No | |
ice5 | unit | No | |
IDKey1Bool | boolean | No | |
IDKey1Bool2 | boolean | No | |
INIAI | integer | Yes | |
Integer | integer | Yes | |
IntegerDT | integer | No | |
intiger | integer | Yes | |
INVUGROUP | group | No | |
KazarinaDummy | unit | No | |
KazarinaGroup | group | No | |
KazarinaTemp | unit | No | |
KB_Angle | real | Yes | |
KB_Casters | unit | Yes | |
KB_CountBuffs | integer | No | |
KB_DestroyTrees | boolean | Yes | |
KB_EffectCounter | integer | Yes | |
KB_EffectCounter2 | integer | Yes | |
KB_Effects_1 | string | Yes | |
KB_Effects_2 | string | Yes | |
KB_GeneralIntegers | integervar | Yes | |
KB_KnockbackedUnits | group | No | |
KB_Levels | integer | Yes | |
KB_MaxDistance | real | Yes | |
KB_ReachedDistance | real | Yes | |
KB_ReducedReal | real | No | |
KB_ReduceSpeedReal | real | Yes | |
KB_SpecificSpeed | real | Yes | |
KB_StartPositions | location | Yes | |
KB_TempPoint | location | Yes | |
KB_TempReal | real | No | |
KB_TotalKnockUnits | integer | No | |
KB_Units | unit | Yes | |
KBA_Angle | real | No | |
KBA_Caster | unit | No | |
KBA_DestroyTrees | boolean | No | |
KBA_DistancePerLevel | real | No | |
KBA_Level | integer | No | |
KBA_SpecialEffects | string | Yes | |
KBA_Speed | real | No | |
KBA_StartingPosition | location | No | |
KBA_TargetUnit | unit | No | |
Kills | integer | Yes | |
KillsLeaderboard | leaderboard | No | |
KING | unit | Yes | |
KnockBackTimer | timer | No | |
KnockDistance | real | No | |
KnockedEffect | effect | No | |
KnockedUnit | unit | No | |
KnockFacing | real | No | |
KnockingUnit | unit | No | |
KnockPoint | location | No | |
KnockSecondPoint | location | No | |
l1 | lightning | No | |
l1_Copy | lightning | No | |
l1_Copy_Copy | lightning | No | |
l1_Copy_Copy_10 | lightning | No | |
l1_Copy_Copy_11 | lightning | No | |
l1_Copy_Copy_12 | lightning | No | |
l1_Copy_Copy_13 | lightning | No | |
l1_Copy_Copy_2 | lightning | No | |
l1_Copy_Copy_3 | lightning | No | |
l1_Copy_Copy_4 | lightning | No | |
l1_Copy_Copy_5 | lightning | No | |
l1_Copy_Copy_6 | lightning | No | |
l1_Copy_Copy_7 | lightning | No | |
l1_Copy_Copy_8 | lightning | No | |
l1_Copy_Copy_9 | lightning | No | |
Leaderboard | leaderboard | No | |
lightning1 | lightning | No | |
lightning1_Copy | lightning | No | |
lightning1_Copy_2 | lightning | No | |
lightning1_Copy_3 | lightning | No | |
lightning1_Copy_4 | lightning | No | |
lightning1_Copy_5 | lightning | No | |
lightning1_Copy_6 | lightning | No | |
lightning1_Copy_7 | lightning | No | |
loc | location | No | |
loopA | integervar | No | |
LotusAngle | real | No | |
LotusCaster | unit | No | |
LotusDummy | unit | No | |
LotusFade | real | No | |
LotusPoint | location | No | |
LotusTarget | unit | No | |
MC | unit | No | |
Messages | string | Yes | |
Mode | string | No | |
MT | unit | No | |
Names | string | Yes | |
NazgrelGroup | group | No | |
NazgrelLoc | location | No | |
NS1 | unit | No | |
NS1_Copy | unit | No | |
NS1_Copy_2 | unit | No | |
NS1_Copy_3 | unit | No | |
NS1_Copy_4 | unit | No | |
NS1_Copy_5 | unit | No | |
NS1_Copy_6 | unit | No | |
NS1_Copy_7 | unit | No | |
P1 | location | No | |
P2 | location | No | |
Palantir | unit | No | |
PassiveSpell | abilcode | No | |
PassiveSpellName | string | No | |
PINGLOC | location | No | |
Player | integer | No | |
Player_Colours | string | Yes | |
Player_Strings | string | Yes | |
PLAYERCon | integer | Yes | |
PlayerNames | string | Yes | |
PLMC | location | No | |
PLMC_Copy | location | No | |
point | location | No | |
Point | location | Yes | |
Point_A | location | Yes | |
Point_B | location | Yes | |
point_move | location | Yes | |
Points | location | Yes | |
Ponit_victim_multi | location | Yes | |
PortalP | location | No | |
PossibleHeroes | group | No | |
QAGroup | group | No | |
RAA | location | No | |
RainingArrowGroup | group | No | |
RandomInt | integer | Yes | 1 |
RANGERGROUP | group | No | |
Real | real | Yes | |
RepickInt | integer | Yes | 1 |
ReturningBolts | group | No | |
Ripple | unit | No | |
ROR | unit | No | |
ROR1 | unit | No | |
ROR2 | unit | No | |
ROR3 | unit | No | |
ROR4 | unit | No | |
ROR5 | unit | No | |
ROR6 | unit | No | |
ROR7 | unit | No | |
ROT | location | No | |
Sample_Group | group | No | |
Sample_Point | location | No | |
Score | integer | Yes | 500 |
SOD1 | location | No | |
SOD1_Copy | location | No | |
SOD1_Copy_2 | location | No | |
SOD1_Copy_3 | location | No | |
SODarray | lightning | Yes | |
SODCaster | unit | No | |
SODmain | location | No | |
SoDtg | unit | No | |
Spheres | group | No | |
SSCaster | unit | Yes | |
SSDamage | real | Yes | |
SSDummyGroup | group | Yes | |
SSGroup | group | No | |
SSIndex | integer | No | |
SSInteger | integervar | No | |
SSInteger2 | integervar | No | |
SSMax | integer | No | |
SSPoint | location | Yes | |
SSPoint2 | location | Yes | |
SSTarget | unit | Yes | |
Stomp_Location | location | No | |
Stomper | unit | No | |
Streak_Kills | integer | Yes | |
Streak_Sounds | sound | Yes | |
Streak_Strings | string | Yes | |
STSF | location | No | |
STSFc | unit | No | |
STSFt | unit | No | |
t1 | trigger | No | |
t1_Copy | trigger | No | |
t1_Copy_2 | trigger | No | |
t1_Copy_3 | trigger | No | |
t1_Copy_4 | trigger | No | |
t1_Copy_5 | trigger | No | |
t1_Copy_6 | trigger | No | |
t1_Copy_7 | trigger | No | |
t1_Copy_8 | trigger | No | |
Target | unit | No | |
targetAOESGD | unit | No | |
Temp_Group_1 | group | No | |
Temp_Group_2 | group | No | |
Temp_Loc_1 | location | No | |
Temp_Loc_2 | location | No | |
Temp_Player_1 | player | No | |
Temp_Player_2 | player | No | |
Temp_Player_Group | force | No | |
Temp_Real_1 | real | No | |
Temp_String | string | No | |
Temp_Unit_1 | unit | No | |
TempHeroLoc | location | No | |
temploc | location | No | |
Timer | timer | No | |
TotalMessages | integer | Yes | |
UC | location | No | |
UC1 | location | No | |
Unit | unit | Yes | |
unit_C | unit | Yes | |
unitAOESNO | unit | No | |
VAMPIRES | group | No | |
Victim_multi | unit | Yes | |
VisionMod | fogmodifier | Yes | |
Way1 | unit | No | |
Way2 | unit | No | |
WEGroup | group | No | |
WTF | unit | No | |
x | real | No | |
x2 | real | No | |
y | real | No | |
y2 | real | No | |
z | real | No | |
zLoc | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Exp_Actions takes nothing returns nothing
call SetPlayerHandicapXPBJ( Player(0), 125.00 )
call SetPlayerHandicapXPBJ( Player(1), 125.00 )
call SetPlayerHandicapXPBJ( Player(2), 125.00 )
call SetPlayerHandicapXPBJ( Player(3), 125.00 )
call SetPlayerHandicapXPBJ( Player(4), 125.00 )
call SetPlayerHandicapXPBJ( Player(5), 125.00 )
call SetPlayerHandicapXPBJ( Player(6), 125.00 )
call SetPlayerHandicapXPBJ( Player(7), 125.00 )
call SetPlayerHandicapXPBJ( Player(8), 125.00 )
call SetPlayerHandicapXPBJ( Player(9), 125.00 )
call SetPlayerHandicapXPBJ( Player(10), 125.00 )
call SetPlayerHandicapXPBJ( Player(11), 125.00 )
endfunction
//===========================================================================
function InitTrig_Exp takes nothing returns nothing
set gg_trg_Exp = CreateTrigger( )
call TriggerAddAction( gg_trg_Exp, function Trig_Exp_Actions )
endfunction
//TESH.scrollpos=18
//TESH.alwaysfold=0
//System Name: EngageSystem
//Made by: Mckill2009
//===FEATURES:
//- This system will order a unit to engage and search for enemies
//- Allows pick up item or an option to pick up only custom item type
//- Allows target random enemy units include creeps and buildings
//- Retreat away from attacker or to building when HP is low
//- Allows to learn/pick custom skill (manually set it up below)
//- Allows target refresh when duration runs out
//- Uses a global timer and group, which is not destroyed but is used during the entire game
//===HOW TO USE:
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//===KNOWN ISSUES:
//- If the target unit is unreachable, it will still lock the attack
//- This system does not support Buy and Selling of items for AI (for the meantime)
//===REQUIRES:
//- Jass New Gen Pack (JNGP) by Vexorian
library EngageSystem initializer init
globals
//===NON-CONFIGURABLES: Meaning, do not touch this!
private constant hashtable HASH = InitHashtable()
private constant integer FOUNTAIN_OF_HEALTH = 'nfoh'
//private constant integer FOUNTAIN_OF_MANA = 'nmoo' //Reserved
private constant integer ATTACK = 851983
private constant integer MOVE = 851986
private constant integer STOP = 851972
private constant integer SMART = 851971
private integer array ITEM_TYPE
private integer array SKILL
private rect R
private unit UNIT_RETREATING
private unit UNIT_DATA
private integer GROUP_COUNTER_ENGAGE = 0
private integer GROUP_COUNTER_ITEM = 0
private group ITEM_SEARCH_GROUP
private group RETREAT_GROUP
private trigger RETREAT_TRIGGER
private constant group ENGAGE_GROUP = CreateGroup()
private constant timer ENGAGE_TIMER = CreateTimer()
endglobals
globals
//===CONFIGURABLES:
private constant real AOE_ITEM_PICK = 500
private constant real AOE_TARGET_RANDOM = 5000
private constant real AOE_TARGET_BUILDING = 6000
private constant real AOE_NEAR_TARGET = 1000
private constant real AOE_TARGET_CREEP = 5000
private constant real AOE_RETREAT_TO_BUILDING = 5000
private constant real RETREAT_DISTANCE = 2700
private constant real ATTACK_DURATION = 45.
private constant real ATTACK_INTERVAL = 3 //Recommended setting
private constant real ITEM_PICK_INTERVAL = 1 //Recommended setting
private constant real RETREAT_INTERVAL = 1 //Recommended setting
private constant real FOLLOW_INTERVAL = 3 //Recommended setting
private constant real MAX_LIFE_PERCENTAGE = 0.35 //Used for retreat
private constant integer MAX_ITEM_TYPE = 3 //Should be match on how many item types created
private constant integer MAX_CUSTOM_SKILL = 5 //Should be match on how many skills created
private constant integer MAX_ITEM_PICKED = 3 //Warning: MAX is 6
private constant boolean ENABLE_PICK_UP_ITEM = true
private constant boolean ENABLE_PICK_UP_ITEM_TYPE = false //Set to false to pick every item types
private constant boolean ENABLE_RETREAT = true
private constant boolean ENABLE_RETREAT_TO_BUILDING = false
private constant boolean ENABLE_PICK_CUSTOM_SKILL = false
endglobals
// Set the skills and item types here!
private function SetupSkillsAndItemTypes takes nothing returns nothing
//You must setup the skills here
set SKILL[1] = 'A000'
set SKILL[2] = 'A000'
set SKILL[3] = 'A000'
set SKILL[4] = 'A000'
set SKILL[5] = 'A000'
//IMPORTANT NOTE: if you increase the item types created, you should increase also the MAX_ITEM_TYPE of the globals
set ITEM_TYPE[1] = 'will' //Default Wand of Illusion
set ITEM_TYPE[2] = 'woms' //Default Wand of Mana Stealing
set ITEM_TYPE[3] = 'wlsd' //Default Wand of Lightning Shield
//set ITEM_TYPE[4] = 'ADDITIONAL ITEM'
//set ITEM_TYPE[5] = 'ADDITIONAL ITEM'
endfunction
//===ATTACKING STRUCT:
private struct Engage
unit hero
unit target
unit target2
unit ally
real duration
static method onLocateAlly takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) and not IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA))
set u = null
return b
endmethod
static method onSearchAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA))
set u = null
return b
endmethod
static method onRangeAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA)) and GetOwningPlayer(u)!=Player(PLAYER_NEUTRAL_AGGRESSIVE)
set u = null
return b
endmethod
static method onCreepAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and GetOwningPlayer(u)==Player(PLAYER_NEUTRAL_AGGRESSIVE)
set u = null
return b
endmethod
static method onLocateBuilding takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA))
set u = null
return b
endmethod
static method onAttackNow takes nothing returns nothing
local unit u = GetEnumUnit()
local thistype this = LoadInteger(HASH, GetHandleId(u), 1)
local real x = GetUnitX(.hero)
local real y = GetUnitY(.hero)
local integer randomatk
set UNIT_DATA = .hero
if .duration > 0 and GetWidgetLife(.hero) > 0.405 then
set .duration = .duration - ATTACK_INTERVAL
if GetWidgetLife(.target) > 0.405 and .target != null then
call IssueTargetOrderById(.hero, ATTACK, .target)
call IssuePointOrderById(.hero, ATTACK, GetUnitX(.target), GetUnitY(.target))
else
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_NEAR_TARGET, Filter(function thistype.onSearchAttack))
set .target2 = FirstOfGroup(bj_lastCreatedGroup)
call IssueTargetOrderById(.hero, ATTACK, .target2)
call IssuePointOrderById(.hero, ATTACK, GetUnitX(.target2), GetUnitY(.target2))
if .target2==null then
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Filter(function thistype.onSearchAttack))
set .target2 = FirstOfGroup(bj_lastCreatedGroup)
call IssueTargetOrderById(.hero, ATTACK, .target2)
call IssuePointOrderById(.hero, ATTACK, GetUnitX(.target2), GetUnitY(.target2))
if .target2==null then
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Filter(function thistype.onLocateAlly))
set .ally = FirstOfGroup(bj_lastCreatedGroup)
call IssuePointOrderById(.hero, MOVE, GetUnitX(.ally), GetUnitY(.ally))
endif
endif
endif
else
if GetWidgetLife(.hero) > 0.405 then
set randomatk = GetRandomInt(1, 4)
if randomatk==1 or randomatk==2 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_RANDOM, Filter(function thistype.onRangeAttack))
elseif randomatk==3 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_CREEP, Filter(function thistype.onCreepAttack))
elseif randomatk==4 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_BUILDING, Filter(function thistype.onLocateBuilding))
endif
set .target = FirstOfGroup(bj_lastCreatedGroup)
set .duration = ATTACK_DURATION //this action resumes the timer without destroying it
else
call GroupRemoveUnit(ENGAGE_GROUP, .hero)
set GROUP_COUNTER_ENGAGE = GROUP_COUNTER_ENGAGE - 1
//call BJDebugMsg("ENGAGE UNIT COUNTER "+I2S(GROUP_COUNTER_ENGAGE))
call .destroy(this)
endif
endif
set u = null
endmethod
static method onAttackSetup takes unit u returns Engage
local Engage EN = Engage.create()
local integer randomatk = GetRandomInt(1, 4)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
set UNIT_DATA = u
if randomatk==1 or randomatk==2 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_RANDOM, Filter(function thistype.onRangeAttack))
elseif randomatk==3 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_CREEP, Filter(function thistype.onCreepAttack))
elseif randomatk==4 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_TARGET_BUILDING, Filter(function thistype.onLocateBuilding))
endif
set EN.target = FirstOfGroup(bj_lastCreatedGroup)
set EN.hero = u
set EN.duration = ATTACK_DURATION
call GroupAddUnit(ENGAGE_GROUP, u)
call SaveInteger(HASH, GetHandleId(u), 1, EN)
set GROUP_COUNTER_ENGAGE = GROUP_COUNTER_ENGAGE + 1
return EN
endmethod
endstruct
//===ITEM PICK STRUCT:
private struct ItemPick
unit hero
private static thistype DATA
static method onPickItem takes nothing returns boolean
local thistype this = DATA
local item it = GetFilterItem()
local integer i = 0
if ENABLE_PICK_UP_ITEM_TYPE then
loop
set i = i+1
if GetItemTypeId(it)==ITEM_TYPE[i] then
call IssueTargetOrderById(.hero, SMART, it)
endif
exitwhen i >= MAX_ITEM_TYPE
endloop
else
call IssueTargetOrderById(.hero, SMART, it)
endif
set it = null
return false
endmethod
static method enumerateItem takes nothing returns nothing
local unit u = GetEnumUnit()
local thistype this = LoadInteger(HASH, GetHandleId(u), 1+1)
local real x
local real y
local integer index = 0
local integer count = 0
loop
if (UnitItemInSlot(.hero, index) != null) then
set count = count + 1
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
if GetWidgetLife(.hero) > 0.405 and count < MAX_ITEM_PICKED then
set x = GetUnitX(.hero)
set y = GetUnitY(.hero)
set DATA = this
call MoveRectTo(R, x, y)
call EnumItemsInRect(R, function thistype.onPickItem, null)
elseif GetWidgetLife(.hero) < 0.405 then
set GROUP_COUNTER_ITEM = GROUP_COUNTER_ITEM - 1
call GroupRemoveUnit(ITEM_SEARCH_GROUP, .hero)
call .destroy(this)
//call BJDebugMsg("ITEM COUNTER "+I2S(GROUP_COUNTER_ITEM))
endif
set u = null
endmethod
static method onenumerateItem takes unit hero returns thistype
local thistype this = thistype.create()
local timer t = CreateTimer()
set .hero = hero
call GroupAddUnit(ITEM_SEARCH_GROUP, .hero)
call SaveInteger(HASH, GetHandleId(.hero), 1+1, this)
set GROUP_COUNTER_ITEM = GROUP_COUNTER_ITEM + 1
set t = null
return this
endmethod
endstruct
//===RETREAT:
private function SearchAllyBase takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitAlly(u, GetOwningPlayer(UNIT_RETREATING)) and IsUnitType(u, UNIT_TYPE_STRUCTURE)
set u = null
return b
endfunction
private function RetreatForHealth takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b
if GetRandomInt(1,2)==1 then
set b = GetUnitTypeId(u)==FOUNTAIN_OF_HEALTH
else
set b = not IsUnitEnemy(u, GetOwningPlayer(UNIT_RETREATING)) and GetWidgetLife(u) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) or GetUnitTypeId(u)==FOUNTAIN_OF_HEALTH
endif
set u = null
return b
endfunction
private function DamageGroup takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit retreatpoint
local real maxlife = GetUnitState(u, UNIT_STATE_MAX_LIFE)
local real x
local real y
local real x1
local real y1
if GetWidgetLife(u) > 0.405 then
if GetWidgetLife(u) <= maxlife*MAX_LIFE_PERCENTAGE then
set x = GetUnitX(u)
set y = GetUnitY(u)
set UNIT_RETREATING = u
if ENABLE_RETREAT_TO_BUILDING then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_RETREAT_TO_BUILDING, function RetreatForHealth)
set retreatpoint = FirstOfGroup(bj_lastCreatedGroup)
call IssuePointOrderById(u, MOVE, GetUnitX(retreatpoint), GetUnitY(retreatpoint))
else
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_NEAR_TARGET, function SearchAllyBase)
set retreatpoint = FirstOfGroup(bj_lastCreatedGroup)
set x1 = GetUnitX(retreatpoint) + RETREAT_DISTANCE * Cos(GetUnitFacing(u)+180)
set y1 = GetUnitY(retreatpoint) + RETREAT_DISTANCE * Sin(GetUnitFacing(u)+180)
call IssuePointOrderById(u, MOVE, x1, y1)
endif
endif
else
call RemoveSavedInteger(HASH, GetHandleId(u), 200)
endif
set retreatpoint = null
set u = null
endfunction
//===LEARN SKILL AND PICK UP ITEM: FOR CUSTOM SKILL ONLY
private function PickSkillNow takes nothing returns boolean
local integer i
if GetPlayerController(GetTriggerPlayer())==MAP_CONTROL_COMPUTER then
set i = 0
loop
set i = i + 1
call SelectHeroSkill(GetTriggerUnit(), SKILL[i])
exitwhen i >= MAX_CUSTOM_SKILL
endloop
endif
return false
endfunction
//===GROUP LOOPERS:
private function RunItemPick takes nothing returns nothing
if GROUP_COUNTER_ITEM > 0 then
call ForGroup(ITEM_SEARCH_GROUP, function ItemPick.enumerateItem)
endif
endfunction
private function RunAttack takes nothing returns nothing
if GROUP_COUNTER_ENGAGE > 0 then
call ForGroup(ENGAGE_GROUP, function Engage.onAttackNow)
endif
endfunction
//===INITIALIZER:
private function init takes nothing returns nothing
local trigger t1
local trigger t2
if ENABLE_PICK_CUSTOM_SKILL then
set t1 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_HERO_LEVEL)
call TriggerAddCondition(t1, function PickSkillNow)
endif
if ENABLE_PICK_UP_ITEM then
set t2 = CreateTrigger()
call TriggerRegisterTimerEvent(t2, ITEM_PICK_INTERVAL, true)
call TriggerAddAction(t2, function RunItemPick)
set R = Rect(-AOE_ITEM_PICK, -AOE_ITEM_PICK, AOE_ITEM_PICK, AOE_ITEM_PICK)
set ITEM_SEARCH_GROUP = CreateGroup()
endif
if ENABLE_RETREAT then
set RETREAT_TRIGGER = CreateTrigger()
call TriggerAddAction(RETREAT_TRIGGER, function DamageGroup)
set RETREAT_GROUP = CreateGroup()
endif
call SetupSkillsAndItemTypes()
call TimerStart(ENGAGE_TIMER, ATTACK_INTERVAL, true, function RunAttack)
set t1 = null
set t2 = null
endfunction
//===SETUP EVERYTHING:
function SetEngageUnit takes unit u returns nothing
if not IsUnitType(u, UNIT_TYPE_STRUCTURE) then
call Engage.onAttackSetup(u)
if ENABLE_PICK_UP_ITEM and GetPlayerController(GetOwningPlayer(u))==MAP_CONTROL_COMPUTER and IsUnitType(u, UNIT_TYPE_HERO) then
call ItemPick.onenumerateItem(u)
endif
if ENABLE_RETREAT then
call GroupAddUnit(RETREAT_GROUP, u)
if not HaveSavedInteger(HASH, GetHandleId(u), 200) then
call SaveInteger(HASH, GetHandleId(u), 200, 1)
call TriggerRegisterUnitEvent(RETREAT_TRIGGER, u, EVENT_UNIT_DAMAGED)
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=291
//TESH.alwaysfold=0
library MBLib initializer init
globals
//Never touch these!
private constant integer MBCOLUMN = 5
private constant integer MBROW = 24
private constant integer MBSCORECOL = 1
private constant integer MBBOSSKILLCOL = 2
private constant integer MBKILLCOL = 3
private constant integer MBDEATHCOL = 4
//Configurables
private constant string MBTITLE = "Monster Showdown Ultimate"
private constant boolean SCORESON = true
//non-constants
public multiboard MB
private integer array MONSTERS
private integer array KILLS
private integer array DEATHS
private integer array TOTAL
private integer MONSTERS1 = 0
private integer MONSTERS2 = 0
private integer MONSTERS3 = 0
private integer MONSTERS4 = 0
private integer MONSTERS5 = 0
private integer MONSTERS6 = 0
private integer TOTAL1 = 0
private integer TOTAL2 = 0
private integer TOTAL3 = 0
private integer TOTAL4 = 0
private integer TOTAL5 = 0
private integer TOTAL6 = 0
private integer DEATHS1 = 0
private integer DEATHS2 = 0
private integer DEATHS3 = 0
private integer DEATHS4 = 0
private integer DEATHS5 = 0
private integer DEATHS6 = 0
endglobals
private function onPlayerCond takes integer pid returns boolean
return GetPlayerSlotState(Player(pid)) == PLAYER_SLOT_STATE_PLAYING
endfunction
private function onMonsterUpdate takes unit u, integer pid returns nothing
set MONSTERS[pid] = MONSTERS[pid]+1
if GetOwningPlayer(u)==Player(0) or GetOwningPlayer(u)==Player(1) then
set MONSTERS1=MONSTERS1+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+1, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 1, MBBOSSKILLCOL), I2S(MONSTERS1))
elseif GetOwningPlayer(u)==Player(2) or GetOwningPlayer(u)==Player(3) then
set MONSTERS2=MONSTERS2+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+3, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 5, MBBOSSKILLCOL), I2S(MONSTERS2))
elseif GetOwningPlayer(u)==Player(4) or GetOwningPlayer(u)==Player(5) then
set MONSTERS3=MONSTERS3+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+5, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 9, MBBOSSKILLCOL), I2S(MONSTERS3))
elseif GetOwningPlayer(u)==Player(6) or GetOwningPlayer(u)==Player(7) then
set MONSTERS4=MONSTERS4+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+7, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 13, MBBOSSKILLCOL), I2S(MONSTERS4))
elseif GetOwningPlayer(u)==Player(8) or GetOwningPlayer(u)==Player(9) then
set MONSTERS5=MONSTERS5+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+9, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 17, MBBOSSKILLCOL), I2S(MONSTERS5))
elseif GetOwningPlayer(u)==Player(10) or GetOwningPlayer(u)==Player(11) then
set MONSTERS6=MONSTERS6+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+11, MBBOSSKILLCOL), I2S(MONSTERS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 21, MBBOSSKILLCOL), I2S(MONSTERS6))
endif
endfunction
private function onKillsUpdate takes unit u, integer pid returns nothing
set KILLS[pid] = KILLS[pid]+1
if GetOwningPlayer(u)==Player(0) or GetOwningPlayer(u)==Player(1) then
set TOTAL1=TOTAL1+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+1, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 1, MBKILLCOL), I2S(TOTAL1))
elseif GetOwningPlayer(u)==Player(2) or GetOwningPlayer(u)==Player(3) then
set TOTAL2=TOTAL2+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+3, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 5, MBKILLCOL), I2S(TOTAL2))
elseif GetOwningPlayer(u)==Player(4) or GetOwningPlayer(u)==Player(5) then
set TOTAL3=TOTAL3+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+5, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 9, MBKILLCOL), I2S(TOTAL3))
elseif GetOwningPlayer(u)==Player(6) or GetOwningPlayer(u)==Player(7) then
set TOTAL4=TOTAL4+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+7, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 13, MBKILLCOL), I2S(TOTAL4))
elseif GetOwningPlayer(u)==Player(8) or GetOwningPlayer(u)==Player(9) then
set TOTAL5=TOTAL5+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+9, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 17, MBKILLCOL), I2S(TOTAL5))
elseif GetOwningPlayer(u)==Player(10) or GetOwningPlayer(u)==Player(11) then
set TOTAL6=TOTAL6+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+11, MBKILLCOL), I2S(KILLS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 21, MBKILLCOL), I2S(TOTAL6))
endif
endfunction
private function onDeathsUpdate takes unit u, integer pid returns nothing
set DEATHS[pid] = DEATHS[pid]+1
if GetOwningPlayer(u)==Player(0) or GetOwningPlayer(u)==Player(1) then
set DEATHS1 = DEATHS1+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+1, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 1, MBDEATHCOL), I2S(DEATHS1))
elseif GetOwningPlayer(u)==Player(2) or GetOwningPlayer(u)==Player(3) then
set DEATHS2 = DEATHS2+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+3, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 5, MBDEATHCOL), I2S(DEATHS2))
elseif GetOwningPlayer(u)==Player(4) or GetOwningPlayer(u)==Player(5) then
set DEATHS3 = DEATHS3+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+5, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 9, MBDEATHCOL), I2S(DEATHS3))
elseif GetOwningPlayer(u)==Player(6) or GetOwningPlayer(u)==Player(7) then
set DEATHS4 = DEATHS4+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+7, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 13, MBDEATHCOL), I2S(DEATHS4))
elseif GetOwningPlayer(u)==Player(8) or GetOwningPlayer(u)==Player(9) then
set DEATHS5 = DEATHS5+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+9, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 17, MBDEATHCOL), I2S(DEATHS5))
elseif GetOwningPlayer(u)==Player(10) or GetOwningPlayer(u)==Player(11) then
set DEATHS6 = DEATHS6+1
call MultiboardSetItemValue(MultiboardGetItem(MB, pid+11, MBDEATHCOL), I2S(DEATHS[pid]))
call MultiboardSetItemValue(MultiboardGetItem(MB, 21, MBDEATHCOL), I2S(DEATHS6))
endif
endfunction
private function onMb takes nothing returns nothing
local integer i = 0
local integer pteam = 0
local integer pname
call MultiboardSetTitleText(MB, MBTITLE)
call MultiboardDisplay(MB, true)
call MultiboardSetColumnCount(MB, MBCOLUMN)
call MultiboardSetRowCount(MB, MBROW)
call MultiboardSetItemsStyle(MB, true, false)
loop
exitwhen i > 24
call MultiboardSetItemWidth(MultiboardGetItem(MB, i, 0), 0.06)
call MultiboardSetItemWidth(MultiboardGetItem(MB, i, 1), 0.03)
call MultiboardSetItemWidth(MultiboardGetItem(MB, i, 2), 0.04)
call MultiboardSetItemWidth(MultiboardGetItem(MB, i, 3), 0.04)
call MultiboardSetItemWidth(MultiboardGetItem(MB, i, 4), 0.03)
set i = i + 1
endloop
set i = 1
loop
set pteam = pteam+1
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 0), " |cff0080ffTEAM " + I2S(pteam) + "|r")
set i = i+4
exitwhen i >= MBROW
endloop
//TEAM 1
set i = 0
set pname = 1
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 3
endloop
//TEAM2
set i = 2
set pname = 5
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 7
endloop
//TEAM 3
set i = 4
set pname = 9
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 11
endloop
//TEAM 4
set i = 6
set pname = 13
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 15
endloop
//TEAM 5
set i = 8
set pname = 17
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 19
endloop
//TEAM 6
set i = 10
set pname = 21
loop
set pname = pname+1
if onPlayerCond(i) then
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "|cff" + udg_Player_Colours[GetPlayerId(Player( i )) + 1] + GetPlayerName(Player(i)) + "|r")
else
call MultiboardSetItemValue(MultiboardGetItem(MB, pname, 0), "None")
endif
set i = i+1
exitwhen pname >= 23
endloop
set i = 1
loop
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 1), "500")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 2), "0")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 3), "0")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 4), "0")
set i = i+1
exitwhen i >=MBROW
endloop
call MultiboardSetItemValue(MultiboardGetItem(MB, 0, 1), "|cff0080ffScore")
call MultiboardSetItemValue(MultiboardGetItem(MB, 0, 2), "|cff0080ffMonsters")
call MultiboardSetItemValue(MultiboardGetItem(MB, 0, 3), "|cff0080ffPlayers")
call MultiboardSetItemValue(MultiboardGetItem(MB, 0, 4), "|cff0080ffDeaths")
set i = 0
loop
set i = i+4
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 1), " ")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 2), " ")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 3), " ")
call MultiboardSetItemValue(MultiboardGetItem(MB, i, 4), " ")
exitwhen i >=MBROW
endloop
call MultiboardMinimize(MB, true)
endfunction
private function onMbSetup takes nothing returns boolean
call onMb()
return false
endfunction
private function onMbKillsEvent takes nothing returns boolean
local integer pid
local integer pid2
if GetKillingUnit() == null and GetTriggerUnit() != null and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true then
set pid2 = GetPlayerId(GetTriggerPlayer())+1
call onDeathsUpdate(GetTriggerUnit(), pid2)
return false
endif
if IsUnitEnemy(GetKillingUnit(), GetTriggerPlayer()) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true and GetOwningPlayer(GetTriggerUnit()) != Player(PLAYER_NEUTRAL_AGGRESSIVE) then
set pid = GetPlayerId(GetOwningPlayer(GetKillingUnit()))+1
set pid2 = GetPlayerId(GetTriggerPlayer())+1
call onKillsUpdate(GetKillingUnit(), pid)
call onDeathsUpdate(GetTriggerUnit(), pid2)
return false
endif
if IsUnitEnemy(GetKillingUnit(), GetTriggerPlayer()) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == true and GetOwningPlayer(GetTriggerUnit()) == Player(PLAYER_NEUTRAL_AGGRESSIVE) then
set pid = GetPlayerId(GetOwningPlayer(GetKillingUnit()))+1
set pid2 = GetPlayerId(GetTriggerPlayer())+1
call onMonsterUpdate(GetKillingUnit(), pid)
return false
endif
return false
endfunction
function runScores takes integer playerid, integer score returns nothing
if playerid==0 or playerid==1 then
set TOTAL[1] = udg_Score[0]+udg_Score[1]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+2, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 1, MBSCORECOL), I2S(TOTAL[1]))
elseif playerid==2 or playerid==3 then
set TOTAL[2] = udg_Score[2]+udg_Score[3]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+4, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 5, MBSCORECOL), I2S(TOTAL[2]))
elseif playerid==4 or playerid==5 then
set TOTAL[3] = udg_Score[4]+udg_Score[5]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+6, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 9, MBSCORECOL), I2S(TOTAL[3]))
elseif playerid==6 or playerid==7 then
set TOTAL[4] = udg_Score[6]+udg_Score[7]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+8, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 13, MBSCORECOL), I2S(TOTAL[4]))
elseif playerid==8 or playerid==9 then
set TOTAL[5] = udg_Score[8]+udg_Score[9]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+10, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 17, MBSCORECOL), I2S(TOTAL[5]))
elseif playerid==10 or playerid==11 then
set TOTAL[6] = udg_Score[10]+udg_Score[11]
call MultiboardSetItemValue(MultiboardGetItem(MB, playerid+12, MBSCORECOL), I2S(score))
call MultiboardSetItemValue(MultiboardGetItem(MB, 21, MBSCORECOL), I2S(TOTAL[6]))
endif
endfunction
private function init takes nothing returns nothing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
call TriggerRegisterTimerEvent(t1, 0.1, false)
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t1, Condition(function onMbSetup))
call TriggerAddCondition(t2, Condition(function onMbKillsEvent))
set MB = CreateMultiboard()
set t1 = null
set t2 = null
endfunction
endlibrary
//TESH.scrollpos=324
//TESH.alwaysfold=0
//
// _ ___ ___ ___ _______________________________________________
// /_\ |_ _| \/ __| || A D V A N C E D I N D E X I N G ||
// / _ \ | || |) \__ \ || A N D ||
// /_/ \_\___|___/|___/ || D A T A S T O R A G E ||
// By Jesus4Lyf ———————————————————————————————————————————————
// v 1.0.3
// What is AIDS?
// ———————————————
// AIDS assigns unique integers between 1 and 8191 to units which enter
// the map. These can be used for arrays and data attaching.
//
// AIDS also allows you to define structs which are created automatically
// when units enter the map, and filtering which units should be indexed
// as well as for which units these structs should be created.
//
// How to implement?
// ———————————————————
// Simply create a new trigger object called AIDS, go to 'Edit -> Convert
// to Custom Text', and replace everything that's there with this script.
//
// At the top of the script, there is a 'UnitIndexingFilter' constant
// function. If the function returns true for the unit, then that unit
// will be automatically indexed. Setting this to true will automatically
// index all units. Setting it to false will disable automatic indexing.
//
// Functions:
// ————————————
// function GetUnitId takes unit u returns integer
// - This returns the index of an indexed unit. This will return 0
// if the unit has not been indexed.
// - This function inlines. It does not check if the unit needs an
// index. This function is for the speed freaks.
// - Always use this if 'UnitIndexingFilter' simply returns true.
//
// function GetUnitIndex takes unit u returns integer
// - This will return the index of a unit if it has one, or assign
// an index if the unit doesn't have one (and return the new index).
// - Use this if 'UnitIndexingFilter' doesn't return true.
//
// function GetIndexUnit takes integer index returns unit
// - This returns the unit which has been assigned the 'index'.
//
// AIDS Structs:
// ——————————————
// - Insert: //! runtextmacro AIDS() at the top of a struct to make it
// an AIDS struct.
// - AIDS structs cannot be created or destroyed manually. Instead, they
// are automatically created when an appropriate unit enters the map.
// - You cannot give members default values in their declaration.
// (eg: private integer i=5 is not allowed)
// - You cannot use array members.
// - AIDS structs must "extend array". This will remove some unused
// functions and enforce the above so there will be no mistakes.
// - There are four optional methods you can use in AIDS structs:
// - AIDS_onCreate takes nothing returns nothing
// - This is called when the struct is 'created' for the unit.
// - In here you can assign members their default values, which
// you would usually assign in their declarations.
// (eg: set this.i=5)
// - AIDS_onDestroy takes nothing returns nothing
// - This is called when the struct is 'destroyed' for the unit.
// - This is your substitute to the normal onDestroy method.
// - AIDS_filter takes unit u returns boolean
// - This is similar to the constant filter in the main system.
// - Each unit that enters the map will be tested by each AIDS
// struct filter. If it returns true for that unit, that unit
// will be indexed if it was not already, the AIDS struct will
// have its AIDS_onCreate method called, and later have its
// AIDS_onDestroy method called when the index is recycled.
// - Not declaring this will use the default AIDS filter instead.
// - AIDS_onInit takes nothing returns nothing
// - This is because I stole your onInit function with my textmacro.
// - You can use '.unit' from any AIDS struct to get the unit for which
// the struct is for.
// - The structs id will be the units index, so getting the struct for
// a unit inlines to a single native call, and you can typecast between
// different AIDS structs. This is the premise of AIDS.
// - Never create or destroy AIDS structs directly.
// - You can call .AIDS_addLock() and AIDS_removeLock() to increase or
// decrease the lock level on the struct. If a struct's lock level is
// not 0, it will not be destroyed until it is reduced to 0. Locks just
// put off AIDS struct destruction in case you wish to attach to a timer
// or something which must expire before the struct data disappears.
// Hence, not freeing all locks will leak the struct (and index).
//
// PUI and AutoIndex:
// ————————————————————
// - AIDS includes the PUI textmacros and the AutoIndex module, because
// these systems are not compatible with AIDS but have valid and distinct
// uses.
// - The PUI textmacros are better to use for spells than AIDS structs,
// because they are not created for all units, just those targetted by
// the spell (or whatever else is necessary).
// - The AutoData module is good for very simple array syntax for data
// attachment (although I don't recommend that people actually use it,
// it's here mostly for compatability). Note that unlike the PUI textmacros,
// units must pass the AIDS filter in order for this module to work with
// them. This is exactly as the same as in AutoIndex itself (AutoIndex
// has a filter too).
//
// Thanks:
// —————————
// - Romek, for writing 90% of this user documentation, challenging my
// interface, doing some testing, suggesting improvements and inspiring
// me to re-do my code to include GetUnitIndex as non-inlining.
// - grim001, for writing the AutoData module, and AutoIndex. I used the
// on-enter-map method that he used. Full credits for the AutoData module.
// - Cohadar, for writing his PUI textmacros. Full credits to him for these,
// except for my slight optimisations for this system.
// Also, I have used an optimised version of his PeriodicRecycler from
// PUI in this system to avoid needing a RemoveUnitEx function.
// - Vexorian, for helping Cohadar on the PUI textmacro.
// - Larcenist, for suggesting the AIDS acronym. Originally he suggested
// 'Alternative Index Detection System', but obviously I came up with
// something better. In fact, I'd say it looks like the acronym was
// an accident. Kinda neat, don't you think? :P
//
// Final Notes:
// ——————————————
// - With most systems, I wouldn't usually add substitutes for alternative
// systems. However, UnitData systems are an exception, because they
// are incompatible with eachother. Since using this system forbids
// people from using the real PUI or AutoIndex, and a lot of resources
// use either of these, it made sense not to break them all.
//
// - If this documentation confused you as to how to use the system, just
// leave everything as default and use GetUnitId everywhere.
//
// - To use this like PUI (if you don't like spamming indices) simply
// make the AIDS filter return false, and use GetUnitIndex.
//
library AIDS initializer InitAIDS
//==============================================================================
// Configurables
//
globals
private constant real PERIOD = 0.03125 // Recycles 32 units/second max.
endglobals // Lower to be able to recycle faster.
private constant function UnitIndexingFilter takes unit u returns boolean
return true
endfunction
//==============================================================================
// System code
//
globals
// The unit stored at an index.
private unit array IndexUnit
private integer array LockLevel
endglobals
//==============================================================================
globals
// Recycle stack
private integer array RecycledIndex
private integer MaxRecycledIndex = 0
// Previous highest index
private integer MaxIndex = 0
endglobals
//==============================================================================
globals
private integer array DecayingIndex
private integer MaxDecayingIndex=0
private integer DecayChecker=0
endglobals
//==============================================================================
globals
// The Add/Remove stack (or assign/recycle stack).
//
// Indexing can become recusive since units can be created on index
// assignment or deallocation.
// To support this, a stack is used to store the event response results.
private integer ARStackLevel=0
private integer array ARStackIndex
private unit array ARStackUnit
// A later discovery revealed that the Add/Remove stack did not need to be
// used for deallocation. The alternative used works fine...
endglobals
public constant function GetEnteringIndexUnit takes nothing returns unit
return ARStackUnit[ARStackLevel]
endfunction
public function GetIndexOfEnteringUnit takes nothing returns integer
// Called in AIDS structs when units do not pass the initial AIDS filter.
if ARStackIndex[ARStackLevel]==0 then
// Get new index, from recycler first, else new.
// Store the current index on the (new) top level of the AR stack.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set ARStackIndex[ARStackLevel]=MaxIndex
else // Get from recycle stack.
set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
endif
return ARStackIndex[ARStackLevel]
endfunction
public constant function GetIndexOfEnteringUnitAllocated takes nothing returns integer
// Called in AIDS structs when units have passed the initial AIDS filter.
return ARStackIndex[ARStackLevel]
endfunction
public constant function GetDecayingIndex takes nothing returns integer
return DecayingIndex[DecayChecker]
endfunction
//==============================================================================
globals
// For structs and such which need to do things on unit index assignment.
private trigger OnEnter=CreateTrigger()
// The same, but for when units pass the initial filter anyway.
private trigger OnEnterAllocated=CreateTrigger()
// For structs and such which need to do things on unit index deallocation.
private trigger OnDeallocate=CreateTrigger()
endglobals
public function RegisterOnEnter takes boolexpr b returns triggercondition
return TriggerAddCondition(OnEnter,b)
endfunction
public function RegisterOnEnterAllocated takes boolexpr b returns triggercondition
return TriggerAddCondition(OnEnterAllocated,b)
endfunction
public function RegisterOnDeallocate takes boolexpr b returns triggercondition
return TriggerAddCondition(OnDeallocate,b)
endfunction
//==============================================================================
function GetIndexUnit takes integer index returns unit
debug if index==0 then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of index 0.")
debug elseif IndexUnit[index]==null then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of unassigned index.")
debug endif
return IndexUnit[index]
endfunction
function GetUnitId takes unit u returns integer
debug if u==null then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the id (inlines) of null unit.")
debug elseif GetUnitUserData(u)==0 then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to use GetUnitId (inlines) when you should be using GetUnitIndex (unit didn't pass filter).")
debug endif
return GetUnitUserData(u)
endfunction
globals//locals
private integer getindex
endglobals
function GetUnitIndex takes unit u returns integer // Cannot be recursive.
set getindex=GetUnitId(u)
if getindex==0 then
// Get new index, from recycler first, else new.
// Store the current index in getindex.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set getindex=MaxIndex
else // Get from recycle stack.
set getindex=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(u,getindex)
set IndexUnit[getindex]=u
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=getindex
// Do not fire things here. No AIDS structs will be made at this point.
endif
return getindex
endfunction
//==============================================================================
public function AddLock takes integer index returns nothing
set LockLevel[index]=LockLevel[index]+1
endfunction
public function RemoveLock takes integer index returns nothing
set LockLevel[index]=LockLevel[index]-1
endfunction
//==============================================================================
private function PeriodicRecycler takes nothing returns nothing
if MaxDecayingIndex>0 then
set DecayChecker=DecayChecker+1
if DecayChecker>MaxDecayingIndex then
set DecayChecker=1
endif
if GetUnitUserData(IndexUnit[DecayingIndex[DecayChecker]])==0 then
if LockLevel[DecayingIndex[DecayChecker]]==0 then
// Fire things.
call TriggerEvaluate(OnDeallocate)
// Add the index to the recycler stack.
set MaxRecycledIndex=MaxRecycledIndex+1
set RecycledIndex[MaxRecycledIndex]=DecayingIndex[DecayChecker]
// Null the unit.
set IndexUnit[DecayingIndex[DecayChecker]]=null
// Remove index from decay list.
set DecayingIndex[DecayChecker]=DecayingIndex[MaxDecayingIndex]
set MaxDecayingIndex=MaxDecayingIndex-1
endif
endif
endif
endfunction
//==============================================================================
public function IndexEnum takes nothing returns boolean // Can be recursive...
// Start by adding another level on the AR stack (for recursion's sake).
set ARStackLevel=ARStackLevel+1
// Store the current unit on the (new) top level of the AR stack.
set ARStackUnit[ARStackLevel]=GetFilterUnit()
if UnitIndexingFilter(ARStackUnit[ARStackLevel]) then
// Get new index, from recycler first, else new.
// Store the current index on the (new) top level of the AR stack.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set ARStackIndex[ARStackLevel]=MaxIndex
else // Get from recycle stack.
set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
// Fire things.
call TriggerEvaluate(OnEnter)
else
// The unit did not pass the filters, so does not need to be auto indexed.
// However, for certain AIDS structs, it may still require indexing.
// These structs may index the unit on their creation.
// We flag that an index must be assigned by setting the current index to 0.
set ARStackIndex[ARStackLevel]=0
// Fire things.
call TriggerEvaluate(OnEnter)
endif
// Decrement the stack.
set ARStackLevel=ARStackLevel-1
return false
endfunction
//==============================================================================
private function InitAIDS takes nothing returns nothing
local region r=CreateRegion()
local group g=CreateGroup()
local integer n=15
// This must be done first, due to recursion. :)
call RegionAddRect(r,bj_mapInitialPlayableArea)
call TriggerRegisterEnterRegion(CreateTrigger(),r,Condition(function IndexEnum))
set r=null
loop
call GroupEnumUnitsOfPlayer(g,Player(n),Condition(function IndexEnum))
//Enum every non-filtered unit on the map during initialization and assign it a unique
//index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
exitwhen n==0
set n=n-1
endloop
call DestroyGroup(g)
set g=null
call TimerStart(CreateTimer(),PERIOD,true,function PeriodicRecycler)
endfunction
//==============================================================================
public struct DEFAULT extends array
method AIDS_onCreate takes nothing returns nothing
endmethod
method AIDS_onDestroy takes nothing returns nothing
endmethod
static method AIDS_filter takes unit u returns boolean
return UnitIndexingFilter(u)
endmethod
static method AIDS_onInit takes nothing returns nothing
endmethod
endstruct
//===========================================================================
// Never create or destroy AIDS structs directly.
// Also, do not initialise members except by using the AIDS_onCreate method.
//===========================================================================
//! textmacro AIDS
// This magic line makes default methods get called which do nothing
// if the method are otherwise undefined.
private static delegate AIDS_DEFAULT AIDS_DELEGATE=0
//-----------------------------------------------------------------------
// Gotta know whether or not to destroy on deallocation...
private boolean AIDS_instanciated
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns thistype
return GetUnitId(whichUnit)
endmethod
method operator unit takes nothing returns unit
// Allows structVar.unit to return the unit.
return GetIndexUnit(this)
endmethod
//-----------------------------------------------------------------------
method AIDS_addLock takes nothing returns nothing
call AIDS_AddLock(this)
endmethod
method AIDS_removeLock takes nothing returns nothing
call AIDS_RemoveLock(this)
endmethod
//-----------------------------------------------------------------------
private static method AIDS_onEnter takes nothing returns boolean
// At this point, the unit might not have been assigned an index.
if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
// Flag it for destruction on deallocation.
set thistype(AIDS_GetIndexOfEnteringUnit()).AIDS_instanciated=true
// Can use inlining "Assigned" function now, as it must be assigned.
call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
endif
return false
endmethod
private static method AIDS_onEnterAllocated takes nothing returns boolean
// At this point, the unit must have been assigned an index.
if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
// Flag it for destruction on deallocation. Slightly faster!
set thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_instanciated=true
// Can use inlining "Assigned" function now, as it must be assigned.
call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
endif
return false
endmethod
private static method AIDS_onDeallocate takes nothing returns boolean
if thistype(AIDS_GetDecayingIndex()).AIDS_instanciated then
call thistype(AIDS_GetDecayingIndex()).AIDS_onDestroy()
// Unflag destruction on deallocation.
set thistype(AIDS_GetDecayingIndex()).AIDS_instanciated=false
endif
return false
endmethod
//-----------------------------------------------------------------------
private static method onInit takes nothing returns nothing
call AIDS_RegisterOnEnter(Condition(function thistype.AIDS_onEnter))
call AIDS_RegisterOnEnterAllocated(Condition(function thistype.AIDS_onEnterAllocated))
call AIDS_RegisterOnDeallocate(Condition(function thistype.AIDS_onDeallocate))
// Because I robbed you of your struct's onInit method.
call thistype.AIDS_onInit()
endmethod
//! endtextmacro
endlibrary
library PUI uses AIDS
//===========================================================================
// 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 = GetUnitId(whichUnit) // Changed from GetUnitIndex.
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 = GetUnitId(whichUnit) // Changed from GetUnitIndex.
// Switched the next two lines for optimisation.
if .pui_unit[pui] != whichUnit then
if .pui_data[pui] != 0 then
// recycled index 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
endlibrary
library AutoIndex uses AIDS
module AutoData
private static thistype array data
// Fixed up the below to use thsitype instead of integer.
static method operator []= takes unit u, thistype i returns nothing
set .data[GetUnitId(u)] = i //Just attaching a struct to the unit
endmethod //using the module's thistype array.
static method operator [] takes unit u returns thistype
return .data[GetUnitId(u)] //Just returning the attached struct.
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~ Event ~~ By Jesus4Lyf ~~ Version 1.02 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Event?
// - Event simulates Warcraft III events. They can be created,
// registered for, fired and also destroyed.
// - Event, therefore, can also be used like a trigger "group".
// - This was created when there was an influx of event style systems
// emerging that could really benefit from a standardised custom
// events snippet. Many users were trying to achieve the same thing
// and making the same kind of errors. This snippet aims to solve that.
//
// Functions:
// - Event.create() --> Creates a new Event.
// - .chainDestroy() --> Destroys an Event.
// DO NOT use .destroy().
// - .fire() --> Fires all triggers which have been
// registered on this Event.
// - .register(trigger) --> Registers another trigger on this Event.
//
// Details:
// - Event is extremely efficient and lightweight.
// - It is safe to use with dynamic triggers.
// - Internally, it is just a singularly linked list. Very simple.
//
// How to import:
// - Create a trigger named Event.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Builder Bob for the trigger destroy detection method.
// - Azlier for inspiring this by ripping off my dodgier code.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Event
///////////////
// EventRegs //
////////////////////////////////////////////////////////////////////////////
// For reading this far, you can learn one thing more.
// Unlike normal Warcraft III events, you can attach to Event registries.
//
// Event Registries are registrations of one trigger on one event.
// These cannot be created or destroyed, just attached to.
//
// It is VERY efficient for loading and saving data.
//
// Functions:
// - set eventReg.data = someStruct --> Store data.
// - eventReg.data --> Retreive data.
// - Event.getTriggeringEventReg() --> Get the triggering EventReg.
//
struct EventReg
integer data
method clear takes nothing returns nothing
set this.data=0
endmethod
endstruct
struct Event
private trigger trig
private Event next
static method create takes nothing returns Event
local Event this=Event.allocate()
set this.next=0
return this
endmethod
private static Event current
static method getTriggeringEventReg takes nothing returns EventReg
return .current
endmethod
private static trigger t
method fire takes nothing returns nothing
// this = last.
loop
set .current=this.next
exitwhen .current==0
set .t=.current.trig
if IsTriggerEnabled(.t) then
if TriggerEvaluate(.t) then
call TriggerExecute(.t)
endif
set this=.current
else
call EnableTrigger(.t) // Was trigger destroyed?
if IsTriggerEnabled(.t) then
call DisableTrigger(.t)
set this=.current
else // If trigger destroyed...
set .current.trig=null
set this.next=.current.next
call .current.destroy()
endif
endif
endloop
endmethod
method register takes trigger t returns EventReg
local Event new=Event.allocate()
set new.next=this.next
set new.trig=t
set this.next=new
call EventReg(new).clear()
return new
endmethod
method chainDestroy takes nothing returns nothing
loop
call this.destroy()
set this=this.next
exitwhen this==0
set this.trig=null
endloop
endmethod
endstruct
/////////////////////////////////////////////////////
// Demonstration Functions & Alternative Interface //
////////////////////////////////////////////////////////////////////////////
// What this would look like in normal WC3 style JASS (should all inline).
//
function CreateEvent takes nothing returns Event
return Event.create()
endfunction
function DestroyEvent takes Event whichEvent returns nothing
call whichEvent.chainDestroy()
endfunction
function FireEvent takes Event whichEvent returns nothing
call whichEvent.fire()
endfunction
function TriggerRegisterEvent takes trigger whichTrigger, Event whichEvent returns EventReg
return whichEvent.register(whichTrigger)
endfunction
// And for EventRegs...
function SetEventRegData takes EventReg whichEventReg, integer data returns nothing
set whichEventReg.data=data
endfunction
function GetEventRegData takes EventReg whichEventReg returns integer
return whichEventReg.data
endfunction
function GetTriggeringEventReg takes nothing returns integer
return Event.getTriggeringEventReg()
endfunction
endlibrary
//TESH.scrollpos=27
//TESH.alwaysfold=0
//
// ___ _ __ __ _ ___ ____ _______________________________
// | \ /_\ / |/ | /_\ / _\| __| || D E A L I T , ||
// | |) / _ \ / / | / |/ _ \| |/|| __| || D E T E C T I T , ||
// |___/_/ \_/_/|__/|_|_/ \_\___/|____| || B L O C K I T . ||
// By Jesus4Lyf ———————————————————————————————
// v 1.0.1
// What is Damage?
// —————————————————
// Damage is a damage dealing, detection and blocking system. It implements
// all such functionality. It also provides a means to detect what type
// of damage was dealt, so long as all damage in your map is dealt using
// this system's deal damage functions (except for basic attacks).
//
// It is completely recursively defined, meaning if you deal damage on
// taking damage, the type detection and other features like blocking
// will not malfunction.
//
// How to implement?
// ———————————————————
// Create a new trigger object called Damage, go to 'Edit -> Convert to
// Custom Text', and replace everything that's there with this script.
//
// At the top of the script, there is a '//! external ObjectMerger' line.
// Save your map, close your map, reopen your map, and then comment out this
// line. Damage is now implemented. This line creates a dummy ability used
// in the system in some circumstances with damage blocking.
//
// Functions:
// ————————————
// function Damage_RegisterEvent takes trigger whichTrigger returns nothing
// - This registers a special "any unit takes damage" event.
// - This event supports dynamic trigger use.
// - Only triggers registered on this event may block damage.
//
// function Damage_GetType takes nothing returns damagetype
// - This will get the type of damage dealt, like an event response,
// for when using a unit takes damage event (or the special event above).
//
// function Damage_Block takes real amount returns nothing
// function Damage_BlockAll takes nothing returns nothing
// - For use only with Damage_RegisterEvent.
// - Blocks 'amount' of the damage dealt.
// - Multiple blocks at once work correctly.
// - Blocking more than 100% of the damage will block 100% instead.
// - Damage_BlockAll blocks 100% of the damage being dealt.
//
// function Damage_EnableEvent takes boolean enable returns nothing
// - For disabling and re-enabling the special event.
// - Use it to deal damage which you do not want to be detected by
// the special event.
//
// function UnitDamageTargetEx takes lots of things returns boolean
// - Replaces UnitDamageTarget in your map, with the same arguments.
//
// function Damage_Physical takes unit source, unit target, real amount,
// attacktype whichType, boolean attack, boolean ranged returns boolean
// - A clean wrapper for physical damage.
// - 'attack' determines if this is to be treated as a real physical
// attack or just physical type damage.
// - 'ranged' determines if this is to be treated as a ranged or melee
// attack.
//
// function Damage_Spell takes unit source, unit target, real amount returns boolean
// - A clean wrapper for spell damage.
//
// function Damage_Pure takes unit source, unit target, real amount returns boolean
// - A clean wrapper for pure type damage (universal type, 100% damage).
//
// Thanks:
// —————————
// - Romek, for helping me find a better way to think about damage blocking.
//
library Damage initializer OnInit uses AIDS, Event
//============================================================
////! external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Damage System)" Ilif 1 500000 aite 0
globals
private constant integer LIFE_BONUS_ABIL='dprv'
endglobals
//============================================================
globals
private Event OnDamageEvent
private boolean EventEnabled=true
endglobals
public function RegisterEvent takes trigger whichTrigger returns nothing
call OnDamageEvent.register(whichTrigger)
endfunction
public function EnableEvent takes boolean enable returns nothing
set EventEnabled=enable
endfunction
//============================================================
globals
private integer TypeStackLevel=0
private damagetype array TypeStackValue
private real array ToBlock
endglobals
public function GetType takes nothing returns damagetype
return TypeStackValue[TypeStackLevel]
endfunction
public function Block takes real amount returns nothing
set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+amount
endfunction
public function BlockAll takes nothing returns nothing
set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+GetEventDamage()
endfunction
//============================================================
globals
private integer BlockNum=0
private unit array BlockUnit
private real array BlockUnitLife
private real array BlockRedamage
private unit array BlockDamageSource
private timer BlockTimer=CreateTimer()
endglobals
//============================================================
globals
private unit array RemoveBoosted
private integer RemoveBoostedMax=0
private timer RemoveBoostedTimer=CreateTimer()
endglobals
globals//locals
private real BoostedLifeTemp
private unit BoostedLifeUnit
endglobals
private function RemoveBoostedTimerFunc takes nothing returns nothing
loop
exitwhen RemoveBoostedMax==0
set BoostedLifeUnit=RemoveBoosted[RemoveBoostedMax]
set BoostedLifeTemp=GetWidgetLife(BoostedLifeUnit)
call UnitRemoveAbility(BoostedLifeUnit,LIFE_BONUS_ABIL)
if BoostedLifeTemp>0.405 then
call SetWidgetLife(BoostedLifeUnit,BoostedLifeTemp)
endif
set RemoveBoostedMax=RemoveBoostedMax-1
endloop
endfunction
//============================================================
private keyword Detector // Darn, I actually had to do this. XD
globals//locals
private unit ForUnit
private real NextHealth
endglobals
private function OnDamageActions takes nothing returns boolean
if EventEnabled then
call OnDamageEvent.fire()
endif
if ToBlock[TypeStackLevel]!=0. then
//====================================================
// Blocking
set ForUnit=GetTriggerUnit()
set NextHealth=GetEventDamage()
if ToBlock[TypeStackLevel]>=NextHealth then
set NextHealth=GetWidgetLife(ForUnit)+NextHealth
else
set NextHealth=GetWidgetLife(ForUnit)+ToBlock[TypeStackLevel]
endif
call SetWidgetLife(ForUnit,NextHealth)
if GetWidgetLife(ForUnit)<NextHealth then
// NextHealth is over max health.
call UnitAddAbility(ForUnit,LIFE_BONUS_ABIL)
call SetWidgetLife(ForUnit,NextHealth)
set RemoveBoostedMax=RemoveBoostedMax+1
set RemoveBoosted[RemoveBoostedMax]=ForUnit
call ResumeTimer(RemoveBoostedTimer)
endif
//====================================================
set ToBlock[TypeStackLevel]=0.
endif
return false
endfunction
//============================================================
function UnitDamageTargetEx takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
local boolean result
set TypeStackLevel=TypeStackLevel+1
set TypeStackValue[TypeStackLevel]=damageType
set result=UnitDamageTarget(whichUnit,target,amount,attack,ranged,attackType,damageType,weaponType)
set TypeStackLevel=TypeStackLevel-1
return result
endfunction
//! textmacro Damage__DealTypeFunc takes NAME, TYPE
public function $NAME$ takes unit source, unit target, real amount returns boolean
return UnitDamageTargetEx(source,target,amount,false,false,ATTACK_TYPE_NORMAL,$TYPE$,WEAPON_TYPE_WHOKNOWS)
endfunction
//! endtextmacro
//! runtextmacro Damage__DealTypeFunc("Pure","DAMAGE_TYPE_UNIVERSAL")
//! runtextmacro Damage__DealTypeFunc("Spell","DAMAGE_TYPE_MAGIC")
// Uses different stuff, but works much the same way.
public function Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
return UnitDamageTargetEx(source,target,amount,attack,ranged,whichType,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endfunction
//============================================================
private struct Detector extends array // Uses AIDS.
//! runtextmacro AIDS()
private static conditionfunc ACTIONS_COND
private trigger t
private method AIDS_onCreate takes nothing returns nothing
set this.t=CreateTrigger()
call TriggerAddCondition(this.t,thistype.ACTIONS_COND)
call TriggerRegisterUnitEvent(this.t,this.unit,EVENT_UNIT_DAMAGED)
endmethod
private method AIDS_onDestroy takes nothing returns nothing
call DestroyTrigger(this.t)
endmethod
private static method AIDS_onInit takes nothing returns nothing
set thistype.ACTIONS_COND=Condition(function OnDamageActions)
endmethod
endstruct
//============================================================
private function OnInit takes nothing returns nothing
local unit abilpreload=CreateUnit(Player(15),'uloc',0,0,0)
call UnitAddAbility(abilpreload,LIFE_BONUS_ABIL)
call RemoveUnit(abilpreload)
set abilpreload=null
set OnDamageEvent=Event.create()
set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
local texttag te = CreateTextTag()
call SetTextTagText(te, I2S(R2I(dps))+"!", 0.024)
call SetTextTagPos(te, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagColor(te, 255, 0, 0, 255)
call SetTextTagVelocity(te, 0, 0.04)
call SetTextTagVisibility(te, true)
call SetTextTagFadepoint(te, 2)
call SetTextTagLifespan(te, 5)
call SetTextTagPermanent(te, false)
set te = null
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CastSpellSystem initializer InitTrig_Cast_Spell_System
private function Conditions takes nothing returns boolean
if GetUnitTypeId(GetTriggerUnit()) == 'H00N' then
return true
endif
return GetUnitAbilityLevel(GetTriggerUnit(), 'Aloc') <= 0 and not (GetSpellAbilityId() == 'A04P') and not (GetSpellAbilityId() == 'A04O') and not (GetSpellAbilityId() == 'A04M')
endfunction
private function Actions takes nothing returns nothing
local texttag te = CreateTextTag()
local string n = GetObjectName(GetSpellAbilityId())
call SetTextTagText(te, n +"!", 0.024)
call SetTextTagPos(te, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), 0.00)
call SetTextTagColor(te, 255, 0, 0, 255)
call SetTextTagVelocity(te, 0, 0.04)
call SetTextTagVisibility(te, true)
call SetTextTagFadepoint(te, 2)
call SetTextTagLifespan(te, 5)
call SetTextTagPermanent(te, false)
set te = null
endfunction
//===========================================================================
private function InitTrig_Cast_Spell_System takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=20
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'e000'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
//TESH.scrollpos=164
//TESH.alwaysfold=0
library xedamage initializer init requires xebasic
//************************************************************************
// xedamage 0.8
// --------
// For all your damage and targetting needs.
//
//************************************************************************
//===========================================================================================================
globals
private constant integer MAX_SUB_OPTIONS = 3
private constant real FACTOR_TEST_DAMAGE = 0.01
// a low damage to do on units to test their damage factors for specific
// attacktype/damagetype combos.
// You'll need something as high as 20.0 to make it work well with armor resistances.
// (Yes, you read it correctly, 20 ...
//
// If you use such a large value, there may be conflicts with some things relying on damage
// (ie they are not away of the isDummyDamage tag that xedamage posseses.) which may be quite bad if you think about it...
// then maybe it is better to change it to 0.01 ... then will work fine, just fine - but it will generally ignore armor -
// I am leaving it as 0.01 by default, because honestly, I'd rather make it ignore armor than have a lot of people sending me
// rants about how they detect 20.0 damage where none is visible...
private constant real MAX_DAMAGE_FACTOR = 3.00
// The maximum damage factor in the map. I think 3 is fine.
//=======================================================
private constant real EPSILON = 0.000000001
private unit dmger
private constant integer MAX_SPACE = 8190 // MAX_SPACE/MAX_SUB_OPTIONS is the instance limit for xedamage, usually big enough...
endglobals
private keyword structInit
struct xedamage[MAX_SPACE]
//----
// fields and methods for a xedamage object, they aid determining valid targets and special
// damage factor conditions.
//
// Notice the default values.
//
boolean damageSelf = false // the damage and factor methods usually have a source unit parameter
// xedamage would consider this unit as immune unless you set damageSelf to true
boolean damageAllies = false // Alliance dependent target options.
boolean damageEnemies = true // *
boolean damageNeutral = true // *
boolean ranged = true // Is the attack ranged? This has some effect on the AI of the affected units
// true by default, you may not really need to modify this.
boolean visibleOnly = false // Should only units that are visible for source unit's owner be affected?
boolean deadOnly = false // Should only corpses be affected by "the damage"? (useful when using xedamage as a target selector)
boolean alsoDead = false // Should even corpses and alive units be considered?
boolean damageTrees = false //Also damage destructables? Notice this is used only in certain methods.
//AOE for example targets a circle, so it can affect the destructables
//in that circle, a custom spell using xedamage for targetting configuration
//could also have an if-then-else implemented so it can verify if it is true
//then affect trees manually.
//
// Damage type stuff:
// .dtype : the "damagetype" , determines if the spell is physical, magical or ultimate.
// .atype : the "attacktype" , deals with armor.
// .wtype : the "weapontype" , determines the sound effect to be played when damage is done.
//
// Please use common.j/blizzard.j/ some guide to know what damage/attack/weapon types can be used
//
damagetype dtype = DAMAGE_TYPE_UNIVERSAL
attacktype atype = ATTACK_TYPE_NORMAL
weapontype wtype = WEAPON_TYPE_WHOKNOWS
//
// Damage type 'tag' people might use xedamage.isInUse() to detect xedamage usage, there are other static
// variables like xedamage.CurrentDamageType and xedamage.CurrentDamageTag. The tag allows you to specify
// a custom id for the damage type ** Notice the tag would aid you for some spell stuff, for example,
// you can use it in a way similar to Rising_Dusk's damage system.
//
integer tag = 0
//
// if true, forceDamage will make xedamage ignore dtype and atype and try as hard as possible to deal 100%
// damage.
boolean forceDamage = false
//
// Ally factor! Certain spells probably have double purposes and heal allies while harming enemies. This
// field allows you to do such thing.
//
real allyfactor = 1.0
//
// field: .exception = SOME_UNIT_TYPE
// This field adds an exception unittype (classification), if the unit belongs to this unittype it will
// be ignored.
//
method operator exception= takes unittype ut returns nothing
set this.use_ex=true
set this.ex_ut=ut
endmethod
//
// field: .required = SOME_UNIT_TYPE
// This field adds a required unittype (classification), if the unit does not belong to this unittype
// it will be ignored.
//
method operator required= takes unittype ut returns nothing
set this.use_req=true
set this.req_ut=ut
endmethod
private boolean use_ex = false
private unittype ex_ut = null
private boolean use_req = false
private unittype req_ut = null
private unittype array fct[MAX_SUB_OPTIONS]
private real array fc[MAX_SUB_OPTIONS]
private integer fcn=0
//
// method .factor(SOME_UNIT_TYPE, factor)
// You might call factor() if you wish to specify a special damage factor for a certain classification,
// for example call d.factor(UNIT_TYPE_STRUCTURE, 0.5) makes xedamage do half damage to structures.
//
method factor takes unittype ut, real fc returns nothing
if(this.fcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to factor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of factor() calls")
return
endif
set this.fct[this.fcn] = ut
set this.fc[this.fcn] = fc
set this.fcn = this.fcn+1
endmethod
private integer array abifct[MAX_SUB_OPTIONS]
private real array abifc[MAX_SUB_OPTIONS]
private integer abifcn=0
//
// method .abilityFactor('abil', factor)
// You might call abilityFactor() if you wish to specify a special damage factor for units that have a
// certain ability/buff.
// for example call d.abilityFactor('A000', 1.5 ) makes units that have the A000 ability take 50% more
// damage than usual.
//
method abilityFactor takes integer abilityId, real fc returns nothing
if(this.abifcn==MAX_SUB_OPTIONS) then
debug call BJDebugMsg("In one instance of xedamage, you are doing too much calls to abilityFactor(), please increase MAX_SUB_OPTIONS to allow more, or cut the number of abilityFactor() calls")
return
endif
set this.abifct[this.abifcn] = abilityId
set this.abifc[this.abifcn] = fc
set this.abifcn = this.abifcn+1
endmethod
private boolean usefx = false
private string fxpath
private string fxattach
//
// method .useSpecialEffect("effect\\path.mdl", "origin")
// Makes it add (and destroy) an effect when damage is performed.
//
method useSpecialEffect takes string path, string attach returns nothing
set this.usefx = true
set this.fxpath=path
set this.fxattach=attach
endmethod
//********************************************************************
//* Now, the usage stuff:
//*
//================================================================================
// static method xedamage.isInUse() will return true during a unit damaged
// event in case this damage was caused by xedamage, in this case, you can
// read variables like CurrentDamageType, CurrentAttackType and CurrentDamageTag
// to be able to recognize what sort of damage was done.
//
readonly static damagetype CurrentDamageType=null
readonly static attacktype CurrentAttackType=null
readonly static integer CurrentDamageTag =0
private static integer inUse = 0
static method isInUse takes nothing returns boolean
return (inUse>0) //inline friendly.
endmethod
readonly static boolean isDummyDamage = false
//========================================================================================================
// This function calculates the damage factor caused by a certain attack and damage
// type, it is static : xedamage.getDamageTypeFactor(someunit, ATTAcK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, 100)
//
static method getDamageTypeFactor takes unit u, attacktype a, damagetype d returns real
local real hp=GetWidgetLife(u)
local real mana=GetUnitState(u,UNIT_STATE_MANA)
local real r
local real fc = FACTOR_TEST_DAMAGE
//Since a unit is in that point, we don't need checks.
call SetUnitX(dmger,GetUnitX(u))
call SetUnitY(dmger,GetUnitY(u))
call SetUnitOwner(dmger,GetOwningPlayer(u),false)
set r=hp
if (hp< FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR) then
call SetWidgetLife(u, hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR )
set r = hp + FACTOR_TEST_DAMAGE*MAX_DAMAGE_FACTOR
set fc = GetWidgetLife(u)-hp + EPSILON
endif
set isDummyDamage = true
call UnitDamageTarget(dmger,u, fc ,false,false,a,d,null)
static if DEBUG_MODE then
if IsUnitType(u, UNIT_TYPE_DEAD) and (hp>0.405) then
call BJDebugMsg("xedamage: For some reason, the unit being tested by getDamageTypeFactor has died. Verify MAX_DAMAGE_FACTOR is set to a correct value. ")
endif
endif
set isDummyDamage = false
call SetUnitOwner(dmger,Player(15),false)
if (mana>GetUnitState(u,UNIT_STATE_MANA)) then
//Unit had mana shield, return 1 and restore mana too.
call SetUnitState(u,UNIT_STATE_MANA,mana)
set r=1
else
set r= (r-GetWidgetLife(u)) / fc
endif
call SetWidgetLife(u,hp)
return r
endmethod
private method getTargetFactorCore takes unit source, unit target, boolean usetypes returns real
local player p=GetOwningPlayer(source)
local boolean allied=IsUnitAlly(target,p)
local boolean enemy =IsUnitEnemy(target,p)
local boolean neutral=allied
local real f
local real negf=1.0
local integer i
if(this.damageAllies != this.damageNeutral) then
set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_REQUEST ))
//I thought accuracy was not as important as speed , I think that REQUEST is false is enough to consider
// it neutral.
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_HELP_RESPONSE ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_XP ))
//set neutral= allied and not (GetPlayerAlliance(GetOwningPlayer(target),p, ALLIANCE_SHARED_SPELLS ))
set allied= allied and not(neutral)
endif
if (not this.damageAllies) and allied then
return 0.0
elseif (not this.damageEnemies) and enemy then
return 0.0
elseif( (not this.damageSelf) and (source==target) ) then
return 0.0
elseif (not this.damageNeutral) and neutral then
return 0.0
elseif( this.use_ex and IsUnitType(target, this.ex_ut) ) then
return 0.0
elseif( this.visibleOnly and not IsUnitVisible(target,p) ) then
return 0.0
elseif ( this.deadOnly and not IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
elseif ( not(this.alsoDead) and IsUnitType(target,UNIT_TYPE_DEAD) ) then
return 0.0
endif
set f=1.0
if ( IsUnitAlly(target,p) ) then
set f=f*this.allyfactor
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
if (this.use_req and not IsUnitType(target,this.req_ut)) then
return 0.0
endif
set i=.fcn-1
loop
exitwhen (i<0)
if( IsUnitType(target, this.fct[i] ) ) then
set f=f*this.fc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set i=.abifcn-1
loop
exitwhen (i<0)
if( GetUnitAbilityLevel(target,this.abifct[i] )>0 ) then
set f=f*this.abifc[i]
if(f<=-EPSILON) then
set f=-f
set negf=-1.0
endif
endif
set i=i-1
endloop
set f=f*negf
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
if( this.forceDamage or not usetypes ) then
return f
endif
set f=f*xedamage.getDamageTypeFactor(target,this.atype,this.dtype)
if ( f<EPSILON) and (f>-EPSILON) then
return 0.0
endif
return f
endmethod
//====================================================================
// With this you might decide if a unit is a valid target for a spell.
//
method getTargetFactor takes unit source, unit target returns real
return this.getTargetFactorCore(source,target,true)
endmethod
//======================================================================
// a little better, I guess
//
method allowedTarget takes unit source, unit target returns boolean
return (this.getTargetFactorCore(source,target,false)!=0.0)
endmethod
//=======================================================================
// performs damage to the target unit, for unit 'source'.
//
method damageTarget takes unit source, unit target, real damage returns boolean
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local real f = this.getTargetFactorCore(source,target,false)
local real pl
if(f!=0.0) then
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set pl=GetWidgetLife(target)
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
if(pl != GetWidgetLife(target) ) then
if(usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
return true
endif
endif
return false
endmethod
//=======================================================================================
// The same as damageTarget, but it forces a specific damage value, good if you already
// know the target.
//
method damageTargetForceValue takes unit source, unit target, real damage returns nothing
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
if( usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
set .inUse = .inUse +1
call UnitDamageTarget(source,target, damage, true, .ranged, null, null, .wtype )
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
endmethod
//=====================================================================================
// Notice: this will not Destroy the group, but it will certainly empty the group.
//
method damageGroup takes unit source, group targetGroup, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
local unit target
local real f
local integer count=0
local real hp
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
loop
set target=FirstOfGroup(targetGroup)
exitwhen (target==null)
call GroupRemoveUnit(targetGroup,target)
set f= this.getTargetFactorCore(source,target,false)
if (f!=0.0) then
set count=count+1
if(usefx) then
set hp = GetWidgetLife(target)
endif
call UnitDamageTarget(source,target, f*damage, true, .ranged, .atype, .dtype, .wtype )
if(usefx and (hp > GetWidgetLife(target)) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
endloop
set .inUse = .inUse -1
set .CurrentDamageTag=tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return count
endmethod
private static xedamage instance
private integer countAOE
private unit sourceAOE
private real AOEx
private real AOEy
private real AOEradius
private real AOEdamage
private static boolexpr filterAOE
private static boolexpr filterDestAOE
private static group enumgroup
private static rect AOERect
private static method damageAOE_Enum takes nothing returns boolean
local unit target=GetFilterUnit()
local xedamage this=.instance //adopting a instance.
local real f
local real hp
if( not IsUnitInRangeXY(target,.AOEx, .AOEy, .AOEradius) ) then
set target=null
return false
endif
set f=.getTargetFactorCore(.sourceAOE, target, false)
if(f!=0.0) then
set .countAOE=.countAOE+1
if(this.usefx) then
set hp =GetWidgetLife(target)
endif
call UnitDamageTarget(.sourceAOE,target, f*this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
if(this.usefx and (hp > GetWidgetLife(target) ) ) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
endif
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
private static method damageAOE_DestructablesEnum takes nothing returns boolean
local destructable target=GetFilterDestructable()
local xedamage this=.instance //adopting a instance.
local real dx=.AOEx-GetDestructableX(target)
local real dy=.AOEy-GetDestructableY(target)
if( dx*dx + dy*dy >= .AOEradius+EPSILON ) then
set target=null
return false
endif
set .countAOE=.countAOE+1
if(.usefx) then
call DestroyEffect( AddSpecialEffectTarget(this.fxpath, target, this.fxattach) )
endif
call UnitDamageTarget(.sourceAOE,target, this.AOEdamage, true, .ranged, .atype, .dtype, .wtype )
set .instance= this //better restore, nesting IS possible!
set target=null
return false
endmethod
//==========================================================================================
// will affect trees if damageTrees is true!
//
method damageAOE takes unit source, real x, real y, real radius, real damage returns integer
local damagetype dt=.CurrentDamageType
local attacktype at=.CurrentAttackType
local integer tg=.CurrentDamageTag
set .CurrentDamageType = .dtype
set .CurrentAttackType = .atype
set .CurrentDamageTag = .tag
set .inUse = .inUse +1
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius
set .AOEy=y
set .AOEdamage=damage
call GroupEnumUnitsInRange(.enumgroup,x,y,radius+XE_MAX_COLLISION_SIZE, .filterAOE)
if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
set .AOEradius=.AOEradius*.AOEradius
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
endif
set .inUse = .inUse -1
set .CurrentDamageTag = tg
set .CurrentDamageType = dt
set .CurrentAttackType = at
return .countAOE
endmethod
method damageAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageAOE(source, GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//==========================================================================================
// only affects trees, ignores damageTrees
//
method damageDestructablesAOE takes unit source, real x, real y, real radius, real damage returns integer
set .instance=this
set .countAOE=0
set .sourceAOE=source
set .AOEx=x
set .AOEradius=radius*radius
set .AOEy=y
set .AOEdamage=damage
//if(.damageTrees) then
call SetRect(.AOERect, x-radius, y-radius, x+radius, y+radius)
call EnumDestructablesInRect(.AOERect, .filterDestAOE, null)
//endif
return .countAOE
endmethod
method damageDestructablesAOELoc takes unit source, location loc, real radius, real damage returns integer
return .damageDestructablesAOE(source,GetLocationX(loc), GetLocationY(loc), radius, damage)
endmethod
//'friend' with the library init
static method structInit takes nothing returns nothing
set .AOERect= Rect(0,0,0,0)
set .filterAOE= Condition(function xedamage.damageAOE_Enum)
set .filterDestAOE = Condition( function xedamage.damageAOE_DestructablesEnum)
set .enumgroup = CreateGroup()
endmethod
endstruct
private function init takes nothing returns nothing
set dmger=CreateUnit(Player(15), XE_DUMMY_UNITID , 0.,0.,0.)
call UnitAddAbility(dmger,'Aloc')
call xedamage.structInit()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***********************************************************************************
//* By Kingz: *
//* Basic Stuff Library *
//* A library i made to speed up my coding of the submision *
//* Contains several usefull functions and several functions i use *
//* are simmilar to existing ones. *
//* Also contains the Max/Min values of the maps X/Y which are used as boundaries *
//* Used in all of the spells in this submision to provide easier coding *
//***********************************************************************************
library MathBasic initializer XY
globals
real MaxX // used for the maps Max X
real MaxY // used for the maps Max Y
real MinX // used for the maps Min X
real MinY // used for the maps Min Y
private constant real OffsetAngle = 0 // used for the Z facing function but is model based,for this model the value is 0
endglobals
//parabola function for the missile - Credits go to Moyack
constant function ParabolaZ takes real h,real d,real cd returns real
return (4*h / d)*(d - cd)*(cd / d)
endfunction
//when you need that extra true
constant function dummyFilter takes nothing returns boolean
return true
endfunction
//polar projection x
function PPX takes real x,real dist,real rad returns real
return x + dist * Cos(rad)
endfunction
//polar projection y
function PPY takes real y,real dist,real rad returns real
return y + dist * Sin(rad)
endfunction
//radian between locations
function RBL takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2 - y1, x2 - x1)
endfunction
//distance between locations
function DBL takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))
endfunction
// used for dummy unit z facings
function SetUnitZFacing takes unit whichUnit, real facingAngle returns nothing
local integer i = R2I((facingAngle+OffsetAngle)*0.7+0.5)
if i>0 then
call SetUnitAnimationByIndex(whichUnit, i)
else
call SetUnitAnimationByIndex(whichUnit, i+252)
endif
endfunction
//sets up the min/max X/Y values
function XY takes nothing returns nothing
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedFadeUnit
struct fade2
unit u
real per
real str
static thistype array index
static integer num = 0
static timer counter = CreateTimer()
static method CreateInstance takes nothing returns fade2
local fade2 this = fade2.allocate()
set fade2.index[fade2.num] = this
set fade2.num = fade2.num +1
return this
endmethod
static method onLoop takes nothing returns nothing
local fade2 this
local integer i = 0
loop
exitwhen i >= fade2.num
set this = fade2.index[i]
set this.per = this.per - this.str
call SetUnitVertexColor(this.u,255,255,255,R2I(this.per))
if this.per <= 0.00 then
call this.destroy()
set fade2.num = fade2.num - 1
set fade2.index[i] = fade2.index[num]
endif
set i = i+1
endloop
if fade2.num == 0 then
call PauseTimer(fade2.counter)
endif
endmethod
method onDestroy takes nothing returns nothing
call RemoveUnit(this.u)
set this.u = null
endmethod
endstruct
function FadeUnitTimed takes unit u, real timeout, real startper returns nothing
local fade2 this = fade2.CreateInstance()
set this.u = u
set this.per = (1.0 - startper) * 255
set this.str = (this.per / timeout) * 0.02
if fade2.num == 1 then
call TimerStart(fade2.counter,0.02,true,function fade2.onLoop)
endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedAnimationStop
struct animation2
unit u
real t
static thistype array ind
static integer num = 0
static timer timeout = CreateTimer()
method onDestroy takes nothing returns nothing
set this.u = null
endmethod
static method Create takes nothing returns animation2
local animation2 this = animation2.allocate()
set animation2.ind[num] = this
set animation2.num = animation2.num +1
return(this)
endmethod
static method StopAnimation2 takes nothing returns nothing
local animation2 this
local integer i = 0
loop
exitwhen i >= animation2.num
set this = animation2.ind[i]
set this.t = this.t - 0.02
if this.t <= 0.00 then
call PauseUnit(this.u,true)
call SetUnitTimeScale(this.u,0)
call this.destroy()
set animation2.num = animation2.num - 1
set animation2.ind[i] = animation2.ind[animation2.num]
endif
set i = i +1
endloop
if animation2.num == 0 then
call PauseTimer(animation2.timeout)
endif
endmethod
endstruct
function StopAnimationTimed takes unit u, real time returns nothing
local animation2 this = animation2.Create()
set this.u = u
set this.t = time
if animation2.num == 1 then
call TimerStart(animation2.timeout,0.02,true,function animation2.StopAnimation2)
endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***************************************************************************
//*
//* TimedHandles - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* Simply copy this script into your map, as well as TimerUtils.
//*
//***************************************************************************
//*
//* Documentation
//*
//* All this script does it associates a handle to a
//* timer and then destroys the handle upon the timer's expiration.
//*
//***************************************************************************
//*
//* The Public Functions
//*
//* $DESTROY$Timed - Starts the handle and it's timer, once it expires
//* the handle will be destroyed.
//*
//***************************************************************************
//*
//* Examples
//*
//* call DestroyEffectTimed(AddSpecialEffect("MODELNAME", X, X), 2)
//* call DestroyEffectTimed(AddSpecialEffectTarget("MODELNAME", unit, "attachment-point"), 2)
//*
//***************************************************************************
library TimedHandles requires TimerUtils
//! textmacro TIMEDHANDLES takes HANDLE,DESTROY
struct $HANDLE$timed
$HANDLE$ $HANDLE$_var
private static method remove takes nothing returns nothing
local timer t = GetExpiredTimer()
local $HANDLE$timed d = GetTimerData(t)
call $DESTROY$(d.$HANDLE$_var)
call ReleaseTimer(t)
call d.destroy()
endmethod
static method create takes $HANDLE$ h, real timeout returns $HANDLE$timed
local $HANDLE$timed t = $HANDLE$timed.allocate()
local timer ti = NewTimer()
set t.$HANDLE$_var = h
call SetTimerData(ti, t)
call TimerStart(ti, timeout, false, function $HANDLE$timed.remove)
return t
endmethod
endstruct
function $DESTROY$Timed takes $HANDLE$ h, real duration returns nothing
call $HANDLE$timed.create(h, duration)
endfunction
//! endtextmacro
//! runtextmacro TIMEDHANDLES("effect","DestroyEffect")
//! runtextmacro TIMEDHANDLES("lightning","DestroyLightning")
//! runtextmacro TIMEDHANDLES("weathereffect","RemoveWeatherEffect")
//! runtextmacro TIMEDHANDLES("item","RemoveItem")
//! runtextmacro TIMEDHANDLES("ubersplat","DestroyUbersplat")
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//a simple library which is used to inline GroupAddGroup() function
//made by Anachron
library Group2Group
globals
private group tmp = null
endglobals
private function addGroupUnit takes nothing returns nothing
call GroupAddUnit(tmp, GetEnumUnit())
endfunction
function Group2Group takes group src, group tar returns group
set tmp = tar
call ForGroup(src, function addGroupUnit)
return tar
endfunction
endlibrary
//TESH.scrollpos=88
//TESH.alwaysfold=0
library_once TimerUtils initializer redInit
//*********************************************************************
//* TimerUtils (Red flavor)
//* ----------
//*
//* 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=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Red flavor: Fastest, method in existence for timer attaching,
//* only takes an array lookup, H2I and subtraction.
//* However, all the code in your map requires extra care
//* not to forget to call ReleaseTimer. It also requires
//* to preload a lot of timers at map init, they use
//* memory and handle ids.
//*
//* I recommend you run your map in debug mode the first
//* time after adding it, make sure you can see map init messages
//* if nothing appears, all is done, if an error appears, it might
//* suggest you a value with OFFSET, in that case, update that value
//* if it still does not work after updating (rare), try a bigger
//* OFFSET by 1000 for example. (Sounds hard? Then use blue or purple
//* timerutils that are friendlier though not as fast)
//*
//********************************************************************
//================================================================
globals
private constant integer OFFSET = 0x100000
private constant integer QUANTITY = 1000
private constant integer ARRAY_SIZE = 8191 //changing this to a higher value would effectively
//cripple the performance making this thing irrelevant
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return GetHandleId( h )
endfunction
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
debug endif
set data[H2I(t)-OFFSET]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-OFFSET<0) then
debug call BJDebugMsg("GetTimerData: Wrong handle id, only use GetTimerData on timers created by NewTimer")
debug endif
return data[H2I(t)-OFFSET]
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 NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, please increase it for your map, fix your map's timer leaks or switch to blue flavor when applicable")
set tT[0]=CreateTimer()
if (H2I(tT[0])-OFFSET<0) or (H2I(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably switch to the blue flavor or fix timer leaks.")
return null
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==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: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function redInit takes nothing returns nothing
local integer i=0
local integer bestoffset=-1
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set bestoffset=H2I(tT[i])
endif
if (H2I(tT[i])-OFFSET>=ARRAY_SIZE) then
debug call BJDebugMsg("TimerUtils_redInit: Failed a initializing attempt")
debug call BJDebugMsg("The timer limit is "+I2S(i))
debug call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low, to change OFFSET to "+I2S(bestoffset) )
exitwhen true
endif
if (H2I(tT[i])-OFFSET>=0) then
set i=i+1
endif
endloop
set tN=i
endfunction
endlibrary
//TESH.scrollpos=28
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Heights
globals
private location loc = Location( 0.00, 0.00 )
endglobals
function GetFloorHeight takes real x, real y returns real
call MoveLocation( loc, x, y )
return GetLocationZ( loc )
endfunction
function GetUnitZ takes unit whichUnit returns real
local real z = ( GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ) + GetUnitFlyHeight( whichUnit ) )
set whichUnit = null
return z
endfunction
function SetUnitZ takes unit whichUnit, real z returns nothing
local boolean whichUnitHasNotAmrf = ( GetUnitAbilityLevel( whichUnit, 'Amrf' ) <= 0 ) and IsUnitType(whichUnit, UNIT_TYPE_FLYING) == false
if ( whichUnitHasNotAmrf ) then
call UnitAddAbility( whichUnit, 'Amrf' )
endif
call SetUnitFlyHeight( whichUnit, z - GetFloorHeight( GetUnitX( whichUnit ), GetUnitY( whichUnit ) ), 0.00 )
if ( whichUnitHasNotAmrf ) then
call UnitRemoveAbility( whichUnit, 'Amrf' )
endif
set whichUnit = null
endfunction
endlibrary
//TESH.scrollpos=12
//TESH.alwaysfold=0
// AutoFly - by Azlier
// Requires a vJass preprocessor
// How to import:
// 1. Create a new trigger called AutoFly.
// 2. Convert the trigger to custom script, and replace all the code inside with this.
library_once AutoFly
private function Actions takes nothing returns boolean
if UnitAddAbility(GetFilterUnit(), 'Amrf') then
call UnitRemoveAbility(GetFilterUnit(), 'Amrf')
endif
return false
endfunction
private struct Hack extends array
static method onInit takes nothing returns nothing
local region r = CreateRegion()
local rect re = GetWorldBounds()
local group g = CreateGroup()
local integer i = 15
call RegionAddRect(r, re)
call TriggerRegisterEnterRegion(CreateTrigger(), r, Filter(function Actions))
call RemoveRect(re)
set re = null
loop
call GroupEnumUnitsOfPlayer(g, Player(i), Filter(function Actions))
exitwhen i == 0
set i = i - 1
endloop
call DestroyGroup(g)
set g = null
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library xepreload initializer init requires xebasic
//************************************************************************
// xepreload 0.4
// ---------
// Ah, the joy of preloading abilities, it is such a necessary evil...
// Notice you are not supposed to use this system in places outside map init
//
// This one does the preloading and tries to minimize the hit on loading time
// for example, it only needs one single native call per ability preloaded.
//
//************************************************************************
//===========================================================================================================
globals
private unit dum=null
endglobals
//inline friendly
function XE_PreloadAbility takes integer abilid returns nothing
call UnitAddAbility(dum, abilid)
endfunction
private function kill takes nothing returns nothing
call RemoveUnit(dum)
set dum=null
call DestroyTimer(GetExpiredTimer()) //I do hope this doesn't trigger the apocallypse. I didn't think
// it was a great idea to make this require a whole timer recycling
// system, so, just destroy. Anyone got a better idea on how to make
// this execute after all the other calls at init?
endfunction
private function init takes nothing returns nothing
set dum=CreateUnit(Player(15),XE_DUMMY_UNITID, 0,0,0)
call TimerStart(CreateTimer(),0.0,false,function kill)
endfunction
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=42
//TESH.alwaysfold=0
scope Combo initializer InitTrig_Illusion_Slash
// SETTINGS
globals
private constant integer dummy_id = 'h007' // the ID of the dummy unit
private constant integer spell_id = 'A02T' // the ID of the spell
private constant real anim_delay = 1.25 // the delay before the dummy dies
private constant integer red = 100 // the color red of the dummy
private constant integer green = 100 // the color green of the dummy
private constant integer blue = 100 // the color blue of the dummy
private constant integer alpha = 75 // the color transparency of the dummy
private constant integer red_c = 255 // the color red of the caster
private constant integer green_c = 255 // the color green of the caster
private constant integer blue_c = 255 // the color blue of the caster
private constant integer alpha_c = 100 // the color transparency of the caster
private constant real tag_red = 100 // the text tag color : red
private constant real tag_green = 10 // the text tag color : green
private constant real tag_blue = 10 // the text tag color : blue
private constant string animation = "attack" // the animation the dummy will play
private constant boolean attack = true // is the spell a attack?
private constant boolean ranged = false // is the spell ranged?
private constant attacktype atk_type = ATTACK_TYPE_CHAOS // the attack type of the dummy damage
private constant damagetype dmg_type = DAMAGE_TYPE_NORMAL // the damage type of the dummy damage
private constant weapontype wep_type = WEAPON_TYPE_WHOKNOWS // the weapon type of the dummy damage
private constant boolean enable_texttag = true // if set to true, it will show the damage dealt by the dummy
private constant string special_effect = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"
private constant string attachment_point = "origin" // this is where the above special effect is placed
private real array extra_damage // set the extra damage bellow in function Settings
private integer array chance // set the chance bellow in function Settings
endglobals
function Settings takes nothing returns nothing
// set the chances:
set chance[1] = 15
set chance[2] = 20
set chance[3] = 25
set chance[4] = 30
// set the extra damage values
set extra_damage[1] = 100
set extra_damage[2] = 200
set extra_damage[3] = 300
set extra_damage[4] = 400
endfunction
// END OF SETTINGS
private function Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetAttacker(), spell_id ) >= 1
endfunction
private function Actions takes nothing returns nothing
local unit u = GetAttacker()
local unit t = GetTriggerUnit()
local unit dummy
local integer lvl = GetUnitAbilityLevel(u , spell_id)
local real dmg = extra_damage[lvl]
local real angle = GetUnitFacing(t) + 180
local player owner = GetOwningPlayer(u)
local location l = GetUnitLoc(u)
local location l2
local integer ch = GetRandomInt(1 , 100)
local texttag text
local real pos = 60.
local effect eff
if t == u then
set u = null
set t = null
set dummy = null
call RemoveLocation(l)
call RemoveLocation(l2)
set l = null
set l2 = null
return
else
// We call the chance function
call Settings()
if chance[lvl] >= ch then
set eff = AddSpecialEffectTarget(special_effect , u , attachment_point)
call SetUnitVertexColor(u, red_c , green_c, blue_c, alpha_c)
set dummy = CreateUnitAtLoc(owner, dummy_id , l , angle)
set l2 = GetUnitLoc(dummy)
call PauseUnit(dummy, true)
call SetUnitVertexColor(dummy , red , green, blue, alpha)
call SetUnitAnimation(dummy , animation)
if enable_texttag == true then
set text = CreateTextTagLocBJ( I2S(R2I(dmg))+"!" , l2, pos, 12, tag_red, tag_green, tag_blue, 0 )
call SetTextTagVelocityBJ( text, 60.00, 90 )
call SetTextTagPermanent( text, false )
call SetTextTagLifespan( text, 1)
call SetTextTagFadepoint( text, 0.1)
endif
call UnitDamageTarget(u, t, dmg, attack, ranged, atk_type , dmg_type , wep_type)
call TriggerSleepAction(anim_delay)
call RemoveUnit(dummy)
call DestroyEffect(eff)
call SetUnitVertexColor(u, 255 , 255, 255, 255)
endif
set u = null
set t = null
set dummy = null
call RemoveLocation(l)
call RemoveLocation(l2)
set l = null
set l2 = null
endif
endfunction
//===========================================================================
private function InitTrig_Illusion_Slash takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Arctic_Field_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00A'
endfunction
function Trig_Arctic_Field_Actions takes nothing returns nothing
call CreateNUnitsAtLoc( 1, 'nfrm', GetOwningPlayer(GetSpellAbilityUnit()), GetUnitLoc(GetSpellAbilityUnit()), bj_UNIT_FACING )
set udg_ice5 = GetLastCreatedUnit()
call CreateNUnitsAtLoc( 1, 'nfrm', GetOwningPlayer(GetSpellAbilityUnit()), PolarProjectionBJ(GetUnitLoc(GetSpellAbilityUnit()), 300.00, 90.00), bj_UNIT_FACING )
set udg_ice1 = GetLastCreatedUnit()
call CreateNUnitsAtLoc( 1, 'nfrm', GetOwningPlayer(GetSpellAbilityUnit()), PolarProjectionBJ(GetUnitLoc(GetSpellAbilityUnit()), 300.00, 270.00), bj_UNIT_FACING )
set udg_ice2 = GetLastCreatedUnit()
call CreateNUnitsAtLoc( 1, 'nfrm', GetOwningPlayer(GetSpellAbilityUnit()), PolarProjectionBJ(GetUnitLoc(GetSpellAbilityUnit()), 300.00, 360.00), bj_UNIT_FACING )
set udg_ice3 = GetLastCreatedUnit()
call CreateNUnitsAtLoc( 1, 'nfrm', GetOwningPlayer(GetSpellAbilityUnit()), PolarProjectionBJ(GetUnitLoc(GetSpellAbilityUnit()), 300.00, 180.00), bj_UNIT_FACING )
set udg_ice4 = GetLastCreatedUnit()
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', udg_ice5 )
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', udg_ice1 )
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', udg_ice2 )
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', udg_ice3 )
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', udg_ice4 )
endfunction
//===========================================================================
function InitTrig_Arctic_Field takes nothing returns nothing
set gg_trg_Arctic_Field = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Arctic_Field, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Arctic_Field, Condition( function Trig_Arctic_Field_Conditions ) )
call TriggerAddAction( gg_trg_Arctic_Field, function Trig_Arctic_Field_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LSLeo initializer InitTrig_Lightning_Strike
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00E'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit y = GetSpellTargetUnit()
local unit d
local real t = 0.25
local integer c = 17
call PlaySoundBJ( gg_snd_ShamanPissed1 )
loop
exitwhen c <= 0
// call AddSpecialEffectTarget( "war3mapImported\\Great Lightning.mdx", y, "origin" )
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h00J', GetUnitLoc(y), 0.00)
call IssueImmediateOrder(d, "stomp")
call UnitApplyTimedLife(d, 'BTLF', 2.00)
set c = c - 1
call TriggerSleepAction(t)
endloop
set u = null
set y = null
endfunction
//===========================================================================
private function InitTrig_Lightning_Strike takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=54
//TESH.alwaysfold=0
//=======================Insane Revenge=======================
//============================================================
//====================Made by: Mckill2009=====================
//============================================================
//====================Ideas by: Ironside======================
//===HOW TO USE:
//- Create a HASH variable in the trigger editor
//- Initialize the HASH
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- The trigger name MUST be >>> Insane Revenge (or you may change it as long as it matches InitTrig_NAME_OF_TRIGGER below
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//- The raw code of the spell MUST match the IR_SPELLID below
//============================================================
//=======================CONFIGURABLES========================
//============================================================
function IR_SPELLID takes nothing returns integer
return 'A00V' //To see the raw code press CTRL+B in the ability tab
endfunction
function IR_DURATION takes nothing returns real
return 4. //This is the duration of the spell
endfunction
function IR_TIMERSPEED takes nothing returns real
return 0.5 //This is the speed of the spell
endfunction
function IR_DAMAGE takes integer i returns real
return 50. + i * 25
endfunction
function IR_ATY takes nothing returns attacktype
return ATTACK_TYPE_CHAOS
endfunction
function IR_DAM takes nothing returns damagetype
return DAMAGE_TYPE_NORMAL
endfunction
function IR_SFX_MOONSOON takes nothing returns string
return "Abilities\\Spells\\Other\\Monsoon\\MonsoonBoltTarget.mdl" //You may configure youw own SFX
endfunction
function IR_SFX_TC takes nothing returns string
return "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl" //You may configure youw own SFX
endfunction
//============================================================
//====================END OF CONFIGURABLES====================
//============================================================
function IR_LOOP takes nothing returns nothing
local timer tim = GetExpiredTimer()
local integer timerID = GetHandleId(tim)
local unit u = LoadUnitHandle(udg_HASH, timerID, 1)
local unit t = LoadUnitHandle(udg_HASH, timerID, 2)
local real x1 = LoadReal(udg_HASH, timerID, 3)
local real y1 = LoadReal(udg_HASH, timerID, 4)
local real damage = LoadReal(udg_HASH, timerID, 7)
local real duration = LoadReal(udg_HASH, timerID, 8)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real angle = GetRandomReal(0, 360)
local integer distance = GetRandomInt(200, 400)
if duration > 0 and GetWidgetLife(t) >= 0.405 then
call SaveReal(udg_HASH, timerID, 8, duration - IR_TIMERSPEED())
call DestroyEffect(AddSpecialEffect(IR_SFX_TC(), x, y))
call DestroyEffect(AddSpecialEffectTarget(IR_SFX_MOONSOON(), u, "overhead"))
call UnitDamageTarget(u, t, damage, false, false, IR_ATY(), IR_DAM(), null)
call SetUnitX(u, x1 + distance*Cos(angle))
call SetUnitY(u, y1 + distance*Sin(angle))
call SetUnitX(t, GetUnitX(u))
call SetUnitY(t, GetUnitY(u))
call SetUnitAnimation(t, "death" )
call SetUnitAnimation(u, "attack" )
else
call TerrainDeformRipple(x, y, 1024, 90, 4, 300, 1500, 0.5, 5, false)
call SetUnitPathing(u, true)
call SetUnitPathing(t, true)
call PauseUnit(t, false)
call PauseUnit(u, false)
call SetUnitAnimation(t, "stand" )
call SetUnitX(u, x1)
call SetUnitY(u, y1)
call SetUnitX(t, LoadReal(udg_HASH, timerID, 5))
call SetUnitY(t, LoadReal(udg_HASH, timerID, 6))
call SetUnitFlyHeight(u, GetUnitDefaultFlyHeight(u), 1000.)
call SetUnitFlyHeight(t, GetUnitDefaultFlyHeight(t), 1000.)
call UnitRemoveAbility(u, 'Amrf')
call UnitRemoveAbility(t, 'Amrf')
call PauseTimer(tim)
call DestroyTimer(tim)
call FlushChildHashtable(udg_HASH, timerID)
endif
set u = null
set t = null
set tim = null
endfunction
function IR_CAST2 takes nothing returns nothing
local timer tim2 = GetExpiredTimer()
local integer timerID2 = GetHandleId(tim2)
local timer tim = LoadTimerHandle(udg_HASH, timerID2, 1)
local real ver = LoadReal(udg_HASH, timerID2, 2)
local unit u = LoadUnitHandle(udg_HASH, timerID2, 3)
local unit t = LoadUnitHandle(udg_HASH, timerID2, 4)
if ver > 0 and GetWidgetLife(u) >= 0.405 and GetWidgetLife(t) >= 0.405 then
call SaveReal(udg_HASH, timerID2, 2, ver - 10)
call SetUnitVertexColor(u , 100, 100, 100, R2I(ver))
else
call SetUnitX(u, GetUnitX(t))
call SetUnitY(u, GetUnitY(t))
call SetUnitVertexColor(u, 200, 200, 200, 200)
call PauseTimer(tim2)
call DestroyTimer(tim2)
call SetUnitFlyHeight(u, 500., 1000.)
call PauseUnit(u, true)
call TimerStart(tim, IR_TIMERSPEED(), true, function IR_LOOP)
call FlushChildHashtable(udg_HASH, timerID2)
endif
set tim = null
set tim2 = null
set u = null
set t = null
endfunction
function IR_CAST takes nothing returns nothing
local timer tim
local timer tim2
local integer timerID
local integer timerID2
local unit u = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(u, IR_SPELLID())
local real vertex = 100
if GetSpellAbilityId()==IR_SPELLID() then
set tim = CreateTimer()
set timerID = GetHandleId(tim)
set tim2 = CreateTimer()
set timerID2 = GetHandleId(tim2)
call PauseUnit(t, true)
call SetUnitPathing(u, false)
call SetUnitPathing(t, false)
call UnitAddAbility(u, 'Amrf')
call UnitAddAbility(t, 'Amrf')
call DestroyEffect(AddSpecialEffectTarget(IR_SFX_MOONSOON(), u, "overhead"))
call UnitDamageTarget(u, t, IR_DAMAGE(level), false, false, IR_ATY(), IR_DAM(), null)
call SetUnitAnimation(t, "death" )
call SetUnitAnimation(u, "spell" )
call SetUnitFlyHeight(t, 500., 1000.)
//===timerID
call SaveUnitHandle(udg_HASH, timerID, 1, u)
call SaveUnitHandle(udg_HASH, timerID, 2, t)
call SaveReal(udg_HASH, timerID, 3, GetUnitX(u))
call SaveReal(udg_HASH, timerID, 4, GetUnitY(u))
call SaveReal(udg_HASH, timerID, 5, GetUnitX(t))
call SaveReal(udg_HASH, timerID, 6, GetUnitY(t))
call SaveReal(udg_HASH, timerID, 7, IR_DAMAGE(level))
call SaveReal(udg_HASH, timerID, 8, IR_DURATION())
//===timerID2
call SaveTimerHandle(udg_HASH, timerID2, 1, tim)
call SaveReal(udg_HASH, timerID2, 2, 100.)
call SaveUnitHandle(udg_HASH, timerID2, 3, u)
call SaveUnitHandle(udg_HASH, timerID2, 4, t)
call TimerStart(tim2, 0.05, true, function IR_CAST2)
endif
set u = null
set t = null
set tim = null
endfunction
//============================================================
function InitTrig_Insane_Revenge takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction (t, function IR_CAST)
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Gravity_Desforation_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A003'
endfunction
function Trig_Gravity_Desforation_Actions takes nothing returns nothing
local location l = GetUnitLoc(GetSpellTargetUnit())
call CreateNUnitsAtLoc( 1, 'n027', GetOwningPlayer(GetSpellAbilityUnit()), l, bj_UNIT_FACING )
set udg_targetAOESGD = GetLastCreatedUnit()
call UnitApplyTimedLifeBJ( 2.00, 'BTLF', udg_targetAOESGD )
call RemoveLocation(l)
set l = null
endfunction
//===========================================================================
function InitTrig_Gravity_Desforation takes nothing returns nothing
set gg_trg_Gravity_Desforation = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Gravity_Desforation, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Gravity_Desforation, Condition( function Trig_Gravity_Desforation_Conditions ) )
call TriggerAddAction( gg_trg_Gravity_Desforation, function Trig_Gravity_Desforation_Actions )
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ManaFreeze initializer InitTrig_Mana_Freeze
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02M' or GetSpellAbilityId() == 'A02Y'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit v = GetSpellTargetUnit()
local real mana = GetUnitState(v, UNIT_STATE_MANA)
local real t = 0.5
local real dur = 2+ (GetUnitAbilityLevel(u, 'A02M' ) * 1.5)
loop
exitwhen dur < 0.0
call SetUnitState(v, UNIT_STATE_MANA, 0.00)
set dur = dur - t
call TriggerSleepAction(t)
endloop
call SetUnitState(v, UNIT_STATE_MANA, mana)
set u = null
set v = null
endfunction
//===========================================================================
private function InitTrig_Mana_Freeze takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope Shadow initializer InitTrig_Shadow
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A032'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit v = GetSpellTargetUnit()
local unit d
local unit c
local group g = CreateGroup()
local location l = GetUnitLoc(v)
local real t = 0.1
local real dmg = 300 + (GetUnitAbilityLevel(u, 'A032') * 300)
set g = GetUnitsOfPlayerAndTypeId(GetOwningPlayer(u), 'H00K')
set c = GroupPickRandomUnit(g)
loop
exitwhen UnitHasBuffBJ(v, 'B00D') == true
call TriggerSleepAction(t)
endloop
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h00L', l, 0.00)
call IssueTargetOrder(d, "deathcoil", c)
call UnitDamageTargetBJ(c, v, dmg, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
call UnitApplyTimedLife( d, 'BTLF', 2.00 )
set u = null
set v = null
set d = null
set c = null
set l = null
call RemoveLocation(l)
call DestroyGroup(g)
endfunction
//===========================================================================
private function InitTrig_Shadow takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=21
//TESH.alwaysfold=0
scope Teleport initializer onInit
globals
private location array p
endglobals
// function for group conditions
private function Group_Con takes nothing returns boolean
return ( IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false ) and (GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetTriggerUnit()))
endfunction
// function for group actions
private function Group_Act takes nothing returns nothing
local string e = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl"
call AddSpecialEffectLoc(e , GetUnitLoc(GetEnumUnit()))
call SetUnitPositionLoc(GetEnumUnit(), p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))])
call AddSpecialEffectLoc(e , GetUnitLoc(GetEnumUnit()))
endfunction
// function for trigger conditions
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A02A'
endfunction
// function for trigger actions
private function Actions takes nothing returns nothing
local unit x = GetTriggerUnit()
local location px = GetUnitLoc(x)
local group g = GetUnitsInRangeOfLocMatching(750.00, GetUnitLoc(x), Condition(function Group_Con))
local real delay = 4.0 - ((GetUnitAbilityLevel(x, 'A02A') * 0.5))
// End of locals, start of main code.
set p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))] = GetSpellTargetLoc()
call TriggerSleepAction(delay)
call ForGroup(g , function Group_Act)
// Nulling variables
set x = null
call RemoveLocation(p[GetConvertedPlayerId(GetOwningPlayer(GetTriggerUnit()))])
call RemoveLocation(px)
call DestroyGroup(g)
endfunction
private function onInit takes nothing returns nothing
local trigger Teleport = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( Teleport, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( Teleport, Condition( function Conditions ) )
call TriggerAddAction( Teleport, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ForceIncrease initializer InitTrig_Force_Increase
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A036' and IsUnitType(GetSpellTargetUnit(), UNIT_TYPE_HERO) == true
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellTargetUnit()
local real t = 90.
local real t2 = 0.5
call UnitAddItemById(u, 'I000')
call TriggerSleepAction(t)
if IsUnitDeadBJ(u) then
loop
exitwhen IsUnitAliveBJ(u) == true
call TriggerSleepAction(t2)
endloop
endif
call UnitAddItemById(u, 'I001')
set u = null
endfunction
//===========================================================================
private function InitTrig_Force_Increase takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=38
//TESH.alwaysfold=0
//=========================Mimic v1.2=========================
//============================================================
//====================Made by: Mckill2009=====================
//============================================================
//============================================================
//===HOW TO USE:
//- Create a HASH variable in the trigger editor
//- Initialize the HASH
//- Copy the Dummy Hero and Ability
//- make sure that the Hero and Ability has the RAW CODE 'H000' and 'A001' respectively
// if not then you may change the MIMIC_SPELLID and MIMIC_DUMMYID raw codes
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- The trigger name MUST be >>> Mimic (or you may change it as long as it matches InitTrig_NAME_OF_TRIGGER below
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//- You may configure some things
//============================================================
//=======================CONFIGURABLES========================
//============================================================
function MIMIC_SPELLID takes nothing returns integer
return 'A03B' //This is the Hero ability ID
endfunction
function MIMIC_DUMMYID takes nothing returns integer
return 'H00N' //This is the HERO DUMMY ID (IT MUST BE A HERO)
endfunction
function MIMIC_CHANCE takes nothing returns integer
return 15 //This is the BASE CHANCE, adjust it if you want
endfunction
//============================================================
//====================END OF CONFIGURABLES====================
//============================================================
//=====This function is just to get the ORDER STRING of the spell so...
//=====DO NOT TOUCH THIS!
function MIMIC_ORDER_ID takes nothing returns nothing
call SaveInteger(udg_HASH, GetHandleId(GetTriggerUnit()), 1, GetIssuedOrderId())
endfunction
//============================================================
//============================================================
function MIMIC_COND takes nothing returns boolean
return GetUnitAbilityLevel(GetSpellTargetUnit(), MIMIC_SPELLID()) > 0 and (GetTriggerUnit() != GetSpellTargetUnit())
endfunction
function MIMIC_CAST takes nothing returns nothing
local unit c = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local unit dummy
local integer ID = GetHandleId(GetTriggerUnit())
local integer spellid = GetSpellAbilityId()
local integer spellidlvl = GetUnitAbilityLevel(c, spellid)
local integer spelllevel = 40 + (GetUnitAbilityLevel(t, MIMIC_SPELLID()) * MIMIC_CHANCE())
if GetRandomInt(1, 100) <= spelllevel then
call PlaySoundBJ( gg_snd_SpellbreakerYesAttack3 )
set dummy = CreateUnit(GetOwningPlayer(t), MIMIC_DUMMYID(), GetUnitX(t), GetUnitY(t), 0)
call SetHeroLevel(dummy, 30, false)
call UnitApplyTimedLife(dummy, 'BTLF', 5)
call UnitAddAbility(dummy, spellid)
call SetUnitAbilityLevel(dummy, spellid, spellidlvl)
call IssueTargetOrderById(dummy, LoadInteger(udg_HASH, ID, 1), c)
endif
call FlushChildHashtable(udg_HASH, ID)
set c = null
set t = null
set dummy = null
endfunction
//==== Init Trigger Mimic ====
function InitTrig_Spell_Deflect takes nothing returns nothing
local trigger t = CreateTrigger()
local trigger tt = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition (t, Condition(function MIMIC_COND))
call TriggerAddAction (t, function MIMIC_CAST)
call TriggerRegisterAnyUnitEventBJ (tt, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddAction (tt, function MIMIC_ORDER_ID)
set t = null
set tt = null
endfunction
//TESH.scrollpos=43
//TESH.alwaysfold=0
scope ShadowVortex initializer init
//*************************************************************************************************************//
// ShadowVortex v0.01 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// Heights by cedi //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Shadow
private keyword Main
private keyword Missile
globals
//ID of the spell
private constant integer SPELL_ID = 'A03P'
//ID of your dummy
private constant integer DUMMY_ID = 'h00Q'
//Amount of shadows created each time.
private constant integer SHADOW_COUNT = 5
//Amount of missiles created in the nova.
private constant integer MISSILE_COUNT = 36
//Interval of the moves
private constant real TIMER_INTERVAL = 0.035
//Time between the nova and the absorbing
private constant real SHADOW_NOVA_INT = 0.5
//Speed of the shadows. In wc3 ms.
private constant real SPEED = 522.00
//Interval of picking
private constant real PICK_INT = 0.10
//Floating height of the shadows.
private constant real SHADOW_HEIGHT = 50.00
//Speed of the rotating in angle per second.
private constant real ANGLE_CHANGE = 150.00
//Start Height
private constant real START_Z = 500.00
//Start distance
private constant real SHADOW_DISTANCE = 550.00
//Min Dist
private constant real SHADOW_MIN_DIST = 5.00
//Interval of the shadow creation.
private constant real SHADOW_INTERVAL = 0.5
//On Damage sfx
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//Model of the shadows.
private constant string SHADOW_MODEL = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//SYSTEM
private Shadow SHADOW
private Main MAIN
private Missile MISSILE
private group GROUP = CreateGroup()
endglobals
private function DAMAGE takes integer level returns real
return 100.00 * level
endfunction
private function AOE takes integer level returns real
return 50.
endfunction
private function RANGE takes integer level returns real
return 1500.0
endfunction
private function NEEDED takes integer level returns integer
return 36
endfunction
private function HIT_FUNC takes Missile m, unit target returns nothing
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
local real A = (2*(y0+y1)-4*h)/(d*d)
local real B = (y1-y0-A*d*d)/d
return A*x*x + B*x + y0
endfunction
private function MissileControl takes nothing returns nothing
set MISSILE = GetTimerData( GetExpiredTimer() )
call MISSILE.control()
endfunction
private function ShadowControl takes nothing returns nothing
set SHADOW = GetTimerData( GetExpiredTimer() )
call SHADOW.control()
endfunction
private function MainControl takes nothing returns nothing
set MAIN = GetTimerData( GetExpiredTimer() )
call MAIN.control()
endfunction
private struct Missile
unit caster = null
unit u = null
integer level = 1
real vx = 0.00
real vy = 0.00
real range = 0.00
real maxrange = 0.00
real x = 0.00
real y = 0.00
real interval = 0.00
effect model = null
timer t = null
group g = null
private method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( GROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( GROUP )
exitwhen u == null
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call GroupAddUnit( .g, u )
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
endif
endif
call GroupRemoveUnit( GROUP, u )
set u = null
endloop
endmethod
method onDestroy takes nothing returns nothing
set .caster = null
call DestroyEffect( .model )
set .model = null
call KillUnit( .u )
set .u = null
call ReleaseTimer( .t )
set .t = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .u ) <= 0.405 then
call .destroy()
return
endif
set .range = .range - SPEED * TIMER_INTERVAL
if .range <= 0.00 then
call .destroy()
return
endif
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .u, .x )
call SetUnitY( .u, .y )
set .interval = .interval + TIMER_INTERVAL
if .interval >= PICK_INT then
set .interval = 0.00
call .pick()
endif
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
set angle = angle * bj_DEGTORAD
set .caster = m.caster
set .level = m.level
set .vx = Cos( angle ) * SPEED * TIMER_INTERVAL
set .vy = Sin( angle ) * SPEED * TIMER_INTERVAL
set .x = GetUnitX( .caster ) + .vx
set .y = GetUnitY( .caster ) + .vy
set .range = RANGE( .level )
set .maxrange = .range
set .u = CreateUnit( GetOwningPlayer( .caster ), DUMMY_ID, .x, .y, angle * bj_RADTODEG )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .t = NewTimer()
set .g = CreateGroup()
call SetUnitZ( .u, SHADOW_HEIGHT )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MissileControl )
return this
endmethod
endstruct
private struct Shadow
Main main = 0
unit caster = null
unit u = null
real distance = 0.00
real angle = 0.00
real z = 0.00
effect model = null
timer t = null
method control takes nothing returns nothing
local real x
local real y
local real z
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
return
endif
set .angle = .angle + ANGLE_CHANGE * TIMER_INTERVAL
set .distance = .distance - SPEED * TIMER_INTERVAL
if .distance <= 0.00 then
call .destroy()
return
endif
set x = GetUnitX( .caster ) + Cos( .angle * bj_DEGTORAD ) * .distance
set y = GetUnitY( .caster ) + Sin( .angle * bj_DEGTORAD ) * .distance
set z = ParabolaZ2( GetUnitZ( .caster ), .z, START_Z / 2.00, SHADOW_DISTANCE, .distance )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
call SetUnitZ( .u, z )
if IsUnitInRange( .u, .main.caster, SHADOW_MIN_DIST ) then
call .main.addCharge()
call .destroy()
endif
endmethod
method onDestroy takes nothing returns nothing
call DestroyEffect( .model )
set .model = null
call ReleaseTimer( .t )
set .t = null
call KillUnit( .u )
set .u = null
set .caster = null
endmethod
static method create takes Main m, real angle returns thistype
local thistype this = thistype.allocate()
local real x = GetUnitX( m.caster )
local real y = GetUnitY( m.caster )
set .main = m
set .distance = SHADOW_DISTANCE
set .angle = angle
set .t = NewTimer()
set x = x + Cos( angle * bj_DEGTORAD ) * .distance
set y = y + Sin( angle * bj_DEGTORAD ) * .distance
set .u = CreateUnit( GetOwningPlayer( m.caster ), DUMMY_ID, x, y, 0.00 )
call SetUnitZ( .u, START_Z )
set .model = AddSpecialEffectTarget( SHADOW_MODEL, .u, "origin" )
set .caster = m.caster
set .z = GetUnitZ( .u )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function ShadowControl )
return this
endmethod
endstruct
private struct Main
unit caster = null
integer level = 1
integer needed = 0
real interval = 0.00
timer t = null
boolean enough = false
method addCharge takes nothing returns nothing
set .needed = .needed - 1
if .needed <= 0 then
set .enough = true
set .interval = SHADOW_NOVA_INT
endif
endmethod
method newShadows takes nothing returns nothing
local integer i = 0
local real r = 360.00 / SHADOW_COUNT
loop
exitwhen i > SHADOW_COUNT
call Shadow.create( this, r * i )
set i = i + 1
endloop
endmethod
method nova takes nothing returns nothing
local integer i = 0
local real r = 360.00 / MISSILE_COUNT
loop
exitwhen i > MISSILE_COUNT
call Missile.create( this, r * i )
set i = i + 1
endloop
endmethod
method control takes nothing returns nothing
if GetWidgetLife( .caster ) <= 0.405 then
call .destroy()
endif
set .interval = .interval - TIMER_INTERVAL
if not .enough then
if .interval <= 0.00 then
call .newShadows()
set .interval = SHADOW_INTERVAL
endif
else
if .interval <= 0.00 then
call .nova()
call .destroy()
endif
endif
endmethod
method onDestroy takes nothing returns nothing
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .needed = NEEDED( .level )
set .t = NewTimer()
set .interval = SHADOW_INTERVAL
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function MainControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit() )
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function IsSpell ) )
set t = null
endfunction
endscope
//TESH.scrollpos=10
//TESH.alwaysfold=0
scope KnockingArrow initializer InitTrig_Knocking_Arrow
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A03W'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit v = GetSpellTargetUnit()
local location l
local location l2 = GetUnitLoc(u)
local real t = 0.01
loop
exitwhen UnitHasBuffBJ(v, 'B00K') == true
call TriggerSleepAction(t)
endloop
call SetUnitFacingToFaceLocTimed(v, l2, 0.0)
set l = GetUnitLoc(v)
// This are the applied actions of the 'Actions to apply' trigger.
set udg_KBA_Caster = u
set udg_KBA_TargetUnit = v
set udg_KBA_StartingPosition = l2
set udg_KBA_Level = 1
set udg_KBA_Speed = 25.00
set udg_KBA_DistancePerLevel = 600
set udg_KBA_SpecialEffects[1] = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl"
set udg_KBA_SpecialEffects[2] = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl"
set udg_KBA_DestroyTrees = true
call ConditionalTriggerExecute( gg_trg_Cast_A_Knockback )
//
call RemoveLocation(l)
call RemoveLocation(l2)
set u = null
set v = null
set l = null
set l2 = null
endfunction
//===========================================================================
private function InitTrig_Knocking_Arrow takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CriticalStrikeRanger initializer InitTrig_Critical_Strike_Rem
private function Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetEventDamageSource(), 'A03Z') > 0
endfunction
private function Actions takes nothing returns nothing
local unit u = GetEventDamageSource()
local real t = 10.0
call UnitRemoveAbility(u, 'A03Z')
call TriggerSleepAction(t)
call UnitAddAbility(u, 'A03Z')
set u = null
endfunction
//===========================================================================
private function InitTrig_Critical_Strike_Rem takes nothing returns nothing
local trigger t = CreateTrigger( )
call Damage_RegisterEvent(t)
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=48
//TESH.alwaysfold=0
library ShadowAttack requires TimerUtils, GroupUtils, xedamage
//===============================================================================================
// shadow attack v1.00 by scorpion182
// requires: TimerUtils, xedamage by Vexorian
// GroupUtils by RisingDusk
//
// optional: BoundSentinel by Vexorian (use it if you don't want your hero stuck outside the map bound)
//
//===============================================================================================
globals
private keyword data
//-----------------------CALIBRATION SECTION-----------------------------------------------------
//spell id
private constant integer SPELL_ID = 'A040'
//shadow trail unit id
private constant integer SHADOW_TRAIL = 'h00V'
//shadow number
private constant integer MAX_SHADOW = 30
//attack animation index
private constant integer ANIMATION_INDEX = 2
//walk animation index
private constant integer ATTACK_AN_INDEX = 5
//collision distance
private constant real COLLISION_DIST = 75.
//spell order id
private constant string ORDER_ID = "blizzard"
//image special effect
private constant string IMAGE_FX = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl"
//on-damage effect
private constant string ON_DAMAGE_FX = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
//on-damage effect attachment point
private constant string DAMAGE_ATTCH = "origin"
//preload effect?
private constant boolean PRELOAD_FX = true
endglobals
//do damage each hit
private constant function GetDamage takes integer lvl returns real
return 100. + lvl * 100.
endfunction
//attack interval
private constant function GetAttackInterval takes integer lvl returns real
return 0.30
endfunction
//maximum number target per level
private constant function GetTargetNum takes integer lvl returns integer
return 10
endfunction
//rotation speed
private constant function GetAngleSpeed takes integer lvl returns real
return .05 + lvl * 0.
endfunction
//caster movement speed
private constant function GetSpeed takes integer lvl returns real
return 1000. * XE_ANIMATION_PERIOD + lvl * 0.
endfunction
//shadow number
private constant function GetShadowNum takes integer lvl returns integer
return 18 + lvl * 0
endfunction
//area of effect
private constant function GetDistance takes integer lvl returns real
return 450. + lvl * 0.
endfunction
//filter the target
private function IsValidTarget takes unit u, data s returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE)==false and IsUnitEnemy(u,GetOwningPlayer(s.caster))==true and IsUnitVisible(u,GetOwningPlayer(s.caster))==true
endfunction
//damage options must match the target filter
private function DamageOptions takes xedamage spellDamage returns nothing
set spellDamage.dtype=DAMAGE_TYPE_UNIVERSAL
set spellDamage.atype=ATTACK_TYPE_NORMAL
set spellDamage.exception=UNIT_TYPE_STRUCTURE
set spellDamage.visibleOnly=true
endfunction
//----------------------END OF CALIBRATION-------------------------------------------------------
globals
private xedamage xed
private constant real A = 2 * bj_PI
endglobals
private struct shadow
unit array shadow[MAX_SHADOW]
real array angle[MAX_SHADOW]
boolean array show[MAX_SHADOW]
group victim
unit target = null
boolean sets = false
boolean attack = false
boolean ready = false
boolean back = false
boolean inpos = false
real interval = 0
real cap = 0
real ag = 0
integer idx = 0
integer num = 0
integer n = 0
integer pos = 0
unit caster
timer t
integer lvl
real cx
real cy
private static thistype temp
static method create takes unit c, real x, real y returns thistype
local thistype this = thistype.allocate()
local integer i = 0
local real a
set .caster = c
set .t = NewTimer()
set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
set .victim = NewGroup()
set .cap = A
set .cx = x
set .cy = y
loop
exitwhen i == GetShadowNum(.lvl)
set a = i * A / GetShadowNum(.lvl)
set .shadow[i] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, x, y, a)
set .angle[i] = a
// call SetUnitTimeScale(.shadow[i], 2.)
// call SetUnitColor(.shadow[i], PLAYER_COLOR_LIGHT_GRAY)
// call SetUnitVertexColor(.shadow[i], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[i], ANIMATION_INDEX)
call ShowUnit(.shadow[i], false)
set i = i + 1
endloop
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop)
return this
endmethod
//i don't know why i can't detect locust unit, so i reverse it
static method IsCaster takes nothing returns boolean
local unit u = GetFilterUnit()
if u==temp.caster and not temp.sets then
set temp.pos = temp.idx
set temp.sets = true
call RemoveUnit(temp.shadow[temp.idx])
set temp.shadow[temp.idx] = temp.caster
set temp.show[temp.idx] = true
set temp.num = temp.num + 1
endif
set u = null
return false
endmethod
static method IsTarget takes nothing returns boolean
local unit u = GetFilterUnit()
if temp.target == null and IsValidTarget(u, temp) and not IsUnitInGroup(u, temp.victim) then
set temp.target = u
set temp.n = temp.n + 1
set temp.attack = true
call GroupAddUnit(temp.victim, u)
endif
set u = null
return false
endmethod
static method onLoop takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local integer i = 0
local real dx
local real dy
local real dis
local real angle
if GetUnitCurrentOrder(.caster) == OrderId(ORDER_ID) then
set temp = this
if .ready then
if .back then
set .interval = .interval + XE_ANIMATION_PERIOD
if .interval > GetAttackInterval(.lvl) then
set .interval = 0.
set .back = false
set .shadow [.pos] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, GetUnitX(.caster), GetUnitY(.caster), GetUnitFacing(.caster))
// call SetUnitTimeScale(.shadow[.pos], 2.)
// call SetUnitColor(.shadow[.pos], PLAYER_COLOR_LIGHT_GRAY)
// call SetUnitVertexColor(.shadow[.pos], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[.pos], ANIMATION_INDEX)
call UnitAddAbility(.shadow[.pos], 'Aloc')
call GroupClear(.victim)
endif
endif
if not .attack and .target == null and .n < GetTargetNum(.lvl) and not .back then
call GroupEnumUnitsInRange(ENUM_GROUP, .cx, .cy, GetDistance(.lvl), function thistype.IsTarget)
if .n == 0 and .target == null and not .inpos then
set .inpos = true
call RemoveUnit(.shadow[.pos])
set .shadow[.pos] = .caster
set .show[.pos] = true
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
if .n >= 1 and .target == null then
set .ready = false
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
elseif .attack and .target!=null then
set dx = GetUnitX(.target) - GetUnitX(.caster)
set dy = GetUnitY(.target) - GetUnitY(.caster)
set dis = SquareRoot(dx * dx + dy * dy)
set angle = Atan2(dy, dx)
if dis > COLLISION_DIST and IsUnitInRangeXY(.target, .cx, .cy, GetDistance(.lvl)) then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
call xed.damageTarget(.caster,.target,GetDamage(.lvl))
set .attack = false
set .target = null
call SetUnitAnimationByIndex(.caster, ATTACK_AN_INDEX)
endif
elseif .n == GetTargetNum (.lvl) then
set .ready = false
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
else
if .num == GetShadowNum(.lvl) then
set dx = GetUnitX(.shadow[.pos]) - GetUnitX(.caster)
set dy = GetUnitY(.shadow[.pos]) - GetUnitY(.caster)
set dis = SquareRoot(dx * dx + dy * dy)
set angle = Atan2(dy, dx)
if dis > 215. then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
if not .back then
set .back = true
set .ready = true
set .attack = false
set .inpos = false
set .n = 0
set .target = null
set .pos = .pos - 1
if .pos < 0 then
set .pos = GetShadowNum(.lvl) - 1
endif
call RemoveUnit(.shadow[.pos])
set .shadow[.pos] = .caster
set .show[.pos] = true
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
endif
endif
endif
endif
if .sets and .ag > .cap then
set temp.idx = temp.idx - 1
if temp.idx < 0 then
set temp.idx = GetShadowNum(.lvl) - 1
endif
set .ag = 0
if not .show[.idx] then
set .num = .num + 1
if .num > GetShadowNum(.lvl) then
set .num = GetShadowNum(.lvl)
endif
if .num == GetShadowNum(.lvl) then
set .ready = true
set .shadow [.pos] = CreateUnit(GetOwningPlayer(.caster), SHADOW_TRAIL, GetUnitX(.caster), GetUnitY(.caster), GetUnitFacing(.caster))
call SetUnitTimeScale(.shadow[.pos], 2.)
// call SetUnitColor(.shadow[.pos], PLAYER_COLOR_LIGHT_GRAY)
// call SetUnitVertexColor(.shadow[.pos], 255, 255, 255, 125)
call SetUnitAnimationByIndex(.shadow[.pos], ANIMATION_INDEX)
call UnitAddAbility(.shadow[.pos], 'Aloc')
endif
set .show[.idx] = true
call ShowUnit(.shadow[.idx], true)
call UnitAddAbility(.shadow[.idx], 'Aloc')
call DestroyEffect(AddSpecialEffectTarget(IMAGE_FX, .shadow[.idx], "origin"))
endif
endif
loop
exitwhen i == GetShadowNum(.lvl)
if not .sets then
call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(.shadow[i]), GetUnitY(.shadow[i]), COLLISION_DIST, function thistype.IsCaster)
set .idx = i
endif
set .ag = .ag + GetAngleSpeed(.lvl)
set .angle[i] = .angle[i] + GetAngleSpeed(.lvl)
call SetUnitX(.shadow[i], .cx + GetDistance(.lvl) * Cos(.angle[i]))
call SetUnitY(.shadow[i], .cy + GetDistance(.lvl) * Sin(.angle[i]))
call SetUnitFacing(.shadow[i], .angle[i] * bj_RADTODEG + 90. )
set i = i + 1
endloop
else
call .destroy()
endif
endmethod
private method onDestroy takes nothing returns nothing
local integer i = 0
call ReleaseTimer(.t)
call ReleaseGroup(.victim)
call SetUnitTimeScale(.caster, 1.)
loop
exitwhen i == GetShadowNum(.lvl)
set .show[i] = false
if .shadow[i] != .caster then
call SetUnitExploded(.shadow[i], true)
call KillUnit(.shadow[i])
endif
set i = i + 1
endloop
endmethod
endstruct
private struct data
unit caster
timer t
real tx
real ty
integer lvl
real cx
real cy
static method create takes unit c, real x, real y returns thistype
local thistype this = thistype.allocate()
local real angle = bj_RADTODEG * Atan2(y - GetUnitY(c), x - GetUnitX(c))
set .cx = x
set .cy = y
set .caster = c
set .t = NewTimer()
set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
set .tx = x + GetDistance(.lvl) * Cos(angle)
set .ty = y + GetDistance(.lvl) * Sin(angle)
call SetUnitFacing(.caster, angle)
call SetUnitAnimationByIndex(.caster, ANIMATION_INDEX)
// call SetUnitTimeScale(.caster, 2.)
return this
endmethod
private method onDestroy takes nothing returns nothing
call ReleaseTimer(.t)
endmethod
static method onLoop takes nothing returns nothing
local thistype this = thistype(GetTimerData(GetExpiredTimer()))
local real dx = .tx - GetUnitX(.caster)
local real dy = .ty - GetUnitY(.caster)
local real dis = SquareRoot(dx * dx + dy * dy)
local real angle = Atan2(dy, dx)
local shadow s
if dis > COLLISION_DIST and GetUnitCurrentOrder(.caster) == OrderId(ORDER_ID) then
call SetUnitX(.caster, GetUnitX(.caster) + GetSpeed(.lvl) * Cos(angle))
call SetUnitY(.caster, GetUnitY(.caster) + GetSpeed(.lvl) * Sin(angle))
call SetUnitFacing(.caster, angle * bj_RADTODEG)
else
call .destroy()
set s = shadow.create(.caster, .cx, .cy)
endif
endmethod
static method SpellEffect takes nothing returns boolean
local thistype this
local unit u = GetTriggerUnit()
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
if GetSpellAbilityId() == SPELL_ID then
set this = thistype.create(u, x, y)
call SetTimerData(.t, this)
call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop)
endif
set u = null
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.SpellEffect))
//init xedamage
set xed=xedamage.create()
call DamageOptions(xed)
call xed.useSpecialEffect(ON_DAMAGE_FX, DAMAGE_ATTCH)
//preload fx
static if PRELOAD_FX then
call Preload(IMAGE_FX)
call Preload(ON_DAMAGE_FX)
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CriticalStrikeSirenaAdd initializer InitTrig_Critical_Strike_Add_Sirena
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A046'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellTargetUnit()
local integer n = GetUnitAbilityLevel(u, 'A02F')
local real t = 3.0
call TriggerSleepAction( t )
call UnitAddAbility(u, 'A041')
call SetUnitAbilityLevel(u, 'A041', n)
set u = null
endfunction
//===========================================================================
private function InitTrig_Critical_Strike_Add_Sirena takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CriticalStrikeSirena initializer InitTrig_Critical_Strike_Rem_Sirena
private function Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetEventDamageSource(), 'A041') > 0
endfunction
private function Actions takes nothing returns nothing
local unit u = GetEventDamageSource()
call UnitRemoveAbility(u, 'A041')
set u = null
endfunction
//===========================================================================
private function InitTrig_Critical_Strike_Rem_Sirena takes nothing returns nothing
local trigger t = CreateTrigger( )
call Damage_RegisterEvent(t)
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Windcut initializer InitWindCut requires TimerUtils,GroupUtils,MathBasic,TimedFadeUnit,TimedAnimationStop,Group2Group
//SETTINGS
globals
// ID's
private constant integer Spell_ID = 'A047' // spell ID must match this value
private constant integer Dummy_ID = 'e003' // dummy unit Id must match this value
// end of ID setup
private constant boolean InvulnerableCaster = true // if true caster is invulnerable
// damage
private constant real BaseDamage = 200. // base damage per slash
private constant real DamageInc = 200. // damage added on base damage with every levelup of the ability
// end of damage options
// eyecandy
private constant string SlashEff = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl" // effect created on unit strike
private constant string WeaponEff = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl" // effect created on illusions blade
private constant string TrailEff = "Abilities\\Weapons\\GlaiveMissile\\GlaiveMissileTarget.mdl" // trail effect which is created on the ground as the hero moves
private constant integer ESR = 3 // ESR = Effect Spam Ration, increase in this = less effects, decrease = more effects (used for trail effects)
// end of eyecandy options
// fade options
private constant real CasterFade = 0.6 // takes a value from 0.00 to 1.00; 0.00 is transparent, 1.00 is normal value of every unit.
// 0.7 = 70% visibility, 30% transparency
private constant real ImageFade = 0.5 // same as CasterFade but for illusions
private constant real FadeTime = 0.3 // fade time for illusions, 0.3 = 0.3 seconds of delay before the trail illusions behind the heroes are removed
private constant real AnimStopValue = 0.85 // varies from model to model, takes a value when the animation is stoped
// blademaster's animation of attack ("attack") is 1.167 seconds so this is
// a user defined value, there is no equation for it
private constant real FadeTimeEx = 3.00 // this value is used for the illusions that play the attack animation
// this value should be larget than FadeTime to show the full eyecandy
// and the effect of TimedAnimationStop
// end of fade options
// speed related things
private constant real FPS = 30.00 // optimal values from 30 to 60
private constant real ChargeSpeed = 1025. * (1/FPS) // speed of the hero,uses WC3 movement speed values, don't touch anything after the sign *
private constant real AoE = 600. // AoE which is actualy used for a strange AoE calculated by distance from caster to cast point
// end of speed options
endglobals
//END OF SETTINGS
// Don't Touch the stuff bellow this point
globals
private unit TU = null
private player TP = null
private real TR = 0.00
private group FG = CreateGroup()
private constant real MinOffset = 50.00
endglobals
private function GroupFilter takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > .405 and IsUnitInGroup(GetFilterUnit(),FG)==false and GetFilterUnit() != TU and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false and IsUnitEnemy(GetFilterUnit(),TP) and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL)==false
endfunction
private function groupfunc takes nothing returns nothing
call GroupAddUnit(FG,GetEnumUnit())
endfunction
private constant function GetDamage takes integer lvl returns real
return BaseDamage + (lvl-1)*DamageInc
endfunction
private function ExtractInteger takes real r returns integer
local integer i = R2I(r)
local real s = r - I2R(i)
if s >= 0.50 then
set i = i+1
endif
return i
endfunction
private struct windcut
unit u
unit tar
group g
group d
timer t
real x
real y
real tx
real ty
real rad
real tpx
real tpy
real dmg
method onDestroy takes nothing returns nothing
call SetUnitVertexColor(this.u,255,255,255,255)
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,false)
endif
call SetUnitTimeScale(this.u,1)
set this.u = null
call GroupClear(this.g)
call GroupClear(this.d)
call ReleaseGroup(this.g)
call ReleaseGroup(this.d)
set this.g = null
set this.d = null
endmethod
static method Create takes nothing returns windcut
local windcut this = windcut.allocate()
return(this)
endmethod
static method motion takes nothing returns nothing
local windcut this = GetTimerData(GetExpiredTimer())
local unit tu = CreateUnit(GetOwningPlayer(this.u),Dummy_ID,this.x,this.y,this.rad*bj_RADTODEG)
call SetUnitX(tu,this.x)
call SetUnitY(tu,this.y)
call SetUnitFacing(this.u,this.rad*bj_RADTODEG)
if this.tar != null then
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
if DBL(this.x,this.y,this.tx,this.ty) <= 128 and this.tar != null then
call UnitDamageTarget(this.u,this.tar,this.dmg,true,false,null,null,null)
if WeaponEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(WeaponEff,tu,"weapon"),FadeTimeEx/2)
endif
if SlashEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(SlashEff,this.tar,"chest"),FadeTimeEx/2)
endif
call SetUnitAnimation(tu,"attack")
call FadeUnitTimed(tu,FadeTimeEx,ImageFade)
call StopAnimationTimed(tu,0.80)
call GroupRemoveUnit(this.g,this.tar)
set this.tar = FirstOfGroup(this.g)
else
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
else
if DBL(this.x,this.y,this.tpx,this.tpy) <= MinOffset then
call RemoveUnit(tu)
call PauseTimer(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
set this.t = null
call this.destroy()
else
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
endif
if this.x > MaxX or this.x < MinX or this.y > MaxY or this.y < MinY then
set this.tar = null
set this.x = this.x - ChargeSpeed * Cos(this.rad)
set this.y = this.y - ChargeSpeed * Sin(this.rad)
set this.tpx = this.x
set this.tpy = this.y
endif
endmethod
endstruct
private function condition2run takes nothing returns boolean
local windcut this
local real d
local integer groupnum
local integer i
local real x
local real y
if GetSpellAbilityId() == Spell_ID then
set this = windcut.Create()
set this.g = NewGroup()
set this.d = NewGroup()
set this.u = GetTriggerUnit()
set this.t = NewTimer()
set this.x = GetUnitX(this.u)
set this.y = GetUnitY(this.u)
set this.tpx = GetSpellTargetX()
set this.tpy = GetSpellTargetY()
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.dmg = GetDamage(GetUnitAbilityLevel(this.u,Spell_ID))
call SetUnitVertexColor(this.u,255,255,255, 255 - R2I(CasterFade*255))
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,true)
endif
call SetUnitTimeScale(this.u,0)
set d = DBL(this.x,this.y,this.tpx,this.tpy)
set groupnum = ExtractInteger(d / AoE)
set i = 0
set x = this.x
set y = this.y
if groupnum < 1 then
set groupnum = 1
endif
loop
exitwhen i > groupnum
set TU = this.u
set TP = GetOwningPlayer(TU)
call GroupEnumUnitsInRange(this.d,x,y,AoE,Filter(function GroupFilter))
call ForGroup(this.d,function groupfunc)
call Group2Group(this.d,this.g)
set x = x + (AoE) * Cos(this.rad)
set y = y + (AoE) * Sin(this.rad)
call GroupClear(this.d)
set i = i+1
endloop
call GroupClear(FG)
call SetTimerData(this.t,integer(this))
call TimerStart(this.t,1/FPS,true,function windcut.motion)
set this.tar = FirstOfGroup(this.g)
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
endif
return false
endfunction
private function InitWindCut takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function condition2run))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=1
//*********************************************************************************
// CREDITS *
//*********************************************************************************
//***************************************************************************************************************** *
//Credits to Rising_Dusk *
//Credits to Vexorian for so many reasons(do i even have to name them?) *
//Credits to TriggerHappy187 for TimedHandles library *
//Credits to Volvox for making the terrain. *
//Credits to Eccho for the test map. *
//*****************************************************************************************************************
function InitTrig_Credits takes nothing returns nothing
endfunction
//TESH.scrollpos=54
//TESH.alwaysfold=1
scope ReleaseLimits initializer InitTrig_Release_Limits
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A048'
endfunction
private function Con takes nothing returns boolean
return IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), GetOwningPlayer(GetTriggerUnit())) == true and IsUnitDeadBJ(GetFilterUnit()) == false
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location l
local real AOE = 750.
local unit d
local integer i = 25
local integer c
local real t = 0.01
local group g = CreateGroup()
local integer i2
local unit ta
local integer lvl = GetUnitAbilityLevel(u, 'A048')
call PauseUnit(u, true)
call ShowUnit(u, false)
loop
exitwhen i <= 0
set l = PolarProjectionBJ(GetUnitLoc(u), GetRandomReal(100, AOE), GetRandomReal(0, 360))
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h00Y', l, 0.00)
call AddSpecialEffectLoc("Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", l)
call SetUnitVertexColor(d, 255, 255, 255, 100)
call SetUnitExploded(d, true)
set c = GetRandomInt(1, 6)
if c == 1 or c == 2 or c == 3 then
call SetUnitAnimation(d, "attack")
set g = GetUnitsInRangeOfLocMatching(300, l, function Con)
set i2 = CountUnitsInGroup(g)
loop
exitwhen i2 <= 0
set ta = GroupPickRandomUnit(g)
exitwhen ta == null
call UnitDamageTargetBJ(u, ta, 100 + (lvl * 50), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
call GroupRemoveUnit(g, ta)
set ta = null
set i2 = i2 - 1
endloop
call UnitApplyTimedLife(d, 'BTLF', 1.5 )
call DestroyGroup(g)
endif
if c == 4 or c == 5 then
call SetUnitAnimation(d, "slam")
set g = GetUnitsInRangeOfLocMatching(450, l, function Con)
set i2 = CountUnitsInGroup(g)
loop
exitwhen i2 <= 0
set ta = GroupPickRandomUnit(g)
exitwhen ta == null
call UnitDamageTargetBJ(u, ta, 100 + (lvl * 75), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
call GroupRemoveUnit(g, ta)
set ta = null
set i2 = i2 - 1
endloop
call UnitApplyTimedLife(d, 'BTLF', 1.5 )
call DestroyGroup(g)
endif
if c == 6 then
call SetUnitAnimation(d, "attack walk stand spin")
set g = GetUnitsInRangeOfLocMatching(600, l, function Con)
set i2 = CountUnitsInGroup(g)
loop
exitwhen i2 <= 0
set ta = GroupPickRandomUnit(g)
exitwhen ta == null
call UnitDamageTargetBJ(u, ta, 100 + (lvl * 100), ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL)
call GroupRemoveUnit(g, ta)
set ta = null
set i2 = i2 - 1
endloop
call UnitApplyTimedLife(d, 'BTLF', 2.5 )
call DestroyGroup(g)
endif
set d = null
call RemoveLocation(l)
set i = i - 1
call TriggerSleepAction(t)
endloop
call ShowUnit(u, true)
call PauseUnit(u, false)
set u = null
endfunction
//===========================================================================
private function InitTrig_Release_Limits takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(t, Condition( function Conditions ) )
call TriggerAddAction(t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope VampiricPower initializer InitTrig_Vampiric_Power
private function Conditions takes nothing returns boolean
return GetUnitAbilityLevel(GetAttacker(), 'A04D') > 0
endfunction
private function Actions takes nothing returns nothing
local unit u = GetAttacker()
local integer lv = GetUnitAbilityLevel(u, 'A04D')
local real t = 10 + (lv * 5)
call ModifyHeroStat( bj_HEROSTAT_AGI, u, bj_MODIFYMETHOD_ADD, 1 )
call AddSpecialEffectTarget("Abilities\\Spells\\Orc\\AncestralSpirit\\AncestralSpiritCaster.mdl", u, "origin")
call TriggerSleepAction(t)
call ModifyHeroStat( bj_HEROSTAT_AGI, u, bj_MODIFYMETHOD_SUB, 1 )
call AddSpecialEffectTarget("Abilities\\Spells\\Orc\\AncestralSpirit\\AncestralSpiritCaster.mdl", u, "origin")
set u = null
endfunction
//===========================================================================
private function InitTrig_Vampiric_Power takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CallDown01 initializer InitTrig_Call_Down
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A04T'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local location l = GetSpellTargetLoc()
local unit d
local real t = 3.0
local integer lvl = GetSpellAbilityId()
call TriggerSleepAction(t)
set d = CreateUnitAtLoc(GetOwningPlayer(u), 'h015', Location(GetRectCenterX(gg_rct_Vision_Reg_3), GetRectCenterY(gg_rct_Vision_Reg_3)), 0.0)
call UnitApplyTimedLife( d, 'BTLF', 30.0 )
call SetUnitAbilityLevel(d, 'A04U', lvl)
call IssuePointOrderLoc( d, "clusterrockets", l)
call RemoveLocation(l)
set u = null
set d = null
set l = null
endfunction
//===========================================================================
private function InitTrig_Call_Down takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=3
//TESH.alwaysfold=0
scope MineField01 initializer InitTrig_Mine_Field
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A05B'
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local player pl = GetOwningPlayer(u)
local location l
local real t = 0.5
local integer lvl = GetUnitAbilityLevel(u, 'A05B')
local integer lv = GetUnitAbilityLevel(u, 'A055')
local real i = 5 * lvl
local integer id
loop
exitwhen i <= 0
set l = GetUnitLoc(u)
//
if lv == 1 then
call CreateUnitAtLoc(pl, 'n00P', l, bj_UNIT_FACING )
endif
if lv == 2 then
call CreateUnitAtLoc(pl, 'n00Q', l, bj_UNIT_FACING )
endif
if lv == 3 then
call CreateUnitAtLoc(pl, 'n00R', l, bj_UNIT_FACING )
endif
if lv == 4 then
call CreateUnitAtLoc(pl, 'n00S', l, bj_UNIT_FACING )
else
call CreateUnitAtLoc(pl, 'n00P', l, bj_UNIT_FACING )
endif
//
set i = i - 1
call RemoveLocation(l)
set l = null
call TriggerSleepAction(t)
endloop
set u = null
endfunction
//===========================================================================
private function InitTrig_Mine_Field takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GreedyGoblin01 initializer InitTrig_Greedy_Goblin
private function Conditions takes nothing returns boolean
return GetUnitAbilityLevel(udg_Heroes[GetPlayerId(GetOwningPlayer(GetKillingUnit())) + 1], 'A05C') > 0 and IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(GetKillingUnit())) == true and IsUnitType(GetTriggerUnit(), UNIT_TYPE_SUMMONED) == false
endfunction
private function Actions takes nothing returns nothing
local unit u = udg_Heroes[GetPlayerId(GetOwningPlayer(GetKillingUnit())) + 1]
local unit v = GetTriggerUnit()
local player p = GetOwningPlayer(u)
local texttag te = CreateTextTag()
local real lv = GetUnitAbilityLevel(u, 'A05C')
local integer income = R2I(GetUnitState(v, UNIT_STATE_MAX_LIFE) * (lv * 0.01))
if income <= 0 then
set income = 1
endif
call SetTextTagText(te, "+" + I2S(income), 0.024)
call SetTextTagPos(te, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagColor(te, 255, 255, 0, 255)
call SetTextTagVelocity(te, 0, 0.04)
call SetTextTagVisibility(te, true)
call SetTextTagFadepoint(te, 2)
call SetTextTagLifespan(te, 5)
call SetTextTagPermanent(te, false)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + income)
set u = null
set v = null
set te = null
endfunction
//===========================================================================
private function InitTrig_Greedy_Goblin takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( t, Condition( function Conditions ) )
call TriggerAddAction( t, function Actions )
endfunction
endscope