[v]JASS - Acrane Bubble v0.7a

Description

Summons a huge bubble wich lifts all enemys within it into the air. After a short period of time the bubble disappears and all enemys fall onto the ground and get damaged.



Level 1:
Damage: 100
Additional Time in Air: 2.25 Seconds

Level 2:
Damage: 160
Additional Time in Air: 2.75 Seconds

Level 3
Damage: 220
Additional Time in Air: 3.25 Seconds
This spell needs New Gen to be edited. Download it from here

JASS:
scope ArcaneBubble initializer Init

    globals
        private     constant    integer SID = 'Abbs'
        //The spell rawcode
        
        private     constant    integer DID = 'acbd'
        //The bubble´s rawcode (the upper part)
        
        private     constant    integer DID2 = 'acb2'
        //Also the bubble´s rawcode but the lower part
        
        private     constant    boolean AFFECT_AIR = false
        //Should the bubble also pick up flying units ? (yes = true; no = false)
        
        private     constant    real      BUBBLE_HEIGHT = 750
        //How far should the bubble raise in the air ?
        
        private     constant    real      BUBBLE_FLY_SPEED     = 250
        //How fast should the bubble raise ?
        
        private     constant    real      TARGET_MIN_HEIGHT = 600
        //The minimal height of an enemy which is in the bubble.
        //The target height is any random number between the the bubble height and this value
        
        private     constant    real      TARGET_FLY_SPEED    = 200
        //How fast should a target raise ? 
        
        private     constant    real      TARGET_FALL_SPEED = 2300
        //How fast sould a unit fall back to the ground ?
        
        private     constant    real      LIFT_OFF_RANGE = 400
        //The AoE range of the spell
        
        private     constant    real      CRATER_RADIUS = 190
        //When a unit falls back onto the ground it creates a small crater. How large shall the radius be ?
        
        private     constant    real      CRATER_DEPTH   = 120
        //Self explaining
        
        private     constant    real      CRATER_DUR       = 0.55
        //How long should the create being displayed ?
        
        private     constant    real       BUBBLE_SIZE        = 4
        //You may want to change the size of the bubble
                
        private     constant    string   IMPACT_SFX = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
        //The special effect being displayd when a unit hits the ground
        
        //_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-
        //_-=-_-=-_-=-_-=-_-=-Spell Privates. Please don´t touch !!_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=
        //_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-
        private     constant    real      UPDATE_INTER    = 0.1
        private     constant    real      EFFECT_DELAY    = BUBBLE_HEIGHT/BUBBLE_FLY_SPEED - 0.4
        private     constant    real      INNER_DIAMETER = 250
        private     constant    timer   TIM = CreateTimer()
        private     constant    group  SAFE_GROUP = CreateGroup()
        private                       filterfunc LIFT_OFF
        private                       integer TEMP_STRUCT
        //_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-
        //_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-_-=-
    endglobals
    
    //How long should the units stay in the air ? (based on the level ofc)
    private constant function StayInAir takes real level returns real
        return level * 1.5 + 0.75
    endfunction
    
    //How much damage should a unit recieve when it´s hitting the ground ? (based on the level too ofc)
    private constant function GetImpactDamage takes real level returns real
        return level * 60 + 40
    endfunction
    
    //The main struct
    private struct Bubble
    
        static thistype array Index
        static integer Total = 0
        //Static member used for the indexing method
        
        unit caster
        unit bubble
        unit bubble2
        group targets
        boolean freeze
        real timeout
        
        //Destructor method
        method onDestroy takes nothing returns nothing
        
            call RemoveUnit(.bubble)
            call RemoveUnit(.bubble2)
            call DestroyGroup(.targets)
            
        endmethod
        
        //Creator method
        static method create takes unit ca, location loc returns thistype
        
            local thistype this = thistype.allocate()
            
            set .caster = ca
            set .bubble = CreateUnit(GetOwningPlayer(ca),DID,GetLocationX(loc),GetLocationY(loc),0)
            set .bubble2 = CreateUnit(GetOwningPlayer(ca),DID2,GetLocationX(loc),GetLocationY(loc),0)
            set .targets = CreateGroup()
            set .timeout = StayInAir(GetUnitAbilityLevel(ca,SID)) + BUBBLE_HEIGHT/BUBBLE_FLY_SPEED
            set .freeze = true
            set TEMP_STRUCT = this
            call GroupEnumUnitsInRange(.targets,GetLocationX(loc),GetLocationY(loc),LIFT_OFF_RANGE,LIFT_OFF)
            call SetUnitFlyHeight(.bubble,BUBBLE_HEIGHT,BUBBLE_FLY_SPEED)
            call SetUnitFlyHeight(.bubble2,BUBBLE_HEIGHT - INNER_DIAMETER,BUBBLE_FLY_SPEED)
            call SetUnitScale(.bubble,BUBBLE_SIZE,BUBBLE_SIZE,BUBBLE_SIZE)
            call SetUnitScale(.bubble2,BUBBLE_SIZE,BUBBLE_SIZE,BUBBLE_SIZE)
            
            set thistype.Index[thistype.Total] = this
            set thistype.Total = thistype.Total + 1
            
            return this
            
        endmethod
        
    endstruct
    
    //The struct holds the data which is necessary for hitting the ground
    private struct Fall
    
        static thistype array Index
        static integer Total = 0
        //Again some static members for struct indexing
        
        unit target
        unit caster
        real  timeout
        
        //Another Destructor
        method onDestroy takes nothing returns nothing
        
            call UnitRemoveAbility(.target,'Amrf')
            call PauseUnit(.target,false)
            call UnitDamageTarget(.caster,.target,GetImpactDamage(GetUnitAbilityLevel(.caster,SID)),false,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_UNKNOWN,WEAPON_TYPE_WHOKNOWS)
            call DestroyEffect(AddSpecialEffect(IMPACT_SFX,GetUnitX(.target),GetUnitY(.target)))
            call TerrainDeformCrater(GetUnitX(.target),GetUnitY(.target),CRATER_RADIUS,CRATER_DEPTH,R2I(CRATER_DUR * 1000),false)
            call GroupRemoveUnit(SAFE_GROUP,.target)
            
        endmethod
        
        //...And another Creator
        static method create takes unit ca, unit ta returns thistype
        
            local thistype this = thistype.allocate()
            
            set .target = ta
            set .caster = ca
            set .timeout = (GetUnitFlyHeight(ta) - GetUnitDefaultFlyHeight(ta)) / TARGET_FALL_SPEED
            call SetUnitFlyHeight(ta,GetUnitDefaultFlyHeight(ta),TARGET_FALL_SPEED)
            
            set thistype.Index[thistype.Total] = this
            set thistype.Total = thistype.Total + 1
            
            return this
        
        endmethod
        
    endstruct
    
    //Functions which sends all unit (even flying ones) into the air
    private function LiftOffAll takes nothing returns boolean
    
        local unit u = GetFilterUnit()
        local Bubble this = TEMP_STRUCT
        
        if IsUnitEnemy(u,GetOwningPlayer(this.caster)) and IsUnitInGroup(u,SAFE_GROUP) != true and GetWidgetLife(u) > 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) !=true and IsUnitType(u, UNIT_TYPE_MECHANICAL) != true and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) != true and IsUnitType(u, UNIT_TYPE_ANCIENT) != true then
            call PauseUnit(u,true)
            call UnitAddAbility(u,'Amrf')
            call SetUnitFlyHeight(u,GetRandomReal(TARGET_MIN_HEIGHT,BUBBLE_HEIGHT),TARGET_FLY_SPEED)
            call GroupAddUnit(SAFE_GROUP,u)
            set u = null
            
            return true
        endif
        
        set u = null
        return false
        
    endfunction
    
    //This function won´t send flying units into the air
    private function LiftOffGround takes nothing returns boolean
    
        local unit u = GetFilterUnit()
        local Bubble this = TEMP_STRUCT
        
        if IsUnitEnemy(u,GetOwningPlayer(this.caster)) and IsUnitInGroup(u,SAFE_GROUP) != true and IsUnitType(u,UNIT_TYPE_FLYING) != true and GetWidgetLife(u) > 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) !=true and IsUnitType(u, UNIT_TYPE_MECHANICAL) != true and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) != true and IsUnitType(u, UNIT_TYPE_ANCIENT) != true then
            call PauseUnit(u,true)
            call UnitAddAbility(u,'Amrf')
            call SetUnitFlyHeight(u,GetRandomReal(TARGET_MIN_HEIGHT,BUBBLE_HEIGHT),TARGET_FLY_SPEED)
            call GroupAddUnit(SAFE_GROUP,u)
            set u = null
            
            return true
        endif
        
        set u = null
        return false
        
    endfunction
        
    //Lets all units fall down
    private function InitFallDown takes nothing returns nothing
        
        local Bubble this = TEMP_STRUCT
        local Fall that = Fall.create(this.caster,GetEnumUnit())
        
    endfunction
  
    //This function is used for the timing...It loops through both structs
    private function WaitLoop takes nothing returns nothing
    
        local Bubble bub
        local Fall fa
        local integer inst = 0
        
        //Looping through the main struct
        loop
            exitwhen inst == Bubble.Total
            set bub = Bubble.Index[inst]
            
            if bub.timeout > 0 then
                set bub.timeout = bub.timeout - UPDATE_INTER
                
                if bub.freeze and bub.timeout <= EFFECT_DELAY + StayInAir(GetUnitAbilityLevel(bub.caster,SID)) then
                    call SetUnitTimeScale(bub.bubble,0)
                    call SetUnitTimeScale(bub.bubble2,0)
                    set bub.freeze = false
                endif
                
            else
                set TEMP_STRUCT = bub
                call ForGroup(bub.targets,function InitFallDown)
                call bub.destroy()
                set Bubble.Total = Bubble.Total - 1
                set Bubble.Index[inst] = Bubble.Index[Bubble.Total]
                set inst = inst - 1
            endif
            
            set inst = inst + 1
        endloop
        
        //Looping through the Fall struct
        set inst = 0
        
        loop
            exitwhen inst == Fall.Total
            set fa = Fall.Index[inst]
            
            if fa.timeout > 0 then
                set fa.timeout = fa.timeout - UPDATE_INTER
            else
                call fa.destroy()
                set Fall.Total = Fall.Total - 1
                set Fall.Index[inst] = Fall.Index[Fall.Total]
                set inst = inst -1
            endif
            
            set inst = inst + 1
        endloop
        
        //If BOTH structs are not running we pause the timer
        if Bubble.Total == 0 and Fall.Total == 0 then
            call PauseTimer(TIM)
        endif
        
    endfunction
    
    //The remains of GUI
    private function Actions takes nothing returns nothing
        
        call Bubble.create(GetTriggerUnit(),GetSpellTargetLoc())
        
        if Bubble.Total - 1 == 0 then
            call TimerStart(TIM,UPDATE_INTER,true,function WaitLoop)
        endif
        
    endfunction

    //Checking the spell rawcode
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == SID
    endfunction

    //Prevents leak upon trigger creation
    private constant function AntiLeak takes nothing returns boolean
        return true
    endfunction

    //The Initializer
    private function Init takes nothing returns nothing
    
        local trigger t = CreateTrigger()
        local filterfunc f = Filter(function AntiLeak)
        local integer i = 0
        
        if AFFECT_AIR then
            set LIFT_OFF = Filter(function LiftOffAll)
        else
            set LIFT_OFF = Filter(function LiftOffGround)
        endif
        
        loop
            call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,f)
            exitwhen i == 15
            set i = i + 1
        endloop
        
        //Preloading....
        call RemoveUnit(CreateUnit(Player(15),DID,0,0,0))
        call Preload(IMPACT_SFX)
        call PreloadStart()
        
        call TriggerAddCondition(t,Condition(function Conditions))
        call TriggerAddAction(t,function Actions)
        call DestroyFilter(f)
        set t = null
        set f = null
        
    endfunction

endscope


v0.1

-Initial Release

v0.2

- The dummy is now unpickable
- Improved comments to make the spell more userfriendly
- Nulled locals
- Improved the filterfunc

v0.3

- The Spell is now [v]JASS
- Completely reworked
- Should be leakless now
- Now uses timers instead of TriggerSleep
- Removed all BJ`s
- Added a globals block to make the spell more userfriendly

v0.4

-The Spell now requires JNGP and Kattanas Attatch System (included)
- Explicit credit to Ice Frog for the model and to Kattana for his Attatch System.

v0.5

- Removed the imported Icon
- Removed the (hopefully) last leak: GetSpellTargetLoc()
- Removed the useless timer start
- Removed a bug:
-> When a unit is inside a bubble i cannot be added to another bubble.
This is only valid when its the first and the second bubble spell are
created by the same script(Timer Utils version or Keygen version).
- The code was cleared up
- Adjusted the damage
- Testhero will respawn when killed
- There are 2 spell versions now:
1.is using Vexorians Timer Utils instead of Gamecache
2.is using Keygen (an algorithem created by myself to provide indexes)

v0.6

- The spell won´t crash JNGP any further !
- Removed the Keygen version because it caused an unknown bug:
->Whe GenerateKey() was called every other action was skipped.
- No major code changes were made
- Improved the Testmap

v0.7

- The spell is now compatible with ANY Warcraft III version.
- Code was completely reworked
- Now using Struct Indexing instead of Timer Utils
- Greatly improved efficiency
- Added more comments

v0.7a

- Removed the custom model and replaced it with a dummy construction
- Adjusted the code to support the dummy construction

Keywords:
Arcane Bubble ,Bubble, AoE, Arcane, Air, Orb
Contents

Arcane Bubble Spell (Map)

Reviews
14:35, 9th Aug 2009 Reapproved for removing the model hvo-busterkomo: Complete re-review. I'm glad you ending up fixing the complaints I had. You really shouldn't be using the gg_trg prefix for a local. There are a few other...
Status
Not open for further replies.

Moderator

M

Moderator

14:35, 9th Aug 2009


Reapproved for removing the model


hvo-busterkomo:
Complete re-review.

I'm glad you ending up fixing the complaints I had. You really shouldn't be using the gg_trg prefix for a local. There are a few other optimizations that could be made, but would require a lot of code re-writing. You could also preload the effects.
 
Level 14
Joined
Jan 15, 2007
Messages
349
There are some points you have to add or to improve:

1.) Add constants to your spell. So it will be much more easier for users to configurate your spell.
2.) Null locals if you don't need them anymore. For example like this:
JASS:
function bla takes unit a returns nothing
local location loc=Location(0,0)
local group g     =CreateGroup()
local unit b        =a
call RemoveLocation(loc)
call DestroyGroup(g)
set loc=null
set g=null
set b=null
endfunction
3.) Don't use any TSA functions in your script
4.) Try to avoid to use BJ's and also try to make your spell script always so fast as possible.
5.) If you would use vJASS (JassHelper, get it at Welcome to Wc3Campaigns), you could optimize the script much better. Also you could make the script much more readable.
6.) You don't need to check twice if a boolean is true, just if you use IsUnitType. Else you must just write for example:
JASS:
function blub takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetSpellAbilityUnit()))
endfunction

I think that's all for now.
 
Level 17
Joined
Mar 17, 2009
Messages
1,350
@ QueenOfOblivion:
- it's really easy to remove the protection from some map (basically hacking it :p)... thus u'll be able to reach all the models from DotA. I'm totally against that cause if IceFrog wanted whatever is in his map public, he wouldnt have protected it first place. the important thing is that credit was given to IceFrog ;)
 
Level 25
Joined
Jun 5, 2008
Messages
2,573
That is not the only method to get a model, you could just search it here on some other wc3 site and find it like all normal people do...
EDIT:
This is almost a ripoff of Telekinesis spell we have here on the hive, the idea is the same, only thing difrent is the damage variable and the gfx.
 
Level 9
Joined
Aug 2, 2008
Messages
219
1.Sorry but jass helper has a problem with my windows…dont know what that is.
2.What are TSA functions ?
3.I dident check the hive for compareable spells, i apologize if i made an almost ripoff of an other spell. If someone demands ill give credits, but dont delete this spell i put a lot of efforts in it. I created it by myslef just with WE and JC.
4.I searched the model on WC3 stuff sites but couldn´t find it. I´ve extracted it with an MPQ editor and thought DOTA is a public map so using the stuff in it should be ok while giving credits to the creator.
 
Level 4
Joined
Sep 21, 2008
Messages
8
i dont become its working^^ im to bad... i copied the dummy the skin the skill and the trigger... all its like in his map.. and in my map he only makes this sphere on the ground the units get green and burn.. ^^

hu.. i am nearly done.. the skill works and does dmg ^^ but... no chronosphere spawns.. a defensetower of humans spawn^^
 
Last edited:
Level 9
Joined
Aug 2, 2008
Messages
219
@Senseless
ok do it like this…create a new unit in the object editor, use a human worker as basic unit and call it dummy. Then change the dummies model in the object editor to the chronospehre model. Check if the rawcode of the dummy (you will see it when u press STRG+d in the objecteditor) is the same as in the script and make shure your dummy is just a simple unit. Buildings and tower cant fly anyway. Besides did the targetunits start to fly ?

ok and now an other stupid question concerning the TSA…is look in JC´s native list for some kind of substitute for the lame TSA. I found something called call PolledWait(real)
shuld i use that or not. if not say me please how i shuld time my script correctly.
 
Level 9
Joined
Aug 2, 2008
Messages
219
Sorry guys but im still n00b…i tried it for some hours to stop my script with timers and then resume it when the timer fished but i cant figure that out. Can someone give me an example how to do it or post a link to a tutorial or somthing…The result of my experiments an research was a bit frustrating:angry:

JASS:
//Well here you can see what i tried in the end…
function b takes nothing returns nothing
local real s = 5
local timer t = CreateTimer()
local timerdialog d = CreateTimerDialog(t) 
//Creating a dialog to check if the timer spawns and is couting down
call TimerStart(t,s,false,null) 
call TimerDialogDisplay(d,true)
call DisplayTextToPlayer(Player(0),0,0,"Let´s get started")
loop
exitwhen TimerGetRemaining(t) <= 0
endloop
call DisplayTextToPlayer(Player(0),0,0,"Here should the be the proof that it works")
call DestroyTimer(t)
call DestroyTimerDialog(d)
set t = null
set d = null
endfunction

function InitTrig_timer_test takes nothing returns nothing
    local trigger gg_trg_timer_test = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_timer_test, Player(0), "-a", true )
    call TriggerAddAction( gg_trg_timer_test, function b )
endfunction

I´ve needed that TSA to let the units in the bubble stay in the air for a short time (similar to a stun) and than wait a short moment until they are all back on the ground to deal the damage and do some other things. But i finally cleaned up all leaks. Please help me…
 
Level 1
Joined
Feb 3, 2008
Messages
1
is there a way to remove those flames form their feet? i have looked around in your trigger and stuff but cant see where u attach them although im not good with jass.

the reason i want to do this is just cuz when other units that arnt in the bubble run under it they get flames on their feet and they dont seem to go away also if u have a unit in the bubble and he doesnt die the flames dont seem to go away and i dont know why there would be flames in a arcane spell anyway.

but apart from that i like it and i plan to use it in my map

and you explained your jass very well ty for that it definatley helps.

4/5
 
Level 9
Joined
Aug 2, 2008
Messages
219
@branno
ok this is my fault. I used bloodmages flamestrike as basic ability and im pretty shure i removed any additional effects and etc.
Im going to update the spell when my final exams are over. Thank you 4 the feed back.

[edited]

My examination is over:grin::grin::grin: Life is better now
Spell has been updated
 
Last edited:
Level 2
Joined
Apr 29, 2009
Messages
8
Why did you added the serpents since they are invulnerable aganist magic spells ?

They just killed me in a few secs when i noticed the spell didnt worked on them...
 
Level 9
Joined
Aug 2, 2008
Messages
219
Spell Update 0.04

Allright guys i have updated the spell:

hvo-busterkomo said:
An alright attempt at a vJASS spell, but it needs a few things fixed to be approved:
1. Remove the imported icon, it's against the submission rules.
2. You have a leak (GetSpellTargetLoc).
3. In your Init_Fall function you start a timer with a null handlerFunc. What's the reason behind that?
4. You need to indent your code.
5. You really shouldn't be using LHV anymore. Switch to a struct attachment system such as TimerUtils.

1. Done
2. Remove the leak
3.Dunno why i did that. It had no spefic purpose and i removed it (actually i have reworked the complete spell).
4.Sorry dont really know what you mean but i think it was something like this:

Unindented code example:
JASS:
function some_func takes nothing returns nothing
local integer i = 0
local unit u = GetTriggerUnit()
call RemoveUnit(u)
set u = null
endfunction
Indented code example:
JASS:
function some_func takes nothing returns nothing
     local integer i = 0
     local unit u = GetTriggerUnit()
     call RemoveUnit(u)
     set u = null
endfunction
If this is right i have indented the code^^

5.The spell is not using gamecache any further i put an script in the map which uses Vexorians Timer Utils and another script version which uses my Keygen method (there is some information in "How to import" trigger what the Keygen actually is.

Lakai said:
Why did you added the serpents since they are invulnerable aganist magic spells ?

They just killed me in a few secs when i noticed the spell didnt worked on them...
Well i have added the serpent ward to show the spell wont work by spell immune units. But for you i have added a revival trigger :grin:.

One last thing: I have already removed the bug with the bubbles shadow in a preverios update.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,244
Aparently this spell is using some form of enhanced GUI looking at the load errors given. I say it uses JNGP, but with the funky GUI enhancement system it comes with turned on. I never could get that working, thus never could open such maps. . .

Also nowhere did it say in the rules that he is not allowed to use gamecache systems to attach structs. Last I head purple.poot had nothing wrong with them. However, they are best avoided still as they can result in exessive string leaks which is not particually good for one's map.
 
Level 9
Joined
Aug 2, 2008
Messages
219
update v0.5

sorry guys i´m now a bit busy…give me one or 2 days until i have fixed this spell too.
[edit]
at least i´ve been able to remove the crashing bug so that the spell will work with every version of JNGP now.
If there is still something i can do to approve this just tell me.
 
Last edited:
Level 9
Joined
Aug 2, 2008
Messages
219
Approved

Somehow this one got approved too :grin:

@Jack_Sparrow93

by only using PauseUnit(whichunit,true) you ofc will pause the unit but it won´t interrupt the animation. I did that intentionally and i´d like to give you an opporturnity to configurate this aspect of the spell, but for me this one is finished until someone mentiones something urgent that has to be fixed.

~TNT (Deuteriums idea:wink:)
 
Status
Not open for further replies.
Top