87 INVALID_STRING_ID |
88 INVALID_STRING_ID |
88 }; |
89 }; |
89 |
90 |
90 void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type) |
91 void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type) |
91 { |
92 { |
92 if (!(vl->vehicles.flags & VL_REBUILD)) return; |
93 if (!vl->vehicles.NeedRebuild()) return; |
93 |
94 |
94 DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, index); |
95 DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, index); |
95 |
96 |
96 GenerateVehicleSortList(&vl->vehicles, vl->vehicle_type, owner, index, window_type); |
97 GenerateVehicleSortList(&vl->vehicles, vl->vehicle_type, owner, index, window_type); |
97 |
98 |
98 vl->vehicles.flags &= ~VL_REBUILD; |
99 vl->vehicles.RebuildDone(); |
99 vl->vehicles.flags |= VL_RESORT; |
|
100 } |
100 } |
101 |
101 |
102 /* cached values for VehicleNameSorter to spare many GetString() calls */ |
102 /* cached values for VehicleNameSorter to spare many GetString() calls */ |
103 static const Vehicle *_last_vehicle[2] = { NULL, NULL }; |
103 static const Vehicle *_last_vehicle[2] = { NULL, NULL }; |
104 static char _last_name[2][64] = { "", "" }; |
|
105 |
104 |
106 void SortVehicleList(VehicleListBase *vl) |
105 void SortVehicleList(VehicleListBase *vl) |
107 { |
106 { |
108 if (!(vl->vehicles.flags & VL_RESORT)) return; |
107 if (vl->vehicles.Sort(_vehicle_sorter[vl->vehicles.SortType()])) return; |
109 |
108 |
110 /* invalidate cached values for name sorter - vehicle names could change */ |
109 /* invalidate cached values for name sorter - vehicle names could change */ |
111 _last_vehicle[0] = _last_vehicle[1] = NULL; |
110 _last_vehicle[0] = _last_vehicle[1] = NULL; |
112 |
|
113 _internal_sort_order = (vl->vehicles.flags & VL_DESC) != 0; |
|
114 qsort((void*)vl->vehicles.Begin(), vl->vehicles.Length(), sizeof(*vl->vehicles.Begin()), |
|
115 _vehicle_sorter[vl->vehicles.sort_type]); |
|
116 |
|
117 vl->vehicles.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS; |
|
118 vl->vehicles.flags &= ~VL_RESORT; |
|
119 } |
111 } |
120 |
112 |
121 void DepotSortList(VehicleList *list) |
113 void DepotSortList(VehicleList *list) |
122 { |
114 { |
123 _internal_sort_order = 0; |
|
124 if (list->Length() < 2) return; |
115 if (list->Length() < 2) return; |
125 qsort((void*)list->Begin(), list->Length(), sizeof(*list->Begin()), _vehicle_sorter[0]); |
116 QSortT(list->Begin(), list->Length(), _vehicle_sorter[0]); |
126 } |
117 } |
127 |
118 |
128 /** draw the vehicle profit button in the vehicle list window. */ |
119 /** draw the vehicle profit button in the vehicle list window. */ |
129 void DrawVehicleProfitButton(const Vehicle *v, int x, int y) |
120 void DrawVehicleProfitButton(const Vehicle *v, int x, int y) |
130 { |
121 { |
505 |
496 |
506 return DrawStringMultiLine(x, y, STR_SPEC_USERSTRING, w); |
497 return DrawStringMultiLine(x, y, STR_SPEC_USERSTRING, w); |
507 } |
498 } |
508 |
499 |
509 |
500 |
510 /* if the sorting criteria had the same value, sort vehicle by unitnumber */ |
501 /** Sort vehicles by their number */ |
511 #define VEHICLEUNITNUMBERSORTER(r, a, b) {if (r == 0) {r = a->unitnumber - b->unitnumber;}} |
502 static int CDECL VehicleNumberSorter(const Vehicle* const *a, const Vehicle* const *b) |
512 |
503 { |
513 static int CDECL VehicleNumberSorter(const void *a, const void *b) |
504 return (*a)->unitnumber - (*b)->unitnumber; |
514 { |
505 } |
515 const Vehicle* va = *(const Vehicle**)a; |
506 |
516 const Vehicle* vb = *(const Vehicle**)b; |
507 /** Sort vehicles by their name */ |
517 int r = va->unitnumber - vb->unitnumber; |
508 static int CDECL VehicleNameSorter(const Vehicle* const *a, const Vehicle* const *b) |
518 |
509 { |
519 return (_internal_sort_order & 1) ? -r : r; |
510 static char last_name[2][64]; |
520 } |
511 |
521 |
512 if (*a != _last_vehicle[0]) { |
522 static int CDECL VehicleNameSorter(const void *a, const void *b) |
513 _last_vehicle[0] = *a; |
523 { |
514 SetDParam(0, (*a)->index); |
524 const Vehicle* va = *(const Vehicle**)a; |
515 GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0])); |
525 const Vehicle* vb = *(const Vehicle**)b; |
516 } |
526 int r; |
517 |
527 |
518 if (*b != _last_vehicle[1]) { |
528 if (va != _last_vehicle[0]) { |
519 _last_vehicle[1] = *b; |
529 _last_vehicle[0] = va; |
520 SetDParam(0, (*b)->index); |
530 SetDParam(0, va->index); |
521 GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1])); |
531 GetString(_last_name[0], STR_VEHICLE_NAME, lastof(_last_name[0])); |
522 } |
532 } |
523 |
533 |
524 int r = strcmp(last_name[0], last_name[1]); |
534 if (vb != _last_vehicle[1]) { |
525 return (r != 0) ? r : VehicleNumberSorter(a, b); |
535 _last_vehicle[1] = vb; |
526 } |
536 SetDParam(0, vb->index); |
527 |
537 GetString(_last_name[1], STR_VEHICLE_NAME, lastof(_last_name[1])); |
528 /** Sort vehicles by their age */ |
538 } |
529 static int CDECL VehicleAgeSorter(const Vehicle* const *a, const Vehicle* const *b) |
539 |
530 { |
540 r = strcmp(_last_name[0], _last_name[1]); // sort by name |
531 int r = (*a)->age - (*b)->age; |
541 |
532 return (r != 0) ? r : VehicleNumberSorter(a, b); |
542 VEHICLEUNITNUMBERSORTER(r, va, vb); |
533 } |
543 |
534 |
544 return (_internal_sort_order & 1) ? -r : r; |
535 /** Sort vehicles by this year profit */ |
545 } |
536 static int CDECL VehicleProfitThisYearSorter(const Vehicle* const *a, const Vehicle* const *b) |
546 |
537 { |
547 static int CDECL VehicleAgeSorter(const void *a, const void *b) |
538 int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear()); |
548 { |
539 return (r != 0) ? r : VehicleNumberSorter(a, b); |
549 const Vehicle* va = *(const Vehicle**)a; |
540 } |
550 const Vehicle* vb = *(const Vehicle**)b; |
541 |
551 int r = va->age - vb->age; |
542 /** Sort vehicles by last year profit */ |
552 |
543 static int CDECL VehicleProfitLastYearSorter(const Vehicle* const *a, const Vehicle* const *b) |
553 VEHICLEUNITNUMBERSORTER(r, va, vb); |
544 { |
554 |
545 int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear()); |
555 return (_internal_sort_order & 1) ? -r : r; |
546 return (r != 0) ? r : VehicleNumberSorter(a, b); |
556 } |
547 } |
557 |
548 |
558 static int CDECL VehicleProfitThisYearSorter(const void *a, const void *b) |
549 /** Sort vehicles by their cargo */ |
559 { |
550 static int CDECL VehicleCargoSorter(const Vehicle* const *a, const Vehicle* const *b) |
560 const Vehicle* va = *(const Vehicle**)a; |
551 { |
561 const Vehicle* vb = *(const Vehicle**)b; |
552 const Vehicle *v; |
562 int r = ClampToI32(va->GetDisplayProfitThisYear() - vb->GetDisplayProfitThisYear()); |
553 AcceptedCargo diff; |
563 |
554 MemSetT(diff, 0); |
564 VEHICLEUNITNUMBERSORTER(r, va, vb); |
555 |
565 |
556 /* Append the cargo of the connected weagons */ |
566 return (_internal_sort_order & 1) ? -r : r; |
557 for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; |
567 } |
558 for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; |
568 |
559 |
569 static int CDECL VehicleProfitLastYearSorter(const void *a, const void *b) |
|
570 { |
|
571 const Vehicle* va = *(const Vehicle**)a; |
|
572 const Vehicle* vb = *(const Vehicle**)b; |
|
573 int r = ClampToI32(va->GetDisplayProfitLastYear() - vb->GetDisplayProfitLastYear()); |
|
574 |
|
575 VEHICLEUNITNUMBERSORTER(r, va, vb); |
|
576 |
|
577 return (_internal_sort_order & 1) ? -r : r; |
|
578 } |
|
579 |
|
580 static int CDECL VehicleCargoSorter(const void *a, const void *b) |
|
581 { |
|
582 const Vehicle* va = *(const Vehicle**)a; |
|
583 const Vehicle* vb = *(const Vehicle**)b; |
|
584 const Vehicle* v; |
|
585 AcceptedCargo cargoa; |
|
586 AcceptedCargo cargob; |
|
587 int r = 0; |
560 int r = 0; |
588 |
|
589 memset(cargoa, 0, sizeof(cargoa)); |
|
590 memset(cargob, 0, sizeof(cargob)); |
|
591 for (v = va; v != NULL; v = v->Next()) cargoa[v->cargo_type] += v->cargo_cap; |
|
592 for (v = vb; v != NULL; v = v->Next()) cargob[v->cargo_type] += v->cargo_cap; |
|
593 |
|
594 for (CargoID i = 0; i < NUM_CARGO; i++) { |
561 for (CargoID i = 0; i < NUM_CARGO; i++) { |
595 r = cargoa[i] - cargob[i]; |
562 r = diff[i]; |
596 if (r != 0) break; |
563 if (r != 0) break; |
597 } |
564 } |
598 |
565 |
599 VEHICLEUNITNUMBERSORTER(r, va, vb); |
566 return (r != 0) ? r : VehicleNumberSorter(a, b); |
600 |
567 } |
601 return (_internal_sort_order & 1) ? -r : r; |
568 |
602 } |
569 /** Sort vehicles by their reliability */ |
603 |
570 static int CDECL VehicleReliabilitySorter(const Vehicle* const *a, const Vehicle* const *b) |
604 static int CDECL VehicleReliabilitySorter(const void *a, const void *b) |
571 { |
605 { |
572 int r = (*a)->reliability - (*b)->reliability; |
606 const Vehicle* va = *(const Vehicle**)a; |
573 return (r != 0) ? r : VehicleNumberSorter(a, b); |
607 const Vehicle* vb = *(const Vehicle**)b; |
574 } |
608 int r = va->reliability - vb->reliability; |
575 |
609 |
576 /** Sort vehicles by their max speed */ |
610 VEHICLEUNITNUMBERSORTER(r, va, vb); |
577 static int CDECL VehicleMaxSpeedSorter(const Vehicle* const *a, const Vehicle* const *b) |
611 |
578 { |
612 return (_internal_sort_order & 1) ? -r : r; |
579 int r = 0; |
613 } |
580 if ((*a)->type == VEH_TRAIN && (*b)->type == VEH_TRAIN) { |
614 |
581 r = (*a)->u.rail.cached_max_speed - (*b)->u.rail.cached_max_speed; |
615 static int CDECL VehicleMaxSpeedSorter(const void *a, const void *b) |
|
616 { |
|
617 const Vehicle* va = *(const Vehicle**)a; |
|
618 const Vehicle* vb = *(const Vehicle**)b; |
|
619 int r; |
|
620 |
|
621 if (va->type == VEH_TRAIN && vb->type == VEH_TRAIN) { |
|
622 r = va->u.rail.cached_max_speed - vb->u.rail.cached_max_speed; |
|
623 } else { |
582 } else { |
624 r = va->max_speed - vb->max_speed; |
583 r = (*a)->max_speed - (*b)->max_speed; |
625 } |
584 } |
626 |
585 return (r != 0) ? r : VehicleNumberSorter(a, b); |
627 VEHICLEUNITNUMBERSORTER(r, va, vb); |
586 } |
628 |
587 |
629 return (_internal_sort_order & 1) ? -r : r; |
588 /** Sort vehicles by model */ |
630 } |
589 static int CDECL VehicleModelSorter(const Vehicle* const *a, const Vehicle* const *b) |
631 |
590 { |
632 static int CDECL VehicleModelSorter(const void *a, const void *b) |
591 int r = (*a)->engine_type - (*b)->engine_type; |
633 { |
592 return (r != 0) ? r : VehicleNumberSorter(a, b); |
634 const Vehicle* va = *(const Vehicle**)a; |
593 } |
635 const Vehicle* vb = *(const Vehicle**)b; |
594 |
636 int r = va->engine_type - vb->engine_type; |
595 /** Sort vehciles by their value */ |
637 |
596 static int CDECL VehicleValueSorter(const Vehicle* const *a, const Vehicle* const *b) |
638 VEHICLEUNITNUMBERSORTER(r, va, vb); |
597 { |
639 |
|
640 return (_internal_sort_order & 1) ? -r : r; |
|
641 } |
|
642 |
|
643 static int CDECL VehicleValueSorter(const void *a, const void *b) |
|
644 { |
|
645 const Vehicle* va = *(const Vehicle**)a; |
|
646 const Vehicle* vb = *(const Vehicle**)b; |
|
647 const Vehicle *u; |
598 const Vehicle *u; |
648 Money valuea = 0, valueb = 0; |
599 Money diff = 0; |
649 |
600 |
650 for (u = va; u != NULL; u = u->Next()) valuea += u->value; |
601 for (u = *a; u != NULL; u = u->Next()) diff += u->value; |
651 for (u = vb; u != NULL; u = u->Next()) valueb += u->value; |
602 for (u = *b; u != NULL; u = u->Next()) diff -= u->value; |
652 |
603 |
653 int r = ClampToI32(valuea - valueb); |
604 int r = ClampToI32(diff); |
654 |
605 return (r != 0) ? r : VehicleNumberSorter(a, b); |
655 VEHICLEUNITNUMBERSORTER(r, va, vb); |
606 } |
656 |
607 |
657 return (_internal_sort_order & 1) ? -r : r; |
608 /** Sort vehicles by their length */ |
658 } |
609 static int CDECL VehicleLengthSorter(const Vehicle* const *a, const Vehicle* const *b) |
659 |
610 { |
660 static int CDECL VehicleLengthSorter(const void *a, const void *b) |
|
661 { |
|
662 const Vehicle *va = *(const Vehicle**)a; |
|
663 const Vehicle *vb = *(const Vehicle**)b; |
|
664 int r = 0; |
611 int r = 0; |
665 |
612 switch ((*a)->type) { |
666 switch (va->type) { |
|
667 case VEH_TRAIN: |
613 case VEH_TRAIN: |
668 r = va->u.rail.cached_total_length - vb->u.rail.cached_total_length; |
614 r = (*a)->u.rail.cached_total_length - (*b)->u.rail.cached_total_length; |
669 break; |
615 break; |
670 |
616 |
671 case VEH_ROAD: |
617 case VEH_ROAD: { |
672 for (const Vehicle *u = va; u != NULL; u = u->Next()) r += u->u.road.cached_veh_length; |
618 const Vehicle *u; |
673 for (const Vehicle *u = vb; u != NULL; u = u->Next()) r -= u->u.road.cached_veh_length; |
619 for (u = *a; u != NULL; u = u->Next()) r += u->u.road.cached_veh_length; |
674 break; |
620 for (u = *b; u != NULL; u = u->Next()) r -= u->u.road.cached_veh_length; |
|
621 } break; |
675 |
622 |
676 default: NOT_REACHED(); |
623 default: NOT_REACHED(); |
677 } |
624 } |
678 |
625 return (r != 0) ? r : VehicleNumberSorter(a, b); |
679 VEHICLEUNITNUMBERSORTER(r, va, vb); |
|
680 |
|
681 return (_internal_sort_order & 1) ? -r : r; |
|
682 } |
626 } |
683 |
627 |
684 void InitializeGUI() |
628 void InitializeGUI() |
685 { |
629 { |
686 memset(&_sorting, 0, sizeof(_sorting)); |
630 MemSetT(&_sorting, 0); |
687 } |
631 } |
688 |
632 |
689 /** Assigns an already open vehicle window to a new vehicle. |
633 /** Assigns an already open vehicle window to a new vehicle. |
690 * Assigns an already open vehicle window to a new vehicle. If the vehicle got |
634 * Assigns an already open vehicle window to a new vehicle. If the vehicle got |
691 * any sub window open (orders and so on) it will change owner too. |
635 * any sub window open (orders and so on) it will change owner too. |