Name | Type | is_array | initial_value |
pon | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
//Electric Grapple v1.1a //
// by: Nherwyziant //
//=======================//
//Credits: //
// Jesus4Lyf //
// Silvenon //
// PitzerMike //
//=======================//
scope ElectricGrapple initializer I
globals
private constant integer RAWCODE = 'A000' //~The rawcode of the spell
private constant integer LIGHTNINGCODE = 'A004' //~The rawcode of the chain lightning spell
private constant integer DUMMYID = 'h001' //~The rawcode of the dummy who casts the chain lightning
private constant real DURATION = 1 //~The duration of pulling
endglobals
private constant function ChancePerLvl takes integer lvl returns integer
return ( lvl * 5 ) + 10 //~The Chance is here
endfunction
private constant function Damage takes real lvl returns real
return GetEventDamage() * lvl
endfunction
//=======================DO NOT TOUCH==============================\\
private function Conditions takes nothing returns boolean
return GetUnitTypeId(GetEventDamageSource()) != DUMMYID and GetRandomInt(1,100)<=ChancePerLvl(GetUnitAbilityLevel(GetEventDamageSource(),RAWCODE))
endfunction
private function Actions takes nothing returns nothing
local real r
local unit c
local unit d = GetEventDamageSource()
local unit u = GetTriggerUnit()
local real dx = GetUnitX(u) - GetUnitX(d)
local real dy = GetUnitY(u) - GetUnitY(d)
local real dist = SquareRoot(dx * dx + dy * dy)-100
local real angle = Atan2(GetUnitY(d)-GetUnitY(u),GetUnitX(d)-GetUnitX(u))
local texttag t = CreateTextTag()
if IsUnitType(u,UNIT_TYPE_STRUCTURE)==false then
if GetUnitAbilityLevel(d,RAWCODE)>0 then
set c = CreateUnit(GetOwningPlayer(d),DUMMYID,GetUnitX(d),GetUnitY(d),GetUnitFacing(d))
set r = GetEventDamage()+Damage(GetUnitAbilityLevel(d,RAWCODE))
call Knockback(u,dist,angle,DURATION)
call UnitAddAbility(c,'Amrf')
call UnitRemoveAbility(c,'Amrf')
call SetUnitFlyHeight(c,GetUnitFlyHeight(d),0)
call UnitAddAbility(c,LIGHTNINGCODE)
call IssueTargetOrder(c,"fingerofdeath",u)
call UnitDamageTarget(c,u,Damage(GetUnitAbilityLevel(d,RAWCODE)),true,false,ATTACK_TYPE_HERO,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
call SetTextTagText(t,"|cffff0000"+I2S(R2I(r))+"!|r", 0.023)
call SetTextTagPos(t,GetUnitX(d),GetUnitY(d),GetUnitFlyHeight(d))
call SetTextTagColor(t,255,255,255,255)
call SetTextTagFadepoint(t,3)
call SetTextTagPermanent(t,false)
call SetTextTagVelocity(t,0,0.0455)
call SetTextTagLifespan(t,4)
call SetTextTagVisibility(t,true)
endif
endif
set u = null
set d = null
set t = null
endfunction
private function I takes nothing returns nothing
local trigger g=CreateTrigger()
call Damage_RegisterEvent(g)
call TriggerAddCondition(g,Condition(function Conditions))
call TriggerAddAction(g,function Actions)
endfunction
endscope
//TESH.scrollpos=0
//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.4
// 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_IsPhysical takes nothing returns boolean
// function Damage_IsSpell takes nothing returns boolean
// function Damage_IsPure takes nothing returns boolean
// - Wrappers to simply check if Damage_GetType is certain types.
//
// function Damage_IsAttack takes nothing returns boolean
// - Checks if the damage is from a physical attack (so you can deal
// physical damage without it being registered as an actual attack).
//
// 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 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 boolean array TypeStackAttack
private real array ToBlock
endglobals
public function GetType takes nothing returns damagetype
return TypeStackValue[TypeStackLevel]
endfunction
public function IsAttack takes nothing returns boolean
return TypeStackAttack[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 and GetEventDamage()!=0. then
call OnDamageEvent.fire()
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
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 TypeStackAttack[TypeStackLevel]=attack
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
public function Is$NAME$ takes nothing returns boolean
return GetType()==$TYPE$
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
public function IsPhysical takes nothing returns boolean
return GetType()==DAMAGE_TYPE_NORMAL
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 module InitModule
private static method 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
set TypeStackAttack[TypeStackLevel]=true
call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
endmethod
endmodule
private struct InitStruct extends array
implement InitModule
endstruct
endlibrary
//TESH.scrollpos=0
//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=77
//TESH.alwaysfold=0
library Knockback initializer Init
// **************************************************************************
// ** **
// ** Knockback(Ex) **
// ** ————————————— **
// ** **
// ** A function made for efficient knockbacking **
// ** **
// ** By: Silvenon **
// ** **
// **************************************************************************
//=======================================//
//Credits to PitzerMike for this function//
//=======================================//
globals
private constant integer DUMMY_ID = 'h000'
endglobals
private function TreeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local boolean i = IsDestructableInvulnerable(d)
local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), DUMMY_ID, GetWidgetX(d), GetWidgetY(d), 0)
local boolean result = false
call UnitAddAbility(u, 'Ahrl')
if i then
call SetDestructableInvulnerable(d, false)
endif
set result = IssueTargetOrder(u, "harvest", d)
call RemoveUnit(u)
if i then
call SetDestructableInvulnerable(d, true)
endif
set u = null
set d = null
return result
endfunction
//===========================================================================
globals
private timer Tim = CreateTimer()
private integer Total = 0
private boolexpr Cond = null
private integer array Ar
private boolean array BoolAr
private real MAX_X
private real MAX_Y
private real MIN_X
private real MIN_Y
endglobals
private constant function Interval takes nothing returns real
return 0.04
endfunction
private function KillTree takes nothing returns nothing
if BoolAr[0] then
call KillDestructable(GetEnumDestructable())
else
set BoolAr[1] = true
endif
endfunction
public struct Data
unit u
real d1
real d2
real sin
real cos
real r
string s = ""
effect e = null
static method create takes unit u, integer q, real d, real a, real r, integer t, string s, string p returns Data
local Data dat = Data.allocate()
set dat.u = u
set dat.d1 = 2 * d / (q + 1)
set dat.d2 = dat.d1 / q
set dat.sin = Sin(a)
set dat.cos = Cos(a)
set dat.r = r
if s != "" and s != null then
if t == 2 then
if p != "" and p != null then
set dat.e = AddSpecialEffectTarget(s, u, p)
else
set dat.e = AddSpecialEffectTarget(s, u, "chest")
endif
elseif t == 1 then
set dat.s = s
endif
endif
if Total == 0 then
call TimerStart(Tim, Interval(), true, function Data.Execute)
endif
set Total = Total + 1
set Ar[Total - 1] = dat
return dat
endmethod
static method Execute takes nothing returns nothing
local Data dat
local integer i = 0
local real x
local real y
local rect r
local real rad
loop
exitwhen i >= Total
set dat = Ar[i]
if dat.s != "" and dat.s != null then
set x = GetUnitX(dat.u)
set y = GetUnitY(dat.u)
call DestroyEffect(AddSpecialEffect(dat.s, x, y))
set x = x + dat.d1 * dat.cos
set y = y + dat.d1 * dat.sin
else
set x = GetUnitX(dat.u) + dat.d1 * dat.cos
set y = GetUnitY(dat.u) + dat.d1 * dat.sin
endif
if dat.r != 0 then
set BoolAr[0] = dat.r > 0
set rad = dat.r
if not BoolAr[0] then
set rad = rad * (-1)
endif
set r = Rect(x - rad, y - rad, x + rad, y + rad)
call EnumDestructablesInRect(r, Cond, function KillTree)
call RemoveRect(r)
set r = null
endif
if (x < MAX_X and y < MAX_Y and x > MIN_X and y > MIN_Y) and not BoolAr[1] then
call SetUnitX(dat.u, x)
call SetUnitY(dat.u, y)
endif
set dat.d1 = dat.d1 - dat.d2
if dat.d1 <= 0 or (x > MAX_X or y > MAX_Y or x < MIN_X or y < MIN_Y) or BoolAr[1] then
set Ar[i] = Ar[Total - 1]
set Total = Total - 1
call dat.destroy()
endif
set i = i + 1
endloop
if Total == 0 then
call PauseTimer(Tim)
endif
endmethod
method onDestroy takes nothing returns nothing
if .e != null then
call DestroyEffect(.e)
endif
set BoolAr[0] = false
set BoolAr[1] = false
endmethod
endstruct
function Knockback takes unit u, real d, real a, real w returns nothing
call Data.create(u, R2I(w / Interval()), d, a, 0, 0, "", "")
endfunction
private function Init takes nothing returns nothing
set Cond = Filter(function TreeFilter)
set BoolAr[0] = false
set BoolAr[1] = false
set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea) - 64
set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea) - 64
set MIN_X = GetRectMinX(bj_mapInitialPlayableArea) + 64
set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea) + 64
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Initialization initializer Init
private function Actions takes nothing returns nothing
local location l
local unit h
local real x = 0
local real y = 0
local integer i = 0
call FogEnable(false)
call FogMaskEnable(false)
loop
exitwhen i > 4
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
set l = GetStartLocationLoc(GetPlayerStartLocation(Player(0)))
set h = CreateUnitAtLoc(Player(i),'H000',l,GetRandomReal(0, 360))
call SetHeroLevel(h, 10, true)
call PanCameraToLocForPlayer(Player(i), l)
call SelectUnitAddForPlayer(h, Player(i))
call AdjustPlayerStateBJ( 30, Player(i), PLAYER_STATE_RESOURCE_GOLD )
endif
set i = i+1
endloop
set l = null
set h = null
endfunction
private function Init takes nothing returns nothing
set gg_trg_Initialization = CreateTrigger( )
call TriggerAddAction( gg_trg_Initialization, function Actions )
endfunction
endscope