Foreword: I posted this in the .com forums, saving a copy here for posterity. Be warned, there is a lot of code text-walls in here. You can skip most of them if you are so inclined, and just read the words outside of the quote boxes.
Recently, Panda insulted my JASS skills. Since he locked the topic in question, I could not respond.
I would like to do so now.
First remark he makes is how this code is bad:
function IsPlayerAdmin takes string s returns boolean
local string lower=StringCase(s,false)
local boolean b=true
if lower=="Darox" then
set b=false
elseif lower=="Disabled" then
set b=false
elseif lower=="Admins" then
set b=false
endif
return b
endfunction
In case you can't work it out, this is the code that checks if someone is as admin. You may notice that the code takes the name of the player, converts it to lower case, and then checks it against these three strings. You may notice that the three strings I have replaced in this are 'Darox', 'Disabled', and 'Admins'. Because these all have an upper case letter, they will never be valid. Clearly I have made some kind of grievous error!
Wait. Let's have a look at those three strings again to see what's wrong. "Darox" "Disabled" "Admins". Hmm. There might be a hidden code in there. Maybe if we run it all together we will discover the secret. "Darox Disabled Admins". Can you see the secret message?
--
Later on he makes further comments about how I never use JASS.
Let's take a short list of things I have done in JASS.
Autocasting for titan heals
Tauren XP on hit
Reactive Satyr gold on hit changing based on HP
Manashield bugfix for upgraded Draenei walls
Self sacrifice used by Demonic Fiends
Granticles Boulder skill
Catapult Lockdown & Release
Nether Stone
Portal
Spirit Bind
Assorted bookkeeping with start up (I.E. Adding builders to selection triggers)
--
Finally, lets compare Darox's JASS to Panda's JASS in something both maps developed separately. The Autocast healing. You may recall that earlier Panda insulted my skills by suggesting the only way I could have developed an Autocast system is by deprotecting his map and copying it. Let's see how they match up, shall we?
function Trig_Autocast_Conditions takes nothing returns boolean
if GetSpellAbilityId()=='A0EB' then
return true
elseif GetSpellAbilityId()=='A0EC' then
return true
elseif GetSpellAbilityId()=='A0ED' then
return true
elseif GetSpellAbilityId()=='A0EE' then
return true
elseif GetSpellAbilityId()=='A0EF' then
return true
elseif GetSpellAbilityId()=='A0EG' then
return true
elseif GetSpellAbilityId()=='A0EH' then
return true
elseif GetSpellAbilityId()=='A0EI' then
return true
elseif GetSpellAbilityId()=='A0EJ' then
return true
endif
return false
endfunction
function WhichSpellHW takes integer i returns integer
if i=='A0EB' then
return('A02H')
elseif i=='A0EC' then
return('A045')
elseif i=='A0ED' then
return('A06O')
elseif i=='A0EE' then
return('A068')
elseif i=='A0EF' then
return('AOhw')
else
return(1)
endif
endfunction
function WhichSpellHL takes integer i returns integer
if i=='A0EG' then
return('A03S')
elseif i=='A0EH' then
return('A01I')
else
return(1)
endif
endfunction
function WhichSpellRejuv takes integer i returns integer
if i=='A0EI' then
return('A09N')
elseif i=='A0EJ' then
return('A04F')
else
return(1)
endif
endfunction
function Trig_Autocast_Actions takes nothing returns nothing
local unit u=GetTriggerUnit()
local integer i=GetSpellAbilityId()
local integer lvl=GetUnitAbilityLevel(u,i)
local unit z
set z=CreateUnit(GetOwningPlayer(u),'h03N',GetUnitX(u),GetUnitY(u),270)
call UnitApplyTimedLife(z,'BTLF',3.00)
if WhichSpellHW(i)!=1 then
call UnitAddAbility(z,WhichSpellHW(i))
call SetUnitAbilityLevel(z,WhichSpellHW(i),lvl)
call IssueTargetOrder(z,"healingwave",u)
elseif WhichSpellHL(i)!=1 then
call UnitAddAbility(z,WhichSpellHL(i))
call SetUnitAbilityLevel(z,WhichSpellHL(i),lvl)
call IssueTargetOrder(z,"holybolt",u)
elseif WhichSpellRejuv(i)!=1 then
call UnitAddAbility(z,WhichSpellRejuv(i))
call SetUnitAbilityLevel(z,WhichSpellRejuv(i),lvl)
call IssueTargetOrder(z,"rejuvination",u)
endif
set u=null
set z=null
endfunction
function InitTrig_Autocast takes nothing returns nothing
set gg_trg_Autocast = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Autocast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Autocast, Condition( function Trig_Autocast_Conditions ) )
call TriggerAddAction( gg_trg_Autocast, function Trig_Autocast_Actions )
endfunction
To describe it simply, it triggers whenever any of the listed base healing spells is used, then compares it against three tables until it matches the type of spell used (Healing Wave, Holy Light, or Rejuvenation), then returns the appropriate spell and casts it on the user.
Now, let's look at Panda's Autocast, as provided by Bodyhammer. Before I show you, I'd like to point out one thing from before when Panda mocked my JASS skills. One of my goals in creating this system was combining it all into one trigger, and as you can see above, I succeeded, and as you can see in 2.8.6bX, it is bug free. Now, since panda claimed that I had just ripped his system, you would assume that his autocast system was also all one trigger.
However, this is what I am told right away.
It's a little messy as everything is a separate trigger, but this is the general idea:
Oh dear.
Let's just see it shall we?
function Self_Heal takes unit u, integer dummyAbi, integer casterAbi, string IOrder returns nothing
local location curLoc =GetUnitLoc(u)
local integer abiLevel = GetUnitAbilityLevel(u,casterAbi)
local unit dummy = CreateUnitAtLoc(GetOwningPlayer(u),'hfoo',GetUnitLoc(u),0)
if (GetUnitLifePercent(u) > 99) then
call SetUnitLifePercentBJ(u,99)
endif
call UnitAddAbility(dummy,dummyAbi)
call SetUnitAbilityLevel(dummy,dummyAbi,abiLevel)
call IssueTargetOrder(dummy,IOrder,u)
call PolledWait(3.00)
call RemoveUnit(dummy)
call RemoveLocation(curLoc)
set u=null
set dummy=null
set abiLevel=0
set casterAbi = 0
set dummyAbi = 0
set IOrder = null
endfunction
This is the main body of Panda's autocast trigger, where all the stuff actually happens. It takes a unit, an ability, the level of an ability, and an order string, then enters them all into a standard dummy trigger and casts the ability on the unit at the level specified. Simple, right? Much shorter than mine, and all in one trigger! But where does it get these values? Oh, seems I forgot a tiny bit of his code.
function Trig_Self_Heal_Glac_Main_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A0EH' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Glac_Main_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'A01I', 'A0EH', "holybolt")
endfunction
//===========================================================================
function InitTrig_Glac_Main takes nothing returns nothing
set gg_trg_Glac_Main = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Glac_Main, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Glac_Main, Condition( function Trig_Self_Heal_Glac_Main_Conditions ) )
call TriggerAddAction( gg_trg_Glac_Main, function Trig_Self_Heal_Glac_Main_Actions )
endfunction
(Anyone who has used JASS may notice that this trigger was actually done in GUI then converted, hence the comment bar as well some other untidy parts)There, that should work! Now we have a working trigger! Whenever Glacious casts his heal, it will work properly. But what about the other titans? Well, Bodyhammer did not provide the entire thing, because as he said above, it was too long and messy to quote, but we can infer everything but the IDcodes for abilities, so lets display them here as well.
function Trig_Self_Heal_Glac_Minion_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Glac_Minion_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "rejuvination")
endfunction
//===========================================================================
function InitTrig_Glac_Minion takes nothing returns nothing
set gg_trg_Glac_Minion = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Glac_Minion, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Glac_Minion, Condition( function Trig_Self_Heal_Glac_Minion_Conditions ) )
call TriggerAddAction( gg_trg_Glac_Minion, function Trig_Self_Heal_Glac_Minion_Actions )
endfunction
function Trig_Self_Heal_Water_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Water_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "healingwave")
endfunction
//===========================================================================
function InitTrig_Water takes nothing returns nothing
set gg_trg_Water = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Water, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Water, Condition( function Trig_Self_Heal_Water_Conditions ) )
call TriggerAddAction( gg_trg_Water, function Trig_Self_Heal_Water_Actions )
endfunction
function Trig_Self_Heal_Molt_Main_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Molt_Main_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "holybolt")
endfunction
//===========================================================================
function InitTrig_Molt_Main takes nothing returns nothing
set gg_trg_Molt_Main = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Molt_Main, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Molt_Main, Condition( function Trig_Self_Heal_Molt_Main_Conditions ) )
call TriggerAddAction( gg_trg_Molt_Main, function Trig_Self_Heal_Molt_Main_Actions )
endfunction
function Trig_Self_Heal_Molt_Minion_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Molt_Minion_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "healingwave")
endfunction
//===========================================================================
function InitTrig_Molt_Minion takes nothing returns nothing
set gg_trg_Molt_Minion= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Molt_Minion, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Molt_Minion, Condition( function Trig_Self_Heal_Molt_Minion_Conditions ) )
call TriggerAddAction( gg_trg_Molt_Minion, function Trig_Self_Heal_Molt_Minion_Actions )
endfunction
function Trig_Self_Heal_Grant_Minion_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Grant_Minion_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "healingwave")
endfunction
//===========================================================================
function InitTrig_Grant_Minion takes nothing returns nothing
set gg_trg_Grant_Minion= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Grant_Minion, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Grant_Minion, Condition( function Trig_Self_Heal_Grant_Minion_Conditions ) )
call TriggerAddAction( gg_trg_Grant_Minion, function Trig_Self_Heal_Grant_Minion_Actions )
endfunction
function Trig_Self_Heal_Bubs_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Bubs_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "healingwave")
endfunction
//===========================================================================
function InitTrig_Bubs takes nothing returns nothing
set gg_trg_Bubs= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Bubs, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Bubs, Condition( function Trig_Self_Heal_Bubs_Conditions ) )
call TriggerAddAction( gg_trg_Bubs, function Trig_Self_Heal_Bubs_Actions )
endfunction
function Trig_Self_Heal_Volt_Minion_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Volt_Minion_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "healingwave")
endfunction
//===========================================================================
function InitTrig_Volt_Minion takes nothing returns nothing
set gg_trg_Volt_Minion= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Volt_Minion, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Volt_Minion, Condition( function Trig_Self_Heal_Volt_Minion_Conditions ) )
call TriggerAddAction( gg_trg_Volt_Minion, function Trig_Self_Heal_Volt_Minion_Actions )
endfunction
function Trig_Self_Heal_Breeze_Minion_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'XXXX' ) ) then
return false
endif
return true
endfunction
function Trig_Self_Heal_Breeze_Minion_Actions takes nothing returns nothing
call Self_Heal(GetTriggerUnit(), 'XXXX', 'XXXX', "rejuvination")
endfunction
//===========================================================================
function InitTrig_Breeze_Minion takes nothing returns nothing
set gg_trg_Breeze_Minion= CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Breeze_Minion, EVENT_PLAYER_UNIT_SPELL_FINISH )
call TriggerAddCondition( gg_trg_Breeze_Minion, Condition( function Trig_Self_Heal_Breeze_Minion_Conditions ) )
call TriggerAddAction( gg_trg_Breeze_Minion, function Trig_Self_Heal_Breeze_Minion_Actions )
endfunction
Phew, that took a lot of copy pasting. There we go, Panda's Autocast system in it's entirety! It's all just a bunch of copy paste, so it shouldn't have any bugs, right? Well, actually I heard that Moltenious could cancel-cast and use his heal for free when it was released, but it's ok Panda, it's hard work copy pasting and you were bound to make a mistake. It happens to everybody.
--
Bam.