forked from mirror/OpenTTD
(svn r1009) -Feature: per-station vehicle lists
This adds a little button per vehicle class to the station window which opens a list of all vehicles that have this station on their schedule. As side effect this gets rid of some global variables.
This commit is contained in:
284
train_gui.c
284
train_gui.c
@@ -10,6 +10,7 @@
|
||||
#include "command.h"
|
||||
#include "player.h"
|
||||
#include "engine.h"
|
||||
#include "vehicle_gui.h"
|
||||
|
||||
|
||||
int _traininfo_vehicle_pitch = 0;
|
||||
@@ -39,7 +40,7 @@ void CcBuildWagon(bool success, uint tile, uint32 p1, uint32 p2)
|
||||
found = GetLastVehicleInChain(found);
|
||||
// put the new wagon at the end of the loco.
|
||||
DoCommandP(0, _new_wagon_id | (found->index<<16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
|
||||
_vehicle_sort_dirty[VEHTRAIN] = true;
|
||||
RebuildVehicleLists();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,155 +1167,125 @@ void ShowTrainDetailsWindow(Vehicle *v)
|
||||
WP(w,traindetails_d).tab = 0;
|
||||
}
|
||||
|
||||
// used to get a sorted list of the vehicles
|
||||
static SortStruct _train_sort[NUM_NORMAL_VEHICLES];
|
||||
static uint16 _num_train_sort[MAX_PLAYERS];
|
||||
|
||||
static void GlobalSortTrainList()
|
||||
{
|
||||
const Vehicle *v;
|
||||
uint16 *i;
|
||||
uint32 n = 0;
|
||||
static Widget _player_trains_widgets[] = {
|
||||
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_CAPTION, 14, 11, 324, 0, 13, STR_881B_TRAINS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 80, 14, 25, SRT_SORT_BY, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 81, 232, 14, 25, 0x0, STR_SORT_TIP},
|
||||
{ WWT_CLOSEBOX, 14, 233, 243, 14, 25, STR_0225, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 244, 324, 14, 25, 0x0, STR_NULL},
|
||||
{ WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
|
||||
{ WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 161, 208, 219, STR_8815_NEW_VEHICLES, STR_883E_BUILD_NEW_TRAINS_REQUIRES},
|
||||
{ WWT_PANEL, 14, 162, 324, 208, 219, 0x0, STR_NULL},
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
// reset #-of trains to 0 because ++ is used for value-assignment
|
||||
for (i = _num_train_sort; i != endof(_num_train_sort); i++) {*i = 0;}
|
||||
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if(v->type == VEH_Train && v->subtype == 0) {
|
||||
_train_sort[n].index = v->index;
|
||||
_train_sort[n++].owner = v->owner;
|
||||
_num_train_sort[v->owner]++; // add number of trains of player
|
||||
}
|
||||
}
|
||||
|
||||
// create cumulative train-ownership
|
||||
// trains are stored as a cummulative index, eg 25, 41, 43. This means
|
||||
// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
|
||||
for (i = &_num_train_sort[1]; i != endof(_num_train_sort); i++) {*i += *(i-1);}
|
||||
|
||||
qsort(_train_sort, n, sizeof(_train_sort[0]), GeneralOwnerSorter); // sort by owner
|
||||
|
||||
// since indexes are messed up after adding/removing a station, mark all lists dirty
|
||||
memset(_train_sort_dirty, true, sizeof(_train_sort_dirty));
|
||||
_vehicle_sort_dirty[VEHTRAIN] = false;
|
||||
|
||||
DEBUG(misc, 1) ("Resorting global trains list...");
|
||||
}
|
||||
|
||||
static void MakeSortedTrainList(byte owner)
|
||||
{
|
||||
SortStruct *firstelement;
|
||||
uint32 n = 0;
|
||||
|
||||
if (owner == 0) { // first element starts at 0th element and has n elements as described above
|
||||
firstelement = &_train_sort[0];
|
||||
n = _num_train_sort[0];
|
||||
} else { // nth element starts at the end of the previous one, and has n elements as described above
|
||||
firstelement = &_train_sort[_num_train_sort[owner-1]];
|
||||
n = _num_train_sort[owner] - _num_train_sort[owner-1];
|
||||
}
|
||||
|
||||
_internal_sort_order = _train_sort_order[owner];
|
||||
_internal_name_sorter_id = STR_SV_TRAIN_NAME;
|
||||
_last_vehicle_idx = 0; // used for "cache" in namesorting
|
||||
qsort(firstelement, n, sizeof(_train_sort[0]), _vehicle_sorter[_train_sort_type[owner]]);
|
||||
|
||||
_train_sort_dirty[owner] = false;
|
||||
|
||||
DEBUG(misc, 1) ("Resorting Trains list player %d...", owner+1);
|
||||
}
|
||||
static Widget _other_player_trains_widgets[] = {
|
||||
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_CAPTION, 14, 11, 324, 0, 13, STR_881B_TRAINS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 80, 14, 25, SRT_SORT_BY, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 81, 232, 14, 25, 0x0, STR_SORT_TIP},
|
||||
{ WWT_CLOSEBOX, 14, 233, 243, 14, 25, STR_0225, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 244, 324, 14, 25, 0x0, STR_NULL},
|
||||
{ WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
|
||||
{ WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
|
||||
{
|
||||
int station = (int)w->window_number >> 16;
|
||||
int owner = w->window_number & 0xff;
|
||||
vehiclelist_d *vl = &WP(w, vehiclelist_d);
|
||||
|
||||
switch(e->event) {
|
||||
case WE_PAINT: {
|
||||
uint32 i;
|
||||
const byte window_number = (byte)w->window_number;
|
||||
int x = 2;
|
||||
int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
|
||||
int max;
|
||||
int i;
|
||||
|
||||
if (_train_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
|
||||
BuildVehicleList(vl, VEH_Train, owner, station);
|
||||
SortVehicleList(vl);
|
||||
|
||||
SetVScrollCount(w, vl->list_length);
|
||||
|
||||
// disable 'Sort By' tooltip on Unsorted sorting criteria
|
||||
if (vl->sort_type == SORT_BY_UNSORTED)
|
||||
w->disabled_state |= (1 << 2);
|
||||
|
||||
// resort trains window if roadvehicles have been added/removed
|
||||
if (_vehicle_sort_dirty[VEHTRAIN])
|
||||
GlobalSortTrainList();
|
||||
|
||||
if (_train_sort_dirty[window_number]) {
|
||||
MakeSortedTrainList(window_number);
|
||||
/* reset sorting timeout */
|
||||
w->custom[0] = DAY_TICKS;
|
||||
w->custom[1] = PERIODIC_RESORT_DAYS;
|
||||
}
|
||||
|
||||
// Trains are stored as a cummulative index, eg 25, 41, 43. This means
|
||||
// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 trains
|
||||
i = (window_number == 0) ? 0 : _num_train_sort[window_number-1];
|
||||
SetVScrollCount(w, _num_train_sort[window_number] - i);
|
||||
|
||||
/* draw the widgets */
|
||||
{
|
||||
Player *p = DEREF_PLAYER(window_number);
|
||||
/* Company Name -- (###) Trains */
|
||||
SetDParam(0, p->name_1);
|
||||
SetDParam(1, p->name_2);
|
||||
SetDParam(2, w->vscroll.count);
|
||||
const Player *p = DEREF_PLAYER(owner);
|
||||
/* XXX hack */
|
||||
if (station == -1) {
|
||||
/* Company Name -- (###) Trains */
|
||||
SetDParam(0, p->name_1);
|
||||
SetDParam(1, p->name_2);
|
||||
SetDParam(2, w->vscroll.count);
|
||||
_player_trains_widgets[1].unkA = STR_881B_TRAINS;
|
||||
_other_player_trains_widgets[1].unkA = STR_881B_TRAINS;
|
||||
} else {
|
||||
/* Station Name -- (###) Trains */
|
||||
SetDParam(0, DEREF_STATION(station)->index);
|
||||
SetDParam(1, w->vscroll.count);
|
||||
_player_trains_widgets[1].unkA = STR_SCHEDULED_TRAINS;
|
||||
_other_player_trains_widgets[1].unkA = STR_SCHEDULED_TRAINS;
|
||||
}
|
||||
DrawWindowWidgets(w);
|
||||
}
|
||||
/* draw sorting criteria string */
|
||||
DrawString(85, 15, _vehicle_sort_listing[_train_sort_type[window_number]], 0x10);
|
||||
/* draw arrow pointing up/down for ascending/descending soring */
|
||||
DoDrawString(_train_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 69, 15, 0x10);
|
||||
DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
|
||||
/* draw arrow pointing up/down for ascending/descending sorting */
|
||||
DoDrawString(
|
||||
vl->flags & VL_DESC ? "\xAA" : "\xA0", 69, 15, 0x10);
|
||||
|
||||
/* draw the trains */
|
||||
{
|
||||
Vehicle *v;
|
||||
int n = 0;
|
||||
const int x = 2; // offset from left side of widget
|
||||
int y = PLY_WND_PRC__OFFSET_TOP_WIDGET; // offset from top of widget
|
||||
i += w->vscroll.pos; // offset from sorted trains list of current player
|
||||
max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
|
||||
for (i = w->vscroll.pos; i < max; ++i) {
|
||||
Vehicle *v = DEREF_VEHICLE(vl->sort_list[i].index);
|
||||
StringID str;
|
||||
|
||||
while (i < _num_train_sort[window_number]) {
|
||||
StringID str;
|
||||
v = DEREF_VEHICLE(_train_sort[i].index);
|
||||
assert(v->type == VEH_Train && v->owner == owner);
|
||||
|
||||
assert(v->type == VEH_Train && v->subtype == 0 && v->owner == window_number);
|
||||
DrawTrainImage(
|
||||
v, x + 21, y + 6 + _traininfo_vehicle_pitch, 10, 0, INVALID_VEHICLE);
|
||||
DrawVehicleProfitButton(v, x, y + 13);
|
||||
|
||||
DrawTrainImage(v, x + 21, y + 6 + _traininfo_vehicle_pitch, 10, 0, INVALID_VEHICLE);
|
||||
DrawVehicleProfitButton(v, x, y+13);
|
||||
SetDParam(0, v->unitnumber);
|
||||
if (IsTrainDepotTile(v->tile))
|
||||
str = STR_021F;
|
||||
else
|
||||
str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
|
||||
DrawString(x, y + 2, str, 0);
|
||||
|
||||
SetDParam(0, v->unitnumber);
|
||||
if (IsTrainDepotTile(v->tile)) {
|
||||
str = STR_021F;
|
||||
} else {
|
||||
str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
|
||||
}
|
||||
DrawString(x, y+2, str, 0);
|
||||
SetDParam(0, v->profit_this_year);
|
||||
SetDParam(1, v->profit_last_year);
|
||||
DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
|
||||
|
||||
SetDParam(0, v->profit_this_year);
|
||||
SetDParam(1, v->profit_last_year);
|
||||
DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
|
||||
|
||||
if (v->string_id != STR_SV_TRAIN_NAME) {
|
||||
SetDParam(0, v->string_id);
|
||||
DrawString(x+21, y, STR_01AB, 0);
|
||||
}
|
||||
|
||||
y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
|
||||
i++; // next train
|
||||
if (++n == w->vscroll.cap) { break;} // max number of trains in the window
|
||||
if (v->string_id != STR_SV_TRAIN_NAME) {
|
||||
SetDParam(0, v->string_id);
|
||||
DrawString(x + 21, y, STR_01AB, 0);
|
||||
}
|
||||
|
||||
y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case WE_CLICK: {
|
||||
switch(e->click.widget) {
|
||||
case 2: /* Flip sorting method ascending/descending */
|
||||
_train_sort_order[(byte)w->window_number] ^= 1;
|
||||
_train_sort_dirty[(byte)w->window_number] = true;
|
||||
vl->flags ^= VL_DESC;
|
||||
vl->flags |= VL_RESORT;
|
||||
SetWindowDirty(w);
|
||||
break;
|
||||
|
||||
case 3: case 4:/* Select sorting criteria dropdown menu */
|
||||
ShowDropDownMenu(w, _vehicle_sort_listing, _train_sort_type[(byte)w->window_number], 4, 0); // do it for widget 4
|
||||
ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 4, 0);
|
||||
return;
|
||||
|
||||
case 6: { /* Matrix to show vehicles */
|
||||
uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_SMALL;
|
||||
|
||||
@@ -1323,13 +1294,11 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
|
||||
id_v += w->vscroll.pos;
|
||||
|
||||
{
|
||||
const byte owner = (byte)w->window_number;
|
||||
Vehicle *v;
|
||||
id_v += (owner == 0) ? 0 : _num_train_sort[owner - 1]; // first element in list
|
||||
|
||||
if (id_v >= _num_train_sort[owner]) { return;} // click out of vehicle bound
|
||||
if (id_v >= vl->list_length) return; // click out of list bound
|
||||
|
||||
v = DEREF_VEHICLE(_train_sort[id_v].index); // add the offset id_x to that
|
||||
v = DEREF_VEHICLE(vl->sort_list[id_v].index);
|
||||
|
||||
assert(v->type == VEH_Train && v->subtype == 0 && v->owner == owner);
|
||||
|
||||
@@ -1357,48 +1326,37 @@ static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
|
||||
} break;
|
||||
|
||||
case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
|
||||
if (_train_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
|
||||
_train_sort_dirty[(byte)w->window_number] = true;
|
||||
|
||||
_train_sort_type[(byte)w->window_number] = e->dropdown.index;
|
||||
|
||||
if (_train_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
|
||||
w->disabled_state &= ~(1 << 2);
|
||||
if (vl->sort_type != e->dropdown.index) {
|
||||
// value has changed -> resort
|
||||
vl->flags |= VL_RESORT;
|
||||
vl->sort_type = e->dropdown.index;
|
||||
|
||||
// enable 'Sort By' if a sorter criteria is chosen
|
||||
if (vl->sort_type != SORT_BY_UNSORTED)
|
||||
w->disabled_state &= ~(1 << 2);
|
||||
}
|
||||
SetWindowDirty(w);
|
||||
break;
|
||||
|
||||
case WE_CREATE: /* set up resort timer */
|
||||
w->custom[0] = DAY_TICKS;
|
||||
w->custom[1] = PERIODIC_RESORT_DAYS;
|
||||
vl->sort_list = NULL;
|
||||
vl->flags = VL_REBUILD;
|
||||
vl->sort_type = SORT_BY_UNSORTED;
|
||||
vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
|
||||
break;
|
||||
|
||||
case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
|
||||
if (--w->custom[0] == 0) {
|
||||
w->custom[0] = DAY_TICKS;
|
||||
if (--w->custom[1] == 0) {
|
||||
w->custom[1] = PERIODIC_RESORT_DAYS;
|
||||
_train_sort_dirty[(byte)w->window_number] = true;
|
||||
DEBUG(misc, 1) ("Periodic resort Trains list player %d...", w->window_number+1);
|
||||
SetWindowDirty(w);
|
||||
}
|
||||
if (--vl->resort_timer == 0) {
|
||||
DEBUG(misc, 1) ("Periodic resort trains list player %d station %d",
|
||||
owner, station);
|
||||
vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
|
||||
vl->flags |= VL_RESORT;
|
||||
SetWindowDirty(w);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const Widget _player_trains_widgets[] = {
|
||||
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_CAPTION, 14, 11, 324, 0, 13, STR_881B_TRAINS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 80, 14, 25, SRT_SORT_BY, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 81, 232, 14, 25, 0x0, STR_SORT_TIP},
|
||||
{ WWT_CLOSEBOX, 14, 233, 243, 14, 25, STR_0225, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 244, 324, 14, 25, 0x0, STR_NULL},
|
||||
{ WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
|
||||
{ WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 161, 208, 219, STR_8815_NEW_VEHICLES, STR_883E_BUILD_NEW_TRAINS_REQUIRES},
|
||||
{ WWT_PANEL, 14, 162, 324, 208, 219, 0x0, STR_NULL},
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
static const WindowDesc _player_trains_desc = {
|
||||
-1, -1, 325, 220,
|
||||
WC_TRAINS_LIST,0,
|
||||
@@ -1407,18 +1365,6 @@ static const WindowDesc _player_trains_desc = {
|
||||
PlayerTrainsWndProc
|
||||
};
|
||||
|
||||
static const Widget _other_player_trains_widgets[] = {
|
||||
{ WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||
{ WWT_CAPTION, 14, 11, 324, 0, 13, STR_881B_TRAINS, STR_018C_WINDOW_TITLE_DRAG_THIS},
|
||||
{ WWT_PUSHTXTBTN, 14, 0, 80, 14, 25, SRT_SORT_BY, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 81, 232, 14, 25, 0x0, STR_SORT_TIP},
|
||||
{ WWT_CLOSEBOX, 14, 233, 243, 14, 25, STR_0225, STR_SORT_TIP},
|
||||
{ WWT_PANEL, 14, 244, 324, 14, 25, 0x0, STR_NULL},
|
||||
{ WWT_MATRIX, 14, 0, 313, 26, 207, 0x701, STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
|
||||
{ WWT_SCROLLBAR, 14, 314, 324, 26, 207, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||
{ WIDGETS_END},
|
||||
};
|
||||
|
||||
static const WindowDesc _other_player_trains_desc = {
|
||||
-1, -1, 325, 208,
|
||||
WC_TRAINS_LIST,0,
|
||||
@@ -1427,14 +1373,14 @@ static const WindowDesc _other_player_trains_desc = {
|
||||
PlayerTrainsWndProc
|
||||
};
|
||||
|
||||
void ShowPlayerTrains(int player)
|
||||
void ShowPlayerTrains(int player, int station)
|
||||
{
|
||||
Window *w;
|
||||
|
||||
if (player == _local_player) {
|
||||
w = AllocateWindowDescFront(&_player_trains_desc, player);
|
||||
w = AllocateWindowDescFront(&_player_trains_desc, (station << 16) | player);
|
||||
} else {
|
||||
w = AllocateWindowDescFront(&_other_player_trains_desc, player);
|
||||
w = AllocateWindowDescFront(&_other_player_trains_desc, (station << 16) | player);
|
||||
}
|
||||
if (w) {
|
||||
w->caption_color = w->window_number;
|
||||
|
Reference in New Issue
Block a user