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