00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "variables.h"
00008 #include "command_func.h"
00009 #include "engine.h"
00010 #include "gui.h"
00011 #include "window_gui.h"
00012 #include "textbuf_gui.h"
00013 #include "cargotype.h"
00014 #include "depot.h"
00015 #include "strings_func.h"
00016 #include "vehicle_base.h"
00017 #include "string_func.h"
00018 #include "gfx_func.h"
00019 #include "player_func.h"
00020 #include "settings_type.h"
00021
00022 #include "table/strings.h"
00023
00024 static int GetOrderFromTimetableWndPt(Window *w, int y, const Vehicle *v)
00025 {
00026
00027
00028
00029
00030
00031 int sel = (y - 15) / 10;
00032
00033 if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
00034
00035 sel += w->vscroll.pos;
00036
00037 return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
00038 }
00039
00040 static inline void SetTimetableParams(int param1, int param2, uint32 time)
00041 {
00042 if (_patches.timetable_in_ticks) {
00043 SetDParam(param1, STR_TIMETABLE_TICKS);
00044 SetDParam(param2, time);
00045 } else {
00046 SetDParam(param1, STR_TIMETABLE_DAYS);
00047 SetDParam(param2, time / DAY_TICKS);
00048 }
00049 }
00050
00051 static void DrawTimetableWindow(Window *w)
00052 {
00053 const Vehicle *v = GetVehicle(w->window_number);
00054 if (WP(w, order_d).sel >= v->num_orders * 2) WP(w, order_d).sel = -1;
00055 int selected = WP(w, order_d).sel;
00056
00057 SetVScrollCount(w, v->num_orders * 2);
00058
00059 if (v->owner == _local_player) {
00060 if (selected == -1) {
00061 w->DisableWidget(6);
00062 w->DisableWidget(7);
00063 } else if (selected % 2 == 1) {
00064 w->EnableWidget(6);
00065 w->EnableWidget(7);
00066 } else {
00067 const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
00068 bool disable = order == NULL || order->type != OT_GOTO_STATION || (_patches.new_nonstop && (order->flags & OFB_NON_STOP));
00069
00070 w->SetWidgetDisabledState(6, disable);
00071 w->SetWidgetDisabledState(7, disable);
00072 }
00073
00074 w->EnableWidget(8);
00075 w->EnableWidget(9);
00076 } else {
00077 w->DisableWidget(6);
00078 w->DisableWidget(7);
00079 w->DisableWidget(8);
00080 w->DisableWidget(9);
00081 }
00082
00083 w->SetWidgetLoweredState(9, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
00084
00085 SetDParam(0, v->index);
00086 DrawWindowWidgets(w);
00087
00088 int y = 15;
00089 int i = w->vscroll.pos;
00090 VehicleOrderID order_id = (i + 1) / 2;
00091 bool final_order = false;
00092
00093 const Order *order = GetVehicleOrder(v, order_id);
00094
00095 while (order != NULL) {
00096
00097 if (i - w->vscroll.pos >= w->vscroll.cap) break;
00098
00099 if (i % 2 == 0) {
00100 SetDParam(2, STR_EMPTY);
00101
00102 switch (order->type) {
00103 case OT_DUMMY:
00104 SetDParam(0, STR_INVALID_ORDER);
00105 break;
00106
00107 case OT_GOTO_STATION:
00108 SetDParam(0, (order->flags & OFB_NON_STOP) ? STR_880A_GO_NON_STOP_TO : STR_8806_GO_TO);
00109 SetDParam(1, order->dest);
00110
00111 if (order->wait_time > 0) {
00112 SetDParam(2, STR_TIMETABLE_STAY_FOR);
00113 SetTimetableParams(3, 4, order->wait_time);
00114 }
00115
00116 break;
00117
00118 case OT_GOTO_DEPOT: {
00119 StringID string = STR_EMPTY;
00120
00121 if (v->type == VEH_AIRCRAFT) {
00122 string = STR_GO_TO_AIRPORT_HANGAR;
00123 SetDParam(1, order->dest);
00124 } else {
00125 SetDParam(1, GetDepot(order->dest)->town_index);
00126
00127 switch (v->type) {
00128 case VEH_TRAIN: string = (order->flags & OFB_NON_STOP) ? STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT : STR_GO_TO_TRAIN_DEPOT; break;
00129 case VEH_ROAD: string = STR_GO_TO_ROADVEH_DEPOT; break;
00130 case VEH_SHIP: string = STR_GO_TO_SHIP_DEPOT; break;
00131 default: break;
00132 }
00133 }
00134
00135 if (order->flags & OFB_FULL_LOAD) string++;
00136
00137 SetDParam(0, string);
00138 } break;
00139
00140 case OT_GOTO_WAYPOINT:
00141 SetDParam(0, (order->flags & OFB_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
00142 SetDParam(1, order->dest);
00143 break;
00144
00145 default: break;
00146 }
00147
00148 DrawString(2, y, STR_TIMETABLE_GO_TO, (i == selected) ? TC_WHITE : TC_BLACK);
00149
00150 order_id++;
00151
00152 if (order_id >= v->num_orders) {
00153 order = GetVehicleOrder(v, 0);
00154 final_order = true;
00155 } else {
00156 order = order->next;
00157 }
00158 } else {
00159 StringID string;
00160
00161 if (order->travel_time == 0) {
00162 string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
00163 } else {
00164 SetTimetableParams(0, 1, order->travel_time);
00165 string = STR_TIMETABLE_TRAVEL_FOR;
00166 }
00167
00168 DrawString(12, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
00169
00170 if (final_order) break;
00171 }
00172
00173 i++;
00174 y += 10;
00175 }
00176
00177 y = w->widget[5].top + 1;
00178
00179 {
00180 uint total_time = 0;
00181 bool complete = true;
00182
00183 for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
00184 total_time += order->travel_time + order->wait_time;
00185 if (order->travel_time == 0) complete = false;
00186 if (order->wait_time == 0 && order->type == OT_GOTO_STATION && !(_patches.new_nonstop && (order->flags & OFB_NON_STOP))) complete = false;
00187 }
00188
00189 if (total_time != 0) {
00190 SetTimetableParams(0, 1, total_time);
00191 DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, TC_BLACK);
00192 }
00193 }
00194 y += 10;
00195
00196 if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
00197 DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, TC_BLACK);
00198 } else {
00199 SetTimetableParams(0, 1, abs(v->lateness_counter));
00200 DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, TC_BLACK);
00201 }
00202 }
00203
00204 static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
00205 {
00206 uint order_number = (selected + 1) / 2;
00207 uint is_journey = (selected % 2 == 1) ? 1 : 0;
00208
00209 if (order_number >= v->num_orders) order_number = 0;
00210
00211 return v->index | (order_number << 16) | (is_journey << 24);
00212 }
00213
00214 static void TimetableWndProc(Window *w, WindowEvent *we)
00215 {
00216 switch (we->event) {
00217 case WE_PAINT:
00218 DrawTimetableWindow(w);
00219 break;
00220
00221 case WE_CLICK: {
00222 const Vehicle *v = GetVehicle(w->window_number);
00223
00224 switch (we->we.click.widget) {
00225 case 3: {
00226 int selected = GetOrderFromTimetableWndPt(w, we->we.click.pt.y, v);
00227
00228 if (selected == INVALID_ORDER || selected == WP(w, order_d).sel) {
00229
00230 WP(w, order_d).sel = -1;
00231 } else {
00232
00233 WP(w, order_d).sel = selected;
00234 }
00235 } break;
00236
00237 case 6: {
00238 int selected = WP(w, order_d).sel;
00239 VehicleOrderID real = (selected + 1) / 2;
00240
00241 if (real >= v->num_orders) real = 0;
00242
00243 const Order *order = GetVehicleOrder(v, real);
00244 StringID current = STR_EMPTY;
00245
00246 if (order != NULL) {
00247 uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
00248 if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
00249
00250 if (time != 0) {
00251 SetDParam(0, time);
00252 current = STR_CONFIG_PATCHES_INT32;
00253 }
00254 }
00255
00256 ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, w, CS_NUMERAL);
00257 } break;
00258
00259 case 7: {
00260 uint32 p1 = PackTimetableArgs(v, WP(w, order_d).sel);
00261 DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
00262 } break;
00263
00264 case 8:
00265 DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
00266 break;
00267
00268 case 9:
00269 DoCommandP(0, v->index, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
00270 break;
00271 }
00272
00273 SetWindowDirty(w);
00274 } break;
00275
00276 case WE_ON_EDIT_TEXT: {
00277 const Vehicle *v = GetVehicle(w->window_number);
00278
00279 uint32 p1 = PackTimetableArgs(v, WP(w, order_d).sel);
00280
00281 uint64 time = StrEmpty(we->we.edittext.str) ? 0 : strtoul(we->we.edittext.str, NULL, 10);
00282 if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
00283
00284 uint32 p2 = minu(time, MAX_UVALUE(uint16));
00285
00286 DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
00287 } break;
00288
00289 case WE_RESIZE:
00290
00291 w->vscroll.cap = (w->widget[3].bottom - w->widget[3].top) / 10;
00292 break;
00293
00294 }
00295 }
00296
00297 static const Widget _timetable_widgets[] = {
00298 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00299 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 387, 0, 13, STR_TIMETABLE_TITLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
00300 { WWT_STICKYBOX, RESIZE_LR, 14, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON},
00301
00302 { WWT_PANEL, RESIZE_RB, 14, 0, 387, 14, 95, STR_NULL, STR_TIMETABLE_TOOLTIP},
00303 { WWT_SCROLLBAR, RESIZE_LRB, 14, 388, 399, 14, 95, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00304
00305 { WWT_PANEL, RESIZE_RTB, 14, 0, 399, 96, 117, STR_NULL, STR_NULL},
00306
00307 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 109, 118, 129, STR_TIMETABLE_CHANGE_TIME, STR_TIMETABLE_WAIT_TIME_TOOLTIP},
00308 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 110, 219, 118, 129, STR_CLEAR_TIME, STR_TIMETABLE_CLEAR_TIME_TOOLTIP},
00309 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 220, 337, 118, 129, STR_RESET_LATENESS, STR_TIMETABLE_RESET_LATENESS_TOOLTIP},
00310 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 338, 387, 118, 129, STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP},
00311
00312 { WWT_PANEL, RESIZE_RTB, 14, 388, 387, 118, 129, STR_NULL, STR_NULL},
00313 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 388, 399, 118, 129, STR_NULL, STR_RESIZE_BUTTON},
00314
00315 { WIDGETS_END }
00316 };
00317
00318 static const WindowDesc _timetable_desc = {
00319 WDP_AUTO, WDP_AUTO, 400, 130, 400, 130,
00320 WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW,
00321 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00322 _timetable_widgets,
00323 TimetableWndProc
00324 };
00325
00326 void ShowTimetableWindow(const Vehicle *v)
00327 {
00328 Window *w = AllocateWindowDescFront(&_timetable_desc, v->index);
00329
00330 if (w != NULL) {
00331 w->caption_color = v->owner;
00332 w->vscroll.cap = 8;
00333 w->resize.step_height = 10;
00334 WP(w, order_d).sel = -1;
00335 }
00336 }