00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "window_gui.h"
00014 #include "gfx_func.h"
00015 #include "command_func.h"
00016 #include "vehicle_gui.h"
00017 #include "train.h"
00018 #include "strings_func.h"
00019 #include "vehicle_func.h"
00020 #include "engine_base.h"
00021 #include "window_func.h"
00022 #include "settings_type.h"
00023
00024 #include "table/sprites.h"
00025 #include "table/strings.h"
00026
00027 void CcBuildWagon(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00028 {
00029 if (result.Failed()) return;
00030
00031
00032 const Vehicle *found = NULL;
00033 const Train *t;
00034 FOR_ALL_TRAINS(t) {
00035 if (t->IsFrontEngine() && t->tile == tile &&
00036 t->track == TRACK_BIT_DEPOT) {
00037 if (found != NULL) return;
00038 found = t;
00039 }
00040 }
00041
00042
00043 if (found != NULL) {
00044 found = found->Last();
00045
00046 DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, CMD_MOVE_RAIL_VEHICLE);
00047 InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
00048 }
00049 }
00050
00060 void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, int skip)
00061 {
00062 bool rtl = _dynlang.text_dir == TD_RTL;
00063 Direction dir = rtl ? DIR_E : DIR_W;
00064
00065 DrawPixelInfo tmp_dpi, *old_dpi;
00066
00067 int highlight_l = 0;
00068 int highlight_r = 0;
00069 int max_width = right - left + 1;
00070
00071 if (!FillDrawPixelInfo(&tmp_dpi, left, y, max_width, 14)) return;
00072
00073 old_dpi = _cur_dpi;
00074 _cur_dpi = &tmp_dpi;
00075
00076 int px = rtl ? max_width + skip : -skip;
00077 bool sel_articulated = false;
00078 for (; v != NULL && (rtl ? px > 0 : px < max_width); v = v->Next()) {
00079 Point offset;
00080 int width = Train::From(v)->GetDisplayImageWidth(&offset);
00081
00082 if (rtl ? px + width > 0 : px - width < max_width) {
00083 SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
00084 DrawSprite(v->GetImage(dir), pal, px + (rtl ? -offset.x : offset.x), 7 + offset.y);
00085 }
00086
00087 if (!v->IsArticulatedPart()) sel_articulated = false;
00088
00089 if (v->index == selection) {
00090
00091 highlight_l = rtl ? px - width : px;
00092 highlight_r = rtl ? px - 1 : px + width - 1;
00093 sel_articulated = true;
00094 } else if ((_cursor.vehchain && highlight_r != 0) || sel_articulated) {
00095 if (rtl) {
00096 highlight_l -= width;
00097 } else {
00098 highlight_r += width;
00099 }
00100 }
00101
00102 px += rtl ? -width : width;
00103 }
00104
00105 if (highlight_l != highlight_r) {
00106
00107
00108 DrawFrameRect(highlight_l, 0, highlight_r, 13, COLOUR_WHITE, FR_BORDERONLY);
00109 }
00110
00111 _cur_dpi = old_dpi;
00112 }
00113
00115 struct CargoSummaryItem {
00116 CargoID cargo;
00117 StringID subtype;
00118 uint capacity;
00119 uint amount;
00120 StationID source;
00121
00123 FORCEINLINE bool operator != (const CargoSummaryItem &other) const
00124 {
00125 return this->cargo != other.cargo || this->subtype != other.subtype;
00126 }
00127 };
00128
00129 enum {
00130 TRAIN_DETAILS_MIN_INDENT = 32,
00131 TRAIN_DETAILS_MAX_INDENT = 72,
00132 };
00133
00135 typedef SmallVector<CargoSummaryItem, 2> CargoSummary;
00137 static CargoSummary _cargo_summary;
00138
00147 static void TrainDetailsCargoTab(const CargoSummaryItem *item, int left, int right, int y)
00148 {
00149 StringID str = STR_VEHICLE_DETAILS_CARGO_EMPTY;
00150
00151 if (item->amount > 0) {
00152 SetDParam(0, item->cargo);
00153 SetDParam(1, item->amount);
00154 SetDParam(2, item->source);
00155 SetDParam(3, _settings_game.vehicle.freight_trains);
00156 str = FreightWagonMult(item->cargo) > 1 ? STR_VEHICLE_DETAILS_CARGO_FROM_MULT : STR_VEHICLE_DETAILS_CARGO_FROM;
00157 }
00158
00159 DrawString(left, right, y, str);
00160 }
00161
00170 static void TrainDetailsInfoTab(const Vehicle *v, int left, int right, int y)
00171 {
00172 if (RailVehInfo(v->engine_type)->railveh_type == RAILVEH_WAGON) {
00173 SetDParam(0, v->engine_type);
00174 SetDParam(1, v->value);
00175 DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE, TC_FROMSTRING, SA_LEFT | SA_STRIP);
00176 } else {
00177 SetDParam(0, v->engine_type);
00178 SetDParam(1, v->build_year);
00179 SetDParam(2, v->value);
00180 DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE, TC_FROMSTRING, SA_LEFT | SA_STRIP);
00181 }
00182 }
00183
00192 static void TrainDetailsCapacityTab(const CargoSummaryItem *item, int left, int right, int y)
00193 {
00194 SetDParam(0, item->cargo);
00195 SetDParam(1, item->capacity);
00196 SetDParam(4, item->subtype);
00197 SetDParam(5, _settings_game.vehicle.freight_trains);
00198 DrawString(left, right, y, FreightWagonMult(item->cargo) > 1 ? STR_VEHICLE_INFO_CAPACITY_MULT : STR_VEHICLE_INFO_CAPACITY);
00199 }
00200
00206 static void GetCargoSummaryOfArticulatedVehicle(const Train *v, CargoSummary *summary)
00207 {
00208 summary->Clear();
00209 do {
00210 if (v->cargo_cap == 0) continue;
00211
00212 CargoSummaryItem new_item;
00213 new_item.cargo = v->cargo_type;
00214 new_item.subtype = GetCargoSubtypeText(v);
00215
00216 CargoSummaryItem *item = summary->Find(new_item);
00217 if (item == summary->End()) {
00218 item = summary->Append();
00219 item->cargo = new_item.cargo;
00220 item->subtype = new_item.subtype;
00221 item->capacity = 0;
00222 item->amount = 0;
00223 item->source = INVALID_STATION;
00224 }
00225
00226 item->capacity += v->cargo_cap;
00227 item->amount += v->cargo.Count();
00228 if (item->source == INVALID_STATION) item->source = v->cargo.Source();
00229 } while ((v = v->Next()) != NULL && v->IsArticulatedPart());
00230 }
00231
00237 static uint GetLengthOfArticulatedVehicle(const Train *v)
00238 {
00239 uint length = 0;
00240
00241 do {
00242 length += v->GetDisplayImageWidth();
00243 } while ((v = v->Next()) != NULL && v->IsArticulatedPart());
00244
00245 return length;
00246 }
00247
00254 int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab)
00255 {
00256 int num = 0;
00257
00258 if (det_tab == TDW_TAB_TOTALS) {
00259 CargoArray act_cargo;
00260 CargoArray max_cargo;
00261 for (const Vehicle *v = Vehicle::Get(veh_id); v != NULL; v = v->Next()) {
00262 act_cargo[v->cargo_type] += v->cargo.Count();
00263 max_cargo[v->cargo_type] += v->cargo_cap;
00264 }
00265
00266
00267
00268
00269 for (CargoID i = 0; i < NUM_CARGO; i++) {
00270 if (max_cargo[i] > 0) num++;
00271 }
00272 num++;
00273 } else {
00274 for (const Train *v = Train::Get(veh_id); v != NULL; v = v->GetNextVehicle()) {
00275 GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary);
00276 num += max(1u, _cargo_summary.Length());
00277
00278 uint length = GetLengthOfArticulatedVehicle(v);
00279 if (length > TRAIN_DETAILS_MAX_INDENT) num++;
00280 }
00281 }
00282
00283 return num;
00284 }
00285
00297 void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab)
00298 {
00299
00300 if (det_tab != TDW_TAB_TOTALS) {
00301 bool rtl = _dynlang.text_dir == TD_RTL;
00302 Direction dir = rtl ? DIR_E : DIR_W;
00303 int x = rtl ? right : left;
00304 int sprite_y_offset = 4 + (FONT_HEIGHT_NORMAL - 10) / 2;
00305 int line_height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00306 for (; v != NULL && vscroll_pos > -vscroll_cap; v = v->GetNextVehicle()) {
00307 GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary);
00308
00309
00310 int dx = 0;
00311 int px = x;
00312 const Train *u = v;
00313 do {
00314 Point offset;
00315 int width = u->GetDisplayImageWidth(&offset);
00316 if (vscroll_pos <= 0 && vscroll_pos > -vscroll_cap) {
00317 SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
00318 DrawSprite(u->GetImage(dir), pal, px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + offset.y);
00319 }
00320 px += rtl ? -width : width;
00321 dx += width;
00322 u = u->Next();
00323 } while (u != NULL && u->IsArticulatedPart());
00324
00325 bool separate_sprite_row = (dx > TRAIN_DETAILS_MAX_INDENT);
00326 if (separate_sprite_row) {
00327 vscroll_pos--;
00328 dx = 0;
00329 }
00330
00331 uint num_lines = max(1u, _cargo_summary.Length());
00332 for (uint i = 0; i < num_lines; i++) {
00333 int sprite_width = max<int>(dx, TRAIN_DETAILS_MIN_INDENT) + 3;
00334 int data_left = left + (rtl ? 0 : sprite_width);
00335 int data_right = right - (rtl ? sprite_width : 0);
00336 if (vscroll_pos <= 0 && vscroll_pos > -vscroll_cap) {
00337 int py = y - line_height * vscroll_pos;
00338 if (i > 0 || separate_sprite_row) {
00339 if (vscroll_pos != 0) GfxFillRect(left, py - WD_MATRIX_TOP - 1, right, py - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][5]);
00340 }
00341 switch (det_tab) {
00342 case TDW_TAB_CARGO:
00343 if (i < _cargo_summary.Length()) {
00344 TrainDetailsCargoTab(&_cargo_summary[i], data_left, data_right, py);
00345 } else {
00346 DrawString(data_left, data_right, py, STR_QUANTITY_N_A, TC_LIGHT_BLUE);
00347 }
00348 break;
00349
00350 case TDW_TAB_INFO:
00351 if (i == 0) TrainDetailsInfoTab(v, data_left, data_right, py);
00352 break;
00353
00354 case TDW_TAB_CAPACITY:
00355 if (i < _cargo_summary.Length()) {
00356 TrainDetailsCapacityTab(&_cargo_summary[i], data_left, data_right, py);
00357 } else {
00358 DrawString(data_left, data_right, py, STR_VEHICLE_INFO_NO_CAPACITY);
00359 }
00360 break;
00361
00362 default: NOT_REACHED();
00363 }
00364 }
00365 vscroll_pos--;
00366 }
00367 }
00368 } else {
00369 CargoArray act_cargo;
00370 CargoArray max_cargo;
00371 Money feeder_share = 0;
00372
00373 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00374 act_cargo[u->cargo_type] += u->cargo.Count();
00375 max_cargo[u->cargo_type] += u->cargo_cap;
00376 feeder_share += u->cargo.FeederShare();
00377 }
00378
00379
00380 DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT);
00381 y += WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00382
00383 for (CargoID i = 0; i < NUM_CARGO; i++) {
00384 if (max_cargo[i] > 0 && --vscroll_pos < 0 && vscroll_pos > -vscroll_cap) {
00385 SetDParam(0, i);
00386 SetDParam(1, act_cargo[i]);
00387 SetDParam(2, i);
00388 SetDParam(3, max_cargo[i]);
00389 SetDParam(4, _settings_game.vehicle.freight_trains);
00390 DrawString(left, right, y, FreightWagonMult(i) > 1 ? STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT : STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY);
00391 y += WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00392 }
00393 }
00394 SetDParam(0, feeder_share);
00395 DrawString(left, right, y, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE);
00396 }
00397 }