bridge_gui.cpp

Go to the documentation of this file.
00001 /* $Id: bridge_gui.cpp 15726 2009-03-15 16:04:39Z smatz $ */
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 /* Names of the build bridge selection window */
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   /* Runtime saved values */
00065   static uint16 last_size;
00066   static Listing last_sorting;
00067 
00068   /* Constants for sorting the bridges */
00069   static const StringID sorter_names[];
00070   static GUIBridgeList::SortFunction * const sorter_funcs[];
00071 
00072   /* Internal variables */
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     /* Display the current sort variant */
00113     this->widget[BBSW_DROPDOWN_CRITERIA].data = this->sorter_names[this->bridges->SortType()];
00114 
00115     /* Set the modified widgets dirty */
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     /* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
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       /* Resize the bridge selection window if we used a bigger one the last time */
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       /* Build the requested bridge */
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 /* Set the default size of the Build Bridge Window */
00237 uint16 BuildBridgeWindow::last_size = 4;
00238 /* Set the default sorting for the bridges */
00239 Listing BuildBridgeWindow::last_sorting = {false, 0};
00240 
00241 /* Availible bridge sorting functions */
00242 GUIBridgeList::SortFunction * const BuildBridgeWindow::sorter_funcs[] = {
00243   &BridgeIndexSorter,
00244   &BridgePriceSorter,
00245   &BridgeSpeedSorter
00246 };
00247 
00248 /* Names of the sorting functions */
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 /* Widget definition for the rail bridge selection window */
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},            // BBSW_CLOSEBOX
00259 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_DARK_GREEN,  11, 199,   0,  13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},  // BBSW_CAPTION
00260 
00261 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   0,  80,  14,  25, STR_SORT_BY,                 STR_SORT_ORDER_TIP},               // BBSW_DROPDOWN_ORDER
00262 {   WWT_DROPDOWN,   RESIZE_NONE,  COLOUR_DARK_GREEN,  81, 199,  14,  25, 0x0,                         STR_SORT_CRITERIA_TIP},            // BBSW_DROPDOWN_CRITERIA
00263 
00264 {     WWT_MATRIX, RESIZE_BOTTOM,  COLOUR_DARK_GREEN,   0, 187,  26, 113, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},  // BBSW_BRIDGE_LIST
00265 {  WWT_SCROLLBAR, RESIZE_BOTTOM,  COLOUR_DARK_GREEN, 188, 199,  26, 101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
00266 {  WWT_RESIZEBOX,     RESIZE_TB,  COLOUR_DARK_GREEN, 188, 199, 102, 113, 0x0,                         STR_RESIZE_BUTTON},                // BBSW_RESIZEBOX
00267 {   WIDGETS_END},
00268 };
00269 
00270 /* Window definition for the rail bridge selection window */
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   /* Data type for the bridge.
00293    * Bit 16,15 = transport type,
00294    *     14..8 = road/rail types,
00295    *      7..0 = type of bridge */
00296   uint32 type = (transport_type << 15) | (road_rail_type << 8);
00297 
00298   /* The bridge length without ramps. */
00299   const uint bridge_len = GetTunnelBridgeLength(start, end);
00300 
00301   /* If Ctrl is being pressed, check wether the last bridge built is available
00302    * If so, return this bridge type. Otherwise continue normally.
00303    * We store bridge types for each transport type, so we have to check for
00304    * the transport type beforehand.
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; // water ways and air routes don't have bridge types
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   /* only query bridge building possibility once, result is the same for all bridges!
00318    * returns CMD_ERROR on failure, and price on success */
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     /* check which bridges can be built */
00327     const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2);
00328 
00329     bl = new GUIBridgeList();
00330 
00331     /* loop for all bridgetypes */
00332     for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
00333       if (CheckBridge_Stuff(brd_type, bridge_len)) {
00334         /* bridge is accepted, add to list */
00335         BuildBridgeData *item = bl->Append();
00336         item->index = brd_type;
00337         item->spec = GetBridgeSpec(brd_type);
00338         /* Add to terraforming & bulldozing costs the cost of the
00339          * bridge itself (not computed with DC_QUERY_COST) */
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 }

Generated on Tue Jul 21 18:48:22 2009 for OpenTTD by  doxygen 1.5.6