🧙♂️Hello,
This is an automated message:
A new shop has been established, which allows you to purchase products for "Z" loyalty points, which you can find in your profile or on the top bars. You can find the store under the section Downloads (Top Menu).
This is an automated message:
A new shop has been established, which allows you to purchase products for "Z" loyalty points, which you can find in your profile or on the top bars. You can find the store under the section Downloads (Top Menu).
The beginning of the code
C++
public Soup DetermineUpdatedState(void)
{
//Interface.Print("SSignal <" + me.GetLocalisedName() + ">: DetermineUpdatedState called!");
MapObject nextMapObject;
JunctionBase lastJunction = null; //this is just the most recent junction found in the tracksearch
JunctionBase revJunction = null; //this is the first junction that doesnt match the straight path
string pathJunction;
int pathIndex = 0;
int trainApproaching = -1; //0 = train not facing this signal. 1 = train is facing this signal.
int trainLeaving = -1; //0 = train heading to this signal from ahead. 1 = no train or moving away.
Signal nextSignal = null;
Train approachingTrain = null;
Train trainInBlock = null;
float signalDistance, maxDistance;
bool trainInPortalArea;
bool lightSignal = false;
bool activeBlock = false;
int signalState = -1;
string signalStateReason = "";
string myName = "";
if(me.GetLocalisedName() != "")
{
myName = me.GetLocalisedName() + " - ";
}
srchDst = SmartSignalCommon.BlockDistance(me);
Display More
Block Settings of Signals
Check to see if the block we signal to is active at all and if it is, light the signal, otherwise its idle.
C++
// block set-up
// check to see if the block we signal to is active at all and if it is, light the signal, otherwise its idle.
trainInBlock = SmartSignalCommon.checkBlockActive(me, false, 2, 16090);
if(trainInBlock)
{
activeBlock = true;
lightSignal = true;
}
//check to see if a train is looking at this signal (train does not have to be moving, just facing this signal)
approachingTrain = SmartSignalCommon.TrainMovingTowardSignal(me, false, 4, 16090);
if(approachingTrain and approachingTrain.GetFrontmostLocomotive())
{
trainApproaching = 1;
}
else
{
trainApproaching = 0;
}
//look for trains in the block protected by this signal and heading this way. (train must be moving toward this signal)
trainInBlock = null;
trainInBlock = SmartSignalCommon.TrainMovingTowardSignal(me, true , 0, srchDst);
if (trainInBlock)
{
trainLeaving = 0; //there is a train heading our way from up ahead.
}
else
{
trainLeaving = 1; //there is no train or it is moving away
}
Display More
Switch settings
C++
//set switch locks
if (updateLocks and ctrlJctList.size() > 0)
{
trainInBlock = null;
trainInBlock = SmartSignalCommon.TrainMovingTowardSignal(me, false, 0, 400);
lockJcts = (trainInBlock and (Math.Fabs(trainInBlock.GetTrainVelocity()) > 0.1));
SmartSignalCommon.SetJunctionLock(m_signalToken, ctrlJctList, lockJcts);
}
updateLocks = false;
Channel control
C++
//check channels
if(lightSignal and gChannel and !isActiveSignal)//send message to channel that I am active
{
isActiveSignal = true;
PostMessage(null, "SSChannelON", gChannel, 0.5);
}
if(!lightSignal and isActiveSignal) //can only post off message if it has posted on message.
{
isActiveSignal = false;
activeChannel = false;
PostMessage(null, "SSChannelOFF", gChannel, 0.1);
}
if(activeChannel) lightSignal = true;
Display More
Determine signal status
C++
//determine signal state
if (approachLit and !lightSignal) //turn signal off
{
signalState = SS_DARK;
signalStateReason = myName + m_textStrings.GetString("signal_approach_lit");
}
else if (idleRed and !activeBlock) //make signal red
{
signalState = SS_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_notrain");
}
else if (activeBlock and trainApproaching == 0) //block has not been cleared
{
signalState = SS_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_train_not_cleared");
}
else if (trainLeaving == 0) //block is reserved
{
signalState = SS_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_reserved");
}
else //turn this signal on and perform logic
{
//GSTrackSearch our way down the track, and find out what is ahead of us.
GSTrackSearch myGST = me.BeginTrackSearch(true);
while (nextMapObject = myGST.SearchNext())
{
if (cast<Vehicle> nextMapObject and !me.GetIsRepeater())
{
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found traincar \"" + nextMapObject.GetLocalisedName() + "\".");
// Base overlap test used here to prevent home signals from displaying confusing behaviour
// on very small portal-to-terminus layouts (e.g. Portal -> Home -> Buffers)
// and far too heavy traffic generated from the portal
//updateLocks = true;
if (myGST.GetDistance() < 100)
{
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_block_occupied");
SetAutopilotHintObj(nextMapObject);
RestrictingOverride = false;
break;
}
if ((overlapTC) or (me.GetIsHome() and (me.GetOverlap() != baseOverlap)) or (myGST.GetDistance() > me.GetOverlap() - HALF_A_CAR_LENGTH))
{
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_block_occupied");
SetAutopilotHintObj(nextMapObject);
break;
}
else
{
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: ... traincar is entirely within overlap, and is thus still in the block in rear.");
RestrictingOverride = false;
}
}
else if (cast<Junction> nextMapObject and !me.GetIsRepeater())
{
//Interface.Print("SSignal: <" + me.GetLocalisedName() + ">: Found junction \"" + nextMapObject.GetLocalisedName() + "\".");
//Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found junction \"" + nextMapObject.GetLocalisedName() + "\".");
if(!lastJunction)
{
SetAutopilotJunction(cast<Junction> nextMapObject);
}
lastJunction = cast<Junction> nextMapObject;
if(trainApproaching == -1)
{
approachingTrain = SmartSignalCommon.TrainMovingTowardSignal(me, false, 5, 16090); // 5 signals or 10 miles, whichever is closer
if(approachingTrain and approachingTrain.GetFrontmostLocomotive())
{
trainApproaching = 1;
}
else
{
trainApproaching = 0;
}
}
//
// Checking the straight path
//
if (pathIndex < pathStraight.size() and !revJunction)
{
ctrlJctList[pathIndex] = lastJunction; //put this junction in our control list
switch (lastJunction.GetDirection())
{
case Junction.DIRECTION_LEFT:
pathJunction = "L";
break;
case Junction.DIRECTION_RIGHT:
pathJunction = "R";
break;
default:
pathJunction = "F";
}
if (pathJunction != pathStraight[pathIndex,pathIndex + 1])
{
revJunction = lastJunction; //mark our first reverse junction found
}
pathIndex = pathIndex + 1;
}
}
else if (cast<Signal> nextMapObject)
{
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found signal \"" + nextMapObject.GetLocalisedName() + "\" ...");
if (myGST.GetFacingRelativeToSearchDirection())
{
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: ... and it's facing the correct way :)");
if ((cast<Signal> nextMapObject).GetIsRepeater())
{
// it's a repeater - ignore it.
// It is only copying it's state from the signal in advance.
// It is that signal we need to be looking at.
}
else if (me.GetIsRepeater())
{
// I am a repeater - copy my state from the signal in advance.
signalState = (cast<Signal> nextMapObject).GetSignalStateEx();
signalStateReason = myName + m_textStrings.GetString("signal_repeater");
break;
}
else if (!me.CanDisplayStateEx(SS_STOP_THEN_PROCEED) and (cast<Signal> nextMapObject).CanDisplayStateEx(SS_STOP_THEN_PROCEED) and trainLeaving == 0)
{
// If I am an absolute signal, and the next signal is not an absolute, and there is a train heading this direction.
// It's a permissive intermediate signal and there is a train heading this way after it.
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_conflicting");
RestrictingOverride = false;
if (junctionBeyond)
{
SetAutopilotJunction(junctionBeyond);
}
else if (lastJunction)
{
SetAutopilotHintObj(lastJunction.GetMapObject());
}
break;
}
else if (!me.CanDisplayStateEx(SS_STOP_THEN_PROCEED) and !(cast<Signal> nextMapObject).CanDisplayStateEx(SS_STOP_THEN_PROCEED) and trainLeaving == 0)
{
// If I am an absolute signal, and the next signal is absolute, and there is a train heading this direction.
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_conflicting");
RestrictingOverride = false;
if (junctionBeyond)
{
SetAutopilotJunction(junctionBeyond);
}
else if (lastJunction)
{
SetAutopilotHintObj(lastJunction.GetMapObject());
}
break;
}
else if ((cast<Signal> nextMapObject).GetIsDistant())
{
// it's a distant
if (!nextSignal and myGST.GetDistance() > me.GetOverlap() + HALF_A_CAR_LENGTH)
{
// it's the first distant we've seen, and it's far enough away from the start of the search to want to increment states
// remember this one, as our aspect will be one greater than this, provided we can clear to the next home.
nextSignal = cast<Signal> nextMapObject;
}
}
else
{
if (!nextSignal)
{
// we haven't seen a distant, so our aspect will be based off this home or combined signal
nextSignal = cast<Signal> nextMapObject;
// if we are a home, the distance to this signal (minus a bit of fudge distance) is our overlap
if (me.GetIsHome())
{
overlap = myGST.GetDistance() - HALF_A_CAR_LENGTH;
}
}
else
{
// if we are a home and our next signal is a distant (thus more accurately, we are a starter), set our default overlap
if (me.GetIsHome())
{
overlap = baseOverlap;
}
}
signalDistance = myGST.GetDistance();
Vehicle theVeh = null;
theVeh = CheckForTrainInOverlap(myGST, nextSignal.GetOverlap());
if (theVeh)
{
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_overlap");
RestrictingOverride = false;
SetAutopilotHintObj(cast<MapObject> theVeh);
}
else if (theVeh = CheckForOncomingTrain(myGST))
{
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_reserved");
RestrictingOverride = false;
SetAutopilotHintObj(theVeh);
}
else if(signalDistance < me.GetOverlap() + HALF_A_CAR_LENGTH)
{
// signals too close to each other for the AI to stop safely - don't advance state.
signalStateReason = myName + m_textStrings.GetString("signal_tooclose");
switch (nextSignal.GetSignalStateEx())
{
case SS_STOP:
case SS_STOP_THEN_PROCEED:
case SS_DARK:
case SS_APPROACH:
case SS_APPROACH_LIMITED:
case SS_APPROACH_MEDIUM:
case SS_ADVANCE_APPROACH:
case SS_PROCEED:
case SS_LIMITED_CLEAR:
case SS_LIMITED_APPROACH:
case SS_MEDIUM_APPROACH:
case SS_MEDIUM_CLEAR:
case SS_SLOW:
case SS_RESTRICTING:
case SS_APPROACH_RESTRICTING :
signalState = nextSignal.GetSignalStateEx();
break;
default:
signalState = SS_RESTRICTING;
signalStateReason = myName + m_textStrings.GetString("signal_tooclose_unkn");
Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Signal ahead is in unknown state of " + nextSignal.GetSignalStateEx());
}
}
else
{
switch (nextSignal.GetSignalStateEx())
{
case SS_STOP:
if(doubleBlocking) {
signalState = SS_RESTRICTING;
break;
}
case SS_DARK:
case SS_STOP_THEN_PROCEED:
signalState = SS_APPROACH;
break;
case SS_APPROACH_RESTRICTING :
case SS_APPROACH :
case SS_APPROACH_LIMITED:
case SS_APPROACH_MEDIUM:
if(advanceApp)
{
signalState = SS_ADVANCE_APPROACH;
} else {
signalState = SS_PROCEED;
}
break;
case SS_ADVANCE_APPROACH:
case SS_PROCEED:
signalState = SS_PROCEED;
break;
case SS_LIMITED_CLEAR:
case SS_LIMITED_APPROACH:
signalState = SS_APPROACH_LIMITED;
break;
case SS_MEDIUM_APPROACH:
case SS_MEDIUM_CLEAR:
signalState = SS_APPROACH_MEDIUM;
break;
case SS_SLOW:
case SS_RESTRICTING:
signalState = SS_APPROACH_RESTRICTING;
break;
default:
signalState = SS_RESTRICTING;
signalStateReason = myName + m_textStrings.GetString("signal_unknown");
Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Signal ahead is in unknown state of " + nextSignal.GetSignalStateEx());
}
}
//updateLocks = true; //update locks after clearing a path
break;
}
}
else
{
//Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: ... but it's facing the wrong way. This means we're on bi-di track...");
}
}
else if (cast<Trackside> nextMapObject)
{
// some other trackside object.
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found trackside scenery item.");
if ((cast<Trackside> nextMapObject).GetIsSearchLimit())
{
// oh lookee here, it's a direction marker - does it affect signalling?
if (nextMapObject.GetAsset().GetConfigSoup().GetNamedSoup("extensions").GetNamedTagAsBool("30501-search-limit-affects-signaling"))
{
if (!myGST.GetFacingRelativeToSearchDirection())
{
// facing against us
signalState = SS_RESTRICTING;
signalStateReason = myName + m_textStrings.GetString("signal_direction_mrkr");
if (lastJunction)
{
SetAutopilotHintObj(lastJunction.GetMapObject());
}
break;
}
}
}
}
else if(cast<SceneryWithTrack> nextMapObject)
{
// some kind of crossing / turntable / buildable (i.e. industry).
// Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found a Scenery object with attached track.");
if((cast<SceneryWithTrack> nextMapObject).GetAttachedJunctions())
{
//a fixed track junction
//Interface.Log("JR SmartSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found a Scenery object with attached track junctions.");
JunctionBase[] nodes = new JunctionBase[0];
nodes = (cast<SceneryWithTrack> nextMapObject).GetAttachedJunctions();
if(nodes.size())
{
//Interface.Print("SSignal: <" + me.GetLocalisedName() + ">: Found fixed junction \"" + nextMapObject.GetLocalisedName() + "\".");
//Interface.Print("Smartsignals:> Last junction: " + (nodes.size() - 1) );
if(!lastJunction)
{
SetAutopilotJunction(nodes[nodes.size() - 1]);
}
lastFTJunction = nodes[nodes.size() - 1];
lastJunction = lastFTJunction;
if(trainApproaching == -1)
{
approachingTrain = SmartSignalCommon.TrainMovingTowardSignal(me, false, 5, 16090); // 5 signals or 10 miles, whichever is closer
if(approachingTrain and approachingTrain.GetFrontmostLocomotive())
{
trainApproaching = 1;
}
else
{
trainApproaching = 0;
}
}
//
// Checking the straight path
//
if (pathIndex < pathStraight.size() and !revJunction)
{
ctrlJctList[pathIndex] = lastJunction; //put this junction in our control list
switch (lastJunction.GetDirection())
{
case Junction.DIRECTION_LEFT:
pathJunction = "L";
break;
case Junction.DIRECTION_RIGHT:
pathJunction = "R";
break;
default:
pathJunction = "F";
}
if (pathJunction != pathStraight[pathIndex,pathIndex + 1])
{
revJunction = nodes[nodes.size() - 1];
//Interface.Print("Smartsignals:> First junction: " + pathJunction );
}
pathIndex = pathIndex + 1;
}
}
}
if(cast<BasePortal> nextMapObject)
{
// it's a portal.
// BasePortal thePortal = cast<BasePortal> nextMapObject;
// Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found a Portal");
// Search to end of track to prove no additional trains are lurking.
trainInPortalArea = false;
maxDistance = myGST.GetDistance() + PORTAL_LENGTH + HALF_A_CAR_LENGTH;
while(nextMapObject = myGST.SearchNext()) {
if(cast<Vehicle> nextMapObject and myGST.GetDistance() < maxDistance) {
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_block_occupied");
SetAutopilotHintObj(nextMapObject);
break;
}
}
if(signalState == -1) {
// assume portal is willing to accept a train if there is no evidence of traincars nearby.
signalStateReason = myName + m_textStrings.GetString("signal_portal");
if(lastJunction) {
if(trainApproaching)
{
signalState = EX_PROCEED;
//
// Checking the straight path
//
if (pathIndex < pathStraight.size() and !revJunction)
{
ctrlJctList[pathIndex] = lastJunction; //put this junction in our control list
switch (lastJunction.GetDirection())
{
case Junction.DIRECTION_LEFT:
pathJunction = "L";
break;
case Junction.DIRECTION_RIGHT:
pathJunction = "R";
break;
default:
pathJunction = "F";
}
if (pathJunction != pathStraight[pathIndex,pathIndex + 1])
{
revJunction = lastJunction;
}
pathIndex = pathIndex + 1;
}
} else {
signalState = EX_STOP;
signalStateReason = myName + m_textStrings.GetString("signal_portal_blocked");
}
} else {
if(!trainApproaching) {
if(idleRed) signalState = SS_STOP;
else signalState = SS_PROCEED;
signalStateReason = myName + m_textStrings.GetString("signal_notrain");
} else {
signalState = EX_PROCEED;
}
}
}
break;
}
else
{
// something other than a portal - ignore
// Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Scenery with track is not a Portal.");
}
}
else
{
Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Found some other type of object I'm not sure about.");
}
}
if (signalState == -1)
{
//Interface.Log("SSignal 06signal.gs <" + me.GetLocalisedName() + ">: Ran out of things in the search.");
signalState = EX_STOP;
if (lastJunction)
{
SetAutopilotHintObj(lastJunction.GetMapObject());
signalStateReason = myName + m_textStrings.GetString("signal_closed_junction");
}
else
{
signalStateReason = myName + m_textStrings.GetString("signal_line_terminated");
}
}
//
// With a repeater we will not change anything so if this is not a repeater then
//
if (!me.GetIsRepeater())
{
//
// A first junction means a non-match with the straight path
// So we have to change the signalstate according to this junction direction
//
if (revJunction)
{
if(unbonded)
{
signalState = SS_RESTRICTING;
}
else
{
switch (revJunction.GetDirection())
{
case Junction.DIRECTION_LEFT: //junction is switched
case Junction.DIRECTION_RIGHT:
switch (signalState)
{
case SS_STOP:
break;
case SS_APPROACH:
if(limSpd)
signalState = SS_LIMITED_APPROACH;
else
signalState = SS_MEDIUM_APPROACH;
break;
case SS_ADVANCE_APPROACH:
case SS_PROCEED:
if(limSpd)
signalState = SS_LIMITED_CLEAR;
else
signalState = SS_MEDIUM_CLEAR;
break;
default:;
}
break;
default:; //Forward
}
}
}
}
// okay, so we've found what we think is the state we want.
// however, we have no idea if the signal can display it,
// so we now check this against what the signal can do
// ***we dont need this since it can display ALL of the available aspects in the script
// signalState = FindNearestDisplayableStateEx(signalState);
}
//check to see if restricting override is in effect. - Set by dispatcher
if (RestrictingOverride)
{
signalState = SS_RESTRICTING;
}
if (signalState == SS_PROCEED and !CanDisplayStateEx(SS_PROCEED))
{
signalState = SS_APPROACH;
}
//set signal reason if it has not been set
if (signalStateReason == "")
{
signalStateReason = myName + DescState(signalState, m_textStrings);
}
Soup signalStateSoup = Constructors.NewSoup();
signalStateSoup.SetNamedTag("state", signalState);
signalStateSoup.SetNamedTag("reason", signalStateReason);
return signalStateSoup;
}
Display More
Comments