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

[vJASS] Mana Master

Status
Not open for further replies.
JASS:
////////////////////////////////////////////////////////////////////////////////////////////////
//                                      The Mana Master v 1.10
//                                              by: eubz
//WHAT THIS SPELL DO
//This spell:
//1. Gives mana to allies from the percentage of current mana of the caster.
//2. Gets percentage of enemies' current mana
//NOTE: Can only be caster on heroes. Enemies or Allies.
//HOW TO IMPORT
//1. Copy this code into your map.
//2. Copy the custom ability here and paste it into your map
////////////////////////////////////////////////////////////////////////////////////////////////
library manaMaster initializer init
//These globals can be configured.
globals
    private constant real MANA_PERCENT  = 0.25 // The percentage of mana taken from enemies.
                                                // This is also the percentage of mana given to allied units.
    private constant string SFX         = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareBoltImpact.mdl"
    private constant string SFX1         = "Abilities\\Spells\\Human\\ManaShield\\ManaShieldCaster.mdl"
    private constant string ATTACHMENT  = "origin"
    private constant integer ABIL_CODE  = 'A000'
endglobals
//end of configurations
native UnitAlive takes unit id returns boolean

private function getManaAmount takes unit caster, integer level returns real
    return GetUnitState(caster, UNIT_STATE_MANA)*MANA_PERCENT*level
endfunction

private function getManaAmountTarget takes unit target, integer level returns real
    return GetUnitState(target, UNIT_STATE_MANA)*MANA_PERCENT*level
endfunction
//filter for allied units
private function getFilter takes unit caster, unit target returns boolean
    return UnitAlive(target)/*
            */and IsUnitAlly(target, GetOwningPlayer(caster))/*
            */and IsUnitType(target, UNIT_TYPE_HERO)/*
            */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)/*
            */and not IsUnitType(target, UNIT_TYPE_STRUCTURE)/*
            */and GetUnitState(target, UNIT_STATE_MANA) < GetUnitState(target, UNIT_STATE_MAX_MANA)
endfunction
//filter for enemy units
private function enemyFilter takes unit caster, unit target returns boolean
    return UnitAlive(target)/*
            */and IsUnitEnemy(target, GetOwningPlayer(caster))/*
            */and IsUnitType(target, UNIT_TYPE_HERO)/*
            */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)/*
            */and not IsUnitType(target, UNIT_TYPE_STRUCTURE)/*
            */and GetUnitState(target, UNIT_STATE_MANA) > 0
endfunction

private function spellConditions takes nothing returns boolean
    return GetSpellAbilityId() == ABIL_CODE
endfunction

private function spellActions takes nothing returns nothing
    local unit caster = GetTriggerUnit( )
    local unit target = GetSpellTargetUnit( )
    local integer level = GetUnitAbilityLevel( caster, ABIL_CODE)
    if getFilter(caster, target) then
        call SetUnitManaBJ( target, ( GetUnitStateSwap(UNIT_STATE_MANA, target) + getManaAmount(caster, level)))
        call SetUnitManaBJ( caster, ( GetUnitStateSwap(UNIT_STATE_MANA, caster) - getManaAmount(caster, level)))
        call DestroyEffect(AddSpecialEffectTarget(SFX, target, ATTACHMENT))
    elseif enemyFilter(caster, target) then
        call SetUnitManaBJ( target, ( GetUnitStateSwap(UNIT_STATE_MANA, target) - getManaAmountTarget(target, level)))
        call SetUnitManaBJ( caster, ( GetUnitStateSwap(UNIT_STATE_MANA, caster) + getManaAmountTarget(target, level)))
        call DestroyEffect(AddSpecialEffectTarget(SFX, target, ATTACHMENT))
        call DestroyEffect(AddSpecialEffectTarget(SFX1, caster, ATTACHMENT))
    endif
        set target = null
        set caster = null
endfunction

function init takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function spellConditions ) )
    call TriggerAddAction( t, function spellActions )
endfunction
endlibrary
Please, leave comments about the code.

EDIT:
I have got here some updates.
JASS:
//==================================================================================================================
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                      The Mana Master v 1.10
//                                              by: eubz
//
//WHAT DOES THIS SPELL DO
//This spell:
//A hero uses his current mana to damage non-hero units. If the target is a hero, 
//the target will not be harmed but he will lose his mana based on the percentage taken from his max mana.
//this lost mana is stolen by the caster.
//
//1. Gives mana to allies from the percentage of current mana of the caster.
//2. Gets percentage of enemies' max mana
//3. kills a target if he is not a hero and his life is 25% of the current mana of the caster
//4. Damages a target if the target is not a hero.
//
//HOW TO IMPORT
//1. Copy this code into your map.
//2. Copy the custom ability here and paste it into your map
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//================================================================================================================
library manaMaster initializer init

//These globals can be configured.
    globals

        private constant real       MANA_GIVEN  = 0.25 // This is the percentage of mana given to allied heroes.
                                                        
        private constant real       MANA_TAKEN    = 0.20 // The percentage of mana taken from enemies.          
                                                    
        private constant string     SFX           = "Abilities\\Spells\\Human\\ManaFlare\\ManaFlareBoltImpact.mdl"//special effect for caster
    
        private constant string     SFX1          = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl"//special effect for target
    
        private constant string     ATTACHMENT    = "origin"
    
        private constant integer    ABIL_CODE     = 'A000'
    
        private constant real       DAMAGE        = 0.30 //30% / 60% / 90% of caster's current mana is dealt as damage
                                                        //If you set this to 1.00 that would mean 100%/200%/300%
                                                        // of the caster's current mana will be dealt as
                                                        //damage to the target.
                                                            
        private constant damagetype D_TYPE        = DAMAGE_TYPE_NORMAL
    
        private constant attacktype  A_TYPE       = ATTACK_TYPE_NORMAL
    
    endglobals
//end of configurations
    native UnitAlive takes unit id returns boolean
    
    private function spellConditions takes nothing returns boolean
        return GetSpellAbilityId() == ABIL_CODE
    endfunction 

    struct spell
        private static method getManaAmount takes unit caster, integer level returns real
            return GetUnitState(caster, UNIT_STATE_MANA)*(MANA_GIVEN*level)
        endmethod

        private static method getManaAmountTarget takes unit target, integer level returns real
            return GetUnitState(target, UNIT_STATE_MAX_MANA)*(MANA_TAKEN*level)
        endmethod

        private static method getDamage takes unit caster, integer level returns real
            return GetUnitState(caster, UNIT_STATE_MANA)*(DAMAGE*level)
        endmethod
//========================================================================
//FILTER NOTES:
//Filter for allied units states that you can only cast this spell if the hero (which is your ally)
// has a mana lesser than his current mana.
//Filter for enemy units states that you can cast this spell to enemy heroes if the target has
//mana greater than zero. 
//You can also cast the spell to enemy non-hero units. This spell will damage enemy non-hero units
        private static method getFilter takes unit target returns boolean//this filters both enemy and allies
            return UnitAlive(target)/*
                */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)/*
                */and not IsUnitType(target, UNIT_TYPE_STRUCTURE)
        endmethod

        private static method allyFilter takes unit caster, unit target returns boolean//this filters ally hero units
            return IsUnitAlly(target, GetOwningPlayer(caster))/*
            */and IsUnitType(target, UNIT_TYPE_HERO)/*
            */and GetUnitState(target, UNIT_STATE_MANA) < GetUnitState(target, UNIT_STATE_MAX_MANA)
        endmethod

        private static method targetEnemyFilter takes unit caster, unit target returns boolean//this filters both hero and non-hero enemy units
            return IsUnitEnemy(target, GetOwningPlayer(caster))
        endmethod

        private static method enemyHeroFilter takes unit caster, unit target returns boolean//this filters enemy hero units
            return IsUnitType(target, UNIT_TYPE_HERO)/*
               */and GetUnitState(target, UNIT_STATE_MANA) > 0 //with a mana greater than zero
        endmethod

        private static method enemyUnitFilter takes unit target returns boolean//this filters non-hero enemy units
            return not IsUnitType(target, UNIT_TYPE_HERO)
        endmethod

        private static method unitKillFilter takes unit caster, unit target returns boolean // filters for killing enemy non-hero units
            return  GetUnitState(target,UNIT_STATE_LIFE) < (GetUnitState(caster, UNIT_STATE_MANA)*0.25)
        endmethod
//end of filters
//============================================================================================================    
        public static method m2Actions takes nothing returns nothing
            local unit caster = GetTriggerUnit( )
            local unit target = GetSpellTargetUnit( )
            local integer level = GetUnitAbilityLevel( caster, ABIL_CODE)
    
            if thistype.getFilter(target) and .allyFilter(caster, target) then
        //if the target is an ally of the caster, he gives some percentage of his mana.
                call SetUnitManaBJ( target, ( GetUnitState(target, UNIT_STATE_MANA) + .getManaAmount(caster, level)))
                call SetUnitManaBJ( caster, ( GetUnitState(caster, UNIT_STATE_MANA) - .getManaAmount(caster, level)))
                call DestroyEffect(AddSpecialEffectTarget(SFX, target, ATTACHMENT))
            elseif thistype.getFilter(target)/*
                */and .targetEnemyFilter(caster, target)/*
                */and .enemyHeroFilter(caster, target) then
        // if the target is an enemy which conforms with enemyFilter, these events take place.
        //1. The target loses mana
        //2. The caster gains mana from the target
                call SetUnitManaBJ( target, ( GetUnitState(target, UNIT_STATE_MANA) - .getManaAmountTarget(target, level)))
                call SetUnitManaBJ( caster, ( GetUnitState(caster, UNIT_STATE_MANA) + .getManaAmountTarget(target, level)))
        //Adding some special effects for caster and target
                call DestroyEffect(AddSpecialEffectTarget(SFX, target, ATTACHMENT))
                call DestroyEffect(AddSpecialEffectTarget(SFX1, caster, ATTACHMENT))
    // damages a target if he is not a hero
            elseif thistype.getFilter(target)/*
                */and .targetEnemyFilter(caster, target)/*
                */and .enemyUnitFilter(target) then
                call UnitDamageTarget(caster, target, .getDamage(caster, level), false, true, A_TYPE, D_TYPE, null) 
                call DestroyEffect(AddSpecialEffectTarget(SFX, target, ATTACHMENT))
    //kills a target if he is not a hero and his life is 25% of the current mana of the caster
            elseif thistype.getFilter(target)/*
                */and .targetEnemyFilter(caster, target)/*
                */and .enemyUnitFilter(target)/* 
                */and .unitKillFilter(caster, target) then
                call KillUnit(target)

            endif
                set target = null
                set caster = null
        
        endmethod
    endstruct

    private function spellActions takes nothing returns nothing
        call spell.m2Actions ( )
    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 spellConditions ) )
        call TriggerAddAction( t, function spellActions )
    endfunction
endlibrary
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//===========================================================================================================================
 
Last edited:
I don't know if having these two is right.
JASS:
//filter for allied units
private function getFilter takes unit caster, unit target returns boolean
    return UnitAlive(target)/*
            */and IsUnitAlly(target, GetOwningPlayer(caster))/*
            */and IsUnitType(target, UNIT_TYPE_HERO)/*
            */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)/*
            */and not IsUnitType(target, UNIT_TYPE_STRUCTURE)/*
            */and GetUnitState(target, UNIT_STATE_MANA) < GetUnitState(target, UNIT_STATE_MAX_MANA)
endfunction
//filter for enemy units
private function enemyFilter takes unit caster, unit target returns boolean
    return UnitAlive(target)/*
            */and IsUnitEnemy(target, GetOwningPlayer(caster))/*
            */and IsUnitType(target, UNIT_TYPE_HERO)/*
            */and not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)/*
            */and not IsUnitType(target, UNIT_TYPE_STRUCTURE)/*
            */and GetUnitState(target, UNIT_STATE_MANA) > 0
 
You can pretty much eliminate these:
JASS:
        private static method getManaAmount takes unit caster, integer level returns real
            return GetUnitState(caster, UNIT_STATE_MANA)*(MANA_GIVEN*level)
        endmethod

        private static method getManaAmountTarget takes unit target, integer level returns real
            return GetUnitState(target, UNIT_STATE_MAX_MANA)*(MANA_TAKEN*level)
        endmethod

        private static method getDamage takes unit caster, integer level returns real
            return GetUnitState(caster, UNIT_STATE_MANA)*(DAMAGE*level)
        endmethod

Since you already have the constants that are able to be modified. Unless you want them to be able to modify the algorithm too, but IMO they only need to modify the constants.

You can just directly inline it into the actions code. To make it a bit more simple, you can declare these locals:
JASS:
local integer casterMana = GetUnitState(caster, UNIT_STATE_MANA)
local integer targetMana = GetUnitState(target, UNIT_STATE_MANA)

Then just use them instead of calling GetUnitState() each time. You should also just inline SetUnitManaBJ(unit, x) to SetUnitState(unit, UNIT_STATE_MANA, x).
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Here are some things:

  • Make the struct spell private to avoid conflicting with other spells. Actually, why did you put the spell code in a struct?
  • Since this is a unit target spell, I don't think the conditions in getFilter are necessary except maybe for the magic-immune check, which depends on your base ability. An ability based on Chain Lightning could cover getFilter's conditions.
  • You can use Get/SetWidgetLife instead of the Get/SetUnitState alternative since it's easier to type and faster.
  • The 0.25 in return GetUnitState(target,UNIT_STATE_LIFE) < (GetUnitState(caster, UNIT_STATE_MANA)*0.25) could be a configurable constant.
  • Notice how you're repeating some of the conditions in that if-check?
    You can make the code remove the duplication if you nest some of the ifs together:

    JASS:
    // Ensures that the target can be affected by the spell
    if thistype.getFilter(target) then
        if thistype.allyFilter(caster, target) then
            // Ally restore mana code here
        elseif thistype.targetEnemyFilter(caster, target)    
    
            // Spell is targeting an enemy and does specific things based on the target
            
            if thistype.enemyHeroFilter(caster, target) then
                // Enemy hero mana drain code here            
            elseif thistype.enemyUnitFilter(target) then
            
                // Spell is dealing with a target enemy unit            
                if thistype.unitKillFilter(caster, target) then
                    // Enemy unit kill code here
                else
                    // Enemy damage code here
                endif        
                
            endif        
        endif    
    endif
  • Avoid using KillUnit since it won't give any credit (exp/gold) to the caster. You should use UnitDamageTarget with some arbitrarily high number.
  • JASS:
    call TriggerAddAction( t, function spellActions )
    You can directly use function spell.m2Actions instead.

Other things:

  • Usually, you put the spell ability id configuration as the first constant.
  • Comments are nice but simply commenting what the code does when it's pretty obvious isn't necessary.
 
Status
Not open for further replies.
Top