• 🏆 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!

Metasis v1.3

  • Like
Reactions: Manasurge
DESCRIPTION:
Calls a dark magic from the underworld which can transform an ally unit to a random powerful creature such as Death Reverant, Satyr Hellcaller, Bandit Lord, Eredar Warlock or Elder Voidwalker.
When the creature dies, it restores the original unit but it's life and mana is depleted by x%.
Heroes and structures are immune to this magic.
Summoned units will instantly die after restoration.

Level 1 - Creature lasts 15 seconds, life and mana depleted by 80%
Level 2 - Creature lasts 30 seconds, life and mana depleted by 65%
Level 3 - Creature lasts 45 seconds, life and mana depleted by 50%
Level 4 - Creature lasts 60 seconds, life and mana depleted by 35%
Level 5 - Creature lasts 75 seconds, life and mana depleted by 20%


JASS:
//===Spell Name: Metasis v1.3
//===Created by Mckill2009

//===INSTRUCTIONS: Follow these steps
//- Be sure to check the 'Automatically create unknown variables...', via File>Preferences>General tab.
//- In the object editor, copy the custom Ability to your map.
//- Be sure to input the correct MET_SpellId(rawID).
//- Copy the "Metasis" trigger to your map.
//- If you want to change the units you may do it by changing the rawID from the MET_SetupNewUnits function.
//- To view the rawID in the object editor press CTRL+D.

//===REQUIRED VARIABLES:
//- HASH = hashtable
//- MET_NewUnit = integer array
//- MET_Error = sound

//Credits to Vexorian for the sound, I got the idea from his SimError library

//===FULL DESCRIPTION:
//Calls a dark magic from the underworld which can transform an ally unit to a random powerful creature such as Death Reverant, Satyr Hellcaller, Bandit Lord, Eredar Warlock or Elder Voidwalker.
//When the creature dies, it restores the original unit but it's life and mana is depleted by x%.
//Heroes and structures are immune to this magic.
//Summoned units will instantly die after restoration.

//Level 1 - Creature lasts 15 seconds, life and mana depleted by 80%
//Level 2 - Creature lasts 30 seconds, life and mana depleted by 65%
//Level 3 - Creature lasts 45 seconds, life and mana depleted by 50%
//Level 4 - Creature lasts 60 seconds, life and mana depleted by 35%
//Level 5 - Creature lasts 75 seconds, life and mana depleted by 20%

function MET_SpellId takes nothing returns integer
    return 'A002' //rawID, you may change this when necessary
endfunction

//==========CONFIGURABLES:
function MET_SetupNewUnits takes nothing returns nothing
    set udg_MET_NewUnit[1] = 'nbld' //rawID (default Bandit Lord)
    set udg_MET_NewUnit[2] = 'nerw' //rawID (default Eredar Warlock)
    set udg_MET_NewUnit[3] = 'nrvd' //rawID (default Death Reverant)
    set udg_MET_NewUnit[4] = 'nvde' //rawID (default Elder Voidwalker)
    set udg_MET_NewUnit[5] = 'nsth' //rawID (default Satyr Hellcaller)
endfunction

function MET_SfxNewUnit takes nothing returns string
    return "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
endfunction 

function MET_SfxRestore takes nothing returns string
    return "Abilities\\Spells\\Human\\ReviveHuman\\ReviveHuman.mdl"
endfunction

function MET_ErrorMsg takes nothing returns string
    return "This unit has been changed!"
endfunction

function MET_NeedLifeMin takes nothing returns string
    return "Life of unit must be at least 80%"
endfunction

function MET_Duration takes integer i returns real
    return i * 15.
endfunction

function MET_RestoredState takes real state, integer i returns real
    return (state)*(0.15*i+0.05) //0.2,0.35,0.50,0.65,0.80
endfunction

function MET_MaxUnits takes nothing returns integer
    return 5 //this number should be the last index number of set udg_MET_NewUnit[5]
endfunction
//==========END OF CONFIGURABLES:

//===================================================
//=====THIS IS THE RESTORE POINT AND RESTORED UNIT
function MET_Restore takes nothing returns boolean
    local unit r = GetTriggerUnit()
    local integer newunitID = GetHandleId(r)
    local unit restoredunit = LoadUnitHandle(udg_HASH, newunitID, 0) //this is the original unit
    call SetUnitX(restoredunit, GetUnitX(r)) 
    call SetUnitY(restoredunit, GetUnitY(r))
    //Restoring the previous unit
    if not (IsUnitType(restoredunit, UNIT_TYPE_SUMMONED) or IsUnitType(restoredunit, UNIT_TYPE_HERO)) then
        call DestroyEffect(AddSpecialEffectTarget(MET_SfxRestore(), restoredunit, "origin"))
    endif
    call PauseUnit(restoredunit, false)
    call ShowUnit(restoredunit, true)
    call SetUnitInvulnerable(restoredunit, false)
    call SetUnitUseFood(restoredunit, true)    
    call SetWidgetLife(restoredunit, LoadReal(udg_HASH, newunitID, 1)) //statelife
    call SetUnitState(restoredunit, UNIT_STATE_MANA, LoadReal(udg_HASH, newunitID, 2)) //statemana
    //Summoned and Hero units dies instantly
    if IsUnitType(restoredunit, UNIT_TYPE_SUMMONED) or IsUnitType(restoredunit, UNIT_TYPE_HERO) then
        call KillUnit(restoredunit)
    endif
    
    call FlushChildHashtable(udg_HASH, newunitID)    
    set r = null
    set restoredunit = null
    return false
endfunction                                

//=====THIS IS THE METASIS SPELL
function MET_Looper takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer metkey = GetHandleId(t) 
    local unit tar = LoadUnitHandle(udg_HASH, metkey, 1)//This is the original unit
    local unit newunit
    local integer newunitID
    local real x = GetUnitX(tar)
    local real y = GetUnitY(tar)
    
    call ShowUnit(tar, false)
    call SetUnitUseFood(tar, false)    
               
    set newunit = CreateUnit(GetOwningPlayer(tar), udg_MET_NewUnit[GetRandomInt(1,MET_MaxUnits())], x, y, 0) 
    set newunitID = GetHandleId(newunit)// This will be used when the newunit dies and restores the previous unit
    call DestroyEffect(AddSpecialEffectTarget(MET_SfxNewUnit(), newunit, "origin"))
    
    //when newunit dies, the target will return to these settings
    call SaveUnitHandle(udg_HASH, newunitID, 0, tar) //the original target
    call SaveReal(udg_HASH, newunitID, 1, LoadReal(udg_HASH, metkey, 2)) //statelife
    call SaveReal(udg_HASH, newunitID, 2, LoadReal(udg_HASH, metkey, 3)) //statemana    
    
    call UnitApplyTimedLife(newunit, 'BTLF', LoadReal(udg_HASH, metkey, 4))
    call FlushChildHashtable(udg_HASH, metkey)
    call PauseTimer(t)
    call DestroyTimer(t)
    
    set t = null
    set tar = null
    set newunit = null
endfunction

function MET_Action takes nothing returns nothing
    local timer t
    local integer metkey
    local unit cas = GetTriggerUnit()
    local unit tar = GetSpellTargetUnit()
    local integer targetkey = GetHandleId(tar)
    local integer level
    local string msg
    local real maxlife
    
    if HaveSavedHandle(udg_HASH, targetkey, 0) then
        call ClearTextMessages()
        set msg="\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00"+MET_ErrorMsg()+"|r"
        call IssueImmediateOrder(cas, "stop")
        call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0.52, 0.96, 2.00, msg)
        call StartSound(udg_MET_Error)
    else
        set maxlife = GetUnitState(tar,UNIT_STATE_MAX_LIFE)
        if GetWidgetLife(tar) > (maxlife*0.8) then
            set t = CreateTimer()
            set metkey = GetHandleId(t)
            set level = GetUnitAbilityLevel(cas, MET_SpellId())       
            call UnitPauseTimedLife(tar, true) //this is used only for summoned unit
            call PauseUnit(tar, true)
            call SetUnitInvulnerable(tar, true)
            call SaveUnitHandle(udg_HASH, metkey, 1, tar)
            call SaveReal(udg_HASH, metkey, 2, MET_RestoredState(GetWidgetLife(tar), level))
            call SaveReal(udg_HASH, metkey, 3, MET_RestoredState(GetUnitState(tar, UNIT_STATE_MANA), level))
            call SaveReal(udg_HASH, metkey, 4, MET_Duration(level))
            call TimerStart(t, 3, false, function MET_Looper) 
            set t = null  
        else
            call ClearTextMessages()
            set msg="\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00"+MET_NeedLifeMin()+"|r"
            call IssueImmediateOrder(cas, "stop")
            call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0.52, 0.96, 2.00, msg)
            call StartSound(udg_MET_Error)
        endif
    endif      
    set tar = null
    set cas = null
endfunction

function MET_Condition takes nothing returns boolean
    return GetSpellAbilityId()==MET_SpellId()
endfunction

function InitTrig_Metasis takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function MET_Condition))
    call TriggerAddAction(t, function MET_Action)
    set t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(t, function MET_Restore)
    set udg_HASH = InitHashtable()
    call MET_SetupNewUnits()
    set udg_MET_Error = CreateSoundFromLabel("InterfaceError",false,false,false,10,10)
    set t = null
endfunction



167625-albums4356-picture46167.jpg

167625-albums4356-picture46168.jpg




Magtheridon96 for reminding me to store the coordinates to a varriable
Vexorian for his SimError



v1.3
- Code improved by adding arrayed integers to create units.
- Added Sound Error (credits to vexorian for his SimError).
- Description changed.

v1.2
- CreateUnit function has been replaced
- Fixed a bug that a summoned unit will not die after the conversion
- Added tooltip description "Summoned unit will instantly die after restoration."
- Added function for summoned unit Id

v1.1
- Fixed a bug that creates more than 1 creature when cast at the same time


Keywords:
metamorphosis, change, dota, dark, spell, convert, ultimate, power, war, heal
Contents

Metasis v1.3 (Map)

Reviews
Approved You could think about unit selection and hiding the summoned units when they die.

Moderator

M

Moderator

Reviewed by Maker, Metasis v1.3, 5th Apr 2012

Approved

You could think about unit selection and hiding the summoned units when they die.
 
Level 6
Joined
Aug 20, 2009
Messages
95
Interesting. DLing now, will edit.
Seems good, no leaks, but incredibly simple. I'd probably edit the creatures, make them heroes so that way the hero icons will show.
Also, make like two unique abilities for each, not just forked lightning...
 
JASS:
if random==1 then
        set newunit = CreateUnit(GetOwningPlayer(tar), MET_WARLOCK(), GetUnitX(tar), GetUnitY(tar), 0)    
    elseif random==2 then
        set newunit = CreateUnit(GetOwningPlayer(tar), MET_REVERANT(), GetUnitX(tar), GetUnitY(tar), 0)
    elseif random==3 then
        set newunit = CreateUnit(GetOwningPlayer(tar), MET_VOIDWALKER(), GetUnitX(tar), GetUnitY(tar), 0)
    elseif random==4 then
        set newunit = CreateUnit(GetOwningPlayer(tar), MET_SATYR(), GetUnitX(tar), GetUnitY(tar), 0)
    elseif random==5 then
        set newunit = CreateUnit(GetOwningPlayer(tar), MET_SASQUATCH(), GetUnitX(tar), GetUnitY(tar), 0)
    endif

Over here, instead of repeating "GetUnitX" and "GetUnitY", store it in a local variable :)
That will increase performance :D
 
Level 4
Joined
Jul 24, 2010
Messages
85
I think this is bug.
1. SASQUATCH (having reincarnation) will not be changed back to default unit.
2. Can target summoned unit. After duration is over, summoned unit will stay forever (Don't have expiration time)
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
I think this is bug.
1. SASQUATCH (having reincarnation) will not be changed back to default unit.
2. Can target summoned unit. After duration is over, summoned unit will stay forever (Don't have expiration time)

Thank you...
1. When the SASQUATCH dies 'again' the original unit will come out...
2. Fixed already...See description...

===UPDATE===

v1.2
- CreateUnit function has been replaced
- Fixed a bug that a summoned unit will not die after the conversion
- Added tooltip description "Summoned unit will instantly die after restoration."
- Added function for summoned unit Id
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
call SetUnitState(restoredunit, UNIT_STATE_LIFE, statelife/10)
--> call SetWidgetLife(restoredunit, statelife/10)



JASS:
    set summonedid = GetHandleId(restoredunit)
    set summonchk = LoadInteger(udg_HASH, summonedid, 100)

Can be set already when declaring the locals

JASS:
    local integer summonedid = GetHandleId(restoredunit)
    local integer summonchk = LoadInteger(udg_HASH, summonedid, 100)

This doesn't even need a local declared nor set as it's only used for one call below it with the SaveInteger.

JASS:
    local integer summonedid
    set summonedid = GetHandleId(GetTriggerUnit())

You do declare and call these functions:

JASS:
    local real x = GetUnitX(tar)
    local real y = GetUnitY(tar)

Yet you don't use them

JASS:
    call DestroyEffect(AddSpecialEffect(MET_SFX(), GetUnitX(tar), GetUnitY(tar)))

This should probably be stored into the hashtable.

GetOwningPlayer(tar)

Didn't I tell you about timer recycling? And btw you leak the timers.

JASS:
    local timer t = CreateTimer()

Change into GetWidgetLife, faster.

JASS:
local real statelife = GetUnitState(tar, UNIT_STATE_LIFE)

Set this when it's declared.

JASS:
    local integer check2 
    set check2 = LoadInteger(udg_HASH, targetkey, 1)

And yeah did I mention that you should merge the actions with the condition?

You really need to improve this. But you're making progress and that's good. You know where to find me.
 
Top