• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Mimic v1.4

Spell Name: Mimic (active version)

When activated, it gives a chance to mirror a Positive or Negative spell that is casted to the Hero. The mirrored spell is casted back to the caster.

|cffffcc00Level 1|r - Gives 10% chance.
|cffffcc00Level 2|r - Gives 20% chance.
|cffffcc00Level 3|r - Gives 30% chance.
|cffffcc00Level 4|r - Gives 40% chance.
|cffffcc00Level 5|r - Gives 50% chance.


JASS:
/*=======================Mimic v1.4=========================
============================================================
====================Made by: Mckill2009=====================
============================================================
============================================================

REQUIRES:
- JassNewGenPack by Vexorian
- TimerUtils by Vexorian

HOW TO USE:
- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
- Copy ALL that is written here (overwrite the existing texts in the trigger)
- Copy the Dummy unit and the custom ability OR make your own
- You MUST input or change the correct raw ID's (see below)
- To view raw ID, press CTRL+D in the object editor

FULL DESCRIPTION:
When activated, it gives a chance to mirror a Positive or Negative spell that is casted to the Hero. The mirrored spell is casted back to the caster.

|cffffcc00Level 1|r - Gives 10% chance.
|cffffcc00Level 2|r - Gives 20% chance.
|cffffcc00Level 3|r - Gives 30% chance.
|cffffcc00Level 4|r - Gives 40% chance.
|cffffcc00Level 5|r - Gives 50% chance.
*/

scope Mimic initializer init

globals
    private constant hashtable          HASH = InitHashtable()
    private constant integer        SPELL_ID = 'A000' //raw code, change if needed
    private constant integer        DUMMY_ID = 'e000' //raw code, change if needed
    //===Configurables
    private constant string         BUFF_SFX = "Abilities\\Spells\\Items\\AIda\\AIdaTarget.mdl"
    private constant string        DUMMY_SFX = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
endglobals

//===CONFIGURABLES:
private function GetChance takes integer i returns integer
    return i * 10
endfunction

private function GetDuration takes integer i returns real
    return 30.
endfunction
//===END OF CONFIGURABLES

private function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

//target is the hero
private function MirrorSpellNow takes unit caster, unit target, integer abilityid returns nothing
    local unit dummy
    local real x 
    local real y
    local integer orderid
    local integer level = GetUnitAbilityLevel(caster, abilityid)
    if GetRandomInt(1, 100) <= GetChance(level) then
        set orderid = GetUnitCurrentOrder(caster)
        set x = GetUnitX(target)+100*Cos(GetUnitFacing(target)*bj_DEGTORAD)
        set y = GetUnitY(target)+100*Sin(GetUnitFacing(target)*bj_DEGTORAD)       
        call DestroyEffect(AddSpecialEffect(BUFF_SFX, x, y))
        set dummy = CreateUnit(GetOwningPlayer(target), DUMMY_ID, x, y, GetUnitFacing(target))
        call UnitApplyTimedLife(dummy, 'BTLF', 2.0)
        call UnitAddAbility(dummy, abilityid)
        call SetUnitAbilityLevel(dummy, abilityid, level)
        call IssueTargetOrderById(dummy, orderid, caster)
        set dummy = null
    endif    
endfunction

private function TimerLoop takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer ID = GetTimerData(t)
    local real duration = LoadReal(HASH, ID, 2)
    if duration > 0 and UnitAlive(LoadUnitHandle(HASH, ID, 1)) then
        call SaveReal(HASH, ID, 2, duration - 1)
    else
        call DestroyEffect(LoadEffectHandle(HASH, ID, 3))
        call RemoveSavedInteger(HASH, GetHandleId(LoadUnitHandle(HASH, ID, 1)), 0x4568) 
        call ReleaseTimer(t)
    endif
    set t = null
endfunction

private function TimerAction takes unit u returns nothing
    local timer t = NewTimer()
    local integer ID = GetHandleId(t)
    local integer level = GetUnitAbilityLevel(u, SPELL_ID)
    //===Timer ID
    call SaveUnitHandle(HASH, ID, 1, u)
    call SaveReal(HASH, ID, 2, GetDuration(level))
    call SaveEffectHandle(HASH, ID, 3, AddSpecialEffectTarget(BUFF_SFX, u, "overhead"))
    //===Unit ID
    call SaveInteger(HASH, GetHandleId(u), 0x4568, 1) 
    //===Saves the information
    call SetTimerData(t, ID)
    call TimerStart(t, 1.0, true, function TimerLoop)
    set t = null    
endfunction

private function Cond takes nothing returns boolean
    if GetSpellAbilityId()==SPELL_ID then
        call TimerAction(GetTriggerUnit())
        
    elseif GetUnitAbilityLevel(GetSpellTargetUnit(), SPELL_ID) > 0 and HaveSavedInteger(HASH, GetHandleId(GetSpellTargetUnit()), 0x4568) then
        call MirrorSpellNow(GetTriggerUnit(), GetSpellTargetUnit(), GetSpellAbilityId())        
    endif   
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()      
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Cond))
    set t = null
endfunction

endscope



Changelogs:
Changelogs:
v1.4
- Converted to vJass
- Uses TimerUtils
- Codes greatly reduced like triggers reduced from 4 to 1
- Description changed

v1.3
- Now it's active, but passive results
- A dummy is created to cast the mirrored spell
- Code improved like hashtable flushed & nulls variables
- Description changed

v1.2
- bj_lastCreatedUnit has been replaced by a local variable
- BJDebugMsg has been removed
- Local variables created in MIMIC_CAST (actually this was done before, I just removed it)

v1.1
- SaveStr is replaced by SaveInteger then Loaded as IssueTargetOrderById (Bribe's suggestion)
- Local usage has been greatly reduced
- Added configurable chance


Keywords:
mirror, duplicate, spell, counter, strike, negative, buff, positive, diablo, dota
Contents

Mimic (Map)

Reviews
12 Dec 2011 Bribe: Approved (useful).
Level 6
Joined
Aug 20, 2009
Messages
95
You can better filter the thing if its like this, and you can get rid of that function.
JASS:
function MIMIC_CAST takes nothing returns boolean
local integer i = GetUnitAbilityLevel(GetTriggerUnit(), MIMIC_ID)
if i > 0 and randomizer <= spelllevel then\
//Do shit.
endfunction

Also, why are you using a global hashtable in GUI? Just declare one up top.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
OK, now it's been updated Bribe, thanks to your suggestion...

@illegalpie
- Merging is better but I cant really do that coz ALL spells is the event
so I have to mimimize the amount of locals by putting a Condition first...
Although your example has a condition, still the randomizer and the spelllevel will be generated above...

- I'm not using vJASS so I cant declare globals, but its simple to add it...
 
Level 6
Joined
Aug 20, 2009
Messages
95
It wouldn't be that hard to make it, Wait a second, you hadn't thought of this? Instead of making it cast the order string back, simply store the spell being cast, add the spell to a dummy, set it to the level, and order the dummy to cast it, that way you can simply use custom spells too.
 
Level 11
Joined
Mar 18, 2009
Messages
788
What I meant was that not all custom spells will work properly with this one, those that are not MUI will definitely not work but also some other spells or systems (like mine) will bug up to. But that is something that the mapper will have to customize by himself.

In other words you must adapt some spells and systems if you are going to use this spell in your map.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Thanks for all your positive comments guys...

@EloTheMan
If the mirrored spell isnt MUI, this spell wont bug but the non-MUI spell will bug ofc...

@illegalpie
I already did store the spell being cast via >>> spellid but you cant get a
GetIssuedOrderId if the event is Starts the effect on ability...I've tried it before with strings, it didnt work...
 
Level 23
Joined
Jan 1, 2011
Messages
1,504
Yeah as said up top this obviously wont work with a shit ton of custom spells, though it does look extremely cool. Actually, you could just create a dummy, give him the spell casted (set his stats to the casting unit for custom spells) and set it to the lvl of the abil casted. Order the unit to cast it on the target and vwala. This still would conflict with who actually killed the unit, but I'm pretty sure that wont matter too much.
Overall neat spell 4/5.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
JASS:
    local trigger t = CreateTrigger()      
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MIMIC_ConditionCast))
    call TriggerAddAction(t, function MIMIC_Timer)
    set t = null
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MIMIC_ConditionTrig))
    call TriggerAddAction(t, function MIMIC_Actions)
    set t = null  
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)    
    call TriggerAddAction(t, function MIMIC_OrderId) 
    set t = null
        
    set t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 1.0, true)    
    call TriggerAddAction(t, function MIMIC_LooperTimer) 
    set t = null

Nothing major (actually doesn't matter if you leave it as is or not), but just for the sake of better coding:
you don't need to null t after every time you use it before reusing it.

Why? Because once you create a trigger it would overwrite the local variable t.

So only null it once you aren't going to use it anymore to avoid the local leak before exiting the function :)

So this is what we get:
JASS:
    local trigger t = CreateTrigger()      
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MIMIC_ConditionCast))
    call TriggerAddAction(t, function MIMIC_Timer)
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MIMIC_ConditionTrig))
    call TriggerAddAction(t, function MIMIC_Actions)
    
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)    
    call TriggerAddAction(t, function MIMIC_OrderId) 
        
    set t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 1.0, true)    
    call TriggerAddAction(t, function MIMIC_LooperTimer) 
    set t = null
 
Level 4
Joined
Jan 9, 2011
Messages
28
gui please?

I like this spell :thumbs_up:. Though I would like it in GUI (might be easier to do for dmg reversal). Though u could make a redirect spell (have a small cutscene in between) to spank the guy who cast the spell up the ass!
 
Top