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

Mend v.1.2 and Time Phase v1.3

  • Like
Reactions: IcemanBo
Two Spells


Mend:
Mend with the targeted allied unit or tree transfering HP. If the target is a unit, this Hero will give its HP for a certain duration and moves with the targeted unit. Mending with a tree heals this Hero.

Time Phase:
Distort space-time continuum allowing you to save your current location, hitpoints and mana at the time this spell was casted. After a short delay or when 'Return Time' is activated, you will go back in time at the moment this spell was casted restoring location but can only recover portion of the hitpoints and mana lost.

CONFIGURABLES:

- The amount of HP transfer per level (target it unit)
- The amount of HP heal per level (target is tree)
- Mend duration



- Time Phase Delay
- Percentage of HP recovered
- Percentage of Mana recovered
- Image transparency



REQUIREMENTS:
- JNGP

SPELL TRIGGERS:
Mend
JASS:
scope Mend initializer OnInit

    /*
    MEND by Shadow Flux, idea by jonbon29
    
    SPELL INFO
        Mend with the targeted allied unit or tree transfering HP. 
        If the target is a unit, this Hero will give its HP for a 
        certain duration and moves with the targeted unit. 
        Mending with a tree heals this Hero.
        
    NOTES:
        - Stops when the targeted unit becomes invisible
        - Does not start cooldown, effect and does not reduce mana cost when target is initially invisible.
        - Stops when the mended tree dies.
        - Stops when targeted unit comes to an unwalkable path.
        - Targeting an amphibious unit makes it's pathing off.
        
    EDITABLE AT OBJECT EDITOR:
        - To change the duration of the spell, edit the "Mend Dummy Channeling" Follow Through Timer
        - To change animation when unit is targeted, edit the "Mend Dummy Channeling" Art-Animation Names
    */
    native UnitAlive takes unit u returns boolean
    //===========================================================
    //========= MEND CONFIGURABLES ==============================
    //===========================================================
    globals
        private constant integer MEND_ABILITYCODE = 'Amnd'
        private constant integer CHANNEL_MEND_ABILITYCODE = 'Achm'
        private constant string CHANNEL_STRINGID = "mount" //Base Order Id of Mend Channeling
        private constant string MEND_ANIMATION_TREE = "stand lumber"  //the animation of the unit when the target is tree
    endglobals
    
    //The amount of HP Mend Heals per second
    private function MendHeal takes integer level, boolean targetIsUnit returns real
        if (targetIsUnit) then
            //HP TRANSFER WHEN UNIT IS TARGETED
            return 0.0 + 10.0*level
        else
            //HP HEAL WHEN TREE IS TARGETED
            return 10.0 + 10.0*level
        endif
    endfunction
    
    //===========================================================
    //========= END CONFIGURABLES ===============================
    //===========================================================
    
    
    //===========================================================
    //========= Important Spell Variables =======================
    //===========================================================
    globals
        private integer index = -1
        private timer period = CreateTimer()
        private constant real FPS = 0.0312500
        private constant integer GHOST_ABILITYCODE = 'Aeth'
        private constant player NEUTRAL_PASSIVE_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE)
    endglobals
    
    private struct SpellData
        unit caster
        unit target
        destructable treeTarget
        real hpHeal
        
        method destroy takes nothing returns nothing
            if index == -1 then
                call PauseTimer(period)
            endif
            call this.deallocate()
        endmethod
    endstruct
    
    globals
        private SpellData array data
    endglobals
    
    //===========================================================
    //========= MEND LOOP =======================================
    //=========================================================== 
    private function Periodic takes nothing returns nothing
        local SpellData this
        local integer i = 0
        local real hp
        local real x
        local real y
        loop
            exitwhen i > index
            
            //========== MEND PERIODIC ACTIONS ============
            set this = data[i]

            if (this.target != null) then
                //Positioning Code and HP
                set x = GetUnitX(this.target)
                set y = GetUnitY(this.target)
                set hp = GetWidgetLife(this.target)
                
                //if target is at unwalkable path, target is invisible, or target is dead
                if (IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) or IsUnitInvisible(this.target, NEUTRAL_PASSIVE_PLAYER) or not(UnitAlive(this.target)) ) then
                    call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE)
                else
                    call SetUnitX(this.caster, x)
                    call SetUnitY(this.caster, y)
                endif
                
                if (hp < GetUnitState(this.target, UNIT_STATE_MAX_LIFE) and UnitAlive(this.target)) then    //only heals when target hp is not full and not dead
                    call SetWidgetLife(this.target, hp + this.hpHeal)
                    call SetWidgetLife(this.caster, GetWidgetLife(this.caster) - this.hpHeal)
                endif
            else
                set hp = GetWidgetLife(this.caster)
                if (GetWidgetLife(this.treeTarget) >= 0.405) then //if target tree is still alive, continue healing even
                    if (hp < GetUnitState(this.caster, UNIT_STATE_MAX_LIFE)) then   //only heals when hp is not full
                        call SetWidgetLife(this.caster, hp + this.hpHeal)
                    endif
                else
                    call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE)
                endif
            endif
            
            //=============================================================
            set i = i + 1
        endloop
    endfunction
    
    //===========================================================
    //========= MEND CASTED =====================================
    //===========================================================    
    private function Casted takes nothing returns boolean
        local SpellData this
        local integer level
        local boolean b = false
        
        if GetSpellAbilityId() == MEND_ABILITYCODE then
            set this = SpellData.create()
            set this.caster = GetTriggerUnit()
            set this.target = GetSpellTargetUnit()
            
            if (this.target != null) then
                set b = true
                if not(IsUnitType(this.target, UNIT_TYPE_GROUND)) then      //For avoiding collision when target is amphibious
                    call SetUnitPathing(this.target, false)
                endif
            else
                set this.treeTarget = GetSpellTargetDestructable()
                call SetUnitPathing(this.caster, false)
                call SetUnitX(this.caster, GetDestructableX(this.treeTarget))
                call SetUnitY(this.caster, GetDestructableY(this.treeTarget))
            endif
 
            set level = GetUnitAbilityLevel(this.caster, MEND_ABILITYCODE)
            set this.hpHeal = MendHeal(level, b)*FPS

                        
            call UnitAddAbility(this.caster, GHOST_ABILITYCODE)
            //call SetUnitPathing(this.caster, false)

            
            //CHANNEL MEND
            call UnitAddAbility(this.caster, CHANNEL_MEND_ABILITYCODE)
            call IssueImmediateOrder(this.caster, CHANNEL_STRINGID)
            
            
            if (b == false) then
                call SetUnitAnimation(this.caster, MEND_ANIMATION_TREE)
            endif
            
            set index = index + 1
            set data[index] = this
            if (index == 0) then
                call TimerStart(period, FPS, true, function Periodic)
            endif
        endif
        return false
    endfunction
    
    
    private function BeginCasting takes nothing returns boolean
        local SpellData this
        local unit target = GetSpellTargetUnit()
        
        if GetSpellAbilityId() == MEND_ABILITYCODE then
            if (target != null and IsUnitInvisible(target, NEUTRAL_PASSIVE_PLAYER) ) then
                call IssueImmediateOrder(GetTriggerUnit(), "stop")
            endif
        endif
        
        set target = null
        return false
    endfunction
    
    
    //===========================================================
    //========= NO LONGER MENDING ===============================
    //===========================================================
    private function End takes nothing returns boolean
        local integer i = 0
        local SpellData this
        local unit u
        if GetSpellAbilityId() == CHANNEL_MEND_ABILITYCODE then
            set u = GetTriggerUnit()
            loop
                //========== STOP AND REMOVE FROM INDEX ==========
                set this = data[i]
                if this.caster == u then
                    call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE)
                    call SetUnitPathing(this.caster, true)
                    call SetUnitPathing(this.target, true)
                    call UnitRemoveAbility(this.caster, GHOST_ABILITYCODE)
                    set this.caster = null
                    set this.target = null
                    set this.treeTarget = null
                    set data[i] = data[index]
                    set index = index - 1
                    call this.destroy()
                    exitwhen true
                endif
                
                //=============================================================
                set i = i + 1
            endloop
            set u = null

        endif
        return false
    endfunction
    
    
    //===========================================================================
    private function OnInit takes nothing returns nothing
        local trigger t1 = CreateTrigger( )  // trigger when casted
        local trigger t2 = CreateTrigger( )  // trigger when ended
        local trigger t3 = CreateTrigger( )
        
        call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition( t1, Condition( function Casted ) )

        call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
        call TriggerAddCondition( t2, Condition( function End ) )
        
        //To have the ability to stop the unit when targeted on invisible units
        call TriggerRegisterAnyUnitEventBJ( t3, EVENT_PLAYER_UNIT_SPELL_CAST)
        call TriggerAddCondition( t3, Condition( function BeginCasting ) )
        
        //for invisibility detection
        if (GetLocalPlayer() == NEUTRAL_PASSIVE_PLAYER) then
            call FogMaskEnable(false)
            call FogEnable(false)
        endif
        
        set t1 = null
        set t2 = null
        set t3 = null
    endfunction
endscope
[/size]

Time Phase
JASS:
scope TimePhase initializer OnInit

    /*
    TIME PHASE by Shadow Flux
    
    SPELL INFO
        Distort space-time continuum allowing you to save your current location, hitpoints and mana at 
        the time this spell was casted. After a short delay or when 'Return Time' is activated, you will
        go back in time at the moment this spell was casted restoring location but can only 
        recover portion of the hitpoints and mana lost.
        
    NOTES:
        - Image and floating text created is only visible to player casting the spell.
        - Does not desync when tested in Multiplayer Emulation of JNGP.
        
    */
    native UnitAlive takes unit u returns boolean
    //===========================================================
    //========= TIME PHASE CONFIGURABLES ========================
    //===========================================================
    globals
        private constant integer TIMEPHASE_ABILITYCODE = 'Atmp'          // The Hero Ability Time Phase
        private constant integer RETURNTIME_ABILITYCODE = 'Atpr'        // Return Time Ability
        private constant integer TIMEPHASE_HIDE_ABILITYCODE = 'Ahde'    // The Dummy Ability based on Engineering Upgrades that hides Time Phase ability
        private constant integer IMAGE_TRANSPARENCY = 160                      // How transparent the image is. Max value is 255 which is fully non-transparent
        private constant string SPELL_EFFECT_CASTER = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl" 
        private constant string SPELL_EFFECT_TARGET = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl" 
        private constant real TEXT_HEIGHT = 150   //height offset of the floating text
        private constant real TEXT_SIZE = 0.035
    endglobals
    
    private function Duration takes integer level returns real
        return 4.5 + 0.5*level
    endfunction
    
    //THE PERCENTAGE OF HP RECOVERED UPON RETURNING IN Time 
    /*Example: 
    Time Phase (level 1) casted at 1000 HP and after taking damage resulting to 500 HP left, returning
    in time, caster will recover (1000-500)*0.6 = 300 resulting to 800 HP.
    */
    private function PortionHp takes integer level returns real
        return 0.1 + 0.2*level
    endfunction
    
    private function PortionMana takes integer level returns real
        return 0.1 + 0.2*level
    endfunction
    
    //===========================================================
    //========= END CONFIGURABLES ===============================
    //===========================================================
    
    
    //===========================================================
    //========= Important Spell Variables =======================
    //===========================================================
    globals
        private integer index = -1
        private timer period = CreateTimer()
        private constant real FPS = 0.0312500
        private constant player NEUTRAL_PASSIVE_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE)
        private constant integer TIMEPHASE_ORDERINT = 852589
    endglobals
    
    private struct SpellData
        unit caster
        unit imageUnit
        boolean exchange
        integer lvl
        real delay
        real hp
        real mana
        texttag timeLeft
        
        method destroy takes nothing returns nothing
            if index == -1 then
                call PauseTimer(period)
            endif
            call this.deallocate()
        endmethod
    endstruct
    
    globals
        private SpellData array data
    endglobals
        
    private function ReturnTime takes integer i returns nothing   
        local SpellData this
        local real x
        local real y
        local real hp
        local real hpRecover
        local real mana
        local real manaRecover
        
        set this = data[i]
        if (UnitAlive(this.caster)) then
            set x = GetUnitX(this.imageUnit)
            set y = GetUnitY(this.imageUnit)
            
            //SPELL VISUAL EFFECTS
            call DestroyEffect(AddSpecialEffect(SPELL_EFFECT_CASTER, GetUnitX(this.caster), GetUnitY(this.caster)))
            call DestroyEffect(AddSpecialEffect(SPELL_EFFECT_TARGET, x, y))

            
            //SPELL ACTIONS
            call SetUnitFacing(this.caster, GetUnitFacing(this.imageUnit))
            call SetUnitPosition(this.caster, x, y)
            //HP RECOVER
            set hp = GetWidgetLife(this.caster)
            set hpRecover = (this.hp - hp)*PortionHp(this.lvl)
            if (hpRecover > 0) then
                //if saved hp > current hp, recover hp
                call SetWidgetLife(this.caster, hp + hpRecover)
            else
                //if saved hp < current hp, set hp to saved hp
                call SetWidgetLife(this.caster, this.hp)
            endif
            //MANA RECOVER
            set mana = GetUnitState(this.caster, UNIT_STATE_MANA)
            set manaRecover = (this.mana-mana)*PortionMana(this.lvl)
            if (manaRecover > 0) then
                //if saved mana > current mana, recover mana
                call SetUnitState(this.caster, UNIT_STATE_MANA, mana + manaRecover)
            else
                //if saved mana < current mana, set mana to saved mana
                call SetUnitState(this.caster, UNIT_STATE_MANA, this.mana)
            endif
        endif
        call RemoveUnit(this.imageUnit)
        call DestroyTextTag(this.timeLeft)
            
        //RESET ABILITIES
        call UnitRemoveAbility(this.caster, RETURNTIME_ABILITYCODE)
        call UnitRemoveAbility(this.caster, TIMEPHASE_HIDE_ABILITYCODE)
            
        //CLEANUP
        set this.caster = null
        set this.imageUnit = null
        set this.timeLeft = null
        set data[i] = data[index]
        set index = index - 1
        call this.destroy()
    endfunction
        
    //===========================================================
    //========= TIME PHASE LOOP =================================
    //=========================================================== 
    private function Periodic takes nothing returns nothing
        local SpellData this
        local integer i = 0
        loop
            exitwhen i > index
            //========== TIME PHASE PERIODIC ACTIONS ============
            set this = data[i]
            set this.delay = this.delay - FPS
            call SetTextTagText(this.timeLeft, R2S(this.delay), TEXT_SIZE)
            if this.delay <= 0 then
                call ReturnTime(i)
            else
                //HIDE ABILITY 
                if (this.exchange) then
                    call UnitAddAbility(this.caster, RETURNTIME_ABILITYCODE)
                    call UnitAddAbility(this.caster, TIMEPHASE_HIDE_ABILITYCODE)
                    call UnitMakeAbilityPermanent(this.caster, true, RETURNTIME_ABILITYCODE)
                    call UnitMakeAbilityPermanent(this.caster, true, TIMEPHASE_HIDE_ABILITYCODE)
                    set this.mana = GetUnitState(this.caster, UNIT_STATE_MANA)
                    set this.exchange = false
                endif
            endif
            
            //=============================================================
            set i = i + 1
        endloop
    endfunction
    
    //===========================================================
    //========= TIME PHASE CASTED ===============================
    //===========================================================    
    private function Casted takes nothing returns boolean
        local SpellData this
        local integer id
        local real x
        local real y
        if (GetIssuedOrderId() == TIMEPHASE_ORDERINT) then
            //STORE SPELL STRUCT VARIABLES
            set this = SpellData.create()
            set this.caster = GetTriggerUnit()
            set this.lvl = GetUnitAbilityLevel(this.caster, TIMEPHASE_ABILITYCODE)
            set this.exchange = true
            set this.hp = GetWidgetLife(this.caster)
            
            set this.delay = Duration(this.lvl)
            
            //LOCAL VARIABLES
            set x = GetUnitX(this.caster)
            set y = GetUnitY(this.caster)
            
            //FLOATING TEXT SCRIPTS
            set this.timeLeft = CreateTextTag()
            call SetTextTagPos(this.timeLeft, x, y, TEXT_HEIGHT)
            call SetTextTagColor(this.timeLeft, 80, 175, 250, 230)
            call SetTextTagVisibility(this.timeLeft, false)
            
            
            //IMAGE UNIT
            set id = GetUnitTypeId(this.caster)
            set this.imageUnit = CreateUnit(NEUTRAL_PASSIVE_PLAYER, id, x, y, GetUnitFacing(this.caster))
            
            //ONLY SHOW THE IMAGE UNIT AND TIME LEFT TO THE CASTER PLAYER
            call SetUnitVertexColor(this.imageUnit, 255, 255, 255, 0)
            if (GetLocalPlayer() == GetTriggerPlayer()) then
                call SetUnitVertexColor(this.imageUnit, 255, 255, 255, IMAGE_TRANSPARENCY)
                call SetTextTagVisibility(this.timeLeft, true)
            endif
            call UnitAddAbility(this.imageUnit, 'Aloc')   //make the image unit unselectable
            call SetUnitTimeScale(this.imageUnit, 0) //stop image unit animation
            call PauseUnit(this.imageUnit, true) //disable image unit from auto-attacking
            
            //MAKE IMAGE UNIT GOES THROUGH CASTER
            call SetUnitX(this.imageUnit, x)
            call SetUnitY(this.imageUnit, y)
            
            //INDEXING
            set index = index + 1
            set data[index] = this
            if (index == 0) then
                call TimerStart(period, FPS, true, function Periodic)
            endif
        endif
        return false
    endfunction
    
    //===========================================================
    //========= TIME PHASE RETURN ===============================
    //===========================================================  
    private function ReturnTimeActivated takes nothing returns boolean
        local SpellData this
        local unit u
        local integer i = 0
        if (GetSpellAbilityId() == RETURNTIME_ABILITYCODE) then
            set u = GetTriggerUnit()
            loop
                set this = data[i]
                if this.caster == u then
                    set u = null
                    call ReturnTime(i)
                    exitwhen true
                endif
                //=============================================================
                set i = i + 1
            endloop
            set u = null
        endif
        return false
    endfunction
    
    private function Disable takes nothing returns nothing
        call SetPlayerAbilityAvailable(GetEnumPlayer(), TIMEPHASE_HIDE_ABILITYCODE, false)
    endfunction
    
    //===========================================================================
    private function OnInit takes nothing returns nothing
        local trigger t1 = CreateTrigger(  )
        local trigger t2 = CreateTrigger(  )
        
        call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_UNIT_ISSUED_ORDER)
        call TriggerAddCondition( t1, Condition( function Casted ) )
        call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition( t2, Condition( function ReturnTimeActivated ) )
        
        set t1 = null
        set t2 = null
        
        //for hiding the other ability
        call ForForce(bj_FORCE_ALL_PLAYERS, function Disable)
        
        
    endfunction

endscope


IMPLEMENTATION
1) Copy the Abilities in Object Editor to your map.
2) Copy the Spell Trigger Folder to your map.



Keywords:
time, phase, mend, tree, heal
Contents

Mend and Time Phase (Map)

Reviews
Mend v1.2 and Time Phase v1.3 | Reviewed by BPower | 28.06.2015 Concept[/COLOR]] Time Phase locks a unit status, allowing it to travel back in time after x seconds. Then life, mana and position will be restored. Once activated the effect is...

Moderator

M

Moderator


Mend v1.2 and Time Phase v1.3 | Reviewed by BPower | 28.06.2015

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png
Time Phase locks a unit status, allowing it to travel back in time after x seconds.
Then life, mana and position will be restored.

Once activated the effect is not stop-able, but can be executed at any time via ability.
The spell is based on Manashield so it doesn't stop the casters current order.
The concept itself has been seen many times.
126248-albums6177-picture66521.png

Mend mounts a unit to another unit, giving it extra bonuses.
For example a temporary increased life regeneration.
This effects ends, when a different order is given to the unit.

Code[/COLOR]]
126248-albums6177-picture66521.png
  • Both spells are MUI, leakless and working,
126248-albums6177-picture66523.png
  • Everything issue I pointed out has been fixed. Good job!
Objects[/COLOR]]
126248-albums6177-picture66523.png
  • Object data seems to be ok.
Effects[/COLOR]]
126248-albums6177-picture66521.png
Effects are minimal, but fit to their spell concepts.
They are good.
Rating[/COLOR]]
CONCEPTCODEOBJECTSEFFECTSRATINGSTATUS
3.5/5
3.5/5
4/5
3/5
3.5/5
APPROVED
Links[/COLOR]]

[COLOR="gray"

[/TD]
 
Level 13
Joined
Aug 19, 2014
Messages
1,111
Now this is really good, especially the Mend spell that I requested. Thanks dude, hope to see some more from you.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Mend:
You should check, if the caster is still alive every period or is this included in unit end cast?
GetWidgetLife(widget) < 0.405 is not a valid way to detect whether a unit is dead or not.
Use either native UnitAlive(unit) or (GetUnitTypeId(unit) != 0 and not GetUnitState(unit, UNIT_STATE_DEAD))

Could use SpellEffectEvent as optional requirement.

'Aeth' should be stored into a constant variable, so should be Player(PLAYER_NEUTAL_PASSIVE)

You check for walkability and cancel is it is false, but allow mounting to a flying unit?

When you return the mend heal, you can use a formula instead: 0 + 10*level

function names should be written MyFunction.

If no, then this is really useful.
And otherwise not?
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Isn't this exactly what : http://www.hiveworkshop.com/forums/jass-resources-412/system-retro-time-travel-167921/ does?

If no, then this is really useful.
I did not know there already is one. But I think they are different because the one you link used Hashtable and mine has a 'Return Time' ability (but I'm not sure if your link has) which immediately shifts you back in time.


Mend:
You should check, if the caster is still alive every period or is this included in unit end cast?
Included in the end cast

GetWidgetLife(widget) < 0.405 is not a valid way to detect whether a unit is dead or not.
Use either native UnitAlive(unit) or (GetUnitTypeId(unit) != 0 and not GetUnitState(unit, UNIT_STATE_DEAD))
Why is GetWidgetLife(widget) < 0.405 not valid?

Could use SpellEffectEvent as optional requirement.
Yeah I might add a special effect

'Aeth' should be stored into a constant variable, so should be Player(PLAYER_NEUTAL_PASSIVE)
'Aeth' is Ghost (Visible) which is a default ability in Warcraft not a custom one. Why store them?
Why store Player(PLAYER_NEUTAL_PASSIVE) ??

You check for walkability and cancel is it is false, but allow mounting to a flying unit?
So you can heal flying units.

When you return the mend heal, you can use a formula instead: 0 + 10*level
But what if the heal for each level are random, e.g. level 1: 7, level 2: 8, level 3: 15. Plus this is much easier to edit.

function names should be written MyFunction.
Why?
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Asking questions never hurt :p So let me explain.
Sorted the list in the order you asked
  • Dead units can have more than .405 life.
    Also native UnitAlive performs best. native UnitAlive takes unit id returns boolean
    .
  • SpellEffectEvent is a snippet, which optimizes an on spell effect event trigger evaluation and not a special effect.
    It is in our jass section, written by Bribe and very recommended to use.
    .
  • For clean code don't use magic number, but store your constants into variables.
    .
  • Player(x) is a function call, while stored it's a constant. Talking about speed optimization here.
    .
  • You miss the point, as flying units can move over non walkable terrain.
    .
  • And if I want 4 or just 2 levels? Users will change that if required.
    .
  • We have an official standart for naming functions, constants, non- constants, methods, ... it is called JPAG
    Consider this like a internal grammar, so code is uniform and readable for everyone.
    It sticks to the style Blizzard has chosen for the WE.
    There is a link in my signature.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
BPower said:
[*]Dead units can have more than .405 life.
Also native UnitAlive performs best. native UnitAlive takes unit id returns boolean
Ok i will update it.

BPower said:
[*]SpellEffectEvent is a snippet, which optimizes an on spell effect event trigger evaluation and not a special effect.
It is in our jass section, written by Bribe and very recommended to use.
I see what you meant. I will use Bribe's SpellEffectEvent


BPower said:
[*]For clean code don't use magic number, but store your constants into variables.
Will do.

BPower said:
[*]Player(x) is a function call, while stored it's a constant. Talking about speed optimization here.
Yeah you are right, i will also change it.

BPower said:
[*]You miss the point, as flying units can move over non walkable terrain.
It was in the request that Mend will stop when moving to an non-walkable terrain. Plus any user can just uncheck the Targets Allowed of Mend.

BPower said:
[*]And if I want 4 or just 2 levels? Users will change that if required.
The thing about having it in formula is that the system will have to perform arithmetic operation which I think is slower than using If-Then-Else. Furthermore, what if the heal is not linear (you have to use Transcendental, Power, Exponential which is even slower) or cannot be represented by an equation. So I think the best way is to just use arrays, e.g.
JASS:
globals
    private real array mendHeal
    set mendHeal[1] = 10.0
    set mendHeal[2] = 15.0
    set mendHeal[3] = 20.0
endglobals
What do you think?

BPower said:
[*]We have an official standart for naming functions, constants, non- constants, methods, ... it is called JPAG
Consider this like a internal grammar, so code is uniform and readable for everyone.
It sticks to the style Blizzard has chosen for the WE.
There is a link in my signature.
Ok I will also change the names to fit the standard.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
At this point, speed is not an important factor. When you do ( please don't )
you have to consider, that the JassHelper does inline functions matching
certain criterias. You can check them in the link in my signature.

arrays have to initialized with an onInit trigger, functions don't.
Also you can't guess what the user finally needs for his spell.
He will manipulate your code in a way it fits to his map.

I just give you a small example. In the map I'm working on at the moment,
damage is completly custom so I would erase your damage config completly
if using your spell. My Damage detection implementation will correct the amount of
damage, once any damage is dealt.

Just go with a function.
 
Level 11
Joined
Dec 3, 2011
Messages
366
How?

@Bpower, still not clear to me but fine, i will not use an array.I will stick to function which returns the number at each level.

Thanks, for helping. I will update it soon.

Y are u still using function. Imagine, you have an ability with 50 lvl what will you do with function which returns the number at each level? An array is fine, everyone who use your skill can config it easier.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Before everyone gets more confused.

For a public release a function overs the exact amount of configurability we want in this case.
New map concepts will always be different and so is the final setup from the one who writes the code.

Ok. You are a Resource Mod so I have to follow you.

You do have a point there, final setup is different depending on the concept. I will update this and follow all those you said that needs to be changed.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I guess it's not a good idea to copy a hero type unit. I just saw this in the picture of the submission :)
Here other ingame problems can occure ( xp related, display, revial, .... everything connected with heroes).
It's not so often used, but there is an agent named "image". Maybe you want to experiment with this. ( Just an idea )
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
There is no obvious connection between the two spells.
In future just create two seperate threads instead of merging them into one.

For resources with a common context you can of course use one thread.

I gave a detailed review for your spell. If you would like to discuss about what I mentioned
feel free to post it here in the comments :)
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
in function Casted you need local player p just once. --> if GetTriggerPlayer() == GetLocalPlayer() then

For perfect visuals you could also set the image fly height to the casters flyheight.
Before setting fly height you have to add crowform to the dummy unit.

UnitMakeAbilityPermanent() should be used to ensure it's working with Meatmorphosis aswell.

Either use native UnitAlive or not GetUnitState(unit, UNIT_STATE_DEAD) and GetUnitTypeId(unit) != 0
Agree. Will be done in the next update.
I will also make the image flying if the hero is flying.
I will also make the ability permnanent.
I will use UnitAlive like I ded in Mend.

852589 is the orderid for "manashieldon"
I will change this as well.

IsUnitType(this.target, UNIT_TYPE_GROUND) == false is a redundant boolean comparison
and can be shortend to not IsUnitType(this.target, UNIT_TYPE_GROUND)
This isn't the same? I thought they are the same.

Is it really required to set the targets pathing off? Can't you solve it using the ghost ability? ( honest question )
No, but when the target is amphibious, yes it is required. I created a thread about it. Basically, even though the caster has ghost, it cannot phase through the target.
http://www.hiveworkshop.com/forums/world-editor-help-zone-98/problem-amphibious-units-265782/

Both spells don't provide a learn tooltip
Apart from that object data seems to be ok
I will put a tooltip. I thought that wasn't much required since the downloaded can just edit it to his standard.

Do I really need to use one of these or is it only optional?
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I used to use this for my pick hero system, It cause disconect when play multiplayer!

Nope, I checked it using Multiplayer Emulation. It doesn't disconnect.
Besides, I also used this in my own map and players doesn't report experiencing Disconnection. Like I said earlier, the unit is Locust and has no pathing that's why I think it doesn't cause desync.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
BPower said:
Storing locust is neat, but not required. You can directly use 'Aloc'
I thought you will make me store that too since you stated earlier
'Aeth' should be stored into a constant variable.
Still, I removed it and now directly uses 'Aloc'.


BPower said:
call DestroyEffect(AddSpecialEffect(....))
Done.


BPower said:
Using ShowUnit in for just one client is a big no-go.
Please use SetUnitVertexColor with an alpha of 0 instead.
Never provocate a disconnect, by not using local traffic
within a GetLocalPlayer == player block.
Done.
 
Level 11
Joined
Jul 4, 2016
Messages
627
Great spell! Just what I needed. Would it be possible to make so that when you go back in time, the person will return in his exact state? Like without avatar if hes in avatar mode or remove any buffs he did not had at that time of casting?
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Great spell! Just what I needed. Would it be possible to make so that when you go back in time, the person will return in his exact state? Like without avatar if hes in avatar mode or remove any buffs he did not had at that time of casting?
Without a Buff system, that would be impossible because default Buffs in WC3 have limited API (e.g. you can't set/get the duration of a Buff).
But if you don't wanna preserve Buff duration during the time of activation, I guess you can edit the spell script directly to check for hardcoded status like Avatar but it is not that simple.
 
Top