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

[JASS] Spell help

Status
Not open for further replies.
Level 8
Joined
Jul 28, 2008
Messages
211
I'm making a stackable spell and I need a way to change the time remaining for a wait or a timer.

Here's my code so far:
JASS:
scope Endless initializer Init

globals
    private constant integer SPELL_ID = 'A001'
    private constant integer DAMAGE_ID = 'A002'
    private constant integer SPEED_ID = 'A003'
    private group g = CreateGroup()
endglobals

private function Conditions takes nothing returns boolean
    return (GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) > 0) and (GetRandomInt(0, 100) < (GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) * 10 + 5))
endfunction

private function Actions takes nothing returns nothing
    local unit attacker = GetTriggerUnit()
    if IsUnitInGroup(attacker, g) then
        call SetUnitAbilityLevel(attacker, DAMAGE_ID, GetUnitAbilityLevel(attacker, DAMAGE_ID) + 1)
        call SetUnitAbilityLevel(attacker, SPEED_ID, GetUnitAbilityLevel(attacker, SPEED_ID) + 1)
    else
        call UnitAddAbility(attacker, DAMAGE_ID)
        call UnitAddAbility(attacker, SPEED_ID)
        call SetUnitAbilityLevel(attacker, DAMAGE_ID, 1)
        call SetUnitAbilityLevel(attacker, SPEED_ID, 1)
    endif
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction

endscope

Gives the Berseker 25% to get bonus damage and attack speed for a short period of time. Stacks 5 times.


I need a way to restart the timer when it triggers twice for the same unit? Any suggestions?
 
Level 8
Joined
Jul 28, 2008
Messages
211
Here's my code for now:

JASS:
scope Endless initializer Init_Rage

globals
    private constant integer SPELL_ID = 'A001'
    private constant integer DAMAGE_ID = 'A002'
    private constant integer SPEED_ID = 'A003'
    private group g = CreateGroup()
endglobals

private struct Rage
    unit ber
    timer Timer
    integer lvl
    triggeraction a
    triggercondition c
    event e
    trigger t
    static integer Total
    static Rage Index

    static method Cond takes nothing returns boolean
        return GetTriggerUnit() == .ber and (GetRandomInt(0, 100) < .lvl * 10 + 5)
    endmethod
    
    static method Action takes nothing returns nothing
        call PauseTimer(.Timer)
        call SetUnitAbilityLevel(.ber, DAMAGE_ID, GetUnitAbilityLevel(.ber, DAMAGE_ID) + 1)
        call SetUnitAbilityLevel(.ber, SPEED_ID, GetUnitAbilityLevel(.ber, SPEED_ID) + 1)
        call TimerStart(.Timer, 10.00, false, function Rage.Destroy)
    endmethod
    
    static method Destroy takes nothing returns nothing
        set .ber = null
        call TriggerRemoveAction(.t, .a)
        call TriggerRemoveCondition(.t, .c)
        call DestroyTrigger(.t)
        set .t = null
        set .c = null
        set .a = null
        call DestroyTimer(.Timer)
        set .Timer = null
        call .destroy()
    endmethod
    
    static method start takes unit caster returns nothing
        local Rage r = Rage.allocate()
        set r.ber = caster
        set r.lvl = GetUnitAbilityLevel(r.ber, SPELL_ID)
        set r.t = CreateTrigger()
        set r.c = TriggerAddCondition(r.t, Condition(function Rage.Cond))
        set r.a = TriggerAddAction(r.t, function Rage.Action)
        call TriggerRegisterAnyUnitEventBJ(r.t, EVENT_PLAYER_UNIT_ATTACKED)
        set r.Timer = CreateTimer()
        call TimerStart(r.Timer, 10.00, false, function Rage.Destroy)
    endmethod
    
endstruct

private function Conditions takes nothing returns boolean
    return (GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) > 0) and (GetRandomInt(0, 100) < (GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) * 10 + 5))
endfunction

private function Actions takes nothing returns nothing
    call Rage.start(GetAttacker())
endfunction

private function Init_Rage takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction

endscope

Yes, there are some unneeded things (like static integer Total and stuff).
The only problem is that it reports this as an undeclared variable in static method Cond, Action and Destroy. Any way to fix that?
 
Hashtables are easy:
JASS:
globals
    //Declare and create your hashtable
    hashtable MyHashtable = InitHashtable()
endglobals

function AttachData takes handle h, integer dat returns nothing
    //Save the data into the hashtable using an index of [0][<the handle's id>] (hashtables are two-dimensional, and any index will work.
    call SaveInteger(MyHashtable, 0, GetHandleId(h), dat)
endfunction

function LoadData takes handle h returns integer
    //load the data from the hashtable
    return LoadInteger(MyHashtable, 0, GetHandleId(h))
endfunction
They're just like arrays, but better. They are, however, slightly slower and more complicated to use. You can store literally anything in a hashtable.
 
Level 8
Joined
Jul 28, 2008
Messages
211
Hmm...maybe I haven't updated my editor version...

EDIT: How can I check my editor's version? Cuz I have 2 Warcrafts on my pc (ver 1.24 and 1.22) and I need to know which editor does JNPG use.

EDIT 2: It's using the old version for some reason. I started the normal editor and I could use hashtables. Can I change that? Or do I have to reinstall JNPG?

EDIT 3: I deleted the old editor and it's working. But why doesn't it highlight hashtable like it does integer and other variables?

EDIT 4: And I can't find hashtable functions in the Function List. They aren't highlighted either.
 
Last edited:
Level 8
Joined
Jul 28, 2008
Messages
211
Don't mind what you're saying, just help me when I need help xD

Too much rep in last 24 hours... I just go spreading so I can give you rep again and I overdo it >.>

EDIT: Can you show me how to do it with hashtables in this trigger? I know how to use them, but I'm just now sure.
 
Last edited:
Level 10
Joined
Jun 1, 2008
Messages
485
uh, just a suggestion, but it can be done in another way.
first, create struct with your stuff in it. add a real member called TimeLeft or something like that. When the spell start, you check if the spell have stacked or not. if it haven't stacked yet, you run periodic timer with 0.01 second timeout. Add function to that timer that reducing the TimeLeft by 0.01 and check if the TimeLeft is <= 0.0, if yes, end timer. If the spell is about to stacked, just change the TimeLeft amount.

it looks like this
JASS:
scope Endless initializer Init_Rage

globals
    private constant integer SPELL_ID = 'A001'
    private constant integer DAMAGE_ID = 'A002'
    private constant integer SPEED_ID = 'A003'
endglobals

private struct Rage
    unit Caster
    integer level
    real TimeLeft
    integer Stacked
    static timer Timer = CreateTimer()
    static integer Total = 0
    static Rage array Index

    static method Loop takes nothing returns nothing
        local Rage r
        local integer i = 0
        loop
            exitwhen i >= Rarge.Total
            set r = Rage.Index[i]
            set r.TimeLeft = r.TimeLeft - 0.01
            if r.TimeLeft <= 0.00 then              
                call UnitRemoveAbility(r.Caster,DAMAGE_ID)              
                call UnitRemoveAbility(r.Caster,SPEED_ID)
                set r.Caster = null
                call r.Destroy()
                set Rage.Total = Rage.Total - 1
                set Rage.Index[i] = Rage.Index[i]
                set i = i - 1
            endif
            set i = i + 1
        endloop
        if Rage.Total == 0 then
            call PauseTimer(Rage.Timer)
        endif
    endmethod

    static method start takes unit caster returns nothing
        local Rage r
        local integer i
        loop
            exitwhen i >= Rage.Total
            if r.Caster = GetAttacker() then
                set i = Rage.Total
            endif
            set i = i + 1
        endloop
        if r.Caster != null then
            set r.Stacked = r.Stacked + 1
            set r.TimeLeft = 10.00
            call SetUnitAbilityLevel(r.Caster, DAMAGE_ID, r.Stacked)
            call SetUnitAbilityLevel(r.Caster, SPEED_ID, r.Stacked)        
        else
            set r = Rage.Allocate()
            set r.Caster = caster
            set r.level = GetUnitAbilityLevel(r.Caster, SPELL_ID)
            set r.TimeLeft = 10.00
            set r.Stacked = 1
            if Rage.Total == 0 then
                call TimerStart(Rage.Timer, 0.01, true, function Rage.Loop)
            endif
            set Rage.Index[Rage.Total] = r
            set Rage.Total = Rage.Total + 1
        endif
    endmethod

endstruct

private function Conditions takes nothing returns boolean
    return (GetUnitAbilityLevel(GetAttacker(), SPELL_ID) > 0) and (GetRandomInt(0, 100) < (GetUnitAbilityLevel(GetTriggerUnit(), SPELL_ID) * 10 + 5))
endfunction

private function Actions takes nothing returns nothing
    call Rage.start(GetAttacker())
endfunction

private function Init_Rage takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer index
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction

endscope
 
Level 8
Joined
Jul 28, 2008
Messages
211
Sounds good. I hope it works... I'll try it later. Thanks

EDIT: Too much rep in last 24 hours... just gonna have to wait >.>

EDIT 2: Syntax error at line
JASS:
if r.Caster = GetAttacker() then
How can I fix this?

EDIT 3: Tried changing GetAttacker to caster and still doesn't work.
 
Last edited:
Level 8
Joined
Jul 28, 2008
Messages
211
Nah, it doesn't.

JASS:
static method start takes unit caster returns nothing
        local Rage r    
        local integer i   
        loop           
            exitwhen i >= Rage.Total  
            if r.Caster == caster then    
                set i = Rage.Total        
            endif     
            set i = i + 1 
        endloop

I think that this isn't needed in the start method.
 
Level 10
Joined
Jun 1, 2008
Messages
485
Nah, it doesn't.

JASS:
static method start takes unit caster returns nothing
        local Rage r    
        local integer i   
        loop           
            exitwhen i >= Rage.Total
            if r.Caster == caster then    
                set i = Rage.Total        
            endif     
            set i = i + 1 
        endloop

I think that this isn't needed in the start method.
Oops! another wrong part.
it should have like this
JASS:
static method start takes unit caster returns nothing
        local Rage r    
        local integer i   
        loop
            set r = Rage.Index[i]  
            exitwhen i >= Rage.Total  
            if r.Caster == caster then    
                set i = Rage.Total        
            endif     
            set i = i + 1 
        endloop
add this line:
JASS:
set r = Rage.Index[i]
i forgot to add it. sorry, still new to JASS.

btw, this part is to 'search' for the caster's struct in 'Index'. If found, it will end the loop cause the struct is already set to right struct.
 
Status
Not open for further replies.
Top