library ChainAbilSystem initializer Init needs Array, GroupUtils, DamageDetection
//*******************************************************************************
//* ChainAbilSystem - v.01 by Inferior
//*
//* requires:
//* - Array by Inferior
//* - GroupUtils by Rising_Dusk
//* - DamageDetection by Inferior ( But can use any other DamageDetectionSystem aswell )
//*
//* The purpose of this System is to easily create Chain Abilities
//* like ChainLightning or HealingWave, with your own effects.
//* First of all you have to create the very important buff.
//* Therefor you can use the ObjectMerger call below. Just remove the exclamations,
//* Save the map, close and reopen your map and put exclamations again.
//*
//* //! external ObjectMerger w3h BNab ChAB fnam "ChainAbilBuff" fart "ReplaceableTextures\CommandButtons\BTNScatterRockets.blp" ftat "" ftip "" fube ""
//*
//* Befor you can use a Chain Ability you have to specify its type:
//* Example:
//* local ChainAbil c=ChainAbil.create("TheCasterAbility","TheDummyAbility","WhatHappensWhenTheChainHits","PickTargetAoE","HitsMoreThanOnce?","FilterMeOut")
//* - "TheCasterAbility" : This Specifies the Chain Type. A Chain can only be assigned to one Ability and vice versa.
//* It is aswell required to check for the Chains Level.
//* - "TheDummyAbility" : This is like the Chains core. This is allways required. It makes the Chain have an Eyecandy.
//* - "WhatHappensWhenTheChainHits" : The Function that shall be executed when the Chain hits a target:
//* This Function must follow the function interface below!
//* - "PickTargetAoE" : The Area in which possible Targets shall be picked.
//* - "HitsMoreThanOnce?" : Can a Target be hit more than one time.
//* - "FilterMeOut" : To Filter the possible Targets. Better check the sample for that.
//*
//* c.hitCount[0]=4
//* c.hitCount[1]=6 - Assigns the number of targets per Level. Be carefull the counter starts at 0
//* ........... not at 1!!
//* c.hitCount["how much levels you like"]=9
//*
//* To create the Dummy Ability just use the ObjectMerger below.
//! textmacro AbilGen takes id,missile,arc,speed
//! external ObjectMerger w3a ANab $id$ anam "ChainAbil$id$" Nab4 1 0.0 Nab3 1 0 Nab6 1 100. Nab5 1 0.0 aani "" amat "$missile$" amac $arc$ amsp $speed$ acdn 1 0 ahdu 1 1.0 adur 1 1.0 amcs 1 0 alev 1 aher 0 aare 1 0.0 aran 1 9999.0 abuf 1 ChAB
//! endtextmacro
//* Example: //! runtextmacro AbilGen("WhatEverRawCode","WhatEverMissileArt","WhateverArc (between 0.0 and 1.0)","WhatEverSpeed")
//*
//* Now you are done. To use a chain simply use the function:
//*
//* call CastChainOnUnit("AtWhichUnit","WhichUnitUsesIt","OneOfYourChainTypes")
//*
//* For more Information check out the samples!
//****************************************************************************************************
globals
private constant integer dummyID = 'e000' //* Set this to the Dummy Rawcode of your map
//* If you do not have a dummy unit create one and
//* Import the model included in this map!
private constant integer maxLevel = 4 //* The maximum Level that the Chains can have
//* The limit is at 8190!
private constant integer checkBuff ='ChAB' //* If You have used the ObjectMerger to create the buff
//* you don't have to change this. Else you have to set this
//* to the correct RawCode!
//* DO NOT TOUCH ANYTHING BELOW, UNLESS YOU KNOW WHAT YOU DO!!
unit ChainAbil_TempUnit
unit ChainAbil_TempTarg
endglobals
function interface onChainHit takes unit whichTarget, unit whichSource, integer hitCount returns nothing
struct ChainData
integer hitCount=0
unit caster
unit dummy
integer index
IntegerArray DataArray
static IntegerArray cData
method clear takes nothing returns nothing
set this.hitCount=0
call RemoveUnit(this.dummy)
set this.index=0
call this.DataArray.clear()
endmethod
static method operator [] takes unit whichUnit returns ChainData
return thistype.cData[whichUnit]
endmethod
static method create takes nothing returns ChainData
return ChainData.allocate()
endmethod
endstruct
struct ChainAbil
private integer AbilID
private integer ChainID
private onChainHit response
private real AoE
private boolean multiHit
private boolexpr filter
integer array hitCount[maxLevel]
static InfiniteIntegerArray AbilData
method onCast takes unit whichTarget, unit whichSource returns nothing
local ChainData Data=ChainData.create()
set Data.hitCount=.hitCount[GetUnitAbilityLevel(whichSource,.AbilID)-1]
set Data.caster=whichSource
set Data.DataArray=IntegerArray.newArray()
set Data.index=this
set Data.dummy=CreateUnit(GetOwningPlayer(Data.caster),dummyID,0,0,0)
call UnitAddAbility(Data.dummy,'Amrf')
call UnitRemoveAbility(Data.dummy,'Amrf')
call SetUnitX(Data.dummy,GetUnitX(Data.caster))
call SetUnitY(Data.dummy,GetUnitY(Data.caster))
set ChainData.cData[Data.dummy]=Data
call UnitAddAbility(Data.dummy,.ChainID)
call IssueTargetOrder(Data.dummy,"acidbomb",whichTarget)
endmethod
static method onAbilHit takes unit whichTarget, unit whichSource, real damage returns nothing
local ChainAbil data
local ChainData Data
local group g
if GetUnitAbilityLevel(whichTarget,checkBuff)>0 then
call UnitRemoveAbility(whichTarget,checkBuff)
set Data=ChainData.cData[whichSource]
set data=Data.index
call data.response.evaluate(whichTarget,Data.caster,Data.hitCount)
set Data.hitCount=Data.hitCount-1
if Data.hitCount<=0 then
call Data.clear()
return
endif
call SetUnitX(Data.dummy,GetUnitX(whichTarget))
call SetUnitY(Data.dummy,GetUnitY(whichTarget))
set g=NewGroup()
set ChainAbil_TempUnit=Data.dummy
set ChainAbil_TempTarg=whichTarget
call GroupEnumUnitsInArea(g,GetUnitX(Data.dummy),GetUnitY(Data.dummy),data.AoE,data.filter)
set ChainAbil_TempTarg=GroupPickRandomUnit(g)
call ReleaseGroup(g)
if ChainAbil_TempTarg==null then
call Data.clear()
return
endif
call IssueTargetOrder(Data.dummy,"acidbomb",ChainAbil_TempTarg)
if not data.multiHit then
set Data.DataArray[whichTarget]=Data
endif
set ChainAbil_TempUnit=null
set ChainAbil_TempTarg=null
endif
endmethod
static method create takes integer abilID, integer chainID, onChainHit response, real AoE, boolean flag, boolexpr filter returns ChainAbil
local ChainAbil data
if not ChainAbil.AbilData.assigned(abilID) then
set data=ChainAbil.allocate()
set data.AbilID=abilID
set data.ChainID=chainID
set data.response=response
set data.AoE=AoE
set data.filter=filter
set data.multiHit=flag
set ChainAbil.AbilData[abilID]=data
return data
else
debug call BJDebugMsg("Warning: There allready exists a ChainType for this Ability!!")
return 0x00
endif
endmethod
endstruct
function CastChainOnUnit takes unit whichTarget, unit whichSource, ChainAbil whichChain returns nothing
call whichChain.onCast(whichTarget,whichSource)
endfunction
private function Init takes nothing returns nothing
set ChainAbil.AbilData=IntegerArray.newArray()
set ChainData.cData=IntegerArray.newArray()
call AddSpellResponse(ChainAbil.onAbilHit)
endfunction
endlibrary