Frozen Orb v2.1

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

Frozen Orb


A pulsating orb that shreds an area with Ice Bolts. Each Bolt deals damage and has a chance to burst dying enemies, leaving no corpse behind.


Obligatory Requirements


Frozen Orb

JASS:
native UnitAlive takes unit id returns boolean

scope FrozenOrb initializer Init
//=========================================================================
// Name: Frozen Orb; ©Blizzard Entertainment, Diablo II
// Version: 2.1
// Author: BPower
// Requirements: Missile, SpellEffectEvent
// Credits: Bribe for SpellEffectEvent 
//=========================================================================
// Description:
// A pulsating orb that shreds an area with Ice Bolts. 
// Each Bolt deals damage and has chance to burst dying enemies,
// leaving no corpse behind. 
//=========================================================================

// User settings:
// ==============

    globals
        private constant integer    FROZEN_ORB_ABILITY  = 'A001'
        private constant attacktype ATTACK_TYPE         = ATTACK_TYPE_NORMAL       
        private constant damagetype DAMAGE_TYPE         = DAMAGE_TYPE_MAGIC
        private constant real       MISSILE_FLY_HEIGHT  = 50.00// Shared over all missiles of FrozenOrb. 
        private constant string     ON_BURST_SFX        = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
    endglobals
        
    // Set the maximum fly distance for the main orb.
    private constant function GetOrbMaxDistance takes integer level returns real
        return 800. + level*0.
    endfunction
    
    // Set the maximum fly distance for the ice bolts.
    private constant function GetIceBoltMaxDistance takes integer level returns real
        return 400. + level*0.
    endfunction

    // Set the amount of ice bolts created when the main orb explodes.
    private constant function GetIceBoltCountOnExplode takes integer level returns integer
        return 12
    endfunction
    
    // You have full access granted to all members and methods from library Missile.
    // However missile.data, missile.source and missile.owner are reserved.
    private function CustomizeFrozenOrb takes Missile orb, integer level returns nothing
        set orb.speed = 13.
        set orb.model = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
        set orb.scale = .75
    endfunction
    
    // Same as CustomizeFrozenOrb, but for ice bolts.
    private function CustomizeIceBolt takes Missile bolt, integer level returns nothing
        set bolt.speed = 20.
        set bolt.model = "Abilities\\Weapons\\LichMissile\\LichMissile.mdl"  
        set bolt.scale = .65
        set bolt.damage = 10. + 20.*level
        set bolt.collision = 48.
    endfunction
        
    // Filter which units are hit by ice bolts.
    private function TargetFilter takes unit target, player owner returns boolean
        return not IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE) and not IsUnitType(target, UNIT_TYPE_STRUCTURE) and UnitAlive(target) and IsUnitEnemy(target, owner)
    endfunction
    
    // Set the chance to burst an enemy to ice. Real comparison in range of 0 - 100.
    // Return smaller or equal to 0 if you don't need this feature.
    private constant function GetBurstChance takes integer level returns real
        return 5. + 5.*level
    endfunction
        
    // Filter out all units which shouldn't be removed from the game on burst. Heroes, .. etc
    // Those units who pass the filter get removed from the game and are inevitably gone.
    private function ExplodeFilter takes unit target returns boolean
        return not IsUnitType(target, UNIT_TYPE_MECHANICAL) and not IsUnitType(target, UNIT_TYPE_HERO)
    endfunction

    // The following struct "Buff" creates the buff- and frostnova effect of Frozen Orb.
    // Adjust the constants to your needs.
    private struct Buff extends array
        
        // Buff type settings. 
        private static constant integer CASTER_UNIT_ID = 'n000'
        private static constant integer BUFF_ORDER_ID  = 852226// OrderId("frostnova")
        private static constant integer BUFF_ABILITY   = 'A002'
        
        private static unit caster = null
        
        static method castTarget takes player owner, unit target returns nothing
            call SetUnitOwner(caster, owner, false)
            call IssueTargetOrderById(caster, BUFF_ORDER_ID, target)
            call SetUnitOwner(caster, Missile_NEUTRAL_PASSIVE, false)            
        endmethod
    
        private static method onInit takes nothing returns nothing
            set caster = CreateUnit(Missile_NEUTRAL_PASSIVE, CASTER_UNIT_ID, 0., 0., 0.)
            call SetUnitPosition(caster, 2147483647, 2147483647)
            call UnitAddAbility(caster, BUFF_ABILITY)
            call ShowUnit(caster, false)
        endmethod
    endstruct
    
//=====================================================================
// Frozen orb source code. Make changes carefully.
//=====================================================================
// You can extend struct IceBolt and / or struct FrozenOrb with 
// available Missile API, such as onDestructable, onTerrain ...
    
    private struct IceBolt extends array
        static constant real OFFSET = 32.// That ice bolts don't emit 
                                         // directly from the center of the orb.
        real chance
        
        private static method onRemove takes Missile missile returns boolean
            return true
        endmethod
                              // Runs when a missile collides with a unit.
        private static method onCollide takes Missile missile, unit hit returns boolean
            local thistype this = thistype(missile)
            
            if TargetFilter(hit, missile.owner) then
                call Buff.castTarget(missile.owner, hit)
                call UnitDamageTarget(missile.source, hit, missile.damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                
                if GetUnitTypeId(hit) != 0 and GetRandomReal(0., 100.) < chance and ExplodeFilter(hit) then
                    call DestroyEffect(AddSpecialEffect(ON_BURST_SFX, missile.x, missile.y))
                    call RemoveUnit(hit)
                endif
                return true// returning true will destroy the missile instance.
            endif
            return false// returning false will keep the missile flying.
        endmethod
        
        implement MissileStruct
    endstruct
    
    private function CreateIceBolt takes Missile orb, real angle, integer level returns nothing
        local real x = orb.x + IceBolt.OFFSET*Cos(angle)
        local real y = orb.y + IceBolt.OFFSET*Sin(angle)
        local Missile missile = Missile.create(x, y, MISSILE_FLY_HEIGHT, angle, GetIceBoltMaxDistance(level), MISSILE_FLY_HEIGHT)
    
        set IceBolt(missile).chance = GetBurstChance(level)
        call CustomizeIceBolt(missile, level)
        set missile.source = orb.source
        set missile.owner = orb.owner
        call IceBolt.launch(missile)
    endfunction
    
    private struct FrozenOrb extends array
        static constant real SPACING_ON_PERIOD = bj_PI*3/5
        static constant real SPACING_ON_REMOVE = bj_PI/4 
        
        integer level
                      // When the main orb gets deallocated.
        static method onRemove takes Missile missile returns boolean
            local thistype this = thistype(missile)
            local integer index = 0
            local integer count = GetIceBoltCountOnExplode(level)
            local real space = 2*bj_PI/count
            
            loop
                exitwhen index >= count
                call CreateIceBolt(missile, index*space + thistype.SPACING_ON_REMOVE, level)
                set index = index + 1
            endloop
            
            return true
        endmethod
                      // Every Missile_TIMER_TIMEOUT interval.
        static method onPeriod takes Missile missile returns boolean
            local thistype this = thistype(missile)
            
            call CreateIceBolt(missile, thistype.SPACING_ON_PERIOD*missile.data, level)
            set missile.data = missile.data + 1
            return false
        endmethod
    
        implement MissileStruct
    endstruct
                     // EVENT_PLAYER_UNIT_SPELL_EFFECT.
    private function OnEffect takes nothing returns nothing
        local unit source = GetTriggerUnit()
        local real x = GetUnitX(source)
        local real y = GetUnitY(source)
        local real angle = Atan2(GetSpellTargetY() - y, GetSpellTargetX() - x)
        local integer level = GetUnitAbilityLevel(source, FROZEN_ORB_ABILITY)
        local Missile missile = Missile.create(x, y, MISSILE_FLY_HEIGHT, angle, GetOrbMaxDistance(level), MISSILE_FLY_HEIGHT)
        
        set FrozenOrb(missile).level = level
        call CustomizeFrozenOrb(missile, level)
        set missile.source = source
        set missile.owner = GetTriggerPlayer()
        call FrozenOrb.launch(missile)
        
        set source = null 
    endfunction
    
    private function Init takes nothing returns nothing
        call RegisterSpellEffectEvent(FROZEN_ORB_ABILITY, function OnEffect)    
    endfunction
    
endscope


Code:
-v1.0.0
-- Initial release
-v1.0.1
-- Updated documentation
-- Added detailed import instructions
-- Changed IsUnitType to native UnitAlive
-v1.0.2
-- Added an explosion effect 
-- Reworked the demo map
-v1.0.3
-- Changed the way the explosion effect is displayed
-- Changed GetWidgetXY back to GetUnitXY
-- added variables for Sin and Cos since they are constant
-- Updated documentation
v1.0.4
-- Now slighly faster than before
-- Alloc is now optional
-- functions are now constant functions
-- Moved none configurable constant variables into the struct
-- Improved the code
-- Updated the documentation to my standart format
v1.0.4
-- DummyCaster is now optional
-- Updated hyperlinks
-- Function names are now more generic
-- Replaced bj_lastCreatedGroup with a static group to avoid unwanted bugs
v2.0
-- Projectiles are now based on Missile.
-- No longer uses DummyCaster. You may add your own caster resource.
-- Better presentation.
v2.1
-- Improved customization options.
-- Restructured code a bit.
Credits:
Bribe for SpellEffectEvent​

Keywords:
Frozen Orb, FrozenOrb, Frost, Ice, BPower, Diablo, Orb, burst, aoe, winter, snow, wizard
Contents

Frozen Orb (Map)

Reviews
Frozen Orb v1.0.3 | Reviewed by Maker | 5th November 2013 Concept[/COLOR]] The core of the spell is a forward moving projectile which is not that special by itself. The smalled projectiles that spawn and scatter around really make it more...

Moderator

M

Moderator


Frozen Orb v1.0.3 | Reviewed by Maker | 5th November 2013

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

[COLOR="gray"

Concept[/COLOR]]
126248-albums6177-picture66521.png

The core of the spell is a forward moving projectile which is not
that special by itself. The smalled projectiles that spawn and
scatter around really make it more impressive, and making the
spell have a chance to not leave corpses is a nice touch
Triggers[/COLOR]]
126248-albums6177-picture66521.png
  • Good importing instructions
  • The spell performs well and causes no FPS drop even with multiple
    simultaneous casts
126248-albums6177-picture66523.png
  • You can declare locals inside a static if
  • Use TriggerRegisterAnyUnitEventBJ instead of writing it yourself
  • Null the destroyed current.model immediately. The destroy method
    could check if the effect is not null and then destroy and null it
Objects[/COLOR]]
126248-albums6177-picture66521.png
  • Good tooltip
  • Overall well done configuration
Effects[/COLOR]]
126248-albums6177-picture66521.png
  • The visual effects fit the theme
  • And so do the sounds
Rating[/COLOR]]
CONCEPTTRIGGERSOBJECTSEFFECTSRATINGSTATUS
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
126248-albums6177-picture75360.jpg
APPROVED
 
Level 19
Joined
Aug 13, 2013
Messages
1,680
Reviewing..

EDIT: Review

Review


Frozen Orb v1.0.0
This spell had been reviewed by jakeZinc.


Trigger Code
The triggering looks good, neat and clean. I don't find some wrong or harm code nor leaks in the code and I understand it correctly in the help of documenting the codes.
Documentation
The documentation is well fine and it gives directly to the point but the configuration is lacking in documentation .
Configuration
The configuration is well good but you can try to add constant configuration in the global blocks than enumerating the currently value in the function
Pros
It is nice spell that it really fits the lich's spell. I don't notice anything lags and it is MUI Spell.
Cons
None.
Importing Instruction
The importing instruction is a bit simple maybe adding more documentation to it.
Special Effects
The special effects is good and it really fits the concept of the spell.
Usefulness
Useful in the damage line and clusters of the units in the line.
Suggestions
Adding a special effect or a blast effect to the mini shard of frost when exploding will really gonna be nice that removing like seems nothing or boring. You can set the movement type of the dummy to fly than hover. You don't need invulnerable ability to the dummy because Locust ability already does it. The test unit is too bit frustating because it is already reviving the footman units in 0.00 seconds that looks like odd xD but anyway there's no problem with that."Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"//Displayed of the target explodes maybe try it to explain why it does need a aposthropy and double slash because some users don't know about that. It is really good spell there's nothing to say.
Description Tooltip
The tooltip description supports the level of the spell but a little bit too unexplain.

jakeZinc Score Board
Rejected: 1-10
Unacceptable : 11-30
Lacking : 31-49
Useful : 50-69
Recommended : 70-90
Highly Recommended : 91-100
Director Cut : 101-105
Scores
1) Triggering - 18/20
2) Documentation - 9/10
3) Importing Instruction - 6/10
4) Special Effects - 10/15
5) Usefulness - 17/20
6) Tooltip - 7/10
7) Configuration - 7/10
Ratings
Total Score - 74/105
jakeZinc Rating - 4/5
Status - Recommended and Expected vote for Approval
Award - +Rep
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,717
Adding a special effect or a blast effect to the mini shard of frost when exploding will really gonna be nice that removing like seems nothing or boring.

Actually the Lich missile has an explosion effect. The problem you mentioned is connected to the way Dummy works. I already have two solutions in mind :).

EDIT: Added an explosion effect, by creating an extra effect. It's a dirty way and better solutions are very welcome.
EDIT: Found a better solution :D

You can set the movement type of the dummy to fly than hover. You don't need invulnerable ability to the dummy because Locust ability already does it.

It's the default setting of Particle provided by the Dummy testmap. I'm not changing it.

The test unit is too bit frustating ...

Its a demo map not a game itself and therefore totally fine :D.

Thank you for the extensive review.
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,717
Updated: Changed the code based on the Maker's suggestions, since they make sense.

  • You can declare locals inside a static if
  • Use TriggerRegisterAnyUnitEventBJ instead of writing it yourself
  • Null the destroyed current.model immediately. The destroy method could check if the effect is not null and then destroy and null it
 
Level 19
Joined
Mar 18, 2012
Messages
1,717
Update: Minor changes made. I didn't intend to bump this resource.

Changes:
  • Now slighly faster than before
  • Alloc is now optional
  • functions are now constant functions
  • Moved none configurable constant variables into the struct
  • Improved the code
  • Updated the documentation to my standart format
 
Level 19
Joined
Mar 18, 2012
Messages
1,717
Updated to v1.0.5, if you are using v1.0.4 you don't have to update it in your map.

DummyCaster is no longer required, but optional.
Fixed a very minor issue, as the spell was using bj_lastCreatedGroup for the group enumeration.
Also updated the links posted in the spell description.
 
Level 19
Joined
Mar 18, 2012
Messages
1,717
Update:

The spell is now based on my Missile library. The code of the previous version can still be found in the demo map and in the thread description.

If you compare the previous and new version, you will see that the amount of code has shrunk, as
projectile movement and collision checks are now takes over by Missile.

For very little overhead Missile provides you incredible useful projectile features. Check out the full API in the link I posted or
read Missile's API in the library, which is included in the demo map
Also UnitIndexer and requirements are no longer part of Frozen Orb.
DummyCaster has been removed, if you use a dummy spell casting system feel free to integrate it to Frozen Orb.

I highly recommend to import some of Missiles optional requirements ( MissileRecycler, WorldBounds, GroupUtils, ... )
 
Top