darkvater@164: #include "stdafx.h" darkvater@164: #include "ttd.h" tron@507: #include "table/strings.h" darkvater@164: #include "vehicle.h" tron@588: #include "window.h" darkvater@164: tron@505: VehicleSortListingTypeFunctions * const _vehicle_sorter[] = { tron@505: &VehicleUnsortedSorter, tron@505: &VehicleNumberSorter, tron@505: &VehicleNameSorter, tron@505: &VehicleAgeSorter, tron@505: &VehicleProfitThisYearSorter, tron@505: &VehicleProfitLastYearSorter, tron@505: &VehicleCargoSorter, tron@505: &VehicleReliabilitySorter, tron@505: &VehicleMaxSpeedSorter tron@505: }; tron@505: tron@505: const StringID _vehicle_sort_listing[] = { tron@505: STR_SORT_BY_UNSORTED, tron@505: STR_SORT_BY_NUMBER, tron@505: STR_SORT_BY_DROPDOWN_NAME, tron@505: STR_SORT_BY_AGE, tron@505: STR_SORT_BY_PROFIT_THIS_YEAR, tron@505: STR_SORT_BY_PROFIT_LAST_YEAR, tron@505: STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE, tron@505: STR_SORT_BY_RELIABILITY, tron@505: STR_SORT_BY_MAX_SPEED, tron@505: INVALID_STRING_ID tron@505: }; tron@505: tron@588: void RebuildVehicleLists(void) tron@588: { tron@588: Window *w; tron@588: tron@588: for (w = _windows; w != _last_window; ++w) tron@588: switch (w->window_class) { tron@588: case WC_TRAINS_LIST: tron@588: case WC_ROADVEH_LIST: tron@588: case WC_SHIPS_LIST: tron@588: case WC_AIRCRAFT_LIST: tron@588: WP(w, vehiclelist_d).flags |= VL_REBUILD; tron@588: SetWindowDirty(w); tron@588: break; tron@588: tron@588: default: tron@588: break; tron@588: } tron@588: } tron@588: tron@588: void ResortVehicleLists(void) tron@588: { tron@588: Window *w; tron@588: tron@588: for (w = _windows; w != _last_window; ++w) tron@588: switch (w->window_class) { tron@588: case WC_TRAINS_LIST: tron@588: case WC_ROADVEH_LIST: tron@588: case WC_SHIPS_LIST: tron@588: case WC_AIRCRAFT_LIST: tron@588: WP(w, vehiclelist_d).flags |= VL_RESORT; tron@588: SetWindowDirty(w); tron@588: break; tron@588: tron@588: default: tron@588: break; tron@588: } tron@588: } tron@588: tron@588: void BuildVehicleList(vehiclelist_d *vl, int type, int owner, int station) tron@588: { tron@588: SortStruct sort_list[NUM_NORMAL_VEHICLES]; tron@588: int subtype = (type != VEH_Aircraft) ? 0 : 2; tron@588: int n = 0; tron@588: int i; tron@588: tron@588: if (!(vl->flags & VL_REBUILD)) return; tron@588: tron@588: DEBUG(misc, 1) ("Building vehicle list for player %d station %d...", tron@588: owner, station); tron@588: tron@588: if (station != -1) { tron@588: const Vehicle *v; tron@588: FOR_ALL_VEHICLES(v) { tron@588: if (v->type == type && v->subtype <= subtype) { tron@588: const Order *ord; tron@588: for (ord = v->schedule_ptr; ord->type != OT_NOTHING; ++ord) tron@588: if (ord->type == OT_GOTO_STATION && ord->station == station) { tron@588: sort_list[n].index = v - _vehicles; tron@588: sort_list[n].owner = v->owner; tron@588: ++n; tron@588: break; tron@588: } tron@588: } tron@588: } tron@588: } else { tron@588: const Vehicle *v; tron@588: FOR_ALL_VEHICLES(v) { tron@588: if (v->type == type && v->subtype <= subtype && v->owner == owner) { tron@588: sort_list[n].index = v - _vehicles; tron@588: sort_list[n].owner = v->owner; tron@588: ++n; tron@588: } tron@588: } tron@588: } tron@588: tron@588: vl->sort_list = realloc(vl->sort_list, n * sizeof(vl->sort_list[0])); /* XXX unchecked malloc */ tron@588: vl->list_length = n; tron@588: tron@588: for (i = 0; i < n; ++i) tron@588: vl->sort_list[i] = sort_list[i]; tron@588: tron@588: vl->flags &= ~VL_REBUILD; tron@588: vl->flags |= VL_RESORT; tron@588: } tron@588: tron@588: void SortVehicleList(vehiclelist_d *vl) tron@588: { tron@588: if (!(vl->flags & VL_RESORT)) return; tron@588: tron@588: _internal_sort_order = vl->flags & VL_DESC; tron@588: _internal_name_sorter_id = STR_SV_TRAIN_NAME; tron@588: _last_vehicle_idx = 0; // used for "cache" in namesorting tron@588: qsort(vl->sort_list, vl->list_length, sizeof(vl->sort_list[0]), tron@588: _vehicle_sorter[vl->sort_type]); tron@588: tron@588: vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS; tron@588: vl->flags &= ~VL_RESORT; tron@588: } tron@588: tron@588: darkvater@164: /* General Vehicle GUI based procedures that are independent of vehicle types */ darkvater@164: void InitializeVehiclesGuiList() darkvater@164: { darkvater@164: } darkvater@164: darkvater@164: // draw the vehicle profit button in the vehicle list window. darkvater@164: void DrawVehicleProfitButton(Vehicle *v, int x, int y) darkvater@164: { darkvater@164: uint32 ormod; darkvater@164: darkvater@164: // draw profit-based colored icons darkvater@164: if(v->age <= 365 * 2) darkvater@164: ormod = 0x3158000; // grey darkvater@164: else if(v->profit_last_year < 0) darkvater@164: ormod = 0x30b8000; //red darkvater@164: else if(v->profit_last_year < 10000) darkvater@164: ormod = 0x30a8000; // yellow darkvater@164: else darkvater@164: ormod = 0x30d8000; // green dominik@579: DrawSprite((SPR_BLOT) | ormod, x, y); darkvater@164: } darkvater@164: darkvater@164: /************ Sorter functions *****************/ darkvater@164: int CDECL GeneralOwnerSorter(const void *a, const void *b) darkvater@164: { darkvater@168: return (*(const SortStruct*)a).owner - (*(const SortStruct*)b).owner; darkvater@168: } darkvater@168: darkvater@168: /* Variables you need to set before calling this function! darkvater@168: * 1. (byte)_internal_sort_type: sorting criteria to sort on darkvater@168: * 2. (bool)_internal_sort_order: sorting order, descending/ascending darkvater@168: * 3. (uint32)_internal_name_sorter_id: default StringID of the vehicle when no name is set. eg darkvater@168: * STR_SV_TRAIN_NAME for trains or STR_SV_AIRCRAFT_NAME for aircraft darkvater@168: */ darkvater@168: int CDECL VehicleUnsortedSorter(const void *a, const void *b) darkvater@168: { darkvater@168: return DEREF_VEHICLE((*(const SortStruct*)a).index)->index - DEREF_VEHICLE((*(const SortStruct*)b).index)->index; darkvater@168: } darkvater@168: darkvater@243: // if the sorting criteria had the same value, sort vehicle by unitnumber darkvater@243: #define VEHICLEUNITNUMBERSORTER(r, a, b) {if (r == 0) {r = a->unitnumber - b->unitnumber;}} darkvater@243: darkvater@168: int CDECL VehicleNumberSorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->unitnumber - vb->unitnumber; darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@164: } darkvater@164: darkvater@164: static char _bufcache[64]; // used together with _last_vehicle_idx to hopefully speed up stringsorting darkvater@164: int CDECL VehicleNameSorter(const void *a, const void *b) darkvater@164: { darkvater@171: const SortStruct *cmp1 = (const SortStruct*)a; darkvater@171: const SortStruct *cmp2 = (const SortStruct*)b; darkvater@168: const Vehicle *va = DEREF_VEHICLE(cmp1->index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE(cmp2->index); darkvater@164: char buf1[64] = "\0"; darkvater@164: int r; darkvater@164: darkvater@168: if (va->string_id != _internal_name_sorter_id) { tron@534: SetDParam(0, va->string_id); darkvater@164: GetString(buf1, STR_0315); darkvater@164: } darkvater@164: darkvater@164: if ( cmp2->index != _last_vehicle_idx) { darkvater@164: _last_vehicle_idx = cmp2->index; darkvater@164: _bufcache[0] = '\0'; darkvater@168: if (vb->string_id != _internal_name_sorter_id) { tron@534: SetDParam(0, vb->string_id); darkvater@164: GetString(_bufcache, STR_0315); darkvater@164: } darkvater@164: } darkvater@164: darkvater@164: r = strcmp(buf1, _bufcache); // sort by name truelight@193: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@164: } darkvater@164: darkvater@168: int CDECL VehicleAgeSorter(const void *a, const void *b) darkvater@164: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->age - vb->age; darkvater@164: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@168: } darkvater@168: darkvater@168: int CDECL VehicleProfitThisYearSorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->profit_this_year - vb->profit_this_year; truelight@193: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@168: } darkvater@168: darkvater@168: int CDECL VehicleProfitLastYearSorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->profit_last_year - vb->profit_last_year; darkvater@168: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@168: } darkvater@168: darkvater@168: int CDECL VehicleCargoSorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); tron@594: const Vehicle *v; darkvater@168: int r = 0; darkvater@168: int i; tron@594: uint _cargo_counta[NUM_CARGO]; tron@594: uint _cargo_countb[NUM_CARGO]; darkvater@168: memset(_cargo_counta, 0, sizeof(_cargo_counta)); darkvater@168: memset(_cargo_countb, 0, sizeof(_cargo_countb)); darkvater@168: tron@594: for (v = va; v != NULL; v = v->next) tron@594: _cargo_counta[v->cargo_type] += v->cargo_cap; darkvater@168: tron@594: for (v = vb; v != NULL; v = v->next) tron@594: _cargo_countb[v->cargo_type] += v->cargo_cap; darkvater@168: darkvater@168: for (i = 0; i < NUM_CARGO; i++) { darkvater@168: r = _cargo_counta[i] - _cargo_countb[i]; darkvater@168: if (r != 0) darkvater@164: break; darkvater@168: } darkvater@164: tron@594: VEHICLEUNITNUMBERSORTER(r, va, vb); tron@594: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@164: } darkvater@168: darkvater@168: int CDECL VehicleReliabilitySorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->reliability - vb->reliability; darkvater@168: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; darkvater@168: } darkvater@168: darkvater@168: int CDECL VehicleMaxSpeedSorter(const void *a, const void *b) darkvater@168: { darkvater@168: const Vehicle *va = DEREF_VEHICLE((*(const SortStruct*)a).index); darkvater@168: const Vehicle *vb = DEREF_VEHICLE((*(const SortStruct*)b).index); darkvater@168: int r = va->max_speed - vb->max_speed; darkvater@168: darkvater@243: VEHICLEUNITNUMBERSORTER(r, va, vb); darkvater@168: darkvater@168: return (_internal_sort_order & 1) ? -r : r; truelight@193: }