mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
6 Commits
9a27fff66c
...
5459c78603
Author | SHA1 | Date |
---|---|---|
|
5459c78603 | |
|
ae917cb8c6 | |
|
e6b45731c0 | |
|
24f173e7a8 | |
|
ccfb40944b | |
|
5b0e9f82d5 |
|
@ -449,6 +449,7 @@ if(WIN32)
|
|||
psapi
|
||||
winhttp
|
||||
bcrypt
|
||||
xinput
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ void HandleTextInput(std::string_view str, bool marked = false,
|
|||
std::optional<size_t> insert_location = std::nullopt, std::optional<size_t> replacement_end = std::nullopt);
|
||||
void HandleCtrlChanged();
|
||||
void HandleMouseEvents();
|
||||
void HandleGamepadScrolling(int stick_x, int stick_y, int max_axis_value);
|
||||
void UpdateWindows();
|
||||
void ChangeGameSpeed(bool enable_fast_forward);
|
||||
|
||||
|
|
|
@ -1700,6 +1700,25 @@ STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zoom map
|
|||
STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Scroll map
|
||||
STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Off
|
||||
|
||||
STR_CONFIG_SETTING_GAMEPAD_STICK_SELECTION :Gamepad stick for scrolling: {STRING2}
|
||||
STR_CONFIG_SETTING_GAMEPAD_STICK_SELECTION_HELPTEXT :Select which analog stick to use for map scrolling
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_GAMEPAD_STICK_DISABLED :Disabled
|
||||
STR_CONFIG_SETTING_GAMEPAD_STICK_LEFT :Left stick
|
||||
STR_CONFIG_SETTING_GAMEPAD_STICK_RIGHT :Right stick
|
||||
|
||||
STR_CONFIG_SETTING_GAMEPAD_DEADZONE :Gamepad deadzone: {STRING2}%
|
||||
STR_CONFIG_SETTING_GAMEPAD_DEADZONE_HELPTEXT :Minimum stick movement required before scrolling starts (0-100%)
|
||||
|
||||
STR_CONFIG_SETTING_GAMEPAD_SENSITIVITY :Gamepad sensitivity: {STRING2}
|
||||
STR_CONFIG_SETTING_GAMEPAD_SENSITIVITY_HELPTEXT :Control the sensitivity of gamepad analog stick scrolling
|
||||
|
||||
STR_CONFIG_SETTING_GAMEPAD_INVERT_X :Invert gamepad X-axis: {STRING2}
|
||||
STR_CONFIG_SETTING_GAMEPAD_INVERT_X_HELPTEXT :Invert the horizontal axis movement of the gamepad analog stick
|
||||
|
||||
STR_CONFIG_SETTING_GAMEPAD_INVERT_Y :Invert gamepad Y-axis: {STRING2}
|
||||
STR_CONFIG_SETTING_GAMEPAD_INVERT_Y_HELPTEXT :Invert the vertical axis movement of the gamepad analog stick
|
||||
|
||||
STR_CONFIG_SETTING_OSK_ACTIVATION :On screen keyboard: {STRING2}
|
||||
STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Select the method to open the on screen keyboard for entering text into editboxes only using the pointing device. This is meant for small devices without actual keyboard
|
||||
###length 4
|
||||
|
|
|
@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}năm
|
|||
STR_UNITS_PERIODS :{NUM}{NBSP}kỳ
|
||||
|
||||
STR_LIST_SEPARATOR :,{SPACE}
|
||||
STR_TRUNCATION_ELLIPSIS :...
|
||||
|
||||
# Common window strings
|
||||
STR_LIST_FILTER_TITLE :{BLACK}Lọc:
|
||||
|
@ -285,7 +286,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Đóng c
|
|||
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Tiêu đề cửa sổ - kéo nó để di chuyển cửa số
|
||||
STR_TOOLTIP_SHADE :{BLACK}Thu gọn cửa sổ - Chỉ hiển thị thanh tiêu đề
|
||||
STR_TOOLTIP_DEBUG :{BLACK}Hiện thông tin debug của NewGRF
|
||||
STR_TOOLTIP_DEFSIZE :{BLACK}Chuyển cửa sổ về kích thước mặc định. Ctrl+Click để lưu kích thước hiện tại làm mặc định
|
||||
STR_TOOLTIP_DEFSIZE :{BLACK}Chuyển cửa sổ về kích thước mặc định. Ctrl+Click để lưu kích thước hiện tại làm mặc định. Ctri+Click kép để thiết lập lại mặc định cũ.
|
||||
STR_TOOLTIP_STICKY :{BLACK}Đánh dấu không-thể-đóng khi bấm nút "Đóng Tất Cả Cửa Sổ". Ctrl+Click để lưu thành trạng thái mặc định
|
||||
STR_TOOLTIP_RESIZE :{BLACK}Click và kéo để thay đổi kích thước cửa sổ
|
||||
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Bật kích cỡ cửa sổ lớn/nhỏ
|
||||
|
@ -451,6 +452,12 @@ STR_SETTINGS_MENU_SANDBOX_OPTIONS :Tuỳ chọn Sa
|
|||
STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Thiết lập hiệu ứng trong suốt
|
||||
STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Hiển thị tên thị trấn
|
||||
STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Hiển thị tên nhà ga
|
||||
STR_SETTINGS_MENU_STATION_NAMES_TRAIN :Ga tàu
|
||||
STR_SETTINGS_MENU_STATION_NAMES_LORRY :Trạm xe tải
|
||||
STR_SETTINGS_MENU_STATION_NAMES_BUS :Trạm xe buýt
|
||||
STR_SETTINGS_MENU_STATION_NAMES_SHIP :Cảng
|
||||
STR_SETTINGS_MENU_STATION_NAMES_PLANE :Sân bay
|
||||
STR_SETTINGS_MENU_STATION_NAMES_GHOST :Trạm ma
|
||||
STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Hiển thị tên điểm mốc
|
||||
STR_SETTINGS_MENU_SIGNS_DISPLAYED :Hiển thị ký hiệu
|
||||
STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Hiển thị biển hiệu và tên của đối thủ
|
||||
|
@ -627,8 +634,11 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Không h
|
|||
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Bật/tắt đồ thị cho hàng hóa này
|
||||
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
|
||||
|
||||
STR_GRAPH_INDUSTRY_CAPTION :{WHITE}{INDUSTRY} - Lịch sử hàng hóa
|
||||
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Đã cung cấp
|
||||
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Đã vận chuyển
|
||||
STR_GRAPH_INDUSTRY_RANGE_DELIVERED :Đã giao
|
||||
STR_GRAPH_INDUSTRY_RANGE_WAITING :Đang chờ...
|
||||
|
||||
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Hiện chi tiết đánh giá chỉ số năng suất
|
||||
|
||||
|
@ -958,11 +968,14 @@ STR_GAME_OPTIONS_TAB_SOUND :Âm thanh
|
|||
STR_GAME_OPTIONS_TAB_SOUND_TOOLTIP :Lựa chọn thiết lập cho âm thanh và nhạc
|
||||
STR_GAME_OPTIONS_TAB_SOCIAL :Xã hội
|
||||
STR_GAME_OPTIONS_TAB_SOCIAL_TOOLTIP :Chọn thiết lập các tích hợp xã hội
|
||||
STR_GAME_OPTIONS_TAB_ADVANCED :Tùy chọn nâng cao
|
||||
STR_GAME_OPTIONS_TAB_ADVANCED_TOOLTIP :Thay đổi tùy chọn nâng cao
|
||||
|
||||
STR_GAME_OPTIONS_VOLUME :Âm lượng
|
||||
STR_GAME_OPTIONS_SFX_VOLUME :Hiệu ứng âm thanh
|
||||
STR_GAME_OPTIONS_MUSIC_VOLUME :Âm nhạc
|
||||
|
||||
STR_GAME_OPTIONS_SETTING :{STRING}: {ORANGE}{STRING}
|
||||
|
||||
STR_GAME_OPTIONS_VOLUME_MARK :{NUM}%
|
||||
|
||||
|
@ -1016,6 +1029,7 @@ STR_GAME_OPTIONS_CURRENCY_IDR :Rupiah Indonesi
|
|||
STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysia
|
||||
STR_GAME_OPTIONS_CURRENCY_LVL :Lát-vi-a Lats
|
||||
STR_GAME_OPTIONS_CURRENCY_PTE :Escudo Bồ Đào Nha
|
||||
STR_GAME_OPTIONS_CURRENCY_UAH :Hryvnia Ukraina
|
||||
|
||||
STR_GAME_OPTIONS_AUTOSAVE_FRAME :Lưu tự động
|
||||
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :Lựa chọn khoảng thời gian tự động lưu
|
||||
|
@ -1049,6 +1063,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :Đánh dấu v
|
|||
|
||||
STR_GAME_OPTIONS_VIDEO_DRIVER_INFO :Trình điều khiển hiện tại: {STRING}
|
||||
|
||||
STR_GAME_OPTIONS_INTERFACE :Giao diện
|
||||
|
||||
STR_GAME_OPTIONS_GUI_SCALE_FRAME :Kích thước giao diện
|
||||
STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :Kéo thanh trượt để điều chỉnh kích thước giao diện. Giữ Ctrl để điều chỉnh liên tục
|
||||
|
@ -1073,6 +1088,7 @@ STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :Sẽ mở trìn
|
|||
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :Xem trước kết quả khảo sát
|
||||
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :Hiển thị kết quả khảo sát ở ván chơi hiện tại
|
||||
|
||||
STR_GAME_OPTIONS_DISPLAY :Hiển thị
|
||||
|
||||
STR_GAME_OPTIONS_REFRESH_RATE :Tần số quét màn hình
|
||||
STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :Chọn tần số quét màn hình
|
||||
|
@ -1094,7 +1110,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :Thông tin thê
|
|||
STR_GAME_OPTIONS_ONLINE_CONTENT :Tải Nội Dung
|
||||
STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Kiểm tra những nội dung mới & cập nhật để tải về
|
||||
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :{LTBLUE}(không có plugins được cài đặt để tích hợp vào nền tảng xã hội)
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :(không có plugins được cài đặt để tích hợp vào nền tảng xã hội)
|
||||
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING})
|
||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Nền tảng:
|
||||
|
@ -1288,6 +1304,9 @@ STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Lãi xuất vay
|
|||
STR_CONFIG_SETTING_RUNNING_COSTS :Chi phí hoạt động: {STRING}
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Thiết lập mức độ tính chi phí bảo trì và vận hành đối với phương tiện và hạ tầng giao thông
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_LOW :Thấp
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_MEDIUM :Trung bình
|
||||
STR_CONFIG_SETTING_RUNNING_COSTS_HIGH :Cao
|
||||
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Tốc độ xây dựng: {STRING}
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Giới hạn hành động xây dựng của AI
|
||||
|
@ -1310,6 +1329,9 @@ STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Không có tr
|
|||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Chi phí xây dựng: {STRING}
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Thiết lập mức độ xây dựng và chi phí mua sắm
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_LOW :Thấp
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_MEDIUM :Trung bình
|
||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HIGH :Cao
|
||||
|
||||
STR_CONFIG_SETTING_RECESSIONS :Suy thoái: {STRING}
|
||||
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Nếu bật, thì các đợt suy thoái sẽ xảy ra vài năm một lần. Trong suy thoái tất cả sản xuất sẽ giảm mạnh (và sẽ trở lại như cũ sau khi suy thoái kết thúc)
|
||||
|
@ -1979,8 +2001,12 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :không cho phé
|
|||
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :cho phép
|
||||
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :cho phép, tùy chọn bố trí đô thị
|
||||
|
||||
STR_CONFIG_SETTING_HOUSE_PLACER :Đật từng ngôi nhà: {STRING}
|
||||
STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Bật tùy chọn này cho phép người chơi đặt nhà cửa bằng tay
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN :Không cho phép
|
||||
STR_CONFIG_SETTING_HOUSE_PLACER_ALLOWED :Cho phép
|
||||
STR_CONFIG_SETTING_HOUSE_PLACER_FULLY_CONSTRUCTED :Cho phép, đã hoàn thành thi công
|
||||
|
||||
STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Nhu cầu vận chuyển hàng đô thị: {STRING}
|
||||
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Lượng hàng hoá cần vận chuyển ở trong đô thị, tỉ lệ với tổng dân số của độ thị.{}Tăng tỉ lệ bình phương: một đô thị to gấp 2 sẽ tăng 4 lần số hành khách.{}Tăng tỉ lệ thuận: một đô thị tăng gấp 2 sẽ tăng gấp 2 lần số hành khách
|
||||
|
@ -2009,7 +2035,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Giới hạn s
|
|||
STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Số lượng cửa sổ chưa neo (tối đa) trước khi tự động đóng để nhường chỗ khi mở cửa sổ mới
|
||||
STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA}
|
||||
###setting-zero-is-special
|
||||
STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :tắt
|
||||
STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Tắt
|
||||
|
||||
STR_CONFIG_SETTING_ZOOM_MIN :Độ phóng to tối đa: {STRING}
|
||||
STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Độ phóng to tối đa của cửa sổ. Độ càng cao thì yêu cầu bộ nhớ càng nhiều
|
||||
|
@ -2061,9 +2087,9 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Loại hàng h
|
|||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Chế độ phân phối đối với các loại hàng hóa mặc định: {STRING}
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Không đối xứng" có nghĩa là số lượng hàng hóa tùy ý có thể được gửi theo một trong hai hướng. "Thủ công" có nghĩa là những loại hàng hóa đó sẽ không được phân phối tự động
|
||||
###length 3
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :bằng tay
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :bất đối xứng
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :đối xứng
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :Bằng tay
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :Bất đối xứng
|
||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :Đối xứng
|
||||
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Độ chính xác phân phối: {STRING}
|
||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Mức chính xác tính toán đồ thị, nếu giá trị càng cao càng tốn CPU và trò chơi có thể chậm phản ứng, tuy nhiên giá trị thấp sẽ khiến việc phân phối sẽ giảm sự chính xác và bạn sẽ thấy sự khác biệt là hàng hóa không gửi đến chỗ cần đến
|
||||
|
@ -2124,7 +2150,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m)
|
|||
STR_CONFIG_SETTING_LOCALISATION :Tiêu Chuẩn Đo Lường
|
||||
STR_CONFIG_SETTING_GRAPHICS :Đồ họa
|
||||
STR_CONFIG_SETTING_SOUND :Âm thanh
|
||||
STR_CONFIG_SETTING_INTERFACE :Giao Diện
|
||||
STR_CONFIG_SETTING_INTERFACE :Giao diện
|
||||
STR_CONFIG_SETTING_INTERFACE_GENERAL :Tổng quát
|
||||
STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :Vùng nhìn
|
||||
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :Xây Dựng
|
||||
|
@ -2178,6 +2204,8 @@ STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION :{WHITE}... khô
|
|||
STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH :{WHITE}... trình điều khiển GPU đã làm trò chơi bị lỗi. Tăng tốc phần cứng đã được tắt
|
||||
|
||||
# Intro window
|
||||
STR_INTRO_CAPTION :{WHITE}OpenTTD
|
||||
STR_INTRO_VERSION :OpenTTD {REV}
|
||||
|
||||
STR_INTRO_NEW_GAME :{BLACK}Màn Chơi Mới
|
||||
STR_INTRO_LOAD_GAME :{BLACK}Nạp Ván Chơi
|
||||
|
@ -2311,16 +2339,19 @@ STR_FACE_SIMPLE_TOOLTIP :{BLACK}Trình c
|
|||
STR_FACE_LOAD :{BLACK}Nạp
|
||||
STR_FACE_LOAD_TOOLTIP :{BLACK}Chọn vẻ mặt ưa thích
|
||||
STR_FACE_LOAD_DONE :{WHITE}Vẻ mặt ưa thích đã được nạp từ file thiết lập của OpenTTD.
|
||||
STR_FACE_FACECODE :{BLACK}Khuôn mặt thứ.
|
||||
STR_FACE_FACECODE_TOOLTIP :{BLACK}Xem và/hoặc sửa số vẻ mặt của chủ tịch công ty
|
||||
STR_FACE_FACECODE_CAPTION :{WHITE}Xem và/hoặc chọn số bộ mặt người chơi
|
||||
STR_FACE_FACECODE_SET :{WHITE}Mã số gương mặt mới được thiết lập.
|
||||
STR_FACE_FACECODE_ERR :{WHITE}Không thể thiết lập mã số gương mặt - mã số phải trong khoảng từ 0 đến 4,294,967,295!
|
||||
STR_FACE_FACECODE :{BLACK}Mã số khuôn mặt
|
||||
STR_FACE_FACECODE_TOOLTIP :{BLACK}Xem và/hoặc sửa mã số gương mặt của chủ tịch công ty
|
||||
STR_FACE_FACECODE_CAPTION :{WHITE}Xem và/hoặc chọn mã số gương mặt người chơi
|
||||
STR_FACE_FACECODE_SET :{WHITE}Gương mặt người chơi mới được thiết lập.
|
||||
STR_FACE_FACECODE_ERR :{WHITE}Không thể thiết lập mã số gương mặt - Nhãn và mã số phải hợp lệ
|
||||
STR_FACE_SAVE :{BLACK}Lưu
|
||||
STR_FACE_SAVE_TOOLTIP :{BLACK}Lưu gương mặt yêu thích
|
||||
STR_FACE_SAVE_DONE :{WHITE}Gương mặt yêu thích này sẽ được lưu lại trong tập tin cấu hình OpenTTD .
|
||||
STR_FACE_SETTING_TOGGLE :{STRING} {ORANGE}{STRING}
|
||||
STR_FACE_SETTING_NUMERIC :{STRING} {ORANGE}{NUM} / {NUM}
|
||||
STR_FACE_YES :Đồng ý
|
||||
STR_FACE_NO :Không
|
||||
STR_FACE_STYLE :Kiểu:
|
||||
STR_FACE_HAIR :Tóc:
|
||||
STR_FACE_EYEBROWS :Lông mày:
|
||||
STR_FACE_EYECOLOUR :Màu mắt:
|
||||
|
@ -2607,7 +2638,7 @@ STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} r
|
|||
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} đã đổi tên thành {STRING}
|
||||
STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} tặng {CURRENCY_LONG} cho {STRING}
|
||||
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Server kết thúc phiên
|
||||
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Server khởi động lại...{}Xin chờ...
|
||||
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Server khởi động lại...{}{}Xin chờ...
|
||||
STR_NETWORK_MESSAGE_KICKED :*** {STRING} đã bị đá khỏi ván chơi. Lý do: ({STRING})
|
||||
|
||||
STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Đăng ký server thất bại
|
||||
|
@ -2793,6 +2824,10 @@ STR_PICKER_MODE_USED_TOOLTIP :Bật/tắt hi
|
|||
STR_PICKER_MODE_SAVED :Đã lưu
|
||||
STR_PICKER_MODE_SAVED_TOOLTIP :Bật/tắt hiển thị những hạng mục được lưu
|
||||
|
||||
STR_PICKER_PREVIEW_SHRINK :-
|
||||
STR_PICKER_PREVIEW_SHRINK_TOOLTIP :Giảm chiều cao của ảnh xem trước. Ctrl+Click để giảm đến mức tối thiểu
|
||||
STR_PICKER_PREVIEW_EXPAND :+
|
||||
STR_PICKER_PREVIEW_EXPAND_TOOLTIP :Tăng chiều cao của ảnh xem trước. Ctrl+Click để tăng đến mức tối đa
|
||||
|
||||
STR_PICKER_STATION_CLASS_TOOLTIP :Chọn loại ga bến cần hiển thị
|
||||
STR_PICKER_STATION_TYPE_TOOLTIP :Chọn loại ga bến để xây. Ctrl+Click để thêm hoặc bớt vào danh sách lưu
|
||||
|
@ -2816,6 +2851,7 @@ STR_HOUSE_PICKER_YEARS_FROM :{BLACK}Năm: {O
|
|||
STR_HOUSE_PICKER_YEARS_UNTIL :{BLACK}Năm: {ORANGE}Đến {NUM}
|
||||
STR_HOUSE_PICKER_SIZE :{BLACK}Kích thước: {ORANGE}{NUM}x{NUM} ô
|
||||
STR_HOUSE_PICKER_CARGO_ACCEPTED :{BLACK}Hàng hóa được chấp nhận: {ORANGE}
|
||||
STR_HOUSE_PICKER_CARGO_PRODUCED :{BLACK}Hàng hóa cung cấp: {ORANGE}{CARGO_LIST}
|
||||
|
||||
STR_HOUSE_PICKER_CLASS_ZONE1 :Ngoài rìa
|
||||
STR_HOUSE_PICKER_CLASS_ZONE2 :Ngoại ô
|
||||
|
@ -2824,6 +2860,7 @@ STR_HOUSE_PICKER_CLASS_ZONE4 :Phía trong ngo
|
|||
STR_HOUSE_PICKER_CLASS_ZONE5 :Nội thành
|
||||
|
||||
STR_HOUSE_PICKER_PROTECT_TITLE :Ngăn chặn nâng cấp
|
||||
STR_HOUSE_PICKER_PROTECT_TOOLTIP :Chọn nếu ngôi nhà này có được bảo vệ khỏi việc bị thay thế hay không khi thị trấn phát triển
|
||||
STR_HOUSE_PICKER_PROTECT_OFF :Tắt
|
||||
STR_HOUSE_PICKER_PROTECT_ON :Bật
|
||||
|
||||
|
@ -3031,6 +3068,11 @@ STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Chọn q
|
|||
STR_FOUND_TOWN_CITY :{BLACK}Đô thị
|
||||
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Thành phố phát triển nhanh hơn thị trấn{}Tuỳ thuộc thiết lập, chúng lớn hơn khi khai sinh
|
||||
|
||||
STR_FOUND_TOWN_EXPAND_MODE :{YELLOW}Mở rộng thị trấn:
|
||||
STR_FOUND_TOWN_EXPAND_BUILDINGS :Công trình
|
||||
STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP :Tăng số công trình của thị trấn
|
||||
STR_FOUND_TOWN_EXPAND_ROADS :Đường sá
|
||||
STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP :Tăng số đường sá của thị trấn
|
||||
|
||||
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Quy hoạch đường đô thị:
|
||||
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Chọn để quy hoạch đường bộ trong đô thị
|
||||
|
@ -3103,6 +3145,8 @@ STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Kiểu x
|
|||
STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Giới hạn tốc độ đường ray: {LTBLUE}{VELOCITY}
|
||||
STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Hạn chế tốc độ đường bộ: {LTBLUE}{VELOCITY}
|
||||
STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tốc độ xe điện giới hạn: {LTBLUE}{VELOCITY}
|
||||
STR_LAND_AREA_INFORMATION_TOWN_CAN_UPGRADE :{BLACK}Nâng cấp thị trấn: {LTBLUE}Có thể
|
||||
STR_LAND_AREA_INFORMATION_TOWN_CANNOT_UPGRADE :{BLACK}Nâng cấp thị trấn: {LTBLUE}Không thể
|
||||
|
||||
# Description of land area of different tiles
|
||||
STR_LAI_CLEAR_DESCRIPTION_ROCKS :Đá
|
||||
|
@ -3111,6 +3155,9 @@ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Đất trống
|
|||
STR_LAI_CLEAR_DESCRIPTION_GRASS :Bãi cỏ
|
||||
STR_LAI_CLEAR_DESCRIPTION_FIELDS :Cánh đồng
|
||||
STR_LAI_CLEAR_DESCRIPTION_DESERT :Hoang mạc
|
||||
STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROCKS :Đá có tuyết phủ
|
||||
STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROUGH_LAND :Đất gồ ghề có tuyết phủ
|
||||
STR_LAI_CLEAR_DESCRIPTION_SNOWY_GRASS :Cỏ có tuyết phủ
|
||||
|
||||
STR_LAI_RAIL_DESCRIPTION_TRACK :Đường ray
|
||||
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Đường ray với đèn hiệu khóa
|
||||
|
@ -3579,17 +3626,17 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Đã t
|
|||
STR_NEWGRF_LIST_MISSING :{RED}Thiếu files
|
||||
|
||||
# NewGRF 'it's broken' warnings
|
||||
STR_NEWGRF_BROKEN :{WHITE}Hoạt động của NewGRF '{0:STRING}' có thể gây mất đồng bộ hoặc bị treo.
|
||||
STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Trạng thái đầu kéo '{1:ENGINE}' được thay đổi khi không ở trong xưởng sửa chữa.
|
||||
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Nó cắt ngắn độ dài của đoàn tàu '{1:ENGINE}' nếu không ở trong xưởng.
|
||||
STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Sức chứa của phương tiện bị thay đổi '{1:ENGINE}' khi không ở trong xưởng hoặc vì cải biến
|
||||
STR_NEWGRF_BROKEN :{WHITE}Hoạt động của NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' có thể gây mất đồng bộ hoặc bị treo.
|
||||
STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Trạng thái đầu kéo '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' được thay đổi khi không ở trong xưởng sửa chữa.
|
||||
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Nó cắt ngắn độ dài của đoàn tàu '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' nếu không ở trong xưởng.
|
||||
STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Sức chứa của phương tiện bị thay đổi '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' khi không ở trong xưởng hoặc vì cải biến
|
||||
STR_BROKEN_VEHICLE_LENGTH :{WHITE}Đoàn tàu '{VEHICLE}' của '{COMPANY}' có độ dài không hợp lệ. Sự cố có thể có căn nguyên từ NewGRFs. Ván chơi có thể mất đồng bộ hoặc bị treo
|
||||
|
||||
STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' không hợp lệ.
|
||||
STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Danh mục hàng hoá/cải biến được cho '{1:ENGINE}' khác với danh mục mua được sau khi đã có. Việc này khiến cho việc tự thay thế hay là tự cải biến không chính xác.
|
||||
STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' gây ra một vòng lặp vô tận khi gọi hàm callback.
|
||||
STR_NEWGRF_BUGGY :{WHITE}NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' không hợp lệ.
|
||||
STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Danh mục hàng hoá/cải biến được cho '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' khác với danh mục mua được sau khi đã có. Việc này khiến cho việc tự thay thế hay là tự cải biến không chính xác.
|
||||
STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' gây ra một vòng lặp vô tận khi gọi hàm callback.
|
||||
STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Hàm callback {1:HEX} gửi trả kết quả sai/không rõ {2:HEX}
|
||||
STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' trả về loại hàng hoá sản xuất không hợp lệ khi gọi lại tại {2:HEX}
|
||||
STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' trả về loại hàng hoá sản xuất không hợp lệ khi gọi lại tại {2:HEX}
|
||||
|
||||
# 'User removed essential NewGRFs'-placeholders for stuff without specs
|
||||
STR_NEWGRF_INVALID_CARGO :<sai kiểu hàng>
|
||||
|
@ -3650,6 +3697,10 @@ STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Đổi t
|
|||
|
||||
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Mở rộng
|
||||
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Tăng quy mô đô thị
|
||||
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Mở rộng công trình
|
||||
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Tăng số công trình của thị trấn
|
||||
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Mở rộng đường
|
||||
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Tăng số đường sá của thị trấn
|
||||
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Xoá
|
||||
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Xoá bỏ đô thị này hoàn toàn
|
||||
|
||||
|
@ -3975,6 +4026,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Sản l
|
|||
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Sản lượng phút trước:
|
||||
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% đã vận chuyển)
|
||||
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Xem vị trí trung tâm của nhà máy. Ctrl+Click mở cửa sổ mới để xem
|
||||
STR_INDUSTRY_VIEW_CARGO_GRAPH :{BLACK}Đồ thị hàng hóa
|
||||
STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP :{BLACK}Xem đồ thị lịch sử kinh doanh hàng hóa
|
||||
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Mức sản lượng: {YELLOW}{COMMA}%
|
||||
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Nhà máy này đã thông báo sắp đóng cửa!
|
||||
|
||||
|
@ -4386,10 +4439,10 @@ STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Hiện l
|
|||
STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Hiện lộ trình máy bay. Ctrl+Click để hiện lịch trình
|
||||
|
||||
###length VEHICLE_TYPES
|
||||
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu hoả
|
||||
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết xe
|
||||
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu thuỷ
|
||||
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết máy bay
|
||||
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu hoả. Ctrl+Click vào để hiện nhóm của tàu hỏa
|
||||
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết xe. Ctrl+Click để hiện nhóm phương tiện
|
||||
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu thuỷ. Ctrl+Click vào để hiện nhóm của tàu thủy
|
||||
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết máy bay. Ctrl+Click để hiện nhóm của máy bay
|
||||
|
||||
###length VEHICLE_TYPES
|
||||
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Tác động đến tàu hỏa hiện tại - bấm để dừng/chạy tàu hỏa
|
||||
|
@ -4644,55 +4697,56 @@ STR_ORDER_ROAD_VEHICLE_DEPOT :Xưởng xe
|
|||
STR_ORDER_SHIP_DEPOT :Xưởng tàu thuỷ
|
||||
###next-name-looks-similar
|
||||
|
||||
STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING} xưởng sân bay gần nhất
|
||||
STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} gần {STRING} nhất
|
||||
STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT}
|
||||
|
||||
STR_ORDER_REFIT_ORDER :(Cải biến thành {STRING})
|
||||
STR_ORDER_REFIT_STOP_ORDER :(Cải biến thành {STRING} và dừng)
|
||||
STR_ORDER_STOP_ORDER :(Dừng)
|
||||
STR_ORDER_REFIT_ORDER :{SPACE}(Cải biến thành {STRING})
|
||||
STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Cải biến thành {STRING} và dừng)
|
||||
STR_ORDER_STOP_ORDER :{SPACE}(Dừng)
|
||||
|
||||
STR_ORDER_WAIT_TO_UNBUNCH :(Chờ để gỡ gộp)
|
||||
STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(Chờ để gỡ gộp)
|
||||
|
||||
STR_ORDER_GO_TO_STATION :{STRING} {STATION}
|
||||
STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Không thể sử dụng trạm){POP_COLOUR} {STRING} {STATION}
|
||||
|
||||
STR_ORDER_IMPLICIT :(Chạy ngầm)
|
||||
STR_ORDER_IMPLICIT :{SPACE}(Chạy ngầm)
|
||||
|
||||
STR_ORDER_FULL_LOAD :(Bốc đầy hàng)
|
||||
STR_ORDER_FULL_LOAD_ANY :(Bốc đủ bất kỳ hàng nào)
|
||||
STR_ORDER_NO_LOAD :(Không bốc xếp)
|
||||
STR_ORDER_UNLOAD :(Dỡ và lấy hàng khác)
|
||||
STR_ORDER_UNLOAD_FULL_LOAD :(Dỡ tất hàng và chờ bốc đầy hàng)
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Dỡ tất hàng và chờ bốc đủ bất kỳ hàng nào)
|
||||
STR_ORDER_UNLOAD_NO_LOAD :(Dỡ tất hàng và để trống)
|
||||
STR_ORDER_TRANSFER :(Trung chuyển hàng và lấy hàng khác)
|
||||
STR_ORDER_TRANSFER_FULL_LOAD :(Trung chuyển và chờ bốc đầy hàng)
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Trung chuyển và chờ bốc đủ hàng bất kỳ)
|
||||
STR_ORDER_TRANSFER_NO_LOAD :(Trung chuyển và để trống)
|
||||
STR_ORDER_NO_UNLOAD :(Không dỡ và lấy hàng)
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD :(Không dỡ và chờ lấy thêm đầy hàng)
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Không dỡ và chờ lấy đủ hàng bất kỳ)
|
||||
STR_ORDER_NO_UNLOAD_NO_LOAD :(Không bốc hàng và không dỡ hàng)
|
||||
STR_ORDER_FULL_LOAD :{SPACE}(Bốc đầy hàng)
|
||||
STR_ORDER_FULL_LOAD_ANY :{SPACE}(Bốc đủ bất kỳ hàng nào)
|
||||
STR_ORDER_NO_LOAD :{SPACE}(Không bốc xếp)
|
||||
STR_ORDER_UNLOAD :{SPACE}(Dỡ và lấy hàng khác)
|
||||
STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Dỡ tất hàng và chờ bốc đầy hàng)
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Dỡ tất hàng và chờ bốc đủ bất kỳ hàng nào)
|
||||
STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Dỡ tất hàng và để trống)
|
||||
STR_ORDER_TRANSFER :{SPACE}(Trung chuyển hàng và lấy hàng khác)
|
||||
STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Trung chuyển và chờ bốc đầy hàng)
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Trung chuyển và chờ bốc đủ hàng bất kỳ)
|
||||
STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Trung chuyển và để trống)
|
||||
STR_ORDER_NO_UNLOAD :{SPACE}(Không dỡ và lấy hàng)
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(Không dỡ và chờ lấy thêm đầy hàng)
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(Không dỡ và chờ lấy đủ hàng bất kỳ)
|
||||
STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(Không bốc hàng và không dỡ hàng)
|
||||
|
||||
STR_ORDER_AUTO_REFIT :(Tự cải biến thành {STRING})
|
||||
STR_ORDER_FULL_LOAD_REFIT :(Tự cải biến và chất đầy {STRING})
|
||||
STR_ORDER_FULL_LOAD_ANY_REFIT :(Tự cải biến và chất đầy bất kỳ {STRING})
|
||||
STR_ORDER_UNLOAD_REFIT :(Dỡ hàng và tự cải biến để lấy {STRING})
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Dỡ hàng và tự cải biến đề bốc đầy {STRING})
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
STR_ORDER_TRANSFER_REFIT :(Trung chuyển và tự cải biến để lấy {STRING})
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Trung chuyển và tự cải biến đề bốc đầy {STRING})
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Trung chuyển và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
STR_ORDER_NO_UNLOAD_REFIT :(Không dỡ hàng và tự cái biến để lấy {STRING})
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Không dỡ hàng và tự cải biến để bốc đầy {STRING})
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Không dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
STR_ORDER_AUTO_REFIT :{SPACE}(Tự cải biến thành {STRING})
|
||||
STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Tự cải biến và chất đầy {STRING})
|
||||
STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Tự cải biến và chất đầy bất kỳ {STRING})
|
||||
STR_ORDER_UNLOAD_REFIT :{SPACE}(Dỡ hàng và tự cải biến để lấy {STRING})
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Dỡ hàng và tự cải biến đề bốc đầy {STRING})
|
||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
STR_ORDER_TRANSFER_REFIT :{SPACE}(Trung chuyển và tự cải biến để lấy {STRING})
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Trung chuyển và tự cải biến đề bốc đầy {STRING})
|
||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Trung chuyển và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(Không dỡ hàng và tự cái biến để lấy {STRING})
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Không dỡ hàng và tự cải biến để bốc đầy {STRING})
|
||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Không dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||
|
||||
STR_ORDER_AUTO_REFIT_ANY :hàng hóa sẵn có
|
||||
|
||||
###length 3
|
||||
STR_ORDER_STOP_LOCATION_NEAR_END :[đỗ ở đầu gần]
|
||||
STR_ORDER_STOP_LOCATION_MIDDLE :[đỗ ở giữa]
|
||||
STR_ORDER_STOP_LOCATION_FAR_END :[đỗ ở đầu xa]
|
||||
STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[đỗ ở đầu gần]
|
||||
STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[đỗ ở giữa]
|
||||
STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[đỗ ở đầu xa]
|
||||
|
||||
STR_ORDER_OUT_OF_RANGE :{RED} (Điểm đến kế tiếp ngoài tầm xa)
|
||||
|
||||
|
@ -4712,14 +4766,15 @@ STR_TIMETABLE_TOOLTIP :{BLACK}Lịch t
|
|||
STR_TIMETABLE_NO_TRAVEL :Không di chuyển
|
||||
STR_TIMETABLE_NOT_TIMETABLEABLE :Hành trình (tự động; tính thời gian theo lịch trình thủ công kế tiếp)
|
||||
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Di chuyển (không bó buộc theo lịch trình)
|
||||
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Hành trình với tốc độ tối đa là {VELOCITY} (chưa dựng lịch trình)
|
||||
STR_TIMETABLE_TRAVEL_FOR :Di chuyển trong {STRING}
|
||||
STR_TIMETABLE_TRAVEL_FOR_SPEED :Lộ trình {STRING} với tốc độ tối đa {VELOCITY}
|
||||
STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình)
|
||||
STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình) với tốc độ đối đa {VELOCITY}
|
||||
STR_TIMETABLE_STAY_FOR_ESTIMATED :(ở lại {STRING}, chưa có lịch trình)
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(di chuyển đến {STRING}, chưa có lịch trình)
|
||||
STR_TIMETABLE_STAY_FOR :và ở lại trong {STRING}
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR :và di chuyển trong {STRING}
|
||||
STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(ở lại {STRING}, chưa có lịch trình)
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(di chuyển đến {STRING}, chưa có lịch trình)
|
||||
STR_TIMETABLE_STAY_FOR :{SPACE}và ở lại trong {STRING}
|
||||
STR_TIMETABLE_AND_TRAVEL_FOR :{SPACE}và di chuyển trong {STRING}
|
||||
|
||||
STR_TIMETABLE_APPROX_TIME :{BLACK}Lịch trình này sẽ mất khoảng {STRING} để hoàn thành
|
||||
STR_TIMETABLE_TOTAL_TIME :{BLACK}Lịch trình này sẽ mất {STRING} để hoàn thành
|
||||
|
@ -4738,12 +4793,14 @@ STR_TIMETABLE_START_SECONDS_QUERY :Số giây cho
|
|||
|
||||
STR_TIMETABLE_CHANGE_TIME :{BLACK}Đổi thời gian
|
||||
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Thay đổi thời lượng của điểm lộ trình được phép sử dụng. Ctrl+Click đặt thời gian cho mọi lộ trình
|
||||
STR_TIMETABLE_CHANGE_TIME_QUERY :Thay đổi thời gian
|
||||
|
||||
STR_TIMETABLE_CLEAR_TIME :{BLACK}Xoá thời gian
|
||||
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Xóa thời lượng áp dụng cho điểm lộ trình. Ctrl+Click xoá tất cả thời gian cho mọi lộ trình
|
||||
|
||||
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Thay Đổi Giới Hạn Tốc Độ
|
||||
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Thay đổi tốc độ tối đa của lộ trình được chọn. Ctrl+Click đặt tốc độ cho mọi lộ trình
|
||||
STR_TIMETABLE_CHANGE_SPEED_QUERY :Thay đổi giới hạn tốc độ
|
||||
|
||||
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Xóa Giới Hạn Tốc Độ
|
||||
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Xóa tốc độ đối đa đối với lộ trình được chọn. Ctrl+Click xoá tốc độ cho mọi lộ trình
|
||||
|
@ -4907,7 +4964,7 @@ STR_GAME_SAVELOAD_NOT_AVAILABLE :<không có s
|
|||
STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Lưu ván chơi sẽ không có xe điện. Những công trình cho xe điện sẽ bị xoá bỏ
|
||||
|
||||
# Map generation messages
|
||||
STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Sinh bản đồ bị ngưng...{}... không có nơi đặt đô thị
|
||||
STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Sinh bản đồ bị ngưng...{}{}... không có nơi đặt đô thị
|
||||
STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... không có đô thị nào ở màn chơi kịch bản này
|
||||
|
||||
STR_ERROR_PNGMAP :{WHITE}Không thể nạp nền từ file PNG...
|
||||
|
@ -4946,6 +5003,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Yêu c
|
|||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Tạo dốc bị sai hướng
|
||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Không làm thế này được...
|
||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Cần giải toả nhà cửa trước
|
||||
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... công trình được bảo vệ
|
||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Không thể dọn dẹp khu vực này...
|
||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... điểm không phù hợp
|
||||
STR_ERROR_ALREADY_BUILT :{WHITE}... đã xây rồi
|
||||
|
@ -4998,7 +5056,7 @@ STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... quá
|
|||
STR_ERROR_TOO_MANY_TOWNS :{WHITE}... quá nhiều đô thị
|
||||
STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... không còn khoảng trống nào trên bản đồ
|
||||
STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Xây dựng cầu đường đang tiến hành
|
||||
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Không thể xoá đo thị này...{}Có một ga, bến hoặc xưởng thuộc đô thị hoặc là 1 ô đất của đô thị không thể xoá được.
|
||||
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Không thể xoá đo thị này...{}{}Có một ga, bến hoặc xưởng thuộc đô thị hoặc là 1 ô đất của đô thị không thể xoá được.
|
||||
STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... không có nơi nào hợp lý để dựng tượng đài ở trung tâm đô thị này
|
||||
STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}Không thể xây dựng nhà...
|
||||
|
||||
|
@ -5825,6 +5883,7 @@ STR_CURRENCY_SHORT_GIGA :{NBSP}tỷ
|
|||
STR_CURRENCY_SHORT_TERA :{NBSP}ktỷ
|
||||
|
||||
STR_JUST_CARGO :{CARGO_LONG}
|
||||
STR_JUST_LEFT_ARROW :{LEFT_ARROW}
|
||||
STR_JUST_RIGHT_ARROW :{RIGHT_ARROW}
|
||||
STR_JUST_CHECKMARK :{CHECKMARK}
|
||||
STR_JUST_COMMA :{COMMA}
|
||||
|
@ -5864,3 +5923,11 @@ STR_SHIP :{BLACK}{SHIP}
|
|||
STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
|
||||
|
||||
STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING}
|
||||
STR_BADGE_CONFIG_MENU_TOOLTIP :Mở thiết lập phù hiệu
|
||||
STR_BADGE_CONFIG_RESET :Thiêt lập lại
|
||||
STR_BADGE_CONFIG_ICONS :{WHITE}Ảnh phù hiệu
|
||||
STR_BADGE_CONFIG_FILTERS :{WHITE}Bộ lọc phù hiệu
|
||||
STR_BADGE_CONFIG_PREVIEW :Ảnh xem trước
|
||||
STR_BADGE_CONFIG_NAME :Tên
|
||||
STR_BADGE_FILTER_ANY_LABEL :Bất cứ {STRING} nào
|
||||
STR_BADGE_FILTER_IS_LABEL :{STRING} là {STRING}
|
||||
|
|
|
@ -681,6 +681,11 @@ SettingsContainer &GetSettingsTree()
|
|||
* Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */
|
||||
viewports->Add(new SettingEntry("gui.scrollwheel_scrolling"));
|
||||
viewports->Add(new SettingEntry("gui.scrollwheel_multiplier"));
|
||||
viewports->Add(new SettingEntry("gui.gamepad_stick_selection"));
|
||||
viewports->Add(new SettingEntry("gui.gamepad_deadzone"));
|
||||
viewports->Add(new SettingEntry("gui.gamepad_sensitivity"));
|
||||
viewports->Add(new SettingEntry("gui.gamepad_invert_x"));
|
||||
viewports->Add(new SettingEntry("gui.gamepad_invert_y"));
|
||||
#ifdef __APPLE__
|
||||
/* We might need to emulate a right mouse button on mac */
|
||||
viewports->Add(new SettingEntry("gui.right_mouse_btn_emulation"));
|
||||
|
|
|
@ -140,6 +140,13 @@ enum ScrollWheelScrollingSetting : uint8_t {
|
|||
SWS_OFF = 2 ///< Scroll wheel has no effect.
|
||||
};
|
||||
|
||||
/** Settings related to gamepad stick selection. */
|
||||
enum GamepadStickSelection : uint8_t {
|
||||
GSS_DISABLED = 0, ///< Gamepad scrolling disabled.
|
||||
GSS_LEFT_STICK = 1, ///< Use left analog stick for scrolling.
|
||||
GSS_RIGHT_STICK = 2, ///< Use right analog stick for scrolling.
|
||||
};
|
||||
|
||||
/** Settings related to the GUI and other stuff that is not saved in the savegame. */
|
||||
struct GUISettings {
|
||||
bool sg_full_load_any; ///< new full load calculation, any cargo must be full read from pre v93 savegames
|
||||
|
@ -183,6 +190,11 @@ struct GUISettings {
|
|||
uint8_t right_mouse_btn_emulation; ///< should we emulate right mouse clicking?
|
||||
uint8_t scrollwheel_scrolling; ///< scrolling using the scroll wheel?
|
||||
uint8_t scrollwheel_multiplier; ///< how much 'wheel' per incoming event from the OS?
|
||||
uint8_t gamepad_deadzone; ///< deadzone for gamepad analog sticks (0-100)
|
||||
uint8_t gamepad_sensitivity; ///< sensitivity multiplier for gamepad scrolling
|
||||
bool gamepad_invert_x; ///< invert X axis for gamepad scrolling?
|
||||
bool gamepad_invert_y; ///< invert Y axis for gamepad scrolling?
|
||||
uint8_t gamepad_stick_selection; ///< which stick to use for scrolling (left/right/disabled)
|
||||
bool timetable_arrival_departure; ///< show arrivals and departures in vehicle timetables
|
||||
RightClickClose right_click_wnd_close; ///< close window with right click
|
||||
bool pause_on_newgame; ///< whether to start new games paused or not
|
||||
|
|
|
@ -912,3 +912,62 @@ post_cb = [](auto) { SetupWidgetDimensions(); ReInitAllWindows(true); }
|
|||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
[SDTC_VAR]
|
||||
var = gui.gamepad_deadzone
|
||||
type = SLE_UINT8
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
def = 10
|
||||
min = 0
|
||||
max = 100
|
||||
interval = 5
|
||||
str = STR_CONFIG_SETTING_GAMEPAD_DEADZONE
|
||||
strhelp = STR_CONFIG_SETTING_GAMEPAD_DEADZONE_HELPTEXT
|
||||
strval = STR_JUST_COMMA
|
||||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
[SDTC_VAR]
|
||||
var = gui.gamepad_sensitivity
|
||||
type = SLE_UINT8
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
def = 10
|
||||
min = 1
|
||||
max = 100
|
||||
interval = 5
|
||||
str = STR_CONFIG_SETTING_GAMEPAD_SENSITIVITY
|
||||
strhelp = STR_CONFIG_SETTING_GAMEPAD_SENSITIVITY_HELPTEXT
|
||||
strval = STR_JUST_COMMA
|
||||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
[SDTC_BOOL]
|
||||
var = gui.gamepad_invert_x
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
def = false
|
||||
str = STR_CONFIG_SETTING_GAMEPAD_INVERT_X
|
||||
strhelp = STR_CONFIG_SETTING_GAMEPAD_INVERT_X_HELPTEXT
|
||||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
[SDTC_BOOL]
|
||||
var = gui.gamepad_invert_y
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
|
||||
def = false
|
||||
str = STR_CONFIG_SETTING_GAMEPAD_INVERT_Y
|
||||
strhelp = STR_CONFIG_SETTING_GAMEPAD_INVERT_Y_HELPTEXT
|
||||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
[SDTC_VAR]
|
||||
var = gui.gamepad_stick_selection
|
||||
type = SLE_UINT8
|
||||
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown
|
||||
def = GSS_LEFT_STICK
|
||||
min = GSS_DISABLED
|
||||
max = GSS_RIGHT_STICK
|
||||
str = STR_CONFIG_SETTING_GAMEPAD_STICK_SELECTION
|
||||
strhelp = STR_CONFIG_SETTING_GAMEPAD_STICK_SELECTION_HELPTEXT
|
||||
strval = STR_CONFIG_SETTING_GAMEPAD_STICK_DISABLED
|
||||
cat = SC_BASIC
|
||||
startup = true
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../fileio_func.h"
|
||||
#include "../framerate_type.h"
|
||||
#include "../window_func.h"
|
||||
#include "../zoom_func.h"
|
||||
#include "sdl2_v.h"
|
||||
#include <SDL.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
@ -524,6 +525,27 @@ bool VideoDriver_SDL_Base::PollEvent()
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_CONTROLLERDEVICEADDED: {
|
||||
Debug(driver, 1, "SDL2: Gamepad device added, index: {}", ev.cdevice.which);
|
||||
/* Try to open the newly connected gamepad */
|
||||
if (this->gamepad == nullptr) {
|
||||
this->OpenGamepad();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_CONTROLLERDEVICEREMOVED: {
|
||||
Debug(driver, 1, "SDL2: Gamepad device removed, instance ID: {}", ev.cdevice.which);
|
||||
/* Close gamepad if it was removed */
|
||||
if (this->gamepad != nullptr && ev.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(this->gamepad))) {
|
||||
Debug(driver, 1, "SDL2: Current gamepad was removed, closing and reopening");
|
||||
this->CloseGamepad();
|
||||
/* Try to open another gamepad if available */
|
||||
this->OpenGamepad();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -539,6 +561,12 @@ static std::optional<std::string_view> InitializeSDL()
|
|||
#endif
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) return SDL_GetError();
|
||||
|
||||
/* Initialize gamepad subsystem for gamepad scrolling support */
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) {
|
||||
Debug(driver, 1, "SDL2: Failed to initialize gamepad subsystem: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -590,6 +618,11 @@ std::optional<std::string_view> VideoDriver_SDL_Base::Start(const StringList &pa
|
|||
SDL_StopTextInput();
|
||||
this->edit_box_focused = false;
|
||||
|
||||
/* Initialize gamepad for scrolling */
|
||||
Debug(driver, 1, "SDL2: Attempting to initialize gamepad support");
|
||||
Debug(driver, 1, "SDL2: Gamepad stick selection setting: {}", _settings_client.gui.gamepad_stick_selection);
|
||||
this->OpenGamepad();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
this->is_game_threaded = false;
|
||||
#else
|
||||
|
@ -601,6 +634,8 @@ std::optional<std::string_view> VideoDriver_SDL_Base::Start(const StringList &pa
|
|||
|
||||
void VideoDriver_SDL_Base::Stop()
|
||||
{
|
||||
this->CloseGamepad();
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
|
||||
SDL_Quit(); // If there's nothing left, quit SDL
|
||||
|
@ -629,6 +664,9 @@ void VideoDriver_SDL_Base::InputLoop()
|
|||
(keys[SDL_SCANCODE_DOWN] ? 8 : 0);
|
||||
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
|
||||
/* Process gamepad input for scrolling */
|
||||
this->ProcessGamepadInput();
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::LoopOnce()
|
||||
|
@ -755,3 +793,84 @@ void VideoDriver_SDL_Base::UnlockVideoBuffer()
|
|||
|
||||
this->buffer_locked = false;
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::OpenGamepad()
|
||||
{
|
||||
/* Don't open gamepad if already open or if gamepad scrolling is disabled */
|
||||
if (this->gamepad != nullptr) {
|
||||
Debug(driver, 1, "SDL2: Gamepad already open, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_DISABLED) {
|
||||
Debug(driver, 1, "SDL2: Gamepad scrolling disabled, not opening gamepad");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if any gamepads are available */
|
||||
int num_gamepads = SDL_NumJoysticks();
|
||||
Debug(driver, 1, "SDL2: Found {} joystick(s)", num_gamepads);
|
||||
|
||||
for (int i = 0; i < num_gamepads; i++) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
Debug(driver, 1, "SDL2: Joystick {} is a gamepad, attempting to open", i);
|
||||
this->gamepad = SDL_GameControllerOpen(i);
|
||||
if (this->gamepad != nullptr) {
|
||||
Debug(driver, 1, "SDL2: Opened gamepad: {}", SDL_GameControllerName(this->gamepad));
|
||||
break;
|
||||
} else {
|
||||
Debug(driver, 1, "SDL2: Failed to open gamepad {}: {}", i, SDL_GetError());
|
||||
}
|
||||
} else {
|
||||
Debug(driver, 1, "SDL2: Joystick {} is not a gamepad", i);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->gamepad == nullptr) {
|
||||
Debug(driver, 1, "SDL2: No gamepad opened");
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::CloseGamepad()
|
||||
{
|
||||
if (this->gamepad != nullptr) {
|
||||
SDL_GameControllerClose(this->gamepad);
|
||||
this->gamepad = nullptr;
|
||||
Debug(driver, 1, "SDL2: Closed gamepad");
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::ProcessGamepadInput()
|
||||
{
|
||||
/* Skip if gamepad is not available */
|
||||
if (this->gamepad == nullptr) {
|
||||
static bool logged_no_gamepad = false;
|
||||
if (!logged_no_gamepad) {
|
||||
Debug(driver, 2, "SDL2: No gamepad available for input processing");
|
||||
logged_no_gamepad = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if gamepad is still connected */
|
||||
if (!SDL_GameControllerGetAttached(this->gamepad)) {
|
||||
Debug(driver, 1, "SDL2: Gamepad disconnected, closing and reopening");
|
||||
this->CloseGamepad();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get analog stick values based on stick selection */
|
||||
Sint16 stick_x = 0, stick_y = 0;
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_LEFT_STICK) {
|
||||
stick_x = SDL_GameControllerGetAxis(this->gamepad, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
stick_y = SDL_GameControllerGetAxis(this->gamepad, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
Debug(driver, 3, "SDL2: Left stick raw values: x={}, y={}", stick_x, stick_y);
|
||||
} else if (_settings_client.gui.gamepad_stick_selection == GSS_RIGHT_STICK) {
|
||||
stick_x = SDL_GameControllerGetAxis(this->gamepad, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
stick_y = SDL_GameControllerGetAxis(this->gamepad, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
Debug(driver, 3, "SDL2: Right stick raw values: x={}, y={}", stick_x, stick_y);
|
||||
}
|
||||
|
||||
/* Use the common gamepad handling function */
|
||||
HandleGamepadScrolling(stick_x, stick_y, 32767);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include "video_driver.hpp"
|
||||
|
||||
/* Forward declaration of SDL_GameController */
|
||||
struct _SDL_GameController;
|
||||
typedef struct _SDL_GameController SDL_GameController;
|
||||
|
||||
/** The SDL video driver. */
|
||||
class VideoDriver_SDL_Base : public VideoDriver {
|
||||
public:
|
||||
|
@ -69,6 +73,13 @@ protected:
|
|||
/** Create the main window. */
|
||||
virtual bool CreateMainWindow(uint w, uint h, uint flags = 0);
|
||||
|
||||
protected:
|
||||
/** Gamepad support for map scrolling */
|
||||
SDL_GameController *gamepad = nullptr; ///< Currently opened gamepad.
|
||||
void OpenGamepad();
|
||||
void CloseGamepad();
|
||||
void ProcessGamepadInput();
|
||||
|
||||
private:
|
||||
void LoopOnce();
|
||||
void MainLoopCleanup();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <windows.h>
|
||||
#include <imm.h>
|
||||
#include <versionhelpers.h>
|
||||
#include <xinput.h>
|
||||
#if defined(_MSC_VER) && defined(NTDDI_WIN10_RS4)
|
||||
#include <winrt/Windows.UI.ViewManagement.h>
|
||||
#endif
|
||||
|
@ -984,6 +985,9 @@ void VideoDriver_Win32Base::InputLoop()
|
|||
}
|
||||
|
||||
if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
|
||||
|
||||
/* Process gamepad input for scrolling */
|
||||
this->ProcessGamepadInput();
|
||||
}
|
||||
|
||||
bool VideoDriver_Win32Base::PollEvent()
|
||||
|
@ -1143,6 +1147,106 @@ void VideoDriver_Win32Base::UnlockVideoBuffer()
|
|||
this->buffer_locked = false;
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::OpenGamepad()
|
||||
{
|
||||
/* Don't open gamepad if already open or if gamepad scrolling is disabled */
|
||||
if (this->gamepad_user_index != XUSER_MAX_COUNT) {
|
||||
Debug(driver, 1, "Win32: Gamepad already open, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_DISABLED) {
|
||||
Debug(driver, 1, "Win32: Gamepad scrolling disabled, not opening gamepad");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for any connected gamepads */
|
||||
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||
XINPUT_STATE state = {};
|
||||
|
||||
if (XInputGetState(i, &state) == ERROR_SUCCESS) {
|
||||
this->gamepad_user_index = i;
|
||||
Debug(driver, 1, "Win32: Opened gamepad at index {}", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::CloseGamepad()
|
||||
{
|
||||
if (this->gamepad_user_index != XUSER_MAX_COUNT) {
|
||||
this->gamepad_user_index = XUSER_MAX_COUNT;
|
||||
Debug(driver, 1, "Win32: Closed gamepad");
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::ProcessGamepadInput()
|
||||
{
|
||||
/* Skip if gamepad scrolling is disabled */
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If no gamepad is currently open, try to reconnect periodically */
|
||||
if (this->gamepad_user_index == XUSER_MAX_COUNT) {
|
||||
static bool logged_no_gamepad = false;
|
||||
|
||||
/* Only try to reconnect every 60 frames (~1 second at 60 FPS) to avoid spam */
|
||||
if (this->gamepad_reconnect_timer > 0) {
|
||||
this->gamepad_reconnect_timer--;
|
||||
if (!logged_no_gamepad) {
|
||||
Debug(driver, 2, "Win32: No gamepad available for input processing");
|
||||
logged_no_gamepad = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to open gamepad */
|
||||
this->OpenGamepad();
|
||||
|
||||
/* If still no gamepad, set timer for next retry */
|
||||
if (this->gamepad_user_index == XUSER_MAX_COUNT) {
|
||||
this->gamepad_reconnect_timer = 60; /* Retry in ~1 second */
|
||||
if (!logged_no_gamepad) {
|
||||
Debug(driver, 2, "Win32: No gamepad available for input processing");
|
||||
logged_no_gamepad = true;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
/* Successfully reconnected */
|
||||
logged_no_gamepad = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get gamepad state */
|
||||
XINPUT_STATE state = {};
|
||||
|
||||
if (XInputGetState(this->gamepad_user_index, &state) != ERROR_SUCCESS) {
|
||||
Debug(driver, 1, "Win32: Gamepad disconnected, closing and will retry connection");
|
||||
this->CloseGamepad();
|
||||
this->gamepad_reconnect_timer = 60; /* Start retry timer */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get analog stick values based on stick selection
|
||||
* Note: XInput uses SHORT values for stick positions, but we have to extend to INT
|
||||
* to avoid overflow when inverting the Y-axis value */
|
||||
INT stick_x = 0, stick_y = 0;
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_LEFT_STICK) {
|
||||
stick_x = state.Gamepad.sThumbLX;
|
||||
stick_y = state.Gamepad.sThumbLY;
|
||||
Debug(driver, 3, "Win32: Left stick raw values: x={}, y={}", stick_x, stick_y);
|
||||
} else if (_settings_client.gui.gamepad_stick_selection == GSS_RIGHT_STICK) {
|
||||
stick_x = state.Gamepad.sThumbRX;
|
||||
stick_y = state.Gamepad.sThumbRY;
|
||||
Debug(driver, 3, "Win32: Right stick raw values: x={}, y={}", stick_x, stick_y);
|
||||
}
|
||||
stick_y = -stick_y; // Xinput Y-axis is inverted from other libraries
|
||||
|
||||
/* Use the common gamepad handling function */
|
||||
HandleGamepadScrolling(stick_x, stick_y, 32767);
|
||||
}
|
||||
|
||||
|
||||
static FVideoDriver_Win32GDI iFVideoDriver_Win32GDI;
|
||||
|
||||
|
@ -1158,6 +1262,11 @@ std::optional<std::string_view> VideoDriver_Win32GDI::Start(const StringList &pa
|
|||
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
/* Initialize gamepad for scrolling */
|
||||
Debug(driver, 1, "Win32: Attempting to initialize gamepad support");
|
||||
Debug(driver, 1, "Win32: Gamepad stick selection setting: {}", _settings_client.gui.gamepad_stick_selection);
|
||||
this->OpenGamepad();
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -1165,6 +1274,7 @@ std::optional<std::string_view> VideoDriver_Win32GDI::Start(const StringList &pa
|
|||
|
||||
void VideoDriver_Win32GDI::Stop()
|
||||
{
|
||||
this->CloseGamepad();
|
||||
DeleteObject(this->gdi_palette);
|
||||
DeleteObject(this->dib_sect);
|
||||
|
||||
|
@ -1472,6 +1582,11 @@ std::optional<std::string_view> VideoDriver_Win32OpenGL::Start(const StringList
|
|||
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
/* Initialize gamepad for scrolling */
|
||||
Debug(driver, 1, "Win32: Attempting to initialize gamepad support");
|
||||
Debug(driver, 1, "Win32: Gamepad stick selection setting: {}", _settings_client.gui.gamepad_stick_selection);
|
||||
this->OpenGamepad();
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return std::nullopt;
|
||||
|
@ -1479,6 +1594,7 @@ std::optional<std::string_view> VideoDriver_Win32OpenGL::Start(const StringList
|
|||
|
||||
void VideoDriver_Win32OpenGL::Stop()
|
||||
{
|
||||
this->CloseGamepad();
|
||||
this->DestroyContext();
|
||||
this->VideoDriver_Win32Base::Stop();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
/** Base class for Windows video drivers. */
|
||||
class VideoDriver_Win32Base : public VideoDriver {
|
||||
|
@ -48,6 +49,13 @@ protected:
|
|||
|
||||
bool buffer_locked; ///< Video buffer was locked by the main thread.
|
||||
|
||||
/** Gamepad support for map scrolling */
|
||||
DWORD gamepad_user_index = XUSER_MAX_COUNT; ///< Index of currently opened gamepad (XUSER_MAX_COUNT = no gamepad).
|
||||
uint32_t gamepad_reconnect_timer = 0; ///< Timer for retrying gamepad connection after disconnect.
|
||||
void OpenGamepad();
|
||||
void CloseGamepad();
|
||||
void ProcessGamepadInput();
|
||||
|
||||
Dimension GetScreenSize() const override;
|
||||
float GetDPIScale() override;
|
||||
void InputLoop() override;
|
||||
|
|
|
@ -3572,3 +3572,81 @@ void PickerWindowBase::Close([[maybe_unused]] int data)
|
|||
ResetObjectToPlace();
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process gamepad analog stick input for viewport scrolling.
|
||||
* This is a common function that can be used by any video driver that supports gamepads.
|
||||
* @param stick_x Raw analog stick X value (typically -32768 to 32767 range)
|
||||
* @param stick_y Raw analog stick Y value (typically -32768 to 32767 range)
|
||||
* @param max_axis_value Maximum value for the analog stick axes (e.g., 32767 for SDL2)
|
||||
*/
|
||||
void HandleGamepadScrolling(int stick_x, int stick_y, int max_axis_value)
|
||||
{
|
||||
/* Skip if gamepad stick selection is disabled */
|
||||
if (_settings_client.gui.gamepad_stick_selection == GSS_DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply deadzone (convert percentage to axis range) */
|
||||
const int deadzone = (_settings_client.gui.gamepad_deadzone * max_axis_value) / 100;
|
||||
|
||||
if (abs(stick_x) < deadzone) stick_x = 0;
|
||||
if (abs(stick_y) < deadzone) stick_y = 0;
|
||||
|
||||
/* Skip if no movement after deadzone */
|
||||
if (stick_x == 0 && stick_y == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate scroll delta with sensitivity */
|
||||
float sensitivity = _settings_client.gui.gamepad_sensitivity / 10.0f;
|
||||
int delta_x = (int)(stick_x * sensitivity / (max_axis_value / 16)); // Scale down from axis range
|
||||
int delta_y = (int)(stick_y * sensitivity / (max_axis_value / 16));
|
||||
|
||||
/* Apply axis inversion */
|
||||
if (_settings_client.gui.gamepad_invert_x) delta_x = -delta_x;
|
||||
if (_settings_client.gui.gamepad_invert_y) delta_y = -delta_y;
|
||||
|
||||
/* Skip if deltas are too small */
|
||||
if (abs(delta_x) < 1 && abs(delta_y) < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply scrolling based on cursor position */
|
||||
if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
|
||||
Window *target_window = nullptr;
|
||||
|
||||
/* Check if cursor is over a window with a viewport */
|
||||
Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
|
||||
if (w != nullptr && w->viewport != nullptr) {
|
||||
/* Check if cursor is actually over the viewport area within the window */
|
||||
Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
|
||||
if (pt.x >= w->viewport->left - w->left &&
|
||||
pt.x < w->viewport->left - w->left + w->viewport->width &&
|
||||
pt.y >= w->viewport->top - w->top &&
|
||||
pt.y < w->viewport->top - w->top + w->viewport->height) {
|
||||
target_window = w;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no viewport under cursor, use main window */
|
||||
if (target_window == nullptr) {
|
||||
target_window = GetMainWindow();
|
||||
}
|
||||
|
||||
/* Apply scrolling to the target viewport */
|
||||
if (target_window != nullptr && target_window->viewport != nullptr) {
|
||||
/* Check if the viewport is following a vehicle (similar to mouse scroll behavior) */
|
||||
if (target_window == GetMainWindow() && target_window->viewport->follow_vehicle != VehicleID::Invalid()) {
|
||||
/* If following a vehicle, center on it and stop following (like mouse scroll) */
|
||||
const Vehicle *veh = Vehicle::Get(target_window->viewport->follow_vehicle);
|
||||
ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle
|
||||
return; // Don't apply gamepad scroll, just like mouse scroll returns ES_NOT_HANDLED
|
||||
}
|
||||
|
||||
/* Apply the scroll using the same method as keyboard scrolling */
|
||||
target_window->viewport->dest_scrollpos_x += ScaleByZoom(delta_x, target_window->viewport->zoom);
|
||||
target_window->viewport->dest_scrollpos_y += ScaleByZoom(delta_y, target_window->viewport->zoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue