diff --git a/src/lang/english.txt b/src/lang/english.txt index 07d493900c..222c7a2884 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2627,9 +2627,8 @@ STR_PROGSIG_COND_ALWAYS :always STR_PROGSIG_COND_NEVER :never STR_PROGSIG_COND_COMPARE :{STRING} {STRING} {NUM} STR_PROGSIG_COND_SIGNAL_STATE :signal state -STR_PROGSIG_CONDVAR_SIGNAL_STATE :{STRING1} is green -STR_PROGSIG_CONDVAR_SIGNAL_STATE_SPECIFIED :specified signal -STR_PROGSIG_CONDVAR_SIGNAL_STATE_UNSPECIFIED :{RED}unspecified signal{STRING} +STR_PROGSIG_CONDVAR_SIGNAL_STATE_SPECIFIED :signal at {NUM} x {NUM} is green +STR_PROGSIG_CONDVAR_SIGNAL_STATE_UNSPECIFIED :{RED}unspecified signal{STRING} is green STR_PROGSIG_CONDVAR_NUM_RED :red signals STR_PROGSIG_CONDVAR_NUM_GREEN :green signals diff --git a/src/programmable_signals.cpp b/src/programmable_signals.cpp index 58d8865919..bf7a5490a6 100644 --- a/src/programmable_signals.cpp +++ b/src/programmable_signals.cpp @@ -121,21 +121,23 @@ SignalStateCondition::SignalStateCondition(SignalReference this_sig, : SignalCondition(PSC_SIGNAL_STATE), this_sig(this_sig), sig_tile(sig_tile) , sig_track(sig_track) { - if (this->IsSignalValid()) + if (this->CheckSignalValid()) AddSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig); } -bool SignalStateCondition::IsSignalValid() +bool SignalStateCondition::IsSignalValid() const { - if (IsValidTile(this->sig_tile)) { - if (IsTileType(this->sig_tile, MP_RAILWAY) && HasSignalOnTrackdir(this->sig_tile, this->sig_track)) { - return true; - } else { - Invalidate(); - } + return IsValidTile(this->sig_tile) && IsTileType(this->sig_tile, MP_RAILWAY) && HasSignalOnTrackdir(this->sig_tile, this->sig_track); +} + +bool SignalStateCondition::CheckSignalValid() +{ + bool valid = this->IsSignalValid(); + if (!valid) { + this->Invalidate(); } - return false; + return valid; } void SignalStateCondition::Invalidate() @@ -151,7 +153,7 @@ void SignalStateCondition::SetSignal(TileIndex tile, Trackdir track) this->this_sig); this->sig_tile = tile; this->sig_track = track; - if (this->IsSignalValid()) + if (this->CheckSignalValid()) AddSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig); } @@ -165,7 +167,7 @@ void SignalStateCondition::SetSignal(TileIndex tile, Trackdir track) /*virtual*/ bool SignalStateCondition::Evaluate(SignalVM& vm) { - if (!this->IsSignalValid()) { + if (!this->CheckSignalValid()) { DEBUG(misc, 1, "Signal (%x, %d) has an invalid condition", this->this_sig.tile, this->this_sig.track); return false; } @@ -412,9 +414,9 @@ SignalState RunSignalProgram(SignalReference ref, uint num_exits, uint num_green return vm.state; } -void RemoveProgramDependencies(SignalReference by, SignalReference on) +void RemoveProgramDependencies(SignalReference dependency_target, SignalReference signal_to_update) { - SignalProgram *prog = GetSignalProgram(by); + SignalProgram *prog = GetSignalProgram(signal_to_update); for (SignalInstruction **b = prog->instructions.Begin(), **i = b, **e = prog->instructions.End(); i != e; i++) { SignalInstruction *insn = *i; @@ -422,13 +424,14 @@ void RemoveProgramDependencies(SignalReference by, SignalReference on) SignalIf* ifi = static_cast(insn); if (ifi->condition->ConditionCode() == PSC_SIGNAL_STATE) { SignalStateCondition* c = static_cast(ifi->condition); - if(c->sig_tile == by.tile && TrackdirToTrack(c->sig_track) == by.track) + if(c->sig_tile == dependency_target.tile && TrackdirToTrack(c->sig_track) == dependency_target.track) c->Invalidate(); } } } - AddTrackToSignalBuffer(by.tile, by.track, GetTileOwner(by.tile)); + InvalidateWindowData(WC_SIGNAL_PROGRAM, (signal_to_update.tile << 3) | signal_to_update.track); + AddTrackToSignalBuffer(signal_to_update.tile, signal_to_update.track, GetTileOwner(signal_to_update.tile)); UpdateSignalsInBuffer(); } diff --git a/src/programmable_signals.h b/src/programmable_signals.h index d9bb94d4c1..5cf251c6ed 100644 --- a/src/programmable_signals.h +++ b/src/programmable_signals.h @@ -33,10 +33,10 @@ struct SignalProgram { SignalProgram(TileIndex tile, Track track, bool raw = false); ~SignalProgram(); void DebugPrintProgram(); - + TileIndex tile; Track track; - + SignalSpecial *first_instruction; SignalSpecial *last_instruction; InstructionList instructions; @@ -55,7 +55,7 @@ enum SignalOpcode { PSO_IF_ELSE = 3, ///< If Else pseudo instruction PSO_IF_ENDIF = 4, ///< If Endif pseudo instruction PSO_SET_SIGNAL = 5, ///< Set signal instruction - + PSO_END, PSO_INVALID = 0xFF }; @@ -66,22 +66,22 @@ class SignalInstruction { public: /// Get the instruction's opcode inline SignalOpcode Opcode() const { return this->opcode; } - + /// Get the previous instruction. If this is NULL, then this is the first /// instruction. inline SignalInstruction *Previous() const { return this->previous; } - + /// Get the Id of this instruction - inline int Id() const + inline int Id() const // Const cast is safe (perculiarity of SmallVector) { return program->instructions.FindIndex(const_cast(this)); } - + /// Insert this instruction, placing it before @p before_insn virtual void Insert(SignalInstruction *before_insn); - + /// Evaluate the instruction. The instruction should update the VM state. virtual void Evaluate(SignalVM &vm) = 0; - + /// Remove the instruction. When removing itself, an instruction should ///
    ///
  • Set next->previous to previous @@ -89,20 +89,20 @@ public: ///
  • Destroy any other children ///
virtual void Remove() = 0; - + /// Gets a reference to the previous member. This is only intended for use by /// the saveload code. inline SignalInstruction *&GetPrevHandle() { return previous; } - - /// Sets the previous instruction of this instruction. This is only intended + + /// Sets the previous instruction of this instruction. This is only intended /// to be used by instructions to update links during insertion and removal. inline void SetPrevious(SignalInstruction *prev) { previous = prev; } /// Set the next instruction. This is only intended to be used by instructions /// to update links during insertion and removal virtual void SetNext(SignalInstruction *next_insn) = 0; - + protected: /// Constructs an instruction /// @param prog the program to add this instruction to @@ -117,7 +117,7 @@ protected: /** Programmable Signal condition code. * - * These discriminate conditions in much the same way that SignalOpcode + * These discriminate conditions in much the same way that SignalOpcode * discriminates instructions. */ enum SignalConditionCode { @@ -126,7 +126,7 @@ enum SignalConditionCode { PSC_NUM_GREEN = 2, ///< Number of green signals behind this signal PSC_NUM_RED = 3, ///< Number of red signals behind this signal PSC_SIGNAL_STATE = 4, ///< State of another signal - + PSC_MAX = PSC_SIGNAL_STATE }; @@ -134,16 +134,16 @@ class SignalCondition { public: /// Get the condition's code inline SignalConditionCode ConditionCode() const { return this->cond_code; } - + /// Evaluate the condition virtual bool Evaluate(SignalVM& vm) = 0; - + /// Destroy the condition. Any children should also be destroyed virtual ~SignalCondition(); - + protected: SignalCondition(SignalConditionCode code) : cond_code(code) {} - + const SignalConditionCode cond_code; }; @@ -167,7 +167,7 @@ enum SignalComparator { SGC_MORE_THAN_EQUALS = 5, ///< the variable is grater than or equal to the specified value SGC_IS_TRUE = 6, ///< the variable is true (non-zero) SGC_IS_FALSE = 7, ///< the variable is false (zero) - + SGC_LAST = SGC_IS_FALSE }; @@ -188,10 +188,10 @@ public: /// Constructs a condition refering to the value @p code refers to. Sets the /// comparator and value to sane defaults. SignalVariableCondition(SignalConditionCode code); - + SignalComparator comparator; uint32 value; - + /// Evaluates the condition virtual bool Evaluate(SignalVM &vm); }; @@ -200,14 +200,15 @@ public: class SignalStateCondition: public SignalCondition { public: SignalStateCondition(SignalReference this_sig, TileIndex sig_tile, Trackdir sig_track); - + void SetSignal(TileIndex tile, Trackdir track); - bool IsSignalValid(); + bool IsSignalValid() const; + bool CheckSignalValid(); void Invalidate(); - + virtual bool Evaluate(SignalVM& vm); virtual ~SignalStateCondition(); - + SignalReference this_sig; TileIndex sig_tile; Trackdir sig_track; @@ -223,8 +224,8 @@ class SignalStateCondition: public SignalCondition { *
  • They permit every other instruction to assume that there is another * following it. This makes the code much simpler (and by extension less * error prone)
  • - *
  • Particularly in the case of the End instruction, they provide an - * instruction in the user interface that can be clicked on to add + *
  • Particularly in the case of the End instruction, they provide an + * instruction in the user interface that can be clicked on to add * instructions at the end of a program
  • * */ @@ -232,23 +233,23 @@ class SignalSpecial: public SignalInstruction { public: /** Constructs a special signal of the opcode @p op in program @p prog. * - * Generally you should not need to call this; it will be called by the + * Generally you should not need to call this; it will be called by the * program's constructor. An exception is in the saveload code, which needs * to construct raw objects to deserialize into */ SignalSpecial(SignalProgram *prog, SignalOpcode op); - + /** Evaluates the instruction. If this is an Start instruction, flow will be * vectored to the first instruction; if it is an End instruction, the program * will terminate and the signal will be left red. */ virtual void Evaluate(SignalVM &vm); - + /** Links the first and last instructions in the program. Generally only to be * called from the SignalProgram constructor. */ static void link(SignalSpecial *first, SignalSpecial *last); - + /** Removes this instruction. If this is the start instruction, then all of * the other instructions in the program will be successively removed, * (emptying it). If this is the End instruction, then it will do nothing. @@ -257,12 +258,12 @@ public: * the instruction. */ virtual void Remove(); - - /** The next instruction after this one. On the End instruction, this should + + /** The next instruction after this one. On the End instruction, this should * be NULL. */ SignalInstruction *next; - + virtual void SetNext(SignalInstruction *next_insn); }; @@ -273,12 +274,12 @@ public: */ class SignalIf: public SignalInstruction { public: - /** The If-Else and If-Endif pseudo instructions. The Else instruction + /** The If-Else and If-Endif pseudo instructions. The Else instruction * follows the Then block, and the Endif instruction follows the Else block. * * These serve two purposes: *
      - *
    • They correctly vector the execution to after the if block + *
    • They correctly vector the execution to after the if block * (if needed) *
    • They provide an instruction for the GUI to insert other instructions * before. @@ -286,55 +287,55 @@ public: */ class PseudoInstruction: public SignalInstruction { public: - /** Normal constructor. The pseudo instruction will be constructed as + /** Normal constructor. The pseudo instruction will be constructed as * belonging to @p block. */ PseudoInstruction(SignalProgram *prog, SignalIf *block, SignalOpcode op); - + /** Constructs an empty instruction of type @p op. This should only be used * by the saveload code during deserialization. The instruction must have * its block field set correctly before the program is run. */ PseudoInstruction(SignalProgram *prog, SignalOpcode op); - + /** Removes the pseudo instruction. Unless you are also removing the If it * belongs to, this is nonsense and dangerous. */ virtual void Remove(); - + /** Evaluate the pseudo instruction. This involves vectoring execution to * the instruction after the if. */ virtual void Evaluate(SignalVM &vm); - + /** The block to which this instruction belongs */ SignalIf *block; virtual void SetNext(SignalInstruction *next_insn); }; - + public: - /** Constructs an If instruction belonging to program @p prog. If @p raw is - * true, then the instruction is constructed raw (in order for the + /** Constructs an If instruction belonging to program @p prog. If @p raw is + * true, then the instruction is constructed raw (in order for the * deserializer to be able to correctly deserialize the instruction). */ SignalIf(SignalProgram *prog, bool raw = false); - + /** Sets the instruction's condition, and releases the old condition */ void SetCondition(SignalCondition *cond); - + /** Evaluates the If and takes the appropriate branch */ virtual void Evaluate(SignalVM &vm); - + virtual void Insert(SignalInstruction *before_insn); - + /** Removes the If and all of its children */ virtual void Remove(); - + SignalCondition *condition; ///< The if conditon SignalInstruction *if_true; ///< The branch to take if true SignalInstruction *if_false; ///< The branch to take if false SignalInstruction *after; ///< The branch to take after the If - + virtual void SetNext(SignalInstruction *next_insn); }; @@ -343,16 +344,16 @@ class SignalSet: public SignalInstruction { public: /// Constructs the instruction and sets the state the signal is to be set to SignalSet(SignalProgram *prog, SignalState = SIGNAL_STATE_RED); - + virtual void Evaluate(SignalVM &vm); virtual void Remove(); - + /// The state to set the signal to SignalState to_state; - + /// The instruction following this one (for the editor) SignalInstruction *next; - + virtual void SetNext(SignalInstruction *next_insn); }; @@ -369,7 +370,7 @@ static inline bool HasProgrammableSignals(SignalReference ref) && IsPresignalProgrammable(ref.tile, ref.track); } -/// Shows the programming window for the signal identified by @p tile and +/// Shows the programming window for the signal identified by @p tile and /// @p track. void ShowSignalProgramWindow(SignalReference ref); @@ -389,7 +390,7 @@ void FreeSignalPrograms(); SignalState RunSignalProgram(SignalReference ref, uint num_exits, uint num_green); /// Remove dependencies on signal @p on from @p by -void RemoveProgramDependencies(SignalReference by, SignalReference on); +void RemoveProgramDependencies(SignalReference dependency_target, SignalReference signal_to_update); ///@} #endif diff --git a/src/programmable_signals_gui.cpp b/src/programmable_signals_gui.cpp index 29cba83c96..90d11f5b69 100644 --- a/src/programmable_signals_gui.cpp +++ b/src/programmable_signals_gui.cpp @@ -137,10 +137,15 @@ static char *GetConditionString(SignalCondition *cond, char *buf, char *buflast, } else { string = _program_condvar[cond->ConditionCode()]; if (cond->ConditionCode() == PSC_SIGNAL_STATE) { - string = STR_PROGSIG_CONDVAR_SIGNAL_STATE; - SetDParam(0, static_cast(cond)->IsSignalValid() - ? STR_PROGSIG_CONDVAR_SIGNAL_STATE_SPECIFIED : STR_PROGSIG_CONDVAR_SIGNAL_STATE_UNSPECIFIED); - SetDParam(1, selected ? STR_WHITE : STR_BLACK); + SignalStateCondition *sig_cond = static_cast(cond); + if (sig_cond->IsSignalValid()) { + string = STR_PROGSIG_CONDVAR_SIGNAL_STATE_SPECIFIED; + SetDParam(0, TileX(sig_cond->sig_tile)); + SetDParam(1, TileY(sig_cond->sig_tile)); + } else { + string = STR_PROGSIG_CONDVAR_SIGNAL_STATE_UNSPECIFIED; + SetDParam(0, selected ? STR_WHITE : STR_BLACK); + } } } return GetString(buf, string, buflast); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 7a7af1461c..5b18e4b4e7 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -646,7 +646,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, /* Charge extra to remove signals on the track, if they are there */ if (HasSignalOnTrack(tile, track)) { - CheckRemoveSignal(tile, track); + if (flags & DC_EXEC) CheckRemoveSignal(tile, track); cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS)); } diff --git a/src/signal.cpp b/src/signal.cpp index a68861f82f..f42dd8d09a 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -802,12 +802,14 @@ void CheckRemoveSignalsFromTile(TileIndex tile) } } -static void NotifyRemovingDependentSignal(SignalReference on, SignalReference by) +static void NotifyRemovingDependentSignal(SignalReference being_removed, SignalReference dependant) { - SignalType t = GetSignalType(by.tile, by.track); - if (IsProgrammableSignal(t)) { - RemoveProgramDependencies(by, on); - } else DEBUG(misc, 0, "Removing dependency held by non-programmable signal (Unexpected)"); + SignalType t = GetSignalType(dependant.tile, dependant.track); + if (IsProgrammableSignal(t)) { + RemoveProgramDependencies(being_removed, dependant); + } else { + DEBUG(misc, 0, "Removing dependency held by non-programmable signal (Unexpected)"); + } } void CheckRemoveSignal(TileIndex tile, Track track)