diff --git a/src/economy.cpp b/src/economy.cpp index 7b6228747d..f35188ba7b 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -51,6 +51,7 @@ #include "goal_base.h" #include "story_base.h" #include "linkgraph/refresh.h" +#include "tracerestrict.h" #include "table/strings.h" #include "table/pricebase.h" @@ -486,10 +487,11 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) if (new_owner != INVALID_OWNER) GroupStatistics::UpdateAutoreplace(new_owner); } else { - /* Depending on sharing settings, other companies could be affected too. - * Let the infrastructure sharing code handle this. */ - HandleSharingCompanyDeletion(old_owner); + /* Depending on sharing settings, other companies could be affected too. + * Let the infrastructure sharing code handle this. */ + HandleSharingCompanyDeletion(old_owner); } + TraceRestrictUpdateCompanyID(old_owner, new_owner); /* Change ownership of tiles */ { @@ -509,7 +511,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) /* tracks are being removed while sharing is enabled. * Thus, update all signals and crossings. */ UpdateAllBlockSignals(); - } + } /* Update any signals in the buffer */ UpdateSignalsInBuffer(); } diff --git a/src/lang/english.txt b/src/lang/english.txt index d37f3837a6..342f91f75c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2509,6 +2509,7 @@ STR_TRACE_RESTRICT_VARIABLE_CARGO :cargo STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION :entry direction STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL :PBS entry signal STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL_LONG :entered signal of PBS block +STR_TRACE_RESTRICT_VARIABLE_TRAIN_OWNER :train owner STR_TRACE_RESTRICT_VARIABLE_UNDEFINED :undefined STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_INTEGER :{STRING} {STRING} {STRING} {COMMA} then STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_SPEED :{STRING} {STRING} {STRING} {VELOCITY} then @@ -2519,6 +2520,7 @@ STR_TRACE_RESTRICT_CONDITIONAL_CARGO :{STRING} train STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_DIRECTION :{STRING} train {STRING} entering from {STRING} tile edge then STR_TRACE_RESTRICT_CONDITIONAL_ENTRY_SIGNAL_FACE :{STRING} train {STRING} entering from {STRING} of signal then STR_TRACE_RESTRICT_CONDITIONAL_TILE_INDEX :{STRING} {STRING} {STRING} at {NUM} x {NUM} then +STR_TRACE_RESTRICT_CONDITIONAL_OWNER :{STRING} {STRING} {STRING} {COMPANY} {COMPANY_NUM} then STR_TRACE_RESTRICT_CONDITIONAL_UNDEFINED :{STRING} {STRING} {STRING} {RED}undefined {BLACK}{STRING}then STR_TRACE_RESTRICT_CONDITIONAL_COMPARE_UNDEFINED :{STRING} {RED}undefined {BLACK}{STRING}then STR_TRACE_RESTRICT_PF_PENALTY_ITEM :Add pathfinder penalty: {COMMA} @@ -2542,6 +2544,8 @@ STR_TRACE_RESTRICT_DIRECTION_NE :north-east STR_TRACE_RESTRICT_DIRECTION_SE :south-east STR_TRACE_RESTRICT_DIRECTION_SW :south-west STR_TRACE_RESTRICT_DIRECTION_NW :north-west +STR_TRACE_RESTRICT_COMPANY :Company +STR_TRACE_RESTRICT_UNDEFINED_COMPANY :Undefined company STR_TRACE_RESTRICT_VALUE_CAPTION :{WHITE}Value STR_TRACE_RESTRICT_CAPTION :{WHITE}Routefinding restriction STR_TRACE_RESTRICT_CAPTION_SHARED :{WHITE}Routefinding restriction - shared by {COMMA} signals diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 241f56975f..7d670acdb1 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -48,6 +48,7 @@ static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TRACE_RESTRICT, XSCF_NULL, 3, 3, "tracerestrict", NULL, NULL, "TRRM,TRRP" }, + { XSLFI_TRACE_RESTRICT_OWNER, XSCF_NULL, 1, 1, "tracerestrict_owner", NULL, NULL, NULL }, { XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", NULL, NULL, "SPRG" }, { XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", NULL, NULL, NULL }, { XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL }, diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index d99cf702b2..eef153a3d6 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -22,6 +22,7 @@ enum SlXvFeatureIndex { XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use XSLFI_TRACE_RESTRICT, ///< Trace restrict + XSLFI_TRACE_RESTRICT_OWNER, ///< Trace restrict: train owner test XSLFI_PROG_SIGS, ///< programmable signals patch XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch XSLFI_DEPARTURE_BOARDS, ///< Departure boards patch, in ticks mode diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 49a2cffff5..9207a18b72 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -169,6 +169,11 @@ public: } }; +DropDownListItem *MakeCompanyDropDownListItem(CompanyID cid) +{ + return new DropDownListCompanyItem(cid, false, false); +} + /** * Pop up a generic text only menu. * @param w Toolbar diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h index 37fc8f0e9f..f02d4ea751 100644 --- a/src/toolbar_gui.h +++ b/src/toolbar_gui.h @@ -12,10 +12,15 @@ #ifndef TOOLBAR_GUI_H #define TOOLBAR_GUI_H +#include "company_type.h" +#include "widgets/dropdown_type.h" + void AllocateToolbar(); void ToggleBoundingBoxes(); void ToggleDirtyBlocks(); +DropDownListItem *MakeCompanyDropDownListItem(CompanyID cid); + extern uint _toolbar_width; #endif /* TOOLBAR_GUI_H */ diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index d376376245..8d174a00cf 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -348,6 +348,11 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp break; } + case TRIT_COND_TRAIN_OWNER: { + result = TestBinaryConditionCommon(item, v->owner == condvalue); + break; + } + default: NOT_REACHED(); } @@ -476,6 +481,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector case TRIT_COND_CARGO: case TRIT_COND_ENTRY_DIRECTION: case TRIT_COND_PBS_ENTRY_SIGNAL: + case TRIT_COND_TRAIN_OWNER: break; default: @@ -569,6 +575,11 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp SetTraceRestrictAuxField(item, TRPPAF_PRESET); break; + case TRVT_OWNER: + SetTraceRestrictValue(item, INVALID_OWNER); + SetTraceRestrictAuxField(item, 0); + break; + default: NOT_REACHED(); break; @@ -1091,3 +1102,27 @@ void TraceRestrictRemoveDestinationID(TraceRestrictOrderCondAuxField type, uint1 // update windows InvalidateWindowClassesData(WC_TRACE_RESTRICT); } + +/** + * This is called when a company is about to be deleted or taken over + * Scan program pool and change any references to it to the new company ID, to avoid dangling references + */ +void TraceRestrictUpdateCompanyID(CompanyID old_company, CompanyID new_company) +{ + TraceRestrictProgram *prog; + + FOR_ALL_TRACE_RESTRICT_PROGRAMS(prog) { + for (size_t i = 0; i < prog->items.size(); i++) { + TraceRestrictItem &item = prog->items[i]; // note this is a reference, + if (GetTraceRestrictType(item) == TRIT_COND_TRAIN_OWNER) { + if (GetTraceRestrictValue(item) == old_company) { + SetTraceRestrictValue(item, new_company); // this updates the instruction in-place + } + } + if (IsTraceRestrictDoubleItem(item)) i++; + } + } + + // update windows + InvalidateWindowClassesData(WC_TRACE_RESTRICT); +} diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 3696b44224..7b9791d7f8 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -110,7 +110,7 @@ enum TraceRestrictItemType { TRIT_COND_CARGO = 15, ///< Test if train can carry cargo type TRIT_COND_ENTRY_DIRECTION = 16, ///< Test which side of signal/signal tile is being entered from TRIT_COND_PBS_ENTRY_SIGNAL = 17, ///< Test tile and PBS-state of previous signal - //TRIT_COND_TRAIN_OWNER = 24, ///< Test train owner: reserved for future use + TRIT_COND_TRAIN_OWNER = 24, ///< Test train owner /* space up to 31 */ }; @@ -407,6 +407,7 @@ enum TraceRestrictValueType { TRVT_TILE_INDEX = 8, ///< takes a TileIndex in the next item slot TRVT_PF_PENALTY = 9, ///< takes a pathfinder penalty value or preset index, as per the auxiliary field as type: TraceRestrictPathfinderPenaltyAuxField TRVT_RESERVE_THROUGH = 10,///< takes a value 0 = reserve through, 1 = cancel previous reserve through + TRVT_OWNER = 11,///< takes a CompanyID }; /** @@ -468,6 +469,11 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR out.cond_type = TRCOT_BINARY; break; + case TRIT_COND_TRAIN_OWNER: + out.value_type = TRVT_OWNER; + out.cond_type = TRCOT_BINARY; + break; + default: NOT_REACHED(); break; @@ -560,5 +566,6 @@ CommandCost CmdProgramSignalTraceRestrictProgMgmt(TileIndex tile, DoCommandFlag void ShowTraceRestrictProgramWindow(TileIndex tile, Track track); void TraceRestrictRemoveDestinationID(TraceRestrictOrderCondAuxField type, uint16 index); +void TraceRestrictUpdateCompanyID(CompanyID old_company, CompanyID new_company); #endif /* TRACERESTRICT_H */ diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index efa8d42412..cdc0413e27 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -20,6 +20,7 @@ #include "string_func.h" #include "viewport_func.h" #include "textbuf_gui.h" +#include "company_base.h" #include "company_func.h" #include "tilehighlight_func.h" #include "widgets/dropdown_func.h" @@ -34,6 +35,7 @@ #include "error.h" #include "cargotype.h" #include "table/sprites.h" +#include "toolbar_gui.h" extern uint ConvertSpeedToDisplaySpeed(uint speed); extern uint ConvertDisplaySpeedToSpeed(uint speed); @@ -249,6 +251,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictI STR_TRACE_RESTRICT_VARIABLE_CARGO, STR_TRACE_RESTRICT_VARIABLE_ENTRY_DIRECTION, STR_TRACE_RESTRICT_VARIABLE_PBS_ENTRY_SIGNAL, + STR_TRACE_RESTRICT_VARIABLE_TRAIN_OWNER, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED, INVALID_STRING_ID, }; @@ -261,6 +264,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictI TRIT_COND_CARGO, TRIT_COND_ENTRY_DIRECTION, TRIT_COND_PBS_ENTRY_SIGNAL, + TRIT_COND_TRAIN_OWNER, TRIT_COND_UNDEFINED, }; static const TraceRestrictDropDownListSet set_cond = { @@ -614,6 +618,22 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric break; } + case TRVT_OWNER: { + assert(GetTraceRestrictCondFlags(item) <= TRCF_OR); + CompanyID cid = static_cast(GetTraceRestrictValue(item)); + if (cid == INVALID_COMPANY) { + DrawInstructionStringConditionalInvalidValue(item, properties, instruction_string, selected); + } else { + instruction_string = STR_TRACE_RESTRICT_CONDITIONAL_OWNER; + SetDParam(0, _program_cond_type[GetTraceRestrictCondFlags(item)]); + SetDParam(1, GetTypeString(GetTraceRestrictType(item))); + SetDParam(2, GetDropDownStringByValue(GetCondOpDropDownListSet(properties), GetTraceRestrictCondOp(item))); + SetDParam(3, cid); + SetDParam(4, cid); + } + break; + } + default: NOT_REACHED(); break; @@ -681,6 +701,7 @@ class TraceRestrictWindow: public Window { int selected_instruction; ///< selected instruction index, this is offset by one due to the display of the "start" item Scrollbar *vscroll; ///< scrollbar widget std::map drop_down_list_mapping; ///< mapping of widget IDs to drop down list sets + bool value_drop_down_is_company; ///< TR_WIDGET_VALUE_DROPDOWN is a company list TraceRestrictItem expecting_inserted_item; ///< set to instruction when performing an instruction insertion, used to handle selection update on insertion int current_placement_widget; ///< which widget has a SetObjectToPlaceWnd, if any @@ -870,6 +891,10 @@ public: this->ShowDropDownListWithValue(&_reserve_through_value, GetTraceRestrictValue(item), false, TR_WIDGET_VALUE_DROPDOWN, 0, 0, 0); break; + case TRVT_OWNER: + this->ShowCompanyDropDownListWithValue(static_cast(GetTraceRestrictValue(item)), false, TR_WIDGET_VALUE_DROPDOWN); + break; + default: break; } @@ -941,6 +966,13 @@ public: return; } + if (widget == TR_WIDGET_VALUE_DROPDOWN && this->value_drop_down_is_company) { + // this is a special company drop-down + SetTraceRestrictValue(item, index); + TraceRestrictDoCommandP(this->tile, this->track, TRDCT_MODIFY_ITEM, this->selected_instruction - 1, item, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM); + return; + } + const TraceRestrictDropDownListSet *list_set = this->drop_down_list_mapping[widget]; if (!list_set) { return; @@ -1615,6 +1647,12 @@ private: GetTraceRestrictValue(item) ? STR_TRACE_RESTRICT_RESERVE_THROUGH_CANCEL : STR_TRACE_RESTRICT_RESERVE_THROUGH; break; + case TRVT_OWNER: + right_sel->SetDisplayedPlane(DPR_VALUE_DROPDOWN); + this->EnableWidget(TR_WIDGET_VALUE_DROPDOWN); + this->GetWidget(TR_WIDGET_VALUE_DROPDOWN)->widget_data = STR_TRACE_RESTRICT_COMPANY; + break; + default: break; } @@ -1637,9 +1675,33 @@ private: { drop_down_list_mapping[button] = list_set; int selected = GetDropDownListIndexByValue(list_set, value, missing_ok); + if (button == TR_WIDGET_VALUE_DROPDOWN) this->value_drop_down_is_company = false; ShowDropDownMenu(this, list_set->string_array, selected, button, disabled_mask, hidden_mask, width); } + /** + * Show a drop down list using @p list_set, setting the pre-selected item to the one corresponding to @p value + * This asserts if @p value is not in @p list_set, and @p missing_ok is false + */ + void ShowCompanyDropDownListWithValue(CompanyID value, bool missing_ok, int button) + { + DropDownList *list = new DropDownList(); + + Company *c; + FOR_ALL_COMPANIES(c) { + *(list->Append()) = MakeCompanyDropDownListItem(c->index); + if (c->index == value) missing_ok = true; + } + *(list->Append()) = new DropDownListStringItem(STR_TRACE_RESTRICT_UNDEFINED_COMPANY, INVALID_COMPANY, false); + if (INVALID_COMPANY == value) missing_ok = true; + + assert(missing_ok == true); + assert(button == TR_WIDGET_VALUE_DROPDOWN); + this->value_drop_down_is_company = true; + + ShowDropDownList(this, list, value, button, 0, true, false); + } + /** * Helper function to set or unset a SetObjectToPlaceWnd, for the given widget and cursor type */