Moderator
M
Moderator
Twisted Fate 006 | Reviewed by Maker | 28th May 2013 | ||||
APPROVED | ||||
|
library tfConsts initializer i
globals
//* SETUP SECTION
public constant integer TF_ID ='H000' //unit ID of "Card Master" unit
public constant integer CASTER_DUMMY_ID ='h002' //unit ID of "Caster (Dummy)" unit
public constant integer EYE_DUMMY_ID ='h003' //unit ID of "Eye (Dummy)" unit
public constant integer CARD_DUMMY_ID ='h001' //unit ID of "Card (Dummy)" unit
public constant integer WILD_CARDS_ID ='A001' //ability ID of "Wild Cards" ability
public constant integer PICK_A_CARD_ID ='A002' //ability ID of "Pick a Card" ability
public constant integer DIS_PICK_A_CARD_ID='A006' //ability ID of "Pick a Card (disabled dummy ability" ability
public constant integer BLUE_CARD_ID ='A003' //ability ID of "Blue" ability
public constant integer DIS_BLUE_CARD_ID ='A007' //ability ID of "Blue (enabled card)" ability
public constant integer RED_CARD_ID ='A004' //ability ID of "Red" ability
public constant integer DIS_RED_CARD_ID ='A008' //ability ID of "Red (enabled card)" ability
public constant integer GOLD_CARD_ID ='A005' //ability ID of "Gold" ability
public constant integer DIS_GOLD_CARD_ID ='A009' //ability ID of "Gold (enabled card)" ability
public constant integer DUMMY_SLOW_ID ='A00B' //ability ID of "Slow (Red Card)" ability
public constant integer DUMMY_STUN_ID ='A00C' //ability ID of "Stun (Gold Card)" ability
public constant integer STACKED_DECK_ID ='A00D' //ability ID of "Stacked Deck" ability
public constant integer DESTINY_ID ='A00E' //ability ID of "Destiny" ability
public constant integer GATE_ID ='A00G' //ability ID of "Gate" ability
public constant integer DIS_GATE_ID ='A00F' //ability ID of "Gate (disabled)" ability
//* END SETUP SECTION
//* CUSTOMIZE SECTION
public constant real FPS =1./30. //The period for smooth abilities. should be between 1./100. and 1./20. depending on necessary
//performance. A good starting value for multiplayer should be 1./30.
//* END CUSTOMIZE SECTION
public constant integer BLUE_CARD=0
public constant integer RED_CARD =1
public constant integer GOLD_CARD=2
public integer array CARD_ID[3]
public HandleTable hiddenCard
private group grp=CreateGroup()
endglobals
private function f takes nothing returns boolean
local unit enum=GetEnumUnit()
if GetUnitTypeId(enum)==TF_ID then
set hiddenCard[enum]=BLUE_CARD
endif
set enum=null
return false
endfunction
private function c takes nothing returns boolean
local unit tU=GetTriggerUnit()
if GetUnitTypeId(tU)==TF_ID then
set hiddenCard[tU]=BLUE_CARD
endif
set tU=null
return false
endfunction
private function i takes nothing returns nothing
local trigger initializeNewTFs=CreateTrigger()
local region reg=CreateRegion()
set hiddenCard=HandleTable.create()
set CARD_ID[BLUE_CARD]=BLUE_CARD_ID
set CARD_ID[RED_CARD]=RED_CARD_ID
set CARD_ID[GOLD_CARD]=GOLD_CARD_ID
call RegionAddRect(reg,bj_mapInitialPlayableArea)
call TriggerRegisterEnterRegion(initializeNewTFs,reg,null)
call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,Filter(function f))
call TriggerAddCondition(initializeNewTFs,Condition(function c))
call DestroyGroup(grp)
set grp=null
set reg=null
set initializeNewTFs=null
endfunction
endlibrary
scope loadedDice initializer i
globals
private group grp=CreateGroup()
endglobals
private function c takes nothing returns boolean
local unit FoG
local unit kU=GetKillingUnit()
local player kUOwner=GetOwningPlayer(kU)
local boolean found=false
if IsUnitType(kU,UNIT_TYPE_HERO) then
call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null or found
if GetUnitTypeId(FoG)==tfConsts_TF_ID and IsUnitType(FoG,UNIT_TYPE_DEAD)==false and IsUnitAlly(FoG,kUOwner) then
set found=true
endif
call GroupRemoveUnit(grp,FoG)
endloop
if found then
call SetPlayerState(kUOwner,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(kUOwner,PLAYER_STATE_RESOURCE_GOLD)+2)
call TextTag_GoldBounty(kU,2,kUOwner)
endif
endif
set kU=null
return false
endfunction
private function i takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function c))
set t=null
endfunction
endscope
scope wildCards initializer i
private struct cardDat
unit caster
unit array cards[3]
real array gradX[3]
real array gradY[3]
real damage
real traveled=0.
group struckUnits
endstruct
private struct cdrDat
unit fate
endstruct
globals
private constant real OFFSET_ANGLE=30.*bj_DEGTORAD
private constant real PROJECTILE_SPEED=700.
private constant real ENUM_RADIUS=125./2.
private constant real TOTAL_DISTANCE=1450.
private constant real COOLDOWN=6.
private cardDat array datDB
private integer dbIndex=-1
private timer time=CreateTimer()
private group grp=CreateGroup()
private HandleTable cdrTable
endglobals
private function setCardRandHue takes unit u returns nothing
local integer i=GetRandomInt(0,2)
if i==0 then
call SetUnitVertexColor(u,255,55,55,255)
elseif i==1 then
call SetUnitVertexColor(u,255,245,55,255)
else
call SetUnitVertexColor(u,80,80,255,255)
endif
endfunction
private function p takes nothing returns nothing
local integer index=0
local integer tripleLooper
local cardDat tempDat
local real uX
local real uY
local unit FoG
loop
exitwhen index>dbIndex
set tempDat=datDB[index]
set tripleLooper=0
loop
exitwhen tripleLooper>2
set uX=GetUnitX(tempDat.cards[tripleLooper])+tempDat.gradX[tripleLooper]
set uY=GetUnitY(tempDat.cards[tripleLooper])+tempDat.gradY[tripleLooper]
call SetUnitX(tempDat.cards[tripleLooper],uX)
call SetUnitY(tempDat.cards[tripleLooper],uY)
call GroupEnumUnitsInRange(grp,uX,uY,ENUM_RADIUS,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitEnemy(FoG,GetOwningPlayer(tempDat.caster)) and IsUnitType(FoG,UNIT_TYPE_DEAD)==false and IsUnitType(FoG,UNIT_TYPE_STRUCTURE)==false and IsUnitInGroup(FoG,tempDat.struckUnits)==false then
call DamageType_dealCodeDamage(tempDat.caster,FoG,tempDat.damage,DAMAGE_TYPE_MAGIC)
call GroupAddUnit(tempDat.struckUnits,FoG)
endif
call GroupRemoveUnit(grp,FoG)
endloop
set tripleLooper=tripleLooper+1
endloop
set tempDat.traveled=tempDat.traveled+PROJECTILE_SPEED*tfConsts_FPS
if tempDat.traveled>=TOTAL_DISTANCE then
call RemoveUnit(tempDat.cards[0])
call RemoveUnit(tempDat.cards[1])
call RemoveUnit(tempDat.cards[2])
call DestroyGroup(tempDat.struckUnits)
call tempDat.destroy()
set datDB[index]=datDB[dbIndex]
set index=index-1
set dbIndex=dbIndex-1
if dbIndex==-1 then
call PauseTimer(time)
endif
endif
set index=index+1
endloop
endfunction
private function cdr takes nothing returns nothing
local timer clock=GetExpiredTimer()
local cdrDat tempDat=cdrTable[clock]
call UnitRemoveAbility(tempDat.fate,tfConsts_WILD_CARDS_ID)
call UnitAddAbility(tempDat.fate,tfConsts_WILD_CARDS_ID)
call tempDat.destroy()
call cdrTable.flush(clock)
call DestroyTimer(clock)
set clock=null
endfunction
private function c takes nothing returns boolean
local cardDat tempDat
local cdrDat ridiculousUseOfStruct
local player owner
local unit tU
local real tX
local real tY
local real tUX
local real tUY
local real angle
local timer cdrClock
if GetSpellAbilityId()==tfConsts_WILD_CARDS_ID then
set tU=GetTriggerUnit()
set owner=GetOwningPlayer(tU)
set tX=GetSpellTargetX()
set tY=GetSpellTargetY()
set tUX=GetUnitX(tU)
set tUY=GetUnitY(tU)
set angle=Atan2(tY-tUY,tX-tUX)
set tempDat=cardDat.create()
set tempDat.cards[0]=CreateUnit(owner,tfConsts_CARD_DUMMY_ID,0.,0.,(angle-OFFSET_ANGLE)*bj_RADTODEG)
set tempDat.cards[1]=CreateUnit(owner,tfConsts_CARD_DUMMY_ID,0.,0.,angle*bj_RADTODEG)
set tempDat.cards[2]=CreateUnit(owner,tfConsts_CARD_DUMMY_ID,0.,0.,(angle+OFFSET_ANGLE)*bj_RADTODEG)
call setCardRandHue(tempDat.cards[0])
call setCardRandHue(tempDat.cards[1])
call setCardRandHue(tempDat.cards[2])
call SetUnitX(tempDat.cards[0],tUX)
call SetUnitX(tempDat.cards[1],tUX)
call SetUnitX(tempDat.cards[2],tUX)
call SetUnitY(tempDat.cards[0],tUY)
call SetUnitY(tempDat.cards[1],tUY)
call SetUnitY(tempDat.cards[2],tUY)
set tempDat.gradX[0]=PROJECTILE_SPEED*tfConsts_FPS*Cos(angle-OFFSET_ANGLE)
set tempDat.gradX[1]=PROJECTILE_SPEED*tfConsts_FPS*Cos(angle)
set tempDat.gradX[2]=PROJECTILE_SPEED*tfConsts_FPS*Cos(angle+OFFSET_ANGLE)
set tempDat.gradY[0]=PROJECTILE_SPEED*tfConsts_FPS*Sin(angle-OFFSET_ANGLE)
set tempDat.gradY[1]=PROJECTILE_SPEED*tfConsts_FPS*Sin(angle)
set tempDat.gradY[2]=PROJECTILE_SPEED*tfConsts_FPS*Sin(angle+OFFSET_ANGLE)
set tempDat.struckUnits=CreateGroup()
set tempDat.caster=tU
set tempDat.damage=10.+50.*GetUnitAbilityLevel(tU,tfConsts_WILD_CARDS_ID)+.65*GetHeroInt(tU,true)
set dbIndex=dbIndex+1
set datDB[dbIndex]=tempDat
if dbIndex==0 then
call TimerStart(time,tfConsts_FPS,true,function p)
endif
if GetUnitAbilityLevel(tempDat.caster,tfConsts_STACKED_DECK_ID)>0 then
set cdrClock=CreateTimer()
set ridiculousUseOfStruct=cdrDat.create()
set ridiculousUseOfStruct.fate=tempDat.caster
set cdrTable[cdrClock]=ridiculousUseOfStruct
call TimerStart(cdrClock,COOLDOWN-COOLDOWN*0.03*GetUnitAbilityLevel(tempDat.caster,tfConsts_STACKED_DECK_ID),false,function cdr)
set cdrClock=null
endif
set tU=null
endif
return false
endfunction
private function i takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function c))
set cdrTable=HandleTable.create()
set t=null
endfunction
endscope
scope pickACard initializer i
private struct pickDat
unit fate
integer revertAbilityLevel
real elapsedTime
boolean locked=false
boolean thrown=false
endstruct
private struct dummyCardDat
unit dummy
unit fate
endstruct
globals
private constant real CYCLE_MAX_DURATION=15.
private constant real COOLDOWN=6.
private constant real CARD_CYCLE_PERIOD=.6
private constant real RED_CARD_ENUM_RANGE=200.
private constant string TICKSOUND="Sound\\Interface\\MouseClick1.wav"
private constant string BLUESOUND="Abilities\\Spells\\Human\\Banish\\BanishCaster.wav"
private constant string BLUEFX ="Units\\NightElf\\Wisp\\WispExplode.mdl"
private constant string REDSOUND ="Abilities\\Spells\\Human\\Defend\\DefendCaster.wav"
private constant string REDFX ="Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl"
private constant string GOLDSOUND="Abilities\\Spells\\Human\\HolyBolt\\HolyBolt.mdl"
private constant string GOLDFX ="Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private HandleTable fromTimer
private HandleTable fromFate
private sound snd
private dummyCardDat array dummyDB
private integer dummyDBIndex=-1
private timer dummyClock=CreateTimer()
private unit casterDummy
private group grp=CreateGroup()
endglobals
private function ddHandler takes nothing returns nothing
local real damage=GetEventDamage()
local unit dSource=GetEventDamageSource()
local unit tU
local unit FoG
local pickDat tempDat
local player owner
local sound colorSound
local real tX
local real tY
local real index
if DamageType_get(damage)==DamageType_ATTACK and GetUnitTypeId(dSource)==tfConsts_TF_ID then
set tempDat=fromFate[dSource]
set tU=GetTriggerUnit()
set owner=GetOwningPlayer(dSource)
if GetUnitAbilityLevel(dSource,tfConsts_DIS_BLUE_CARD_ID)>0 then
set colorSound=CreateSound(BLUESOUND,false,true,true,12700,12700,"")
call SetSoundVolume(colorSound,127)
call SetSoundPitch(colorSound,.75)
call SetSoundPosition(colorSound,GetUnitX(tU),GetUnitY(tU),100.)
call StartSound(colorSound)
call KillSoundWhenDone(colorSound)
if IsUnitType(tU,UNIT_TYPE_DEAD)==false then
call DamageType_dealCodeDamage(dSource,tU,20+20*tempDat.revertAbilityLevel+.4*GetHeroInt(dSource,true),DAMAGE_TYPE_MAGIC)
endif
call SetUnitState(dSource,UNIT_STATE_MANA,GetUnitState(dSource,UNIT_STATE_MANA)+46+2.9*GetHeroLevel(dSource)+13+13*tempDat.revertAbilityLevel)
call UnitRemoveAbility(dSource,tfConsts_DIS_BLUE_CARD_ID)
set tempDat.thrown=true
set tempDat.elapsedTime=CYCLE_MAX_DURATION
call DestroyEffect(AddSpecialEffect(BLUEFX,GetUnitX(tU),GetUnitY(tU)))
elseif GetUnitAbilityLevel(dSource,tfConsts_DIS_RED_CARD_ID)>0 then
set tX=GetUnitX(tU)
set tY=GetUnitY(tU)
set colorSound=CreateSound(REDSOUND,false,true,true,12700,12700,"")
call SetSoundVolume(colorSound,127)
call SetSoundPitch(colorSound,.75)
call SetSoundPosition(colorSound,tX,tY,100.)
call StartSound(colorSound)
call KillSoundWhenDone(colorSound)
call GroupEnumUnitsInRange(grp,GetUnitX(tU),GetUnitY(tU),RED_CARD_ENUM_RANGE,null)
if IsUnitType(tU,UNIT_TYPE_STRUCTURE)==false and IsUnitType(tU,UNIT_TYPE_DEAD)==false then
call DamageType_dealCodeDamage(dSource,tU,15+15*tempDat.revertAbilityLevel+.4*GetHeroInt(tempDat.fate,true),DAMAGE_TYPE_MAGIC)
endif
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitEnemy(FoG,owner) and IsUnitType(FoG,UNIT_TYPE_STRUCTURE)==false and IsUnitType(FoG,UNIT_TYPE_DEAD)==false then
if FoG!=tU then
call DamageType_dealCodeDamage(dSource,FoG,15+15*tempDat.revertAbilityLevel+.4*GetHeroInt(dSource,true)+46+2.9*GetHeroLevel(dSource),DAMAGE_TYPE_MAGIC)
endif
call SetUnitX(casterDummy,tX)
call SetUnitY(casterDummy,tY)
call UnitAddAbility(casterDummy,tfConsts_DUMMY_SLOW_ID)
call SetUnitAbilityLevel(casterDummy,tfConsts_DUMMY_SLOW_ID,tempDat.revertAbilityLevel)
call IssueTargetOrder(casterDummy,"slow",FoG)
call UnitRemoveAbility(casterDummy,tfConsts_DUMMY_SLOW_ID)
endif
call GroupRemoveUnit(grp,FoG)
endloop
call UnitRemoveAbility(dSource,tfConsts_DIS_RED_CARD_ID)
set tempDat.thrown=true
set tempDat.elapsedTime=CYCLE_MAX_DURATION
call DestroyEffect(AddSpecialEffect(REDFX,tX,tY))
set index=0.
loop
exitwhen index>bj_PI*2.
call DestroyEffect(AddSpecialEffect(REDFX,tX+RED_CARD_ENUM_RANGE/2.*Cos(index),tY+RED_CARD_ENUM_RANGE/2.*Sin(index)))
set index=index+bj_PI/9.
endloop
elseif GetUnitAbilityLevel(dSource,tfConsts_DIS_GOLD_CARD_ID)>0 then
set tX=GetUnitX(tU)
set tY=GetUnitY(tU)
set colorSound=CreateSound(GOLDSOUND,false,true,true,12700,12700,"")
call SetSoundVolume(colorSound,127)
call SetSoundPitch(colorSound,2.)
call SetSoundPosition(colorSound,tX,tY,100.)
call StartSound(colorSound)
call KillSoundWhenDone(colorSound)
if IsUnitType(tU,UNIT_TYPE_DEAD)==false then
call DamageType_dealCodeDamage(dSource,tU,7.5+7.5*tempDat.revertAbilityLevel+.4*GetHeroInt(tempDat.fate,true),DAMAGE_TYPE_MAGIC)
call SetUnitX(casterDummy,tX)
call SetUnitY(casterDummy,tY)
call UnitAddAbility(casterDummy,tfConsts_DUMMY_STUN_ID)
call SetUnitAbilityLevel(casterDummy,tfConsts_DUMMY_STUN_ID,tempDat.revertAbilityLevel)
call IssueTargetOrder(casterDummy,"thunderbolt",tU)
call UnitRemoveAbility(casterDummy,tfConsts_DUMMY_STUN_ID)
endif
call UnitRemoveAbility(dSource,tfConsts_DIS_GOLD_CARD_ID)
set tempDat.thrown=true
set tempDat.elapsedTime=CYCLE_MAX_DURATION
call DestroyEffect(AddSpecialEffect(GOLDFX,tX,tY))
endif
set tU=null
set colorSound=null
endif
set dSource=null
endfunction
private function dummyP takes nothing returns nothing
local integer index=0
local dummyCardDat tempDat
loop
exitwhen index>dummyDBIndex
set tempDat=dummyDB[index]
call SetUnitX(tempDat.dummy,GetUnitX(tempDat.fate))
call SetUnitY(tempDat.dummy,GetUnitY(tempDat.fate))
if GetUnitAbilityLevel(tempDat.fate,tfConsts_CARD_ID[tfConsts_BLUE_CARD])>0 or GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_BLUE_CARD_ID)>0 then
call SetUnitVertexColor(tempDat.dummy,80,80,255,255)
elseif GetUnitAbilityLevel(tempDat.fate,tfConsts_CARD_ID[tfConsts_RED_CARD])>0 or GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_RED_CARD_ID)>0 then
call SetUnitVertexColor(tempDat.dummy,255,55,55,255)
elseif GetUnitAbilityLevel(tempDat.fate,tfConsts_CARD_ID[tfConsts_GOLD_CARD])>0 or GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_GOLD_CARD_ID)>0 then
call SetUnitVertexColor(tempDat.dummy,255,245,55,255)
else
call RemoveUnit(tempDat.dummy)
set tempDat.dummy=null
set tempDat.fate=null
call tempDat.destroy()
set dummyDB[index]=dummyDB[dummyDBIndex]
set dummyDBIndex=dummyDBIndex-1
set index=index-1
if dummyDBIndex==-1 then
call PauseTimer(dummyClock)
endif
endif
set index=index+1
endloop
endfunction
private function p takes nothing returns nothing
local timer time=GetExpiredTimer()
local pickDat tempDat=fromTimer[time]
local integer cardID=tfConsts_hiddenCard[tempDat.fate]
set tempDat.elapsedTime=tempDat.elapsedTime+CARD_CYCLE_PERIOD
if tempDat.elapsedTime<CYCLE_MAX_DURATION and tempDat.thrown==false then
if tempDat.locked==false and (GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_BLUE_CARD_ID)>0 or GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_RED_CARD_ID)>0 or GetUnitAbilityLevel(tempDat.fate,tfConsts_DIS_GOLD_CARD_ID)>0) then
set tempDat.locked=true
endif
if tempDat.locked==false then
call UnitRemoveAbility(tempDat.fate,tfConsts_CARD_ID[cardID])
endif
if cardID==tfConsts_GOLD_CARD then
set cardID=tfConsts_BLUE_CARD
else
set cardID=cardID+1
endif
if tempDat.locked==false then
call UnitAddAbility(tempDat.fate,tfConsts_CARD_ID[cardID])
if GetLocalPlayer()==GetOwningPlayer(tempDat.fate) then
call StartSound(snd)
endif
endif
else
call UnitRemoveAbility(tempDat.fate,tfConsts_CARD_ID[cardID])
call UnitRemoveAbility(tempDat.fate,tfConsts_DIS_BLUE_CARD_ID)
call UnitRemoveAbility(tempDat.fate,tfConsts_DIS_RED_CARD_ID)
call UnitRemoveAbility(tempDat.fate,tfConsts_DIS_GOLD_CARD_ID)
call UnitAddAbility(tempDat.fate,tfConsts_DIS_PICK_A_CARD_ID)
endif
if tempDat.elapsedTime>CYCLE_MAX_DURATION+COOLDOWN-COOLDOWN*0.03*GetUnitAbilityLevel(tempDat.fate,tfConsts_STACKED_DECK_ID) then
call SetUnitAbilityLevel(tempDat.fate,tfConsts_PICK_A_CARD_ID,tempDat.revertAbilityLevel)
call UnitRemoveAbility(tempDat.fate,tfConsts_DIS_PICK_A_CARD_ID)
call tempDat.destroy()
call fromTimer.flush(time)
call DestroyTimer(time)
endif
set tfConsts_hiddenCard[tempDat.fate]=cardID
set time=null
endfunction
private function c takes nothing returns boolean
local pickDat tempDat
local dummyCardDat tempDCDat
local timer time
if GetSpellAbilityId()==tfConsts_PICK_A_CARD_ID then
//store all data in struct instance
set tempDat=pickDat.create()
set tempDat.fate=GetTriggerUnit()
set tempDat.revertAbilityLevel=GetUnitAbilityLevel(tempDat.fate,tfConsts_PICK_A_CARD_ID)
set tempDat.elapsedTime=0.
//make the ability unavailable
call SetUnitAbilityLevel(tempDat.fate,tfConsts_PICK_A_CARD_ID,5)
call IncUnitAbilityLevel(tempDat.fate,tfConsts_PICK_A_CARD_ID)
//add the proper ability depending on the current value stored in the table
call UnitAddAbility(tempDat.fate,tfConsts_CARD_ID[tfConsts_hiddenCard[tempDat.fate]])
//create new timer, because sharing a periodic timer with a card cycle period between 0.3 and 0.7 seconds will not only look poor,
//but potentially cause problems for TF vs TF situations.
//begin counting towards the duration. After picking a card, this same duration will be kept, and after the max is reached,
//or the card is thrown, the ability will reset to the original ability.
set time=CreateTimer()
set fromTimer[time]=tempDat
set fromFate[tempDat.fate]=tempDat
call TimerStart(time,CARD_CYCLE_PERIOD,true,function p)
//create the dummy card and give it the proper color. we need to attach it to a different, more smooth timer. This one will be stack based.
set tempDCDat=dummyCardDat.create()
set tempDCDat.fate=tempDat.fate
set tempDCDat.dummy=CreateUnit(GetOwningPlayer(tempDat.fate),tfConsts_CARD_DUMMY_ID,GetUnitX(tempDat.fate),GetUnitY(tempDat.fate),0.)
call UnitAddAbility(tempDCDat.dummy,'arav')
call UnitRemoveAbility(tempDCDat.dummy,'arav')
call SetUnitFlyHeight(tempDCDat.dummy,150.,0.)
call SetUnitTimeScale(tempDCDat.dummy,.5)
set dummyDBIndex=dummyDBIndex+1
set dummyDB[dummyDBIndex]=tempDCDat
if dummyDBIndex==0 then
call TimerStart(dummyClock,tfConsts_FPS,true,function dummyP)
endif
set time=null
endif
return false
endfunction
private function secondC takes nothing returns boolean
local integer id=GetSpellAbilityId()
local unit tU
if id==tfConsts_BLUE_CARD_ID then
set tU=GetTriggerUnit()
call UnitRemoveAbility(tU,tfConsts_BLUE_CARD_ID)
call UnitAddAbility(tU,tfConsts_DIS_BLUE_CARD_ID)
set tU=null
elseif id==tfConsts_RED_CARD_ID then
set tU=GetTriggerUnit()
call UnitRemoveAbility(tU,tfConsts_RED_CARD_ID)
call UnitAddAbility(tU,tfConsts_DIS_RED_CARD_ID)
set tU=null
elseif id==tfConsts_GOLD_CARD_ID then
set tU=GetTriggerUnit()
call UnitRemoveAbility(tU,tfConsts_GOLD_CARD_ID)
call UnitAddAbility(tU,tfConsts_DIS_GOLD_CARD_ID)
set tU=null
endif
return false
endfunction
private function i takes nothing returns nothing
local trigger initialCast=CreateTrigger()
local trigger secondCast=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(secondCast,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(secondCast,Condition(function secondC))
set fromTimer=HandleTable.create()
set fromFate =HandleTable.create()
set snd=CreateSound(TICKSOUND,false,false,false,12700,12700,"")
call SetSoundVolume(snd,127)
call SetSoundPitch(snd,0.5)
call StartSound(snd)
call TriggerRegisterAnyUnitEventBJ(initialCast,EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(initialCast,Condition(function c))
call StructuredDD_ddBucket.addHandler(function ddHandler)
set casterDummy=CreateUnit(Player(15),tfConsts_CASTER_DUMMY_ID,0.,0.,0.)
set initialCast=null
endfunction
endscope
scope stackedDeck initializer i
private struct stackDat
integer count
effect aura
endstruct
globals
private constant string NEXT_HIT_FX="Abilities\\Spells\\Undead\\RegenerationAura\\ObsidianRegenAura.mdl"
private constant string TARGET_FX="Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
private constant string HIT_SOUND="Abilities\\Spells\\Human\\Polymorph\\PolymorphDone.wav"
private HandleTable attackCounts
endglobals
private function handler takes nothing returns nothing
local unit dSource=GetEventDamageSource()
local integer level=GetUnitAbilityLevel(dSource,tfConsts_STACKED_DECK_ID)
local integer count
local stackDat tempDat
local unit tU
local sound snd
if DamageType_get(GetEventDamage())==DamageType_ATTACK and level>0 then
if attackCounts.exists(dSource) then
set tempDat=attackCounts[dSource]
if tempDat.count==3 then //this attack is a proc, let's deal extra damage
set tU=GetTriggerUnit()
call DamageType_dealCodeDamage(dSource,tU,30.+25.*level+.4*GetHeroInt(dSource,true),DAMAGE_TYPE_MAGIC)
//then reset attackCount
set tempDat.count=0
//and remove the effect added when count was 2
call DestroyEffect(tempDat.aura)
call DestroyEffect(AddSpecialEffectTarget(TARGET_FX,tU,"origin"))
set snd=CreateSound(HIT_SOUND,false,true,true,12700,12700,"")
call SetSoundVolume(snd,127)
call SetSoundPitch(snd,1.25)
call SetSoundPosition(snd,GetUnitX(tU),GetUnitY(tU),100.)
call StartSound(snd)
call KillSoundWhenDone(snd)
set snd=null
set tU=null
elseif tempDat.count==2 then //the next attack we'll proc, so let's display an effect
set tempDat.aura=AddSpecialEffectTarget(NEXT_HIT_FX,dSource,"origin")
set tempDat.count=tempDat.count+1
else //this is attack 0 or 1 so just increment count
set tempDat.count=tempDat.count+1
endif
else //this is the first time the unit attacks with the ability so let's instanciate a stackDat and set the default count.
set tempDat=stackDat.create()
set tempDat.count=0
set attackCounts[dSource]=tempDat
endif
endif
set dSource=null
endfunction
private function i takes nothing returns nothing
call StructuredDD_ddBucket.addHandler(function handler)
set attackCounts=HandleTable.create()
endfunction
endscope
scope destiny initializer i
private struct cdrDat
unit fate
endstruct
private struct target
unit who
endstruct
private struct destinyDat
unit fate
group visionDummies
real elapsedTime=0.
real duration
integer revertAbilityLevel
endstruct
globals
private constant string GATE_SOUND="Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.wav"
private destinyDat array destinyDB
private timer time=CreateTimer()
private integer dbIndex=-1
private group grp=CreateGroup()
private HandleTable attachments
private HandleTable cdrTable
endglobals
private function move takes nothing returns nothing
local unit enum=GetEnumUnit()
local target tempDat=attachments[enum]
call SetUnitX(enum,GetUnitX(tempDat.who))
call SetUnitY(enum,GetUnitY(tempDat.who))
set enum=null
endfunction
private function flusher takes nothing returns nothing
local unit enum=GetEnumUnit()
call attachments.flush(enum)
call RemoveUnit(enum)
set enum=null
endfunction
private function p takes nothing returns nothing
local integer index=0
local destinyDat tempDat
loop
exitwhen index>dbIndex
set tempDat=destinyDB[index]
set tempDat.elapsedTime=tempDat.elapsedTime+tfConsts_FPS
if tempDat.elapsedTime<tempDat.duration then
call ForGroup(tempDat.visionDummies,function move)
else
call UnitRemoveAbility(tempDat.fate,tfConsts_GATE_ID)
call UnitRemoveAbility(tempDat.fate,tfConsts_DIS_GATE_ID)
call SetUnitAbilityLevel(tempDat.fate,tfConsts_DESTINY_ID,tempDat.revertAbilityLevel)
call ForGroup(tempDat.visionDummies,function flusher)
call DestroyGroup(tempDat.visionDummies)
set destinyDB[index]=destinyDB[dbIndex]
set dbIndex=dbIndex-1
set index=index-1
if dbIndex==-1 then
call PauseTimer(time)
endif
endif
set index=index+1
endloop
endfunction
private function cdr takes nothing returns nothing
local timer clock=GetExpiredTimer()
local cdrDat tempDat=cdrTable[clock]
call UnitRemoveAbility(tempDat.fate,tfConsts_DESTINY_ID)
call UnitAddAbility(tempDat.fate,tfConsts_DESTINY_ID)
call tempDat.destroy()
call cdrTable.flush(clock)
call DestroyTimer(clock)
set clock=null
endfunction
private function c takes nothing returns boolean
local destinyDat tempDat
local cdrDat tempCDR
local target tStruct
local unit FoG
local unit u
local player who
local timer cdrClock
local real cooldown
if GetSpellAbilityId()==tfConsts_DESTINY_ID then
set tempDat=destinyDat.create()
set tempDat.fate=GetTriggerUnit()
set tempDat.visionDummies=CreateGroup()
set tempDat.revertAbilityLevel=GetUnitAbilityLevel(tempDat.fate,tfConsts_DESTINY_ID)
set tempDat.duration=4.+2.*tempDat.revertAbilityLevel
call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,null)
set who=GetOwningPlayer(tempDat.fate)
call SetUnitAbilityLevel(tempDat.fate,tfConsts_DESTINY_ID,3)
call IncUnitAbilityLevel(tempDat.fate,tfConsts_DESTINY_ID)
call UnitAddAbility(tempDat.fate,tfConsts_GATE_ID)
set cooldown=165.-15.*GetUnitAbilityLevel(tempDat.fate,tfConsts_DESTINY_ID)
if GetUnitAbilityLevel(tempDat.fate,tfConsts_STACKED_DECK_ID)>0 then
set cdrClock=CreateTimer()
set tempCDR=cdrDat.create()
set tempCDR.fate=tempDat.fate
set cdrTable[cdrClock]=tempCDR
call TimerStart(cdrClock,cooldown-cooldown*0.03*GetUnitAbilityLevel(tempDat.fate,tfConsts_STACKED_DECK_ID),false,function cdr)
set cdrClock=null
endif
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitType(FoG,UNIT_TYPE_HERO) and IsUnitEnemy(FoG,who) and UnitAlive(FoG) then
set u=CreateUnit(who,tfConsts_EYE_DUMMY_ID,GetUnitX(FoG),GetUnitY(FoG),270.)
call GroupAddUnit(tempDat.visionDummies,u)
set tStruct=target.create()
set tStruct.who=FoG
set attachments[u]=tStruct
set u=null
endif
call GroupRemoveUnit(grp,FoG)
endloop
set dbIndex=dbIndex+1
set destinyDB[dbIndex]=tempDat
if dbIndex==0 then
call TimerStart(time,tfConsts_FPS,true,function p) //The only reason this timer has to be smooth is so that the effect (dummy) will track fast
//moving/gap closing/teleporting heroes.
endif
endif
return false
endfunction
private function gateC takes nothing returns boolean
local unit tU
local sound snd
if GetSpellAbilityId()==tfConsts_GATE_ID then
set tU=GetTriggerUnit()
set snd=CreateSound(GATE_SOUND,false,true,true,12700,12700,"")
call SetSoundVolume(snd,127)
call SetSoundPosition(snd,GetUnitX(tU),GetUnitY(tU),100.)
call SetSoundPitch(snd,2.)
call StartSound(snd)
call KillSoundWhenDone(snd)
set snd=null
call UnitRemoveAbility(tU,tfConsts_GATE_ID)
call UnitAddAbility(tU,tfConsts_DIS_GATE_ID)
set tU=null
endif
return false
endfunction
private function preloadSound takes nothing returns nothing
local sound s=CreateSound(GATE_SOUND,false,true,true,12700,12700,"")
call SetSoundVolume(s,1)
call SetSoundPosition(s,0.,0.,100.)
call StartSound(s)
call KillSoundWhenDone(s)
call DestroyTimer(GetExpiredTimer())
set s=null
endfunction
private function i takes nothing returns nothing
local trigger t=CreateTrigger()
local trigger gate=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gate,EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(gate,Condition(function gateC))
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_FINISH)
call TriggerAddCondition(t,Condition(function c))
call TimerStart(CreateTimer(),0.01,false,function preloadSound)
set attachments=HandleTable.create()
set cdrTable =HandleTable.create()
set gate=null
set t=null
endfunction
endscope