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

[Solved] Bash like spell that knockbacks to air(only Z)

Status
Not open for further replies.
Level 8
Joined
Jun 13, 2008
Messages
346
like the title says, it should only burst the unit towards air...no X and Y movement, only Z(like how impale does to units).

I always try to do my needs before requesting them here...but using a 3D-knockback system with DDS was kinda hard for me...though I'm not sure if I actually need a knockback system just to move the unit at Z coords.

in fact I'd be still grateful if someone guides me to make it by myself.

to be more specific; basic attacks have a chance(20%/30%/40%) to burst the target to air while dealing extra damage to them(apparently splash attacks will still proc the spell and there's no solution to this because of DDS limitations).

What I exactly want is very similar to this, except I want it to throw/knockback to air instead of x/y;
Spell - Max Bash 2.0
 
Level 39
Joined
Feb 27, 2007
Messages
5,027
You could easily modify that code to do what you want. Granted it's a little overkill but you just need to change it from moving in the XY plane to moving up/down the Z axis. The hard part is just detecting the bash, and that spell has done it all for you with a DDS. You'll need to add some variables to the bash struct and change a bit in the create(), destroy(), and launch() functions.
JASS:
struct bash {
        private {
            unit      b, s;
            real      dist, mxdist;
            real      dx, dy;
            real        dmg;
            p_real     vec;
            integer    p;

         @  ADDED  @
            real z;
            real vz;
            real az;
            real zprev;
         @   END  @
        }
     
        /// ----------------------------------------------------------------
     
        // ***
        static method create(integer castplayer, unit bashingUnit, unit whichUnit, integer lvl, real distance, real radians, real damage, @real vertAccel, real height@) -> bash {
            bash this = allocate();
         
            s       = bashingUnit;
            b       = whichUnit;
            dist    = distance;
            mxdist  = SquareRoot(BashPushDistance(lvl));
            dx      = Cos(radians);
            dy      = Sin(radians);
            vec     = pVector(GetUnitX(b), GetUnitY(b), I2R(lvl));
            p       = castplayer;
            dmg     = damage;

         @  ADDED  @
            zprev = GetUnitFlyHeight(b);
            z = zprev;
            az = vertAccel; //added 2 arguments to this method, see above; will have to change arguments to all .create() calls
            vz = 2*az*height; //knematics bro

            UnitAddAbility(b, 'Amrf');
            UnitRemoveAbility(b, 'Amrf');
         @  END  @
         
            DDSet(b, UNIT_BASH_KEY, 1);
            SetUnitTimeScale(b, UNIT_ANIM_SPEED*.01);
            if (!IsUnitType(b, UNIT_TYPE_DEAD)) {
                SetUnitAnimation(b, UNIT_ANIM_NAME);
                QueueUnitAnimation(b, "stand");
            }
         
            return this;
        }
     
        // ***
        method destroy() {
            DDSet(b, UNIT_BASH_KEY, 0);
            SetUnitTimeScale(b, 1.);
         @  SetUnitFlyHeight(b, zprev, 0.00);  @
            vec.destroy();
            s = null;
            b = null;
            deallocate();
        }

        method Launch() {
            DDStartTim(DD_INTERVAL, true, this, static method() {
                bash       this      = bash( DDTimData() );
                integer    tick        = DDTimTick();
                real      speed       = DD_INTERVAL * (PUSH_SPEED_END + ( (PUSH_SPEED_START-PUSH_SPEED_END)/mxdist )*SquareRoot(dist));
                // basic formula for speed: y = a*sqrt(x) + b
              
                // ----------------------------------
                // *** Position calcs
                dist    -= speed;
                vec[0]  += speed * dx;
                vec[1]  += speed * dy;
             @  vz = vz-az;  @
             @  z = z+vz;  @
              
                // ----------------------------------
                // *** Motion
                SetUnitX(b, vec[0]);
                SetUnitY(b, vec[1]);
             @  SetUnitFlyHeight(b, z, 0.00);  @
              
                // ----------------------------------
                // *** Push Effects
                if (ModuloReal(tick*DD_INTERVAL, PUSH_EFFECT_INTERVAL) < DD_INTERVAL)
                    static if (USE_WATER_FILE)
                        if (IsTerrainPathable(vec[0], vec[1], PATHING_TYPE_FLOATABILITY))
                            DestroyEffect(AddSpecialEffect(PUSH_MODEL_FILE, vec[0], vec[1]));
                        else
                            DestroyEffect(AddSpecialEffect(PUSH_MODEL_WATER_FILE, vec[0], vec[1]));
                    else
                        DestroyEffect(AddSpecialEffect(PUSH_MODEL_FILE, vec[0], vec[1]));
              
                // ----------------------------------------
                // *** Check if trees are in the way
                static if (DESTROY_TREES)
                    if (ModuloReal(tick*DD_INTERVAL, CLEAR_TREES_INTERVAL) < DD_INTERVAL) {
                      
                        DDEnumDestsInRange(vec, CLEAR_TREES_RADIUS, null, function() {
                            if (DDIsDestructableTree(GetEnumDestructable()))
                                KillDestructable(GetEnumDestructable());
                        });
                    }
              
                // ---------------------------------------------------------
                // *** Check for bounce/collision with unpathable points
                if (ModuloReal(tick*DD_INTERVAL, CLEAR_TREES_INTERVAL) < DD_INTERVAL) {
                    if (IsTerrainPathable(vec[0]+BOUNCE_DETECT_RANGE*dx, vec[1], PATHING_TYPE_WALKABILITY))
                        dx = -dx;
                    else if (IsTerrainPathable(vec[0], vec[1]+BOUNCE_DETECT_RANGE*dy, PATHING_TYPE_WALKABILITY))
                        dy = -dy;
                }
              
                // ----------------------------------------
                // *** Check if there are any units to be splash bashed
                static if (ENABLE_SPLASH_BASH)
                    if (speed > SPLASH_BASH_NEED_SPEED*DD_INTERVAL && ModuloReal(tick*DD_INTERVAL, SPLASH_BASH_INTERVAL) < DD_INTERVAL)
                        TryDoSplashBash();
                  
                // ----------------------------------
                // *** Check to quit push
             @  if ((dist <= 0.) and (z <= zprev)) {  @ //Now we check to make sure the vertical displacement is done too.
                    PauseUnit(b, false);
                    destroy();
                    DDQuitTim();
                }
            });
        }

I probably made a small syntax error somewhere but that's the gist of what you need to do.
 
Level 8
Joined
Jun 13, 2008
Messages
346
thanks for your help guys but I think am just gonna pass this type of spell...decided to use an active type one which does everything I need better actually.

Have an another question though;

I added an extra special effect on the target units' position which works...but the problem is I don't know how to destroy it when the spell ends.

JASS:
 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)
            /*call AddSpecialEffectLoc(VOID_SFX, GetUnitLoc(u))*/
            set u = null
           
            return true
        endif
       
        set u = null
        return false
       
    endfunction

the comment outed code is the one that I added....there's a struct called "fall" that has a destructor which runs when units hit the ground...in othersaying when the spell ends.


JASS:
 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 DestroyEffect((VOID_SFX)) /*this didn't work...*/
           
            call TerrainDeformCrater(GetUnitX(.target),GetUnitY(.target),CRATER_RADIUS,CRATER_DEPTH,R2I(CRATER_DUR * 1000),false)
            call GroupRemoveUnit(SAFE_GROUP,.target)
           
        endmethod

what should I do to destroy the effect I added at the end of the spell?
 
Level 39
Joined
Feb 27, 2007
Messages
5,027
Add an effect variable to the struct and remove it during the onDestroy()
JASS:
private struct Fall
    //...
    effect SFX
    //In LiftOffAll
    set .SFX = AddSpecialEffect(VOID_SFX, GetUnitX(u), GetUnitY(u)) //Note doesn't use locations, usually better to use X/Y coordinates if you can
    //in onDestroy
    call DestroyEffect(.SFX)
endstruct
 
Level 23
Joined
Oct 18, 2008
Messages
938
to be more specific; basic attacks have a chance(20%/30%/40%) to burst the target to air while dealing extra damage to them(apparently splash attacks will still proc the spell and there's no solution to this because of DDS limitations).
not sure if I understood right but just saving the last attacked unit on the attacking one can be easily used to rule out the others from being bashed.
 
Level 8
Joined
Jun 13, 2008
Messages
346
ok I think I gotta pass the reference of the effect variable to the destructor of the struct to be destroyed there...don't know if something like this is possible in vjass though.
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,027
Post all the code for the spell and its much easier to help you. I thought LiftOffAll was a method, but it isn't.

The only struct instantiated in that function is local Bubble this = TEMP_STRUCY but it isn't of the type you posted above (Bubble instead of Fall). Unless Bubble extends Fall this won't work but change it to set this.SFX = AddSpecialEffect(...).
 
Level 8
Joined
Jun 13, 2008
Messages
346
screw it...I tried that and hadn't worked either. I just found the perfect GUI version of the spell anyway which I made it work with my changes in like 30 seconds...fuck vjass. Thanks for your help though, gave u rep before.
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,510
Lol, what a roller-coaster ride.

It's funny, I only just discovered this 'recently'... You mentioned "Impale", and that was actually the key to it for me. See, with several bouts of 'test & check', I managed to end up with an ability that only works at melee range on a single target (pretty sure), which pretty much does exactly as you describe (damage, 'knock-back-up', stun). Big secret, though, hush-hush.
 
Level 8
Joined
Jun 13, 2008
Messages
346
the amount of modeling knowledge required to make those changes to effect is equal to amount of jass knowledge required to make the changes I needed on this spell imo.
Besides, its just a graphical difference, real height can't be configured since its hardcoded...or something like that..don't know the technical details.
Apart from that I needed some extra special effects which can't be added through object editor because I want those to get attached to units' locations and not to them...you forgot to mention attack type btw which can't be configured either but "at least for me" is important.

in visual style yes you're absolutely right it would be very similar to what I wanted but I just care about the details which is annoying I agree.
 

Kyrbi0

Arena Moderator
Level 45
Joined
Jul 29, 2008
Messages
9,510
the amount of modeling knowledge required to make those changes to effect is equal to amount of jass knowledge required to make the changes I needed on this spell imo.
It's hard to compare, but I'm pretty sure it's not that difficult. It's quite easy, even just in Magos, to move the model 'up' or 'down'.

However,
hemmedo said:
Besides, its just a graphical difference, real height can't be configured since its hardcoded...or something like that..don't know the technical details.
Yeah, this is it, basically. You can't change the fly-height via coding or anything dynamic like that; if you wanted a variety of heights you'd have to modify & import a different model for each height you wanted (which, given that the model is like a handful of KBs, wouldn't take up space so much as just be a big hassle).

hemmedo said:
Apart from that I needed some extra special effects which can't be added through object editor because I want those to get attached to units' locations and not to them...
Also (relatively easily) doable via model editor.

hemmedo said:
you forgot to mention attack type btw which can't be configured either but "at least for me" is important.
I did not:
Kyrbi0 said:
- the damage (type)... pfah, who changes that? (no way to change it)

hemmedo said:
in visual style yes you're absolutely right it would be very similar to what I wanted but I just care about the details which is annoying I agree.
No, that's fine; that's your prerogative to make whatever kinda mod you want. Just offering suggestions. : )
 
Status
Not open for further replies.
Top