866 } |
865 } |
867 } |
866 } |
868 } |
867 } |
869 } |
868 } |
870 |
869 |
|
870 // used to get a sorted list of the vehicles |
|
871 static SortStruct _ship_sort[NUM_NORMAL_VEHICLES]; |
|
872 static uint16 _num_ship_sort[MAX_PLAYERS]; |
|
873 |
|
874 static void MakeSortedShiptList(byte owner) |
|
875 { |
|
876 SortStruct *firstelement; |
|
877 Vehicle *v; |
|
878 uint32 n = 0; |
|
879 uint16 *i; |
|
880 |
|
881 if (_vehicle_sort_dirty[VEHSHIP]) { // only resort the whole array if vehicles have been added/removed |
|
882 // reset to 0 just to be sure |
|
883 for (i = _num_ship_sort; i != endof(_num_ship_sort); i++) {*i = 0;} |
|
884 |
|
885 FOR_ALL_VEHICLES(v) { |
|
886 if(v->type == VEH_Ship) { |
|
887 _ship_sort[n].index = v->index; |
|
888 _ship_sort[n++].owner = v->owner; |
|
889 _num_ship_sort[v->owner]++; // add number of trains of player |
|
890 } |
|
891 } |
|
892 |
|
893 // create cumulative ship-ownage |
|
894 // ships are stored as a cummulative index, eg 25, 41, 43. This means |
|
895 // Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 |
|
896 for (i = &_num_ship_sort[1]; i != endof(_num_ship_sort); i++) {*i += *(i-1);} |
|
897 |
|
898 |
|
899 // sort by owner, then only subsort the requested owner-vehicles |
|
900 qsort(_ship_sort, n, sizeof(_ship_sort[0]), GeneralOwnerSorter); |
|
901 |
|
902 _last_vehicle_idx = 0; // used for "cache" in namesorting |
|
903 _vehicle_sort_dirty[VEHSHIP] = false; |
|
904 } |
|
905 |
|
906 if (owner == 0) { // first element starts at 0th element and has n elements as described above |
|
907 firstelement = &_ship_sort[0]; |
|
908 n = _num_ship_sort[0]; |
|
909 } else { // nth element starts at the end of the previous one, and has n elements as described above |
|
910 firstelement = &_ship_sort[_num_ship_sort[owner-1]]; |
|
911 n = _num_ship_sort[owner] - _num_ship_sort[owner-1]; |
|
912 } |
|
913 |
|
914 _internal_sort_type = _ship_sort_type[owner]; |
|
915 _internal_sort_order = _ship_sort_order[owner]; |
|
916 _internal_name_sorter_id = STR_SV_SHIP_NAME; |
|
917 // only name sorting needs a different procedure, all others are handled by the general sorter |
|
918 qsort(firstelement, n, sizeof(_ship_sort[0]), (_internal_sort_type == SORT_BY_NAME) ? VehicleNameSorter : GeneralVehicleSorter); |
|
919 |
|
920 DEBUG(misc, 1) ("Resorting Ships list player %d...", owner+1); |
|
921 } |
|
922 |
871 static void PlayerShipsWndProc(Window *w, WindowEvent *e) |
923 static void PlayerShipsWndProc(Window *w, WindowEvent *e) |
872 { |
924 { |
873 switch(e->event) { |
925 switch(e->event) { |
874 case WE_PAINT: |
926 case WE_PAINT: { |
875 /* determine amount of items for scroller */ |
927 uint32 i; |
|
928 const byte window_number = (byte)w->window_number; |
|
929 |
|
930 if (_ship_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria |
|
931 w->disabled_state |= (1 << 3); |
|
932 |
|
933 if (_ship_sort_dirty[window_number] || _vehicle_sort_dirty[VEHSHIP]) { |
|
934 _ship_sort_dirty[window_number] = false; |
|
935 MakeSortedShiptList(window_number); |
|
936 /* reset sorting timeout */ |
|
937 w->custom[0] = DAY_TICKS; |
|
938 w->custom[1] = PERIODIC_RESORT_DAYS; |
|
939 } |
|
940 |
|
941 // ships are stored as a cummulative index, eg 25, 41, 43. This means |
|
942 // Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 ships |
|
943 i = (window_number == 0) ? 0 : _num_ship_sort[window_number-1]; |
|
944 SetVScrollCount(w, _num_ship_sort[window_number] - i); |
|
945 |
|
946 /* draw the widgets */ |
|
947 { |
|
948 Player *p = DEREF_PLAYER(window_number); |
|
949 /* Company Name -- (###) Ships */ |
|
950 SET_DPARAM16(0, p->name_1); |
|
951 SET_DPARAM32(1, p->name_2); |
|
952 SET_DPARAM16(2, w->vscroll.count); |
|
953 SET_DPARAM16(3, _vehicle_sort_listing[_ship_sort_type[window_number]]); |
|
954 DrawWindowWidgets(w); |
|
955 } |
|
956 /* draw arrow pointing up/down for ascending/descending soring */ |
|
957 DoDrawString(_ship_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 85, 15, 0x10); |
|
958 |
|
959 /* draw the ship vehicles */ |
876 { |
960 { |
877 Vehicle *v; |
961 Vehicle *v; |
878 int num = 0; |
962 int n = 0; |
879 byte owner = (byte)w->window_number; |
963 const int x = 2; // offset from left side of widget |
880 |
964 int y = PLY_WND_PRC__OFFSET_TOP_WIDGET; // offset from top of widget |
881 FOR_ALL_VEHICLES(v) { |
965 i += w->vscroll.pos; // offset from sorted ship list of current player |
882 if (v->type == VEH_Ship && v->owner == owner) |
966 |
883 num++; |
967 while (i < _num_ship_sort[window_number]) { |
884 } |
968 StringID str; |
885 SetVScrollCount(w, num); |
969 v = DEREF_VEHICLE(_ship_sort[i].index); |
886 } |
970 |
887 |
971 DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE); |
888 /* draw the widgets */ |
972 DrawVehicleProfitButton(v, x, y+13); |
889 { |
973 |
890 Player *p = DEREF_PLAYER(w->window_number); |
974 SET_DPARAM16(0, v->unitnumber); |
891 SET_DPARAM16(0, p->name_1); |
975 if (IsShipDepotTile(v->tile)) { |
892 SET_DPARAM32(1, p->name_2); |
976 str = STR_021F; |
893 DrawWindowWidgets(w); |
977 } else { |
894 } |
978 str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2; |
895 |
979 } |
896 /* draw the ships vehicles */ |
980 DrawString(x, y+2, str, 0); |
897 { |
981 |
898 Vehicle *v; |
982 SET_DPARAM32(0, v->profit_this_year); |
899 int pos = w->vscroll.pos; |
983 SET_DPARAM32(1, v->profit_last_year); |
900 byte owner = (byte)w->window_number; |
984 DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0); |
901 int x = 2; |
985 |
902 int y = 15; |
986 if (v->string_id != STR_SV_SHIP_NAME) { |
|
987 SET_DPARAM16(0, v->string_id); |
|
988 DrawString(x+12, y, STR_01AB, 0); |
|
989 } |
|
990 |
|
991 DrawSmallShipSchedule(v, x+138, y); |
|
992 |
|
993 |
|
994 y += PLY_WND_PRC__SIZE_OF_ROW_BIG; |
|
995 i++; // next ship |
|
996 if (++n == w->vscroll.cap) { break;} // max number of ships in the window |
|
997 } |
|
998 } |
|
999 } break; |
|
1000 |
|
1001 case WE_CLICK: { |
|
1002 switch(e->click.widget) { |
|
1003 case 3: /* Flip sorting method ascending/descending */ |
|
1004 _ship_sort_order[(byte)w->window_number] ^= 1; |
|
1005 _ship_sort_dirty[(byte)w->window_number] = true; |
|
1006 SetWindowDirty(w); |
|
1007 break; |
|
1008 case 4: case 5:/* Select sorting criteria dropdown menu */ |
|
1009 ShowDropDownMenu(w, _vehicle_sort_listing, _ship_sort_type[(byte)w->window_number], 5, 0); // do it for widget 5 |
|
1010 return; |
|
1011 case 6: { /* Matrix to show vehicles */ |
|
1012 int id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG; |
903 |
1013 |
904 FOR_ALL_VEHICLES(v) { |
1014 if ((uint)id_v >= w->vscroll.cap) { return;} // click out of bounds |
905 if (v->type == VEH_Ship && v->owner == owner && |
1015 |
906 --pos < 0 && pos >= -4) { |
1016 id_v += w->vscroll.pos; |
907 StringID str; |
1017 |
908 |
1018 { |
909 DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE); |
1019 byte owner = (byte)w->window_number; |
910 DrawVehicleProfitButton(v, x, y+13); |
1020 uint16 adder = (owner == 0) ? 0 : _num_ship_sort[owner - 1]; // first element in list |
911 |
1021 Vehicle *v; |
912 SET_DPARAM16(0, v->unitnumber); |
1022 |
913 if (IsShipDepotTile(v->tile)) { |
1023 if (id_v + adder >= _num_ship_sort[owner]) { return;} // click out of vehicle bound |
914 str = STR_021F; |
1024 |
915 } else { |
1025 v = DEREF_VEHICLE(_ship_sort[adder+id_v].index); // add the offset id_x to that |
916 str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2; |
1026 |
917 } |
1027 assert(v->type == VEH_Ship && v->owner == owner && v->owner == _ship_sort[adder+id_v].owner); |
918 DrawString(x, y+2, str, 0); |
1028 |
919 |
1029 ShowShipViewWindow(v); |
920 SET_DPARAM32(0, v->profit_this_year); |
1030 } |
921 SET_DPARAM32(1, v->profit_last_year); |
1031 } break; |
922 DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0); |
1032 |
923 |
1033 case 8: { /* Build new Vehicle */ |
924 if (v->string_id != STR_SV_SHIP_NAME) { |
|
925 SET_DPARAM16(0, v->string_id); |
|
926 DrawString(x+12, y, STR_01AB, 0); |
|
927 } |
|
928 |
|
929 DrawSmallShipSchedule(v, x+138, y); |
|
930 |
|
931 y += 36; |
|
932 } |
|
933 } |
|
934 } |
|
935 break; |
|
936 case WE_CLICK: |
|
937 switch(e->click.widget) { |
|
938 case 2: { /* click ship */ |
|
939 int sel; |
|
940 Vehicle *v; |
|
941 byte owner; |
|
942 |
|
943 sel = (e->click.pt.y - 14) / 36; |
|
944 |
|
945 if ((uint)sel >= 4) |
|
946 break; |
|
947 sel += w->vscroll.pos; |
|
948 owner = (byte)w->window_number; |
|
949 FOR_ALL_VEHICLES(v) { |
|
950 if (v->type == VEH_Ship && v->owner == owner && --sel < 0) { |
|
951 ShowShipViewWindow(v); |
|
952 break; |
|
953 } |
|
954 } |
|
955 break; |
|
956 } |
|
957 case 4: {/* click buy */ |
|
958 uint tile; |
1034 uint tile; |
959 |
1035 |
960 tile = _last_built_ship_depot_tile; |
1036 tile = _last_built_ship_depot_tile; |
961 do { |
1037 do { |
962 if (_map_owner[tile] == _local_player && |
1038 if (_map_owner[tile] == _local_player && IsShipDepotTile(tile)) { |
963 IsShipDepotTile(tile)) { |
|
964 |
|
965 ShowShipDepotWindow(tile); |
1039 ShowShipDepotWindow(tile); |
966 ShowBuildShipWindow(tile); |
1040 ShowBuildShipWindow(tile); |
967 return; |
1041 return; |
968 } |
1042 } |
969 |
1043 |
971 } while(tile != _last_built_ship_depot_tile); |
1045 } while(tile != _last_built_ship_depot_tile); |
972 |
1046 |
973 ShowBuildShipWindow(0); |
1047 ShowBuildShipWindow(0); |
974 } break; |
1048 } break; |
975 } |
1049 } |
976 break; |
1050 } break; |
977 } |
1051 |
978 } |
1052 case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ |
979 |
1053 if (_ship_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list |
|
1054 _ship_sort_dirty[(byte)w->window_number] = true; |
|
1055 |
|
1056 _ship_sort_type[(byte)w->window_number] = e->dropdown.index; |
|
1057 |
|
1058 if (_ship_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen |
|
1059 w->disabled_state &= ~(1 << 3); |
|
1060 |
|
1061 SetWindowDirty(w); |
|
1062 break; |
|
1063 case WE_CREATE: /* set up resort timer */ |
|
1064 w->custom[0] = DAY_TICKS; |
|
1065 w->custom[1] = PERIODIC_RESORT_DAYS; |
|
1066 break; |
|
1067 case WE_TICK: /* resort the list every 20 seconds orso (10 days) */ |
|
1068 if (--w->custom[0] == 0) { |
|
1069 w->custom[0] = DAY_TICKS; |
|
1070 if (--w->custom[1] == 0) { |
|
1071 w->custom[1] = PERIODIC_RESORT_DAYS; |
|
1072 _ship_sort_dirty[(byte)w->window_number] = true; |
|
1073 DEBUG(misc, 1) ("Periodic resort Ships list player %d...", w->window_number+1); |
|
1074 SetWindowDirty(w); |
|
1075 } |
|
1076 } |
|
1077 break; |
|
1078 } |
|
1079 } |
980 static const Widget _player_ships_widgets[] = { |
1080 static const Widget _player_ships_widgets[] = { |
981 { WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
1081 { WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
982 { WWT_CAPTION, 14, 11, 259, 0, 13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
1082 { WWT_CAPTION, 14, 11, 259, 0, 13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
983 { WWT_MATRIX, 14, 0, 248, 14, 157, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR}, |
1083 { WWT_PANEL, 14, 0, 15, 14, 25, 0x0, 0}, |
984 { WWT_SCROLLBAR, 14, 249, 259, 14, 157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
1084 { WWT_PUSHTXTBTN, 14, 16, 96, 14, 25, SRT_SORT_BY, STR_SORT_TIP}, |
985 { WWT_PUSHTXTBTN, 14, 0, 129, 158, 169, STR_9804_NEW_SHIPS, STR_9824_BUILD_NEW_SHIPS_REQUIRES}, |
1085 { WWT_TEXTBTN, 14, 97, 248, 14, 25, STR_02E7, 0}, |
986 { WWT_IMGBTN, 14, 130, 259, 158, 169, 0x0}, |
1086 { WWT_CLOSEBOX, 14, 249, 259, 14, 25, STR_0225, STR_SORT_TIP}, |
|
1087 { WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR}, |
|
1088 { WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
|
1089 { WWT_PUSHTXTBTN, 14, 0, 129, 170, 181, STR_9804_NEW_SHIPS, STR_9824_BUILD_NEW_SHIPS_REQUIRES}, |
|
1090 { WWT_PANEL, 14, 130, 259, 170, 181, 0x0, 0}, |
987 { WWT_LAST}, |
1091 { WWT_LAST}, |
988 }; |
1092 }; |
|
1093 |
989 static const WindowDesc _player_ships_desc = { |
1094 static const WindowDesc _player_ships_desc = { |
|
1095 -1, -1, 260, 182, |
|
1096 WC_SHIPS_LIST,0, |
|
1097 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM, |
|
1098 _player_ships_widgets, |
|
1099 PlayerShipsWndProc |
|
1100 }; |
|
1101 |
|
1102 static const Widget _other_player_ships_widgets[] = { |
|
1103 { WWT_CLOSEBOX, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
1104 { WWT_CAPTION, 14, 11, 259, 0, 13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
1105 { WWT_PANEL, 14, 0, 15, 14, 25, 0x0, 0}, |
|
1106 { WWT_PUSHTXTBTN, 14, 16, 96, 14, 25, SRT_SORT_BY, STR_SORT_TIP}, |
|
1107 { WWT_TEXTBTN, 14, 97, 248, 14, 25, STR_02E7, 0}, |
|
1108 { WWT_CLOSEBOX, 14, 249, 259, 14, 25, STR_0225, STR_SORT_TIP}, |
|
1109 { WWT_MATRIX, 14, 0, 248, 26, 169, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR}, |
|
1110 { WWT_SCROLLBAR, 14, 249, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
|
1111 { WWT_LAST}, |
|
1112 }; |
|
1113 |
|
1114 static const WindowDesc _other_player_ships_desc = { |
990 -1, -1, 260, 170, |
1115 -1, -1, 260, 170, |
991 WC_SHIPS_LIST,0, |
1116 WC_SHIPS_LIST,0, |
992 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, |
1117 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM, |
993 _player_ships_widgets, |
|
994 PlayerShipsWndProc |
|
995 }; |
|
996 |
|
997 static const Widget _other_player_ships_widgets[] = { |
|
998 { WWT_TEXTBTN, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, |
|
999 { WWT_CAPTION, 14, 11, 259, 0, 13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS}, |
|
1000 { WWT_MATRIX, 14, 0, 248, 14, 157, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR}, |
|
1001 { WWT_SCROLLBAR, 14, 249, 259, 14, 157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, |
|
1002 { WWT_LAST}, |
|
1003 }; |
|
1004 static const WindowDesc _other_player_ships_desc = { |
|
1005 -1, -1, 260, 158, |
|
1006 WC_SHIPS_LIST,0, |
|
1007 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, |
|
1008 _other_player_ships_widgets, |
1118 _other_player_ships_widgets, |
1009 PlayerShipsWndProc |
1119 PlayerShipsWndProc |
1010 }; |
1120 }; |
1011 |
1121 |
1012 |
1122 |