bridge_gui.cpp

Go to the documentation of this file.
00001 /* $Id: bridge_gui.cpp 14326 2008-09-14 19:36:31Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gui.h"
00008 #include "window_gui.h"
00009 #include "command_func.h"
00010 #include "economy_func.h"
00011 #include "variables.h"
00012 #include "bridge.h"
00013 #include "strings_func.h"
00014 #include "window_func.h"
00015 #include "sound_func.h"
00016 #include "map_func.h"
00017 #include "viewport_func.h"
00018 #include "gfx_func.h"
00019 #include "tunnelbridge.h"
00020 #include "sortlist_type.h"
00021 #include "widgets/dropdown_func.h"
00022 
00023 #include "table/strings.h"
00024 
00028 struct BuildBridgeData {
00029   BridgeType index;
00030   const BridgeSpec *spec;
00031   Money cost;
00032 };
00033 
00034 typedef GUIList<BuildBridgeData> GUIBridgeList;
00035 
00044 void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
00045 {
00046   if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
00047 }
00048 
00049 /* Names of the build bridge selection window */
00050 enum BuildBridgeSelectionWidgets {
00051   BBSW_CLOSEBOX = 0,
00052   BBSW_CAPTION,
00053   BBSW_DROPDOWN_ORDER,
00054   BBSW_DROPDOWN_CRITERIA,
00055   BBSW_BRIDGE_LIST,
00056   BBSW_SCROLLBAR,
00057   BBSW_RESIZEBOX
00058 };
00059 
00060 class BuildBridgeWindow : public Window {
00061 private:
00062   /* Runtime saved values */
00063   static uint16 last_size;
00064   static Listing last_sorting;
00065 
00066   /* Constants for sorting the bridges */
00067   static const StringID sorter_names[];
00068   static GUIBridgeList::SortFunction *const sorter_funcs[];
00069 
00070   /* Internal variables */
00071   TileIndex start_tile;
00072   TileIndex end_tile;
00073   uint32 type;
00074   GUIBridgeList *bridges;
00075 
00077   static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00078   {
00079     return a->index - b->index;
00080   }
00081 
00083   static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00084   {
00085     return a->cost - b->cost;
00086   }
00087 
00089   static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b)
00090   {
00091     return a->spec->speed - b->spec->speed;
00092   }
00093 
00094   void BuildBridge(uint8 i)
00095   {
00096     DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index,
00097         CcBuildBridge, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
00098   }
00099 
00101   void SortBridgeList()
00102   {
00103     this->bridges->Sort();
00104 
00105     /* Display the current sort variant */
00106     this->widget[BBSW_DROPDOWN_CRITERIA].data = this->sorter_names[this->bridges->SortType()];
00107 
00108     /* Set the modified widgets dirty */
00109     this->InvalidateWidget(BBSW_DROPDOWN_CRITERIA);
00110     this->InvalidateWidget(BBSW_BRIDGE_LIST);
00111   }
00112 
00113 public:
00114   BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc),
00115     start_tile(start),
00116     end_tile(end),
00117     type(br_type),
00118     bridges(bl)
00119   {
00120     this->bridges->SetListing(this->last_sorting);
00121     this->bridges->SetSortFuncs(this->sorter_funcs);
00122     this->bridges->NeedResort();
00123     this->SortBridgeList();
00124 
00125     /* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
00126     this->widget[BBSW_CAPTION].data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
00127 
00128     this->resize.step_height = 22;
00129     this->vscroll.count = bl->Length();
00130 
00131     if (this->last_size <= 4) {
00132       this->vscroll.cap = 4;
00133     } else {
00134       /* Resize the bridge selection window if we used a bigger one the last time */
00135       this->vscroll.cap = min(this->last_size, this->vscroll.count);
00136       ResizeWindow(this, 0, (this->vscroll.cap - 4) * this->resize.step_height);
00137     }
00138 
00139     this->FindWindowPlacementAndResize(desc);
00140   }
00141 
00142   ~BuildBridgeWindow()
00143   {
00144     this->last_sorting = this->bridges->GetListing();
00145 
00146     delete bridges;
00147   }
00148 
00149   virtual void OnPaint()
00150   {
00151     this->DrawWidgets();
00152 
00153     this->DrawSortButtonState(BBSW_DROPDOWN_ORDER, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00154 
00155     uint y = this->widget[BBSW_BRIDGE_LIST].top + 2;
00156 
00157     for (int i = this->vscroll.pos; (i < (this->vscroll.cap + this->vscroll.pos)) && (i < (int)this->bridges->Length()); i++) {
00158       const BridgeSpec *b = this->bridges->Get(i)->spec;
00159 
00160       SetDParam(2, this->bridges->Get(i)->cost);
00161       SetDParam(1, b->speed * 10 / 16);
00162       SetDParam(0, b->material);
00163 
00164       DrawSprite(b->sprite, b->pal, 3, y);
00165       DrawString(44, y, STR_500D, TC_FROMSTRING);
00166       y += this->resize.step_height;
00167 
00168     }
00169   }
00170 
00171   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00172   {
00173     const uint8 i = keycode - '1';
00174     if (i < 9 && i < this->bridges->Length()) {
00175       /* Build the requested bridge */
00176       this->BuildBridge(i);
00177       delete this;
00178       return ES_HANDLED;
00179     }
00180     return ES_NOT_HANDLED;
00181   }
00182 
00183   virtual void OnClick(Point pt, int widget)
00184   {
00185     switch (widget) {
00186       default: break;
00187       case BBSW_BRIDGE_LIST: {
00188         uint i = ((int)pt.y - this->widget[BBSW_BRIDGE_LIST].top) / this->resize.step_height;
00189         if (i < this->vscroll.cap) {
00190           i += this->vscroll.pos;
00191           if (i < this->bridges->Length()) {
00192             this->BuildBridge(i);
00193             delete this;
00194           }
00195         }
00196       } break;
00197 
00198       case BBSW_DROPDOWN_ORDER:
00199         this->bridges->ToggleSortOrder();
00200         this->SetDirty();
00201         break;
00202 
00203       case BBSW_DROPDOWN_CRITERIA:
00204         ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), BBSW_DROPDOWN_CRITERIA, 0, 0);
00205         break;
00206     }
00207   }
00208 
00209   virtual void OnDropdownSelect(int widget, int index)
00210   {
00211     if (widget == BBSW_DROPDOWN_CRITERIA && this->bridges->SortType() != index) {
00212       this->bridges->SetSortType(index);
00213 
00214       this->SortBridgeList();
00215     }
00216   }
00217 
00218   virtual void OnResize(Point new_size, Point delta)
00219   {
00220     this->vscroll.cap += delta.y / (int)this->resize.step_height;
00221     this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
00222     SetVScrollCount(this, this->bridges->Length());
00223 
00224     this->last_size = max(this->vscroll.cap, this->last_size);
00225   }
00226 };
00227 
00228 /* Set the default size of the Build Bridge Window */
00229 uint16 BuildBridgeWindow::last_size = 4;
00230 /* Set the default sorting for the bridges */
00231 Listing BuildBridgeWindow::last_sorting = {false, 0};
00232 
00233 /* Availible bridge sorting functions */
00234 GUIBridgeList::SortFunction* const BuildBridgeWindow::sorter_funcs[] = {
00235   &BridgeIndexSorter,
00236   &BridgePriceSorter,
00237   &BridgeSpeedSorter
00238 };
00239 
00240 /* Names of the sorting functions */
00241 const StringID BuildBridgeWindow::sorter_names[] = {
00242   STR_SORT_BY_NUMBER,
00243   STR_ENGINE_SORT_COST,
00244   STR_SORT_BY_MAX_SPEED,
00245   INVALID_STRING_ID
00246 };
00247 
00248 /* Widget definition for the rail bridge selection window */
00249 static const Widget _build_bridge_widgets[] = {
00250 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW},            // BBSW_CLOSEBOX
00251 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_DARK_GREEN,  11, 199,   0,  13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},  // BBSW_CAPTION
00252 
00253 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   0,  80,  14,  25, STR_SORT_BY,                 STR_SORT_ORDER_TIP},               // BBSW_DROPDOWN_ORDER
00254 {   WWT_DROPDOWN,   RESIZE_NONE,  COLOUR_DARK_GREEN,  81, 199,  14,  25, 0x0,                         STR_SORT_CRITERIA_TIP},            // BBSW_DROPDOWN_CRITERIA
00255 
00256 {     WWT_MATRIX, RESIZE_BOTTOM,  COLOUR_DARK_GREEN,   0, 187,  26, 113, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},  // BBSW_BRIDGE_LIST
00257 {  WWT_SCROLLBAR, RESIZE_BOTTOM,  COLOUR_DARK_GREEN, 188, 199,  26, 101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
00258 {  WWT_RESIZEBOX,     RESIZE_TB,  COLOUR_DARK_GREEN, 188, 199, 102, 113, 0x0,                         STR_RESIZE_BUTTON},                // BBSW_RESIZEBOX
00259 {   WIDGETS_END},
00260 };
00261 
00262 /* Window definition for the rail bridge selection window */
00263 static const WindowDesc _build_bridge_desc = {
00264   WDP_AUTO, WDP_AUTO, 200, 114, 200, 114,
00265   WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
00266   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
00267   _build_bridge_widgets,
00268 };
00269 
00280 void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type)
00281 {
00282   DeleteWindowById(WC_BUILD_BRIDGE, 0);
00283 
00284   /* Data type for the bridge.
00285    * Bit 16,15 = transport type,
00286    *     14..8 = road/rail types,
00287    *      7..0 = type of bridge */
00288   uint32 type = (transport_type << 15) | (road_rail_type << 8);
00289 
00290   /* only query bridge building possibility once, result is the same for all bridges!
00291    * returns CMD_ERROR on failure, and price on success */
00292   StringID errmsg = INVALID_STRING_ID;
00293   CommandCost ret = DoCommand(end, start, type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
00294 
00295   GUIBridgeList *bl = NULL;
00296   if (CmdFailed(ret)) {
00297     errmsg = _error_message;
00298   } else {
00299     /* check which bridges can be built
00300      * get absolute bridge length
00301      * length of the middle parts of the bridge */
00302     const uint bridge_len = GetTunnelBridgeLength(start, end);
00303     /* total length of bridge */
00304     const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2);
00305 
00306     bl = new GUIBridgeList();
00307 
00308     /* loop for all bridgetypes */
00309     for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
00310       if (CheckBridge_Stuff(brd_type, bridge_len)) {
00311         /* bridge is accepted, add to list */
00312         BuildBridgeData *item = bl->Append();
00313         item->index = brd_type;
00314         item->spec = GetBridgeSpec(brd_type);
00315         /* Add to terraforming & bulldozing costs the cost of the
00316          * bridge itself (not computed with DC_QUERY_COST) */
00317         item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * item->spec->price) >> 8);
00318       }
00319     }
00320   }
00321 
00322   if (bl != NULL && bl->Length() != 0) {
00323     new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
00324   } else {
00325     if (bl != NULL) delete bl;
00326     ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
00327   }
00328 }

Generated on Fri Nov 21 19:01:31 2008 for openttd by  doxygen 1.5.6