tron@2186: /* $Id$ */ tron@2186: belugas@6117: /** @file bridge_gui.cpp Graphical user interface for bridge construction */ celestar@2262: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" truelight@0: #include "gui.h" rubidium@8107: #include "window_gui.h" rubidium@8116: #include "command_func.h" rubidium@8116: #include "economy_func.h" tron@2159: #include "variables.h" celestar@2262: #include "bridge.h" rubidium@8114: #include "strings_func.h" rubidium@8131: #include "window_func.h" rubidium@8157: #include "sound_func.h" rubidium@8139: #include "map_func.h" rubidium@8224: #include "viewport_func.h" rubidium@8224: #include "gfx_func.h" truelight@0: rubidium@8264: #include "table/strings.h" rubidium@8264: truelight@0: static struct BridgeData { skidd13@8020: uint8 last_size; tron@2133: uint count; truelight@0: TileIndex start_tile; truelight@0: TileIndex end_tile; skidd13@7983: uint8 type; skidd13@7983: uint8 indexes[MAX_BRIDGES]; rubidium@6990: Money costs[MAX_BRIDGES]; skidd13@8020: skidd13@8020: BridgeData() skidd13@8020: : last_size(4) skidd13@8020: , count(0) skidd13@8020: {}; celestar@2262: } _bridgedata; truelight@0: tron@1977: void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2) truelight@0: { tron@541: if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile); truelight@0: } truelight@0: truelight@0: static void BuildBridge(Window *w, int i) truelight@0: { truelight@0: DeleteWindow(w); tron@2639: DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile, tron@2639: _bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge, rubidium@7521: CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE)); truelight@0: } truelight@0: skidd13@8020: /* Names of the build bridge selection window */ skidd13@8020: enum BuildBridgeSelectionWidgets { skidd13@8020: BBSW_CLOSEBOX = 0, skidd13@8020: BBSW_CAPTION, skidd13@8020: BBSW_BRIDGE_LIST, skidd13@8020: BBSW_SCROLLBAR, skidd13@8020: BBSW_RESIZEBOX skidd13@8020: }; skidd13@8020: truelight@0: static void BuildBridgeWndProc(Window *w, WindowEvent *e) truelight@0: { tron@2952: switch (e->event) { skidd13@8020: case WE_CREATE: skidd13@8020: w->resize.step_height = 22; skidd13@8020: w->vscroll.count = _bridgedata.count; skidd13@8020: skidd13@8020: if (_bridgedata.last_size <= 4) { skidd13@8020: w->vscroll.cap = 4; skidd13@8020: } else { skidd13@8020: /* Resize the bridge selection window if we used a bigger one the last time */ skidd13@8020: w->vscroll.cap = (w->vscroll.count > _bridgedata.last_size) ? _bridgedata.last_size : w->vscroll.count; skidd13@8020: ResizeWindow(w, 0, (w->vscroll.cap - 4) * w->resize.step_height); skidd13@8020: w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1; skidd13@8020: } skidd13@8020: break; skidd13@8020: skidd13@7983: case WE_PAINT: { peter1138@6204: DrawWindowWidgets(w); truelight@0: skidd13@7983: uint y = 15; skidd13@7983: for (uint i = 0; (i < w->vscroll.cap) && ((i + w->vscroll.pos) < _bridgedata.count); i++) { peter1138@6204: const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]]; truelight@0: rubidium@7002: SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]); peter1138@6204: SetDParam(1, b->speed * 10 / 16); peter1138@6204: SetDParam(0, b->material); truelight@0: skidd13@7983: DrawSprite(b->sprite, b->pal, 3, y); skidd13@7983: DrawString(44, y, STR_500D, TC_FROMSTRING); skidd13@7983: y += w->resize.step_height; peter1138@6204: } peter1138@6204: break; skidd13@7983: } peter1138@6204: peter1138@6204: case WE_KEYPRESS: { skidd13@7983: const uint8 i = e->we.keypress.keycode - '1'; peter1138@6204: if (i < 9 && i < _bridgedata.count) { peter1138@6204: e->we.keypress.cont = false; peter1138@6204: BuildBridge(w, i); peter1138@6204: } peter1138@6204: peter1138@6204: break; truelight@0: } truelight@193: peter1138@6204: case WE_CLICK: skidd13@8020: if (e->we.click.widget == BBSW_BRIDGE_LIST) { skidd13@7983: uint ind = ((int)e->we.click.pt.y - 14) / w->resize.step_height; skidd13@7983: if (ind < w->vscroll.cap) { skidd13@7983: ind += w->vscroll.pos; skidd13@7983: if (ind < _bridgedata.count) { skidd13@7983: BuildBridge(w, ind); skidd13@7983: } skidd13@7983: } peter1138@6204: } peter1138@6204: break; skidd13@7983: skidd13@7983: case WE_RESIZE: skidd13@7983: w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height; skidd13@8020: w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1; skidd13@7983: SetVScrollCount(w, _bridgedata.count); skidd13@8020: skidd13@8020: _bridgedata.last_size = w->vscroll.cap; skidd13@7983: break; truelight@0: } truelight@0: } truelight@0: skidd13@8020: /* Widget definition for the rail bridge selection window */ truelight@0: static const Widget _build_bridge_widgets[] = { skidd13@8020: { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BBSW_CLOSEBOX skidd13@8020: { WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BBSW_CAPTION skidd13@8020: { WWT_MATRIX, RESIZE_BOTTOM, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK}, // BBSW_BRIDGE_LIST skidd13@8020: { WWT_SCROLLBAR, RESIZE_BOTTOM, 7, 188, 199, 14, 89, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR skidd13@8020: { WWT_RESIZEBOX, RESIZE_TB, 7, 188, 199, 90, 101, 0x0, STR_RESIZE_BUTTON}, // BBSW_RESIZEBOX darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: skidd13@8020: /* Window definition for the rail bridge selection window */ truelight@0: static const WindowDesc _build_bridge_desc = { rubidium@7341: WDP_AUTO, WDP_AUTO, 200, 102, 200, 102, Darkvater@5070: WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR, skidd13@7983: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, truelight@0: _build_bridge_widgets, truelight@0: BuildBridgeWndProc truelight@0: }; truelight@0: skidd13@8020: /* Widget definition for the road bridge selection window */ truelight@0: static const Widget _build_road_bridge_widgets[] = { skidd13@8020: { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BBSW_CLOSEBOX skidd13@8020: { WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BBSW_CAPTION skidd13@8020: { WWT_MATRIX, RESIZE_BOTTOM, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK}, // BBSW_BRIDGE_LIST skidd13@8020: { WWT_SCROLLBAR, RESIZE_BOTTOM, 7, 188, 199, 14, 89, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR skidd13@8020: { WWT_RESIZEBOX, RESIZE_TB, 7, 188, 199, 90, 101, 0x0, STR_RESIZE_BUTTON}, // BBSW_RESIZEBOX darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: skidd13@8020: /* Window definition for the road bridge selection window */ truelight@0: static const WindowDesc _build_road_bridge_desc = { rubidium@7341: WDP_AUTO, WDP_AUTO, 200, 102, 200, 102, Darkvater@5070: WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR, skidd13@7983: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, truelight@0: _build_road_bridge_widgets, truelight@0: BuildBridgeWndProc truelight@0: }; truelight@0: truelight@0: tron@1977: void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type) truelight@0: { truelight@0: DeleteWindowById(WC_BUILD_BRIDGE, 0); truelight@0: celestar@2262: _bridgedata.type = bridge_type; celestar@2262: _bridgedata.start_tile = start; celestar@2262: _bridgedata.end_tile = end; truelight@0: skidd13@7983: /* only query bridge building possibility once, result is the same for all bridges! skidd13@7983: * returns CMD_ERROR on failure, and price on success */ skidd13@7983: StringID errmsg = INVALID_STRING_ID; skidd13@7983: CommandCost ret = DoCommand(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE); truelight@0: skidd13@7983: uint8 j = 0; peter1138@2737: if (CmdFailed(ret)) { truelight@0: errmsg = _error_message; tron@2548: } else { skidd13@7983: /* check which bridges can be built skidd13@7983: * get absolute bridge length skidd13@7983: * length of the middle parts of the bridge */ skidd13@7983: const uint bridge_len = GetBridgeLength(start, end); skidd13@7983: /* total length of bridge */ skidd13@7983: const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2); truelight@0: skidd13@7983: /* loop for all bridgetypes */ skidd13@7983: for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { truelight@0: if (CheckBridge_Stuff(bridge_type, bridge_len)) { skidd13@7983: /* bridge is accepted, add to list */ celestar@2262: const Bridge *b = &_bridge[bridge_type]; skidd13@7983: /* Add to terraforming & bulldozing costs the cost of the skidd13@7983: * bridge itself (not computed with DC_QUERY_COST) */ rubidium@6950: _bridgedata.costs[j] = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8); celestar@2262: _bridgedata.indexes[j] = bridge_type; truelight@0: j++; truelight@0: } truelight@0: } skidd13@7983: skidd13@7983: _bridgedata.count = j; truelight@0: } truelight@0: truelight@0: if (j != 0) { skidd13@8020: AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc); truelight@0: } else { celestar@3422: ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE); truelight@0: } truelight@0: }