diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 62f7dcecd3..9d8a6caca9 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -194,6 +194,7 @@ STR_COLOUR_DEFAULT :Default STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s +STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL}{NBSP}tiles/day STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}hp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}hp @@ -313,8 +314,15 @@ STR_SORT_BY_CARGO_CAPACITY :Cargo capacity STR_SORT_BY_RANGE :Range STR_SORT_BY_POPULATION :Population STR_SORT_BY_RATING :Rating +STR_SORT_BY_NUM_VEHICLES :Number of vehicles +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Total profit last year +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Total profit this year +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Average profit last year +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Average profit this year # Group by options for vehicle list +STR_GROUP_BY_NONE :None +STR_GROUP_BY_SHARED_ORDERS :Shared orders # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pause game @@ -605,7 +613,7 @@ STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Transport Coord STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Route Supervisor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Director STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Chief Executive -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Chairman +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Chairperson STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tycoon @@ -688,7 +696,7 @@ STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Click on STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top companies who reached {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Company League Table in {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. -STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Businessman +STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Businessperson STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrialist STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Capitalist @@ -740,6 +748,7 @@ STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLA STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Rough Land STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Grass Land STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Bare Land +STR_SMALLMAP_LEGENDA_RAINFOREST :{TINY_FONT}{BLACK}Rainforest STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Fields STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Trees STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Rocks @@ -771,6 +780,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Display STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Show last message or news report STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUSED * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * PAUSED (waiting for link graph update) * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOSAVE STR_STATUSBAR_SAVING_GAME :{RED}* * SAVING GAME * * @@ -936,6 +946,8 @@ STR_GAME_OPTIONS_CURRENCY_MXN :Mexican Peso (M STR_GAME_OPTIONS_CURRENCY_NTD :New Taiwan Dollar (NTD) STR_GAME_OPTIONS_CURRENCY_CNY :Chinese Renminbi (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dollar (HKD) +STR_GAME_OPTIONS_CURRENCY_INR :Indian Rupee (INR) +STR_GAME_OPTIONS_CURRENCY_IDR :Indonesian Rupiah (IDR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left @@ -992,6 +1004,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :other STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interface size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface element size to use +STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_AUTO :(auto-detect) STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Double size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Quad size @@ -999,6 +1012,7 @@ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Quad size STR_GAME_OPTIONS_FONT_ZOOM :{BLACK}Font size STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface font size to use +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_AUTO :(auto-detect) STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Double size STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :Quad size @@ -1437,6 +1451,7 @@ STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Keep building t STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Keep the building tools for bridges, tunnels, etc. open after use STR_CONFIG_SETTING_EXPENSES_LAYOUT :Group expenses in company finance window: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Define the layout for the company expenses window +STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS_HELPTEXT :Automatically remove signals during track construction if the signals are in the way. Note that this can potentially lead to train crashes. STR_CONFIG_SETTING_SOUND_TICKER :News ticker: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Play sound for summarized news messages @@ -1550,6 +1565,10 @@ STR_CONFIG_SETTING_ENDING_YEAR :Scoring end yea STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT :Year the game ends for scoring purposes. At the end of this year, the company's score is recorded and the high-score screen is displayed, but the players can continue playing after that.{}If this is before the starting year, the high-score screen is never displayed. STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM} STR_CONFIG_SETTING_ENDING_YEAR_ZERO :Never +STR_CONFIG_SETTING_ECONOMY_TYPE_HELPTEXT :Smooth economy makes production changes more often, and in smaller steps. Frozen economy stops production changes and industry closures. This setting may have no effect if industry types are provided by a NewGRF. +STR_CONFIG_SETTING_ECONOMY_TYPE_ORIGINAL :Original +STR_CONFIG_SETTING_ECONOMY_TYPE_SMOOTH :Smooth +STR_CONFIG_SETTING_ECONOMY_TYPE_FROZEN :Frozen STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying shares from other companies: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :Minimum company age to trade shares: {STRING} @@ -1601,6 +1620,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Linear STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In-game placement of trees: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Grow but don't spread {RED}(breaks lumber mill) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Grow but only spread in rain forests +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Grow and spread everywhere +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :Don't grow, don't spread {RED}(breaks lumber mill) STR_CONFIG_SETTING_TOOLBAR_POS :Position of main toolbar: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontal position of the main toolbar at the top of the screen @@ -1667,6 +1690,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Whenever a spee STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :Game units (tiles/day) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Vehicle power units: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Whenever a vehicle's power is shown in the user interface, show it in the selected units @@ -1810,6 +1834,7 @@ STR_ABANDON_SCENARIO_QUERY :{YELLOW}Are you # Cheat window STR_CHEATS :{WHITE}Cheats STR_CHEATS_TOOLTIP :{BLACK}Checkboxes indicate if you have used this cheat before +STR_CHEATS_NOTE :{BLACK}Note: any usage of these settings will be recorded by the savegame STR_CHEAT_MONEY :{LTBLUE}Increase money by {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Playing as company: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magic bulldozer (remove industries, unmovable objects): {ORANGE}{STRING} @@ -1961,6 +1986,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Join gam STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Refresh server STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Refresh the server info +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Search internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Search internet for public servers +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Search LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Search local area network for servers STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Add server STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list which will always be checked for running games STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Start server @@ -2185,11 +2214,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Game still paus STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Game still paused ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Game still paused ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Game still paused ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :Game still paused ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Game unpaused ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :number of players STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connecting clients STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manual STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :game script +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :waiting for link graph update ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :leaving STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} has joined the game @@ -2317,6 +2348,7 @@ STR_JOIN_WAYPOINT_CAPTION :{WHITE}Join way STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Build a separate waypoint # Generic toolbar +STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE :{BLACK}Disabled as currently no vehicles are available for this infrastructure # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Railroad Construction @@ -2512,6 +2544,12 @@ STR_TREES_RANDOM_TYPE :{BLACK}Trees of STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Plant single trees by dragging over the landscape. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Grove +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Plant small forests by dragging over the landscape. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Forest +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Plant large forests by dragging over the landscape. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation @@ -2562,12 +2600,18 @@ STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Random # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Fund new industry STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Choose the appropriate industry from this list -STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Many random industries +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :{BLACK}Create random industries STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Cover the map with randomly placed industries +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_CAPTION :{WHITE}Create random industries +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_QUERY :{YELLOW}Are you sure you want to create many random industries? STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cost: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospect STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Build STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Fund +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES :{BLACK}Remove all industries +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES_TOOLTIP :{BLACK}Remove all industries currently present on the map +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES_CAPTION :{WHITE}Remove all industries +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES_QUERY :{YELLOW}Are you sure you want to remove all industries? # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industry chain for {STRING} industry @@ -2588,6 +2632,7 @@ STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Select t # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land Area Information +STR_LAND_AREA_INFORMATION_LOCATION_TOOLTIP :{BLACK}Center the main view on tile location. Ctrl+Click opens a new viewport on tile location STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cost to clear: {LTBLUE}N/A STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cost to clear: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Revenue when cleared: {LTBLUE}{CURRENCY_LONG} @@ -3057,6 +3102,7 @@ STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toggle m # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign text +STR_EDIT_SIGN_LOCATION_TOOLTIP :{BLACK}Center the main view on sign location. Ctrl+Click opens a new viewport on sign location STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign @@ -3140,10 +3186,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}Company STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on goal to center main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Question -STR_GOAL_QUESTION_CAPTION_INFORMATION :Information -STR_GOAL_QUESTION_CAPTION_WARNING :Warning -STR_GOAL_QUESTION_CAPTION_ERROR :Error +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}Question +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}Information +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}Warning +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}Error ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel @@ -3334,6 +3380,7 @@ STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Rebuild STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Details STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}View detailed infrastructure counts STR_COMPANY_VIEW_GIVE_MONEY_BUTTON :{BLACK}Give money +STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP :{BLACK}Give money to this company STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}New Face STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Select new face for president @@ -3373,6 +3420,10 @@ STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industri STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- None - STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industry names - click on name to center main view on industry. Ctrl+Click opens a new viewport on industry location +STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER :{BLACK}Accepted cargo: {SILVER}{STRING} +STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER :{BLACK}Produced cargo: {SILVER}{STRING} +STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES :All cargo types +STR_INDUSTRY_DIRECTORY_FILTER_NONE :None # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} @@ -3703,6 +3754,10 @@ STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make aut # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} +STR_VEHICLE_VIEW_TRAIN_CENTER_TOOLTIP :{BLACK}Center main view on train's location. Double click will follow train in main view. Ctrl+Click opens a new viewport on train's location +STR_VEHICLE_VIEW_ROAD_VEHICLE_CENTER_TOOLTIP :{BLACK}Center main view on vehicle's location. Double click will follow vehicle in main view. Ctrl+Click opens a new viewport on vehicle's location +STR_VEHICLE_VIEW_SHIP_CENTER_TOOLTIP :{BLACK}Center main view on ship's location. Double click will follow ship in main view. Ctrl+Click opens a new viewport on ship's location +STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}Center main view on aircraft's location. Double click will follow aircraft in main view. Ctrl+Click opens a new viewport on aircraft's location STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send train to depot. Ctrl+Click will only service STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send vehicle to depot. Ctrl+Click will only service @@ -3734,7 +3789,12 @@ STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Show roa STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Show ship details STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Show aircraft details +STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Current train action - click to stop/start train +STR_VEHICLE_VIEW_ROAD_VEHICLE_STATUS_START_STOP_TOOLTIP :{BLACK}Current vehicle action - click to stop/start vehicle +STR_VEHICLE_VIEW_SHIP_STATE_STATUS_STOP_TOOLTIP :{BLACK}Current ship action - click to stop/start ship +STR_VEHICLE_VIEW_AIRCRAFT_STATUS_START_STOP_TOOLTIP :{BLACK}Current aircraft action - click to stop/start aircraft +STR_VEHICLE_VIEW_ORDER_LOCATION_TOOLTIP :{BLACK}Center main view on order destination. Ctrl+Click opens a new viewport on the order destination's location # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Loading / Unloading @@ -4206,6 +4266,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Savegame is mad STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :File not readable STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :File not writable STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integrity check failed +STR_GAME_SAVELOAD_ERROR_PATCHPACK :Savegame is made with a modified version STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without streetcar support. All streetcars have been removed @@ -4286,6 +4347,7 @@ STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... no l STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} required STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Can't repay loan... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Can't give away money that is loaned from the bank... +STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}Can't give away money to this company... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Can't buy company... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Can't build company headquarters... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Can't buy 25% share in this company... @@ -4412,6 +4474,8 @@ STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Wrong depot typ STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} is too long after replacement STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}No autoreplace/renew rules applied STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(money limit) +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO :{WHITE}New vehicle can't carry {STRING} +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT :{WHITE}New vehicle can't do refit in order {NUM} # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Impossible track combination @@ -4698,10 +4762,10 @@ STR_INDUSTRY_NAME_SUGAR_MINE :Sugar Mine ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Unnamed -STR_SV_TRAIN_NAME :Train {COMMA} -STR_SV_ROAD_VEHICLE_NAME :Road Vehicle {COMMA} -STR_SV_SHIP_NAME :Ship {COMMA} -STR_SV_AIRCRAFT_NAME :Aircraft {COMMA} +STR_SV_TRAIN_NAME :Train #{COMMA} +STR_SV_ROAD_VEHICLE_NAME :Road Vehicle #{COMMA} +STR_SV_SHIP_NAME :Ship #{COMMA} +STR_SV_AIRCRAFT_NAME :Aircraft #{COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} North @@ -5003,6 +5067,7 @@ STR_FORMAT_BUOY_NAME :{TOWN} Buoy STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Buoy #{COMMA} STR_FORMAT_COMPANY_NUM :(Company {COMMA}) STR_FORMAT_GROUP_NAME :Group {COMMA} +STR_FORMAT_GROUP_VEHICLE_NAME :{GROUP} #{COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :{TOWN} Waypoint STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Waypoint #{COMMA} diff --git a/src/lang/polish.txt b/src/lang/polish.txt index f5a90b0438..3da40c6bd2 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1327,6 +1327,7 @@ STR_GAME_OPTIONS_CURRENCY_NTD :Nowy dolar tajw STR_GAME_OPTIONS_CURRENCY_CNY :Juan chiński (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :Dolar hongkoński (HKD) STR_GAME_OPTIONS_CURRENCY_INR :Rupia Indyjska (INR) +STR_GAME_OPTIONS_CURRENCY_IDR :Rupia Indonezyjska (IDR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Jazda po lewej diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 2cf1ad13cc..8b384ecb36 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -46,15 +46,11 @@ #endif static struct { - HWND main_wnd; ///< Handle to system window. - HBITMAP dib_sect; ///< System bitmap object referencing our rendering buffer. void *buffer_bits; ///< Internal rendering buffer. - HPALETTE gdi_palette; ///< Palette object for 8bpp blitter. int width; ///< Width in pixels of our display surface. int height; ///< Height in pixels of our display surface. int width_org; ///< Original monitor resolution width, before we changed it. int height_org; ///< Original monitor resolution height, before we changed it. - bool fullscreen; ///< Whether to use (true) fullscreen mode. bool has_focus; ///< Does our window have system focus? bool running; ///< Is the main loop running? } _wnd; @@ -76,44 +72,7 @@ static Palette _local_palette; /** Region of the screen that needs redrawing. */ static Rect _dirty_rect; -static void MakePalette() -{ - _cur_palette.first_dirty = 0; - _cur_palette.count_dirty = 256; - _local_palette = _cur_palette; - - LOGPALETTE *pal = (LOGPALETTE*)alloca(sizeof(LOGPALETTE) + (256 - 1) * sizeof(PALETTEENTRY)); - - pal->palVersion = 0x300; - pal->palNumEntries = 256; - - for (uint i = 0; i != 256; i++) { - pal->palPalEntry[i].peRed = _local_palette.palette[i].r; - pal->palPalEntry[i].peGreen = _local_palette.palette[i].g; - pal->palPalEntry[i].peBlue = _local_palette.palette[i].b; - pal->palPalEntry[i].peFlags = 0; - - } - _wnd.gdi_palette = CreatePalette(pal); - if (_wnd.gdi_palette == nullptr) usererror("CreatePalette failed!\n"); -} - -static void UpdatePalette(HDC dc, uint start, uint count) -{ - RGBQUAD rgb[256]; - uint i; - - for (i = 0; i != count; i++) { - rgb[i].rgbRed = _local_palette.palette[start + i].r; - rgb[i].rgbGreen = _local_palette.palette[start + i].g; - rgb[i].rgbBlue = _local_palette.palette[start + i].b; - rgb[i].rgbReserved = 0; - } - - SetDIBColorTable(dc, start, count, rgb); -} - -bool VideoDriver_Win32::ClaimMousePointer() +bool VideoDriver_Win32Base::ClaimMousePointer() { MyShowCursor(false, true); return true; @@ -187,65 +146,28 @@ static uint MapWindowsKey(uint sym) return key; } -static bool AllocateDibSection(int w, int h, bool force = false); - -static void ClientSizeChanged(int w, int h) +/** Colour depth to use for fullscreen display modes. */ +uint8 VideoDriver_Win32Base::GetFullscreenBpp() { - /* allocate new dib section of the new size */ - if (AllocateDibSection(w, h)) { - /* mark all palette colours dirty */ - _cur_palette.first_dirty = 0; - _cur_palette.count_dirty = 256; - _local_palette = _cur_palette; - - BlitterFactory::GetCurrentBlitter()->PostResize(); - - GameSizeChanged(); - } + /* Check modes for the relevant fullscreen bpp */ + return _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); } -#ifdef _DEBUG -/* Keep this function here.. - * It allows you to redraw the screen from within the MSVC debugger */ -int RedrawScreenDebug() -{ - HDC dc, dc2; - static int _fooctr; - HBITMAP old_bmp; - HPALETTE old_palette; - - UpdateWindows(); - - dc = GetDC(_wnd.main_wnd); - dc2 = CreateCompatibleDC(dc); - - old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); - old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); - BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); - SelectPalette(dc, old_palette, TRUE); - SelectObject(dc2, old_bmp); - DeleteDC(dc2); - ReleaseDC(_wnd.main_wnd, dc); - - return _fooctr++; -} -#endif - /** * Instantiate a new window. * @param full_screen Whether to make a full screen window or not. * @return True if the window could be created. */ -bool VideoDriver_Win32::MakeWindow(bool full_screen) +bool VideoDriver_Win32Base::MakeWindow(bool full_screen) { /* full_screen is whether the new window should be fullscreen, * _wnd.fullscreen is whether the current window is. */ _fullscreen = full_screen; /* recreate window? */ - if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) { - DestroyWindow(_wnd.main_wnd); - _wnd.main_wnd = 0; + if ((full_screen || this->fullscreen) && this->main_wnd) { + DestroyWindow(this->main_wnd); + this->main_wnd = 0; } if (full_screen) { @@ -257,13 +179,12 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - settings.dmBitsPerPel = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); + settings.dmBitsPerPel = this->GetFullscreenBpp(); settings.dmPelsWidth = _wnd.width_org; settings.dmPelsHeight = _wnd.height_org; /* Check for 8 bpp support. */ - if (settings.dmBitsPerPel == 8 && - (_support8bpp != S8BPP_HARDWARE || ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)) { + if (settings.dmBitsPerPel == 8 && ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) { settings.dmBitsPerPel = 32; } @@ -282,7 +203,7 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) this->MakeWindow(false); // don't care about the result return false; // the request failed } - } else if (_wnd.fullscreen) { + } else if (this->fullscreen) { /* restore display? */ ChangeDisplaySettings(nullptr, 0); /* restore the resolution */ @@ -296,8 +217,8 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) int w, h; showstyle = SW_SHOWNORMAL; - _wnd.fullscreen = full_screen; - if (_wnd.fullscreen) { + this->fullscreen = full_screen; + if (this->fullscreen) { style = WS_POPUP; SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org); } else { @@ -311,8 +232,8 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) w = r.right - r.left; h = r.bottom - r.top; - if (_wnd.main_wnd != nullptr) { - if (!_window_maximize) SetWindowPos(_wnd.main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE); + if (this->main_wnd != nullptr) { + if (!_window_maximize) SetWindowPos(this->main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE); } else { int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; @@ -320,92 +241,19 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) char window_title[64]; seprintf(window_title, lastof(window_title), "OpenTTD %s", _openttd_revision); - _wnd.main_wnd = CreateWindow(_T("OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), 0); - if (_wnd.main_wnd == nullptr) usererror("CreateWindow failed"); - ShowWindow(_wnd.main_wnd, showstyle); + this->main_wnd = CreateWindow(_T("OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), this); + if (this->main_wnd == nullptr) usererror("CreateWindow failed"); + ShowWindow(this->main_wnd, showstyle); } } BlitterFactory::GetCurrentBlitter()->PostResize(); - GameSizeChanged(); // invalidate all windows, force redraw - return true; // the request succeeded + GameSizeChanged(); + return true; } -/** Do palette animation and blit to the window. */ -void VideoDriver_Win32::Paint() -{ - PerformanceMeasurer framerate(PFE_VIDEO); - - if (IsEmptyRect(_dirty_rect)) return; - - /* Convert update region from logical to device coordinates. */ - POINT pt = {0, 0}; - ClientToScreen(_wnd.main_wnd, &pt); - - RECT r = { _dirty_rect.left, _dirty_rect.top, _dirty_rect.right, _dirty_rect.bottom }; - OffsetRect(&r, pt.x, pt.y); - - /* Create a device context that is clipped to the region we need to draw. - * GetDCEx 'consumes' the update region, so we may not destroy it ourself. */ - HRGN rgn = CreateRectRgnIndirect(&r); - HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN); - - HDC dc2 = CreateCompatibleDC(dc); - HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); - HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); - - if (_cur_palette.count_dirty != 0) { - Blitter *blitter = BlitterFactory::GetCurrentBlitter(); - - switch (blitter->UsePaletteAnimation()) { - case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: - UpdatePalette(dc2, _local_palette.first_dirty, _local_palette.count_dirty); - break; - - case Blitter::PALETTE_ANIMATION_BLITTER: - blitter->PaletteAnimate(_local_palette); - break; - - case Blitter::PALETTE_ANIMATION_NONE: - break; - - default: - NOT_REACHED(); - } - _cur_palette.count_dirty = 0; - } - - BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); - SelectPalette(dc, old_palette, TRUE); - SelectObject(dc2, old_bmp); - DeleteDC(dc2); - - ReleaseDC(_wnd.main_wnd, dc); - - _dirty_rect = {}; -} - -void VideoDriver_Win32::PaintThread() -{ - /* First tell the main thread we're started */ - std::unique_lock lock(*_draw_mutex); - _draw_signal->notify_one(); - - /* Now wait for the first thing to draw! */ - _draw_signal->wait(*_draw_mutex); - - while (_draw_continue) { - this->Paint(); - - /* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */ - GdiFlush(); - - _draw_signal->wait(*_draw_mutex); - } -} - -/* static */ void VideoDriver_Win32::PaintThreadThunk(VideoDriver_Win32 *drv) +/* static */ void VideoDriver_Win32Base::PaintThreadThunk(VideoDriver_Win32Base *drv) { drv->PaintThread(); } @@ -609,13 +457,16 @@ static void CancelIMEComposition(HWND hwnd) HandleTextInput(nullptr, true); } -static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static uint32 keycode = 0; static bool console = false; + VideoDriver_Win32Base *video_driver = (VideoDriver_Win32Base *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + switch (msg) { case WM_CREATE: + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams); _cursor.in_window = false; // Win32 has mouse tracking. SetCompositionPos(hwnd); _imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY); @@ -624,7 +475,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP case WM_PAINT: { RECT r; GetUpdateRect(hwnd, &r, FALSE); - static_cast(VideoDriver::GetInstance())->MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top); + video_driver->MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top); ValidateRect(hwnd, nullptr); return 0; @@ -634,18 +485,9 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP if ((HWND)wParam == hwnd) return 0; FALLTHROUGH; - case WM_QUERYNEWPALETTE: { - HDC hDC = GetWindowDC(hwnd); - HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE); - UINT nChanged = RealizePalette(hDC); - - SelectPalette(hDC, hOldPalette, TRUE); - ReleaseDC(hwnd, hDC); - if (nChanged != 0) { - static_cast(VideoDriver::GetInstance())->MakeDirty(0, 0, _screen.width, _screen.height); - } + case WM_QUERYNEWPALETTE: + video_driver->PaletteChanged(hwnd); return 0; - } case WM_CLOSE: HandleExitGameRequest(); @@ -829,7 +671,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP switch (wParam) { case VK_RETURN: case 'F': // Full Screen on ALT + ENTER/F - ToggleFullScreen(!_wnd.fullscreen); + ToggleFullScreen(!video_driver->fullscreen); return 0; case VK_MENU: // Just ALT @@ -851,7 +693,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP * switched to fullscreen from a maximized state */ _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen)); if (_window_maximize || _fullscreen) _bck_resolution = _cur_resolution; - ClientSizeChanged(LOWORD(lParam), HIWORD(lParam)); + video_driver->ClientSizeChanged(LOWORD(lParam), HIWORD(lParam)); } return 0; @@ -948,11 +790,11 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP bool active = (LOWORD(wParam) != WA_INACTIVE); bool minimized = (HIWORD(wParam) != 0); - if (_wnd.fullscreen) { + if (video_driver->fullscreen) { if (active && minimized) { /* Restore the game window */ ShowWindow(hwnd, SW_RESTORE); - static_cast(VideoDriver::GetInstance())->MakeWindow(true); + video_driver->MakeWindow(true); } else if (!active && !minimized) { /* Minimise the window and restore desktop */ ShowWindow(hwnd, SW_MINIMIZE); @@ -990,43 +832,6 @@ static void RegisterWndClass() if (!RegisterClass(&wnd)) usererror("RegisterClass failed"); } -static bool AllocateDibSection(int w, int h, bool force) -{ - BITMAPINFO *bi; - HDC dc; - uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - - w = std::max(w, 64); - h = std::max(h, 64); - - if (!force && w == _screen.width && h == _screen.height) return false; - - bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); - memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); - bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - - bi->bmiHeader.biWidth = _wnd.width = w; - bi->bmiHeader.biHeight = -(_wnd.height = h); - - bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = bpp; - bi->bmiHeader.biCompression = BI_RGB; - - if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect); - - dc = GetDC(0); - _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, nullptr, 0); - if (_wnd.dib_sect == nullptr) usererror("CreateDIBSection failed"); - ReleaseDC(0, dc); - - _screen.width = w; - _screen.pitch = (bpp == 8) ? Align(w, 4) : w; - _screen.height = h; - _screen.dst_ptr = _wnd.buffer_bits; - - return true; -} - static const Dimension default_resolutions[] = { { 640, 480 }, { 800, 600 }, @@ -1041,20 +846,12 @@ static const Dimension default_resolutions[] = { { 1920, 1200 } }; -static void FindResolutions() +static void FindResolutions(uint8 bpp) { - uint i; - DEVMODEA dm; - - /* Check modes for the relevant fullscreen bpp */ - uint bpp = _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - _resolutions.clear(); - /* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95 - * Doesn't really matter since we don't pass a string anyways, but still - * a letdown */ - for (i = 0; EnumDisplaySettingsA(nullptr, i, &dm) != 0; i++) { + DEVMODE dm; + for (uint i = 0; EnumDisplaySettings(nullptr, i, &dm) != 0; i++) { if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480) continue; if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(dm.dmPelsWidth, dm.dmPelsHeight)) != _resolutions.end()) continue; _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight); @@ -1068,55 +865,36 @@ static void FindResolutions() SortResolutions(); } -static FVideoDriver_Win32 iFVideoDriver_Win32; - -const char *VideoDriver_Win32::Start(const StringList &parm) +void VideoDriver_Win32Base::Initialize() { - if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported"; - this->UpdateAutoResolution(); memset(&_wnd, 0, sizeof(_wnd)); RegisterWndClass(); - - MakePalette(); - - FindResolutions(); - - DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height); + FindResolutions(this->GetFullscreenBpp()); /* fullscreen uses those */ - _wnd.width_org = _cur_resolution.width; - _wnd.height_org = _cur_resolution.height; + _wnd.width = _wnd.width_org = _cur_resolution.width; + _wnd.height = _wnd.height_org = _cur_resolution.height; - AllocateDibSection(_cur_resolution.width, _cur_resolution.height); - this->MakeWindow(_fullscreen); - - MarkWholeScreenDirty(); - - _draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread") && std::thread::hardware_concurrency() > 1; - - return nullptr; + DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height); } -void VideoDriver_Win32::Stop() +void VideoDriver_Win32Base::Stop() { - DeleteObject(_wnd.gdi_palette); - DeleteObject(_wnd.dib_sect); - DestroyWindow(_wnd.main_wnd); + DestroyWindow(this->main_wnd); - if (_wnd.fullscreen) ChangeDisplaySettings(nullptr, 0); + if (this->fullscreen) ChangeDisplaySettings(nullptr, 0); MyShowCursor(true); } - -void VideoDriver_Win32::MakeDirty(int left, int top, int width, int height) +void VideoDriver_Win32Base::MakeDirty(int left, int top, int width, int height) { Rect r = {left, top, left + width, top + height}; _dirty_rect = BoundingRect(_dirty_rect, r); } -void VideoDriver_Win32::CheckPaletteAnim() +void VideoDriver_Win32Base::CheckPaletteAnim() { if (_cur_palette.count_dirty == 0) return; @@ -1124,7 +902,7 @@ void VideoDriver_Win32::CheckPaletteAnim() this->MakeDirty(0, 0, _screen.width, _screen.height); } -void VideoDriver_Win32::InputLoop() +void VideoDriver_Win32Base::InputLoop() { bool old_ctrl_pressed = _ctrl_pressed; bool old_shift_pressed = _shift_pressed; @@ -1160,7 +938,7 @@ void VideoDriver_Win32::InputLoop() if (old_shift_pressed != _shift_pressed) HandleShiftChanged(); } -void VideoDriver_Win32::MainLoop() +void VideoDriver_Win32Base::MainLoop() { MSG mesg; @@ -1180,7 +958,7 @@ void VideoDriver_Win32::MainLoop() this->draw_lock = std::unique_lock(*_draw_mutex); _draw_continue = true; - _draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &VideoDriver_Win32::PaintThreadThunk, this); + _draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &VideoDriver_Win32Base::PaintThreadThunk, this); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { @@ -1239,12 +1017,27 @@ void VideoDriver_Win32::MainLoop() } } -bool VideoDriver_Win32::ChangeResolution(int w, int h) +void VideoDriver_Win32Base::ClientSizeChanged(int w, int h) +{ + /* Allocate backing store of the new size. */ + if (this->AllocateBackingStore(w, h)) { + /* Mark all palette colours dirty. */ + _cur_palette.first_dirty = 0; + _cur_palette.count_dirty = 256; + _local_palette = _cur_palette; + + BlitterFactory::GetCurrentBlitter()->PostResize(); + + GameSizeChanged(); + } +} + +bool VideoDriver_Win32Base::ChangeResolution(int w, int h) { std::unique_lock lock; if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); - if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); + if (_window_maximize) ShowWindow(this->main_wnd, SW_SHOWNORMAL); _wnd.width = _wnd.width_org = w; _wnd.height = _wnd.height_org = h; @@ -1252,7 +1045,7 @@ bool VideoDriver_Win32::ChangeResolution(int w, int h) return this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching } -bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) +bool VideoDriver_Win32Base::ToggleFullscreen(bool full_screen) { std::unique_lock lock; if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); @@ -1260,38 +1053,32 @@ bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) return this->MakeWindow(full_screen); } -bool VideoDriver_Win32::AfterBlitterChange() -{ - assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0); - return AllocateDibSection(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen); -} - -void VideoDriver_Win32::AcquireBlitterLock() +void VideoDriver_Win32Base::AcquireBlitterLock() { if (_draw_mutex != nullptr) _draw_mutex->lock(); } -void VideoDriver_Win32::ReleaseBlitterLock() +void VideoDriver_Win32Base::ReleaseBlitterLock() { if (_draw_mutex != nullptr) _draw_mutex->unlock(); } -void VideoDriver_Win32::EditBoxLostFocus() +void VideoDriver_Win32Base::EditBoxLostFocus() { std::unique_lock lock; if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); - CancelIMEComposition(_wnd.main_wnd); - SetCompositionPos(_wnd.main_wnd); - SetCandidatePos(_wnd.main_wnd); + CancelIMEComposition(this->main_wnd); + SetCompositionPos(this->main_wnd); + SetCandidatePos(this->main_wnd); } -Dimension VideoDriver_Win32::GetScreenSize() const +Dimension VideoDriver_Win32Base::GetScreenSize() const { return { static_cast(GetSystemMetrics(SM_CXSCREEN)), static_cast(GetSystemMetrics(SM_CYSCREEN)) }; } -float VideoDriver_Win32::GetDPIScale() +float VideoDriver_Win32Base::GetDPIScale() { typedef UINT (WINAPI *PFNGETDPIFORWINDOW)(HWND hwnd); typedef UINT (WINAPI *PFNGETDPIFORSYSTEM)(VOID); @@ -1312,14 +1099,14 @@ float VideoDriver_Win32::GetDPIScale() UINT cur_dpi = 0; - if (cur_dpi == 0 && _GetDpiForWindow != nullptr && _wnd.main_wnd != nullptr) { + if (cur_dpi == 0 && _GetDpiForWindow != nullptr && this->main_wnd != nullptr) { /* Per window DPI is supported since Windows 10 Ver 1607. */ - cur_dpi = _GetDpiForWindow(_wnd.main_wnd); + cur_dpi = _GetDpiForWindow(this->main_wnd); } - if (cur_dpi == 0 && _GetDpiForMonitor != nullptr && _wnd.main_wnd != nullptr) { + if (cur_dpi == 0 && _GetDpiForMonitor != nullptr && this->main_wnd != nullptr) { /* Per monitor is supported since Windows 8.1. */ UINT dpiX, dpiY; - if (SUCCEEDED(_GetDpiForMonitor(MonitorFromWindow(_wnd.main_wnd, MONITOR_DEFAULTTOPRIMARY), 0 /* MDT_EFFECTIVE_DPI */, &dpiX, &dpiY))) { + if (SUCCEEDED(_GetDpiForMonitor(MonitorFromWindow(this->main_wnd, MONITOR_DEFAULTTOPRIMARY), 0 /* MDT_EFFECTIVE_DPI */, &dpiX, &dpiY))) { cur_dpi = dpiX; // X and Y are always identical. } } @@ -1331,13 +1118,211 @@ float VideoDriver_Win32::GetDPIScale() return cur_dpi > 0 ? cur_dpi / 96.0f : 1.0f; // Default Windows DPI value is 96. } -bool VideoDriver_Win32::LockVideoBuffer() +bool VideoDriver_Win32Base::LockVideoBuffer() { if (_draw_threaded) this->draw_lock.lock(); return true; } -void VideoDriver_Win32::UnlockVideoBuffer() +void VideoDriver_Win32Base::UnlockVideoBuffer() { if (_draw_threaded) this->draw_lock.unlock(); } + + +static FVideoDriver_Win32GDI iFVideoDriver_Win32GDI; + +const char *VideoDriver_Win32GDI::Start(const StringList ¶m) +{ + if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported"; + + this->Initialize(); + + this->MakePalette(); + this->AllocateBackingStore(_cur_resolution.width, _cur_resolution.height); + this->MakeWindow(_fullscreen); + + MarkWholeScreenDirty(); + + _draw_threaded = !GetDriverParam(param, "no_threads") && !GetDriverParam(param, "no_thread") && std::thread::hardware_concurrency() > 1; + + return nullptr; +} + +void VideoDriver_Win32GDI::Stop() +{ + DeleteObject(this->gdi_palette); + DeleteObject(this->dib_sect); + + this->VideoDriver_Win32Base::Stop(); +} + +bool VideoDriver_Win32GDI::AllocateBackingStore(int w, int h, bool force) +{ + uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); + + w = std::max(w, 64); + h = std::max(h, 64); + + if (!force && w == _screen.width && h == _screen.height) return false; + + BITMAPINFO *bi = (BITMAPINFO *)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); + memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + bi->bmiHeader.biWidth = _wnd.width = w; + bi->bmiHeader.biHeight = -(_wnd.height = h); + + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = bpp; + bi->bmiHeader.biCompression = BI_RGB; + + if (this->dib_sect) DeleteObject(this->dib_sect); + + HDC dc = GetDC(0); + this->dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID **)&_wnd.buffer_bits, nullptr, 0); + if (this->dib_sect == nullptr) usererror("CreateDIBSection failed"); + ReleaseDC(0, dc); + + _screen.width = w; + _screen.pitch = (bpp == 8) ? Align(w, 4) : w; + _screen.height = h; + _screen.dst_ptr = _wnd.buffer_bits; + + return true; +} + +bool VideoDriver_Win32GDI::AfterBlitterChange() +{ + assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0); + return this->AllocateBackingStore(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen); +} + +void VideoDriver_Win32GDI::MakePalette() +{ + _cur_palette.first_dirty = 0; + _cur_palette.count_dirty = 256; + _local_palette = _cur_palette; + + LOGPALETTE *pal = (LOGPALETTE*)alloca(sizeof(LOGPALETTE) + (256 - 1) * sizeof(PALETTEENTRY)); + + pal->palVersion = 0x300; + pal->palNumEntries = 256; + + for (uint i = 0; i != 256; i++) { + pal->palPalEntry[i].peRed = _local_palette.palette[i].r; + pal->palPalEntry[i].peGreen = _local_palette.palette[i].g; + pal->palPalEntry[i].peBlue = _local_palette.palette[i].b; + pal->palPalEntry[i].peFlags = 0; + + } + this->gdi_palette = CreatePalette(pal); + if (this->gdi_palette == nullptr) usererror("CreatePalette failed!\n"); +} + +void VideoDriver_Win32GDI::UpdatePalette(HDC dc, uint start, uint count) +{ + RGBQUAD rgb[256]; + + for (uint i = 0; i != count; i++) { + rgb[i].rgbRed = _local_palette.palette[start + i].r; + rgb[i].rgbGreen = _local_palette.palette[start + i].g; + rgb[i].rgbBlue = _local_palette.palette[start + i].b; + rgb[i].rgbReserved = 0; + } + + SetDIBColorTable(dc, start, count, rgb); +} + +void VideoDriver_Win32GDI::PaletteChanged(HWND hWnd) +{ + HDC hDC = GetWindowDC(hWnd); + HPALETTE hOldPalette = SelectPalette(hDC, this->gdi_palette, FALSE); + UINT nChanged = RealizePalette(hDC); + + SelectPalette(hDC, hOldPalette, TRUE); + ReleaseDC(hWnd, hDC); + if (nChanged != 0) this->MakeDirty(0, 0, _screen.width, _screen.height); +} + +void VideoDriver_Win32GDI::Paint() +{ + PerformanceMeasurer framerate(PFE_VIDEO); + + if (IsEmptyRect(_dirty_rect)) return; + + HDC dc = GetDC(this->main_wnd); + HDC dc2 = CreateCompatibleDC(dc); + + HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, this->dib_sect); + HPALETTE old_palette = SelectPalette(dc, this->gdi_palette, FALSE); + + if (_cur_palette.count_dirty != 0) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + this->UpdatePalette(dc2, _local_palette.first_dirty, _local_palette.count_dirty); + break; + + case Blitter::PALETTE_ANIMATION_BLITTER: + blitter->PaletteAnimate(_local_palette); + break; + + case Blitter::PALETTE_ANIMATION_NONE: + break; + + default: + NOT_REACHED(); + } + _cur_palette.count_dirty = 0; + } + + BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); + SelectPalette(dc, old_palette, TRUE); + SelectObject(dc2, old_bmp); + DeleteDC(dc2); + + ReleaseDC(this->main_wnd, dc); + + _dirty_rect = {}; +} + +void VideoDriver_Win32GDI::PaintThread() +{ + /* First tell the main thread we're started */ + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); + + /* Now wait for the first thing to draw! */ + _draw_signal->wait(*_draw_mutex); + + while (_draw_continue) { + this->Paint(); + + /* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */ + GdiFlush(); + + _draw_signal->wait(*_draw_mutex); + } +} + + +#ifdef _DEBUG +/* Keep this function here.. + * It allows you to redraw the screen from within the MSVC debugger */ +/* static */ int VideoDriver_Win32GDI::RedrawScreenDebug() +{ + static int _fooctr; + + _screen.dst_ptr = _wnd.buffer_bits; + UpdateWindows(); + + VideoDriver_Win32GDI *drv = static_cast(VideoDriver::GetInstance()); + + drv->Paint(); + GdiFlush(); + + return _fooctr++; +} +#endif diff --git a/src/video/win32_v.h b/src/video/win32_v.h index 6954770855..b50f4e7a5a 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -12,10 +12,10 @@ #include "video_driver.hpp" -/** The video driver for windows. */ -class VideoDriver_Win32 : public VideoDriver { +/** Base class for Windows video drivers. */ +class VideoDriver_Win32Base : public VideoDriver { public: - const char *Start(const StringList ¶m) override; + VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false) {} void Stop() override; @@ -27,8 +27,6 @@ public: bool ToggleFullscreen(bool fullscreen) override; - bool AfterBlitterChange() override; - void AcquireBlitterLock() override; void ReleaseBlitterLock() override; @@ -37,31 +35,71 @@ public: void EditBoxLostFocus() override; - const char *GetName() const override { return "win32"; } - - bool MakeWindow(bool full_screen); - protected: + HWND main_wnd; ///< Handle to system window. + bool fullscreen; ///< Whether to use (true) fullscreen mode. + Dimension GetScreenSize() const override; float GetDPIScale() override; void InputLoop() override; bool LockVideoBuffer() override; void UnlockVideoBuffer() override; - void Paint() override; - void PaintThread() override; void CheckPaletteAnim() override; + void Initialize(); + bool MakeWindow(bool full_screen); + virtual uint8 GetFullscreenBpp(); + + /** (Re-)create the backing store. */ + virtual bool AllocateBackingStore(int w, int h, bool force = false) = 0; + /** Palette of the window has changed. */ + virtual void PaletteChanged(HWND hWnd) = 0; + private: std::unique_lock draw_lock; - static void PaintThreadThunk(VideoDriver_Win32 *drv); + void ClientSizeChanged(int w, int h); + + static void PaintThreadThunk(VideoDriver_Win32Base *drv); + + friend LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +}; +/** The GDI video driver for windows. */ +class VideoDriver_Win32GDI : public VideoDriver_Win32Base { +public: + VideoDriver_Win32GDI() : dib_sect(nullptr), gdi_palette(nullptr) {} + + const char *Start(const StringList ¶m) override; + + void Stop() override; + + bool AfterBlitterChange() override; + + const char *GetName() const override { return "win32"; } + +protected: + HBITMAP dib_sect; ///< System bitmap object referencing our rendering buffer. + HPALETTE gdi_palette; ///< Palette object for 8bpp blitter. + + void Paint() override; + void PaintThread() override; + + bool AllocateBackingStore(int w, int h, bool force = false) override; + void PaletteChanged(HWND hWnd) override; + void MakePalette(); + void UpdatePalette(HDC dc, uint start, uint count); + +#ifdef _DEBUG +public: + static int RedrawScreenDebug(); +#endif }; /** The factory for Windows' video driver. */ -class FVideoDriver_Win32 : public DriverFactoryBase { +class FVideoDriver_Win32GDI : public DriverFactoryBase { public: - FVideoDriver_Win32() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32", "Win32 GDI Video Driver") {} - Driver *CreateInstance() const override { return new VideoDriver_Win32(); } + FVideoDriver_Win32GDI() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32", "Win32 GDI Video Driver") {} + Driver *CreateInstance() const override { return new VideoDriver_Win32GDI(); } }; #endif /* VIDEO_WIN32_H */