• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Scope Deprecation

Do you think scopes should be deprecated?


  • Total voters
    23
Status
Not open for further replies.
- both will have errors if T32 is NOT present
- both will work if T32 is present

But when you use a library it will tell you that T32 is present and when you use
a scope, it will tell you that all the functions are undefined, and on some occasions,
functions containing undefined functions are seen as undefined in JassHelper (Sometimes)

That would cause a shit load of errors that don't make sense :p
 
Level 13
Joined
Mar 16, 2008
Messages
941
Dumb people don't make scopes useless.
Scopes have the simple advantage of having less features what means less to care about.
Why should you realy be able to "require" a spell?
Why would you ever need to rearrange the spells spot?
That's what libraries are used for, the require keyword is only one feature.

To show you the problem of this feature:
If you forget to add T32 in the example above, the mistake would be easier to find in a library.
If you forget to type "requires T32" in the library and the order is wrong the librarie would cause the same errors as scopes withour requirement.
Scopes don't even need you to require the libraries as they always are behind them.

Seems like scopes also have advantages, hm?
 
Level 13
Joined
Mar 16, 2008
Messages
941
Why should it be bad?
Your only real argument is that the mistake of missing a library is more easily found with libraries as the error messages are better. However, this should nearly never happen.
I say that libraries can cause the error of forgetting to even require stuff what can cause new error messages while scopes are always using all libraries (as they are written after libraries).
Since this fully kills your requirement argument I see no point in killing scopes.
It rather structures your code into system code and map code.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
I do not draw a very sharp line between header/non-header. This is a typical spell of mine in current style, which I indeed tend to rework in case I discover something more fitting:

JASS:
//! runtextmacro Folder("TempestStrike")
    //! runtextmacro Struct("CriticalAttacks")
        static real array CRITICAL_INCREMENT
        static Buff DUMMY_BUFF
        static constant real DURATION = 5.

        real criticalAdd

        static method Event_BuffLose takes nothing returns nothing
            local Unit target = UNIT.Event.GetTrigger()

            local thistype this = target

            local real criticalAdd = this.criticalAdd

            call target.CriticalChance.Bonus.Subtract(criticalAdd)
        endmethod

        static method Event_BuffGain takes nothing returns nothing
            local integer level = BUFF.Event.GetLevel()
            local Unit target = UNIT.Event.GetTrigger()

            local real criticalAdd = CRITICAL_INCREMENT[level]
            local thistype this = target

            set this.criticalAdd = criticalAdd
            call target.CriticalChance.Bonus.Add(criticalAdd)
        endmethod

        static method Start takes integer level, Unit target returns nothing
            call target.Buffs.Timed.Start(thistype.DUMMY_BUFF, level, thistype.DURATION)
        endmethod

        static method Init takes nothing returns nothing
            //! runtextmacro Buff_Create("/", "DUMMY_BUFF", "CrA", "Tempest Strike", "5", "true", "ReplaceableTextures\\CommandButtons\\BTNCleavingAttack.blp", "Does a lot of critical strikes.")

            call thistype.DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Gain.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffGain))
            call thistype.DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Lose.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffLose))
            call thistype.DUMMY_BUFF.SetLostOnDeath(true)
            call thistype.DUMMY_BUFF.SetLostOnDispel(true)
            call thistype.DUMMY_BUFF.TargetEffects.Add("Abilities\\Spells\\Orc\\TrollBerserk\\HeadhunterWEAPONSLeft.mdl", AttachPoint.WEAPON_LEFT, EffectLevel.LOW)
            call thistype.DUMMY_BUFF.TargetEffects.Add("Abilities\\Spells\\Orc\\TrollBerserk\\HeadhunterWEAPONSRight.mdl", AttachPoint.WEAPON_RIGHT, EffectLevel.LOW)

            set CRITICAL_INCREMENT[1] = 40.
            set CRITICAL_INCREMENT[2] = 60.
            set CRITICAL_INCREMENT[3] = 80.
            set CRITICAL_INCREMENT[4] = 100.
            set CRITICAL_INCREMENT[5] = 120.
        endmethod
    endstruct

    //! runtextmacro Struct("Refresh")
        static Event CAST_EVENT

        static method Event_CooldownEnding takes nothing returns nothing
            call UNIT.Event.GetTrigger().Event.Remove(CAST_EVENT)
        endmethod

        static method Event_Cast takes nothing returns nothing
            if (SPELL.Event.GetTrigger() == TempestStrike.THIS_SPELL) then
                return
            endif

            call UNIT.Event.GetTrigger().Abilities.Refresh(TempestStrike.THIS_SPELL)
        endmethod

        static method Event_CooldownStart takes nothing returns nothing
            call UNIT.Event.GetTrigger().Event.Add(CAST_EVENT)
        endmethod

        static method Init takes nothing returns nothing
            set CAST_EVENT = Event.Create(UNIT.Abilities.Events.Effect.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_Cast)
            call TempestStrike.THIS_SPELL.Event.Add(Event.Create(UNIT.Abilities.Cooldown.ENDING_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_CooldownEnding))
            call TempestStrike.THIS_SPELL.Event.Add(Event.Create(UNIT.Abilities.Cooldown.START_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_CooldownStart))
        endmethod
    endstruct
endscope

//! runtextmacro BaseStruct("TempestStrike", "TEMPEST_STRIKE")
    static constant real AREA_RANGE = 90.
    static real array DAMAGE
    static Buff DUMMY_BUFF
    static constant real DURATION = 0.5
    static Group ENUM_GROUP
    static constant real LENGTH = 500.
    static constant real SPEED_END = 100.
    static constant string TARGET_EFFECT_ATTACH_POINT = AttachPoint.CHEST
    static constant string TARGET_EFFECT_PATH = "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
    static BoolExpr TARGET_FILTER
    static constant real UPDATE_TIME = FRAME_UPDATE_TIME

    static Spell THIS_SPELL

    real damage
    integer level
    Group targetGroup
    Timer updateTimer

    //! runtextmacro LinkToStruct("TempestStrike", "CriticalAttacks")
    //! runtextmacro LinkToStruct("TempestStrike", "Refresh")

    static method Event_BuffLose takes nothing returns nothing
        local Unit target = UNIT.Event.GetTrigger()

        local thistype this = target

        local integer level = this.level
        local Group targetGroup = this.targetGroup
        local Timer updateTimer = this.updateTimer

        local boolean useBuff = (targetGroup.GetFirst() != NULL)

        call targetGroup.Destroy()
        call updateTimer.Destroy()

        call target.Animation.Queue(UNIT.Animation.STAND)
        call target.Ghost.Subtract()
        call target.Stun.Subtract(UNIT.Stun.NONE_BUFF)

        if (useBuff) then
            call thistype(NULL).CriticalAttacks.Start(level, target)
        endif
    endmethod

    static method Conditions takes nothing returns boolean
        local Unit filterUnit = UNIT.Event.Native.GetFilter()

        if (Group.TEMP.ContainsUnit(filterUnit)) then
            return false
        endif

        if (filterUnit.Classes.Contains(UnitClass.DEAD)) then
            return false
        endif
        if (filterUnit.IsAllyOf(User.TEMP)) then
            return false
        endif

        return true
    endmethod

    static method Update takes nothing returns nothing
        local real damage
        local Unit target
        local thistype this = Timer.GetExpired().GetData()

        local Unit caster = this

        local Group targetGroup = this.targetGroup

        set Group.TEMP = targetGroup
        set User.TEMP = caster.Owner.Get()

        call ENUM_GROUP.EnumUnits.InRange.WithCollision.Do(caster.Position.X.Get(), caster.Position.Y.Get(), AREA_RANGE, TARGET_FILTER)

        set target = ENUM_GROUP.FetchFirst()

        if (target != NULL) then
            set damage = this.damage
            set targetGroup = this.targetGroup

            loop
                call target.Effects.Create(TARGET_EFFECT_PATH, TARGET_EFFECT_ATTACH_POINT, EffectLevel.NORMAL)
                call targetGroup.AddUnit(target)

                call caster.DamageUnitBySpell(target, damage, false, true)

                set target = ENUM_GROUP.FetchFirst()
                exitwhen (target == NULL)
            endloop
        endif
    endmethod

    static method Event_BuffGain takes nothing returns nothing
        local integer level = BUFF.Event.GetLevel()
        local Unit target = UNIT.Event.GetTrigger()
        local real targetX = SPOT.Event.GetTargetX()
        local real targetY = SPOT.Event.GetTargetY()
        local Timer updateTimer = Timer.Create()

        local thistype this = target

        set this.damage = DAMAGE[level]
        set this.level = level
        set this.targetGroup = Group.Create()
        set this.updateTimer = updateTimer
        call updateTimer.SetData(this)

        call target.Ghost.Add()
        call target.Position.Timed.Accelerated.AddSpeedDirection(2. * LENGTH / DURATION - SPEED_END, 2. / DURATION * (SPEED_END - LENGTH / DURATION), Math.AtanByDeltas(targetY - target.Position.Y.Get(), targetX - target.Position.X.Get()), DURATION)
        call target.Stun.Add(UNIT.Stun.NONE_BUFF)

        call updateTimer.Start(UPDATE_TIME, true, function thistype.Update)
    endmethod

    static method Event_SpellEffect takes nothing returns nothing
        call UNIT.Event.GetTrigger().Buffs.Timed.Start(thistype.DUMMY_BUFF, SPELL.Event.GetLevel(), thistype.DURATION)
    endmethod

    static method Init takes nothing returns nothing
        set thistype.DUMMY_BUFF = Buff.CreateHidden("Tempest Strike")

        call thistype.DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Gain.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffGain))
        call thistype.DUMMY_BUFF.Event.Add(Event.Create(UNIT.Buffs.Events.Lose.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_BuffLose))
        call thistype.DUMMY_BUFF.TargetEffects.Add("Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", AttachPoint.ORIGIN, EffectLevel.NORMAL)

        //! runtextmacro Spell_Create("/", "THIS_SPELL", "ATeS", "Tempest Strike", "HERO_FIRST")

        //! runtextmacro Spell_SetAnimation("/", "spell")
        //! runtextmacro Spell_SetCooldown5("/", "7.", "7.", "7.", "7.", "7.")
        //! runtextmacro Spell_SetIcon("/", "ReplaceableTextures\\CommandButtons\\BTNCleavingAttack.blp")
        //! runtextmacro Spell_SetManaCost5("/", "60", "70", "80", "90", "100")
        //! runtextmacro Spell_SetOrder("/", "evileye")
        //! runtextmacro Spell_SetRange("/", "99999.")
        //! runtextmacro Spell_SetResearchRaw("/", "Te")
        //! runtextmacro Spell_SetResearchUberTooltipLv("/", "1", "Slices through a distance to reach the target location. Encountering units will be damaged and if at least one unit is hit, Smokealot will gain a critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.")
        //! runtextmacro Spell_SetResearchUberTooltipLv("/", "2", "Slices through a distance to reach the target location. Encountering units will be damaged and if at least one unit is hit, Smokealot will gain a critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|n|nNext Level:|nCritical value increment: 40 --> 60|nDamage: 30 --> 60|nMana cost: 60 --> 70.")
        //! runtextmacro Spell_SetResearchUberTooltipLv("/", "3", "Slices through a distance to reach the target location. Encountering units will be damaged and if at least one unit is hit, Smokealot will gain a critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|n|nNext Level:|nCritical value increment: 60 --> 80|nDamage: 60 --> 90|nMana cost: 70 --> 80.")
        //! runtextmacro Spell_SetResearchUberTooltipLv("/", "4", "Slices through a distance to reach the target location. Encountering units will be damaged and if at least one unit is hit, Smokealot will gain a critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|n|nNext Level:|nCritical value increment: 80 --> 100|nDamage: 90 --> 120|nMana cost: 80 --> 90.")
        //! runtextmacro Spell_SetResearchUberTooltipLv("/", "5", "Slices through a distance to reach the target location. Encountering units will be damaged and if at least one unit is hit, Smokealot will gain a critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|n|nNext Level:|nCritical value increment: 100 --> 120|nDamage: 120 --> 150|nMana cost: 90 --> 100.")
        //! runtextmacro Spell_SetTargetType("/", "POINT")
        //! runtextmacro Spell_SetUberTooltipLv("/", "1", "Slices through a distance of 500 to reach the target location. Encountering units will be damaged by 30 and if at least one unit is hit, Smokealot will gain a 40 critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|nLasts 5 seconds.")
        //! runtextmacro Spell_SetUberTooltipLv("/", "2", "Slices through a distance of 500 to reach the target location. Encountering units will be damaged by 60 and if at least one unit is hit, Smokealot will gain a 60 critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|nLasts 5 seconds.")
        //! runtextmacro Spell_SetUberTooltipLv("/", "3", "Slices through a distance of 500 to reach the target location. Encountering units will be damaged by 90 and if at least one unit is hit, Smokealot will gain a 80 critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|nLasts 5 seconds.")
        //! runtextmacro Spell_SetUberTooltipLv("/", "4", "Slices through a distance of 500 to reach the target location. Encountering units will be damaged by 120 and if at least one unit is hit, Smokealot will gain a 100 critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|nLasts 5 seconds.")
        //! runtextmacro Spell_SetUberTooltipLv("/", "5", "Slices through a distance of 500 to reach the target location. Encountering units will be damaged by 150 and if at least one unit is hit, Smokealot will gain a 120 critical value buff. The cast of any other ability lifts the cooldown of 'Tempest Strike'.|nLasts 5 seconds.")

        //! runtextmacro Spell_Finalize("/")

        set DAMAGE[1] = 30.
        set DAMAGE[2] = 60.
        set DAMAGE[3] = 90.
        set DAMAGE[4] = 120.
        set DAMAGE[5] = 150.
        set ENUM_GROUP = Group.Create()
        set TARGET_FILTER = BoolExpr.GetFromFunction(function thistype.Conditions)
        call THIS_SPELL.Event.Add(Event.Create(UNIT.Abilities.Events.Effect.DUMMY_EVENT_TYPE, EventPriority.SPELLS, function thistype.Event_SpellEffect))

        call thistype(NULL).CriticalAttacks.Init()
        call thistype(NULL).Refresh.Init()
    endmethod
endstruct

When we look only at the folders under the type Unit here, there is Event, CriticalChance.Bonus, Buffs.Timed, Abilities, Abilities.Events.Effect, Abilities.Cooldown, Animation, Ghost, Stun, Classes, Owner, Position, Effects and Position.Timed.Accelerated. Would be annoying to demand all of these apart but requiring just Unit as a whole in contrast would be some vague due to the fact that not everything is really vital for the existence of a Unit. Maybe, at some point, I decided to remove critical strikes. That said, the paths shown here already indicate where the source of information is hiding.

In my opinion, the JassHelper errors do not really matter. You concentrate on the first output, easily find the problem (if it was really about block requirement) and with a sense of overview/thinking can most likely apply it to the rest.
 
Status
Not open for further replies.
Top