Spell Mojo Magic

Nexor

...
Reaction score
74
Mojo Magic v1.31 - reworked


Import Difficulty: Easy

Requirements: JASS NewGen, T32 (map has it)

Allowed Targets: Enemies/Allies/Not Self/Organic

Leakless?: Check yourself

GUI/JASS?: vJASS

Lagless?: Yes

MUI?: Of course :)

Spell Description: Binds the target to the Witch Doctor using dark magic. If the linked units' distance is more than 600 range or the duration ends, the link will break and damage or heal the linked units.
The Witch Doctor recieves only the half of the damage if casted on enemy unit.
Level 1 - 60 damage/heal
Level 2 - 120 damage/heal
Level 3 - 180 damage/heal

Screenshots:

At cast:

Link breaks:


Triggers:
JASS:
scope MojoMagic

globals
  constant integer SPELL_ID  = 'A000'   //Spell ID (Ctrl+D at Object Editor)
  constant real DAMAGE_MULTI = 60.      //Damage multiplier
  constant real CASTER_MULTI = 0.5      //Multiplier of damage on caster
  constant integer DURATION  = 5       //Multiplier of duration
  constant string FX_STRING  = "Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl" //Spell SFX
  constant real RED          = 0.75  //*******************************
  constant real GREEN        = 0.2   //
  constant real BLUE         = 0.8   //These are the colors and the alpha value of the lightning
  constant real ALPHA        = 0.8   //*******************************
  constant real DISTANCE     = 600.0 //The maximal range of the link
  constant real HEIGHT       = 50.    // Height of lightning effect
  constant string LIGHT_TYPE = "SPLK" // Type of lightning (STLK is Spirit Link)
  constant boolean DMG_ON_END= true   //This will set whether the damage part shall run when the chain is broken
  private location MoveLoc   = Location (0, 0)
endglobals

function GetCoordZ takes real x, real y returns real
  call MoveLocation (MoveLoc, x, y)
  return GetLocationZ (MoveLoc)
endfunction
    
    
private function Damage takes integer level returns real
    return DAMAGE_MULTI * level
endfunction

private function Duration takes integer level returns integer
    return DURATION * level
endfunction    

//! textmacro DAMAGE_PART
    if IsUnitEnemy(.target, GetOwningPlayer(.caster)) == true then
        call UnitDamageTarget( .caster, .target, DAMAGE_MULTI, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS ) //Damage Target
        call UnitDamageTarget( .caster, .caster, DAMAGE_MULTI*CASTER_MULTI, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS ) //Damage Caster
    else
        call SetUnitState( .target, UNIT_STATE_LIFE, ( GetWidgetLife( .target) + DAMAGE_MULTI ) ) //Heal Target
        call SetUnitState( .caster, UNIT_STATE_LIFE, ( GetWidgetLife( .caster) + DAMAGE_MULTI ) ) //Heal Caster
    endif
//! endtextmacro


private struct mojo
    unit caster
    unit target
    lightning light
    real damage
    integer ticks
    private method periodic takes nothing returns boolean
            local real loc1x = GetUnitX(.caster)
            local real loc1y = GetUnitY(.caster)
            local real loc1z = GetCoordZ(loc1x,loc1y) + GetUnitFlyHeight(.caster) + HEIGHT
            local real loc2x = GetUnitX(.target)
            local real loc2y = GetUnitY(.target)
            local real loc2z = GetCoordZ(loc2x,loc2y) + GetUnitFlyHeight(.target) + HEIGHT
            local real disx = loc2x - loc1x
            local real disy = loc2y - loc1y
            
            local real distance = disx * disx + disy * disy
            
            call MoveLightningEx( .light, true, loc1x, loc1y, loc1z, loc2x, loc2y, loc2z)
            
            set .ticks = .ticks - 1
            
            if .ticks == 0 and DMG_ON_END then
                //! runtextmacro DAMAGE_PART()
                    
                call DestroyEffect( AddSpecialEffect( FX_STRING, loc1x, loc1y))
                call DestroyEffect( AddSpecialEffect( FX_STRING, loc2x, loc2y))
                call DestroyLightning(.light)
                
                return true
            endif
            
            if distance >= DISTANCE*DISTANCE or GetWidgetLife(.target) <.405 or GetWidgetLife(.caster) <.405 then
                
                //! runtextmacro DAMAGE_PART()
                call DestroyEffect( AddSpecialEffect( FX_STRING, loc1x, loc1y))
                call DestroyEffect( AddSpecialEffect( FX_STRING, loc2x, loc2y))
                call DestroyLightning(.light)
                
                return true
            endif
            
            return false
    endmethod
    implement T32
endstruct

private function Trig_Mojo_Magic_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

function Trig_Mojo_Magic_Actions takes nothing returns nothing
    local mojo d = mojo.create()
    local unit caster = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local real loc1x = GetUnitX(caster)
    local real loc1y = GetUnitY(caster)
    local real loc1z = GetCoordZ(loc1x,loc1y) + GetUnitFlyHeight(d.caster) + HEIGHT
    local real loc2x = GetUnitX(target)
    local real loc2y = GetUnitY(target)
    local real loc2z = GetCoordZ(loc2x,loc2y) + GetUnitFlyHeight(d.target) + HEIGHT
    

    set d.light =  AddLightningEx( LIGHT_TYPE, true, loc1x, loc1y, loc1z, loc2x, loc2y, loc2z ) //Set the type of the lightning (in this case, it's Spirit Link)
    call SetLightningColor( d.light, RED, GREEN, BLUE, ALPHA )                                  //Set the color of the lightning
    set d.caster = caster
    set d.target = target
    set d.damage = Damage( GetUnitAbilityLevel(d.caster, SPELL_ID) )
    set d.ticks  = R2I(Duration( GetUnitAbilityLevel(d.caster, SPELL_ID) ) / T32_PERIOD)

    call d.startPeriodic()
    set caster = null
    set target = null
endfunction

//===========================================================================
function InitTrig_Mojo_Magic takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Trig_Mojo_Magic_Conditions ) )
    call TriggerAddAction( t, function Trig_Mojo_Magic_Actions )
    set t = null
endfunction

endscope


I made this spell for fun :)
It can be used to heal and damage either, but it will take effect on the caster too.
Enjoy!
 

Attachments

  • Mojo Magic v1.31.w3x
    51 KB · Views: 261

Vestras

Retired
Reaction score
249
The screenies are so small :(

1)
JASS:
    call SetHandleHandle(tim, "Unit1", caster)
    call SetHandleHandle(tim, "Unit2", target) 
    call SetHandleHandle(tim, "Light", light)


Really slow, use some struct attachment system instead. (vJASS)

2) Use coordinates instead of locations.

3)
JASS:
    call AddLightningLoc( "SPLK", loc1, loc2 ) //Set the type of the lightning (in this case, it's Spirit Link)
    set light =  bj_lastCreatedLightning


Just do
JASS:
set light = AddLightningLoc( "SPLK", loc1, loc2 ) //Set the type of the lightning (in this case, it's Spirit Link)


4)
JASS:
or IsUnitAliveBJ(target) == false or IsUnitAliveBJ(caster) == false then


Ufh... BJs... Use
JASS:
GetWidgetLife(caster) <.405

instead.

5)
JASS:
call SetLightningColorBJ( light, 0.75, 0.20, 0.75, 0.80 ) //Set the color of the lightning


BJ... eew, replace with native plox.

That's all, I think...
 

Flare

Stops copies me!
Reaction score
662
Really slow, use some struct attachment system instead. (vJASS)
And are you ever going to see the difference in speed? Maybe a TIIIIIINY fraction of a second of a difference, but who the f*ck is going to notice that?

And a configuration header would be nice - it may be a fairly short spell code-wise, but it'll make the spell much more usable by others (since they don't have to search through the code to find what to change) - if you're using vJASS
JASS:
//Don't forget to add the other stuff as well, like the lightning colours
globals
  constant integer SPELL_ID = 'a000'
  constant integer DAMAGE_MULTI = 60 //This * Abil Level = Damage dealt
  constant string FX_STRING = "insert\\fx\\string\\here"
  constant real TIMER_INT = 0.03 //0.01 is asking for lag, specially on slower computers
endglobals

otherwise
JASS:
constant function SpellId takes nothing returns integer
  return 'A000'
endfunction

constant function GetDamage takes integer level returns real
   return level*60.
endfunction

constant function FxString takes nothing returns string
  return "someParticularFxString"
endfunction

constant function TimerInt takes nothing returns real
  return 0.03
endfunction
 

Nexor

...
Reaction score
74
Thanks for replies, I will change what I can

The periodic trigger is 0.01 because at 0.03 the lightning moved too slow
and it sets only a real and 2 locations every 0.01 seconds.

I will make the locations to reals, and for the globals thing, do I have to insert it to the top of the trigger? and use their names, like SPELL_ID ?
 

Flare

Stops copies me!
Reaction score
662
The periodic trigger is 0.01 because at 0.03 the lightning moved too slow
0.03 is fine for moving lightning effects (my TimedLightning system runs on a 0.03125s timer and it's just fine)

and for the globals thing, do I have to insert it to the top of the trigger?
They should be above the rest of the code

and use their names, like SPELL_ID ?
Doesn't have to be SPELL_ID, you could name it anything you like as long as it's understandable

Just replace all instances of 'A000' with INSERT_VARIABLE_HERE e.g.
JASS:
globals
  constant integer SID = 'A000'
endglobals

function CondFunc takes notthing returns boolean
  return GetSpellAbilityId () == SID
endfunction


And your lightning ID also needs to be configurable (not everyone wants Spirit Link :p)
 

Nexor

...
Reaction score
74
I made some changes, and for the attachment system, I don't know the other systems, I'm just learning JASS.

Other: I made the changes but my Wc3 crashes on opening, what can it be?
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
You are not nulling your handles at the end of your functions (units, timer, and lightning).

In order for it to be leakless, you would need those to be nulled. You also need to FlushHandleLocals from the timer.

You may want to put vJASS instead of JASS, since you are using a global block, which is only available to those who have Newgen.

One last minor thing, the formatting for your if-thens looks bad when you don't have it indented, it makes it a lot harder to read.
 

Nexor

...
Reaction score
74
Yes I'm using NewGen and I made the changes (grimorie off) but can't test my own map :S

Please write the triggers of the flush thing and the others (I'm new to thehelper and new to JASS, this is my first finished spell using handles)
 

quraji

zap
Reaction score
144
Really slow, use some struct attachment system instead.*

2) Use coordinates instead of locations.**

BJ... eew, replace with native plox.***

*quraji facepalms Vestras. I really want to start a mailing list of anyone who says this, and mail them anthrax :p Please, read:
Non-Gamecache attachment offers a *slight* speed increase. Conversely, Gamecache is *slightly* slower.
"Really slow" applies to neither of these.

**quraji slaps Vestras. As long as you don't misuse locations (read: cause leaks), or constantly convert back and forth between locs and coords, they're fine. Besides...does this code even use locs?

***quraji backhands Vestras. Yes BJs are often wasteful functions. But, they often provide the benefit of readability. One extra function call isn't going to break a code. If it makes a code unreadable to inline a BJ, then I'd rather use the BJ. That said, there are some very stupid BJs people should take an extra second to inline. I'm tired of seeing "Ew BJ gross", "omg a BJ you nub", "your code sucks you have a BJ", etc.


*deep breath* Okay, I'm good now :D

Now, to force this post back on topic. Sounds like a neat spell, but you have to break the line to get the effect? I'll try it and tell you what I think :thup:
 

Romek

Super Moderator
Reaction score
964
quraji:
But a lot of the BJ's he does use are the shitty ones. Which is just an extra function call.

JASS:
  constant integer DAMAGE_MULTI = 60 //This * Abil Level = Damage dealt


I disagree with that (and Flare).
That should be a function.
So you can do a full formula such as "level*10+700" or anything else really.
 

Flare

Stops copies me!
Reaction score
662
That should be a function.
So you can do a full formula such as "level*10+700" or anything else really.

You don't need a function for a formula >_<

JASS:
globals
constant real BASE = 100
constant real MULTI = 60
endglobals

function bla takes nothing returns nothing
  local real dmg = BASE + GetUnitAbilityLevel (whichUnit, SID) * MULTI
...
endfunction


While a function would allow alot more flexibility, it isn't an absolute essential and if someone needs that flexibility, they can modify it themselves or ask Nexor to do it if they don't know how - for the most part, ability stats are associated with the ability's level so it's fine the way it is
 

Romek

Super Moderator
Reaction score
964
You don't need a function for a formula >_<

JASS:
constant real BASE = 100
constant real MULTI = 60

function bla takes nothing returns nothing
  local real dmg = BASE + GetUnitAbilityLevel (whichUnit, SID) * MULTI
...
endfunction

What if I want (level*100) - (Pow(level, 3) + (level * 50) :p (Ignore the fact that this equation sucks)

It's easier to use a function than loads of globals anyway.
 

Nexor

...
Reaction score
74
and without the globals I can open my map... :S

It's more work with the globals to write but the users don't have to know JASS well to change the numbers in the triggers.
 

Flare

Stops copies me!
Reaction score
662
What if I want (level*100) - (Pow(level, 2)
Pow is lame, X * X instead ^_^

It's easier to use a function than loads of globals anyway.
That's opinion - I personally find functions easier to deal with (since I like the flexibility) but others don't, or they may just prefer globals (I believe Tinki3 uses/used BASE + AbilLevel * MULTIPLIER for most of his spells)

Anyway, if they don't like how the author does things, they can deal with it, or just ask nicely for the author to modify it (or do it themselves if they know how) - there's no law saying that anyone must use a function (or globals, for that matter) for calculating a spell's attributes and ,as such, they aren't obliged to, unless they don't mind and/or want to do it anyway

Anyway, enough arguing about the merits of functions and globals for formulas - it's Nexor's spell, and he is the one who is supposed to be making that decision

and without the globals I can open my map... :S
Well, you've got bigger problems there - you said you were using NewGen right? If so, global declarations shouldn't be causing you any problems
 

Romek

Super Moderator
Reaction score
964
and without the globals I can open my map... :S

It's more work with the globals to write but the users don't have to know JASS well to change the numbers in the triggers.

They won't need JASS knowledge for a basic equation they would have to do with globals. Something like level*10.

But if they know how to do basic maths (Or use math functions), then they would be able to.
 

Nexor

...
Reaction score
74
the 90% of the people don't like/know or don't like --> don't know maths really good, this global block is for them :p

I don't know why my map won't open correctly, the syntax check didn't say any syntax errors, but it says the handle things are undeclared functions :S
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top