00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "programmable_signals.h"
00014 #include "debug.h"
00015 #include "command_func.h"
00016 #include "table/strings.h"
00017 #include "window_func.h"
00018 #include "company_func.h"
00019 #include "cmd_helper.h"
00020 #include <assert.h>
00021
00022 ProgramList _signal_programs;
00023 SpeedLimits _speedlimits;
00024
00025 SignalProgram::SignalProgram(TileIndex tile, Track track, bool raw)
00026 {
00027 this->tile = tile;
00028 this->track = track;
00029 if (!raw) {
00030 this->first_instruction = new SignalSpecial(this, PSO_FIRST);
00031 this->last_instruction = new SignalSpecial(this, PSO_LAST);
00032 SignalSpecial::link(this->first_instruction, this->last_instruction);
00033 }
00034 }
00035
00036 SignalProgram::~SignalProgram()
00037 {
00038 this->DebugPrintProgram();
00039 this->first_instruction->Remove();
00040 delete this->first_instruction;
00041 delete this->last_instruction;
00042 }
00043
00044 struct SignalVM {
00045
00046 uint num_exits;
00047 uint num_green;
00048 SignalProgram *program;
00049
00050
00051 SignalInstruction *instruction;
00052
00053
00054 SignalState state;
00055
00056 void Execute()
00057 {
00058 DEBUG(misc, 6, "Begining execution of programmable signal on tile %x, track %d",
00059 this->program->tile, this->program->track);
00060 do {
00061 DEBUG(misc, 10, " Executing instruction %d, opcode %d", this->instruction->Id(), this->instruction->Opcode());
00062 this->instruction->Evaluate(*this);
00063 } while (this->instruction);
00064
00065 DEBUG(misc, 6, "Completed");
00066 }
00067 };
00068
00071 SignalCondition::~SignalCondition()
00072 {}
00073
00074 SignalSimpleCondition::SignalSimpleCondition(SignalConditionCode code)
00075 : SignalCondition(code)
00076 {}
00077
00078 bool SignalSimpleCondition::Evaluate(SignalVM &vm)
00079 {
00080 switch (this->cond_code) {
00081 case PSC_ALWAYS: return true;
00082 case PSC_NEVER: return false;
00083 default: NOT_REACHED();
00084 }
00085 }
00086
00087 SignalVariableCondition::SignalVariableCondition(SignalConditionCode code)
00088 : SignalCondition(code)
00089 {
00090 switch (this->cond_code) {
00091 case PSC_NUM_GREEN: comparator = SGC_NOT_EQUALS; break;
00092 case PSC_NUM_RED: comparator = SGC_EQUALS; break;
00093 default: NOT_REACHED();
00094 }
00095 value = 0;
00096 }
00097
00098 bool SignalVariableCondition::Evaluate(SignalVM &vm)
00099 {
00100 uint32 var_val;
00101 switch (this->cond_code) {
00102 case PSC_NUM_GREEN: var_val = vm.num_green; break;
00103 case PSC_NUM_RED: var_val = vm.num_exits - vm.num_green; break;
00104 default: NOT_REACHED();
00105 }
00106
00107 switch (this->comparator) {
00108 case SGC_EQUALS: return var_val == this->value;
00109 case SGC_NOT_EQUALS: return var_val != this->value;
00110 case SGC_LESS_THAN: return var_val < this->value;
00111 case SGC_LESS_THAN_EQUALS: return var_val <= this->value;
00112 case SGC_MORE_THAN: return var_val > this->value;
00113 case SGC_MORE_THAN_EQUALS: return var_val >= this->value;
00114 case SGC_IS_TRUE: return var_val != 0;
00115 case SGC_IS_FALSE: return !var_val;
00116 default: NOT_REACHED();
00117 }
00118 }
00119
00120 SignalStateCondition::SignalStateCondition(SignalReference this_sig, TileIndex sig_tile, Trackdir sig_track)
00121 : SignalCondition(PSC_SIGNAL_STATE), this_sig(this_sig), sig_tile(sig_tile)
00122 , sig_track(sig_track)
00123 {
00124 if (this->IsSignalValid()) {
00125 AddSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig);
00126 }
00127 }
00128
00129 bool SignalStateCondition::IsSignalValid()
00130 {
00131 if (IsValidTile(this->sig_tile)) {
00132 if (HasSignalOnTrackdir(this->sig_tile, this->sig_track)) {
00133 return true;
00134 } else {
00135 Invalidate();
00136 }
00137 }
00138 return false;
00139 }
00140
00141 void SignalStateCondition::Invalidate()
00142 {
00143 this->sig_tile = INVALID_TILE;
00144 }
00145
00146
00147 void SignalStateCondition::SetSignal(TileIndex tile, Trackdir track)
00148 {
00149 if (this->IsSignalValid()) {
00150 RemoveSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig);
00151 }
00152 this->sig_tile = tile;
00153 this->sig_track = track;
00154 if (this->IsSignalValid()) {
00155 AddSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig);
00156 }
00157 }
00158
00159 SignalStateCondition::~SignalStateCondition()
00160 {
00161 if (this->IsSignalValid()) {
00162 RemoveSignalDependency(SignalReference(this->sig_tile, TrackdirToTrack(sig_track)), this->this_sig);
00163 }
00164 }
00165
00166 bool SignalStateCondition::Evaluate(SignalVM& vm)
00167 {
00168 if (!this->IsSignalValid()) {
00169 DEBUG(misc, 1, "Signal (%x, %d) has an invalid condition", this->this_sig.tile, this->this_sig.track);
00170 return false;
00171 }
00172
00173 return GetSignalStateByTrackdir(this->sig_tile, this->sig_track) == SIGNAL_STATE_GREEN;
00174 }
00175
00178 SignalInstruction::SignalInstruction(SignalProgram *prog, SignalOpcode op)
00179 : opcode(op), previous(NULL), program(prog)
00180 {
00181 *program->instructions.Append() = this;
00182 }
00183
00184 SignalInstruction::~SignalInstruction()
00185 {
00186 SignalInstruction** pthis = program->instructions.Find(this);
00187 assert(pthis != program->instructions.End());
00188 program->instructions.Erase(pthis);
00189 }
00190
00191 void SignalInstruction::Insert(SignalInstruction *before_insn)
00192 {
00193 this->previous = before_insn->Previous();
00194 before_insn->Previous()->SetNext(this);
00195 before_insn->SetPrevious(this);
00196 this->SetNext(before_insn);
00197 }
00198
00199 SignalSpecial::SignalSpecial(SignalProgram *prog, SignalOpcode op)
00200 : SignalInstruction(prog, op)
00201 {
00202 assert(op == PSO_FIRST || op == PSO_LAST);
00203 this->next = NULL;
00204 }
00205
00206 void SignalSpecial::Remove()
00207 {
00208 if (opcode == PSO_FIRST) {
00209 while (this->next->Opcode() != PSO_LAST) this->next->Remove();
00210 } else if (opcode == PSO_LAST) {
00211 } else NOT_REACHED();
00212 }
00213
00214 void SignalSpecial::link(SignalSpecial *first, SignalSpecial *last)
00215 {
00216 assert(first->opcode == PSO_FIRST && last->opcode == PSO_LAST);
00217 first->next = last;
00218 last->previous = first;
00219 }
00220
00221 void SignalSpecial::Evaluate(SignalVM &vm)
00222 {
00223 if (this->opcode == PSO_FIRST) {
00224 DEBUG(misc, 7, " Executing First");
00225 vm.instruction = this->next;
00226 } else {
00227 DEBUG(misc, 7, " Executing Last");
00228 vm.instruction = NULL;
00229 }
00230 }
00231
00232 void SignalSpecial::SetNext(SignalInstruction *next_insn)
00233 {
00234 this->next = next_insn;
00235 }
00236
00237 SignalIf::PseudoInstruction::PseudoInstruction(SignalProgram *prog, SignalOpcode op)
00238 : SignalInstruction(prog, op)
00239 {}
00240
00241 SignalIf::PseudoInstruction::PseudoInstruction(SignalProgram *prog, SignalIf *block, SignalOpcode op)
00242 : SignalInstruction(prog, op)
00243 {
00244 this->block = block;
00245 if (op == PSO_IF_ELSE) {
00246 previous = block;
00247 } else if (op == PSO_IF_ENDIF) {
00248 previous = block->if_true;
00249 } else NOT_REACHED();
00250 }
00251
00252 void SignalIf::PseudoInstruction::Remove()
00253 {
00254 if (opcode == PSO_IF_ELSE) {
00255 this->block->if_true = NULL;
00256 while(this->block->if_false) this->block->if_false->Remove();
00257 } else if (opcode == PSO_IF_ENDIF) {
00258 this->block->if_false = NULL;
00259 } else NOT_REACHED();
00260 delete this;
00261 }
00262
00263 void SignalIf::PseudoInstruction::Evaluate(SignalVM &vm)
00264 {
00265 DEBUG(misc, 7, " Executing If Pseudo Instruction %s", opcode == PSO_IF_ELSE ? "Else" : "Endif");
00266 vm.instruction = this->block->after;
00267 }
00268
00269 void SignalIf::PseudoInstruction::SetNext(SignalInstruction *next_insn)
00270 {
00271 if (this->opcode == PSO_IF_ELSE) {
00272 this->block->if_false = next_insn;
00273 } else if (this->opcode == PSO_IF_ENDIF) {
00274 this->block->after = next_insn;
00275 } else NOT_REACHED();
00276 }
00277
00278 SignalIf::SignalIf(SignalProgram *prog, bool raw)
00279 : SignalInstruction(prog, PSO_IF)
00280 {
00281 if (!raw) {
00282 this->condition = new SignalSimpleCondition(PSC_ALWAYS);
00283 this->if_true = new PseudoInstruction(prog, this, PSO_IF_ELSE);
00284 this->if_false = new PseudoInstruction(prog, this, PSO_IF_ENDIF);
00285 this->after = NULL;
00286 }
00287 }
00288
00289 void SignalIf::Remove()
00290 {
00291 delete this->condition;
00292 while (this->if_true) this->if_true->Remove();
00293
00294 this->previous->SetNext(this->after);
00295 this->after->SetPrevious(this->previous);
00296 delete this;
00297 }
00298
00299 void SignalIf::Insert(SignalInstruction *before_insn)
00300 {
00301 this->previous = before_insn->Previous();
00302 before_insn->Previous()->SetNext(this);
00303 before_insn->SetPrevious(this->if_false);
00304 this->after = before_insn;
00305 }
00306
00307 void SignalIf::SetCondition(SignalCondition *cond)
00308 {
00309 assert(cond != this->condition);
00310 delete this->condition;
00311 this->condition = cond;
00312 }
00313
00314 void SignalIf::Evaluate(SignalVM &vm)
00315 {
00316 bool is_true = this->condition->Evaluate(vm);
00317 DEBUG(misc, 7, " Executing If, taking %s branch", is_true ? "then" : "else");
00318 if (is_true) {
00319 vm.instruction = this->if_true;
00320 } else {
00321 vm.instruction = this->if_false;
00322 }
00323 }
00324
00325 void SignalIf::SetNext(SignalInstruction *next_insn)
00326 {
00327 this->if_true = next_insn;
00328 }
00329
00330
00331
00332 SignalSet::SignalSet(SignalProgram *prog, SignalState state)
00333 : SignalInstruction(prog, PSO_SET_SIGNAL)
00334 {
00335 this->to_state = state;
00336 }
00337
00338 void SignalSet::Remove()
00339 {
00340 this->next->SetPrevious(this->previous);
00341 this->previous->SetNext(this->next);
00342 delete this;
00343 }
00344
00345 void SignalSet::Evaluate(SignalVM &vm)
00346 {
00347 DEBUG(misc, 7, " Executing SetSignal, making %s", this->to_state? "green" : "red");
00348 vm.state = this->to_state;
00349 vm.instruction = NULL;
00350 }
00351
00352
00353 void SignalSet::SetNext(SignalInstruction *next_insn)
00354 {
00355 this->next = next_insn;
00356 }
00357
00358 static SignalProgram *GetExistingSignalProgram(SignalReference ref)
00359 {
00360 ProgramList::iterator i = _signal_programs.find(ref);
00361 if (i != _signal_programs.end()) {
00362 assert(i->first == ref);
00363 return i->second;
00364 } else {
00365 return NULL;
00366 }
00367 }
00368
00369
00370 SignalProgram *GetSignalProgram(SignalReference ref)
00371 {
00372 SignalProgram *pr = GetExistingSignalProgram(ref);
00373 if (!pr) {
00374 pr = new SignalProgram(ref.tile, ref.track);
00375 _signal_programs[ref] = pr;
00376 } else {
00377 assert(pr->tile == ref.tile && pr->track == ref.track);
00378 }
00379 return pr;
00380 }
00381
00382 uint16 GetSignalSpeed(SignalReference ref)
00383 {
00384 SpeedLimits::iterator i = _speedlimits.find(ref);
00385 if (i != _speedlimits.end()) {
00386 assert(i->first == ref);
00387 return i->second;
00388 } else {
00389 return 0;
00390 }
00391 }
00392
00393 void FreeSignalProgram(SignalReference ref)
00394 {
00395 DeleteWindowById(WC_SIGNAL_PROGRAM, (ref.tile << 3) | ref.track);
00396 ProgramList::iterator i = _signal_programs.find(ref);
00397 if (i != _signal_programs.end()) {
00398 delete i->second;
00399 _signal_programs.erase(i);
00400 }
00401 }
00402
00403 void FreeSignalSpeed(SignalReference ref)
00404 {
00405 DeleteWindowById(WC_SIGNAL_PROGRAM, (ref.tile << 3) | ref.track);
00406 SpeedLimits::iterator i = _speedlimits.find(ref);
00407 if (i != _speedlimits.end()) {
00408 _speedlimits.erase(i);
00409 }
00410 }
00411
00412 void FreeSignalSpeeds()
00413 {
00414 _speedlimits.clear();
00415 }
00416
00417 void FreeSignalPrograms()
00418 {
00419 ProgramList::iterator i, e;
00420 for (i = _signal_programs.begin(), e = _signal_programs.end(); i != e;) {
00421 delete i->second;
00422 _signal_programs.erase(i++);
00423 }
00424 }
00425
00426 SignalState RunSignalProgram(SignalReference ref, uint num_exits, uint num_green)
00427 {
00428 SignalProgram *program = GetSignalProgram(ref);
00429 SignalVM vm;
00430 vm.program = program;
00431 vm.num_exits = num_exits;
00432 vm.num_green = num_green;
00433
00434 vm.instruction = program->first_instruction;
00435 vm.state = SIGNAL_STATE_RED;
00436
00437 DEBUG(misc, 7, "%d exits, of which %d green", vm.num_exits, vm.num_green);
00438 vm.Execute();
00439 DEBUG(misc, 7, "Returning %s", vm.state == SIGNAL_STATE_GREEN ? "green" : "red");
00440 return vm.state;
00441 }
00442
00443 void RemoveProgramDependencies(SignalReference by, SignalReference on)
00444 {
00445 SignalProgram *prog = GetSignalProgram(by);
00446 for (SignalInstruction **b = prog->instructions.Begin(), **i = b, **e = prog->instructions.End();
00447 i != e; i++) {
00448 SignalInstruction *insn = *i;
00449 if (insn->Opcode() == PSO_IF) {
00450 SignalIf* ifi = static_cast<SignalIf*>(insn);
00451 if (ifi->condition->ConditionCode() == PSC_SIGNAL_STATE) {
00452 SignalStateCondition* c = static_cast<SignalStateCondition*>(ifi->condition);
00453 if(c->sig_tile == by.tile && TrackdirToTrack(c->sig_track) == by.track) {
00454 c->Invalidate();
00455 }
00456 }
00457 }
00458 }
00459
00460 AddTrackToSignalBuffer(by.tile, by.track, GetTileOwner(by.tile));
00461 UpdateSignalsInBuffer();
00462 }
00463
00464 void SignalProgram::DebugPrintProgram()
00465 {
00466 DEBUG(misc, 5, "Program %p listing", this);
00467 for (SignalInstruction **b = this->instructions.Begin(), **i = b, **e = this->instructions.End();
00468 i != e; i++) {
00469 SignalInstruction *insn = *i;
00470 DEBUG(misc, 5, " %ld: Opcode %d, prev %d", long(i - b), int(insn->Opcode()),
00471 int(insn->Previous() ? insn->Previous()->Id() : -1));
00472 }
00473 }
00474
00489 CommandCost CmdInsertSignalInstruction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00490 {
00491 Track track = Extract<Track, 0, 3>(p1);
00492 uint instruction_id = GB(p1, 3, 16);
00493 SignalOpcode op = Extract<SignalOpcode, 19, 8>(p1);
00494
00495 if (!IsValidTrack(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
00496 return CMD_ERROR;
00497 }
00498
00499 if (!IsTileOwner(tile, _current_company)) {
00500 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
00501 }
00502
00503 SignalProgram *prog = GetExistingSignalProgram(SignalReference(tile, track));
00504 if (!prog) {
00505 return_cmd_error(STR_ERR_PROGSIG_NOT_THERE);
00506 }
00507
00508 if (instruction_id > prog->instructions.Length()) {
00509 return_cmd_error(STR_ERR_PROGSIG_INVALID_INSTRUCTION);
00510 }
00511
00512 bool exec = (flags & DC_EXEC) != 0;
00513
00514 SignalInstruction *insert_before = prog->instructions[instruction_id];
00515 switch (op) {
00516 case PSO_IF: {
00517 if (!exec) return CommandCost();
00518 SignalIf *if_ins = new SignalIf(prog);
00519 if_ins->Insert(insert_before);
00520 break;
00521 }
00522
00523 case PSO_SET_SIGNAL: {
00524 SignalState ss = (SignalState) p2;
00525 if (ss > SIGNAL_STATE_MAX) return_cmd_error(STR_ERR_PROGSIG_INVALID_OPCODE);
00526 if (!exec) return CommandCost();
00527
00528 SignalSet *set = new SignalSet(prog, ss);
00529 set->Insert(insert_before);
00530 break;
00531 }
00532
00533 case PSO_FIRST:
00534 case PSO_LAST:
00535 case PSO_IF_ELSE:
00536 case PSO_IF_ENDIF:
00537 default:
00538 return_cmd_error(STR_ERR_PROGSIG_INVALID_OPCODE);
00539 }
00540
00541 if (!exec) return CommandCost();
00542 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
00543 UpdateSignalsInBuffer();
00544 InvalidateWindowData(WC_SIGNAL_PROGRAM, (tile << 3) | track);
00545 return CommandCost();
00546 }
00547
00569 CommandCost CmdModifySignalInstruction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00570 {
00571 Track track = Extract<Track, 0, 3 >(p1);
00572 uint instruction_id = GB(p1, 3, 16);
00573
00574 if (!IsValidTrack(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
00575 return CMD_ERROR;
00576 }
00577
00578 if (!IsTileOwner(tile, _current_company)) {
00579 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
00580 }
00581
00582 SignalProgram *prog = GetExistingSignalProgram(SignalReference(tile, track));
00583 if (!prog) {
00584 return_cmd_error(STR_ERR_PROGSIG_NOT_THERE);
00585 }
00586
00587 if (instruction_id > prog->instructions.Length()) {
00588 return_cmd_error(STR_ERR_PROGSIG_INVALID_INSTRUCTION);
00589 }
00590
00591 bool exec = (flags & DC_EXEC) != 0;
00592
00593 SignalInstruction *insn = prog->instructions[instruction_id];
00594 switch (insn->Opcode()) {
00595 case PSO_SET_SIGNAL: {
00596 SignalState state = (SignalState) p2;
00597 if (state > SIGNAL_STATE_MAX) {
00598 return_cmd_error(STR_ERR_PROGSIG_INVALID_SIGNAL_STATE);
00599 }
00600 if (!exec) {
00601 return CommandCost();
00602 }
00603 SignalSet *ss = static_cast<SignalSet*>(insn);
00604 ss->to_state = state;
00605 } break;
00606
00607 case PSO_IF: {
00608 SignalIf *si = static_cast<SignalIf*>(insn);
00609 byte act = GB(p2, 0, 1);
00610 if (act == 0) {
00611 SignalConditionCode code = (SignalConditionCode) GB(p2, 1, 8);
00612 if (code > PSC_MAX) {
00613 return_cmd_error(STR_ERR_PROGSIG_INVALID_CONDITION);
00614 }
00615 if (!exec) return CommandCost();
00616
00617 SignalCondition *cond;
00618 switch (code) {
00619 case PSC_ALWAYS:
00620 case PSC_NEVER:
00621 cond = new SignalSimpleCondition(code);
00622 break;
00623
00624 case PSC_NUM_GREEN:
00625 case PSC_NUM_RED:
00626 cond = new SignalVariableCondition(code);
00627 break;
00628
00629 case PSC_SIGNAL_STATE:
00630 cond = new SignalStateCondition(SignalReference(tile, track), INVALID_TILE, INVALID_TRACKDIR);
00631 break;
00632
00633 default: NOT_REACHED();
00634 }
00635 si->SetCondition(cond);
00636 } else {
00637 switch (si->condition->ConditionCode()) {
00638 case PSC_ALWAYS:
00639 case PSC_NEVER:
00640 return CommandCost(STR_ERR_PROGSIG_INVALID_CONDITION_FIELD);
00641
00642 case PSC_NUM_GREEN:
00643 case PSC_NUM_RED: {
00644 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(si->condition);
00645 SignalConditionField f = (SignalConditionField) GB(p2, 1, 2);
00646 uint32 val = GB(p2, 3, 27);
00647 if (f == SCF_COMPARATOR) {
00648 if (val > SGC_LAST) return_cmd_error(STR_ERR_PROGSIG_INVALID_COMPARATOR);
00649 if (!exec) return CommandCost();
00650 vc->comparator = (SignalComparator) val;
00651 } else if (f == SCF_VALUE) {
00652 if (!exec) return CommandCost();
00653 vc->value = val;
00654 } else CommandCost(STR_ERR_PROGSIG_INVALID_CONDITION_FIELD);
00655 } break;
00656
00657 case PSC_SIGNAL_STATE: {
00658 SignalStateCondition *sc = static_cast<SignalStateCondition*>(si->condition);
00659 Trackdir td = (Trackdir) GB(p2, 1, 4);
00660 TileIndex ti = (TileIndex) GB(p2, 5, 27);
00661
00662 if (!IsValidTile(ti) || !IsValidTrackdir(td) || !HasSignalOnTrackdir(ti, td)
00663 || GetTileOwner(ti) != _current_company) {
00664 return_cmd_error(STR_ERR_PROGSIG_INVALID_SIGNAL);
00665 }
00666 if (!exec) return CommandCost();
00667 sc->SetSignal(ti, td);
00668 } break;
00669 }
00670 }
00671 } break;
00672
00673 case PSO_FIRST:
00674 case PSO_LAST:
00675 case PSO_IF_ELSE:
00676 case PSO_IF_ENDIF:
00677 default:
00678 return CommandCost(STR_ERR_PROGSIG_INVALID_OPCODE);
00679 }
00680
00681 if (!exec) return CommandCost();
00682
00683 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
00684 UpdateSignalsInBuffer();
00685 InvalidateWindowData(WC_SIGNAL_PROGRAM, (tile << 3) | track);
00686 return CommandCost();
00687 }
00688
00699 CommandCost CmdRemoveSignalInstruction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00700 {
00701 Track track = Extract<Track, 0, 3 >(p1);
00702 uint instruction_id = GB(p1, 3, 16);
00703
00704 if (!IsValidTrack(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
00705 return CMD_ERROR;
00706 }
00707
00708 if (!IsTileOwner(tile, _current_company)) {
00709 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
00710 }
00711
00712 SignalProgram *prog = GetExistingSignalProgram(SignalReference(tile, track));
00713 if (!prog) {
00714 return_cmd_error(STR_ERR_PROGSIG_NOT_THERE);
00715 }
00716
00717 if (instruction_id > prog->instructions.Length()) {
00718 return_cmd_error(STR_ERR_PROGSIG_INVALID_INSTRUCTION);
00719 }
00720
00721 bool exec = (flags & DC_EXEC) != 0;
00722
00723 SignalInstruction *insn = prog->instructions[instruction_id];
00724 switch (insn->Opcode()) {
00725 case PSO_SET_SIGNAL:
00726 case PSO_IF:
00727 if (!exec) return CommandCost();
00728 insn->Remove();
00729 break;
00730
00731 case PSO_FIRST:
00732 case PSO_LAST:
00733 case PSO_IF_ELSE:
00734 case PSO_IF_ENDIF:
00735 default:
00736 return_cmd_error(STR_ERR_PROGSIG_INVALID_OPCODE);
00737 }
00738
00739 if (!exec) return CommandCost();
00740 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
00741 UpdateSignalsInBuffer();
00742 InvalidateWindowData(WC_SIGNAL_PROGRAM, (tile << 3) | track);
00743 return CommandCost();
00744 }
00745
00755 CommandCost CmdSetSignalSpeedLimit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00756 {
00757 Track track = Extract<Track, 0, 3 >(p1);
00758
00759 if (!IsValidTrack(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
00760 return CMD_ERROR;
00761 }
00762
00763 if (!IsTileOwner(tile, _current_company))
00764 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
00765
00766 SignalReference ref = SignalReference(tile, track);
00767 _speedlimits[ref] = p2;
00768
00769 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
00770 UpdateSignalsInBuffer();
00771 InvalidateWindowData(WC_SPEED_SIGNAL, (tile << 3) | track);
00772 return CommandCost();
00773 }