void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed() || !_settings_game.economy.give_money) return; /* Inform the company of the action of one of its clients (controllers). */ char msg[64]; SetDParam(0, p2); GetString(msg, STR_COMPANY_NAME, lastof(msg)); if (!_network_server) { NetworkClientSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, p1); } else { NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER, p1); } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d; switch (widget) { /* Left and right should have same sizing. */ case WID_S_LEFT: case WID_S_RIGHT: { SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); d = GetStringBoundingBox(STR_WHITE_DATE_LONG); int64 max_money = UINT32_MAX; const Company *c; FOR_ALL_COMPANIES(c) max_money = max<int64>(c->money, max_money); SetDParam(0, 100LL * max_money); d = maxdim(d, GetStringBoundingBox(STR_COMPANY_MONEY)); break; } case WID_S_MIDDLE: d = GetStringBoundingBox(STR_STATUSBAR_AUTOSAVE); d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_PAUSED)); if (Company::IsValidID(_local_company)) { SetDParam(0, _local_company); d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_COMPANY_NAME)); } break; default: return; } d.width += padding.width; d.height += padding.height; *size = maxdim(d, *size); }
/* Draw rail wagon specific details */ static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) { const Engine *e = Engine::Get(engine_number); /* Purchase cost */ SetDParam(0, e->GetCost()); DrawString(left, right, y, STR_PURCHASE_INFO_COST); y += FONT_HEIGHT_NORMAL; /* Wagon weight - (including cargo) */ uint weight = e->GetDisplayWeight(); SetDParam(0, weight); uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); SetDParam(1, cargo_weight + weight); DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); y += FONT_HEIGHT_NORMAL; /* Wagon speed limit, displayed if above zero */ if (_settings_game.vehicle.wagon_speed_limits) { uint max_speed = e->GetDisplayMaxSpeed(); if (max_speed > 0) { SetDParam(0, max_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED); y += FONT_HEIGHT_NORMAL; } } /* Running cost */ if (rvi->running_cost_class != INVALID_PRICE) { SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; } return y; }
virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case MTSW_LIST_LEFT: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, song_name); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); y += FONT_HEIGHT_SMALL; } break; } case MTSW_LIST_RIGHT: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; for (const byte *p = _playlists[_settings_client.music.playlist]; *p != 0; p++) { uint i = *p - 1; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); y += FONT_HEIGHT_SMALL; } break; } } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_MH_BACKGROUND) { this->line_height = FONT_HEIGHT_NORMAL + 2; resize->height = this->line_height; /* Months are off-by-one, so it's actually 8. Not using * month 12 because the 1 is usually less wide. */ SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30)); this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width; size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible. size->width = max(200u, size->width); // At least 200 pixels wide. } }
virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AP_CLASS_DROPDOWN: SetDParam(0, AirportClass::Get(_selected_airport_class)->name); break; case WID_AP_LAYOUT_NUM: SetDParam(0, STR_EMPTY); if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); if (string != STR_UNDEFINED) { SetDParam(0, string); } else if (as->num_table > 1) { SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); SetDParam(1, _selected_airport_layout + 1); } } break; default: break; } }
static void ShipArrivesAt(const Vehicle *v, Station *st) { /* Check if station was ever visited before */ if (!(st->had_vehicle_of_type & HVOT_SHIP)) { st->had_vehicle_of_type |= HVOT_SHIP; SetDParam(0, st->index); AddVehicleNewsItem( STR_NEWS_FIRST_SHIP_ARRIVAL, (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index)); } }
virtual void OnClick(Point pt, int widget, int click_count) { const NWidgetBase *wid = this->GetWidget<NWidgetBase>(CW_PANEL); uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL); uint x = pt.x - wid->pos_x; bool rtl = _current_text_dir == TD_RTL; if (rtl) x = wid->current_x - x; if (btn >= lengthof(_cheats_ui)) return; const CheatEntry *ce = &_cheats_ui[btn]; int value = (int32)ReadValue(ce->variable, ce->type); int oldvalue = value; if (btn == CHT_CHANGE_DATE && x >= 40) { /* Click at the date text directly. */ SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); return; } /* Not clicking a button? */ if (!IsInsideMM(x, 20, 40)) return; *ce->been_used = true; switch (ce->type) { case SLE_BOOL: value ^= 1; if (ce->proc != NULL) ce->proc(value, 0); break; default: /* Take whatever the function returns */ value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1); /* The first cheat (money), doesn't return a different value. */ if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + ((x >= 30) != rtl ? 1 : 0); break; } if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value); this->flags4 |= WF_TIMEOUT_BEGIN; this->SetDirty(); }
virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case AIL_WIDGET_LIST: { /* Draw a list of all available AIs. */ int y = this->GetWidget<NWidgetBase>(AIL_WIDGET_LIST)->pos_y; /* First AI in the list is hardcoded to random */ if (this->vscroll->IsVisible(0)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_BLACK); y += this->line_height; } AIInfoList::const_iterator it = this->ai_info_list->begin(); for (int i = 1; it != this->ai_info_list->end(); i++, it++) { if (this->vscroll->IsVisible(i)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_BLACK); y += this->line_height; } } break; } case AIL_WIDGET_INFO_BG: { AIInfo *selected_info = NULL; AIInfoList::const_iterator it = this->ai_info_list->begin(); for (int i = 1; selected_info == NULL && it != this->ai_info_list->end(); i++, it++) { if (this->selected == i - 1) selected_info = (*it).second; } /* Some info about the currently selected AI. */ if (selected_info != NULL) { int y = r.top + WD_FRAMERECT_TOP; SetDParamStr(0, selected_info->GetAuthor()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_AUTHOR); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; SetDParam(0, selected_info->GetVersion()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_VERSION); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (selected_info->GetURL() != NULL) { SetDParamStr(0, selected_info->GetURL()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_URL); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } SetDParamStr(0, selected_info->GetDescription()); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, STR_JUST_RAW_STRING, TC_BLACK); } break; } } }
/* Draw ship specific details */ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) { const Engine *e = Engine::Get(engine_number); /* Purchase cost - Max speed */ uint raw_speed = e->GetDisplayMaxSpeed(); uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true); uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false); SetDParam(0, e->GetCost()); if (ocean_speed == canal_speed) { SetDParam(1, ocean_speed); DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); y += FONT_HEIGHT_NORMAL; } else { DrawString(left, right, y, STR_PURCHASE_INFO_COST); y += FONT_HEIGHT_NORMAL; SetDParam(0, ocean_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN); y += FONT_HEIGHT_NORMAL; SetDParam(0, canal_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL); y += FONT_HEIGHT_NORMAL; } /* Cargo type + capacity */ SetDParam(0, e->GetDefaultCargoType()); SetDParam(1, e->GetDisplayDefaultCapacity()); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; /* Running cost */ SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; return y; }
static StringID GetAircraftEngineInfoString(const Engine *e) { CargoID cargo = e->GetDefaultCargoType(); uint16 mail_capacity; uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); uint16 range = e->GetRange(); uint i = 0; SetDParam(i++, e->GetCost()); SetDParam(i++, e->GetDisplayMaxSpeed()); if (range > 0) SetDParam(i++, range); SetDParam(i++, cargo); SetDParam(i++, capacity); if (mail_capacity > 0) { SetDParam(i++, CT_MAIL); SetDParam(i++, mail_capacity); SetDParam(i++, e->GetRunningCost()); return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST; } else { SetDParam(i++, e->GetRunningCost()); return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST; } }
void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { /* Just a fail-safe.. should never happen */ if (!_network_udp_server) return; Packet packet(PACKET_UDP_SERVER_DETAIL_INFO); /* Send the amount of active companies */ packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION); packet.Send_uint8 ((uint8)Company::GetNumItems()); /* Fetch the latest version of the stats */ NetworkCompanyStats company_stats[MAX_COMPANIES]; NetworkPopulateCompanyStats(company_stats); /* The minimum company information "blob" size. */ static const uint MIN_CI_SIZE = 54; uint max_cname_length = NETWORK_COMPANY_NAME_LENGTH; if (Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH) >= (uint)SEND_MTU - packet.size) { /* Assume we can at least put the company information in the packets. */ assert(Company::GetNumItems() * MIN_CI_SIZE < (uint)SEND_MTU - packet.size); /* At this moment the company names might not fit in the * packet. Check whether that is really the case. */ for (;;) { int free = SEND_MTU - packet.size; Company *company; FOR_ALL_COMPANIES(company) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, company->index); GetString(company_name, STR_COMPANY_NAME, company_name + max_cname_length - 1); free -= MIN_CI_SIZE; free -= (int)strlen(company_name); } if (free >= 0) break; /* Try again, with slightly shorter strings. */ assert(max_cname_length > 0); max_cname_length--; } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SGI_TRANSLATION: { SetDParam(0, _current_language->missing); int height = GetStringHeight(STR_INTRO_TRANSLATION, size->width); if (height > 3 * FONT_HEIGHT_NORMAL) { /* Don't let the window become too high. */ Dimension textdim = GetStringBoundingBox(STR_INTRO_TRANSLATION); textdim.height *= 3; textdim.width -= textdim.width / 2; *size = maxdim(*size, textdim); } else { size->height = height + padding.height; } break; } } }
void UpdateSignEditWindow(const Sign *si) { char *last_of = &this->edit_str_buf[this->edit_str_size - 1]; // points to terminating '\0' /* Display an empty string when the sign hasnt been edited yet */ if (si->name != NULL) { SetDParam(0, si->index); GetString(this->edit_str_buf, STR_SIGN_NAME, last_of); } else { GetString(this->edit_str_buf, STR_EMPTY, last_of); } *last_of = '\0'; this->cur_sign = si->index; InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, this->max_chars); this->SetWidgetDirty(WID_QES_TEXT); this->SetFocusedWidget(WID_QES_TEXT); }
static StringID GetAircraftEngineInfoString(const Engine *e) { CargoID cargo = e->GetDefaultCargoType(); uint16 mail_capacity; uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); SetDParam(2, cargo); SetDParam(3, capacity); if (mail_capacity > 0) { SetDParam(4, CT_MAIL); SetDParam(5, mail_capacity); SetDParam(6, e->GetRunningCost()); return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST; } else { SetDParam(4, e->GetRunningCost()); return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST; } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != CW_PANEL) return; uint width = 0; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; switch (ce->type) { case SLE_BOOL: SetDParam(0, STR_CONFIG_SETTING_ON); width = max(width, GetStringBoundingBox(ce->str).width); SetDParam(0, STR_CONFIG_SETTING_OFF); width = max(width, GetStringBoundingBox(ce->str).width); break; default: switch (ce->str) { /* Display date for change date cheat */ case STR_CHEAT_CHANGE_DATE: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 11, 31)); width = max(width, GetStringBoundingBox(ce->str).width); break; /* Draw coloured flag for change company cheat */ case STR_CHEAT_CHANGE_COMPANY: SetDParam(0, 15); width = max(width, GetStringBoundingBox(ce->str).width + 10 + 10); break; /* Set correct string for switch climate cheat */ case STR_CHEAT_SWITCH_CLIMATE: for (StringID i = STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE; i <= STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE; i++) { SetDParam(0, i); width = max(width, GetStringBoundingBox(ce->str).width); } break; default: SetDParam(0, INT64_MAX); width = max(width, GetStringBoundingBox(ce->str).width); break; } break; } } size->width = width + 50 /* stuff on the left */ + 10 /* extra spacing on right */; this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE; size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL) * lengthof(_cheats_ui); }
/* Draw locomotive specific details */ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) { const Engine *e = Engine::Get(engine_number); /* Purchase Cost - Engine weight */ SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayWeight()); DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT); y += FONT_HEIGHT_NORMAL; /* Max speed - Engine power */ SetDParam(0, e->GetDisplayMaxSpeed()); SetDParam(1, e->GetPower()); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); y += FONT_HEIGHT_NORMAL; /* Max tractive effort - not applicable if old acceleration or maglev */ if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) { SetDParam(0, e->GetDisplayMaxTractiveEffort()); DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); y += FONT_HEIGHT_NORMAL; } /* Running cost */ if (rvi->running_cost_class != INVALID_PRICE) { SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; } /* Powered wagons power - Powered wagons extra weight */ if (rvi->pow_wag_power != 0) { SetDParam(0, rvi->pow_wag_power); SetDParam(1, rvi->pow_wag_weight); DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT); y += FONT_HEIGHT_NORMAL; } return y; }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case TTV_ARRIVAL_DEPARTURE_PANEL: SetDParam(0, MAX_YEAR * DAYS_IN_YEAR); this->deparr_time_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width; this->deparr_abbr_width = max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width); size->width = WD_FRAMERECT_LEFT + this->deparr_abbr_width + 10 + this->deparr_time_width + WD_FRAMERECT_RIGHT; /* fall through */ case TTV_ARRIVAL_DEPARTURE_SELECTION: case TTV_TIMETABLE_PANEL: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM; break; case TTV_SUMMARY_PANEL: size->height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SIL_LIST: { Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON); this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text. resize->height = max<uint>(FONT_HEIGHT_NORMAL, spr_dim.height); Dimension d = {this->text_offset + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM}; *size = maxdim(*size, d); break; } case WID_SIL_CAPTION: SetDParam(0, max<size_t>(1000, Sign::GetPoolSize())); *size = GetStringBoundingBox(STR_SIGN_LIST_CAPTION); size->height += padding.height; size->width += padding.width; break; } }
/** * Call a given command as an ingredient of a paste operation. * * Costs and possible errors will be aggregated. After return, call PastingState::IsInterrupted to * test if the paste operation is disallowed to be continued. * * @param tile The tile to apply the command on. * @param p1 Additional data for the command. * @param p2 Additional data for the command. * @param cmd The command-id to execute (a value of the CMD_* enums) and the error summary message (CMD_MSG). * @return The cost of this operation or an error. * * @pre The command is not flagged with CMD_NO_TEST. * @pre The type of the command is CMDT_LANDSCAPE_CONSTRUCTION. * * @see PastingState::IsInterrupted * @see PastingState::CollectCost * @see PastingState::CollectError */ void PastingState::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) { /* make sure we are still allowed to paste */ if (this->IsInterrupted()) { this->last_result = CMD_ERROR; // mark that the command didn't succeed return; } /* PastingState::DoCommand can handle only fully predictable commands, those without * CMD_NO_TEST flag. Unpredictable command have to be handled separately. */ assert(!(GetCommandFlags(cmd) & CMD_NO_TEST)); /* ignore some of the given flags, instead use those from the command proc table */ DoCommandFlag flags = this->dc_flags; flags &= ~DC_AUTO & ~DC_NO_WATER & ~DC_ALL_TILES; flags |= CommandFlagsToDCFlags(GetCommandFlags(cmd)); /* use given error message or the default one */ StringID summary_error_msg = GB(cmd, 16, 16); if (summary_error_msg == 0) summary_error_msg = STR_ERROR_CAN_T_PASTE_HERE; /* test the command, output is the return value */ CommandCost ret = ::DoCommand(tile, p1, p2, flags & ~DC_EXEC, cmd); /* apply if exec'ing */ if (ret.Succeeded() && (flags & DC_EXEC)) { /* check if there is enough money */ if (ret.GetCost() > 0 && this->GetAvailableMoney() < ret.GetCost()) { SetDParam(0, ret.GetCost()); ret = CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY); } else { CommandCost ret2 = ::DoCommand(tile, p1, p2, flags, cmd); assert(ret == ret2); } } /* aggregate costs */ this->CollectCost(ret, tile, summary_error_msg); }
virtual void DrawWidget(const Rect &r, int widget) const { if (widget != AIS_WIDGET_BACKGROUND) return; AIConfig *config = this->ai_config; AIConfigItemList::const_iterator it = config->GetConfigList()->begin(); int i = 0; for (; !this->vscroll.IsVisible(i); i++) it++; bool rtl = _dynlang.text_dir == TD_RTL; uint buttons_left = rtl ? r.right - 23 : r.left + 4; uint value_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 28); uint value_right = r.right - (rtl ? 28 : WD_FRAMERECT_RIGHT); uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 54); uint text_right = r.right - (rtl ? 54 : WD_FRAMERECT_RIGHT); int y = r.top; for (; this->vscroll.IsVisible(i) && it != config->GetConfigList()->end(); i++, it++) { int current_value = config->GetSetting((*it).name); bool editable = (_game_mode == GM_MENU) || ((it->flags & AICONFIG_INGAME) != 0); uint x = rtl ? r.right : r.left; if (((*it).flags & AICONFIG_BOOLEAN) != 0) { DrawFrameRect(buttons_left, y + 2, buttons_left + 19, y + 10, (current_value != 0) ? COLOUR_GREEN : COLOUR_RED, (current_value != 0) ? FR_LOWERED : FR_NONE); } else { DrawArrowButtons(buttons_left, y + 2, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > (*it).min_value, editable && current_value < (*it).max_value); if (it->labels != NULL && it->labels->Find(current_value) != it->labels->End()) { x = DrawString(value_left, value_right, y + WD_MATRIX_TOP, it->labels->Find(current_value)->second, TC_ORANGE); } else { SetDParam(0, current_value); x = DrawString(value_left, value_right, y + WD_MATRIX_TOP, STR_JUST_INT, TC_ORANGE); } } DrawString(max(rtl ? 0U : x + 3, text_left), min(rtl ? x - 3 : r.right, text_right), y + WD_MATRIX_TOP, (*it).description, TC_LIGHT_BLUE); y += this->line_height; } }
virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AP_AIRPORT_LIST: { int y = r.top; AirportClass *apclass = AirportClass::Get(_selected_airport_class); for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); if (!as->IsAvailable()) { GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); } DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, Center(y, this->line_height), as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); y += this->line_height; } break; } case WID_AP_AIRPORT_SPRITE: if (this->preview_sprite != 0) { Dimension d = GetSpriteSize(this->preview_sprite); DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); } break; case WID_AP_EXTRA_TEXT: if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string != STR_UNDEFINED) { SetDParam(0, string); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); } } break; } }
Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) { NewsReferenceType reftype1 = NR_NONE; NewsReferenceType reftype2 = NR_NONE; /* if mode is false, use the singular form */ const CargoSpec *cs = CargoSpec::Get(s->cargo_type); SetDParam(0, mode ? cs->name : cs->name_single); switch (s->src_type) { case ST_INDUSTRY: reftype1 = NR_INDUSTRY; SetDParam(1, STR_INDUSTRY_NAME); break; case ST_TOWN: reftype1 = NR_TOWN; SetDParam(1, STR_TOWN_NAME); break; default: NOT_REACHED(); } SetDParam(2, s->src); switch (s->dst_type) { case ST_INDUSTRY: reftype2 = NR_INDUSTRY; SetDParam(4, STR_INDUSTRY_NAME); break; case ST_TOWN: reftype2 = NR_TOWN; SetDParam(4, STR_TOWN_NAME); break; default: NOT_REACHED(); } SetDParam(5, s->dst); Pair p; p.a = reftype1; p.b = reftype2; return p; }
/** * Set the right DParams to get the name of an owner. * @param owner the owner to get the name of. * @param tile optional tile to get the right town. * @pre if tile == 0, then owner can't be OWNER_TOWN. */ void GetNameOfOwner(Owner owner, TileIndex tile) { SetDParam(2, owner); if (owner != OWNER_TOWN) { if (!Company::IsValidID(owner)) { SetDParam(0, STR_COMPANY_SOMEONE); } else { SetDParam(0, STR_COMPANY_NAME); SetDParam(1, owner); } } else { assert(tile != 0); const Town *t = ClosestTownFromTile(tile, UINT_MAX); SetDParam(0, STR_TOWN_NAME); SetDParam(1, t->index); } }
/** * Sets the arrival or departure string and parameters. * @param param1 the first DParam to fill * @param param2 the second DParam to fill * @param ticks the number of ticks to 'draw' */ static void SetArrivalDepartParams(int param1, int param2, Ticks ticks) { SetDParam(param1, STR_JUST_DATE_TINY); SetDParam(param2, _date + (ticks / DAY_TICKS)); }
virtual void OnClick(Point pt, int widget, int click_count) { const Vehicle *v = this->vehicle; switch (widget) { case WID_VT_ORDER_VIEW: // Order view button ShowOrdersWindow(v); break; case WID_VT_TIMETABLE_PANEL: { // Main panel. int selected = GetOrderFromTimetableWndPt(pt.y, v); this->DeleteChildWindows(); this->sel_index = (selected == INVALID_ORDER || selected == this->sel_index) ? -1 : selected; break; } case WID_VT_START_DATE: // Change the date that the timetable starts. ShowSetDateWindow(this, v->index, _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback); break; case WID_VT_CHANGE_TIME: { // "Wait For" button. int selected = this->sel_index; VehicleOrderID real = (selected + 1) / 2; if (real >= v->GetNumOrders()) real = 0; const Order *order = v->GetOrder(real); StringID current = STR_EMPTY; if (order != NULL) { uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time; if (!_settings_client.gui.timetable_in_ticks) time /= DAY_TICKS; if (time != 0) { SetDParam(0, time); current = STR_JUST_INT; } } this->query_is_speed_query = false; ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, this, CS_NUMERAL, QSF_NONE); break; } case WID_VT_CHANGE_SPEED: { // Change max speed button. int selected = this->sel_index; VehicleOrderID real = (selected + 1) / 2; if (real >= v->GetNumOrders()) real = 0; StringID current = STR_EMPTY; const Order *order = v->GetOrder(real); if (order != NULL) { if (order->max_speed != UINT16_MAX) { SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->max_speed)); current = STR_JUST_INT; } } this->query_is_speed_query = true; ShowQueryString(current, STR_TIMETABLE_CHANGE_SPEED, 31, this, CS_NUMERAL, QSF_NONE); break; } case WID_VT_CLEAR_TIME: { // Clear waiting time. uint32 p1 = PackTimetableArgs(v, this->sel_index, false); DoCommandP(0, p1, 0, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_CLEAR_SPEED: { // Clear max speed button. uint32 p1 = PackTimetableArgs(v, this->sel_index, true); DoCommandP(0, p1, UINT16_MAX, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter. DoCommandP(0, v->index, 0, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; case WID_VT_AUTOFILL: { // Autofill the timetable. uint32 p2 = 0; if (!HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(p2, 0); if (_ctrl_pressed) SetBit(p2, 1); DoCommandP(0, v->index, p2, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_EXPECTED: this->show_expected = !this->show_expected; break; case WID_VT_SHARED_ORDER_LIST: ShowVehicleListWindow(v); break; } this->SetDirty(); }
virtual void DrawWidget(const Rect &r, int widget) const { const Vehicle *v = this->vehicle; int selected = this->sel_index; switch (widget) { case WID_VT_TIMETABLE_PANEL: { int y = r.top + WD_FRAMERECT_TOP; int i = this->vscroll->GetPosition(); VehicleOrderID order_id = (i + 1) / 2; bool final_order = false; bool rtl = _current_text_dir == TD_RTL; SetDParamMaxValue(0, v->GetNumOrders(), 2); int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width; const Order *order = v->GetOrder(order_id); while (order != NULL) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { DrawOrderString(v, order, order_id, y, i == selected, true, r.left + WD_FRAMERECT_LEFT, middle, r.right - WD_FRAMERECT_RIGHT); order_id++; if (order_id >= v->GetNumOrders()) { order = v->GetOrder(0); final_order = true; } else { order = order->next; } } else { StringID string; TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK; if (order->IsType(OT_CONDITIONAL)) { string = STR_TIMETABLE_NO_TRAVEL; } else if (order->IsType(OT_IMPLICIT)) { string = STR_TIMETABLE_NOT_TIMETABLEABLE; colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE; } else if (order->travel_time == 0) { string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED : STR_TIMETABLE_TRAVEL_NOT_TIMETABLED; } else { SetTimetableParams(0, 1, order->travel_time); string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR; } SetDParam(2, order->max_speed); DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour); if (final_order) break; } i++; y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_ARRIVAL_DEPARTURE_PANEL: { /* Arrival and departure times are handled in an all-or-nothing approach, * i.e. are only shown if we can calculate all times. * Excluding order lists with only one order makes some things easier. */ Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break; TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders()); const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders(); VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID; int y = r.top + WD_FRAMERECT_TOP; bool show_late = this->show_expected && v->lateness_counter > DAY_TICKS; Ticks offset = show_late ? 0 : -v->lateness_counter; bool rtl = _current_text_dir == TD_RTL; int abbr_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->deparr_abbr_width : r.left + WD_FRAMERECT_LEFT; int abbr_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->deparr_abbr_width; int time_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_RIGHT - this->deparr_time_width; int time_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->deparr_time_width : r.right - WD_FRAMERECT_RIGHT; for (int i = this->vscroll->GetPosition(); i / 2 < v->GetNumOrders(); ++i) { // note: i is also incremented in the loop /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { if (arr_dep[i / 2].arrival != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_ARRIVAL_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); if (this->show_expected && i / 2 == earlyID) { SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival); DrawString(time_left, time_right, y, STR_GREEN_STRING, i == selected ? TC_WHITE : TC_BLACK); } else { SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival + offset); DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK); } } } else { if (arr_dep[i / 2].departure != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); SetArrivalDepartParams(0, 1, arr_dep[i/2].departure + offset); DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK); } } y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_SUMMARY_PANEL: { int y = r.top + WD_FRAMERECT_TOP; Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time != 0) { SetTimetableParams(0, 1, total_time); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE); } y += FONT_HEIGHT_NORMAL; if (v->timetable_start != 0) { /* We are running towards the first station so we can start the * timetable at the given time. */ SetDParam(0, STR_JUST_DATE_TINY); SetDParam(1, v->timetable_start); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_START_AT); } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { /* We aren't running on a timetable yet, so how can we be "on time" * when we aren't even "on service"/"on duty"? */ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_NOT_STARTED); } else if (v->lateness_counter == 0 || (!_settings_client.gui.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_ON_TIME); } else { SetTimetableParams(0, 1, abs(v->lateness_counter)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE); } break; } } }
/** * Draw the purchase info details of a vehicle at a given location. * @param left,right,y location where to draw the info * @param engine_number the engine of which to draw the info of * @return y after drawing all the text */ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) { const Engine *e = Engine::Get(engine_number); YearMonthDay ymd; ConvertDateToYMD(e->intro_date, &ymd); bool refittable = IsArticulatedVehicleRefittable(engine_number); bool articulated_cargo = false; switch (e->type) { default: NOT_REACHED(); case VEH_TRAIN: if (e->u.rail.railveh_type == RAILVEH_WAGON) { y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); } else { y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); } articulated_cargo = true; break; case VEH_ROAD: y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); articulated_cargo = true; break; case VEH_SHIP: y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); break; case VEH_AIRCRAFT: y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); break; } if (articulated_cargo) { /* Cargo type + capacity, or N/A */ int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, refittable); if (new_y == y) { SetDParam(0, CT_INVALID); SetDParam(2, STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; } else { y = new_y; } } /* Draw details that apply to all types except rail wagons. */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { /* Design date - Life length */ SetDParam(0, ymd.year); SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR); DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE); y += FONT_HEIGHT_NORMAL; /* Reliability */ SetDParam(0, ToPercent16(e->reliability)); DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY); y += FONT_HEIGHT_NORMAL; } if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number); /* Additional text from NewGRF */ y = ShowAdditionalText(left, right, y, engine_number); return y; }
/* Draw aircraft specific details */ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) { const Engine *e = Engine::Get(engine_number); CargoID cargo = e->GetDefaultCargoType(); /* Purchase cost - Max speed */ SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); y += FONT_HEIGHT_NORMAL; /* Cargo capacity */ uint16 mail_capacity; uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); if (mail_capacity > 0) { SetDParam(0, cargo); SetDParam(1, capacity); SetDParam(2, CT_MAIL); SetDParam(3, mail_capacity); DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY); } else { /* Note, if the default capacity is selected by the refit capacity * callback, then the capacity shown is likely to be incorrect. */ SetDParam(0, cargo); SetDParam(1, capacity); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); } y += FONT_HEIGHT_NORMAL; /* Running cost */ SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; uint16 range = e->GetRange(); if (range != 0) { SetDParam(0, range); DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE); y += FONT_HEIGHT_NORMAL; } return y; }
void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const { int left = r.left + WD_MATRIX_LEFT; int right = r.right - WD_MATRIX_RIGHT; bool rtl = _current_text_dir == TD_RTL; bool ltr = !rtl; int text_offset = WD_FRAMERECT_RIGHT; int text_left = left + (rtl ? 0 : text_offset); int text_right = right - (rtl ? text_offset : 0); int y = r.top + 1; uint max_departures = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->departures->Length() + this->arrivals->Length()); if (max_departures > _settings_client.gui.max_departures) { max_departures = _settings_client.gui.max_departures; } byte small_font_size = _settings_client.gui.departure_larger_font ? FONT_HEIGHT_NORMAL : FONT_HEIGHT_SMALL; /* Draw the black background. */ GfxFillRect(r.left + 1, r.top, r.right - 1, r.bottom, PC_BLACK); /* Nothing selected? Then display the information text. */ bool none_selected[2] = {true, true}; for (uint i = 0; i < 4; ++i) { if (this->show_types[i]) { none_selected[0] = false; break; } } for (uint i = 0; i < 2; ++i) { if (this->departure_types[i]) { none_selected[1] = false; break; } } if (none_selected[0] || none_selected[1]) { DrawString(text_left, text_right, y + 1, STR_DEPARTURES_NONE_SELECTED); return; } /* No scheduled departures? Then display the information text. */ if (max_departures == 0) { DrawString(text_left, text_right, y + 1, STR_DEPARTURES_EMPTY); return; } /* Find the maximum possible width of the departure time and "Expt <time>" fields. */ int time_width = cached_date_width; if (!_settings_client.gui.departure_show_both) { time_width += (departure_types[0] && departure_types[1] ? cached_date_arrow_width : 0); } /* Vehicle type icon */ int type_width = _settings_client.gui.departure_show_vehicle_type ? (GetStringBoundingBox(STR_DEPARTURES_TYPE_PLANE)).width : 0; /* Find the maximum width of the status field */ int status_width = cached_status_width; /* Find the width of the "Calling at:" field. */ int calling_at_width = (GetStringBoundingBox(_settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)).width; /* Find the maximum company name width. */ int toc_width = 0; /* Find the maximum group name width. */ int group_width = 0; /* Find the maximum vehicle name width. */ int veh_width = 0; if (_settings_client.gui.departure_show_vehicle || _settings_client.gui.departure_show_company || _settings_client.gui.departure_show_group) { for (uint i = 0; i < 4; ++i) { VehicleList vehicles; /* MAX_COMPANIES is probably the wrong thing to put here, but it works. GenerateVehicleSortList doesn't check the company when the type of list is VL_STATION_LIST (r20801). */ if (!GenerateVehicleSortList(&vehicles, VehicleListIdentifier(VL_STATION_LIST, (VehicleType)(VEH_TRAIN + i), MAX_COMPANIES, station).Pack())) { /* Something went wrong: panic! */ continue; } for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) { SetDParam(0, (uint64)((*v)->index)); int width = (GetStringBoundingBox(STR_DEPARTURES_VEH)).width; if (_settings_client.gui.departure_show_vehicle && width > veh_width) veh_width = width; if ((*v)->group_id != INVALID_GROUP && (*v)->group_id != DEFAULT_GROUP) { SetDParam(0, (uint64)((*v)->group_id)); width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width; if (_settings_client.gui.departure_show_group && width > group_width) group_width = width; } SetDParam(0, (uint64)((*v)->owner)); width = (GetStringBoundingBox(STR_DEPARTURES_TOC)).width; if (_settings_client.gui.departure_show_company && width > toc_width) toc_width = width; } } } uint departure = 0; uint arrival = 0; /* Draw each departure. */ for (uint i = 0; i < max_departures; ++i) { const Departure *d; if (arrival == this->arrivals->Length()) { d = (*(this->departures))[departure++]; } else if (departure == this->departures->Length()) { d = (*(this->arrivals))[arrival++]; } else { d = (*(this->departures))[departure]; const Departure *a = (*(this->arrivals))[arrival]; if (a->scheduled_date < d->scheduled_date) { d = a; arrival++; } else { departure++; } } if (i < this->vscroll->GetPosition()) { continue; } /* If for some reason the departure is too far in the future or is at a negative time, skip it. */ if ((d->scheduled_date / DAY_TICKS) > (_date + _settings_client.gui.max_departure_time) || d->scheduled_date < 0) { continue; } if (d->terminus == INVALID_STATION) continue; StringID time_str = (departure_types[0] && departure_types[1]) ? (d->type == D_DEPARTURE ? STR_DEPARTURES_TIME_DEP : STR_DEPARTURES_TIME_ARR) : STR_DEPARTURES_TIME; if (_settings_client.gui.departure_show_both) time_str = STR_DEPARTURES_TIME_BOTH; /* Time */ SetDParam(0, d->scheduled_date); SetDParam(1, d->scheduled_date - d->order->wait_time); ltr ? DrawString( text_left, text_left + time_width, y + 1, time_str) : DrawString(text_right - time_width, text_right, y + 1, time_str); /* Vehicle type icon, with thanks to sph */ if (_settings_client.gui.departure_show_vehicle_type) { StringID type = STR_DEPARTURES_TYPE_TRAIN; int offset = (_settings_client.gui.departure_show_vehicle_color ? 1 : 0); switch (d->vehicle->type) { case VEH_TRAIN: type = STR_DEPARTURES_TYPE_TRAIN; break; case VEH_ROAD: type = IsCargoInClass(d->vehicle->cargo_type, CC_PASSENGERS) ? STR_DEPARTURES_TYPE_BUS : STR_DEPARTURES_TYPE_LORRY; break; case VEH_SHIP: type = STR_DEPARTURES_TYPE_SHIP; break; case VEH_AIRCRAFT: type = STR_DEPARTURES_TYPE_PLANE; break; default: break; } type += offset; DrawString(text_left + time_width + 3, text_left + time_width + type_width + 3, y, type); } /* The icons to show with the destination and via stations. */ StringID icon = STR_DEPARTURES_STATION_NONE; StringID icon_via = STR_DEPARTURES_STATION_NONE; if (_settings_client.gui.departure_destination_type) { Station *t = Station::Get(d->terminus.station); if (t->facilities & FACIL_DOCK && t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_SHIP && d->vehicle->type != VEH_AIRCRAFT) { icon = STR_DEPARTURES_STATION_PORTAIRPORT; } else if (t->facilities & FACIL_DOCK && d->vehicle->type != VEH_SHIP) { icon = STR_DEPARTURES_STATION_PORT; } else if (t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_AIRCRAFT) { icon = STR_DEPARTURES_STATION_AIRPORT; } } if (_settings_client.gui.departure_destination_type && d->via != INVALID_STATION) { Station *t = Station::Get(d->via); if (t->facilities & FACIL_DOCK && t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_SHIP && d->vehicle->type != VEH_AIRCRAFT) { icon_via = STR_DEPARTURES_STATION_PORTAIRPORT; } else if (t->facilities & FACIL_DOCK && d->vehicle->type != VEH_SHIP) { icon_via = STR_DEPARTURES_STATION_PORT; } else if (t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_AIRCRAFT) { icon_via = STR_DEPARTURES_STATION_AIRPORT; } } /* Destination */ if (d->via == INVALID_STATION) { /* Only show the terminus. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS); } else { /* Show the terminus and the via station. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); SetDParam(2, d->via); SetDParam(3, icon_via); int text_width = (GetStringBoundingBox(STR_DEPARTURES_TERMINUS_VIA_STATION)).width; if (text_width < text_right - status_width - (toc_width + veh_width + group_width + 2) - 2 - (text_left + time_width + type_width + 6)) { /* They will both fit, so show them both. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); SetDParam(2, d->via); SetDParam(3, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION); } else { /* They won't both fit, so switch between showing the terminus and the via station approximately every 4 seconds. */ if (this->tick_count & (1 << 7)) { SetDParam(0, d->via); SetDParam(1, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_VIA) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_VIA); } else { SetDParam(0, d->terminus.station); SetDParam(1, icon); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA); } } } /* Status */ { int status_left = ltr ? text_right - status_width - 2 - (toc_width + veh_width + group_width + 2) : text_left + (toc_width + veh_width + group_width + 2) + 7; int status_right = ltr ? text_right - (toc_width + veh_width + group_width + 2) + 2 : text_left + status_width + 2 + (toc_width + veh_width + group_width + 7); if (d->status == D_ARRIVED) { /* The vehicle has arrived. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ARRIVED); } else if(d->status == D_CANCELLED) { /* The vehicle has been cancelled. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_CANCELLED); } else{ if (d->lateness <= DAY_TICKS && d->scheduled_date > ((_date * DAY_TICKS) + _date_fract)) { /* We have no evidence that the vehicle is late, so assume it is on time. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ON_TIME); } else { if ((d->scheduled_date + d->lateness) < ((_date * DAY_TICKS) + _date_fract)) { /* The vehicle was expected to have arrived by now, even if we knew it was going to be late. */ /* We assume that the train stays at least a day at a station so it won't accidentally be marked as delayed for a fraction of a day. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_DELAYED); } else { /* The vehicle is expected to be late and is not yet due to arrive. */ SetDParam(0, d->scheduled_date + d->lateness); DrawString(status_left, status_right, y + 1, STR_DEPARTURES_EXPECTED); } } } } /* Vehicle name */ if (_settings_client.gui.departure_show_vehicle) { SetDParam(0, (uint64)(d->vehicle->index)); ltr ? DrawString(text_right - (toc_width + veh_width + group_width + 2), text_right - toc_width - group_width - 2, y + 1, STR_DEPARTURES_VEH) : DrawString( text_left + toc_width + group_width + 2, text_left + (toc_width + veh_width + group_width + 2), y + 1, STR_DEPARTURES_VEH); } /* Group name */ if (_settings_client.gui.departure_show_group && d->vehicle->group_id != INVALID_GROUP && d->vehicle->group_id != DEFAULT_GROUP) { SetDParam(0, (uint64)(d->vehicle->group_id)); ltr ? DrawString(text_right - (toc_width + group_width + 2), text_right - toc_width - 2, y + 1, STR_DEPARTURES_GROUP) : DrawString( text_left + toc_width + 2, text_left + (toc_width + group_width + 2), y + 1, STR_DEPARTURES_GROUP); } /* Operating company */ if (_settings_client.gui.departure_show_company) { SetDParam(0, (uint64)(d->vehicle->owner)); ltr ? DrawString(text_right - toc_width, text_right, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_RIGHT) : DrawString( text_left, text_left + toc_width, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_LEFT); } int bottom_y = y + this->entry_height - small_font_size - (_settings_client.gui.departure_larger_font ? 1 : 3); /* Calling at */ ltr ? DrawString( text_left, text_left + calling_at_width, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT) : DrawString(text_right - calling_at_width, text_right, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT); /* List of stations */ /* RTL languages can be handled in the language file, e.g. by having the following: */ /* STR_DEPARTURES_CALLING_AT_STATION :{STATION}, {RAW_STRING} */ /* STR_DEPARTURES_CALLING_AT_LAST_STATION :{STATION} & {RAW_STRING}*/ char buffer[512], scratch[512]; if (d->calling_at.Length() != 0) { SetDParam(0, (uint64)(*d->calling_at.Get(0)).station); GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch)); StationID continuesTo = INVALID_STATION; if (d->calling_at.Get(0)->station == d->terminus.station && d->calling_at.Length() > 1) { continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station; } else if (d->calling_at.Length() > 1) { /* There's more than one stop. */ uint i; /* For all but the last station, write out ", <station>". */ for (i = 1; i < d->calling_at.Length() - 1; ++i) { StationID s = d->calling_at.Get(i)->station; if (s == d->terminus.station) { continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station; break; } SetDParam(0, (uint64)scratch); SetDParam(1, (uint64)s); GetString(buffer, STR_DEPARTURES_CALLING_AT_STATION, lastof(buffer)); strncpy(scratch, buffer, sizeof(scratch)); } /* Finally, finish off with " and <station>". */ SetDParam(0, (uint64)scratch); SetDParam(1, (uint64)d->calling_at.Get(i)->station); GetString(buffer, STR_DEPARTURES_CALLING_AT_LAST_STATION, lastof(buffer)); strncpy(scratch, buffer, sizeof(scratch)); } SetDParam(0, (uint64)scratch); StringID string; if (continuesTo == INVALID_STATION) { string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_LARGE : STR_DEPARTURES_CALLING_AT_LIST; } else { SetDParam(1, continuesTo); string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS_LARGE : STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS; } GetString(buffer, string, lastof(buffer)); } else { buffer[0] = 0; //SetDParam(0, d->terminus); //GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch)); } int list_width = (GetStringBoundingBox(buffer, _settings_client.gui.departure_larger_font ? FS_NORMAL : FS_SMALL)).width; /* Draw the whole list if it will fit. Otherwise scroll it. */ if (list_width < text_right - (text_left + calling_at_width + 2)) { ltr ? DrawString(text_left + calling_at_width + 2, text_right, bottom_y, buffer) : DrawString( text_left, text_right - calling_at_width - 2, bottom_y, buffer); } else { DrawPixelInfo tmp_dpi; if (ltr ? !FillDrawPixelInfo(&tmp_dpi, text_left + calling_at_width + 2, bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3) : !FillDrawPixelInfo(&tmp_dpi, text_left , bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)) { y += this->entry_height; continue; } DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; /* The scrolling text starts out of view at the right of the screen and finishes when it is out of view at the left of the screen. */ int pos = ltr ? text_right - (this->tick_count % (list_width + text_right - text_left)) : text_left + (this->tick_count % (list_width + text_right - text_left)); ltr ? DrawString( pos, INT16_MAX, 0, buffer, TC_FROMSTRING, SA_LEFT | SA_FORCE) : DrawString(-INT16_MAX, pos, 0, buffer, TC_FROMSTRING, SA_RIGHT | SA_FORCE); _cur_dpi = old_dpi; } y += this->entry_height; } }