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

why does Jcast lib give error? JCast___TARGET_TABLE is not a type that allows .syntax

Status
Not open for further replies.
Level 7
Joined
Nov 18, 2012
Messages
312
src= System - JCast (advanced casting-system) | The Helper
JASS:
//TESH.scrollpos=583
//TESH.alwaysfold=0
//***************************************************************************************************
//*  JCast
//* -------
//* Author: profet (profetiser_AT_hotmail.com)
//*
//* Description:
//*   
//*     This system provides an easy way to create complex custom spells.
//*
//*     JCast is a surrogate to the whole warcraft3's casting system : it replaces the functioning of
//*     the cast itself and allows a lot of new behaviours like variable casttime (a buff or an item
//*     could increases or decreases the cast/channeling time).
//*     It also encapsulates the whole spell inside a struct, that enables us to easily attach data to
//*     each spell instance (effects, numerical values...), solving by the way a lot of programing problems.
//*
//*
//* Usage:
//*   
//*     The creation of a new spell is a very simple task:
//*         1. Create a new structure that extends the IJCast interface.
//*         2. Define the static constant AbilityId, needed for spell's registration.
//*         3. Implement JCastModule (at the end of the struct, see FocusedHealing example for details).
//*         4. Override the methods required to fit your needs.
//*   
//*     Overridable methods are numerous:
/*       
            method CanCast takes nothing returns boolean defaults true
            //Returns FALSE to deny the cast.
          
            method CanBeInterrupted takes nothing returns boolean defaults true
            //Returns FALSE to allow the caster to move during the cast (see RemoteBomb example for details).
          
            method ResumeAttack takes nothing returns boolean defaults false
            //Returns TRUE to restore caster's attack order when the spell is cast.
          
            method RefundManaOnCancel takes nothing returns boolean defaults true
            //Returns FALSE to make the mana consumed if the spell is canceled.
          
            method GetCastTime takes nothing returns real defaults 0.
            //Returns the duration of the cast (time before the spell's effects)
          
            method GetChannelTime takes nothing returns real defaults 0.
            //Returns the duration of the channeling (duration of spell's effects, used in combination with GetChannelTickTime)
          
            method GetChannelTickTime takes nothing returns real defaults 0.
            //Returns the period of channeling tick's (see LifeDrain example for details).
          
            method ApplyCastPushback takes real progress, real castTime, real pushCount returns real
            //Returns the new casting progress value, modified by the pushback effect.
            //Note: You can return a changeless 'progress' value to ignore this effect.
          
            method ApplyChannelPushback takes real progress, real channelTime, real pushCount returns real
            //Returns the new channeling progress value, modified by the pushback effect.
            //Note: You can return a changeless 'progress' value to ignore this effect.
          
          
            static method OnInit takes nothing returns nothing
            //Called just after struct's initialization.
          
            method OnBegin takes nothing returns nothing
            //Called at spell's initialization start.
          
            method OnFail takes nothing returns nothing
            //Called when the spell fails (CanCast returned FALSE).
          
            method OnPreCast takes nothing returns nothing
            //Called when the spell starts (after manacost calculation).
          
            method OnCastStart takes nothing returns nothing
            //(only if cast duration > 0) Called when the cast starts.
          
            method OnCastUpdate takes real progress returns nothing
            //(only if cast duration > 0) Called at each cast update (ref. TIMER_THRESHOLD constant),
            //use this only if you need to update things all along the cast.
          
            method OnCastEnd takes nothing returns nothing
            //(only if cast duration > 0) Called when the cast ends (after the duration returned by GetCastTime).
          
            method OnEffect takes nothing returns nothing
            //Called just after OnCastEnd if spell conditions are still valid (CanCast is reevaluated when the cast ends)
          
            method OnChannelStart takes nothing returns nothing
            //(only if channel duration > 0) Called when the channeling starts.
          
            method OnChannelUpdate takes real progress returns nothing
            //(only if channel duration > 0) Called at each channeling update (ref. TIMER_THRESHOLD
            //constant), use this only if you need to update things all along the channeling.
          
            method OnChannelTick takes nothing returns nothing
            //(only if channel duration > 0) Called when a channeling tick is reached (used to
            //execute periodical code during channeling)
          
            method OnChannelEnd takes nothing returns nothing
            //(only if channel duration > 0) Called when the channeling ends.
          
            method OnEnd takes nothing returns nothing
            //Called whenever the spell ends, even on failure.
          
          
*/     
//*
//*
//* Requirements:
//*   Table (by Vexorian, http://www.wc3c.net/showthread.php?t=101246 )
//*   TimerUtils (by Vexorian, http://www.wc3c.net/showthread.php?t=101322 )
//*
//*  To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//***************************************************************************************************
library JCast initializer init uses Table, TimerUtils, optional JDebug
//===========================================================================
// SETTINGS
// ˉˉˉˉˉˉˉˉ
//  This section exposes all the system's configuration variables and functions.
//  Feel free to modify them to suit your needs !
//===========================================================================
globals
  
    //Period of the spell's update timer, keeping it as low as possible increases precision but lowers system's performances.
    //Note that update period also affects casting/channeling bar and OnCastUpdate/OnChannelUpdate update rate.
    private constant real           TIMER_THRESHOLD                     = 0.01
  
endglobals
  
  
//===========================================================================
//* LIBRARY'S CORE
//* ˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
//*  Do NOT modify without a really good reason !!
//===========================================================================

//***********************************************************
//* LAST TARGET SYSTEM
//*  Allow to retrieve the last attacked unit if interrupted by a cast
//*

    // The target is stored whenever the unit issue an "attack" or "smart" order.
    // When the unit issue a point order, stored target is instantly cleared.
    // When the unit issue an order with no target, if issue order is not "stop" nor "holdposition"
    // the target is flagged as "previous target" and will be cleared if an other no-target order is issued.
  
    globals
        private HandleTable     TARGET_TABLE
        private integer         tempOrder
    endglobals
  
    private struct sTargetManager
        private unit        m_unit
        private unit        m_target    = null
        private boolean     m_current   = false
      
        method Reset takes nothing returns nothing
        //-> Point order or "Stop"
            if (.m_target != null) then
                set .m_target = null
                //set .m_current = false
            endif
        endmethod
      
        method Set takes unit target returns nothing
        //-> "Attack" or "Smart" order
            if (target != null) then
                set .m_target = target
                set .m_current = true
            endif
        endmethod
      
        method Unset takes nothing returns nothing
        //-> order with no target
            if (.m_target != null) then
                if (.m_current) then
                    set .m_current = false
                else
                    set .m_target = null
                    set .m_current = false
                endif
            endif
        endmethod
      
        method getTarget takes nothing returns unit
            if (.m_target != null) and (GetWidgetLife(.m_target) > .405) then
                return .m_target
            endif
            return null
        endmethod
      
        static method GetTarget takes unit un returns unit
            if TARGET_TABLE.exists(un) then
                return thistype(TARGET_TABLE[un]).getTarget()
            endif
            return null
        endmethod
      
        static method create takes unit un returns thistype
        local thistype this = thistype.allocate()
            set this.m_unit = un
            return this
        endmethod
      
    endstruct
  
  
    //smart:        851971
    //stop:         851972
    //attack:       851983
    //move:         851986
    //patrol:       851990
    //holdposition: 851993
    private function TargetOrder_Actions takes nothing returns nothing
        if TARGET_TABLE.exists(GetOrderedUnit()) then
            //If the unit issued an "Attack" order (or "Smart" order on hostile target)
            if (GetIssuedOrderId() == 851983 /*attack*/) or ((GetIssuedOrderId() == 851971 /*smart*/) and IsUnitEnemy(GetOrderTargetUnit(), GetOwningPlayer(GetOrderedUnit()))) then
                call sTargetManager(TARGET_TABLE[GetOrderedUnit()]).Set( GetOrderTargetUnit() )
            endif
        endif
    endfunction
  
    private function VoidOrder_Actions takes nothing returns nothing
        if TARGET_TABLE.exists(GetOrderedUnit()) then
            if (GetIssuedOrderId() == 851972 /*stop*/) or (GetIssuedOrderId() == 851993 /*holdposition*/) then
                call sTargetManager(TARGET_TABLE[GetOrderedUnit()]).Reset()
            else
                call sTargetManager(TARGET_TABLE[GetOrderedUnit()]).Unset()
            endif
        endif
    endfunction
  
    private function PointOrder_Actions takes nothing returns nothing
        if TARGET_TABLE.exists(GetOrderedUnit()) then
            call sTargetManager(TARGET_TABLE[GetOrderedUnit()]).Reset()
        endif
    endfunction
  
  
    private function initLastTarget takes nothing returns nothing
    local integer i = 0
    local trigger t
      
        set TARGET_TABLE = HandleTable.create()
      
        //Issue a target order
        set t = CreateTrigger()
        call TriggerAddAction(t, function TargetOrder_Actions)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
            set i = i +1
            exitwhen (i == bj_MAX_PLAYER_SLOTS)
        endloop
        set i = 0
      
        //Issue a point order
        set t = CreateTrigger()
        call TriggerAddAction(t, function PointOrder_Actions)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
            set i = i +1
            exitwhen (i == bj_MAX_PLAYER_SLOTS)
        endloop
        set i = 0
      
        //Issue an order with no target
        set t = CreateTrigger()
        call TriggerAddAction(t, function VoidOrder_Actions)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
            set i = i +1
            exitwhen (i == bj_MAX_PLAYER_SLOTS)
        endloop
      
    endfunction
  
  
  
//***********************************************************
//* CASTING SYSTEM

    globals
        private HandleTable     UNIT_TABLE
        private trigger         STOP_TRIGGER
    endglobals
  
  
    interface IJCast
        //Optional methods
        method CanCast takes nothing returns boolean                    defaults true
        method CanBeInterrupted takes nothing returns boolean           defaults true
      
        method GetCastTime takes nothing returns real                   defaults 0.
        method GetChannelTime takes nothing returns real                defaults 0.
        method GetChannelTickTime takes nothing returns real            defaults 0.
      
        method ResumeAttack takes nothing returns boolean               defaults false
        method RefundManaOnCancel takes nothing returns boolean         defaults true
      
        method OnBegin takes nothing returns nothing                  defaults nothing
        method OnFail takes nothing returns nothing                     defaults nothing
        method OnPreCast takes nothing returns nothing                  defaults nothing
      
        method OnCastStart takes nothing returns nothing                defaults nothing
        method OnCastEnd takes nothing returns nothing                  defaults nothing
        method OnEffect takes nothing returns nothing                   defaults nothing
        method OnChannelStart takes nothing returns nothing             defaults nothing
        method OnChannelTick takes nothing returns nothing              defaults nothing
        method OnChannelEnd takes nothing returns nothing               defaults nothing
        method OnEnd takes nothing returns nothing                      defaults nothing
      
        //Automatically implemented by JCastModule
        method destroy takes nothing returns nothing
        method interrupt takes trigger t returns nothing
        method pushback takes nothing returns nothing
    endinterface



module JCastModule
//----------------------------------------------------------------------
// Private Members
  
    //States
    private static constant integer     STATE_INIT      = 0
    private static constant integer     STATE_FAIL      = 1 //only if the cast fails
    private static constant integer     STATE_CAST      = 2 //skipped if no cast time
    private static constant integer     STATE_EFFECT    = 3
    private static constant integer     STATE_CHANNEL   = 4 //skipped if no channel time
    private static constant integer     STATE_INTERRUPT = 5
    private static constant integer     STATE_END       = 6
  
    private static method getStateName takes integer state returns string
        if (state == STATE_INIT) then
            return "INIT"
        elseif (state == STATE_FAIL) then
            return "FAIL"
        elseif (state == STATE_CAST) then
            return "CAST"
        elseif (state == STATE_EFFECT) then
            return "EFFECT"
        elseif (state == STATE_CHANNEL) then
            return "CHANNEL"
        elseif (state == STATE_INTERRUPT) then
            return "INTERRUPT"
        elseif (state == STATE_END) then
            return "END"
        endif
        return ""
    endmethod
  
    //Core properties
    private timer               m_timer                 = null
    private integer             m_state                 = STATE_INIT
    private boolean             m_isRegistered          = false
    private boolean             m_isCast                = false
    private real                m_progress              = 0.
    private real                m_tickProgress          = 0.
    private integer             m_pushCount             = 0
    private real                m_manaCostTemp          //used to calculate spell's manacost
    private real                m_manaCost              = 0.
  
    //Properties loaded from custom struct's definition
    private boolean             m_manaRefundOnCancel
    private unit                m_attackTarget
    private boolean             m_resumeAttack
    private real                m_castTime
    private real                m_channelTime
    private real                m_channelTickTime
  
    //Spell's event response properties
    private unit                m_caster
    private integer             m_level
    private real                m_targetX
    private real                m_targetY 
    private unit                m_targetUnit
    private destructable        m_targetDest
    private item                m_targetItem
  
  
//----------------------------------------------------------------------
// Constructor and Destructor
  
    //Constructor is defined as private to prevent wild allocation of this struct
    private static method create takes nothing returns thistype
        return 0
    endmethod
  
    //Simple destructor :)
    private method destroy takes nothing returns nothing
        //If the cast is not complete, give the mana back to the caster
            if (not .m_isCast) and (.m_manaCost > 0) and .m_manaRefundOnCancel then
                call SetUnitState(.m_caster, UNIT_STATE_MANA, GetUnitState(.m_caster,UNIT_STATE_MANA) + .m_manaCost)
            endif
        //Clear instance
            if (.m_timer != null) then
                call ReleaseTimer( .m_timer )
            endif
        call this.deallocate()
    endmethod
  
//----------------------------------------------------------------------
// Private Helpers

    private method setState takes integer newState returns nothing
        static if LIBRARY_JDebug then
        call JDebug_LibMsg("JCast("+I2S(this)+")", "State changed from "+I2S(.m_state)+":"+.getStateName(.m_state)+" to "+I2S(newState)+":"+.getStateName(newState))
        endif
        set .m_state = newState
    endmethod
  
    private method getState takes nothing returns integer
        return .m_state
    endmethod
  
  
    method pushback takes nothing returns nothing
        static if thistype.ApplyCastPushback.exists then
        if (getState() == STATE_CAST) then
            set .m_pushCount = .m_pushCount + 1
            set .m_progress = ApplyCastPushback(.m_progress, .m_castTime, .m_pushCount)
            return
        endif
        else
        //No casting pushback!
        endif
        static if thistype.ApplyChannelPushback.exists then
        if (getState() == STATE_CHANNEL) then
            set .m_pushCount = .m_pushCount + 1
            set .m_progress = ApplyChannelPushback(.m_progress, .m_channelTime, .m_pushCount)
        endif
        else
        //No channeling pushback!
        endif
    endmethod
  
  
//----------------------------------------------------------------------
// Public Helpers
  
    method GetLevel takes nothing returns integer
        return .m_level
    endmethod
  
    method GetCaster takes nothing returns unit
        return .m_caster
    endmethod
  
    method GetAttackTarget takes nothing returns unit
        return .m_attackTarget
    endmethod
  
    method GetTargetX takes nothing returns real
        return .m_targetX
    endmethod
  
    method GetTargetY takes nothing returns real
        return .m_targetY
    endmethod
  
    method GetTargetUnit takes nothing returns unit
        return .m_targetUnit
    endmethod
  
    method GetTargetItem takes nothing returns item
        return .m_targetItem
    endmethod
  
    method GetTargetDestructable takes nothing returns destructable
        return .m_targetDest
    endmethod
  
    method GetManaCost takes nothing returns real
        return .m_manaCost
    endmethod
  
    method IsCast takes nothing returns boolean
        return .m_isCast
    endmethod
  
    static constant method GetUpdateRate takes nothing returns real
        return TIMER_THRESHOLD
    endmethod
  
  
//----------------------------------------------------------------------
// STATE : End
  
    private method stopAttackContinuation takes nothing returns nothing
        call IssueTargetOrderById(m_caster, 851983 /*attack*/, .m_attackTarget)
        call destroy()
    endmethod
    private static method stopAttackContinuation_Callback takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).stopAttackContinuation()
    endmethod
  
    private method doEnd takes nothing returns nothing
        //Execute custom event
            if (getState() != STATE_FAIL) then
                call OnEnd()
            endif
        //Change state
            call setState(STATE_END)
        //If the spell is registered, we have to stop the spell
        //(prevent the unit from keeping channeling if the spell's based on Channel that has a follow through time)
        //If the spell uses attack continuation, order the caster to attack with a tiny delay (else 851973 order won't stop the cast)
        if .m_resumeAttack then
            call TimerStart(m_timer, 0.00, false, function thistype.stopAttackContinuation_Callback)
            return
        endif
        //else destroy the spell instance
        call destroy()
    endmethod
  
    private method doFail takes nothing returns nothing
        //Stop the WC3 spell
            call IssueImmediateOrderById(m_caster, 851973 /*stunned*/)
        //Change state from STATE_INIT
            call setState(STATE_FAIL)
        //Execute custom event
            call OnFail()
        //Stop the spell before mana and cooldown are consumed
            if (not .m_isRegistered) then
                call doEnd()
            endif
    endmethod
  
//----------------------------------------------------------------------
// STATE : Channel
  
    private method cleanChannel takes nothing returns nothing
        call PauseTimer(m_timer)
        //if .m_showChannelBar then
        //    call channelBarStop(m_caster)
        //endif
        call OnChannelEnd()
    endmethod
  
    private method channelTerminate takes nothing returns nothing
        //Clear channeling data
            call cleanChannel()
        //Jump to STOP state
            if .m_isRegistered then
                call IssueImmediateOrderById(m_caster, 851973 /*stunned*/)
            else
                call doEnd()
            endif
    endmethod
  
    private method channelUpdate takes nothing returns nothing
        //If custom spell's conditions are not met, end the channeling
            if (not CanCast()) then
                call channelTerminate()
                return
            endif
        //Update channeling and tick progress
            set .m_progress     = .m_progress     + TIMER_THRESHOLD
            set .m_tickProgress = .m_tickProgress + TIMER_THRESHOLD
        //Execute custom update method
            static if thistype.OnChannelUpdate.exists then
            call OnChannelUpdate(.m_progress / .m_channelTime)
            else
            //No update method call (OnChannelUpdate() method is not found)
            endif
        //If we reached a tick, execute tick event
            if (m_channelTickTime > 0.) and (m_tickProgress >= .m_channelTickTime) then
                set .m_tickProgress = .m_tickProgress - .m_channelTickTime
                //Execute custom event
                    call OnChannelTick()
                //Check again spell's conditions
                    if (not CanCast()) then
                        call channelTerminate()
                        return
                    endif
                //Update channel tick period
                    set .m_channelTickTime = .GetChannelTickTime()
            endif
        //If channeling is complete, terminate.
            if (m_progress >= .m_channelTime) then
                call channelTerminate()
            endif
    endmethod
  
    private static method channelUpdate_Callback takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).channelUpdate()
    endmethod
  
  
    private method doChannel takes nothing returns nothing
        //Change state from STATE_EFFECT
            call setState(STATE_CHANNEL)
        //Execute custom event and start channeling
            call OnChannelStart()
            call TimerStart(m_timer, TIMER_THRESHOLD, true, function thistype.channelUpdate_Callback)
    endmethod
          
          
//----------------------------------------------------------------------
// STATE : Effect
  
    private method doEffect takes nothing returns nothing
        //Change state from STATE_START or STATE_CAST
            call setState(STATE_EFFECT)
        //Mana is now irreparably lost
            set .m_isCast = true
        //If the spell do have a channel time, start channeling
            if (m_channelTime > 0.) then
                call OnEffect()
                call doChannel()
        //The cast is complete, then execute custom event and stop the spell
            else
                if .m_isRegistered then
                    call IssueImmediateOrderById(m_caster, 851973 /*stunned*/)  //stop WC3 spell casting
                    call OnEffect()
                else
                    call OnEffect()
                    call doEnd()
                endif
            endif
    endmethod
  
  
//----------------------------------------------------------------------
// STATE : Cast
  
    private method cleanCast takes nothing returns nothing
        call PauseTimer(m_timer)
        set .m_progress = 0.
        set .m_pushCount = 0
        call OnCastEnd()
    endmethod
  
    private method castTerminate takes nothing returns nothing
        //Clear casting data
            call cleanCast()
        //If custom spell's conditions are met, go to the EFFECT state or stop the spell
            if CanCast() then
                call doEffect()
            else
                call doFail()
            endif
    endmethod
  
    private method castUpdate takes nothing returns nothing
        //Update precast progress
            set .m_progress = .m_progress + TIMER_THRESHOLD
        //Execute custom update method
            static if thistype.OnCastUpdate.exists then
            call OnCastUpdate(.m_progress / .m_castTime)
            else
            //No update method call (OnCastUpdate() method is not found)
            endif
        //If progress is complete, terminate.
            if (m_progress >= .m_castTime) then
                call castTerminate()
            endif
    endmethod
    private static method castUpdate_Callback takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).castUpdate()
    endmethod
  
    private method doCast takes nothing returns nothing
        //Change state from STATE_INIT
            call setState(STATE_CAST)
        //Execute custom event and start casting
            call OnCastStart()
            call TimerStart(m_timer, TIMER_THRESHOLD, true, function thistype.castUpdate_Callback)
    endmethod
  
  
//----------------------------------------------------------------------
// Initialization
//
//  This system automatically handles Warcraft3's casting events.
//  To do that, a trigger is created at struct initialization.
// 
//  Each time the spell is cast by a unit, an instance of this structure
//  is created and proceeded.
//
//----------------------------------------------------------------------
  
    private method initTerminate takes nothing returns nothing
        //Execute custom event
            call OnPreCast()
        //If the spell do have a cast time, start casting
            if (m_castTime > 0.) then
                call doCast()
        //Else skip the CAST state and jump to the EFFECT state
            else
                call doEffect()
            endif
    endmethod
  
    private method initAttackContinuation takes nothing returns nothing
        set .m_resumeAttack = false
        call IssueTargetOrderById(m_caster, 851983 /*attack*/, .m_attackTarget)
        call initTerminate()
    endmethod
    private static method initAttackContinuation_Callback takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).initAttackContinuation()
    endmethod
  
    private method initFull takes nothing returns nothing
        //Calculate spell's manacost
            set .m_manaCost = .m_manaCostTemp - GetUnitState(m_caster, UNIT_STATE_MANA)
        //If the spell is not registered, the caster should not be involved in the cast then stop his current order
        //(prevent the unit from keeping channeling if the spell's based on Channel that has a follow through time)
            if (not .m_isRegistered) then
                call IssueImmediateOrderById(m_caster, 851973 /*stunned*/)
                //If the spell uses attack continuation, order the caster to attack with a tiny delay (else 851973 order won't stop the cast)
                if .m_resumeAttack then
                    call TimerStart(m_timer, 0.00, false, function thistype.initAttackContinuation_Callback)
                    return
                endif
            endif
        //Go to the casting phase
            call initTerminate()
    endmethod
    private static method initFull_Callback takes nothing returns nothing
        call thistype(GetTimerData(GetExpiredTimer())).initFull()
    endmethod
  
  
    private static method init_Conditions takes nothing returns boolean
        return (GetSpellAbilityId() == thistype.AbilityId)
    endmethod
  
    private static method init_Actions takes nothing returns nothing
    local thistype this = thistype.allocate()
        //Initialization of core data (availaible in struct's methods through the use of getters)
            set this.m_manaCost = 0.
            set this.m_caster   = GetSpellAbilityUnit()
            set this.m_level    = GetUnitAbilityLevel(this.m_caster, GetSpellAbilityId())
            set this.m_targetX  = GetSpellTargetX()
            set this.m_targetY  = GetSpellTargetY()
            set this.m_targetUnit = GetSpellTargetUnit()
            set this.m_targetDest = GetSpellTargetDestructable()
            set this.m_targetItem = GetSpellTargetItem()
            set this.m_attackTarget = sTargetManager.GetTarget(this.m_caster)
            set this.m_timer = NewTimer()
            call SetTimerData(this.m_timer, this)
            call this.OnBegin()
            set this.m_resumeAttack = this.ResumeAttack() and (this.m_attackTarget != null)
        //If custom spell's conditions are met, start the cast
            if this.CanCast() then
                //Gather more required informations about the spell
                    set this.m_manaCostTemp           = GetUnitState(this.m_caster, UNIT_STATE_MANA)
                    set this.m_manaRefundOnCancel     = this.RefundManaOnCancel()
                    set this.m_castTime               = this.GetCastTime()
                    set this.m_channelTime            = this.GetChannelTime()
                    set this.m_channelTickTime        = this.GetChannelTickTime()
                //If the spell is interruptable and has a casting or channeling time, register this instance
                    if this.CanBeInterrupted() and ((this.m_castTime > 0.) or (this.m_channelTime > 0.)) then
                        set this.m_isRegistered = true
                        set UNIT_TABLE[this.m_caster] = integer(this)
                    endif
                //We are at EVENT_PLAYER_UNIT_SPELL_ENDCAST stage and neither cooldown nor manacost was applied yet,
                //then wait for a very short period to calculate the spell's manacost
                    call TimerStart(this.m_timer, 0.00, false, function thistype.initFull_Callback)
        //Else abort the cast
            else
                call this.doFail()
            endif
          
    endmethod
  
  
//----------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------
  
    //Note: I needed a public (since there is no protected keyword in vJass) method to be call by system's STOP_TRIGGER.
    //However, allowing users to call this method from inside the struct (although it may seem interesting) would be
    //contrary to the way I designed the system ; spell's control should be done through CanCast() method only.
    method interrupt takes trigger t returns nothing
        call PauseTimer(m_timer)
        //Check if the call is legitimate
            if (t != STOP_TRIGGER) then
                static if LIBRARY_JDebug then
                call JDebug_LibError( "JCast", "Trying to terminate a cast via interrupt() is not allowed, use CanCast() method instead" )
                endif
                return
            endif
        //Unregister the caster
            call UNIT_TABLE.flush(.m_caster)
        //Interrupt the spell
            if (getState() == STATE_CAST) then
                call cleanCast()
            elseif (getState() == STATE_CHANNEL) then
                call cleanChannel()
            else
                return // do nothing if we are in STATE_STOP
            endif
        //Change state and stop the spell
            call setState(STATE_INTERRUPT)
            call doEnd()
    endmethod
  
  
//----------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------
  
    private static method onInit takes nothing returns nothing
    local trigger t
        //Check if the specified ability exists or already registered
            if (thistype.AbilityId <= 0) or (GetObjectName(thistype.AbilityId) == "Default string") then
                return
            endif
        //Create a trigger to detect the cast of this spell
            set t = CreateTrigger()
            call TriggerAddAction(t, function thistype.init_Actions)
            call TriggerAddCondition(t, Condition(function thistype.init_Conditions) )
            call TriggerRegisterPlayerUnitEvent(t, Player(0),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(1),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(2),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(3),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(4),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(5),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(6),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(7),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(8),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(9),  EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(10), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            call TriggerRegisterPlayerUnitEvent(t, Player(11), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            //Note: EVENT_PLAYER_UNIT_SPELL_CHANNEL : fired whenever a spell is cast, this is the first spell's event
            //      EVENT_PLAYER_UNIT_SPELL_EFFECT  : fired just before mana is removed and cooldown started (if the cast was not canceled during war3's casting time)
            //      EVENT_PLAYER_UNIT_SPELL_FINISH  : fired only when War3's cast is complete, interrupted spells won't fire this event
            //      EVENT_PLAYER_UNIT_SPELL_ENDCAST : fired whenever a spell is stopped, even if it was canceled
        //Execute custom initialization event
            static if thistype.OnInit.exists then
            call thistype.OnInit()
            else
            //No init method call (OnInit() method is not found)
            endif
    endmethod
  
endmodule


//***********************************************************
//* LIBRARY INITIALIZER
//* A global trigger is used to catch SPELL_ENDCAST event, and stop current
//* cast spell instance.
//*
  
    private function endCast_Actions takes nothing returns nothing
        if UNIT_TABLE.exists(GetSpellAbilityUnit()) then
            call IJCast(UNIT_TABLE[GetSpellAbilityUnit()]).interrupt(GetTriggeringTrigger()) //Destroy current cast instance
        endif
    endfunction
  
    private function init takes nothing returns nothing
        set STOP_TRIGGER = CreateTrigger()
        call TriggerAddAction(STOP_TRIGGER, function endCast_Actions )
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(0), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(1), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(2), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(3), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(4), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(5), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(6), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(7), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(8), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(9), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(10), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        call TriggerRegisterPlayerUnitEvent(STOP_TRIGGER, Player(11), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        set UNIT_TABLE = HandleTable.create()
        call initLastTarget()
    endfunction



//===========================================================================
//* PUBLIC FUNCTIONS
//===========================================================================

    function JCast_IsCasting takes unit un returns boolean
        return ((un != null) and UNIT_TABLE.exists(un))
    endfunction
  
    function JCast_Pushback takes unit target returns nothing
        if (target != null) and UNIT_TABLE.exists(target) then
            call IJCast(UNIT_TABLE[target]).pushback()
        endif
    endfunction
  
    function JCast_Interrupt takes unit target returns nothing
        if (target != null) and UNIT_TABLE.exists(target) then
            call IssueImmediateOrderById(target, 851972 /*stop*/)
        endif
    endfunction
  
    function JCast_RegisterTargetWatch takes unit watchedUnit returns nothing
        if (watchedUnit == null) or TARGET_TABLE.exists(watchedUnit) then
            return
        endif
        set TARGET_TABLE[watchedUnit] = integer(sTargetManager.create(watchedUnit))
    endfunction
  
  
endlibrary
 
Level 7
Joined
Nov 18, 2012
Messages
312
Which line is giving that error. I think you forgot to include Table in map.
JASS:
//TESH.scrollpos=228
//TESH.alwaysfold=0
library Table // made by Bribe, special thanks to Nestharus, version 3.0.0.0
/*
    API
   
    ------------
    struct Table
    | static method create takes nothing returns Table
    |     create a new Table
    |    
    | method destroy takes nothing returns nothing
    |     destroy it
    |    
    | method flush takes nothing returns nothing
    |     flush all stored values inside of it
    |    
    | method remove takes integer key returns nothing
    |     remove the value at index "key"
    |    
    | method operator []= takes integer key, $TYPE$ value returns nothing
    |     assign "value" to index "key"
    |    
    | method operator [] takes integer key returns $TYPE$
    |     load the value at index "key"
    |    
    | method has takes integer key returns boolean
    |     whether or not the key was assigned
    |
    ----------------
    struct TableArray
    | static method operator [] takes integer array_size returns TableArray
    |     create a new array of Tables of size "array_size"
    |
    | method destroy takes nothing returns nothing
    |     destroy it
    |
    | method flush takes nothing returns nothing
    |     flush and destroy it
    |
    | method operator size takes nothing returns integer
    |     returns the size of the TableArray
    |
    | method operator [] takes integer key returns Table
    |     returns a Table accessible exclusively to index "key"
*/
   
globals
    private hashtable ht = InitHashtable() //The last hashtable you need
    private integer more = 2 //Index generation for Tables (above 2)
    private integer less = 0 //Index generation for TableArrays (below 0)
endglobals
   
private struct dex extends array
    static method operator size takes nothing returns Table
        return 1
    endmethod
    static method operator list takes nothing returns Table
        return 2
    endmethod
endstruct
   
private struct handles extends array
    method has takes integer key returns boolean
        return HaveSavedHandle(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSavedHandle(ht, this, key)
    endmethod
endstruct
   
private struct agents extends array
    method operator []= takes integer key, agent value returns nothing
        call SaveAgentHandle(ht, this, key, value)
    endmethod
endstruct
   
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$(ht, this, key, value)
    endmethod
    method has takes integer key returns boolean
        return HaveSaved$SUPER$(ht, this, key)
    endmethod
    method remove takes integer key returns nothing
        call RemoveSaved$SUPER$(ht, this, key)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
    method operator [] takes integer key returns $TYPE$
        return Load$FUNC$Handle(ht, this, key)
    endmethod
    method operator []= takes integer key, $TYPE$ value returns nothing
        call Save$FUNC$Handle(ht, this, key, value)
    endmethod
endstruct
private module $TYPE$m
    method operator $TYPE$ takes nothing returns $TYPE$s
        return this
    endmethod
endmodule
//! endtextmacro
   
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
   
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
   
struct Table extends array
   
    // Implement modules for intuitive type-syntax
    implement realm
    implement booleanm
    implement stringm
    implement playerm
    implement widgetm
    implement destructablem
    implement itemm
    implement unitm
    implement abilitym
    implement timerm
    implement triggerm
    implement triggerconditionm
    implement triggeractionm
    implement eventm
    implement forcem
    implement groupm
    implement locationm
    implement rectm
    implement boolexprm
    implement soundm
    implement effectm
    implement unitpoolm
    implement itempoolm
    implement questm
    implement questitemm
    implement defeatconditionm
    implement timerdialogm
    implement leaderboardm
    implement multiboardm
    implement multiboarditemm
    implement trackablem
    implement dialogm
    implement buttonm
    implement texttagm
    implement lightningm
    implement imagem
    implement ubersplatm
    implement regionm
    implement fogstatem
    implement fogmodifierm
    implement hashtablem
   
    method operator handle takes nothing returns handles
        return this
    endmethod
   
    method operator agent takes nothing returns agents
        return this
    endmethod
   
    // set this = a[GetSpellAbilityId()]
    method operator [] takes integer key returns Table
        return LoadInteger(ht, this, key)
    endmethod
   
    // set a[389034] = 8192
    method operator []= takes integer key, Table a returns nothing
        call SaveInteger(ht, this, key, a)
    endmethod
   
    // set b = a.has(2493223)
    method has takes integer key returns boolean
        return HaveSavedInteger(ht, this, key)
    endmethod
   
    // call a.remove(294080)
    method remove takes integer key returns nothing
        call RemoveSavedInteger(ht, this, key)
    endmethod
   
    // Remove all data from a Table instance
    method flush takes nothing returns nothing
        call FlushChildHashtable(ht, this)
    endmethod
   
    // local Table a = Table.create()
    static method create takes nothing returns Table
        local Table this = dex.list[0]
       
        if this == 0 then
            set more = more + 1
            set this = more
        else
            set dex.list[0] = dex.list[this]
            call dex.list.remove(this)
        endif
       
        debug set dex.list[this] = -1
        return this
    endmethod
   
    // Removes all data from a Table instance and recycles its index.
    //
    //     call a.destroy()
    //
    method destroy takes nothing returns nothing
        debug if dex.list[this] != -1 then
            debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
            debug return
        debug endif
       
        call this.flush()
       
        set dex.list[this] = dex.list[0]
        set dex.list[0] = this
    endmethod
   
endstruct
   
struct TableArray extends array
   
    //Returns a new TableArray to do your bidding. Simply use:
    //
    //    local TableArray ta = TableArray[array_size]
    //
    static method operator [] takes integer array_size returns TableArray
        local Table a = dex.size[array_size] //Get the unique recycle list for this array size
        local TableArray this = a[0]         //The last-destroyed TableArray that had this array size
       
        debug if array_size <= 0 then
            debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
            debug return 0
        debug endif
       
        if this == 0 then
            set less = less - array_size
            set this = less
        else
            set a[0] = a[this]  //Set the last destroyed to the last-last destroyed
            call a.remove(this) //Clear hash memory
        endif
       
        set dex.size[this] = array_size //This remembers the array size
        return this
    endmethod
   
    //Returns the size of the TableArray
    method operator size takes nothing returns integer
        return dex.size[this]
    endmethod
   
    //da[integer a].unit[integer b] = unit u
    //da[integer a][integer c] = integer d
    //
    //Inline-friendly when not running in debug mode
    //
    method operator [] takes integer key returns Table
        static if DEBUG_MODE then
            local integer i = this.size
            if i == 0 then
                call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
                return 0
            elseif key < 0 or key >= i then
                call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
                return 0
            endif
        endif
        return this + key
    endmethod
   
    //Destroys a TableArray without flushing it; assumed you'd call .flush()
    //if you want it flushed too. This is public so that if you are flushing
    //instances the whole time you don't waste efficiency when disposing the
    //TableArray.
    //
    method destroy takes nothing returns nothing
        local Table a = dex.size[this.size]
       
        debug if this.size <= 0 then
            debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
            debug return
        debug endif
       
        if a == 0 then
            //Create an array to index recycled instances with their array size
            set a = Table.create()
            set dex.size[this.size] = a
        endif
       
        call dex.size.remove(this) //Clear the array size from hash memory
       
        set a[this] = a[0]
        set a[0] = this
    endmethod
   
    //All you need to know about this one is that it won't hit the op limit.
    private static method clean takes Table a, integer end returns nothing
        local integer i = a + 5000
        if i < end then
            call clean.evaluate(i, end)
            set end = i
        endif
        loop
            call a.flush()
            set a = a + 1
            exitwhen a == end
        endloop
    endmethod
   
    //Flushes the TableArray and also destroys it. Doesn't get any more
    //similar to the FlushParentHashtable native than this.
    //
    method flush takes nothing returns nothing
        local integer end = this.size + this
        debug if this == end then
            debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
            debug return
        debug endif
        call clean.evaluate(this, end)
        call this.destroy()
    endmethod
   
endstruct
   
endlibrary
I have this in my map though
 
Level 38
Joined
Feb 27, 2007
Messages
4,951
I repeat: which line is causing that error?

Edit: Don't use Bribe's version. He didn't make it, Vexorian did-- find it on wc3campaigns. Bribe's version doesn't include HandleTables. If you switch to Vex's it should work.

If you insist on using this one add this line to all the other textmacro calls:
//! runtextmacro NEW_ARRAY("Handle", "handle")
 
Last edited:
Level 7
Joined
Nov 18, 2012
Messages
312
this line
JASS:
            if JCast__TARGET_TABLE.exists(un) then
gives error

but when i replace the table with vexorian table, i get error
JASS:
 set Base__t[i].string[-value]=char                      // this line
string is not a member of Table__GTable
 

Attachments

  • upload_2016-9-30_23-29-44.png
    upload_2016-9-30_23-29-44.png
    530.2 KB · Views: 52
Level 38
Joined
Feb 27, 2007
Messages
4,951
IDK what you're doing but I used the latest Vexorian's Table (Bribe's will not work because it doesn't have handletables!) and it compiles just fine. Check my attached map for the code I'm using (I literally copied Jcast from your post and Table/TimerUtils from their respective threads on wc3campaigns).
 

Attachments

  • Blank JNGP Map.w3x
    43.8 KB · Views: 91

Deleted member 219079

D

Deleted member 219079

Wow nice system, so it enables to set custom casting time and attach data to the cast? We have surprisingly little amount of systems approved atm.
 
Level 7
Joined
Nov 18, 2012
Messages
312
I think my problem occurs because bribe's table is being called in Nes's Save/Load, and i imported Nes's save/load for the game.
awkward
 
Level 7
Joined
Nov 18, 2012
Messages
312
Either I'll have no Jcast, or it'll be no Nes's Save/Load. LOL
JASS:
//Need save/load For..
//sort of strong security
string stringChars="1qazPOL2wsxIK3edcUJM4rfvYHN5tgbTGB6yhnRFV7ujmEDC8ikWSX9ol0pQAZ"
//maybe symbols too
string array IGN //because you can't copy another player's code
integer PlayerNumber //further hashing to randomize the code string which prevents the code to be easily guessed-because it should be unguessable
//What is intended to be saved
integer array HeroLv
integer Hero Id
integer arrayHero Inventory[1]
integer arrayHero Inventory[2]
integer arrayHero Inventory[3]
integer arrayHero Inventory[4]
integer arrayHero Inventory[5]
integer arrayHero Inventory[6]

//and can't be bothered to make by self because code is all open and crackable.
// First compress the number of stringChars
// just need encryption for (What is intended to be saved)
// generates a key
// but i suck at coding so
Any recommendation for jass save/load?
I've seen some like ..

GUI
AceHart= Save/Load Code, Yet Another | The Helper
Effane= Save/Load Code | The Helper
Kode= System - The Shortest Save/Load Code Ever | The Helper
diod= Demo Map - Preloader based save-load system + sync local data system | The Helper
This system can be used only if local files is allowed.

Jass
Dr Super Good= GUI save/load system?
Nestharus= JASS/Save and Load With Snippets.w3x at master · nestharus/JASS · GitHub
TriggerHappy= Codeless Save and Load (Multiplayer) - v1.2.2
 
Last edited:
Status
Not open for further replies.
Top