diff --git a/src/command.cpp b/src/command.cpp index 28b9f0f119..c9801667af 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -245,6 +245,9 @@ CommandProc CmdAlterTraceRestrictSlot; CommandProc CmdDeleteTraceRestrictSlot; CommandProc CmdAddVehicleTraceRestrictSlot; CommandProc CmdRemoveVehicleTraceRestrictSlot; +CommandProc CmdCreateTraceRestrictCounter; +CommandProc CmdAlterTraceRestrictCounter; +CommandProc CmdDeleteTraceRestrictCounter; CommandProc CmdInsertSignalInstruction; CommandProc CmdModifySignalInstruction; @@ -469,6 +472,9 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdDeleteTraceRestrictSlot, 0, CMDT_OTHER_MANAGEMENT ), // CMD_DELETE_TRACERESTRICT_SLOT DEF_CMD(CmdAddVehicleTraceRestrictSlot, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_VEHICLE_TRACERESTRICT_SLOT DEF_CMD(CmdRemoveVehicleTraceRestrictSlot, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_VEHICLE_TRACERESTRICT_SLOT + DEF_CMD(CmdCreateTraceRestrictCounter, 0, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_TRACERESTRICT_COUNTER + DEF_CMD(CmdAlterTraceRestrictCounter, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ALTER_TRACERESTRICT_COUNTER + DEF_CMD(CmdDeleteTraceRestrictCounter, 0, CMDT_OTHER_MANAGEMENT ), // CMD_DELETE_TRACERESTRICT_COUNTER DEF_CMD(CmdInsertSignalInstruction, 0, CMDT_OTHER_MANAGEMENT ), // CMD_INSERT_SIGNAL_INSTRUCTION DEF_CMD(CmdModifySignalInstruction, 0, CMDT_OTHER_MANAGEMENT ), // CMD_MODIFY_SIGNAL_INSTRUCTION diff --git a/src/command_type.h b/src/command_type.h index 2a2985fd21..d2b68f9d3e 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -408,6 +408,9 @@ enum Commands { CMD_DELETE_TRACERESTRICT_SLOT, ///< delete a tracerestrict slot CMD_ADD_VEHICLE_TRACERESTRICT_SLOT, ///< add a vehicle to a tracerestrict slot CMD_REMOVE_VEHICLE_TRACERESTRICT_SLOT, ///< remove a vehicle from a tracerestrict slot + CMD_CREATE_TRACERESTRICT_COUNTER, ///< create a tracerestrict counter + CMD_ALTER_TRACERESTRICT_COUNTER, ///< alter a tracerestrict counter + CMD_DELETE_TRACERESTRICT_COUNTER, ///< delete a tracerestrict counter CMD_INSERT_SIGNAL_INSTRUCTION, ///< insert a signal instruction CMD_MODIFY_SIGNAL_INSTRUCTION, ///< modifies a signal instruction diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 396b7eca05..d31d3cad7b 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -1006,6 +1006,12 @@ public: break; } + case ADI_TRACERESTRICT_COUNTER_MGMT: { + extern void ShowTraceRestrictCounterWindow(CompanyID company); + ShowTraceRestrictCounterWindow(this->owner); + break; + } + default: NOT_REACHED(); } break; diff --git a/src/lang/english.txt b/src/lang/english.txt index d7f6637b82..0cbc376767 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2731,6 +2731,7 @@ STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY :slot occupancy STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_REMAINING :slot occupancy remaining STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_SHORT :occupancy STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_REMAINING_SHORT :occupancy remaining +STR_TRACE_RESTRICT_VARIABLE_COUNTER_VALUE :counter value STR_TRACE_RESTRICT_VARIABLE_TRAIN_WEIGHT :weight STR_TRACE_RESTRICT_VARIABLE_TRAIN_POWER :power STR_TRACE_RESTRICT_VARIABLE_TRAIN_MAX_TE :max T.E. @@ -2762,6 +2763,8 @@ STR_TRACE_RESTRICT_CONDITIONAL_SLOT_STR :{STRING} train STR_TRACE_RESTRICT_CONDITIONAL_SLOT_OCCUPANCY :{STRING} {STRING} of slot: {TRSLOT} {STRING} {COMMA} then STR_TRACE_RESTRICT_CONDITIONAL_SLOT_OCCUPANCY_STR :{STRING} {STRING} of slot: {STRING} {BLACK}{STRING} {STRING} {COMMA} then STR_TRACE_RESTRICT_CONDITIONAL_TRAIN_STATUS :{STRING} train {STRING} status: {STRING} then +STR_TRACE_RESTRICT_CONDITIONAL_COUNTER :{STRING} value of counter: {TRCOUNTER} {STRING} {COMMA} then +STR_TRACE_RESTRICT_CONDITIONAL_COUNTER_STR :{STRING} value of counter: {STRING} {BLACK}{STRING} {STRING} {COMMA} 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} @@ -2799,6 +2802,7 @@ STR_TRACE_RESTRICT_SLOT_OP :Slot operation STR_TRACE_RESTRICT_REVERSE :Reverse STR_TRACE_RESTRICT_SPEED_RESTRICTION :Speed restriction STR_TRACE_RESTRICT_NEWS_CONTROL :News control +STR_TRACE_RESTRICT_COUNTER_OP :Counter operation STR_TRACE_RESTRICT_SLOT_ACQUIRE_WAIT :Acquire or wait STR_TRACE_RESTRICT_SLOT_TRY_ACQUIRE :Try to acquire STR_TRACE_RESTRICT_SLOT_RELEASE_FRONT :Release (front) @@ -2816,6 +2820,13 @@ STR_TRACE_RESTRICT_SLOT_PBS_RES_END_RELEASE_ITEM :PBS reservation STR_TRACE_RESTRICT_SLOT_NAME :{TRSLOT} STR_TRACE_RESTRICT_SLOT_LIST_HEADER :{BLACK}Slot{CONSUME_ARG}{P "" s}: {LTBLUE} STR_TRACE_RESTRICT_SLOT_LIST_SEPARATOR :{BLACK}, {LTBLUE} +STR_TRACE_RESTRICT_COUNTER_NAME :{TRCOUNTER} +STR_TRACE_RESTRICT_COUNTER_INCREASE :Increase +STR_TRACE_RESTRICT_COUNTER_DECREASE :Decrease +STR_TRACE_RESTRICT_COUNTER_SET :Set +STR_TRACE_RESTRICT_COUNTER_INCREASE_ITEM :Increase counter: {STRING1}{BLACK}{STRING} by {COMMA} +STR_TRACE_RESTRICT_COUNTER_DECREASE_ITEM :Decrease counter: {STRING1}{BLACK}{STRING} by {COMMA} +STR_TRACE_RESTRICT_COUNTER_SET_ITEM :Set counter: {STRING1}{BLACK}{STRING} to {COMMA} STR_TRACE_RESTRICT_TRAIN_STATUS_EMPTY :empty STR_TRACE_RESTRICT_TRAIN_STATUS_FULL :full STR_TRACE_RESTRICT_TRAIN_STATUS_BROKEN_DOWN :broken down @@ -2859,6 +2870,23 @@ STR_TRACE_RESTRICT_SLOT_CREATE_CAPTION :{BLACK}Create a STR_TRACE_RESTRICT_SLOT_SET_MAX_OCCUPANCY_CAPTION :{BLACK}Set maximum occupancy of a slot STR_TRACE_RESTRICT_SLOT_QUERY_DELETE_CAPTION :{WHITE}Delete Slot STR_TRACE_RESTRICT_SLOT_DELETE_QUERY_TEXT :{WHITE}Are you sure you want to delete this slot? +STR_TRACE_RESTRICT_COUNTER_OP_TOOLTIP :{BLACK}Counter operation type +STR_TRACE_RESTRICT_COUNTER_GUI_LIST_TOOLTIP :{BLACK}Counters - click on a counter to modify it. +STR_TRACE_RESTRICT_COUNTER_CREATE :{BLACK}Create +STR_TRACE_RESTRICT_COUNTER_DELETE :{BLACK}Delete +STR_TRACE_RESTRICT_COUNTER_RENAME :{BLACK}Rename +STR_TRACE_RESTRICT_COUNTER_SET_VALUE :{BLACK}Set Value +STR_TRACE_RESTRICT_COUNTER_CREATE_TOOLTIP :{BLACK}Click to create a counter +STR_TRACE_RESTRICT_COUNTER_DELETE_TOOLTIP :{BLACK}Delete the selected counter +STR_TRACE_RESTRICT_COUNTER_RENAME_TOOLTIP :{BLACK}Rename the selected counter +STR_TRACE_RESTRICT_COUNTER_SET_VALUE_TOOLTIP :{BLACK}Set the value of the selected counter +STR_TRACE_RESTRICT_COUNTER_CAPTION :{WHITE}Routing Restrictions - Counter Management +STR_TRACE_RESTRICT_COUNTER_MANAGE :Manage counters +STR_TRACE_RESTRICT_COUNTER_RENAME_CAPTION :{BLACK}Rename a counter +STR_TRACE_RESTRICT_COUNTER_CREATE_CAPTION :{BLACK}Create a counter +STR_TRACE_RESTRICT_COUNTER_SET_VALUE_CAPTION :{BLACK}Set counter value +STR_TRACE_RESTRICT_COUNTER_QUERY_DELETE_CAPTION :{WHITE}Delete counter +STR_TRACE_RESTRICT_COUNTER_DELETE_QUERY_TEXT :{WHITE}Are you sure you want to delete this counter? STR_TRACE_RESTRICT_INSERT :{BLACK}Insert STR_TRACE_RESTRICT_REMOVE :{BLACK}Remove STR_TRACE_RESTRICT_RESET :{BLACK}Reset @@ -2903,6 +2931,10 @@ STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_RENAME :{WHITE}Can't re STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this slot... STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_REMOVE_VEHICLE :{WHITE}Can't remove the vehicle from this slot... STR_TRACE_RESTRICT_ERROR_SLOT_CAN_T_SET_MAX_OCCUPANCY :{WHITE}Can't set maximum occupancy of this slot... +STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_CREATE :{WHITE}Can't create counter... +STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_DELETE :{WHITE}Can't delete this counter... +STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_RENAME :{WHITE}Can't rename counter... +STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_MODIFY :{WHITE}Can't modify this counter... # Programmable Pre-Signals STR_PROGRAM_SIGNAL_TOOLTIP :{BLACK}Program pre-signal diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 60e2709a77..dcc2360f6a 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -71,6 +71,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TRACE_RESTRICT_STATUSCND,XSCF_NULL, 1, 1, "tracerestrict_status_cond", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_REVERSE, XSCF_NULL, 1, 1, "tracerestrict_reverse", nullptr, nullptr, nullptr }, { XSLFI_TRACE_RESTRICT_NEWSCTRL,XSCF_NULL, 1, 1, "tracerestrict_newsctrl", nullptr, nullptr, nullptr }, + { XSLFI_TRACE_RESTRICT_COUNTER, XSCF_NULL, 1, 1, "tracerestrict_counter", nullptr, nullptr, "TRRC" }, { XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", nullptr, nullptr, "SPRG" }, { XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", nullptr, nullptr, nullptr }, { XSLFI_SAFER_CROSSINGS, XSCF_NULL, 1, 1, "safer_crossings", nullptr, nullptr, nullptr }, diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 5b732ac05e..d273664bf0 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -28,6 +28,7 @@ enum SlXvFeatureIndex { XSLFI_TRACE_RESTRICT_STATUSCND, ///< Trace restrict: train status condition XSLFI_TRACE_RESTRICT_REVERSE, ///< Trace restrict: reverse XSLFI_TRACE_RESTRICT_NEWSCTRL, ///< Trace restrict: news control + XSLFI_TRACE_RESTRICT_COUNTER, ///< Trace restrict: counters XSLFI_PROG_SIGS, ///< programmable pre-signals patch XSLFI_ADJACENT_CROSSINGS, ///< Adjacent level crossings closure patch XSLFI_SAFER_CROSSINGS, ///< Safer level crossings diff --git a/src/saveload/tracerestrict_sl.cpp b/src/saveload/tracerestrict_sl.cpp index 89d795a39d..98ef076603 100644 --- a/src/saveload/tracerestrict_sl.cpp +++ b/src/saveload/tracerestrict_sl.cpp @@ -170,6 +170,44 @@ static void Save_TRRS() } } +static const SaveLoad _trace_restrict_counter_desc[] = { + SLE_VAR(TraceRestrictCounter, value, SLE_INT32), + SLE_SSTR(TraceRestrictCounter, name, SLF_ALLOW_CONTROL), + SLE_VAR(TraceRestrictCounter, owner, SLE_UINT8), + SLE_END() +}; + +/** + * Load counter pool + */ +static void Load_TRRC() +{ + int index; + while ((index = SlIterateArray()) != -1) { + TraceRestrictCounter *ctr = new (index) TraceRestrictCounter(); + SlObject(ctr, _trace_restrict_counter_desc); + } +} + +/** + * Save a counter, used by SlAutolength + */ +static void RealSave_TRRC(TraceRestrictCounter *ctr) +{ + SlObject(ctr, _trace_restrict_counter_desc); +} + +/** + * Save counter pool + */ +static void Save_TRRC() +{ + for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + SlSetArrayIndex(ctr->index); + SlAutolength((AutolengthProc*) RealSave_TRRC, ctr); + } +} + /** * Update program reference counts from just-loaded mapping */ @@ -184,5 +222,6 @@ void AfterLoadTraceRestrict() extern const ChunkHandler _trace_restrict_chunk_handlers[] = { { 'TRRM', Save_TRRM, Load_TRRM, nullptr, nullptr, CH_SPARSE_ARRAY}, // Trace Restrict Mapping chunk { 'TRRP', Save_TRRP, Load_TRRP, nullptr, nullptr, CH_ARRAY}, // Trace Restrict Mapping Program Pool chunk - { 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_ARRAY | CH_LAST}, // Trace Restrict Slot Pool chunk + { 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_ARRAY}, // Trace Restrict Slot Pool chunk + { 'TRRC', Save_TRRC, Load_TRRC, nullptr, nullptr, CH_ARRAY | CH_LAST}, // Trace Restrict Counter Pool chunk }; diff --git a/src/strings.cpp b/src/strings.cpp index e20da934a5..9d9901d50e 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1783,6 +1783,15 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg break; } + case SCC_TR_COUNTER_NAME: { // {TRCOUNTER} + const TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(args->GetInt32(SCC_TR_SLOT_NAME)); + if (ctr == nullptr) break; + int64 args_array[] = {(int64)(size_t)ctr->name.c_str()}; + StringParameters tmp_params(args_array); + buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); + break; + } + case SCC_STATION_FEATURES: { // {STATIONFEATURES} buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last); break; diff --git a/src/table/control_codes.h b/src/table/control_codes.h index 893bfd91cc..be5e00a555 100644 --- a/src/table/control_codes.h +++ b/src/table/control_codes.h @@ -48,6 +48,7 @@ enum StringControlCode { SCC_PRESIDENT_NAME, SCC_ENGINE_NAME, SCC_TR_SLOT_NAME, + SCC_TR_COUNTER_NAME, SCC_CURRENCY_SHORT, SCC_CURRENCY_LONG, diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index 6e7238d16e..a3a841641e 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -127,6 +127,7 @@ static const CmdStruct _cmd_structs[] = { {"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, -1, C_NONE}, {"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, -1, C_NONE | C_GENDER}, {"TRSLOT", EmitSingleChar, SCC_TR_SLOT_NAME, 1, -1, C_NONE | C_GENDER}, + {"TRCOUNTER", EmitSingleChar, SCC_TR_COUNTER_NAME, 1, -1, C_NONE | C_GENDER}, {"", EmitSingleChar, '\n', 0, -1, C_DONTCOUNT}, {"{", EmitSingleChar, '{', 0, -1, C_DONTCOUNT}, diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 41729e0a1c..0a17c3a875 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -69,6 +69,9 @@ INSTANTIATE_POOL_METHODS(TraceRestrictProgram) TraceRestrictSlotPool _tracerestrictslot_pool("TraceRestrictSlot"); INSTANTIATE_POOL_METHODS(TraceRestrictSlot) +TraceRestrictCounterPool _tracerestrictcounter_pool("TraceRestrictCounter"); +INSTANTIATE_POOL_METHODS(TraceRestrictCounter) + /** * TraceRestrictRefId --> TraceRestrictProgramID (Pool ID) mapping * The indirection is mainly to enable shared programs @@ -499,6 +502,15 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp break; } + case TRIT_COND_COUNTER_VALUE: { + // TRVT_COUNTER_INDEX_INT value type uses the next slot + i++; + uint32_t value = this->items[i]; + const TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GetTraceRestrictValue(item)); + result = TestCondition(ctr != nullptr ? ctr->value : 0, condop, value); + break; + } + default: NOT_REACHED(); } @@ -657,6 +669,33 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp } break; + case TRIT_COUNTER: { + // TRVT_COUNTER_INDEX_INT value type uses the next slot + i++; + uint32_t value = this->items[i]; + if (!(input.permitted_slot_operations & TRPISP_CHANGE_COUNTER)) break; + TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GetTraceRestrictValue(item)); + if (ctr == nullptr) break; + switch (static_cast(GetTraceRestrictCondOp(item))) { + case TRCCOF_INCREASE: + ctr->UpdateValue(ctr->value + value); + break; + + case TRCCOF_DECREASE: + ctr->UpdateValue(ctr->value - value); + break; + + case TRCCOF_SET: + ctr->UpdateValue(value); + break; + + default: + NOT_REACHED(); + break; + } + break; + } + default: NOT_REACHED(); } @@ -751,6 +790,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector case TRIT_COND_TRAIN_OWNER: case TRIT_COND_TRAIN_STATUS: case TRIT_COND_LOAD_PERCENT: + case TRIT_COND_COUNTER_VALUE: break; default: @@ -834,6 +874,10 @@ CommandCost TraceRestrictProgram::Validate(const std::vector actions_used_flags |= TRPAUF_TRAIN_NOT_STUCK; break; + case TRIT_COUNTER: + actions_used_flags |= TRPAUF_CHANGE_COUNTER; + break; + default: return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION); } @@ -943,6 +987,10 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp SetTraceRestrictValue(item, INVALID_TRACE_RESTRICT_SLOT_ID); break; + case TRVT_COUNTER_INDEX_INT: + SetTraceRestrictValue(item, INVALID_TRACE_RESTRICT_COUNTER_ID); + break; + default: NOT_REACHED(); break; @@ -1147,8 +1195,12 @@ static uint32 GetDualInstructionInitialValue(TraceRestrictItem item) return INVALID_TILE; case TRIT_COND_SLOT_OCCUPANCY: + case TRIT_COND_COUNTER_VALUE: return 0; + case TRIT_COUNTER: + return 1; + default: NOT_REACHED(); } @@ -1636,9 +1688,20 @@ void TraceRestrictUpdateCompanyID(CompanyID old_company, CompanyID new_company) } } + for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + if (ctr->owner != old_company) continue; + if (new_company == INVALID_OWNER) { + TraceRestrictRemoveCounterID(ctr->index); + delete ctr; + } else { + ctr->owner = new_company; + } + } + // update windows InvalidateWindowClassesData(WC_TRACE_RESTRICT); InvalidateWindowClassesData(WC_TRACE_RESTRICT_SLOTS); + InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS); } static std::unordered_multimap slot_vehicle_index; @@ -1922,7 +1985,7 @@ CommandCost CmdDeleteTraceRestrictSlot(TileIndex tile, DoCommandFlag flags, uint * @param flags type of operation * @param p1 index of array group * - p1 bit 0-15 : GroupID - * - p1 bit 16: 0 - Rename grouop + * - p1 bit 16: 0 - Rename group * 1 - Change max occupancy * @param p2 new max occupancy * @param text the new name @@ -2012,3 +2075,148 @@ CommandCost CmdRemoveVehicleTraceRestrictSlot(TileIndex tile, DoCommandFlag flag return CommandCost(); } + +void TraceRestrictCounter::UpdateValue(int32 new_value) +{ + new_value = max(0, new_value); + if (new_value != this->value) { + this->value = new_value; + InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS); + } +} + +static bool IsUniqueCounterName(const char *name) +{ + for (const TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + if (ctr->name == name) return false; + } + return true; +} + +/** + * This is called when a counter is about to be deleted + * Scan program pool and change any references to it to the invalid counter ID, to avoid dangling references + */ +void TraceRestrictRemoveCounterID(TraceRestrictCounterID index) +{ + for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) { + for (size_t i = 0; i < prog->items.size(); i++) { + TraceRestrictItem &item = prog->items[i]; // note this is a reference, + if ((GetTraceRestrictType(item) == TRIT_COUNTER || GetTraceRestrictType(item) == TRIT_COND_COUNTER_VALUE) && GetTraceRestrictValue(item) == index) { + SetTraceRestrictValueDefault(item, TRVT_COUNTER_INDEX_INT); // this updates the instruction in-place + } + if (IsTraceRestrictDoubleItem(item)) i++; + } + } + + // update windows + InvalidateWindowClassesData(WC_TRACE_RESTRICT); +} + +/** + * Create a new counter. + * @param tile unused + * @param flags type of operation + * @param p1 unused + * @param p2 unused + * @param text new counter name + * @return the cost of this operation or an error + */ +CommandCost CmdCreateTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (!TraceRestrictCounter::CanAllocateItem()) return CMD_ERROR; + if (StrEmpty(text)) return CMD_ERROR; + + size_t length = Utf8StringLength(text); + if (length <= 0) return CMD_ERROR; + if (length >= MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS) return CMD_ERROR; + if (!IsUniqueCounterName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); + + if (flags & DC_EXEC) { + TraceRestrictCounter *ctr = new TraceRestrictCounter(_current_company); + ctr->name = text; + + // update windows + InvalidateWindowClassesData(WC_TRACE_RESTRICT); + InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS); + } + + return CommandCost(); +} + + +/** + * Deletes a counter. + * @param tile unused + * @param flags type of operation + * @param p1 index of array group + * - p1 bit 0-15 : Counter ID + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDeleteTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(p1); + if (ctr == nullptr || ctr->owner != _current_company) return CMD_ERROR; + + if (flags & DC_EXEC) { + /* notify tracerestrict that counter is about to be deleted */ + TraceRestrictRemoveCounterID(ctr->index); + + delete ctr; + + InvalidateWindowClassesData(WC_TRACE_RESTRICT); + InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS); + InvalidateWindowClassesData(WC_VEHICLE_ORDERS); + } + + return CommandCost(); +} + +/** + * Alter a counter + * @param tile unused + * @param flags type of operation + * @param p1 index of array counter + * - p1 bit 0-15 : Counter ID + * - p1 bit 16: 0 - Rename counter + * 1 - Change value + * @param p2 new value + * @param text the new name + * @return the cost of this operation or an error + */ +CommandCost CmdAlterTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GB(p1, 0, 16)); + if (ctr == nullptr || ctr->owner != _current_company) return CMD_ERROR; + + if (!HasBit(p1, 16)) { + /* Rename counter */ + + if (StrEmpty(text)) return CMD_ERROR; + size_t length = Utf8StringLength(text); + if (length <= 0) return CMD_ERROR; + if (length >= MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS) return CMD_ERROR; + if (!IsUniqueCounterName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); + + if (flags & DC_EXEC) { + ctr->name = text; + } + } else { + /* Change value */ + + if (flags & DC_EXEC) { + ctr->UpdateValue(p2); + } + } + + if (flags & DC_EXEC) { + // update windows + InvalidateWindowClassesData(WC_TRACE_RESTRICT); + InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS); + InvalidateWindowClassesData(WC_VEHICLE_ORDERS); + } + + return CommandCost(); +} diff --git a/src/tracerestrict.h b/src/tracerestrict.h index 68835ccfe4..1bc3167c6f 100644 --- a/src/tracerestrict.h +++ b/src/tracerestrict.h @@ -52,6 +52,18 @@ static const TraceRestrictSlotID NEW_TRACE_RESTRICT_SLOT_ID = 0xFFFD; // static const TraceRestrictSlotID ALL_TRAINS_TRACE_RESTRICT_SLOT_ID = 0xFFFE; // for GUI use only static const TraceRestrictSlotID INVALID_TRACE_RESTRICT_SLOT_ID = 0xFFFF; +/** Counter pool ID type. */ +typedef uint16 TraceRestrictCounterID; +struct TraceRestrictCounter; + +/** Type of the pool for trace restrict slots. */ +typedef Pool TraceRestrictCounterPool; +/** The actual pool for trace restrict nodes. */ +extern TraceRestrictCounterPool _tracerestrictcounter_pool; + +static const TraceRestrictCounterID NEW_TRACE_RESTRICT_COUNTER_ID = 0xFFFE; // for GUI use only +static const TraceRestrictCounterID INVALID_TRACE_RESTRICT_COUNTER_ID = 0xFFFF; + extern const uint16 _tracerestrict_pathfinder_penalty_preset_values[]; /** Type used for the TraceRestrictRefId -> TraceRestrictProgramID mapping */ @@ -136,11 +148,13 @@ enum TraceRestrictItemType { TRIT_COND_TRAIN_OWNER = 24, ///< Test train owner TRIT_COND_TRAIN_STATUS = 25, ///< Test train status TRIT_COND_LOAD_PERCENT = 26, ///< Test train load percentage + TRIT_COND_COUNTER_VALUE = 27, ///< Test counter value TRIT_COND_END = 48, ///< End (exclusive) of conditional item types, note that this has the same value as TRIT_REVERSE TRIT_REVERSE = 48, ///< Reverse behind signal TRIT_SPEED_RESTRICTION = 49, ///< Speed restriction TRIT_NEWS_CONTROL = 50, ///< News control + TRIT_COUNTER = 51, ///< Change counter value /* space up to 63 */ }; @@ -294,6 +308,16 @@ enum TraceRestrictSlotOccupancyCondAuxField { /* space up to 3 */ }; +/** + * TraceRestrictItem repurposed condition operator field, for counter operation type actions + */ +enum TraceRestrictCounterCondOpField { + TRCCOF_INCREASE = 0, ///< increase counter by value + TRCCOF_DECREASE = 1, ///< decrease counter by value + TRCCOF_SET = 2, ///< set counter to value + /* space up to 8 */ +}; + /** * TraceRestrictItem pathfinder penalty preset index * This may not be shortened, only lengthened, as preset indexes are stored in save games @@ -336,6 +360,7 @@ enum TraceRestrictProgramActionsUsedFlags { TRPAUF_REVERSE = 1 << 9, ///< Reverse behind signal TRPAUF_SPEED_RESTRICTION = 1 << 10, ///< Speed restriction TRPAUF_TRAIN_NOT_STUCK = 1 << 11, ///< Train is not stuck + TRPAUF_CHANGE_COUNTER = 1 << 12, ///< Change counter value is present }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramActionsUsedFlags) @@ -349,6 +374,7 @@ enum TraceRestrictProgramInputSlotPermissions { TRPISP_PBS_RES_END_ACQUIRE = 1 << 3, ///< Slot acquire (PBS reservations ending at this signal) is permitted TRPISP_PBS_RES_END_ACQ_DRY = 1 << 4, ///< Dry-run slot acquire (PBS reservations ending at this signal) is permitted TRPISP_PBS_RES_END_RELEASE = 1 << 5, ///< Slot release (PBS reservations ending at this signal) is permitted + TRPISP_CHANGE_COUNTER = 1 << 6, ///< Change counter value is permitted }; DECLARE_ENUM_AS_BIT_SET(TraceRestrictProgramInputSlotPermissions) @@ -527,7 +553,7 @@ static inline bool IsTraceRestrictConditional(TraceRestrictItem item) static inline bool IsTraceRestrictDoubleItem(TraceRestrictItem item) { const TraceRestrictItemType type = GetTraceRestrictType(item); - return type == TRIT_COND_PBS_ENTRY_SIGNAL || type == TRIT_COND_SLOT_OCCUPANCY; + return type == TRIT_COND_PBS_ENTRY_SIGNAL || type == TRIT_COND_SLOT_OCCUPANCY || type == TRIT_COUNTER || type == TRIT_COND_COUNTER_VALUE; } /** @@ -571,6 +597,7 @@ enum TraceRestrictValueType { TRVT_TRAIN_STATUS = 41,///< takes a TraceRestrictTrainStatusValueField TRVT_REVERSE = 42,///< takes a TraceRestrictReverseValueField TRVT_NEWS_CONTROL = 43,///< takes a TraceRestrictNewsControlField + TRVT_COUNTER_INDEX_INT = 44,///< takes a TraceRestrictCounterID, and an integer in the next item slot }; /** @@ -696,6 +723,10 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR out.value_type = TRVT_PERCENT; break; + case TRIT_COND_COUNTER_VALUE: + out.value_type = TRVT_COUNTER_INDEX_INT; + break; + default: NOT_REACHED(); break; @@ -720,6 +751,8 @@ static inline TraceRestrictTypePropertySet GetTraceRestrictTypeProperties(TraceR out.value_type = TRVT_SPEED; } else if (GetTraceRestrictType(item) == TRIT_NEWS_CONTROL) { out.value_type = TRVT_NEWS_CONTROL; + } else if (GetTraceRestrictType(item) == TRIT_COUNTER) { + out.value_type = TRVT_COUNTER_INDEX_INT; } else { out.value_type = TRVT_NONE; } @@ -823,6 +856,7 @@ void TraceRestrictRemoveDestinationID(TraceRestrictOrderCondAuxField type, uint1 void TraceRestrictRemoveGroupID(GroupID index); void TraceRestrictUpdateCompanyID(CompanyID old_company, CompanyID new_company); void TraceRestrictRemoveSlotID(TraceRestrictSlotID index); +void TraceRestrictRemoveCounterID(TraceRestrictCounterID index); void TraceRestrictRemoveVehicleFromAllSlots(VehicleID id); void TraceRestrictTransferVehicleOccupantInAllSlots(VehicleID from, VehicleID to); @@ -871,4 +905,20 @@ struct TraceRestrictSlot : TraceRestrictSlotPool::PoolItem<&_tracerestrictslot_p void DeIndex(VehicleID id); }; +/** + * Slot type, used for slot operations + */ +struct TraceRestrictCounter : TraceRestrictCounterPool::PoolItem<&_tracerestrictcounter_pool> { + int32 value = 0; + std::string name; + Owner owner; + + TraceRestrictCounter(CompanyID owner = INVALID_COMPANY) + { + this->owner = owner; + } + + void UpdateValue(int32 new_value); +}; + #endif /* TRACERESTRICT_H */ diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 9d9105f2b3..b99d0b314e 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -69,6 +69,7 @@ enum TraceRestrictWindowWidgets { TR_WIDGET_CONDFLAGS, TR_WIDGET_COMPARATOR, TR_WIDGET_SLOT_OP, + TR_WIDGET_COUNTER_OP, TR_WIDGET_VALUE_INT, TR_WIDGET_VALUE_DECIMAL, TR_WIDGET_VALUE_DROPDOWN, @@ -100,6 +101,7 @@ enum PanelWidgets { // Left DPL_TYPE = 0, + DPL_COUNTER_OP, DPL_BLANK, // Left aux @@ -153,6 +155,7 @@ static const StringID _program_insert_str[] = { STR_TRACE_RESTRICT_REVERSE, STR_TRACE_RESTRICT_SPEED_RESTRICTION, STR_TRACE_RESTRICT_NEWS_CONTROL, + STR_TRACE_RESTRICT_COUNTER_OP, INVALID_STRING_ID }; static const uint32 _program_insert_else_hide_mask = 8; ///< disable bitmask for else @@ -162,6 +165,7 @@ static const uint32 _program_wait_pbs_hide_mask = 0x100; ///< disable bitm static const uint32 _program_slot_hide_mask = 0x200; ///< disable bitmask for slot static const uint32 _program_reverse_hide_mask = 0x400; ///< disable bitmask for reverse static const uint32 _program_speed_res_hide_mask = 0x800; ///< disable bitmask for speed restriction +static const uint32 _program_counter_hide_mask = 0x2000; ///< disable bitmask for counter static const uint _program_insert_val[] = { TRIT_COND_UNDEFINED, // if block TRIT_COND_UNDEFINED | (TRCF_ELSE << 16), // elif block @@ -176,6 +180,7 @@ static const uint _program_insert_val[] = { TRIT_REVERSE, // reverse TRIT_SPEED_RESTRICTION, // speed restriction TRIT_NEWS_CONTROL, // news control + TRIT_COUNTER, // counter operation }; /** insert drop down list strings and values */ @@ -392,6 +397,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG STR_TRACE_RESTRICT_REVERSE, STR_TRACE_RESTRICT_SPEED_RESTRICTION, STR_TRACE_RESTRICT_NEWS_CONTROL, + STR_TRACE_RESTRICT_COUNTER_OP, INVALID_STRING_ID, }; static const uint val_action[] = { @@ -404,6 +410,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG TRIT_REVERSE, TRIT_SPEED_RESTRICTION, TRIT_NEWS_CONTROL, + TRIT_COUNTER, }; static const TraceRestrictDropDownListSet set_action = { str_action, val_action, @@ -430,6 +437,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG STR_TRACE_RESTRICT_VARIABLE_TRAIN_SLOT, STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY, STR_TRACE_RESTRICT_VARIABLE_SLOT_OCCUPANCY_REMAINING, + STR_TRACE_RESTRICT_VARIABLE_COUNTER_VALUE, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED, INVALID_STRING_ID, }; @@ -454,6 +462,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG TRIT_COND_TRAIN_IN_SLOT, TRIT_COND_SLOT_OCCUPANCY | (TRSOCAF_OCCUPANTS << 16), TRIT_COND_SLOT_OCCUPANCY | (TRSOCAF_REMAINING << 16), + TRIT_COND_COUNTER_VALUE, TRIT_COND_UNDEFINED, }; static const TraceRestrictDropDownListSet set_cond = { @@ -465,7 +474,7 @@ static const TraceRestrictDropDownListSet *GetTypeDropDownListSet(TraceRestrictG if (_settings_client.gui.show_adv_tracerestrict_features) { *hide_mask = 0; } else { - *hide_mask = is_conditional ? 0xE0000 : 0xF0; + *hide_mask = is_conditional ? 0x1E0000 : 0xF0; } } return is_conditional ? &set_cond : &set_action; @@ -568,6 +577,46 @@ DropDownList GetSlotDropDownList(Owner owner, TraceRestrictSlotID slot_id, int & return dlist; } +/** Sort counters by their name */ +static bool CounterNameSorter(const TraceRestrictCounter * const &a, const TraceRestrictCounter * const &b) +{ + int r = strnatcmp(a->name.c_str(), b->name.c_str()); // Sort by name (natural sorting). + if (r == 0) return a->index < b->index; + return r < 0; +} + +/** + * Get a DropDownList of the counter list + */ +DropDownList GetCounterDropDownList(Owner owner, TraceRestrictCounterID ctr_id, int &selected) +{ + GUIList list; + DropDownList dlist; + + for (const TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + if (ctr->owner == owner) { + list.push_back(ctr); + } + } + + if (list.size() == 0) return dlist; + + list.ForceResort(); + list.Sort(&CounterNameSorter); + + selected = -1; + + for (size_t i = 0; i < list.size(); ++i) { + const TraceRestrictCounter *s = list[i]; + if (ctr_id == s->index) selected = ctr_id; + DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_TRACE_RESTRICT_COUNTER_NAME, s->index, false); + item->SetParam(0, s->index); + dlist.emplace_back(item); + } + + return dlist; +} + static const StringID _cargo_cond_ops_str[] = { STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_EQUALS, STR_TRACE_RESTRICT_CONDITIONAL_COMPARATOR_CARGO_NOT_EQUALS, @@ -620,6 +669,22 @@ static const TraceRestrictDropDownListSet _slot_op_cond_ops = { _slot_op_cond_ops_str, _slot_op_cond_ops_val, }; +static const StringID _counter_op_cond_ops_str[] = { + STR_TRACE_RESTRICT_COUNTER_INCREASE, + STR_TRACE_RESTRICT_COUNTER_DECREASE, + STR_TRACE_RESTRICT_COUNTER_SET, + INVALID_STRING_ID, +}; +static const uint _counter_op_cond_ops_val[] = { + TRCCOF_INCREASE, + TRCCOF_DECREASE, + TRCCOF_SET, +}; +/** counter operators dropdown list set */ +static const TraceRestrictDropDownListSet _counter_op_cond_ops = { + _counter_op_cond_ops_str, _counter_op_cond_ops_val, +}; + /** * Get the StringID for a given CargoID @p cargo, or STR_NEWGRF_INVALID_CARGO */ @@ -1114,6 +1179,26 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric SetDParam(2, GetDropDownStringByValue(&_train_status_value, GetTraceRestrictValue(item))); break; + case TRVT_COUNTER_INDEX_INT: { + assert(prog != nullptr); + assert(GetTraceRestrictType(item) == TRIT_COND_COUNTER_VALUE); + uint32 value = *(TraceRestrictProgram::InstructionAt(prog->items, index - 1) + 1); + SetDParam(0, _program_cond_type[GetTraceRestrictCondFlags(item)]); + if (GetTraceRestrictValue(item) == INVALID_TRACE_RESTRICT_COUNTER_ID) { + instruction_string = STR_TRACE_RESTRICT_CONDITIONAL_COUNTER_STR; + SetDParam(1, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED); + SetDParam(2, selected ? STR_TRACE_RESTRICT_WHITE : STR_EMPTY); + SetDParam(3, GetDropDownStringByValue(GetCondOpDropDownListSet(properties), GetTraceRestrictCondOp(item))); + SetDParam(4, value); + } else { + instruction_string = STR_TRACE_RESTRICT_CONDITIONAL_COUNTER; + SetDParam(1, GetTraceRestrictValue(item)); + SetDParam(2, GetDropDownStringByValue(GetCondOpDropDownListSet(properties), GetTraceRestrictCondOp(item))); + SetDParam(3, value); + } + break; + } + default: NOT_REACHED(); break; @@ -1277,6 +1362,36 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric } break; + case TRIT_COUNTER: { + uint32 value = *(TraceRestrictProgram::InstructionAt(prog->items, index - 1) + 1); + switch (static_cast(GetTraceRestrictCondOp(item))) { + case TRCCOF_INCREASE: + instruction_string = STR_TRACE_RESTRICT_COUNTER_INCREASE_ITEM; + break; + + case TRCCOF_DECREASE: + instruction_string = STR_TRACE_RESTRICT_COUNTER_DECREASE_ITEM; + break; + + case TRCCOF_SET: + instruction_string = STR_TRACE_RESTRICT_COUNTER_SET_ITEM; + break; + + default: + NOT_REACHED(); + break; + } + if (GetTraceRestrictValue(item) == INVALID_TRACE_RESTRICT_COUNTER_ID) { + SetDParam(0, STR_TRACE_RESTRICT_VARIABLE_UNDEFINED_RED); + } else { + SetDParam(0, STR_TRACE_RESTRICT_COUNTER_NAME); + SetDParam(1, GetTraceRestrictValue(item)); + } + SetDParam(2, selected ? STR_TRACE_RESTRICT_WHITE : STR_EMPTY); + SetDParam(3, value); + break; + } + default: NOT_REACHED(); break; @@ -1400,7 +1515,7 @@ public: if (ElseIfInsertionDryRun(false)) disabled &= ~_program_insert_or_if_hide_mask; } } - if (!_settings_client.gui.show_adv_tracerestrict_features) hidden |= _program_slot_hide_mask | _program_wait_pbs_hide_mask | _program_reverse_hide_mask | _program_speed_res_hide_mask; + if (!_settings_client.gui.show_adv_tracerestrict_features) hidden |= _program_slot_hide_mask | _program_wait_pbs_hide_mask | _program_reverse_hide_mask | _program_speed_res_hide_mask | _program_counter_hide_mask; this->ShowDropDownListWithValue(&_program_insert, 0, true, TR_WIDGET_INSERT, disabled, hidden, 0); break; @@ -1489,13 +1604,19 @@ public: break; } + case TR_WIDGET_COUNTER_OP: { + TraceRestrictItem item = this->GetSelected(); + this->ShowDropDownListWithValue(&_counter_op_cond_ops, GetTraceRestrictCondOp(item), false, TR_WIDGET_COUNTER_OP, 0, 0, 0); + break; + } + case TR_WIDGET_VALUE_INT: { TraceRestrictItem item = this->GetSelected(); TraceRestrictValueType type = GetTraceRestrictTypeProperties(item).value_type; if (IsIntegerValueType(type)) { SetDParam(0, ConvertIntegerValue(type, GetTraceRestrictValue(item), true)); ShowQueryString(STR_JUST_INT, STR_TRACE_RESTRICT_VALUE_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); - } else if (type == TRVT_SLOT_INDEX_INT) { + } else if (type == TRVT_SLOT_INDEX_INT || type == TRVT_COUNTER_INDEX_INT) { SetDParam(0, *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items, this->selected_instruction - 1) + 1)); ShowQueryString(STR_JUST_INT, STR_TRACE_RESTRICT_VALUE_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); } @@ -1595,6 +1716,13 @@ public: break; } + case TRVT_COUNTER_INDEX_INT: { + int selected; + DropDownList dlist = GetCounterDropDownList(this->GetOwner(), GetTraceRestrictValue(item), selected); + if (!dlist.empty()) ShowDropDownList(this, std::move(dlist), selected, TR_WIDGET_LEFT_AUX_DROPDOWN); + break; + } + default: break; } @@ -1670,7 +1798,7 @@ public: ShowErrorMessage(STR_TRACE_RESTRICT_ERROR_VALUE_TOO_LARGE, STR_EMPTY, WL_INFO); return; } - } else if (type == TRVT_SLOT_INDEX_INT) { + } else if (type == TRVT_SLOT_INDEX_INT || type == TRVT_COUNTER_INDEX_INT) { value = atoi(str); TraceRestrictDoCommandP(this->tile, this->track, TRDCT_MODIFY_DUAL_ITEM, this->selected_instruction - 1, value, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM); return; @@ -1691,7 +1819,7 @@ public: if (widget == TR_WIDGET_VALUE_DROPDOWN || widget == TR_WIDGET_LEFT_AUX_DROPDOWN) { TraceRestrictTypePropertySet type = GetTraceRestrictTypeProperties(item); - if (this->value_drop_down_is_company || type.value_type == TRVT_GROUP_INDEX || type.value_type == TRVT_SLOT_INDEX || type.value_type == TRVT_SLOT_INDEX_INT) { + if (this->value_drop_down_is_company || type.value_type == TRVT_GROUP_INDEX || type.value_type == TRVT_SLOT_INDEX || type.value_type == TRVT_SLOT_INDEX_INT || type.value_type == TRVT_COUNTER_INDEX_INT) { // this is a special company drop-down or group/slot-index 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); @@ -1747,7 +1875,8 @@ public: } case TR_WIDGET_COMPARATOR: - case TR_WIDGET_SLOT_OP: { + case TR_WIDGET_SLOT_OP: + case TR_WIDGET_COUNTER_OP: { SetTraceRestrictCondOp(item, static_cast(value)); TraceRestrictDoCommandP(this->tile, this->track, TRDCT_MODIFY_ITEM, this->selected_instruction - 1, item, STR_TRACE_RESTRICT_ERROR_CAN_T_MODIFY_ITEM); break; @@ -2023,7 +2152,7 @@ public: TraceRestrictValueType type = GetTraceRestrictTypeProperties(item).value_type; if (IsIntegerValueType(type)) { SetDParam(0, ConvertIntegerValue(type, GetTraceRestrictValue(item), true)); - } else if (type == TRVT_SLOT_INDEX_INT) { + } else if (type == TRVT_SLOT_INDEX_INT || type == TRVT_COUNTER_INDEX_INT) { SetDParam(0, *(TraceRestrictProgram::InstructionAt(this->GetProgram()->items, this->selected_instruction - 1) + 1)); } break; @@ -2068,7 +2197,7 @@ public: case TR_WIDGET_LEFT_AUX_DROPDOWN: { TraceRestrictItem item = this->GetSelected(); TraceRestrictTypePropertySet type = GetTraceRestrictTypeProperties(item); - if (type.value_type == TRVT_SLOT_INDEX_INT) { + if (type.value_type == TRVT_SLOT_INDEX_INT || type.value_type == TRVT_COUNTER_INDEX_INT) { SetDParam(0, GetTraceRestrictValue(item)); } break; @@ -2239,6 +2368,7 @@ private: this->RaiseWidget(TR_WIDGET_CONDFLAGS); this->RaiseWidget(TR_WIDGET_COMPARATOR); this->RaiseWidget(TR_WIDGET_SLOT_OP); + this->RaiseWidget(TR_WIDGET_COUNTER_OP); this->RaiseWidget(TR_WIDGET_VALUE_INT); this->RaiseWidget(TR_WIDGET_VALUE_DECIMAL); this->RaiseWidget(TR_WIDGET_VALUE_DROPDOWN); @@ -2259,6 +2389,7 @@ private: this->DisableWidget(TR_WIDGET_CONDFLAGS); this->DisableWidget(TR_WIDGET_COMPARATOR); this->DisableWidget(TR_WIDGET_SLOT_OP); + this->DisableWidget(TR_WIDGET_COUNTER_OP); this->DisableWidget(TR_WIDGET_VALUE_INT); this->DisableWidget(TR_WIDGET_VALUE_DECIMAL); this->DisableWidget(TR_WIDGET_VALUE_DROPDOWN); @@ -2576,6 +2707,36 @@ private: GetDropDownStringByValue(&_news_control_value, GetTraceRestrictValue(item)); break; + case TRVT_COUNTER_INDEX_INT: { + right_sel->SetDisplayedPlane(DPR_VALUE_INT); + left_aux_sel->SetDisplayedPlane(DPLA_DROPDOWN); + this->EnableWidget(TR_WIDGET_VALUE_INT); + if (!IsTraceRestrictConditional(item)) { + left_sel->SetDisplayedPlane(DPL_COUNTER_OP); + this->EnableWidget(TR_WIDGET_COUNTER_OP); + this->GetWidget(TR_WIDGET_COUNTER_OP)->widget_data = + GetDropDownStringByValue(&_counter_op_cond_ops, GetTraceRestrictCondOp(item)); + } + + for (const TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + if (ctr->owner == this->GetOwner()) { + this->EnableWidget(TR_WIDGET_LEFT_AUX_DROPDOWN); + break; + } + } + + switch (GetTraceRestrictValue(item)) { + case INVALID_TRACE_RESTRICT_COUNTER_ID: + this->GetWidget(TR_WIDGET_LEFT_AUX_DROPDOWN)->widget_data = STR_TRACE_RESTRICT_VARIABLE_UNDEFINED; + break; + + default: + this->GetWidget(TR_WIDGET_LEFT_AUX_DROPDOWN)->widget_data = STR_TRACE_RESTRICT_COUNTER_NAME; + break; + } + break; + } + default: break; } @@ -2728,6 +2889,8 @@ static const NWidgetPart _nested_program_widgets[] = { NWidget(NWID_SELECTION, INVALID_COLOUR, TR_WIDGET_SEL_TOP_LEFT), NWidget(WWT_DROPDOWN, COLOUR_GREY, TR_WIDGET_TYPE_COND), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_TRACE_RESTRICT_TYPE_TOOLTIP), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, TR_WIDGET_COUNTER_OP), SetMinimalSize(124, 12), SetFill(1, 0), + SetDataTip(STR_NULL, STR_TRACE_RESTRICT_COUNTER_OP_TOOLTIP), SetResize(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, TR_WIDGET_BLANK_L), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_EMPTY, STR_NULL), SetResize(1, 0), EndContainer(), @@ -3488,3 +3651,343 @@ void DeleteTraceRestrictSlotHighlightOfVehicle(const Vehicle *v) TraceRestrictSlotWindow *w = FindTraceRestrictSlotWindow(v->owner); if (w != nullptr) w->UnselectVehicle(v->index); } + +/** Counter GUI widget IDs */ +enum TraceRestrictCounterWindowWidgets { + WID_TRCL_CAPTION, + WID_TRCL_LIST_COUNTERS, + WID_TRCL_LIST_COUNTERS_SCROLLBAR, + WID_TRCL_CREATE_COUNTER, + WID_TRCL_DELETE_COUNTER, + WID_TRCL_RENAME_COUNTER, + WID_TRCL_SET_COUNTER_VALUE, +}; + + +static const NWidgetPart _nested_counter_widgets[] = { + NWidget(NWID_HORIZONTAL), // Window header + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_TRCL_CAPTION), SetDataTip(STR_TRACE_RESTRICT_COUNTER_CAPTION, STR_NULL), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_VERTICAL), + //NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetFill(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_TRCL_LIST_COUNTERS), SetMatrixDataTip(1, 0, STR_TRACE_RESTRICT_COUNTER_GUI_LIST_TOOLTIP), + SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_TRCL_LIST_COUNTERS_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_TRCL_LIST_COUNTERS_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TRCL_CREATE_COUNTER), SetMinimalSize(75, 12), SetFill(1, 0), + SetDataTip(STR_TRACE_RESTRICT_COUNTER_CREATE, STR_TRACE_RESTRICT_COUNTER_CREATE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TRCL_DELETE_COUNTER), SetMinimalSize(75, 12), SetFill(1, 0), + SetDataTip(STR_TRACE_RESTRICT_COUNTER_DELETE, STR_TRACE_RESTRICT_COUNTER_DELETE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TRCL_RENAME_COUNTER), SetMinimalSize(75, 12), SetFill(1, 0), + SetDataTip(STR_TRACE_RESTRICT_COUNTER_RENAME, STR_TRACE_RESTRICT_COUNTER_RENAME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TRCL_SET_COUNTER_VALUE), SetMinimalSize(75, 12), SetFill(1, 0), + SetDataTip(STR_TRACE_RESTRICT_COUNTER_SET_VALUE, STR_TRACE_RESTRICT_COUNTER_SET_VALUE_TOOLTIP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), +}; + +class TraceRestrictCounterWindow : public Window { +private: + enum QueryTextOperation { + QTO_RENAME, + QTO_SET_VALUE, + }; + + CompanyID owner; + QueryTextOperation qto; ///< Active query text operation + TraceRestrictCounterID ctr_qt_op; ///< Counter being adjusted in query text operation, INVALID_TRACE_RESTRICT_COUNTER_ID if none + TraceRestrictCounterID ctr_confirm; ///< Counter awaiting delete confirmation + TraceRestrictCounterID selected; ///< Selected counter + GUIList ctrs; ///< List of slots + uint tiny_step_height; ///< Step height for the counter list + uint value_col_width; ///< Value column width + Scrollbar *sb; + + void BuildCounterList() + { + if (!this->ctrs.NeedRebuild()) return; + + this->ctrs.clear(); + + for (const TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { + if (ctr->owner == this->owner) { + this->ctrs.push_back(ctr); + } + } + + this->ctrs.ForceResort(); + this->ctrs.Sort(&CounterNameSorter); + this->ctrs.shrink_to_fit(); + this->ctrs.RebuildDone(); + } + + /** + * Compute tiny_step_height and column_size + * @return Total width required for the group list. + */ + uint ComputeInfoSize() + { + SetDParamMaxValue(0, 9999, 3); + Dimension dim = GetStringBoundingBox(STR_JUST_COMMA); + this->tiny_step_height = dim.height + WD_MATRIX_TOP; + this->value_col_width = dim.width; + + return WD_FRAMERECT_LEFT + 8 + + 170 + 8 + + dim.width + 8 + + WD_FRAMERECT_RIGHT; + } + + /** + * Draw a row in the slot list. + * @param y Top of the row. + * @param left Left of the row. + * @param right Right of the row. + * @param g_id Group to list. + */ + void DrawCounterInfo(int y, int left, int right, TraceRestrictCounterID ctr_id) const + { + /* draw the selected counter in white, else we draw it in black */ + TextColour colour = ctr_id == this->selected ? TC_WHITE : TC_BLACK; + bool rtl = _current_text_dir == TD_RTL; + + SetDParam(0, ctr_id); + DrawString(left + WD_FRAMERECT_LEFT + 8 + (rtl ? this->value_col_width + 8 : 0), + right - WD_FRAMERECT_RIGHT - 8 - (rtl ? 0 : this->value_col_width + 8), + y, STR_TRACE_RESTRICT_COUNTER_NAME, colour); + + SetDParam(0, TraceRestrictCounter::Get(ctr_id)->value); + DrawString(rtl ? left + WD_FRAMERECT_LEFT + 8 : right - WD_FRAMERECT_RIGHT - 8 - this->value_col_width, + rtl ? left + WD_FRAMERECT_LEFT + 8 + this->value_col_width : right - WD_FRAMERECT_RIGHT - 8, + y, STR_JUST_COMMA, colour, SA_RIGHT | SA_FORCE); + } + +public: + TraceRestrictCounterWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->owner = (CompanyID)window_number; + this->CreateNestedTree(); + + this->sb = this->GetScrollbar(WID_TRCL_LIST_COUNTERS_SCROLLBAR); + + this->ctr_qt_op = INVALID_TRACE_RESTRICT_COUNTER_ID; + this->ctr_confirm = INVALID_TRACE_RESTRICT_COUNTER_ID; + this->selected = INVALID_TRACE_RESTRICT_COUNTER_ID; + + this->ctrs.ForceRebuild(); + this->ctrs.NeedResort(); + this->BuildCounterList(); + + this->FinishInitNested(window_number); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + switch (widget) { + case WID_TRCL_LIST_COUNTERS: { + size->width = max(size->width, this->ComputeInfoSize()); + resize->height = this->tiny_step_height; + size->height = max(size->height, 8 * resize->height); + break; + } + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) override + { + if (data == 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->ctrs.ForceRebuild(); + } else { + this->ctrs.ForceResort(); + } + + if (this->ctr_qt_op != INVALID_TRACE_RESTRICT_COUNTER_ID && this->ctr_qt_op != NEW_TRACE_RESTRICT_COUNTER_ID && + !TraceRestrictCounter::IsValidID(this->ctr_qt_op)) { + DeleteWindowByClass(WC_QUERY_STRING); + this->ctr_qt_op = INVALID_TRACE_RESTRICT_COUNTER_ID; + } + + if (this->selected != INVALID_TRACE_RESTRICT_COUNTER_ID && !TraceRestrictCounter::IsValidID(this->selected)) { + this->selected = INVALID_TRACE_RESTRICT_COUNTER_ID; + } + + this->SetDirty(); + } + + virtual void OnPaint() override + { + this->BuildCounterList(); + + this->sb->SetCount(this->ctrs.size()); + + /* Disable the counter specific functions when no counter is selected */ + this->SetWidgetsDisabledState(this->selected == INVALID_TRACE_RESTRICT_COUNTER_ID || _local_company != this->owner, + WID_TRCL_DELETE_COUNTER, + WID_TRCL_RENAME_COUNTER, + WID_TRCL_SET_COUNTER_VALUE, + WIDGET_LIST_END); + + /* Disable remaining buttons for non-local companies + * Needed while changing _local_company, eg. by cheats + * All procedures (eg. move vehicle to a slot) + * verify, whether you are the owner of the vehicle, + * so it doesn't have to be disabled + */ + this->SetWidgetsDisabledState(_local_company != this->owner, + WID_TRCL_CREATE_COUNTER, + WIDGET_LIST_END); + + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const override + { + switch (widget) { + case WID_TRCL_LIST_COUNTERS: { + int y1 = r.top + WD_FRAMERECT_TOP; + int max = min(this->sb->GetPosition() + this->sb->GetCapacity(), this->ctrs.size()); + for (int i = this->sb->GetPosition(); i < max; ++i) { + const TraceRestrictCounter *ctr = this->ctrs[i]; + + assert(ctr->owner == this->owner); + + DrawCounterInfo(y1, r.left, r.right, ctr->index); + + y1 += this->tiny_step_height; + } + break; + } + } + } + + static void DeleteCounterCallback(Window *win, bool confirmed) + { + if (confirmed) { + TraceRestrictCounterWindow *w = (TraceRestrictCounterWindow*)win; + w->selected = INVALID_TRACE_RESTRICT_COUNTER_ID; + DoCommandP(0, w->ctr_confirm, 0, CMD_DELETE_TRACERESTRICT_COUNTER | CMD_MSG(STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_DELETE)); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) override + { + switch (widget) { + case WID_TRCL_LIST_COUNTERS: { // Matrix + uint id_s = this->sb->GetScrolledRowFromWidget(pt.y, this, WID_TRCL_LIST_COUNTERS, 0, this->tiny_step_height); + if (id_s >= this->ctrs.size()) return; + + this->selected = this->ctrs[id_s]->index; + + this->SetDirty(); + break; + } + + case WID_TRCL_CREATE_COUNTER: { // Create a new counter + this->ShowCreateCounterWindow(); + break; + } + + case WID_TRCL_DELETE_COUNTER: { // Delete the selected counter + this->ctr_confirm = this->selected; + ShowQuery(STR_TRACE_RESTRICT_COUNTER_QUERY_DELETE_CAPTION, STR_TRACE_RESTRICT_COUNTER_DELETE_QUERY_TEXT, this, DeleteCounterCallback); + break; + } + + case WID_TRCL_RENAME_COUNTER: // Rename the selected counter + this->ShowRenameCounterWindow(this->selected); + break; + + case WID_TRCL_SET_COUNTER_VALUE: + this->ShowSetCounterValueWindow(this->selected); + break; + } + } + + virtual void OnQueryTextFinished(char *str) override + { + if (str != nullptr) { + switch (this->qto) { + case QTO_RENAME: + if (this->ctr_qt_op == NEW_TRACE_RESTRICT_COUNTER_ID) { + DoCommandP(0, 0, 0, CMD_CREATE_TRACERESTRICT_COUNTER | CMD_MSG(STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_CREATE), nullptr, str); + } else { + DoCommandP(0, this->ctr_qt_op, 0, CMD_ALTER_TRACERESTRICT_COUNTER | CMD_MSG(STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_MODIFY), nullptr, str); + } + break; + + case QTO_SET_VALUE: + if (!StrEmpty(str)) DoCommandP(0, this->ctr_qt_op | (1 << 16), atoi(str), CMD_ALTER_TRACERESTRICT_COUNTER | CMD_MSG(STR_TRACE_RESTRICT_ERROR_COUNTER_CAN_T_MODIFY)); + break; + } + } + this->ctr_qt_op = INVALID_TRACE_RESTRICT_COUNTER_ID; + } + + virtual void OnResize() override + { + this->sb->SetCapacityFromWidget(this, WID_TRCL_LIST_COUNTERS); + } + + virtual void OnGameTick() override + { + if (this->ctrs.NeedResort()) { + this->SetDirty(); + } + } + + void ShowRenameCounterWindow(TraceRestrictCounterID ctr_id) + { + assert(TraceRestrictCounter::IsValidID(ctr_id)); + this->qto = QTO_RENAME; + this->ctr_qt_op = ctr_id; + SetDParam(0, ctr_id); + ShowQueryString(STR_TRACE_RESTRICT_COUNTER_NAME, STR_TRACE_RESTRICT_COUNTER_RENAME_CAPTION, MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + + void ShowSetCounterValueWindow(TraceRestrictCounterID ctr_id) + { + assert(TraceRestrictCounter::IsValidID(ctr_id)); + this->qto = QTO_SET_VALUE; + this->ctr_qt_op = ctr_id; + SetDParam(0, TraceRestrictCounter::Get(ctr_id)->value); + ShowQueryString(STR_JUST_INT, STR_TRACE_RESTRICT_COUNTER_SET_VALUE_CAPTION, 5, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); + } + + void ShowCreateCounterWindow() + { + this->qto = QTO_RENAME; + this->ctr_qt_op = NEW_TRACE_RESTRICT_COUNTER_ID; + ShowQueryString(STR_EMPTY, STR_TRACE_RESTRICT_COUNTER_CREATE_CAPTION, MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } +}; + +static WindowDesc _counter_window_desc( + WDP_AUTO, "list_tr_counters", 525, 246, + WC_TRACE_RESTRICT_COUNTERS, WC_NONE, + 0, + _nested_counter_widgets, lengthof(_nested_counter_widgets) +); + +/** + * Show the trace restrict counter window for the given company. + * @param company The company to show the window for. + */ +void ShowTraceRestrictCounterWindow(CompanyID company) +{ + if (!Company::IsValidID(company)) return; + + AllocateWindowDescFront(&_counter_window_desc, (WindowNumber)company); +} diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 1a51a16e84..5e03e1e935 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4123,10 +4123,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) const Trackdir dir = FindFirstTrackdir(trackdirbits); if (HasSignalOnTrack(gp.new_tile, TrackdirToTrack(dir))) { const TraceRestrictProgram *prog = GetExistingTraceRestrictProgram(gp.new_tile, TrackdirToTrack(dir)); - if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_REVERSE | TRPAUF_SPEED_RESTRICTION)) { + if (prog && prog->actions_used_flags & (TRPAUF_SLOT_ACQUIRE | TRPAUF_SLOT_RELEASE_FRONT | TRPAUF_REVERSE | TRPAUF_SPEED_RESTRICTION | TRPAUF_CHANGE_COUNTER)) { TraceRestrictProgramResult out; TraceRestrictProgramInput input(gp.new_tile, dir, nullptr, nullptr); - input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT; + input.permitted_slot_operations = TRPISP_ACQUIRE | TRPISP_RELEASE_FRONT | TRPISP_CHANGE_COUNTER; prog->Execute(v, input, out); if (out.flags & TRPRF_REVERSE && GetSignalType(gp.new_tile, TrackdirToTrack(dir)) == SIGTYPE_PBS && !HasSignalOnTrackdir(gp.new_tile, dir)) { diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 6e4da8ff5e..8fc9257928 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -367,6 +367,7 @@ DropDownList BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplac } if (this->vli.vtype == VEH_TRAIN && _settings_client.gui.show_adv_tracerestrict_features) { list.emplace_back(new DropDownListStringItem(STR_TRACE_RESTRICT_SLOT_MANAGE, ADI_TRACERESTRICT_SLOT_MGMT, false)); + list.emplace_back(new DropDownListStringItem(STR_TRACE_RESTRICT_COUNTER_MANAGE, ADI_TRACERESTRICT_COUNTER_MGMT, false)); } if (change_order_str != 0) { list.emplace_back(new DropDownListStringItem(change_order_str, ADI_CHANGE_ORDER, disable)); @@ -2115,6 +2116,12 @@ public: break; } + case ADI_TRACERESTRICT_COUNTER_MGMT: { + extern void ShowTraceRestrictCounterWindow(CompanyID company); + ShowTraceRestrictCounterWindow(this->owner); + break; + } + default: NOT_REACHED(); } break; diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index bb7a30a1c6..5e54fbd52d 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -51,6 +51,7 @@ struct BaseVehicleListWindow : public Window { ADI_CHANGE_ORDER, ADI_CREATE_GROUP, ADI_TRACERESTRICT_SLOT_MGMT, + ADI_TRACERESTRICT_COUNTER_MGMT, }; static const StringID vehicle_depot_name[]; diff --git a/src/window_type.h b/src/window_type.h index 3a6813688f..28f833d9d4 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -733,6 +733,12 @@ enum WindowClass { */ WC_TRACE_RESTRICT_SLOTS, + /** + * Trace restrict counter window; %Window numbers: + * - Packed value = #SlotListWidgets / #VehicleListWidgets + */ + WC_TRACE_RESTRICT_COUNTERS, + /** * Programmable pre-signals window */