1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. The Results have come out of the old ARENA oven. Check out who won the 30th Texturing Contest!
    Dismiss Notice
  4. Hey guys, we've posted the Results for the 30th Modeling Contest. Check them out!
    Dismiss Notice
  5. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  6. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  7. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Healing Arcs v1.5

Submitted by mckill2009
This bundle is marked as approved. It works and satisfies the submission rules.

DESCRIPTION:
[​IMG]

PREVIEW:
[​IMG]

Healing Arcs v1.5

Code (vJASS):

/***************************************************************
    Healing Arcs v1.5
    by mckill2009
****************************************************************
    REQUIRED LIBRARIES:
        - SpellEffectEvent by Bribe
        - Table by Bribe
        - DamageEvent by looking_for_help
****************************************************************/

library HealingArcs initializer Init uses SpellEffectEvent, Table, DamageEvent

globals
    /***********************************************************
    *   RAW CODES: Press CTRL+D view and change raw codes from
    *               object editor accordingly
    ************************************************************/

    private constant integer            SPELL_ID = 'A000' //unit target spell to ally
    private constant integer            DUMMY_ID = 'h000' //unit who cast the healing arc
    private constant integer       BOLT_SPELL_ID = 'A001' //firebolt ID with arc  
    private constant integer       BOLT_ORDER_ID = 852231 //firebolt order ID, must match with BOLT_SPELL_ID
   
    /***********************************************************
    *   CONFIGURABLE GLOBALS
    ************************************************************/

    private constant string             HEAL_SFX = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
    private constant string           DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
    private constant string      HEAL_ATTACHMENT = "overhead"
    private constant string    DAMAGE_ATTACHMENT = "chest"  
    private constant player      NEUTRAL_PASSIVE = Player(15)
    private constant attacktype              ATK = ATTACK_TYPE_CHAOS
    private constant damagetype              DMG = DAMAGE_TYPE_DEATH
   
    /***********************************************************
    *   NON-CONFIGURABLE GLOBALS
    ************************************************************/

    private group g = CreateGroup()
    private unit dummy
    private player owner
    private integer uID
    private Table heal
endglobals

/***********************************************************
*   CONFIGURABLE FUNCTIONS
************************************************************/

//Area of effect when searching allies to heal
private function GetAoE takes integer level returns real
    return 200. * level + 300 //500, 700, 900, 1100, 1300
endfunction

//Targets only 1 enemy
private function GetDamageAmount takes integer level returns real
    return 25. * level + 25 //50, 75, 100, 125, 150
endfunction

//Heals the main ally target
private function GetHealAmount takes integer level returns real
    return 50. * level + 50 //100, 150, 200, 250, 300
endfunction

//Heal Amount of the allies nearby
private function GetHealAmountArc takes integer level returns real
    return 50. * level + 50 //100, 150, 200, 250, 300
endfunction

private function UnitFilter takes unit u returns boolean
    return not (IsUnitType(u, UNIT_TYPE_STRUCTURE) or IsUnitType(u, UNIT_TYPE_MECHANICAL))
endfunction

/***********************************************************
*   NON-CONFIGURABLE FUNCTIONS
************************************************************/

private function UnitAlive takes unit u returns boolean
    return not (IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u)==0 or u==null)
endfunction

private function IsAllyUnitDamaged takes unit u returns boolean
    return GetWidgetLife(u) < GetUnitState(u, UNIT_STATE_MAX_LIFE)
endfunction

private function ArcLands takes nothing returns nothing
    if PDDS.source==dummy then
        if UnitFilter(PDDS.target) then
            set uID = GetHandleId(PDDS.target)
            set owner = heal.player[uID]
            if IsUnitEnemy(PDDS.target, owner) then
                call UnitDamageTarget(dummy, PDDS.target, GetDamageAmount(heal[uID]), false, false, ATK, DMG, null)
                call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, PDDS.target, DAMAGE_ATTACHMENT))
            else
                call SetWidgetLife(PDDS.target, GetWidgetLife(PDDS.target) + heal.real[uID])
                call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX, PDDS.target, HEAL_ATTACHMENT))
            endif      
        endif
        set heal.player[uID] = null
        call heal.remove(uID)
    endif  
endfunction

private function Cast takes nothing returns nothing
    local unit first
    local unit u = GetSpellTargetUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local integer level = GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID)
    local real healAmt = GetHealAmount(level)
    local real healAmtArc = GetHealAmountArc(level)
    call SetUnitX(dummy, x)
    call SetUnitY(dummy, y)
    call SetUnitOwner(dummy, GetTriggerPlayer(), false)
    call SetUnitFlyHeight(dummy, GetUnitFlyHeight(u), 0)
    if IsUnitEnemy(u, GetTriggerPlayer()) then
        call UnitDamageTarget(GetTriggerUnit(), u, GetDamageAmount(level), false, false, ATK, DMG, null)
        call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, u, DAMAGE_ATTACHMENT))
    else
        call SetWidgetLife(u, GetWidgetLife(u) + healAmt)
        call DestroyEffect(AddSpecialEffectTarget(HEAL_SFX, u, HEAL_ATTACHMENT))
    endif
    call GroupEnumUnitsInRange(g, x, y, GetAoE(level), null)
    loop
        set first = FirstOfGroup(g)
        exitwhen first==null
        if UnitAlive(first) and first!=u then
            if (IsAllyUnitDamaged(first) or IsUnitEnemy(first, GetTriggerPlayer())) and UnitFilter(first) then
                set uID = GetHandleId(first)
                set heal[uID] = level
                set heal.real[uID] = healAmtArc
                set heal.player[uID] = GetTriggerPlayer()
                call IssueTargetOrderById(dummy, BOLT_ORDER_ID, first)
            endif
        endif
        call GroupRemoveUnit(g, first)
    endloop
    call SetUnitOwner(dummy, NEUTRAL_PASSIVE, false)
    set u = null
endfunction

private function OnDeath takes nothing returns nothing
    if heal.has(GetHandleId(GetTriggerUnit())) then
        set heal.player[GetHandleId(GetTriggerUnit())] = null
        call heal.remove(GetHandleId(GetTriggerUnit()))
    endif
endfunction

private function Init takes nothing returns nothing
    call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeath)
    call RegisterSpellEffectEvent(SPELL_ID, function Cast)
    set dummy = CreateUnit(NEUTRAL_PASSIVE, DUMMY_ID, 0,0,0)
    call UnitRemoveAbility(dummy, 'Amov')
    call UnitAddAbility(dummy, BOLT_SPELL_ID)    
    call AddDamageHandler(function ArcLands)
    set heal = Table.create()
endfunction

endlibrary
 



  • Importing Objects

    - Go to object editor and copy ALL the custom buff and abilities to your map
    - If your map doesnt have a dummy unit, you need to copy it as well
    - Make sure that the dummy unit has locust ability, movement type is fly and;

    Art - Animation - Cast Backswing = 0
    Art - Animation - Cast Point = 0

    since this spell is only using ONE dummy

    - Copy ALL the required library and spell triggers to your map


    Setting the Codes

    - Hold CTRL and press D while viewing object editor to view raw codes
    - Raw codes are the first 4 digits of any object in the object editor
    - Replace the ID's of the integer with the correct raw codes in the global block
    - For some reasons this spell doesnt work if DamageEvent is changed to the correct raw codes, so set it like this;
    private constant integer DAMAGE_TYPE_DETECTOR = 0

    private constant integer SET_MAX_LIFE = 0

    - I've contacted looking_for_help for this long ago but no reply


  • SpellEffectEvent by Bribe
    Table by Bribe
    DamageEvent by looking_for_help

  • - Doesnt work if DamageEvent raw code is correctly filled, so do like this;
    private constant integer DAMAGE_TYPE_DETECTOR = 0

    private constant integer SET_MAX_LIFE = 0

    - Overwrites the previous cast since it used the handle of the target unit as ID which i think not a big deal coz
    the damage event is fast if not instantaneous


  • v1.5
    - Most suggestions is added or included
    - Instead of buf effect, trigger effect is added
    - Player(15) is now a variable so that people can change it

    v1.4
    - Added filter to ArcLands
    - Added safety when target is dead

    v1.3
    - Some changes in code as suggested by the moderator

    v1.2
    - Some code improvements
    - Some names are now verbose

    v1.1
    - AOE globals moved to function

Contents

Healing Arcs (Map)

Reviews
KILLCIDE
Simple spell concept, but it looks pretty cool. The idea of using Firebolt was also extremely clever. Parts of your code could use some work, but overall everything works and I don't see anything gamebreaking. Needs Fixed Nothing Suggestions You...
  1. Mythic

    Mythic

    Joined:
    Apr 24, 2012
    Messages:
    7,647
    Resources:
    101
    Models:
    86
    Icons:
    4
    Maps:
    3
    Spells:
    6
    Tutorials:
    2
    Resources:
    101
    Great spell, nice to see one from you live.

    What do you mean?
     
  2. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    Try to use another DDS. And I see you are not really using lfh's DDS special feature (get damage type). Try the easiest one, Weep's GDD.
     
  3. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Hey there! Some minor things to optimize:

    To check if a unit is dead this is the recommended method:

    IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0


    What's the point of this...
    private constant boolean    ENABLE_LARGE_AOE = true

    ... if there exists a function for AOE in configuration part?

    call SetUnitState(u, UNIT_STATE_LIFE, GetWidgetLife(u) + healAmt)

    ->
    call SetWidgetLife(u, GetWidgetLife(u) + healAmt


    You just could move all conditions into your UnitFilter function, so the main code (in loop) gets more readable ->
     if UnitFilter(first) then

    And
    first!=u
    is not needed as you also check if the owner is an enemy.

    GetTriggerUnit()
    and
    GetTriggerPlayer()
    can be stored into locals, to avoid extra funcion calls.

    GetUnitDefaultFlyHeight(dummy)
    and
    Player(15)
    can be stored into globals, to avoid extra funcion calls.

    And finaly change to scope, instead of library. There is no need for an library here.
     
    Last edited: Nov 13, 2014
  4. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    Tnx for rep bro...for some reasons, it cant increase the target's HP if I follow input the correct raw code of the system, I already told looking_for_help for this...

    tried that and cokemonkey's as well in jass section, but registers heal abnormally, I wanted to make my own but no need since looking_for_help's system works...

    @IcemanBo
    Tnx
    maybe you mean...
    not IsUnitType(first, UNIT_TYPE_DEAD) and first!=null

    OR
    not IsUnitType(first, UNIT_TYPE_DEAD) or GetUnitTypeId(first) != 0


    it's my fault I didnt explain it in the code, if the player wants to go beyond the range limit without adjusting the configurabled GetAoE, they can set it to true providing that the bold also has that range...

    I noticed it too late, I'll change it...

    if I remove the
    first!=u
    , then it will heal also the main target which gives him doubled heal and doubled buff eyecandy...

    But you're right all filtering should be on top...

    if just one call, then it's OK...

    one or 2 calls is OK...

    Although libraries is best for systems, spells also are fine to make note requirements easily...

    tnx for the tips though, +rep 4u

    EDIT:
    inlining tags
     
  5. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    ^Yes, for checking if a unit is alive yes. I just said a method to check if a unit is idead. :D

    GetTriggerUnit()
    -> is only called twice, ok, you're right. :)

    GetTriggerPlayer()
    -> is called twice before the loop, and then potentially called once for reach loop iteration. So I think a local is ok to use here.

    By suggesting to use the globals. Yes, you're right there are not many calls per one cast. But you only need to initialisize these globals once, and then you will use them for each single cast. -> Win performance!
     
  6. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,235
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    • You should utilize another DDS or user need to break the whole features of lfh's DDS just to use your spell. Otherwise, your spell has zero usability.
    • (Optional) You also can completely eliminate the use of hashtable by using UnitIndexer and global array variables. Hashtable is much slower than variables. But this is not a big deal for your spell.
    • Code (vJASS):
      not (IsUnitType(first, UNIT_TYPE_DEAD)

      Since this is vJass, you can use native function to check unit alive:
      Code (vJASS):
      native UnitAlive takes unit id returns boolean

      But first you need to declare it somewhere.
    • Code (vJASS):

          call SetUnitFlyHeight(dummy, GetUnitDefaultFlyHeight(dummy), 0)

      Can be removed. And just remove this condition:
      Code (vJASS):

          if GetUnitFlyHeight(u) > 0 then

      It won't get any performance gain/loss.
    • Code (vJASS):

          private attacktype                       ATK = ATTACK_TYPE_CHAOS
          private damagetype                       DMG = DAMAGE_TYPE_DEATH

      They should be constants too.
    • Code (vJASS):
      private function UnitFilter takes unit u returns boolean

      private function GetAoE takes integer level returns real

      //ENABLE_LARGE_AOE must be true and range of the BOLT_SPELL_ID must be equal or greater than the retured value
      private function GetLargeAoE takes nothing returns real

      private function GetDamageAmt takes integer level returns real

      private function GetHealAmt takes integer level returns real

      private function GetHealAmtArc takes integer level returns real
       

      Could be constant.
    • Player(15)

      Could be store to constant variable at map init first to avoid repetitive FCs along the game.
    Sorry that's not a complete review.
     
  7. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    GetDamageAmt --> GetDamageAmount 3 more letters remove a big questionmark, if amt does mean amount.

    or u==null
    does not happen, ever.

    Remove all the fly height conditions and just set it directly. I can't think of a scenario where this isn't a good solution.

    Personally for me an
    or
    within a condition is much more confusing to read then
    and
    .

    Table is fine, actually also my first choice. Just because I read something about unit indexing systems in the upper comment.

    You need a filter for the impact function, targets may be dead, removed, immun, etc.

    Store
    GetTriggerPlayer()
    . Ofc depending on the total amount of targets,
    it's (theoretically) an useful performance boost.

    Nice spell judging from the gif :)
     
  8. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    Tnx people for the comments;

    If a function/command like GetTriggerPlayer() or GetTriggerUnit() has ZERO arguments and it's responding to the Event, then it's fine to use without locals...

    attacktype and damagetype are by default constants...

    functions (and globals) declared as constants only serves for inlining and not to change the value of something, but has no impact on performance...

    The native UnitAlive is fine but creating a function is also OK...

    I'm really not a fan of UnitIndexer even though its faster than HT, or Table, so its fine...

    The fly height senario is OK...I'll change that...

    it's suppose to be
    not (IsUnitType(first, UNIT_TYPE_DEAD) and first!=null and first!=u
    , but I put it just like the UnitFilter with 'or' inside the 'not'...

    They are free to do whatever they want as long as they have permission, I'm just using DDS for them to avoid editing the object to certain levels and to heal certain amounts...
     
    Last edited: Nov 14, 2014
  9. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    • BPower is right about to filter in
      function ArcLands
      . Add it, please.
    • Use following check if unit is dead:
      IsUnitType(unit, UNIT_TYPE_DEAD) or GetUnitTypeId(unit) == 0 
    • Move the loop conditions (except you check for variable == null) into the filter function.
    • ENABLE_LARGE_AOE seems redundant. It can be used for testing, but user can use the normal AOE config.
    • The dummy player could be set in a constant function.
    • Make it a scope, not library.
    • Attack/damage type are CAPITALIZED, and should be declared as constants.

    I like the concept. :) For now Needs Fix
     
  10. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    Ok my friend Ima change most of it except;
    1 - Coz it will NOT register if enemy is already dead (tested already), the filter is already in the CAST function...

    3 - Coz I preffer to use libraries, coz it doesnt mean that if it's a spell then a scope is a MUST?, what could possibly wrong with libraries used in a spell?...
     
  11. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    1. You filter onCast, yes. But it may change after certain duration... or not?

    2. You put API functions in a library for example, that they can be called from anywhere.
    I don't really see sense in putting a spell code into a library. It just gets moved up for nothing. Though it does not really hurt, if you use library over scope. It's just my opinion, :)
     
  12. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    thanks for the quick reply...

    there's nothing to be damaged if the units is dead, ive tested it already like this;
    Code (vJASS):

    cast
    spread
    if target dies before arclands then
       nothing happens //coz target is dead
    endif
     


    nothing wrong and doesnt hurt to use scopes, yes...but libraries are my preference nowadays on both systems and spells...but Im thanking all opinions...
     
  13. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    But some ciscumstances can change, like the owner of unit for example.
    Then your check for enemy/ally would be ignored. (it should be moved in filter btw)

    Filter is also configurable, so user might add more circumstances that might needed to be checke. It's just safer I think.
     
  14. Sunreaver

    Sunreaver

    Joined:
    Aug 22, 2013
    Messages:
    1,199
    Resources:
    13
    Packs:
    1
    Maps:
    12
    Resources:
    13
    Can somewant make it in Gui
     
  15. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Filter on
    ArcLands
    . I thought about it once again, and I still think it's needed.
    Circumstances might change during the duration so a new filter is definitly needed.
    (user can modify the filter)

    IsUnitAlive and check is unit is enemy should be moved in filter. But that's more minor.
     
  16. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    That can only happen when target changes status as non-ally or unit type, not the dead ones, but...

    v1.4
    - Added filter to ArcLands
    - Added safety when target is dead

    There is 1 more known issue, the only solution I can think of is to add mutiple dummies, but I dont like it...
     
  17. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,113
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    I don't see a reason why not to combine the check for enemy and check if unit is alive with filter.

    What's about this?
     
  18. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,492
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20

    Needs Fixed

    • Player(15)
      is now a used player slot.

    Suggestions

    • Update some of your naming conventions to follow JPAG:
      init -> Init
      &
      onDeath -> OnDeath
      are some examples

    Status


    Awaiting Update