# programmable_signals.h

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #ifndef PROGRAMMABLE_SIGNALS_H
    00013 #define PROGRAMMABLE_SIGNALS_H
    00014 #include "rail_map.h"
    00015 #include "core/smallvec_type.hpp"
    00016 #include <map>
    00017
    00019
    00020
    00026 struct SignalVM;
    00027
    00028 class SignalInstruction;
    00029 class SignalSpecial;
    00030 typedef SmallVector<SignalInstruction*, 4> InstructionList;
    00031
    00033 struct SignalProgram {
    00034   SignalProgram(TileIndex tile, Track track, bool raw = false);
    00035   ~SignalProgram();
    00036   void DebugPrintProgram();
    00037
    00038   TileIndex tile;
    00039   Track track;
    00040
    00041   SignalSpecial *first_instruction;
    00042   SignalSpecial *last_instruction;
    00043   InstructionList instructions;
    00044 };
    00045
    00053 enum SignalOpcode {
    00054   PSO_FIRST      = 0,
    00055   PSO_LAST       = 1,
    00056   PSO_IF         = 2,
    00057   PSO_IF_ELSE    = 3,
    00058   PSO_IF_ENDIF   = 4,
    00059   PSO_SET_SIGNAL = 5,
    00060
    00061   PSO_END,
    00062   PSO_INVALID   = 0xFF
    00063 };
    00064 template <> struct EnumPropsT<SignalOpcode> : MakeEnumPropsT<SignalOpcode, byte, PSO_FIRST, PSO_END, PSO_INVALID, 8> {};
    00065
    00067 class SignalInstruction {
    00068 public:
    00069   /* Get the instruction's opcode. */
    00070   inline SignalOpcode Opcode() const { return this->opcode; }
    00071
    00072   /* Get the previous instruction. If this is NULL, then this is the first
    00073    * instruction. */
    00074   inline SignalInstruction *Previous() const { return this->previous; }
    00075
    00076   /* Get the Id of this instruction. */
    00077   inline int Id() const
    00078   /* Const cast is safe (perculiarity of SmallVector). */
    00079   { return program->instructions.FindIndex(const_cast<SignalInstruction*>(this)); }
    00080
    00081   /* Insert this instruction, placing it before @p before_insn. */
    00082   virtual void Insert(SignalInstruction *before_insn);
    00083
    00084   /* Evaluate the instruction. The instruction should update the VM state. */
    00085   virtual void Evaluate(SignalVM &vm) = 0;
    00086
    00087   /* Remove the instruction. When removing itself, an instruction should
    00088    * <ul>
    00089    *   <li>Set next->previous to previous.
    00090    *   <li>Set previous->next to next.
    00091    *   <li>Destroy any other children.
    00092    * </ul> */
    00093   virtual void Remove() = 0;
    00094
    00095   /* Gets a reference to the previous member. This is only intended for use by
    00096    * the saveload code. */
    00097   inline SignalInstruction *&GetPrevHandle()
    00098   { return previous; }
    00099
    00100   /* Sets the previous instruction of this instruction. This is only intended
    00101    * to be used by instructions to update links during insertion and removal. */
    00102   inline void SetPrevious(SignalInstruction *prev)
    00103   { previous = prev; }
    00104   /* Set the next instruction. This is only intended to be used by instructions
    00105    * to update links during insertion and removal. */
    00106   virtual void SetNext(SignalInstruction *next_insn) = 0;
    00107
    00108 protected:
    00109   /* Constructs an instruction.
    00110    * @param prog the program to add this instruction to
    00111    * @param op the opcode of the instruction. */
    00112   SignalInstruction(SignalProgram *prog, SignalOpcode op) ;
    00113   ~SignalInstruction();
    00114
    00115   const SignalOpcode opcode;
    00116   SignalInstruction *previous;
    00117   SignalProgram *program;
    00118 };
    00119
    00126 enum SignalConditionCode {
    00127   PSC_ALWAYS = 0,
    00128   PSC_NEVER = 1,
    00129   PSC_NUM_GREEN = 2,
    00130   PSC_NUM_RED = 3,
    00131   PSC_SIGNAL_STATE = 4,
    00132
    00133   PSC_MAX = PSC_SIGNAL_STATE
    00134 };
    00135
    00136 class SignalCondition {
    00137 public:
    00138   /* Get the condition's code. */
    00139   inline SignalConditionCode ConditionCode() const { return this->cond_code; }
    00140
    00141   /* Evaluate the condition. */
    00142   virtual bool Evaluate(SignalVM& vm) = 0;
    00143
    00144   /* Destroy the condition. Any children should also be destroyed. */
    00145   virtual ~SignalCondition();
    00146
    00147 protected:
    00148   SignalCondition(SignalConditionCode code) : cond_code(code) {}
    00149
    00150   const SignalConditionCode cond_code;
    00151 };
    00152
    00153
    00154 /* -- Condition codes. -- */
    00155
    00160 class SignalSimpleCondition: public SignalCondition {
    00161 public:
    00162   SignalSimpleCondition(SignalConditionCode code);
    00163   virtual bool Evaluate(SignalVM& vm);
    00164 };
    00165
    00167 enum SignalComparator {
    00168   SGC_EQUALS = 0,
    00169   SGC_NOT_EQUALS = 1,
    00170   SGC_LESS_THAN = 2,
    00171   SGC_LESS_THAN_EQUALS = 3,
    00172   SGC_MORE_THAN = 4,
    00173   SGC_MORE_THAN_EQUALS = 5,
    00174   SGC_IS_TRUE = 6,
    00175   SGC_IS_FALSE = 7,
    00176
    00177   SGC_LAST = SGC_IS_FALSE
    00178 };
    00179
    00181 enum SignalConditionField {
    00182   SCF_COMPARATOR = 0,
    00183   SCF_VALUE = 1,
    00184 };
    00185
    00193 class SignalVariableCondition: public SignalCondition {
    00194 public:
    00195   /* Constructs a condition refering to the value @p code refers to. Sets the
    00196    * comparator and value to sane defaults. */
    00197   SignalVariableCondition(SignalConditionCode code);
    00198
    00199   SignalComparator comparator;
    00200   uint32 value;
    00201
    00202   /* Evaluates the condition. */
    00203   virtual bool Evaluate(SignalVM &vm);
    00204 };
    00205
    00207 class SignalStateCondition: public SignalCondition {
    00208   public:
    00209     SignalStateCondition(SignalReference this_sig, TileIndex sig_tile,
    00210                          Trackdir sig_track);
    00211
    00212     void SetSignal(TileIndex tile, Trackdir track);
    00213     bool IsSignalValid();
    00214         void Invalidate();
    00215
    00216     virtual bool Evaluate(SignalVM& vm);
    00217     virtual ~SignalStateCondition();
    00218
    00219     SignalReference this_sig;
    00220     TileIndex sig_tile;
    00221     Trackdir sig_track;
    00222     SignalState state;
    00223 };
    00224
    00225
    00226 /* -- Instructions. -- */
    00227
    00241 class SignalSpecial: public SignalInstruction {
    00242 public:
    00250   SignalSpecial(SignalProgram *prog, SignalOpcode op);
    00251
    00257   virtual void Evaluate(SignalVM &vm);
    00258
    00263   static void link(SignalSpecial *first, SignalSpecial *last);
    00264
    00273   virtual void Remove();
    00274
    00279   SignalInstruction *next;
    00280
    00281   virtual void SetNext(SignalInstruction *next_insn);
    00282 };
    00283
    00290 class SignalIf: public SignalInstruction {
    00291 public:
    00304   class PseudoInstruction: public SignalInstruction {
    00305   public:
    00310     PseudoInstruction(SignalProgram *prog, SignalIf *block, SignalOpcode op);
    00311
    00317     PseudoInstruction(SignalProgram *prog, SignalOpcode op);
    00318
    00323     virtual void Remove();
    00324
    00329     virtual void Evaluate(SignalVM &vm);
    00330
    00332     SignalIf *block;
    00333     virtual void SetNext(SignalInstruction *next_insn);
    00334   };
    00335
    00336 public:
    00342   SignalIf(SignalProgram *prog, bool raw = false);
    00343
    00345   void SetCondition(SignalCondition *cond);
    00346
    00348   virtual void Evaluate(SignalVM &vm);
    00349
    00350   virtual void Insert(SignalInstruction *before_insn);
    00351
    00353   virtual void Remove();
    00354
    00355   SignalCondition *condition;
    00356   SignalInstruction *if_true;
    00357   SignalInstruction *if_false;
    00358   SignalInstruction *after;
    00359
    00360   virtual void SetNext(SignalInstruction *next_insn);
    00361 };
    00362
    00364 class SignalSet: public SignalInstruction {
    00365 public:
    00366   /* Constructs the instruction and sets the state the signal is to be set to. */
    00367   SignalSet(SignalProgram *prog, SignalState = SIGNAL_STATE_RED);
    00368
    00369   virtual void Evaluate(SignalVM &vm);
    00370   virtual void Remove();
    00371
    00372   /* The state to set the signal to. */
    00373   SignalState to_state;
    00374
    00375   /* The instruction following this one (for the editor). */
    00376   SignalInstruction *next;
    00377
    00378   virtual void SetNext(SignalInstruction *next_insn);
    00379 };
    00380
    00381 /* The map type used for looking up signal programs. */
    00382 typedef std::map<SignalReference, SignalProgram*> ProgramList;
    00383
    00384 /* The global signal program list. */
    00385 extern ProgramList _signal_programs;
    00386
    00387 /* The map type used for looking up signal programs. */
    00388 typedef std::map<SignalReference, uint16> SpeedLimits;
    00389
    00390 /* The global signal program list */
    00391 extern SpeedLimits _speedlimits;
    00392
    00393 /* Verifies that a SignalReference refers to a signal which has a program. */
    00394 static inline bool HasProgrammableSignals(SignalReference ref)
    00395 {
    00396   return IsTileType(ref.tile, MP_RAILWAY) && GetRailTileType(ref.tile) == RAIL_TILE_SIGNALS
    00397       && IsPresignalProgrammable(ref.tile, ref.track);
    00398 }
    00399
    00400 /* Verifies that a SignalReference refers to a speed-signal. */
    00401 static inline bool HasSpeedSignals(SignalReference ref)
    00402 {
    00403   return GetRailTileType(ref.tile) == RAIL_TILE_SIGNALS
    00404       && IsSpeedSignal(ref.tile, ref.track);
    00405 }
    00406
    00407 /* Shows the programming window for the signal identified by @p tile and
    00408  * @p track. */
    00409 void ShowSignalProgramWindow(SignalReference ref);
    00410
    00411 /* Shows the window to set the value of the speed-signal identified by @p
    00412  * tile and @p track. */
    00413 void ShowSpeedSignalWindow(SignalReference ref);
    00414
    00415 /* Gets the signal program for the tile identified by @p t and @p track.
    00416  * An empty program will be constructed if none is specified. */
    00417 SignalProgram *GetSignalProgram(SignalReference ref);
    00418
    00419 /* Gets the speed for the signal identified by @p t and @p track. */
    00420 uint16 GetSignalSpeed(SignalReference ref);
    00421
    00422 /* Frees a signal program by tile and track. */
    00423 void FreeSignalProgram(SignalReference ref);
    00424
    00425 /* Frees all signal programs (For use when creating a new game). */
    00426 void FreeSignalPrograms();
    00427
    00428 /* Frees a signal speed by tile and track. */
    00429 void FreeSignalSpeed(SignalReference ref);
    00430
    00431 /* Frees all signal speeds (For use when creating a new game). */
    00432 void FreeSignalSpeeds();
    00433
    00434 /* Runs the signal program, specifying the following parameters. */
    00435 SignalState RunSignalProgram(SignalReference ref, uint num_exits, uint num_green);
    00436
    00437 /* Remove dependencies on signal @p on from @p by. */
    00438 void RemoveProgramDependencies(SignalReference by, SignalReference on);
    00440
    00441 #endif