Code (vJASS):





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

