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

vjass bootstrap templates

Status
Not open for further replies.

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
I was toying with the idea of having a module with onCast and onLoop functions in order to bootstrap a spell as quickly as possible without the standard repetitive boring steps.

My result had some undesirable lines of code which sadly are required, but overall I am pretty pleased with the result.

My question is if there is something similar already created? I checked the spell section quickly and did not find anything other than one of GUI. Does not have to be in wurst, I would be keenly interested in seeing how others have done it in vjass.

Wurst:
package Hello

import SpellTemplate

class myCoolSpell extends Spell
    real counter = 0
    real interval = 1
    real intervalCounter = 1
    real totalTicks = 3
    real dmg = 10

    unit u

    static integer id = 'AHfs'

    construct(unit magician)
        print(caster.getName() + " casting " + GetAbilityName(id))
        u = magician

    override function onLoop()
        counter += 0.03
        print(counter.toString())
        if(counter >= interval * intervalCounter)
            u.damageTarget(u, dmg)
            if(intervalCounter == totalTicks)
                destroy this
            else
                intervalCounter++

function onCast()
    new myCoolSpell(myCoolSpell.caster)

init
    setupSpell(myCoolSpell.id, Condition(function onCast))

    // Testing MUI
    for u in GetUnitsInRectAll(GetPlayableMapRect())
        u.issuePointOrder("flamestrike", vec2(0, 0))


Wurst:
package Hello

import SpellTemplate

/*
    Template spell, deals 10 damage every 1 second for 3 seconds.

    Instructions:
    1. import SpellTemplate
    2. Make class which extends Spell
    3. onCast(), onLoop() and getAbilityId() returns integer with the keyword override are required
    4. the onCast function needs to create a new instance of your class. Make sure to use newInstance(yourInstance) afterwards
        Otherwise your new instance wont have onLoop called.
    5. on init make an instance of your class.
        The first instance will merely make a trigger which executes when your specified spell is cast.

    The following variables can be used in the onCast function
        unit caster
        vec2 targetPos
        unit targetUnit
        item targetItem
        destructable targetDestructable
*/

class myCoolSpell extends Spell
    real counter = 0
    real interval = 1
    real intervalCounter = 1
    real totalTicks = 3
    real dmg = 10

    unit u

    static integer id = 'AHfs'

    override function getAbilityId() returns integer
        return id

    override function onCast()
        thistype instance = newInstance(new myCoolSpell()) castTo thistype

        print(GetUnitName(caster) + " casting " + GetAbilityName(id))
     
        instance.u = caster

    override function onLoop()
        counter += 0.03
        print(counter.toString())
        if(counter >= interval * intervalCounter)
            u.damageTarget(u, dmg)
            if(intervalCounter == totalTicks)
                destroy this
            else
                intervalCounter++

init
    new myCoolSpell()

    // Testing MUI
    for u in GetUnitsInRectAll(GetPlayableMapRect())
        u.issuePointOrder("flamestrike", vec2(0, 0))
 
Last edited:
Some people used this template:
vJASS Spell Templates

But that one has all the unnecessary custom-allocation-boiler-plate that kinda gets in the way of things. T32 is another one that is "kinda" like a template, since it gets implemented as a module:
System - Timer32

It was super popular a while back. You would just implement T32 and write a method "periodic". In your onCast function, though, you'd have to specifically call startPeriodic() if you want to register an instance for the timer. Both were pretty good, but there was still a bit of manual work in there.

IMO, it is important to think about all the typical kinds of spells people want to implement:
(1) Some are instant
(2) Some are periodic (e.g. DoTs)
(3) Some are one-shot timers (e.g. buffs)

A lot of spells can get more complicated than that, but you can do a ton with just those 3 rules. I like your template so far, and it seems like you have the two main cases down (instant and periodic). I think you should try to think of a way to incorporate #3, if possible. If it starts to get too bloated, I would separate them into three separate modules/classes.
 
From what I can tell from Timer32 it does not have automatic event creation + filter for the spell?
Seems like the create() function is the onCast which you have to trigger manually.
It seems reasonable otherwise.

I'll consider the third one at some point :3

Yep, T32 doesn't do automatic event creation. It was just a timer + attachment system. But I linked it since it is a nice example of a template that was widely used.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
I kind of created my own a while back here, in vjass. Since extending structs in vjass is not very well implemented, I used modules instead. Basically, it simplifies your work to this format:

JASS:
struct SpellUsingSpellEvent extends array

    private static method spellId takes nothing returns integer
        return 'XXXX'
    endmethod

    private static method spellPeriod takes nothing returns real
        return 0.03125
    endmethod

    private static method spellDuration takes nothing returns real
        return 10.00
    endmethod

    private method onSpellStart takes nothing returns nothing
        /*
        *   -> Activates after the spell is cast <-
        */
    endmethod

    private method onSpellPeriodic takes nothing returns nothing
        /*
        *   -> Periodic actions <-
        */
    endmethod

    private method onSpellEnd takes nothing returns nothing
        /*
        *   -> Cleanup <-
        */
    endmethod

    implement SpellEffectEvent

endstruct

Spell instances creation/destruction (i.e. allocation/deallocation) is already taken cared of by the system internally. Currently, it is specifically designed for spells with periodic callbacks and also, you are required to specify a duration (which is quite limiting), but I plan on changing this and have the user return a boolean value under the periodic method instead which allows them to decide to end the spell based on other factors aside from depending solely on a time limit.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
So some updates here..

I got rid of the clutter in the onCast function, but the price is that I now use global variables which could lead to some unfortunate overlaps. The chance of this is very slim if used properly though.

Since static functions in interfaces are not allowed, nor static abstract functions... there is now an requirement which is not forced automatically, which is that the callback function create an instance of the spell.
 
Status
Not open for further replies.
Top