00001
00002
00005 #include "stdafx.h"
00006 #include "gui.h"
00007 #include "window_gui.h"
00008 #include "command_func.h"
00009 #include "economy_func.h"
00010 #include "bridge.h"
00011 #include "strings_func.h"
00012 #include "window_func.h"
00013 #include "sound_func.h"
00014 #include "map_func.h"
00015 #include "gfx_func.h"
00016 #include "tunnelbridge.h"
00017 #include "sortlist_type.h"
00018 #include "widgets/dropdown_func.h"
00019
00020 #include "table/strings.h"
00021
00023 static BridgeType _last_railbridge_type = 0;
00025 static BridgeType _last_roadbridge_type = 0;
00026
00030 struct BuildBridgeData {
00031 BridgeType index;
00032 const BridgeSpec *spec;
00033 Money cost;
00034 };
00035
00036 typedef GUIList<BuildBridgeData> GUIBridgeList;
00037
00046 void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
00047 {
00048 if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
00049 }
00050
00051
00052 enum BuildBridgeSelectionWidgets {
00053 BBSW_CLOSEBOX = 0,
00054 BBSW_CAPTION,
00055 BBSW_DROPDOWN_ORDER,
00056 BBSW_DROPDOWN_CRITERIA,
00057 BBSW_BRIDGE_LIST,
00058 BBSW_SCROLLBAR,
00059 BBSW_RESIZEBOX
00060 };
00061
00062 class BuildBridgeWindow : public Window {
00063 private:
00064
00065 static uint16 last_size;
00066 static Listing last_sorting;
00067
00068
00069 static const StringID sorter_names[];
00070 static GUIBridgeList::SortFunction * const sorter_funcs[];
00071
00072
00073 TileIndex start_tile;
00074 TileIndex end_tile;
00075 uint32 type;
00076 GUIBridgeList *bridges;
00077
00079 static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00080 {
00081 return a->index - b->index;
00082 }
00083
00085 static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00086 {
00087 return a->cost - b->cost;
00088 }
00089
00091 static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00092 {
00093 return a->spec->speed - b->spec->speed;
00094 }
00095
00096 void BuildBridge(uint8 i)
00097 {
00098 switch ((TransportType)(this->type >> 15)) {
00099 case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->Get(i)->index; break;
00100 case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->Get(i)->index; break;
00101 default: break;
00102 }
00103 DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index,
00104 CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge);
00105 }
00106
00108 void SortBridgeList()
00109 {
00110 this->bridges->Sort();
00111
00112
00113 this->widget[BBSW_DROPDOWN_CRITERIA].data = this->sorter_names[this->bridges->SortType()];
00114
00115
00116 this->InvalidateWidget(BBSW_DROPDOWN_CRITERIA);
00117 this->InvalidateWidget(BBSW_BRIDGE_LIST);
00118 }
00119
00120 public:
00121 BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc),
00122 start_tile(start),
00123 end_tile(end),
00124 type(br_type),
00125 bridges(bl)
00126 {
00127 this->parent = FindWindowById(WC_BUILD_TOOLBAR, GB(this->type, 15, 2));
00128 this->bridges->SetListing(this->last_sorting);
00129 this->bridges->SetSortFuncs(this->sorter_funcs);
00130 this->bridges->NeedResort();
00131 this->SortBridgeList();
00132
00133
00134 this->widget[BBSW_CAPTION].data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
00135
00136 this->resize.step_height = 22;
00137 this->vscroll.count = bl->Length();
00138
00139 if (this->last_size <= 4) {
00140 this->vscroll.cap = 4;
00141 } else {
00142
00143 this->vscroll.cap = min(this->last_size, this->vscroll.count);
00144 ResizeWindow(this, 0, (this->vscroll.cap - 4) * this->resize.step_height);
00145 }
00146
00147 this->FindWindowPlacementAndResize(desc);
00148 }
00149
00150 ~BuildBridgeWindow()
00151 {
00152 this->last_sorting = this->bridges->GetListing();
00153
00154 delete bridges;
00155 }
00156
00157 virtual void OnPaint()
00158 {
00159 this->DrawWidgets();
00160
00161 this->DrawSortButtonState(BBSW_DROPDOWN_ORDER, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00162
00163 uint y = this->widget[BBSW_BRIDGE_LIST].top + 2;
00164
00165 for (int i = this->vscroll.pos; (i < (this->vscroll.cap + this->vscroll.pos)) && (i < (int)this->bridges->Length()); i++) {
00166 const BridgeSpec *b = this->bridges->Get(i)->spec;
00167
00168 SetDParam(2, this->bridges->Get(i)->cost);
00169 SetDParam(1, b->speed);
00170 SetDParam(0, b->material);
00171
00172 DrawSprite(b->sprite, b->pal, 3, y);
00173 DrawString(44, y, STR_500D, TC_FROMSTRING);
00174 y += this->resize.step_height;
00175
00176 }
00177 }
00178
00179 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00180 {
00181 const uint8 i = keycode - '1';
00182 if (i < 9 && i < this->bridges->Length()) {
00183
00184 this->BuildBridge(i);
00185 delete this;
00186 return ES_HANDLED;
00187 }
00188 return ES_NOT_HANDLED;
00189 }
00190
00191 virtual void OnClick(Point pt, int widget)
00192 {
00193 switch (widget) {
00194 default: break;
00195 case BBSW_BRIDGE_LIST: {
00196 uint i = ((int)pt.y - this->widget[BBSW_BRIDGE_LIST].top) / this->resize.step_height;
00197 if (i < this->vscroll.cap) {
00198 i += this->vscroll.pos;
00199 if (i < this->bridges->Length()) {
00200 this->BuildBridge(i);
00201 delete this;
00202 }
00203 }
00204 } break;
00205
00206 case BBSW_DROPDOWN_ORDER:
00207 this->bridges->ToggleSortOrder();
00208 this->SetDirty();
00209 break;
00210
00211 case BBSW_DROPDOWN_CRITERIA:
00212 ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), BBSW_DROPDOWN_CRITERIA, 0, 0);
00213 break;
00214 }
00215 }
00216
00217 virtual void OnDropdownSelect(int widget, int index)
00218 {
00219 if (widget == BBSW_DROPDOWN_CRITERIA && this->bridges->SortType() != index) {
00220 this->bridges->SetSortType(index);
00221
00222 this->SortBridgeList();
00223 }
00224 }
00225
00226 virtual void OnResize(Point new_size, Point delta)
00227 {
00228 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00229 this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
00230 SetVScrollCount(this, this->bridges->Length());
00231
00232 this->last_size = max(this->vscroll.cap, this->last_size);
00233 }
00234 };
00235
00236
00237 uint16 BuildBridgeWindow::last_size = 4;
00238
00239 Listing BuildBridgeWindow::last_sorting = {false, 0};
00240
00241
00242 GUIBridgeList::SortFunction * const BuildBridgeWindow::sorter_funcs[] = {
00243 &BridgeIndexSorter,
00244 &BridgePriceSorter,
00245 &BridgeSpeedSorter
00246 };
00247
00248
00249 const StringID BuildBridgeWindow::sorter_names[] = {
00250 STR_SORT_BY_NUMBER,
00251 STR_ENGINE_SORT_COST,
00252 STR_SORT_BY_MAX_SPEED,
00253 INVALID_STRING_ID
00254 };
00255
00256
00257 static const Widget _build_bridge_widgets[] = {
00258 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00259 { WWT_CAPTION, RESIZE_NONE, COLOUR_DARK_GREEN, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
00260
00261 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
00262 { WWT_DROPDOWN, RESIZE_NONE, COLOUR_DARK_GREEN, 81, 199, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
00263
00264 { WWT_MATRIX, RESIZE_BOTTOM, COLOUR_DARK_GREEN, 0, 187, 26, 113, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
00265 { WWT_SCROLLBAR, RESIZE_BOTTOM, COLOUR_DARK_GREEN, 188, 199, 26, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00266 { WWT_RESIZEBOX, RESIZE_TB, COLOUR_DARK_GREEN, 188, 199, 102, 113, 0x0, STR_RESIZE_BUTTON},
00267 { WIDGETS_END},
00268 };
00269
00270
00271 static const WindowDesc _build_bridge_desc(
00272 WDP_AUTO, WDP_AUTO, 200, 114, 200, 114,
00273 WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
00274 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE | WDF_CONSTRUCTION,
00275 _build_bridge_widgets
00276 );
00277
00288 void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type)
00289 {
00290 DeleteWindowById(WC_BUILD_BRIDGE, 0);
00291
00292
00293
00294
00295
00296 uint32 type = (transport_type << 15) | (road_rail_type << 8);
00297
00298
00299 const uint bridge_len = GetTunnelBridgeLength(start, end);
00300
00301
00302
00303
00304
00305
00306 BridgeType last_bridge_type = 0;
00307 switch (transport_type) {
00308 case TRANSPORT_ROAD: last_bridge_type = _last_roadbridge_type; break;
00309 case TRANSPORT_RAIL: last_bridge_type = _last_railbridge_type; break;
00310 default: break;
00311 }
00312 if (_ctrl_pressed && CheckBridge_Stuff(last_bridge_type, bridge_len)) {
00313 DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge);
00314 return;
00315 }
00316
00317
00318
00319 StringID errmsg = INVALID_STRING_ID;
00320 CommandCost ret = DoCommand(end, start, type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
00321
00322 GUIBridgeList *bl = NULL;
00323 if (CmdFailed(ret)) {
00324 errmsg = _error_message;
00325 } else {
00326
00327 const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2);
00328
00329 bl = new GUIBridgeList();
00330
00331
00332 for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
00333 if (CheckBridge_Stuff(brd_type, bridge_len)) {
00334
00335 BuildBridgeData *item = bl->Append();
00336 item->index = brd_type;
00337 item->spec = GetBridgeSpec(brd_type);
00338
00339
00340 item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * item->spec->price) >> 8);
00341 }
00342 }
00343 }
00344
00345 if (bl != NULL && bl->Length() != 0) {
00346 new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
00347 } else {
00348 if (bl != NULL) delete bl;
00349 ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
00350 }
00351 }