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

Bouncing Bombs v1.4

  • Like
Reactions: Bannar
Spell Name: Bouncing Bombs

Throws 5 bouncing bombs towards the targeted point, it bounce and bounce until it blows, damaging enemy units including trees and other destructables.

|cffffcc00Level 1|r - each bomb damages 50.
|cffffcc00Level 2|r - each bomb damages 75.
|cffffcc00Level 3|r - each bomb damages 100.
|cffffcc00Level 4|r - each bomb damages 125.
|cffffcc00Level 5|r - each bomb damages 150.


JASS:
/*
==========Bouncing Bombs 1.4
==========Made by: Mckill2009

REQUIRES:
- Jass New Gen Pack (JNGP) by Vexorian
- BoundSentinel by Vexorian
- TimerUtils by Vexorian
- Vector by Anitarf
- DestructableLib by PitzerMike

HOW TO INSTALL:
- Copy ALL the triggers in the folder at the left of this screen that says "All these MUST be copied to your map".
- If you already have the "Required Libraries" in your map, then no need to copy the said library.
- Change the raw codes if needed.

FEATURES:
- You can configure how many bombs you want to create
- Much of the features are configurables, please see below

CREDITS:
- Bribe for the tip
*/

library BouncingBombs uses Vector, TimerUtils, DestructableLib, BoundSentinel

globals
    //These are the raw codes, change it if necessary
    private constant integer              SPELL_ID = 'A000' //flame strike
    private constant integer               BOMB_ID = 'h000'
    //Never touch these!
    private vector xV
    private vector yV
    private vector zV
    private rect REC
endglobals

globals
    //Configurables
    private constant integer             MAX_BOMBS = 5 //maximum bombs created
    private constant real                      AOE = 200 //aoe of the bomb when explodes
    private constant real                 MAX_DIST = 300 //used for bombs to be at random point in SpellTargetXY
    private constant real                 PERIODIC = 0.03125
    private constant real                    SPEED = 15 //recommended
    private constant attacktype                ATK = ATTACK_TYPE_CHAOS
    private constant damagetype                DMG = DAMAGE_TYPE_NORMAL
    private constant string                    SFX = "Objects\\Spawnmodels\\Human\\FragmentationShards\\FragBoomSpawn.mdl"
    private constant boolean      DAMAGE_ONLY_TREE = true
endglobals

private function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

private function GetDamage takes integer i returns real
    return 25 + i * 25.
endfunction

private function ParabolaZ takes real h, real d, real x returns real
   return (4 * h / d) * (d - x) * (x / d)
endfunction

struct VectorLib
    vector position
    vector velocity
    
    method bounce takes unit u, real x, real y returns nothing
        local vector v
        set .position.x = x
        set .position.y = y
        call .velocity.add(yV)
        call .position.add(.velocity)
        call .velocity.add(yV)
        call zV.getTerrainPoint(.position.x, .position.y)
        call SetUnitPosition(u, .position.x, .position.y)
        call SetUnitFlyHeight(u, .position.z, 0.0)
        if zV.z >= .position.z then
            call zV.getTerrainNormal(zV.x, zV.y,4.0)
            set v = vector.projectionVector(.velocity, zV)
            call v.scale(-2.0)
            call .velocity.add(v)
            call v.destroy()
        endif
    endmethod
    
    method vcreate takes unit u, real velocityX, real velocityY, real bounceheight returns nothing
        set .position = vector.create(GetUnitX(u),GetUnitY(u),bounceheight)
        set .velocity = vector.create(velocityX,velocityY,10)
    endmethod  
endstruct

private struct BB extends VectorLib
    unit caster
    unit missile
    real duration
    real damage
    real angle
    real distance
    real distx
    real height
    static constant real FIXED_CREATION_HEIGHT = 100
      
    static method getDestructables takes nothing returns boolean
        local destructable d = GetFilterDestructable()
        if DAMAGE_ONLY_TREE and IsDestructableTree(d) then
            call KillDestructable(d)
        elseif not DAMAGE_ONLY_TREE then
            if GetDestructableLife(d) >= 0.405 then
                call KillDestructable(d)
            endif
        endif
        set d = null
        return false
    endmethod 
    
    method dest takes real x, real y returns nothing
        call MoveRectTo(REC, x, y)
        call EnumDestructablesInRect(REC,null,function thistype.getDestructables)
    endmethod
    
    private static method bombmovements takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local thistype this = GetTimerData(t)
        local unit first
        local unit dummy
        local real x = GetUnitX(.missile)
        local real y = GetUnitY(.missile)
        local real x1
        local real y1
        if .duration > 0 then
            set .duration = .duration - PERIODIC
            if .distx > 0 then
                set .distx = .distx - SPEED
                call SetUnitPosition(.missile, x + SPEED * Cos(.angle), y + SPEED * Sin(.angle))
                call SetUnitFlyHeight(.missile, ParabolaZ(.height, .distance, .distx), 0)
            else
                call bounce(.missile,x,y)
                if GetUnitFlyHeight(.missile) <= 10 then
                    call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)
                    loop
                        set first = FirstOfGroup(bj_lastCreatedGroup)
                        exitwhen first==null
                        if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.missile)) then
                            call UnitDamageTarget(.missile, first, .damage, false, false, ATK, DMG, null)
                            call KillUnit(.missile)
                            call DestroyEffect(AddSpecialEffectTarget(SFX, .missile, "chest"))
                            call .dest(x,y)
                        endif
                        call GroupRemoveUnit(bj_lastCreatedGroup, first)
                    endloop
                endif
            endif
        else
            if UnitAlive(.missile) then 
                call KillUnit(.missile)
                call DestroyEffect(AddSpecialEffectTarget(SFX, .missile, "chest"))
                call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)
                call .dest(x,y)
                loop
                    set first = FirstOfGroup(bj_lastCreatedGroup)
                    exitwhen first==null
                    if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.missile)) then
                        call UnitDamageTarget(.missile, first, .damage, false, false, ATK, DMG, null)
                    endif  
                    call GroupRemoveUnit(bj_lastCreatedGroup, first)
                endloop
            endif
            call ReleaseTimer(t)
            call .destroy()
        endif
        set t = null
    endmethod
    
    private static method create takes unit u, unit missile, real distance, real angle, integer level returns thistype
        local thistype this = thistype.allocate()
        local timer t = NewTimer()
        call vcreate(u,GetRandomReal(-3,3),GetRandomReal(-3,3),100)
        set .caster = u
        set .missile = missile
        set .distance = distance
        set .distx = distance
        set .angle = angle        
        set .height = FIXED_CREATION_HEIGHT
        set .damage = GetDamage(level)
        set .duration = GetRandomReal(5, 10)
        call SetTimerData(t, this)   
        call TimerStart(t, PERIODIC, true, function thistype.bombmovements)
        return this
    endmethod
    
    private static method creation takes unit u returns nothing
        local integer i = 0
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real x1
        local real y1        
        local real dx
        local real dy
        local unit missile
        loop
            set x1 = GetSpellTargetX()+GetRandomReal(50, MAX_DIST)*(GetRandomReal(-1,1))
            set y1 = GetSpellTargetY()+GetRandomReal(50, MAX_DIST)*(GetRandomReal(-1,1))
            set dx = x1-x
            set dy = y1-y
            set missile = CreateUnit(GetTriggerPlayer(), BOMB_ID, x, y, 0)
            call BB.create(u, missile, SquareRoot(dx*dx+dy*dy), Atan2(y1-y, x1-x), GetUnitAbilityLevel(u, SPELL_ID))
            set i = i + 1 
            exitwhen i==MAX_BOMBS
        endloop
        set missile = null
    endmethod
    
    static method go takes nothing returns boolean
        if GetSpellAbilityId()==SPELL_ID then
            call creation(GetTriggerUnit())
        endif
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, function thistype.go)
        set xV = vector.create(1,0,30)
        set yV = vector.create(0,0,-0.5)
        set zV = vector.create(0,0,-0.035)     
        set REC = Rect(-AOE,-AOE,AOE,AOE)
        set t = null
    endmethod
    
endstruct

endlibrary



v1.4
- Added option of destroying trees or destroy all destructables
- DestructableLib added again.

v1.3a
- Extra spell removed.
- Targets also other destructables.
- DestructableLib removed.

v1.3
- New libraries implemented.
- Codes reduced but more efficient including the instruction.

v1.2
- MapBounds is now required
- Bomb prematurely explodes if enemy unit is near


Keywords:
bomb, bounce, vector, fire, war, grenade, launch, vexorian, jngp, vjass, gui
Contents

Bouncing Bombs v1.4 (Map)

Reviews
16 July 2012 Bribe: A good spell. Not perfect, could use fine-tuning here and there. Approved 3.7/5.

Moderator

M

Moderator

16 July 2012
Bribe: A good spell. Not perfect, could use fine-tuning here and there. Approved 3.7/5.
 
Level 2
Joined
Sep 23, 2011
Messages
11
//===HOW TO USE:
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//- Change the raw codes of the SPELL_ID and spell

What does this mean?This spell looks cool i realy like it but i'm new to importing spells in vJass or jass so can anyone send a pm with a link on "how to" , I would realy like a tutorial.Pls don't say bad things i just don't know.

And grats on the spell looks very cool keep up the good work.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
What does this mean?This spell looks cool i realy like it but i'm new to importing spells in vJass or jass so can anyone send a pm with a link on "how to" , I would realy like a tutorial.Pls don't say bad things i just don't know.

And grats on the spell looks very cool keep up the good work.

in the trigger editor go to EDIT >>> CONVERT CUSTOM TEXT
the trigger looks like this
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

ERASE ALL that and COPY all that is written in the bouncing bomb code then paste it to the empty space...

raw codes of SPELL_ID can be viewd by pressing CTRL+D in the object editor, change it if necessary...

if you still dont understand then I recommend learning the basics of triggers before using this spell...
 
JASS:
            set x1 = GetSpellTargetX()+GetRandomReal(50, MAX_DIST)*Cos(GetRandomReal(-1,1))
            set y1 = GetSpellTargetY()+GetRandomReal(50, MAX_DIST)*Sin(GetRandomReal(-1,1))

->

JASS:
            set x1 = GetSpellTargetX() + GetRandomReal(50, MAX_DIST) * GetRandomReal(-1,1)
            set y1 = GetSpellTargetY() + GetRandomReal(50, MAX_DIST) * GetRandomReal(-1,1)

That's what Bribe meant.

---
You should cache GetTriggerPlayer() in your creation function (It's repeated inside a loop.)
Same for GetSpellTargetX and GetSpellTargetY.

And must you use that old Vector library? :/
It sucks :c
 
Level 10
Joined
Sep 19, 2011
Messages
527
set x1 = GetSpellTargetX()+GetRandomReal(50, MAX_DIST)*Cos(GetRandomReal(-1,1))

->

local real x1 = GetSpellTargetX()

In the loop:

set x1 = x1+GetRandomReal(50, MAX_DIST)*Cos(GetRandomReal(-1,1))

The same with "y1".
My bad.

Maybe you can put the actions that are in the "creation" method in "go" method, but you will need UnitSpellEffect library.

0.03125 period is too short for TimerUtils, use T32 or CTL instead (better).

If return executes (in the bombmovements method) you will have a leak (the timer).

call EnumDestructablesInRect(REC, function thistype.getDestructables, null)

I don't know how to work with rects, but here, can you work like groups?, you know, the loop (is faster by this way, that's why I'm asking :p).

Nice spell.

Greetings.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
>>> Maybe you can put the actions that are in the "creation" method in "go" method, but you will need UnitSpellEffect library.

Nah, I preffer not to use it at the moment, coz I really hate too many library
imports, it should have been 4 imports but I decreased it to 3...

>>> 0.03125 period is too short for TimerUtils, use T32 or CTL instead (better).

T32 or CTL is better for this, yes, but I preffer TU, still works fine...

>>> If return executes (in the bombmovements method) you will have a leak (the timer).

like nulling units, this works the same, it's recommended to null but not a must...

>>> call EnumDestructablesInRect(REC, function thistype.getDestructables, null)
>>> I don't know how to work with rects, but here, can you work like groups?, you know, the loop (is faster by this way, that's why I'm asking :p).

there is no native FirstOfGroup for destructables...
 
Top