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

[Lua] What is bad with this code?

Status
Not open for further replies.
Level 24
Joined
Jun 26, 2020
Messages
1,853
I getting tired with the WE, I tried to improve the Lua version of my Unit Transmission system, but the game displays error when I wanna run the map, so what is wrong with this code?
Lua:
do -- version 1.1.0
    --[[
    Also requires the Lua Timer Utils. https://www.hiveworkshop.com/threads/lua-timerutils.316957/
    How it works:
        a value of type Transmission and use the function create like this:
    
            local curr = Transmission.create([force toForce, any data])

            "toForce" is the target force of the transmission
            "data" is if you wanna save a value during the transmission
            
        also you can set manually this values using:
            
            curr:SetTargetForce(force toForce) This not assing a force, just move the players of the input to the actually target force, so using a function that creates a force
                                         in the argument toForce will cause an object leak.
            
        you can also save a value to use during the transmission using:
    
            curr.Data = value
            
        if you wanna add or remove a player or a force to the target force just use the normal functions ForceAddPlayer, ForceRemovePlayer and the added ForceAddForce, ForceRemoveForce
        
       Then to add a dialogue line just do:
        
            curr:AddLine(unit whichUnit, playercolor color, string unitName, sound soundHandle, string message, integer timeType, real timeVal, boolean wait) returns TransmissionElements
            
          "whichUnit": The unit who do the dialogue line.
          "color": The color of the unit in the dialogue (if you set this value to nil so then, if you have the StoreUnitColor library the unit will have their actual color, if not, it will have their owner color).
          "unitName": The name of that unit.
          "soundHandle": The sound that will be played during the dialogue line.
          "message": What the unit will say.
          "timeType": Is like the GUI function, you can use 0 (Transmission.ADD), 1 (Transmission.SET), 2 (Transmission.SUB), another value will make the wait time to 0.
          "timeVal": Is like the GUI function, the normal duration of the transmission is the duration of the sound and you can edit the value depending of this and the previous value.
          "wait": Is like the GUI function, if this is true the next transmission will be wait the time depending of the previous two values.
        
        In case you don't wanna set a unit, but instead a unit-type you can use curr.AddLinebyId instead (default color BLACK)
    
        Also you can add actions between the lines using the function:
        
            curr:AddAction(real delay [, function actions])
            
          "delay": If you wanna add a delay to the next action or line.
          "actions": The function that will run, don't add nothing if you just wanna a delay.
          
        If you wanna the action run in the exact moment a line is happening just set the delay to 0.00 and put it right before the line.
        
        I have to say this steps are assinged an index by the order they were declared that is the number of the step.
    
        You can also add an action to the end of the transmission (this function will run yes or yes even you skip the transmission)  using:
    
            curr:AddEnd(function func)
            
        Where you can use the values curr = Transmission.instance to reffer to the actual instance, and with that use curr.Data if you stored one and curr.Skipped to detect
        if the cinematic was skipped but if was skipped in the last line this value will remain false.
            
        After set the lines the function
    
            curr:Start()
            
        To start the transmission, and to skip the transmission (the end function will run anyway) just press the ESC button,
        (this will skip all the transmissions where the player is) but if the implied force has more than one player the process will continue
        to the rest of players on that force (.toForce is empty). The transmission will end only if all the implied players skip the transmission (So if you use "All players"
        probably you never won't skip the transmission) but you can use the function Force(player p) to have a force just for 1 player (Don't destroy those forces).
    
        If you wanna you can also pause the transmission using:
            
            curr:Stop(boolean fadeout [, real delay])
            
            "fadeout" is to set you wanna end actual played sound with a fade out.
            "delay" is if you wanna the transmission resume itself after a while
            
        And to resume manually use:
    
            curr:Resume()
            
        Note: The transsmision and its elements are not stored after start it, they are recycled once the transmission ends.
    
        Other members:
    
            force toForce, to reffer the force to which it is addressed the transmission.
            force OriginalTargetForce, if you edited the force toForce, you can have the original force with this.
            player toPlayer, if the transmission is just for one player you can use this instead, in other case this will return the last added player. --(I don't know the order)
            integer LineNumber, is more precise if you use the method AddSceneActions. Same as Transmission.instance.Elements.NumberLine
            integer ActionNumber, is the number of the actions those are running. Same as Transmission.instance.Elements.NumberAction
            integer StepNumber, is the number of the step that is running (line or actions). Same as Transmission.instance.Elements.NumberStep
            boolean Paused, returns if the transmission is paused.
            TransmissionElements Elements, to reffer to the elements instance of the actual step.
            
            method AddSceneActions(function func)
                If you wanna add an action that runs everytime an step (line or action except the end) is runned, this also can be a replace of .AddAction in some
                moments if you compare the number of the step with StepNumber, to know if is a line or action use the member boolean IsLine
                and if is true you can use the member integer LineNumber to know the number of the actual line.
                This also runs before the action or line is runned, so you can use it to edit the current step.
                
            method RemoveSceneActions(function func)
                This remove the actions that you added before.
                
            If you wanna set the elements by separated you can use the member
            
            method AddStep(string whattype [, integer stepnumber]) returns TransmissionElements
                This add an step in the 'stepnumber' place, 'whattype' only can be "line" and "action" and move the next steps and renum them.
                The default value of stepnumber is the length quantity of steps added.
            
            method RemoveStep(integer stepnumber)
                This remove an step using the number of the step and move the next steps and renum them.
            
            After add the step the returned value have their own members
            
            unit Unit   -- This is the unit who will be marked during the transmission (not who will apear in the transmission).
            integer UnitType
            playercolor Color
            string Name
            sound Sound
            string Message
            real Time
            integer TimeType
            boolean WillWait
            real Delay
            
            integer NumberLine
            integer NumberAction
            integer NumberStep
            
            method SetActions(function func)     This replace all the actions
            method AddActions(function func)  This add action without affecting the added actions
            method GetActions() returns a Array<functions>
            
            But if you wanna use this members using the number of the step use their "ByIndex" methods (these are members of Transmission not of TransmissionElements)
            You have to do:
            
                curr:Set$Name of the member$ByIndex(integer stepnumber, $type of the member$ value)
                
                value = curr:Get$Name of the member$ByIndex(integer stepnumber)  (Except WillWait and AddActions)
                
            Example:
                
                local curr = Transmission.create()
                curr:AddStep("line")    --is the step 1
                curr:AddStep("action")  --is the step 2
                curr:SetUnitByIndex(1, <your unit>)
                curr:SetActionsByIndex(2, <your actions>)
                
                A replace of:
                
                local curr = Transmission.create()
                local what
                what = curr:AddStep("line")
                what:SetUnit(<your unit>)
                what = curr:AddStep("action")
                what:SetActions(<your actions>)
                
            But if you wanna save the number of lines you can set default values (before than create the steps)
            
            unit DefUnit
            integer DefUnitType
            playercolor DefColor
            string DefName
            sound DefSound
            string DefMessage
            real DefTime
            integer DefTimeType
            boolean DefWillWait
            real DefDelay
                
            Here are more members:
            
            Array<TransmissionElements> Lines
            Array<TransmissionElements> Actions
            Array<TransmissionElements> Steps
                
    ]]--
    
    --A function to use
    local What_Force = {}
    
    function IsForceEmpty(f)
        if f then
            local Temp = 0
            ForForce(f, function ()
                Temp = Temp + 1
            end)
            return Temp == 0
        end
        return true
    end
    
    function ForceAddForce(principal, other)
        if not principal or not other then
            return
        else
            ForForce(principal ,function ()
                ForceAddPlayer(other, GetEnumPlayer())
            end)
        end
    end
    
    function ForceRemoveForce(principal, other)
        if not principal or not other then
            return
        else
            ForForce(principal ,function ()
                ForceRemovePlayer(other,GetEnumPlayer())
            end)
        end
    end

    function Force(p)
        return What_Force[GetPlayerId(p)]
    end

    function CheckType(v, t)
        if type(t) ~= "string" then
            error("Is this a joke?", 3)
        end
        if type(v) == t then
            return true
        elseif math.type(v) == t then
            return true
        else
            if type(v) == "table" then
                local mt = getmetatable(t)
                local name = mt.__name
                if t == name then
                    return true
                end
            end
        end
        error("Wrong type, expected: " .. t, 3)
    end

    -- This are the elements of each line transmission
    TransmissionElementsMT = {
        --[[
            private:
            table actions
        ]]
        __index = function (t, k)
            -- Define only what fields can have your object
            if TransmissionElementsMT[k] then
                return TransmissionElementsMT[k]
            elseif k == "isline" or
                k == "NumberStep" then
                return rawget(t, k)
            elseif k == "Unit" or
                k == "UnitType" or
                k == "Color" or
                k == "Name" or
                k == "Sound" or
                k == "Message" or
                k == "TimeType" or
                k == "Time" or
                k == "WillWait" or
                k == "NumberLine" then
                if not rawget(t, "isline") then
                    error("This is an action", 2)
                end
                return rawget(t, k)
            elseif k == "Delay" or
                k == "NumberAction" then
                if rawget(t, "isline") then
                    error("This is a line", 2)
                end
                return rawget(t, k)
            else
                error("This field doesn't exist " .. tostring(k), 2)
            end
        end,
    
        __newindex = function (t, k , v)
            -- Define only what fields can have your object
            if TransmissionElementsMT[k] then
                error("You can't edit this method", 2)
            elseif (k == "NumberStep" and CheckType(v, "integer")) then
                rawset(t, k, v)
            elseif k == "Unit" or
                (k == "UnitType" and CheckType(v, "integer")) or
                k == "Color" or
                (k == "Name" and CheckType(v, "string")) or
                k == "Sound" or
                (k == "Message" and CheckType(v, "string")) or
                (k == "TimeType" and CheckType(v, "integer")) or
                (k == "Time" and CheckType(v, "number")) or
                (k == "WillWait" and CheckType(v, "boolean")) or
                (k == "NumberLine" and CheckType(v, "integer")) then
                if not rawget(t, "isline") then
                    error("This is an action", 2)
                end
                rawset(t, k, v)
            elseif (k == "Delay" and CheckType(v, "number")) or
                (k == "NumberAction" and CheckType(v, "integer")) then
                if rawget(t, "isline") then
                    error("This is a line", 2)
                end
                rawset(t, k, v)
            elseif k == "isline" then
                error("You can't edit a read-only field " .. tostring(k), 2)
            else
                error("You can't add new fields " .. tostring(k), 2)
            end
        end,
    
        __name = "TransmissionElements",
    
        __tostring = function (t)
            local result = ""
            if rawget(t, "isline") then
                result = result .. "Unit: " .. tostring(t.Unit) .. "\n"
                                .. "UnitType: " .. tostring(t.UnitType) .. "\n"
                                .. "Color: " .. tostring(t.Color) .. "\n"
                                .. "Name: " .. t.Name .. "\n"
                                .. "Sound: " .. tostring(t.Sound) .. "\n"
                                .. "Message" .. t.Message .. "\n"
                                .. "TimeType: " .. tostring(t.TimeType) .. "\n"
                                .. "Time: " .. t.Time .. "\n"
                                .. "WillWait: " .. t.WillWait .. "\n"
            else
                result = result .. "Delay: " .. tostring(t.Delay) .. "\n"
                for k, v in ipairs(rawget(t, "actions")) do
                    result = result .. "Action ".. k .. ": " .. tostring(v) .. "\n"
                end
            end
            return result
        end
    }

    function TransmissionElementsMT:SetActions(func)
        if rawget(self, "isline") then
            error("This is a line |cffff0000SetActions|r", 2)
        end
        rawset(self, "actions", {})
        if func then
            table.insert(rawget(self, "actions"), func)
        end
    end
    
    function TransmissionElementsMT:AddActions(func)
        if rawget(self, "isline") then
            error("This is a line |cffff0000AddActions|r", 2)
        -- Only add actions if func is not nil and self.actions was created previously
        elseif  not func then
            return
        elseif not rawget(self, "actions") then
            error("Why do you wanna add \"more\" actions if there isn't even a trigger with actions?", 2)
        else
            table.insert(rawget(self, "actions"), func)
        end
    end
        
    function TransmissionElementsMT:GetActions()
        if rawget(self, "isline") then
            error("This is a line |cffff0000GetActions|r", 2)
        end
        return rawget(self, "actions")
    end

    TransmissionElements = setmetatable({

        create = function (whattype)
            local self = setmetatable({}, TransmissionElementsMT)
            
            if whattype == "line" then
                rawset(self, "isline", true)
            elseif whattype == "action" then
                rawset(self, "isline", false)
            else
                error("Invalid type.", 2)
            end
            
            return self
        end,
    
        create_action = function (delay, func)
            local self = TransmissionElements.create("action")
            
            -- Now I can store functions :D
            if not rawget(self, "actions") then
                rawset(self, "actions", {})
            end
            if func then
                table.insert(rawget(self, "actions"), func)
            end
            self.Delay = delay
            
            return self
        end,
    
        create_line = function (whichUnit, whichColor, unitName, soundHandle, message, timeType, timeVal, wait)
            local self = TransmissionElements.create("line")
            
            self.Unit = whichUnit
            self.Name = unitName
            self.Sound = soundHandle
            self.Message = message
            self.TimeType = timeType
            self.Time = timeVal
            self.WillWait = wait
            if not whichUnit then
                self.UnitType = 0
                if not whichColor then
                    if LIBRARY_StoreUnitColor then
                        self.Color = PLAYER_COLOR_BLACK
                    else
                        self.Color = ConvertPlayerColor(PLAYER_NEUTRAL_AGGRESSIVE)
                    end
                else
                    self.Color = whichColor
                end
            else
                self.UnitType = GetUnitTypeId(whichUnit)
                if not whichColor then
                    if LIBRARY_StoreUnitColor then
                        self.Color = GetUnitColor(whichUnit)
                    else
                        self.Color = GetPlayerColor(GetOwningPlayer(whichUnit))
                    end
                else
                    self.Color = whichColor
                end
            end
            
            return self
        end
    }, {
        __index = function (t, k)
            if k == "create" or
                k == "create_action" or
                k == "create_line" then
                return rawget(t, k)
            else
                error("This field don't exist " .. tostring(k), 2)
            end
        end,

        __newindex = function (t, k, v)
            -- Define only what fields can have your class
            if true then
                error("You can't add new fields " .. tostring(k), 2)
            end
        end,
    
        __name = "TransmissionElements",
    
        __tostring = function (t)
            return "Class: TransmissionElements"
        end
    })

    --*****************************************************
    --********The actual struct of the transmission********
    --*****************************************************

    local LocalPlayer = nil

    local AllInstances = {}
    for i = 0, PLAYER_NEUTRAL_AGGRESSIVE do
        AllInstances[Player(i)] = {}
    end

    TransmissionMT = {
        --[[
            private
            boolean paused
            TransmissionElements elements
            boolean skipped
            sound played
            Array<functions> final
            timer t
            integer current
            integer actual_line
            integer actual_action
            integer actual_step
            boolean ended
            Array<functions> scene
        ]]
        __index = function (t, k)
            -- Define only what fields can have your object
            if TransmissionMT[k] then
                return TransmissionMT[k]
            elseif k == "toPlayer" or
                k == "toForce" or
                k == "OriginalTargetForce" or
                k == "DefUnit" or
                k == "DefUnitType" or
                k == "DefColor" or
                k == "DefName" or
                k == "DefSound" or
                k == "DefMessage" or
                k == "DefTime" or
                k == "DefTimeType" or
                k == "DefWillWait" or
                k == "DefDelay" or
                k == "Data" or
                k == "Steps" or
                k == "Lines" or
                k == "Actions" then
                return rawget(t, k)
            elseif k == "Paused" then
                return rawget(t, "paused")
            elseif k == "Skipped" then
                return rawget(t, "skipped")
            elseif k == "Elements" then
                return rawget(t, "elements")
            elseif k == "IsLine" then
                return rawget(rawget(t, "elements"), "isline")
            elseif k == "StepNumber" then
                return rawget(t, "elements").NumberAction
            elseif k == "ActionNumber" then
                return rawget(t, "elements").NumberAction
            elseif k == "LineNumber" then
                return rawget(t, "elements").NumberLine
            else
                error("This field doesn't exist " .. tostring(k), 2)
            end
        end,
    
        __newindex = function (t, k , v)
            -- Define only what fields can have your object
            if TransmissionMT[k] then
                error("You can't edit this method")
            elseif k == "toPlayer" or
                k == "toForce" or
                k == "OriginalTargetForce" or
                k == "DefUnit" or
                (k == "DefUnitType" and CheckType(v, "integer")) or
                k == "DefColor" or
                (k == "DefName" and CheckType(v, "string")) or
                k == "DefSound" or
                (k == "DefMessage" and CheckType(v, "string")) or
                (k == "DefTime" and CheckType(v, "number")) or
                (k == "DefTimeType" and CheckType(v, "integer")) or
                (k == "DefWillWait" and CheckType(v, "boolean")) or
                (k == "DefDelay" and CheckType(v, "number")) or
                k == "Data" or
                (k == "Steps" and CheckType(v, "table")) or
                (k == "Lines" and CheckType(v, "table")) or
                (k == "Actions" and CheckType(v, "table")) then
                rawset(t, k, v)
            elseif k == "Paused" or
                k == "Skipped" or
                k == "Elements" or
                k == "IsLine" or
                k == "StepNumber" or
                k == "ActionNumber" or
                k == "LineNumber" then
                error("You can't edit a read-only field " .. tostring(k), 2)
            else
                error("You can't add new fields " .. tostring(k), 2)
            end
        end,

        __len = function (t)
            return #t.Steps
        end,
    
        __name = "Transmission",

        __tostring = function (t)
            local result = ""
            for _, v in ipairs(t.Steps) do
                result = result .. tostring(v)
            end
            return result
        end
    }
    -- When the transmission ends
    
    local function finish(self)
        ReleaseTimer(rawget(self, "t"))
        rawset(self, "ended", true)
        if rawget(self, "final") then
            Transmission.instance = self
            for _, func in ipairs(rawget(self, "final")) do
                func()
            end
            Transmission.instance = nil
            rawset(self, "final", nil)
        end
        ForForce(self.toForce, function ()
            for k, v in ipairs(AllInstances[GetEnumPlayer()]) do
                if v == self then
                    table.remove(AllInstances[GetEnumPlayer()], k)
                    break
                end
            end
        end)
        DestroyForce(self.OriginalTargetForce)
        DestroyForce(self.toForce)
        self.Steps = nil
        self.Lines = nil
        self.Actions = nil
        rawset(self, "scene", nil)
        rawset(self, "elements", nil)
        self.Data = nil
        rawset(self, "played", nil)
        self.toForce = nil
        self.toPlayer = nil
        self.t = nil
    end
        
    local function what_call(self)
        rawset(self, "current", rawget(self, "current") + 1)
        rawset(t, "elements", self.Steps[rawget(self, "current")])
        if not rawget(self, "elements") or IsForceEmpty(self.toForce) then
            -- If the cinematic was skipped just in the last line it won't be counted as skipped
            rawset(self, "skipped", IsForceEmpty(self.toForce) and rawget(self, "elements"))
            finish(self)
        else
            if rawget(rawget(self, "elements"), "isline") then
                self:cinematic_line()
            else
                self:cinematic_actions()
            end
        end
    end
    
    local function callback()
        what_call(GetTimerData())
    end

    -- Where the magic happens
    function TransmissionMT:cinematic_line()
        local alpha = 0
        local delay = 0.00
        local what = rawget(self, "elements")
        
        if rawget(self, "scene") then
            Transmission.instance = self
            for _, func in ipairs(rawget(self, "scene")) do
                func()
            end
            Transmission.instance = nil
        end
        
        rawset(self, "played", what.Sound)
        bj_lastTransmissionDuration = GetTransmissionDuration(rawget(self, "played"), what.TimeType, what.Time)
        
        if IsPlayerInForce(LocalPlayer, self.toForce) then
            if rawget(self, "played") then
                StartSound(rawget(self, "played"))
            end
            SetCinematicScene(what.UnitType, what.Color, what.Name, what.Message, bj_lastTransmissionDuration + bj_TRANSMISSION_PORT_HANGTIME, bj_lastTransmissionDuration)
            alpha = 255
        end
        if what.Unit then
            UnitAddIndicator(what.Unit, 255, 255, 255, alpha)
        end
        
        if what.WillWait then
            delay = bj_lastTransmissionDuration
        end
        
        if delay > 0.00 then
            TimerStart(rawget(self, "t"), delay, false, callback)
        else
            what_call(self)
        end
    end
    
    function TransmissionMT:cinematic_actions()
        local what = rawget(self, "elements")
        
        Transmission.instance = self
        if rawget(self, "scene") then
            for _, func in ipairs(rawget(self, "scene")) do
                func()
            end
        end
        pcall(function ()
            for _, func in ipairs(what:GetActions()) do
                func()
            end
        end)
        Transmission.instance = nil
        
        if what.Delay > 0.00 then
            TimerStart(rawget(self, "t"), what.Delay, false, callback)
        else
            what_call(self)
        end
    end

    function TransmissionMT:Resume()
        if rawget(self, "paused") then
            rawset(self, "paused", false)
            ResumeTimer(rawget(self, "t"))
            if IsPlayerInForce(LocalPlayer, self.toForce) then
                StartSound(rawget(self, "played"))
            end
            SetSoundOffsetBJ(TimerGetElapsed(rawget(self, "t")), rawget(self, "played")) -- In case of desync
        end
    end

    function TransmissionMT:Stop(fadeout, delay)
        CheckType(fadeout, "boolean")
        if delay ~= nil then
            CheckType(delay, "number")
        end
        rawset(self, "paused", true)
        PauseTimer(rawget(self, "t"))
        StopSound(rawget(self, "played"), false, fadeout)
        if delay then
            if delay>0.00 then
                TimerStart(NewTimer(), delay, false, function ()
                    self:Resume()
                    ReleaseTimer()
                end)
            else
                self:Resume()
                warn("Why do you even use this method?, Ay.")
            end
        end
    end
    
    function TransmissionMT:Start()
        -- If there is not a line or action so it just go to the end
        rawset(self, "current", 0)
        rawset(self, "elements", nil)
        what_call(self)
    end
        
    -- Now I can save functions :D
    function TransmissionMT:AddEnd(func)
        CheckType(func, "function")
        if not rawget(self, "final") then
            rawset(self, "final", {})
        end
        table.insert(rawget(self, "final"), func)
    end
    
    -- To add an action everytime a line or action is runned
    function TransmissionMT:AddSceneActions(func)
        CheckType(func, "function")
        if not rawget(self, "scene") then
            rawset(self, "scene", {})
        end
        table.insert(rawget(self, "scene"), func)
    end
    
    -- But if you wanna remove it
    function TransmissionMT:RemoveSceneActions(actions)
        table.remove(rawget(self, "scene"), actions)
    end

    --To set and get the values using their step position

    function TransmissionMT:SetUnitByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        self.Steps[stepnumber].Unit = value
    end
    
    function TransmissionMT:GetUnitByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Unit
    end

    function TransmissionMT:SetUnitTypeByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        self.Steps[stepnumber].UnitType = value
    end
    
    function TransmissionMT:GetUnitTypeByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].UnitType
    end

    function TransmissionMT:SetColorByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        self.Steps[stepnumber].Color = value
    end
    
    function TransmissionMT:GetColorByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Color
    end

    function TransmissionMT:SetNameByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "string")
        self.Steps[stepnumber].Name = value
    end
    
    function TransmissionMT:GetNameByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Name
    end

    function TransmissionMT:SetSoundByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        self.Steps[stepnumber].Sound = value
    end
    
    function TransmissionMT:GetSoundByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Sound
    end

    function TransmissionMT:SetMessageByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "string")
        self.Steps[stepnumber].Message = value
    end
    
    function TransmissionMT:GetMessageByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Message
    end

    function TransmissionMT:SetTimeTypeByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "integer")
        self.Steps[stepnumber].TimeType = value
    end
    
    function TransmissionMT:GetTimeTypeByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].TimeType
    end

    function TransmissionMT:SetTimeByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "number")
        self.Steps[stepnumber].Time = value
    end
    
    function TransmissionMT:GetTimeByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Time
    end

    function TransmissionMT:SetWillWaitByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "boolean")
        self.Steps[stepnumber].WillWait = value
    end
    
    function TransmissionMT:WillWaitByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].WillWait
    end

    function TransmissionMT:SetDelayByIndex(stepnumber, value)
        CheckType(stepnumber, "integer")
        CheckType(value, "number")
        self.Steps[stepnumber].Delay = value
    end
    
    function TransmissionMT:GetDelayByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        return self.Steps[stepnumber].Delay
    end
    
    function TransmissionMT:SetActionsByIndex(stepnumber, func)
        CheckType(stepnumber, "integer")
        CheckType(func, "function")
        self.Steps[stepnumber].SetActions(func)
    end
    
    function TransmissionMT:GetActionsByIndex(stepnumber)
        CheckType(stepnumber, "integer")
        self.Steps[stepnumber].GetActions()
    end
    
    function TransmissionMT:AddActionsByIndex(stepnumber, func)
        CheckType(stepnumber, "integer")
        CheckType(func, "function")
        self.Steps[stepnumber].AddActions(func)
    end
        
    --If you wanna remove a step
    function TransmissionMT:RemoveStep(stepnumber)
        CheckType(stepnumber, "integer")

        local what = table.remove(self.Steps, stepnumber)
        
        if rawget(what, "isline") then
            for k, v in ipairs(self.Lines) do
                if what == v then
                    table.remove(self.Lines, k)
                    break
                end
            end
            rawset(self, "actual_line", #self.Lines)
            for j = stepnumber, rawget(self, "actual_line") do
                self.Lines[j].NumberLine = self.Lines[j].NumberLine - 1
            end
        else
            for k, v in ipairs(self.Actions) do
                if what == v then
                    table.remove(self.Actions, k)
                    break
                end
            end
            rawset(self, "actual_action", #self.Actions)
            for j = stepnumber, rawget(self, "actual_action") do
                self.Actions[j].NumberAction = self.Steps[j].NumberAction - 1
            end
        end
        rawset(self, "actual_step", #self.Steps)
        for j = stepnumber, rawget(self, "actual_step") do
            self.Steps[j].NumberStep = self.Steps[j].NumberStep - 1
        end
    end

    -- To set a line with all the needed values (at the beggining)
        
    function TransmissionMT:AddLine(whichUnit, whichColor, unitName, soundHandle, message, timeType, timeVal, wait)
        CheckType(unitName, "string")
        CheckType(message, "string")
        CheckType(timeType, "integer")
        CheckType(timeVal, "number")
        CheckType(wait, "boolean")

        local what = TransmissionElements.create_line(whichUnit, whichColor, unitName, soundHandle, message, timeType, timeVal, wait)
        table.insert(self.Lines, what)
        rawset(self, "actual_line", #self.Lines)
        what.NumberLine = rawget(self, "actual_line")
        table.insert(self.Steps, what)
        rawset(self, "actual_step", #self.Steps)
        what.NumberStep = rawget(self, "actual_step")
        
        return what
    end
    
    function TransmissionMT:AddLineById(id, whichColor, unitName, soundHandle, message, timeType, timeVal, wait)
        CheckType(id, "integer")
        CheckType(unitName, "string")
        CheckType(message, "string")
        CheckType(timeType, "integer")
        CheckType(timeVal, "number")
        CheckType(wait, "boolean")

        local what = self:AddLine(nil, whichColor, unitName, soundHandle, message, timeType, timeVal, wait)
        what.UnitType = id
        
        return what
    end
    
    -- To add an action and (maybe) a delay to the next action or line
    function TransmissionMT:AddAction(delay, actions)
        CheckType(delay, "number")
        if actions ~= nil then
            CheckType(actions, "function")
        end

        local what = TransmissionElements.create_action(delay, actions)
        table.insert(self.Actions, what)
        rawset(self, "actual_action", #self.Actions)
        table.insert(self.Steps, what)
        rawset(self, "actual_step", #self.Steps)
        what.NumberStep = rawget(self, "actual_step")
        
        return what
    end

    function TransmissionMT:AddStep(whattype, stepnumber)
        CheckType(whattype, "string")
        if stepnumber ~= nil then
            CheckType(stepnumber, "integer")
        end

        local node = TransmissionElements.create(whattype)
    
        if whattype == "line" then
            node.Unit = self.DefUnit
            node.UnitType = self.DefUnitType or 0
            node.Color = self.DefColor
            node.Name = self.DefName or ""
            node.Sound = self.DefSound
            node.Message = self.DefMessage or ""
            node.Time = self.DefTime or 0.00
            node.TimeType = self.DefTimeType or 1
            node.WillWait = self.DefWillWait
            if stepnumber then
                table.insert(self.Lines, node)
                rawset(self, "actual_line", #self.Lines)
                node.NumberLine = self.actual_line
            else
                local i = 1
                for j = stepnumber, 0, -1 do
                    if rawget(self.Steps[j], "isline") == true then
                        i = j + 1
                        break
                    end
                end
                table.insert(self.Lines, i, node)
                rawset(self, "actual_line", #self.Lines)
                for j = i + 1, rawget(self, "actual_line") do
                    self.Lines[j].NumberLine = self.Lines[j].NumberLine + 1
                end
                node.NumberLine = i
            end
        else
            node.Delay = self.DefDelay or 0.00
            if stepnumber then
                table.insert(self.Actions, node)
                rawset(self, "actual_action", #self.Actions)
                node.NumberLine = rawget(self, "actual_action")
            else
                local i = 1
                for j = stepnumber, 0, -1 do
                    if rawget(self.Steps[j], "isline") == false then
                        i = j + 1
                        break
                    end
                end
                table.insert(self.Actions, i, node)
                rawset(self, "actual_action", #self.Actions)
                for j = i + 1, rawget(self, "actual_action") do
                    self.Actions[j].NumberAction = self.Actions[j].NumberAction + 1
                end
                node.NumberAction = i
            end
        end
        
        if stepnumber then
            table.insert(self.Steps, stepnumber, node)
            rawset(self, "actual_step", #self.Steps)
            for j = stepnumber, rawget(self, "actual_step") do
                self.Steps[j].NumberStep = self.Steps[j].NumberStep + 1
            end
            node.NumberStep = stepnumber
        else
            table.insert(self.Steps, node)
            rawset(self, "actual_step", #self.Steps)
            node.NumberStep = rawget(self, "actual_step")
        end
        
        return node
    end
        
    -- You can edit the target force and the data

    function TransmissionMT:SetTargetForce(toForce)
        if toForce and not IsForceEmpty(toForce) then
            ForForce(toForce, function ()
                local p = GetEnumPlayer()
                self.toPlayer = p
                ForceAddPlayer(self.toForce, p)
                ForceAddPlayer(self.OriginalTargetForce, p)
                table.insert(AllInstances[p], self)
            end)
        end
    end

    Transmission = setmetatable({
        ADD = bj_TIMETYPE_ADD, -- 0
        SET = bj_TIMETYPE_SET, -- 1
        SUB = bj_TIMETYPE_SUB, -- 2
    }, {
        __index = function (t, k)
            if k == "create" or
                k == "ADD" or
                k == "SET" or
                k == "SUB" or
                k == "instance" then
                return rawget(t, k)
            else
                error("This field doesn't exist " .. tostring(k), 2)
            end
        end,

        __newindex = function (t, k, v)
            -- Define only what fields can have your class
            if k == "ADD" or
                k == "SET" or
                k == "SUB" then
                error("This value is a constant " .. tostring(k), 2)
            elseif k == "instance" then
                error("You can't edit a read-only field " .. tostring(k), 2)
            else
                error("You can't add new fields " .. tostring(k), 2)
            end
        end,
    
        __name = "Transmission",
    
        __tostring = function (t)
            return "Class: Transmission"
        end
    })

    function Transmission.create(toForce, data)
        if toForce and not data then
            error("Insufficient arguments", 2)
        end
        local self = setmetatable({}, TransmissionMT)
        rawset(self, "skipped", false)
        rawset(self, "paused", false)
        self.toForce = CreateForce()
        self.OriginalTargetForce = CreateForce()
        rawset(self, t, NewTimer(self))
        rawset(self, "actual_line", 0)
        rawset(self, "actual_action", 0)
        rawset(self, "actual_step", 0)
        rawset(self, "ended", false)

        self.Steps = {}
        self.Lines = {}
        self.Actions = {}

        if toForce and data then
            if not IsForceEmpty(toForce) then
                ForForce(toForce, function ()
                    local p = GetEnumPlayer()
                    self.toPlayer = p
                    ForceAddPlayer(self.toForce, p)
                    ForceAddPlayer(self.OriginalTargetForce, p)
                    table.insert(AllInstances[p], self)
                end)
            end
            self.Data = data
        end

        return self
    end

    -- To add a player or force to the target force just use ForceAddPlayer(this.toForce, <your player>) or the added ForceAddForce(this.toForce, <your force>)
    
    local oldinit = InitBlizzard
    
    function InitBlizzard()
        local t = CreateTrigger()
        for i = 0, PLAYER_NEUTRAL_AGGRESSIVE do
            What_Force[i] = GetForceOfPlayer(Player(i)) -- To use it if you wanna send the transmission just for 1 player
            TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
        end
        -- If a player skips cinematic he will be removed from every instance trasnmission where is in
        TriggerAddAction(t, function ()
            local p = GetTriggerPlayer()
            for _, self in ipairs(AllInstances[p]) do
                if IsPlayerInForce(p, self.toForce) then
                    ForceRemovePlayer(self.toForce, p)
                    if p == LocalPlayer then
                        -- I don't know if this is free of desync (I checked and there is not desync yet)
                        EndCinematicScene()
                        if rawget(self, "played") then
                            StopSound(rawget(self, "played"), false, true)
                        end
                    end
                end
                if IsForceEmpty(self.toForce) then
                    PauseTimer(rawget(self, "t"))
                    TimerStart(rawget(self, "t"), RMinBJ(bj_TRANSMISSION_PORT_HANGTIME, TimerGetRemaining(rawget(self, "t"))), false, callback)
                end
            end
            AllInstances[p] = {}
        end)
        -- --
        LocalPlayer = GetLocalPlayer()
        ForceCinematicSubtitles(true)
        -- --
        oldinit()
    end

end
 
Status
Not open for further replies.
Top