Order occupancy: Add column to orders GUI to show occupancy running average.

This is an exponentially weighted moving average of occupancies updated
when any vehicle in the shared order set leaves the station of that order.
The weighting factor is an adv setting.
pull/3/head
Jonathan G Rennison 9 years ago
parent a9200aa69a
commit 117599ec7f

@ -1703,6 +1703,9 @@ STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to
STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value
STR_CONFIG_OCCUPANCY_SMOOTHNESS :Smoothness of order occupancy measurement: {STRING2}
STR_CONFIG_OCCUPANCY_SMOOTHNESS_HELPTEXT :0% sets the measurement to the most recent value, 100% leaves it unchanged
# Config errors
STR_CONFIG_ERROR :{WHITE}Error with the configuration file...
STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}'
@ -3819,6 +3822,11 @@ STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Insert a
STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all vehicles that share this schedule
STR_ORDERS_OCCUPANCY_BUTTON :{BLACK}%
STR_ORDERS_OCCUPANCY_BUTTON_TOOLTIP :{BLACK}Show occupancy running averages
STR_ORDERS_OCCUPANCY_LIST_TOOLTIP :{BLACK}Order occupancy - this shows runnings averages of recent occupancy levels when leaving a station, for all vehicles sharing these orders
STR_ORDERS_OCCUPANCY_PERCENT :{NUM}%
# String parts to build the order string
STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT}
STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT}

@ -43,6 +43,8 @@ private:
CargoID refit_cargo; ///< Refit CargoID
uint8 occupancy; ///< Estimate of vehicle occupancy on departure, for the current order, 0 indicates invalid, 1 - 101 indicate 0 - 100%
uint16 wait_time; ///< How long in ticks to wait at the destination.
uint16 travel_time; ///< How long in ticks the journey to this destination should take.
uint16 max_speed; ///< How fast the vehicle may go on the way to the destination.
@ -217,6 +219,18 @@ public:
*/
inline void SetMaxSpeed(uint16 speed) { this->max_speed = speed; }
/**
* Get the occupancy value
* @return occupancy
*/
inline uint8 GetOccupancy() const { return this->occupancy; }
/**
* Set the occupancy value
* @param occupancy The occupancy to set
*/
inline void SetOccupancy(uint8 occupancy) { this->occupancy = occupancy; }
bool ShouldStopAtStation(const Vehicle *v, StationID station) const;
bool CanLoadOrUnload() const;
bool CanLeaveWithCargo(bool has_cargo) const;

@ -239,6 +239,7 @@ Order::Order(uint32 packed)
this->dest = GB(packed, 16, 16);
this->next = NULL;
this->refit_cargo = CT_NO_REFIT;
this->occupancy = 0;
this->wait_time = 0;
this->travel_time = 0;
this->max_speed = UINT16_MAX;

@ -770,6 +770,7 @@ public:
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_O_SCROLLBAR);
this->GetWidget<NWidgetStacked>(WID_O_SEL_OCCUPANCY)->SetDisplayedPlane(SZSP_NONE);
this->FinishInitNested(v->index);
if (v->owner == _local_company) {
this->DisableWidget(WID_O_EMPTY);
@ -798,6 +799,12 @@ public:
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
{
switch (widget) {
case WID_O_OCCUPANCY_LIST:
SetDParamMaxValue(0, 100);
size->width = WD_FRAMERECT_LEFT + GetStringBoundingBox(STR_ORDERS_OCCUPANCY_PERCENT).width + 10 + WD_FRAMERECT_RIGHT;
/* FALL THROUGH */
case WID_O_SEL_OCCUPANCY:
case WID_O_ORDER_LIST:
resize->height = FONT_HEIGHT_NORMAL;
size->height = 6 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
@ -1064,6 +1071,8 @@ public:
/* Disable list of vehicles with the same shared orders if there is no list */
this->SetWidgetDisabledState(WID_O_SHARED_ORDER_LIST, !shared_orders);
this->GetWidget<NWidgetStacked>(WID_O_SEL_OCCUPANCY)->SetDisplayedPlane(IsWidgetLowered(WID_O_OCCUPANCY_TOGGLE) ? 0 : SZSP_NONE);
this->SetDirty();
}
@ -1079,8 +1088,19 @@ public:
virtual void DrawWidget(const Rect &r, int widget) const
{
if (widget != WID_O_ORDER_LIST) return;
switch (widget) {
case WID_O_ORDER_LIST:
DrawOrderListWidget(r);
break;
case WID_O_OCCUPANCY_LIST:
DrawOccupancyListWidget(r);
break;
}
}
void DrawOrderListWidget(const Rect &r) const
{
bool rtl = _current_text_dir == TD_RTL;
SetDParamMaxValue(0, this->vehicle->GetNumOrders(), 2);
int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3;
@ -1135,6 +1155,30 @@ public:
}
}
void DrawOccupancyListWidget(const Rect &r) const
{
int y = r.top + WD_FRAMERECT_TOP;
int line_height = this->GetWidget<NWidgetBase>(WID_O_ORDER_LIST)->resize_y;
int i = this->vscroll->GetPosition();
const Order *order = this->vehicle->GetOrder(i);
/* Draw the orders. */
while (order != NULL) {
/* Don't draw anything if it extends past the end of the window. */
if (!this->vscroll->IsVisible(i)) break;
uint8 occupancy = order->GetOccupancy();
if (occupancy > 0) {
SetDParam(0, occupancy - 1);
DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_ORDERS_OCCUPANCY_PERCENT, (i == this->selected_order) ? TC_WHITE : TC_BLACK);
}
y += line_height;
i++;
order = order->next;
}
}
virtual void SetStringParameters(int widget) const
{
switch (widget) {
@ -1318,6 +1362,12 @@ public:
case WID_O_SHARED_ORDER_LIST:
ShowVehicleListWindow(this->vehicle);
break;
case WID_O_OCCUPANCY_TOGGLE:
ToggleWidgetLoweredState(WID_O_OCCUPANCY_TOGGLE);
this->UpdateButtonState();
this->ReInit();
break;
}
}
@ -1541,6 +1591,10 @@ static const NWidgetPart _nested_orders_train_widgets[] = {
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_O_ORDER_LIST), SetMinimalSize(372, 62), SetDataTip(0x0, STR_ORDERS_LIST_TOOLTIP), SetResize(1, 1), SetScrollbar(WID_O_SCROLLBAR), EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_OCCUPANCY),
NWidget(WWT_PANEL, COLOUR_GREY, WID_O_OCCUPANCY_LIST), SetMinimalSize(50, 0), SetFill(0, 1), SetDataTip(STR_NULL, STR_ORDERS_OCCUPANCY_LIST_TOOLTIP),
SetScrollbar(WID_O_SCROLLBAR), EndContainer(),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_O_SCROLLBAR),
EndContainer(),
@ -1578,6 +1632,7 @@ static const NWidgetPart _nested_orders_train_widgets[] = {
SetDataTip(STR_BLACK_COMMA, STR_ORDER_CONDITIONAL_VALUE_TOOLTIP), SetResize(1, 0),
EndContainer(),
EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_OCCUPANCY_TOGGLE), SetMinimalSize(12, 12), SetDataTip(STR_ORDERS_OCCUPANCY_BUTTON, STR_ORDERS_OCCUPANCY_BUTTON_TOOLTIP),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_O_SHARED_ORDER_LIST), SetMinimalSize(12, 12), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
EndContainer(),
@ -1619,6 +1674,10 @@ static const NWidgetPart _nested_orders_widgets[] = {
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_O_ORDER_LIST), SetMinimalSize(372, 62), SetDataTip(0x0, STR_ORDERS_LIST_TOOLTIP), SetResize(1, 1), SetScrollbar(WID_O_SCROLLBAR), EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_OCCUPANCY),
NWidget(WWT_PANEL, COLOUR_GREY, WID_O_OCCUPANCY_LIST), SetMinimalSize(50, 0), SetFill(0, 1), SetDataTip(STR_NULL, STR_ORDERS_OCCUPANCY_LIST_TOOLTIP),
SetScrollbar(WID_O_SCROLLBAR), EndContainer(),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_O_SCROLLBAR),
EndContainer(),
@ -1653,6 +1712,7 @@ static const NWidgetPart _nested_orders_widgets[] = {
EndContainer(),
EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_OCCUPANCY_TOGGLE), SetMinimalSize(12, 12), SetDataTip(STR_ORDERS_OCCUPANCY_BUTTON, STR_ORDERS_OCCUPANCY_BUTTON_TOOLTIP),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_O_SHARED_ORDER_LIST), SetMinimalSize(12, 12), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
EndContainer(),

@ -110,6 +110,7 @@ const SaveLoad *GetOrderDescription()
SLE_REF(Order, next, REF_ORDER),
SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION),
SLE_CONDNULL(1, 36, 181), // refit_subtype
SLE_CONDVAR(Order, occupancy, SLE_UINT8, 300, SL_MAX_VERSION),
SLE_CONDVAR(Order, wait_time, SLE_UINT16, 67, SL_MAX_VERSION),
SLE_CONDVAR(Order, travel_time, SLE_UINT16, 67, SL_MAX_VERSION),
SLE_CONDVAR(Order, max_speed, SLE_UINT16, 172, SL_MAX_VERSION),

@ -263,7 +263,7 @@
* 193 26802
* 194 26881 1.5.x
*/
extern const uint16 SAVEGAME_VERSION = 194; ///< Current savegame version of OpenTTD.
extern const uint16 SAVEGAME_VERSION = 300; ///< Current savegame version of OpenTTD.
SavegameType _savegame_type; ///< type of savegame we are loading

@ -1626,6 +1626,7 @@ static SettingsContainer &GetSettingsTree()
vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns"));
vehicles->Add(new SettingEntry("order.serviceathelipad"));
vehicles->Add(new SettingEntry("order.occupancy_smoothness"));
}
SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS));

@ -439,6 +439,7 @@ struct OrderSettings {
bool selectgoods; ///< only send the goods to station if a train has been there
bool no_servicing_if_no_breakdowns; ///< don't send vehicles to depot when breakdowns are disabled
bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot)
uint8 occupancy_smoothness; ///< percentage smoothness of occupancy measurement changes
};
/** Settings related to vehicles. */

@ -2145,6 +2145,20 @@ min = 0
max = 1000000
cat = SC_EXPERT
[SDT_VAR]
base = GameSettings
var = order.occupancy_smoothness
type = SLE_UINT8
from = 300
def = 75
min = 0
max = 100
interval = 10
str = STR_CONFIG_OCCUPANCY_SMOOTHNESS
strhelp = STR_CONFIG_OCCUPANCY_SMOOTHNESS_HELPTEXT
strval = STR_CONFIG_SETTING_PERCENTAGE
cat = SC_EXPERT
##
[SDT_VAR]
base = GameSettings

@ -2115,6 +2115,28 @@ void Vehicle::LeaveStation()
SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
}
if (this->cur_real_order_index < this->GetNumOrders()) {
Order *real_current_order = this->GetOrder(this->cur_real_order_index);
uint current_occupancy = CalcPercentVehicleFilled(this, NULL);
uint old_occupancy = real_current_order->GetOccupancy();
uint new_occupancy;
if (old_occupancy == 0) {
new_occupancy = current_occupancy;
} else {
// Exponential weighted moving average using occupancy_smoothness
new_occupancy = (old_occupancy - 1) * _settings_game.order.occupancy_smoothness;
new_occupancy += current_occupancy * (100 - _settings_game.order.occupancy_smoothness);
new_occupancy += 50; // round to nearest integer percent, rather than just floor
new_occupancy /= 100;
}
if (new_occupancy + 1 != old_occupancy) {
real_current_order->SetOccupancy(static_cast<uint8>(new_occupancy + 1));
for (const Vehicle *v = this->FirstShared(); v != NULL; v = v->NextShared()) {
SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
}
}
}
this->MarkDirty();
}

@ -39,6 +39,9 @@ enum OrderWidgets {
WID_O_SEL_TOP_ROW, ///< #NWID_SELECTION widget for the top row of the 'your non-trains' order window.
WID_O_SEL_BOTTOM_MIDDLE, ///< #NWID_SELECTION widget for the middle part of the bottom row of the 'your train' order window.
WID_O_SHARED_ORDER_LIST, ///< Open list of shared vehicles.
WID_O_SEL_OCCUPANCY, ///< #NWID_SELECTION widget for the occupancy list panel.
WID_O_OCCUPANCY_LIST, ///< Occupancy list panel.
WID_O_OCCUPANCY_TOGGLE, ///< Toggle display of occupancy measures.
};
#endif /* WIDGETS_ORDER_WIDGET_H */

Loading…
Cancel
Save