Nothing you find in Mark Brinton's scripts will help as his signals don't communicate with mine.
If you feel courageous, you can spend the time on combining the External Arm with the External Text-based Indicator.
Just copy the text here to separate files for a start. (The forum does not like .lua attachments in posts. But it has this "copy all" links in code blocks that is really handy.)
FP External Arms.lua:
- Code: Select all
--------------------------------------------------------------------------------------
-- One or more arms (or disks) in a separate slave object that solely moves as ordered by the master stop signal
-- They are specified in a two-dimensional array with dimensions doll number and
-- SEM_CHILD_NAME/SEM_PROCEED_ANIM/SEM_BLOCKED_ANIM. This should facilitate copying over from standard signals
-- It is the same arrangement as for splitting distants.
-- Call-on functionality is not supported currently.
-- Configuration, i.e., remapping of dolls is not supported. They can be remapped by the virtual signal
-- controlling this external signal
require "Assets/AndiS/FPSignals/scripts/Shared by All.out"
function DefaultInitialise ()
InitialiseId()
-- HardDebug("DefaultInitialise", "starting")
InitialiseConstantsAndArrays()
MAX_HOME = 9
gConnectedLink = 0
-- initialise it the old way for backward compatibility
gArmTable = {}
for i = 1, 9 do
gArmTable[i] = {}
gArmTable[i][SEM_PROCEED_ANIM] = "Clear"
gArmTable[i][SEM_BLOCKED_ANIM] = "Stop"
gArmState[i] = -1
end
armMotion = false
armsInMotion = 0
gInitialised = false -- has the route finished loading yet?
Call( "BeginUpdate" )
ResetSignalState ()
-- HardDebug("DefaultInitialise", "done")
end
function ResetSignalState ( )
gInitialised = false -- induce resending of SIGNAL_I_AM_ARM
end
function ArmExists(dollIndex)
if gArmTable[dollIndex] == nil then
return false
else
return gArmTable[dollIndex][SEM_CHILD_NAME] ~= nil
end
end
function SetArmState(newState, routeIndex)
-- Initial checks: Make sure the arm exists before trying to do anything to it!
-- Plus: be sure that this call is not just redundant
-- Base copied from semaphore distant
if ArmExists(routeIndex) then -- currently redundant check
if newState == gArmState[routeIndex] then
RasterLog("SetArmState", routeIndex .. " " .. printNil(gArmState[routeIndex]) .. " = " ..
printNil(newState) .. " nothing to do")
else
RasterLog("SetArmState", animName(newState) .. " " .. routeIndex .. " " .. printNil(gArmState[routeIndex]) ..
" -> " ..
printNil(newState) .. " " .. printBoolean(armMotion) .. " " .. printNil(armsInMotion))
if newState == ANIMSTATE_ANIMTOOPEN then -- want to open
if gArmState[routeIndex] == ANIMSTATE_CLOSED then -- normal case: closed now
armsInMotion = armsInMotion + 1
if not armMotion then -- first arm animation
UpdateLog("SetArmState", "BeginUpdate" )
Call( "BeginUpdate" )
end
gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN
if startOpening ~= nil then
startOpening(routeIndex)
end
elseif gArmState[routeIndex] == ANIMSTATE_ANIMTOCLOSED then -- currently closing -> gross error
-- if gInitialised then
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] starting to open while closing") -- reset as an emergency measure
-- gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN
-- return false
-- else
gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN -- before actually running, overwriting does not hurt
-- end
end -- if ANIMSTATE_OPEN or ANIMSTATE_ANIMTOOPEN,
-- no action is required
elseif newState == ANIMSTATE_ANIMTOCLOSED then -- want to close
if gArmState[routeIndex] == ANIMSTATE_OPEN then -- normal case: closed now
armsInMotion = armsInMotion + 1
if not armMotion then -- first arm animation
UpdateLog("SetArmState", "BeginUpdate" )
Call( "BeginUpdate" )
end
gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED
if startClosing ~= nil then
startClosing(routeIndex)
end
elseif gArmState[routeIndex] == ANIMSTATE_ANIMTOOPEN then -- currently opening -> gross error
-- if gInitialised then
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] starting to close while opening") -- reset as an emergency measure
-- gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED
-- return false
-- else
gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED -- before actually running, overwriting does not hurt
-- end
end -- if ANIMSTATE_CLOSED or ANIMSTATE_ANIMTOCLOSED,
-- no action is required
elseif newState == ANIMSTATE_OPEN then -- opening complete
if gArmState[routeIndex] == ANIMSTATE_ANIMTOOPEN then -- normal case: open now
armsInMotion = armsInMotion - 1 -- reaction to armsInMotion == 0 in Update
elseif gArmState[routeIndex] ~= nil
and gArmState[routeIndex] ~= ANIMSTATE_OPEN then
-- could be a result of quick changes to signal state
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] ~= ANIMSTATE_ANIMTOOPEN")
return false
end
gArmState[routeIndex] = ANIMSTATE_OPEN
if finishOpening ~= nil then
finishOpening(routeIndex)
end
elseif newState == ANIMSTATE_CLOSED then --closing complete
if gArmState[routeIndex] == ANIMSTATE_ANIMTOCLOSED then -- normal case: closed now
armsInMotion = armsInMotion - 1 -- reaction to armsInMotion == 0 in Update
elseif gArmState[routeIndex] ~= ANIMSTATE_CLOSED
and gArmState[routeIndex] ~= nil then -- bad surprise
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] ~= ANIMSTATE_ANIMTOCLOSED")
return false
end
gArmState[routeIndex] = ANIMSTATE_CLOSED
if finishClosing ~= nil then
finishClosing(routeIndex)
end
end
end
else
RasterLog("SetArmState", routeIndex .. " arm does not exist")
end
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
-- don't care about trains
end
--------------------------------------------------------------------------------------
-- UPDATE
--
function Update (time)
if gInitialised then -- normal operation: carry on the animation until it is complete, then set animState accordingly
if armsInMotion == 0 then -- no animations running
if armMotion then -- we were active until recently
armMotion = false -- nothing more to do
end -- if armMotion is false, Update is called for another reason
else -- step along the current animations
armMotion = true -- remember we are animating for the time point when we just completed it
for i = 1, MAX_DISTANT do
if ArmExists(i) then
local animState = gArmState[i]
if (animState == ANIMSTATE_ANIMTOOPEN) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_OPEN, i )
end
elseif (animState == ANIMSTATE_ANIMTOCLOSED) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_PROCEED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_BLOCKED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_CLOSED, i )
end
end
end
end
end
else -- first call to Update
--SimpleSendTestMessageWithinLinks() -- makes assumptions about numbered links that are not true
for i = 1, MAX_DISTANT do
if ArmExists(i) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], 0 )
gArmState[i] = ANIMSTATE_CLOSED
end
end
-- not sure this is neeeded:
-- Call("*:Reset", stopAnim )
-- Call( "*:AddTime", clearAnim, 0 )
-- gAnimState = ANIMSTATE_CLOSED
-- not in distant - forgotten there?
-- anyone still using this ??
-- if yes, add index and loop
if finishClosing ~= nil then -- needed to get the lights right initially (for AP)
for i = 1, MAX_DISTANT do
finishClosing(i)
end
end
indices = ""
for dollIndex=1, 9 do
if ArmExists(dollIndex) then
indices = indices .. dollIndex
end
end
for link = 0, gLinkCount-1 do
SendBackwardFromLink(SIGNAL_I_AM_ARM, indices, link)
end
gInitialised = true
end
if armsInMotion == 0 and not armMotion and gInitialised then
UpdateLog("Animations", "EndUpdate" )
Call( "EndUpdate" )
end
end
-------------------------------------------------------------------------------------
-- ON SIGNAL MESSAGE
-- Shunt signals just forward the signal messages on to other signals
--
function OnSignalMessage( message, parameter, direction, linkIndex )
MessageLog( message, parameter, direction, linkIndex )
if (message == RESET_SIGNAL_STATE) then
ResetSignalState()
elseif (message == OPEN_ARM) then
if ArmExists(0 + parameter) then
SetArmState(ANIMSTATE_ANIMTOOPEN, 0 + parameter)
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
elseif (message == CLOSE_ARM) then
if ArmExists(0 + parameter) then
SetArmState(ANIMSTATE_ANIMTOCLOSED, 0 + parameter)
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
elseif message == OPEN_LOG then
OpenLog(parameter, direction, linkIndex)
-- Ignore initialisation messages from trains straddling a link - these will have the "DoNotForward" parameter
-- Otherwise forward on the message
-- this includes TEST_MESSAGE which is not treated in any way here
elseif parameter ~= "DoNotForward" then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
FP External Text-based indicator.lua:
- Code: Select all
--------------------------------------------------------------------------------------
-- A theater box type indicator in a separate slave object controlled by the master stop signal
-- The current implementation is based on texture set switching.
--
require "Assets/AndiS/FPSignals/scripts/Shared by All.out"
function Initialise ()
InitialiseId()
InitialiseConstantsAndArrays()
gConnectedLink = 0
gAnimState = -1
gInitialised = false -- has the route finished loading yet?
ResetSignalState ()
end
function ResetSignalState ( )
gId = Call ("GetId") -- TODO: insert parsing for special codes in ID here
if gId == nil or gId == "" then
ErrorPrint("ResetSignalState", "Indicator without ID shows nothing")
gInitialised = true -- do nothing on update (a bit redundant since BeginUpdate is not called)
else
gInitialised = false -- induce resending of SIGNAL_I_AM_ARM
Call( "BeginUpdate" )
end
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
-- don't care about trains
end
--------------------------------------------------------------------------------------
-- UPDATE
--
function Update (time)
if gInitialised then
else
SimpleSendTestMessageWithinLinks()
-- new 21 Sept 2017
if closedCharacter == nil then
Call( "SetText", "", 0 )
else
Call( "SetText", closedCharacter, 0 )
end
Call( "SendSignalMessage", SIGNAL_I_AM_INDICATOR, gId, -1, 1, 0 )
gInitialised = true
Call ("EndUpdate")
end
end
-------------------------------------------------------------------------------------
-- ON SIGNAL MESSAGE
-- Shunt signals just forward the signal messages on to other signals
--
function OnSignalMessage( message, parameter, direction, linkIndex )
MessageLog( message, parameter, direction, linkIndex )
if (message == RESET_SIGNAL_STATE) then
ResetSignalState()
elseif (message == SHOW) then
-- new 21 Sept 2017
if closedCharacter == nil or parameter ~= "" then
Call( "SetText", parameter, 0 )
else
Call( "SetText", closedCharacter, 0 )
end
elseif message == OPEN_LOG then
OpenLog(parameter, direction, linkIndex)
-- Ignore initialisation messages from trains straddling a link - these will have the "DoNotForward" parameter
-- Otherwise forward on the message
elseif parameter ~= "DoNotForward" then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
The external arms is an afterthought for those cases, where a signal reads to two parallel tracks. Since you can only have one unnumbered link 0, you need two invisible "master signals" in the two tracks and a "slave signal" that is the External Arms that has a link in each track and listens for commands that to do and animate the arms of a single signal shape placed somewhere in proximity of the scene. I only spell this out so you know why you should ignore most of the stuff that does not make sense now.
The aim is a external arms script that interfaces with the main signal like an indicator, not like the external arms script that is the starting point.
The indicator script is dead simple, but it is crucial to keep all the lines except those mentioned below to maintain all sorts of functionalities not discussed here.
We start from the indicator script.
In function Update, we keep almost nothing:
- Code: Select all
function Update (time)
if gInitialised then
-- big chunk of copied code will be inserted here !
else
SimpleSendTestMessageWithinLinks()
-- small chunk of copied code goes here
Call( "SendSignalMessage", SIGNAL_I_AM_INDICATOR, gId, -1, 1, 0 )
gInitialised = true
Call ("EndUpdate")
end
-- extra stuff at end goes here
end
The small chunk is quite simple. In the External Arms script, we steal this:
- Code: Select all
for i = 1, MAX_DISTANT do
if ArmExists(i) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], 0 )
gArmState[i] = ANIMSTATE_CLOSED
end
end
-- the following is an afterthought explained in the end
indices = ""
for dollIndex=1, 9 do
if ArmExists(dollIndex) then
indices = indices .. dollIndex
end
end
I believe it is all you need there.
The "extra stuff at end" is this little bit:
- Code: Select all
if armsInMotion == 0 and not armMotion and gInitialised then
UpdateLog("Animations", "EndUpdate" )
Call( "EndUpdate" )
end
I go some extra mile to get rid of some edge cases. I forgot the edge cases, I just remember the frustration.
Now for the big chunk that operates the arms. As you may have read in the original developer documentation, Update gets called often so you can inch the animations forward. This is done in a special Kuju way that I don't want to comment on.
The big chunk reads like this:
- Code: Select all
if armsInMotion == 0 then -- no animations running
if armMotion then -- we were active until recently
armMotion = false -- nothing more to do
end -- if armMotion is false, Update is called for another reason
else -- step along the current animations
armMotion = true -- remember we are animating for the time point when we just completed it
for i = 1, MAX_DISTANT do
if ArmExists(i) then
local animState = gArmState[i]
if (animState == ANIMSTATE_ANIMTOOPEN) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_OPEN, i )
end
elseif (animState == ANIMSTATE_ANIMTOCLOSED) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_PROCEED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_BLOCKED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_CLOSED, i )
end
end
end
end
end
Next we copy functions ArmExists and SetArmState. It does not really matter where you put them but in the source files the are found before function Update.
I am not too sure about ResetSignalState, so I would keep the version in the indicator script.
Function Initialise shows a big difference. We need the style found in the indicator script, that is function Initialise. I would just copy over this block:
- Code: Select all
gArmTable = {}
for i = 1, 9 do
gArmTable[i] = {}
gArmTable[i][SEM_PROCEED_ANIM] = "Clear"
gArmTable[i][SEM_BLOCKED_ANIM] = "Stop"
gArmState[i] = -1
end
armMotion = false
armsInMotion = 0
Moving from function Update up was a bit chaotic but that was my biggest worry. Now checking what follows function Update, we only find OnSignalMessage. One reason why this code never got release to the public is that I would have to remember all the stop-gap solutions I stuck on top of each other to make the signals look bright when they are innocent if not clueless observers of the train movements happening around them. This shows most in all the messages sent around.
The interface of an indicator towards the main signal is fundamentally different from that of the external arms. We do not get separate messages for open and close, we only get one and if the parameter is the empty string, then we close any arm that is open.
So when we get message SHOW, we check whether parameter is unequal "". In that case, we do:
- Code: Select all
if ArmExists(0 + parameter) then
SetArmState(ANIMSTATE_ANIMTOOPEN, 0 + parameter)
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
The else branch is for the case where there are several external indicators.
For closing, the indicator does not the information what to close, so we need our own variable to keep track of that. I call this shownIndication to be sure it does not clash with anything out there. It is set to the parameter on opening and set to nil after we closed.
When we get the command to close (SHOW with empty parameter), we check whether we opened anything, i.e., whether shownIndication is not nil. In that case, we close that. Otherwise we forward the message, assuming that there will be another indicator that needs closing. This is a bit wonky, but so one complained yet about signals with two indicators not working right because of my scripts.
After all this, function OnSignalMessage should look like this:
- Code: Select all
function OnSignalMessage( message, parameter, direction, linkIndex )
MessageLog( message, parameter, direction, linkIndex )
if (message == RESET_SIGNAL_STATE) then
ResetSignalState()
elseif (message == SHOW) then
if parameter ~= "" then
shownIndication = parameter
if ArmExists(0 + parameter) then
SetArmState(ANIMSTATE_ANIMTOOPEN, 0 + parameter)
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
else
if shownIndication =~ nil then
SetArmState(ANIMSTATE_ANIMTOCLOSED, 0 + parameter)
shownIndication = nil
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
elseif message == OPEN_LOG then
OpenLog(parameter, direction, linkIndex)
-- Ignore initialisation messages from trains straddling a link - these will have the "DoNotForward" parameter
-- Otherwise forward on the message
elseif parameter ~= "DoNotForward" then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
The indicator will want you to put 123 in the signal ID if you have arms 1, 2, 3. To get rid of this, you put in the stuff marked afterthought above and you replace gId by indices in the line that follows, so it reads:
- Code: Select all
Call( "SendSignalMessage", SIGNAL_I_AM_INDICATOR, indices, -1, 1, 0 )
Then you get rid of most of function ResetSignalState so it just reads:
- Code: Select all
function ResetSignalState ( )
gInitialised = false
Call( "BeginUpdate" )
end
Now the indicator finds out which arms it has and sends a message to the signal that conveys this information. This will cause the signal to only ask for indications in this list.
I enclose the result of all this here:
- Code: Select all
--------------------------------------------------------------------------------------
-- A theater box type indicator in a separate slave object controlled by the master stop signal
-- The current implementation is based on texture set switching.
--
require "Assets/AndiS/FPSignals/scripts/Shared by All.out"
function Initialise ()
InitialiseId()
InitialiseConstantsAndArrays()
-- copied over from External Arms
gArmTable = {}
for i = 1, 9 do
gArmTable[i] = {}
gArmTable[i][SEM_PROCEED_ANIM] = "Clear"
gArmTable[i][SEM_BLOCKED_ANIM] = "Stop"
gArmState[i] = -1
end
armMotion = false
armsInMotion = 0
-- end of copied block
gConnectedLink = 0
gAnimState = -1
gInitialised = false -- has the route finished loading yet?
ResetSignalState ()
end
function ResetSignalState ( )
gInitialised = false
Call( "BeginUpdate" )
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
-- don't care about trains
end
function ArmExists(dollIndex)
if gArmTable[dollIndex] == nil then
return false
else
return gArmTable[dollIndex][SEM_CHILD_NAME] ~= nil
end
end
function SetArmState(newState, routeIndex)
-- Initial checks: Make sure the arm exists before trying to do anything to it!
-- Plus: be sure that this call is not just redundant
-- Base copied from semaphore distant
if ArmExists(routeIndex) then -- currently redundant check
if newState == gArmState[routeIndex] then
RasterLog("SetArmState", routeIndex .. " " .. printNil(gArmState[routeIndex]) .. " = " ..
printNil(newState) .. " nothing to do")
else
RasterLog("SetArmState", animName(newState) .. " " .. routeIndex .. " " .. printNil(gArmState[routeIndex]) ..
" -> " ..
printNil(newState) .. " " .. printBoolean(armMotion) .. " " .. printNil(armsInMotion))
if newState == ANIMSTATE_ANIMTOOPEN then -- want to open
if gArmState[routeIndex] == ANIMSTATE_CLOSED then -- normal case: closed now
armsInMotion = armsInMotion + 1
if not armMotion then -- first arm animation
UpdateLog("SetArmState", "BeginUpdate" )
Call( "BeginUpdate" )
end
gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN
if startOpening ~= nil then
startOpening(routeIndex)
end
elseif gArmState[routeIndex] == ANIMSTATE_ANIMTOCLOSED then -- currently closing -> gross error
-- if gInitialised then
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] starting to open while closing") -- reset as an emergency measure
-- gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN
-- return false
-- else
gArmState[routeIndex] = ANIMSTATE_ANIMTOOPEN -- before actually running, overwriting does not hurt
-- end
end -- if ANIMSTATE_OPEN or ANIMSTATE_ANIMTOOPEN,
-- no action is required
elseif newState == ANIMSTATE_ANIMTOCLOSED then -- want to close
if gArmState[routeIndex] == ANIMSTATE_OPEN then -- normal case: closed now
armsInMotion = armsInMotion + 1
if not armMotion then -- first arm animation
UpdateLog("SetArmState", "BeginUpdate" )
Call( "BeginUpdate" )
end
gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED
if startClosing ~= nil then
startClosing(routeIndex)
end
elseif gArmState[routeIndex] == ANIMSTATE_ANIMTOOPEN then -- currently opening -> gross error
-- if gInitialised then
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] starting to close while opening") -- reset as an emergency measure
-- gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED
-- return false
-- else
gArmState[routeIndex] = ANIMSTATE_ANIMTOCLOSED -- before actually running, overwriting does not hurt
-- end
end -- if ANIMSTATE_CLOSED or ANIMSTATE_ANIMTOCLOSED,
-- no action is required
elseif newState == ANIMSTATE_OPEN then -- opening complete
if gArmState[routeIndex] == ANIMSTATE_ANIMTOOPEN then -- normal case: open now
armsInMotion = armsInMotion - 1 -- reaction to armsInMotion == 0 in Update
elseif gArmState[routeIndex] ~= nil
and gArmState[routeIndex] ~= ANIMSTATE_OPEN then
-- could be a result of quick changes to signal state
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] ~= ANIMSTATE_ANIMTOOPEN")
return false
end
gArmState[routeIndex] = ANIMSTATE_OPEN
if finishOpening ~= nil then
finishOpening(routeIndex)
end
elseif newState == ANIMSTATE_CLOSED then --closing complete
if gArmState[routeIndex] == ANIMSTATE_ANIMTOCLOSED then -- normal case: closed now
armsInMotion = armsInMotion - 1 -- reaction to armsInMotion == 0 in Update
elseif gArmState[routeIndex] ~= ANIMSTATE_CLOSED
and gArmState[routeIndex] ~= nil then -- bad surprise
ErrorPrint ("SetArmState", "gArmState[" .. routeIndex .. "] ~= ANIMSTATE_ANIMTOCLOSED")
return false
end
gArmState[routeIndex] = ANIMSTATE_CLOSED
if finishClosing ~= nil then
finishClosing(routeIndex)
end
end
end
else
RasterLog("SetArmState", routeIndex .. " arm does not exist")
end
end
--------------------------------------------------------------------------------------
-- UPDATE
--
function Update (time)
if gInitialised then
-- big chunk of copied code will be inserted here !
if armsInMotion == 0 then -- no animations running
if armMotion then -- we were active until recently
armMotion = false -- nothing more to do
end -- if armMotion is false, Update is called for another reason
else -- step along the current animations
armMotion = true -- remember we are animating for the time point when we just completed it
for i = 1, MAX_DISTANT do
if ArmExists(i) then
local animState = gArmState[i]
if (animState == ANIMSTATE_ANIMTOOPEN) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_OPEN, i )
end
elseif (animState == ANIMSTATE_ANIMTOCLOSED) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_PROCEED_ANIM] )
if Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_BLOCKED_ANIM], time ) ~= 0 then
SetArmState( ANIMSTATE_CLOSED, i )
end
end
end
end
end
else
SimpleSendTestMessageWithinLinks()
-- small chunk of copied code goes here
for i = 1, MAX_DISTANT do
if ArmExists(i) then
Call( gArmTable[i][SEM_CHILD_NAME] .. ":Reset", gArmTable[i][SEM_BLOCKED_ANIM] )
Call( gArmTable[i][SEM_CHILD_NAME] .. ":AddTime", gArmTable[i][SEM_PROCEED_ANIM], 0 )
gArmState[i] = ANIMSTATE_CLOSED
end
end
indices = ""
for dollIndex=1, 9 do
if ArmExists(dollIndex) then
indices = indices .. dollIndex
end
end
Call( "SendSignalMessage", SIGNAL_I_AM_INDICATOR, indices, -1, 1, 0 )
gInitialised = true
Call ("EndUpdate")
end
-- extra stuff at end goes here
if armsInMotion == 0 and not armMotion and gInitialised then
UpdateLog("Animations", "EndUpdate" )
Call( "EndUpdate" )
end
end
-------------------------------------------------------------------------------------
-- ON SIGNAL MESSAGE
-- Shunt signals just forward the signal messages on to other signals
--
function OnSignalMessage( message, parameter, direction, linkIndex )
MessageLog( message, parameter, direction, linkIndex )
if (message == RESET_SIGNAL_STATE) then
ResetSignalState()
elseif (message == SHOW) then
if parameter ~= "" then
shownIndication = parameter
if ArmExists(0 + parameter) then
SetArmState(ANIMSTATE_ANIMTOOPEN, 0 + parameter)
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
else
if shownIndication =~ nil then
SetArmState(ANIMSTATE_ANIMTOCLOSED, 0 + parameter)
shownIndication = nil
else
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
elseif message == OPEN_LOG then
OpenLog(parameter, direction, linkIndex)
-- Ignore initialisation messages from trains straddling a link - these will have the "DoNotForward" parameter
-- Otherwise forward on the message
elseif parameter ~= "DoNotForward" then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
I am sure there are bugs in there, and I am sure I have no clue where. But it is all I can supply at the moment.