# HG changeset patch # User celestar # Date 1167813137 0 # Node ID bfa6074e2833bdd8c0cf034ed0317f54a618b044 # Parent d4d00a16ef2687f2b3e9f97833ec7ef2a3614d93 (svn r7789) [cbh] - Sync with r7720:7758 from trunk diff -r d4d00a16ef26 -r bfa6074e2833 Makefile --- a/Makefile Tue Jan 02 18:40:37 2007 +0000 +++ b/Makefile Wed Jan 03 08:32:17 2007 +0000 @@ -733,13 +733,16 @@ SRCS += music.c SRCS += music_gui.c SRCS += namegen.c -SRCS += network.c -SRCS += network_client.c -SRCS += network_data.c -SRCS += network_gamelist.c -SRCS += network_gui.c -SRCS += network_server.c -SRCS += network_udp.c +SRCS += network/core/packet.c +SRCS += network/core/tcp.c +SRCS += network/core/udp.c +SRCS += network/network.c +SRCS += network/network_client.c +SRCS += network/network_data.c +SRCS += network/network_gamelist.c +SRCS += network/network_gui.c +SRCS += network/network_server.c +SRCS += network/network_udp.c SRCS += newgrf.c SRCS += newgrf_cargo.c SRCS += newgrf_config.c diff -r d4d00a16ef26 -r bfa6074e2833 ai/ai.c --- a/ai/ai.c Tue Jan 02 18:40:37 2007 +0000 +++ b/ai/ai.c Wed Jan 03 08:32:17 2007 +0000 @@ -4,7 +4,7 @@ #include "../openttd.h" #include "../variables.h" #include "../command.h" -#include "../network.h" +#include "../network/network.h" #include "ai.h" #include "default/default.h" diff -r d4d00a16ef26 -r bfa6074e2833 ai/ai.h --- a/ai/ai.h Tue Jan 02 18:40:37 2007 +0000 +++ b/ai/ai.h Wed Jan 03 08:32:17 2007 +0000 @@ -2,7 +2,7 @@ #define AI_H #include "../functions.h" -#include "../network.h" +#include "../network/network.h" #include "../player.h" #include "../command.h" diff -r d4d00a16ef26 -r bfa6074e2833 command.c --- a/command.c Tue Jan 02 18:40:37 2007 +0000 +++ b/command.c Wed Jan 03 08:32:17 2007 +0000 @@ -8,7 +8,7 @@ #include "gui.h" #include "command.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "genworld.h" diff -r d4d00a16ef26 -r bfa6074e2833 console.c --- a/console.c Tue Jan 02 18:40:37 2007 +0000 +++ b/console.c Wed Jan 03 08:32:17 2007 +0000 @@ -13,9 +13,9 @@ #include #include #include "console.h" -#include "network.h" -#include "network_data.h" -#include "network_server.h" +#include "network/network.h" +#include "network/network_data.h" +#include "network/network_server.h" #define ICON_BUFFER 79 #define ICON_HISTORY_SIZE 20 diff -r d4d00a16ef26 -r bfa6074e2833 console_cmds.c --- a/console_cmds.c Tue Jan 02 18:40:37 2007 +0000 +++ b/console_cmds.c Wed Jan 03 08:32:17 2007 +0000 @@ -9,10 +9,10 @@ #include "saveload.h" #include "string.h" #include "variables.h" -#include "network_data.h" -#include "network_client.h" -#include "network_server.h" -#include "network_udp.h" +#include "network/network_data.h" +#include "network/network_client.h" +#include "network/network_server.h" +#include "network/network_udp.h" #include "command.h" #include "settings.h" #include "fios.h" @@ -22,7 +22,7 @@ #include "screenshot.h" #include "genworld.h" #include "date.h" -#include "network.h" +#include "network/network.h" // ** scriptfile handling ** // static FILE *_script_file; diff -r d4d00a16ef26 -r bfa6074e2833 date.c --- a/date.c Tue Jan 02 18:40:37 2007 +0000 +++ b/date.c Wed Jan 03 08:32:17 2007 +0000 @@ -6,9 +6,9 @@ #include "variables.h" #include "macros.h" #include "vehicle.h" -#include "network.h" -#include "network_data.h" -#include "network_server.h" +#include "network/network.h" +#include "network/network_data.h" +#include "network/network_server.h" #include "functions.h" #include "currency.h" @@ -92,9 +92,22 @@ int rem = date % (365 * 400 + 97); uint16 x; - /* There are 24 leap years in 100 years */ - yr += 100 * (rem / (365 * 100 + 24)); - rem = rem % (365 * 100 + 24); + if (rem >= 365 * 100 + 25) { + /* There are 25 leap years in the first 100 years after + * every 400th year, as every 400th year is a leap year */ + yr += 100; + rem -= 365 * 100 + 25; + + /* There are 24 leap years in the next couple of 100 years */ + yr += 100 * (rem / (365 * 100 + 24)); + rem = (rem % (365 * 100 + 24)); + } + + if (!IsLeapYear(yr) && rem >= 365 * 4) { + /* The first 4 year of the century are not always a leap year */ + yr += 4; + rem -= 365 * 4; + } /* There is 1 leap year every 4 years */ yr += 4 * (rem / (365 * 4 + 1)); diff -r d4d00a16ef26 -r bfa6074e2833 date.h --- a/date.h Tue Jan 02 18:40:37 2007 +0000 +++ b/date.h Wed Jan 03 08:32:17 2007 +0000 @@ -3,6 +3,8 @@ #ifndef DATE_H #define DATE_H +#include "openttd.h" + /** * 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On * an overflow the new day begun and 65535 / 885 = 74. diff -r d4d00a16ef26 -r bfa6074e2833 depot_gui.c --- a/depot_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/depot_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -779,11 +779,11 @@ STR_A002_AIRCRAFT_HANGAR }; TileIndex tile = w->window_number; - byte vehtype = WP(w, depot_d).type - VEH_Train; + byte vehtype = WP(w, depot_d).type; SetDParam(0, (vehtype == VEH_Aircraft) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index); ShowQuery( - confirm_captions[vehtype], + confirm_captions[vehtype - VEH_Train], STR_DEPOT_SELL_CONFIRMATION_TEXT, w, DepotSellAllConfirmationCallback diff -r d4d00a16ef26 -r bfa6074e2833 economy.c --- a/economy.c Tue Jan 02 18:40:37 2007 +0000 +++ b/economy.c Wed Jan 03 08:32:17 2007 +0000 @@ -19,10 +19,10 @@ #include "economy.h" #include "industry.h" #include "town.h" -#include "network.h" +#include "network/network.h" #include "sound.h" #include "engine.h" -#include "network_data.h" +#include "network/network_data.h" #include "variables.h" #include "vehicle_gui.h" #include "ai/ai.h" diff -r d4d00a16ef26 -r bfa6074e2833 genworld.c --- a/genworld.c Tue Jan 02 18:40:37 2007 +0000 +++ b/genworld.c Wed Jan 03 08:32:17 2007 +0000 @@ -11,7 +11,7 @@ #include "gfx.h" #include "gfxinit.h" #include "gui.h" -#include "network.h" +#include "network/network.h" #include "debug.h" #include "settings.h" #include "heightmap.h" diff -r d4d00a16ef26 -r bfa6074e2833 genworld_gui.c --- a/genworld_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/genworld_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -19,7 +19,7 @@ #include "settings.h" #include "debug.h" #include "genworld.h" -#include "network.h" +#include "network/network.h" #include "thread.h" #include "date.h" #include "newgrf_config.h" @@ -43,7 +43,6 @@ GLWP_END } glwp_modes; -static char _edit_str_buf[LEN_RND_SEED]; static uint _heightmap_x = 0; static uint _heightmap_y = 0; static StringID _heightmap_str = STR_NULL; @@ -193,11 +192,22 @@ static const StringID num_towns[] = {STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID}; static const StringID num_inds[] = {STR_26816_NONE, STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID}; + /* Data used for the generate seed edit box */ + static querystr_d _genseed_query; + static char _genseed_buffer[LEN_RND_SEED]; + uint mode = w->window_number; uint y; switch (e->event) { - case WE_CREATE: LowerWindowWidget(w, _opt_newgame.landscape + 3); break; + case WE_CREATE: + LowerWindowWidget(w, _opt_newgame.landscape + 3); + + snprintf(_genseed_buffer, sizeof(_genseed_buffer), "%u", _patches_newgame.generation_seed); + InitializeTextBuffer(&_genseed_query.text, _genseed_buffer, lengthof(_genseed_buffer), 120); + _genseed_query.caption = STR_NULL; + _genseed_query.afilter = CS_NUMERAL; + break; case WE_PAINT: /* You can't select smoothness if not terragenesis */ @@ -244,7 +254,7 @@ } DrawString( 12, 153 + y, STR_RANDOM_SEED, 0); - DrawEditBox(w, &WP(w, querystr_d), SEED_EDIT); + DrawEditBox(w, &_genseed_query, SEED_EDIT); DrawString(182, 113 + y, STR_DATE, 0); SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1)); @@ -315,8 +325,8 @@ break; case 16: // Random seed _patches_newgame.generation_seed = InteractiveRandom(); - snprintf(_edit_str_buf, lengthof(_edit_str_buf), "%u", _patches_newgame.generation_seed); - UpdateTextBufferSize(&WP(w, querystr_d).text); + snprintf(_genseed_buffer, lengthof(_genseed_buffer), "%u", _patches_newgame.generation_seed); + UpdateTextBufferSize(&_genseed_query.text); SetWindowDirty(w); break; case 17: // Generate @@ -385,17 +395,17 @@ break; case WE_MOUSELOOP: - HandleEditBox(w, &WP(w, querystr_d), SEED_EDIT); + HandleEditBox(w, &_genseed_query, SEED_EDIT); break; case WE_KEYPRESS: - HandleEditBoxKey(w, &WP(w, querystr_d), SEED_EDIT, e); + HandleEditBoxKey(w, &_genseed_query, SEED_EDIT, e); /* the seed is unsigned, therefore atoi cannot be used. * As 2^32 - 1 (MAX_UVALUE(uint32)) is a 'magic' value * (use random seed) it should not be possible to be * entered into the input field; the generate seed * button can be used instead. */ - _patches_newgame.generation_seed = minu(strtoul(_edit_str_buf, NULL, 10), MAX_UVALUE(uint32) - 1); + _patches_newgame.generation_seed = minu(strtoul(_genseed_buffer, NULL, sizeof(_genseed_buffer) - 1), MAX_UVALUE(uint32) - 1); break; case WE_DROPDOWN_SELECT: @@ -503,13 +513,6 @@ w = AllocateWindowDescFront((mode == GLWP_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc, mode); if (w != NULL) { - querystr_d *querystr = &WP(w, querystr_d); - - snprintf(_edit_str_buf, lengthof(_edit_str_buf), "%u", _patches_newgame.generation_seed); - - InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120); - querystr->caption = STR_NULL; - querystr->afilter = CS_NUMERAL; InvalidateWindow(WC_GENERATE_LANDSCAPE, mode); } diff -r d4d00a16ef26 -r bfa6074e2833 intro_gui.c --- a/intro_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/intro_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -9,12 +9,12 @@ #include "gui.h" #include "gfx.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "settings.h" #include "heightmap.h" #include "genworld.h" -#include "network_gui.h" +#include "network/network_gui.h" #include "newgrf.h" static const Widget _select_game_widgets[] = { diff -r d4d00a16ef26 -r bfa6074e2833 lang/danish.txt --- a/lang/danish.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/danish.txt Wed Jan 03 08:32:17 2007 +0000 @@ -154,6 +154,7 @@ STR_00B1_GAME_OPTIONS :{WHITE}Spilindstillinger STR_00B2_MESSAGE :{YELLOW}Besked STR_00B3_MESSAGE_FROM :{YELLOW}Besked fra {STRING} +STR_POPUP_CAUTION_CAPTION :{WHITE}Advarsel! STR_00B4_CAN_T_DO_THIS :{WHITE}Det kan du ikke.... STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Kan ikke rydde området.... STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, Alle rettigheder reserveret @@ -235,7 +236,7 @@ STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Gummiplantage STR_010D_WATER_SUPPLY :{BLACK}{TINYFONT}Vandværk STR_010E_WATER_TOWER :{BLACK}{TINYFONT}Vandtårn -STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Tømmerfabrik +STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Træfabrik STR_0110_COTTON_CANDY_FOREST :{BLACK}{TINYFONT}Candyfloss-skov STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}Slikfabrik STR_0112_BATTERY_FARM :{BLACK}{TINYFONT}Batterigård @@ -353,7 +354,7 @@ STR_PERFORMANCE_DETAIL_MENU :Præstations oversigt ############ range for menu ends -STR_015B_OPENTTD :{WHITE}OpenTTD +STR_015B_OPENTTD :{WHITE}Om OpenTTD STR_015C_SAVE_GAME :Gem Spil STR_015D_LOAD_GAME :Hent Spil STR_015E_QUIT_GAME :Afslut Spil @@ -396,7 +397,7 @@ STR_AVAILABLE_ENGINES_TIP :{BLACK}Se liste over tilgængelige designs for denne køretøjstype. STR_MANAGE_LIST :{BLACK}Administrer liste STR_MANAGE_LIST_TIP :{BLACK}Send instruktioner til alle køretøjer in denne liste -STR_REPLACE_VEHICLES :Udskift Køretøjer +STR_REPLACE_VEHICLES :Udskift køretøjer STR_SEND_TRAIN_TO_DEPOT :Send til remise STR_SEND_ROAD_VEHICLE_TO_DEPOT :Send til værksted STR_SEND_SHIP_TO_DEPOT :Send til dok @@ -463,8 +464,8 @@ STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Vis transportruter på kortet STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}Vis vegetation på kortet STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Vis landejere på kortet -STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Tænd/sluk bynavne -STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Dette års overskud: {CURRENCY} (sidste år: {CURRENCY}) +STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Vis/skjul bynavne på kort +STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Overskud i år: {CURRENCY} (sidste år: {CURRENCY}) ############ range for service numbers starts STR_AGE :{COMMA} år ({COMMA}) @@ -567,8 +568,8 @@ STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Select 'Custom 2' (brugerdefineret) programmet STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Ryd det valgte program (Gælder kun Custom1/Custom2) STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Gem opsætning for musik -STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Klik på et musiknummer for at tilføje det til programlisten (Kun for Custom1/Custom2) -STR_CLICK_ON_TRACK_TO_REMOVE :{BLACK}Klik på et musiknummer for at fjerne det fra programlisten (kun Custom1 eller Custom2) +STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Klik på et musiknummer for at tilføje det til programlisten (kun for Custom1/Custom2) +STR_CLICK_ON_TRACK_TO_REMOVE :{BLACK}Klik på et musiknummer for at fjerne det fra programlisten (kun for Custom1/Custom2) STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Tilfældig afspilning til/fra STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Vis vinduet med musiknummervalg STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klik på servicen for at centrere skærmen over industrien/byen @@ -590,7 +591,7 @@ STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Ændring i accepteret last STR_020E_SUBSIDIES :{YELLOW}Statsstøttede aftaler STR_020F_GENERAL_INFORMATION :{YELLOW}Generel information -STR_MESSAGES_ALL :{YELLOW}Opsætning for all beskeder (on/off/refereret) +STR_MESSAGES_ALL :{YELLOW}Sæt alle beskedtyper til: Fra / Kortfattet / Fuld STR_MESSAGE_SOUND :{YELLOW}Afspil lyd for refererede nyheder STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...for langt fra forrige destination STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Bedste virksomheder, som har nået {NUM}{}({STRING} Niveau) @@ -694,7 +695,7 @@ STR_0270_CONSTRUCT_PRINTING_WORKS :{BLACK}Byg Trykkeri STR_0271_CONSTRUCT_GOLD_MINE :{BLACK}Byg Guldmine STR_0272_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Byg Bank (Kan kun bygges i en by) -STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Byg Tømmerfabrik (for at rydde regnskoven og producere træ) +STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Byg Træfabrik (for at rydde regnskoven og producere træ) STR_0274_PLANT_FRUIT_PLANTATION :{BLACK}Plant Frugtplantage STR_0275_PLANT_RUBBER_PLANTATION :{BLACK}Plant Gummiplantage STR_0276_CONSTRUCT_WATER_SUPPLY :{BLACK}Byg Vandværk @@ -769,7 +770,7 @@ STR_02C3_GAME_OPTIONS :Spilindstillinger STR_02C5_DIFFICULTY_SETTINGS :Sværhedsgrad STR_02C7_CONFIG_PATCHES :Konfigurér patches -STR_NEWGRF_SETTINGS :Newgrf indstillinger +STR_NEWGRF_SETTINGS :NewGRF indstillinger STR_GAMEOPTMENU_0A : STR_02CA_TOWN_NAMES_DISPLAYED :{SETX 12}Bynavne vist STR_02CC_STATION_NAMES_DISPLAYED :{SETX 12}Stationsnavne vist @@ -785,8 +786,8 @@ STR_02D5_LAND_BLOCK_INFO :Landområde information STR_02D6 : STR_CONSOLE_SETTING :Tænd/Sluk konsol -STR_02D7_SCREENSHOT_CTRL_S :Screenshot (Ctrl-S) -STR_02D8_GIANT_SCREENSHOT_CTRL_G :Kæmpe Screenshot (Ctrl-G) +STR_02D7_SCREENSHOT_CTRL_S :Skærmbillede (Ctrl-S) +STR_02D8_GIANT_SCREENSHOT_CTRL_G :Kæmpe skærmbillede (Ctrl-G) STR_02D9_ABOUT_OPENTTD :Om 'OpenTTD' ############ range ends here @@ -857,8 +858,8 @@ STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}...kan kun bygges i ørkenområder STR_0319_PAUSED :{YELLOW}* * PAUSE * * -STR_031B_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot gemt '{STRING}' -STR_031C_SCREENSHOT_FAILED :{WHITE}Fejl under tagning af screenshot! +STR_031B_SCREENSHOT_SUCCESSFULLY :{WHITE}Skærmbilledet blev gemt som '{STRING}' +STR_031C_SCREENSHOT_FAILED :{WHITE}Fejl under tagning af skærmbillede! STR_0329_PURCHASE_LAND_FOR_FUTURE :{BLACK}Køb land til senere brug STR_032F_AUTOSAVE :{RED}AUTOSAVE @@ -934,9 +935,9 @@ STR_OPTIONS_RES_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} STR_OPTIONS_RES_TIP :{BLACK}Vælg skørmopløsning -STR_OPTIONS_SCREENSHOT_FORMAT :{BLACK}Screenshot format +STR_OPTIONS_SCREENSHOT_FORMAT :{BLACK}Skærmbillede format STR_OPTIONS_SCREENSHOT_FORMAT_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} -STR_OPTIONS_SCREENSHOT_FORMAT_TIP :{BLACK}Vælg det format til screenshots +STR_OPTIONS_SCREENSHOT_FORMAT_TIP :{BLACK}Vælg skærmbillede format STR_AUTOSAVE_1_MONTH :Hver måned STR_AUTOSAVE_FAILED :{WHITE}Fejl under autogem @@ -976,7 +977,7 @@ STR_TRAIN_IS_LOST :{WHITE}Tog {COMMA} er faret vild. STR_TRAIN_IS_UNPROFITABLE :{WHITE}Tog {COMMA}'s profit sidste år var {CURRENCY} -STR_EURO_INTRODUCE :{BLACK}{BIGFONT}Europæisk fællesvaluta!{}{}Euroen er introduceret som eneste betalingsmiddel it dit land! +STR_EURO_INTRODUCE :{BLACK}{BIGFONT}Europæisk fællesvaluta!{}{}Euroen er introduceret som eneste betalingsmiddel i dit land! # Start of order review system. # DON'T ADD OR REMOVE LINES HERE @@ -995,7 +996,7 @@ STR_AIRCRAFT_HAS_TOO_FEW_ORDERS :{WHITE}Fly {COMMA} har for få ordre i sin flyveplan STR_AIRCRAFT_HAS_VOID_ORDER :{WHITE}Fly {COMMA} har en ugyldig ordre STR_AIRCRAFT_HAS_DUPLICATE_ENTRY :{WHITE}Fly {COMMA} har dobbelt ordre -STR_AIRCRAFT_HAS_INVALID_ENTRY :{WHITE}Fly {COMMA} har en ugyldig station i sin flyveplan +STR_AIRCRAFT_HAS_INVALID_ENTRY :{WHITE}Fly {COMMA} har en ugyldig lufthavn i sin flyveplan # end of order system STR_TRAIN_AUTORENEW_FAILED :{WHITE}Automatisk fornyelse af tog mislykkedes {COMMA} (ikke penge nok) @@ -1074,7 +1075,7 @@ STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE :Med uret STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT :{LTBLUE}Den højde et flat scenariekort får: {ORANGE}{STRING} -STR_CONFIG_PATCHES_STATION_SPREAD :{LTBLUE}Max station udbreddelse: {ORANGE}{STRING} {RED}Advarsel: Høj værdi gør spillet langsomt +STR_CONFIG_PATCHES_STATION_SPREAD :{LTBLUE}Maks. station udbreddelse: {ORANGE}{STRING} {RED}Advarsel: Høj værdi gør spillet langsomt STR_CONFIG_PATCHES_SERVICEATHELIPAD :{LTBLUE}Automatisk service på helikopterlandingspladser: {ORANGE}{STRING} STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR :{LTBLUE}Link landskabs værktøjsbaren til skinne/vej/vand/lufthavn værktøjsbaren: {ORANGE}{STRING} STR_CONFIG_PATCHES_REVERSE_SCROLLING :{LTBLUE}Når der scrolles med musen, flyt viewet i den modsatte retning: {ORANGE}{STRING} @@ -1185,7 +1186,7 @@ STR_NO_TOWN_IN_SCENARIO :{WHITE}...der er ingen byer i dette scenarie -STR_GENERATE_RANDOM_LANDSCAPE :{WHITE}Er du sikker på, at ud vil have lavet et tilfældigt landskab? +STR_GENERATE_RANDOM_LANDSCAPE :{WHITE}Er du sikker på, at du vil lave et tilfældigt landskab? STR_MANY_RANDOM_TOWNS :{BLACK}Mange tilfældige byer STR_RANDOM_TOWNS_TIP :{BLACK}Dæk kortet med tilfældigt placerede byer STR_MANY_RANDOM_INDUSTRIES :{BLACK}Mange tilfældige industrier @@ -1264,7 +1265,7 @@ STR_CONFIG_PATCHES_SERVINT_ISPERCENT :{LTBLUE}Service intervaller er i procent: {ORANGE}{STRING} STR_CONFIG_GAME_PRODUCTION :{WHITE}Skift produktion -TEMP_AI_IN_PROGRESS :{WHITE}Velkommen til den nye kunstige intelligents, der er under udarbejdelse. Du kan forvente problemer. Når det sker, så lav et screenshot og sæt det på forummet. +TEMP_AI_IN_PROGRESS :{WHITE}Velkommen til den nye kunstige intelligents, der er under udarbejdelse. Du kan forvente problemer. Når det sker, så lav et skærmbillede og sæt det på forummet. TEMP_AI_ACTIVATED :{WHITE}Advarsel: den nye kunstige intelligents er i et tidligt stadie! Lige nu virker den kun med busser og lastbiler! TEMP_AI_MULTIPLAYER :{WHITE}Advarsel: denne funktion er stadig eksperimentel. Rapporter venligst problemer til truelight@openttd.org. @@ -1308,6 +1309,7 @@ STR_NETWORK_SERVER_OFFLINE :{SILVER}SERVEREN ER OFFLINE STR_NETWORK_SERVER_FULL :{SILVER}SERVEREN ER FULD STR_NETWORK_VERSION_MISMATCH :{SILVER}Din og serverens version passer ikke sammen +STR_NETWORK_GRF_MISMATCH :{SILVER}NEWGRF MATCHER IKKE STR_NETWORK_JOIN_GAME :{BLACK}Tilslut dig et spil @@ -1339,10 +1341,10 @@ STR_NETWORK_8_PLAYERS :8 spillere STR_NETWORK_9_PLAYERS :9 spillere STR_NETWORK_10_PLAYERS :10 spillere -STR_NETWORK_NUMBER_OF_COMPANIES :{BLACK}Max firmaer: +STR_NETWORK_NUMBER_OF_COMPANIES :{BLACK}Maks. firmaer: STR_NETWORK_NUMBER_OF_COMPANIES_TIP :{BLACK}Begræns serveren to et bestemt antal firmaer STR_NETWORK_COMBO3 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} -STR_NETWORK_NUMBER_OF_SPECTATORS :{BLACK}Max tilskuere: +STR_NETWORK_NUMBER_OF_SPECTATORS :{BLACK}Maks. tilskuere: STR_NETWORK_NUMBER_OF_SPECTATORS_TIP :{BLACK}Begræns serveren til et bestemt antal tilskurere STR_NETWORK_COMBO4 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} STR_NETWORK_LANGUAGE_SPOKEN :{BLACK}Talt sprog: @@ -1613,7 +1615,7 @@ STR_201D_OFFICE_BLOCK :Kontorbygning STR_201E_STADIUM :Stadion STR_201F_OLD_HOUSES :Gamle huse -STR_2020_LOCAL_AUTHORITY :{BLACK}Lokale myndigheder +STR_2020_LOCAL_AUTHORITY :{BLACK}Myndigheder STR_2021_SHOW_INFORMATION_ON_LOCAL :{BLACK}Vis information om de lokale myndigheder STR_2022_LOCAL_AUTHORITY :{WHITE}{TOWN} lokal myndighed STR_2023_TRANSPORT_COMPANY_RATINGS :{BLACK}Transportselskabsbedømmelse: @@ -1840,7 +1842,7 @@ STR_4818_WATER_TOWER :Vandtårn STR_4819_FACTORY :Fabrik STR_481A_FARM :Bondegård -STR_481B_LUMBER_MILL :Tømmerfabrik +STR_481B_LUMBER_MILL :Træfabrik STR_481C_COTTON_CANDY_FOREST :Candyfloss Skov STR_481D_CANDY_FACTORY :Slikfabrik STR_481E_BATTERY_FARM :Batterigård @@ -2067,7 +2069,7 @@ STR_700F_EXPENDITURE_INCOME :{WHITE}Udgifter/Indkomst STR_7010 :{WHITE}{NUM} STR_7011_CONSTRUCTION :{GOLD}Konstruktion -STR_7012_NEW_VEHICLES :{GOLD}Nye Køretøjer +STR_7012_NEW_VEHICLES :{GOLD}Nye køretøjer STR_7013_TRAIN_RUNNING_COSTS :{GOLD}Togdriftsomkostning STR_7014_ROAD_VEH_RUNNING_COSTS :{GOLD}Køretøjsdriftsomkostning STR_7015_AIRCRAFT_RUNNING_COSTS :{GOLD}Flydriftsomkostning @@ -2087,9 +2089,9 @@ STR_CURRCOMPACT :{CURRCOMPACT64} STR_7024 :{COMMA} STR_7025_OPERATING_PROFIT_GRAPH :{WHITE}Profit Garf -STR_7026_BANK_BALANCE :{WHITE}Bank Balance +STR_7026_BANK_BALANCE :{WHITE}Bank balance STR_7027_LOAN :{WHITE}Lån -STR_MAX_LOAN :{WHITE}Max Lån: {BLACK}{CURRENCY64} +STR_MAX_LOAN :{WHITE}Maks. Lån: {BLACK}{CURRENCY64} STR_7028 :{BLACK}{CURRENCY64} STR_7029_BORROW :{BLACK}Lån {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} STR_702A_REPAY :{BLACK}Tilbagebetal {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} @@ -2503,8 +2505,8 @@ STR_HEADING_FOR_TRAIN_DEPOT :{ORANGE}Kører til {TOWN} Remise STR_HEADING_FOR_TRAIN_DEPOT_VEL :{ORANGE}Kører til {TOWN} Remise, {VELOCITY} -STR_HEADING_FOR_TRAIN_DEPOT_SERVICE :{LTBLUE}Eftersyn på {TOWN} Remise -STR_HEADING_FOR_TRAIN_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn i {TOWN} Remise, {VELOCITY} +STR_HEADING_FOR_TRAIN_DEPOT_SERVICE :{LTBLUE}Eftersyn i {TOWN} remise +STR_HEADING_FOR_TRAIN_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn i {TOWN} remise, {VELOCITY} STR_INVALID_ORDER :{RED} (Ugyldig Order) @@ -2526,10 +2528,10 @@ STR_ALL_AVAIL_RAIL_VEHICLES :{WHITE}Jernbanekøretøjer STR_881F_BUILD_VEHICLE :{BLACK}Byg Køretøj -STR_CLONE_ROAD_VEHICLE :{BLACK}Klon Køretøj +STR_CLONE_ROAD_VEHICLE :{BLACK}Klon køretøj STR_CLONE_ROAD_VEHICLE_INFO :{BLACK}Dette vil bygge en kopi af køretøjet. Control-click vil dele ordre STR_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Dette vil bygge en kopi af køretøjet. Klik på denne knap, så på et køretøj indeni eller udenfor værkstedet. Control-click vil dele ordre -STR_CLONE_TRAIN :{BLACK}Klon Tog +STR_CLONE_TRAIN :{BLACK}Klon tog STR_CLONE_TRAIN_INFO :{BLACK}Dette vil bygge en kopi af toget inklusiv alle vogne. Control-click vil dele ordre STR_CLONE_TRAIN_DEPOT_INFO :{BLACK}Dette vil bygge en kopi af toget inklusiv alle vogne. Klik på denne knap, så på et tog indeni eller udenfor remisen. Control-click vil dele ordre STR_8820_RENAME :{BLACK}Omdøb @@ -2601,7 +2603,8 @@ STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER :{BLACK}Pris: {CURRENCY} Vægt: {WEIGHT_S}{}Hastighed: {VELOCITY} Styrke: {POWER}{}Driftsomkostninger: {CURRENCY}/år{}Kapacitet: {CARGO} STR_885C_BROKEN_DOWN :{RED}Gået i stykker STR_885D_AGE_RUNNING_COST_YR :{BLACK}Alder: {LTBLUE}{STRING}{BLACK} Kørselsomkostning: {LTBLUE}{CURRENCY}/år -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Vægt: {LTBLUE}{WEIGHT_S} {BLACK}Styrke: {LTBLUE}{POWER}{BLACK} Maks hastighed: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Vægt: {LTBLUE}{WEIGHT_S} {BLACK}Styrke: {LTBLUE}{POWER}{BLACK} Maks. hastighed: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Vægt: {LTBLUE}{WEIGHT_S} {BLACK}Kraft: {LTBLUE}{POWER}{BLACK} Maks. hastighed: {LTBLUE}{VELOCITY} {BLACK}Maks. trækkraft: {LTBLUE}{FORCE} STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Dette års profit: {LTBLUE}{CURRENCY} (sidste år: {CURRENCY}) STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}Pålidelighed {LTBLUE}{COMMA}% {BLACK}nedbrud siden sidste service: {LTBLUE}{COMMA} STR_8861_STOPPED :{RED}Stoppet @@ -2635,7 +2638,7 @@ STR_9009_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Kan ikke bygge køretøj... STR_900C_DETAILS :{WHITE}{VEHICLE} (Detaljer) STR_900D_AGE_RUNNING_COST_YR :{BLACK}Alder: {LTBLUE}{STRING}{BLACK} Kørselsomkostning: {LTBLUE}{CURRENCY}/år -STR_900E_MAX_SPEED :{BLACK}Maks hastighed: {LTBLUE}{VELOCITY} +STR_900E_MAX_SPEED :{BLACK}Maks. hastighed: {LTBLUE}{VELOCITY} STR_900F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Dette års profit: {LTBLUE}{CURRENCY} (sidste år: {CURRENCY}) STR_9010_RELIABILITY_BREAKDOWNS :{BLACK}Pålidelighed: {LTBLUE}{COMMA}% {BLACK}Nedbrud siden sidste service: {LTBLUE}{COMMA} STR_9011_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Bygget: {LTBLUE}{NUM}{BLACK} Værdi: {LTBLUE}{CURRENCY} @@ -2646,8 +2649,8 @@ STR_9016_ROAD_VEHICLE_IS_WAITING :{WHITE}Køretøj {COMMA} venter i værksted STR_HEADING_FOR_ROAD_DEPOT :{ORANGE}Kører til {TOWN} Værksted STR_HEADING_FOR_ROAD_DEPOT_VEL :{ORANGE}Kører til {TOWN} Værksted, {VELOCITY} -STR_HEADING_FOR_ROAD_DEPOT_SERVICE :{LTBLUE}Eftersyn på {TOWN} Værksted -STR_HEADING_FOR_ROAD_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn på {TOWN} Værksted, {VELOCITY} +STR_HEADING_FOR_ROAD_DEPOT_SERVICE :{LTBLUE}Eftersyn på {TOWN} værksted +STR_HEADING_FOR_ROAD_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn på {TOWN} værksted, {VELOCITY} STR_9018_CAN_T_SEND_VEHICLE_TO_DEPOT :{WHITE}Kan ikke sende køretøj til værksted... STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Kan ikke finde lokalt værksted STR_901A_ROAD_VEHICLES_CLICK_ON :{BLACK}Køretøjer - klik på et køretøj for information @@ -2699,7 +2702,7 @@ STR_9805_SHIPS :{WHITE}{COMPANY} - {COMMA} Skibe STR_9808_NEW_SHIPS :{WHITE}Nye skibe STR_9809_BUILD_SHIP :{BLACK}Byg skib -STR_CLONE_SHIP :{BLACK}Klon Skib +STR_CLONE_SHIP :{BLACK}Klon skib STR_CLONE_SHIP_INFO :{BLACK}Dette vil bygge en kopi af skibet. Control-click vil dele ordre STR_CLONE_SHIP_DEPOT_INFO :{BLACK}Dette vil bygge en kopi af skibet. Klik på denne knap så, på et skib indeni eller udenfor dokken. Control-click vil dele ordre STR_980B_SHIP_MUST_BE_STOPPED_IN :{WHITE}Skibet skal være stoppet i dok @@ -2709,7 +2712,7 @@ STR_980F :{WHITE}{VEHICLE} STR_9811_DETAILS :{WHITE}{VEHICLE} (Detaljer) STR_9812_AGE_RUNNING_COST_YR :{BLACK}Alder: {LTBLUE}{STRING}{BLACK} Kørselsomkostning: {LTBLUE}{CURRENCY}/år -STR_9813_MAX_SPEED :{BLACK}Maks hastighed: {LTBLUE}{VELOCITY} +STR_9813_MAX_SPEED :{BLACK}Maks. hastighed: {LTBLUE}{VELOCITY} STR_9814_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Dette års profit: {LTBLUE}{CURRENCY} (sidste år: {CURRENCY}) STR_9815_RELIABILITY_BREAKDOWNS :{BLACK}Pålidelighed: {LTBLUE}{COMMA}% {BLACK}Nedbrud siden sidste service: {LTBLUE}{COMMA} STR_9816_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Bygget: {LTBLUE}{NUM}{BLACK} Værdi: {LTBLUE}{CURRENCY} @@ -2719,8 +2722,8 @@ STR_981A_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Kan ikke finde lokal dok STR_HEADING_FOR_SHIP_DEPOT :{ORANGE}Sejler til {TOWN} Dok STR_HEADING_FOR_SHIP_DEPOT_VEL :{ORANGE}Sejler til {TOWN} Dok, {VELOCITY} -STR_HEADING_FOR_SHIP_DEPOT_SERVICE :{LTBLUE}Eftersyn i {TOWN} Dok -STR_HEADING_FOR_SHIP_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn i {TOWN} Dok, {VELOCITY} +STR_HEADING_FOR_SHIP_DEPOT_SERVICE :{LTBLUE}Eftersyn i {TOWN} skibsdok +STR_HEADING_FOR_SHIP_DEPOT_SERVICE_VEL :{LTBLUE}Eftersyn i {TOWN} skibsdok, {VELOCITY} STR_981C_SHIP_IS_WAITING_IN_DEPOT :{WHITE}Skib {COMMA} venter i dok STR_981D_BUILD_SHIP_DOCK :{BLACK}Byg havn STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING :{BLACK}Byg skibsdok (til bygning og servicering af skibe) @@ -2739,7 +2742,7 @@ STR_982B_SHOW_SHIP_DETAILS :{BLACK}Vis detaljer omkring skibet STR_982C_NEW_SHIP_NOW_AVAILABLE :{BLACK}{BIGFONT}Nyt skib er tilgængeligt! STR_982D :{BLACK}{BIGFONT}{STRING} -STR_982E_COST_MAX_SPEED_CAPACITY :{BLACK}Pris: {CURRENCY} Maks Hastighed: {VELOCITY}{}Kapacitet: {CARGO}{}Kørselsomkostning: {CURRENCY}/år +STR_982E_COST_MAX_SPEED_CAPACITY :{BLACK}Pris: {CURRENCY} Maks. hastighed: {VELOCITY}{}Kapacitet: {CARGO}{}Kørselsomkostning: {CURRENCY}/år STR_982F_NAME_SHIP :{BLACK}Giv skibet et navn STR_9831_NAME_SHIP :{WHITE}Giv skibet et navn @@ -2779,15 +2782,15 @@ STR_A00B_ORDERS :{WHITE}{VEHICLE} (Ordre) STR_A00C_DETAILS :{WHITE}{VEHICLE} (Detaljer) STR_A00D_AGE_RUNNING_COST_YR :{BLACK}Alder: {LTBLUE}{STRING}{BLACK} Kørselsomkostning: {LTBLUE}{CURRENCY}/år -STR_A00E_MAX_SPEED :{BLACK}Maks hastighed: {LTBLUE}{VELOCITY} +STR_A00E_MAX_SPEED :{BLACK}Maks. hastighed: {LTBLUE}{VELOCITY} STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Dette års profit: {LTBLUE}{CURRENCY} (sidste år: {CURRENCY}) STR_A010_RELIABILITY_BREAKDOWNS :{BLACK}Pålidelighed: {LTBLUE}{COMMA}% {BLACK}Nedbrud siden sidste service: {LTBLUE}{COMMA} STR_A011_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Bygget: {LTBLUE}{NUM}{BLACK} Værdi: {LTBLUE}{CURRENCY} STR_A012_CAN_T_SEND_AIRCRAFT_TO :{WHITE}Kan ikke sende flyet til en hangar... STR_HEADING_FOR_HANGAR :{ORANGE}Flyver til {STATION} Hangar STR_HEADING_FOR_HANGAR_VEL :{ORANGE}Flyver til {STATION} Hangar, {VELOCITY} -STR_HEADING_FOR_HANGAR_SERVICE :{LTBLUE}Eftersyn i {STATION} Hangar -STR_HEADING_FOR_HANGAR_SERVICE_VEL :{LTBLUE}Eftersyn i {STATION} Hangar, {VELOCITY} +STR_HEADING_FOR_HANGAR_SERVICE :{LTBLUE}Eftersyn i {STATION} hangar +STR_HEADING_FOR_HANGAR_SERVICE_VEL :{LTBLUE}Eftersyn i {STATION} hangar, {VELOCITY} STR_A014_AIRCRAFT_IS_WAITING_IN :{WHITE}Fly {COMMA} venter i flyhangar STR_A015_AIRCRAFT_IN_THE_WAY :{WHITE}Fly i vejen STR_A016_CAN_T_STOP_START_AIRCRAFT :{WHITE}Kan ikke stoppe/starte fly... @@ -2813,7 +2816,7 @@ STR_A02B_SHOW_AIRCRAFT_DETAILS :{BLACK}Vis detaljet omkring flyet STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE :{BLACK}{BIGFONT}Nyt fly tilgængeligt! STR_A02D :{BLACK}{BIGFONT}{STRING} -STR_A02E_COST_MAX_SPEED_CAPACITY :{BLACK}Pris: {CURRENCY} Maks hastighed: {VELOCITY}{}Kapacitet: {COMMA} passagerer, {COMMA} sække post{}Kørselsomkostning: {CURRENCY}/år +STR_A02E_COST_MAX_SPEED_CAPACITY :{BLACK}Pris: {CURRENCY} Maks. hastighed: {VELOCITY}{}Kapacitet: {COMMA} passagerer, {COMMA} sække post{}Kørselsomkostning: {CURRENCY}/år STR_A030_NAME_AIRCRAFT :{WHITE}Navngiv flyet STR_A031_CAN_T_NAME_AIRCRAFT :{WHITE}Kan ikke navngive flyet... @@ -2861,7 +2864,7 @@ STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stationer: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Minimum profit: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Minimum indkomst: -STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. indtægt: +STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Maks. indtægt: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Afleveret: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Last: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Penge: @@ -2880,17 +2883,38 @@ STR_PERFORMANCE_DETAIL_TOTAL_TIP :{BLACK}Samlet point af max point STR_NEWGRF_SETTINGS_BUTTON :{BLACK}NewGRF indstillinger -STR_NEWGRF_SETTINGS_CAPTION :{WHITE}Newgrf indstillinger +STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF indstillinger STR_NEWGRF_APPLY_CHANGES :{BLACK}Anvend ændringer -STR_NEWGRF_SET_PARAMETERS :{BLACK}Indstil parametre +STR_NEWGRF_SET_PARAMETERS :{BLACK}Indstil parameter STR_NEWGRF_TIP :{BLACK}Liste med alle Newgrf sæt du har installeret. Marker et sæt for at ændre indstilliger. -STR_NEWGRF_NO_FILES_INSTALLED :{BLACK}Der er ingen newgrf filer installeret! Du kan læse i manualen hvordan man installerer newgrf sæt. +STR_NEWGRF_NO_FILES_INSTALLED :{BLACK}Der er ingen newgrf filer installeret! Læs venligst om installation af nye grafiksæt i manualen STR_NEWGRF_FILENAME :{BLACK}Filnavn: {SILVER}{STRING} STR_NEWGRF_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} +STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Du er ved at lave ændringer i et igangværende spil; dette kan få OpenTTD til at gå ned.{}Er du helt sikker på at du vil fortsætte? +STR_NEWGRF_ADD :{BLACK}Tilføj +STR_NEWGRF_ADD_TIP :{BLACK}Tilføj et NewGRF sæt til listen +STR_NEWGRF_REMOVE :{BLACK}Fjern +STR_NEWGRF_REMOVE_TIP :{BLACK}Fjern det valgte NewGRF sæt fra listen +STR_NEWGRF_MOVEUP :{BLACK}Flyt op +STR_NEWGRF_MOVEUP_TIP :{BLACK}Flyt det valgte NewGRF sæt op i listen +STR_NEWGRF_MOVEDOWN :{BLACK}Flyt ned +STR_NEWGRF_MOVEDOWN_TIP :{BLACK}Flyt det valgte NewGRF sæt ned i listen +STR_NEWGRF_FILE_TIP :{BLACK}En liste over de NewGRF sæt der er installeret. Klik på et sæt for at ændre dets parameter +STR_NEWGRF_PARAMETER :{BLACK}Parameter: {SILVER}{STRING} +STR_NEWGRF_PARAMETER_QUERY :{BLACK}Indtast NewGRF-parameter +STR_NEWGRF_NO_INFO :{BLACK}Ingen information tilgængelig +STR_NEWGRF_ADD_CAPTION :{WHITE}Tilgængelige NewGRF sæt +STR_NEWGRF_ADD_FILE :{BLACK}Tilføj til udvalg +STR_NEWGRF_ADD_FILE_TIP :{BLACK}Tilføj det valgte NewGRF sæt til din konfiguration +STR_NEWGRF_RESCAN_FILES :{BLACK}Genfind filer +STR_NEWGRF_RESCAN_FILES_TIP :{BLACK}Opdater listen over tilgængelige NewGRF sæt +STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Kan ikke tilføje sæt: dobbelt GRF ID +STR_NEWGRF_NOT_FOUND :{RED}Tilsvarende fil blev ikke fundet +STR_NEWGRF_DISABLED :{RED}Deaktiveret STR_CURRENCY_WINDOW :{WHITE}Brugerdefineret møntfod STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Kurs: {ORANGE}{CURRENCY} = £ {COMMA} @@ -2922,6 +2946,8 @@ STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}Vis alle transportmidler, som har den samme rute ### depot strings +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Du er ved at sælge alle køretøjer i depotet. Er du sikker? + STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP :{BLACK}Sælg alle toge i remisen STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP :{BLACK}Sælg alle køretøjer i værkstedet STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP :{BLACK}Sælg alle skibe i dokken @@ -2997,8 +3023,8 @@ STR_PURCHASE_INFO_SPEED :{BLACK}Hastighed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Kørselsudgift: {GOLD}{CURRENCY}/år STR_PURCHASE_INFO_CAPACITY :{BLACK}Lasteevne: {GOLD}{CARGO} {STRING} -STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designet: {GOLD}{NUM}{BLACK} Liv: {GOLD}{COMMA} år -STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Pålidelighed: {GOLD}{COMMA}% +STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designet: {GOLD}{NUM}{BLACK} Levealder: {GOLD}{COMMA} år +STR_PURCHASE_INFO_RELIABILITY :{BLACK}Maks. pålidelighed: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Pris: {GOLD}{CURRENCY} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Vægt: {GOLD}{WEIGHT_S} ({WEIGHT_S}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Pris: {GOLD}{CURRENCY}{BLACK} Hastighed: {GOLD}{VELOCITY} @@ -3007,6 +3033,7 @@ STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Kan ombygges til: {GOLD} STR_PURCHASE_INFO_ALL_TYPES :Alle lasttyper STR_PURCHASE_INFO_ALL_BUT :Alle undtagen {GOLD} +STR_PURCHASE_INFO_MAX_TE :{BLACK}Maks. trækkraft: {GOLD}{FORCE} ########### String for New Landscape Generator @@ -3036,10 +3063,10 @@ STR_SNOW_LINE_HEIGHT_NUM :{NUM} STR_HEIGHTMAP_NAME :{BLACK}Højdekortets navn: STR_HEIGHTMAP_SIZE :{BLACK}Størrelse: {ORANGE}{NUM} x {NUM} -STR_GENERATION_WORLD :{WHITE}Generere verden... +STR_GENERATION_WORLD :{WHITE}Genererer verden... STR_GENERATION_ABORT :{BLACK}Afbryd -STR_GENERATION_ABORT_CAPTION :{WHITE}Afbryd Kort Genereringen -STR_GENERATION_ABORT_MESSAGE :{YELLOW}Vil du virkelig afbryde kort genereringen? +STR_GENERATION_ABORT_CAPTION :{WHITE}Afbryd Kortgenereringen +STR_GENERATION_ABORT_MESSAGE :{YELLOW}Vil du virkelig afbryde kortgenereringen? STR_PROGRESS :{WHITE}{NUM}% færdig STR_GENERATION_PROGRESS :{BLACK}{NUM} / {NUM} STR_WORLD_GENERATION :{BLACK}Verdensgenerering @@ -3055,10 +3082,10 @@ STR_SE_RANDOM_LAND :{WHITE}Tilfældigt land STR_SE_NEW_WORLD :{BLACK}Opret nyt scenarie STR_SE_CAPTION :{WHITE}Scenarietype -STR_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Flyt højden af flat land en ned -STR_FLAT_WORLD_HEIGHT_UP :{BLACK}Flyt højden af flat land en up -STR_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Ændre højden af flat land -STR_FLAT_WORLD_HEIGHT :{BLACK}Højde af flat land: +STR_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Flyt højden af fladt land en ned +STR_FLAT_WORLD_HEIGHT_UP :{BLACK}Flyt højden af fladt land en op +STR_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Ændre højden af fladt land +STR_FLAT_WORLD_HEIGHT :{BLACK}Højde af fladt land: STR_FLAT_WORLD_HEIGHT_NUM :{NUM} STR_SMALLMAP_CENTER :{BLACK}Centrer det lille kort ved den nuværende position diff -r d4d00a16ef26 -r bfa6074e2833 lang/esperanto.txt --- a/lang/esperanto.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/esperanto.txt Wed Jan 03 08:32:17 2007 +0000 @@ -14,7 +14,7 @@ STR_EMPTY : STR_0007_FLAT_LAND_REQUIRED :{WHITE}Necesas ebena lando STR_0008_WAITING :{BLACK}Atendas: {WHITE}{STRING} -STR_0009 :{WHITE}{CARGO} +STR_0009 :{WHITE} {CARGO} STR_000A_EN_ROUTE_FROM :{WHITE}{CARGO}{YELLOW} (survoje de STR_000B :{YELLOW}{STATION}) STR_000C_ACCEPTS :{BLACK}Akceptas: {WHITE} @@ -1024,6 +1024,7 @@ STR_CONFIG_PATCHES_IMPROVEDLOAD :{LTBLUE}Uzu plibonigitan ŝarĝalgoritmon: {ORANGE}{STRING} STR_CONFIG_PATCHES_GRADUAL_LOADING :{LTBLUE}Laŭgrade ŝarĝu veturilojn: {ORANGE}{STRING} STR_CONFIG_PATCHES_INFLATION :{LTBLUE}Inflacio: {ORANGE}{STRING} +STR_CONFIG_PATCHES_SELECTGOODS :{LTBLUE}Nur liveru ŝarĝon al stacio se estas peto: {ORANGE}{STRING} STR_CONFIG_PATCHES_LONGBRIDGES :{LTBLUE}Permesu konstruadon de tre longaj pontoj: {ORANGE}{STRING} STR_CONFIG_PATCHES_GOTODEPOT :{LTBLUE}Permesu ordenojn por iri al deponejo: {ORANGE}{STRING} STR_CONFIG_PATCHES_BUILDXTRAIND :{LTBLUE}Permesu konstruadon de fontmalerialaj industrioj: {ORANGE}{STRING} @@ -1309,6 +1310,7 @@ STR_NETWORK_SERVER_OFFLINE :{SILVER}SERVILO NE SURRETAS STR_NETWORK_SERVER_FULL :{SILVER}SERVILO PLENAS STR_NETWORK_VERSION_MISMATCH :{SILVER}VERSIOJ NE KONGRUAS +STR_NETWORK_GRF_MISMATCH :{SILVER}MISO PRI NEWGRF STR_NETWORK_JOIN_GAME :{BLACK}Aliĝu al la ludo @@ -1502,6 +1504,8 @@ STR_0808_CAN_T_RAISE_LAND_HERE :{WHITE}Ne povas altigi landon ĉi tie... STR_0809_CAN_T_LOWER_LAND_HERE :{WHITE}Ne povas malaltigi landon ĉi tie... STR_080A_ROCKS :Rokoj +STR_080B_ROUGH_LAND :Malglata lando +STR_080C_BARE_LAND :Nuda lando STR_080D_GRASS :Herbo STR_080E_FIELDS :Kampoj STR_080F_SNOW_COVERED_LAND :Neĝkovrita lando @@ -1579,6 +1583,10 @@ ##id 0x2000 STR_2000_TOWNS :{WHITE}Urboj +STR_TOWN_LABEL_POP :{WHITE}{TOWN} ({COMMA}) +STR_TOWN_LABEL :{WHITE}{TOWN} +STR_TOWN_LABEL_TINY_BLACK :{TINYFONT}{BLACK}{TOWN} +STR_TOWN_LABEL_TINY_WHITE :{TINYFONT}{WHITE}{TOWN} STR_2002 :{TINYFONT}{BLACK}{STRING} STR_2004_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Antaŭe forigu konstruaĵon STR_2005 :{WHITE}{TOWN} @@ -1652,6 +1660,7 @@ STR_204A_BUILD_STATUE_OF_COMPANY :Konstruu statuon de la kompaniestro STR_204B_FUND_NEW_BUILDINGS :Fondu novajn konstruaĵojn STR_204C_BUY_EXCLUSIVE_TRANSPORT :Aĉetu ekskluzivan transportrajton +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY :Subaĉetu la lokajn estrojn STR_204D_INITIATE_A_SMALL_LOCAL :{WHITE}{STRING}{}{YELLOW} Komencu malgrandan lokan reklamadon, por altiri pli da pasaĝeroj kaj ŝarĝoj al viaj transportservoj.{} Kosto: {CURRENCY} STR_204E_INITIATE_A_MEDIUM_LOCAL :{WHITE}{STRING}{}{YELLOW} Komencu mezgrandan lokan reklamadon, por altiri pli da pasaĝeroj kaj ŝarĝoj al viaj transportservoj.{} Kosto: {CURRENCY} STR_204F_INITIATE_A_LARGE_LOCAL :{WHITE}{STRING}{}{YELLOW} Komencu grandan lokan reklamadon, por altiri pli da pasaĝeroj kaj ŝarĝoj al viaj transportservoj.{} Kosto: {CURRENCY} @@ -1659,6 +1668,7 @@ STR_2051_BUILD_A_STATUE_IN_HONOR :{WHITE}{STRING}{}{YELLOW} Konstruu statuon honore al via kompanio.{} Kosto: {CURRENCY} STR_2052_FUND_THE_CONSTRUCTION_OF :{WHITE}{STRING}{}{YELLOW} Fondu la konstruadon de novaj komercaj konstruaĵoj en la urbo.{} Kosto: {CURRENCY} STR_2053_BUY_1_YEAR_S_EXCLUSIVE :{WHITE}{STRING}{}{YELLOW} Aĉetu ekskluzivan transportrajton en la urbo por 1 jaro. La urbo nur permesos pasaĝerojn kaj ŝarĝojn uzi viajn staciojn {} Cost: {CURRENCY} +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY_DESC :{WHITE}{STRING}{}{YELLOW} Subaĉetu la lokajn estrojn por pliigi vian rendimenton, riskante grandan punon je kapto.{} Kosto: {CURRENCY} STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING :{BIGFONT}{BLACK}Trafika ĥaoso en {TOWN}!{}{}Vojrekonstruada programo komencita de {COMPANY} alportas 6-monatan mizeron al vojuzantoj! STR_2056 :{TINYFONT}{WHITE}{TOWN} STR_2057 :{ORANGE}{TOWN}{BLACK} ({COMMA}) @@ -1669,7 +1679,9 @@ STR_205C_PIGGY_BANK :Porko-Banko STR_INDUSTRY :{INDUSTRY} +STR_TOWN :{TOWN} STR_INDUSTRY_FORMAT :{TOWN} {STRING} +STR_STATION :{STATION} ##id 0x2800 STR_LANDSCAPING :Landaspektigi @@ -1734,6 +1746,7 @@ STR_3043_TRUCK_STATION_ORIENT :{WHITE}Ŝarĝstacia Direkto STR_3046_MUST_DEMOLISH_BUS_STATION :{WHITE}Antaŭe forigu bushaltejon STR_3047_MUST_DEMOLISH_TRUCK_STATION :{WHITE}Antaŭe forigu ŝarĝstacion +STR_3048_STATIONS :{WHITE}{COMPANY} - {COMMA} Stacio{P "" j} STR_3049_0 :{YELLOW}{STATION} {STATIONFEATURES} STR_304A_NONE :{YELLOW}- Neniu - STR_304B_SITE_UNSUITABLE :{WHITE}...loko ne uzeblas @@ -1751,6 +1764,7 @@ STR_3057_STATION_NAMES_CLICK_ON :{BLACK}Staciaj nomoj - alklaku nomon por centre de la ĉefvido vidi ĝin STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT :{BLACK}Elektu grandecon/tipon de flughaveno STR_305C_0 :{STATION} {STATIONFEATURES} +STR_STATION_SIGN_TINY :{TINYFONT}{STATION} STR_305E_RAILROAD_STATION :Stacidomo STR_305F_AIRCRAFT_HANGAR :Aviadila hangaro STR_3060_AIRPORT :Flughaveno @@ -1765,7 +1779,11 @@ STR_306A_BUOY_IN_THE_WAY :{WHITE}...buo okupas la lokon STR_306C_STATION_TOO_SPREAD_OUT :{WHITE}...stacio tro vastas STR_306D_NONUNIFORM_STATIONS_DISALLOWED :{WHITE}...nekonformaj stacioj neebligitaj +STR_USE_CTRL_TO_SELECT_MORE :{BLACK}Tenu la CTRL-klavon por elekti pliajn erojn +STR_UNDEFINED :(nedifinita tekstero) +STR_STAT_CLASS_DFLT :Defaŭlta stacio +STR_STAT_CLASS_WAYP :Transirejoj ##id 0x3800 STR_3800_SHIP_DEPOT_ORIENTATION :{WHITE}Ŝipdeponeja Direkto @@ -1783,6 +1801,7 @@ STR_4002_SAVE :{BLACK}Konservu STR_4003_DELETE :{BLACK}Forviŝu STR_4004 :{COMPANY} je {DATE_LONG} +STR_4005_BYTES_FREE :{BLACK}{COMMA} megabitoko{P "" j} libera{P "" j} STR_4006_UNABLE_TO_READ_DRIVE :{BLACK}Ne eblas legi diskon STR_4007_GAME_SAVE_FAILED :{WHITE}Ludkonservado Fiaskis STR_4008_UNABLE_TO_DELETE_FILE :{WHITE}Ne eblas forviŝi dosieron @@ -1917,6 +1936,12 @@ ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 +STR_SV_EMPTY : +STR_SV_UNNAMED :Sennome +STR_SV_TRAIN_NAME :Trajno {COMMA} +STR_SV_ROADVEH_NAME :Vojveturilo {COMMA} +STR_SV_SHIP_NAME :Ŝipo {COMMA} +STR_SV_AIRCRAFT_NAME :Aviadilo {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :Norda {STRING} @@ -2031,12 +2056,12 @@ STR_7000 : STR_7001 :{WHITE}{COMPANY} {BLACK}{PLAYERNAME} STR_7002_PLAYER :(Ludanto {COMMA}) -STR_7004_NEW_FACE :{BLACK}Novan Vizaĝon +STR_7004_NEW_FACE :{BLACK}Nova Vizaĝo STR_7005_COLOR_SCHEME :{BLACK}Kolorskemo STR_7006_COLOR_SCHEME :{GOLD}Kolorskemo: -STR_7007_NEW_COLOR_SCHEME :{WHITE}Novan Kolorskemon -STR_7008_COMPANY_NAME :{BLACK}Kompania Nomo -STR_7009_PRESIDENT_NAME :{BLACK}Manaĝanta Nomo +STR_7007_NEW_COLOR_SCHEME :{WHITE}Nova Kolorskemo +STR_7008_COMPANY_NAME :{BLACK}Kompaninomo +STR_7009_PRESIDENT_NAME :{BLACK}Manaĝantnomo STR_700A_COMPANY_NAME :Kompania Nomo STR_700B_PRESIDENT_S_NAME :Nomo de la Manaĝanto STR_700C_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Ne povas ŝanĝi kompaninomon... @@ -2095,7 +2120,7 @@ STR_7043_FACE_SELECTION :{WHITE}Vizaĝelekto STR_7044_MALE :{BLACK}Vira STR_7045_FEMALE :{BLACK}Virina -STR_7046_NEW_FACE :{BLACK}Novan Vizaĝon +STR_7046_NEW_FACE :{BLACK}Nova Vizaĝo STR_7047_CANCEL_NEW_FACE_SELECTION :{BLACK}Nuligu elekton de nova vizaĝo STR_7048_ACCEPT_NEW_FACE_SELECTION :{BLACK}Akceptu elekton de nova vizaĝo STR_7049_SELECT_MALE_FACES :{BLACK}Elektu virajn vizaĝojn @@ -2149,12 +2174,12 @@ STR_7074_RECESSION_OVER_UPTURN_IN :{BIGFONT}{BLACK}Recesio finiĝis!{}{}Komerca pliboniĝos donas konfidon al industrioj! Ekonomio pliboniĝas! STR_7075_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Ŝaltu inter granda kaj malgranda fenestro STR_7076_COMPANY_VALUE :{GOLD}Kompania valoro: {WHITE}{CURRENCY64} -STR_7077_BUY_25_SHARE_IN_COMPANY :{BLACK}Aĉetu 25%-an dividaĵon en kompanio -STR_7078_SELL_25_SHARE_IN_COMPANY :{BLACK}Vendu 25%-an dividaĵon en kompanio +STR_7077_BUY_25_SHARE_IN_COMPANY :{BLACK}Aĉetu 25%-an dividaĵon +STR_7078_SELL_25_SHARE_IN_COMPANY :{BLACK}Vendu 25%-an dividaĵon STR_7079_BUY_25_SHARE_IN_THIS_COMPANY :{BLACK}Aĉetu 25%-an dividaĵon en ĉi tiu kompanio STR_707A_SELL_25_SHARE_IN_THIS_COMPANY :{BLACK}Vendu 25%-an dividaĵon en ĉi tiu kompanio -STR_707B_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Ne povas aĉeti 25%-an dividaĵon en ĉi tiu kompanio... -STR_707C_CAN_T_SELL_25_SHARE_IN :{WHITE}Ne povas vendi 25%-an dividaĵon en ĉi tiu kompanio... +STR_707B_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Ne povas aĉeti 25%-an dividaĵon... +STR_707C_CAN_T_SELL_25_SHARE_IN :{WHITE}Ne povas vendi 25%-an dividaĵon... STR_707D_OWNED_BY :{WHITE}({COMMA}% posedataj de {COMPANY}) STR_707E_OWNED_BY_OWNED_BY :{WHITE}({COMMA}% posedataj de {COMPANY}{} {COMMA}% posedataj de {COMPANY}) STR_707F_HAS_BEEN_TAKEN_OVER_BY :{BLACK}{BIGFONT}{COMPANY} estas transprenita de {COMPANY}! @@ -2322,9 +2347,9 @@ STR_8081_MIGHTYMOVER_MAIL_TRUCK :Poŝtaŭto "MightyMover" STR_8082_POWERNAUGHT_MAIL_TRUCK :Poŝtaŭto "Powernaught" STR_8083_WIZZOWOW_MAIL_TRUCK :Poŝtaŭto "Wizzowow" -STR_8084_WITCOMBE_OIL_TANKER :Oleŝipo "Witcombe" -STR_8085_FOSTER_OIL_TANKER :Oleŝipo "Foster" -STR_8086_PERRY_OIL_TANKER :Oleŝipo "Perry" +STR_8084_WITCOMBE_OIL_TANKER :Oleŝarĝaŭto "Witcombe" +STR_8085_FOSTER_OIL_TANKER :Oleŝarĝaŭto "Foster" +STR_8086_PERRY_OIL_TANKER :Oleŝarĝaŭto "Perry" STR_8087_TALBOTT_LIVESTOCK_VAN :Brutŝarĝaŭto "Talbott" STR_8088_UHL_LIVESTOCK_VAN :Brutŝarĝaŭto "Uhl" STR_8089_FOSTER_LIVESTOCK_VAN :Brutŝarĝaŭto "Foster" @@ -2580,7 +2605,7 @@ STR_885C_BROKEN_DOWN :{RED}Rompite STR_885D_AGE_RUNNING_COST_YR :{BLACK}Aĝo: {LTBLUE}{STRING}{BLACK} Irkosto: {LTBLUE}po {CURRENCY} jare STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Pezo: {LTBLUE}{WEIGHT_S} {BLACK}Forto: {LTBLUE}{POWER}{BLACK} Pleja rapideco: {LTBLUE}{VELOCITY} -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Pezo: {LTBLUE}{WEIGHT_S} {BLACK}Forto: {LTBLUE}{POWER}{BLACK} Pleja rapideco: {LTBLUE}{VELOCITY} {BLACK}Pleja T.E.: {LTBLUE}{FORCE} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Pezo: {LTBLUE}{WEIGHT_S} {BLACK}Forto: {LTBLUE}{POWER}{BLACK} Pleja rapido: {LTBLUE}{VELOCITY} {BLACK}Pleja tiro: {LTBLUE}{FORCE} STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Ĉi-jara gajno: {LTBLUE}{CURRENCY} (lastjara: {CURRENCY}) STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}Fidebleco: {LTBLUE}{COMMA}% {BLACK}Rompiĝoj post lasta prizorgo: {LTBLUE}{COMMA} STR_8861_STOPPED :{RED}Haltis @@ -2605,6 +2630,7 @@ ##id 0x9000 STR_9000_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Vojveturilo okupas la lokon +STR_9001_ROAD_VEHICLES :{WHITE}{COMPANY} - {COMMA} Vojveturilo{P "" j} STR_9002 :{WHITE}{VEHICLE} STR_9003_ROAD_VEHICLE_DEPOT :{WHITE}{TOWN} Vojveturila Deponejo STR_9004_NEW_VEHICLES :{BLACK}Novaj Veturiloj @@ -2660,7 +2686,13 @@ STR_9036_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Renomu vojveturilan tipon STR_9037_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Ne povas renomi vojveturilan tipon... STR_9038_GO_TO_ROADVEH_DEPOT :Iru al {TOWN} Vojveturila Deponejo +STR_SERVICE_AT_ROADVEH_DEPOT :Prizorgo ĉe {TOWN} Vojveturila Deponejo +STR_REFIT_ROAD_VEHICLE_TO_CARRY :{BLACK}Transformu vojveturilon por porti alian ŝarĝon +STR_REFIT_ROAD_VEHICLE :{BLACK}Transformu vojveturilon +STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED :{BLACK}Transformu vojveturilon por porti elektitan ŝarĝon +STR_REFIT_ROAD_VEHICLE_CAN_T :{WHITE}Ne povas transformi vojveturilon... +STR_ROAD_SELECT_TYPE_OF_CARGO_FOR :{BLACK}Elektu portotan ŝarĝon de la vojveturilo ##id 0x9800 STR_9800_DOCK_CONSTRUCTION :Havenkonstruado @@ -2668,6 +2700,7 @@ STR_9802_CAN_T_BUILD_DOCK_HERE :{WHITE}Ne povas konstrui havenon ĉi tie... STR_9803_SHIP_DEPOT :{WHITE}{TOWN} Ŝipdeponejo STR_9804_NEW_SHIPS :{BLACK}Novaj Ŝipoj +STR_9805_SHIPS :{WHITE}{COMPANY} - {COMMA} Ŝipo{P "" j} STR_9808_NEW_SHIPS :{WHITE}Novaj Ŝipoj STR_9809_BUILD_SHIP :{BLACK}Kreu Ŝipon STR_CLONE_SHIP :{BLACK}Klonu Ŝipon @@ -2791,6 +2824,7 @@ STR_A032_NAME_AIRCRAFT :{BLACK}Nomu aviadilon STR_A033_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Enloĝantoj festas . . .{}Unua aviadilo alvenas en {STATION}! STR_A034_PLANE_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}Aviadilo Kraŝas!{}{COMMA} mortas pro fajro en {STATION} +STR_PLANE_CRASH_OUT_OF_FUEL :{BLACK}{BIGFONT}Aviadila Kraŝo!{}Aviadilo ne havis sufiĉan brulaĵon, {COMMA} mortas pro fajro! STR_A036 :{TINYFONT}{BLACK}{STATION} STR_A037_RENAME :{BLACK}Renomu STR_A038_RENAME_AIRCRAFT_TYPE :{BLACK}Renomu aviadiltipon @@ -2824,23 +2858,33 @@ STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detaloj STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRCOMPACT}/{CURRCOMPACT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) +STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% SET_PERFORMANCE_DETAIL_INT :{BLACK}{NUM} ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Veturiloj: +STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stacioj: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Malpleja gajno: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Malpleja enspezo: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Pleja enspezo: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Liverite: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Ŝarĝo: +STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Mono: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Prunto: +STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Entute: ############ End of order list +STR_PERFORMANCE_DETAIL_VEHICLES_TIP :{BLACK}Nombro da veturiloj; tio enkalkulas vojveturilojn, trajnojn, ŝipojn kaj aviadilojn +STR_PERFORMANCE_DETAIL_STATIONS_TIP :{BLACK}Nombro da staciaj eroj. Ĉiu parto de stacio (ekz. stacidomo, bushaltejo, flughaveno) kalkuliĝas, eĉ se konektite kiel unu stacio +STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP :{BLACK}La gajno de la malplejenspeza veturilo (de ĉiuj veturiloj pli aĝaj ol 2 jaroj) STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP :{BLACK}Enspezite en la plej malaltenspeza monato de la lasta 12 kvaronoj STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP :{BLACK}Enspezite en la plej altenspeza monato de la lasta 12 kvaronoj STR_PERFORMANCE_DETAIL_DELIVERED_TIP :{BLACK}Ŝarĝunuoj liveritaj en la lastaj 4 kvaronoj STR_PERFORMANCE_DETAIL_CARGO_TIP :{BLACK}Nombro da ŝarĝtipoj liveritaj en la lasta kvarono +STR_PERFORMANCE_DETAIL_MONEY_TIP :{BLACK}Monkvanto de ĉi tiu kompanio en la banko STR_PERFORMANCE_DETAIL_LOAN_TIP :{BLACK}La monkvanto pruntita de ĉi tiu kompanio +STR_PERFORMANCE_DETAIL_TOTAL_TIP :{BLACK}Entuta poentaro el eblaj poentoj STR_NEWGRF_SETTINGS_BUTTON :{BLACK}Agordoj de NewGRF +STR_NEWGRF_SETTINGS_CAPTION :{WHITE}Agordoj de NewGRF STR_NEWGRF_APPLY_CHANGES :{BLACK}Apliku ŝanĝojn STR_NEWGRF_SET_PARAMETERS :{BLACK}Agordu parametrojn STR_NEWGRF_TIP :{BLACK}Listo da ĉiuj instalitaj Newgrf-aj aroj. Alklaku aron por ŝanĝi la agordojn @@ -2848,14 +2892,15 @@ STR_NEWGRF_FILENAME :{BLACK}Dosiernomo: {SILVER}{STRING} STR_NEWGRF_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} +STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Vi ĉi tiel ŝanĝos al kuranta ludo; tio povas kraŝigi la ludon.{}Ĉu vi nepre volas fari tion? STR_NEWGRF_ADD :{BLACK}Aldonu STR_NEWGRF_ADD_TIP :{BLACK}Aldonu NewGRF-dosieron al la listo STR_NEWGRF_REMOVE :{BLACK}Forviŝu STR_NEWGRF_REMOVE_TIP :{BLACK}Remove the selected NewGRF file from the list -STR_NEWGRF_MOVEUP :{BLACK}Movu Supren +STR_NEWGRF_MOVEUP :{BLACK}Supren STR_NEWGRF_MOVEUP_TIP :{BLACK}Movu la elektitan NewGRF-dosieron supren en la listo -STR_NEWGRF_MOVEDOWN :{BLACK}Movu Malsupren +STR_NEWGRF_MOVEDOWN :{BLACK}Malsupren STR_NEWGRF_MOVEDOWN_TIP :{BLACK}Movu la elektitan NewGRF-dosieron malsupren en la listo STR_NEWGRF_FILE_TIP :{BLACK}Listo da instalitaj NewGRF-dosieroj. Alklaku dosieron por ŝanĝi la parametrojn STR_NEWGRF_PARAMETER :{BLACK}Parametroj: {SILVER}{STRING} @@ -2882,13 +2927,27 @@ STR_CURRENCY_PREVIEW :{LTBLUE}Antaŭvido: {ORANGE}{CURRENCY} STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Ŝanĝu parametron por alia monunuo +STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} +STR_PLANE :{BLACK}{PLANE} +STR_SHIP :{BLACK}{SHIP} +STR_SCHEDULED_TRAINS :{WHITE}{STATION} - {COMMA} Trajno{P "" j} +STR_SCHEDULED_ROAD_VEHICLES :{WHITE}{STATION} - {COMMA} Vojveturilo{P "" j} +STR_SCHEDULED_AIRCRAFT :{WHITE}{STATION} - {COMMA} Aviadilo{P "" j} +STR_SCHEDULED_SHIPS :{WHITE}{STATION} - {COMMA} Ŝipo{P "" j} +STR_SCHEDULED_TRAINS_TIP :{BLACK}Montru ĉiujn trajnojn kun ĉi tiu stacio en la plano +STR_SCHEDULED_ROAD_VEHICLES_TIP :{BLACK}Montru ĉiujnvojveturilojn kun ĉi tiu stacio en la plano +STR_SCHEDULED_AIRCRAFT_TIP :{BLACK}Montru ĉiujn aviadilojn kun ĉi tiu stacio en la plano +STR_SCHEDULED_SHIPS_TIP :{BLACK}Montru ĉiujn ŝipojn kun ĉi tiu stacio en la plano +STR_VEH_WITH_SHARED_ORDERS_LIST :{WHITE}Dividitaj ordenoj de {COMMA} Veturilo{P "" j} +STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}Montru ĉiujn veturilojn kiuj dividas ĉi tiun planon ### depot strings +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Vi volas vendi ĉiujn veturilojn en la deponejo. Ĉu vi certas? STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP :{BLACK}Vendu ĉiujn trajnojn en la deponejo STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP :{BLACK}Vendu ĉiujn vojveturilojn en la deponejo @@ -2905,12 +2964,30 @@ STR_DEPOT_AUTOREPLACE_SHIP_TIP :{BLACK}Aŭtomate anstataŭu ĉiujn ŝipojn en la deponejo STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP :{BLACK}Aŭtomate anstataŭu ĉiujn aviadilojn en la hangaro +STR_VEHICLE_LIST_ROADVEH_DEPOT :{BLACK}{STRING} - {COMMA} Vojveturilo{P "" j} +STR_VEHICLE_LIST_SHIP_DEPOT :{BLACK}{STRING} - {COMMA} Ŝipo{P "" j} +STR_VEHICLE_LIST_AIRCRAFT_DEPOT :{BLACK}{STRING} - {COMMA} Aviadilo{P "" j} +STR_REPLACE_VEHICLES_WHITE :{WHITE}Anstataŭu {STRING.n} +STR_REPLACE_VEHICLES_START :{BLACK}Komencu Anstataŭi +STR_REPLACE_VEHICLES_STOP :{BLACK}Ĉesu Anstataŭi STR_NOT_REPLACING :{BLACK}Ne anstataŭante STR_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Ne elektiĝis veturilo +STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Elektu maŝinon por anstataŭi +STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Elektu novan maŝinon por uzi anstataŭ la maldekstre elektitan +STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Premu por ĉesi anstataŭi la maldekstre elektitan maŝinon +STR_REPLACE_HELP_START_BUTTON :{BLACK}Premu por komenci anstataŭi la maldekstre elektitan maŝinon per la dekstre elektitan +STR_REPLACE_HELP_RAILTYPE :{BLACK}Elektu fervojtipon por kiu vi volas anstataŭigi maŝinojn +STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Montras ontan maŝinecon de la maldekstra maŝino, se anstataŭote +STR_REPLACE_HELP :{BLACK}Ĉi tio permesas vin anstataŭi maŝinojn de unu al alia tipo, kiam trajnoj de la unu tipo eniras la deponejon +STR_REPLACE_REMOVE_WAGON :{BLACK}Vagonforigo: {ORANGE}{SKIP}{STRING} +STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Ĉe aŭtomata anstataŭigo tenu saman longecon de la trajno per forigo de vagonoj (defronte), se per nova maŝino la trajno plilongiĝas +STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Anstataŭante: {ORANGE}{SKIP}{SKIP}{STRING} +STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK} EKSPERIMENTA AĴO {}Ŝaltu inter maŝina kaj vagona anstataŭigo.{}Vagona anstataŭigo nur okazos se la nova vagono povas transformiĝi por porti saman ŝarĝon kiel la malnova. Por ĉiu vagono tio kontroliĝos dum anstataŭado. STR_ENGINE_NOT_BUILDABLE :{WHITE}Maŝino ne kreeblas STR_ENGINES :Maŝinoj +STR_WAGONS :Vagonoj STR_MASS_STOP_DEPOT_TRAIN_TIP :{BLACK}Alklaku por haltigi ĉiujn trajnojn en la deponejo STR_MASS_STOP_DEPOT_ROADVEH_TIP :{BLACK}Alklaku por haltigi ĉiujn vojveturilojn en la deponejo @@ -2925,6 +3002,8 @@ STR_MASS_STOP_LIST_TIP :{BLACK}Alklaku por haltigi ĉiujn veturilojn en la listo STR_MASS_START_LIST_TIP :{BLACK}Alklaku por starti ĉiujn veturilojn en la listo +STR_SHORT_DATE :{WHITE}{DATE_TINY} +STR_SIGN_LIST_CAPTION :{WHITE}Signolisto - {COMMA} Signo{P "" j} STR_ORDER_REFIT_FAILED :{WHITE}Fiasko de ordeno transformi haltigis {STRING.n} {COMMA} @@ -2937,35 +3016,82 @@ ############ End of list of rail types +STR_TINY_BLACK :{BLACK}{TINYFONT}{COMMA} +STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kosto: {GOLD}{CURRENCY}{BLACK} Pezo: {GOLD}{WEIGHT_S} +STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Rapido: {GOLD}{VELOCITY}{BLACK} Forto: {GOLD}{POWER} +STR_PURCHASE_INFO_SPEED :{BLACK}Rapido: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Irkosto: {GOLD}po {CURRENCY} jare +STR_PURCHASE_INFO_CAPACITY :{BLACK}Kapablo: {GOLD}{CARGO} {STRING} +STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Pripensite: {GOLD}{NUM}{BLACK} Vivlongo: {GOLD}{COMMA} jaroj +STR_PURCHASE_INFO_RELIABILITY :{BLACK}Pleja Fidebleco: {GOLD}{COMMA}% +STR_PURCHASE_INFO_COST :{BLACK}Kosto: {GOLD}{CURRENCY} +STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Pezo: {GOLD}{WEIGHT_S} ({WEIGHT_S}) +STR_PURCHASE_INFO_COST_SPEED :{BLACK}Kosto: {GOLD}{CURRENCY}{BLACK} Rapido: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kapablo: {GOLD}{COMMA} pasaĝeroj, {COMMA} sakoj da poŝto +STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Vagonfortoj: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_S} +STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Transformebla al: {GOLD} +STR_PURCHASE_INFO_ALL_TYPES :Ĉiaj ŝarĝoj +STR_PURCHASE_INFO_ALL_BUT :Ĉio krom {GOLD} +STR_PURCHASE_INFO_MAX_TE :{BLACK}Maksimuma Tiro: {GOLD}{FORCE} ########### String for New Landscape Generator STR_GENERATE :{WHITE}Generu +STR_RANDOM :{BLACK}Hazardigu +STR_RANDOM_HELP :{BLACK}Ŝanĝo la hazardan enigon uzatan de la terengenerilo +STR_WORLD_GENERATION_CAPTION :{WHITE}Mondgenerado +STR_RANDOM_SEED :{BLACK}Hazarda Enigo: +STR_RANDOM_SEED_HELP :{BLACK}Klaku por enigi hazardan enigon STR_LAND_GENERATOR :{BLACK}Landgenerilo: +STR_TREE_PLACER :{BLACK}Arba algoritmo: STR_HEIGHTMAP_ROTATION :{BLACK}Altecmapa turniĝo: +STR_TERRAIN_TYPE :{BLACK}Terentipo: +STR_QUANTITY_OF_SEA_LAKES :{BLACK}Marnivelo: +STR_SMOOTHNESS :{BLACK}Ebeneco: +STR_SNOW_LINE_HEIGHT :{BLACK}Neĝlinia alteco: STR_DATE :{BLACK}Dato: STR_NUMBER_OF_TOWNS :{BLACK}Kiom da urboj: STR_NUMBER_OF_INDUSTRIES :{BLACK}Kiom da industrioj: STR_GENERATE_DATE :{BLACK}{DATE_LONG} +STR_SNOW_LINE_UP :{BLACK}Altigu la neĝlinion per unu +STR_SNOW_LINE_DOWN :{BLACK}Malaltigu la neĝlinion per unu +STR_SNOW_LINE_QUERY_CAPT :{WHITE}Ŝanĝu altecon de la neĝlinio +STR_START_DATE_QUERY_CAPT :{WHITE}Ŝanĝu komencjaron STR_HEIGHTMAP_SCALE_WARNING_CAPTION :{WHITE}Skala averto STR_HEIGHTMAP_SCALE_WARNING_MESSAGE :{YELLOW}Ne rekomendindas tro ŝanĝi la grandecon de la mapo. Ĉu daŭrigi la generadon? +STR_SNOW_LINE_HEIGHT_NUM :{NUM} STR_HEIGHTMAP_NAME :{BLACK}Altecmapa nomo: STR_HEIGHTMAP_SIZE :{BLACK}Grandeco: {ORANGE}{NUM} x {NUM} STR_GENERATION_WORLD :{WHITE}Generante mondon... STR_GENERATION_ABORT :{BLACK}Ĉesu STR_GENERATION_ABORT_CAPTION :{WHITE}Ĉesu generi mondon STR_GENERATION_ABORT_MESSAGE :{YELLOW}Ĉu vi vere volas ĉesi generi mondon? +STR_PROGRESS :{WHITE}{NUM}% komplete STR_GENERATION_PROGRESS :{BLACK}{NUM} / {NUM} +STR_WORLD_GENERATION :{BLACK}Mondgenerado +STR_TREE_GENERATION :{BLACK}Arba generado +STR_UNMOVABLE_GENERATION :{BLACK}Nemoveblaĵa generado +STR_CLEARING_TILES :{BLACK}Generado de malglataj kaj rokaj regionoj +STR_SETTINGUP_GAME :{BLACK}Agordante ludon +STR_PREPARING_TILELOOP :{BLACK}Trakurante kvadratojn +STR_PREPARING_GAME :{BLACK}Preparante ludon STR_DIFFICULTY_TO_CUSTOM :{WHITE}Ĉi tiu ago ŝanĝis la malfacilec-nivelon al 'ŝanĝite' +STR_SE_FLAT_WORLD :{WHITE}Ebena lando +STR_SE_FLAT_WORLD_TIP :{BLACK}Generu ebenan landon +STR_SE_RANDOM_LAND :{WHITE}Hazarda lando +STR_SE_NEW_WORLD :{BLACK}Kreu novan scenaron +STR_SE_CAPTION :{WHITE}Scenara tipo STR_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Malaltigu la altecon de ebena lando per unu STR_FLAT_WORLD_HEIGHT_UP :{BLACK}Altigu la altecon de ebena lando per unu STR_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Ŝanĝu altecon de ebena lando STR_FLAT_WORLD_HEIGHT :{BLACK}Alteco de ebena lando: STR_FLAT_WORLD_HEIGHT_NUM :{NUM} +STR_SMALLMAP_CENTER :{BLACK}Centrigu la mapeton al la nuna loko ########### String for new airports +STR_SMALL_AIRPORT :{BLACK}Malgranda STR_CITY_AIRPORT :{BLACK}Urbo STR_METRO_AIRPORT :{BLACK}Ĉefurba Flughaveno STR_INTERNATIONAL_AIRPORT :{BLACK}Internacia flughaveno @@ -2975,6 +3101,7 @@ STR_HELIDEPOT :{BLACK}Helikopterdeponejo STR_HELISTATION :{BLACK}Helikopterstacio +STR_SMALL_AIRPORTS :{BLACK}Malgrandaj flughavenoj STR_LARGE_AIRPORTS :{BLACK}Grandaj flughavenoj STR_HUB_AIRPORTS :{BLACK}Nabaj flughavenoj STR_HELIPORTS :{BLACK}Helikopterhaveno diff -r d4d00a16ef26 -r bfa6074e2833 lang/estonian.txt --- a/lang/estonian.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/estonian.txt Wed Jan 03 08:32:17 2007 +0000 @@ -113,6 +113,7 @@ STR_0032_OIL.genitiiv :Nafta STR_0033_LIVESTOCK :Kariloom STR_0033_LIVESTOCK.g :Kariloomade +STR_0033_LIVESTOCK.genitiiv :Kariloomade STR_0034_GOODS :Kaubad STR_0034_GOODS.g :Kaupade STR_0034_GOODS.genitiiv :Kaupade @@ -368,7 +369,7 @@ STR_012D :{WHITE}{STRING} STR_012E_CANCEL :{BLACK}Loobu STR_012F_OK :{BLACK}OK -STR_0130_RENAME :{BLACK}Nime muutmine +STR_0130_RENAME :{BLACK}Muuda nime STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Liiga palju määratletud nimesid STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Valitud nimi on juba kasutusel @@ -386,7 +387,7 @@ STR_013E_CAPACITIES :{BLACK}Mahutavused STR_013E_TOTAL_CARGO :{BLACK}Laadungit kokku STR_013F_CAPACITY :{BLACK}Mahutavus: {LTBLUE}{CARGO} -STR_CAPACITY_MULT :{BLACK}Mahutuvus: {LTBLUE}{CARGO} (x{NUM}) +STR_CAPACITY_MULT :{BLACK}Mahutavus: {LTBLUE}{CARGO} (x{NUM}) STR_013F_TOTAL_CAPACITY_TEXT :{BLACK}Rongi kogumahutavus: STR_013F_TOTAL_CAPACITY :{LTBLUE}- {CARGO} ({SHORTCARGO}) STR_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO} ({SHORTCARGO}) (x{NUM}) @@ -415,7 +416,7 @@ STR_UNITS_SI :SI STR_UNITS_VELOCITY_IMPERIAL :{COMMA} miili tunnis -STR_UNITS_VELOCITY_METRIC :{COMMA} km tunnis +STR_UNITS_VELOCITY_METRIC :{COMMA} km/h STR_UNITS_VELOCITY_SI :{COMMA} m/s STR_UNITS_POWER_IMPERIAL :{COMMA}hj @@ -1098,10 +1099,10 @@ STR_AIRCRAFT_HAS_INVALID_ENTRY :{WHITE}Õhusõiduki {COMMA} plaanis on kehtetud jaam # end of order system -STR_TRAIN_AUTORENEW_FAILED :{WHITE}Rongi automaatne uuendamine {COMMA} ebaõnnestus (money limit) -STR_ROADVEHICLE_AUTORENEW_FAILED :{WHITE}Maanteesõiduki automaatne uuendus ebaõnnestus {COMMA} (money limit) -STR_SHIP_AUTORENEW_FAILED :{WHITE}Laeva automaatne uuendus ebaõnnestus {COMMA} (money limit) -STR_AIRCRAFT_AUTORENEW_FAILED :{WHITE}Õhusõiduki automaatne uuendus ebaõnnestus{COMMA} (money limit) +STR_TRAIN_AUTORENEW_FAILED :{WHITE}Rongi automaatne uuendamine {COMMA} ebaõnnestus (rahalimiit) +STR_ROADVEHICLE_AUTORENEW_FAILED :{WHITE}Maanteesõiduki automaatne uuendus ebaõnnestus {COMMA} (rahalimiit) +STR_SHIP_AUTORENEW_FAILED :{WHITE}Laeva automaatne uuendus ebaõnnestus {COMMA} (rahalimiit) +STR_AIRCRAFT_AUTORENEW_FAILED :{WHITE}Õhusõiduki automaatne uuendus ebaõnnestus{COMMA} (rahalimiit) STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}Rong {COMMA} on peale asendust liiga pikk STR_CONFIG_PATCHES :{BLACK}Paranduste seaded @@ -1174,7 +1175,7 @@ STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE :Päevapidi STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT :{LTBLUE}Kõrguse level kui kõrgele lapik kaart läheb: {ORANGE}{STRING} -STR_CONFIG_PATCHES_STATION_SPREAD :{LTBLUE}Maksimaalne jaama ala: {ORANGE}{STRING} {RED}Hoiatus: Kõrged seaded aeglustavad mängu +STR_CONFIG_PATCHES_STATION_SPREAD :{LTBLUE}Maksimaalne jaama ala: {ORANGE}{STRING} {RED}Hoiatus: kõrged seaded aeglustavad mängu STR_CONFIG_PATCHES_SERVICEATHELIPAD :{LTBLUE}Kopteri jaamades helikopterite automaatne teenindus: {ORANGE}{STRING} STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR :{LTBLUE}Lingi maastiku riba raudtee/tee/vee/lennujaama tööriistaribaga: {ORANGE}{STRING} STR_CONFIG_PATCHES_REVERSE_SCROLLING :{LTBLUE}Kui kerid hiirega, liiguta vaade vastassuunda: {ORANGE}{STRING} @@ -1247,7 +1248,7 @@ STR_CHEATS :{WHITE}Petmine STR_CHEATS_TIP :{BLACK}Märgistatud kastid näitavad et, kas sa oled varem seda pettust kasutanud -STR_CHEATS_WARNING :{BLACK}Hoiatus! Sa kavatsed oma konkurente reeta. Pea meeles, et sellest häbist ei saa sa enam kunagi lahti. +STR_CHEATS_WARNING :{BLACK}Hoiatus! Sa kavatsed oma konkurente reeta. Pea meeles, et sellisest häbist ei saa sa enam kunagi lahti. STR_CHEAT_MONEY :{LTBLUE}Suurenda raha hulka {CURRENCY64} võrra STR_CHEAT_CHANGE_PLAYER :{LTBLUE}Mängi, kui mängija: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Maagiline buldooser(eemaldamatute objektide eemaldamine): {ORANGE}{STRING} @@ -1365,7 +1366,7 @@ STR_CONFIG_GAME_PRODUCTION :{WHITE}Tootlikuse muutmine TEMP_AI_IN_PROGRESS :{WHITE}Tervitused uuele TI'le(AI). Töö selle kallal veel käib. Peaksite eeldama, et esineb probleeme. Kui juhtud tegema kuvatõmmise, siis postita see ka foorumisse. Edu! -TEMP_AI_ACTIVATED :{WHITE}Hoiatus: uus TI(AI) on veel alfa staadiumis! Ainult maanteesõidukid töötavad! +TEMP_AI_ACTIVATED :{WHITE}Hoiatus: uus tehisintelligents on veel katsetamisel! Hetkel töötavad ainult maanteesõidukid! TEMP_AI_MULTIPLAYER :{WHITE}TÄHELEPANU! Seda funksiooni veel teistitakse. Palun teata kõik probleemid sellega truelight@openttd.org. ############ network gui strings @@ -1629,7 +1630,7 @@ STR_1011_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Siia ei saa raudteed ehitada... STR_1012_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Siit ei saa raudteed eemaldada... STR_1013_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Siit ei saa signaaltulesid eemaldada... -STR_1014_TRAIN_DEPOT_ORIENTATION :{WHITE}Depoo orientatsioon +STR_1014_TRAIN_DEPOT_ORIENTATION :{WHITE}Depoo suuna STR_1015_RAILROAD_CONSTRUCTION :Raudtee ehitus STR_TOOLB_ELRAIL_CONSTRUCTION :Elektriraudtee ehitus STR_1016_MONORAIL_CONSTRUCTION :Monorelsi ehitus @@ -1642,7 +1643,7 @@ STR_101D_BUILD_RAILROAD_TUNNEL :{BLACK}Ehita rongitunnel STR_101E_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Rööbaste ja signaaltulede ehitamine/eemaldamine STR_101F_BRIDGE_SELECTION_CLICK :{BLACK}Silla valik - klõpsa sobivale sillale, et seda ehitada -STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO :{BLACK}Depoo orientatsiooni valimine +STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO :{BLACK}Depoole suuna valimine STR_1021_RAILROAD_TRACK :Raudtee STR_1023_RAILROAD_TRAIN_DEPOT :Rongidepoo STR_1024_AREA_IS_OWNED_BY_ANOTHER :{WHITE}...ala kuulub teisele ettevõttele @@ -1660,7 +1661,7 @@ STR_1803_SELECT_ROAD_BRIDGE :{WHITE}Vali sillatüüp STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Siia ei saa maanteed ehitada... STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Siit ei saa maanteed eemaldada... -STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}Depoo orientatsioon +STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}Depoo suund STR_1807_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Siia ei saa depood ehitada... STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}Siia ei saa bussijaama ehitada... STR_1809_CAN_T_BUILD_TRUCK_STATION :{WHITE}Siia ei saa laadimisplatsi ehitada... @@ -1672,7 +1673,7 @@ STR_180F_BUILD_ROAD_BRIDGE :{BLACK}Ehita sild STR_1810_BUILD_ROAD_TUNNEL :{BLACK}Ehita tunnel STR_1811_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Teeehituse ja -eemaldamise vahetamine -STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}Vali depoo orientatsioon +STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}Vali depoole suund STR_1814_ROAD :Maantee STR_1815_ROAD_WITH_STREETLIGHTS :Valgustatud maantee STR_1816_TREE_LINED_ROAD :Kolmerajaline tee @@ -1840,8 +1841,8 @@ STR_303F_NO_LONGER_ACCEPTS_OR :{WHITE}Jaam {STATION} ei võta enam vastu veoseid {STRING}, ega {STRING} STR_3040_NOW_ACCEPTS :{WHITE}Jaam {STATION} võtab nüüd vastu veost {STRING} STR_3041_NOW_ACCEPTS_AND :{WHITE}Jaam {STATION} võtab nüüd vastu veoseid {STRING} ja {STRING} -STR_3042_BUS_STATION_ORIENTATION :{WHITE}Bussijaama orientatsioon -STR_3043_TRUCK_STATION_ORIENT :{WHITE}Laadimisplatsi orientatsioon +STR_3042_BUS_STATION_ORIENTATION :{WHITE}Bussijaama suund +STR_3043_TRUCK_STATION_ORIENT :{WHITE}Laadimisplatsi suund STR_3046_MUST_DEMOLISH_BUS_STATION :{WHITE}Bussijaam tuleb enne hävitada STR_3047_MUST_DEMOLISH_TRUCK_STATION :{WHITE}Enne pead laadimisplatsi hävitama STR_3048_STATIONS :{WHITE}{COMPANY} - {COMMA} Jaam{P "" ad} @@ -1850,11 +1851,11 @@ STR_304B_SITE_UNSUITABLE :{WHITE}...ebasobiv koht STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Liiga lähedal teisele sadamale STR_304D_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Enne pead sadama hävitama -STR_304E_SELECT_RAILROAD_STATION :{BLACK}Raudteejaama orientatsiooni valimine +STR_304E_SELECT_RAILROAD_STATION :{BLACK}Raudteejaamale suuna valimine STR_304F_SELECT_NUMBER_OF_PLATFORMS :{BLACK}Vali raudteejaama platvormide arv STR_3050_SELECT_LENGTH_OF_RAILROAD :{BLACK}Vali raudteejaama pikkus -STR_3051_SELECT_BUS_STATION_ORIENTATION :{BLACK}Vali bussijaama orientatsioon -STR_3052_SELECT_TRUCK_LOADING_BAY :{BLACK}Vali laadimisplatsi orientatsioon +STR_3051_SELECT_BUS_STATION_ORIENTATION :{BLACK}Vali bussijaamale suund +STR_3052_SELECT_TRUCK_LOADING_BAY :{BLACK}Vali laadimisplatsile suund STR_3053_CENTER_MAIN_VIEW_ON_STATION :{BLACK}Vaate viimine jaama juurde STR_3054_SHOW_STATION_RATINGS :{BLACK}Näita jaama reitinguid STR_3055_CHANGE_NAME_OF_STATION :{BLACK}Muuda jaama nime @@ -1887,7 +1888,7 @@ STR_3800_SHIP_DEPOT_ORIENTATION :{WHITE}Paadikuuri Orientatsioon STR_3801_MUST_BE_BUILT_ON_WATER :{WHITE}...peab ehitama vette STR_3802_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Siia ei saa laevaangaari ehitada... -STR_3803_SELECT_SHIP_DEPOT_ORIENTATION :{BLACK}Laevaangaari orientatsiooni valimine +STR_3803_SELECT_SHIP_DEPOT_ORIENTATION :{BLACK}Laevaangaarile suuna valimine STR_3804_WATER :Vesi STR_3805_COAST_OR_RIVERBANK :Kallas STR_3806_SHIP_DEPOT :Laevaangaar @@ -1911,7 +1912,7 @@ STR_400E_SELECT_NEW_GAME_TYPE :{WHITE}Vali uue mängu tüüp STR_400F_SELECT_SCENARIO_GREEN_PRE :{BLACK}Vali valmis kaart (roheline), eelseadistatud mäng (sinine), või juhusliku kaardiga uus mäng STR_4010_GENERATE_RANDOM_NEW_GAME :Tekita juhuslik kaart -STR_4011_LOAD_HEIGHTMAP :{WHITE}Lae kõrgustekaart +STR_4011_LOAD_HEIGHTMAP :{WHITE}Laadi kõrguskaart ##id 0x4800 STR_4800_IN_THE_WAY :{WHITE}{STRING} on ees @@ -2037,43 +2038,43 @@ STR_SV_EMPTY : STR_SV_UNNAMED :Nimetu STR_SV_TRAIN_NAME :Rong {COMMA} -STR_SV_ROADVEH_NAME :Maantee sõiduk {COMMA} +STR_SV_ROADVEH_NAME :Maanteesõiduk {COMMA} STR_SV_SHIP_NAME :Laev {COMMA} STR_SV_AIRCRAFT_NAME :Õhusõiduk {COMMA} STR_SV_STNAME :{STRING} -STR_SV_STNAME_NORTH :{STRING} Põhi -STR_SV_STNAME_SOUTH :{STRING} Lõuna -STR_SV_STNAME_EAST :{STRING} Ida -STR_SV_STNAME_WEST :{STRING} Lääs -STR_SV_STNAME_CENTRAL :{STRING} Keskus -STR_SV_STNAME_TRANSFER :{STRING} Transport -STR_SV_STNAME_HALT :{STRING} Peatus -STR_SV_STNAME_VALLEY :{STRING} Org -STR_SV_STNAME_HEIGHTS :{STRING} Kõrgendikud -STR_SV_STNAME_WOODS :{STRING} Metsad -STR_SV_STNAME_LAKESIDE :{STRING} Järveäärne -STR_SV_STNAME_EXCHANGE :{STRING} Vahetus -STR_SV_STNAME_AIRPORT :{STRING} Lennujaam -STR_SV_STNAME_OILFIELD :{STRING} Naftaväli -STR_SV_STNAME_MINES :{STRING} Kaevandus -STR_SV_STNAME_DOCKS :{STRING} Sadam -STR_SV_STNAME_BUOY_1 :{STRING} Poi 1 -STR_SV_STNAME_BUOY_2 :{STRING} Poi 2 -STR_SV_STNAME_BUOY_3 :{STRING} Poi 3 -STR_SV_STNAME_BUOY_4 :{STRING} Poi 4 -STR_SV_STNAME_BUOY_5 :{STRING} Poi 5 -STR_SV_STNAME_BUOY_6 :{STRING} Poi 6 -STR_SV_STNAME_BUOY_7 :{STRING} Poi 7 -STR_SV_STNAME_BUOY_8 :{STRING} Poi 8 -STR_SV_STNAME_BUOY_9 :{STRING} Poi 9 -STR_SV_STNAME_ANNEXE :{STRING} Juurdeehitis -STR_SV_STNAME_SIDINGS :{STRING} Hargnemine -STR_SV_STNAME_BRANCH :{STRING} Filiaal +STR_SV_STNAME_NORTH :Põhja {STRING} +STR_SV_STNAME_SOUTH : Lõuna {STRING} +STR_SV_STNAME_EAST : Ida {STRING} +STR_SV_STNAME_WEST : Lääne {STRING} +STR_SV_STNAME_CENTRAL :{STRING} keskus +STR_SV_STNAME_TRANSFER :{STRING} ülekanne +STR_SV_STNAME_HALT :{STRING} peatus +STR_SV_STNAME_VALLEY :{STRING} org +STR_SV_STNAME_HEIGHTS :{STRING} kõrgendikud +STR_SV_STNAME_WOODS :{STRING} metsad +STR_SV_STNAME_LAKESIDE :{STRING} järveäärne +STR_SV_STNAME_EXCHANGE :{STRING} vahetus +STR_SV_STNAME_AIRPORT :{STRING} lennujaam +STR_SV_STNAME_OILFIELD :{STRING} naftaväli +STR_SV_STNAME_MINES :{STRING} kaevandused +STR_SV_STNAME_DOCKS :{STRING} sadam +STR_SV_STNAME_BUOY_1 :{STRING} poi #1 +STR_SV_STNAME_BUOY_2 :{STRING} poi #2 +STR_SV_STNAME_BUOY_3 :{STRING} poi #3 +STR_SV_STNAME_BUOY_4 :{STRING} poi #4 +STR_SV_STNAME_BUOY_5 :{STRING} poi #5 +STR_SV_STNAME_BUOY_6 :{STRING} poi #6 +STR_SV_STNAME_BUOY_7 :{STRING} poi #7 +STR_SV_STNAME_BUOY_8 :{STRING} poi #8 +STR_SV_STNAME_BUOY_9 :{STRING} poi #9 +STR_SV_STNAME_ANNEXE :{STRING} juurdeehitis +STR_SV_STNAME_SIDINGS :{STRING} hargnemine +STR_SV_STNAME_BRANCH :{STRING} filiaal STR_SV_STNAME_UPPER :Ülemine {STRING} STR_SV_STNAME_LOWER :Alumine {STRING} -STR_SV_STNAME_HELIPORT :{STRING} Helikopteri plats -STR_SV_STNAME_FOREST :{STRING} Mets +STR_SV_STNAME_HELIPORT :{STRING} helikopteri maandumisplats +STR_SV_STNAME_FOREST :{STRING} mets ############ end of savegame specific region! @@ -2190,7 +2191,7 @@ STR_7025_OPERATING_PROFIT_GRAPH :{WHITE}Opereerimiskasumi graafik STR_7026_BANK_BALANCE :{WHITE}Kontojääk STR_7027_LOAN :{WHITE}Laen -STR_MAX_LOAN :{WHITE}Maksimaalne laen: {BLACK}{CURRENCY64} +STR_MAX_LOAN :{WHITE}Suurim võimalik laen: {BLACK}{CURRENCY64} STR_7028 :{BLACK}{CURRENCY64} STR_7029_BORROW :{BLACK}Laena {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} STR_702A_REPAY :{BLACK}Maksa tagasi {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} @@ -2276,8 +2277,8 @@ STR_7078_SELL_25_SHARE_IN_COMPANY :{BLACK}Müü 25% ettevõtte aktsiatest STR_7079_BUY_25_SHARE_IN_THIS_COMPANY :{BLACK}Osta 25% ettevõtte aktsiatest STR_707A_SELL_25_SHARE_IN_THIS_COMPANY :{BLACK}Müü 25% ettevõtte aktsiatest -STR_707B_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Ei saa 25% selle ettevõtte aktsiatest osta... -STR_707C_CAN_T_SELL_25_SHARE_IN :{WHITE}Ei saa 25% selle ettevõtte aktsiatest müüa... +STR_707B_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Selle ettevõtte aktsiatest ei saa 25% osta... +STR_707C_CAN_T_SELL_25_SHARE_IN :{WHITE}Selle ettevõtte aktsiatest ei saa 25% müüa... STR_707D_OWNED_BY :{WHITE}({COMMA}% on ettevõtte {COMPANY} käes) STR_707E_OWNED_BY_OWNED_BY :{WHITE}({COMMA}% on ettevõtte {COMPANY} käes{} {COMMA}% on ettevõtte {COMPANY} käes) STR_707F_HAS_BEEN_TAKEN_OVER_BY :{BLACK}{BIGFONT}{COMPANY} võeti üle ettevõtte {COMPANY} poolt! @@ -2313,52 +2314,52 @@ STR_LIVERY_PANEL_TIP :{BLACK}Vali värviskeem mida muuta, või mitu tükki vajutades CTRL+Kõps. Vajuta kastil et valida värviskeemi kaustamise vahel. ##id 0x8000 -STR_8000_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Auruvedur) -STR_8001_MJS_250_DIESEL :MJS 250 (Diisel) +STR_8000_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (auruvedur) +STR_8001_MJS_250_DIESEL :MJS 250 (diisel) STR_8002_PLODDYPHUT_CHOO_CHOO :Ploddyphuti tšuhh-tšuhh STR_8003_POWERNAUT_CHOO_CHOO :Powernauti tšuhh-tšuhh -STR_8004_MIGHTYMOVER_CHOO_CHOO :Mightymover Choo-Choo -STR_8005_PLODDYPHUT_DIESEL :Ploddyphut Diesel -STR_8006_POWERNAUT_DIESEL :Powernaut Diesel -STR_8007_WILLS_2_8_0_STEAM :Wills 2-8-0 (Auruvedur) -STR_8008_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Auruvedur) -STR_8009_GINZU_A4_STEAM :Ginzu 'A4' (Auruvedur) -STR_800A_SH_8P_STEAM :SH '8P' (Auruvedur) -STR_800B_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diisel) -STR_800C_DASH_DIESEL :'Dash' (Diisel) -STR_800D_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diisel) -STR_800E_UU_37_DIESEL :UU '37' (Diisel) -STR_800F_FLOSS_47_DIESEL :Floss '47' (Diisel) -STR_8010_CS_4000_DIESEL :CS 4000 (Diisel) -STR_8011_CS_2400_DIESEL :CS 2400 (Diisel) -STR_8012_CENTENNIAL_DIESEL :Centennial (Diisel) -STR_8013_KELLING_3100_DIESEL :Kelling 3100 (Diisel) -STR_8014_TURNER_TURBO_DIESEL :Turner Turbo (Diisel) -STR_8015_MJS_1000_DIESEL :MJS 1000 (Diisel) -STR_8016_SH_125_DIESEL :SH '125' (Diisel) -STR_8017_SH_30_ELECTRIC :SH '30' (Elektrivedur) -STR_8018_SH_40_ELECTRIC :SH '40' (Elektrivedur) -STR_8019_T_I_M_ELECTRIC :'T.I.M.' (Elektrivedur) -STR_801A_ASIASTAR_ELECTRIC :'AsiaStar' (Elektrivedur) +STR_8004_MIGHTYMOVER_CHOO_CHOO :Mightymoveri tšuhh-tšuhh +STR_8005_PLODDYPHUT_DIESEL :Ploddyphut diisel +STR_8006_POWERNAUT_DIESEL :Powernaut diisel +STR_8007_WILLS_2_8_0_STEAM :Wills 2-8-0 (auruvedur) +STR_8008_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (auruvedur) +STR_8009_GINZU_A4_STEAM :Ginzu 'A4' (auruvedur) +STR_800A_SH_8P_STEAM :SH '8P' (auruvedur) +STR_800B_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (diisel) +STR_800C_DASH_DIESEL :'Dash' (diisel) +STR_800D_SH_HENDRY_25_DIESEL :SH/Hendry '25' (diisel) +STR_800E_UU_37_DIESEL :UU '37' (diisel) +STR_800F_FLOSS_47_DIESEL :Floss '47' (diisel) +STR_8010_CS_4000_DIESEL :CS 4000 (diisel) +STR_8011_CS_2400_DIESEL :CS 2400 (diisel) +STR_8012_CENTENNIAL_DIESEL :Centennial (diisel) +STR_8013_KELLING_3100_DIESEL :Kelling 3100 (diisel) +STR_8014_TURNER_TURBO_DIESEL :Turner Turbo (diisel) +STR_8015_MJS_1000_DIESEL :MJS 1000 (diisel) +STR_8016_SH_125_DIESEL :SH '125' (diisel) +STR_8017_SH_30_ELECTRIC :SH '30' (elektrivedur) +STR_8018_SH_40_ELECTRIC :SH '40' (elektrivedur) +STR_8019_T_I_M_ELECTRIC :'T.I.M.' (elektrivedur) +STR_801A_ASIASTAR_ELECTRIC :'AsiaStar' (elektrivedur) STR_801B_PASSENGER_CAR :Reisivagun STR_801C_MAIL_VAN :Postivagun -STR_801D_COAL_CAR :Söevagun +STR_801D_COAL_CAR :Kivisöevagun STR_801E_OIL_TANKER :Naftatanker -STR_801F_LIVESTOCK_VAN :Kariloomade veok +STR_801F_LIVESTOCK_VAN :Loomavagun STR_8020_GOODS_VAN :Kaubavagun STR_8021_GRAIN_HOPPER :Teraviljavagun -STR_8022_WOOD_TRUCK :Puiduveok -STR_8023_IRON_ORE_HOPPER :Rauamaagi vagun -STR_8024_STEEL_TRUCK :Teraseveok +STR_8022_WOOD_TRUCK :Palgivagun +STR_8023_IRON_ORE_HOPPER :Rauamaagivagun +STR_8024_STEEL_TRUCK :Terasevagun STR_8025_ARMORED_VAN :Soomusvagun STR_8026_FOOD_VAN :Toiduvagun STR_8027_PAPER_TRUCK :Paberivagun -STR_8028_COPPER_ORE_HOPPER :Vasemaagi vagun -STR_8029_WATER_TANKER :Vee Tanker +STR_8028_COPPER_ORE_HOPPER :Vasemaagivagun +STR_8029_WATER_TANKER :Veetanker STR_802A_FRUIT_TRUCK :Puuviljavagun STR_802B_RUBBER_TRUCK :Kummivagun STR_802C_SUGAR_TRUCK :Suhkruvagun -STR_802D_COTTON_CANDY_HOPPER :Suhkruvati vagun +STR_802D_COTTON_CANDY_HOPPER :Suhkruvativagun STR_802E_TOFFEE_HOPPER :Iirisevagun STR_802F_BUBBLE_VAN :Mullivagun STR_8030_COLA_TANKER :Koolavagun @@ -2366,167 +2367,167 @@ STR_8032_TOY_VAN :Mänguasjavagun STR_8033_BATTERY_TRUCK :Patareivagun STR_8034_FIZZY_DRINK_TRUCK :Kihisevate jookide vagun -STR_8035_PLASTIC_TRUCK :Plastiku vagun -STR_8036_X2001_ELECTRIC :'X2001' (Elektri) -STR_8037_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Elektri) +STR_8035_PLASTIC_TRUCK :Plastikuvagun +STR_8036_X2001_ELECTRIC :'X2001' (elektri) +STR_8037_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (elektri) STR_8038_WIZZOWOW_Z99 :Wizzowow Z99 STR_8039_PASSENGER_CAR :Reisivagun STR_803A_MAIL_VAN :Postivagun -STR_803B_COAL_CAR :Kivisöe vagun +STR_803B_COAL_CAR :Kivisöevagun STR_803C_OIL_TANKER :Naftatanker -STR_803D_LIVESTOCK_VAN :Kariloomade vagun +STR_803D_LIVESTOCK_VAN :Loomavagun STR_803E_GOODS_VAN :Kaubavagun -STR_803F_GRAIN_HOPPER :Teravilja vagun -STR_8040_WOOD_TRUCK :Puidu vagun -STR_8041_IRON_ORE_HOPPER :Rauamaagi vagun -STR_8042_STEEL_TRUCK :Terase vagun +STR_803F_GRAIN_HOPPER :Teraviljavagun +STR_8040_WOOD_TRUCK :Palgivagun +STR_8041_IRON_ORE_HOPPER :Rauamaagivagun +STR_8042_STEEL_TRUCK :Terasevagun STR_8043_ARMORED_VAN :Soomusvagun -STR_8044_FOOD_VAN :Toidu vagun -STR_8045_PAPER_TRUCK :Paberi vagun -STR_8046_COPPER_ORE_HOPPER :Vasemaagi vagun -STR_8047_WATER_TANKER :Vee Tanker -STR_8048_FRUIT_TRUCK :Puuvilja vagun -STR_8049_RUBBER_TRUCK :Kummi vagun +STR_8044_FOOD_VAN :Toiduvagun +STR_8045_PAPER_TRUCK :Paberivagun +STR_8046_COPPER_ORE_HOPPER :Vasemaagivagun +STR_8047_WATER_TANKER :Veetanker +STR_8048_FRUIT_TRUCK :Puuviljavagun +STR_8049_RUBBER_TRUCK :Kummivagun STR_804A_SUGAR_TRUCK :Suhkruvagun -STR_804B_COTTON_CANDY_HOPPER :Suhkruvati vagun -STR_804C_TOFFEE_HOPPER :Iirise vagun +STR_804B_COTTON_CANDY_HOPPER :Suhkruvativagun +STR_804C_TOFFEE_HOPPER :Iirisevagun STR_804D_BUBBLE_VAN :Mullivagun STR_804E_COLA_TANKER :Koolatanker -STR_804F_CANDY_VAN :Maiustuste vagun -STR_8050_TOY_VAN :Mänguasjade vagun +STR_804F_CANDY_VAN :Maiustustevagun +STR_8050_TOY_VAN :Mänguasjavagun STR_8051_BATTERY_TRUCK :Patareivagun STR_8052_FIZZY_DRINK_TRUCK :Kihisevate jookide vagun -STR_8053_PLASTIC_TRUCK :Plastiku vagun -STR_8054_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Elektri) -STR_8055_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Elektri) -STR_8056_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Elektri) -STR_8057_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Elektri) +STR_8053_PLASTIC_TRUCK :Plastikuvagun +STR_8054_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (elektri) +STR_8055_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (elektri) +STR_8056_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (elektri) +STR_8057_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (elektri) STR_8058_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_8059_PASSENGER_CAR :Reisivagun STR_805A_MAIL_VAN :Postivagun -STR_805B_COAL_CAR :Kivisöe vagun +STR_805B_COAL_CAR :Kivisöevagun STR_805C_OIL_TANKER :Naftatanker -STR_805D_LIVESTOCK_VAN :Kariloomade vagun +STR_805D_LIVESTOCK_VAN :Loomavagun STR_805E_GOODS_VAN :Kaubavagun -STR_805F_GRAIN_HOPPER :Teravilja vagun -STR_8060_WOOD_TRUCK :Puidu vagun -STR_8061_IRON_ORE_HOPPER :Rauamaagi vagun -STR_8062_STEEL_TRUCK :Terase vagun +STR_805F_GRAIN_HOPPER :Teraviljavagun +STR_8060_WOOD_TRUCK :Palgivagun +STR_8061_IRON_ORE_HOPPER :Rauamaagivagun +STR_8062_STEEL_TRUCK :Terasevagun STR_8063_ARMORED_VAN :Soomusvagun STR_8064_FOOD_VAN :Toiduvagun STR_8065_PAPER_TRUCK :Paberivagun -STR_8066_COPPER_ORE_HOPPER :Vasemaagi vagun +STR_8066_COPPER_ORE_HOPPER :Vasemaagivagun STR_8067_WATER_TANKER :Veetanker -STR_8068_FRUIT_TRUCK :Puuvilja vagun +STR_8068_FRUIT_TRUCK :Puuviljavagun STR_8069_RUBBER_TRUCK :Kummivagun STR_806A_SUGAR_TRUCK :Suhkruvagun -STR_806B_COTTON_CANDY_HOPPER :Suhkruvati vagun -STR_806C_TOFFEE_HOPPER :Iirise vagun +STR_806B_COTTON_CANDY_HOPPER :Suhkruvativagun +STR_806C_TOFFEE_HOPPER :Iirisevagun STR_806D_BUBBLE_VAN :Mullivagun -STR_806E_COLA_TANKER :Koola Tanker -STR_806F_CANDY_VAN :Maiustuste vagun +STR_806E_COLA_TANKER :Koolatanker +STR_806F_CANDY_VAN :Maiustustevagun STR_8070_TOY_VAN :Mänguasjavagun -STR_8071_BATTERY_TRUCK :Patareide vagun +STR_8071_BATTERY_TRUCK :Patareivagun STR_8072_FIZZY_DRINK_TRUCK :Kihisevate jookide vagun -STR_8073_PLASTIC_TRUCK :Plastiku vagun -STR_8074_MPS_REGAL_BUS :MPS Kuninglik Buss -STR_8075_HEREFORD_LEOPARD_BUS :Herefordi Leopardi Buss -STR_8076_FOSTER_BUS :Foster Buss -STR_8077_FOSTER_MKII_SUPERBUS :Foster MkII Superbuss -STR_8078_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Buss -STR_8079_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Buss -STR_807A_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Buss -STR_807B_BALOGH_COAL_TRUCK :Balogh Söe Veok -STR_807C_UHL_COAL_TRUCK :Uhl Söe Veok -STR_807D_DW_COAL_TRUCK :DW Söe Veok -STR_807E_MPS_MAIL_TRUCK :MPS Postiauto -STR_807F_REYNARD_MAIL_TRUCK :Reynard Postiauto -STR_8080_PERRY_MAIL_TRUCK :Perry Postiauto -STR_8081_MIGHTYMOVER_MAIL_TRUCK :MightyMover Postiauto -STR_8082_POWERNAUGHT_MAIL_TRUCK :Powernaught Postiauto -STR_8083_WIZZOWOW_MAIL_TRUCK :Wizzowow Postiauto +STR_8073_PLASTIC_TRUCK :Plastikuvagun +STR_8074_MPS_REGAL_BUS :Kuninglik MPS buss +STR_8075_HEREFORD_LEOPARD_BUS :Hereford Leopard buss +STR_8076_FOSTER_BUS :Foster buss +STR_8077_FOSTER_MKII_SUPERBUS :Foster MkII superbuss +STR_8078_PLODDYPHUT_MKI_BUS :Ploddyphut MkI buss +STR_8079_PLODDYPHUT_MKII_BUS :Ploddyphut MkII buss +STR_807A_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII buss +STR_807B_BALOGH_COAL_TRUCK :Balogh kivisöeveok +STR_807C_UHL_COAL_TRUCK :Uhl kivisõeveok +STR_807D_DW_COAL_TRUCK :DW kivisõeveok +STR_807E_MPS_MAIL_TRUCK :MPS postiauto +STR_807F_REYNARD_MAIL_TRUCK :Reynard postiauto +STR_8080_PERRY_MAIL_TRUCK :Perry postiauto +STR_8081_MIGHTYMOVER_MAIL_TRUCK :MightyMover postiauto +STR_8082_POWERNAUGHT_MAIL_TRUCK :Powernaught postiauto +STR_8083_WIZZOWOW_MAIL_TRUCK :Wizzowow postiauto STR_8084_WITCOMBE_OIL_TANKER :Witcombe naftaveok STR_8085_FOSTER_OIL_TANKER :Foster naftaveok STR_8086_PERRY_OIL_TANKER :Perry naftaveok -STR_8087_TALBOTT_LIVESTOCK_VAN :Talbott Karjaveoauto -STR_8088_UHL_LIVESTOCK_VAN :Uhl Karjaveoauto -STR_8089_FOSTER_LIVESTOCK_VAN :Foster Karjaveoauto -STR_808A_BALOGH_GOODS_TRUCK :Balogh Kaubaveoauto -STR_808B_CRAIGHEAD_GOODS_TRUCK :Craighead Kaubaveoauto -STR_808C_GOSS_GOODS_TRUCK :Goss Kaubaveoauto -STR_808D_HEREFORD_GRAIN_TRUCK :Hereford Viljaveoauto -STR_808E_THOMAS_GRAIN_TRUCK :Thomas Viljaveoauto -STR_808F_GOSS_GRAIN_TRUCK :Goss Viljaveoauto -STR_8090_WITCOMBE_WOOD_TRUCK :Witcombe Puiduveoauto -STR_8091_FOSTER_WOOD_TRUCK :Foster Puiduveoauto -STR_8092_MORELAND_WOOD_TRUCK :Moreland Puiduveoauto -STR_8093_MPS_IRON_ORE_TRUCK :MPS Rauamaagiveoauto -STR_8094_UHL_IRON_ORE_TRUCK :Uhl Rauamaagiveoauto -STR_8095_CHIPPY_IRON_ORE_TRUCK :Chippy Rauamaagiveoauto -STR_8096_BALOGH_STEEL_TRUCK :Balogh Teraseveoauto -STR_8097_UHL_STEEL_TRUCK :Uhl Teraseveoauto -STR_8098_KELLING_STEEL_TRUCK :Kelling Teraseveoauto -STR_8099_BALOGH_ARMORED_TRUCK :Balogh Soomusauto -STR_809A_UHL_ARMORED_TRUCK :Uhl Soomusauto -STR_809B_FOSTER_ARMORED_TRUCK :Foster Soomusauto -STR_809C_FOSTER_FOOD_VAN :Foster Toiduveoauto -STR_809D_PERRY_FOOD_VAN :Perry Toiduveoauto -STR_809E_CHIPPY_FOOD_VAN :Chippy Toiduveoauto -STR_809F_UHL_PAPER_TRUCK :Uhl Paberiveoauto -STR_80A0_BALOGH_PAPER_TRUCK :Balogh Paberiveoauto -STR_80A1_MPS_PAPER_TRUCK :MPS Paberiveoauto -STR_80A2_MPS_COPPER_ORE_TRUCK :MPS Vasemaagiveoauto -STR_80A3_UHL_COPPER_ORE_TRUCK :Uhl Vasemaagiveoauto -STR_80A4_GOSS_COPPER_ORE_TRUCK :Goss Vasemaagiveoauto -STR_80A5_UHL_WATER_TANKER :Uhl Veeveoauto -STR_80A6_BALOGH_WATER_TANKER :Balogh Veeveoauto -STR_80A7_MPS_WATER_TANKER :MPS Veeveoauto -STR_80A8_BALOGH_FRUIT_TRUCK :Balogh Veeveoauto -STR_80A9_UHL_FRUIT_TRUCK :Uhl Puuviljaveoauto -STR_80AA_KELLING_FRUIT_TRUCK :Kelling Puuviljaveoauto +STR_8087_TALBOTT_LIVESTOCK_VAN :Talbott loomaveok +STR_8088_UHL_LIVESTOCK_VAN :Uhl loomaveok +STR_8089_FOSTER_LIVESTOCK_VAN :Foster loomaveok +STR_808A_BALOGH_GOODS_TRUCK :Balogh kaubaveok +STR_808B_CRAIGHEAD_GOODS_TRUCK :Craighead kaubaveok +STR_808C_GOSS_GOODS_TRUCK :Goss kaubaveok +STR_808D_HEREFORD_GRAIN_TRUCK :Hereford viljaveok +STR_808E_THOMAS_GRAIN_TRUCK :Thomas viljaveok +STR_808F_GOSS_GRAIN_TRUCK :Goss viljaveok +STR_8090_WITCOMBE_WOOD_TRUCK :Witcombe palgiveok +STR_8091_FOSTER_WOOD_TRUCK :Foster palgiveok +STR_8092_MORELAND_WOOD_TRUCK :Moreland palgiveok +STR_8093_MPS_IRON_ORE_TRUCK :MPS rauamaagiveok +STR_8094_UHL_IRON_ORE_TRUCK :Uhl rauamaagiveok +STR_8095_CHIPPY_IRON_ORE_TRUCK :Chippy rauamaagiveok +STR_8096_BALOGH_STEEL_TRUCK :Balogh teraseveok +STR_8097_UHL_STEEL_TRUCK :Uhl teraseveok +STR_8098_KELLING_STEEL_TRUCK :Kelling teraseveok +STR_8099_BALOGH_ARMORED_TRUCK :Balogh soomusauto +STR_809A_UHL_ARMORED_TRUCK :Uhl soomusauto +STR_809B_FOSTER_ARMORED_TRUCK :Foster soomusauto +STR_809C_FOSTER_FOOD_VAN :Foster toiduveok +STR_809D_PERRY_FOOD_VAN :Perry toiduveok +STR_809E_CHIPPY_FOOD_VAN :Chippy toiduveok +STR_809F_UHL_PAPER_TRUCK :Uhl paberiveok +STR_80A0_BALOGH_PAPER_TRUCK :Balogh paberiveok +STR_80A1_MPS_PAPER_TRUCK :MPS paberiveok +STR_80A2_MPS_COPPER_ORE_TRUCK :MPS vasemaagiveok +STR_80A3_UHL_COPPER_ORE_TRUCK :Uhl vasemaagiveok +STR_80A4_GOSS_COPPER_ORE_TRUCK :Goss vasemaagiveok +STR_80A5_UHL_WATER_TANKER :Uhl veeveok +STR_80A6_BALOGH_WATER_TANKER :Balogh veeveok +STR_80A7_MPS_WATER_TANKER :MPS veeveok +STR_80A8_BALOGH_FRUIT_TRUCK :Balogh veeveok +STR_80A9_UHL_FRUIT_TRUCK :Uhl puuviljaveok +STR_80AA_KELLING_FRUIT_TRUCK :Kelling puuviljaveok STR_80AB_BALOGH_RUBBER_TRUCK :Balogh kummiveok STR_80AC_UHL_RUBBER_TRUCK :Uhl kummiveok STR_80AD_RMT_RUBBER_TRUCK :RMT kummiveok -STR_80AE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Suhkruveoauto -STR_80AF_POWERNAUGHT_SUGAR_TRUCK :Powernaught Suhkruveoauto -STR_80B0_WIZZOWOW_SUGAR_TRUCK :Wizzowow Suhkruveoauto -STR_80B1_MIGHTYMOVER_COLA_TRUCK :MightyMover Koolaveoauto -STR_80B2_POWERNAUGHT_COLA_TRUCK :Powernaught Koolaveoauto -STR_80B3_WIZZOWOW_COLA_TRUCK :Wizzowow Koolaveoauto -STR_80B4_MIGHTYMOVER_COTTON_CANDY :MightyMover Suhkruvativeoauto -STR_80B5_POWERNAUGHT_COTTON_CANDY :Powernaught Suhkruvativeoauto -STR_80B6_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Suhkruvativeoauto -STR_80B7_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Iiriseveoauto -STR_80B8_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Iiriseveoauto -STR_80B9_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Iiriseveoauto -STR_80BA_MIGHTYMOVER_TOY_VAN :MightyMover Mänguasjaveoauto -STR_80BB_POWERNAUGHT_TOY_VAN :Powernaught Mänguasjaveoauto -STR_80BC_WIZZOWOW_TOY_VAN :Wizzowow Mänguasjaveoauto -STR_80BD_MIGHTYMOVER_CANDY_TRUCK :MightyMover Maiustusteveoauto -STR_80BE_POWERNAUGHT_CANDY_TRUCK :Powernaught Maiustusteveoauto -STR_80BF_WIZZOWOW_CANDY_TRUCK :Wizzowow Maiustusteveoauto -STR_80C0_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Patareiveoauto -STR_80C1_POWERNAUGHT_BATTERY_TRUCK :Powernaught Patareiveoauto -STR_80C2_WIZZOWOW_BATTERY_TRUCK :Wizzowow Patareiveoauto -STR_80C3_MIGHTYMOVER_FIZZY_DRINK :MightyMover Limonaadiveoauto -STR_80C4_POWERNAUGHT_FIZZY_DRINK :Powernaught Limonaadiveoauto -STR_80C5_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Limonaadiveoauto -STR_80C6_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastikuveoauto -STR_80C7_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastikuveoauto -STR_80C8_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastikuveoauto -STR_80C9_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Mulliveoauto -STR_80CA_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Mulliveoauto -STR_80CB_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Mulliveoauto +STR_80AE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover suhkruveok +STR_80AF_POWERNAUGHT_SUGAR_TRUCK :Powernaught suhkruveok +STR_80B0_WIZZOWOW_SUGAR_TRUCK :Wizzowow suhkruveok +STR_80B1_MIGHTYMOVER_COLA_TRUCK :MightyMover koolaveok +STR_80B2_POWERNAUGHT_COLA_TRUCK :Powernaught koolaveok +STR_80B3_WIZZOWOW_COLA_TRUCK :Wizzowow koolaveok +STR_80B4_MIGHTYMOVER_COTTON_CANDY :MightyMover suhkruvativeok +STR_80B5_POWERNAUGHT_COTTON_CANDY :Powernaught suhkruvativeok +STR_80B6_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow suhkruvativeok +STR_80B7_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover iiriseveok +STR_80B8_POWERNAUGHT_TOFFEE_TRUCK :Powernaught iiriseveok +STR_80B9_WIZZOWOW_TOFFEE_TRUCK :Wizzowow iiriseveok +STR_80BA_MIGHTYMOVER_TOY_VAN :MightyMover mänguasjaveok +STR_80BB_POWERNAUGHT_TOY_VAN :Powernaught mänguasjaveok +STR_80BC_WIZZOWOW_TOY_VAN :Wizzowow mänguasjaveok +STR_80BD_MIGHTYMOVER_CANDY_TRUCK :MightyMover maiustusteveok +STR_80BE_POWERNAUGHT_CANDY_TRUCK :Powernaught maiustusteveok +STR_80BF_WIZZOWOW_CANDY_TRUCK :Wizzowow maiustusteveok +STR_80C0_MIGHTYMOVER_BATTERY_TRUCK :MightyMover patareiveok +STR_80C1_POWERNAUGHT_BATTERY_TRUCK :Powernaught patareiveok +STR_80C2_WIZZOWOW_BATTERY_TRUCK :Wizzowow patareiveok +STR_80C3_MIGHTYMOVER_FIZZY_DRINK :MightyMover limonaadiveok +STR_80C4_POWERNAUGHT_FIZZY_DRINK :Powernaught limonaadiveok +STR_80C5_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow limonaadiveok +STR_80C6_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover plastikuveok +STR_80C7_POWERNAUGHT_PLASTIC_TRUCK :Powernaught plastikuveok +STR_80C8_WIZZOWOW_PLASTIC_TRUCK :Wizzowow plastikuveok +STR_80C9_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover mulliveok +STR_80CA_POWERNAUGHT_BUBBLE_TRUCK :Powernaught mulliveok +STR_80CB_WIZZOWOW_BUBBLE_TRUCK :Wizzowow mulliveok STR_80CC_MPS_OIL_TANKER :MPS naftatanker STR_80CD_CS_INC_OIL_TANKER :CS-Inc. naftatanker -STR_80CE_MPS_PASSENGER_FERRY :MPS Praam -STR_80CF_FFP_PASSENGER_FERRY :FFP Praam -STR_80D0_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hõljuk -STR_80D1_CHUGGER_CHUG_PASSENGER :Chugger-Chug Praam -STR_80D2_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Praam -STR_80D3_YATE_CARGO_SHIP :Yate Kaubalaev -STR_80D4_BAKEWELL_CARGO_SHIP :Bakewell Kaubalaev -STR_80D5_MIGHTYMOVER_CARGO_SHIP :Mightymover Kaubalaev +STR_80CE_MPS_PASSENGER_FERRY :MPS reisipraam +STR_80CF_FFP_PASSENGER_FERRY :FFP reisipraam +STR_80D0_BAKEWELL_300_HOVERCRAFT :Bakewell 300 hõljuklaev +STR_80D1_CHUGGER_CHUG_PASSENGER :Chugger-Chug reisipraam +STR_80D2_SHIVERSHAKE_PASSENGER_FERRY :Shivershake reisipraam +STR_80D3_YATE_CARGO_SHIP :Yate kaubalaev +STR_80D4_BAKEWELL_CARGO_SHIP :Bakewell kaubalaev +STR_80D5_MIGHTYMOVER_CARGO_SHIP :Mightymover kaubalaev STR_80D6_POWERNAUT_CARGO_SHIP :Powernaut Kaubalaev STR_80D7_SAMPSON_U52 :Sampson U52 STR_80D8_COLEMAN_COUNT :Coleman Count @@ -2580,7 +2581,7 @@ ##id 0x8800 STR_8800_TRAIN_DEPOT :{WHITE}{TOWN} Rongi Depoo -STR_8801_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab. . .{}Esimene rong saabus {STATION} jaama! +STR_8801_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab. . .{}{STATION} jaama saabus esimene rong! STR_8802_DETAILS :{WHITE}{STRING} (Detailid) STR_8803_TRAIN_IN_THE_WAY :{WHITE}Rong on ees STR_8804 :{SETX 10}{COMMA}: {STRING} {STRING} @@ -2595,15 +2596,15 @@ STR_880D_GO_TO_NON_STOP_TRANSFER :Sõida läbi {STATION} (Vea ja oota täislaadingut) STR_880E_GO_NON_STOP_TO_UNLOAD :Sõida läbi {STATION} (Laadi maha) STR_880F_GO_TO_NON_STOP_TRANSFER_UNLOAD :Sõida läbi {STATION} (Vea ja jäta tühjaks) -STR_8810_GO_NON_STOP_TO_LOAD :Sõida läbi {STATION} (Lae) +STR_8810_GO_NON_STOP_TO_LOAD :Sõida läbi {STATION} (laadi) STR_8811_GO_TO_NON_STOP_TRANSFER_LOAD :Sõida läbi {STATION} (Vea ja oota täislaadingut) -STR_GO_TO_TRAIN_DEPOT :Mine {TOWN} Rongidepoosse +STR_GO_TO_TRAIN_DEPOT :Mine linna {TOWN} rongidepoosse STR_SERVICE_AT_TRAIN_DEPOT :Hooldus linna {TOWN} rongidepoos -STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT :Sõida läbi {TOWN} Rongidepoo -STR_SERVICE_NON_STOP_AT_TRAIN_DEPOT :Hooldus Läbisõidul läbi {TOWN} Rongidepoo +STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT :Sõida läbi linna {TOWN} rongidepoo +STR_SERVICE_NON_STOP_AT_TRAIN_DEPOT :Hooldus Läbisõidul läbi linna {TOWN} rongidepoo -STR_HEADING_FOR_TRAIN_DEPOT :{ORANGE}Suundub {TOWN} Rongidepoosse -STR_HEADING_FOR_TRAIN_DEPOT_VEL :{ORANGE}Suundub {TOWN} Rongidepoosse, {VELOCITY} +STR_HEADING_FOR_TRAIN_DEPOT :{ORANGE}Suundub linna {TOWN} rongidepoosse +STR_HEADING_FOR_TRAIN_DEPOT_VEL :{ORANGE}Suundub linna {TOWN} rongidepoosse, {VELOCITY} STR_HEADING_FOR_TRAIN_DEPOT_SERVICE :{LTBLUE}Parandus{TOWN} Rongijaamas STR_HEADING_FOR_TRAIN_DEPOT_SERVICE_VEL :{LTBLUE}Parandus {TOWN} Rongijaamas, {VELOCITY} @@ -2633,13 +2634,13 @@ STR_CLONE_TRAIN :{BLACK}Klooni rong STR_CLONE_TRAIN_INFO :{BLACK}See ehitab koopia rongist koos kõikide vagunitega. CTRL-klikk jagab sihtpunkte STR_CLONE_TRAIN_DEPOT_INFO :{BLACK}See ehitab koopia rongist koos kõikide vagunitega. Vajuta sellele nuppule, ning seejärel rongile depoo sees või väljas. CTRL-klikk jagab sihtpunkte -STR_8820_RENAME :{BLACK}Nimeta ümber +STR_8820_RENAME :{BLACK}Muuda nime STR_8823_SKIP :{BLACK}Jäta vahele STR_8824_DELETE :{BLACK}Kustuta STR_8825_NON_STOP :{BLACK}Peatuseta STR_8826_GO_TO :{BLACK}Mine -STR_8827_FULL_LOAD :{BLACK}Täis laadung -STR_8828_UNLOAD :{BLACK}Lae maha +STR_8827_FULL_LOAD :{BLACK}Laadi täis +STR_8828_UNLOAD :{BLACK}Laadi maha STR_REFIT :{BLACK}Taasseadista STR_REFIT_TIP :{BLACK}Vali, millist laadungit ümber seadistada selles järjestuses. Ümberseadistuse käsu eemaldamiseks hoia klõpsamise ajal all Control nuppu STR_REFIT_ORDER :(Taasseadista {STRING}) @@ -2651,8 +2652,8 @@ STR_882C_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Ehitatud: {LTBLUE}{NUM}{BLACK} Väärtus: {LTBLUE}{CURRENCY} STR_882D_VALUE :{LTBLUE}{STRING}{BLACK} Väärtus: {LTBLUE}{CURRENCY} STR_882E :{WHITE}{VEHICLE} -STR_882F_LOADING_UNLOADING :{LTBLUE}Laen / Laen maha -STR_TRAIN_MUST_BE_STOPPED :{WHITE}Rong peab olema depoos peatutud +STR_882F_LOADING_UNLOADING :{LTBLUE}Laadin / Laadin maha +STR_TRAIN_MUST_BE_STOPPED :{WHITE}Rong peab olema depoos peatatud STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Ei saa saata rongi depoosse... STR_8831_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Pole ruumi käskudeks STR_8832_TOO_MANY_ORDERS :{WHITE}Liiga palju käske @@ -2675,7 +2676,7 @@ STR_8842_CENTER_MAIN_VIEW_ON_TRAIN :{BLACK}Keskenda põhivaade rongidepoo kohale STR_8843_TRAIN_VEHICLE_SELECTION :{BLACK}Rongivagunite nimekiri - vajuta sõidukile info jaoks STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN :{BLACK}Ehita valitud rongi sõiduk -STR_8845_RENAME_TRAIN_VEHICLE_TYPE :{BLACK}Nimeta ümber rongisõiduki tüüp +STR_8845_RENAME_TRAIN_VEHICLE_TYPE :{BLACK}Muuda rongisõiduki tüübi nime STR_8846_CURRENT_TRAIN_ACTION_CLICK :{BLACK}Praegune rongi tegevus - vajuta siia et peatada/käivitada rong STR_8847_SHOW_TRAIN_S_ORDERS :{BLACK}Näita rongi käske STR_8848_CENTER_MAIN_VIEW_ON_TRAIN :{BLACK}Vaate viimine rongi asukohale @@ -2715,7 +2716,7 @@ STR_8867_NAME_TRAIN :{BLACK}Rongi nimi STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}RONGIKOKKUPÕRGE!{}{COMMA} surid tules peale kokkusõitmist STR_8869_CAN_T_REVERSE_DIRECTION :{WHITE}Ei saa rongi ümber pöörata. -STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}Nimeta ümber rongisõiduki tüüp +STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}Muuda rongisõiduki tüübi nime STR_886B_CAN_T_RENAME_TRAIN_VEHICLE :{WHITE}Ei saa nimetada ümber rongisõiduki tüüpi... STR_886D_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Sunni valitud käsul visata maha laadung STR_886F_TRANSFER :{BLACK}Transpordi @@ -2730,7 +2731,7 @@ STR_9000_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Maanteesõiduk on ees STR_9001_ROAD_VEHICLES :{WHITE}{COMPANY} - {COMMA} Maanteesõiduk{P "" s} STR_9002 :{WHITE}{VEHICLE} -STR_9003_ROAD_VEHICLE_DEPOT :{WHITE}{TOWN} Maanteesõiduki depoo +STR_9003_ROAD_VEHICLE_DEPOT :{WHITE}Linna {TOWN} maanteesõidukite depoo STR_9004_NEW_VEHICLES :{BLACK}Uued sõidukid STR_9006_NEW_ROAD_VEHICLES :{WHITE}Uued maanteesõidukid STR_9007_BUILD_VEHICLE :{BLACK}Ehita sõidukeid @@ -2773,13 +2774,13 @@ STR_902C_NAME_ROAD_VEHICLE :{WHITE}Nimeta maanteeveok ümber STR_902D_CAN_T_NAME_ROAD_VEHICLE :{WHITE}Ei saa maanteveokit ümber nimetada... STR_902E_NAME_ROAD_VEHICLE :{BLACK}Nimeta maanteeveok ümber -STR_902F_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}Esimene buss saabus {STATION} jaama! -STR_9030_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}Esimene maanteesõiduk saabus {STATION} jaama! +STR_902F_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}{STATION} jaama saabus esimene buss! +STR_9030_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}{STATION} jaama saabus esimene maanteesõiduk! STR_9031_ROAD_VEHICLE_CRASH_DRIVER :{BLACK}{BIGFONT}Rongikokkupõrge!{}Juht suri peale õnnetust tules STR_9032_ROAD_VEHICLE_CRASH_DIE :{BLACK}{BIGFONT}Maanteesõiduki kokkupõrge rongiga!{}{COMMA} suri tules peale kokkupõrget rongiga STR_9033_CAN_T_MAKE_VEHICLE_TURN :{WHITE}Maanteesõidukit ei saa ringi pöörata... STR_ONLY_TURN_SINGLE_UNIT :{WHITE}Sa ei saa pöörata sõidukeid millel on mitu üksust -STR_9034_RENAME :{BLACK}Nimeta ümber +STR_9034_RENAME :{BLACK}Muuda nime STR_9035_RENAME_ROAD_VEHICLE_TYPE :{BLACK}Nimeta maanteesõiduki tüüp ümber STR_9036_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Nimeta maanteesõiduki tüüp ümber STR_9037_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Ei saa nimetada ümber maanteesõiduki tüüpi... @@ -2787,9 +2788,9 @@ STR_SERVICE_AT_ROADVEH_DEPOT :Hoolda {TOWN} Garaaþis STR_REFIT_ROAD_VEHICLE_TO_CARRY :{BLACK}Seadista maanteesõidukit kandma teist tüüpi laadungit -STR_REFIT_ROAD_VEHICLE :{BLACK}Seadista maantee sõiduk ümber +STR_REFIT_ROAD_VEHICLE :{BLACK}Muuda maanteesõiduki seadistust STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED :{BLACK}Seadista maanteesõiduk kandma valitud laadungitüüpi -STR_REFIT_ROAD_VEHICLE_CAN_T :{WHITE}Ei saa seadistada maantee sõidukit ümber +STR_REFIT_ROAD_VEHICLE_CAN_T :{WHITE}Maanteesõiduki seadistust ei saa ümber muuta STR_ROAD_SELECT_TYPE_OF_CARGO_FOR :{BLACK}Vali, millist tüüpi laadungit sõiduk veab ##id 0x9800 @@ -2832,7 +2833,7 @@ STR_9822_CENTER_MAIN_VIEW_ON_SHIP :{BLACK}Vii pea vaade paadikuuri juurde STR_9823_SHIPS_CLICK_ON_SHIP_FOR :{BLACK}Laevad - info saamiseks vajuta laevale STR_9824_BUILD_NEW_SHIPS_REQUIRES :{BLACK}Ehita uus laev (vajad paadikuuri) -STR_9825_SHIP_SELECTION_LIST_CLICK :{BLACK}Laeva valimisnimekiri - info saamiseks vajuta laevale +STR_9825_SHIP_SELECTION_LIST_CLICK :{BLACK}Laevade nimekiri - info saamiseks vajuta laevale STR_9826_BUILD_THE_HIGHLIGHTED_SHIP :{BLACK}Ehita valitud laev STR_9827_CURRENT_SHIP_ACTION_CLICK :{BLACK}Praegune laeva tegevus - vajuta siia, et peatada/käivitada laeva STR_9828_SHOW_SHIP_S_ORDERS :{BLACK}Näita laeva sihtpunkte @@ -2846,10 +2847,10 @@ STR_9831_NAME_SHIP :{WHITE}Anna laevale nimi STR_9832_CAN_T_NAME_SHIP :{WHITE}Ei saa laeva ümber nimetada... -STR_9833_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}Esimene laev saabus {STATION} sadamasse! +STR_9833_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}{STATION} sadamasse saabus esimene laev! STR_9834_POSITION_BUOY_WHICH_CAN :{BLACK}Aseta teemärgisena kasutatav poi STR_9835_CAN_T_POSITION_BUOY_HERE :{WHITE}Poid ei saa siia asetada... -STR_9836_RENAME :{BLACK}Nimeta ümber +STR_9836_RENAME :{BLACK}Muuda nime STR_9837_RENAME_SHIP_TYPE :{BLACK}Nimeta laeva tüüp ümber STR_9838_RENAME_SHIP_TYPE :{WHITE}Nimeta laeva tüüp ümber STR_9839_CAN_T_RENAME_SHIP_TYPE :{WHITE}Ei saa laeva tüüpi ümber nimetada... @@ -2878,7 +2879,7 @@ STR_A008_CAN_T_BUILD_AIRCRAFT :{WHITE}Ei saa ehitada lennukit... STR_A009_AIRCRAFT :{WHITE}{COMPANY} - {COMMA} Lennuk STR_A00A :{WHITE}{VEHICLE} -STR_A00B_ORDERS :{WHITE}{VEHICLE} (Sihtpunktid) +STR_A00B_ORDERS :{WHITE}{VEHICLE} (sihtpunktid) STR_A00C_DETAILS :{WHITE}{VEHICLE} (Detailid) STR_A00D_AGE_RUNNING_COST_YR :{BLACK}Vanus: {LTBLUE}{STRING}{BLACK} Hoolduskulud: {LTBLUE}{CURRENCY}/aastas STR_A00E_MAX_SPEED :{BLACK}Maks. kiirus: {LTBLUE}{VELOCITY} @@ -2920,11 +2921,11 @@ STR_A030_NAME_AIRCRAFT :{WHITE}Anna lennukile nimi STR_A031_CAN_T_NAME_AIRCRAFT :{WHITE}Ei saa lennukile nime anda STR_A032_NAME_AIRCRAFT :{BLACK}Nimeta lennuk ümber -STR_A033_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}Esimene lennuk saabub {STATION}i! +STR_A033_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Rahvas rõõmustab . . .{}{STATION} lennujaama saabus esimene lennuk! STR_A034_PLANE_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}Lennuõnnetus!{}{COMMA} surid tules {STATION}s STR_PLANE_CRASH_OUT_OF_FUEL :{BLACK}{BIGFONT}Lennuõnnetus!{}Lennukil lõppes kütus, {COMMA} surid tules! STR_A036 :{TINYFONT}{BLACK}{STATION} -STR_A037_RENAME :{BLACK}Nimeta ümber +STR_A037_RENAME :{BLACK}Muuda nime STR_A038_RENAME_AIRCRAFT_TYPE :{BLACK}Nimeta lennuki tüüp ümber STR_A039_RENAME_AIRCRAFT_TYPE :{WHITE}Nimeta lennuki tüüp ümber STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Ei saa lennuki tüüpi ümber nimetada... @@ -3090,7 +3091,7 @@ STR_MASS_STOP_DEPOT_TRAIN_TIP :{BLACK}Vajuta, kui tahad seisata kõiki ronge jaamas STR_MASS_STOP_DEPOT_ROADVEH_TIP :{BLACK}Vajuta, kui tahad seisata kõiki masinaid garaažis -STR_MASS_STOP_DEPOT_SHIP_TIP :{BLACK}Vajuta, kui tahad seisata kõiki laevu sadamas +STR_MASS_STOP_DEPOT_SHIP_TIP :{BLACK}Klõpsa, et peatada kõik sadamas olevad laevad. STR_MASS_STOP_HANGAR_TIP :{BLACK}Vajuta, kui tahad seisata kõiki lennukeid angaaris STR_MASS_START_DEPOT_TRAIN_TIP :{BLACK}Klõpsa kõikide depoos asuvate rongide käivitamiseks @@ -3120,14 +3121,14 @@ STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Maksuvus: {GOLD}{CURRENCY}{BLACK} Kaal: {GOLD}{WEIGHT_S} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Kiirus: {GOLD}{VELOCITY}{BLACK} Võimsus: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Kiirus: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Hoodluskulud: {GOLD}{CURRENCY}/aasta -STR_PURCHASE_INFO_CAPACITY :{BLACK}Mahutuvus: {GOLD}{CARGO} {STRING} +STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Hoolduskulud: {GOLD}{CURRENCY}/aasta +STR_PURCHASE_INFO_CAPACITY :{BLACK}Mahutavus: {GOLD}{CARGO} {STRING} STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Kujundatud: {GOLD}{NUM}{BLACK} Vanus: {GOLD}{COMMA} aastat STR_PURCHASE_INFO_RELIABILITY :{BLACK}Suurim töökindlus: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Maksuvus: {GOLD}{CURRENCY} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Kaal: {GOLD}{WEIGHT_S} ({WEIGHT_S}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Maksumus: {GOLD}{CURRENCY}{BLACK} Kiirus: {GOLD}{VELOCITY} -STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Mahutuvusy: {GOLD}{COMMA} reisjat, {COMMA} kotti kirju +STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Mahutavus: {GOLD}{COMMA} reisijat, {COMMA} kotti kirju STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Kiirendavad vagunid: {GOLD}+{POWER}{BLACK} Kaal: {GOLD}+{WEIGHT_S} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Ümberseadistatav: {GOLD} STR_PURCHASE_INFO_ALL_TYPES :Kõik kaubatüübid diff -r d4d00a16ef26 -r bfa6074e2833 lang/finnish.txt --- a/lang/finnish.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/finnish.txt Wed Jan 03 08:32:17 2007 +0000 @@ -154,11 +154,12 @@ STR_00B1_GAME_OPTIONS :{WHITE}Pelin asetukset STR_00B2_MESSAGE :{YELLOW}Viesti STR_00B3_MESSAGE_FROM :{YELLOW}Viesti: {STRING} +STR_POPUP_CAUTION_CAPTION :{WHITE}Varoitus! STR_00B4_CAN_T_DO_THIS :{WHITE}Ei onnistu.... STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Aluetta ei voi tyhjentää.... STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Alkuperäiset oikeudet {COPYRIGHT} 1995 Chris Sawyer, kaikki oikeudet pidätetään STR_00B7_VERSION :{BLACK}OpenTTD-versio {REV} -STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2006 OpenTTD-yhteisö +STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2006 The OpenTTD team STR_TRANSLATED_BY :{BLACK} Kääntäjä(t) - STR_00C5 :{BLACK}{CROSS} @@ -166,7 +167,7 @@ STR_00C7_QUIT :{WHITE}Sulje STR_00C8_YES :{BLACK}Kyllä STR_00C9_NO :{BLACK}Ei -STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Hylätäänkö peli ja palataan {STRING}-järjestelmään? +STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Lopetetaanko peli ja palataan {STRING}-järjestelmään? STR_00CB_1 :{BLACK}1 STR_00CC_2 :{BLACK}2 STR_00CD_3 :{BLACK}3 @@ -201,21 +202,21 @@ STR_00EA_OWNERS :Omistajat STR_00EB_ROADS :{BLACK}{TINYFONT}Tie STR_00EC_RAILROADS :{BLACK}{TINYFONT}Rautatie -STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Asema/lentokenttä/satama +STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Asemat/lentokentät/satamat STR_00EE_BUILDINGS_INDUSTRIES :{BLACK}{TINYFONT}Rakennus -STR_00EF_VEHICLES :{BLACK}{TINYFONT}Liikenneväline +STR_00EF_VEHICLES :{BLACK}{TINYFONT}Liikennevälineet STR_00F0_100M :{BLACK}{TINYFONT}100 m STR_00F1_200M :{BLACK}{TINYFONT}200 m STR_00F2_300M :{BLACK}{TINYFONT}300 m STR_00F3_400M :{BLACK}{TINYFONT}400 m STR_00F4_500M :{BLACK}{TINYFONT}500 m -STR_00F5_TRAINS :{BLACK}{TINYFONT}Juna -STR_00F6_ROAD_VEHICLES :{BLACK}{TINYFONT}Ajoneuvo -STR_00F7_SHIPS :{BLACK}{TINYFONT}Laiva -STR_00F8_AIRCRAFT :{BLACK}{TINYFONT}Lentokone -STR_00F9_TRANSPORT_ROUTES :{BLACK}{TINYFONT}Kuljetusreitti +STR_00F5_TRAINS :{BLACK}{TINYFONT}Junat +STR_00F6_ROAD_VEHICLES :{BLACK}{TINYFONT}Ajoneuvot +STR_00F7_SHIPS :{BLACK}{TINYFONT}Laivat +STR_00F8_AIRCRAFT :{BLACK}{TINYFONT}Lentokoneet +STR_00F9_TRANSPORT_ROUTES :{BLACK}{TINYFONT}Kuljetusreitit STR_00FA_COAL_MINE :{BLACK}{TINYFONT}Hiilikaivos -STR_00FB_POWER_STATION :{BLACK}{TINYFONT}Sähkölaitos +STR_00FB_POWER_STATION :{BLACK}{TINYFONT}Voimala STR_00FC_FOREST :{BLACK}{TINYFONT}Metsä STR_00FD_SAWMILL :{BLACK}{TINYFONT}Saha STR_00FE_OIL_REFINERY :{BLACK}{TINYFONT}Öljynjalostamo @@ -229,7 +230,7 @@ STR_0106_PAPER_MILL :{BLACK}{TINYFONT}Paperitehdas STR_0107_GOLD_MINE :{BLACK}{TINYFONT}Kultakaivos STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}Ruoanjalostamo -STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}timanttikaivos +STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}Timanttikaivos STR_010A_COPPER_ORE_MINE :{BLACK}{TINYFONT}Kuparikaivos STR_010B_FRUIT_PLANTATION :{BLACK}{TINYFONT}Hedelmäviljelmä STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Kumiviljelmä @@ -242,7 +243,7 @@ STR_0113_COLA_WELLS :{BLACK}{TINYFONT}Limsakenttä STR_0114_TOY_SHOP :{BLACK}{TINYFONT}Lelukauppa STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}Lelutehdas -STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}Muovikaivo +STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}Muovilähde STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}Sihijuomatehdas STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}Kuplageneraattori STR_0119_TOFFEE_QUARRY :{BLACK}{TINYFONT}Toffeelouhos @@ -269,8 +270,8 @@ STR_012E_CANCEL :{BLACK}Peruuta STR_012F_OK :{BLACK}OK STR_0130_RENAME :{BLACK}Nimeä uud. -STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Liian monta nimeä määritelty. -STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Nimi on jo käytössä. +STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Liian monta nimeä määritelty +STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Nimi on jo käytössä STR_0133_WINDOWS :Windows STR_0134_UNIX :Unix @@ -282,7 +283,7 @@ STR_013B_OWNED_BY :{WHITE}...omistaja: {STRING} STR_013C_CARGO :{BLACK}Rahti -STR_013D_INFORMATION :{BLACK}Tietoja +STR_013D_INFORMATION :{BLACK}Tietoa STR_013E_CAPACITIES :{BLACK}Kapasiteetit STR_013E_TOTAL_CARGO :{BLACK}Rahtia yhteensä STR_013F_CAPACITY :{BLACK}Kapaisteetti: {LTBLUE}{CARGO} @@ -308,7 +309,7 @@ STR_0150_SOMEONE :joku{SKIP}{SKIP} STR_0151_MAP_OF_WORLD :Maailmankartta STR_0152_TOWN_DIRECTORY :Kaupunkihakemisto -STR_0153_SUBSIDIES :Tukitarjoukset +STR_0153_SUBSIDIES :Tukiaiset STR_UNITS_IMPERIAL :Englantilainen STR_UNITS_METRIC :Metrinen @@ -343,17 +344,17 @@ STR_UNITS_FORCE_SI :{COMMA} kN ############ range for menu starts -STR_0154_OPERATING_PROFIT_GRAPH :Käyttökatekuvaaja -STR_0155_INCOME_GRAPH :Ansiotulon kuvaaja -STR_0156_DELIVERED_CARGO_GRAPH :Kuljetetun rahdin kuvaaja -STR_0157_PERFORMANCE_HISTORY_GRAPH :Suoritehistoriakuvaaja -STR_0158_COMPANY_VALUE_GRAPH :Yhtiön arvon kuvaaja +STR_0154_OPERATING_PROFIT_GRAPH :Liikevoitto +STR_0155_INCOME_GRAPH :Tulot +STR_0156_DELIVERED_CARGO_GRAPH :Kuljetettu rahti +STR_0157_PERFORMANCE_HISTORY_GRAPH :Suoritehistoria +STR_0158_COMPANY_VALUE_GRAPH :Yhtiön arvo STR_0159_CARGO_PAYMENT_RATES :Rahtimaksutaksat STR_015A_COMPANY_LEAGUE_TABLE :Yhtiökilpataulukko STR_PERFORMANCE_DETAIL_MENU :Suoritearviointi ############ range for menu ends -STR_015B_OPENTTD :{WHITE}Tietoja OpenTTD:stä +STR_015B_OPENTTD :{WHITE}Tietoa OpenTTD:stä STR_015C_SAVE_GAME :Tallenna peli STR_015D_LOAD_GAME :Lataa peli STR_015E_QUIT_GAME :Lopeta peli @@ -393,7 +394,14 @@ STR_NO_WAITING_CARGO :{BLACK}Minkäänlaista lastia ei ole odottamassa STR_SELECT_ALL_FACILITIES :{BLACK}Valitse kaikki laitteet STR_SELECT_ALL_TYPES :{BLACK}Valitse kaikki lastityypit (myös odottava lasti) +STR_MANAGE_LIST :{BLACK}Muokkaa listaa +STR_MANAGE_LIST_TIP :{BLACK}Ohjaa kaikkia listan ajoneuvoja STR_REPLACE_VEHICLES :Korvaa liikennevälineitä +STR_SEND_TRAIN_TO_DEPOT :Lähetä varikolle +STR_SEND_ROAD_VEHICLE_TO_DEPOT :Lähetä varikolle +STR_SEND_SHIP_TO_DEPOT :Lähetä varikolle +STR_SEND_AIRCRAFT_TO_HANGAR :Lähetä varikolle +STR_SEND_FOR_SERVICING :Lähetä huollettavaksi ############ range for months starts STR_0162_JAN :01. @@ -417,7 +425,7 @@ STR_0172_SAVE_GAME_ABANDON_GAME :{BLACK}Pelin tallennus, hylkääminen ja lopetus. STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}Näytä luettelo yhtiön asemista. STR_0174_DISPLAY_MAP :{BLACK}Näytä kartta. -STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Näytä kartta, kaupunkihakemisto +STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Näytä kartta, kaupunkihakemisto. STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}Näytä kaupunkihakemisto. STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}Näytä yhtiön taloustiedot. STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}Näytä yhtiön yleiset tiedot. @@ -438,7 +446,7 @@ STR_0187_OPTIONS :{BLACK}Asetukset STR_0188 :{BLACK}{SMALLUPARROW} STR_0189 :{BLACK}{SMALLDOWNARROW} -STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}Huoltoväliä ei voi muuttaa... +STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}Huoltoväliä ei voi muuttaa. STR_018B_CLOSE_WINDOW :{BLACK}Sulje ikkuna STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}Ikkunan otsake - vedä tästä siirtääksesi ikkunaa STR_STICKY_BUTTON :{BLACK}Merkitse ikkuna tahmeaksi; 'Sulje kaikki ikkunat'-nappi ei vaikuta tahmeisiin ikkunoihin. @@ -468,11 +476,11 @@ STR_019E_SHIP :Laiva STR_019F_TRAIN :Juna STR_01A0_IS_GETTING_OLD :{WHITE}{STRING} {COMMA} vanhenee. -STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} on kohta todella vanha. -STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} on kohta todella vanha ja pitää pikaisesti korvata. +STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} on todella vanha. +STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} on todella vanha ja täytyy korvata pikaisesti. STR_01A3_LAND_AREA_INFORMATION :{WHITE}Maa-aluetiedot -STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Puhdistuksen kustannus: {LTBLUE}- -STR_01A5_COST_TO_CLEAR :{BLACK}Puhdistuksen kustannus: {LTBLUE}{CURRENCY} +STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Puhdistuksen hinta: {LTBLUE}- +STR_01A5_COST_TO_CLEAR :{BLACK}Puhdistuksen hinta: {LTBLUE}{CURRENCY} STR_01A6_N_A :- STR_01A7_OWNER :{BLACK}Omistaja: {LTBLUE}{STRING} STR_01A8_LOCAL_AUTHORITY :{BLACK}Kunta: {LTBLUE}{STRING} @@ -521,7 +529,7 @@ STR_01D1_8 :({COMMA}/8 {STRING}) STR_01D2_JAZZ_JUKEBOX :{WHITE}Jazz-jukeboksi STR_01D3_SOUND_MUSIC :Ääni/musiikki -STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Näytä ääniasetukset. +STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Näytä ääni- ja musiikkiasetukset STR_01D5_ALL :{TINYFONT}Kaikki STR_01D6_OLD_STYLE :{TINYFONT}Vanha tyyli STR_01D7_NEW_STYLE :{TINYFONT}Uusi tyyli @@ -535,7 +543,7 @@ STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Hyppää seuraavaan raitaan. STR_01E0_STOP_PLAYING_MUSIC :{BLACK}Pysäytä musiikki. STR_01E1_START_PLAYING_MUSIC :{BLACK}Aloita musiikki. -STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Aseta liukusäätimiä vetämällä sopiva äänenvoimakkuus musiikille ja äänitehosteille. +STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Aseta liukusäätimillä sopiva äänenvoimakkuus musiikille ja tehosteille. STR_01E3 :{DKGREEN}{TINYFONT}-- STR_01E4_0 :{DKGREEN}{TINYFONT}0{COMMA} STR_01E5 :{DKGREEN}{TINYFONT}{COMMA} @@ -543,23 +551,23 @@ STR_01E7 :{DKGREEN}{TINYFONT}"{STRING}" STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}Raita{SETX 88}Nimi STR_01E9_SHUFFLE :{TINYFONT}Sekoita -STR_01EA_PROGRAM :{TINYFONT}{BLACK}Ohjelmoi +STR_01EA_PROGRAM :{TINYFONT}{BLACK}Soittolista STR_01EB_MUSIC_PROGRAM_SELECTION :{WHITE}Soittolistan valinta STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} "{STRING}" STR_01ED :{TINYFONT}{LTBLUE}{COMMA} "{STRING}" STR_01EE_TRACK_INDEX :{TINYFONT}{BLACK}Raita STR_01EF_PROGRAM :{TINYFONT}{BLACK}Soittolista - '{STRING}' -STR_01F0_CLEAR :{TINYFONT}{BLACK}Tyhjää +STR_01F0_CLEAR :{TINYFONT}{BLACK}Tyhjennä STR_01F1_SAVE :{TINYFONT}{BLACK}Tallenna -STR_01F2_CURRENT_PROGRAM_OF_MUSIC :{BLACK}Raitojen nykyinen soittolista +STR_01F2_CURRENT_PROGRAM_OF_MUSIC :{BLACK}Nykyinen soittolista STR_01F3_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Valitse 'kaikki raidat' STR_01F4_SELECT_OLD_STYLE_MUSIC :{BLACK}Valitse 'vanhan tyylin musiikki' STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}Valitse 'uuden tyylin musiikki' STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Valitse 'oma 1' (käyttäjän määritettävissä) STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Valitse 'oma 2' (käyttäjän määritettävissä) -STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Tyhjää nykyinen soittolista (vain Oma1 tai Oma2) +STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Tyhjennä nykyinen soittolista (vain Oma1 tai Oma2) STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Tallenna musiikkiasetukset -STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Napsauta musiikkiraitaa lisätäksesi sen nykyiseen soittolistaan (vain Oma1 tai Oma2). +STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Valitse musiikkiraita lisätäksesi sen nykyiseen soittolistaan (vain Oma1 tai Oma2). STR_CLICK_ON_TRACK_TO_REMOVE :{BLACK}Klikkaa raitaa poistaaksesi se nykyisestä ohjelmasta (ainoastaan Custom1 tai Custom2) STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Sekoittaminen päälle/pois STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Näytä musiikkiraitojen valintaikkuna @@ -603,14 +611,14 @@ STR_0220_CREATE_SCENARIO :{BLACK}Luo skenaario STR_0221_OPENTTD :{YELLOW}OpenTTD STR_0222_SCENARIO_EDITOR :{YELLOW}Skenaariomuokkain -STR_0223_LAND_GENERATION :{WHITE}Maan luominen +STR_0223_LAND_GENERATION :{WHITE}Maanrakennus STR_0224 :{BLACK}{UPARROW} STR_0225 :{BLACK}{DOWNARROW} STR_0226_RANDOM_LAND :{BLACK}Satunnainen maa STR_0227_RESET_LAND :{BLACK}Nollaa maa STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Suurenna madallettavan/korotettavan maa-alueen kokoa. STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Pienennä madallettavan/korotettavan maa-alueen kokoa. -STR_022A_GENERATE_RANDOM_LAND :{BLACK}Luo satunnainen maa. +STR_022A_GENERATE_RANDOM_LAND :{BLACK}Luo satunnainen maa STR_022B_RESET_LANDSCAPE :{BLACK}Nollaa maasto STR_022C_RESET_LANDSCAPE :{WHITE}Nollaa maasto STR_LOAD_GAME_HEIGHTMAP :{WHITE}Käytä korkeuskarttaa @@ -633,10 +641,10 @@ STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}Suurenna kaupunkia STR_023C_EXPAND :{BLACK}Laajenna STR_023D_RANDOM_TOWN :{BLACK}Satunnainen kaupunki -STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Rakenna kaupunki satunnaiseen kohtaan +STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Rakenna kaupunki satunnaiseen paikkaan STR_023F_INDUSTRY_GENERATION :{WHITE}Luo teollisuutta STR_0240_COAL_MINE :{BLACK}Hiilikaivos -STR_0241_POWER_STATION :{BLACK}Sähkölaitos +STR_0241_POWER_STATION :{BLACK}Voimala STR_0242_SAWMILL :{BLACK}Saha STR_0243_FOREST :{BLACK}Metsä STR_0244_OIL_REFINERY :{BLACK}Öljynjalostamo @@ -1029,6 +1037,7 @@ STR_CONFIG_PATCHES_BRIBE :{LTBLUE}Salli viranomaisten lahjominen: {ORANGE}{STRING} STR_CONFIG_PATCHES_NONUNIFORM_STATIONS :{LTBLUE}Epäyhtenäiset asemat: {ORANGE}{STRING} STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL :{LTBLUE}Uusi globaali tienhakualgor. (NPF, korvaa NTP:n): {ORANGE}{STRING} +STR_CONFIG_PATCHES_FREIGHT_TRAINS :{LTBLUE}Kerroin rahdin painolle raskaiden junien simuilointiin: {ORANGE}{STRING} STR_CONFIG_PATCHES_SMALL_AIRPORTS :{LTBLUE}Salli aina pienet lentokentät: {ORANGE}{STRING} @@ -2177,7 +2186,7 @@ STR_LIVERY_DIESEL :Dieselveturi STR_LIVERY_ELECTRIC :Sähköveturi STR_LIVERY_MONORAIL :Yksiraiteinen veturi -STR_LIVERY_MAGLEV :Maglev veturi +STR_LIVERY_MAGLEV :Maglev-veturi STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Matkustajavaunu (höyry) @@ -2199,7 +2208,7 @@ STR_LIVERY_AIRCRAFT_TIP :{BLACK}Näytä lentokoneiden väriteemat STR_LIVERY_PRIMARY_TIP :{BLACK}Valitse valitulle teemalle ensisijainen väri STR_LIVERY_SECONDARY_TIP :{BLACK}Valitse valitulle teemalle toissijainen väri -STR_LIVERY_PANEL_TIP :{BLACK}Valitse muutettava väriteema, tai valitse useita CTRL+klikkaus. Klikkaa valintalaatikkoa valitaksesi teeman +STR_LIVERY_PANEL_TIP :{BLACK}Valitse muutettava väriteema, tai valitse useita CTRL pohjassa. Paina valintalaatikkoa valitaksesi teeman ##id 0x8000 STR_8000_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (höyry) @@ -2878,16 +2887,30 @@ STR_NEWGRF_FILENAME :{BLACK}Tiedostonimi: {SILVER}{STRING} STR_NEWGRF_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_MD5SUM :{BLACK}MD5-summa: {SILVER}{STRING} +STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Olet tekemässä muutoksia käynnissä olevaan peliin. OpenTTD voi kaatua.{}Oletko varma? STR_NEWGRF_ADD :{BLACK}Lisää STR_NEWGRF_ADD_TIP :{BLACK}Lisää NewGRF-tiedosto listaan STR_NEWGRF_REMOVE :{BLACK}Poista STR_NEWGRF_REMOVE_TIP :{BLACK}Poista valittu NewGRF-tiedosto listalta STR_NEWGRF_MOVEUP :{BLACK}Siirrä ylös +STR_NEWGRF_MOVEUP_TIP :{BLACK}Siirrä valittua NewGRF-tiedostoa listassa ylöspäin STR_NEWGRF_MOVEDOWN :{BLACK}Siirrä alas +STR_NEWGRF_MOVEDOWN_TIP :{BLACK}Siirrä valittua NewGRF-tiedostoa listassa alaspäin +STR_NEWGRF_FILE_TIP :{BLACK}Lista asennetuista NewGRF-tiedostoista. Valitse tiedosto muokataksesi sen parametreja. STR_NEWGRF_PARAMETER :{BLACK}Parametrit: {SILVER}{STRING} +STR_NEWGRF_PARAMETER_QUERY :{BLACK}Anna NewGRF-parametrit +STR_NEWGRF_NO_INFO :{BLACK}Ei tietoa +STR_NEWGRF_ADD_CAPTION :{WHITE}NewGRF-tiedostot +STR_NEWGRF_ADD_FILE :{BLACK}Lisää valintaan +STR_NEWGRF_ADD_FILE_TIP :{BLACK}Lisää valittu NewGRF-tiedosto peliin +STR_NEWGRF_RESCAN_FILES :{BLACK}Päivitä +STR_NEWGRF_RESCAN_FILES_TIP :{BLACK}Päivitä saatavilla olevien NewGRF-tiedostojen lista +STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Ei voi lisätä tiedostoa: duplicate GRF ID +STR_NEWGRF_NOT_FOUND :{RED}Sopivaa tiedostoa ei löydy +STR_NEWGRF_DISABLED :{RED}Ei käytössä STR_CURRENCY_WINDOW :{WHITE}Oma valuutta STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Vaihtokurssi: {ORANGE}{CURRENCY} = £ {COMMA} @@ -2919,6 +2942,8 @@ STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}Näytä kaikki ajoneuvot, joilla on sama aikataulu ### depot strings +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Olet myymässä kaikki varikon ajoneuvot. Oletko varma? + STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP :{BLACK}Myy kaikki varikolla olevat junat STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP :{BLACK}Myy kaikki varikolla olevat ajoneuvot STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP :{BLACK}Myy kaikki telakalla olevat laivat @@ -2982,7 +3007,7 @@ STR_RAIL_VEHICLES :Rautatiejunat STR_ELRAIL_VEHICLES :Sähköjunat -STR_MONORAIL_VEHICLES :Yksiraidejunat +STR_MONORAIL_VEHICLES :Yksiraiteiset STR_MAGLEV_VEHICLES :Maglev-junat ############ End of list of rail types diff -r d4d00a16ef26 -r bfa6074e2833 lang/slovak.txt --- a/lang/slovak.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/slovak.txt Wed Jan 03 08:32:17 2007 +0000 @@ -1936,15 +1936,15 @@ STR_4832_ANNOUNCES_IMMINENT_CLOSURE :{BLACK}{BIGFONT}{INDUSTRY} oznamuje skore uzavretie! STR_4833_SUPPLY_PROBLEMS_CAUSE_TO :{BLACK}{BIGFONT}Zasobovacie problemy donutili {INDUSTRY} oznamit skore uzavretie! STR_4834_LACK_OF_NEARBY_TREES_CAUSES :{BLACK}{BIGFONT}Nedostatok dostupnej drevnej suroviny donutil {INDUSTRY} oznamit skore uzavretie! -STR_4835_INCREASES_PRODUCTION :{BLACK}{BIGFONT}{INDUSTRY} zvysuje produkciu! +STR_4835_INCREASES_PRODUCTION :{BLACK}{BIGFONT}{INDUSTRY} zvyšuje produkciu! STR_4836_NEW_COAL_SEAM_FOUND_AT :{BLACK}{BIGFONT}Nove nalezisko uhlia sa objavilo v {INDUSTRY}!{}Ocakava sa zdvojnasobenie produkcie! STR_4837_NEW_OIL_RESERVES_FOUND :{BLACK}{BIGFONT}Nove nalezisko ropy sa objavilo na {INDUSTRY}!{}Ocakava sa zdvojnasobenie produkcie! STR_4838_IMPROVED_FARMING_METHODS :{BLACK}{BIGFONT}Na {INDUSTRY} zlepsili pouzivane metody!Ocakava sa zdvojnasobenie produkcie! -STR_4839_PRODUCTION_DOWN_BY_50 :{BLACK}{BIGFONT}{INDUSTRY} znizuje produkciu o 50% +STR_4839_PRODUCTION_DOWN_BY_50 :{BLACK}{BIGFONT}{INDUSTRY} znižuje produkciu o 50% STR_483A_INSECT_INFESTATION_CAUSES :{BLACK}{BIGFONT}Premnozenie skodcov sposobilo znicenie urody na {INDUSTRY}!{}Produkcia sa znizila o 50% STR_483B_CAN_ONLY_BE_POSITIONED :{WHITE}... moze byt umiestnene len pri okraji mapy -STR_INDUSTRY_PROD_GOUP :{BLACK}{BIGFONT}{1:INDUSTRY} zvysuje produkciu {0:STRING.g} o {2:COMMA}%! -STR_INDUSTRY_PROD_GODOWN :{BLACK}{BIGFONT}{1:INDUSTRY} znizuje produkciu {0:STRING.g} o {2:COMMA}%! +STR_INDUSTRY_PROD_GOUP :{BLACK}{BIGFONT}{1:INDUSTRY} zvyšuje produkciu {0:STRING.g} o {2:COMMA}%! +STR_INDUSTRY_PROD_GODOWN :{BLACK}{BIGFONT}{1:INDUSTRY} znižuje produkciu {0:STRING.g} o {2:COMMA}%! ##id 0x5000 STR_5000_TRAIN_IN_TUNNEL :{WHITE}Vlak v tuneli @@ -2668,6 +2668,7 @@ STR_885C_BROKEN_DOWN :{RED}Pokazene STR_885D_AGE_RUNNING_COST_YR :{BLACK}Vek: {LTBLUE}{STRING}{BLACK} Naklady na prevadzku: {LTBLUE}{CURRENCY}/rok STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Nosnost: {LTBLUE}{WEIGHT_S} {BLACK}Vykon: {LTBLUE}{POWER}{BLACK} Max. rychlost: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Hmotnost: {LTBLUE}{WEIGHT_S} {BLACK}Výkon: {LTBLUE}{POWER}{BLACK} Max. rýchlost: {LTBLUE}{VELOCITY} {BLACK}Max. T.S.: {LTBLUE}{FORCE} STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Zisk tento rok: {LTBLUE}{CURRENCY} (predchadzajuci rok: {CURRENCY}) STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}Spolahlivost: {LTBLUE}{COMMA}% {BLACK}Pocet poruch od posledneho servisu: {LTBLUE}{COMMA} STR_8861_STOPPED :{RED}Zastavene @@ -3009,6 +3010,8 @@ STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}Zobrazit vsetky vozidla s rovnakym zoznamom prikazov ### depot strings +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Chystáte sa predat všetky vozidlá v depe. Ste si isý? + STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP :{BLACK}Predat všetky vlaky v depe STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP :{BLACK}Predat všetky vozidlá v garáži STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP :{BLACK}Predat všetky lode v lodenici @@ -3094,6 +3097,7 @@ STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Prestavatelne na: {GOLD} STR_PURCHASE_INFO_ALL_TYPES :Všetky druhy nákladu STR_PURCHASE_INFO_ALL_BUT :Všetko okrem {GOLD} +STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. trakcna sila: {GOLD}{FORCE} ########### String for New Landscape Generator diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/croatian.txt --- a/lang/unfinished/croatian.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/unfinished/croatian.txt Wed Jan 03 08:32:17 2007 +0000 @@ -309,7 +309,6 @@ STR_015D_LOAD_GAME :Učitaj igru STR_015E_QUIT_GAME :Napusti igru STR_015F_QUIT :Izlaz -STR_0160_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Sigurno želiš napustiti ovu igru? STR_0161_QUIT_GAME :{WHITE}Napusti igru STR_SORT_ORDER_TIP :{BLACK}Izaberi način sortiranja (silazno/uzlazno) STR_SORT_CRITERIA_TIP :{BLACK}Izaberi kriterij za sortiranje @@ -558,7 +557,6 @@ STR_0298_LOAD_SCENARIO :{WHITE}Učitaj scenarij STR_0299_SAVE_SCENARIO :{WHITE}Spremi scenarij STR_029A_PLAY_SCENARIO :{BLACK}Igraj scenarij -STR_029B_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Jesi li siguran da želiš odustati od ovog scenarija? STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Pomakni početni datum 1 godinu unatrag STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Pomakni početni datum 1 godinu unaprijed STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}...oba kraja mosta moraju biti na zemlji @@ -1017,6 +1015,7 @@ STR_100A_RAILROAD_CONSTRUCTION :{WHITE}Željeznička konstrukcija STR_100B_MONORAIL_CONSTRUCTION :{WHITE}Jednotračna konstrukcija STR_100C_MAGLEV_CONSTRUCTION :{WHITE}MagLev konstrukcija +STR_1010_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ne možeš postaviti znakove ovdje... STR_1011_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ne možeš graditi tračnice ovdje... STR_1012_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ne možeš ukloniti tračnice odavdje... STR_1013_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Ne možeš maknuti signale odavdje... @@ -1027,21 +1026,87 @@ STR_1017_MAGLEV_CONSTRUCTION :Izgradnja MagLeva STR_1018_BUILD_RAILROAD_TRACK :{BLACK}Izgradi željezničke tračnice STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Izgradi spremište vlakova (za gradnju i servisiranje vlakova) +STR_101D_BUILD_RAILROAD_TUNNEL :{BLACK}Izgradi željeznički tunel +STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO :{BLACK}Odaberi smjer željezničkog spremišta +STR_1021_RAILROAD_TRACK :Željezničke tračnice +STR_1023_RAILROAD_TRAIN_DEPOT :Spremište vlakova STR_1024_AREA_IS_OWNED_BY_ANOTHER :{WHITE}...područje je u vlasništvu druge tvrke +STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS :Željezničke tračnice s normalnim znakovima +STR_RAILROAD_TRACK_WITH_PRESIGNALS :Željezničke tračnice s prethodno postavljenim znakovima +STR_RAILROAD_TRACK_WITH_EXITSIGNALS :Željezničke tračnice s izlaznim znakovima +STR_RAILROAD_TRACK_WITH_COMBOSIGNALS :Željezničke tračnice s kombo znakovima ##id 0x1800 STR_1801_MUST_REMOVE_ROAD_FIRST :{WHITE}Moraš prvo ukloniti cestu +STR_ROAD_WORKS_IN_PROGRESS :{WHITE}Cestovni radovi u tijeku +STR_1802_ROAD_CONSTRUCTION :{WHITE}Rekonstrukcija ceste +STR_1803_SELECT_ROAD_BRIDGE :{WHITE}Izaberi cestovni most STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Ne možeš graditi cestu ovdje... STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Ne možep maknuti cestu odavdje... +STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}Smjer cestovnog spremišta +STR_1807_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Ne možeš izgraditi spremište cestovnih vozila ovdje... +STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}Nije moguće izgraditi autobusnu stanicu... +STR_1809_CAN_T_BUILD_TRUCK_STATION :{WHITE}Nije moguće izgraditi kamionski terminal... +STR_180A_ROAD_CONSTRUCTION :Rekonstrukcija ceste +STR_180B_BUILD_ROAD_SECTION :{BLACK}Izgradi dio ceste +STR_180C_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Izgradi spremište cestovnih vozila (za izgradnju i servisiranje vozila) +STR_180D_BUILD_BUS_STATION :{BLACK}Izgradi autobusnu stanicu +STR_180E_BUILD_TRUCK_LOADING_BAY :{BLACK}Izgradi pretovarni kamionski terminal STR_180F_BUILD_ROAD_BRIDGE :{BLACK}Izgradi cestovni most STR_1810_BUILD_ROAD_TUNNEL :{BLACK}Izgradi cestovni tunel +STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}Izaberi smjer spremišta cestovnih vozila STR_1814_ROAD :Cesta STR_1815_ROAD_WITH_STREETLIGHTS :Cesta sa semaforima +STR_1817_ROAD_VEHICLE_DEPOT :Spremište cestovnih vozila ##id 0x2000 STR_2000_TOWNS :{WHITE}Gradovi +STR_TOWN_LABEL_POP :{WHITE}{TOWN} ({COMMA}) +STR_TOWN_LABEL :{WHITE}{TOWN} +STR_TOWN_LABEL_TINY_BLACK :{TINYFONT}{BLACK}{TOWN} +STR_TOWN_LABEL_TINY_WHITE :{TINYFONT}{WHITE}{TOWN} +STR_2002 :{TINYFONT}{BLACK}{STRING} +STR_2004_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Građevina mora prvo biti srušena +STR_2005 :{WHITE}{TOWN} +STR_2006_POPULATION :{BLACK}Stanovništvo: {ORANGE}{COMMA}{BLACK} Kuće: {ORANGE}{COMMA} +STR_2007_RENAME_TOWN :Preimenuj grad +STR_2008_CAN_T_RENAME_TOWN :{WHITE}Grad se ne može preimenovati... +STR_2009_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN} lokalna samouprava odbija dozvoliti ovo +STR_200A_TOWN_NAMES_CLICK_ON_NAME :{BLACK}Imena gradova - klikni na ime kako bi centrirao pogled na ekran +STR_200B_CENTER_THE_MAIN_VIEW_ON :{BLACK}Centriraj glavni pogled na lokaciju grada +STR_200C_CHANGE_TOWN_NAME :{BLACK}Promijeni ime grada +STR_200D_PASSENGERS_LAST_MONTH_MAX :{BLACK}Putnika prošli mjesec: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} +STR_200E_MAIL_LAST_MONTH_MAX :{BLACK}Pošte prošli mjesec: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} +STR_200F_TALL_OFFICE_BLOCK :Visoki uredski blok +STR_2010_OFFICE_BLOCK :Uredski blok +STR_2011_SMALL_BLOCK_OF_FLATS :Mali stambeni blok +STR_2012_CHURCH :Crkva +STR_2013_LARGE_OFFICE_BLOCK :Veliki uredski blok +STR_2014_TOWN_HOUSES :Gradske kuće +STR_2015_HOTEL :Hotel +STR_2016_STATUE :Kip +STR_2017_FOUNTAIN :Fontana +STR_2018_PARK :Park +STR_2019_OFFICE_BLOCK :Uredski blok +STR_201A_SHOPS_AND_OFFICES :Trgovine i uredi +STR_201B_MODERN_OFFICE_BUILDING :Moderne uredske zgrade +STR_201C_WAREHOUSE :Skladište +STR_201D_OFFICE_BLOCK :Uredski blok +STR_201E_STADIUM :Stadion +STR_201F_OLD_HOUSES :Stare kuće +STR_2020_LOCAL_AUTHORITY :{BLACK}Lokalna samouprava +STR_2021_SHOW_INFORMATION_ON_LOCAL :{BLACK}Prikaži informacije o lokalnoj samoupravi +STR_2022_LOCAL_AUTHORITY :{WHITE}{TOWN} lokalna samouprava +STR_2023_TRANSPORT_COMPANY_RATINGS :{BLACK}Ocjene prijevoznih tvrtki: +STR_2024 :{YELLOW}{COMPANY}{PLAYERNAME}: {ORANGE}{STRING} +STR_2025_SUBSIDIES :{WHITE}Subvencije +STR_2026_SUBSIDIES_ON_OFFER_FOR :{BLACK}Ponuđene subvencije za pružanje usluga: +STR_2027_FROM_TO :{ORANGE}{STRING} od {STRING} do {STRING} +STR_2028_BY :{YELLOW} (do {DATE_SHORT}) +STR_202A_NONE :{ORANGE}Ništa +STR_202B_SERVICES_ALREADY_SUBSIDISED :{BLACK}Usluge već subvencionirane: STR_202C_FROM_TO :{ORANGE}{STRING} iz {STATION} prema {STATION}{YELLOW} ({COMPANY} STR_202D_UNTIL :{YELLOW}, do {DATE_SHORT}) STR_2035_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN} lokalne vlasti odbijaju dozvoliti izgradnju još jedne zračne luke u ovom gradu @@ -1068,15 +1133,24 @@ STR_204A_BUILD_STATUE_OF_COMPANY :Izgradi kip vlasnika tvrke STR_204B_FUND_NEW_BUILDINGS :Financiraj nove građevine STR_204C_BUY_EXCLUSIVE_TRANSPORT :Kupi ekskluzivna prijevozna prava +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY :Podmiti lokalnu samoupravu STR_204D_INITIATE_A_SMALL_LOCAL :{WHITE}{STRING}{}{YELLOW} Iniciraj malu oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY} STR_204E_INITIATE_A_MEDIUM_LOCAL :{WHITE}{STRING}{}{YELLOW} Iniciraj srednju oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY} STR_204F_INITIATE_A_LARGE_LOCAL :{WHITE}{STRING}{}{YELLOW} Iniciraj veliku oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY} STR_2050_FUND_THE_RECONSTRUCTION :{WHITE}{STRING}{}{YELLOW} Financiraj rekonstrukciju urbane mreže prometnica. Uzrokuje značajne poremećaje u cestovnom prometu do 6 mjeseci.{} Trošak: {CURRENCY} STR_2051_BUILD_A_STATUE_IN_HONOR :{WHITE}{STRING}{}{YELLOW} Izgradi kip u čast svoje tvrke.{} Trošak: {CURRENCY} STR_2052_FUND_THE_CONSTRUCTION_OF :{WHITE}{STRING}{}{YELLOW} Financiraj izgradnju novih poslovnih prostora u gradu.{} Trošak: {CURRENCY} +STR_2053_BUY_1_YEAR_S_EXCLUSIVE :{WHITE}{STRING}{}{YELLOW} Kupi jednogodišnje ekskluzivno prijevozno pravo u gradu. Gradska vlast će dopustiti putnicima i teretu da koriste samo stanice tvoje tvrtke.{} Trošak: {CURRENCY} STR_2056 :{TINYFONT}{WHITE}{TOWN} STR_2057 :{ORANGE}{TOWN}{BLACK} ({COMMA}) +STR_2058_UNDER_CONSTRUCTION :{STRING} (pod rekonstrukcijom) +STR_2059_IGLOO :Iglu +STR_205A_TEPEES :Indijanski šator +STR_INDUSTRY :{INDUSTRY} +STR_TOWN :{TOWN} +STR_INDUSTRY_FORMAT :{TOWN} {STRING} +STR_STATION :{STATION} ##id 0x2800 STR_2800_PLANT_TREES :Posadi drveće @@ -1151,6 +1225,7 @@ STR_3057_STATION_NAMES_CLICK_ON :{BLACK}Imena stanica - klikni na ime kako bi centrirao glavni pogled na stanicu STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT :{BLACK}Izaberi veličinu/tip zračne luke STR_305C_0 :{STATION} {STATIONFEATURES} +STR_STATION_SIGN_TINY :{TINYFONT}{STATION} STR_305E_RAILROAD_STATION :Željeznička stanica STR_305F_AIRCRAFT_HANGAR :Zrakoplovni hangar STR_3060_AIRPORT :Zračna luka @@ -1162,6 +1237,7 @@ STR_306A_BUOY_IN_THE_WAY :{WHITE}...plutača na putu STR_306C_STATION_TOO_SPREAD_OUT :{WHITE}...stanica previše proširena STR_306D_NONUNIFORM_STATIONS_DISALLOWED :{WHITE}...neuniformne stanice zabranjene +STR_USE_CTRL_TO_SELECT_MORE :{BLACK}Drži CTRL kako bi izabrao više od jednog itema ##id 0x3800 @@ -1278,6 +1354,7 @@ STR_5012_WOODEN :Drveni STR_5013_CONCRETE :Betonski STR_5014_TUBULAR_STEEL :Cijevni, čelični +STR_BRIDGE_TUBULAR_SILICON :Cjevni, silikonski STR_5015_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Ovdje se ne može graditi most... STR_5016_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Ovdje se ne može graditi tunel... STR_5017_RAILROAD_TUNNEL :Željeznički tunel @@ -1311,12 +1388,52 @@ ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 +STR_SV_EMPTY : +STR_SV_UNNAMED :Neimenovan +STR_SV_TRAIN_NAME :Vlak {COMMA} +STR_SV_ROADVEH_NAME :Cestovno vozilo {COMMA} +STR_SV_SHIP_NAME :Brod {COMMA} +STR_SV_AIRCRAFT_NAME :Zrakoplov {COMMA} +STR_SV_STNAME :{STRING} +STR_SV_STNAME_NORTH :{STRING} Sjever +STR_SV_STNAME_SOUTH :{STRING} Jug +STR_SV_STNAME_EAST :{STRING} Istok +STR_SV_STNAME_WEST :{STRING} Zapad +STR_SV_STNAME_CENTRAL :{STRING} Centrala +STR_SV_STNAME_TRANSFER :{STRING} Transfer +STR_SV_STNAME_HALT :{STRING} Zaustav +STR_SV_STNAME_VALLEY :{STRING} Dolina +STR_SV_STNAME_HEIGHTS :{STRING} Visine +STR_SV_STNAME_WOODS :{STRING} Šume +STR_SV_STNAME_LAKESIDE :{STRING} Jezero +STR_SV_STNAME_EXCHANGE :{STRING} Burza +STR_SV_STNAME_AIRPORT :{STRING} Zračna luka +STR_SV_STNAME_OILFIELD :{STRING} Naftno polje +STR_SV_STNAME_MINES :{STRING} Rudnici +STR_SV_STNAME_DOCKS :{STRING} Pristaništa +STR_SV_STNAME_BUOY_1 :{STRING} Plutača 1 +STR_SV_STNAME_BUOY_2 :{STRING} Plutača 2 +STR_SV_STNAME_BUOY_3 :{STRING} Plutača 3 +STR_SV_STNAME_BUOY_4 :{STRING} Plutača 4 +STR_SV_STNAME_BUOY_5 :{STRING} Plutača 5 +STR_SV_STNAME_BUOY_6 :{STRING} Plutača 6 +STR_SV_STNAME_BUOY_7 :{STRING} Plutača 7 +STR_SV_STNAME_BUOY_8 :{STRING} Plutača 8 +STR_SV_STNAME_BUOY_9 :{STRING} Plutača 9 +STR_SV_STNAME_ANNEXE :{STRING} Aneks +STR_SV_STNAME_SIDINGS :{STRING} Krak +STR_SV_STNAME_BRANCH :{STRING} Ogranak +STR_SV_STNAME_UPPER :Gornji {STRING} +STR_SV_STNAME_LOWER :Donji {STRING} +STR_SV_STNAME_HELIPORT :{STRING} Heliodrom +STR_SV_STNAME_FOREST :{STRING} Šuma ############ end of savegame specific region! ##id 0x6800 STR_6800_DIFFICULTY_LEVEL :{WHITE}Težina igre +STR_OPTIONS_SAVE_CHANGES :{BLACK}Spremi ############ range for difficulty levels starts STR_6801_EASY :{BLACK}Lagano @@ -1343,8 +1460,10 @@ STR_6813_ECONOMY :{LTBLUE}Ekonomija: {ORANGE}{STRING} STR_6814_TRAIN_REVERSING :{LTBLUE}Promjena smjera vlakova: {ORANGE}{STRING} STR_6815_DISASTERS :{LTBLUE}Prirodne katastrofe: {ORANGE}{STRING} +STR_16816_CITY_APPROVAL :{LTBLUE}Stav gradsko vijeća prema restrukturiranju područja: {ORANGE}{STRING} ############ range for difficulty settings ends +STR_26816_NONE :Ništa STR_6816_LOW :Nisko STR_6817_NORMAL :Normalno STR_6818_HIGH :Visoko @@ -1355,6 +1474,7 @@ STR_681D_MEDIUM :Umjereno STR_681E_FAST :Brzo STR_681F_VERY_FAST :Vrlo brzo +STR_VERY_LOW :Vrlo nisko STR_6820_LOW :Nisko STR_6821_MEDIUM :Umjereno STR_6822_HIGH :Visoko @@ -1419,10 +1539,12 @@ STR_7020_TOTAL :{WHITE}Ukupno: STR_7021 :{COMPANY}{PLAYERNAME} STR_7022_INCOME_GRAPH :{WHITE}Graf prihoda +STR_CURRCOMPACT :{CURRCOMPACT64} STR_7024 :{COMMA} STR_7025_OPERATING_PROFIT_GRAPH :{WHITE}Graf operativnih prihoda STR_7026_BANK_BALANCE :{WHITE}Bankovna bilanca STR_7027_LOAN :{WHITE}Kredit +STR_MAX_LOAN :{WHITE}Maks zajam: {BLACK}{CURRENCY64} STR_7028 :{BLACK}{CURRENCY64} STR_7029_BORROW :{BLACK}Pozajmi {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} STR_702A_REPAY :{BLACK}Otplati {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} @@ -1431,6 +1553,7 @@ STR_702D_LOAN_ALREADY_REPAYED :{WHITE}...nemaš kredita za otplatu STR_702E_REQUIRED :{WHITE}...{CURRENCY} potrebno STR_702F_CAN_T_REPAY_LOAN :{WHITE}Ne možeš otplatiti kredit... +STR_INSUFFICIENT_FUNDS :{WHITE}Ne možeš dati novac koji je pozajmljen od banke... STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT :{BLACK}Odaberi novo lice za direktora STR_7031_CHANGE_THE_COMPANY_VEHICLE :{BLACK}Promijeni izgled vozila tvrtke STR_7032_CHANGE_THE_PRESIDENT_S :{BLACK}Promjeni ime direktora @@ -1441,6 +1564,7 @@ STR_7037_PRESIDENT :{WHITE}{PLAYERNAME}{}{GOLD}(Direktor) STR_7038_INAUGURATED :{GOLD}Na poziciji od: {WHITE}{NUM} STR_7039_VEHICLES :{GOLD}Vozila: +STR_AIRCRAFT :{WHITE}{COMMA} zrakoplov STR_7042_NONE :{WHITE}Ništa STR_7043_FACE_SELECTION :{WHITE}Odabir lica STR_7044_MALE :{BLACK}Muško @@ -1472,7 +1596,9 @@ STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED :{BLACK}{BIGFONT}Osnovana je nova prijevozna tvrtka! STR_705F_STARTS_CONSTRUCTION_NEAR :{BLACK}{BIGFONT}{COMPANY} započinje gradnju blizu grada {TOWN}! STR_7060_CAN_T_BUY_COMPANY :{WHITE}Ne možeš kupiti tvrtku... +STR_7061_CARGO_PAYMENT_RATES :{WHITE}Isplatne rate tereta STR_7062_DAYS_IN_TRANSIT :{BLACK}{TINYFONT}Dana u tranzitu +STR_7064_TOGGLE_GRAPH_FOR_CARGO :{BLACK}Aktiviraj/deaktiviraj graf za vrstu tereta STR_7065 :{BLACK}{TINYFONT}{STRING} STR_7066_ENGINEER :Inženjer STR_7067_TRAFFIC_MANAGER :Prijevozni upravitelj @@ -1567,9 +1693,6 @@ - - - ############ Lists rail types diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/greek.txt --- a/lang/unfinished/greek.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/unfinished/greek.txt Wed Jan 03 08:32:17 2007 +0000 @@ -255,7 +255,6 @@ STR_015D_LOAD_GAME :Φόρτωση παιχνιδιού STR_015E_QUIT_GAME :Παραίτηση από το παιχνίδι STR_015F_QUIT :Έξοδος -STR_0160_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Είστε βέβαιοι ότι θέλετε να παραιτηθείτε από το παιχνίδι; STR_0161_QUIT_GAME :{WHITE}Παραίτηση από το Παιχνίδι @@ -325,9 +324,9 @@ STR_019D_AIRCRAFT :Αεροσκάφος STR_019E_SHIP :Πλοίο STR_019F_TRAIN :Τρένο -STR_01A0_IS_GETTING_OLD :{WHITE}{STRING} {COMMA} παλιώνει -STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} παλιώνει πολύ -STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} παλιώνει πολύ και χρειάζεται αντικατάσταση +STR_01A0_IS_GETTING_OLD :{WHITE}Το {STRING} {COMMA} παλιώνει +STR_01A1_IS_GETTING_VERY_OLD :{WHITE}Το {STRING} {COMMA} παλιώνει πολύ +STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}Το {STRING} {COMMA} παλιώνει πολύ και χρειάζεται επειγόντωςαντικατάσταση STR_01A3_LAND_AREA_INFORMATION :{WHITE}Πληροφορίες Περιοχής Εδάφους STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Κόστος καθαρισμού: {LTBLUE}Μ/Δ STR_01A5_COST_TO_CLEAR :{BLACK}Κόστος καθαρισμού: {LTBLUE}{CURRENCY} @@ -335,41 +334,41 @@ STR_01A7_OWNER :{BLACK}Ιδιοκτήτης: {LTBLUE}{STRING} STR_01A8_LOCAL_AUTHORITY :{BLACK}Τοπική αρχή: {LTBLUE}{STRING} STR_01A9_NONE :Κανένα -STR_01AA_NAME :{BLACK}'Ονομα +STR_01AA_NAME :{BLACK}Όνομα STR_01AB :{BLACK}{TINYFONT}{STRING} ############ range for days starts -STR_01AC_1ST :1ος -STR_01AD_2ND :2ος -STR_01AE_3RD :3ος -STR_01AF_4TH :4ος -STR_01B0_5TH :5ος -STR_01B1_6TH :6ος -STR_01B2_7TH :7ος -STR_01B3_8TH :8ος -STR_01B4_9TH :9ος -STR_01B5_10TH :10ος -STR_01B6_11TH :11ος -STR_01B7_12TH :12ος -STR_01B8_13TH :13ος -STR_01B9_14TH :14ος -STR_01BA_15TH :15ος -STR_01BB_16TH :16ος -STR_01BC_17TH :17ος -STR_01BD_18TH :18ος -STR_01BE_19TH :19ος -STR_01BF_20TH :20ος -STR_01C0_21ST :21ος -STR_01C1_22ND :22ος -STR_01C2_23RD :23ος -STR_01C3_24TH :24ος -STR_01C4_25TH :25ος -STR_01C5_26TH :26ος -STR_01C6_27TH :27ος -STR_01C7_28TH :28ος -STR_01C8_29TH :29ος -STR_01C9_30TH :30ος -STR_01CA_31ST :31ος +STR_01AC_1ST :1{G ος η ο} +STR_01AD_2ND :2{G ος η ο} +STR_01AE_3RD :3{G ος η ο} +STR_01AF_4TH :4{G ος η ο} +STR_01B0_5TH :5{G ος η ο} +STR_01B1_6TH :6{G ος η ο} +STR_01B2_7TH :7{G ος η ο} +STR_01B3_8TH :8{G ος η ο} +STR_01B4_9TH :9{G ος η ο} +STR_01B5_10TH :10{G ος η ο} +STR_01B6_11TH :11{G ος η ο} +STR_01B7_12TH :12{G ος η ο} +STR_01B8_13TH :13{G ος η ο} +STR_01B9_14TH :14{G ος η ο} +STR_01BA_15TH :15{G ος η ο} +STR_01BB_16TH :16{G ος η ο} +STR_01BC_17TH :17{G ος η ο} +STR_01BD_18TH :18{G ος η ο} +STR_01BE_19TH :19{G ος η ο} +STR_01BF_20TH :20{G ος η ο} +STR_01C0_21ST :21{G ος η ο} +STR_01C1_22ND :22{G ος η ο} +STR_01C2_23RD :23{G ος η ο} +STR_01C3_24TH :24{G ος η ο} +STR_01C4_25TH :25{G ος η ο} +STR_01C5_26TH :26{G ος η ο} +STR_01C6_27TH :27{G ος η ο} +STR_01C7_28TH :28{G ος η ο} +STR_01C8_29TH :29{G ος η ο} +STR_01C9_30TH :30{G ος η ο} +STR_01CA_31ST :31{G ος η ο} ############ range for days ends STR_01CB :{TINYFONT}{COMMA} @@ -388,7 +387,7 @@ STR_01DA_CUSTOM_2 :{TINYFONT}Προσαρμοσμένο 2 STR_01DB_MUSIC_VOLUME :{BLACK}{TINYFONT}Ένταση Μουσικής STR_01DC_EFFECTS_VOLUME :{BLACK}{TINYFONT}Ένταση Εφφέ -STR_01DD_MIN_MAX :{BLACK}{TINYFONT}ΕΛ ' ' ' ' ' ' ΜΕΓ +STR_01DD_MIN_MAX :{BLACK}{TINYFONT}ΕΛΑΧ ' ' ' ' ' ' ΜΕΓ STR_01DE_SKIP_TO_PREVIOUS_TRACK :{BLACK}Πλοήγηση στο προηγούμενο κομμάτι της συλλογής STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Πλοήγηση στο επόμενο κομμάτι στη συλλογή STR_01E0_STOP_PLAYING_MUSIC :{BLACK}Σταμάτημα αναπαραγωγής @@ -400,7 +399,7 @@ STR_01E6 :{DKGREEN}{TINYFONT}------ STR_01E7 :{DKGREEN}{TINYFONT}"{STRING}" STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}Κομμάτι{SETX 88}Τίτλος -STR_01E9_SHUFFLE :{TINYFONT}Shuffle +STR_01E9_SHUFFLE :{TINYFONT}Τυχαία αναπαραγωγή STR_01EA_PROGRAM :{TINYFONT}{BLACK}Πρόγραμμα STR_01EB_MUSIC_PROGRAM_SELECTION :{WHITE}Επιλογή Μουσικού Προγράμματος STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} "{STRING}" @@ -413,15 +412,15 @@ STR_01F3_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Επιλογή προγράμματος 'όλα τα κομμάτια' STR_01F4_SELECT_OLD_STYLE_MUSIC :{BLACK}Επιλογή προγράμματος 'παλιό στυλ' STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}Επιλογή προγράμματος 'νέο στυλ' -STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Επιλογή προγράμματος 'προσαρμοσμένο 1' -STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Επιλογή προγράμματος 'προσαρμοσμένο 2' +STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Επιλογή προγράμματος 'Προσαρμοσμένο 1' +STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Επιλογή προγράμματος 'Προσαρμοσμένο 2' STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Καθαρισμός τρέχοντος προγράμματος (Προσαρμοσμένο1 ή Προσαρμοσμένο2 μόνο) STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Αποθήκευση επιλογών μουσικής STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Κάντε κλίκ στο μουσικό κομμάτι για προσθήκη στο τρέχον πρόγραμμα (Προσαρμοσμένο1 ή Προσαρμοσμένο2 μόνο) -STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Εναλλαγή shuffle on/off στο πρόγραμμα +STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Εναλλαγή τυχαίας αναπαραγωγής on/off στο πρόγραμμα STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Εμφάνιση παραθύρου επιλογής μουσικού κομματιού STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Κάντε κλίκ στην υπηρεσία για κεντράρισμα στην βιομηχανία/πόλη -STR_01FE_DIFFICULTY :{BLACK}Δυσκολία ({STRING}) +STR_01FE_DIFFICULTY :{BLACK}{G=f}Δυσκολία ({STRING}) STR_01FF :{TINYFONT}{BLACK}{DATE_LONG} STR_0200_LAST_MESSAGE_NEWS_REPORT :Τελευταίο μήνυμα/αναφορά νέων STR_0201_MESSAGE_SETTINGS :Ρυθμίσεις μηνυμάτων @@ -439,7 +438,7 @@ STR_020E_SUBSIDIES :{YELLOW}Επιχορηγήσεις STR_020F_GENERAL_INFORMATION :{YELLOW}Γενικές πληροφορίες STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...πολύ μακριά από τον προηγούμενο προορισμό -STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Οι καλύτερες εταιρείες που έφτασαν {NUM}{}({STRING} Επίπεδο) +STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Οι καλύτερες εταιρείες που έφτασαν το {NUM}{}({STRING} Επίπεδο) STR_0212 :{BIGFONT}{COMMA}, STR_0213_BUSINESSMAN :Επαγγελματίας STR_0214_ENTREPRENEUR :Επιχειρηματίας @@ -453,8 +452,8 @@ STR_021F :{BLUE}{COMMA} STR_0220_CREATE_SCENARIO :{BLACK}Δημιουργία Σεναρίου STR_0221_OPENTTD :{YELLOW}OpenTTD -STR_0222_SCENARIO_EDITOR :{YELLOW}Συντάκτης Σεναρίου -STR_0223_LAND_GENERATION :{WHITE}Γεννήτρια Γης +STR_0222_SCENARIO_EDITOR :{YELLOW}Πρόγραμμα Επεξερτασίας Σεναρίου +STR_0223_LAND_GENERATION :{WHITE}Δημιουργία Γης STR_0224 :{BLACK}{UPARROW} STR_0225 :{BLACK}{DOWNARROW} STR_0226_RANDOM_LAND :{BLACK}Τυχαία Γη @@ -482,20 +481,20 @@ STR_023D_RANDOM_TOWN :{BLACK}Τυχαία Πόλη STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Χτίσιμο πόλης σε τυχαία τοποθεσία STR_023F_INDUSTRY_GENERATION :{WHITE}Δημιουργία Βιομηχανίας -STR_0240_COAL_MINE :{BLACK}Ορυχείο Άνθρακα -STR_0241_POWER_STATION :{BLACK}Σταθμός Παραγωγής Ηλεκτρισμού -STR_0242_SAWMILL :{BLACK}Πριονιστήριο -STR_0243_FOREST :{BLACK}Δάσος -STR_0244_OIL_REFINERY :{BLACK}Διυλιστήριο -STR_0245_OIL_RIG :{BLACK}Πλατφόρμα Πετρελαίου -STR_0246_FACTORY :{BLACK}Εργοστάσιο -STR_0247_STEEL_MILL :{BLACK}Μύλος Χάλυβα -STR_0248_FARM :{BLACK}Φάρμα -STR_0249_IRON_ORE_MINE :{BLACK}Ορυχείο Μεταλλεύματος Σιδήρου +STR_0240_COAL_MINE :{BLACK}{G=n}Ορυχείο Άνθρακα +STR_0241_POWER_STATION :{BLACK}{G=m}Σταθμός Παραγωγής Ηλεκτρισμού +STR_0242_SAWMILL :{BLACK}{G=n}Πριονιστήριο +STR_0243_FOREST :{BLACK}{G=n}Δάσος +STR_0244_OIL_REFINERY :{BLACK}{G=n}Διυλιστήριο +STR_0245_OIL_RIG :{BLACK}{G=f}Πλατφόρμα Πετρελαίου +STR_0246_FACTORY :{BLACK}{G=n}Εργοστάσιο +STR_0247_STEEL_MILL :{BLACK}{G=m}Μύλος Χάλυβα +STR_0248_FARM :{BLACK}{G=f}Φάρμα +STR_0249_IRON_ORE_MINE :{BLACK}{G=n}Ορυχείο Μεταλλεύματος Σιδήρου STR_024A_OIL_WELLS :{BLACK}Πηγάδια Πετρελαίου -STR_024B_BANK :{BLACK}Τράπεζα -STR_024C_PAPER_MILL :{BLACK}Μύλος Χαρτιού -STR_024D_FOOD_PROCESSING_PLANT :{BLACK}Εργοστάσιο Επεξεργασίας Τροφίμων +STR_024B_BANK :{BLACK}{G=f}Τράπεζα +STR_024C_PAPER_MILL :{BLACK}{G=m}Μύλος Χαρτιού +STR_024D_FOOD_PROCESSING_PLANT :{BLACK}{G=n}Εργοστάσιο Επεξεργασίας Τροφίμων STR_024E_PRINTING_WORKS :{BLACK}Εργασίες Εκτύπωσης STR_024F_GOLD_MINE :{BLACK}Ορυχείο Χρυσού STR_0250_LUMBER_MILL :{BLACK}Μύλος Ξυλείας @@ -551,7 +550,7 @@ STR_0282_CONSTRUCT_BUBBLE_GENERATOR :{BLACK}Κατασκευή Γεννήτριας Φυσαλίδων STR_0283_CONSTRUCT_TOFFEE_QUARRY :{BLACK}Κατασκευή Λατομείου Τόφυ STR_0284_CONSTRUCT_SUGAR_MINE :{BLACK}Κατασκευή Ορυχείου Ζάχαρης -STR_0285_CAN_T_BUILD_HERE :{WHITE}Αδύνατο να χτιστεί {STRING} εδώ... +STR_0285_CAN_T_BUILD_HERE :{WHITE}Αδύνατο να χτιστεί {G ο η το} {STRING} εδώ... STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE}...πρέπει να χτιστεί πόλη πρώτα STR_0287_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}...επιτρέπεται μόνο μία ανά πόλη STR_0288_PLANT_TREES :{BLACK}Φύτευση Δέντρων @@ -566,15 +565,14 @@ STR_0291_DELETE_THIS_TOWN_COMPLETELY :{BLACK}Πλήρης διαγραφή πόλεως STR_0292_SAVE_SCENARIO :Απποθήκευση σεναρίου STR_0293_LOAD_SCENARIO :Φόρτωση σεναρίου -STR_0294_QUIT_EDITOR :Έξοδος από το Συντάκτη +STR_0294_QUIT_EDITOR :Έξοδος από το πρόγραμμα επεξεργασίας STR_0295 : STR_0296_QUIT :Έξοδος -STR_0297_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Αποθήκευση σεναρίου, φόρτωση, παραίτηση συντάκτη, έξοδος +STR_0297_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Αποθήκευση σεναρίου, φόρτωση, παραίτηση πρόγραμμα επεξεργασίας, έξοδος STR_0298_LOAD_SCENARIO :{WHITE}Φόρτωση Σεναρίου STR_0299_SAVE_SCENARIO :{WHITE}Αποθήκευση Σεναρίου STR_029A_PLAY_SCENARIO :{BLACK}Παιξτε το Σενάριο -STR_029B_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Είστε σίγουρος ότι θέλετε να κάνετε έξοδο; -STR_029C_QUIT_EDITOR :{WHITE}Έξοδος από Συντάκτη +STR_029C_QUIT_EDITOR :{WHITE}Έξοδος από το Πρόγραμμα Επεξεργασίας STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...μπορεί να χτιστεί μόνο σε πόλεις με πληθυσμό άνω των 1200 STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Μετακίνηση ημ/νίας εκκίνησης 1 χρόνο πίσω STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Μετακίνηση ημ/νίας εκκίνησης 1 χρόνο μπροστά @@ -591,8 +589,8 @@ STR_02BB_TOWN_DIRECTORY :Καταλογος πόλεων STR_02BC_VEHICLE_DESIGN_NAMES :{BLACK}Ονόματα σχεδίων οχημάτων STR_02BD :{BLACK}{STRING} -STR_02BE_DEFAULT :Προεπιλεγμένο -STR_02BF_CUSTOM :Προσαρμοσμένο +STR_02BE_DEFAULT :Προεπιλεγμέν{G ος η ο} +STR_02BF_CUSTOM :Προσαρμοσμέν{G ος η ο} STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}Αποθήκευση προσαρμοσμένων ονομάτων STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION :{BLACK}Επιλογή ονομάτων σχεδίασης οχημάτων STR_02C2_SAVE_CUSTOMIZED_VEHICLE :{BLACK}Αποθήκευση προσαρμοσμένων ονομάτων σχεδίασης οχημάτων @@ -1468,6 +1466,8 @@ + + ##id 0x9000 @@ -1493,9 +1493,6 @@ -### looks odd, but trainslators requested this as depots aren't the same for all vehicles in all translations -### we can use there whenever we want a depot mentioned in another string to avoid making 4 versions of all strings - @@ -1512,9 +1509,6 @@ - - - ############ Lists rail types @@ -1528,4 +1522,8 @@ ########### String for new airports + +############ Tooltip measurment + + ######## diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/japanese.txt --- a/lang/unfinished/japanese.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/unfinished/japanese.txt Wed Jan 03 08:32:17 2007 +0000 @@ -1,2 +1,1436 @@ ##name Japanese -##ownname æ—¥æœ +##ownname 日本語 +##isocode ja_JP.UTF-8 +##plural 1 + +##id 0x0000 +STR_NULL : +STR_0001_OFF_EDGE_OF_MAP :{WHITE}地図のエッジはちょっと近いです +STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}地図のエッジはちょっと近いです +STR_0003_NOT_ENOUGH_CASH_REQUIRES :{WHITE}お金はありません。{CURRENCY}がかかります +STR_0004 :{WHITE}{CURRENCY64} +STR_0005 :{RED}{CURRENCY64} +STR_EMPTY : +STR_0007_FLAT_LAND_REQUIRED :{WHITE}平たい地面がかかります +STR_0008_WAITING :{BLACK}待っています: {WHITE}{STRING} +STR_0009 :{WHITE}{CARGO} +STR_000B :{YELLOW}{STATION}) +STR_000C_ACCEPTS :{BLACK}受け取れる事は: {WHITE} +STR_000D_ACCEPTS :{BLACK}受け取れる事は: {GOLD} +STR_000E : +STR_000F_PASSENGERS :乗客 +STR_0010_COAL :石炭 +STR_0011_MAIL :郵便物 +STR_0012_OIL :原油 +STR_0013_LIVESTOCK :家畜 +STR_0014_GOODS :商品 +STR_0015_GRAIN :穀物 +STR_0016_WOOD :木材 +STR_0017_IRON_ORE :鉄鉱 +STR_0018_STEEL :鋼鉄 +STR_0019_VALUABLES :貴重品 +STR_001A_COPPER_ORE :銅鉱 +STR_001B_MAIZE :トウモロコシ +STR_001C_FRUIT :果物 +STR_001D_DIAMONDS :ダイヤモンド +STR_001E_FOOD :食べ物 +STR_001F_PAPER :紙 +STR_0020_GOLD :金 +STR_0021_WATER :水 +STR_0022_WHEAT :小麦 +STR_0023_RUBBER :ゴム +STR_0024_SUGAR :砂糖 +STR_0025_TOYS :おもちゃ +STR_0026_CANDY :お菓子 +STR_0027_COLA :コーラ +STR_0028_COTTON_CANDY :綿あめ +STR_0029_BUBBLES :泡 +STR_002A_TOFFEE :タフィー +STR_002B_BATTERIES :乾電池 +STR_002C_PLASTIC :プラスチク +STR_002D_FIZZY_DRINKS :清涼飲料水 +STR_002E : +STR_002F_PASSENGER :乗客 +STR_0030_COAL :石炭 +STR_0031_MAIL :郵便物 +STR_0032_OIL :原油 +STR_0033_LIVESTOCK :家畜 +STR_0034_GOODS :商品 +STR_0035_GRAIN :穀物 +STR_0036_WOOD :木材 +STR_0037_IRON_ORE :鉄鉱 +STR_0038_STEEL :鋼鉄 +STR_0039_VALUABLES :貴重品 +STR_003A_COPPER_ORE :銅鉱 +STR_003B_MAIZE :トウモロコシ +STR_003C_FRUIT :果物 +STR_003D_DIAMOND :ダイヤモンド +STR_003E_FOOD :食べ物 +STR_003F_PAPER :紙 +STR_0040_GOLD :金 +STR_0041_WATER :水 +STR_0042_WHEAT :小麦 +STR_0043_RUBBER :ゴム +STR_0044_SUGAR :砂糖 +STR_0045_TOY :おもちゃ +STR_0046_CANDY :お菓子 +STR_0047_COLA :コーラ +STR_0048_COTTON_CANDY :綿あめ +STR_0049_BUBBLE :泡 +STR_004A_TOFFEE :タフィー +STR_004B_BATTERY :乾電池 +STR_004C_PLASTIC :プラスチク +STR_004D_FIZZY_DRINK :清涼飲料水 +STR_QUANTITY_NOTHING : +STR_00AE :{WHITE}{DATE_SHORT} +STR_00AF :{WHITE}{DATE_LONG} +STR_00B0_MAP :{WHITE}地図- {STRING} +STR_00B1_GAME_OPTIONS :{WHITE}ゲーム設定 +STR_00B2_MESSAGE :{YELLOW}メッセージ +STR_00B3_MESSAGE_FROM :{YELLOW} {STRING}からメッセージ +STR_00B4_CAN_T_DO_THIS :{WHITE}出来ません +STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}その所を空けません +STR_00B7_VERSION :{BLACK}OpenTTD バージョン {REV} +STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2006 The OpenTTD team +STR_TRANSLATED_BY :{BLACK} 訳者- + +STR_00C5 :{BLACK}{CROSS} +STR_00C6 :{SILVER}{CROSS} +STR_00C8_YES :{BLACK}はい +STR_00C9_NO :{BLACK}いいえ +STR_00CB_1 :{BLACK}1 +STR_00CC_2 :{BLACK}2 +STR_00CD_3 :{BLACK}3 +STR_00CE_4 :{BLACK}4 +STR_00CF_5 :{BLACK}5 +STR_00D0_NOTHING :何も +STR_00D1_DARK_BLUE :紺青色 +STR_00D2_PALE_GREEN :薄緑色 +STR_00D3_PINK :ピンク +STR_00D4_YELLOW :黄色 +STR_00D5_RED :赤色 +STR_00D6_LIGHT_BLUE :薄青色 +STR_00D7_GREEN :緑色 +STR_00D8_DARK_GREEN :濃緑色 +STR_00D9_BLUE :青色 +STR_00DA_CREAM :クリーム色 +STR_00DB_MAUVE :藤色 +STR_00DC_PURPLE :紫色 +STR_00DD_ORANGE :オレンジ色 +STR_00DE_BROWN :茶色 +STR_00DF_GREY :灰色 +STR_00E0_WHITE :白色 +STR_00E1_TOO_MANY_VEHICLES_IN_GAME :{WHITE}ゲームのバス/トラック数の制限を超えています +STR_00E2 :{BLACK}{COMMA} +STR_00E3 :{RED}{COMMA} +STR_00E4_LOCATION :{BLACK}見付けます +STR_00E7_INDUSTRIES :産業 +STR_00E8_ROUTES :経路 +STR_00E9_VEGETATION :植物 +STR_00EB_ROADS :{BLACK}{TINYFONT}道路 +STR_00EC_RAILROADS :{BLACK}{TINYFONT}鉄道 +STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}駅/空港/波止場 +STR_00EE_BUILDINGS_INDUSTRIES :{BLACK}{TINYFONT}建物/産業 +STR_00F0_100M :{BLACK}{TINYFONT}100m +STR_00F1_200M :{BLACK}{TINYFONT}200m +STR_00F2_300M :{BLACK}{TINYFONT}300m +STR_00F3_400M :{BLACK}{TINYFONT}400m +STR_00F4_500M :{BLACK}{TINYFONT}500m +STR_00F5_TRAINS :{BLACK}{TINYFONT}電車 +STR_00F6_ROAD_VEHICLES :{BLACK}{TINYFONT}バス/トラック +STR_00F7_SHIPS :{BLACK}{TINYFONT}船 +STR_00F8_AIRCRAFT :{BLACK}{TINYFONT}飛行機 +STR_00F9_TRANSPORT_ROUTES :{BLACK}{TINYFONT}運送経路 +STR_00FA_COAL_MINE :{BLACK}{TINYFONT}炭坑 +STR_00FB_POWER_STATION :{BLACK}{TINYFONT}発電所 +STR_00FC_FOREST :{BLACK}{TINYFONT}森林 +STR_00FD_SAWMILL :{BLACK}{TINYFONT}製材工場 +STR_00FE_OIL_REFINERY :{BLACK}{TINYFONT}製油所 +STR_00FF_FARM :{BLACK}{TINYFONT} 農場 +STR_0100_FACTORY :{BLACK}{TINYFONT} 工場 +STR_0101_PRINTING_WORKS :{BLACK}{TINYFONT}印刷所 +STR_0102_OIL_WELLS :{BLACK}{TINYFONT}油井 +STR_0103_IRON_ORE_MINE :{BLACK}{TINYFONT}鉄鉱石鉱山 +STR_0104_STEEL_MILL :{BLACK}{TINYFONT}製鋼所 +STR_0105_BANK :{BLACK}{TINYFONT}銀行 +STR_0106_PAPER_MILL :{BLACK}{TINYFONT}製紙工場 +STR_0107_GOLD_MINE :{BLACK}{TINYFONT}金鉱 +STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}食品加工場 +STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}ダイヤモンド鉱山 +STR_010A_COPPER_ORE_MINE :{BLACK}{TINYFONT}銅鉱山 +STR_010B_FRUIT_PLANTATION :{BLACK}{TINYFONT}果物農園 +STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}ゴム園 +STR_010D_WATER_SUPPLY :{BLACK}{TINYFONT}給水設備 +STR_010E_WATER_TOWER :{BLACK}{TINYFONT}給水塔 +STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}製材所 +STR_0110_COTTON_CANDY_FOREST :{BLACK}{TINYFONT}綿菓子 +STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}お菓子工場 +STR_0112_BATTERY_FARM :{BLACK}{TINYFONT}電池農園 +STR_0113_COLA_WELLS :{BLACK}{TINYFONT}コーラ泉 +STR_0114_TOY_SHOP :{BLACK}{TINYFONT}玩具店 +STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}玩具工場 +STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}プラスチック泉 +STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}ソーダ工場 +STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}泡の発生器 +STR_0119_TOFFEE_QUARRY :{BLACK}{TINYFONT}トッフィー採石場 +STR_011A_SUGAR_MINE :{BLACK}{TINYFONT}砂糖鉱山 +STR_011B_RAILROAD_STATION :{BLACK}{TINYFONT}駅 +STR_011C_TRUCK_LOADING_BAY :{BLACK}{TINYFONT}トラック荷役所 +STR_011D_BUS_STATION :{BLACK}{TINYFONT}バス停 +STR_011E_AIRPORT_HELIPORT :{BLACK}{TINYFONT}空港/ヘリポート +STR_011F_DOCK :{BLACK}{TINYFONT}波止場 +STR_0120_ROUGH_LAND :{BLACK}{TINYFONT}でこぼこの土地 +STR_0121_GRASS_LAND :{BLACK}{TINYFONT}草地 +STR_0122_BARE_LAND :{BLACK}{TINYFONT}裸地 +STR_0123_FIELDS :{BLACK}{TINYFONT}田畑 +STR_0124_TREES :{BLACK}{TINYFONT}木 +STR_0125_ROCKS :{BLACK}{TINYFONT} +STR_0126_WATER :{BLACK}{TINYFONT}水 +STR_0127_NO_OWNER :{BLACK}{TINYFONT}所有者なし +STR_0128_TOWNS :{BLACK}{TINYFONT}町 +STR_0129_INDUSTRIES :{BLACK}{TINYFONT}産業 +STR_012A_DESERT :{BLACK}{TINYFONT}砂漠 +STR_012B_SNOW :{BLACK}{TINYFONT}雪 +STR_012C_MESSAGE :{WHITE}メッセージ +STR_012D :{WHITE}{STRING} +STR_012E_CANCEL :{BLACK}キャンセル +STR_012F_OK :{BLACK}OK +STR_0130_RENAME :{BLACK}名称を変更 +STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}名称定義数の制限を超えています +STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}指定した名称は既に使用中です + +STR_0133_WINDOWS :Windows +STR_0134_UNIX :Unix +STR_0135_OSX :OS X + +STR_013B_OWNED_BY :{WHITE}...所有者は {STRING} +STR_013C_CARGO :{BLACK}貨物 +STR_013D_INFORMATION :{BLACK}情報 +STR_013E_CAPACITIES :{BLACK}容量 +STR_013E_TOTAL_CARGO :{BLACK}合計貨物 +STR_013F_CAPACITY :{BLACK}容量:{LTBLUE}{CARGO} +STR_013F_TOTAL_CAPACITY_TEXT :{BLACK}この電車の貨物最大容量: +STR_013F_TOTAL_CAPACITY :{LTBLUE}- {CARGO} ({SHORTCARGO}) +STR_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO} ({SHORTCARGO}) (x{NUM}) +STR_0140_NEW_GAME :{BLACK}新しいゲーム +STR_0141_LOAD_GAME :{BLACK}ゲームを開く + +STR_64 :64 +STR_128 :128 +STR_256 :256 +STR_512 :512 +STR_1024 :1024 +STR_2048 :2048 +STR_BY :{BLACK}* +STR_0148_GAME_OPTIONS :{BLACK}ゲームの設定 + +STR_0150_SOMEONE :誰かは{SKIP}{SKIP} +STR_0151_MAP_OF_WORLD :世界の地図 +STR_0152_TOWN_DIRECTORY :町のリスト +STR_0153_SUBSIDIES :助成金 + +STR_UNITS_METRIC :メートル法 + + +STR_UNITS_POWER_IMPERIAL :{COMMA}ホースポワー +STR_UNITS_POWER_METRIC :{COMMA}ホースポワー +STR_UNITS_POWER_SI :{COMMA}キロワット + +STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}トン +STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}トン +STR_UNITS_WEIGHT_SHORT_SI :{COMMA}キロ + +STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} 英トン +STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} 仏トン +STR_UNITS_WEIGHT_LONG_SI :{COMMA} キロ + +STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}ガロン +STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}リットル +STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ + +STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} ガロン +STR_UNITS_VOLUME_LONG_METRIC :{COMMA} リットル +STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ + + +############ range for menu starts +STR_0154_OPERATING_PROFIT_GRAPH :営業利益 +STR_0155_INCOME_GRAPH :所得グラフ +STR_0156_DELIVERED_CARGO_GRAPH :運送した貨物のグラフ +STR_0157_PERFORMANCE_HISTORY_GRAPH :成績グラフ +STR_0158_COMPANY_VALUE_GRAPH :会社価値グラフ +STR_0159_CARGO_PAYMENT_RATES :貨物運送料 +STR_015A_COMPANY_LEAGUE_TABLE :会社の成績表 +############ range for menu ends + +STR_015B_OPENTTD :{WHITE}OpenTTDとは?でぐち +STR_015C_SAVE_GAME :ゲームを保存 +STR_015D_LOAD_GAME :ゲームを開く +STR_015E_QUIT_GAME :ゲームを断念 +STR_015F_QUIT :出口 +STR_0161_QUIT_GAME :{WHITE}ゲームの断念 + +STR_SORT_BY_POPULATION :{BLACK}人口 +STR_SORT_BY_TYPE :{BLACK}種類 +STR_SORT_BY_TRANSPORTED :{BLACK}運びだ +STR_SORT_BY_NAME :{BLACK}名前 +STR_SORT_BY_DROPDOWN_NAME :名前 +STR_SORT_BY_NUMBER :番号 +STR_SORT_BY_VALUE :価値 +STR_SORT_BY_WAITING :待っている積荷価値 +STR_ENGINE_SORT_COST :値段 + +############ range for months starts +STR_0162_JAN :1月 +STR_0163_FEB :2月 +STR_0164_MAR :3月 +STR_0165_APR :4月 +STR_0166_MAY :5月 +STR_0167_JUN :6月 +STR_0168_JUL :7月 +STR_0169_AUG :8月 +STR_016A_SEP :9月 +STR_016B_OCT :10月 +STR_016C_NOV :11月 +STR_016D_DEC :12月 +############ range for months ends + +STR_016E :{TINYFONT}{STRING}{} {STRING} +STR_016F :{TINYFONT}{STRING}{} {STRING}{}{NUM} +STR_0170 :{TINYFONT}{STRING}- +STR_0171_PAUSE_GAME :{BLACK}ポーズ +STR_0172_SAVE_GAME_ABANDON_GAME :{BLACK}ゲームを保存、ゲームを断念、終了 +STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}会社の駅を表示します +STR_0174_DISPLAY_MAP :{BLACK}地図を見せます +STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}地図、町のリストを表示します +STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}町のリストを表示します +STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}会社の財務状況を表示します +STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}会社の一般情報を表示します +STR_0179_DISPLAY_GRAPHS :{BLACK}グラフを表示します +STR_017A_DISPLAY_COMPANY_LEAGUE :{BLACK}会社の成績表を表示します +STR_017B_DISPLAY_LIST_OF_COMPANY :{BLACK}会社の電車のリストを表示します +STR_017C_DISPLAY_LIST_OF_COMPANY :{BLACK}会社のバス/トラックのリストを表示します +STR_017D_DISPLAY_LIST_OF_COMPANY :{BLACK}会社の船のリストを表示します +STR_017E_DISPLAY_LIST_OF_COMPANY :{BLACK}会社の飛行機のリストを表示します +STR_017F_ZOOM_THE_VIEW_IN :{BLACK}拡大します +STR_0180_ZOOM_THE_VIEW_OUT :{BLACK}縮小します +STR_0181_BUILD_RAILROAD_TRACK :{BLACK}鉄道を建造します +STR_0182_BUILD_ROADS :{BLACK}道路を建造します +STR_0183_BUILD_SHIP_DOCKS :{BLACK}波止場を建造します +STR_0184_BUILD_AIRPORTS :{BLACK}空港を建造します +STR_0185_PLANT_TREES_PLACE_SIGNS :{BLACK}木の植え、標示の置くことなど +STR_0186_LAND_BLOCK_INFORMATION :{BLACK}地域情報 +STR_0187_OPTIONS :{BLACK}設定 +STR_0188 :{BLACK}{SMALLUPARROW} +STR_0189 :{BLACK}{SMALLDOWNARROW} +STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}整備間隔が変更できません +STR_018B_CLOSE_WINDOW :{BLACK}ウィンドウを閉じます +STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}ウィンドウのタイトル - ウィンドウを動くには、クリックしてドラッグします +STR_018D_DEMOLISH_BUILDINGS_ETC :{BLACK}土地上の建物などを破壊します +STR_018E_LOWER_A_CORNER_OF_LAND :{BLACK}土地の角を下げます +STR_018F_RAISE_A_CORNER_OF_LAND :{BLACK}土地の角を上げます +STR_0190_SCROLL_BAR_SCROLLS_LIST :{BLACK}スクロールバー +STR_0191_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}地図に土地の形勢を表示します +STR_0192_SHOW_VEHICLES_ON_MAP :{BLACK}地図に乗り物を表示します +STR_0193_SHOW_INDUSTRIES_ON_MAP :{BLACK}地図に産業を表示します +STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}地図に運送経路を表示します +STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}地図に植物を表示します +STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}地図に土地の所有者を表示します +STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}地図に町名の表示を入/切にします +STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}今年の利益:{CURRENCY} (去年:{CURRENCY}) + +############ range for service numbers starts +############ range for service numbers ends + +STR_019C_ROAD_VEHICLE :バス/トラック +STR_019D_AIRCRAFT :飛行機 +STR_019E_SHIP :船 +STR_019F_TRAIN :電車 +STR_01A0_IS_GETTING_OLD :{WHITE}{STRING} {COMMA} は古くなっています +STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} はかねて古くなっています +STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} はかねて古くなっていて、緊急に取り替えられなければなりません +STR_01A3_LAND_AREA_INFORMATION :{WHITE}地域情報 +STR_01A4_COST_TO_CLEAR_N_A :{BLACK}破壊の価格:{LTBLUE}破壊不可 +STR_01A5_COST_TO_CLEAR :{BLACK}破壊の価格:{LTBLUE}{CURRENCY} +STR_01A6_N_A :N/A +STR_01A7_OWNER :{BLACK}所有者:{LTBLUE}{STRING} +STR_01A8_LOCAL_AUTHORITY :{BLACK} 地方官庁:{LTBLUE}{STRING} +STR_01A9_NONE :何も +STR_01AA_NAME :{BLACK}名前 +STR_01AB :{BLACK}{TINYFONT}{STRING} + +############ range for days starts +STR_01AC_1ST :1日 +STR_01AD_2ND :2日 +STR_01AE_3RD :3日 +STR_01AF_4TH :4日 +STR_01B0_5TH :5日 +STR_01B1_6TH :6日 +STR_01B2_7TH :7日 +STR_01B3_8TH :8日 +STR_01B4_9TH :9日 +STR_01B5_10TH :10日 +STR_01B6_11TH :11日 +STR_01B7_12TH :12日 +STR_01B8_13TH :13日 +STR_01B9_14TH :14日 +STR_01BA_15TH :15日 +STR_01BB_16TH :16日 +STR_01BC_17TH :17日 +STR_01BD_18TH :18日 +STR_01BE_19TH :19日 +STR_01BF_20TH :20日 +STR_01C0_21ST :21日 +STR_01C1_22ND :22日 +STR_01C2_23RD :23日 +STR_01C3_24TH :24日 +STR_01C4_25TH :25日 +STR_01C5_26TH :26日 +STR_01C6_27TH :27日 +STR_01C7_28TH :28日 +STR_01C8_29TH :29日 +STR_01C9_30TH :30日 +STR_01CA_31ST :31日 +############ range for days ends + +STR_01CB :{TINYFONT}{COMMA} + +STR_01CE_CARGO_ACCEPTED :{BLACK}受け取る集荷: {LTBLUE} + +STR_01D1_8 :({COMMA}/8 {STRING}) +STR_01D2_JAZZ_JUKEBOX :{WHITE}ジャズジュークボックス +STR_01D3_SOUND_MUSIC :エフェクト/音楽 +STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}エフェクト/音楽のウィンドウを表示します +STR_01D5_ALL :{TINYFONT}すべて +STR_01D6_OLD_STYLE :{TINYFONT}旧式 +STR_01D7_NEW_STYLE :{TINYFONT}新式 +STR_01D8_EZY_STREET :{TINYFONT}Ezy Street +STR_01D9_CUSTOM_1 :{TINYFONT}カスタム 1 +STR_01DA_CUSTOM_2 :{TINYFONT}カスタム 2 +STR_01DB_MUSIC_VOLUME :{BLACK}{TINYFONT}音楽の音量 +STR_01DC_EFFECTS_VOLUME :{BLACK}{TINYFONT}エフェクトの音量 +STR_01DD_MIN_MAX :{BLACK}{TINYFONT}MIN ' ' ' ' ' ' MAX +STR_01DE_SKIP_TO_PREVIOUS_TRACK :{BLACK}選択部分の前の曲へジャンプ +STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}選択部分の次の曲へジャンプ +STR_01E0_STOP_PLAYING_MUSIC :{BLACK}音楽の再生を停止 +STR_01E1_START_PLAYING_MUSIC :{BLACK}音楽の再生を開始 +STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}音楽とエフェクトの音量を設定するには、スライダーをドラッグします +STR_01E3 :{DKGREEN}{TINYFONT}-- +STR_01E4_0 :{DKGREEN}{TINYFONT}0{COMMA} +STR_01E5 :{DKGREEN}{TINYFONT}{COMMA} +STR_01E6 :{DKGREEN}{TINYFONT}------ +STR_01E7 :{DKGREEN}{TINYFONT}"{STRING}" +STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}曲{SETX 88}タイトル +STR_01E9_SHUFFLE :{TINYFONT}シャッフル +STR_01EA_PROGRAM :{TINYFONT}{BLACK}プレイリスト +STR_01EB_MUSIC_PROGRAM_SELECTION :{WHITE}プレイリストの選択 +STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} "{STRING}" +STR_01ED :{TINYFONT}{LTBLUE}{COMMA} "{STRING}" +STR_01EE_TRACK_INDEX :{TINYFONT}{BLACK}曲のリスト +STR_01EF_PROGRAM :{TINYFONT}{BLACK}プレイリスト - '{STRING}' +STR_01F0_CLEAR :{TINYFONT}{BLACK}消去 +STR_01F1_SAVE :{TINYFONT}{BLACK}保存 +STR_01F2_CURRENT_PROGRAM_OF_MUSIC :{BLACK}再生中のプレイリスト +STR_01F3_SELECT_ALL_TRACKS_PROGRAM :{BLACK}プレイリスト「すべての曲」を選択します +STR_01F4_SELECT_OLD_STYLE_MUSIC :{BLACK}プレイリスト「旧式音楽」を選択します +STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}プレイリスト「新式音楽」を選択します +STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}プレイリスト「カスタム 1」を選択します +STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}プレイリスト「カスタム 2」を選択します +STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}選択したプレイリストの内容を消去します(カスタム 1/2 のみ)。 +STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}音楽の設定を保存 +STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}選択したプレイリストへ追加するには、曲をクリックします(カスタム 1/2 のみ)。 +STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}プレイリストのシャッフルを入/切にします +STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}曲の選択のウィンドウ表示します +STR_01FE_DIFFICULTY :{BLACK}難しさ({STRING}) +STR_01FF :{TINYFONT}{BLACK}{DATE_LONG} +STR_0200_LAST_MESSAGE_NEWS_REPORT :最後メッセージ +STR_0201_MESSAGE_SETTINGS :メッセージ設定 +STR_0203_SHOW_LAST_MESSAGE_NEWS :{BLACK}最後メッセージそれとも、メッセージ設定を見せます +STR_0204_MESSAGE_OPTIONS :{WHITE}メッセージ設定 +STR_0205_MESSAGE_TYPES :{BLACK}メッセージタイプ: +STR_0206_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}プレヤーのバス停/駅などへ乗り物の初めての到着 +STR_0207_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}競争者のバス停/駅などへ乗り物の初めての到着 +STR_0208_ACCIDENTS_DISASTERS :{YELLOW}事件/災害 +STR_0209_COMPANY_INFORMATION :{YELLOW}会社情報 +STR_020A_ECONOMY_CHANGES :{YELLOW}経済の変化 +STR_020B_ADVICE_INFORMATION_ON_PLAYER :{YELLOW}プレヤーの乗り物についての情報 +STR_020C_NEW_VEHICLES :{YELLOW}乗り物の新登場 +STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}貨物の受け取りの変化 +STR_020E_SUBSIDIES :{YELLOW}助成金 +STR_020F_GENERAL_INFORMATION :{YELLOW}一般情報 +STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...前の行き先から遠すぎます +STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}{NUM}{}({STRING} レベル) に当たった最高の会社 +STR_TOP_COMPANIES_NETWORK_GAME :{BIGFONT}{BLACK}{NUM}の会社リーグ表 +STR_0212 :{BIGFONT}{COMMA}. +STR_0213_BUSINESSMAN :ビジネスマン +STR_0214_ENTREPRENEUR :企業家 +STR_0215_INDUSTRIALIST :産業主義者 +STR_0216_CAPITALIST :資本家 +STR_0217_MAGNATE :大立者 +STR_0218_MOGUL :大御所 +STR_0219_TYCOON_OF_THE_CENTURY :大将軍 +STR_HIGHSCORE_NAME :{BIGFONT}{PLAYERNAME}、 {COMPANY} +STR_021B_ACHIEVES_STATUS :{BLACK}{BIGFONT}{COMPANY} は「{STRING}」に当たった! +STR_021C_OF_ACHIEVES_STATUS :{WHITE}{BIGFONT}{PLAYERNAME}({COMPANY})は「{STRING}」に当たった! +STR_021F :{BLUE}{COMMA} +STR_0220_CREATE_SCENARIO :{BLACK}シナリオを作成 +STR_0221_OPENTTD :{YELLOW}OpenTTD +STR_0222_SCENARIO_EDITOR :{YELLOW}シナリオエディタ +STR_0223_LAND_GENERATION :{WHITE}地勢の生成 +STR_0224 :{BLACK}{UPARROW} +STR_0225 :{BLACK}{DOWNARROW} +STR_0226_RANDOM_LAND :{BLACK}ランダムな地勢 +STR_0227_RESET_LAND :{BLACK}地勢をリセット +STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}あげる/下げる地域のサイズを拡大します +STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}あげる/下げる地域のサイズを縮小します +STR_022A_GENERATE_RANDOM_LAND :{BLACK}ランダムな地勢を生成します +STR_022B_RESET_LANDSCAPE :{BLACK}地勢をリセットします +STR_022C_RESET_LANDSCAPE :{WHITE}地勢のリセット +STR_022D_ARE_YOU_SURE_YOU_WANT_TO :{WHITE}地勢をリセットしてもよろしいですか? +STR_022E_LANDSCAPE_GENERATION :{BLACK}地勢の生成 +STR_022F_TOWN_GENERATION :{BLACK}市町村の生成 +STR_0230_INDUSTRY_GENERATION :{BLACK}産業の生成 +STR_0231_ROAD_CONSTRUCTION :{BLACK}道路の生成 +STR_0233_TOWN_GENERATION :{WHITE}市町村の生成 +STR_0234_NEW_TOWN :{BLACK}新規町 +STR_0235_CONSTRUCT_NEW_TOWN :{BLACK}新規町を建造します +STR_0236_CAN_T_BUILD_TOWN_HERE :{WHITE}ここで町が建造できません... +STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}...他の町の近すぎます +STR_0239_SITE_UNSUITABLE :{WHITE}...地域が不適当です +STR_023A_TOO_MANY_TOWNS :{WHITE}...市町村数の制限を超えています +STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}町のサイズをあげます +STR_023C_EXPAND :{BLACK}拡大 +STR_023D_RANDOM_TOWN :{BLACK}ランダムな町 +STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}ランダムなところに町を建造します +STR_023F_INDUSTRY_GENERATION :{WHITE}産業の生成 +STR_0240_COAL_MINE :{BLACK}炭坑 +STR_0241_POWER_STATION :{BLACK}発電所 +STR_0242_SAWMILL :{BLACK}製材工場 +STR_0243_FOREST :{BLACK}森林 +STR_0244_OIL_REFINERY :{BLACK}製油所 +STR_0246_FACTORY :{BLACK}工場 +STR_0247_STEEL_MILL :{BLACK}製鋼所 +STR_0248_FARM :{BLACK}農場 +STR_0249_IRON_ORE_MINE :{BLACK}鉄鉱石鉱山 +STR_024A_OIL_WELLS :{BLACK}油井 +STR_024B_BANK :{BLACK}銀行 +STR_024C_PAPER_MILL :{BLACK}製紙工場 +STR_024D_FOOD_PROCESSING_PLANT :{BLACK}食品加工場 +STR_024E_PRINTING_WORKS :{BLACK}印刷所 +STR_024F_GOLD_MINE :{BLACK}金鉱 +STR_0250_LUMBER_MILL :{BLACK}製材所 +STR_0251_FRUIT_PLANTATION :{BLACK}果物農園 +STR_0252_RUBBER_PLANTATION :{BLACK}ゴム園 +STR_0253_WATER_SUPPLY :{BLACK}給水設備 +STR_0254_WATER_TOWER :{BLACK}給水塔 +STR_0255_DIAMOND_MINE :{BLACK}ダイヤモンド鉱山 +STR_0256_COPPER_ORE_MINE :{BLACK}銅鉱石鉱山 +STR_0285_CAN_T_BUILD_HERE :{WHITE}そこに {STRING} を建てられません +STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE}...まずは町を建造しなければなりません +STR_0287_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}...一町内に一つしか建造できません +STR_0296_QUIT :出口 +STR_0298_LOAD_SCENARIO :{WHITE}シナリオを開く +STR_0299_SAVE_SCENARIO :{WHITE}シナリオを保存 +STR_029A_PLAY_SCENARIO :{BLACK}シナリオをプレイ +STR_029C_QUIT_EDITOR :{WHITE}エディタの終了 +STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...人口が1200人以上の市町のみに建造できます +STR_029E_MOVE_THE_STARTING_DATE :{BLACK}開始日を1年間減らします +STR_029F_MOVE_THE_STARTING_DATE :{BLACK}開始日を1年間増やします +STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}...橋の端は両方土地上に建造しなければなりません +STR_02A1_SMALL :{BLACK}小さい +STR_02A2_MEDIUM :{BLACK}町 +STR_02A3_LARGE :{BLACK}大きい +STR_02A4_SELECT_TOWN_SIZE :{BLACK}町のサイズを選択します +STR_02A5_TOWN_SIZE :{YELLOW}町のサイズ: + +STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS :{BLACK}最後のメッセージ/報道を表示します +STR_SUMMARY :粗筋 +STR_02BA :{SILVER}- - {COMPANY} - - +STR_02BB_TOWN_DIRECTORY :市町村のリスト +STR_02BC_VEHICLE_DESIGN_NAMES :{BLACK}乗り物の名称 +STR_02BD :{BLACK}{STRING} +STR_02BE_DEFAULT :デフォルト +STR_02BF_CUSTOM :カスタム +STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}カスタム名称を保存 +STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION :{BLACK}乗り物の名称の選択 +STR_02C2_SAVE_CUSTOMIZED_VEHICLE :{BLACK}カスタマイズした乗り物の名称を保存します + +STR_CHECKMARK :{CHECKMARK} +############ range for menu starts +STR_02C3_GAME_OPTIONS :ゲーム設定 +STR_02C5_DIFFICULTY_SETTINGS :難しさ設定 +STR_02C7_CONFIG_PATCHES :パッチの設定 +STR_GAMEOPTMENU_0A : +STR_02CA_TOWN_NAMES_DISPLAYED :{SETX 12}市町村名の表示 +STR_02CC_STATION_NAMES_DISPLAYED :{SETX 12}駅/バス停名の表示 +STR_02CE_SIGNS_DISPLAYED :{SETX 12}標示の表示 +STR_02D0_FULL_ANIMATION :{SETX 12}高級のアニメーション +STR_02D2_FULL_DETAIL :{SETX 12}高級の画像 +STR_02D4_TRANSPARENT_BUILDINGS :{SETX 12}透明な建物 +STR_TRANSPARENT_SIGNS :{SETX 12}澄む駅看板 +############ range ends here + +############ range for menu starts +STR_02D5_LAND_BLOCK_INFO :地域情報 +STR_02D6 : +STR_02D7_SCREENSHOT_CTRL_S :スクリーンショット(Ctrl-S) +STR_02D8_GIANT_SCREENSHOT_CTRL_G :大型スクリーンショット(Ctrl-G) +STR_02D9_ABOUT_OPENTTD :'OpenTTD'とは? +############ range ends here + +STR_02DB_OFF :{BLACK}切 +STR_02DA_ON :{BLACK}入 +STR_02DC_DISPLAY_SUBSIDIES :{BLACK}助成金を表示 +STR_02DD_SUBSIDIES :助成金 +STR_02DE_MAP_OF_WORLD :世界の地図 +STR_02DF_TOWN_DIRECTORY :市町村のリスト +STR_TOWN_POPULATION :{BLACK}世界人口:{COMMA} + +STR_02E0_CURRENCY_UNITS :{BLACK}通貨単位 +STR_02E1 :{BLACK}{SKIP}{STRING} +STR_02E2_CURRENCY_UNITS_SELECTION :{BLACK}通貨単位の選択 +STR_02E4 :{BLACK}{SKIP}{SKIP}{STRING} +STR_02E6_ROAD_VEHICLES :{BLACK}バス/トラック +STR_02E7 :{BLACK}{SKIP}{SKIP}{SKIP}{STRING} +STR_02E9_DRIVE_ON_LEFT :左に運転します +STR_02EA_DRIVE_ON_RIGHT :右に運転します +STR_02EB_TOWN_NAMES :{BLACK}市町村名 +STR_02EC :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} +STR_02ED_SELECT_STYLE_OF_TOWN_NAMES :{BLACK}市町村名の種類の選択 + +STR_02F4_AUTOSAVE :{BLACK}自動保存 +STR_02F5 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} +STR_02F6_SELECT_INTERVAL_BETWEEN :{BLACK}自動保存の間隔を選択します +STR_02F7_OFF :切 +STR_02F8_EVERY_3_MONTHS :毎3月 +STR_02F9_EVERY_6_MONTHS :毎6月 +STR_02FA_EVERY_12_MONTHS :毎12月 +STR_02FB_START_A_NEW_GAME :{BLACK}新しいゲームを始めます +STR_02FC_LOAD_A_SAVED_GAME :{BLACK}ゲームを開きます +STR_02FE_CREATE_A_CUSTOMIZED_GAME :{BLACK}カスタムシナリオを作成します +STR_02FF_SELECT_SINGLE_PLAYER_GAME :{BLACK}一人プレイを選択します +STR_0300_SELECT_MULTIPLAYER_GAME :{BLACK}多人数プレイ(2〜8人)を選択します +STR_0301_DISPLAY_GAME_OPTIONS :{BLACK}ゲーム設定を見せます +STR_0302_DISPLAY_DIFFICULTY_OPTIONS :{BLACK}難しさ設定を見せます +STR_0303_START_A_NEW_GAME_USING :{BLACK}カスタムシナリオを使用して新規ゲームを開始します +STR_0304_QUIT :{BLACK}出口 +STR_0305_QUIT_OPENTTD :{BLACK}'OpenTTD'を止めます +STR_0307_OPENTTD :{WHITE}OpenTTD {REV} +STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}…町の外に建てません +STR_030E_SELECT_TEMPERATE_LANDSCAPE :{BLACK}温帯地域を選択します +STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE :{BLACK}亜寒帯地域を選択します +STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE :{BLACK}亜熱帯地域を選択します +STR_0311_SELECT_TOYLAND_LANDSCAPE :{BLACK}おもちゃの国を選択します +STR_0312_FUND_CONSTRUCTION_OF_NEW :{BLACK}新規産業の建造に資金を供給します + +############ range for menu starts +STR_0313_FUND_NEW_INDUSTRY :新規産業の建造に資金を出す +############ range ends here + +STR_0314_FUND_NEW_INDUSTRY :{WHITE}新規産業の建造に資金の供給 +STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}…町の外に建てません +STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}...雨林地域のみに建造できます +STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}...砂漠地域のみに建造できます +STR_0319_PAUSED :{YELLOW}**ポーズ** + +STR_031B_SCREENSHOT_SUCCESSFULLY :{WHITE}スクリーンショットを '{STRING}' に正常に保存しました +STR_031C_SCREENSHOT_FAILED :{WHITE}スクリーンショットが失敗しました! + +STR_0329_PURCHASE_LAND_FOR_FUTURE :{BLACK}将来用に土地を購入 +STR_032F_AUTOSAVE :{RED}自動保存 +STR_0330_SELECT_EZY_STREET_STYLE :{BLACK}'Ezy Street 式の音楽'のプレイリストを選択します + +STR_0335_6 :{BLACK}6 +STR_0336_7 :{BLACK}7 + +############ start of townname region +STR_TOWNNAME_ORIGINAL_ENGLISH :イギリス +STR_TOWNNAME_FRENCH :フランス +STR_TOWNNAME_GERMAN :ドイツ +STR_TOWNNAME_ADDITIONAL_ENGLISH :イギリス(おまけ) +STR_TOWNNAME_LATIN_AMERICAN :ラテンアメリカ +STR_TOWNNAME_SILLY :愚 +STR_TOWNNAME_SWEDISH :スウェーデン +STR_TOWNNAME_POLISH :ポーランド +STR_TOWNNAME_SLOVAKISH :スロバキア +STR_TOWNNAME_NORWEGIAN :ノルウェー +STR_TOWNNAME_HUNGARIAN :洪牙利 +STR_TOWNNAME_AUSTRIAN :オーストリア +STR_TOWNNAME_ROMANIAN :ルーマニア +STR_TOWNNAME_CZECH :チェコ +STR_TOWNNAME_SWISS :瑞西 +STR_TOWNNAME_DANISH :デーン +STR_TOWNNAME_TURKISH :土国 +STR_TOWNNAME_ITALIAN :イタリ +STR_TOWNNAME_CATALAN :カタラン +############ end of townname region + +STR_CURR_YEN :日本の円(¥) + + +STR_OPTIONS_LANG_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} + + +STR_OPTIONS_RES_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} + +STR_OPTIONS_SCREENSHOT_FORMAT_CBO :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} + +STR_AUTOSAVE_1_MONTH :毎月 + +STR_MONTH_JAN :1月 +STR_MONTH_FEB :2月 +STR_MONTH_MAR :3月 +STR_MONTH_APR :4月 +STR_MONTH_MAY :5月 +STR_MONTH_JUN :6月 +STR_MONTH_JUL :7月 +STR_MONTH_AUG :8月 +STR_MONTH_SEP :9月 +STR_MONTH_OCT :10月 +STR_MONTH_NOV :11月 +STR_MONTH_DEC :12月 + + +STR_TONS :トン + +STR_SMALL_RIGHT_ARROW :{TINYFONT}{RIGHTARROW} + + +STR_TRAIN_IS_LOST :{WHITE}電車{COMMA}は迷います +STR_TRAIN_IS_UNPROFITABLE :{WHITE}去年、電車{COMMA}の取り柄は{CURRENCY} + +# Start of order review system. +# DON'T ADD OR REMOVE LINES HERE +STR_TRAIN_HAS_TOO_FEW_ORDERS :{WHITE}電車{COMMA}のルートは過小駅があります +STR_TRAIN_HAS_VOID_ORDER :{WHITE}電車{COMMA}は 空々予定があります +STR_TRAIN_HAS_DUPLICATE_ENTRY :{WHITE}電車{COMMA}のルートはデュープリケート 駅があります +STR_TRAIN_HAS_INVALID_ENTRY :{WHITE}電車{COMMA} のルートは無効な駅があります +# end of order system + +STR_TRAIN_AUTORENEW_FAILED :{WHITE}電車{COMMA} のオート取り替えられません (お金のかぎり) +STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}付け替えの後で、電車{COMMA}は ちょっと長いです + + + + + + +STR_CONFIG_PATCHES_LIVERIES_NONE :何も + + + + + + + +STR_CONFIG_PATCHES_INT32 :{NUM} +STR_CONFIG_PATCHES_CURRENCY :{CURRENCY} + + +STR_TEMPERATE_LANDSCAPE :温帯国 +STR_SUB_ARCTIC_LANDSCAPE :北極国 +STR_SUB_TROPICAL_LANDSCAPE :亜熱帯国 +STR_TOYLAND_LANDSCAPE :おまちゃ国 + + + + + + +STR_WAYPOINT_VIEWPORT :{WHITE}{WAYPOINT} +STR_WAYPOINT_VIEWPORT_TINY :{TINYFONT}{WHITE}{WAYPOINT} +STR_WAYPOINT_RAW :{WAYPOINT} + + + + + + + +STR_TREES_RANDOM_TYPE :{BLACK}ランドム種類の木 +STR_TREES_RANDOM_TYPE_TIP :{BLACK}ランドム種類の木を植えます + + + + + + + + + + +STR_INDUSTRYDIR_ITEM_NOPROD :{ORANGE}{INDUSTRY} + + + +TEMP_AI_IN_PROGRESS :{WHITE}いらっしゃいませ!このAIは発展中です。問題があったら、スクリーンショットを取って、フォーラムに送ってください +TEMP_AI_ACTIVATED :{WHITE}注意:AIはまだアルファです!今、貨物自動車とバスだけ疲われます! +TEMP_AI_MULTIPLAYER :{WHITE}注意:AIはまだ実験段階です!問題があったら、英語でtruelight@openttd.orgをメールしてください。 + +############ network gui strings + + + + +STR_NETWORK_GAME_NAME :{BLACK}名前 + + +STR_NETWORK_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} +STR_ORANGE :{ORANGE}{STRING} +STR_NETWORK_LANGUAGE :{SILVER}国語:  {WHITE}{STRING} + + + + +STR_NETWORK_INTERNET :インターネット +STR_NETWORK_COMBO2 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} +STR_NETWORK_COMBO3 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} +STR_NETWORK_COMBO4 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} +STR_NETWORK_COMBO5 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} + +############ Leave those lines in this order!! +STR_NETWORK_LANG_ENGLISH :英語 +STR_NETWORK_LANG_GERMAN :ドイツ語 +STR_NETWORK_LANG_FRENCH :フランス語 +############ End of leave-in-this-order + + + + + + + +############ Leave those lines in this order!! + +############ End of leave-in-this-order + + + + +############ Leave those lines in this order!! +############ End of leave-in-this-order + + + + + +############ end network gui strings + + + + +##### PNG-MAP-Loader + + + +##id 0x0800 +STR_0800_COST :{TINYFONT}{RED}値段:{CURRENCY} +STR_0801_COST :{RED}値段: {CURRENCY} +STR_0802_INCOME :{TINYFONT}{GREEN}所得:{CURRENCY} +STR_0803_INCOME :{GREEN}所得:{CURRENCY} +STR_0805_ESTIMATED_COST :{WHITE}評価の価値:{CURRENCY} +STR_0807_ESTIMATED_INCOME :{WHITE}評価の所得:{CURRENCY} +STR_0808_CAN_T_RAISE_LAND_HERE :{WHITE}ここに土地が上げられません +STR_0809_CAN_T_LOWER_LAND_HERE :{WHITE}ここに土地が下げられません +STR_080A_ROCKS :岩石 +STR_080B_ROUGH_LAND :でこぼこの土地 +STR_080C_BARE_LAND :裸地 +STR_080D_GRASS :草地 +STR_080E_FIELDS :田畑 +STR_080F_SNOW_COVERED_LAND :積雪地域 +STR_0810_DESERT :砂漠 + +##id 0x1000 +STR_1004_TOO_HIGH :{WHITE}ちょっと高いです +STR_1007_ALREADY_BUILT :{WHITE}…もう建てました +STR_100A_RAILROAD_CONSTRUCTION :{WHITE}鉄道の建造 +STR_TITLE_ELRAIL_CONSTRUCTION :{WHITE}電鉄建造 +STR_100B_MONORAIL_CONSTRUCTION :{WHITE}モノレールの建造 +STR_100C_MAGLEV_CONSTRUCTION :{WHITE}マグレブの建造 +STR_100D_SELECT_RAIL_BRIDGE :{WHITE}鉄道の橋の選択 +STR_100E_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}ここに電車庫が建造できません +STR_100F_CAN_T_BUILD_RAILROAD_STATION :{WHITE}ここに駅が建造できません +STR_1010_CAN_T_BUILD_SIGNALS_HERE :{WHITE}ここに信号が建造できません +STR_1011_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}ここに線路が建造できません +STR_1012_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}ここから線路が廃止できません +STR_1013_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}ここから信号が廃止できません +STR_1014_TRAIN_DEPOT_ORIENTATION :{WHITE}電車庫の配置 +STR_1015_RAILROAD_CONSTRUCTION :鉄道の建造 +STR_TOOLB_ELRAIL_CONSTRUCTION :電鉄建造 +STR_1016_MONORAIL_CONSTRUCTION :モノレールの建造 +STR_1017_MAGLEV_CONSTRUCTION :マグレブの建造 +STR_1018_BUILD_RAILROAD_TRACK :{BLACK}線路を建造します +STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}(電車の建造や整備のための)電車庫を建造します +STR_101A_BUILD_RAILROAD_STATION :{BLACK}駅を建造します +STR_101B_BUILD_RAILROAD_SIGNALS :{BLACK}鉄道の信号を建造します +STR_101C_BUILD_RAILROAD_BRIDGE :{BLACK}鉄道の橋を建造します +STR_101D_BUILD_RAILROAD_TUNNEL :{BLACK}鉄道のトンネルを建造します +STR_101E_TOGGLE_BUILD_REMOVE_FOR :{BLACK}線路と信号の建造/廃止を切り替えます +STR_101F_BRIDGE_SELECTION_CLICK :{BLACK}橋の選択 - お好きな橋を建造するにはクリックします +STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO :{BLACK}電車庫の配置を選択します +STR_1021_RAILROAD_TRACK :線路 +STR_1023_RAILROAD_TRAIN_DEPOT :電車庫 +STR_1024_AREA_IS_OWNED_BY_ANOTHER :{WHITE}...この土地は他の会社に所有されています + + + +##id 0x1800 +STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}ここから道路が廃止できません... +STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}車庫の配置 +STR_1807_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}ここに車庫が建造できません... +STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}バス停が建造できません... +STR_1809_CAN_T_BUILD_TRUCK_STATION :{WHITE}荷役所が建造できません... +STR_180A_ROAD_CONSTRUCTION :道路の建造 +STR_180B_BUILD_ROAD_SECTION :{BLACK}道路の部分を建造します +STR_180C_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}(バス、トラックの建造、整備のための)車庫を建造します +STR_180D_BUILD_BUS_STATION :{BLACK}バス停を建造します +STR_180E_BUILD_TRUCK_LOADING_BAY :{BLACK}荷役所を建造します +STR_180F_BUILD_ROAD_BRIDGE :{BLACK}道路の端を建造します +STR_1810_BUILD_ROAD_TUNNEL :{BLACK}道路のトンネルを建造します +STR_1811_TOGGLE_BUILD_REMOVE_FOR :{BLACK}道路の建造/廃止を切り替えます +STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}車庫の配置の選択 +STR_1814_ROAD :道路 +STR_1815_ROAD_WITH_STREETLIGHTS :街路照明のある道路 +STR_1816_TREE_LINED_ROAD :並木道 +STR_1817_ROAD_VEHICLE_DEPOT :車庫 +STR_1818_ROAD_RAIL_LEVEL_CROSSING :踏切 + +##id 0x2000 +STR_2000_TOWNS :{WHITE}町 +STR_TOWN_LABEL_POP :{WHITE}{TOWN} ({COMMA}) +STR_TOWN_LABEL :{WHITE}{TOWN} +STR_TOWN_LABEL_TINY_BLACK :{TINYFONT}{BLACK}{TOWN} +STR_TOWN_LABEL_TINY_WHITE :{TINYFONT}{WHITE}{TOWN} +STR_2002 :{TINYFONT}{BLACK}{STRING} +STR_2004_BUILDING_MUST_BE_DEMOLISHED :{WHITE}まずは建物を破壊しなければなりません +STR_2005 :{WHITE}{TOWN} +STR_2006_POPULATION :{BLACK}人口:{ORANGE}{COMMA}人{BLACK} 建物:{ORANGE}{COMMA}戸 +STR_2007_RENAME_TOWN :町名を変更 +STR_2008_CAN_T_RENAME_TOWN :{WHITE}町名が変更できません... +STR_2009_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN}の町議会は許可しません +STR_200A_TOWN_NAMES_CLICK_ON_NAME :{BLACK}町名 - 画面をその町に集中するには、クリックします +STR_200B_CENTER_THE_MAIN_VIEW_ON :{BLACK}画面を町に集中します +STR_200C_CHANGE_TOWN_NAME :{BLACK}町名を変更します +STR_200D_PASSENGERS_LAST_MONTH_MAX :{BLACK}先月の乗客:{ORANGE}{COMMA}人{BLACK} 最大:{ORANGE}{COMMA}人 +STR_200E_MAIL_LAST_MONTH_MAX :{BLACK}先月の郵便物:{ORANGE}{COMMA}個{BLACK} 最大:{ORANGE}{COMMA}個 +STR_200F_TALL_OFFICE_BLOCK :超高層ビル +STR_2010_OFFICE_BLOCK :オフィスビル +STR_2011_SMALL_BLOCK_OF_FLATS :アパート +STR_2012_CHURCH :チャーチ +STR_2013_LARGE_OFFICE_BLOCK :大型オフィスビル +STR_2014_TOWN_HOUSES :マンション +STR_2015_HOTEL :ホテル +STR_2016_STATUE :彫像 +STR_2017_FOUNTAIN :噴水 +STR_2018_PARK :公園 +STR_2019_OFFICE_BLOCK :オフィスビル +STR_201A_SHOPS_AND_OFFICES :雑居ビル +STR_201B_MODERN_OFFICE_BUILDING :近代のオフィスビル +STR_201C_WAREHOUSE :倉庫 +STR_201D_OFFICE_BLOCK :オフィスビル +STR_201E_STADIUM :スタジアム +STR_201F_OLD_HOUSES :老舗 +STR_2020_LOCAL_AUTHORITY :{BLACK}町議会 +STR_2021_SHOW_INFORMATION_ON_LOCAL :{BLACK}町議会の情報を表示します +STR_2022_LOCAL_AUTHORITY :{WHITE}{TOWN}の町議会 +STR_2023_TRANSPORT_COMPANY_RATINGS :{BLACK}会社の町内の世評: +STR_2024 :{YELLOW}{COMPANY}{PLAYERNAME}: {ORANGE}{STRING} +STR_2025_SUBSIDIES :{WHITE}助成金 +STR_2026_SUBSIDIES_ON_OFFER_FOR :{BLACK}次の運送経路に助成金を提案します: +STR_2027_FROM_TO :{ORANGE}{STRING}を{STRING}から{STRING}へ +STR_2028_BY :{YELLOW} ({DATE_SHORT}の前) +STR_202A_NONE :{ORANGE}何も +STR_202B_SERVICES_ALREADY_SUBSIDISED :{BLACK}既に助成金を受けている運送経路: +STR_202C_FROM_TO :{ORANGE}{STRING}{STATION}から{STATION}まで{YELLOW} ({COMPANY} +STR_202D_UNTIL :{YELLOW}、{DATE_SHORT}まで) +STR_202E_OFFER_OF_SUBSIDY_EXPIRED :{BLACK}{BIGFONT}助成金の提案の有効期限が切られた:{}{}{STRING}を{STRING}から{STRING}への運送経路は今から助成金を受けない。 +STR_2036_COTTAGES :小屋 +STR_2037_HOUSES :家 +STR_2038_FLATS :アパート +STR_2039_TALL_OFFICE_BLOCK :大型オフィスビル +STR_203A_SHOPS_AND_OFFICES :雑居 +STR_203B_SHOPS_AND_OFFICES :雑居 +STR_203C_THEATER :劇場 +STR_203D_STADIUM :スタジアム +STR_203E_OFFICES :オフィスビル +STR_203F_HOUSES :家 +STR_2040_CINEMA :映画館 +STR_2041_SHOPPING_MALL :デパート +STR_2043_LIST_OF_THINGS_TO_DO_AT :{BLACK}この町の起こせる動作 - 詳しくは項目をクリックします +STR_2044_CARRY_OUT_THE_HIGHLIGHTED :{BLACK}上記のリストの洗濯中の動作を起こします。 +STR_2045_ACTIONS_AVAILABLE :{BLACK}起こせる動作: +STR_2046_SMALL_ADVERTISING_CAMPAIGN :小型広告キャンペーン +STR_2047_MEDIUM_ADVERTISING_CAMPAIGN :中型広告キャンペーン +STR_2048_LARGE_ADVERTISING_CAMPAIGN :大型広告キャンペーン +STR_2049_FUND_LOCAL_ROAD_RECONSTRUCTION :道路再建を出資 +STR_204A_BUILD_STATUE_OF_COMPANY :会社長の彫像を建造 +STR_204B_FUND_NEW_BUILDINGS :市街地開発を出資 +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY :地方自治体を買収します +STR_204D_INITIATE_A_SMALL_LOCAL :{WHITE}{STRING}{}{YELLOW} あなたの運送経路の利用率を増やすには、町内の小型広告キャンペーンを行います。{} 価値:{CURRENCY} +STR_204E_INITIATE_A_MEDIUM_LOCAL :{WHITE}{STRING}{}{YELLOW} あなたの運送経路の利用率を増やすには、町内の中型広告キャンペーンを行います。{} 価値:{CURRENCY} +STR_204F_INITIATE_A_LARGE_LOCAL :{WHITE}{STRING}{}{YELLOW} あなたの運送経路の利用率を増やすには、町内の大型広告キャンペーンを行います。{} 価値:{CURRENCY} +STR_2050_FUND_THE_RECONSTRUCTION :{WHITE}{STRING}{}{YELLOW} 町内の道路の再建を出資します。最高 6 ヶ月間まで、道路交通に途絶を与えます。{} 価値:{CURRENCY} +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY_DESC :{WHITE}{STRING}{}{YELLOW} 名声を増殖します地方自治体を買収します。けれども、あぶないです!{} 値段: {CURRENCY} +STR_2056 :{TINYFONT}{WHITE}{TOWN} +STR_2057 :{ORANGE}{TOWN}{BLACK} ({COMMA}) + +STR_INDUSTRY :{INDUSTRY} +STR_TOWN :{TOWN} +STR_INDUSTRY_FORMAT :{TOWN} {STRING} +STR_STATION :{STATION} + +##id 0x2800 +STR_2802_TREES :{WHITE}木 +STR_2803_TREE_ALREADY_HERE :{WHITE}...木はもうあります +STR_2806 :{WHITE}{STRING} +STR_280E_TREES :木 + +##id 0x3000 +STR_3003_NUMBER_OF_TRACKS :{BLACK}線路数 +STR_3004_PLATFORM_LENGTH :{BLACK}ホームの長さ +STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD :{WHITE}他の駅に近すぎます +STR_3007_TOO_MANY_STATIONS_LOADING :{WHITE}町内に駅/バス停/荷役所が多すぎます +STR_3008_TOO_MANY_STATIONS_LOADING :{WHITE}駅/荷役所が多すぎます +STR_3008A_TOO_MANY_BUS_STOPS :{WHITE}バス停が多すぎます +STR_3008B_TOO_MANY_TRUCK_STOPS :{WHITE}荷役所が多すぎます +STR_3009_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}他の駅/荷役所に近すぎます +STR_300A_0 :{WHITE}{STATION} {STATIONFEATURES} +STR_300B_MUST_DEMOLISH_RAILROAD :{WHITE}まずは駅を破壊しなければなりません +STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}他の空港に近すぎます +STR_300E_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}まずは空港を破壊しなければなりません + +STR_3030_RENAME_STATION_LOADING :駅/荷役所の名称の変更 +STR_3031_CAN_T_RENAME_STATION :{WHITE}駅名が変更できません... + +############ range for rating starts +STR_3035_APPALLING :最低 +STR_3036_VERY_POOR :とても悪い +STR_3037_POOR :悪い +STR_3038_MEDIOCRE :平凡 +STR_3039_GOOD :良い +STR_303A_VERY_GOOD :とても良い +STR_303B_EXCELLENT :すばらしい +STR_303C_OUTSTANDING :最高 +############ range for rating ends + +STR_303D :{WHITE}{STRING}: {YELLOW}{STRING} ({COMMA}%) +STR_3049_0 :{YELLOW}{STATION} {STATIONFEATURES} +STR_304A_NONE :{YELLOW}- 何も- +STR_304F_SELECT_NUMBER_OF_PLATFORMS :{BLACK}駅の線路数を選択します +STR_3050_SELECT_LENGTH_OF_RAILROAD :{BLACK}駅のホームの長さを選択します +STR_3051_SELECT_BUS_STATION_ORIENTATION :{BLACK}バス停の配置を選択します +STR_3052_SELECT_TRUCK_LOADING_BAY :{BLACK}荷役所の配置を選択します +STR_3054_SHOW_STATION_RATINGS :{BLACK}駅の評価を表示します +STR_3055_CHANGE_NAME_OF_STATION :{BLACK}駅名を変更します +STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO :{BLACK}受け取る貨物のリストを表示します +STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT :{BLACK}空港のサイズ/種類を選択します +STR_305C_0 :{STATION} {STATIONFEATURES} +STR_STATION_SIGN_TINY :{TINYFONT}{STATION} +STR_305E_RAILROAD_STATION :駅 +STR_305F_AIRCRAFT_HANGAR :格納庫 +STR_3060_AIRPORT :空港 +STR_3061_TRUCK_LOADING_AREA :荷役所 +STR_3062_BUS_STATION :バス停 +STR_3063_SHIP_DOCK :波止場 +STR_3068_DOCK :{WHITE}波止場 +STR_3069_BUOY :ブイ +STR_306C_STATION_TOO_SPREAD_OUT :{WHITE}...駅が広すぎます +STR_USE_CTRL_TO_SELECT_MORE :{BLACK}もっと事を選ぶために、CTRLをプッシュ + +STR_UNDEFINED :(ハンナ・ストリング) +STR_STAT_CLASS_DFLT :デフォルト駅 +STR_STAT_CLASS_WAYP :通過点 + +##id 0x3800 +STR_3800_SHIP_DEPOT_ORIENTATION :{WHITE}造船所の配置 +STR_3803_SELECT_SHIP_DEPOT_ORIENTATION :{BLACK}造船所の配置を選択します +STR_3804_WATER :水 +STR_3806_SHIP_DEPOT :造船所 + +##id 0x4000 +STR_4000_SAVE_GAME :{WHITE}ゲームを保存 +STR_4001_LOAD_GAME :{WHITE}ゲームを開く +STR_4002_SAVE :{BLACK}保存 +STR_4003_DELETE :{BLACK}削除 +STR_4004 :{COMPANY}、 {DATE_LONG} +STR_4005_BYTES_FREE :{BLACK}{COMMA} MB 使用可能 +STR_4007_GAME_SAVE_FAILED :{WHITE}ゲームの保存が失敗しました +STR_4008_UNABLE_TO_DELETE_FILE :{WHITE}ファイルを削除できません +STR_4009_GAME_LOAD_FAILED :{WHITE}ゲームの読み込むが失敗しました +STR_400A_LIST_OF_DRIVES_DIRECTORIES :{BLACK}ドライブ、フォルダ、ゲームファイルのリスト +STR_400B_CURRENTLY_SELECTED_NAME :{BLACK}ゲームのファイル名 +STR_400C_DELETE_THE_CURRENTLY_SELECTED :{BLACK}選択したゲームを削除します +STR_400D_SAVE_THE_CURRENT_GAME_USING :{BLACK}指定したファイル名に現在のゲームを保存します +STR_400E_SELECT_NEW_GAME_TYPE :{WHITE}新規ゲーム種類の選択 +STR_400F_SELECT_SCENARIO_GREEN_PRE :{BLACK}シナリオ(緑)、プリセットゲーム(青)もしくは新規ランダムゲームを選択します +STR_4010_GENERATE_RANDOM_NEW_GAME :新規ランダムゲームを作成 + +##id 0x4800 +STR_4801 :{WHITE}{INDUSTRY} +STR_4802_COAL_MINE :炭坑 +STR_4803_POWER_STATION :発電所 +STR_4804_SAWMILL :製材工場 +STR_4805_FOREST :森林 +STR_4806_OIL_REFINERY :石油精製所 +STR_4808_FACTORY :工場 +STR_4809_PRINTING_WORKS :印刷所 +STR_480A_STEEL_MILL :製鋼所 +STR_480B_FARM :農場 +STR_480C_COPPER_ORE_MINE :銅鉱石鉱山 +STR_480D_OIL_WELLS :油井 +STR_480E_BANK :銀行 +STR_480F_FOOD_PROCESSING_PLANT :食品加工場 +STR_4810_PAPER_MILL :製紙工場 +STR_4811_GOLD_MINE :金山 +STR_4812_BANK :銀行 +STR_4813_DIAMOND_MINE :ダイヤモンド鉱山 +STR_4814_IRON_ORE_MINE :鉄鉱石鉱山 +STR_4815_FRUIT_PLANTATION :果物農園 +STR_4816_RUBBER_PLANTATION :ゴム園 +STR_4817_WATER_SUPPLY :給水設備 +STR_4818_WATER_TOWER :給水塔 +STR_4819_FACTORY :工場 +STR_481A_FARM :農場 +STR_481B_LUMBER_MILL :製材所 +STR_481E_BATTERY_FARM :電池園 +STR_4826_SUGAR_MINE :砂糖鉱山 + +############ range for requires starts +############ range for requires ends + +STR_482F_COST :{BLACK}値段: {YELLOW}{CURRENCY} +STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}この産業がここに建造できません... + +##id 0x5000 +STR_500D :{GOLD}{STRING}、{} {VELOCITY} {WHITE}{CURRENCY} +STR_500E_SUSPENSION_STEEL :つり橋、鋼鉄製 +STR_500F_GIRDER_STEEL :けた橋、鋼鉄製 +STR_5010_CANTILEVER_STEEL :カンチレバー橋、鋼鉄製 +STR_5011_SUSPENSION_CONCRETE :つり橋、コンクリート製 +STR_5012_WOODEN :木製 +STR_5013_CONCRETE :コンクリート製 +STR_5014_TUBULAR_STEEL :鋼管橋、鋼鉄製 +STR_5015_CAN_T_BUILD_BRIDGE_HERE :{WHITE}橋がここに建造できません... +STR_5016_CAN_T_BUILD_TUNNEL_HERE :{WHITE}トンネルがここに建造できません... +STR_5017_RAILROAD_TUNNEL :鉄道トンネル +STR_5018_ROAD_TUNNEL :道路トンネル + +##id 0x5800 +STR_5801_TRANSMITTER :送信機 +STR_5802_LIGHTHOUSE :灯台 +STR_5803_COMPANY_HEADQUARTERS :交通会社本部ビル +STR_5804_COMPANY_HEADQUARTERS_IN :{WHITE}...交通会社本部ビルがあります + + +############ WARNING, using range 0x6000 for strings that are stored in the savegame +############ These strings may never get a new id, or savegames will break! +##id 0x6000 +STR_SV_EMPTY : +STR_SV_UNNAMED :名前無し +STR_SV_TRAIN_NAME :電車{COMMA} +STR_SV_ROADVEH_NAME :車{COMMA} +STR_SV_SHIP_NAME :シップ{COMMA} +STR_SV_AIRCRAFT_NAME :飛行機{COMMA} + +STR_SV_STNAME :{STRING} +STR_SV_STNAME_NORTH :{STRING} 北 +STR_SV_STNAME_SOUTH :{STRING} 南 +STR_SV_STNAME_EAST :{STRING} 東 +STR_SV_STNAME_WEST :{STRING} 西 +STR_SV_STNAME_CENTRAL :{STRING}中 +STR_SV_STNAME_TRANSFER :{STRING}乗り換え +STR_SV_STNAME_HALT :{STRING} 停留 +STR_SV_STNAME_VALLEY :{STRING} 谷 +STR_SV_STNAME_HEIGHTS :{STRING}高地 +STR_SV_STNAME_WOODS :{STRING} 森 +STR_SV_STNAME_LAKESIDE :{STRING} 池側 +STR_SV_STNAME_EXCHANGE :{STRING}更代 +STR_SV_STNAME_AIRPORT :{STRING}空港 +STR_SV_STNAME_OILFIELD :{STRING}油田 +STR_SV_STNAME_MINES :{STRING} 鉱区 +STR_SV_STNAME_DOCKS :{STRING} 船渠 +STR_SV_STNAME_BUOY_1 :{STRING} ボイ1 +STR_SV_STNAME_BUOY_2 :{STRING} ボイ2 +STR_SV_STNAME_BUOY_3 :{STRING} ボイ3 +STR_SV_STNAME_BUOY_4 :{STRING} ボイ4 +STR_SV_STNAME_BUOY_5 :{STRING} ボイ5 +STR_SV_STNAME_BUOY_6 :{STRING} ボイ6 +STR_SV_STNAME_BUOY_7 :{STRING} ボイ7 +STR_SV_STNAME_BUOY_8 :{STRING} ボイ8 +STR_SV_STNAME_BUOY_9 :{STRING} ボイ9 +STR_SV_STNAME_ANNEXE :{STRING}新館 +STR_SV_STNAME_SIDINGS :{STRING} 側線 +STR_SV_STNAME_BRANCH :{STRING}支所 +STR_SV_STNAME_UPPER :{STRING}上 +STR_SV_STNAME_LOWER :{STRING}下 +STR_SV_STNAME_HELIPORT :{STRING}ヘリポート +STR_SV_STNAME_FOREST :{STRING} 森林 + +############ end of savegame specific region! + +##id 0x6800 +STR_6800_DIFFICULTY_LEVEL :{WHITE}難易度 + +############ range for difficulty levels starts +STR_6801_EASY :{BLACK}安い +STR_6802_MEDIUM :{BLACK}中位 +STR_6803_HARD :{BLACK}難しい +STR_6804_CUSTOM :{BLACK}カスタム +############ range for difficulty levels ends + +############ range for difficulty settings starts +STR_6805_MAXIMUM_NO_COMPETITORS :{LTBLUE}競争者数の上限:{ORANGE}{COMMA} +STR_6806_COMPETITOR_START_TIME :{LTBLUE}競争者の開始遅延:{ORANGE}{STRING} +STR_6807_NO_OF_TOWNS :{LTBLUE}市町村数:{ORANGE}{STRING} +STR_6808_NO_OF_INDUSTRIES :{LTBLUE}工業数:{ORANGE}{STRING} +STR_6809_MAXIMUM_INITIAL_LOAN_000 :{LTBLUE}初期の最高貸付金:{ORANGE}{CURRENCY} +STR_680A_INITIAL_INTEREST_RATE :{LTBLUE}初期の金利:{ORANGE}{COMMA}% +STR_680B_VEHICLE_RUNNING_COSTS :{LTBLUE}乗り物の運転費:{ORANGE}{STRING} +STR_680C_CONSTRUCTION_SPEED_OF_COMPETITOR :{LTBLUE}競争者の建造速度:{ORANGE}{STRING} +STR_680D_INTELLIGENCE_OF_COMPETITORS :{LTBLUE}競争者の能力レベル:{ORANGE}{STRING} +STR_680E_VEHICLE_BREAKDOWNS :{LTBLUE}乗り物の機能停止:{ORANGE}{STRING} +STR_680F_SUBSIDY_MULTIPLIER :{LTBLUE}助成金の乗数:{ORANGE}{STRING} +STR_6810_COST_OF_CONSTRUCTION :{LTBLUE}建造の価値:{ORANGE}{STRING} +STR_6813_ECONOMY :{LTBLUE}経済の傾向:{ORANGE}{STRING} +STR_6814_TRAIN_REVERSING :{LTBLUE}電車の反転:{ORANGE}{STRING} +STR_6815_DISASTERS :{LTBLUE}災害:{ORANGE}{STRING} +STR_16816_CITY_APPROVAL :{LTBLUE}町議会の地域の再構築に関わる姿勢:{ORANGE}{STRING} +############ range for difficulty settings ends + +STR_26816_NONE :何も +STR_6816_LOW :低い +STR_6817_NORMAL :通常 +STR_6818_HIGH :高い +STR_6819 :{BLACK}{SMALLLEFTARROW} +STR_681A :{BLACK}{SMALLRIGHTARROW} +STR_681B_VERY_SLOW :特に遅い +STR_681C_SLOW :遅い +STR_681D_MEDIUM :中位 +STR_681E_FAST :速い +STR_681F_VERY_FAST :特に速い +STR_6820_LOW :低い +STR_6821_MEDIUM :中位 +STR_6822_HIGH :高い +STR_6823_NONE :なし +STR_6824_REDUCED :軽減 +STR_6825_NORMAL :通常 +STR_6826_X1_5 :x1.5 +STR_6827_X2 :x2 +STR_6828_X3 :x3 +STR_6829_X4 :x4 +STR_682A_VERY_FLAT :特に平たい +STR_682B_FLAT :平たい +STR_682C_HILLY :丘陵地 +STR_682D_MOUNTAINOUS :山岳地 +STR_682E_STEADY :安定的 +STR_682F_FLUCTUATING :変動的 +STR_6830_IMMEDIATE :すぐに +STR_6831_3_MONTHS_AFTER_PLAYER :開始から 3 ヶ月 +STR_6832_6_MONTHS_AFTER_PLAYER :開始から 6 ヶ月 +STR_6833_9_MONTHS_AFTER_PLAYER :開始から 9 ヶ月 +STR_6834_AT_END_OF_LINE_AND_AT_STATIONS :線路終点と駅 +STR_6835_AT_END_OF_LINE_ONLY :線路終点のみ +STR_6836_OFF :切 +STR_6837_ON :入 +STR_6838_SHOW_HI_SCORE_CHART :{BLACK}ハイスコアを表示 + +##id 0x7000 +STR_7000 : +STR_7001 :{WHITE}{COMPANY} {BLACK}{PLAYERNAME} +STR_7008_COMPANY_NAME :{BLACK}会社名 +STR_7009_PRESIDENT_NAME :{BLACK}社長の名前 +STR_700A_COMPANY_NAME :会社名 +STR_700B_PRESIDENT_S_NAME :社長の名前 +STR_700C_CAN_T_CHANGE_COMPANY_NAME :{WHITE}会社名が変更できません... +STR_700D_CAN_T_CHANGE_PRESIDENT :{WHITE}社長の名前が変更できません... +STR_7010 :{WHITE}{NUM} +STR_701E :{BLACK}-{CURRENCY64} +STR_701F :{BLACK}+{CURRENCY64} +STR_7021 :{COMPANY}{PLAYERNAME} +STR_CURRCOMPACT :{CURRCOMPACT64} +STR_7024 :{COMMA} +STR_7028 :{BLACK}{CURRENCY64} +STR_TRAINS :{WHITE}{COMMA} 電車 +STR_AIRCRAFT :{WHITE}{COMMA} 飛行機 +STR_7042_NONE :{WHITE}何も +STR_7065 :{BLACK}{TINYFONT}{STRING} + +STR_LIVERY_BUS :バス + + +##id 0x8000 +STR_8104_AIRCRAFT :飛行機 + +##id 0x8800 + + + +STR_UNKNOWN_DESTINATION :不明行き先 +STR_8816 :{BLACK}- + + +STR_881F_BUILD_VEHICLE :{BLACK}車両を購入 +STR_8820_RENAME :{BLACK}名称を変更 +STR_8823_SKIP :{BLACK}スキップ +STR_8824_DELETE :{BLACK}削除 +STR_8825_NON_STOP :{BLACK}直行便 +STR_8826_GO_TO :{BLACK}駅を選択 +STR_8827_FULL_LOAD :{BLACK}全負荷 +STR_8828_UNLOAD :{BLACK}降ろす +STR_8829_ORDERS :{WHITE}{VEHICLE}(指令) +STR_882A_END_OF_ORDERS :{SETX 10}- - 指名終了 - - +STR_FULLLOAD_OR_SERVICE :{SKIP}{SKIP}{STRING} +STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE :{WHITE}鉄道車両が購入できません... +STR_882C_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} 購入日付:{LTBLUE}{NUM}{BLACK} 価値:{LTBLUE}{CURRENCY} +STR_882D_VALUE :{LTBLUE}{STRING}{BLACK} 価値:{LTBLUE}{CURRENCY} +STR_882E :{WHITE}{VEHICLE} +STR_882F_LOADING_UNLOADING :{LTBLUE}積み降ろし中 +STR_TRAIN_MUST_BE_STOPPED :{WHITE}電車は車庫に止めなければ成らないんです +STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}電車が電車庫へ回送できません... +STR_8831_NO_MORE_SPACE_FOR_ORDERS :{WHITE}これ以上の指令が追加できません +STR_8832_TOO_MANY_ORDERS :{WHITE}指令が多すぎます +STR_8833_CAN_T_INSERT_NEW_ORDER :{WHITE}新規指令が挿入できません... +STR_8834_CAN_T_DELETE_THIS_ORDER :{WHITE}この指令が削除できません... +STR_8835_CAN_T_MODIFY_THIS_ORDER :{WHITE}この指令が変更できません... +STR_8837_CAN_T_MOVE_VEHICLE :{WHITE}この車輌が移動できません... +STR_8838_N_A :N/A{SKIP} +STR_8839_CAN_T_SELL_RAILROAD_VEHICLE :{WHITE}車両が販売できません... +STR_883A_UNABLE_TO_FIND_ROUTE_TO :{WHITE}電車庫への経路が見つけられません +STR_883B_CAN_T_STOP_START_TRAIN :{WHITE}電車が開始/停止できません... +STR_883C_SERVICING_INTERVAL_DAYS :{BLACK}補修間隔:{LTBLUE}{COMMA}日間{BLACK} 最新の補修:{LTBLUE}{DATE_LONG} +STR_883D_TRAINS_CLICK_ON_TRAIN_FOR :{BLACK}電車 - 情報を見るには電車をクリックします +STR_883E_BUILD_NEW_TRAINS_REQUIRES :{BLACK}新規電車を購入(電車庫が必要) +STR_883F_TRAINS_CLICK_ON_TRAIN_FOR :{BLACK}電車 - 情報を見るには電車をクリックします。車両を追加/取り除くにはドラッグします。 +STR_8840_BUILD_NEW_TRAIN_VEHICLE :{BLACK}新規電車車両を購入 +STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE :{BLACK}車両を販売するには、ここへドラッグします +STR_8843_TRAIN_VEHICLE_SELECTION :{BLACK}電車車両のリスト - 情報を見るには車両をクリックします +STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN :{BLACK}選択した車両を購入 +STR_8845_RENAME_TRAIN_VEHICLE_TYPE :{BLACK}車両名を変更 +STR_8846_CURRENT_TRAIN_ACTION_CLICK :{BLACK}電車の現在の動作 - 開始/停止するにはここにクリックします +STR_8847_SHOW_TRAIN_S_ORDERS :{BLACK}電車の指令を表示します +STR_8849_SEND_TRAIN_TO_DEPOT :{BLACK}電車を電車庫へ回送します。Control+クリックすすると、補修のみします。 +STR_884A_FORCE_TRAIN_TO_PROCEED :{BLACK}信号が青になるまで待たずに電車の続行を強制します +STR_884B_REVERSE_DIRECTION_OF_TRAIN :{BLACK}電車を逆転します +STR_884C_SHOW_TRAIN_DETAILS :{BLACK}電車の情報を表示します +STR_884D_INCREASE_SERVICING_INTERVAL :{BLACK}補修間隔を増やす +STR_884E_DECREASE_SERVICING_INTERVAL :{BLACK}補修間隔を減らす +STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED :{BLACK}積んだ貨物の情報を表示します +STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES :{BLACK}電車車両の情報を表示します +STR_8851_SHOW_CAPACITIES_OF_EACH :{BLACK}各車両の容量を表示します +STR_8852_SHOW_TOTAL_CARGO :{BLACK}貨物種類に並べ替えて電車の合計容量を表示します +STR_8852_ORDERS_LIST_CLICK_ON_ORDER :{BLACK}指令リスト - 指令を選択するにはクリックします。 +STR_8853_SKIP_THE_CURRENT_ORDER :{BLACK}現在の指令をスキップして、次へ移動します +STR_8854_DELETE_THE_HIGHLIGHTED :{BLACK}選択した指令を削除します +STR_8855_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}選択した指令を「直行便」にします +STR_8856_INSERT_A_NEW_ORDER_BEFORE :{BLACK}選択した指令の前/リストの終わりに新規指令を挿入します +STR_8857_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}選択した指令に全負荷まで待つことを強制します +STR_8858_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}選択した指令に降ろすことを強制します +STR_8859_NEW_NOW_AVAILABLE :{BLACK}{BIGFONT}{STRING} が新登場! +STR_885A :{BLACK}{BIGFONT}{STRING} +STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER :{BLACK}値段: {CURRENCY}重さ: {WEIGHT_S}{}スピード: {VELOCITY} 力: {POWER}{}運転費:{CURRENCY}/年{}体積: {CARGO} +STR_885C_BROKEN_DOWN :{RED}故障 +STR_885D_AGE_RUNNING_COST_YR :{BLACK}年齢:{LTBLUE}{STRING}{BLACK} 運転費:{LTBLUE}1 年間に{CURRENCY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}重さ: {LTBLUE}{WEIGHT_S} {BLACK}力: {LTBLUE}{POWER}{BLACK} 最大スピード: {LTBLUE}{VELOCITY} +STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}今年の利益:{LTBLUE}{CURRENCY}(去年:{CURRENCY}) +STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}信頼度:{LTBLUE}{COMMA}% {BLACK}最新補修後の故障:{LTBLUE}{COMMA} +STR_8861_STOPPED :{RED}停止中 + +STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}電車事件!{}{COMMA} 人が死亡 +STR_8869_CAN_T_REVERSE_DIRECTION :{WHITE}電車が逆転できません... +STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}電車車両名を変更 +STR_886B_CAN_T_RENAME_TRAIN_VEHICLE :{WHITE}車両名が変更できません... + +STR_TRAIN_STOPPING :{RED}止まっています +STR_TRAIN_STOPPING_VEL :{RED}止まっています、 {VELOCITY} +STR_TRAIN_NO_POWER :{RED}電源はありません +STR_TRAIN_START_NO_CATENARY :電車はけん垂線がありませんから、電車は動き出せません。 + +##id 0x9000 +STR_9002 :{WHITE}{VEHICLE} +STR_9029 :{BLACK}{BIGFONT}{STRING} + + + +##id 0x9800 +STR_980F :{WHITE}{VEHICLE} + + +##id 0xA000 +STR_A00A :{WHITE}{VEHICLE} +STR_A02D :{BLACK}{BIGFONT}{STRING} + +STR_A036 :{TINYFONT}{BLACK}{STATION} + +##id 0xB000 + + +STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRCOMPACT}/{CURRCOMPACT}) +STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) +SET_PERFORMANCE_DETAIL_INT :{BLACK}{NUM} +############ Those following lines need to be in this order!! +############ End of order list + + + + + + +STR_TRAIN :{BLACK}{TRAIN} +STR_BUS :{BLACK}{BUS} +STR_LORRY :{BLACK}{LORRY} +STR_SHIP :{BLACK}{SHIP} + +STR_SCHEDULED_AIRCRAFT :{WHITE}{STATION} - {COMMA} 飛行機 + + +STR_VEH_WITH_SHARED_ORDERS_LIST :{WHITE}シェアード ・ルート{COMMA} 車 +STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}このスケジュールの車全部を見せます + +### depot strings + + + + +STR_VEHICLE_LIST_TRAIN_DEPOT :{BLACK}{STRING} - {COMMA} 電車 +STR_VEHICLE_LIST_ROADVEH_DEPOT :{BLACK}{STRING} - {COMMA} 車 +STR_VEHICLE_LIST_SHIP_DEPOT :{BLACK}{STRING} - {COMMA} シップ +STR_VEHICLE_LIST_AIRCRAFT_DEPOT :{BLACK}{STRING} - {COMMA} 飛行機 + + + + + + +STR_SHORT_DATE :{WHITE}{DATE_TINY} + + +############ Lists rail types + + +############ End of list of rail types + +STR_TINY_BLACK :{BLACK}{TINYFONT}{COMMA} + + +########### String for New Landscape Generator + +STR_WORLD_GENERATION_CAPTION :{WHITE}世界発電 +STR_TREE_PLACER :{BLACK}木アルゴリズム: +STR_TERRAIN_TYPE :{BLACK}地形種類: +STR_GENERATE_DATE :{BLACK}{DATE_LONG} +STR_START_DATE_QUERY_CAPT :{WHITE}始める年を変えます +STR_SNOW_LINE_HEIGHT_NUM :{NUM} +STR_GENERATION_PROGRESS :{BLACK}{NUM} / {NUM} +STR_WORLD_GENERATION :{BLACK}世界発電 +STR_TREE_GENERATION :{BLACK}木発電 +STR_UNMOVABLE_GENERATION :{BLACK}可動ない 発電 +STR_FLAT_WORLD_HEIGHT_NUM :{NUM} + + +########### String for new airports + + +############ Tooltip measurment + + +######## diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/lithuanian.txt --- a/lang/unfinished/lithuanian.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/unfinished/lithuanian.txt Wed Jan 03 08:32:17 2007 +0000 @@ -1,87 +1,89 @@ ##name Lithuanian -##ownname Lietuviu +##ownname Lietuvių ##isocode lt_LT.UTF-8 ##plural 5 +##case kas ko kam ka kuo kur kreip +##gender vyr mot ##id 0x0000 STR_NULL : -STR_0001_OFF_EDGE_OF_MAP :{WHITE}Uz zemelapio krasto -STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Per arti zemelapio krasto -STR_0003_NOT_ENOUGH_CASH_REQUIRES :{WHITE}Neuztenka lesu - reikia {CURRENCY} +STR_0001_OFF_EDGE_OF_MAP :{WHITE}Už žemelapio kraštų +STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Per arti žemėlapio krašto +STR_0003_NOT_ENOUGH_CASH_REQUIRES :{WHITE}Neužtenka lėšų: reikia {CURRENCY} STR_0004 :{WHITE}{CURRENCY64} STR_0005 :{RED}{CURRENCY64} STR_EMPTY : -STR_0007_FLAT_LAND_REQUIRED :{WHITE}Reikia lygaus paviršiaus +STR_0007_FLAT_LAND_REQUIRED :{WHITE}Paviršius turi būti lygus STR_0008_WAITING :{BLACK}Laukia: {WHITE}{STRING} STR_0009 :{WHITE}{CARGO} -STR_000A_EN_ROUTE_FROM :{WHITE}{CARGO}{YELLOW} (marsrutas is +STR_000A_EN_ROUTE_FROM :{WHITE}{CARGO}{YELLOW} (maršrutas iš STR_000B :{YELLOW}{STATION}) -STR_000C_ACCEPTS :{BLACK}Laukia: {WHITE} -STR_000D_ACCEPTS :{BLACK}Laukia: {GOLD} +STR_000C_ACCEPTS :{BLACK}Priima: {WHITE} +STR_000D_ACCEPTS :{BLACK}Priima: {GOLD} STR_000E : -STR_000F_PASSENGERS :Keleiviu +STR_000F_PASSENGERS : STR_0010_COAL :Anglis -STR_0011_MAIL :Pasto +STR_0011_MAIL :Pašto STR_0012_OIL :Naftos -STR_0013_LIVESTOCK :Galviju -STR_0014_GOODS :Prekiu -STR_0015_GRAIN :Grudu +STR_0013_LIVESTOCK :Galvijų +STR_0014_GOODS :Prekių +STR_0015_GRAIN :Grūdų STR_0016_WOOD :Medienos -STR_0017_IRON_ORE :Gelezies rudos +STR_0017_IRON_ORE :Geležies rūdos STR_0018_STEEL :Plieno -STR_0019_VALUABLES :Brangenybiu -STR_001A_COPPER_ORE :Vario rudos -STR_001B_MAIZE :Kukuruzu -STR_001C_FRUIT :Vaisiu -STR_001D_DIAMONDS :Deimantu +STR_0019_VALUABLES :Brangenybių +STR_001A_COPPER_ORE :Vario rūdos +STR_001B_MAIZE :Kukurūzų +STR_001C_FRUIT :Vaisių +STR_001D_DIAMONDS :Deimantų STR_001E_FOOD :Maisto STR_001F_PAPER :Popieriaus STR_0020_GOLD :Aukso STR_0021_WATER :Vandens -STR_0022_WHEAT :Kvieciu +STR_0022_WHEAT :Kviečių STR_0023_RUBBER :Gumos STR_0024_SUGAR :Cukraus -STR_0025_TOYS :Zaislu -STR_0026_CANDY :Saldumynu +STR_0025_TOYS :Žaislų +STR_0026_CANDY :Saldumynų STR_0027_COLA :Kolos STR_0028_COTTON_CANDY :Cukraus vatos -STR_0029_BUBBLES :Burbulu -STR_002A_TOFFEE :Karameles -STR_002B_BATTERIES :Bateriju -STR_002C_PLASTIC :Plastmases -STR_002D_FIZZY_DRINKS :Gaiviuju gerimu +STR_0029_BUBBLES :Burbulų +STR_002A_TOFFEE :Karamelės +STR_002B_BATTERIES :Baterijų +STR_002C_PLASTIC :Plastmasės +STR_002D_FIZZY_DRINKS :Gaiviųjų gėrimų STR_002E : -STR_002F_PASSENGER :Keleiviu +STR_002F_PASSENGER :Keleivių STR_0030_COAL :Anglies -STR_0031_MAIL :Pasto +STR_0031_MAIL :Pašto STR_0032_OIL :Naftos -STR_0033_LIVESTOCK :Galviju -STR_0034_GOODS :Prekiu -STR_0035_GRAIN :Grudu +STR_0033_LIVESTOCK :Galvijų +STR_0034_GOODS :Prekių +STR_0035_GRAIN :Grūdų STR_0036_WOOD :Medienos -STR_0037_IRON_ORE :Gelezies rudos +STR_0037_IRON_ORE :Geležies rūdos STR_0038_STEEL :Plieno -STR_0039_VALUABLES :Brangenybiu -STR_003A_COPPER_ORE :Vario rudos -STR_003B_MAIZE :Kukuruzu -STR_003C_FRUIT :Vaisiu -STR_003D_DIAMOND :Deimantu +STR_0039_VALUABLES :Brangenybių +STR_003A_COPPER_ORE :Vario rūdos +STR_003B_MAIZE :Kukurūzų +STR_003C_FRUIT :Vaisių +STR_003D_DIAMOND :Deimantų STR_003E_FOOD :Maisto STR_003F_PAPER :Popieriaus STR_0040_GOLD :Aukso STR_0041_WATER :Vandens -STR_0042_WHEAT :Kvieciu -STR_0043_RUBBER :Kauciuko +STR_0042_WHEAT :Kviečių +STR_0043_RUBBER :Kaučiuko STR_0044_SUGAR :Cukraus -STR_0045_TOY :Zaislu -STR_0046_CANDY :Saldumynu +STR_0045_TOY :Žaislų +STR_0046_CANDY :Saldumynų STR_0047_COLA :Kolos STR_0048_COTTON_CANDY :Cukraus vatos -STR_0049_BUBBLE :Burbulu -STR_004A_TOFFEE :Karameles -STR_004B_BATTERY :Bateriju -STR_004C_PLASTIC :Plastic -STR_004D_FIZZY_DRINK :Gaiviuju gerimu +STR_0049_BUBBLE :Burbulų +STR_004A_TOFFEE :Karamelės +STR_004B_BATTERY :Baterijų +STR_004C_PLASTIC :Plastmasės +STR_004D_FIZZY_DRINK :Gaiviųjų gėrimų STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA} keleiviai STR_QUANTITY_COAL :{WEIGHT} tonu anglies @@ -93,6 +95,7 @@ STR_QUANTITY_WOOD :{WEIGHT} tonu medienos STR_QUANTITY_IRON_ORE :{WEIGHT} tonu gelezies rudos STR_QUANTITY_STEEL :{WEIGHT} tonu plieno +STR_QUANTITY_VALUABLES :{COMMA} maiš{P as ai ų} brangenybių STR_QUANTITY_COPPER_ORE :{WEIGHT} tonu vario rudos STR_QUANTITY_MAIZE :{WEIGHT} tonu kukuruzu STR_QUANTITY_FRUIT :{WEIGHT} tonu vaisiu @@ -149,13 +152,14 @@ STR_ABBREV_ALL :{TINYFONT}VISI STR_00AE :{WHITE}{DATE_SHORT} STR_00AF :{WHITE}{DATE_LONG} -STR_00B0_MAP :{WHITE}Zemelapis - {STRING} -STR_00B1_GAME_OPTIONS :{WHITE}Zaidimo nustatymai -STR_00B2_MESSAGE :{YELLOW}Zinute -STR_00B3_MESSAGE_FROM :{YELLOW}Zinute nuo {STRING} +STR_00B0_MAP :{WHITE}Žemėlapis - {STRING} +STR_00B1_GAME_OPTIONS :{WHITE}Žaidimo nustatymai +STR_00B2_MESSAGE :{YELLOW}Žinutė +STR_00B3_MESSAGE_FROM :{YELLOW}Žinutė nuo {STRING} +STR_POPUP_CAUTION_CAPTION :{WHITE}Įspėjimas! STR_00B4_CAN_T_DO_THIS :{WHITE}To daryti negalima.... -STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Negalima griauti sios teritorijos.... -STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Orginalo teises priklauso {COPYRIGHT} 1995 Chris Sawyer, Visos teises saugomos +STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Negalima griauti šios teritorijos.... +STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Pradinės versijos teisės priklauso {COPYRIGHT} 1995 Chris Sawyer, Visos teisės saugomos STR_00B7_VERSION :{BLACK}OpenTTD versija {REV} STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2006 OpenTTD komanda STR_TRANSLATED_BY :{BLACK} Vertejai: Mindaugas Surdokas (L781), Vytautas Liuolia @@ -165,44 +169,44 @@ STR_00C7_QUIT :{WHITE}Baigti STR_00C8_YES :{BLACK}Taip STR_00C9_NO :{BLACK}Ne -STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ar jus tikrai norite nutraukti zaidima ir grizti i {STRING}? +STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ar jūs tikrai norite nutraukti žaidimą ir grižti į {STRING}? STR_00CB_1 :{BLACK}1 STR_00CC_2 :{BLACK}2 STR_00CD_3 :{BLACK}3 STR_00CE_4 :{BLACK}4 STR_00CF_5 :{BLACK}5 -STR_00D0_NOTHING :Tuscia -STR_00D1_DARK_BLUE :Tamsiai melyna -STR_00D2_PALE_GREEN :Pilksvai zalia -STR_00D3_PINK :Ruzava +STR_00D0_NOTHING :Tuščia +STR_00D1_DARK_BLUE :Tamsiai mėlyna +STR_00D2_PALE_GREEN :Pilkšvai žalia +STR_00D3_PINK :Rausva STR_00D4_YELLOW :Geltona STR_00D5_RED :Raudona -STR_00D6_LIGHT_BLUE :Zydra -STR_00D7_GREEN :Zalia -STR_00D8_DARK_GREEN :Tamsiai zalia -STR_00D9_BLUE :Melyna -STR_00DA_CREAM :Kremine -STR_00DB_MAUVE :Pilksvai melyna -STR_00DC_PURPLE :Violetine -STR_00DD_ORANGE :Oranzine +STR_00D6_LIGHT_BLUE :Žydra +STR_00D7_GREEN :Žalia +STR_00D8_DARK_GREEN :Tamsiai žalia +STR_00D9_BLUE :Mėlyna +STR_00DA_CREAM :Kreminė +STR_00DB_MAUVE :Pilkšvai mėlyna +STR_00DC_PURPLE :Violetinė +STR_00DD_ORANGE :Oranžinė STR_00DE_BROWN :Ruda STR_00DF_GREY :Pilka STR_00E0_WHITE :Balta -STR_00E1_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Per daug transporto priemoniu zaidime +STR_00E1_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Per daug transporto priemonių žaidime STR_00E2 :{BLACK}{COMMA} STR_00E3 :{RED}{COMMA} STR_00E4_LOCATION :{BLACK}Vieta -STR_00E5_CONTOURS :Konturai -STR_00E6_VEHICLES :Transporto priemones -STR_00E7_INDUSTRIES :Pramones imones +STR_00E5_CONTOURS :Kontūrai +STR_00E6_VEHICLES :Transporto priemonės +STR_00E7_INDUSTRIES :Pramonės įmonės STR_00E8_ROUTES :Keliai STR_00E9_VEGETATION :Augalija STR_00EA_OWNERS :Savininkai STR_00EB_ROADS :{BLACK}{TINYFONT}Keliai -STR_00EC_RAILROADS :{BLACK}{TINYFONT}Gelezinkeliai -STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Stoteles/Oro uostai/Prieplaukos -STR_00EE_BUILDINGS_INDUSTRIES :{BLACK}{TINYFONT}Pastatai/Pramones imones -STR_00EF_VEHICLES :{BLACK}{TINYFONT}Transporto priemones +STR_00EC_RAILROADS :{BLACK}{TINYFONT}Geležinkeliai +STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Stotelės/Oro uostai/Prieplaukos +STR_00EE_BUILDINGS_INDUSTRIES :{BLACK}{TINYFONT}Pastatai/Pramonės įmonės +STR_00EF_VEHICLES :{BLACK}{TINYFONT}Transporto priemonės STR_00F0_100M :{BLACK}{TINYFONT}100m STR_00F1_200M :{BLACK}{TINYFONT}200m STR_00F2_300M :{BLACK}{TINYFONT}300m @@ -211,64 +215,64 @@ STR_00F5_TRAINS :{BLACK}{TINYFONT}Traukiniai STR_00F6_ROAD_VEHICLES :{BLACK}{TINYFONT}Automobiliai STR_00F7_SHIPS :{BLACK}{TINYFONT}Laivai -STR_00F8_AIRCRAFT :{BLACK}{TINYFONT}Lektuvai +STR_00F8_AIRCRAFT :{BLACK}{TINYFONT}Lėktuvai STR_00F9_TRANSPORT_ROUTES :{BLACK}{TINYFONT}Keliai STR_00FA_COAL_MINE :{BLACK}{TINYFONT}Anglies kasykla -STR_00FB_POWER_STATION :{BLACK}{TINYFONT}Elektrine -STR_00FC_FOREST :{BLACK}{TINYFONT}Miskas -STR_00FD_SAWMILL :{BLACK}{TINYFONT}Lentpjuve -STR_00FE_OIL_REFINERY :{BLACK}{TINYFONT}Naftos perdirbimo imone +STR_00FB_POWER_STATION :{BLACK}{TINYFONT}Elektrinė +STR_00FC_FOREST :{BLACK}{TINYFONT}Miškas +STR_00FD_SAWMILL :{BLACK}{TINYFONT}Lentpjūvė +STR_00FE_OIL_REFINERY :{BLACK}{TINYFONT}Naftos perdirbimo įmonė STR_00FF_FARM :{BLACK}{TINYFONT}Ferma STR_0100_FACTORY :{BLACK}{TINYFONT}Gamykla -STR_0101_PRINTING_WORKS :{BLACK}{TINYFONT}Spaustuve -STR_0102_OIL_WELLS :{BLACK}{TINYFONT}Naftos grezinys -STR_0103_IRON_ORE_MINE :{BLACK}{TINYFONT}Gelezies rudos kasykla +STR_0101_PRINTING_WORKS :{BLACK}{TINYFONT}Spaustuvė +STR_0102_OIL_WELLS :{BLACK}{TINYFONT}Naftos gręžinys +STR_0103_IRON_ORE_MINE :{BLACK}{TINYFONT}Geležies rūdos kasykla STR_0104_STEEL_MILL :{BLACK}{TINYFONT}Plieno liejykla STR_0105_BANK :{BLACK}{TINYFONT}Bankas -STR_0106_PAPER_MILL :{BLACK}{TINYFONT}Popieriaus fabrikas +STR_0106_PAPER_MILL :{BLACK}{TINYFONT}Popieriaus gamykla STR_0107_GOLD_MINE :{BLACK}{TINYFONT}Aukso kasykla -STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}Maisto paruosimo fabrikas -STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}Deimantu kasykla -STR_010A_COPPER_ORE_MINE :{BLACK}{TINYFONT}Vario rudos kasykla -STR_010B_FRUIT_PLANTATION :{BLACK}{TINYFONT}Vaisiu plantacija -STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Kauciuko plantacija -STR_010D_WATER_SUPPLY :{BLACK}{TINYFONT}Vandens grezinys -STR_010E_WATER_TOWER :{BLACK}{TINYFONT}Vandentiekio bokstas -STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Lentpjuve +STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}Maisto perdirbimo įmonė +STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}Deimantų kasykla +STR_010A_COPPER_ORE_MINE :{BLACK}{TINYFONT}Vario rūdos kasykla +STR_010B_FRUIT_PLANTATION :{BLACK}{TINYFONT}Vaismedžių plantacija +STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Kaučiukmedžių plantacija +STR_010D_WATER_SUPPLY :{BLACK}{TINYFONT}Vandens grežinys +STR_010E_WATER_TOWER :{BLACK}{TINYFONT}Vandentiekio bokštas +STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Lentpjūvė STR_0110_COTTON_CANDY_FOREST :{BLACK}{TINYFONT}Cukraus vatos krumynai -STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}Saldainiu fabrikas -STR_0112_BATTERY_FARM :{BLACK}{TINYFONT}Bateriju ferma -STR_0113_COLA_WELLS :{BLACK}{TINYFONT}Kolos greziniai -STR_0114_TOY_SHOP :{BLACK}{TINYFONT}Zaislu parduotuve -STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}Zaislu fabrikas -STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}Plastmases versmes -STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}Gaiviuju gerimu fabrikas -STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}Burbulu leistuvas -STR_0119_TOFFEE_QUARRY :{BLACK}{TINYFONT}Karameles telkinys +STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}Saldumynų gamykla +STR_0112_BATTERY_FARM :{BLACK}{TINYFONT}Baterijų ūkis +STR_0113_COLA_WELLS :{BLACK}{TINYFONT}Kolos gręžiniai +STR_0114_TOY_SHOP :{BLACK}{TINYFONT}Žaislų parduotuvė +STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}Žaislų gamykla +STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}Plastmasės versmės +STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}Gaiviųjų gėrimų gamykla +STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}Burbulų leistuvas +STR_0119_TOFFEE_QUARRY :{BLACK}{TINYFONT}Karamelės telkinys STR_011A_SUGAR_MINE :{BLACK}{TINYFONT}Cukraus kasykla -STR_011B_RAILROAD_STATION :{BLACK}{TINYFONT}Gelezinkelio stotis -STR_011C_TRUCK_LOADING_BAY :{BLACK}{TINYFONT}Sunkvezimiu pakrovimo aikstele -STR_011D_BUS_STATION :{BLACK}{TINYFONT}Autobusu stotele -STR_011E_AIRPORT_HELIPORT :{BLACK}{TINYFONT}Oro uostas/Malunsparniu aikstele +STR_011B_RAILROAD_STATION :{BLACK}{TINYFONT}Geležinkelio stotis +STR_011C_TRUCK_LOADING_BAY :{BLACK}{TINYFONT}Sunkvežimių pakrovimo aikštelė +STR_011D_BUS_STATION :{BLACK}{TINYFONT}Autobusų stotis +STR_011E_AIRPORT_HELIPORT :{BLACK}{TINYFONT}Oro uostas/Sraigtasparnių aikštelė STR_011F_DOCK :{BLACK}{TINYFONT}Prieplauka -STR_0120_ROUGH_LAND :{BLACK}{TINYFONT}Kalnuotas krastas +STR_0120_ROUGH_LAND :{BLACK}{TINYFONT}Kalnuotas kraštas STR_0121_GRASS_LAND :{BLACK}{TINYFONT}Ganykla STR_0122_BARE_LAND :{BLACK}{TINYFONT}Lygumos STR_0123_FIELDS :{BLACK}{TINYFONT}Laukai -STR_0124_TREES :{BLACK}{TINYFONT}Medziai +STR_0124_TREES :{BLACK}{TINYFONT}Medžiai STR_0125_ROCKS :{BLACK}{TINYFONT}Uolos STR_0126_WATER :{BLACK}{TINYFONT}Vanduo -STR_0127_NO_OWNER :{BLACK}{TINYFONT}Nera savininko +STR_0127_NO_OWNER :{BLACK}{TINYFONT}Nėra savininko STR_0128_TOWNS :{BLACK}{TINYFONT}Miestai -STR_0129_INDUSTRIES :{BLACK}{TINYFONT}Pramones imones +STR_0129_INDUSTRIES :{BLACK}{TINYFONT}Pramonės įmonės STR_012A_DESERT :{BLACK}{TINYFONT}Dykuma STR_012B_SNOW :{BLACK}{TINYFONT}Sniegas -STR_012C_MESSAGE :{WHITE}Pranesimas +STR_012C_MESSAGE :{WHITE}Pranešimas STR_012D :{WHITE}{STRING} -STR_012E_CANCEL :{BLACK}Atsaukti +STR_012E_CANCEL :{BLACK}Atšaukti STR_012F_OK :{BLACK}Gerai STR_0130_RENAME :{BLACK}Pervardinti -STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Per daug vardu +STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Per daug vardų STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Pasirinktas vardas jau naudojamas STR_0133_WINDOWS :Windows @@ -285,12 +289,14 @@ STR_013E_CAPACITIES :{BLACK}Talpumas STR_013E_TOTAL_CARGO :{BLACK}Visa keliamoji galia STR_013F_CAPACITY :{BLACK}Talpa: {LTBLUE}{CARGO} +STR_CAPACITY_MULT :{BLACK}Talpa: {LTBLUE}{CARGO} (x{NUM}) STR_013F_TOTAL_CAPACITY_TEXT :{BLACK}Visa traukinio keliamoji galia: STR_013F_TOTAL_CAPACITY :{LTBLUE}- {CARGO} ({SHORTCARGO}) -STR_0140_NEW_GAME :{BLACK}Naujas zaidimas -STR_0141_LOAD_GAME :{BLACK}Atverti zaidima +STR_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO} ({SHORTCARGO}) (x{NUM}) +STR_0140_NEW_GAME :{BLACK}Naujas žaidimas +STR_0141_LOAD_GAME :{BLACK}Atverti žaidimą STR_SINGLE_PLAYER :{BLACK}Vienas zaidejas -STR_MULTIPLAYER :{BLACK}Keli zaidejai +STR_MULTIPLAYER :{BLACK}Komandinis žaidimas STR_64 :64 STR_128 :128 @@ -300,11 +306,11 @@ STR_2048 :2048 STR_MAPSIZE :{BLACK}Zemelapio dydis: STR_BY :{BLACK}* -STR_0148_GAME_OPTIONS :{BLACK}Zaidimo nustatymai +STR_0148_GAME_OPTIONS :{BLACK}Žaidimo nustatymai -STR_0150_SOMEONE :kazkas{SKIP}{SKIP} -STR_0151_MAP_OF_WORLD :Zemelapis -STR_0152_TOWN_DIRECTORY :Miestu sarasas +STR_0150_SOMEONE :kažkas{SKIP}{SKIP} +STR_0151_MAP_OF_WORLD :Žemėlapis +STR_0152_TOWN_DIRECTORY :Miestų sąrašas STR_0153_SUBSIDIES :Subsidijos STR_UNITS_IMPERIAL :Imperines @@ -319,34 +325,44 @@ STR_UNITS_POWER_METRIC :{COMMA}AG STR_UNITS_POWER_SI :{COMMA}kW +STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t +STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t +STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg +STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P a os ų} +STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton{P a os ų} +STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}m? +STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} galon{P as ai ų} +STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litr{P as ai ų} STR_UNITS_VOLUME_LONG_SI :{COMMA} m? +STR_UNITS_FORCE_IMPERIAL :{COMMA}x10³ svar{P o ų ų} jėga (lbf) +STR_UNITS_FORCE_METRIC :{COMMA} ton{P os ų ų} jėga STR_UNITS_FORCE_SI :{COMMA} kN ############ range for menu starts -STR_0154_OPERATING_PROFIT_GRAPH :Dirbancio pelno grafikas -STR_0155_INCOME_GRAPH :Iplauku diagrama -STR_0156_DELIVERED_CARGO_GRAPH :Pristatytu kroviniu diagrama -STR_0157_PERFORMANCE_HISTORY_GRAPH :Spartos istorinis grafikas -STR_0158_COMPANY_VALUE_GRAPH :Kompanijos vertes kitimas -STR_0159_CARGO_PAYMENT_RATES :Kroviniu apmokejimo lygis -STR_015A_COMPANY_LEAGUE_TABLE :Kompanijos uzimama vieta +STR_0154_OPERATING_PROFIT_GRAPH :Įprastinės veiklos pelno diagrama +STR_0155_INCOME_GRAPH :Pajamų diagrama +STR_0156_DELIVERED_CARGO_GRAPH :Krovinių pristatymo diagrama +STR_0157_PERFORMANCE_HISTORY_GRAPH :Našumo diagrama +STR_0158_COMPANY_VALUE_GRAPH :Kompanijos vertės diagrama +STR_0159_CARGO_PAYMENT_RATES :Krovinių apmokėjimo lygis +STR_015A_COMPANY_LEAGUE_TABLE :Kompanijos užimama vieta STR_PERFORMANCE_DETAIL_MENU :Issamus veiklos ivertinimas ############ range for menu ends STR_015B_OPENTTD :{WHITE}Apie OpenTTD -STR_015C_SAVE_GAME :Issaugoti zaidima -STR_015D_LOAD_GAME :Atverti zaidima -STR_015E_QUIT_GAME :Nutraukti zaidima -STR_015F_QUIT :Iseiti -STR_0160_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ar tu tikrai nori nutraukti zaidima? -STR_0161_QUIT_GAME :{WHITE}Nutraukti zaidima +STR_015C_SAVE_GAME :Išsaugoti žaidimą +STR_015D_LOAD_GAME :Atverti žaidimą +STR_015E_QUIT_GAME :Nutraukti žaidimą +STR_015F_QUIT :Išeiti +STR_ABANDON_GAME_QUERY :{YELLOW}Ar tikrai norite išeiti iš žaidimo? +STR_0161_QUIT_GAME :{WHITE}Nutraukti žaidima STR_SORT_ORDER_TIP :{BLACK}Pasirink rikiavimo tvarka (mazejimo/didejimo) STR_SORT_CRITERIA_TIP :{BLACK}Pasirink rikiavimo kriteriju STR_SORT_BY :{BLACK}Rikiuoti pagal @@ -370,10 +386,25 @@ STR_SORT_BY_FACILITY :Stoties tipas STR_SORT_BY_WAITING :Laukiancio krovinio verte STR_SORT_BY_RATING_MAX :Kroviniu reitingavimas +STR_ENGINE_SORT_ENGINE_ID :VariklioID (klasikinis rūšiavimas) +STR_ENGINE_SORT_COST :Kaina +STR_ENGINE_SORT_POWER :Galia +STR_ENGINE_SORT_INTRO_DATE :Atsiradimo data +STR_ENGINE_SORT_RUNNING_COST :Eksplotacijos išlaidos +STR_ENGINE_SORT_POWER_VS_RUNNING_COST :Galia/Eksplotacijos išlaidos +STR_ENGINE_SORT_CARGO_CAPACITY :Vagono talpa STR_NO_WAITING_CARGO :{BLACK}Jokiu kroviniu nera pakrovimui STR_SELECT_ALL_FACILITIES :{BLACK}Pazymeti visus pastatus STR_SELECT_ALL_TYPES :{BLACK}Pazymeti visus krovinio tipus (iskaitant nelaukiancius kroviniu) -STR_REPLACE_VEHICLES :{BLACK}Keisti tr. priemones +STR_AVAILABLE_ENGINES_TIP :{BLACK}Peržiūrėti galimų variklių sąrašą tinkamų šiai transporto priemonei. +STR_MANAGE_LIST :{BLACK}Tvarkyti sąrašą +STR_MANAGE_LIST_TIP :{BLACK}Siųsti nurodymus visoms šio sąrašo tr. priemonėms +STR_REPLACE_VEHICLES :Keisti tr. priemones +STR_SEND_TRAIN_TO_DEPOT :Siųsti į depą +STR_SEND_ROAD_VEHICLE_TO_DEPOT :Siųsti į depą +STR_SEND_SHIP_TO_DEPOT :Siųsti į depą +STR_SEND_AIRCRAFT_TO_HANGAR :Siųsti į angarą +STR_SEND_FOR_SERVICING :Siųsti techninės apžiūros ############ range for months starts STR_0162_JAN :Sau @@ -393,50 +424,50 @@ STR_016E :{TINYFONT}{STRING}{} {STRING} STR_016F :{TINYFONT}{STRING}{} {STRING}{}{NUM} STR_0170 :{TINYFONT}{STRING}- -STR_0171_PAUSE_GAME :{BLACK}Sustabdyti zaidima -STR_0172_SAVE_GAME_ABANDON_GAME :{BLACK}Issaugoti, nutraukti, iseiti is zaidimo -STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}Parodyti stoteliu sarasa -STR_0174_DISPLAY_MAP :{BLACK}Parodyti zemelapi -STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Parodyti zemelapi, miestus -STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}Parodyti miestu sarasa -STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}Parodyti kompanijos finansine informacija -STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}Parodyti pagrindine kompanijos informacija +STR_0171_PAUSE_GAME :{BLACK}Sustabdyti žaidimą +STR_0172_SAVE_GAME_ABANDON_GAME :{BLACK}Išsaugoti, nutraukti, išeiti iš žaidimo +STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti stotelių sąrašą +STR_0174_DISPLAY_MAP :{BLACK}Rodyti žemėlapį +STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Rodyti žemėlapį, miestų sąrašą +STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}Rodyti miestų sąrašą +STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}Rodyti kompanijos finansinę informaciją +STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}Rodyti pagrindinę kompanijos informaciją STR_0179_DISPLAY_GRAPHS :{BLACK}Rodyti diagramas -STR_017A_DISPLAY_COMPANY_LEAGUE :{BLACK}Transporto kompaniju vertinimas -STR_017B_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti traukiniu sarasa -STR_017C_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti automobiliu sarasa -STR_017D_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti laivu sarasa -STR_017E_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti lektuvu sarasa -STR_017F_ZOOM_THE_VIEW_IN :{BLACK}Priartinti vaizda -STR_0180_ZOOM_THE_VIEW_OUT :{BLACK}Atitolinti vaizda -STR_0181_BUILD_RAILROAD_TRACK :{BLACK}Statyti gelezinkeli +STR_017A_DISPLAY_COMPANY_LEAGUE :{BLACK}Transporto kompanijų vertinimas +STR_017B_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti traukinių sąrašą +STR_017C_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti automobilių sąrašą +STR_017D_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti laivų sąrašą +STR_017E_DISPLAY_LIST_OF_COMPANY :{BLACK}Rodyti lektuvų sąrašą +STR_017F_ZOOM_THE_VIEW_IN :{BLACK}Priartinti vaizdą +STR_0180_ZOOM_THE_VIEW_OUT :{BLACK}Nutolinti vaizdą +STR_0181_BUILD_RAILROAD_TRACK :{BLACK}Tiesti geležinkelius STR_0182_BUILD_ROADS :{BLACK}Tiesti kelius -STR_0183_BUILD_SHIP_DOCKS :{BLACK}Statyti prieplauka -STR_0184_BUILD_AIRPORTS :{BLACK}Statyti oro uosta -STR_0185_PLANT_TREES_PLACE_SIGNS :{BLACK}Statyti medzius, zenklus ir kt. -STR_0186_LAND_BLOCK_INFORMATION :{BLACK}Langelio informacija -STR_0187_OPTIONS :{BLACK}Nustatymai +STR_0183_BUILD_SHIP_DOCKS :{BLACK}Statyti prieplaukas +STR_0184_BUILD_AIRPORTS :{BLACK}Statyti oro uostus +STR_0185_PLANT_TREES_PLACE_SIGNS :{BLACK}Sodinti medžius, statyti ženklus ir kt. +STR_0186_LAND_BLOCK_INFORMATION :{BLACK}Žemės ploto informacija +STR_0187_OPTIONS :{BLACK}Parinktys STR_0188 :{BLACK}{SMALLUPARROW} STR_0189 :{BLACK}{SMALLDOWNARROW} STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}Aptarnavimo intervalo keisti negalima... -STR_018B_CLOSE_WINDOW :{BLACK}Uzdaryti langa -STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}Lango pavadinimas - tempk uz jo, jei nori langa perkelti +STR_018B_CLOSE_WINDOW :{BLACK}Uždaryti langą +STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}Lango pavadinimas - už jo tempiant galima judinti langą STR_STICKY_BUTTON :{BLACK}Pazymeti si langa kaip neuzdaroma komandos 'Uzdaryti visus langus' pagalba (arba 'Delete' klavisas) STR_RESIZE_BUTTON :{BLACK}Spragtelk ir trauk, jei nori pakeisti lango dydi STR_SAVELOAD_HOME_BUTTON :{BLACK}Spausti cia persokimui i numatytaja saugojimo/ikrovimo direktorija -STR_018D_DEMOLISH_BUILDINGS_ETC :{BLACK}Sprogdinti pastatus ir kita -STR_018E_LOWER_A_CORNER_OF_LAND :{BLACK}Nuzeminti zemes lygi -STR_018F_RAISE_A_CORNER_OF_LAND :{BLACK}Paaukstinti zemes lygi -STR_0190_SCROLL_BAR_SCROLLS_LIST :{BLACK}Prasukimo juosta - prasuka sarasa aukstyn/zemyn +STR_018D_DEMOLISH_BUILDINGS_ETC :{BLACK}Nugriauti pastatus ir kita pasirinktam žemės plote +STR_018E_LOWER_A_CORNER_OF_LAND :{BLACK}Pažeminti žemės lygį +STR_018F_RAISE_A_CORNER_OF_LAND :{BLACK}Paaukštinti žemės lygį +STR_0190_SCROLL_BAR_SCROLLS_LIST :{BLACK}Slinkties juosta - paslenka sąrašą aukštyn/žemyn STR_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Prasukimo juosta - prasuka sarasa i kaire/desine -STR_0191_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Rodyti zemes konturus zemelapyje -STR_0192_SHOW_VEHICLES_ON_MAP :{BLACK}Rodyti transporto priemones zemelapyje -STR_0193_SHOW_INDUSTRIES_ON_MAP :{BLACK}Rodyti gamyklas zemelapyje -STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Rodyti transporto kelius zemelapyje -STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}Rodyti augmenija zemelapyje -STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Rodyti zemes savininkus zemelapyje -STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Rodyti/paslepti miestu pavadinimus zemelapyje -STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Pelnas siais metais: {CURRENCY} (praeitais metais: {CURRENCY}) +STR_0191_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Rodyti žemės kontūrus žemėlapyje +STR_0192_SHOW_VEHICLES_ON_MAP :{BLACK}Rodyti transporto priemones žemėlapyje +STR_0193_SHOW_INDUSTRIES_ON_MAP :{BLACK}Rodyti gamyklas žemėlapyje +STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Rodyti transporto kelius žemėlapyje +STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}Rodyti augmeniją žemėlapyje +STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Rodyti žemės savininkus žemėlapyje +STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Rodyti/paslepti miestų pavadinimus žemėlapyje +STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Šių metų pelnas: {CURRENCY} (praėjusių metų: {CURRENCY}) ############ range for service numbers starts STR_AGE :{COMMA} metai ({COMMA}) @@ -444,306 +475,308 @@ ############ range for service numbers ends STR_019C_ROAD_VEHICLE :Automobilis -STR_019D_AIRCRAFT :Lektuvas +STR_019D_AIRCRAFT :Lėktuvas STR_019E_SHIP :Laivas STR_019F_TRAIN :Traukinys STR_01A0_IS_GETTING_OLD :{WHITE}{STRING} {COMMA} sensta -STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} labai suseno -STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} labai suseno ir butinai turi buti pakeistas -STR_01A3_LAND_AREA_INFORMATION :{WHITE}Informacija apie zemes plota -STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Kaina isvalyti: {LTBLUE}N/A -STR_01A5_COST_TO_CLEAR :{BLACK}Kaina isvalyti: {LTBLUE}{CURRENCY} -STR_01A6_N_A :N/A +STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} labai paseno +STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} labai paseno ir būtinai turi būti pakeistas +STR_01A3_LAND_AREA_INFORMATION :{WHITE}Informacija apie žemės plotą +STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Išvalymo kaina: {LTBLUE}NĖRA +STR_01A5_COST_TO_CLEAR :{BLACK}Išvalymo kaina: {LTBLUE}{CURRENCY} +STR_01A6_N_A :NĖRA STR_01A7_OWNER :{BLACK}Savininkas: {LTBLUE}{STRING} -STR_01A8_LOCAL_AUTHORITY :{BLACK}Valdzia: {LTBLUE}{STRING} -STR_01A9_NONE :Nieko +STR_01A8_LOCAL_AUTHORITY :{BLACK}Vietos valdžia: {LTBLUE}{STRING} +STR_01A9_NONE :Nėra STR_01AA_NAME :{BLACK}Vardas STR_01AB :{BLACK}{TINYFONT}{STRING} ############ range for days starts -STR_01AC_1ST :1-a -STR_01AD_2ND :2-a -STR_01AE_3RD :3-ias -STR_01AF_4TH :4-a -STR_01B0_5TH :5-a -STR_01B1_6TH :6-a -STR_01B2_7TH :7-a -STR_01B3_8TH :8-a -STR_01B4_9TH :9-a -STR_01B5_10TH :10-a -STR_01B6_11TH :11-a -STR_01B7_12TH :12-a -STR_01B8_13TH :13-a -STR_01B9_14TH :14-a -STR_01BA_15TH :15-a -STR_01BB_16TH :16-a -STR_01BC_17TH :17-a -STR_01BD_18TH :18-a -STR_01BE_19TH :19-a -STR_01BF_20TH :20-a -STR_01C0_21ST :21-a -STR_01C1_22ND :22-a -STR_01C2_23RD :23-ia -STR_01C3_24TH :24-a -STR_01C4_25TH :25-a -STR_01C5_26TH :26-a -STR_01C6_27TH :27-a -STR_01C7_28TH :28-a -STR_01C8_29TH :29-a -STR_01C9_30TH :30-a -STR_01CA_31ST :31-a +STR_01AC_1ST :1-ma(s) +STR_01AD_2ND :2-ra(s) +STR_01AE_3RD :3-čia(s) +STR_01AF_4TH :4-ta(s) +STR_01B0_5TH :5-ta(s) +STR_01B1_6TH :6-ta(s) +STR_01B2_7TH :7-ta(s) +STR_01B3_8TH :8-ta(s) +STR_01B4_9TH :9-ta(s) +STR_01B5_10TH :10-ta(s) +STR_01B6_11TH :11-ta(s) +STR_01B7_12TH :12-ta(s) +STR_01B8_13TH :13-ta(s) +STR_01B9_14TH :14-ta(s) +STR_01BA_15TH :15-ta(s) +STR_01BB_16TH :16-ta(s) +STR_01BC_17TH :17-ta(s) +STR_01BD_18TH :18-ta(s) +STR_01BE_19TH :19-ta(s) +STR_01BF_20TH :20-ta(s) +STR_01C0_21ST :21-ma(s) +STR_01C1_22ND :22-ra(s) +STR_01C2_23RD :23-čia(s) +STR_01C3_24TH :24-ta(s) +STR_01C4_25TH :25-ta(s) +STR_01C5_26TH :26-ta(s) +STR_01C6_27TH :27-ta(s) +STR_01C7_28TH :28-ta(s) +STR_01C8_29TH :29-ta(s) +STR_01C9_30TH :30-ta(s) +STR_01CA_31ST :31-ma(s) ############ range for days ends STR_01CB :{TINYFONT}{COMMA} -STR_01CE_CARGO_ACCEPTED :{BLACK}Krovinys priimamas: {LTBLUE} +STR_01CE_CARGO_ACCEPTED :{BLACK}Krovinys priimtas: {LTBLUE} STR_01D1_8 :({COMMA}/8 {STRING}) STR_01D2_JAZZ_JUKEBOX :{WHITE}Jazz Jukebox STR_01D3_SOUND_MUSIC :Garsas/muzika -STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Rodyti garso/muzikos nustatymu langa -STR_01D5_ALL :{TINYFONT}Viskas +STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Rodyti garso/muzikos nustatymus +STR_01D5_ALL :{TINYFONT}Visi STR_01D6_OLD_STYLE :{TINYFONT}Senas stilius STR_01D7_NEW_STYLE :{TINYFONT}Naujas stilius STR_01D8_EZY_STREET :{TINYFONT}Ezy Street -STR_01D9_CUSTOM_1 :{TINYFONT}Pasirinktas 1 -STR_01DA_CUSTOM_2 :{TINYFONT}Pasirinktas 2 +STR_01D9_CUSTOM_1 :{TINYFONT}Speciali 1 +STR_01DA_CUSTOM_2 :{TINYFONT}Speciali 2 STR_01DB_MUSIC_VOLUME :{BLACK}{TINYFONT}Muzikos garsas -STR_01DC_EFFECTS_VOLUME :{BLACK}{TINYFONT}Efektu garsas -STR_01DD_MIN_MAX :{BLACK}{TINYFONT}MIN ' ' ' ' ' ' MAKS +STR_01DC_EFFECTS_VOLUME :{BLACK}{TINYFONT}Efektų garsas +STR_01DD_MIN_MAX :{BLACK}{TINYFONT}TYLU ' ' ' ' ' ' GARSU STR_01DE_SKIP_TO_PREVIOUS_TRACK :{BLACK}Pereiti prie buvusio garso takelio -STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Pereiti prie kito pazymeto takelio -STR_01E0_STOP_PLAYING_MUSIC :{BLACK}Sustabdyti muzikos grojima -STR_01E1_START_PLAYING_MUSIC :{BLACK}Groti muzika -STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Tempk uz slankiklio, jei nori nustatyti muzikos ir efektu garsuma +STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Pereiti prie kito pažymėto takelio +STR_01E0_STOP_PLAYING_MUSIC :{BLACK}Sustabdyti muzikos grojimą +STR_01E1_START_PLAYING_MUSIC :{BLACK}Groti muziką +STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Muzikos ir efektų garsumą galima keisti stumdant slankiklius STR_01E3 :{DKGREEN}{TINYFONT}-- STR_01E4_0 :{DKGREEN}{TINYFONT}0{COMMA} STR_01E5 :{DKGREEN}{TINYFONT}{COMMA} STR_01E6 :{DKGREEN}{TINYFONT}------ -STR_01E7 :{DKGREEN}{TINYFONT}"{STRING}" +STR_01E7 :{DKGREEN}{TINYFONT}„{STRING}“ STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}Takelis{SETX 88}Pavadinimas STR_01E9_SHUFFLE :{TINYFONT}Atsitiktinis STR_01EA_PROGRAM :{TINYFONT}{BLACK}Programa STR_01EB_MUSIC_PROGRAM_SELECTION :{WHITE}Muzikos programos pasirinkimas -STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} "{STRING}" -STR_01ED :{TINYFONT}{LTBLUE}{COMMA} "{STRING}" +STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} „{STRING}“ +STR_01ED :{TINYFONT}{LTBLUE}{COMMA} „{STRING}“ STR_01EE_TRACK_INDEX :{TINYFONT}{BLACK}Takelio numeris -STR_01EF_PROGRAM :{TINYFONT}{BLACK}Programa - '{STRING}' -STR_01F0_CLEAR :{TINYFONT}{BLACK}Isvalyti -STR_01F1_SAVE :{TINYFONT}{BLACK}Issaugoti -STR_01F2_CURRENT_PROGRAM_OF_MUSIC :{BLACK}Dabartine garso takeliu programa -STR_01F3_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Pazymeti 'visi takeliai' programa -STR_01F4_SELECT_OLD_STYLE_MUSIC :{BLACK}Pazymeti 'seno stiliaus muzika' programa -STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}Pazymeti 'naujo stiliaus muzika' programa -STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Pazymeti 'Speciali 1' (vartotojo sukurta) programa -STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Pazymeti 'Speciali 2' (vartotojo sukurta) programa -STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Panaikinti esama programa (tik Speciali1 arba Speciali2) -STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Issaugoti muzikos nustatymus -STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Paspauskite ant garso takelio, kad itrauktumete i sarasa (tik Speciali1 arba Speciali2) -STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Programos masyti ij./isj. -STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Rodyti muzikos takeliu pasirinkimo langa -STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Paspausk ant paslaugos, kad pamatytum? centre +STR_01EF_PROGRAM :{TINYFONT}{BLACK}Programa - „{STRING}“ +STR_01F0_CLEAR :{TINYFONT}{BLACK}Išvalyti +STR_01F1_SAVE :{TINYFONT}{BLACK}Išsaugoti +STR_01F2_CURRENT_PROGRAM_OF_MUSIC :{BLACK}Dabartinė garso takelių programa +STR_01F3_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Parinkti „visi takeliai“ programą +STR_01F4_SELECT_OLD_STYLE_MUSIC :{BLACK}Parinkti „seno stiliaus muzika“ programą +STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}Parinkti „naujo stiliaus muzika“ programą +STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Parinkti „Speciali 1“ (vartotojo sukurtą) programą +STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Parinkti „Speciali 2“ (vartotojo sukurtą) programą +STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Panaikinti esama programa (tik „Speciali 1“ arba „Speciali 2“) +STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Išsaugoti muzikos nustatymus +STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Paspauskite ant garso takelio, norėdami įtraukti į sąrašą (tik „Speciali 1“ arba „Speciali 2“) +STR_CLICK_ON_TRACK_TO_REMOVE :{BLACK}Spragtelėjus takelį, jis pašalinamas iš dabartinės programos (tik „Speciali 1“ ir „Speciali 2“) +STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Programos „Atsitiktiniai takeliai“ įj./išj. +STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Rodyti muzikos takelių pasirinkimo langą +STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Paspauskite ant paslaugos, norėdami pamatyti įmonę/miestą STR_01FE_DIFFICULTY :{BLACK}Sunkumo lygis ({STRING}) STR_01FF :{TINYFONT}{BLACK}{DATE_LONG} -STR_0200_LAST_MESSAGE_NEWS_REPORT :Paskutine zinute/naujiena -STR_0201_MESSAGE_SETTINGS :Zinuciu nustatymai +STR_0200_LAST_MESSAGE_NEWS_REPORT :Paskutinė žinutė/naujiena +STR_0201_MESSAGE_SETTINGS :Žinučių nustatymai STR_MESSAGE_HISTORY_MENU :Zinuciu istorija -STR_0203_SHOW_LAST_MESSAGE_NEWS :{BLACK}Parodyti paskutine zinute/naujiena, rodyti zinuciu nustatymus -STR_0204_MESSAGE_OPTIONS :{WHITE}Zinuciu nustatymai -STR_0205_MESSAGE_TYPES :{BLACK}Zinuciu tipai: -STR_0206_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Pirmos transporto priemones atvykimas i zaidejo stotele -STR_0207_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Pirmos transporto priemones atvykimas i konkurento stotele -STR_0208_ACCIDENTS_DISASTERS :{YELLOW}Incidentai / nelaimes +STR_0203_SHOW_LAST_MESSAGE_NEWS :{BLACK}Rodyti paskutinę žinute/naujieną, rodyti žinučių nustatymus +STR_0204_MESSAGE_OPTIONS :{WHITE}Žinučių nustatymai +STR_0205_MESSAGE_TYPES :{BLACK}Žinučių tipai: +STR_0206_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Pirmosios transporto priemonės atvykimas į žaidėjo stotelę +STR_0207_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Pirmosios transporto priemonės atvykimas į konkurento stotelę +STR_0208_ACCIDENTS_DISASTERS :{YELLOW}Avarijos / nelaimės STR_0209_COMPANY_INFORMATION :{YELLOW}Kompanijos informacija -STR_020A_ECONOMY_CHANGES :{YELLOW}Ekonomikos pasikeitimai -STR_020B_ADVICE_INFORMATION_ON_PLAYER :{YELLOW}Patarimai / informacija apie zaidejo transporto priemones -STR_020C_NEW_VEHICLES :{YELLOW}Naujas transporto priemones -STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Prekiu supirkimo stotelese pokycius -STR_020E_SUBSIDIES :{YELLOW}Subsidijas -STR_020F_GENERAL_INFORMATION :{YELLOW}Bendraja informacija +STR_020A_ECONOMY_CHANGES :{YELLOW}Ekonomikos pokyčiai +STR_020B_ADVICE_INFORMATION_ON_PLAYER :{YELLOW}Patarimai / informacija apie žaidėjo transporto priemones +STR_020C_NEW_VEHICLES :{YELLOW}Naujos transporto priemonės +STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Prekių supirkimo pokyčiai +STR_020E_SUBSIDIES :{YELLOW}Subsidijos +STR_020F_GENERAL_INFORMATION :{YELLOW}Bendroji informacija STR_MESSAGES_ALL :{YELLOW}Pranesimu nustatymai (ijungta/isjungta/santrauka) STR_MESSAGE_SOUND :{YELLOW}Groti garsus pasirodzius naujienu santraukoms -STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...per toli nuo pries tai buvusio keliones tikslo -STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Geriausios kompanijos, kurios pasieke {NUM}{}({STRING} lygi) +STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...per toli buvusio keliones tikslo +STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Geriausios kompanijos, kurios pasieke {NUM}{}({STRING} lygį) STR_TOP_COMPANIES_NETWORK_GAME :{BIGFONT}{BLACK}Kompaniju Lygos lentele {NUM} STR_0212 :{BIGFONT}{COMMA}. STR_0213_BUSINESSMAN :Biznierius STR_0214_ENTREPRENEUR :Verslininkas -STR_0215_INDUSTRIALIST :Fabrikantas +STR_0215_INDUSTRIALIST :Pramonininkas STR_0216_CAPITALIST :Kapitalistas STR_0217_MAGNATE :Magnatas STR_0218_MOGUL :Didziausias magnatas -STR_0219_TYCOON_OF_THE_CENTURY :Amziaus magnatas +STR_0219_TYCOON_OF_THE_CENTURY :Amžiaus magnatas STR_HIGHSCORE_NAME :{BIGFONT}{PLAYERNAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIGFONT}'{STRING}' ({COMMA}) -STR_021B_ACHIEVES_STATUS :{BLACK}{BIGFONT}{COMPANY} pasieke '{STRING}' statusa! -STR_021C_OF_ACHIEVES_STATUS :{WHITE}{BIGFONT}Zaidejas{PLAYERNAME}{COMPANY} pasieke '{STRING}' statusa! +STR_021B_ACHIEVES_STATUS :{BLACK}{BIGFONT}{COMPANY} pasiekė „{STRING}“ statusą! +STR_021C_OF_ACHIEVES_STATUS :{WHITE}{BIGFONT}{PLAYERNAME} iš {COMPANY} pasiekė „{STRING}“ statusą! STR_021F :{BLUE}{COMMA} -STR_0220_CREATE_SCENARIO :{BLACK}Sukurti scenariju +STR_0220_CREATE_SCENARIO :{BLACK}Sukurti scenarijų STR_0221_OPENTTD :{YELLOW}OpenTTD -STR_0222_SCENARIO_EDITOR :{YELLOW}Scenarijaus Redaktorius -STR_0223_LAND_GENERATION :{WHITE}Sausumos generatorius +STR_0222_SCENARIO_EDITOR :{YELLOW}Scenarijaus redaktorius +STR_0223_LAND_GENERATION :{WHITE}Kraštovaidžio kūrimas STR_0224 :{BLACK}{UPARROW} STR_0225 :{BLACK}{DOWNARROW} -STR_0226_RANDOM_LAND :{BLACK}Atsitiktine sausuma -STR_0227_RESET_LAND :{BLACK}Generuoti isnaujo sausuma -STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Padidinkite plota zemes aukstinimui/zeminimui -STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Sumazinkite plota zemes aukstinimui/zeminimui -STR_022A_GENERATE_RANDOM_LAND :{BLACK}Generuoti atsitiktine sausuma -STR_022B_RESET_LANDSCAPE :{BLACK}Perkrauti landsafta -STR_022C_RESET_LANDSCAPE :{WHITE}Perkrauti landsafta +STR_0226_RANDOM_LAND :{BLACK}Atsitiktinis reljefas +STR_0227_RESET_LAND :{BLACK}Anuliuoti reljefą +STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Padidinkite sausumos plotą norėdami paaukštinti/pažeminti +STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Sumažinkite sausumos plotą norėdami paaukštinti/pažeminti +STR_022A_GENERATE_RANDOM_LAND :{BLACK}Kurti atsitiktinę sausumą +STR_022B_RESET_LANDSCAPE :{BLACK}Anuliuoti kraštovaizdį +STR_022C_RESET_LANDSCAPE :{WHITE}Anuliuoti kraštovaizdį STR_LOAD_GAME_HEIGHTMAP :{WHITE}Naudoti Papildoma Zemelapi STR_LOAD_SCEN_HEIGHTMAP :{BLACK}Naudoti Papildoma Zemelapi -STR_022D_ARE_YOU_SURE_YOU_WANT_TO :{WHITE}Ar tikrai nori perkrauti landsafta? -STR_022E_LANDSCAPE_GENERATION :{BLACK}Landsafto generavimas -STR_022F_TOWN_GENERATION :{BLACK}Miestu generavimas -STR_0230_INDUSTRY_GENERATION :{BLACK}Pramones generavimas -STR_0231_ROAD_CONSTRUCTION :{BLACK}Kelio konstrukcijos -STR_0233_TOWN_GENERATION :{WHITE}Miesto generavimas +STR_022D_ARE_YOU_SURE_YOU_WANT_TO :{WHITE}Ar tikrai norite anuliuoti kraštovaiždį? +STR_022E_LANDSCAPE_GENERATION :{BLACK}Kraštovaizdžio kūrimas +STR_022F_TOWN_GENERATION :{BLACK}Miesto įkūrimas +STR_0230_INDUSTRY_GENERATION :{BLACK}Pramonės kūrimas +STR_0231_ROAD_CONSTRUCTION :{BLACK}Kelio tiesimas +STR_0233_TOWN_GENERATION :{WHITE}Miesto įkūrimas STR_0234_NEW_TOWN :{BLACK}Naujas miestas -STR_0235_CONSTRUCT_NEW_TOWN :{BLACK}Ikurti nauja miesta -STR_0236_CAN_T_BUILD_TOWN_HERE :{WHITE}Miesto cia statyti negalima... -STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}...per arti zemelapio krasto +STR_0235_CONSTRUCT_NEW_TOWN :{BLACK}Įkurti naują miestą +STR_0236_CAN_T_BUILD_TOWN_HERE :{WHITE}Negalima įkurti miesto... +STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}...per arti žemėlapio krašto STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}...per arti kito miesto STR_0239_SITE_UNSUITABLE :{WHITE}...netinkamas sklypas -STR_023A_TOO_MANY_TOWNS :{WHITE}...per daug miestu +STR_023A_TOO_MANY_TOWNS :{WHITE}...per daug miestų STR_CANNOT_GENERATE_TOWN :{WHITE}Neimanoma statyti jokiu miestu STR_NO_SPACE_FOR_TOWN :{WHITE}...daugiau nera vietos zemelapyje -STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}Padidinti miesto dydi -STR_023C_EXPAND :{BLACK}Isplesti +STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}Padidinti miesto dydį +STR_023C_EXPAND :{BLACK}Išplėsti STR_023D_RANDOM_TOWN :{BLACK}Atsitiktinis miestas -STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Pastatyti miesta atsitiktineje vietoje -STR_023F_INDUSTRY_GENERATION :{WHITE}Pramones generavimas +STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Pastatyti miestą atsitiktinėję vietoje +STR_023F_INDUSTRY_GENERATION :{WHITE}Pramonės kūrimas STR_0240_COAL_MINE :{BLACK}Anglies kasykla -STR_0241_POWER_STATION :{BLACK}Elektrine -STR_0242_SAWMILL :{BLACK}Lentpjuve -STR_0243_FOREST :{BLACK}Miskas -STR_0244_OIL_REFINERY :{BLACK}Naftos perdirbimo imone -STR_0245_OIL_RIG :{BLACK}Naftos bokstas -STR_0246_FACTORY :{BLACK}Fabrikas +STR_0241_POWER_STATION :{BLACK}Elektrinė +STR_0242_SAWMILL :{BLACK}Lentpjūvė +STR_0243_FOREST :{BLACK}Miškas +STR_0244_OIL_REFINERY :{BLACK}Naftos perdirbimo įmone +STR_0245_OIL_RIG :{BLACK}Naftos bokštas +STR_0246_FACTORY :{BLACK}Gamykla STR_0247_STEEL_MILL :{BLACK}Plieno liejykla STR_0248_FARM :{BLACK}Ferma -STR_0249_IRON_ORE_MINE :{BLACK}Gelezies rudos kasykla -STR_024A_OIL_WELLS :{BLACK}Naftos greziniai +STR_0249_IRON_ORE_MINE :{BLACK}Geležies rūdos kasykla +STR_024A_OIL_WELLS :{BLACK}Naftos gręžiniai STR_024B_BANK :{BLACK}Bankas -STR_024C_PAPER_MILL :{BLACK}Popieriaus fabrikas -STR_024D_FOOD_PROCESSING_PLANT :{BLACK}Maisto perdirbimo imone -STR_024E_PRINTING_WORKS :{BLACK}Spaustuve +STR_024C_PAPER_MILL :{BLACK}Popieriaus gamykla +STR_024D_FOOD_PROCESSING_PLANT :{BLACK}Maisto perdirbimo įmonė +STR_024E_PRINTING_WORKS :{BLACK}Spaustuvė STR_024F_GOLD_MINE :{BLACK}Aukso kasykla -STR_0250_LUMBER_MILL :{BLACK}Lentpjuve -STR_0251_FRUIT_PLANTATION :{BLACK}Vaisiu plantacija -STR_0252_RUBBER_PLANTATION :{BLACK}Kauciuko plantacija -STR_0253_WATER_SUPPLY :{BLACK}Vandens grezinys -STR_0254_WATER_TOWER :{BLACK}Vandentiekio bokstas -STR_0255_DIAMOND_MINE :{BLACK}Deimantu kasykla -STR_0256_COPPER_ORE_MINE :{BLACK}Vario rudos kasykla -STR_0257_COTTON_CANDY_FOREST :{BLACK}Cukraus vatos krumynai -STR_0258_CANDY_FACTORY :{BLACK}Saldainiu fabrikas -STR_0259_BATTERY_FARM :{BLACK}Bateriju ferma -STR_025A_COLA_WELLS :{BLACK}Kolos greziniai -STR_025B_TOY_SHOP :{BLACK}Zaislu parduotuve -STR_025C_TOY_FACTORY :{BLACK}Zaislu fabrikas -STR_025D_PLASTIC_FOUNTAINS :{BLACK}Plastmases versmes -STR_025E_FIZZY_DRINK_FACTORY :{BLACK}Gaiviuju gerimu fabrikas -STR_025F_BUBBLE_GENERATOR :{BLACK}Burbulu leistuvas -STR_0260_TOFFEE_QUARRY :{BLACK}Karameles telkinys +STR_0250_LUMBER_MILL :{BLACK}Lentpjuvė +STR_0251_FRUIT_PLANTATION :{BLACK}Vaismedžių plantacija +STR_0252_RUBBER_PLANTATION :{BLACK}Kaučiukmedių plantacija +STR_0253_WATER_SUPPLY :{BLACK}Vandens gręžinys +STR_0254_WATER_TOWER :{BLACK}Vandentiekio bokštas +STR_0255_DIAMOND_MINE :{BLACK}Deimantų kasykla +STR_0256_COPPER_ORE_MINE :{BLACK}Vario rūdos kasykla +STR_0257_COTTON_CANDY_FOREST :{BLACK}Cukraus vatos krūmynai +STR_0258_CANDY_FACTORY :{BLACK}Saldumynų gamykla +STR_0259_BATTERY_FARM :{BLACK}Baterijų ūkis +STR_025A_COLA_WELLS :{BLACK}Kolos gręžiniai +STR_025B_TOY_SHOP :{BLACK}Žaislų parduotuvė +STR_025C_TOY_FACTORY :{BLACK}Žaislų gamykla +STR_025D_PLASTIC_FOUNTAINS :{BLACK}Plastmasės versmės +STR_025E_FIZZY_DRINK_FACTORY :{BLACK}Gaiviųjų gėrimų gamykla +STR_025F_BUBBLE_GENERATOR :{BLACK}Burbulų leistuvas +STR_0260_TOFFEE_QUARRY :{BLACK}Karamelės telkinys STR_0261_SUGAR_MINE :{BLACK}Cukraus kasykla -STR_0262_CONSTRUCT_COAL_MINE :{BLACK}Statyti anglies kasykla -STR_0263_CONSTRUCT_POWER_STATION :{BLACK}Statyti elektrine -STR_0264_CONSTRUCT_SAWMILL :{BLACK}Statyti lentpjuve -STR_0265_PLANT_FOREST :{BLACK}Uzsodinti miska -STR_0266_CONSTRUCT_OIL_REFINERY :{BLACK}Statyti naftos perdirbimo imone -STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY :{BLACK}Statyti naftos grezini juroje (Tik netoli zemelapio krastu) -STR_0268_CONSTRUCT_FACTORY :{BLACK}Statyti fabrika -STR_0269_CONSTRUCT_STEEL_MILL :{BLACK}Statyti plieno liejykla -STR_026A_CONSTRUCT_FARM :{BLACK}Statyti ferma -STR_026B_CONSTRUCT_IRON_ORE_MINE :{BLACK}Statyti gelezies rudos kasykla -STR_026C_CONSTRUCT_OIL_WELLS :{BLACK}Grezti naftos grezinius -STR_026D_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Statyti banka (Tik miestuose su bent 1200 gyventoju) -STR_026E_CONSTRUCT_PAPER_MILL :{BLACK}Statyti popieriaus fabrika -STR_026F_CONSTRUCT_FOOD_PROCESSING :{BLACK}Statyti maisto perdirbimo imone -STR_0270_CONSTRUCT_PRINTING_WORKS :{BLACK}Statyti spaustuve -STR_0271_CONSTRUCT_GOLD_MINE :{BLACK}Statyti aukso kasykla -STR_0272_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Statyti banka (statyti galima tiktai miestuose) -STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Pastatykite lentpjuve (nukirstos medienos perdirbimui) -STR_0274_PLANT_FRUIT_PLANTATION :{BLACK}Uzsodinti vaisiu plantacija -STR_0275_PLANT_RUBBER_PLANTATION :{BLACK}Uzsodinti kauciuko plantacija -STR_0276_CONSTRUCT_WATER_SUPPLY :{BLACK}Grezti artezini grezini -STR_0277_CONSTRUCT_WATER_TOWER_CAN :{BLACK}Statyti vandentiekio boksta (tik miestuose) -STR_0278_CONSTRUCT_DIAMOND_MINE :{BLACK}Statyti deimantu kasykla -STR_0279_CONSTRUCT_COPPER_ORE_MINE :{BLACK}Statyti vario rudos kasykla -STR_027A_PLANT_COTTON_CANDY_FOREST :{BLACK}Uzveisti cukraus vatos krumynus -STR_027B_CONSTRUCT_CANDY_FACTORY :{BLACK}Statyti saldainiu fabrika -STR_027C_CONSTRUCT_BATTERY_FARM :{BLACK}Uzsodinti bateriju ferma -STR_027D_CONSTRUCT_COLA_WELLS :{BLACK}Statyti kolos grezinius -STR_027E_CONSTRUCT_TOY_SHOP :{BLACK}Statyti zaislu parduotuve -STR_027F_CONSTRUCT_TOY_FACTORY :{BLACK}Statyti zaislu fabrika -STR_0280_CONSTRUCT_PLASTIC_FOUNTAINS :{BLACK}Statyti plastmases versmes -STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY :{BLACK}Statyti gaiviuju gerimu fabrika -STR_0282_CONSTRUCT_BUBBLE_GENERATOR :{BLACK}Statyti burbulu generatoriu -STR_0283_CONSTRUCT_TOFFEE_QUARRY :{BLACK}Statyti karameles telkini -STR_0284_CONSTRUCT_SUGAR_MINE :{BLACK}Statyti cukraus kasykla -STR_0285_CAN_T_BUILD_HERE :{WHITE}Cia statyti neimanoma {STRING} ... -STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE}...pirma reikia pastatyti miesta +STR_0262_CONSTRUCT_COAL_MINE :{BLACK}Statyti anglies kasyklą +STR_0263_CONSTRUCT_POWER_STATION :{BLACK}Statyti elektrinę +STR_0264_CONSTRUCT_SAWMILL :{BLACK}Statyti lentpjuvę +STR_0265_PLANT_FOREST :{BLACK}Užsodinti mišką +STR_0266_CONSTRUCT_OIL_REFINERY :{BLACK}Statyti naftos perdirbimo įmone +STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY :{BLACK}Statyti naftos grežinį jūroje (tik prie žemelapio kraštų) +STR_0268_CONSTRUCT_FACTORY :{BLACK}Statyti gamyklą +STR_0269_CONSTRUCT_STEEL_MILL :{BLACK}Statyti plieno liejyklą +STR_026A_CONSTRUCT_FARM :{BLACK}Statyti ūkį +STR_026B_CONSTRUCT_IRON_ORE_MINE :{BLACK}Statyti geležies rūdos kasyklą +STR_026C_CONSTRUCT_OIL_WELLS :{BLACK}Gręžti naftos gręžinius +STR_026D_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Statyti banką (tik miestuose, kuriuose yra bent 1200 gyventojų) +STR_026E_CONSTRUCT_PAPER_MILL :{BLACK}Statyti popieriaus gamyklą +STR_026F_CONSTRUCT_FOOD_PROCESSING :{BLACK}Statyti maisto perdirbimo imonę +STR_0270_CONSTRUCT_PRINTING_WORKS :{BLACK}Statyti spaustuvę +STR_0271_CONSTRUCT_GOLD_MINE :{BLACK}Statyti aukso kasyklą +STR_0272_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Statyti banką (tik miestuose) +STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Pastatykite lentpjūvę (perdirbama nukirsta mediena) +STR_0274_PLANT_FRUIT_PLANTATION :{BLACK}Užsodinti vaismedžių plantaciją +STR_0275_PLANT_RUBBER_PLANTATION :{BLACK}Užsodinti kaučiukmedžių plantaciją +STR_0276_CONSTRUCT_WATER_SUPPLY :{BLACK}Statyti vandentiekį +STR_0277_CONSTRUCT_WATER_TOWER_CAN :{BLACK}Statyti vandentiekio bokštą (tik miestuose) +STR_0278_CONSTRUCT_DIAMOND_MINE :{BLACK}Statyti deimantų kasyklą +STR_0279_CONSTRUCT_COPPER_ORE_MINE :{BLACK}Statyti vario rūdos kasyklą +STR_027A_PLANT_COTTON_CANDY_FOREST :{BLACK}Užsodinti cukraus vatos krūmynus +STR_027B_CONSTRUCT_CANDY_FACTORY :{BLACK}Statyti saldumynų gamyklą +STR_027C_CONSTRUCT_BATTERY_FARM :{BLACK}Statyti baterijų ūkį +STR_027D_CONSTRUCT_COLA_WELLS :{BLACK}Statyti kolos šulinius +STR_027E_CONSTRUCT_TOY_SHOP :{BLACK}Statyti žaislų parduotuvę +STR_027F_CONSTRUCT_TOY_FACTORY :{BLACK}Statyti žaislų gamyklą +STR_0280_CONSTRUCT_PLASTIC_FOUNTAINS :{BLACK}Statyti plastmasės versmes +STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY :{BLACK}Statyti gaiviųjų gėrimų gamyklą +STR_0282_CONSTRUCT_BUBBLE_GENERATOR :{BLACK}Statyti burbulų pūstuvą +STR_0283_CONSTRUCT_TOFFEE_QUARRY :{BLACK}Statyti karamelės telkinį +STR_0284_CONSTRUCT_SUGAR_MINE :{BLACK}Statyti cukraus kasyklą +STR_0285_CAN_T_BUILD_HERE :{WHITE}{STRING} čia negali būti pastatytas... +STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE}...pirma reikia pastatyti miestą STR_0287_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}...mieste gali buti tik vienas -STR_0288_PLANT_TREES :{BLACK}Sodinti medzius -STR_0289_PLACE_SIGN :{BLACK}Statyti zenkla -STR_028A_RANDOM_TREES :{BLACK}Atsitiktiniai medziai -STR_028B_PLANT_TREES_RANDOMLY_OVER :{BLACK}Atsitiktinai apsodinti sausuma medziais -STR_028C_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Sukurti uoletas vietas -STR_028D_PLACE_LIGHTHOUSE :{BLACK}Statyti svyturi -STR_028E_PLACE_TRANSMITTER :{BLACK}Statyti retransliatoriu -STR_028F_DEFINE_DESERT_AREA :{BLACK}Pazymeti kaip dykuma +STR_0288_PLANT_TREES :{BLACK}Sodinti medžius +STR_0289_PLACE_SIGN :{BLACK}Statyti ženklą +STR_028A_RANDOM_TREES :{BLACK}Atsitiktiniai medžiai +STR_028B_PLANT_TREES_RANDOMLY_OVER :{BLACK}Atsitiktinai apsodinti sausumą medziais +STR_028C_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Sukurti uolėtas vietas +STR_028D_PLACE_LIGHTHOUSE :{BLACK}Statyti švyturį +STR_028E_PLACE_TRANSMITTER :{BLACK}Statyti siųstuvą +STR_028F_DEFINE_DESERT_AREA :{BLACK}Nurodyti dykumos plotus{}Laikant nuspaustą VALD (CTRL) galima ją pašalinti STR_CREATE_LAKE :{BLACK}Pazymeti kaip vandeni, aplinkines zemes bus uztvindytos, jei bus juros lygyje -STR_0290_DELETE :{BLACK}Salinti -STR_0291_DELETE_THIS_TOWN_COMPLETELY :{BLACK}Salinti si miesta -STR_0292_SAVE_SCENARIO :Issaugoti scenariju -STR_0293_LOAD_SCENARIO :Atverti scenariju -STR_0294_QUIT_EDITOR :Uzdaryti Redaktoriu +STR_0290_DELETE :{BLACK}Šalinti +STR_0291_DELETE_THIS_TOWN_COMPLETELY :{BLACK}Šalinti šį miestą +STR_0292_SAVE_SCENARIO :Išsaugoti scenarijų +STR_0293_LOAD_SCENARIO :Atverti scenarijų +STR_0294_QUIT_EDITOR :Uždaryti redaktoriu STR_0295 : -STR_0296_QUIT :Iseiti -STR_0297_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Issaugoti, atverti scenariju, iseiti -STR_0298_LOAD_SCENARIO :{WHITE}Atverti scenariju -STR_0299_SAVE_SCENARIO :{WHITE}Issaugoti scenariju -STR_029A_PLAY_SCENARIO :{BLACK}Isbandyti scenariju (zaisti) +STR_0296_QUIT :Išeiti +STR_0297_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Išsaugoti scenarijų, atverti scenarijų, išjungti scenarijų redaktorių, išeiti +STR_0298_LOAD_SCENARIO :{WHITE}Atverti scenarijų +STR_0299_SAVE_SCENARIO :{WHITE}Išsaugoti scenarijų +STR_029A_PLAY_SCENARIO :{BLACK}Išbandyti scenarijų (žaisti) STR_PLAY_HEIGHTMAP :{BLACK}Zaisti Papildomam zemelapyje STR_PLAY_HEIGHTMAP_HINT :{BLACK}Pradeti zaidima naudojant papildoma zemelapi ir zemtvraka -STR_029B_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ar tikrai nori iseiti is sio scenarijaus? -STR_029C_QUIT_EDITOR :{WHITE}Iseiti is Redaktoriaus -STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...gali buti pastatyta tik miestuose, kuriuose yra bent 1200 gyventoju -STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Zaidimo pradzios data sumazinti 1 metais -STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Zaidimo pradzios data padidinti 1 metais -STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}...abu tilto galai turi buti ant zemes -STR_02A1_SMALL :{BLACK}Mazas +STR_QUIT_SCENARIO_QUERY :{YELLOW}Ar tikrai norite išeiti iš šio scenarijaus? +STR_029C_QUIT_EDITOR :{WHITE}Išeiti iš redaktoriaus +STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...gali buti pastatyta tik miestuose, kuriuose yra bent 1200 gyventojų +STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Žaidimo pradžios datą sumažinti 1 metais +STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Žaidimo pradžios datą padidinti 1 metais +STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}...abu tilto galai turi buti ant zemės +STR_02A1_SMALL :{BLACK}Mažas STR_02A2_MEDIUM :{BLACK}Vidutinis STR_02A3_LARGE :{BLACK}Didelis -STR_02A4_SELECT_TOWN_SIZE :{BLACK}Issirinkite miesto dydi +STR_02A4_SELECT_TOWN_SIZE :{BLACK}Išsirinkite miesto dydį STR_02A5_TOWN_SIZE :{YELLOW}Miesto dydis: STR_02B6 :{STRING} - {STRING} -STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS :{BLACK}Parodyti paskutine zinute ar spaudos pranesima +STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS :{BLACK}Parodyti paskutinę žinutę ar spaudos pranešimą STR_OFF :Isjungta STR_SUMMARY :Santrauka STR_FULL :Pilnas STR_02BA :{SILVER}- - {COMPANY} - - -STR_02BB_TOWN_DIRECTORY :Miestai -STR_02BC_VEHICLE_DESIGN_NAMES :{BLACK}Tr. priemoniu pavadinimai +STR_02BB_TOWN_DIRECTORY :Miestų sąrašas +STR_02BC_VEHICLE_DESIGN_NAMES :{BLACK}Tr. priemonių pavadinimai STR_02BD :{BLACK}{STRING} STR_02BE_DEFAULT :Standartinis -STR_02BF_CUSTOM :Tinkintas :) -STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}Issaugoti tinkintus vardus -STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION :{BLACK}Transporto priemoniu pavadinimu pasirinkimo laukas -STR_02C2_SAVE_CUSTOMIZED_VEHICLE :{BLACK}Issaugoti transporto priemoniu pavadinimus +STR_02BF_CUSTOM :Tinkintas +STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}Išsaugoti tinkintus vardus +STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION :{BLACK}Transporto priemonių pavadinimų pasirinkimo laukas +STR_02C2_SAVE_CUSTOMIZED_VEHICLE :{BLACK}Išsaugoti transporto priemonių pavadinimus +STR_CHECKMARK :{CHECKMARK} ############ range for menu starts -STR_02C3_GAME_OPTIONS :Zaidimo nustatymai +STR_02C3_GAME_OPTIONS :Žaidimo parinktys STR_02C5_DIFFICULTY_SETTINGS :Sunkumo nustatymai STR_02C7_CONFIG_PATCHES :Nustatymai STR_NEWGRF_SETTINGS :Papild. grafikos nustatymai STR_GAMEOPTMENU_0A : -STR_02CA_TOWN_NAMES_DISPLAYED :{SETX 12}Rodyti miestu pavadinimus -STR_02CC_STATION_NAMES_DISPLAYED :{SETX 12}Rodyti stoteliu pavadinimus -STR_02CE_SIGNS_DISPLAYED :{SETX 12}Rodyti zenklus +STR_02CA_TOWN_NAMES_DISPLAYED :{SETX 12}Rodyti miestų pavadinimus +STR_02CC_STATION_NAMES_DISPLAYED :{SETX 12}Rodyti stotelių pavadinimus +STR_02CE_SIGNS_DISPLAYED :{SETX 12}Rodyti ženklus STR_WAYPOINTS_DISPLAYED2 :{SETX 12}Rodyti tarpines stoteles STR_02D0_FULL_ANIMATION :{SETX 12}Pilna animacija STR_02D2_FULL_DETAIL :{SETX 12}Pilna detalizacija @@ -757,7 +790,7 @@ STR_CONSOLE_SETTING :Konsole STR_02D7_SCREENSHOT_CTRL_S :Fotografuoti ekrano vaizda (Ctrl-S) STR_02D8_GIANT_SCREENSHOT_CTRL_G :Fotografuoti viso ekrano vaizda (Ctrl-G) -STR_02D9_ABOUT_OPENTTD :Apie 'OpenTTD' +STR_02D9_ABOUT_OPENTTD :Apie „OpenTTD“ ############ range ends here STR_02DB_OFF :{BLACK}Isjungta @@ -801,7 +834,7 @@ STR_02FC_LOAD_A_SAVED_GAME :{BLACK}Atverti issaugota zaidima STR_02FE_CREATE_A_CUSTOMIZED_GAME :{BLACK}Sukurk savo zaidimo zemelapi/scenariju STR_02FF_SELECT_SINGLE_PLAYER_GAME :{BLACK}Pasirink 1 zaidejo zaidima -STR_0300_SELECT_MULTIPLAYER_GAME :{BLACK}Pasirink keliu zaideju (2-8) zaidima tinkle +STR_0300_SELECT_MULTIPLAYER_GAME :{BLACK}Pasirinkite komandinį žaidima skirtą 2-8 žaidėjams STR_0301_DISPLAY_GAME_OPTIONS :{BLACK}Rodyti zaidimo nustatymus STR_0302_DISPLAY_DIFFICULTY_OPTIONS :{BLACK}Rodyti sudetingumo nustatymus STR_0303_START_A_NEW_GAME_USING :{BLACK}Naujas zaidimas naudojantis scenarijumi @@ -840,25 +873,27 @@ STR_0336_7 :{BLACK}7 ############ start of townname region -STR_TOWNNAME_ORIGINAL_ENGLISH :Anglu (Oginalus) -STR_TOWNNAME_FRENCH :Prancuzu -STR_TOWNNAME_GERMAN :Vokieciu -STR_TOWNNAME_ADDITIONAL_ENGLISH :Anglu (Papildomas) -STR_TOWNNAME_LATIN_AMERICAN :Lotynu-Amerikos +STR_TOWNNAME_ORIGINAL_ENGLISH :Anglų (Oginalus) +STR_TOWNNAME_FRENCH :Prancūzų +STR_TOWNNAME_GERMAN :Vokiečių +STR_TOWNNAME_ADDITIONAL_ENGLISH :Anglų (Papildomas) +STR_TOWNNAME_LATIN_AMERICAN :Lotynų-Amerikos STR_TOWNNAME_SILLY :Kvaili -STR_TOWNNAME_SWEDISH :Svedu -STR_TOWNNAME_DUTCH :Olandu -STR_TOWNNAME_FINNISH :Suomiu -STR_TOWNNAME_POLISH :Lenku -STR_TOWNNAME_SLOVAKISH :Slovaku -STR_TOWNNAME_NORWEGIAN :Norvegu -STR_TOWNNAME_HUNGARIAN :Vengru -STR_TOWNNAME_AUSTRIAN :Austru -STR_TOWNNAME_ROMANIAN :Rumunu -STR_TOWNNAME_CZECH :Ceku -STR_TOWNNAME_SWISS :Sveicaru -STR_TOWNNAME_DANISH :Daniski -STR_TOWNNAME_TURKISH :Turkiski +STR_TOWNNAME_SWEDISH :Švedų +STR_TOWNNAME_DUTCH :Olandų +STR_TOWNNAME_FINNISH :Suomių +STR_TOWNNAME_POLISH :Lenkų +STR_TOWNNAME_SLOVAKISH :Slovakų +STR_TOWNNAME_NORWEGIAN :Norvegų +STR_TOWNNAME_HUNGARIAN :Vengrų +STR_TOWNNAME_AUSTRIAN :Austrų +STR_TOWNNAME_ROMANIAN :Rumunų +STR_TOWNNAME_CZECH :Čekų +STR_TOWNNAME_SWISS :Šveicarų +STR_TOWNNAME_DANISH :Danų +STR_TOWNNAME_TURKISH :Turkiški +STR_TOWNNAME_ITALIAN :Italų +STR_TOWNNAME_CATALAN :Katalonų ############ end of townname region STR_CURR_GBP :Svarai sterlingai (£) @@ -883,7 +918,11 @@ STR_CURR_PLN :Lenkijos zlotai (PLN) STR_CURR_ROL :Rumunijos lejos (ROL) STR_CURR_RUR :Rusijos rubliai (RUR) +STR_CURR_SIT :Slovėnijos tolarai (SIT) STR_CURR_SEK :Svedijos kronos (SEK) +STR_CURR_YTL :Turkijos liros (YTL) +STR_CURR_SKK :Slovakijos kronos (SKK) +STR_CURR_BRR :Brazilijos realai (BRL) STR_CURR_CUSTOM :Kita... @@ -984,6 +1023,7 @@ STR_CONFIG_PATCHES_JOINSTATIONS :{LTBLUE}Leisti sujungti greta pastatytas stoteles: {ORANGE}{STRING} STR_CONFIG_PATCHES_FULLLOADANY :{LTBLUE}Palikti stotele, jei nors 1 krovinys pilnai pakrautas: {ORANGE}{STRING} STR_CONFIG_PATCHES_IMPROVEDLOAD :{LTBLUE}Naudoti patobulinta krovimo algoritma: {ORANGE}{STRING} +STR_CONFIG_PATCHES_GRADUAL_LOADING :{LTBLUE}Pakrauti tr. priemones paeiliui: {ORANGE}{STRING} STR_CONFIG_PATCHES_INFLATION :{LTBLUE}Infliacija: {ORANGE}{STRING} STR_CONFIG_PATCHES_SELECTGOODS :{LTBLUE}Pristatyti krovini stotelei tiktai tuomet, kai yra poreikis: {ORANGE}{STRING} STR_CONFIG_PATCHES_LONGBRIDGES :{LTBLUE}Leisti statyti labai ilgus tiltus: {ORANGE}{STRING} @@ -1000,9 +1040,11 @@ STR_CONFIG_PATCHES_BRIBE :{LTBLUE}Leisti papirkineti miesto valdzia: {ORANGE}{STRING} STR_CONFIG_PATCHES_NONUNIFORM_STATIONS :{LTBLUE}Nestandartines stoteles: {ORANGE}{STRING} STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL :{LTBLUE}Globalus kelio radimo algoritmas (NPF, panaikina NTP): {ORANGE}{STRING} +STR_CONFIG_PATCHES_FREIGHT_TRAINS :{LTBLUE}Krovinių svorio daugiklis skirtas imituoti prikrautus traukinius: {ORANGE}{STRING} STR_CONFIG_PATCHES_SMALL_AIRPORTS :{LTBLUE}Visada leisti statyti mazus oro uotus: {ORANGE}{STRING} +STR_CONFIG_PATCHES_WARN_LOST_TRAIN :{LTBLUE}Perspėti apie traukinio praradimą: {ORANGE}{STRING} STR_CONFIG_PATCHES_ORDER_REVIEW :{LTBLUE}Perziureti tr. pr. uzduotis: {ORANGE}{STRING} STR_CONFIG_PATCHES_ORDER_REVIEW_OFF :ne STR_CONFIG_PATCHES_ORDER_REVIEW_EXDEPOT :taip, bet isskyrus sustabdytas tr. pr. @@ -1016,10 +1058,35 @@ STR_CONFIG_PATCHES_POPULATION_IN_LABEL :{LTBLUE}Rodyti miestu gyventoju skaiciu salia pavadinimo: {ORANGE}{STRING} STR_CONFIG_PATCHES_INVISIBLE_TREES :{LTBLUE}Nematomi medziai (kai ijungti permatomi pastatai): {ORANGE}{STRING} +STR_CONFIG_PATCHES_LAND_GENERATOR :{LTBLUE}Sausumos kūrimas: {ORANGE}{STRING} +STR_CONFIG_PATCHES_LAND_GENERATOR_ORIGINAL :Originalus +STR_CONFIG_PATCHES_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis +STR_CONFIG_PATCHES_OIL_REF_EDGE_DISTANCE :{LTBLUE}Didžiausias atstumas nuo kraštų naftos perdirbimo įmonėms {ORANGE}{STRING} STR_CONFIG_PATCHES_SNOWLINE_HEIGHT :{LTBLUE}Sniego linijos aukstis: {ORANGE}{STRING} +STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN :{LTBLUE}Paviršiaus nelygumas (tik TerraGenesis) : {ORANGE}{STRING} +STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Labai lygus +STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_SMOOTH :Lygus +STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_ROUGH :Kalnuotas +STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Labai kalnuotas +STR_CONFIG_PATCHES_TREE_PLACER :{LTBLUE}Medžių sodinimo algoritmas: {ORANGE}{STRING} +STR_CONFIG_PATCHES_TREE_PLACER_NONE :Jokio +STR_CONFIG_PATCHES_TREE_PLACER_ORIGINAL :Standartinis +STR_CONFIG_PATCHES_TREE_PLACER_IMPROVED :Pagerintas +STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION :{LTBLUE}Aukščių žemėlapio pasukimas: {ORANGE}{STRING} +STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Prieš laikrodžio rodyklę +STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE :Pagal laikrodžio rodyklę +STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT :{LTBLUE}Aušktis skiriamas „lygiaus scenarijaus“ žemėlapiui: {ORANGE}{STRING} STR_CONFIG_PATCHES_STATION_SPREAD :{LTBLUE}Maks. soties plotis: {ORANGE}{STRING} {RED}Demesio: Auksti parametrai letina zaidima STR_CONFIG_PATCHES_SERVICEATHELIPAD :{LTBLUE}Remontuoti malunsparnius automatiskai: {ORANGE}{STRING} +STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR :{LTBLUE}Susieti kraštovaizdžio įrankių juostą su bėgių/kelių/vandens/orouostų įrankių juostomis: {ORANGE}{STRING} +STR_CONFIG_PATCHES_REVERSE_SCROLLING :{LTBLUE}Apkeisti slinkties kryptį: {ORANGE}{STRING} +STR_CONFIG_PATCHES_MEASURE_TOOLTIP :{LTBLUE}Rodyti matavimo pastabą, kai naudojami įvairūs statybų įrankiai: {ORANGE}{STRING} +STR_CONFIG_PATCHES_LIVERIES :{LTBLUE}Rodyti kompanijos ženklus: {ORANGE}{STRING} +STR_CONFIG_PATCHES_LIVERIES_NONE :Jokių +STR_CONFIG_PATCHES_LIVERIES_OWN :Savo kompanijos +STR_CONFIG_PATCHES_LIVERIES_ALL :Visų kompanijų +STR_CONFIG_PATCHES_PREFER_TEAMCHAT :{LTBLUE}Rašyti komandai naudojant <ĮVESTI> (ENTER): {ORANGE}{STRING} STR_CONFIG_PATCHES_MAX_TRAINS :{LTBLUE}Maks. traukiniu vienam zaidejui: {ORANGE}{STRING} STR_CONFIG_PATCHES_MAX_ROADVEH :{LTBLUE}Maks. automobiliu zaidejui: {ORANGE}{STRING} @@ -1032,6 +1099,7 @@ STR_CONFIG_PATCHES_AI_BUILDS_SHIPS :{LTBLUE}Atjungti laivus kompiuteriui: {ORANGE}{STRING} STR_CONFIG_PATCHES_AINEW_ACTIVE :{LTBLUE}Naujas dirbtinio intelekto algoritmas AI (testuojamas): {ORANGE}{STRING} +STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER :{LTBLUE}Naudoti DI (dirbtinį intelektą) komandiniame žaidime (eksperimentinis): {ORANGE}{STRING} STR_CONFIG_PATCHES_SERVINT_TRAINS :{LTBLUE}Traukiniu remonto intervalas: {ORANGE}{STRING} (d. ar %) STR_CONFIG_PATCHES_SERVINT_TRAINS_DISABLED :{LTBLUE}Traukiniu remonto intervalas: {ORANGE}isjungta @@ -1043,6 +1111,7 @@ STR_CONFIG_PATCHES_SERVINT_SHIPS_DISABLED :{LTBLUE}Laivu remonto intervalas: {ORANGE} isjungta STR_CONFIG_PATCHES_NOSERVICE :{LTBLUE}Atjungti technine apziura, jei gedimai nenaudojami: {ORANGE}{STRING} STR_CONFIG_PATCHES_WAGONSPEEDLIMITS :{LTBLUE}Suaktyvinti vagonu greicio apribojima: {ORANGE}{STRING} +STR_CONFIG_PATCHES_DISABLE_ELRAILS :{LTBLUE}Uždrausti elektrinius bėgius: {ORANGE}{STRING} STR_CONFIG_PATCHES_COLORED_NEWS_YEAR :{LTBLUE}Spalvotos naujienos atsiranda: {ORANGE}{STRING} STR_CONFIG_PATCHES_STARTING_YEAR :{LTBLUE}Zaidimo pradzia: {ORANGE}{STRING} @@ -1055,6 +1124,7 @@ STR_CONFIG_PATCHES_TOOLBAR_POS_CENTER :Centruoti STR_CONFIG_PATCHES_TOOLBAR_POS_RIGHT :Desineje STR_CONFIG_PATCHES_SNAP_RADIUS :{LTBLUE}Langu persidengimo atstumas: {ORANGE}{STRING} px +STR_CONFIG_PATCHES_SNAP_RADIUS_DISABLED :{LTBLUE}Langų kibumo atsumas: {ORANGE}disabled STR_CONFIG_PATCHES_GUI :{BLACK}Vaizdas STR_CONFIG_PATCHES_CONSTRUCTION :{BLACK}Konstrukcijos @@ -1165,14 +1235,14 @@ STR_CONSTRUCT_COAL_MINE_TIP :{BLACK}Statyti anglies kasykla STR_CONSTRUCT_FOREST_TIP :{BLACK}Sodinti miska STR_CONSTRUCT_OIL_RIG_TIP :{BLACK}Statyti naftos platforma -STR_CONSTRUCT_FARM_TIP :{BLACK}Isteigti ferma +STR_CONSTRUCT_FARM_TIP :{BLACK}Įsteigti ūkį STR_CONSTRUCT_COPPER_ORE_MINE_TIP :{BLACK}Statyti vario rudos kasykla STR_CONSTRUCT_OIL_WELLS_TIP :{BLACK}Ieskoti naftos STR_CONSTRUCT_GOLD_MINE_TIP :{BLACK}Statyti aukso kasyklas STR_CONSTRUCT_DIAMOND_MINE_TIP :{BLACK}Statyti deimantu kasyklas STR_CONSTRUCT_IRON_ORE_MINE_TIP :{BLACK}Statyti anglies rudos kasykla -STR_CONSTRUCT_FRUIT_PLANTATION_TIP :{BLACK}Uzsodinti vaisiu plantacija -STR_CONSTRUCT_RUBBER_PLANTATION_TIP :{BLACK}Uzsodinti kauciuko plantacija +STR_CONSTRUCT_FRUIT_PLANTATION_TIP :{BLACK}Užsodinti vaismedžių plantaciją +STR_CONSTRUCT_RUBBER_PLANTATION_TIP :{BLACK}Užsodinti kaučiukmedžių plantaciją STR_CONSTRUCT_WATER_SUPPLY_TIP :{BLACK}Statyti vandens siurbline STR_CONSTRUCT_COTTON_CANDY_TIP :{BLACK}Uzsodinti ledinuku miska STR_CONSTRUCT_BATTERY_FARM_TIP :{BLACK}Statyti saules energijos baterijas @@ -1199,10 +1269,11 @@ TEMP_AI_IN_PROGRESS :{WHITE}Dirbtinio intelekto algoritmas pradeda darba. Jei iskils problemu - fotografuok ekrano vaizda ir konsultuokis forumuose. Sekmes! TEMP_AI_ACTIVATED :{WHITE}Demesio: sis naujas dirbtinio intelekto algoritmas dar tik testuojamas! Siuo metu dirba tik su automobiliais! +TEMP_AI_MULTIPLAYER :{WHITE}Įspėjimas: realizacija dar eksperimentinė (naudojamas naujas Dirbtinis intelektas). Visas iškilusias problemas praneškite truelight@openttd.org. ############ network gui strings -STR_NETWORK_MULTIPLAYER :{WHITE}Tinkle +STR_NETWORK_MULTIPLAYER :{WHITE}Komandinis žaidimas STR_NETWORK_PLAYER_NAME :{BLACK}Zaidejo vardas: STR_NETWORK_ENTER_NAME_TIP :{BLACK}Tai vardas, pagal kuri kiti zaidejai tave pazins @@ -1240,6 +1311,7 @@ STR_NETWORK_SERVER_OFFLINE :{SILVER}SERVERIS ISJUNGTAS STR_NETWORK_SERVER_FULL :{SILVER}SERVERIS PILNAS STR_NETWORK_VERSION_MISMATCH :{SILVER}VERSIJU NESUTAPIMAS +STR_NETWORK_GRF_MISMATCH :{SILVER}NEWGRF NEATITIKIMAS STR_NETWORK_JOIN_GAME :{BLACK}Jungtis @@ -1331,6 +1403,7 @@ STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Gaunama zaidimo informacija.. STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Gaunama kompanijos informacija.. ############ End of leave-in-this-order +STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} vartotoj{P as ai ų} prieš tave STR_NETWORK_CONNECTING_DOWNLOADING :{BLACK}{NUM} / {NUM} Kb parsiusta STR_NETWORK_DISCONNECT :{BLACK}Atsijungti @@ -1377,17 +1450,21 @@ STR_NETWORK_CLIENT_JOINED :prisijunge prie zaidimo STR_NETWORK_GIVE_MONEY :dave tavo kompanijai siek tiek pinigu: ({CURRENCY}) STR_NETWORK_GAVE_MONEY_AWAY :tu davei {STRING} siek tiek pinigu: ({CURRENCY}) -STR_NETWORK_CHAT_COMPANY :[Komanda] {STRING}: -STR_NETWORK_CHAT_TO_COMPANY :[Komanda] Kam {STRING}: -STR_NETWORK_CHAT_CLIENT :[Privaciai] {STRING}: -STR_NETWORK_CHAT_TO_CLIENT :[Privaciai] Kam {STRING}: -STR_NETWORK_CHAT_ALL :[Visiems] {STRING}: +STR_NETWORK_CHAT_COMPANY_CAPTION :[Komandai] : +STR_NETWORK_CHAT_COMPANY :[Komandai] {STRING}: {GRAY}{STRING} +STR_NETWORK_CHAT_TO_COMPANY :[Komandai] {STRING}: {GRAY}{STRING} +STR_NETWORK_CHAT_CLIENT_CAPTION :[Privačiai] : +STR_NETWORK_CHAT_CLIENT :[Privačiai] {STRING}: {GRAY}{STRING} +STR_NETWORK_CHAT_TO_CLIENT :[Privačiai] {STRING}: {GRAY}{STRING} +STR_NETWORK_CHAT_ALL_CAPTION :[Visiems] : +STR_NETWORK_CHAT_ALL :[Visiems] {STRING}: {GRAY}{STRING} STR_NETWORK_NAME_CHANGE :pakeite savo varda i STR_NETWORK_SERVER_SHUTDOWN :{WHITE} Serveris uzsidare STR_NETWORK_SERVER_REBOOT :{WHITE} Serveris persikrauna...{}Prasau palaukti... STR_NETWORK_SERVER :Serveris STR_NETWORK_CLIENT :Zaidejas +STR_NETWORK_SPECTATORS :Stebėtojai STR_NETWORK_CLIENTLIST_NONE :(nera) STR_NETWORK_CLIENTLIST_KICK :Ismesti (Kick) @@ -1413,6 +1490,8 @@ STR_PNGMAP_ERR_IMAGE_TYPE :{WHITE}...Negali perversti paveiklselio. 8 arba 24-bit PNG paveikslelis reikalingas. STR_PNGMAP_ERR_MISC :{WHITE}...kazkas buvo ne taip. Atsiprasome. (greiciausiai pazeistas failas) +STR_BMPMAP_ERROR :{WHITE}Negalima nuskaityti kraštovaizdžio iš BMP... +STR_BMPMAP_ERR_IMAGE_TYPE :{WHITE}...nepavyko pakeisti vaizdo failo formato. ##id 0x0800 STR_0800_COST :{TINYFONT}{RED}Kainuoja: {CURRENCY} @@ -1590,6 +1669,7 @@ STR_2051_BUILD_A_STATUE_IN_HONOR :{WHITE}{STRING}{}{YELLOW} Statyti statula kompanijos garbei.{} Kainuos: {CURRENCY} STR_2052_FUND_THE_CONSTRUCTION_OF :{WHITE}{STRING}{}{YELLOW} Finansuoti nauju komerciniu pastatu statyba mieste.{} Cost: {CURRENCY} STR_2053_BUY_1_YEAR_S_EXCLUSIVE :{WHITE}{STRING}{}{YELLOW} Pirkti isskirtines transporto teises mieste 1 metams. Miesto valdzia keleivius ir krovinius leis pervezti tik tavo kompanijai.{} Kaina: {CURRENCY} +STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY_DESC :{WHITE}{STRING}{}{YELLOW} Paperkant vietinę valdžią pakeliamas Jūsų reitingas, tačiau, jeigu pagaus, bus taikoma sunki bausmė.{} Kaina: {CURRENCY} STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING :{BIGFONT}{BLACK}Eismo chaosas {TOWN}!{}{}Keliu rekonstrukcija, finansuojama {COMPANY}, sukels 6 menesiu chaosa keliuose! STR_2056 :{TINYFONT}{WHITE}{TOWN} STR_2057 :{ORANGE}{TOWN}{BLACK} ({COMMA}) @@ -1700,7 +1780,9 @@ STR_306A_BUOY_IN_THE_WAY :{WHITE}...pluduras pakeliui STR_306C_STATION_TOO_SPREAD_OUT :{WHITE}...stotis per daug issipletusi STR_306D_NONUNIFORM_STATIONS_DISALLOWED :{WHITE}...nestandartines stoteles atjungtos +STR_USE_CTRL_TO_SELECT_MORE :{BLACK}Laikant nuspaustą VALD (CTRL) galima pažymėti daugiau nei vieną +STR_UNDEFINED :(neapibrėžta eilutė) STR_STAT_CLASS_DFLT :Numatytoji stotis STR_STAT_CLASS_WAYP :Keliarodziai @@ -1732,6 +1814,7 @@ STR_400E_SELECT_NEW_GAME_TYPE :{WHITE}Pasirink zaujo zaidimo tipa STR_400F_SELECT_SCENARIO_GREEN_PRE :{BLACK}Pasirinkite scenariju (zalia spalva), nustatyta zaidima (melyna), ar atsitiktini nauja zaidima STR_4010_GENERATE_RANDOM_NEW_GAME :Atsitiktinai generuoti nauja zaidima +STR_4011_LOAD_HEIGHTMAP :{WHITE}Atverti aukščių žemėlapį ##id 0x4800 STR_4800_IN_THE_WAY :{WHITE}{STRING} kelyje @@ -1745,11 +1828,11 @@ STR_4808_FACTORY :gamykla STR_4809_PRINTING_WORKS :spaustuveje STR_480A_STEEL_MILL :plieno liejykla -STR_480B_FARM :ferma +STR_480B_FARM :ūkis STR_480C_COPPER_ORE_MINE :vario rudos kasykla STR_480D_OIL_WELLS :naftos grezinys STR_480E_BANK :banke -STR_480F_FOOD_PROCESSING_PLANT :maisto perdirbimo imone +STR_480F_FOOD_PROCESSING_PLANT :Maisto perdirbimo įmone STR_4810_PAPER_MILL :popieriaus fabrike STR_4811_GOLD_MINE :aukso kasykla STR_4812_BANK :bankas @@ -1760,7 +1843,7 @@ STR_4817_WATER_SUPPLY :vandens saugykloje STR_4818_WATER_TOWER :vandentiekio bokste STR_4819_FACTORY :gamykloje -STR_481A_FARM :ferma +STR_481A_FARM :ūkis STR_481B_LUMBER_MILL :Lentpjuve STR_481C_COTTON_CANDY_FOREST :ledinuku miskas STR_481D_CANDY_FACTORY :saldumynu fabrike @@ -2030,10 +2113,10 @@ STR_7037_PRESIDENT :{WHITE}{PLAYERNAME}{}{GOLD}(Direktorius) STR_7038_INAUGURATED :{GOLD}Eina pareigas nuo: {WHITE}{NUM} STR_7039_VEHICLES :{GOLD}Transporto priemones: -STR_TRAINS :{WHITE}{COMMA} traukin{P ys iai} -STR_ROAD_VEHICLES :{WHITE}{COMMA} automobili{P s ai} +STR_TRAINS :{WHITE}{COMMA} traukin{P ys iai ių} +STR_ROAD_VEHICLES :{WHITE}{COMMA} automobili{P s ai ų} STR_AIRCRAFT :{WHITE}{COMMA} lektuvai -STR_SHIPS :{WHITE}{COMMA} laiva{P s i} +STR_SHIPS :{WHITE}{COMMA} laiv{P as ai ų} STR_7042_NONE :{WHITE}Neturi STR_7043_FACE_SELECTION :{WHITE}Veido pasirinkimas STR_7044_MALE :{BLACK}Vyras @@ -2403,8 +2486,8 @@ STR_8801_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Gyventojai svencia . . .{}Pirmas traukinys atvaziavo i {STATION}! STR_8802_DETAILS :{WHITE}{STRING} (Detales) STR_8803_TRAIN_IN_THE_WAY :{WHITE}Traukinys kelyje -STR_8804 :{SETX 10}{COMMA}: {STRING} -STR_8805 :{RIGHTARROW}{SETX 10}{COMMA}: {STRING} +STR_8804 :{SETX 10}{COMMA}: {STRING} {STRING} +STR_8805 :{RIGHTARROW}{SETX 10}{COMMA}: {STRING} {STRING} STR_8806_GO_TO :Vaziuoja i {STATION} STR_8807_GO_TO_TRANSFER :Vykti i {STATION} (Perkelti ir pakrauti krovinius) STR_8808_GO_TO_UNLOAD :Vykti i {STATION} (Issikrauti) @@ -2432,6 +2515,7 @@ STR_UNKNOWN_DESTINATION :nezinomas tikslas STR_8812_EMPTY :{LTBLUE}Tuscias STR_8813_FROM :{LTBLUE}{CARGO} is {STATION} +STR_FROM_MULT :{LTBLUE}{CARGO} iš {STATION} (x{NUM}) STR_8814_TRAIN_IS_WAITING_IN_DEPOT :{WHITE}Traukinys {COMMA} laukia depe STR_8815_NEW_VEHICLES :{BLACK}Naujos tr. priemones STR_8816 :{BLACK}- @@ -2443,10 +2527,15 @@ STR_NEW_ELRAIL_VEHICLES :{WHITE}Nauji Elektriniai Traukiniai STR_881D_NEW_MONORAIL_VEHICLES :{WHITE}Nauji Vienbegiai Traukiniai STR_881E_NEW_MAGLEV_VEHICLES :{WHITE}Nauji Maglev Traukiniai +STR_ALL_AVAIL_RAIL_VEHICLES :{WHITE}Traukiniai STR_881F_BUILD_VEHICLE :{BLACK}Pirkti -STR_CLONE_ROAD_VEHICLE :{BLACK}Klonuoti Masina -STR_CLONE_TRAIN :{BLACK}Klonuoti Traukini +STR_CLONE_ROAD_VEHICLE :{BLACK}Kopijuoti automobilį +STR_CLONE_ROAD_VEHICLE_INFO :{BLACK}Tai pagamins automobilio kopiją. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai +STR_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Tai pagamins automobilio kopiją. Spragtelkite šį mygtuką, o tada automobilį esantį depe arba už jo ribų. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai +STR_CLONE_TRAIN :{BLACK}Kopijuoti traukinį +STR_CLONE_TRAIN_INFO :{BLACK}Tai pagamins traukinio kopiją su visais vagonais. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai +STR_CLONE_TRAIN_DEPOT_INFO :{BLACK}Tai pagamins traukinio kopiją su visais vagonais. Spragtelkite šį mygtuką, o tada traukinį esantį depe arba už jo ribų. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai STR_8820_RENAME :{BLACK}Pervardinti STR_8823_SKIP :{BLACK}Praleisti STR_8824_DELETE :{BLACK}Istrinti @@ -2454,6 +2543,9 @@ STR_8826_GO_TO :{BLACK}Vaziuoti STR_8827_FULL_LOAD :{BLACK}Pakrauti STR_8828_UNLOAD :{BLACK}Iskrauti +STR_REFIT :{BLACK}Naujinti +STR_REFIT_TIP :{BLACK}Pasirinkite kurį vagonų tipą kuriuo tipu pakeisti (eilės tvarka). Spragtelėjus laikant VALD (CTRL) nurodymas pašalinamas +STR_REFIT_ORDER :(Keisti į {STRING}) STR_8829_ORDERS :{WHITE}{VEHICLE} (Uzduotys) STR_882A_END_OF_ORDERS :{SETX 10}- - Uzduociu pabaiga- - STR_FULLLOAD_OR_SERVICE :{SKIP}{SKIP}{STRING} @@ -2500,6 +2592,7 @@ STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES :{BLACK}Rodyti detalia vagonu informacija STR_8851_SHOW_CAPACITIES_OF_EACH :{BLACK}Rodyti detalia vagonu talpos informacija STR_8852_SHOW_TOTAL_CARGO :{BLACK}Rodyti bendra traukinio talpos informacija pagal kroviniu tipa +STR_8852_ORDERS_LIST_CLICK_ON_ORDER :{BLACK}Nurodymų sąrašas - nurodymas pažymimas ant jo spragtelėjus. Spregtelėjimas laikant VALD (CTRL) nukelia į stotį STR_8853_SKIP_THE_CURRENT_ORDER :{BLACK}Praleisti esama uzduoti, vygdyti sekancia STR_8854_DELETE_THE_HIGHLIGHTED :{BLACK}Istrinti pazymeta uzduoti STR_8855_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Nestoti pazymetoje stoteleje @@ -2509,8 +2602,11 @@ STR_SERVICE_HINT :{BLACK}Nevykdyti sios uzduoties iki tol, kol nereikes remonto STR_8859_NEW_NOW_AVAILABLE :{BLACK}{BIGFONT}Naujas {STRING} atsirado! STR_885A :{BLACK}{BIGFONT}{STRING} +STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER :{BLACK}Kaina: {CURRENCY} Svoris: {WEIGHT_S}{}Greitis: {VELOCITY} Galia: {POWER}{}Eksplotacijos išlaidos: {CURRENCY}/metus{}Talpa: {CARGO} STR_885C_BROKEN_DOWN :{RED}Sugedo STR_885D_AGE_RUNNING_COST_YR :{BLACK}Amzius: {LTBLUE}{STRING}{BLACK} Eksploatacijos islaidos: {LTBLUE}{CURRENCY}/met +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Svoris: {LTBLUE}{WEIGHT_S} {BLACK}Galia: {LTBLUE}{POWER}{BLACK} Did. greitis: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Svoris: {LTBLUE}{WEIGHT_S} {BLACK}Galia: {LTBLUE}{POWER}{BLACK} Did. greitis {LTBLUE}{VELOCITY} {BLACK}Did. K.G.: {LTBLUE}{FORCE} STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Siu metu pelnas : {LTBLUE}{CURRENCY} (praeitu metu: {CURRENCY}) STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}Patikimumas: {LTBLUE}{COMMA}% {BLACK}Gedimai nuo praeito remonto: {LTBLUE}{COMMA} STR_8861_STOPPED :{RED}Sustabdyta @@ -2524,11 +2620,14 @@ STR_8869_CAN_T_REVERSE_DIRECTION :{WHITE}Traukinio vaziavimo krypties pakeisti negalima... STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}Pervardinti traukinio tipa STR_886B_CAN_T_RENAME_TRAIN_VEHICLE :{WHITE}Neimanoma pervardinti traukinio tipo... +STR_886D_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Priversti iškrauti krovinius pažymėta tvarka STR_886F_TRANSFER :{BLACK}Perkelti STR_TRAIN_STOPPING :{RED}Stabdoma STR_TRAIN_STOPPING_VEL :{RED}Stabdomas, {VELOCITY} STR_INCOMPATIBLE_RAIL_TYPES :Nesuderinami begiai +STR_TRAIN_NO_POWER :{RED}Nėra energijos +STR_TRAIN_START_NO_CATENARY :Šiuose bėgiuose trūkta grandies, taigi traukiniai negali judėti ##id 0x9000 STR_9000_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Automobilis kelyje @@ -2594,6 +2693,7 @@ STR_REFIT_ROAD_VEHICLE :{BLACK}Perkomplektuoti STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED :{BLACK}Perkomplektuoti transporto priemone kad galetu vezti pazymeta krovinio tipa STR_REFIT_ROAD_VEHICLE_CAN_T :{WHITE}Neimanoma perkomplektuoti... +STR_ROAD_SELECT_TYPE_OF_CARGO_FOR :{BLACK}Nurodykite šios transporto priemonės pervežamą krovinių tipą ##id 0x9800 STR_9800_DOCK_CONSTRUCTION :Doku konstrukcija @@ -2604,7 +2704,9 @@ STR_9805_SHIPS :{WHITE}{COMPANY} - {COMMA} Laivai STR_9808_NEW_SHIPS :{WHITE}Nauji laivai STR_9809_BUILD_SHIP :{BLACK}Nupirkti Laiva -STR_CLONE_SHIP :{BLACK}Klonuoti Laiva +STR_CLONE_SHIP :{BLACK}Kopijuoti laivą +STR_CLONE_SHIP_INFO :{BLACK}Tai pagamins laivo kopiją. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai +STR_CLONE_SHIP_DEPOT_INFO :{BLACK}Tai pagamins laivo kopiją. Spragtelkite šį mygtuką, o tada traukinį esantį depe arba už jo ribų. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai STR_980B_SHIP_MUST_BE_STOPPED_IN :{WHITE}Laivas turi buti sustabdytas garaze STR_980C_CAN_T_SELL_SHIP :{WHITE}Laivo parduoti negalima... STR_980D_CAN_T_BUILD_SHIP :{WHITE}Laivo isigyti negalima... @@ -2664,15 +2766,16 @@ STR_9841_CAN_T_REFIT_SHIP :{WHITE}Negalima perorientuotilaivo... STR_9842_REFITTABLE :(perorientuotinas) STR_GO_TO_SHIP_DEPOT :Uzduotis: laivu depas {TOWN} -SERVICE_AT_SHIP_DEPOT :Remontas laivu depe {TOWN} +SERVICE_AT_SHIP_DEPOT :Remontas {TOWN} miesto laivų depe ##id 0xA000 STR_A000_AIRPORTS :{WHITE}Oro uostai STR_A001_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Negalima cia statyti oro uosto... STR_A002_AIRCRAFT_HANGAR :{WHITE}{STATION} Lektuvu angaras STR_A003_NEW_AIRCRAFT :{BLACK}Naujas lektuvas -STR_CLONE_AIRCRAFT :{BLACK}Klonuoti lektuva -STR_CLONE_AIRCRAFT_INFO :{BLACK}Tai pagamins lektuvo kopija ir nustatys marsrutus. +STR_CLONE_AIRCRAFT :{BLACK}Kopijuoti lėktuvą +STR_CLONE_AIRCRAFT_INFO :{BLACK}Tai pagamins lėktuvo kopiją. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai +STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Tai pagamins lėktuvo kopiją. Spragtelkite šį mygtuką, o tada traukinį esantį angare arba už jo ribų. Spragtelėjus laikant VALD (CTRL) nukopijuojami nurodymai STR_A005_NEW_AIRCRAFT :{WHITE}Naujas lektuvas STR_A006_BUILD_AIRCRAFT :{BLACK}Isigyti lektuva STR_A008_CAN_T_BUILD_AIRCRAFT :{WHITE}Negalima isigyti lektuvo... @@ -2737,13 +2840,13 @@ STR_A041_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nauja talpa: {GOLD}{STRING}{}{BLACK}Pakeitimo kaina: {GOLD}{CURRENCY} STR_A042_CAN_T_REFIT_AIRCRAFT :{WHITE}Negalima pakeisti krovinio tipo... STR_GO_TO_AIRPORT_HANGAR :Kursas: {STATION} angaras -SERVICE_AT_AIRPORT_HANGAR :Remontas angare: {STATION} +SERVICE_AT_AIRPORT_HANGAR :Remontas {STATION} angare ##id 0xB000 STR_B000_ZEPPELIN_DISASTER_AT :{BLACK}{BIGFONT} Dirizablio katastrofa {STATION}! STR_B001_ROAD_VEHICLE_DESTROYED :{BLACK}{BIGFONT}Automobilis sunaikintas ateiviu! STR_B002_OIL_REFINERY_EXPLOSION :{BLACK}{BIGFONT}Naftos perdirbimo fabriko sprogimas salia {TOWN}! -STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS :{BLACK}{BIGFONT} Del neaiskiu aplinkybiu sunaikinta ferma salia {TOWN}! +STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS :{BLACK}{BIGFONT} Įtartinomis aplinkybėmis sunaikintas ūkis, esantis prie {TOWN}! STR_B004_UFO_LANDS_NEAR :{BLACK}{BIGFONT}Ateiviai nusileido salia {TOWN}! STR_B005_COAL_MINE_SUBSIDENCE_LEAVES :{BLACK}{BIGFONT}Anglies kasyklose salia {TOWN} sedantis gruntas sukele katastrofa - kasykla nenaudojama! STR_B006_FLOOD_VEHICLE_DESTROYED :{BLACK}{BIGFONT}Potvynis!{}Automobilio {COMMA} buvo pasigesta, kaip spejama, tai susije su potvyniu! @@ -2781,6 +2884,7 @@ STR_PERFORMANCE_DETAIL_LOAN_TIP :{BLACK}Kompanijos pasiskolintu pinigu kiekis STR_PERFORMANCE_DETAIL_TOTAL_TIP :{BLACK}Viso tasku (is visu galimu) +STR_NEWGRF_SETTINGS_BUTTON :{BLACK}NewGRF Nustatymai STR_NEWGRF_SETTINGS_CAPTION :{WHITE}Newgrf settings STR_NEWGRF_APPLY_CHANGES :{BLACK}Pakeitimai isigalioja STR_NEWGRF_SET_PARAMETERS :{BLACK}Nustatyti parametrus @@ -2788,9 +2892,31 @@ STR_NEWGRF_NO_FILES_INSTALLED :{BLACK}Nera instaliuota NewGRF failu! Prasau skaityti vartotojo vadove apie tai, kaip instaliuoti naujus grafinus elementus (NewGRF) STR_NEWGRF_FILENAME :{BLACK}Failo vardas: {SILVER}{STRING} STR_NEWGRF_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} +STR_NEWGRF_MD5SUM :{BLACK}MD5suma: {SILVER}{STRING} +STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Jūs norite atlikti pakeitimus veikiančiam žaidimui: OpenTTD gali pakibti.{}Ar jūs tikrai norite tai atlikti? +STR_NEWGRF_ADD :{BLACK}Pridėti +STR_NEWGRF_ADD_TIP :{BLACK}Pridėti NewGRF failą į sąrašą +STR_NEWGRF_REMOVE :{BLACK}Pašalinti +STR_NEWGRF_REMOVE_TIP :{BLACK}Pašalinti pažymėtą NewGRF filą iš sąrašo +STR_NEWGRF_MOVEUP :{BLACK}Perkelti aukštyn +STR_NEWGRF_MOVEUP_TIP :{BLACK}Perkelti pažymėtus NewGRF failus sąraše aukštyn +STR_NEWGRF_MOVEDOWN :{BLACK}Perkelti žemyn +STR_NEWGRF_MOVEDOWN_TIP :{BLACK}Perkelti pažymėtus NewGRF failus sąraše žemyn +STR_NEWGRF_FILE_TIP :{BLACK}Įdiegtų NewGRF filų sąrašas. Sragtelėjus failą galima keisti jo parametrus +STR_NEWGRF_PARAMETER :{BLACK}Parametrai: {SILVER}{STRING} +STR_NEWGRF_PARAMETER_QUERY :{BLACK}Įveskite NewGRF parametrus +STR_NEWGRF_NO_INFO :{BLACK}Informacija neprieinama +STR_NEWGRF_ADD_CAPTION :{WHITE}Prieinami NewGRF filai +STR_NEWGRF_ADD_FILE :{BLACK}Pridėti prie pažymėjimo +STR_NEWGRF_ADD_FILE_TIP :{BLACK}Įtraukti pažymėtus NewGRF failus į jūsų nustatymus +STR_NEWGRF_RESCAN_FILES :{BLACK}Atnaujinti sąrašą +STR_NEWGRF_RESCAN_FILES_TIP :{BLACK}Atnaujinti prieinamų NewGRF filų sąrašą +STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Negalima pridėti failo: pasikartojantis GRF ID +STR_NEWGRF_NOT_FOUND :{RED}Atitinkamas failas nerastas +STR_NEWGRF_DISABLED :{RED}Uždrausta STR_CURRENCY_WINDOW :{WHITE}Pasirinkti valiuta STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Keitimo santykis: {ORANGE}{CURRENCY} = £ {COMMA} @@ -2818,20 +2944,35 @@ STR_SCHEDULED_AIRCRAFT_TIP :{BLACK}Rodyti visus lektuvus, kuriu uzduotyse yra pamineta si stotele STR_SCHEDULED_SHIPS_TIP :{BLACK}Rodyti visus laivus, kuriu uzduotyse yra pamineta si stotele +STR_VEH_WITH_SHARED_ORDERS_LIST :{WHITE}Nurodymais dalijasi {COMMA} tr. priemon{P ė ės ių} +STR_VEH_WITH_SHARED_ORDERS_LIST_TIP :{BLACK}Parodyti visas tr. priemones, kurios dalijasi šiais nurodymais ### depot strings - -STR_SELL :{BLACK}Parduoti - +STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Ar tikrai norite parduoti visas tr. priemones esančias šiame depe? - +STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP :{BLACK}Parduoti visus traukinius šiame depe +STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP :{BLACK}Parduoti visus automobilius šiame depe +STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP :{BLACK}Parduoti visus laivus šiame depe +STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP :{BLACK}Parduoti visus lėktuvus šiame angare +STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP :{BLACK}Gauti sąrašą visų traukinių turiunčių nurodymuose šį depą +STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP :{BLACK}Gauti sąrašą visų automobilių turiunčių nurodymuose šį depą +STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP :{BLACK}Gauti sąrašą visų laivų turiunčių nurodymuose šį depą +STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP :{BLACK}Gauti sąrašą visų lėktuvų turiunčių nurodymuose šį angarą +STR_DEPOT_AUTOREPLACE_TRAIN_TIP :{BLACK}Pakeisti visus traukinius depe +STR_DEPOT_AUTOREPLACE_ROADVEH_TIP :{BLACK}Pakeisti automobilius traukinius depe +STR_DEPOT_AUTOREPLACE_SHIP_TIP :{BLACK}Pakeisti visus laivus depe +STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP :{BLACK}Pakeisti visus lėktuvus angare +STR_VEHICLE_LIST_TRAIN_DEPOT :{BLACK}{STRING} - {COMMA} traukin{P ys iai ių} +STR_VEHICLE_LIST_ROADVEH_DEPOT :{BLACK}{STRING} - {COMMA} automobil{P is iai ių} +STR_VEHICLE_LIST_SHIP_DEPOT :{BLACK}{STRING} - {COMMA} laiv{P as ai ų} +STR_VEHICLE_LIST_AIRCRAFT_DEPOT :{BLACK}{STRING} - {COMMA} lėktuv{P as ai ų} STR_REPLACE_VEHICLES_WHITE :{WHITE}Keisti tr. priemones {STRING} -STR_REPLACE_VEHICLES_START :{BLACK}Pradeti keitima -STR_REPLACE_VEHICLES_STOP :{BLACK}Sustabdyti keitima +STR_REPLACE_VEHICLES_START :{BLACK}Pradeti tr. priemonių keitimą +STR_REPLACE_VEHICLES_STOP :{BLACK}Stabdyti tr. priemonių keitimą STR_NOT_REPLACING :{BLACK}Nekeiciama STR_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Nera pazymeta nei viena tr. priemone STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Pasirink tr. priemones tipa, kuriuo reikes keisti @@ -2842,12 +2983,23 @@ STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Kaireje lango dalyje pazymeta tr. priemone bus pakeista tr. priemone, kuri yra pazymeta desineje lango puseje STR_REPLACE_HELP :{BLACK}Tai leidzia tau keisti viena tr. priemoniu tipa kitu, kai pirmojo tipo traukinys uzsuka i depa STR_REPLACE_REMOVE_WAGON :{BLACK}Vagono pasalinimas: {ORANGE}{SKIP}{STRING} +STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Pakeitimo metu išlaikyti traukinio ilgį atjungiant vagonus (pradedant juo priekio), jeigu pakeitus garvežį traukinys pailgėtų. STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Keicima: {ORANGE}{SKIP}{SKIP}{STRING} +STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK} EKSPERIMENTINĖ GALIMYBĖ {}Pereidinėti tarp garvežių ir vagonų pakeitimo langų.{}Vagonai bus pakeičiami tik tada, jeigu naujasis vagonas galės gabenti tą patį krovinio tipą kaip ir senasis. Tai atliekama patikrinant kiekvieną vagoną jo keitimo metu. STR_ENGINE_NOT_BUILDABLE :{WHITE}Variklio neimanoma pagaminti STR_ENGINES :Varikliai +STR_WAGONS :Vagonai +STR_MASS_STOP_DEPOT_TRAIN_TIP :{BLACK}Spragtelėkite norėdami sustabdyti visus traukinius esančius depe +STR_MASS_STOP_DEPOT_ROADVEH_TIP :{BLACK}Spragtelėkite norėdami sustabdyti visus automobilius esančius depe +STR_MASS_STOP_DEPOT_SHIP_TIP :{BLACK}Spragtelėkite norėdami sustabdyti visus laivus esančius depe +STR_MASS_STOP_HANGAR_TIP :{BLACK}Spragtelėkite norėdami sustabdyti visus lėktuvus esančius angare +STR_MASS_START_DEPOT_TRAIN_TIP :{BLACK}Spragtelėkite norėdami paleisti visus traukinius esančius depe +STR_MASS_START_DEPOT_ROADVEH_TIP :{BLACK}Spragtelėkite norėdami paleisti visus automobilius esančius depe +STR_MASS_START_DEPOT_SHIP_TIP :{BLACK}Spragtelėkite norėdami paleisti visus laivus esančius depe +STR_MASS_START_HANGAR_TIP :{BLACK}Spragtelėkite norėdami paleisti visus lėktuvus esančius angare STR_MASS_STOP_LIST_TIP :{BLACK}Paspauskite noredami sustabdyti automobilius is saraso STR_MASS_START_LIST_TIP :{BLACK}Paspauskite noredami paleisti automobilius is saraso @@ -2855,6 +3007,7 @@ STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_SIGN_LIST_CAPTION :{WHITE}Zenklu sarasas - {COMMA} Zenklai +STR_ORDER_REFIT_FAILED :{WHITE}Klaida pakeitimo metu {STRING} {COMMA} ############ Lists rail types @@ -2879,16 +3032,23 @@ STR_PURCHASE_INFO_COST_SPEED :{BLACK}Kaina: {GOLD}{CURRENCY}{BLACK} Greitis: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Talpa: {GOLD}{COMMA} keleiviu, {COMMA} pasto maisu STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Pajungta vagonu: {GOLD}+{POWER}{BLACK} Svoris: {GOLD}+{WEIGHT_S} +STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Pakeičiami į: {GOLD} +STR_PURCHASE_INFO_ALL_TYPES :Visus krovinių tipus +STR_PURCHASE_INFO_ALL_BUT :Visus, išskyrus {GOLD} +STR_PURCHASE_INFO_MAX_TE :{BLACK}Did. traukiamoji galia: {GOLD}{FORCE} ########### String for New Landscape Generator STR_GENERATE :{WHITE}Generuoti STR_RANDOM :{BLACK}Bet kaip STR_RANDOM_HELP :{BLACK}Pakeisti i bet koki Pasaulio Generavima +STR_WORLD_GENERATION_CAPTION :{WHITE}Pasaulio kūrimas STR_RANDOM_SEED :{BLACK}Bet koks: STR_RANDOM_SEED_HELP :{BLACK}Paspauskite noredami ivesti bet koki seed STR_LAND_GENERATOR :{BLACK}Pasaulio generatorius: +STR_TREE_PLACER :{BLACK}Medžių algoritmas: STR_HEIGHTMAP_ROTATION :{BLACK}Zemelapio rotacija: +STR_TERRAIN_TYPE :{BLACK}Vietovės tipas: STR_QUANTITY_OF_SEA_LAKES :{BLACK}Juros lygis: STR_SMOOTHNESS :{BLACK}Jautrumas: STR_SNOW_LINE_HEIGHT :{BLACK}Sniego linijos aukstis: @@ -2928,13 +3088,16 @@ STR_FLAT_WORLD_HEIGHT_UP :{BLACK}Pakelti lygios zemes lygi vienu lygiu STR_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Keisti lygumos auksti STR_FLAT_WORLD_HEIGHT :{BLACK}Lygumos aukstis: +STR_FLAT_WORLD_HEIGHT_NUM :{NUM} STR_SMALLMAP_CENTER :{BLACK}Centruoti maza zemelapi i sita vieta ########### String for new airports STR_SMALL_AIRPORT :{BLACK}Mazas +STR_CITY_AIRPORT :{BLACK}Miestas STR_METRO_AIRPORT :{BLACK}Metropoliteno orouostas STR_INTERNATIONAL_AIRPORT :{BLACK}Internacionalinis orouostas +STR_COMMUTER_AIRPORT :{BLACK}Rajonas STR_INTERCONTINENTAL_AIRPORT :{BLACK}Tarpkontinentinis STR_HELIPORT :{BLACK}Heliportas STR_HELIDEPOT :{BLACK}Helidepas @@ -2947,5 +3110,9 @@ ############ Tooltip measurment +STR_MEASURE_LENGTH :{BLACK}Atstumas: {NUM} +STR_MEASURE_AREA :{BLACK}Sritis: {NUM} x {NUM} +STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Atstumas: {NUM}{}Aukščių skirtumas: {NUM} m +STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Sritis: {NUM} x {NUM}{}Aukščių skirtumas: {NUM} m ######## diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/slovenian.txt --- a/lang/unfinished/slovenian.txt Tue Jan 02 18:40:37 2007 +0000 +++ b/lang/unfinished/slovenian.txt Wed Jan 03 08:32:17 2007 +0000 @@ -21,16 +21,16 @@ STR_000E : STR_000F_PASSENGERS :Potniki STR_0010_COAL :Premog -STR_0011_MAIL :Posta +STR_0011_MAIL :Pošta STR_0012_OIL :Nafta -STR_0013_LIVESTOCK :Zivina +STR_0013_LIVESTOCK :Živina STR_0014_GOODS :Dobrine -STR_0015_GRAIN :Zito +STR_0015_GRAIN :Žito STR_0016_WOOD :Les -STR_0017_IRON_ORE :Zelezova ruda +STR_0017_IRON_ORE :Železova ruda STR_0018_STEEL :Jeklo STR_0019_VALUABLES :Dragocenosti -STR_001A_COPPER_ORE :Bakrena ruda +STR_001A_COPPER_ORE :Bakrova ruda STR_001B_MAIZE :Koruza STR_001C_FRUIT :Sadje STR_001D_DIAMONDS :Diamanti @@ -38,31 +38,31 @@ STR_001F_PAPER :Papir STR_0020_GOLD :Zlato STR_0021_WATER :Voda -STR_0022_WHEAT :Psenica +STR_0022_WHEAT :Pšenica STR_0023_RUBBER :Guma STR_0024_SUGAR :Sladkor -STR_0025_TOYS :Igrace +STR_0025_TOYS :Igrače STR_0026_CANDY :Bonboni STR_0027_COLA :Cockta STR_0028_COTTON_CANDY :Sladkorna pena -STR_0029_BUBBLES :Mehurcki -STR_002A_TOFFEE :Karamele +STR_0029_BUBBLES :Mehurčki +STR_002A_TOFFEE :Karamela STR_002B_BATTERIES :Baterije STR_002C_PLASTIC :Plastika -STR_002D_FIZZY_DRINKS :Gazirane pijace +STR_002D_FIZZY_DRINKS :Gazirane pijače STR_002E : STR_002F_PASSENGER :Potnik STR_0030_COAL :Premog -STR_0031_MAIL :Posta +STR_0031_MAIL :Pošta STR_0032_OIL :Nafta -STR_0033_LIVESTOCK :Zivina -STR_0034_GOODS :Izdelki -STR_0035_GRAIN :Zito +STR_0033_LIVESTOCK :Živina +STR_0034_GOODS :Dobrine +STR_0035_GRAIN :Žito STR_0036_WOOD :Les -STR_0037_IRON_ORE :Zelezova ruda +STR_0037_IRON_ORE :Železova ruda STR_0038_STEEL :Jeklo STR_0039_VALUABLES :Dragocenosti -STR_003A_COPPER_ORE :Bakrena ruda +STR_003A_COPPER_ORE :Bakrova ruda STR_003B_MAIZE :Koruza STR_003C_FRUIT :Sadje STR_003D_DIAMOND :Diamanti @@ -70,18 +70,18 @@ STR_003F_PAPER :Papir STR_0040_GOLD :Zlato STR_0041_WATER :Voda -STR_0042_WHEAT :psenica +STR_0042_WHEAT :Pšenica STR_0043_RUBBER :Guma STR_0044_SUGAR :Sladkor -STR_0045_TOY :Igrace +STR_0045_TOY :Igrače STR_0046_CANDY :Bombon STR_0047_COLA :Cockta STR_0048_COTTON_CANDY :Sladkorna pena -STR_0049_BUBBLE :Mehurcki +STR_0049_BUBBLE :Mehurčki STR_004A_TOFFEE :Karamela STR_004B_BATTERY :Baterija STR_004C_PLASTIC :Plastika -STR_004D_FIZZY_DRINK :Gazirana pijaca +STR_004D_FIZZY_DRINK :Gazirana pijača STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA} potnikov STR_QUANTITY_COAL :{WEIGHT} ton premoga @@ -90,6 +90,7 @@ STR_QUANTITY_LIVESTOCK :{COMMA} glav zivine STR_QUANTITY_GOODS :{COMMA} paketov dobrin STR_QUANTITY_GRAIN :{WEIGHT} ton zita +STR_QUANTITY_WOOD :{WEIGHT} lesa STR_QUANTITY_IRON_ORE :{WEIGHT} ton zelezove rude STR_QUANTITY_STEEL :{WEIGHT} ton jekla STR_QUANTITY_VALUABLES :{COMMA} vrec dragocenosti @@ -119,17 +120,17 @@ STR_ABBREV_MAIL :{TINYFONT}PS STR_ABBREV_OIL :{TINYFONT}NF STR_ABBREV_LIVESTOCK :{TINYFONT}ZV -STR_ABBREV_GOODS :{TINYFONT}TO +STR_ABBREV_GOODS :{TINYFONT}DO STR_ABBREV_GRAIN :{TINYFONT}ZT STR_ABBREV_WOOD :{TINYFONT}LS -STR_ABBREV_IRON_ORE :{TINYFONT}ZZ +STR_ABBREV_IRON_ORE :{TINYFONT}ZR STR_ABBREV_STEEL :{TINYFONT}JK STR_ABBREV_VALUABLES :{TINYFONT}DR STR_ABBREV_COPPER_ORE :{TINYFONT}BK STR_ABBREV_MAIZE :{TINYFONT}KZ STR_ABBREV_FRUIT :{TINYFONT}SJ STR_ABBREV_DIAMONDS :{TINYFONT}DM -STR_ABBREV_FOOD :{TINYFONT}HR +STR_ABBREV_FOOD :{TINYFONT}ZI STR_ABBREV_PAPER :{TINYFONT}PR STR_ABBREV_GOLD :{TINYFONT}ZL STR_ABBREV_WATER :{TINYFONT}VO @@ -137,25 +138,28 @@ STR_ABBREV_RUBBER :{TINYFONT}GU STR_ABBREV_SUGAR :{TINYFONT}SK STR_ABBREV_TOYS :{TINYFONT}IG -STR_ABBREV_SWEETS :{TINYFONT}BB -STR_ABBREV_COLA :{TINYFONT}CL +STR_ABBREV_SWEETS :{TINYFONT}SL +STR_ABBREV_COLA :{TINYFONT}CK STR_ABBREV_CANDYFLOSS :{TINYFONT}SP -STR_ABBREV_BUBBLES :{TINYFONT}BL -STR_ABBREV_TOFFEE :{TINYFONT}KA +STR_ABBREV_BUBBLES :{TINYFONT}MH +STR_ABBREV_TOFFEE :{TINYFONT}TF STR_ABBREV_BATTERIES :{TINYFONT}BA STR_ABBREV_PLASTIC :{TINYFONT}PL STR_ABBREV_FIZZY_DRINKS :{TINYFONT}GP +STR_ABBREV_NONE :{TINYFONT}NO +STR_ABBREV_ALL :{TINYFONT}VSE STR_00AE :{WHITE}{DATE_SHORT} STR_00AF :{WHITE}{DATE_LONG} -STR_00B0_MAP :{WHITE}Mapa - {STRING} -STR_00B1_GAME_OPTIONS :{WHITE}Moznosti Igre -STR_00B2_MESSAGE :{YELLOW}Sporocilo -STR_00B3_MESSAGE_FROM :{YELLOW}Sporocilo od {STRING} -STR_00B4_CAN_T_DO_THIS :{WHITE}Ne mores narediti tega... -STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Ne mores ocistit tega podrocje... -STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Prvotne avtorske pravice {COPYRIGHT} 1995 Chris Sawyer, Vse pravice pridrzane -STR_00B7_VERSION :{BLACK}OpenTTD verzija {REV} -STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2005 OpenTTD ekipa +STR_00B0_MAP :{WHITE}Zemljevid - {STRING} +STR_00B1_GAME_OPTIONS :{WHITE}Možnosti Igre +STR_00B2_MESSAGE :{YELLOW}Sporočilo +STR_00B3_MESSAGE_FROM :{YELLOW}Sporočilo od {STRING} +STR_POPUP_CAUTION_CAPTION :{WHITE}Pozor! +STR_00B4_CAN_T_DO_THIS :{WHITE}Ne morem narediti tega ... +STR_00B5_CAN_T_CLEAR_THIS_AREA :{WHITE}Ne morem očistiti tega področja ... +STR_00B6_ORIGINAL_COPYRIGHT :{BLACK}Prvotne avtorske pravice {COPYRIGHT} 1995 Chris Sawyer, Vse pravice pridržane +STR_00B7_VERSION :{BLACK}OpenTTD različica {REV} +STR_00BA_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2006 ekipa OpenTTD STR_TRANSLATED_BY :{BLACK} Prevod - seba STR_00C5 :{BLACK}{CROSS} @@ -163,42 +167,42 @@ STR_00C7_QUIT :{WHITE}Izhod STR_00C8_YES :{BLACK}Da STR_00C9_NO :{BLACK}Ne -STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ali ste prepricani, da zelite zapustiti to igro in se vrniti v {STRING}? +STR_00CA_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ali ste prepričani, da želite zapustiti igro in se vrniti v {STRING}? STR_00CB_1 :{BLACK}1 STR_00CC_2 :{BLACK}2 STR_00CD_3 :{BLACK}3 STR_00CE_4 :{BLACK}4 STR_00CF_5 :{BLACK}5 -STR_00D0_NOTHING :Nic +STR_00D0_NOTHING :Nič STR_00D1_DARK_BLUE :Temno modra STR_00D2_PALE_GREEN :Svetlo zelena -STR_00D3_PINK :Roza +STR_00D3_PINK :Rožnata STR_00D4_YELLOW :Rumena -STR_00D5_RED :Rdeca +STR_00D5_RED :Rdeča STR_00D6_LIGHT_BLUE :Svetlo modra STR_00D7_GREEN :Zelena STR_00D8_DARK_GREEN :Temno zelena STR_00D9_BLUE :Modra STR_00DA_CREAM :Kremna STR_00DB_MAUVE :Slezenasta -STR_00DC_PURPLE :Vijola -STR_00DD_ORANGE :Oranzna +STR_00DC_PURPLE :Vijolična +STR_00DD_ORANGE :Oranžna STR_00DE_BROWN :Rjava STR_00DF_GREY :Siva STR_00E0_WHITE :Bela -STR_00E1_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Prevec vozil v igri +STR_00E1_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Preveč vozil v igri STR_00E2 :{BLACK}{COMMA} STR_00E3 :{RED}{COMMA} STR_00E4_LOCATION :{BLACK}Lokacija -STR_00E5_CONTOURS :Nacrt +STR_00E5_CONTOURS :Načrt STR_00E6_VEHICLES :Vozila STR_00E7_INDUSTRIES :Industrije STR_00E8_ROUTES :Poti STR_00E9_VEGETATION :Vegetacija STR_00EA_OWNERS :Lastniki STR_00EB_ROADS :{BLACK}{TINYFONT}Ceste -STR_00EC_RAILROADS :{BLACK}{TINYFONT}Zeleznice -STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Postaje/Letalisca/Pristanisca +STR_00EC_RAILROADS :{BLACK}{TINYFONT}Železnice +STR_00ED_STATIONS_AIRPORTS_DOCKS :{BLACK}{TINYFONT}Postaje/Letališča/Pristanišča STR_00EE_BUILDINGS_INDUSTRIES :{BLACK}{TINYFONT}Stavbe/Industrije STR_00EF_VEHICLES :{BLACK}{TINYFONT}Vozila STR_00F0_100M :{BLACK}{TINYFONT}100m @@ -214,42 +218,42 @@ STR_00FA_COAL_MINE :{BLACK}{TINYFONT}Rudnik premoga STR_00FB_POWER_STATION :{BLACK}{TINYFONT}Termoelektrarna STR_00FC_FOREST :{BLACK}{TINYFONT}Gozd -STR_00FD_SAWMILL :{BLACK}{TINYFONT}Zaga +STR_00FD_SAWMILL :{BLACK}{TINYFONT}Žaga STR_00FE_OIL_REFINERY :{BLACK}{TINYFONT}Naftna rafinerija STR_00FF_FARM :{BLACK}{TINYFONT}Kmetija STR_0100_FACTORY :{BLACK}{TINYFONT}Tovarna STR_0101_PRINTING_WORKS :{BLACK}{TINYFONT}Tiskarna -STR_0102_OIL_WELLS :{BLACK}{TINYFONT}Naftni izvir -STR_0103_IRON_ORE_MINE :{BLACK}{TINYFONT}Rudnik zeleza +STR_0102_OIL_WELLS :{BLACK}{TINYFONT}Naftno polje +STR_0103_IRON_ORE_MINE :{BLACK}{TINYFONT}Rudnik železa STR_0104_STEEL_MILL :{BLACK}{TINYFONT}Jeklarna STR_0105_BANK :{BLACK}{TINYFONT}Banka STR_0106_PAPER_MILL :{BLACK}{TINYFONT}Papirnica STR_0107_GOLD_MINE :{BLACK}{TINYFONT}Rudnik zlata -STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}Zivilska tovarna +STR_0108_FOOD_PROCESSING_PLANT :{BLACK}{TINYFONT}Predelava hrane STR_0109_DIAMOND_MINE :{BLACK}{TINYFONT}Rudnik diamantov STR_010A_COPPER_ORE_MINE :{BLACK}{TINYFONT}Rudnik bakra STR_010B_FRUIT_PLANTATION :{BLACK}{TINYFONT}Sadovnjak -STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Plantaza gume +STR_010C_RUBBER_PLANTATION :{BLACK}{TINYFONT}Plantaža gume STR_010D_WATER_SUPPLY :{BLACK}{TINYFONT}Vodni izvir STR_010E_WATER_TOWER :{BLACK}{TINYFONT}Vodni stolp -STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Zaga +STR_010F_LUMBER_MILL :{BLACK}{TINYFONT}Žaga STR_0110_COTTON_CANDY_FOREST :{BLACK}{TINYFONT}Gozd sladkorne pene -STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}Tovarna slascic +STR_0111_CANDY_FACTORY :{BLACK}{TINYFONT}Tovarna slaščic STR_0112_BATTERY_FARM :{BLACK}{TINYFONT}Farma baterij -STR_0113_COLA_WELLS :{BLACK}{TINYFONT}Izvir cockte -STR_0114_TOY_SHOP :{BLACK}{TINYFONT}Trgovina z igracami -STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}Tovarna igrac +STR_0113_COLA_WELLS :{BLACK}{TINYFONT}Izvir Cockte +STR_0114_TOY_SHOP :{BLACK}{TINYFONT}Trgovina z igračami +STR_0115_TOY_FACTORY :{BLACK}{TINYFONT}Tovarna igrač STR_0116_PLASTIC_FOUNTAINS :{BLACK}{TINYFONT}Vodnjaki plastike -STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}Tovarna gaziranih pijac -STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}Generator balonckov +STR_0117_FIZZY_DRINK_FACTORY :{BLACK}{TINYFONT}Tovarna gaziranih pijač +STR_0118_BUBBLE_GENERATOR :{BLACK}{TINYFONT}Generator balončkov STR_0119_TOFFEE_QUARRY :{BLACK}{TINYFONT}Jama karamele STR_011A_SUGAR_MINE :{BLACK}{TINYFONT}Rudnik sladkorja -STR_011B_RAILROAD_STATION :{BLACK}{TINYFONT}Zelezniska postaja -STR_011C_TRUCK_LOADING_BAY :{BLACK}{TINYFONT}Distribucijsko obmocje za tovornjake +STR_011B_RAILROAD_STATION :{BLACK}{TINYFONT}Železniška postaja +STR_011C_TRUCK_LOADING_BAY :{BLACK}{TINYFONT}Distribucijsko območje za tovornjake STR_011D_BUS_STATION :{BLACK}{TINYFONT}Avtobusna postaja -STR_011E_AIRPORT_HELIPORT :{BLACK}{TINYFONT}Letalisce/Heliport -STR_011F_DOCK :{BLACK}{TINYFONT}Pristanisce -STR_0120_ROUGH_LAND :{BLACK}{TINYFONT}Neravna tla +STR_011E_AIRPORT_HELIPORT :{BLACK}{TINYFONT}Letališče/Heliport +STR_011F_DOCK :{BLACK}{TINYFONT}Pristanišče +STR_0120_ROUGH_LAND :{BLACK}{TINYFONT}Groba tla STR_0121_GRASS_LAND :{BLACK}{TINYFONT}Travnata tla STR_0122_BARE_LAND :{BLACK}{TINYFONT}Gola tla STR_0123_FIELDS :{BLACK}{TINYFONT}Polja @@ -259,15 +263,15 @@ STR_0127_NO_OWNER :{BLACK}{TINYFONT}Brez lastnika STR_0128_TOWNS :{BLACK}{TINYFONT}Mesta STR_0129_INDUSTRIES :{BLACK}{TINYFONT}Industrije -STR_012A_DESERT :{BLACK}{TINYFONT}Puscava +STR_012A_DESERT :{BLACK}{TINYFONT}Puščava STR_012B_SNOW :{BLACK}{TINYFONT}Sneg -STR_012C_MESSAGE :{WHITE}Sporocilo +STR_012C_MESSAGE :{WHITE}Sporočilo STR_012D :{WHITE}{STRING} -STR_012E_CANCEL :{BLACK}Preklici +STR_012E_CANCEL :{BLACK}Prekliči STR_012F_OK :{BLACK}Potrdi STR_0130_RENAME :{BLACK}Preimenuj -STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Prevec definiranih imen -STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Izbrano ime je ze v uporabi +STR_0131_TOO_MANY_NAMES_DEFINED :{WHITE}Preveč definiranih imen +STR_0132_CHOSEN_NAME_IN_USE_ALREADY :{WHITE}Izbrano ime je že v uporabi STR_0133_WINDOWS :Windows STR_0134_UNIX :Unix @@ -277,16 +281,18 @@ STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 -STR_013B_OWNED_BY :{WHITE}...pripada {STRING} +STR_013B_OWNED_BY :{WHITE} ... pripada {STRING} STR_013C_CARGO :{BLACK}Tovor STR_013D_INFORMATION :{BLACK}Informacije -STR_013E_CAPACITIES :{BLACK}Sposobnost +STR_013E_CAPACITIES :{BLACK}Kapacitete STR_013E_TOTAL_CARGO :{BLACK}Skupni tovor -STR_013F_CAPACITY :{BLACK}Sposobnost: {LTBLUE}{CARGO} -STR_013F_TOTAL_CAPACITY_TEXT :{BLACK}Skupna tovorna sposobnost tega vlaka: +STR_013F_CAPACITY :{BLACK}Kapaciteta: {LTBLUE}{CARGO} +STR_CAPACITY_MULT :{BLACK}Kapaciteta: {LTBLUE}{CARGO} (x{NUM}) +STR_013F_TOTAL_CAPACITY_TEXT :{BLACK}Skupna tovorna kapaciteta tega vlaka: STR_013F_TOTAL_CAPACITY :{LTBLUE}- {CARGO} ({SHORTCARGO}) +STR_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO} ({SHORTCARGO}) (x{NUM}) STR_0140_NEW_GAME :{BLACK}Nova igra -STR_0141_LOAD_GAME :{BLACK}Nalozi igro +STR_0141_LOAD_GAME :{BLACK}Naloži igro STR_SINGLE_PLAYER :{BLACK}En igralec STR_MULTIPLAYER :{BLACK}Vec igralcev @@ -298,10 +304,10 @@ STR_2048 :2048 STR_MAPSIZE :{BLACK}Velikost mape: STR_BY :{BLACK}* -STR_0148_GAME_OPTIONS :{BLACK}Moznosti +STR_0148_GAME_OPTIONS :{BLACK}Možnosti STR_0150_SOMEONE :nekdo{SKIP}{SKIP} -STR_0151_MAP_OF_WORLD :Mapa sveta +STR_0151_MAP_OF_WORLD :Zemljevid sveta STR_0152_TOWN_DIRECTORY :Imenik mest STR_0153_SUBSIDIES :Subvencije @@ -321,36 +327,39 @@ STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg -STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P "" s} -STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton{P "" s} +STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton +STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ -STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} galon{P "" s} -STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litrov{P "" s} +STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} galonov +STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litrov STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ +STR_UNITS_FORCE_IMPERIAL :{COMMA}x10³ lbf +STR_UNITS_FORCE_METRIC :{COMMA} ton sile +STR_UNITS_FORCE_SI :{COMMA} kN ############ range for menu starts -STR_0154_OPERATING_PROFIT_GRAPH :Graf dobicka +STR_0154_OPERATING_PROFIT_GRAPH :Graf dobička STR_0155_INCOME_GRAPH :Graf prihodkov STR_0156_DELIVERED_CARGO_GRAPH :Graf dostavljenega tovora STR_0157_PERFORMANCE_HISTORY_GRAPH :Graf zgodovine dela STR_0158_COMPANY_VALUE_GRAPH :Graf vrednosti podjetja -STR_0159_CARGO_PAYMENT_RATES :Graf placila tovora +STR_0159_CARGO_PAYMENT_RATES :Graf plačila za tovor STR_015A_COMPANY_LEAGUE_TABLE :Tabela lige podjetij STR_PERFORMANCE_DETAIL_MENU :Podrobna delavna ocena ############ range for menu ends STR_015B_OPENTTD :{WHITE}O OpenTTD STR_015C_SAVE_GAME :Shrani igro -STR_015D_LOAD_GAME :Nalozi igro +STR_015D_LOAD_GAME :Naloži igro STR_015E_QUIT_GAME :Zapusti igro STR_015F_QUIT :Izhod -STR_0160_ARE_YOU_SURE_YOU_WANT_TO :{YELLOW}Ali ste prepricani, da hocete zapustiti to igro? +STR_ABANDON_GAME_QUERY :{YELLOW}Ali ste prepričani, da želite zapustiti igro? STR_0161_QUIT_GAME :{WHITE}Zapusti igro STR_SORT_ORDER_TIP :{BLACK}Izberi nacin sortiranja (padajoce/narascujoce) STR_SORT_CRITERIA_TIP :{BLACK}Izberi kriterij za sortiranje @@ -370,6 +379,22 @@ STR_SORT_BY_RELIABILITY :Zanesljivost STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Skupna sposobnost po tipu tovora STR_SORT_BY_MAX_SPEED :Najvecja hitrost +STR_SORT_BY_MODEL :Model +STR_SORT_BY_VALUE :Vrednost +STR_SORT_BY_FACILITY :Tip postaje +STR_SORT_BY_WAITING :Čakanje vrednosti tovora +STR_SORT_BY_RATING_MAX :Ocene tovora +STR_ENGINE_SORT_ENGINE_ID :ID motorja (klasično urejanje) +STR_ENGINE_SORT_COST :Cena +STR_ENGINE_SORT_POWER :Moč +STR_ENGINE_SORT_INTRO_DATE :Datum vstopa +STR_ENGINE_SORT_RUNNING_COST :Stroški obratovanja +STR_ENGINE_SORT_POWER_VS_RUNNING_COST :Moč/Stroški obratovanja +STR_ENGINE_SORT_CARGO_CAPACITY :Kapaciteta tovora +STR_NO_WAITING_CARGO :{BLACK}Noben tovor ne čaka +STR_SELECT_ALL_FACILITIES :{BLACK}Izberi vse pripomočke +STR_SELECT_ALL_TYPES :{BLACK}Izberi vse vrste tovora (vključno z nobenega čakanja) +STR_AVAILABLE_ENGINES_TIP :{BLACK}Prikaži seznam motorjev na voljo za ta tip vozila. ############ range for months starts STR_0162_JAN :Jan @@ -391,48 +416,48 @@ STR_0170 :{TINYFONT}{STRING}- STR_0171_PAUSE_GAME :{BLACK}Pavza STR_0172_SAVE_GAME_ABANDON_GAME :{BLACK}Shrani igro, zapusti igro, izhod -STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikazi seznam postaj podjetja -STR_0174_DISPLAY_MAP :{BLACK}Prikazi mapo -STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Prikazi mapo, imenik mest -STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}Prikazi imenik mest -STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}Prikazi financne podatke podjetja -STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}Prikazi splosne podatke podjetja -STR_0179_DISPLAY_GRAPHS :{BLACK}Prikazi grafe -STR_017A_DISPLAY_COMPANY_LEAGUE :{BLACK}Prikazi tabelo lige podjetij -STR_017B_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikazi seznam vlakov podjetja -STR_017C_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikazi seznam cestnih vozil podjetja -STR_017D_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikazi seznam ladij podjetja -STR_017E_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikazi seznam letal podjetja -STR_017F_ZOOM_THE_VIEW_IN :{BLACK}Priblizaj pogled +STR_0173_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikaži seznam postaj podjetja +STR_0174_DISPLAY_MAP :{BLACK}Prikaži zemljevid +STR_0175_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Prikaži zemljevid, imenik mest +STR_0176_DISPLAY_TOWN_DIRECTORY :{BLACK}Prikaži imenik mest +STR_0177_DISPLAY_COMPANY_FINANCES :{BLACK}Prikaži finančne podatke podjetja +STR_0178_DISPLAY_COMPANY_GENERAL :{BLACK}Prikaži splošne podatke podjetja +STR_0179_DISPLAY_GRAPHS :{BLACK}Prikaži grafe +STR_017A_DISPLAY_COMPANY_LEAGUE :{BLACK}Prikaži tabelo lige podjetij +STR_017B_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikaži seznam vlakov podjetja +STR_017C_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikaži seznam cestnih vozil podjetja +STR_017D_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikaži seznam ladij podjetja +STR_017E_DISPLAY_LIST_OF_COMPANY :{BLACK}Prikaži seznam letal podjetja +STR_017F_ZOOM_THE_VIEW_IN :{BLACK}Približaj pogled STR_0180_ZOOM_THE_VIEW_OUT :{BLACK}Oddalji pogled -STR_0181_BUILD_RAILROAD_TRACK :{BLACK}Postavi zelezniske tire +STR_0181_BUILD_RAILROAD_TRACK :{BLACK}Postavi železniške tire STR_0182_BUILD_ROADS :{BLACK}Zgradi ceste -STR_0183_BUILD_SHIP_DOCKS :{BLACK}Zgradi pristanisca -STR_0184_BUILD_AIRPORTS :{BLACK}Zgradi letalisca +STR_0183_BUILD_SHIP_DOCKS :{BLACK}Zgradi pristanišča +STR_0184_BUILD_AIRPORTS :{BLACK}Zgradi letališča STR_0185_PLANT_TREES_PLACE_SIGNS :{BLACK}Posadi drevesa, postavi znake ipd. STR_0186_LAND_BLOCK_INFORMATION :{BLACK}Informacije o terenu -STR_0187_OPTIONS :{BLACK}Moznosti +STR_0187_OPTIONS :{BLACK}Možnosti STR_0188 :{BLACK}{SMALLUPARROW} STR_0189 :{BLACK}{SMALLDOWNARROW} -STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}Ne morem spremeniti interval servisiranja... +STR_018A_CAN_T_CHANGE_SERVICING :{WHITE}Ne morem spremeniti intervala servisiranja ... STR_018B_CLOSE_WINDOW :{BLACK}Zapri okno -STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}Naslov okna - premakni to, da premaknes okno +STR_018C_WINDOW_TITLE_DRAG_THIS :{BLACK}Naslov okna - primi in vleci, da premakneš okno STR_STICKY_BUTTON :{BLACK}Oznaci to okno za nezapirljivo z 'Zapri vsa okna' tipko STR_RESIZE_BUTTON :{BLACK}Klikni in dragaj to, da zmanjsas okno STR_SAVELOAD_HOME_BUTTON :{BLACK}Klikni tukaj za skok na mapo shrani/naloži -STR_018D_DEMOLISH_BUILDINGS_ETC :{BLACK}Podri zgradbe itd. na kvadratu zemlje -STR_018E_LOWER_A_CORNER_OF_LAND :{BLACK}Znizaj rob teren -STR_018F_RAISE_A_CORNER_OF_LAND :{BLACK}Zvisaj rob teren +STR_018D_DEMOLISH_BUILDINGS_ETC :{BLACK}Podri zgradbe itd. na kvadratku zemlje +STR_018E_LOWER_A_CORNER_OF_LAND :{BLACK}Znižaj rob terena +STR_018F_RAISE_A_CORNER_OF_LAND :{BLACK}Zvišaj rob terena STR_0190_SCROLL_BAR_SCROLLS_LIST :{BLACK}Drsnik - premakne seznam gor/dol STR_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Skrol-bar - skrolaj seznam levo/desno -STR_0191_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Pokazi nacrt terena na zemljevidu -STR_0192_SHOW_VEHICLES_ON_MAP :{BLACK}Pokazi vozila na zemljevidu -STR_0193_SHOW_INDUSTRIES_ON_MAP :{BLACK}Pokazi industrije na zemljevidu -STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Pokazi transportne poti na zemljevidu -STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}Pokazi vegetacijo na zemljevidu -STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Pokazi lastnike terena na zemljevidu -STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Vkljuci/izkljuci imena mest na zemljevidu -STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Prihodek to leto: {CURRENCY} (prejsnje leto: {CURRENCY}) +STR_0191_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Pokaži načrt terena na zemljevidu +STR_0192_SHOW_VEHICLES_ON_MAP :{BLACK}Pokaži vozila na zemljevidu +STR_0193_SHOW_INDUSTRIES_ON_MAP :{BLACK}Pokaži industrije na zemljevidu +STR_0194_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Pokaži transportne poti na zemljevidu +STR_0195_SHOW_VEGETATION_ON_MAP :{BLACK}Pokaži vegetacijo na zemljevidu +STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Pokaži lastnike terena na zemljevidu +STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Vključi/izključi imena mest na zemljevidu +STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Prihodki to leto: {CURRENCY} (prejšnje leto: {CURRENCY}) ############ range for service numbers starts STR_AGE :{COMMA} let{P o ""} ({COMMA}) @@ -445,14 +470,14 @@ STR_019F_TRAIN :Vlak STR_01A0_IS_GETTING_OLD :{WHITE}{STRING} {COMMA} postaja staro STR_01A1_IS_GETTING_VERY_OLD :{WHITE}{STRING} {COMMA} postaja zelo staro -STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} postaja zelo star in nujno rabi zamenjavo -STR_01A3_LAND_AREA_INFORMATION :{WHITE}Informacije o zemlji -STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Cena za ocistit: {LTBLUE}N/A -STR_01A5_COST_TO_CLEAR :{BLACK}Cena za ocistit: {LTBLUE}{CURRENCY} -STR_01A6_N_A :N/A +STR_01A2_IS_GETTING_VERY_OLD_AND :{WHITE}{STRING} {COMMA} postaja zelo staro in nujno potrebuje zamenjavo +STR_01A3_LAND_AREA_INFORMATION :{WHITE}Informacije o zemljišču +STR_01A4_COST_TO_CLEAR_N_A :{BLACK}Cena za čiščenje: {LTBLUE}N/A +STR_01A5_COST_TO_CLEAR :{BLACK}Cena za čiščenje: {LTBLUE}{CURRENCY} +STR_01A6_N_A :Ni na voljo STR_01A7_OWNER :{BLACK}Lastnik: {LTBLUE}{STRING} STR_01A8_LOCAL_AUTHORITY :{BLACK}Lokalna oblast: {LTBLUE}{STRING} -STR_01A9_NONE :Noben +STR_01A9_NONE :Nihče STR_01AA_NAME :{BLACK}Ime STR_01AB :{BLACK}{TINYFONT}{STRING} @@ -497,7 +522,7 @@ STR_01D1_8 :({COMMA}/8 {STRING}) STR_01D2_JAZZ_JUKEBOX :{WHITE}Jazz Jukebox STR_01D3_SOUND_MUSIC :Zvok/glasba -STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Pokaži okno za zvok/glasbo +STR_01D4_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Prikaži okno za zvok/glasbo STR_01D5_ALL :{TINYFONT}Vsi STR_01D6_OLD_STYLE :{TINYFONT}Star stil STR_01D7_NEW_STYLE :{TINYFONT}Novi stil @@ -507,23 +532,23 @@ STR_01DB_MUSIC_VOLUME :{BLACK}{TINYFONT}Glasnost glasbe STR_01DC_EFFECTS_VOLUME :{BLACK}{TINYFONT}Glasnost zvokov STR_01DD_MIN_MAX :{BLACK}{TINYFONT}MIN ' ' ' ' ' ' MAX -STR_01DE_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skoci na prejsno skladbo v izboru -STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Presckoci na naslednjo skladbo v izboru +STR_01DE_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skoči na prejšnjo skladbo v izboru +STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Preskoči na naslednjo skladbo v izboru STR_01E0_STOP_PLAYING_MUSIC :{BLACK}Ustavi glasbo STR_01E1_START_PLAYING_MUSIC :{BLACK}Predvajaj glasbo -STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Povleci drsnike za nastavitev glasnosti glasbe in zvokov +STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Premikaj drsnike za nastavitev glasnosti glasbe in zvokov STR_01E3 :{DKGREEN}{TINYFONT}-- STR_01E4_0 :{DKGREEN}{TINYFONT}0{COMMA} STR_01E5 :{DKGREEN}{TINYFONT}{COMMA} STR_01E6 :{DKGREEN}{TINYFONT}------ STR_01E7 :{DKGREEN}{TINYFONT}"{STRING}" -STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}Skladba{SETX 88}Title -STR_01E9_SHUFFLE :{TINYFONT}Mesaj +STR_01E8_TRACK_XTITLE :{BLACK}{TINYFONT}Skladba{SETX 88}Naslov +STR_01E9_SHUFFLE :{TINYFONT}Zmešaj STR_01EA_PROGRAM :{TINYFONT}{BLACK}Program STR_01EB_MUSIC_PROGRAM_SELECTION :{WHITE}Izbor glasbenega programa STR_01EC_0 :{TINYFONT}{LTBLUE}0{COMMA} "{STRING}" STR_01ED :{TINYFONT}{LTBLUE}{COMMA} "{STRING}" -STR_01EE_TRACK_INDEX :{TINYFONT}{BLACK}Spisek skladb +STR_01EE_TRACK_INDEX :{TINYFONT}{BLACK}Seznam skladb STR_01EF_PROGRAM :{TINYFONT}{BLACK}Program - '{STRING}' STR_01F0_CLEAR :{TINYFONT}{BLACK}Zbriši STR_01F1_SAVE :{TINYFONT}{BLACK}Shrani @@ -533,39 +558,48 @@ STR_01F5_SELECT_NEW_STYLE_MUSIC :{BLACK}Izberi glasbeni program 'novi stil' STR_01F6_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Izberi glasbeni program 'po meri 1' STR_01F7_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Izberi glasbeni program 'po meri 2' -STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Zbriši trenuten glasbeni program (samo po meri 1 in 2) +STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Zbriši trenutni glasbeni program (samo po meri 1 in 2) STR_01F9_SAVE_MUSIC_SETTINGS :{BLACK}Shrani glasbene nastavitve -STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Klikni na skladbo da jo dodats na trenutni program (samo po meri 1 in 2) -STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Preklapljaj Mesaj on/off +STR_01FA_CLICK_ON_MUSIC_TRACK_TO :{BLACK}Kliknite na skladbo, če jo želite dodati na trenutni program (samo po meri 1 in 2) +STR_CLICK_ON_TRACK_TO_REMOVE :{BLACK}Kliknite na skladbo, če jo želite odstraniti iz programa (samo Poljubno1 ali Poljubno2) +STR_01FB_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Preklapljaj zmešan program vključeno/izključeno STR_01FC_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Pokaži okno z izborom glasbe -STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikni na servis za centrirat pogled na industrijo/mesto +STR_01FD_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Kliknite na storitev za pogled na industrijo/mesto STR_01FE_DIFFICULTY :{BLACK}Težavnost ({STRING}) STR_01FF :{TINYFONT}{BLACK}{DATE_LONG} -STR_0200_LAST_MESSAGE_NEWS_REPORT :Zadnje sporocilo/novica -STR_0201_MESSAGE_SETTINGS :Nastavitve sporocil -STR_0203_SHOW_LAST_MESSAGE_NEWS :{BLACK}Prikazi zadnje sporocilo/novico, prikazi moznosti sporocil -STR_0204_MESSAGE_OPTIONS :{WHITE}Moznosti Sporocil -STR_0205_MESSAGE_TYPES :{BLACK} -STR_0206_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Prihod prvega vozila na igralcevo postajo +STR_0200_LAST_MESSAGE_NEWS_REPORT :Zadnje sporočilo/novica +STR_0201_MESSAGE_SETTINGS :Nastavitve sporočil +STR_MESSAGE_HISTORY_MENU :Zgodovina sporočil +STR_0203_SHOW_LAST_MESSAGE_NEWS :{BLACK}Prikaži zadnje sporočilo/novico, prikaži možnosti sporočil +STR_0204_MESSAGE_OPTIONS :{WHITE}Možnosti Sporočil +STR_0205_MESSAGE_TYPES :{BLACK}Tipi sporočil: +STR_0206_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Prihod prvega vozila na igralčevo postajo STR_0207_ARRIVAL_OF_FIRST_VEHICLE :{YELLOW}Prihod prvega vozila na nasprotnikovo postajo +STR_0208_ACCIDENTS_DISASTERS :{YELLOW}Nesreče / katastrofe STR_0209_COMPANY_INFORMATION :{YELLOW}Informacije o podjetju STR_020A_ECONOMY_CHANGES :{YELLOW}Ekonomske spremembe -STR_020B_ADVICE_INFORMATION_ON_PLAYER :{YELLOW}Nasvet / informacija o igralcevem vozilu -STR_020C_NEW_VEHICLES :{YELLOW}Novo vozilo -STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Spremebe sprejemanja tovora +STR_020B_ADVICE_INFORMATION_ON_PLAYER :{YELLOW}Nasveti / informacije o igralčevem vozilu +STR_020C_NEW_VEHICLES :{YELLOW}Odkrito novo vozilo +STR_020D_CHANGES_OF_CARGO_ACCEPTANCE :{YELLOW}Spremebe v sprejemanju tovora STR_020E_SUBSIDIES :{YELLOW}Subvencije -STR_020F_GENERAL_INFORMATION :{YELLOW}Glavne Informacije -STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE}...predalec od prejsne destinacije -STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Najboljsa podjetja, ki so dosegla {NUM}{}({STRING} stopnjo) +STR_020F_GENERAL_INFORMATION :{YELLOW}Splošne Informacije +STR_MESSAGES_ALL :{YELLOW}Nastavi prikaz vseh sporočil na: Izključen / Povzetek / Poln +STR_MESSAGE_SOUND :{YELLOW}Zaigraj zvok ob povzetku novega sporočila +STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO :{WHITE} ... predaleč od prejšnjega cilja +STR_0211_TOP_COMPANIES_WHO_REACHED :{BIGFONT}{BLACK}Najboljša podjetja, ki so dosegla {NUM}{}({STRING} stopnjo) +STR_TOP_COMPANIES_NETWORK_GAME :{BIGFONT}{BLACK}Seznam najboljših podjetij v {NUM} STR_0212 :{BIGFONT}{COMMA}. -STR_0213_BUSINESSMAN :Poslovnez +STR_0213_BUSINESSMAN :Poslovnež STR_0214_ENTREPRENEUR :Podjetnik -STR_0215_INDUSTRIALIST :Industrijalist +STR_0215_INDUSTRIALIST :Industrijalec STR_0216_CAPITALIST :Kapitalist STR_0217_MAGNATE :Magnat STR_0218_MOGUL :Vladar -STR_021B_ACHIEVES_STATUS :{BLACK}{BIGFONT}{COMPANY} doseze '{STRING}' status! -STR_021C_OF_ACHIEVES_STATUS :{WHITE}{BIGFONT}{PLAYERNAME} iz {COMPANY} je dosegel '{STRING}' status! +STR_0219_TYCOON_OF_THE_CENTURY :Velekapitalist stoletja +STR_HIGHSCORE_NAME :{BIGFONT}{PLAYERNAME}, {COMPANY} +STR_HIGHSCORE_STATS :{BIGFONT}'{STRING}' ({COMMA}) +STR_021B_ACHIEVES_STATUS :{BLACK}{BIGFONT}{COMPANY} doseže naslov '{STRING}'! +STR_021C_OF_ACHIEVES_STATUS :{WHITE}{BIGFONT}{PLAYERNAME} iz podjetja {COMPANY} je dosegel naslov '{STRING}'! STR_021F :{BLUE}{COMMA} STR_0220_CREATE_SCENARIO :{BLACK}Ustvari Scenarij STR_0221_OPENTTD :{YELLOW}OpenTTD @@ -573,211 +607,247 @@ STR_0223_LAND_GENERATION :{WHITE}Generator terena STR_0224 :{BLACK}{UPARROW} STR_0225 :{BLACK}{DOWNARROW} -STR_0226_RANDOM_LAND :{BLACK}Nakljucna zemlja +STR_0226_RANDOM_LAND :{BLACK}Naključni teren STR_0227_RESET_LAND :{BLACK}Ponastavi teren -STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Povecaj obmocje za nizanje/visanje terena -STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Zmanjsaj obmocje za nizanje/visanje terena -STR_022A_GENERATE_RANDOM_LAND :{BLACK}Zgeneriraj nakljucni teren +STR_0228_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Povečaj območje za nižanje/višanje terena +STR_0229_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Zmanjšaj območje za nižanje/višanje terena +STR_022A_GENERATE_RANDOM_LAND :{BLACK}Zgeneriraj naključni teren STR_022B_RESET_LANDSCAPE :{BLACK}Ponastavi pokrajino STR_022C_RESET_LANDSCAPE :{WHITE}Ponastavi pokrajino -STR_022D_ARE_YOU_SURE_YOU_WANT_TO :{WHITE}Ali si preprican, da hoces ponastaviti pokrajino +STR_LOAD_GAME_HEIGHTMAP :{WHITE}Uporabi višinsko karto +STR_LOAD_SCEN_HEIGHTMAP :{BLACK}Uporabi višinsko karto +STR_022D_ARE_YOU_SURE_YOU_WANT_TO :{WHITE}Ali ste prepričani, da želite ponastaviti pokrajino? STR_022E_LANDSCAPE_GENERATION :{BLACK}Generator pokrajine STR_022F_TOWN_GENERATION :{BLACK}Generator mest STR_0230_INDUSTRY_GENERATION :{BLACK}Generator industrije -STR_0231_ROAD_CONSTRUCTION :{BLACK}Grajenje cest +STR_0231_ROAD_CONSTRUCTION :{BLACK}Gradnja cest STR_0233_TOWN_GENERATION :{WHITE}Generator mest STR_0234_NEW_TOWN :{BLACK}Novo mesto STR_0235_CONSTRUCT_NEW_TOWN :{BLACK}Zgradi novo mesto -STR_0236_CAN_T_BUILD_TOWN_HERE :{WHITE}Nemores graditi mesta tukaj... -STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}...preblizu robu mape -STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}...preblizu drugemu mestu -STR_023A_TOO_MANY_TOWNS :{WHITE}...preveliko stevilo mest -STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}Povecaj velikost mesta -STR_023C_EXPAND :{BLACK}Povecaj -STR_023D_RANDOM_TOWN :{BLACK}Nakljucno mesto -STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Zgradi mesto na nakljucni lokaciji +STR_0236_CAN_T_BUILD_TOWN_HERE :{WHITE}Ne morete zgraditi mesta tukaj ... +STR_0237_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE} ... preblizu roba zemljevida +STR_0238_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE} ... preblizu drugemu mestu +STR_0239_SITE_UNSUITABLE :{WHITE} ... neprimerna lokacija +STR_023A_TOO_MANY_TOWNS :{WHITE} ... preveliko število mest +STR_CANNOT_GENERATE_TOWN :{WHITE}Ni mogoče zgraditi mest +STR_NO_SPACE_FOR_TOWN :{WHITE} ... ni več prostora na zemljevidu +STR_023B_INCREASE_SIZE_OF_TOWN :{BLACK}Povečaj velikost mesta +STR_023C_EXPAND :{BLACK}Razširi +STR_023D_RANDOM_TOWN :{BLACK}Naključno mesto +STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION :{BLACK}Zgradi mesto na naključni lokaciji STR_023F_INDUSTRY_GENERATION :{WHITE}Generator indrustrij STR_0240_COAL_MINE :{BLACK}Rudnik Premoga STR_0241_POWER_STATION :{BLACK}Termoelektrarna -STR_0242_SAWMILL :{BLACK}Zaga +STR_0242_SAWMILL :{BLACK}Žaga STR_0243_FOREST :{BLACK}Gozd STR_0244_OIL_REFINERY :{BLACK}Naftna rafinerija STR_0245_OIL_RIG :{BLACK}Naftne vrtine STR_0246_FACTORY :{BLACK}Tovarna STR_0247_STEEL_MILL :{BLACK}Jeklarna STR_0248_FARM :{BLACK}Kmetija -STR_0249_IRON_ORE_MINE :{BLACK}Rudnik zeleza +STR_0249_IRON_ORE_MINE :{BLACK}Rudnik železa STR_024A_OIL_WELLS :{BLACK}Naftni Vrelci STR_024B_BANK :{BLACK}Banka STR_024C_PAPER_MILL :{BLACK}Papirnica -STR_024D_FOOD_PROCESSING_PLANT :{BLACK}Zivilska tovarna +STR_024D_FOOD_PROCESSING_PLANT :{BLACK}Predelava živil STR_024E_PRINTING_WORKS :{BLACK}Tiskarna STR_024F_GOLD_MINE :{BLACK}Rudnik Zlata -STR_0250_LUMBER_MILL :{BLACK}Zaga +STR_0250_LUMBER_MILL :{BLACK}Žaga STR_0251_FRUIT_PLANTATION :{BLACK}Sadovnjak -STR_0252_RUBBER_PLANTATION :{BLACK}Plantaza kavcuka +STR_0252_RUBBER_PLANTATION :{BLACK}Plantaža kavčuka STR_0253_WATER_SUPPLY :{BLACK}Vodni izvir -STR_0254_WATER_TOWER :{BLACK}Vodni Stolp +STR_0254_WATER_TOWER :{BLACK}Vodovodni Stolp STR_0255_DIAMOND_MINE :{BLACK}Rudnik Diamantov STR_0256_COPPER_ORE_MINE :{BLACK}Rudnik bakra STR_0257_COTTON_CANDY_FOREST :{BLACK}Gozd sladkorne pene -STR_0258_CANDY_FACTORY :{BLACK}Tovarna slascic +STR_0258_CANDY_FACTORY :{BLACK}Tovarna slaščic STR_0259_BATTERY_FARM :{BLACK}Farma baterij -STR_025A_COLA_WELLS :{BLACK}Vrelci cocte -STR_025B_TOY_SHOP :{BLACK}Trgovina z igracami -STR_025C_TOY_FACTORY :{BLACK}Tovarna Igrac +STR_025A_COLA_WELLS :{BLACK}Vrelci Cockte +STR_025B_TOY_SHOP :{BLACK}Trgovina z igračami +STR_025C_TOY_FACTORY :{BLACK}Tovarna Igrač STR_025D_PLASTIC_FOUNTAINS :{BLACK}Vodnjaki plastike -STR_025E_FIZZY_DRINK_FACTORY :{BLACK}Tovarna gaziranih pijac -STR_025F_BUBBLE_GENERATOR :{BLACK}Generator mehurckov +STR_025E_FIZZY_DRINK_FACTORY :{BLACK}Tovarna gaziranih pijač +STR_025F_BUBBLE_GENERATOR :{BLACK}Generator mehurčkov STR_0260_TOFFEE_QUARRY :{BLACK}Jama karamele -STR_0261_SUGAR_MINE :{BLACK}Rudnik Sladkorja -STR_0262_CONSTRUCT_COAL_MINE :{BLACK}Zgradi Rudnik Premoga +STR_0261_SUGAR_MINE :{BLACK}Rudnik sladkorja +STR_0262_CONSTRUCT_COAL_MINE :{BLACK}Zgradi rudnik premoga STR_0263_CONSTRUCT_POWER_STATION :{BLACK}Zgradi termoelektrarno -STR_0264_CONSTRUCT_SAWMILL :{BLACK}Zgradi zago +STR_0264_CONSTRUCT_SAWMILL :{BLACK}Zgradi žago STR_0265_PLANT_FOREST :{BLACK}Posadi gozd STR_0266_CONSTRUCT_OIL_REFINERY :{BLACK}Zgradi naftno rafinerijo -STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY :{BLACK}Zgradi naftno ploscad (Lahko je zgrajena samo blizu robu zemljevida) +STR_0267_CONSTRUCT_OIL_RIG_CAN_ONLY :{BLACK}Zgradi naftno ploščad (Lahko je zgrajena samo blizu robu zemljevida) STR_0268_CONSTRUCT_FACTORY :{BLACK}Zgradi tovarno STR_0269_CONSTRUCT_STEEL_MILL :{BLACK}Zgradi jeklarno STR_026A_CONSTRUCT_FARM :{BLACK}Zgradi kmetijo -STR_026B_CONSTRUCT_IRON_ORE_MINE :{BLACK}Zgradi rudnik zeleza +STR_026B_CONSTRUCT_IRON_ORE_MINE :{BLACK}Zgradi rudnik železa STR_026C_CONSTRUCT_OIL_WELLS :{BLACK}Zgradi naftne vrelce -STR_026D_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Zgradi banko (Lahko je zgrajena samo mestih s populacijo vecjo od 1200) +STR_026D_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Zgradi banko (Lahko je zgrajena samo v mestih s populacijo večjo od 1200 ljudi) STR_026E_CONSTRUCT_PAPER_MILL :{BLACK}Zgradi papirnico -STR_026F_CONSTRUCT_FOOD_PROCESSING :{BLACK}Zgradi zivilsko tovarno +STR_026F_CONSTRUCT_FOOD_PROCESSING :{BLACK}Zgradi tovarno predelave hrane STR_0270_CONSTRUCT_PRINTING_WORKS :{BLACK}Zgradi tiskarno STR_0271_CONSTRUCT_GOLD_MINE :{BLACK}Zgradi rudnik zlata STR_0272_CONSTRUCT_BANK_CAN_ONLY :{BLACK}Zgradi banko (Samo v mestih) -STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Zgradi zago (za izrabo dezevnega gozda in predelovanja lesa) +STR_0273_CONSTRUCT_LUMBER_MILL_TO :{BLACK}Zgradi žago (za zmanjševanje deževnega gozda in predelavo lesa) STR_0274_PLANT_FRUIT_PLANTATION :{BLACK}Zgradi sadovnjak -STR_0275_PLANT_RUBBER_PLANTATION :{BLACK}Zgradi plantazo kavcuka +STR_0275_PLANT_RUBBER_PLANTATION :{BLACK}Zgradi plantažo kavčuka STR_0276_CONSTRUCT_WATER_SUPPLY :{BLACK}Zgradi vodno zajetje -STR_0277_CONSTRUCT_WATER_TOWER_CAN :{BLACK}Zgradi vodni stolp (Samo v mestih) +STR_0277_CONSTRUCT_WATER_TOWER_CAN :{BLACK}Zgradi vodovodni stolp (Samo v mestih) STR_0278_CONSTRUCT_DIAMOND_MINE :{BLACK}Zgradi rudnik diamantov STR_0279_CONSTRUCT_COPPER_ORE_MINE :{BLACK}Zgradi rudnik bakra STR_027A_PLANT_COTTON_CANDY_FOREST :{BLACK}Posadi gozd sladkorne pene -STR_027B_CONSTRUCT_CANDY_FACTORY :{BLACK}Zgradi tovarno slascic +STR_027B_CONSTRUCT_CANDY_FACTORY :{BLACK}Zgradi tovarno slaščic STR_027C_CONSTRUCT_BATTERY_FARM :{BLACK}Zgradi farmo baterij -STR_027D_CONSTRUCT_COLA_WELLS :{BLACK}Zgradi vrelce cocte -STR_027E_CONSTRUCT_TOY_SHOP :{BLACK}Zgradi prodajalno z igracami -STR_027F_CONSTRUCT_TOY_FACTORY :{BLACK}Zgradi tovarno Igrac +STR_027D_CONSTRUCT_COLA_WELLS :{BLACK}Zgradi vrelce Cockte +STR_027E_CONSTRUCT_TOY_SHOP :{BLACK}Zgradi trgovino z igračami +STR_027F_CONSTRUCT_TOY_FACTORY :{BLACK}Zgradi tovarno igrač STR_0280_CONSTRUCT_PLASTIC_FOUNTAINS :{BLACK}Zgradi vodnjake plastike -STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY :{BLACK}Zgradi tovarno gaziranih pijac -STR_0282_CONSTRUCT_BUBBLE_GENERATOR :{BLACK}Zgradi generator mehurckov +STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY :{BLACK}Zgradi tovarno gaziranih pijač +STR_0282_CONSTRUCT_BUBBLE_GENERATOR :{BLACK}Zgradi generator mehurčkov STR_0283_CONSTRUCT_TOFFEE_QUARRY :{BLACK}Zgradi jamo karamele -STR_0284_CONSTRUCT_SUGAR_MINE :{BLACK} Zgradi rudnik sladkorja -STR_0285_CAN_T_BUILD_HERE :{WHITE}Tukaj ni mozno zgraditi {STRING} -STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE}...najprej je potrebno zgraditi mesto -STR_0287_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}...samo en dovoljen v mestu +STR_0284_CONSTRUCT_SUGAR_MINE :{BLACK}Zgradi rudnik sladkorja +STR_0285_CAN_T_BUILD_HERE :{WHITE}Tukaj ni možno zgraditi {STRING} +STR_0286_MUST_BUILD_TOWN_FIRST :{WHITE} ... najprej je potrebno zgraditi mesto +STR_0287_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE} ... samo ena dovoljena v mestu STR_0288_PLANT_TREES :{BLACK}Posadi drevesa STR_0289_PLACE_SIGN :{BLACK}Postavi znak -STR_028A_RANDOM_TREES :{BLACK}Nakljucna drevesa -STR_028D_PLACE_LIGHTHOUSE :{BLACK}Zgradi svetilnik -STR_0290_DELETE :{BLACK}Izbrisi -STR_0291_DELETE_THIS_TOWN_COMPLETELY :{BLACK}Popolnoma izbrisi mesto +STR_028A_RANDOM_TREES :{BLACK}Naključna drevesa +STR_028B_PLANT_TREES_RANDOMLY_OVER :{BLACK}Posadi drevesa naključno po ozemlju +STR_028C_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Ustvari kamnita območja naključno po ozemlju +STR_028D_PLACE_LIGHTHOUSE :{BLACK}Postavi svetilnik +STR_028E_PLACE_TRANSMITTER :{BLACK}Postavi oddajnik +STR_028F_DEFINE_DESERT_AREA :{BLACK}Določi območja puščave.{}Pritisnite in držite CTRL za odstranitev +STR_CREATE_LAKE :{BLACK}Določi vodno območje.{}Voda bo poplavila okolico, če bo na višini morja +STR_0290_DELETE :{BLACK}Izbriši +STR_0291_DELETE_THIS_TOWN_COMPLETELY :{BLACK}Popolnoma izbriši mesto STR_0292_SAVE_SCENARIO :Shrani scenarij -STR_0293_LOAD_SCENARIO :Nalozi scenarij +STR_0293_LOAD_SCENARIO :Naloži scenarij STR_0294_QUIT_EDITOR :Izhod iz urejevalnika STR_0295 : STR_0296_QUIT :Izhod -STR_0298_LOAD_SCENARIO :{WHITE}Nalozi scenarij +STR_0297_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Shrani, naloži scenarij, zapusti urejevalnik scenarijev, izhod +STR_0298_LOAD_SCENARIO :{WHITE}Naloži scenarij STR_0299_SAVE_SCENARIO :{WHITE}Shrani scenarij STR_029A_PLAY_SCENARIO :{BLACK}Igraj scenarij +STR_PLAY_HEIGHTMAP :{BLACK}Igraj višinsko karto +STR_PLAY_HEIGHTMAP_HINT :{BLACK}Začni novo igro z uporabo višinske karte za pokrajino +STR_QUIT_SCENARIO_QUERY :{YELLOW}Ali ste prepričani, da želite zapustiti ta scenarij? STR_029C_QUIT_EDITOR :{WHITE}Izhod iz urejevalnika -STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Premakni zacetni datum za 1. leto nazaj -STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Premakni zacetni datum za 1. leto naprej -STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}...oba prikljucka mosta morata biti na kopnem +STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE} ... lahko zgrajen samo v mestih s populacijo 1200 ali več ljudi +STR_029E_MOVE_THE_STARTING_DATE :{BLACK}Premakni začetni datum za 1 leto nazaj +STR_029F_MOVE_THE_STARTING_DATE :{BLACK}Premakni začetni datum za 1 leto naprej +STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE} ... oba priključka mostu morata biti na kopnem STR_02A1_SMALL :{BLACK}Majhno STR_02A2_MEDIUM :{BLACK}Srednje STR_02A3_LARGE :{BLACK}Veliko -STR_02A4_SELECT_TOWN_SIZE :{BLACK}Izberi velikost mesta +STR_02A4_SELECT_TOWN_SIZE :{BLACK}Izberite velikost mesta STR_02A5_TOWN_SIZE :{YELLOW}Velikost mesta: STR_02B6 :{STRING} - {STRING} -STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS :{BLACK}Prikazi zadnje sporocilo oziroma porocilo novice +STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS :{BLACK}Prikaži zadnje sporočilo oziroma novico +STR_OFF :Izključeno +STR_SUMMARY :Povzetek +STR_FULL :Polno STR_02BA :{SILVER}- - {COMPANY} - - +STR_02BB_TOWN_DIRECTORY :Imenik mest +STR_02BC_VEHICLE_DESIGN_NAMES :{BLACK}Imena oblike vozil STR_02BD :{BLACK}{STRING} STR_02BE_DEFAULT :Privzeto STR_02BF_CUSTOM :Po meri -STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}Shrani +STR_02C0_SAVE_CUSTOM_NAMES :{BLACK}Shrani poljubna imena +STR_02C1_VEHICLE_DESIGN_NAMES_SELECTION :{BLACK}Izbira imen oblik vozil +STR_02C2_SAVE_CUSTOMIZED_VEHICLE :{BLACK}Shrani poljubna imena oblik vozil +STR_CHECKMARK :{CHECKMARK} ############ range for menu starts -STR_02C3_GAME_OPTIONS :Moznosti igre -STR_02C5_DIFFICULTY_SETTINGS :Nastavitve tezavnosti -STR_02C7_CONFIG_PATCHES :Urejevanje popravkov +STR_02C3_GAME_OPTIONS :Možnosti igre +STR_02C5_DIFFICULTY_SETTINGS :Nastavitve težavnosti +STR_02C7_CONFIG_PATCHES :Urejanje popravkov +STR_NEWGRF_SETTINGS :NewGRF nastavitve STR_02CA_TOWN_NAMES_DISPLAYED :{SETX 12}Imena mest prikazana STR_02CC_STATION_NAMES_DISPLAYED :{SETX 12}Imena postaj prikazana -STR_02CE_SIGNS_DISPLAYED :{SETX 12}Sporocila prikazana +STR_02CE_SIGNS_DISPLAYED :{SETX 12}Sporočila prikazana STR_WAYPOINTS_DISPLAYED2 :{SETX 12}Smerokazi prikazani -STR_02D0_FULL_ANIMATION :{SETX 12}Polna animacija -STR_02D2_FULL_DETAIL :{SETX 12}Vse podrobnisti -STR_02D4_TRANSPARENT_BUILDINGS :{SETX 12}Prozorne stavbe +STR_02D0_FULL_ANIMATION :{SETX 12}Polne animacije +STR_02D2_FULL_DETAIL :{SETX 12}Vse podrobnosti +STR_02D4_TRANSPARENT_BUILDINGS :{SETX 12}Prosojne stavbe +STR_TRANSPARENT_SIGNS :{SETX 12}Prosojni napisi postaj ############ range ends here ############ range for menu starts -STR_02D5_LAND_BLOCK_INFO :Informacija o terenu +STR_02D5_LAND_BLOCK_INFO :Informacije o terenu STR_02D6 : -STR_02D7_SCREENSHOT_CTRL_S :Zaslonska slika (Ctrl-S) -STR_02D8_GIANT_SCREENSHOT_CTRL_G :Ogromna zaslonska slika (Ctrl-G) +STR_CONSOLE_SETTING :Vklopi/Izklopi konzolo +STR_02D7_SCREENSHOT_CTRL_S :Zajemi sliko (Ctrl-S) +STR_02D8_GIANT_SCREENSHOT_CTRL_G :Zajemi celostno slika (Ctrl-G) STR_02D9_ABOUT_OPENTTD :O 'OpenTTD' ############ range ends here -STR_02DB_OFF :{BLACK}Izklopljeno -STR_02DA_ON :{BLACK}Vklopljeno -STR_02DC_DISPLAY_SUBSIDIES :{BLACK}Prikazi subvencije +STR_02DB_OFF :{BLACK}Izključeno +STR_02DA_ON :{BLACK}Vključeno +STR_02DC_DISPLAY_SUBSIDIES :{BLACK}Prikaži subvencije STR_02DD_SUBSIDIES :Subvencije STR_02DE_MAP_OF_WORLD :Zemljevid sveta -STR_02DF_TOWN_DIRECTORY :Direktorij mest +STR_EXTRA_VIEW_PORT :Dodaten pogled +STR_SIGN_LIST :Seznam napisov +STR_02DF_TOWN_DIRECTORY :Imenik mest STR_TOWN_POPULATION :{BLACK}Svetovna populacija: {COMMA} +STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Pogled {COMMA} +STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopiraj na pogled -STR_02E0_CURRENCY_UNITS :{BLACK}Denarne valute +STR_02E0_CURRENCY_UNITS :{BLACK}Valute STR_02E1 :{BLACK}{SKIP}{STRING} -STR_02E2_CURRENCY_UNITS_SELECTION :{BLACK}Izbira denarnih valut +STR_02E2_CURRENCY_UNITS_SELECTION :{BLACK}Izbira valut +STR_MEASURING_UNITS :{BLACK}Merske enote STR_02E4 :{BLACK}{SKIP}{SKIP}{STRING} STR_02E6_ROAD_VEHICLES :{BLACK}Cestna vozila STR_02E7 :{BLACK}{SKIP}{SKIP}{SKIP}{STRING} -STR_02E8_SELECT_SIDE_OF_ROAD_FOR :{BLACK}Izberi stran ceste na kateri vozijo cestna vozila -STR_02E9_DRIVE_ON_LEFT :Voznja po levi -STR_02EA_DRIVE_ON_RIGHT :Voznja po desni +STR_02E8_SELECT_SIDE_OF_ROAD_FOR :{BLACK}Izberite smer vožnje cestnih vozil +STR_02E9_DRIVE_ON_LEFT :Vožnja po levi +STR_02EA_DRIVE_ON_RIGHT :Vožnja po desni STR_02EB_TOWN_NAMES :{BLACK}Imena mest STR_02EC :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} -STR_02ED_SELECT_STYLE_OF_TOWN_NAMES :{BLACK}Izberi stil imena mest +STR_02ED_SELECT_STYLE_OF_TOWN_NAMES :{BLACK}Izberite slog imena mest STR_02F4_AUTOSAVE :{BLACK}Shrani STR_02F5 :{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING} -STR_02F6_SELECT_INTERVAL_BETWEEN :{BLACK}Izberi interval med samodejnim shranjevanjem igre +STR_02F6_SELECT_INTERVAL_BETWEEN :{BLACK}Izberite časovni interval samodejnega shranjevanja igre STR_02F7_OFF :Izklopljeno -STR_02F8_EVERY_3_MONTHS :vsake 3 mesece -STR_02F9_EVERY_6_MONTHS :vsakih 6 mesecev -STR_02FA_EVERY_12_MONTHS :vsakih 12 mesecev -STR_02FB_START_A_NEW_GAME :{BLACK}Zacni novo igro -STR_02FC_LOAD_A_SAVED_GAME :{BLACK}Nalozi shranjeno igro +STR_02F8_EVERY_3_MONTHS :Vsake 3 mesece +STR_02F9_EVERY_6_MONTHS :Vsakih 6 mesecev +STR_02FA_EVERY_12_MONTHS :Vsakih 12 mesecev +STR_02FB_START_A_NEW_GAME :{BLACK}Začni novo igro +STR_02FC_LOAD_A_SAVED_GAME :{BLACK}Naloži shranjeno igro STR_02FE_CREATE_A_CUSTOMIZED_GAME :{BLACK}Ustvari poljubni svet/scenarij STR_02FF_SELECT_SINGLE_PLAYER_GAME :{BLACK}Izberi igro za enega igralca -STR_0300_SELECT_MULTIPLAYER_GAME :{BLACK}Izberi igro za vec igralcev 2-8 -STR_0301_DISPLAY_GAME_OPTIONS :{BLACK}Prikazi moznosti igre -STR_0302_DISPLAY_DIFFICULTY_OPTIONS :{BLACK}Prikazi nastavitve tezavnosti -STR_0303_START_A_NEW_GAME_USING :{BLACK}Zacni novo igro z uporabo scenarija +STR_0300_SELECT_MULTIPLAYER_GAME :{BLACK}Izberi igro za 2-8 igralcev +STR_0301_DISPLAY_GAME_OPTIONS :{BLACK}Prikaži možnosti igre +STR_0302_DISPLAY_DIFFICULTY_OPTIONS :{BLACK}Prikaži nastavitve težavnosti +STR_0303_START_A_NEW_GAME_USING :{BLACK}Začni novo igro po scenariju STR_0304_QUIT :{BLACK}Izhod STR_0305_QUIT_OPENTTD :{BLACK}Izhod iz 'OpenTTD' STR_0307_OPENTTD :{WHITE}OpenTTD {REV} -STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...samo v mestih -STR_0312_FUND_CONSTRUCTION_OF_NEW :{BLACK}Podpri izgradnjo nove industrije +STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE} ... samo v mestih +STR_030E_SELECT_TEMPERATE_LANDSCAPE :{BLACK}Izberi običajen slog ozemlja +STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE :{BLACK}Izberi stepski slog ozemlja +STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE :{BLACK}Izberi subtropski slog ozemlja +STR_0311_SELECT_TOYLAND_LANDSCAPE :{BLACK}Izberi ozemlje sveta igrač +STR_0312_FUND_CONSTRUCTION_OF_NEW :{BLACK}Financiraj izgradnjo nove industrije ############ range for menu starts +STR_INDUSTRY_DIR :Imenik tovarn STR_0313_FUND_NEW_INDUSTRY :Odpri novo industrijo ############ range ends here STR_0314_FUND_NEW_INDUSTRY :{WHITE}Odpri novo industrijo -STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}...gradnja mogoca samo v mestih -STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}...gradnja mogoca samo v dezevnem gozdu -STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}...gradnja mogoca samo v puscavi +STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE} ... gradnja mogoča samo v mestih +STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE} ... gradnja mogoča samo v območju deževnega gozda +STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE} ... gradnja mogoča samo v puščavi STR_0319_PAUSED :{YELLOW}* * ZAUSTAVLJENO * * -STR_031B_SCREENSHOT_SUCCESSFULLY :{WHITE}Zaslonska slika je uspesno shranjena kot {} '{STRING}' -STR_031C_SCREENSHOT_FAILED :{WHITE}Jemanje zaslonske slike je {}SPODLETELO!!! +STR_031B_SCREENSHOT_SUCCESSFULLY :{WHITE}Slika je uspešno zajeta kot {} '{STRING}' +STR_031C_SCREENSHOT_FAILED :{WHITE}Zajemanje slike je {}SPODLETELO!!! -STR_0329_PURCHASE_LAND_FOR_FUTURE :{BLACK}Kupi zemljisce za prihodnjo rabo +STR_0329_PURCHASE_LAND_FOR_FUTURE :{BLACK}Kupi zemljišče za prihodnjo rabo STR_032F_AUTOSAVE :{RED}Samodejno shranjevanje STR_0330_SELECT_EZY_STREET_STYLE :{BLACK}Izberi 'Ezy Street' glasbeni program @@ -836,6 +906,7 @@ STR_AUTOSAVE_1_MONTH :Vsak mesec +STR_AUTOSAVE_FAILED :{WHITE}Samodejno shranjevanje spodletelo STR_MONTH_JAN :Januar STR_MONTH_FEB :Februar @@ -851,9 +922,12 @@ STR_MONTH_DEC :December +STR_BAGS :vreč STR_TONS :tone +STR_CANT_SHARE_ORDER_LIST :{WHITE}Ni mogoče deliti navodil ... +STR_CANT_COPY_ORDER_LIST :{WHITE}Ni mogoče skopirati navodil ... STR_TRAIN_IS_LOST :{WHITE}Vlak {COMMA} se je izgubil STR_TRAIN_IS_UNPROFITABLE :{WHITE}Vlak {COMMA} je imel {CURRENCY} lansko leto @@ -863,11 +937,17 @@ STR_TRAIN_HAS_TOO_FEW_ORDERS :{WHITE}Vlak {COMMA} ima premalo narocil na svojem seznamu STR_TRAIN_HAS_DUPLICATE_ENTRY :{WHITE}Vlak {COMMA} ima podvojena narocila STR_TRAIN_HAS_INVALID_ENTRY :{WHITE}Vlak {COMMA} ima nepravilno zaporedje narocil +STR_AIRCRAFT_HAS_TOO_FEW_ORDERS :{WHITE}Letalo {COMMA} ima premalo ukazov v navodilih +STR_AIRCRAFT_HAS_VOID_ORDER :{WHITE}Letalo {COMMA} ima ničen ukaz +STR_AIRCRAFT_HAS_DUPLICATE_ENTRY :{WHITE}Letalo {COMMA} ima podvojene ukaze +STR_AIRCRAFT_HAS_INVALID_ENTRY :{WHITE}Letalo {COMMA} ima neveljavne postaje v navodilih # end of order system STR_TRAIN_AUTORENEW_FAILED :{WHITE}Avtomatska zamenjava je spodletela na vlaku {COMMA} (denarni problemi) +STR_AIRCRAFT_AUTORENEW_FAILED :{WHITE}Samoprenova neuspela na letalu {COMMA} (omejitev z denarjem) STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}Vlak {COMMA} je predolg po zamenjavi +STR_CONFIG_PATCHES :{BLACK}Nastavitve popravkov STR_CONFIG_PATCHES_OFF :Izklopi STR_CONFIG_PATCHES_ON :Vklopi @@ -880,6 +960,9 @@ + +STR_CONFIG_PATCHES_AI :{BLACK}Tekmeci + STR_CONFIG_PATCHES_DISABLED :dizejblano STR_CONFIG_PATCHES_INT32 :{NUM} STR_CONFIG_PATCHES_CURRENCY :{CURRENCY} @@ -888,6 +971,18 @@ STR_TEMPERATE_LANDSCAPE :Zmerno podnebje STR_TOYLAND_LANDSCAPE :Igracarsko pokrajina +STR_CHEATS :{WHITE}Goljufije +STR_CHEATS_TIP :{BLACK}Kljukice kažejo, če so bile goljufije že kdaj uporabljene +STR_CHEATS_WARNING :{BLACK}Pozor! Nameravate izdati svoje tekmece. Tako sramotno dejanje bo zapomnjeno za vselej. +STR_CHEAT_MONEY :{LTBLUE}Povečaj denar za {CURRENCY64} +STR_CHEAT_CHANGE_PLAYER :{LTBLUE}Igra se kot igralec: {ORANGE}{COMMA} +STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Čarobni buldožer (odstrani tovarne, neodstranljive objekte): {ORANGE}{STRING} +STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tuneli se lahko križajo pod zemljo: {ORANGE}{STRING} +STR_CHEAT_BUILD_IN_PAUSE :{LTBLUE}Zgrajeno med pavzo: {ORANGE}{STRING} +STR_CHEAT_NO_JETCRASH :{LTBLUE}Reaktivci ne bodo strmoglavili (pogostokrat) na malih letališčih: {ORANGE} {STRING} +STR_CHEAT_SWITCH_CLIMATE :{LTBLUE}Spreminjanje klime: {ORANGE} {STRING} +STR_CHEAT_CHANGE_DATE :{LTBLUE}Spremeni datum: {ORANGE} {DATE_SHORT} +STR_CHEAT_SETUP_PROD :{LTBLUE}Omogoči spreminjanje vrednosti produktov: {ORANGE}{STRING} @@ -901,8 +996,29 @@ STR_WAYPOINT_VIEWPORT_TINY :{TINYFONT}{WHITE}{WAYPOINT} STR_WAYPOINT_RAW :{WAYPOINT} +STR_CANT_CHANGE_WAYPOINT_NAME :{WHITE}Ni mogoče preimenovati kažipota ... +STR_CANT_BUILD_TRAIN_WAYPOINT :{WHITE}Ni mogoče postaviti kažipotov tukaj ... +STR_CANT_REMOVE_TRAIN_WAYPOINT :{WHITE}Ni mogoče odstraniti kažipota tukaj ... + +STR_BUILD_AUTORAIL_TIP :{BLACK}Gradi železnico s pomočjo Samodejne gradnje +STR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Ni mogoče zgraditi industrij ... + + + + +STR_CANT_BUILD_CANALS :{WHITE}Ni mogoče zgraditi kanalov tukaj ... +STR_BUILD_CANALS_TIP :{BLACK}Gradnja kanalov. CTRL+klik za postavitev morskih kvadratkov (samo na nadmorski višini morja) + +STR_CANT_BUILD_LOCKS :{WHITE}Ni mogoče zgraditi zapornic tukaj ... +STR_BUILD_LOCKS_TIP :{BLACK}Gradnja zapornic + +STR_BUOY_IS_IN_USE :{WHITE} ... boja v uporabi! + + +STR_CANT_REMOVE_PART_OF_STATION :{WHITE}Ni mogoče odstraniti dela postaje ... +STR_CANT_CONVERT_RAIL :{WHITE}Ni mogoče spremeniti železnice tukaj ... @@ -910,15 +1026,7 @@ - - - - - - - - - +STR_CONFIG_GAME_PRODUCTION :{WHITE}Spremeni produkcijo TEMP_AI_IN_PROGRESS :{WHITE}Dobrodosli v UI v razvoju. Ce boste prisli do problemov, posnamite zaslonsko sliko in jo prilepite na forum. TEMP_AI_ACTIVATED :{WHITE}Opozorilo: Nova UI je se vedno alfa razlicica! Zaenkrat, samo tovornjaki in avtobusi delujejo! @@ -963,69 +1071,94 @@ + +##### PNG-MAP-Loader + + +STR_BMPMAP_ERROR :{WHITE}Ni mogoče naložiti pokrajine iz formata BMP ... +STR_BMPMAP_ERR_IMAGE_TYPE :{WHITE} ... ni mogoče spremeniti tipa slike. + ##id 0x0800 -STR_0800_COST :{TINYFONT}{RED}Stroski: {CURRENCY} -STR_0801_COST :{RED}Stroski: {CURRENCY} -STR_0802_INCOME :{TINYFONT}{GREEN}Prihodek: {CURRENCY} -STR_0803_INCOME :{GREEN}Prihodek: {CURRENCY} -STR_0805_ESTIMATED_COST :{WHITE}Ocenjeni strosek: {CURRENCY} -STR_0807_ESTIMATED_INCOME :{WHITE}Predviden prihodek: {CURRENCY} -STR_0808_CAN_T_RAISE_LAND_HERE :{WHITE}Tukaj nemore?dvigniti terena... -STR_0809_CAN_T_LOWER_LAND_HERE :{WHITE}Tukaj nemore?znizati terena... +STR_0800_COST :{TINYFONT}{RED}Stroški: {CURRENCY} +STR_0801_COST :{RED}Stroški: {CURRENCY} +STR_0802_INCOME :{TINYFONT}{GREEN}Prihodki: {CURRENCY} +STR_0803_INCOME :{GREEN}Prihodki: {CURRENCY} +STR_0805_ESTIMATED_COST :{WHITE}Ocenjeni stroški: {CURRENCY} +STR_0807_ESTIMATED_INCOME :{WHITE}Predvideni prihodki: {CURRENCY} +STR_0808_CAN_T_RAISE_LAND_HERE :{WHITE}Tukaj ne morete dvigniti terena ... +STR_0809_CAN_T_LOWER_LAND_HERE :{WHITE}Tukaj ne morete znižati terena ... STR_080A_ROCKS :Kamenje -STR_080C_BARE_LAND :Gol teren +STR_080B_ROUGH_LAND :Groba tla +STR_080C_BARE_LAND :Gola tla STR_080D_GRASS :Trava STR_080E_FIELDS :Polja -STR_080F_SNOW_COVERED_LAND :S snegom pokrit teren -STR_0810_DESERT :Puscava +STR_080F_SNOW_COVERED_LAND :Zasnežen teren +STR_0810_DESERT :Puščava ##id 0x1000 -STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren nagnjen v napacno smer -STR_1001_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Nemogoca kombinacija tracnic -STR_1002_EXCAVATION_WOULD_DAMAGE :{WHITE}Premikanje bi lahko poskodovalo tunel -STR_1003_ALREADY_AT_SEA_LEVEL :{WHITE}Ze na nadmorski visini +STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren nagnjen v napačno smer +STR_1001_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Nemogoča kombinacija tirnic +STR_1002_EXCAVATION_WOULD_DAMAGE :{WHITE}Premikanje bi lahko poškodovalo tunel +STR_1003_ALREADY_AT_SEA_LEVEL :{WHITE}Že na nadmorski višini STR_1004_TOO_HIGH :{WHITE}Previsoko -STR_1005_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nobene uporabne tracnice -STR_1007_ALREADY_BUILT :{WHITE}...ze zgrajeno -STR_1008_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprej moras odstraniti tracnice +STR_1005_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nobene uporabne tračnice +STR_1007_ALREADY_BUILT :{WHITE} ... že zgrajeno +STR_1008_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprej morate odstraniti tračnice STR_100A_RAILROAD_CONSTRUCTION :{WHITE}Gradnja železnice STR_TITLE_ELRAIL_CONSTRUCTION :{WHITE}Elektrificirana Zeleznica -STR_100D_SELECT_RAIL_BRIDGE :{WHITE}Izberi zelezniski most -STR_100E_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Tu ne morete zgraditi zelezniskega skladisca... -STR_100F_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Tu ne morete zgraditi zelezniske postaje... -STR_1010_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Tu ne morete zgraditi signalov... -STR_1011_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Tu ne morete zgraditi zelezniskih tirov... -STR_1012_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Tu ne morete odstraniti zelezniskih tirov... -STR_1013_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Tu ne morete odstraniti signalov... -STR_1015_RAILROAD_CONSTRUCTION :Gradnja zeleznice +STR_100B_MONORAIL_CONSTRUCTION :{WHITE}Gradnja enotirne železnice +STR_100C_MAGLEV_CONSTRUCTION :{WHITE}Gradnja magnetne železnice +STR_100D_SELECT_RAIL_BRIDGE :{WHITE}Izberi železniški most +STR_100E_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Tu ne morete zgraditi železniškega skladišča ... +STR_100F_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Tu ne morete zgraditi železniške postaje ... +STR_1010_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Tu ne morete zgraditi semaforjev ... +STR_1011_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Tu ne morete zgraditi železniških tirov ... +STR_1012_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Tu ne morete odstraniti železniških tirov ... +STR_1013_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Tu ne morete odstraniti semaforjev ... +STR_1014_TRAIN_DEPOT_ORIENTATION :{WHITE}Smer železniškega skladišča +STR_1015_RAILROAD_CONSTRUCTION :Gradnja železnice STR_TOOLB_ELRAIL_CONSTRUCTION :Elektrificirana zeleznica -STR_1016_MONORAIL_CONSTRUCTION :Enotirna zeleznica -STR_1017_MAGLEV_CONSTRUCTION :Magnetna zeleznica -STR_1018_BUILD_RAILROAD_TRACK :{BLACK}Zgradi tracnice -STR_101A_BUILD_RAILROAD_STATION :{BLACK}Zgradi zelezznisko postajo -STR_101B_BUILD_RAILROAD_SIGNALS :{BLACK}Zgradi zelezniske semaforje -STR_101C_BUILD_RAILROAD_BRIDGE :{BLACK}Zgradi zelezniski most -STR_101D_BUILD_RAILROAD_TUNNEL :{BLACK}Zgradi zelezniski tunel -STR_101E_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Preklopi gradi/rusi za zelezniske semaforje -STR_1021_RAILROAD_TRACK :Zelezniska proga -STR_1024_AREA_IS_OWNED_BY_ANOTHER :{WHITE}...zemljisce je last neke druge druzbe +STR_1016_MONORAIL_CONSTRUCTION :Enotirna železnica +STR_1017_MAGLEV_CONSTRUCTION :Magnetna železnica +STR_1018_BUILD_RAILROAD_TRACK :{BLACK}Zgradi tračnice +STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Zgradi železniško skladišče (za izgradnjo in servis vlakov) +STR_101A_BUILD_RAILROAD_STATION :{BLACK}Zgradi železniško postajo +STR_101B_BUILD_RAILROAD_SIGNALS :{BLACK}Zgradi železniške semaforje +STR_101C_BUILD_RAILROAD_BRIDGE :{BLACK}Zgradi železniški most +STR_101D_BUILD_RAILROAD_TUNNEL :{BLACK}Zgradi železniški tunel +STR_101E_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Preklopi gradnjo/rušenje železniških semaforjev +STR_101F_BRIDGE_SELECTION_CLICK :{BLACK}Izbira mostu - kliknite na željeni most za izgradnjo +STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO :{BLACK}Izberi smer železniškega skladišča +STR_1021_RAILROAD_TRACK :Železniška proga +STR_1023_RAILROAD_TRAIN_DEPOT :Železniško skladišče +STR_1024_AREA_IS_OWNED_BY_ANOTHER :{WHITE} ... zemljišče je last nekega drugega podjetja ##id 0x1800 -STR_1801_MUST_REMOVE_ROAD_FIRST :{WHITE}Najprej zgradi cesto +STR_1801_MUST_REMOVE_ROAD_FIRST :{WHITE}Najprej odstrani cesto STR_1802_ROAD_CONSTRUCTION :{WHITE}Cestne gradnje STR_1803_SELECT_ROAD_BRIDGE :{WHITE}Izberi cestni most -STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Tu ne mores zgraditi ceste... -STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Tu ne mores odstraniti ceste... -STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}Ne mores zgraditi avtobusne postaje... +STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Tu ne morete zgraditi ceste ... +STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Tu ne morete odstraniti ceste ... +STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}Smer garaže +STR_1807_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Ne morete zgraditi garaže tukaj ... +STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}Ne morete zgraditi avtobusne postaje ... +STR_1809_CAN_T_BUILD_TRUCK_STATION :{WHITE}Ne morete zgraditi tovorne postaje tukaj ... +STR_180A_ROAD_CONSTRUCTION :Gradnja ceste +STR_180B_BUILD_ROAD_SECTION :{BLACK}Zgradi cestni odsek +STR_180C_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Zgradi garažo (za izgradnjo in servis vozil) STR_180D_BUILD_BUS_STATION :{BLACK}Zgradi avtobusno postajo +STR_180E_BUILD_TRUCK_LOADING_BAY :{BLACK}Zgradi tovorno postajo STR_180F_BUILD_ROAD_BRIDGE :{BLACK}Zgradi cestni most STR_1810_BUILD_ROAD_TUNNEL :{BLACK}Zgradi cestni predor +STR_1811_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Preklapljaj gradnjo/rušenje cestnih konstrukcij +STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}Izberi smer garaže STR_1814_ROAD :Cesta -STR_1815_ROAD_WITH_STREETLIGHTS :Cesta s cestnimi lucmi +STR_1815_ROAD_WITH_STREETLIGHTS :Cesta s cestnimi lučmi STR_1816_TREE_LINED_ROAD :Cesta z drevoredom -STR_1818_ROAD_RAIL_LEVEL_CROSSING :Cestno/zeleznisko krizisce +STR_1817_ROAD_VEHICLE_DEPOT :Garaža +STR_1818_ROAD_RAIL_LEVEL_CROSSING :Cestno/železniško križišče ##id 0x2000 STR_2000_TOWNS :{WHITE}Mesta @@ -1034,181 +1167,221 @@ STR_TOWN_LABEL_TINY_BLACK :{TINYFONT}{BLACK}{TOWN} STR_TOWN_LABEL_TINY_WHITE :{TINYFONT}{WHITE}{TOWN} STR_2002 :{TINYFONT}{BLACK}{STRING} -STR_2004_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Najprej mora bit porusena stavba +STR_2004_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Najprej mora biti stavba porušena STR_2005 :{WHITE}{TOWN} -STR_2006_POPULATION :{BLACK}Populacija: {ORANGE}{COMMA}{BLACK} His: {ORANGE}{COMMA} +STR_2006_POPULATION :{BLACK}Populacija: {ORANGE}{COMMA}{BLACK} Število stavb: {ORANGE}{COMMA} STR_2007_RENAME_TOWN :Preimenuj mesto -STR_2008_CAN_T_RENAME_TOWN :{WHITE}Nemores preimenovati mesta... +STR_2008_CAN_T_RENAME_TOWN :{WHITE}Ne morete preimenovati mesta ... STR_2009_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN} lokalna oblast tega ne dovoli +STR_200A_TOWN_NAMES_CLICK_ON_NAME :{BLACK}Imena mest - kliknite na ime za pogled na mesto +STR_200B_CENTER_THE_MAIN_VIEW_ON :{BLACK}Premakni celotni pogled na mesto STR_200C_CHANGE_TOWN_NAME :{BLACK}Spremeni ime mesta -STR_200D_PASSENGERS_LAST_MONTH_MAX :{BLACK}Potnikov prejsni mesec: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} -STR_200E_MAIL_LAST_MONTH_MAX :{BLACK}Poste prejsni mesec: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} -STR_200F_TALL_OFFICE_BLOCK :Visoka pisarniska hisa -STR_2010_OFFICE_BLOCK :Pisarniska hisa +STR_200D_PASSENGERS_LAST_MONTH_MAX :{BLACK}Potnikov prejšnji mesec: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} +STR_200E_MAIL_LAST_MONTH_MAX :{BLACK}Pošte prejšnji mesec: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} +STR_200F_TALL_OFFICE_BLOCK :Visok pisarniški blok +STR_2010_OFFICE_BLOCK :Pisarniški blok STR_2011_SMALL_BLOCK_OF_FLATS :Majhen blok STR_2012_CHURCH :Cerkev -STR_2013_LARGE_OFFICE_BLOCK :Velika pisarniska hisa -STR_2014_TOWN_HOUSES :Mestna hisa +STR_2013_LARGE_OFFICE_BLOCK :Velik pisarniški blok +STR_2014_TOWN_HOUSES :Meščanske hiše STR_2015_HOTEL :Hotel -STR_2016_STATUE :Kip +STR_2016_STATUE :Spomenik STR_2017_FOUNTAIN :Vodnjak STR_2018_PARK :Park -STR_2019_OFFICE_BLOCK :Pisarniska hisa +STR_2019_OFFICE_BLOCK :Pisarniški blok STR_201A_SHOPS_AND_OFFICES :Trgovine in pisarne -STR_201B_MODERN_OFFICE_BUILDING :Moderna pisarniska hisa -STR_201C_WAREHOUSE :Skladisce -STR_201D_OFFICE_BLOCK :Pisarniska hisa +STR_201B_MODERN_OFFICE_BUILDING :Moderna pisarniška hiša +STR_201C_WAREHOUSE :Skladišče +STR_201D_OFFICE_BLOCK :Pisarniška hiša STR_201E_STADIUM :Stadion -STR_201F_OLD_HOUSES :Stare hise +STR_201F_OLD_HOUSES :Stare hiše STR_2020_LOCAL_AUTHORITY :{BLACK}Mestni svet -STR_2021_SHOW_INFORMATION_ON_LOCAL :{BLACK}Pokazi informacije o lokalni oblasti -STR_2022_LOCAL_AUTHORITY :{WHITE}{TOWN} Mestni svet -STR_2023_TRANSPORT_COMPANY_RATINGS :{BLACK} +STR_2021_SHOW_INFORMATION_ON_LOCAL :{BLACK}Pokaži informacije o lokalni oblasti +STR_2022_LOCAL_AUTHORITY :{WHITE}{TOWN} mestni svet +STR_2023_TRANSPORT_COMPANY_RATINGS :{BLACK}Ocene podjetja: STR_2024 :{YELLOW}{COMPANY}{PLAYERNAME}: {ORANGE}{STRING} STR_2025_SUBSIDIES :{WHITE}Subvencije -STR_2026_SUBSIDIES_ON_OFFER_FOR :{BLACK}Ponudba subvencij: +STR_2026_SUBSIDIES_ON_OFFER_FOR :{BLACK}Ponudba subvencije za storitev: STR_2027_FROM_TO :{ORANGE}{STRING} iz {STRING} v {STRING} STR_2028_BY :{YELLOW} (do {DATE_SHORT}) -STR_202A_NONE :{ORANGE}Noben -STR_202B_SERVICES_ALREADY_SUBSIDISED :{BLACK}Subvencionirane storitve +STR_202A_NONE :{ORANGE}Nihče +STR_202B_SERVICES_ALREADY_SUBSIDISED :{BLACK}Že subvencionirane storitve: STR_202C_FROM_TO :{ORANGE}{STRING} od {STATION} do {STATION}{YELLOW} ({COMPANY} -STR_202D_UNTIL :{YELLOW},do {DATE_SHORT}) -STR_202E_OFFER_OF_SUBSIDY_EXPIRED :{BLACK}{BIGFONT}Ponudba za subvencijo umaknjena:{}{}{STRING} od {STRING} do {STRING} od sedaj ne bo prinesla subvencije. -STR_202F_SUBSIDY_WITHDRAWN_SERVICE :{BLACK}{BIGFONT}Subvencija je potekla:{}{}{STRING} storitev od {STATION} do {STATION} ni vec subvencionirana is no longer subsidised. -STR_2030_SERVICE_SUBSIDY_OFFERED :{BLACK}{BIGFONT}Ponudena subvencija:{}{}Prva {STRING} storitev od {STRING} do {STRING} bo subvencionirana s strani mestnega sveta! -STR_2031_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla 50% vecji prihodek za naslednje leto! +STR_202D_UNTIL :{YELLOW}, do {DATE_SHORT}) +STR_202E_OFFER_OF_SUBSIDY_EXPIRED :{BLACK}{BIGFONT}Subvencioniranje zaključeno: storitev {}{}{STRING} od {STRING} do {STRING} ne bo subvencionirana. +STR_202F_SUBSIDY_WITHDRAWN_SERVICE :{BLACK}{BIGFONT}Subvencija je potekla:{}{}{STRING} storitev od {STATION} do {STATION} ni več subvencionirana. +STR_2030_SERVICE_SUBSIDY_OFFERED :{BLACK}{BIGFONT}Nova subvencija:{}{}Prva {STRING} storitev od {STRING} do {STRING} bo subvencionirana s strani mestnega sveta! +STR_2031_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla 50% večji prihodek za naslednje leto! STR_2032_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla dvakratni prihodek STR_2033_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla trikratni prihodek za naslednje leto! -STR_2034_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla stirikratni prihodek za naslednje leto! -STR_2035_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN} mestni svet prepoveduje granjo se enega letalisca v tem mestu -STR_2036_COTTAGES :Koce -STR_2037_HOUSES :Hise +STR_2034_SERVICE_SUBSIDY_AWARDED :{BLACK}{BIGFONT}Subvencija podeljena {COMPANY}!{}{}{STRING} storitev od {STATION} do {STATION} bo prinesla štirikratni prihodek za naslednje leto! +STR_2035_LOCAL_AUTHORITY_REFUSES :{WHITE}{TOWN} mestni svet prepoveduje gradnjo še enega letališča v tem mestu +STR_2036_COTTAGES :Koče +STR_2037_HOUSES :Hiše STR_2038_FLATS :Stanovanja -STR_2039_TALL_OFFICE_BLOCK :Visoka poslovna hisa -STR_203A_SHOPS_AND_OFFICES :Trgovince in pisarne -STR_203B_SHOPS_AND_OFFICES :Trgovince in pisarne -STR_203C_THEATER :Gledalisce +STR_2039_TALL_OFFICE_BLOCK :Visoka poslovna hiša +STR_203A_SHOPS_AND_OFFICES :Trgovine in pisarne +STR_203B_SHOPS_AND_OFFICES :Trgovine in pisarne +STR_203C_THEATER :Gledališče STR_203D_STADIUM :Stadion STR_203E_OFFICES :Pisarne -STR_203F_HOUSES :Hise +STR_203F_HOUSES :Hiše STR_2040_CINEMA :Kino STR_2041_SHOPPING_MALL :Trgovski center STR_2042_DO_IT :{BLACK}Stori to -STR_2043_LIST_OF_THINGS_TO_DO_AT :{BLACK}Seznam stvari, ki jih lahko naredis v tem mestu - klikni stvar za vec podrobnosti -STR_2046_SMALL_ADVERTISING_CAMPAIGN :Majhna reklamna kampanja -STR_2047_MEDIUM_ADVERTISING_CAMPAIGN :Srednja reklamna kampanja -STR_2048_LARGE_ADVERTISING_CAMPAIGN :Velik reklamna kampanja -STR_2049_FUND_LOCAL_ROAD_RECONSTRUCTION :Podpri obnovo cest -STR_204A_BUILD_STATUE_OF_COMPANY :Zgradi kip lastnikafirme +STR_2043_LIST_OF_THINGS_TO_DO_AT :{BLACK}Seznam stvari, ki jih lahko naredite v tem mestu - kliknite na predmet za podrobnosti +STR_2044_CARRY_OUT_THE_HIGHLIGHTED :{BLACK}Izvrši izbrano storitev na zgornjem seznamu +STR_2045_ACTIONS_AVAILABLE :{BLACK}Storitve na voljo: +STR_2046_SMALL_ADVERTISING_CAMPAIGN :Majhna reklamna kampanija +STR_2047_MEDIUM_ADVERTISING_CAMPAIGN :Srednje velika reklamna kampanija +STR_2048_LARGE_ADVERTISING_CAMPAIGN :Velika reklamna kampanija +STR_2049_FUND_LOCAL_ROAD_RECONSTRUCTION :Financiraj obnovo cest +STR_204A_BUILD_STATUE_OF_COMPANY :Zgradi spomenik lastniku podjetja STR_204B_FUND_NEW_BUILDINGS :Sponzoriraj nove stavbe -STR_204C_BUY_EXCLUSIVE_TRANSPORT :Kupi eksluzivne transportne novice +STR_204C_BUY_EXCLUSIVE_TRANSPORT :Kupi eksluzivne transportne pravice STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY :Podkupi lokalno oblast +STR_204D_INITIATE_A_SMALL_LOCAL :{WHITE}{STRING}{}{YELLOW} Izvrši majhno reklamno kampanijo z namenom privabiti več potnikov in tovora podjetju.{} Cena: {CURRENCY} +STR_204E_INITIATE_A_MEDIUM_LOCAL :{WHITE}{STRING}{}{YELLOW} Izvrši srednje-veliko reklamno kampanijo z namenom privabiti več potnikov in tovora podjetju.{} Cena: {CURRENCY} +STR_204F_INITIATE_A_LARGE_LOCAL :{WHITE}{STRING}{}{YELLOW} Izvrši veliko reklamno kampanijo z namenom privabiti več potnikov in tovora podjetju.{} Cena: {CURRENCY} +STR_2050_FUND_THE_RECONSTRUCTION :{WHITE}{STRING}{}{YELLOW} Financiraj obnovo cest z namenom motnje cestnega prometa tudi do 6 mesecev.{} Cena: {CURRENCY} +STR_2051_BUILD_A_STATUE_IN_HONOR :{WHITE}{STRING}{}{YELLOW} Zgradi spomenik v čast podjetju.{} Cena: {CURRENCY} +STR_2052_FUND_THE_CONSTRUCTION_OF :{WHITE}{STRING}{}{YELLOW} Financiraj izgradnjo novih poslovnih stavb v mestu.{} Cena: {CURRENCY} +STR_2053_BUY_1_YEAR_S_EXCLUSIVE :{WHITE}{STRING}{}{YELLOW} Kupi enoletno izključno pravico do transporta v mestu. Lokalne oblasti bodo dovolile potnikom in tovoru do izključno vaše uporabe transportnih storitev.{} Cena: {CURRENCY} STR_TOWN_BRIBE_THE_LOCAL_AUTHORITY_DESC :{WHITE}{STRING}{}{YELLOW} Podkupi lokalno oblast za izboljsavo svojih rating ob tveganju resnih kazni ob caught.{} Stane: {CURRENCY} +STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING :{BIGFONT}{BLACK}Prometni kaos v mestu {TOWN}!{}{}Obnovitvena dela, ki jih financira podjetje {COMPANY}, bodo prinesla 6 mesecev nočnih mor voznikom motornih vozil! STR_2056 :{TINYFONT}{WHITE}{TOWN} STR_2057 :{ORANGE}{TOWN}{BLACK} ({COMMA}) -STR_2058_UNDER_CONSTRUCTION :{STRING} (v gradnji) +STR_2058_UNDER_CONSTRUCTION :{STRING} (v izgradnji) STR_2059_IGLOO :Iglu +STR_205B_TEAPOT_HOUSE :Čajna hiša +STR_205C_PIGGY_BANK :Prašičkova banka ##id 0x2800 STR_2800_PLANT_TREES :Posadi drevesa STR_2801_PLACE_SIGN :Postavi znak STR_2802_TREES :{WHITE}Drevesa -STR_2803_TREE_ALREADY_HERE :{WHITE}...drevo ze posajeno -STR_2804_SITE_UNSUITABLE :{WHITE}...sajenje nemogoce -STR_2805_CAN_T_PLANT_TREE_HERE :{WHITE}Nemores posaditi drevesa tukaj... +STR_2803_TREE_ALREADY_HERE :{WHITE} ... drevo že posajeno +STR_2804_SITE_UNSUITABLE :{WHITE} ... sajenje nemogoče +STR_2805_CAN_T_PLANT_TREE_HERE :{WHITE}Ne morete posaditi drevesa tukaj ... STR_2806 :{WHITE}{STRING} -STR_2808_TOO_MANY_SIGNS :{WHITE}...prevec znakov -STR_2809_CAN_T_PLACE_SIGN_HERE :{WHITE}Nemores postaviti znaka tukaj +STR_2808_TOO_MANY_SIGNS :{WHITE} ... preveč znakov +STR_2809_CAN_T_PLACE_SIGN_HERE :{WHITE}Ne morete postaviti znaka tukaj STR_280A_SIGN :Znak STR_280B_EDIT_SIGN_TEXT :{WHITE}Uredi znak -STR_280C_CAN_T_CHANGE_SIGN_NAME :{WHITE}Nemores spremeniti ime znaka... -STR_280D_SELECT_TREE_TYPE_TO_PLANT :{BLACK}Izberi vrsto drevesa za posaditev +STR_280C_CAN_T_CHANGE_SIGN_NAME :{WHITE}Ne morete spremeniti imena znaka ... +STR_280D_SELECT_TREE_TYPE_TO_PLANT :{BLACK}Izberite vrsto drevesa za posaditev STR_280E_TREES :Drevesa -STR_280F_RAINFOREST :Dezevni gozd +STR_280F_RAINFOREST :Deževni gozd STR_2810_CACTUS_PLANTS :Kaktusi ##id 0x3000 -STR_3000_RAIL_STATION_SELECTION :{WHITE}Izbira zelezniske postaje -STR_3001_AIRPORT_SELECTION :{WHITE}Izbira letalisca +STR_3000_RAIL_STATION_SELECTION :{WHITE}Izbira železniške postaje +STR_3001_AIRPORT_SELECTION :{WHITE}Izbira letališča STR_3002_ORIENTATION :{BLACK}Orientacija -STR_3003_NUMBER_OF_TRACKS :{BLACK}Stevilo peronov -STR_3004_PLATFORM_LENGTH :{BLACK}Dolzina perona -STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD :{WHITE}Preblizu druge zelezniske postaje -STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Zdruzi dve postaji -STR_3007_TOO_MANY_STATIONS_LOADING :{WHITE}Prevec postaj v tem mestu -STR_3008_TOO_MANY_STATIONS_LOADING :{WHITE}Prevec postaj na zemljevidu -STR_3008A_TOO_MANY_BUS_STOPS :{WHITE}Prevec avtobusnih postaj -STR_3008B_TOO_MANY_TRUCK_STOPS :{WHITE}Prevec tovornih postaj +STR_3003_NUMBER_OF_TRACKS :{BLACK}Število peronov +STR_3004_PLATFORM_LENGTH :{BLACK}Dolžina perona +STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD :{WHITE}Preblizu druge železniške postaje +STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Združi dve postaji +STR_3007_TOO_MANY_STATIONS_LOADING :{WHITE}Preveč postaj v tem mestu +STR_3008_TOO_MANY_STATIONS_LOADING :{WHITE}Preveč postaj na zemljevidu +STR_3008A_TOO_MANY_BUS_STOPS :{WHITE}Preveč avtobusnih postaj +STR_3008B_TOO_MANY_TRUCK_STOPS :{WHITE}Preveč tovornih postaj STR_3009_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Preblizu druge postaje STR_300A_0 :{WHITE}{STATION} {STATIONFEATURES} -STR_300B_MUST_DEMOLISH_RAILROAD :{WHITE}Najprej je potrebno zrusiti postajo -STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Preblizu sosednjemu letaliscu -STR_300E_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Najprej je potrebno zrusiti letalisce +STR_300B_MUST_DEMOLISH_RAILROAD :{WHITE}Najprej je potrebno porušiti postajo +STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Preblizu sosednjemu letališču +STR_300E_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Najprej je potrebno porušiti letališče STR_3030_RENAME_STATION_LOADING :Preimenuj postajo -STR_3031_CAN_T_RENAME_STATION :{WHITE}Ni mozno preimenovati postaje -STR_3032_RATINGS :{BLACK}Ugled +STR_3031_CAN_T_RENAME_STATION :{WHITE}Ni mogoče preimenovati postaje +STR_3032_RATINGS :{BLACK}Ocene STR_3033_ACCEPTS :{BLACK}Sprejema +STR_3034_LOCAL_RATING_OF_TRANSPORT :{BLACK}Lokalne ocene transportne storitve: ############ range for rating starts -STR_3035_APPALLING :Strasen +STR_3035_APPALLING :Strašen STR_3036_VERY_POOR :Zelo slab STR_3037_POOR :Slab -STR_3038_MEDIOCRE :Sreden +STR_3038_MEDIOCRE :Srednji STR_3039_GOOD :Dober STR_303A_VERY_GOOD :Zelo dober STR_303B_EXCELLENT :Izvrsten -STR_303C_OUTSTANDING :Sijajno +STR_303C_OUTSTANDING :Sijajen ############ range for rating ends STR_303D :{WHITE}{STRING}: {YELLOW}{STRING} ({COMMA}%) -STR_303E_NO_LONGER_ACCEPTS :{WHITE}{STATION} ne sprejema vec {STRING} -STR_303F_NO_LONGER_ACCEPTS_OR :{WHITE}{STATION} ne sprejema vec {STRING} in {STRING} -STR_3040_NOW_ACCEPTS :{WHITE}{STATION} sprejema {STRING} -STR_3041_NOW_ACCEPTS_AND :{WHITE}{STATION} sprejema {STRING} in {STRING} +STR_303E_NO_LONGER_ACCEPTS :{WHITE}{STATION} ne sprejema več {STRING} +STR_303F_NO_LONGER_ACCEPTS_OR :{WHITE}{STATION} ne sprejema več {STRING} in {STRING} +STR_3040_NOW_ACCEPTS :{WHITE}{STATION} sedaj sprejema {STRING} +STR_3041_NOW_ACCEPTS_AND :{WHITE}{STATION} sedaj sprejema {STRING} in {STRING} +STR_3042_BUS_STATION_ORIENTATION :{WHITE}Orientacija avtobusne postaje +STR_3043_TRUCK_STATION_ORIENT :{WHITE}Orientacija tovorne postaje. +STR_3046_MUST_DEMOLISH_BUS_STATION :{WHITE}Najprej morate porušiti avtobusno postajo +STR_3047_MUST_DEMOLISH_TRUCK_STATION :{WHITE}Najprej morate porušiti tovorno postajo STR_3048_STATIONS :{WHITE}{COMPANY} - {COMMA} Postaja{P "" s} STR_3049_0 :{YELLOW}{STATION} {STATIONFEATURES} STR_304A_NONE :{YELLOW}- Nobeno - -STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Preblizu drugemu pristaniscu -STR_304D_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Najprej moras porusiti pristanisce -STR_3054_SHOW_STATION_RATINGS :{BLACK}Prikaz rangov postaje +STR_304B_SITE_UNSUITABLE :{WHITE} ... neprimerna lokacija +STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Preblizu drugemu pristanišču +STR_304D_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Najprej morate porušiti pristanišče +STR_304E_SELECT_RAILROAD_STATION :{BLACK}Izberite orientacijo železniške postaje +STR_304F_SELECT_NUMBER_OF_PLATFORMS :{BLACK}Izberite število peronov železniške postaje +STR_3050_SELECT_LENGTH_OF_RAILROAD :{BLACK}Izberite dolžino železniške postaje +STR_3051_SELECT_BUS_STATION_ORIENTATION :{BLACK}Izberite orientacijo železniške postaje +STR_3052_SELECT_TRUCK_LOADING_BAY :{BLACK}Izberite orientacijo tovorne postaje +STR_3053_CENTER_MAIN_VIEW_ON_STATION :{BLACK}Pogled na postajo +STR_3054_SHOW_STATION_RATINGS :{BLACK}Prikaz ocen postaje STR_3055_CHANGE_NAME_OF_STATION :{BLACK}Spremeni ime postaje +STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO :{BLACK}Prikaži seznam sprejetega tovora +STR_3057_STATION_NAMES_CLICK_ON :{BLACK}Imena postaj - kliknite na ime za pogled na postajo +STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT :{BLACK}Izbira velikosti/tipa letališča STR_305C_0 :{STATION} {STATIONFEATURES} -STR_305E_RAILROAD_STATION :Zelezniska postaja +STR_305E_RAILROAD_STATION :Železniška postaja STR_305F_AIRCRAFT_HANGAR :Hangar -STR_3060_AIRPORT :Letalisce +STR_3060_AIRPORT :Letališče STR_3061_TRUCK_LOADING_AREA :Tovorna postaja STR_3062_BUS_STATION :Avtobusna postaja -STR_3063_SHIP_DOCK :Pristanisce -STR_3068_DOCK :{WHITE}Pristanisce +STR_3063_SHIP_DOCK :Pristanišče +STR_3064_HIGHLIGHT_COVERAGE_AREA :{BLACK}Osvetli pokritost območja +STR_3065_DON_T_HIGHLIGHT_COVERAGE :{BLACK}Ne osvetli pokritosti območja +STR_3066_COVERAGE_AREA_HIGHLIGHT :{BLACK}Osvetlitev pokritosti območja +STR_3068_DOCK :{WHITE}Pristanišče STR_3069_BUOY :Boja -STR_306A_BUOY_IN_THE_WAY :{WHITE}...boja na poti +STR_306A_BUOY_IN_THE_WAY :{WHITE} ... boja na poti +STR_306C_STATION_TOO_SPREAD_OUT :{WHITE} ... postaja preveč razširjena +STR_306D_NONUNIFORM_STATIONS_DISALLOWED :{WHITE} ... nehomogene postaje izklopljene ##id 0x3800 -STR_3801_MUST_BE_BUILT_ON_WATER :{WHITE}...potrebno je zgraditi na vodi +STR_3800_SHIP_DEPOT_ORIENTATION :{WHITE}Orientacija ladjedelnice +STR_3801_MUST_BE_BUILT_ON_WATER :{WHITE} ... zgrajeno mora biti na vodi +STR_3802_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Ne morem zgraditi ladjedelnice tukaj ... +STR_3803_SELECT_SHIP_DEPOT_ORIENTATION :{BLACK}Izberite orientacijo ladjedelnice STR_3804_WATER :Voda -STR_3805_COAST_OR_RIVERBANK :Obala ali recni breg -STR_3807_CAN_T_BUILD_ON_WATER :{WHITE}...Ni mozno graditi na vodi +STR_3805_COAST_OR_RIVERBANK :Obala ali nabrežje +STR_3806_SHIP_DEPOT :Ladjedelnica +STR_3807_CAN_T_BUILD_ON_WATER :{WHITE} ... Ni mogoče graditi na vodi ##id 0x4000 STR_4000_SAVE_GAME :{WHITE}Shrani igro -STR_4001_LOAD_GAME :{WHITE}Nalozi igro +STR_4001_LOAD_GAME :{WHITE}Naloži igro STR_4002_SAVE :{BLACK}Shrani -STR_4003_DELETE :{BLACK}Izbrisi +STR_4003_DELETE :{BLACK}Izbriši STR_4004 :{COMPANY}, {DATE_LONG} STR_4005_BYTES_FREE :{BLACK}{COMMA} megabajtov{P "" s} prosto -STR_4006_UNABLE_TO_READ_DRIVE :{BLACK}Ni mozno brati diska +STR_4006_UNABLE_TO_READ_DRIVE :{BLACK}Ni mogoče brati pogona STR_4007_GAME_SAVE_FAILED :{WHITE}Shranjevanje igre ni uspelo -STR_4008_UNABLE_TO_DELETE_FILE :{WHITE}Ni mozno izbrisati datoteko +STR_4008_UNABLE_TO_DELETE_FILE :{WHITE}Ni mogoče izbrisati datoteke STR_4009_GAME_LOAD_FAILED :{WHITE}Nalaganje igre ni uspelo -STR_400A_LIST_OF_DRIVES_DIRECTORIES :{BLACK}Seznam diskov, map in shranjenih iger +STR_400A_LIST_OF_DRIVES_DIRECTORIES :{BLACK}Seznam pogonov, zemljevidov in shranjenih iger STR_400B_CURRENTLY_SELECTED_NAME :{BLACK}Trenutno izbrano ime za shranjevanje -STR_400C_DELETE_THE_CURRENTLY_SELECTED :{BLACK}Izbrisi trenutno izbrano shranjeno igro -STR_400D_SAVE_THE_CURRENT_GAME_USING :{BLACK}Shrani trenutno igro, z izbranim imenom +STR_400C_DELETE_THE_CURRENTLY_SELECTED :{BLACK}Izbriši trenutno izbrano shranjeno igro +STR_400D_SAVE_THE_CURRENT_GAME_USING :{BLACK}Shrani trenutno igro z izbranim imenom STR_400E_SELECT_NEW_GAME_TYPE :{WHITE}Izberi tip nove igre -STR_4010_GENERATE_RANDOM_NEW_GAME :Ustvari nakljucno novo igro +STR_400F_SELECT_SCENARIO_GREEN_PRE :{BLACK}Izberite scenarij (zeleno), prednastavljeno igro (modro) ali naključno novo igro +STR_4010_GENERATE_RANDOM_NEW_GAME :Ustvari naključno novo igro +STR_4011_LOAD_HEIGHTMAP :{WHITE}Naloži višinsko karto ##id 0x4800 STR_4800_IN_THE_WAY :{WHITE}{STRING} na poti @@ -1218,36 +1391,36 @@ STR_4804_SAWMILL :Žaga STR_4805_FOREST :Gozd STR_4806_OIL_REFINERY :Naftna rafinerija -STR_4807_OIL_RIG :Naftna ploscad +STR_4807_OIL_RIG :Naftna ploščad STR_4808_FACTORY :Tovarna STR_4809_PRINTING_WORKS :Tiskarna -STR_480A_STEEL_MILL :Zelezarna +STR_480A_STEEL_MILL :Železarna STR_480B_FARM :Kmetija STR_480C_COPPER_ORE_MINE :Rudnik bakra STR_480D_OIL_WELLS :Naftni izviri STR_480E_BANK :Banka -STR_480F_FOOD_PROCESSING_PLANT :Zivilska tovarna +STR_480F_FOOD_PROCESSING_PLANT :Predelava živil STR_4810_PAPER_MILL :Papirnica STR_4811_GOLD_MINE :Rudnik zlata STR_4812_BANK :Banka STR_4813_DIAMOND_MINE :Rudnik diamantov -STR_4814_IRON_ORE_MINE :Rudnik zeleza +STR_4814_IRON_ORE_MINE :Rudnik železa STR_4815_FRUIT_PLANTATION :Sadovnjak -STR_4816_RUBBER_PLANTATION :Plantaza kavcuka +STR_4816_RUBBER_PLANTATION :Plantaža kavčuka STR_4817_WATER_SUPPLY :Vodno zajetje -STR_4818_WATER_TOWER :Vodni stolp +STR_4818_WATER_TOWER :Vodovodni stolp STR_4819_FACTORY :Tovarna STR_481A_FARM :Kmetija -STR_481B_LUMBER_MILL :Zaga +STR_481B_LUMBER_MILL :Žaga STR_481C_COTTON_CANDY_FOREST :Gozd sladkorne pene -STR_481D_CANDY_FACTORY :Tovarna slascic +STR_481D_CANDY_FACTORY :Tovarna slaščic STR_481E_BATTERY_FARM :Farma baterij -STR_481F_COLA_WELLS :Izviri cockte -STR_4820_TOY_SHOP :Trgovina z igracami -STR_4821_TOY_FACTORY :Tovarna igrac +STR_481F_COLA_WELLS :Izvir Cockte +STR_4820_TOY_SHOP :Trgovina z igračami +STR_4821_TOY_FACTORY :Tovarna igrač STR_4822_PLASTIC_FOUNTAINS :Vodnjaki plastike -STR_4823_FIZZY_DRINK_FACTORY :Tovarna gaziranih pijac -STR_4824_BUBBLE_GENERATOR :Generator mehurckov +STR_4823_FIZZY_DRINK_FACTORY :Tovarna gaziranih pijač +STR_4824_BUBBLE_GENERATOR :Generator mehurčkov STR_4825_TOFFEE_QUARRY :Jama karamele STR_4826_SUGAR_MINE :Rudnik sladkorja @@ -1257,52 +1430,73 @@ STR_4829_REQUIRES :{BLACK}Potrebuje:: {YELLOW}{STRING}, {STRING}, {STRING} ############ range for requires ends -STR_482A_PRODUCTION_LAST_MONTH :{BLACK}Proizvodnja prejsnega meseca: -STR_482B_TRANSPORTED :{YELLOW}{CARGO}{BLACK} ({COMMA}% transportirano) +STR_482A_PRODUCTION_LAST_MONTH :{BLACK}Proizvodnja prejšnjega meseca: +STR_482B_TRANSPORTED :{YELLOW}{CARGO}{BLACK} ({COMMA}% oddano) +STR_482C_CENTER_THE_MAIN_VIEW_ON :{BLACK}Pogled na industrijo +STR_482D_NEW_UNDER_CONSTRUCTION :{BLACK}{BIGFONT}Nov {STRING} v izgradnji blizu mesta {TOWN}! +STR_482E_NEW_BEING_PLANTED_NEAR :{BLACK}{BIGFONT}Nov {STRING} v izgradnji blizu mesta {TOWN}! STR_482F_COST :{BLACK}Cena: {YELLOW}{CURRENCY} -STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Tukaj ni mozno zgraditi tega tipa industrije... -STR_4831_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... gozd je mozno nasaditi samo nad snezno mejo -STR_483B_CAN_ONLY_BE_POSITIONED :{WHITE}...mozno je samo zgraditi ob robu zemljevida +STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Tukaj ni mogoče zgraditi tega tipa industrije ... +STR_4831_FOREST_CAN_ONLY_BE_PLANTED :{WHITE} ... gozd je mogoče posaditi samo nad snežno mejo +STR_4832_ANNOUNCES_IMMINENT_CLOSURE :{BLACK}{BIGFONT}{INDUSTRY} napoveduje takojšnje zaprtje! +STR_4833_SUPPLY_PROBLEMS_CAUSE_TO :{BLACK}{BIGFONT}Zaradi težav z zalogami {INDUSTRY} napoveduje takojšnje zaprtje! +STR_4834_LACK_OF_NEARBY_TREES_CAUSES :{BLACK}{BIGFONT}Zaradi pomanjkanja bližnjih dreves {INDUSTRY} napoveduje takojšnje zaprtje! +STR_4835_INCREASES_PRODUCTION :{BLACK}{BIGFONT}{INDUSTRY} povečuje proizvodnjo! +STR_4836_NEW_COAL_SEAM_FOUND_AT :{BLACK}{BIGFONT}Nova žila premoga najdena v {INDUSTRY}!{}Proizvodnja se bo podvojila! +STR_4837_NEW_OIL_RESERVES_FOUND :{BLACK}{BIGFONT}Nove rezerve nafte odkrite v {INDUSTRY}!{}Proizvodnja se bo podvojila! +STR_4838_IMPROVED_FARMING_METHODS :{BLACK}{BIGFONT}Izboljšane metode pridelovanja v {INDUSTRY} bodo podvojile proizvodnjo! +STR_4839_PRODUCTION_DOWN_BY_50 :{BLACK}{BIGFONT}{INDUSTRY} proizvodnja zmanjšana za 50% +STR_483A_INSECT_INFESTATION_CAUSES :{BLACK}{BIGFONT}Insekti povzročili opustošenje v {INDUSTRY}!{}Proizvodnja zmanjšana za 50% +STR_483B_CAN_ONLY_BE_POSITIONED :{WHITE} ... mogoče zgraditi samo ob robu zemljevida ##id 0x5000 STR_5000_TRAIN_IN_TUNNEL :{WHITE}Vlak v tunelu STR_5001_ROAD_VEHICLE_IN_TUNNEL :{WHITE}Cestno vozilo v tunelu -STR_5006_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Potrebno je najprej zakopati drugi tunel -STR_5007_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Potebno je najprej porusiti most -STR_5008_CANNOT_START_AND_END_ON :{WHITE}Ni mozno zaceti in koncati v isti tocki -STR_5009_LEVEL_LAND_OR_WATER_REQUIRED :{WHITE}Potrebno je izravnati teren ali vodo pod mostom -STR_500A_START_AND_END_MUST_BE_IN :{WHITE}Zacetek in konec morata biti na enaki visini +STR_5003_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Obstoječi tunel v napoto +STR_5005_UNABLE_TO_EXCAVATE_LAND :{WHITE}Ni mogoče izkopati zaključka tunela na drugem koncu +STR_5006_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Potrebno je najprej podreti drugi tunel +STR_5007_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Potebno je najprej porušiti most +STR_5008_CANNOT_START_AND_END_ON :{WHITE}Ni mogoče začeti in končati v isti točki +STR_5009_LEVEL_LAND_OR_WATER_REQUIRED :{WHITE}Raven teren ali vodovje zahtevano pod mostom +STR_500A_START_AND_END_MUST_BE_IN :{WHITE}Začetek in konec morata biti na isti višini +STR_500B_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Lokacija neprimerna za vhod v tunel STR_500D :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY} -STR_500E_SUSPENSION_STEEL :Viseci, Zelezni -STR_500F_GIRDER_STEEL :Nosilni, Zelezni -STR_5010_CANTILEVER_STEEL :Nosilni, Zelezni -STR_5011_SUSPENSION_CONCRETE :Viseci, Betonski +STR_500E_SUSPENSION_STEEL :Viseči, Jekleni +STR_500F_GIRDER_STEEL :Nosilni, Jekleni +STR_5010_CANTILEVER_STEEL :Nosilen, Jeklen +STR_5011_SUSPENSION_CONCRETE :Viseč, Betonski STR_5012_WOODEN :Lesen STR_5013_CONCRETE :Betonski -STR_5014_TUBULAR_STEEL :Cevast, Zelezen -STR_5015_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Tukaj ni mozno zgraditi most... -STR_5016_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Tukaj ni mozno zgraditi tunel -STR_5017_RAILROAD_TUNNEL :Zelezniski tunel -STR_5018_ROAD_TUNNEL :Cestni tunel -STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE :Obeseni zelezni zelezniski most -STR_501C_STEEL_GIRDER_RAIL_BRIDGE :Nosilni zelezni zelezniski most -STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE :Nosilni zelezni zelezniski most -STR_501E_REINFORCED_CONCRETE_SUSPENSION :Obeseni betonsko okrepljeni zelezniski most -STR_501F_WOODEN_RAIL_BRIDGE :Lesen zelezniski most -STR_5020_CONCRETE_RAIL_BRIDGE :Betonski zelezniski most -STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE :Obeseni zelezni cestni most -STR_5022_STEEL_GIRDER_ROAD_BRIDGE :Nosilni zelezni cestni most -STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE :Nosilni zelezni cestni most -STR_5024_REINFORCED_CONCRETE_SUSPENSION :Obeseni betonsko okrepljeni cestni most +STR_5014_TUBULAR_STEEL :Cevast, Jeklen +STR_BRIDGE_TUBULAR_SILICON :Cevast, Silicijev +STR_5015_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Tukaj ni mogoče zgraditi mostu ... +STR_5016_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Tukaj ni mogoče zgraditi tunela ... +STR_5017_RAILROAD_TUNNEL :Železniški predor +STR_5018_ROAD_TUNNEL :Cestni predor +STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE :Viseč jekleni železniški most +STR_501C_STEEL_GIRDER_RAIL_BRIDGE :Nosilen jeklen železniški most +STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE :Nosilen jeklen železniški most +STR_501E_REINFORCED_CONCRETE_SUSPENSION :Ojačan viseč betonski železniški most +STR_501F_WOODEN_RAIL_BRIDGE :Lesen železniški most +STR_5020_CONCRETE_RAIL_BRIDGE :Betonski železniški most +STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE :Viseč jeklen cestni most +STR_5022_STEEL_GIRDER_ROAD_BRIDGE :Nosilen jeklen cestni most +STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE :Jeklen cestni most na nosilcih +STR_5024_REINFORCED_CONCRETE_SUSPENSION :Ojačan viseč betonski cestni most STR_5025_WOODEN_ROAD_BRIDGE :Lesen cestni most STR_5026_CONCRETE_ROAD_BRIDGE :Betonski cestni most -STR_5027_TUBULAR_RAIL_BRIDGE :Cevni zelezniski most -STR_5028_TUBULAR_ROAD_BRIDGE :Cevni cestni most +STR_5027_TUBULAR_RAIL_BRIDGE :Cevast železniški most +STR_5028_TUBULAR_ROAD_BRIDGE :Cevast cestni most ##id 0x5800 STR_5800_OBJECT_IN_THE_WAY :{WHITE}Objekt na poti STR_5801_TRANSMITTER :Oddajnik STR_5802_LIGHTHOUSE :Svetilnik +STR_5803_COMPANY_HEADQUARTERS :Sedež podjetja +STR_5804_COMPANY_HEADQUARTERS_IN :{WHITE} ... sedež podjetja na poti +STR_5805_COMPANY_OWNED_LAND :Ozemlje v lasti podjetja +STR_5806_CAN_T_PURCHASE_THIS_LAND :{WHITE}Ni mogoče kupiti tega zemljišča ... +STR_5807_YOU_ALREADY_OWN_IT :{WHITE} ... ste že lastnik! ############ WARNING, using range 0x6000 for strings that are stored in the savegame @@ -1319,43 +1513,44 @@ ############ end of savegame specific region! ##id 0x6800 -STR_6800_DIFFICULTY_LEVEL :{WHITE}Tezavnostna stopnja +STR_6800_DIFFICULTY_LEVEL :{WHITE}Težavnostna stopnja ############ range for difficulty levels starts STR_6801_EASY :{BLACK}Preprosto STR_6802_MEDIUM :{BLACK}Srednje -STR_6803_HARD :{BLACK}Tezko +STR_6803_HARD :{BLACK}Težko STR_6804_CUSTOM :{BLACK}Po meri ############ range for difficulty levels ends ############ range for difficulty settings starts -STR_6805_MAXIMUM_NO_COMPETITORS :{LTBLUE}Najvecje stevilo nasprotnikov: {ORANGE}{COMMA} -STR_6806_COMPETITOR_START_TIME :{LTBLUE}Nasportnikov zacetni cas: {ORANGE}{STRING} -STR_6807_NO_OF_TOWNS :{LTBLUE}St. mest: {ORANGE}{STRING} -STR_6808_NO_OF_INDUSTRIES :{LTBLUE}St. industrije: {ORANGE}{STRING} -STR_6809_MAXIMUM_INITIAL_LOAN_000 :{LTBLUE}Najvisje mozno posojilo: {ORANGE}{CURRENCY} +STR_6805_MAXIMUM_NO_COMPETITORS :{LTBLUE}Največje število nasprotnikov: {ORANGE}{COMMA} +STR_6806_COMPETITOR_START_TIME :{LTBLUE}Nasportnikov začetni čas: {ORANGE}{STRING} +STR_6807_NO_OF_TOWNS :{LTBLUE}Št. mest: {ORANGE}{STRING} +STR_6808_NO_OF_INDUSTRIES :{LTBLUE}Št. industrij: {ORANGE}{STRING} +STR_6809_MAXIMUM_INITIAL_LOAN_000 :{LTBLUE}Najvišje možno posojilo: {ORANGE}{CURRENCY} STR_680A_INITIAL_INTEREST_RATE :{LTBLUE}Obrestna mera: {ORANGE}{COMMA}% -STR_680B_VEHICLE_RUNNING_COSTS :{LTBLUE}Cena vzdrzevanja vozil: {ORANGE}{STRING} -STR_680C_CONSTRUCTION_SPEED_OF_COMPETITOR :{LTBLUE}Hitrost grajenja nasportnikov: {ORANGE}{STRING} -STR_680D_INTELLIGENCE_OF_COMPETITORS :{LTBLUE}Intiligenca naspornikov: {ORANGE}{STRING} +STR_680B_VEHICLE_RUNNING_COSTS :{LTBLUE}Cena vzdrževanja vozil: {ORANGE}{STRING} +STR_680C_CONSTRUCTION_SPEED_OF_COMPETITOR :{LTBLUE}Nasprotnikova hitrost gradnje: {ORANGE}{STRING} +STR_680D_INTELLIGENCE_OF_COMPETITORS :{LTBLUE}Inteligenca nasprotnikov: {ORANGE}{STRING} STR_680E_VEHICLE_BREAKDOWNS :{LTBLUE}Okvare vozil: {ORANGE}{STRING} +STR_680F_SUBSIDY_MULTIPLIER :{LTBLUE}Večkratnik subvencij: {ORANGE}{STRING} STR_6810_COST_OF_CONSTRUCTION :{LTBLUE}Cena gradnje: {ORANGE}{STRING} STR_6811_TERRAIN_TYPE :{LTBLUE}Tip terena: {ORANGE}{STRING} -STR_6812_QUANTITY_OF_SEA_LAKES :{LTBLUE}Kolicina vode in morij: {ORANGE}{STRING} +STR_6812_QUANTITY_OF_SEA_LAKES :{LTBLUE}Količina vodovij: {ORANGE}{STRING} STR_6813_ECONOMY :{LTBLUE}Ekonomija: {ORANGE}{STRING} -STR_6814_TRAIN_REVERSING :{LTBLUE}Obracanje vlakov: {ORANGE}{STRING} +STR_6814_TRAIN_REVERSING :{LTBLUE}Obračanje vlakov: {ORANGE}{STRING} STR_6815_DISASTERS :{LTBLUE}Katastrofe: {ORANGE}{STRING} -STR_16816_CITY_APPROVAL :{LTBLUE}Odnos mestnega sveta glede restrukturiranja: {ORANGE}{STRING} +STR_16816_CITY_APPROVAL :{LTBLUE}Odnos mestnega sveta do rekonstrukcije: {ORANGE}{STRING} ############ range for difficulty settings ends -STR_26816_NONE :Noben +STR_26816_NONE :Nič STR_6816_LOW :Nizko STR_6817_NORMAL :Normalno STR_6818_HIGH :Visoko STR_6819 :{BLACK}{SMALLLEFTARROW} STR_681A :{BLACK}{SMALLRIGHTARROW} -STR_681B_VERY_SLOW :Zelo pocasno -STR_681C_SLOW :Pocasno +STR_681B_VERY_SLOW :Zelo počasno +STR_681C_SLOW :Počasno STR_681D_MEDIUM :Srednje STR_681E_FAST :Hitro STR_681F_VERY_FAST :Zelo hitro @@ -1364,141 +1559,337 @@ STR_6821_MEDIUM :Srednje STR_6822_HIGH :Visoko STR_6823_NONE :Nobeno -STR_6824_REDUCED :Zmanjsano +STR_6824_REDUCED :Zmanjšano STR_6825_NORMAL :Normalno STR_6826_X1_5 :x1,5 STR_6827_X2 :x2 STR_6828_X3 :x3 STR_6829_X4 :x4 -STR_682A_VERY_FLAT :Zelo polozno -STR_682B_FLAT :Polozno +STR_682A_VERY_FLAT :Zelo položno +STR_682B_FLAT :Položno STR_682C_HILLY :Hribovito STR_682D_MOUNTAINOUS :Gorato STR_682E_STEADY :Stalno -STR_682F_FLUCTUATING :Fluktacija -STR_6830_IMMEDIATE :Takojsno +STR_682F_FLUCTUATING :Fluktuacija +STR_6830_IMMEDIATE :Takojšnje STR_6831_3_MONTHS_AFTER_PLAYER :3 mesece za igralcem STR_6832_6_MONTHS_AFTER_PLAYER :6 mesecev za igralcem STR_6833_9_MONTHS_AFTER_PLAYER :9 mesecev za igralcem -STR_6834_AT_END_OF_LINE_AND_AT_STATIONS :Na koncu linije, in na postajah +STR_6834_AT_END_OF_LINE_AND_AT_STATIONS :Na koncu linije in na postajah STR_6835_AT_END_OF_LINE_ONLY :Samo na koncu linije STR_6836_OFF :Izklopljeno STR_6837_ON :Vklopljeno -STR_6838_SHOW_HI_SCORE_CHART :{BLACK}Pokazi tabelo najboljsih +STR_6838_SHOW_HI_SCORE_CHART :{BLACK}Pokaži tabelo najboljših STR_6839_PERMISSIVE :Dopustno STR_683A_TOLERANT :Tolerantno -STR_683B_HOSTILE :Sovrazno +STR_683B_HOSTILE :Sovražno ##id 0x7000 STR_7000 : STR_7001 :{WHITE}{COMPANY} {BLACK}{PLAYERNAME} -STR_7002_PLAYER :(Igralce {COMMA}) +STR_7002_PLAYER :(Igralec {COMMA}) STR_7004_NEW_FACE :{BLACK}Nov obraz +STR_7005_COLOR_SCHEME :{BLACK}Barva +STR_7006_COLOR_SCHEME :{GOLD}Barva: +STR_7007_NEW_COLOR_SCHEME :{WHITE}Nova barva +STR_7008_COMPANY_NAME :{BLACK}Ime podjetja +STR_7009_PRESIDENT_NAME :{BLACK}Ime lastnika +STR_700A_COMPANY_NAME :Ime podjetja +STR_700B_PRESIDENT_S_NAME :Ime lastnika +STR_700C_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Ni mogoče spremeniti imena podjetja ... +STR_700D_CAN_T_CHANGE_PRESIDENT :{WHITE}Ni mogoče spremeniti imena lastnika ... +STR_700E_FINANCES :{WHITE}{COMPANY} Finance {BLACK}{PLAYERNAME} +STR_700F_EXPENDITURE_INCOME :{WHITE}Izdatki/Prilivi +STR_7011_CONSTRUCTION :{GOLD}Konstrukcija +STR_7012_NEW_VEHICLES :{GOLD}Nova vozila +STR_7013_TRAIN_RUNNING_COSTS :{GOLD}Cena delovanja vlakov +STR_7014_ROAD_VEH_RUNNING_COSTS :{GOLD}Cena delovanja cestnih vozil +STR_7015_AIRCRAFT_RUNNING_COSTS :{GOLD}Cena delovanja letal +STR_7016_SHIP_RUNNING_COSTS :{GOLD}Cena delovanja ladij +STR_7017_PROPERTY_MAINTENANCE :{GOLD}Vzdrževanje +STR_7018_TRAIN_INCOME :{GOLD}Priliv vlakov +STR_7019_ROAD_VEHICLES_INCOME :{GOLD}Priliv cestnih vozil +STR_701A_AIRCRAFT_INCOME :{GOLD}Priliv letal +STR_701B_SHIP_INCOME :{GOLD}Priliv ladij +STR_701C_LOAN_INTEREST :{GOLD}Obresti posojila +STR_701D_OTHER :{GOLD}Drugo +STR_7020_TOTAL :{WHITE}Skupaj: +STR_7022_INCOME_GRAPH :{WHITE}Graf priliva +STR_7025_OPERATING_PROFIT_GRAPH :{WHITE}Graf čistega dobička +STR_7026_BANK_BALANCE :{WHITE}Stanje na banki +STR_7027_LOAN :{WHITE}Posojilo +STR_7029_BORROW :{BLACK}Sposodi {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} +STR_702A_REPAY :{BLACK}Odplačaj {SKIP}{SKIP}{SKIP}{SKIP}{CURRENCY} +STR_702B_MAXIMUM_PERMITTED_LOAN :{WHITE} ... najvišje posojilo je {CURRENCY} +STR_702C_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Ni si mogoče izposoditi več denarja ... +STR_702D_LOAN_ALREADY_REPAYED :{WHITE} ... ni posojila za odplačati +STR_702E_REQUIRED :{WHITE}...{CURRENCY} potrebno +STR_702F_CAN_T_REPAY_LOAN :{WHITE}Ni mogoče odplačati posojila ... +STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT :{BLACK}Izberi nov obraz za lastnika +STR_7031_CHANGE_THE_COMPANY_VEHICLE :{BLACK}Spremeni barvo vozil podjetja +STR_7032_CHANGE_THE_PRESIDENT_S :{BLACK}Spremeni ime lastnika +STR_7033_CHANGE_THE_COMPANY_NAME :{BLACK}Spremeni ime podjetja +STR_7034_CLICK_ON_SELECTED_NEW_COLOR :{BLACK}Kliknite na željeno barvo +STR_7035_INCREASE_SIZE_OF_LOAN :{BLACK}Povečaj višino posojila +STR_7036_REPAY_PART_OF_LOAN :{BLACK}Odplačaj del posojila +STR_7037_PRESIDENT :{WHITE}{PLAYERNAME}{}{GOLD}(Lastnik) +STR_7038_INAUGURATED :{GOLD}Postavljen spomenik: {WHITE}{NUM} +STR_7039_VEHICLES :{GOLD}Vozila: STR_TRAINS :{WHITE}{COMMA} vlak{P "" s} -STR_7049_SELECT_MALE_FACES :{BLACK}Izberi mosko sliko -STR_704A_SELECT_FEMALE_FACES :{BLACK}Izberi zensko sliko -STR_704B_GENERATE_RANDOM_NEW_FACE :{BLACK}Naredi nakljucno novo sliko -STR_704C_KEY :{BLACK}Kljuc -STR_705C_BANKRUPT :{BLACK}{BIGFONT}Bankrotiral si! -STR_7060_CAN_T_BUY_COMPANY :{WHITE}Ne mores kupiti podjetja... +STR_AIRCRAFT :{WHITE}{COMMA} letalo +STR_7042_NONE :{WHITE}Nič +STR_7043_FACE_SELECTION :{WHITE}Izbira obraza +STR_7044_MALE :{BLACK}Moški +STR_7045_FEMALE :{BLACK}Ženska +STR_7046_NEW_FACE :{BLACK}Nov obraz +STR_7047_CANCEL_NEW_FACE_SELECTION :{BLACK}Prekliči izbiro novega obraza +STR_7048_ACCEPT_NEW_FACE_SELECTION :{BLACK}Sprejmi nov obraz +STR_7049_SELECT_MALE_FACES :{BLACK}Izberi moške slike +STR_704A_SELECT_FEMALE_FACES :{BLACK}Izberi ženske slike +STR_704B_GENERATE_RANDOM_NEW_FACE :{BLACK}Naredi naključno novo sliko +STR_704C_KEY :{BLACK}Ključ +STR_704D_SHOW_KEY_TO_GRAPHS :{BLACK}Prikaži ključe grafov +STR_704E_KEY_TO_COMPANY_GRAPHS :{WHITE}Ključi grafov podjetij +STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY :{BLACK}Kliknite sem za napise podjetja na grafu vključeno/izključeno +STR_7050_UNITS_OF_CARGO_DELIVERED :{WHITE}Enot tovora dostavljenega +STR_7051_COMPANY_PERFORMANCE_RATINGS :{WHITE}Ocene podjetja (max=1000) +STR_7052_COMPANY_VALUES :{WHITE}Vrednosti podjetij +STR_7053_COMPANY_LEAGUE_TABLE :{WHITE}Seznam najboljših podjetij +STR_7056_TRANSPORT_COMPANY_IN_TROUBLE :{BLACK}{BIGFONT}Podjetje v težavah! +STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED :Podjetje {BLACK}{BIGFONT}{COMPANY} bo prodano ali prisiljeno v stečajni postopek, če se stanje kmalu ne izboljša! +STR_7058_PRESIDENT :{BLACK}{PLAYERNAME}{}(Lastnik) +STR_7059_TRANSPORT_COMPANY_MERGER :{BLACK}{BIGFONT}Združevalec podjetij! +STR_705A_HAS_BEEN_SOLD_TO_FOR :Podjetje {BLACK}{BIGFONT}{COMPANY} je bilo prodano podejtju {COMPANY} za {CURRENCY}! +STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT :{WHITE}Iščemo novega lastnika, ki bi prevzel naše podjetje.{}{}Ali bi želeli kupiti podjetje {COMPANY} za {CURRENCY}? +STR_705C_BANKRUPT :{BLACK}{BIGFONT}Bankrotirali ste! +STR_705D_HAS_BEEN_CLOSED_DOWN_BY :Investitorji so zaprli podjetje {BLACK}{BIGFONT}{COMPANY} in prodali vse imetje! +STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED :{BLACK}{BIGFONT}Ustanoveljno novo podjetje! +STR_705F_STARTS_CONSTRUCTION_NEAR :Podjetje {BLACK}{BIGFONT}{COMPANY} začenja gradnjo blizu mesta {TOWN}! +STR_7060_CAN_T_BUY_COMPANY :{WHITE}Ne morete kupiti podjetja ... +STR_7061_CARGO_PAYMENT_RATES :{WHITE}Ocene plačevanja tovora +STR_7062_DAYS_IN_TRANSIT :{BLACK}{TINYFONT}Dni v prevozu +STR_7063_PAYMENT_FOR_DELIVERING :{BLACK}{TINYFONT}Plačilo za dostavo 10 enot (ali 10.000 litrov) tovora za razdaljo 20 kvadratkov +STR_7064_TOGGLE_GRAPH_FOR_CARGO :{BLACK}Prikaži graf za tip tovora vključen/izključen STR_7065 :{BLACK}{TINYFONT}{STRING} -STR_7066_ENGINEER :Inzenir -STR_7067_TRAFFIC_MANAGER :Upravnik prometa +STR_7066_ENGINEER :Inženir +STR_7067_TRAFFIC_MANAGER :Vodja prometa +STR_7068_TRANSPORT_COORDINATOR :Koordinator transporta +STR_7069_ROUTE_SUPERVISOR :Nadzornik dostave STR_706A_DIRECTOR :Direktor +STR_706B_CHIEF_EXECUTIVE :Vrhovni direktor STR_706C_CHAIRMAN :Minister STR_706D_PRESIDENT :Predsednik STR_706E_TYCOON :Velekapitalist -STR_706F_BUILD_HQ :{BLACK}Izgradi sedež podjetja +STR_706F_BUILD_HQ :{BLACK}Zgradi sedež podjetja +STR_7070_BUILD_COMPANY_HEADQUARTERS :{BLACK}Zgradi sedež podjetja / poglej sedež podjetja +STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Ne morem zgraditi sedeža podjetja STR_7072_VIEW_HQ :{BLACK}Poglej sedež podjetja +STR_COMPANY_PASSWORD :{BLACK}Geslo +STR_COMPANY_PASSWORD_TOOLTIP :{BLACK}Zaščitite svoje podjetje z geslom, da preprečite priključitev drugih uporabnikov k podjetju. +STR_7073_WORLD_RECESSION_FINANCIAL :{BIGFONT}{BLACK}Svetovna recesija!{}{}Ekonomisti se bojijo najhujšega ob trenutnem poteku dogodkov! +STR_7074_RECESSION_OVER_UPTURN_IN :{BIGFONT}{BLACK}Konec recesije!{}{}Izboljšanje trgovanja povečuje zaupanje domače industrije, gospodarstvo napreduje! +STR_7075_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Menjaj veliko/majhno velikost okna +STR_7076_COMPANY_VALUE :{GOLD}Vrednost podjetja: {WHITE}{CURRENCY64} +STR_7077_BUY_25_SHARE_IN_COMPANY :{BLACK}Kupi 25% delnic podjetja +STR_7078_SELL_25_SHARE_IN_COMPANY :{BLACK}Prodaj 25% delnic podjetja +STR_7079_BUY_25_SHARE_IN_THIS_COMPANY :{BLACK}Kupi 25% delnic tega podjetja +STR_707A_SELL_25_SHARE_IN_THIS_COMPANY :{BLACK}Prodaj 25% delnic tega podjetja +STR_707B_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Ni mogoče kupiti 25% tržnega deleža tega podjetja ... +STR_707C_CAN_T_SELL_25_SHARE_IN :{WHITE}Ni mogoče prodati 25% tržnega deleža tega podjetja ... +STR_707D_OWNED_BY :{WHITE}({COMMA}% last podjetja {COMPANY}) +STR_707E_OWNED_BY_OWNED_BY :{WHITE}({COMMA}% last podjetja {COMPANY}{} {COMMA}% last podjetja {COMPANY}) +STR_707F_HAS_BEEN_TAKEN_OVER_BY :Podjetje {BLACK}{BIGFONT}{COMPANY} je bilo prevzeto iz strani podjetja {COMPANY}! +STR_7080_PROTECTED :{WHITE}Podjetje še ni dovolj staro, da bi lahko trgovalo z lastnimi delnicami ... + + ##id 0x8000 -STR_804F_CANDY_VAN :Tovornjak slascic -STR_8050_TOY_VAN :Tovornjak igrac +STR_8017_SH_30_ELECTRIC :SH '30' (Električen) +STR_8018_SH_40_ELECTRIC :SH '40' (Električen) +STR_8019_T_I_M_ELECTRIC :'T.I.M.' (Električen) +STR_801A_ASIASTAR_ELECTRIC :'AsiaStar' (Električen) +STR_801B_PASSENGER_CAR :Potniški prevoz +STR_801C_MAIL_VAN :Kamion s pošto +STR_801D_COAL_CAR :Kamion s premogom +STR_801E_OIL_TANKER :Naftni tanker +STR_801F_LIVESTOCK_VAN :Kamion z živino +STR_8020_GOODS_VAN :Kamion z dobrinami +STR_8021_GRAIN_HOPPER :Kamion z žitom +STR_8022_WOOD_TRUCK :Kamion z lesom +STR_8023_IRON_ORE_HOPPER :Kamion z železovo rudo +STR_8024_STEEL_TRUCK :Kamion z jeklom +STR_8025_ARMORED_VAN :Oklepen kamion +STR_8026_FOOD_VAN :Kamion s hrano +STR_8027_PAPER_TRUCK :Kamion s papirjem +STR_8028_COPPER_ORE_HOPPER :Kamion z bakrovo rudo +STR_8029_WATER_TANKER :Cisterna z vodo +STR_802A_FRUIT_TRUCK :Kamion s sadjem +STR_802B_RUBBER_TRUCK :Kamion z gumo +STR_802C_SUGAR_TRUCK :Kamion s sladkorjem +STR_802D_COTTON_CANDY_HOPPER :Kamion s sladkorno peno +STR_802E_TOFFEE_HOPPER :Kamion s toffee +STR_802F_BUBBLE_VAN :Kamion z mehurčki +STR_8030_COLA_TANKER :Kamion s Cockto +STR_8031_CANDY_VAN :Kamion s sladkarijami +STR_8032_TOY_VAN :Kamion z igračami +STR_8033_BATTERY_TRUCK :Kamion z baterijami +STR_8034_FIZZY_DRINK_TRUCK :Kamion z gaziranimi pijačami +STR_8035_PLASTIC_TRUCK :Kamion s plastiko +STR_8036_X2001_ELECTRIC :'X2001' (Električen) +STR_8037_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Električen) +STR_8039_PASSENGER_CAR :Prevoz potnikov +STR_803A_MAIL_VAN :Tovornjak pošte +STR_803B_COAL_CAR :Tovornjak premoga +STR_803C_OIL_TANKER :Cisterna z nafto +STR_803D_LIVESTOCK_VAN :Tovornjak živine +STR_803E_GOODS_VAN :Tovornjak dobrin +STR_803F_GRAIN_HOPPER :Tovornjak žita +STR_8040_WOOD_TRUCK :Tovornjak lesa +STR_8041_IRON_ORE_HOPPER :Tovornjak železove rude +STR_8042_STEEL_TRUCK :Tovornjak jekla +STR_8043_ARMORED_VAN :Oklepen tovornjak +STR_8044_FOOD_VAN :Tovornjak hrane +STR_8045_PAPER_TRUCK :Tovornjak papirja +STR_8046_COPPER_ORE_HOPPER :Tovornjak bakrove rude +STR_8047_WATER_TANKER :Cisterna z vodo +STR_8048_FRUIT_TRUCK :Tovornjak sadja +STR_8049_RUBBER_TRUCK :Tovornjak gume +STR_804A_SUGAR_TRUCK :Tovornjak sladkorja +STR_804B_COTTON_CANDY_HOPPER :Tovornjak sladkorne pene +STR_804C_TOFFEE_HOPPER :Tovornjak toffee +STR_804D_BUBBLE_VAN :Tovornjak mehurčkov +STR_804E_COLA_TANKER :Tovornjak Cockte +STR_804F_CANDY_VAN :Tovornjak slaščic +STR_8050_TOY_VAN :Tovornjak igrač STR_8051_BATTERY_TRUCK :Tovornjak baterij -STR_8052_FIZZY_DRINK_TRUCK :Tovornjak gaziranih pijac +STR_8052_FIZZY_DRINK_TRUCK :Tovornjak gaziranih pijač STR_8053_PLASTIC_TRUCK :Tovornjak plastike -STR_8059_PASSENGER_CAR :Potniski vagon -STR_805A_MAIL_VAN :Postni vagon +STR_8054_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Električen) +STR_8055_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Električen) +STR_8056_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Električen) +STR_8057_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Električen) +STR_8059_PASSENGER_CAR :Potniški vagon +STR_805A_MAIL_VAN :Poštni vagon STR_805B_COAL_CAR :Vagon za premog STR_805C_OIL_TANKER :Vagon za nafto -STR_805D_LIVESTOCK_VAN :Vagon za zivino +STR_805D_LIVESTOCK_VAN :Vagon za živino STR_805E_GOODS_VAN :Vagon za dobrine -STR_805F_GRAIN_HOPPER :Vagon za zito +STR_805F_GRAIN_HOPPER :Vagon za žito STR_8060_WOOD_TRUCK :Vagon za les -STR_8061_IRON_ORE_HOPPER :Vagon za zelezovo rudo +STR_8061_IRON_ORE_HOPPER :Vagon za železovo rudo STR_8062_STEEL_TRUCK :Vagon za jeklo STR_8063_ARMORED_VAN :Oklepni vagon STR_8064_FOOD_VAN :Vagon za hrano STR_8065_PAPER_TRUCK :Vagon za papir -STR_8066_COPPER_ORE_HOPPER :Vagon za bakreno rudo -STR_8067_WATER_TANKER :Vodni tanker +STR_8066_COPPER_ORE_HOPPER :Vagon za bakrovo rudo +STR_8067_WATER_TANKER :Vodna cisterna STR_8068_FRUIT_TRUCK :Vagon za sadje -STR_8069_RUBBER_TRUCK :Vagon za kavcuk +STR_8069_RUBBER_TRUCK :Vagon za gumo STR_806A_SUGAR_TRUCK :Vagon za sladkor STR_806B_COTTON_CANDY_HOPPER :Vagon za sladkorno peno STR_806C_TOFFEE_HOPPER :Vagon za karamelo -STR_806D_BUBBLE_VAN :Vagon za mehurcke -STR_806E_COLA_TANKER :Tank za cockto -STR_806F_CANDY_VAN :Vagon za slascice -STR_8070_TOY_VAN :Vagon za igrace +STR_806D_BUBBLE_VAN :Vagon za mehurčke +STR_806E_COLA_TANKER :Cisterna za Cockto +STR_806F_CANDY_VAN :Vagon za slaščice +STR_8070_TOY_VAN :Vagon za igrače STR_8071_BATTERY_TRUCK :Tovornjak za baterije -STR_8072_FIZZY_DRINK_TRUCK :Tovornjak za gazirane pijace +STR_8072_FIZZY_DRINK_TRUCK :Tovornjak za gazirane pijače STR_8073_PLASTIC_TRUCK :Tovornjak za plastiko -STR_807B_BALOGH_COAL_TRUCK :Balogh kamion premoga -STR_807C_UHL_COAL_TRUCK :Uhl kamion premoga -STR_807D_DW_COAL_TRUCK :DW kamion premoga -STR_8084_WITCOMBE_OIL_TANKER :Witcombe naftni tanker -STR_8085_FOSTER_OIL_TANKER :Foster naftni tanker -STR_8086_PERRY_OIL_TANKER :Perry naftni tanker -STR_808A_BALOGH_GOODS_TRUCK :Balogh kamion blaga -STR_808B_CRAIGHEAD_GOODS_TRUCK :Craighead kamion blaga -STR_808C_GOSS_GOODS_TRUCK :Goss kamion blaga -STR_808D_HEREFORD_GRAIN_TRUCK :Hereford kamion zita -STR_808E_THOMAS_GRAIN_TRUCK :Thomas kamion zita -STR_808F_GOSS_GRAIN_TRUCK :Goss kamion zita -STR_8090_WITCOMBE_WOOD_TRUCK :Witcombe kamion lesa -STR_8091_FOSTER_WOOD_TRUCK :Fooster kamion lesa -STR_8092_MORELAND_WOOD_TRUCK :Moreland kamion lesa -STR_8093_MPS_IRON_ORE_TRUCK :MPS kamion zelezne rude -STR_8094_UHL_IRON_ORE_TRUCK :Uhl kamion zelezne rude -STR_8095_CHIPPY_IRON_ORE_TRUCK :Chippy kamion zelezne rude -STR_8096_BALOGH_STEEL_TRUCK :Balogh kamion jekla -STR_8097_UHL_STEEL_TRUCK :Uhl kamion jekla -STR_8098_KELLING_STEEL_TRUCK :Kelling kamion jekla -STR_8099_BALOGH_ARMORED_TRUCK :Balogh oklepni kamion -STR_809A_UHL_ARMORED_TRUCK :Uhl oklepni kamion -STR_809B_FOSTER_ARMORED_TRUCK :Foster oklepni kamion -STR_809C_FOSTER_FOOD_VAN :Foster kamion živil -STR_809D_PERRY_FOOD_VAN :Perry kamion živil -STR_809E_CHIPPY_FOOD_VAN :Chippy kamion živil -STR_809F_UHL_PAPER_TRUCK :Uhl kamion papirja -STR_80A0_BALOGH_PAPER_TRUCK :Balogh kamion papirja -STR_80A1_MPS_PAPER_TRUCK :MPS kamion papirja -STR_80A2_MPS_COPPER_ORE_TRUCK :MPS kamion bakrove rude -STR_80A3_UHL_COPPER_ORE_TRUCK :Uhl kamion bakrove rude -STR_80A4_GOSS_COPPER_ORE_TRUCK :Goss kamion bakrove rude -STR_80A5_UHL_WATER_TANKER :Uhl tanker mineralne vode -STR_80A6_BALOGH_WATER_TANKER :Balogh tanker mineralne vode -STR_80A7_MPS_WATER_TANKER :MPS tanker mineralne vode -STR_80A8_BALOGH_FRUIT_TRUCK :Balogh kamion sadja -STR_80A9_UHL_FRUIT_TRUCK :Uhl kamion sadja -STR_80AA_KELLING_FRUIT_TRUCK :Kelling kamion sadja -STR_80AB_BALOGH_RUBBER_TRUCK :Balogh kamion kavcuka -STR_80AC_UHL_RUBBER_TRUCK :Uhl kamion kavcuka -STR_80AD_RMT_RUBBER_TRUCK :RMT kamion kavcuka -STR_80AE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover kamion sladkorja -STR_80AF_POWERNAUGHT_SUGAR_TRUCK :Powernaught kamion sladkorja -STR_80B0_WIZZOWOW_SUGAR_TRUCK :Wizzowow kamion sladkorja -STR_80B1_MIGHTYMOVER_COLA_TRUCK :MightyMover kamion Cockte -STR_80B2_POWERNAUGHT_COLA_TRUCK :Powernaught kamion Cockte -STR_80B3_WIZZOWOW_COLA_TRUCK :Wizzowow kamion Cockte +STR_8074_MPS_REGAL_BUS :MPS regionalni avtobus +STR_8075_HEREFORD_LEOPARD_BUS :Hereford Leopard avtobus +STR_8076_FOSTER_BUS :Foster avtobus +STR_8077_FOSTER_MKII_SUPERBUS :Foster MkII Superbus +STR_8078_PLODDYPHUT_MKI_BUS :Ploddyphut MkI avtobus +STR_8079_PLODDYPHUT_MKII_BUS :Ploddyphut MkII avtobus +STR_807A_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII avtobus +STR_807B_BALOGH_COAL_TRUCK :Balogh tovornjak za premog +STR_807C_UHL_COAL_TRUCK :Uhl tovornjak za premog +STR_807D_DW_COAL_TRUCK :DW tovornjak za premog +STR_807E_MPS_MAIL_TRUCK :MPS tovornjak za pošto +STR_807F_REYNARD_MAIL_TRUCK :Reynard tovornjak za pošto +STR_8080_PERRY_MAIL_TRUCK :Perry tovornjak za pošto +STR_8081_MIGHTYMOVER_MAIL_TRUCK :MightyMover tovornjak za pošto +STR_8082_POWERNAUGHT_MAIL_TRUCK :Powernaught tovornjak za pošto +STR_8083_WIZZOWOW_MAIL_TRUCK :Wizzowow tovornjak za pošto +STR_8084_WITCOMBE_OIL_TANKER :Witcombe cisterna za nafto +STR_8085_FOSTER_OIL_TANKER :Foster cisterna za nafto +STR_8086_PERRY_OIL_TANKER :Perry cisterna za nafto +STR_8087_TALBOTT_LIVESTOCK_VAN :Talbott tovornjak za živino +STR_8088_UHL_LIVESTOCK_VAN :Uhl tovornjak za živino +STR_8089_FOSTER_LIVESTOCK_VAN :Foster tovornjak za živino +STR_808A_BALOGH_GOODS_TRUCK :Balogh tovornjak za dobrine +STR_808B_CRAIGHEAD_GOODS_TRUCK :Craighead tovornjak za dobrine +STR_808C_GOSS_GOODS_TRUCK :Goss tovornjak za dobrine +STR_808D_HEREFORD_GRAIN_TRUCK :Hereford tovornjak za žito +STR_808E_THOMAS_GRAIN_TRUCK :Thomas tovornjak za žito +STR_808F_GOSS_GRAIN_TRUCK :Goss tovornjak za žito +STR_8090_WITCOMBE_WOOD_TRUCK :Witcombe tovornjak za les +STR_8091_FOSTER_WOOD_TRUCK :Fooster tovornjak za les +STR_8092_MORELAND_WOOD_TRUCK :Moreland tovornjak za les +STR_8093_MPS_IRON_ORE_TRUCK :MPS tovornjak za železovo rudo +STR_8094_UHL_IRON_ORE_TRUCK :Uhl tovornjak za železovo rudo +STR_8095_CHIPPY_IRON_ORE_TRUCK :Chippy tovornjak za železovo rudo +STR_8096_BALOGH_STEEL_TRUCK :Balogh tovornjak za jeklo +STR_8097_UHL_STEEL_TRUCK :Uhl tovornjak za jeklo +STR_8098_KELLING_STEEL_TRUCK :Kelling tovornjak za jeklo +STR_8099_BALOGH_ARMORED_TRUCK :Balogh oklepni tovornjak +STR_809A_UHL_ARMORED_TRUCK :Uhl oklepni tovornjak +STR_809B_FOSTER_ARMORED_TRUCK :Foster oklepni tovornjak +STR_809C_FOSTER_FOOD_VAN :Foster tovornjak za živila +STR_809D_PERRY_FOOD_VAN :Perry tovornjak za živila +STR_809E_CHIPPY_FOOD_VAN :Chippy tovornjak za živila +STR_809F_UHL_PAPER_TRUCK :Uhl tovornjak za papir +STR_80A0_BALOGH_PAPER_TRUCK :Balogh tovornjak za papir +STR_80A1_MPS_PAPER_TRUCK :MPS tovornjak za papir +STR_80A2_MPS_COPPER_ORE_TRUCK :MPS tovornjak za bakrovo rudo +STR_80A3_UHL_COPPER_ORE_TRUCK :Uhl tovornjak za bakrovo rudo +STR_80A4_GOSS_COPPER_ORE_TRUCK :Goss tovornjak za bakrovo rudo +STR_80A5_UHL_WATER_TANKER :Uhl cisterna za vodo +STR_80A6_BALOGH_WATER_TANKER :Balogh cisterna za vodo +STR_80A7_MPS_WATER_TANKER :MPS cisterna za vodo +STR_80A8_BALOGH_FRUIT_TRUCK :Balogh tovornjak za sadje +STR_80A9_UHL_FRUIT_TRUCK :Uhl tovornjak za sadje +STR_80AA_KELLING_FRUIT_TRUCK :Kelling tovornjak za sadje +STR_80AB_BALOGH_RUBBER_TRUCK :Balogh tovornjak za gumo +STR_80AC_UHL_RUBBER_TRUCK :Uhl tovornjak za gumo +STR_80AD_RMT_RUBBER_TRUCK :RMT tovornjak za gumo +STR_80AE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover tovornjak za sladkor +STR_80AF_POWERNAUGHT_SUGAR_TRUCK :Powernaught tovornjak za sladkor +STR_80B0_WIZZOWOW_SUGAR_TRUCK :Wizzowow tovornjak za sladkor +STR_80B1_MIGHTYMOVER_COLA_TRUCK :MightyMover cisterna za Cockto +STR_80B2_POWERNAUGHT_COLA_TRUCK :Powernaught cisterna za Cockto +STR_80B3_WIZZOWOW_COLA_TRUCK :Wizzowow cisterna za Cockto +STR_80B4_MIGHTYMOVER_COTTON_CANDY :MightyMover tovornjak za sladkorno peno +STR_80B5_POWERNAUGHT_COTTON_CANDY :Powernaught tovornjak za sladkorno peno +STR_80B6_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow tovornjak za sladkorno peno +STR_80B7_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover tovornjak za toffee +STR_80B8_POWERNAUGHT_TOFFEE_TRUCK :Powernaught tovornjak za toffee +STR_80B9_WIZZOWOW_TOFFEE_TRUCK :Wizzowow tovornjak za toffee +STR_80BA_MIGHTYMOVER_TOY_VAN :MightyMover tovornjak za igrače +STR_80BB_POWERNAUGHT_TOY_VAN :Powernaught tovornjak za igrače +STR_80BC_WIZZOWOW_TOY_VAN :Wizzowow tovornjak za igrače +STR_80BD_MIGHTYMOVER_CANDY_TRUCK :MightyMover tovornjak za sladkarije +STR_80BE_POWERNAUGHT_CANDY_TRUCK :Powernaught tovornjak za sladkarije +STR_80BF_WIZZOWOW_CANDY_TRUCK :Wizzowow tovornjak za sladkarije +STR_80C0_MIGHTYMOVER_BATTERY_TRUCK :MightyMover tovornjak za baterije +STR_80C1_POWERNAUGHT_BATTERY_TRUCK :Powernaught tovornjak za baterije +STR_80C2_WIZZOWOW_BATTERY_TRUCK :Wizzowow tovornjak za baterije +STR_80C3_MIGHTYMOVER_FIZZY_DRINK :MightyMover tovornjak za gazirane pijače +STR_80C4_POWERNAUGHT_FIZZY_DRINK :Powernaught tovornjak za gazirane pijače +STR_80C5_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow tovornjak za gazirane pijače +STR_80C6_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover tovornjak za plastiko +STR_80C7_POWERNAUGHT_PLASTIC_TRUCK :Powernaught tovornjak za plastiko +STR_80C8_WIZZOWOW_PLASTIC_TRUCK :Wizzowow tovornjak za plastiko +STR_80C9_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover tovornjak za mehurčke +STR_80CA_POWERNAUGHT_BUBBLE_TRUCK :Powernaught tovornjak za mehurčke +STR_80CB_WIZZOWOW_BUBBLE_TRUCK :Wizzowow tovornjak za mehurčke STR_80CC_MPS_OIL_TANKER :MPS naftni tanker STR_80CD_CS_INC_OIL_TANKER :CS-Inc. naftni tanker -STR_80CE_MPS_PASSENGER_FERRY :MPS potniski trajekt -STR_80CF_FFP_PASSENGER_FERRY :FFP potniski trajekt +STR_80CE_MPS_PASSENGER_FERRY :MPS potniški trajekt +STR_80CF_FFP_PASSENGER_FERRY :FFP potniški trajekt STR_80D0_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hovercraft -STR_80D1_CHUGGER_CHUG_PASSENGER :Chugger-Chug potniski trajekt -STR_80D2_SHIVERSHAKE_PASSENGER_FERRY :Shivershake potniski trajekt +STR_80D1_CHUGGER_CHUG_PASSENGER :Chugger-Chug potniški trajekt +STR_80D2_SHIVERSHAKE_PASSENGER_FERRY :Shivershake potniški trajekt STR_80D3_YATE_CARGO_SHIP :Yate tovorna ladja STR_80D4_BAKEWELL_CARGO_SHIP :Bakewell tovorna ladja STR_80D5_MIGHTYMOVER_CARGO_SHIP :Mightymover tovorna ladja @@ -1544,118 +1935,336 @@ STR_80FD_TRICARIO_HELICOPTER :Tricario helikopter STR_80FE_GURU_X2_HELICOPTER :Guru X2 helikopter STR_80FF_POWERNAUT_HELICOPTER :Powernaut helikopter -STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE :{WHITE}Sporocilo od proizvajalca vozila -STR_8101_WE_HAVE_JUST_DESIGNED_A :{GOLD}Pravkar smo izdelali novi {STRING} - ali te zanima enoletna ekskluzivna pravica do uporabe tega vozila, preden ga ponudimo na trgu? -STR_8102_RAILROAD_LOCOMOTIVE :lokomotiva +STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE :{WHITE}Sporočilo od proizvajalca vozila +STR_8101_WE_HAVE_JUST_DESIGNED_A :{GOLD}Pravkar smo izdelali novi {STRING} - ali vas zanima enoletna ekskluzivna pravica do uporabe tega vozila, preden ga ponudimo na trgu? +STR_8102_RAILROAD_LOCOMOTIVE :železniška lokomotiva STR_8103_ROAD_VEHICLE :cestno vozilo STR_8104_AIRCRAFT :letalo STR_8105_SHIP :ladja -STR_8106_MONORAIL_LOCOMOTIVE :enotirni vlak -STR_8107_MAGLEV_LOCOMOTIVE :magnetni vlak +STR_8106_MONORAIL_LOCOMOTIVE :enotirna lokomotiva +STR_8107_MAGLEV_LOCOMOTIVE :magnetna lokomotiva ##id 0x8800 -STR_8800_TRAIN_DEPOT :{WHITE}{TOWN} Zelezniska garaza -STR_8801_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prvi vlak je pripeljal v {STATION}! +STR_8800_TRAIN_DEPOT :{WHITE}{TOWN} Železniška garaža +STR_8801_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prvi vlak je pripeljal na postajo {STATION}! STR_8802_DETAILS :{WHITE}{STRING} (Podrobnosti) STR_8803_TRAIN_IN_THE_WAY :{WHITE}Vlak na poti STR_8804 :{SETX 10}{COMMA}: {STRING} STR_8805 :{RIGHTARROW}{SETX 10}{COMMA}: {STRING} -STR_8806_GO_TO :Pojdi do {STATION} -STR_8807_GO_TO_TRANSFER :Pojdi do {STATION} (Prenesi in vzemi tovor) -STR_8808_GO_TO_UNLOAD :Pojdi do {STATION} (Raztovori) -STR_8809_GO_TO_TRANSFER_UNLOAD :Pojdi do {STATION} (Prenesi in pusti prazno) -STR_880A_GO_TO_LOAD :Pojdi do {STATION} (Nalozi) -STR_880B_GO_TO_TRANSFER_LOAD :Pojdi do {STATION} (Prenesi in pocakaj na polno nalozitev) -STR_880C_GO_NON_STOP_TO :Pojdi brez postanka do {STATION} -STR_880D_GO_TO_NON_STOP_TRANSFER :Pojdi brez postanka do {STATION} (Prenesi in vzemi tovor) -STR_880E_GO_NON_STOP_TO_UNLOAD :Pojdi brez postanka do {STATION} (Raztovori) -STR_880F_GO_TO_NON_STOP_TRANSFER_UNLOAD :Pojdi brez postanka do {STATION} (Prenesi in pusti prazno) -STR_8810_GO_NON_STOP_TO_LOAD :Pojdi brez postanka do {STATION} (Nalozi) -STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT :Pojdi brez postanka do {TOWN} zelezniske garaze +STR_8806_GO_TO :Pojdi do postaje {STATION} +STR_8807_GO_TO_TRANSFER :Pojdi do postaje {STATION} (Prenesi in vzemi tovor) +STR_8808_GO_TO_UNLOAD :Pojdi do postaje {STATION} (Raztovori) +STR_8809_GO_TO_TRANSFER_UNLOAD :Pojdi do postaje {STATION} (Prenesi in pusti prazno) +STR_880A_GO_TO_LOAD :Pojdi do postaje {STATION} (Naloži) +STR_880B_GO_TO_TRANSFER_LOAD :Pojdi do postaje {STATION} (Prenesi in počakaj na polno breme) +STR_880C_GO_NON_STOP_TO :Pojdi brez postanka do postaje {STATION} +STR_880D_GO_TO_NON_STOP_TRANSFER :Pojdi brez postanka do postaje {STATION} (Prenesi in vzemi tovor) +STR_880E_GO_NON_STOP_TO_UNLOAD :Pojdi brez postanka do postaje {STATION} (Raztovori) +STR_880F_GO_TO_NON_STOP_TRANSFER_UNLOAD :Pojdi brez postanka do postaje {STATION} (Prenesi in pusti prazno) +STR_8810_GO_NON_STOP_TO_LOAD :Pojdi brez postanka do postaje {STATION} (Nalozi) +STR_8811_GO_TO_NON_STOP_TRANSFER_LOAD :Pojdi brez postanka do postaje {STATION} (Prenesi in počakaj na polno breme) +STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT :Pojdi brez postanka do garaže {TOWN} STR_UNKNOWN_DESTINATION :neznana lokacija STR_8812_EMPTY :{LTBLUE}Prazen -STR_8813_FROM :{LTBLUE}{CARGO} iz {STATION} -STR_8814_TRAIN_IS_WAITING_IN_DEPOT :{WHITE}Vlak {COMMA} caka v garazi +STR_8813_FROM :Tovor {LTBLUE}{CARGO} iz postaje {STATION} +STR_8814_TRAIN_IS_WAITING_IN_DEPOT :{WHITE}Vlak {COMMA} čaka v garaži STR_8815_NEW_VEHICLES :{BLACK}Nova vozila STR_8816 :{BLACK}- STR_8819_TRAIN_TOO_LONG :{WHITE}Vlak je predolg -STR_881C_NEW_RAIL_VEHICLES :{WHITE}Nova zelezniska vozila -STR_881D_NEW_MONORAIL_VEHICLES :{WHITE}Nov enotirni vlak -STR_881E_NEW_MAGLEV_VEHICLES :{WHITE}Nov magnetni vlak +STR_881A_TRAINS_CAN_ONLY_BE_ALTERED :{WHITE}Vlaki so lahko spremenjeni šele, ko stojijo v garaži + +STR_881C_NEW_RAIL_VEHICLES :{WHITE}Nova železniška vozila +STR_881D_NEW_MONORAIL_VEHICLES :{WHITE}Nova enotirna vozila +STR_881E_NEW_MAGLEV_VEHICLES :{WHITE}Nova magnetna vozila +STR_ALL_AVAIL_RAIL_VEHICLES :{WHITE}Železniška vozila + STR_881F_BUILD_VEHICLE :{BLACK}Zgradi vozilo +STR_CLONE_ROAD_VEHICLE :{BLACK}Kloniraj vozilo +STR_CLONE_ROAD_VEHICLE_INFO :{BLACK}To bo zgradilo kopijo vozila. CTRL+klik skopira tudi navodila +STR_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}To bo zgradilo kopijo vozila. Kliknite na ta gumb in nato na vozilo v ali zunaj garaže. CTRL+klik skopira tudi navodila +STR_CLONE_TRAIN :{BLACK}Kloniraj vlak +STR_CLONE_TRAIN_INFO :{BLACK}To bo zgradilo kopijo vlaka vključno z vsemi vagoni. CTRL+klik skopira tudi navodila +STR_CLONE_TRAIN_DEPOT_INFO :{BLACK}To bo zgradilo kopijo vlaka vključno z vsemi vagoni. Kliknite na ta gumb in nato na vlak v ali zunaj garaže. CTRL+klik skopira tudi navodila STR_8820_RENAME :{BLACK}Preimenuj -STR_8823_SKIP :{BLACK}Preskoci -STR_8824_DELETE :{BLACK}Izbrisi +STR_8823_SKIP :{BLACK}Preskoči +STR_8824_DELETE :{BLACK}Izbriši STR_8825_NON_STOP :{BLACK}Brez prestanka STR_8826_GO_TO :{BLACK}Pojdi do -STR_8827_FULL_LOAD :{BLACK}Polno natovorjenje +STR_8827_FULL_LOAD :{BLACK}Naloži polno STR_8828_UNLOAD :{BLACK}Raztovori STR_8829_ORDERS :{WHITE}{VEHICLE} (Navodila) STR_882A_END_OF_ORDERS :{SETX 10}- - Konec navodil - - -STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE :{WHITE}Ne mores kupiti vozila... +STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE :{WHITE}Ni mogoče kupiti vozila ... STR_882C_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Zgrajen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY} STR_882D_VALUE :{LTBLUE}{STRING}{BLACK} Vrednost: {LTBLUE}{CURRENCY} STR_882E :{WHITE}{VEHICLE} -STR_882F_LOADING_UNLOADING :{LTBLUE}Natovorjenje / Raztovorjenje -STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Vlaka ne mores poslati v garazo... -STR_8831_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Ni vec prostora za ukaze -STR_8832_TOO_MANY_ORDERS :{WHITE}Prevec ukazov -STR_8833_CAN_T_INSERT_NEW_ORDER :{WHITE}Ni mozno vstaviti nov ukaz... -STR_8834_CAN_T_DELETE_THIS_ORDER :{WHITE}Ni mozno izbrisati ta ukaz... -STR_8835_CAN_T_MODIFY_THIS_ORDER :{WHITE}Ni mozno spreminjati ta ukaz -STR_8837_CAN_T_MOVE_VEHICLE :{WHITE}Ni mozno premakniti vozilo... -STR_8838_N_A :Ni razpolozljiv{SKIP} -STR_8839_CAN_T_SELL_RAILROAD_VEHICLE :{WHITE}Vlaka ne mores prodati... -STR_883D_TRAINS_CLICK_ON_TRAIN_FOR :{BLACK}Vlaki - klikni na vlak za informacije -STR_884B_REVERSE_DIRECTION_OF_TRAIN :{BLACK}Obrni smer vlakov -STR_884C_SHOW_TRAIN_DETAILS :{BLACK}Pokazi podrobnosti vlaka -STR_884D_INCREASE_SERVICING_INTERVAL :{BLACK}Zvisaj cas med servisirjanji -STR_884E_DECREASE_SERVICING_INTERVAL :{BLACK}Zmanjsaj cas med servisirjanji -STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED :{BLACK}Pokazi podrobnosti vagonov na vlaku -STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES :{BLACK}Pokazi podrobnosti o vagonih -STR_8859_NEW_NOW_AVAILABLE :{BLACK}{BIGFONT}Nov {STRING} je zdaj navoljo! +STR_882F_LOADING_UNLOADING :{LTBLUE}Natovarjanje / Raztovarjanje +STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Vlaka ni mogoče poslati v garažo ... +STR_8831_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Ni več prostora za navodila +STR_8832_TOO_MANY_ORDERS :{WHITE}Preveč navodil +STR_8833_CAN_T_INSERT_NEW_ORDER :{WHITE}Ni moogče vstaviti nov ukaz ... +STR_8834_CAN_T_DELETE_THIS_ORDER :{WHITE}Ni mogoče izbrisati ukaza ... +STR_8835_CAN_T_MODIFY_THIS_ORDER :{WHITE}Ni mogoče spreminjati ukaza ... +STR_8837_CAN_T_MOVE_VEHICLE :{WHITE}Ni mogoče premakniti vozila ... +STR_8838_N_A :Ni na voljo{SKIP} +STR_8839_CAN_T_SELL_RAILROAD_VEHICLE :{WHITE}Vlaka ni mogoče prodati ... +STR_883A_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Ni mogoče najti poti do najbližje garaže +STR_883B_CAN_T_STOP_START_TRAIN :{WHITE}Ni mogoče ustaviti/zagnati vlaka ... +STR_883C_SERVICING_INTERVAL_DAYS :{BLACK}Interval servisiranja: {LTBLUE}{COMMA}dni{BLACK} Zadnji servis: {LTBLUE}{DATE_LONG} +STR_883D_TRAINS_CLICK_ON_TRAIN_FOR :{BLACK}Vlaki - kliknite na vlak za informacije +STR_883E_BUILD_NEW_TRAINS_REQUIRES :{BLACK}Zgradi nove vlake (zahteva železniško garažo) +STR_883F_TRAINS_CLICK_ON_TRAIN_FOR :{BLACK}Vlaki - kliknite na vlak za informacije, povlecite vozilo za dodajanje/odstranjevanje iz vlaka +STR_8840_BUILD_NEW_TRAIN_VEHICLE :{BLACK}Zgradi novo železniško vozilo +STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE :{BLACK}Povlecite železniško vozilo sem, če ga želite prodati +STR_8842_CENTER_MAIN_VIEW_ON_TRAIN :{BLACK}Pogled na železniško garažo +STR_8843_TRAIN_VEHICLE_SELECTION :{BLACK}Seznam železniških vozil - kliknite na vozilo za informacije +STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN :{BLACK}Zgradi izbrano železniško vozilo +STR_8845_RENAME_TRAIN_VEHICLE_TYPE :{BLACK}Preimenuj železniško vozilo +STR_8846_CURRENT_TRAIN_ACTION_CLICK :{BLACK}Trenutno železniško vozilo - kliknite sem za izklop/zagon vozila +STR_8847_SHOW_TRAIN_S_ORDERS :{BLACK}Pokaži navodila železniškega vozila +STR_8848_CENTER_MAIN_VIEW_ON_TRAIN :{BLACK}Pogled na železniško vozilo +STR_8849_SEND_TRAIN_TO_DEPOT :{BLACK}Pošlji vlak v železniško garažo. CTRL+klik samo na servis +STR_884A_FORCE_TRAIN_TO_PROCEED :{BLACK}Prisili vlak, naj nadaljuje brez čakanja semaforjev +STR_884B_REVERSE_DIRECTION_OF_TRAIN :{BLACK}Obrni smer vlaka +STR_884C_SHOW_TRAIN_DETAILS :{BLACK}Pokaži podrobnosti vlaka +STR_884D_INCREASE_SERVICING_INTERVAL :{BLACK}Podaljšaj čas med servisi +STR_884E_DECREASE_SERVICING_INTERVAL :{BLACK}Skrajšaj čas med servisi +STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED :{BLACK}Pokaži podrobnosti tovora na vlaku +STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES :{BLACK}Pokaži podrobnosti o vagonih +STR_8851_SHOW_CAPACITIES_OF_EACH :{BLACK}Prikaži kapacitete vsakega vagona +STR_8852_SHOW_TOTAL_CARGO :{BLACK}Prikaži polno kapaciteto vlaka, razdeli glede na tip tovora +STR_8852_ORDERS_LIST_CLICK_ON_ORDER :{BLACK}Seznam navodil - kliknite na ukaz, da ga izberete. CTRL+klik prikaže postajo +STR_8853_SKIP_THE_CURRENT_ORDER :{BLACK}Preskoči trenuten ukaz in izvrši naslednjega +STR_8854_DELETE_THE_HIGHLIGHTED :{BLACK}Zbriši izbran ukaz +STR_8855_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Označi izbran ukaz kot brez-postanka +STR_8856_INSERT_A_NEW_ORDER_BEFORE :{BLACK}Vstavi nov ukaz pred izbranega ali pa ga dodaj na koncu seznama +STR_8857_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Označi izbran ukaz, naj vozilo čaka na polno obremenitev +STR_8858_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Označi izbran ukaz, naj se vozilo v celoti raztovori +STR_8859_NEW_NOW_AVAILABLE :{BLACK}{BIGFONT}Nov {STRING} je sedaj na voljo! STR_885A :{BLACK}{BIGFONT}{STRING} STR_885C_BROKEN_DOWN :{RED}Pokvarjen +STR_885D_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Stroški obratovanja: {LTBLUE}{CURRENCY}/leto STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Teza: {LTBLUE}{WEIGHT_S} {BLACK}Moc: {LTBLUE}{POWER}{BLACK} Max. hitrost: {LTBLUE}{VELOCITY} -STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Letosnji profit: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) -STR_8861_STOPPED :{RED}Ustavljen +STR_885F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Letošnji profit: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) +STR_8860_RELIABILITY_BREAKDOWNS :{BLACK}Zanseljivost: {LTBLUE}{COMMA}% {BLACK}Št. okvar od zadnjega servisa: {LTBLUE}{COMMA} +STR_8861_STOPPED :{RED}Ustavljeno +STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Ni mogoče, da vlak v nevarnosti pelje mimo semaforjev ... +STR_8863_CRASHED :{RED}Nesreča! STR_8865_NAME_TRAIN :{WHITE}Poimenuj vlak -STR_8866_CAN_T_NAME_TRAIN :{WHITE}Ni mozno poimenovati vlaka +STR_8866_CAN_T_NAME_TRAIN :{WHITE}Ni mogoče poimenovati vlaka ... STR_8867_NAME_TRAIN :{BLACK}Poimenuj vlak -STR_8869_CAN_T_REVERSE_DIRECTION :{WHITE}Ni mozno spremeniti smeri vlaka... -STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}Preimenuj tip vozila +STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}Železniška nesreča!{}{COMMA} je umrlo v plamenih ob trku +STR_8869_CAN_T_REVERSE_DIRECTION :{WHITE}Ni mogoče spremeniti smeri vlaka ... +STR_886A_RENAME_TRAIN_VEHICLE_TYPE :{WHITE}Preimenuj železniško vozilo +STR_886B_CAN_T_RENAME_TRAIN_VEHICLE :{WHITE}Ni mogoče preimenovati železniškega vozila ... +STR_886D_MAKE_THE_HIGHLIGHTED_ORDER :{BLACK}Nastavi ukaz, naj prisili vozilo, da se raztovori +STR_886F_TRANSFER :{BLACK}Prenos STR_TRAIN_STOPPING :{RED}Ustavljam STR_TRAIN_STOPPING_VEL :{RED}Ustavljam, {VELOCITY} ##id 0x9000 STR_9000_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Cestno vozilo na poti +STR_9001_ROAD_VEHICLES :{WHITE}{COMPANY} - {COMMA} Cestna vozila STR_9002 :{WHITE}{VEHICLE} -STR_9006_NEW_ROAD_VEHICLES :{WHITE}Nova vozila +STR_9003_ROAD_VEHICLE_DEPOT :{WHITE}{TOWN} Garaža za cestna vozila +STR_9004_NEW_VEHICLES :{BLACK}Nova vozila +STR_9006_NEW_ROAD_VEHICLES :{WHITE}Nova cestna vozila STR_9007_BUILD_VEHICLE :{BLACK}Zgradi vozilo +STR_9009_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Ni mogoče zgraditi cestnega vozila ... STR_900C_DETAILS :{WHITE}{VEHICLE} (Podrobnosti) -STR_900D_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Stroski vzdrzevanja: {LTBLUE}{CURRENCY}/ na leto -STR_900E_MAX_SPEED :{BLACK}Najvecja hitrost: {LTBLUE}{VELOCITY} -STR_900F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Letosnji profit: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) -STR_9011_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Zgrajent: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY} -STR_9014_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Ni mozno prodati cestno vozilo... +STR_900D_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Stroški obratovanja: {LTBLUE}{CURRENCY}/leto +STR_900E_MAX_SPEED :{BLACK}Max. hitrost: {LTBLUE}{VELOCITY} +STR_900F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Letošnji profit: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) +STR_9010_RELIABILITY_BREAKDOWNS :{BLACK}Zanesljivost: {LTBLUE}{COMMA}% {BLACK}Št. okvar od zadnjega servisa: {LTBLUE}{COMMA} +STR_9011_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Zgrajen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY} +STR_9012_CAPACITY :{BLACK}Kapaciteta: {LTBLUE}{CARGO} +STR_9013_MUST_BE_STOPPED_INSIDE :{WHITE} ... mora biti ustavljen v garaži +STR_9014_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Ni mogoče prodati cestnega vozila ... +STR_9015_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Ni mogoče ustaviti/zagnati cestnega vozila ... +STR_9016_ROAD_VEHICLE_IS_WAITING :{WHITE}Cestno vozilo {COMMA} čaka v garaži +STR_9018_CAN_T_SEND_VEHICLE_TO_DEPOT :{WHITE}Ni mogoče poslati vozila v garažo ... +STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Ni mogoče najti najbližje garaže +STR_901A_ROAD_VEHICLES_CLICK_ON :{BLACK}Cestna vozila - kliknite na vozilo za informacije +STR_901B_BUILD_NEW_ROAD_VEHICLES :{BLACK}Zgradi nova cestna vozila (zahteva garažo) +STR_901C_CURRENT_VEHICLE_ACTION :{BLACK}Dejanja trenutnega vozila - kliknite za ustavitev/zagon vozila +STR_901D_SHOW_VEHICLE_S_ORDERS :{BLACK}Pokaži navodila vozila +STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE :{BLACK}Pogled na vozilo +STR_901F_SEND_VEHICLE_TO_DEPOT :{BLACK}Pošlji vozilo v garažo. CTRL+klik samo na servis +STR_9020_FORCE_VEHICLE_TO_TURN_AROUND :{BLACK}Prisili vozilo, da se obrne okoli +STR_9021_SHOW_ROAD_VEHICLE_DETAILS :{BLACK}Prikaži podrobnosti cestnega vozila +STR_9022_VEHICLES_CLICK_ON_VEHICLE :{BLACK}Vozila - kliknite na vozilo za informacije +STR_9023_BUILD_NEW_ROAD_VEHICLE :{BLACK}Zgradi novo cestno vozilo +STR_9024_DRAG_ROAD_VEHICLE_TO_HERE :{BLACK}Povlecite cestno vozilo sem, če ga želite prodati +STR_9025_CENTER_MAIN_VIEW_ON_ROAD :{BLACK}Pogled na garažo +STR_9026_ROAD_VEHICLE_SELECTION :{BLACK}Seznam cestnih vozil - kliknite na vozilo za informacije +STR_9027_BUILD_THE_HIGHLIGHTED_ROAD :{BLACK}Zgradi izbrano cestno vozilo +STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE :{BLACK}{BIGFONT}Novo cestno vozilo sedaj na voljo! +STR_9029 :{BLACK}{BIGFONT}{STRING} +STR_902A_COST_SPEED_RUNNING_COST :{BLACK}Cena: {CURRENCY}{}Hitrost: {VELOCITY}{}Stroški obratovanja: {CURRENCY}/leto{}Kapaciteta: {CARGO} +STR_902C_NAME_ROAD_VEHICLE :{WHITE}Poimenuj cestno vozilo +STR_902D_CAN_T_NAME_ROAD_VEHICLE :{WHITE}Ni mogoče poimenovati cestnega vozila ... +STR_902E_NAME_ROAD_VEHICLE :{BLACK}Poimenuj cestno vozilo +STR_902F_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prihod prvega avtobusa na postajo {STATION}! +STR_9030_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prihod prvega tovornjaka na postajo {STATION}! +STR_9031_ROAD_VEHICLE_CRASH_DRIVER :{BLACK}{BIGFONT}Prometna nesreča!{}Voznik umrl v plamenih ob trku z vlakom +STR_9032_ROAD_VEHICLE_CRASH_DIE :{BLACK}{BIGFONT}Prometna nesreča!{}{COMMA} umrlo v plamenih ob trku z vlakom +STR_9033_CAN_T_MAKE_VEHICLE_TURN :{WHITE}Ni mogoče okoli obrniti vozila ... +STR_9034_RENAME :{BLACK}Preimenuj +STR_9035_RENAME_ROAD_VEHICLE_TYPE :{BLACK}Preimenuj cestno vozilo +STR_9036_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Preimenuj cestno vozilo +STR_9037_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Ni mogoče preimenovati cestnega vozila ... +STR_9038_GO_TO_ROADVEH_DEPOT :Pojdi v garažo v mestu {TOWN} ##id 0x9800 +STR_9800_DOCK_CONSTRUCTION :Gradnja pomola +STR_9801_DOCK_CONSTRUCTION :{WHITE}Gradnja pomola +STR_9802_CAN_T_BUILD_DOCK_HERE :{WHITE}Ni mogoče zgraditi pomola tukaj ... +STR_9803_SHIP_DEPOT :{WHITE}{TOWN} Ladjedelnica +STR_9804_NEW_SHIPS :{BLACK}Nove ladje +STR_9805_SHIPS :{WHITE}{COMPANY} - {COMMA} Ladje +STR_9808_NEW_SHIPS :{WHITE}Nove ladje +STR_9809_BUILD_SHIP :{BLACK}Zgradi ladjo +STR_CLONE_SHIP :{BLACK}Kloniraj ladjo +STR_CLONE_SHIP_INFO :{BLACK}To bo zgradilo kopijo ladje. CTRL+klik skopira tudi navodila +STR_CLONE_SHIP_DEPOT_INFO :{BLACK}To bo zgradilo kopijo ladje. Kliknite na ta gumb in nato na ladjo v ali zunaj ladjedelnice. CTRL+klik skopira tudi navodila +STR_980B_SHIP_MUST_BE_STOPPED_IN :{WHITE}Ladja mora biti ustavljena in v ladjedelnici +STR_980C_CAN_T_SELL_SHIP :{WHITE}Ni mogoče prodati ladje ... +STR_980D_CAN_T_BUILD_SHIP :{WHITE}Ni mogoče zgraditi ladje ... +STR_980E_SHIP_IN_THE_WAY :{WHITE}Ladja v napoto +STR_980F :{WHITE}{VEHICLE} +STR_9811_DETAILS :{WHITE}{VEHICLE} (Podrobnosti) +STR_9812_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Stroški obratovanja: {LTBLUE}{CURRENCY}/leto +STR_9813_MAX_SPEED :{BLACK}Max. hitrost: {LTBLUE}{VELOCITY} +STR_9814_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit letos: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) +STR_9815_RELIABILITY_BREAKDOWNS :{BLACK}Zanesljivost: {LTBLUE}{COMMA}% {BLACK}Št. okvar od zadnjegea servisa: {LTBLUE}{COMMA} +STR_9816_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Zgrajen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY} +STR_9817_CAPACITY :{BLACK}Kapaciteta: {LTBLUE}{CARGO} +STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING :{BLACK}Zgradi ladjedelnico (za izgradnjo in servisiranje ladij) +STR_981F_SHIPS_CLICK_ON_SHIP_FOR :{BLACK}Ladje - kliknite na ladjo za informacije +STR_9820_BUILD_NEW_SHIP :{BLACK}Zgradi novo ladjo +STR_9821_DRAG_SHIP_TO_HERE_TO_SELL :{BLACK}Povlecite novo ladjo sem, če jo želite prodati +STR_9822_CENTER_MAIN_VIEW_ON_SHIP :{BLACK}Pogled na ladjedelnico +STR_9823_SHIPS_CLICK_ON_SHIP_FOR :{BLACK}Ladje - kliknite na ladjo za informacije +STR_9824_BUILD_NEW_SHIPS_REQUIRES :{BLACK}Zgradi nove ladje (zahteva ladjedelnico) +STR_9825_SHIP_SELECTION_LIST_CLICK :{BLACK}Seznam ladij - kliknite na ladjo za informacije +STR_9826_BUILD_THE_HIGHLIGHTED_SHIP :{BLACK}Zgradi izbrano ladjo +STR_9827_CURRENT_SHIP_ACTION_CLICK :{BLACK}Trenutna ladja - kliknite sem za ustavitev/zagon ladje +STR_9828_SHOW_SHIP_S_ORDERS :{BLACK}Prikaži navodila ladje +STR_9829_CENTER_MAIN_VIEW_ON_SHIP :{BLACK}Pogled na ladjo +STR_982A_SEND_SHIP_TO_DEPOT :{BLACK}Pošlji ladjo v ladjedelnico. CTRL+klik samo na servis +STR_982B_SHOW_SHIP_DETAILS :{BLACK}Prikaži podrobnosti ladje +STR_982C_NEW_SHIP_NOW_AVAILABLE :{BLACK}{BIGFONT}Nova ladja na voljo! +STR_982D :{BLACK}{BIGFONT}{STRING} +STR_982E_COST_MAX_SPEED_CAPACITY :{BLACK}Cena: {CURRENCY} Max. hitrost: {VELOCITY}{}Kapaciteta: {CARGO}{}Stroški obratovanja: {CURRENCY}/leto +STR_982F_NAME_SHIP :{BLACK}Poimenuj ladjo +STR_9831_NAME_SHIP :{WHITE}Poimenuj ladjo +STR_9832_CAN_T_NAME_SHIP :{WHITE}Ni mogoče poimenovati ladje ... +STR_9833_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prva ladja prispela na postajo {STATION}! +STR_9834_POSITION_BUOY_WHICH_CAN :{BLACK}Postavi bojo, ki je lahko uporabljena kot smerokaz +STR_9835_CAN_T_POSITION_BUOY_HERE :{WHITE}Ni mogoče postaviti boje tukaj ... +STR_9836_RENAME :{BLACK}Preimenuj +STR_9837_RENAME_SHIP_TYPE :{BLACK}Preimenuj ladjo +STR_9838_RENAME_SHIP_TYPE :{WHITE}Preimenuj ladjo +STR_9839_CAN_T_RENAME_SHIP_TYPE :{WHITE}Ni mogoče preimeonvati ladje ... +STR_983A_REFIT_CARGO_SHIP_TO_CARRY :{BLACK}Preuredi tovorni prostor tako, da bo ladja lahko sprejela drug tovor +STR_983B_REFIT :{WHITE}{VEHICLE} (Preuredi) +STR_983C_REFIT_SHIP :{BLACK}Preuredi ladjo +STR_983D_SELECT_TYPE_OF_CARGO_FOR :{BLACK}Izberite tip tovora +STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED :{BLACK}Preuredi tovorni prostor ladje za izbrani tovor +STR_983F_SELECT_CARGO_TYPE_TO_CARRY :{GOLD}Izberite tip tovora: +STR_9840_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nova kapaciteta: {GOLD}{CARGO}{}{BLACK}Cena za preureditev: {GOLD}{CURRENCY} +STR_9841_CAN_T_REFIT_SHIP :{WHITE}Ni mogoče preurediti ladje ... +STR_9842_REFITTABLE :(spremenljivo) SERVICE_AT_SHIP_DEPOT :Storitev v {TOWN} doku ##id 0xA000 +STR_A000_AIRPORTS :{WHITE}Letališča +STR_A001_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Ni mogoče zgraditi letališča tukaj ... +STR_A002_AIRCRAFT_HANGAR :{WHITE}{STATION} Hangar +STR_A003_NEW_AIRCRAFT :{BLACK}Novo letalo +STR_CLONE_AIRCRAFT :{BLACK}Kloniraj letalo +STR_CLONE_AIRCRAFT_INFO :{BLACK}To bo zgradilo kopijo letala. CTRL+klik skopira tudi navodila +STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}To bo zgradilo kopijo letala. Kliknite na ta gumb in nato na letalo v ali zunaj hangarja. CTRL+klik skopira tudi navodila +STR_A005_NEW_AIRCRAFT :{WHITE}Novo letalo +STR_A006_BUILD_AIRCRAFT :{BLACK}Zgradi letalo +STR_A008_CAN_T_BUILD_AIRCRAFT :{WHITE}Ni mogoče zgraditi letala ... +STR_A009_AIRCRAFT :{WHITE}{COMPANY} - {COMMA} Letalo +STR_A00A :{WHITE}{VEHICLE} +STR_A00B_ORDERS :{WHITE}{VEHICLE} (Navodila) +STR_A00C_DETAILS :{WHITE}{VEHICLE} (Podrobnosti) +STR_A00D_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Stroški obratovanja: {LTBLUE}{CURRENCY}/leto +STR_A00E_MAX_SPEED :{BLACK}Max. hitrost: {LTBLUE}{VELOCITY} +STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit letos: {LTBLUE}{CURRENCY} (lansko leto: {CURRENCY}) +STR_A010_RELIABILITY_BREAKDOWNS :{BLACK}Zanesljivost: {LTBLUE}{COMMA}% {BLACK}Št. okvar od zadnjega servisa: {LTBLUE}{COMMA} +STR_A011_BUILT_VALUE :{LTBLUE}{STRING}{BLACK} Zgrajen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY} +STR_A012_CAN_T_SEND_AIRCRAFT_TO :{WHITE}Ni mogoče poslati letala v hangar ... +STR_A014_AIRCRAFT_IS_WAITING_IN :{WHITE}Letalo {COMMA} čaka v hangarju +STR_A015_AIRCRAFT_IN_THE_WAY :{WHITE}Letalo v napoto +STR_A016_CAN_T_STOP_START_AIRCRAFT :{WHITE}Ni mogoče ustaviti/zagnati letala ... +STR_A017_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Letalo v letu +STR_A019_CAPACITY :{BLACK}Kapaciteta: {LTBLUE}{CARGO}, {CARGO} +STR_A01A_CAPACITY :{BLACK}Kapaciteta: {LTBLUE}{CARGO} +STR_A01B_AIRCRAFT_MUST_BE_STOPPED :{WHITE}Letalo mora biti ustavljeno v hangarju +STR_A01C_CAN_T_SELL_AIRCRAFT :{WHITE}Ni mogoče prodati letala ... +STR_A01D_AIRPORT_CONSTRUCTION :Gradnja letališča +STR_A01E_BUILD_AIRPORT :{BLACK}Zgradi letališče +STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT :{BLACK}Letalo - kliknite na letalo za informacije +STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES :{BLACK}Gradnja novega letala (zahteva letališče s hangarjem) +STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT :{BLACK}Letalo - kliknite na letalo za informacije +STR_A022_BUILD_NEW_AIRCRAFT :{BLACK}Zgradi novo letalo +STR_A023_DRAG_AIRCRAFT_TO_HERE_TO :{BLACK}Povlecite letalo sem, če ga želite prodati +STR_A024_CENTER_MAIN_VIEW_ON_HANGAR :{BLACK}Pogled na hangar +STR_A025_AIRCRAFT_SELECTION_LIST :{BLACK}Seznam letal - kliknite na letalo za informacije +STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT :{BLACK}Zgradi izbrano letalo +STR_A027_CURRENT_AIRCRAFT_ACTION :{BLACK}Trenutno letalo - kliknite sem za ustavitev/zagon letala +STR_A028_SHOW_AIRCRAFT_S_ORDERS :{BLACK}Prikaži navodila letala +STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT :{BLACK}Pogled na letalo +STR_A02A_SEND_AIRCRAFT_TO_HANGAR :{BLACK}Pošlji letalo v hangar. CTRL+klik samo na servis +STR_A02B_SHOW_AIRCRAFT_DETAILS :{BLACK}Prikaži podrobnosti letala +STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE :{BLACK}{BIGFONT}Novo letalo na voljo! +STR_A02D :{BLACK}{BIGFONT}{STRING} +STR_A02E_COST_MAX_SPEED_CAPACITY :{BLACK}Cena: {CURRENCY} Max. hitrost: {VELOCITY}{}Kapaciteta: {COMMA} potnikov, {COMMA} vreč pošte{}Stroški obratovanja: {CURRENCY}/leto +STR_A030_NAME_AIRCRAFT :{WHITE}Poimenuj letalo +STR_A031_CAN_T_NAME_AIRCRAFT :{WHITE}Ni mogoče poimenovati letala ... +STR_A032_NAME_AIRCRAFT :{BLACK}Poimenuj letalo +STR_A033_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Prebivalci praznujejo . . .{}Prvo letalo pristalo na postaji {STATION}! +STR_A034_PLANE_CRASH_DIE_IN_FIREBALL :{BLACK}{BIGFONT}Letalska nesreča!{}{COMMA} umrlo v plamenih na letališču {STATION} +STR_A036 :{TINYFONT}{BLACK}{STATION} +STR_A037_RENAME :{BLACK}Preimenuj +STR_A038_RENAME_AIRCRAFT_TYPE :{BLACK}Preimenuj letalo +STR_A039_RENAME_AIRCRAFT_TYPE :{WHITE}Preimenuj letalo +STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Ni mogoče preimenovati letala ... +STR_A03B_REFIT_AIRCRAFT_TO_CARRY :{BLACK}Preuredi tovorni prostor letala, da lahko nosi drugačen tovor +STR_A03C_REFIT :{WHITE}{VEHICLE} (Preuredi) +STR_A03D_REFIT_AIRCRAFT :{BLACK}Preuredi letalo +STR_A03E_SELECT_TYPE_OF_CARGO_FOR :{BLACK}Izberite tip tovora +STR_A03F_REFIT_AIRCRAFT_TO_CARRY :{BLACK}Preuredi letalo, da lahko nosi izbran tovor +STR_A040_SELECT_CARGO_TYPE_TO_CARRY :{GOLD}Izberite tip tovora: +STR_A041_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nova kapaciteta: {GOLD}{STRING}{}{BLACK}Cena za preureditev: {GOLD}{CURRENCY} +STR_A042_CAN_T_REFIT_AIRCRAFT :{WHITE}Ni mogoče preurediti letala ... SERVICE_AT_AIRPORT_HANGAR :Storitev v {STATION} Hangarju ##id 0xB000 +STR_B000_ZEPPELIN_DISASTER_AT :{BLACK}{BIGFONT}Nesreča cepelina na postaji {STATION}! +STR_B001_ROAD_VEHICLE_DESTROYED :{BLACK}{BIGFONT}Cestno vozilo uničeno v trku z 'NLP'! +STR_B002_OIL_REFINERY_EXPLOSION :{BLACK}{BIGFONT}Eksplozija naftne rafinerije blizu mesta {TOWN}! +STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS :{BLACK}{BIGFONT}Tovarna uničena v sumljivih okoliščinah blizu mesta {TOWN}! +STR_B004_UFO_LANDS_NEAR :{BLACK}{BIGFONT}'NLP' pristal blizu mesta {TOWN}! +STR_B005_COAL_MINE_SUBSIDENCE_LEAVES :{BLACK}{BIGFONT}Rudnik premoga pušča opustošenje v okolici mesta {TOWN}! +STR_B006_FLOOD_VEHICLE_DESTROYED :{BLACK}{BIGFONT}Poplave!{}Vsaj {COMMA} pogrešanih, najverjetneje mrtvih ob močnih neurjih! +STR_BRIBE_FAILED :{WHITE}Vaša podkupnina je bila +STR_BRIBE_FAILED_2 :{WHITE}odkrita s strani lokalnih preiskovalcev +STR_BUILD_DATE :{BLACK}Zgrajeno: {LTBLUE}{DATE_LONG} SET_PERFORMANCE_DETAIL_INT :{BLACK}{NUM} ############ Those following lines need to be in this order!! @@ -1663,7 +2272,18 @@ + + + STR_TRAIN :{BLACK}{TRAIN} +STR_BUS :{BLACK}{BUS} + + + + +### depot strings + + @@ -1671,6 +2291,10 @@ STR_WAGONS :Vagoni + + + + ############ Lists rail types @@ -1678,6 +2302,17 @@ +########### String for New Landscape Generator + +STR_CLEARING_TILES :{BLACK}Generiranje grobih in skalnatih tal + + ########### String for new airports +STR_CITY_AIRPORT :{BLACK}Mestno +STR_COMMUTER_AIRPORT :{BLACK}Vozač + + +############ Tooltip measurment + ######## diff -r d4d00a16ef26 -r bfa6074e2833 lang/unfinished/traditional_chinese.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lang/unfinished/traditional_chinese.txt Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,2 @@ +##name Chinese (Simplified) +##isocode zh_TW.UTF-8 diff -r d4d00a16ef26 -r bfa6074e2833 main_gui.c --- a/main_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/main_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -23,7 +23,7 @@ #include "vehicle.h" #include "console.h" #include "sound.h" -#include "network.h" +#include "network/network.h" #include "signs.h" #include "waypoint.h" #include "variables.h" @@ -37,10 +37,10 @@ #include "vehicle_gui.h" #include "newgrf_config.h" -#include "network_data.h" -#include "network_client.h" -#include "network_server.h" -#include "network_gui.h" +#include "network/network_data.h" +#include "network/network_client.h" +#include "network/network_server.h" +#include "network/network_gui.h" #include "industry.h" static int _rename_id = 1; diff -r d4d00a16ef26 -r bfa6074e2833 misc.c --- a/misc.c Tue Jan 02 18:40:37 2007 +0000 +++ b/misc.c Wed Jan 03 08:32:17 2007 +0000 @@ -24,7 +24,7 @@ #ifndef MERSENNE_TWISTER #ifdef RANDOM_DEBUG -#include "network_data.h" +#include "network/network_data.h" uint32 DoRandom(int line, const char *file) #else // RANDOM_DEBUG uint32 Random(void) diff -r d4d00a16ef26 -r bfa6074e2833 misc_cmd.c --- a/misc_cmd.c Tue Jan 02 18:40:37 2007 +0000 +++ b/misc_cmd.c Wed Jan 03 08:32:17 2007 +0000 @@ -11,7 +11,7 @@ #include "window.h" #include "gui.h" #include "economy.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "livery.h" diff -r d4d00a16ef26 -r bfa6074e2833 misc_gui.c --- a/misc_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/misc_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -22,7 +22,7 @@ #include "player.h" #include "town.h" #include "sound.h" -#include "network.h" +#include "network/network.h" #include "string.h" #include "variables.h" #include "vehicle.h" diff -r d4d00a16ef26 -r bfa6074e2833 network.c --- a/network.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1448 +0,0 @@ -/* $Id$ */ - -#include "stdafx.h" -#include "network_data.h" - -#if defined(WITH_REV) - extern const char _openttd_revision[]; -#elif defined(WITH_REV_HACK) - #define WITH_REV - const char _openttd_revision[] = WITH_REV_HACK; -#else - const char _openttd_revision[] = NOREV_STRING; -#endif - - -#ifdef ENABLE_NETWORK - -#include "openttd.h" -#include "debug.h" -#include "functions.h" -#include "string.h" -#include "strings.h" -#include "map.h" -#include "command.h" -#include "variables.h" -#include "date.h" -#include "table/strings.h" -#include "network_client.h" -#include "network_server.h" -#include "network_udp.h" -#include "network_gamelist.h" -#include "network_gui.h" -#include "console.h" /* IConsoleCmdExec */ -#include /* va_list */ -#include "md5.h" - -#ifdef __MORPHOS__ -// the library base is required here -struct Library *SocketBase = NULL; -#endif - -// The listen socket for the server -static SOCKET _listensocket; - -// The amount of clients connected -static byte _network_clients_connected = 0; -// The index counter for new clients (is never decreased) -static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1; - -/* Some externs / forwards */ -extern void StateGameLoop(void); - -// Function that looks up the CI for a given client-index -NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index) -{ - NetworkClientInfo *ci; - - for (ci = _network_client_info; ci != endof(_network_client_info); ci++) { - if (ci->client_index == client_index) return ci; - } - - return NULL; -} - -/** Return the CI for a given IP - * @param ip IP of the client we are looking for. This must be in string-format - * @return return a pointer to the corresponding NetworkClientInfo struct or NULL on failure */ -NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip) -{ - NetworkClientInfo *ci; - uint32 ip_number = inet_addr(ip); - - for (ci = _network_client_info; ci != endof(_network_client_info); ci++) { - if (ci->client_ip == ip_number) return ci; - } - - return NULL; -} - -// Function that looks up the CS for a given client-index -NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index) -{ - NetworkClientState *cs; - - for (cs = _clients; cs != &_clients[MAX_CLIENT_INFO]; cs++) { - if (cs->index == client_index) return cs; - } - - return NULL; -} - -// NetworkGetClientName is a server-safe function to get the name of the client -// if the user did not send it yet, Client # is used. -void NetworkGetClientName(char *client_name, size_t size, const NetworkClientState *cs) -{ - const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); - - if (ci->client_name[0] == '\0') { - snprintf(client_name, size, "Client #%4d", cs->index); - } else { - ttd_strlcpy(client_name, ci->client_name, size); - } -} - -byte NetworkSpectatorCount(void) -{ - const NetworkClientState *cs; - byte count = 0; - - FOR_ALL_CLIENTS(cs) { - if (DEREF_CLIENT_INFO(cs)->client_playas == PLAYER_SPECTATOR) count++; - } - - return count; -} - -// This puts a text-message to the console, or in the future, the chat-box, -// (to keep it all a bit more general) -// If 'self_send' is true, this is the client who is sending the message -void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...) -{ - char buf[1024]; - va_list va; - const int duration = 10; // Game days the messages stay visible - char message[1024]; - char temp[1024]; - - va_start(va, str); - vsnprintf(buf, lengthof(buf), str, va); - va_end(va); - - switch (action) { - case NETWORK_ACTION_SERVER_MESSAGE: - color = 1; - snprintf(message, sizeof(message), "*** %s", buf); - break; - case NETWORK_ACTION_JOIN: - color = 1; - GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp)); - snprintf(message, sizeof(message), "*** %s %s", name, temp); - break; - case NETWORK_ACTION_LEAVE: - color = 1; - GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp)); - snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf); - break; - case NETWORK_ACTION_GIVE_MONEY: - if (self_send) { - SetDParamStr(0, name); - SetDParam(1, atoi(buf)); - GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp)); - snprintf(message, sizeof(message), "*** %s", temp); - } else { - SetDParam(0, atoi(buf)); - GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp)); - snprintf(message, sizeof(message), "*** %s %s", name, temp); - } - break; - case NETWORK_ACTION_NAME_CHANGE: - GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp)); - snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf); - break; - case NETWORK_ACTION_CHAT_COMPANY: - SetDParamStr(0, name); - SetDParamStr(1, buf); - GetString(temp, self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, lastof(temp)); - ttd_strlcpy(message, temp, sizeof(message)); - break; - case NETWORK_ACTION_CHAT_CLIENT: - SetDParamStr(0, name); - SetDParamStr(1, buf); - GetString(temp, self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, lastof(temp)); - ttd_strlcpy(message, temp, sizeof(message)); - break; - default: - SetDParamStr(0, name); - SetDParamStr(1, buf); - GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp)); - ttd_strlcpy(message, temp, sizeof(message)); - break; - } - - IConsolePrintF(color, "%s", message); - AddTextMessage(color, duration, "%s", message); -} - -// Calculate the frame-lag of a client -uint NetworkCalculateLag(const NetworkClientState *cs) -{ - int lag = cs->last_frame_server - cs->last_frame; - // This client has missed his ACK packet after 1 DAY_TICKS.. - // so we increase his lag for every frame that passes! - // The packet can be out by a max of _net_frame_freq - if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter) - lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq); - - return lag; -} - - -// There was a non-recoverable error, drop back to the main menu with a nice -// error -static void NetworkError(StringID error_string) -{ - _switch_mode = SM_MENU; - _switch_mode_errorstr = error_string; -} - -static void ClientStartError(const char *error) -{ - DEBUG(net, 0, "[client] could not start network: %s",error); - NetworkError(STR_NETWORK_ERR_CLIENT_START); -} - -static void ServerStartError(const char *error) -{ - DEBUG(net, 0, "[server] could not start network: %s",error); - NetworkError(STR_NETWORK_ERR_SERVER_START); -} - -static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs) -{ - // First, send a CLIENT_ERROR to the server, so he knows we are - // disconnection (and why!) - NetworkErrorCode errorno; - - // We just want to close the connection.. - if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { - cs->has_quit = true; - NetworkCloseClient(cs); - _networking = false; - - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - return; - } - - switch (res) { - case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; - case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; - default: errorno = NETWORK_ERROR_GENERAL; break; - } - // This means we fucked up and the server closed the connection - if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && - res != NETWORK_RECV_STATUS_SERVER_BANNED) { - SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno); - - // Dequeue all commands before closing the socket - NetworkSend_Packets(DEREF_CLIENT(0)); - } - - _switch_mode = SM_MENU; - NetworkCloseClient(cs); - _networking = false; -} - -/** Retrieve a string representation of an internal error number - * @param buf buffer where the error message will be stored - * @param err NetworkErrorCode - * @return returns a pointer to the error message (buf) */ -char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last) -{ - /* List of possible network errors, used by - * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */ - static const StringID network_error_strings[] = { - STR_NETWORK_ERR_CLIENT_GENERAL, - STR_NETWORK_ERR_CLIENT_DESYNC, - STR_NETWORK_ERR_CLIENT_SAVEGAME, - STR_NETWORK_ERR_CLIENT_CONNECTION_LOST, - STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR, - STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED, - STR_NETWORK_ERR_CLIENT_NOT_EXPECTED, - STR_NETWORK_ERR_CLIENT_WRONG_REVISION, - STR_NETWORK_ERR_CLIENT_NAME_IN_USE, - STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD, - STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH, - STR_NETWORK_ERR_CLIENT_KICKED, - STR_NETWORK_ERR_CLIENT_CHEATER, - STR_NETWORK_ERR_CLIENT_SERVER_FULL - }; - - if (err >= lengthof(network_error_strings)) err = 0; - - return GetString(buf, network_error_strings[err], last); -} - -/* Count the number of active clients connected */ -static uint NetworkCountPlayers(void) -{ - const NetworkClientState *cs; - uint count = 0; - - FOR_ALL_CLIENTS(cs) { - const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); - if (IsValidPlayer(ci->client_playas)) count++; - } - - return count; -} - -static bool _min_players_paused = false; - -/* Check if the minimum number of players has been reached and pause or unpause the game as appropriate */ -void CheckMinPlayers(void) -{ - if (!_network_dedicated) return; - - if (NetworkCountPlayers() < _network_min_players) { - if (_min_players_paused) return; - - _min_players_paused = true; - DoCommandP(0, 1, 0, NULL, CMD_PAUSE); - NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX); - } else { - if (!_min_players_paused) return; - - _min_players_paused = false; - DoCommandP(0, 0, 0, NULL, CMD_PAUSE); - NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX); - } -} - -// Find all IP-aliases for this host -static void NetworkFindIPs(void) -{ - int i; - -#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */ - /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ - int _netstat(int fd, char **output, int verbose); - - int seek_past_header(char **pos, const char *header) { - char *new_pos = strstr(*pos, header); - if (new_pos == 0) { - return B_ERROR; - } - *pos += strlen(header) + new_pos - *pos + 1; - return B_OK; - } - - int output_length; - char *output_pointer = NULL; - char **output; - int sock = socket(AF_INET, SOCK_DGRAM, 0); - i = 0; - - // If something fails, make sure the list is empty - _broadcast_list[0] = 0; - - if (sock < 0) { - DEBUG(net, 0, "[core] error creating socket"); - return; - } - - output_length = _netstat(sock, &output_pointer, 1); - if (output_length < 0) { - DEBUG(net, 0, "[core] error running _netstat"); - return; - } - - output = &output_pointer; - if (seek_past_header(output, "IP Interfaces:") == B_OK) { - for (;;) { - uint32 n, fields, read; - uint8 i1, i2, i3, i4, j1, j2, j3, j4; - struct in_addr inaddr; - uint32 ip; - uint32 netmask; - - fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n", - &n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read); - read += 1; - if (fields != 9) { - break; - } - - ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4; - netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4; - - if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) { - inaddr.s_addr = htonl(ip | ~netmask); - _broadcast_list[i] = inaddr.s_addr; - i++; - } - if (read < 0) { - break; - } - *output += read; - } - /* XXX - Using either one of these crashes openttd heavily? - wber */ - /*free(output_pointer);*/ - /*free(output);*/ - closesocket(sock); - } -#elif defined(HAVE_GETIFADDRS) - struct ifaddrs *ifap, *ifa; - - // If something fails, make sure the list is empty - _broadcast_list[0] = 0; - - if (getifaddrs(&ifap) != 0) - return; - - i = 0; - for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { - if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; - if (ifa->ifa_broadaddr == NULL) continue; - if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; - _broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr; - i++; - } - freeifaddrs(ifap); - -#else /* not HAVE_GETIFADDRS */ - SOCKET sock; -#ifdef WIN32 - DWORD len = 0; - INTERFACE_INFO ifo[MAX_INTERFACES]; - uint j; -#else - char buf[4 * 1024]; // Arbitrary buffer size - struct ifconf ifconf; - const char* buf_end; - const char* p; -#endif - - // If something fails, make sure the list is empty - _broadcast_list[0] = 0; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock == INVALID_SOCKET) return; - -#ifdef WIN32 - memset(&ifo[0], 0, sizeof(ifo)); - if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) { - closesocket(sock); - return; - } - - i = 0; - for (j = 0; j < len / sizeof(*ifo); j++) { - if (ifo[j].iiFlags & IFF_LOOPBACK) continue; - if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue; - /* iiBroadcast is unusable, because it always seems to be set to - * 255.255.255.255. - */ - _broadcast_list[i++] = - ifo[j].iiAddress.AddressIn.sin_addr.s_addr | - ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; - } -#else - ifconf.ifc_len = sizeof(buf); - ifconf.ifc_buf = buf; - if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) { - closesocket(sock); - return; - } - - i = 0; - buf_end = buf + ifconf.ifc_len; - for (p = buf; p < buf_end;) { - const struct ifreq* req = (const struct ifreq*)p; - - if (req->ifr_addr.sa_family == AF_INET) { - struct ifreq r; - - strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name)); - if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && - r.ifr_flags & IFF_BROADCAST && - ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { - _broadcast_list[i++] = - ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr; - } - } - - p += sizeof(struct ifreq); -#ifdef AF_LINK - p += req->ifr_addr.sa_len - sizeof(struct sockaddr); -#endif - } -#endif - - closesocket(sock); -#endif /* not HAVE_GETIFADDRS */ - - _broadcast_list[i] = 0; - - DEBUG(net, 3, "Detected broadcast addresses:"); - // Now display to the debug all the detected ips - for (i = 0; _broadcast_list[i] != 0; i++) { - DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr)); - } -} - -// Resolve a hostname to a inet_addr -unsigned long NetworkResolveHost(const char *hostname) -{ - in_addr_t ip; - - // First try: is it an ip address? - ip = inet_addr(hostname); - - // If not try to resolve the name - if (ip == INADDR_NONE) { - struct hostent *he = gethostbyname(hostname); - if (he == NULL) { - DEBUG(net, 0, "Cannot resolve '%s'", hostname); - } else { - struct in_addr addr = *(struct in_addr *)he->h_addr_list[0]; - DEBUG(net, 1, "Resolved '%s' to %s", hostname, inet_ntoa(addr)); - ip = addr.s_addr; - } - } - return ip; -} - -// Converts a string to ip/port/player -// Format: IP#player:port -// -// connection_string will be re-terminated to seperate out the hostname, and player and port will -// be set to the player and port strings given by the user, inside the memory area originally -// occupied by connection_string. -void ParseConnectionString(const char **player, const char **port, char *connection_string) -{ - char *p; - for (p = connection_string; *p != '\0'; p++) { - if (*p == '#') { - *p = '\0'; - *player = ++p; - while (IsValidChar(*p, CS_NUMERAL)) p++; - if (*p == '\0') break; - } else if (*p == ':') { - *port = p + 1; - *p = '\0'; - } - } -} - -// Creates a new client from a socket -// Used both by the server and the client -static NetworkClientState *NetworkAllocClient(SOCKET s) -{ - NetworkClientState *cs; - byte client_no = 0; - - if (_network_server) { - // Can we handle a new client? - if (_network_clients_connected >= MAX_CLIENTS) return NULL; - if (_network_game_info.clients_on >= _network_game_info.clients_max) return NULL; - - // Register the login - client_no = _network_clients_connected++; - } - - cs = DEREF_CLIENT(client_no); - memset(cs, 0, sizeof(*cs)); - cs->socket = s; - cs->last_frame = 0; - cs->has_quit = false; - - cs->last_frame = _frame_counter; - cs->last_frame_server = _frame_counter; - - if (_network_server) { - NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); - memset(ci, 0, sizeof(*ci)); - - cs->index = _network_client_index++; - ci->client_index = cs->index; - ci->client_playas = PLAYER_INACTIVE_CLIENT; - ci->join_date = _date; - - InvalidateWindow(WC_CLIENT_LIST, 0); - } - - return cs; -} - -// Close a connection -void NetworkCloseClient(NetworkClientState *cs) -{ - NetworkClientInfo *ci; - // Socket is already dead - if (cs->socket == INVALID_SOCKET) { - cs->has_quit = true; - return; - } - - DEBUG(net, 1, "Closed client connection %d", cs->index); - - if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) { - // We did not receive a leave message from this client... - NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST; - char str[100]; - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - NetworkClientState *new_cs; - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - GetNetworkErrorMsg(str, errorno, lastof(str)); - - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); - - // Inform other clients of this... strange leaving ;) - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status > STATUS_AUTH && cs != new_cs) { - SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno); - } - } - } - - /* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */ - if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) { - DoCommandP(0, 0, 0, NULL, CMD_PAUSE); - NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX); - } - - closesocket(cs->socket); - cs->writable = false; - cs->has_quit = true; - - // Free all pending and partially received packets - while (cs->packet_queue != NULL) { - Packet *p = cs->packet_queue->next; - free(cs->packet_queue); - cs->packet_queue = p; - } - free(cs->packet_recv); - cs->packet_recv = NULL; - - while (cs->command_queue != NULL) { - CommandPacket *p = cs->command_queue->next; - free(cs->command_queue); - cs->command_queue = p; - } - - // Close the gap in the client-list - ci = DEREF_CLIENT_INFO(cs); - - if (_network_server) { - // We just lost one client :( - if (cs->status > STATUS_INACTIVE) _network_game_info.clients_on--; - _network_clients_connected--; - - while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) { - *cs = *(cs + 1); - *ci = *(ci + 1); - cs++; - ci++; - } - - InvalidateWindow(WC_CLIENT_LIST, 0); - } - - // Reset the status of the last socket - cs->socket = INVALID_SOCKET; - cs->status = STATUS_INACTIVE; - cs->index = NETWORK_EMPTY_INDEX; - ci->client_index = NETWORK_EMPTY_INDEX; - - CheckMinPlayers(); -} - -// A client wants to connect to a server -static bool NetworkConnect(const char *hostname, int port) -{ - SOCKET s; - struct sockaddr_in sin; - - DEBUG(net, 1, "Connecting to %s %d", hostname, port); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == INVALID_SOCKET) { - ClientStartError("socket() failed"); - return false; - } - - if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed"); - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = NetworkResolveHost(hostname); - sin.sin_port = htons(port); - _network_last_host_ip = sin.sin_addr.s_addr; - - /* We failed to connect for which reason what so ever */ - if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) return false; - - if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error? - - // in client mode, only the first client field is used. it's pointing to the server. - NetworkAllocClient(s); - - _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; - ShowJoinStatusWindow(); - - return true; -} - -// For the server, to accept new clients -static void NetworkAcceptClients(void) -{ - struct sockaddr_in sin; - NetworkClientState *cs; - uint i; - bool banned; - - // Should never ever happen.. is it possible?? - assert(_listensocket != INVALID_SOCKET); - - for (;;) { - socklen_t sin_len = sizeof(sin); - SOCKET s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len); - if (s == INVALID_SOCKET) return; - - SetNonBlocking(s); // XXX error handling? - - DEBUG(net, 1, "Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter); - - SetNoDelay(s); // XXX error handling? - - /* Check if the client is banned */ - banned = false; - for (i = 0; i < lengthof(_network_ban_list); i++) { - if (_network_ban_list[i] == NULL) continue; - - if (sin.sin_addr.s_addr == inet_addr(_network_ban_list[i])) { - Packet *p = NetworkSend_Init(PACKET_SERVER_BANNED); - - DEBUG(net, 1, "Banned ip tried to join (%s), refused", _network_ban_list[i]); - - p->buffer[0] = p->size & 0xFF; - p->buffer[1] = p->size >> 8; - - send(s, p->buffer, p->size, 0); - closesocket(s); - - free(p); - - banned = true; - break; - } - } - /* If this client is banned, continue with next client */ - if (banned) continue; - - cs = NetworkAllocClient(s); - if (cs == NULL) { - // no more clients allowed? - // Send to the client that we are full! - Packet *p = NetworkSend_Init(PACKET_SERVER_FULL); - - p->buffer[0] = p->size & 0xFF; - p->buffer[1] = p->size >> 8; - - send(s, p->buffer, p->size, 0); - closesocket(s); - - free(p); - - continue; - } - - // a new client has connected. We set him at inactive for now - // maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK - // the client stays inactive - cs->status = STATUS_INACTIVE; - - DEREF_CLIENT_INFO(cs)->client_ip = sin.sin_addr.s_addr; // Save the IP of the client - } -} - -// Set up the listen socket for the server -static bool NetworkListen(void) -{ - SOCKET ls; - struct sockaddr_in sin; - - DEBUG(net, 1, "Listening on %s:%d", _network_server_bind_ip_host, _network_server_port); - - ls = socket(AF_INET, SOCK_STREAM, 0); - if (ls == INVALID_SOCKET) { - ServerStartError("socket() on listen socket failed"); - return false; - } - - { // reuse the socket - int reuse = 1; - // The (const char*) cast is needed for windows!! - if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) { - ServerStartError("setsockopt() on listen socket failed"); - return false; - } - } - - if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error? - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = _network_server_bind_ip; - sin.sin_port = htons(_network_server_port); - - if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) { - ServerStartError("bind() failed"); - return false; - } - - if (listen(ls, 1) != 0) { - ServerStartError("listen() failed"); - return false; - } - - _listensocket = ls; - - return true; -} - -// Close all current connections -static void NetworkClose(void) -{ - NetworkClientState *cs; - - FOR_ALL_CLIENTS(cs) { - if (!_network_server) { - SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving"); - NetworkSend_Packets(cs); - } - NetworkCloseClient(cs); - } - - if (_network_server) { - // We are a server, also close the listensocket - closesocket(_listensocket); - _listensocket = INVALID_SOCKET; - DEBUG(net, 1, "Closed listener"); - NetworkUDPClose(); - } -} - -// Inits the network (cleans sockets and stuff) -static void NetworkInitialize(void) -{ - NetworkClientState *cs; - - _local_command_queue = NULL; - - // Clean all client-sockets - memset(_clients, 0, sizeof(_clients)); - for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) { - cs->socket = INVALID_SOCKET; - cs->status = STATUS_INACTIVE; - cs->command_queue = NULL; - } - - // Clean the client_info memory - memset(&_network_client_info, 0, sizeof(_network_client_info)); - memset(&_network_player_info, 0, sizeof(_network_player_info)); - - _sync_frame = 0; - _network_first_time = true; - - _network_reconnect = 0; - - NetworkUDPInitialize(); -} - -// Query a server to fetch his game-info -// If game_info is true, only the gameinfo is fetched, -// else only the client_info is fetched -NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info) -{ - if (!_network_available) return NULL; - - NetworkDisconnect(); - - if (game_info) return NetworkUDPQueryServer(host, port); - - NetworkInitialize(); - - _network_server = false; - - // Try to connect - _networking = NetworkConnect(host, port); - - // We are connected - if (_networking) { - SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)(); - } else { // No networking, close everything down again - NetworkDisconnect(); - } - - return NULL; -} - -/* Validates an address entered as a string and adds the server to - * the list. If you use this function, the games will be marked - * as manually added. */ -void NetworkAddServer(const char *b) -{ - if (*b != '\0') { - NetworkGameList *item; - const char *port = NULL; - const char *player = NULL; - char host[NETWORK_HOSTNAME_LENGTH]; - uint16 rport; - - ttd_strlcpy(host, b, lengthof(host)); - - ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip)); - rport = NETWORK_DEFAULT_PORT; - - ParseConnectionString(&player, &port, host); - if (port != NULL) rport = atoi(port); - - item = NetworkQueryServer(host, rport, true); - item->manually = true; - } -} - -/* Generates the list of manually added hosts from NetworkGameList and - * dumps them into the array _network_host_list. This array is needed - * by the function that generates the config file. */ -void NetworkRebuildHostList(void) -{ - uint i = 0; - const NetworkGameList *item = _network_game_list; - while (item != NULL && i != lengthof(_network_host_list)) { - if (item->manually) { - free(_network_host_list[i]); - _network_host_list[i++] = str_fmt("%s:%i", item->info.hostname, item->port); - } - item = item->next; - } - - for (; i < lengthof(_network_host_list); i++) { - free(_network_host_list[i]); - _network_host_list[i] = NULL; - } -} - -// Used by clients, to connect to a server -bool NetworkClientConnectGame(const char *host, uint16 port) -{ - if (!_network_available) return false; - - if (port == 0) return false; - - ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host)); - _network_last_port = port; - - NetworkDisconnect(); - NetworkUDPClose(); - NetworkInitialize(); - - // Try to connect - _networking = NetworkConnect(host, port); - - // We are connected - if (_networking) { - IConsoleCmdExec("exec scripts/on_client.scr 0"); - NetworkClient_Connected(); - } else { - // Connecting failed - NetworkError(STR_NETWORK_ERR_NOCONNECTION); - } - - return _networking; -} - -static void NetworkInitGameInfo(void) -{ - NetworkClientInfo *ci; - - ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name)); - ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password)); - ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_rcon_password)); - if (_network_game_info.server_name[0] == '\0') - snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server"); - - ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision)); - - // The server is a client too ;) - if (_network_dedicated) { - _network_game_info.clients_on = 0; - _network_game_info.companies_on = 0; - _network_game_info.dedicated = true; - } else { - _network_game_info.clients_on = 1; - _network_game_info.companies_on = 1; - _network_game_info.dedicated = false; - } - - _network_game_info.spectators_on = 0; - - _network_game_info.game_date = _date; - _network_game_info.start_date = ConvertYMDToDate(_patches.starting_year, 0, 1); - _network_game_info.map_width = MapSizeX(); - _network_game_info.map_height = MapSizeY(); - _network_game_info.map_set = _opt.landscape; - - _network_game_info.use_password = (_network_server_password[0] != '\0'); - - // We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it - // The index is NETWORK_SERVER_INDEX ( = 1) - ci = &_network_client_info[MAX_CLIENT_INFO - 1]; - memset(ci, 0, sizeof(*ci)); - - ci->client_index = NETWORK_SERVER_INDEX; - ci->client_playas = _network_dedicated ? PLAYER_SPECTATOR : _local_player; - - ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name)); - ttd_strlcpy(ci->unique_id, _network_unique_id, sizeof(ci->unique_id)); -} - -bool NetworkServerStart(void) -{ - if (!_network_available) return false; - - /* Call the pre-scripts */ - IConsoleCmdExec("exec scripts/pre_server.scr 0"); - if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0"); - - NetworkInitialize(); - if (!NetworkListen()) return false; - - // Try to start UDP-server - _network_udp_server = true; - _network_udp_server = NetworkUDPListen(&_udp_server_socket, _network_server_bind_ip, _network_server_port, false); - - _network_server = true; - _networking = true; - _frame_counter = 0; - _frame_counter_server = 0; - _frame_counter_max = 0; - _last_sync_frame = 0; - _network_own_client_index = NETWORK_SERVER_INDEX; - - /* Non-dedicated server will always be player #1 */ - if (!_network_dedicated) _network_playas = 0; - - _network_clients_connected = 0; - - NetworkInitGameInfo(); - - // execute server initialization script - IConsoleCmdExec("exec scripts/on_server.scr 0"); - // if the server is dedicated ... add some other script - if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0"); - - _min_players_paused = false; - CheckMinPlayers(); - - /* Try to register us to the master server */ - _network_last_advertise_frame = 0; - _network_need_advertise = true; - NetworkUDPAdvertise(); - return true; -} - -// The server is rebooting... -// The only difference with NetworkDisconnect, is the packets that is sent -void NetworkReboot(void) -{ - if (_network_server) { - NetworkClientState *cs; - FOR_ALL_CLIENTS(cs) { - SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs); - NetworkSend_Packets(cs); - } - } - - NetworkClose(); - - // Free all queued commands - while (_local_command_queue != NULL) { - CommandPacket *p = _local_command_queue; - _local_command_queue = _local_command_queue->next; - free(p); - } - - _networking = false; - _network_server = false; -} - -// We want to disconnect from the host/clients -void NetworkDisconnect(void) -{ - if (_network_server) { - NetworkClientState *cs; - FOR_ALL_CLIENTS(cs) { - SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs); - NetworkSend_Packets(cs); - } - } - - if (_network_advertise) NetworkUDPRemoveAdvertise(); - - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - - NetworkClose(); - - // Free all queued commands - while (_local_command_queue != NULL) { - CommandPacket *p = _local_command_queue; - _local_command_queue = _local_command_queue->next; - free(p); - } - - _networking = false; - _network_server = false; -} - -// Receives something from the network -static bool NetworkReceive(void) -{ - NetworkClientState *cs; - int n; - fd_set read_fd, write_fd; - struct timeval tv; - - FD_ZERO(&read_fd); - FD_ZERO(&write_fd); - - FOR_ALL_CLIENTS(cs) { - FD_SET(cs->socket, &read_fd); - FD_SET(cs->socket, &write_fd); - } - - // take care of listener port - if (_network_server) FD_SET(_listensocket, &read_fd); - - tv.tv_sec = tv.tv_usec = 0; // don't block at all. -#if !defined(__MORPHOS__) && !defined(__AMIGA__) - n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv); -#else - n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL); -#endif - if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION); - - // accept clients.. - if (_network_server && FD_ISSET(_listensocket, &read_fd)) NetworkAcceptClients(); - - // read stuff from clients - FOR_ALL_CLIENTS(cs) { - cs->writable = !!FD_ISSET(cs->socket, &write_fd); - if (FD_ISSET(cs->socket, &read_fd)) { - if (_network_server) { - NetworkServer_ReadPackets(cs); - } else { - NetworkRecvStatus res; - - // The client already was quiting! - if (cs->has_quit) return false; - - res = NetworkClient_ReadPackets(cs); - if (res != NETWORK_RECV_STATUS_OKAY) { - // The client made an error of which we can not recover - // close the client and drop back to main menu - NetworkClientError(res, cs); - return false; - } - } - } - } - return true; -} - -// This sends all buffered commands (if possible) -static void NetworkSend(void) -{ - NetworkClientState *cs; - FOR_ALL_CLIENTS(cs) { - if (cs->writable) { - NetworkSend_Packets(cs); - - if (cs->status == STATUS_MAP) { - // This client is in the middle of a map-send, call the function for that - SEND_COMMAND(PACKET_SERVER_MAP)(cs); - } - } - } -} - -// Handle the local-command-queue -static void NetworkHandleLocalQueue(void) -{ - CommandPacket *cp, **cp_prev; - - cp_prev = &_local_command_queue; - - while ( (cp = *cp_prev) != NULL) { - - // The queue is always in order, which means - // that the first element will be executed first. - if (_frame_counter < cp->frame) break; - - if (_frame_counter > cp->frame) { - // If we reach here, it means for whatever reason, we've already executed - // past the command we need to execute. - DEBUG(net, 0, "Trying to execute a packet in the past!"); - assert(0); - } - - // We can execute this command - NetworkExecuteCommand(cp); - - *cp_prev = cp->next; - free(cp); - } - - // Just a safety check, to be removed in the future. - // Make sure that no older command appears towards the end of the queue - // In that case we missed executing it. This will never happen. - for (cp = _local_command_queue; cp; cp = cp->next) { - assert(_frame_counter < cp->frame); - } - -} - -static bool NetworkDoClientLoop(void) -{ - _frame_counter++; - - NetworkHandleLocalQueue(); - - StateGameLoop(); - - // Check if we are in sync! - if (_sync_frame != 0) { - if (_sync_frame == _frame_counter) { -#ifdef NETWORK_SEND_DOUBLE_SEED - if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) { -#else - if (_sync_seed_1 != _random_seeds[0][0]) { -#endif - NetworkError(STR_NETWORK_ERR_DESYNC); - DEBUG(net, 0, "Sync error detected!"); - NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0)); - return false; - } - - // If this is the first time we have a sync-frame, we - // need to let the server know that we are ready and at the same - // frame as he is.. so we can start playing! - if (_network_first_time) { - _network_first_time = false; - SEND_COMMAND(PACKET_CLIENT_ACK)(); - } - - _sync_frame = 0; - } else if (_sync_frame < _frame_counter) { - DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter); - _sync_frame = 0; - } - } - - return true; -} - -// We have to do some UDP checking -void NetworkUDPGameLoop(void) -{ - if (_network_udp_server) { - NetworkUDPReceive(_udp_server_socket); - if (_udp_master_socket != INVALID_SOCKET) { - NetworkUDPReceive(_udp_master_socket); - } - } else if (_udp_client_socket != INVALID_SOCKET) { - NetworkUDPReceive(_udp_client_socket); - if (_network_udp_broadcast > 0) _network_udp_broadcast--; - } -} - -// The main loop called from ttd.c -// Here we also have to do StateGameLoop if needed! -void NetworkGameLoop(void) -{ - if (!_networking) return; - - if (!NetworkReceive()) return; - - if (_network_server) { - bool send_frame = false; - - // We first increase the _frame_counter - _frame_counter++; - // Update max-frame-counter - if (_frame_counter > _frame_counter_max) { - _frame_counter_max = _frame_counter + _network_frame_freq; - send_frame = true; - } - - NetworkHandleLocalQueue(); - - // Then we make the frame - StateGameLoop(); - - _sync_seed_1 = _random_seeds[0][0]; -#ifdef NETWORK_SEND_DOUBLE_SEED - _sync_seed_2 = _random_seeds[0][1]; -#endif - - NetworkServer_Tick(send_frame); - } else { - // Client - - // Make sure we are at the frame were the server is (quick-frames) - if (_frame_counter_server > _frame_counter) { - while (_frame_counter_server > _frame_counter) { - if (!NetworkDoClientLoop()) break; - } - } else { - // Else, keep on going till _frame_counter_max - if (_frame_counter_max > _frame_counter) NetworkDoClientLoop(); - } - } - - NetworkSend(); -} - -static void NetworkGenerateUniqueId(void) -{ - md5_state_t state; - md5_byte_t digest[16]; - char hex_output[16*2 + 1]; - char coding_string[NETWORK_NAME_LENGTH]; - int di; - - snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID"); - - /* Generate the MD5 hash */ - md5_init(&state); - md5_append(&state, (const md5_byte_t*)coding_string, strlen(coding_string)); - md5_finish(&state, digest); - - for (di = 0; di < 16; ++di) - sprintf(hex_output + di * 2, "%02x", digest[di]); - - /* _network_unique_id is our id */ - snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output); -} - -// This tries to launch the network for a given OS -void NetworkStartUp(void) -{ - DEBUG(net, 3, "[core] starting network..."); - -#if defined(__MORPHOS__) || defined(__AMIGA__) - /* - * IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_ - * network related function, else: crash. - */ - DEBUG(net, 3, "[core] loading bsd socket library"); - SocketBase = OpenLibrary("bsdsocket.library", 4); - if (SocketBase == NULL) { - DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable"); - _network_available = false; - return; - } - -#if defined(__AMIGA__) - // for usleep() implementation (only required for legacy AmigaOS builds) - TimerPort = CreateMsgPort(); - if (TimerPort != NULL) { - TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest); - if (TimerRequest != NULL) { - if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) { - TimerBase = TimerRequest->tr_node.io_Device; - if (TimerBase == NULL) { - // free ressources... - DEBUG(net, 0, "[core] can't initialize timer, network unavailable"); - _network_available = false; - return; - } - } - } - } -#endif // __AMIGA__ -#endif // __MORPHOS__ / __AMIGA__ - - // Network is available - _network_available = true; - _network_dedicated = false; - _network_last_advertise_frame = 0; - _network_need_advertise = true; - _network_advertise_retries = 0; - - /* Load the ip from the openttd.cfg */ - _network_server_bind_ip = inet_addr(_network_server_bind_ip_host); - /* And put the data back in it in case it was an invalid ip */ - snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip)); - - /* Generate an unique id when there is none yet */ - if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId(); - - { - byte cl_max = _network_game_info.clients_max; - byte cp_max = _network_game_info.companies_max; - byte sp_max = _network_game_info.spectators_max; - - memset(&_network_game_info, 0, sizeof(_network_game_info)); - _network_game_info.clients_max = cl_max; - _network_game_info.companies_max = cp_max; - _network_game_info.spectators_max = sp_max; - } - - // Let's load the network in windows - #if defined(WIN32) - { - WSADATA wsa; - DEBUG(net, 3, "[core] loading windows socket library"); - if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { - DEBUG(net, 0, "[core] WSAStartup failed, network unavailable"); - _network_available = false; - return; - } - } - #endif // WIN32 - - NetworkInitialize(); - DEBUG(net, 3, "[core] network online, multiplayer available"); - NetworkFindIPs(); -} - -// This shuts the network down -void NetworkShutDown(void) -{ - NetworkDisconnect(); - NetworkUDPClose(); - - DEBUG(net, 3, "[core] shutting down network"); - - _network_available = false; - -#if defined(__MORPHOS__) || defined(__AMIGA__) - // free allocated ressources -#if defined(__AMIGA__) - if (TimerBase != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong - if (TimerRequest != NULL) DeleteIORequest(TimerRequest); - if (TimerPort != NULL) DeleteMsgPort(TimerPort); -#endif - - if (SocketBase != NULL) CloseLibrary(SocketBase); -#endif - -#if defined(WIN32) - WSACleanup(); -#endif -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network.h --- a/network.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,271 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_H -#define NETWORK_H - -#define NOREV_STRING "norev000" - -#ifdef ENABLE_NETWORK - -#include "player.h" - -// If this line is enable, every frame will have a sync test -// this is not needed in normal games. Normal is like 1 sync in 100 -// frames. You can enable this if you have a lot of desyncs on a certain -// game. -// Remember: both client and server have to be compiled with this -// option enabled to make it to work. If one of the two has it disabled -// nothing will happen. -//#define ENABLE_NETWORK_SYNC_EVERY_FRAME - -// In theory sending 1 of the 2 seeds is enough to check for desyncs -// so in theory, this next define can be left off. -//#define NETWORK_SEND_DOUBLE_SEED - -// How many clients can we have? Like.. MAX_PLAYERS - 1 is the amount of -// players that can really play.. so.. a max of 4 spectators.. gives us.. -// MAX_PLAYERS + 3 -#define MAX_CLIENTS (MAX_PLAYERS + 3) - - -// Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1 -#define MAX_CLIENT_INFO (MAX_CLIENTS + 1) - -/* Stuff for the master-server */ -#define NETWORK_MASTER_SERVER_PORT 3978 -#define NETWORK_MASTER_SERVER_HOST "master.openttd.org" -#define NETWORK_MASTER_SERVER_WELCOME_MESSAGE "OpenTTDRegister" - -#define NETWORK_DEFAULT_PORT 3979 - -#define MAX_INTERFACES 9 - - -// How many vehicle/station types we put over the network -#define NETWORK_VEHICLE_TYPES 5 -#define NETWORK_STATION_TYPES 5 - -enum { - NETWORK_NAME_LENGTH = 80, - NETWORK_HOSTNAME_LENGTH = 80, - NETWORK_REVISION_LENGTH = 15, - NETWORK_PASSWORD_LENGTH = 20, - NETWORK_PLAYERS_LENGTH = 200, - NETWORK_CLIENT_NAME_LENGTH = 25, - NETWORK_RCONCOMMAND_LENGTH = 500, - - NETWORK_GRF_NAME_LENGTH = 80, ///< Maximum length of the name of a GRF - /* Maximum number of GRFs that can be sent. - * This value is related to number of handles (files) OpenTTD can open. - * This is currently 64 and about 10 are currently used when OpenTTD loads - * without any NewGRFs. Therefore one can only load about 55 NewGRFs, so - * this is not a limit, but rather a way to easily check whether the limit - * imposed by the handle count is reached. Secondly it isn't possible to - * send much more GRF IDs + MD5sums in the PACKET_UDP_SERVER_RESPONSE, due - * to the limited size of UDP packets. */ - NETWORK_MAX_GRF_COUNT = 55, - - NETWORK_NUM_LANGUAGES = 4, -}; - -// This is the struct used by both client and server -// some fields will be empty on the client (like game_password) by default -// and only filled with data a player enters. -typedef struct NetworkGameInfo { - char server_name[NETWORK_NAME_LENGTH]; // Server name - char hostname[NETWORK_HOSTNAME_LENGTH]; // Hostname of the server (if any) - char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304') - // It even shows a SVN version in release-version, so - // it is easy to compare if a server is of the correct version - bool version_compatible; // Can we connect to this server or not? (based on server_revision) - bool compatible; // Can we connect to this server or not? (based on server_revision _and_ grf_match - byte server_lang; // Language of the server (we should make a nice table for this) - byte use_password; // Is set to != 0 if it uses a password - char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password - byte clients_max; // Max clients allowed on server - byte clients_on; // Current count of clients on server - byte companies_max; // Max companies allowed on server - byte companies_on; // How many started companies do we have (XXX - disabled for server atm, use ActivePlayerCount()) - byte spectators_max; // Max spectators allowed on server - byte spectators_on; // How many spectators do we have? (XXX - disabled for server atm, use NetworkSpectatorCount()) - Date game_date; // Current date - Date start_date; // When the game started - char map_name[NETWORK_NAME_LENGTH]; // Map which is played ["random" for a randomized map] - uint16 map_width; // Map width - uint16 map_height; // Map height - byte map_set; // Graphical set - bool dedicated; // Is this a dedicated server? - char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled - struct GRFConfig *grfconfig; // List of NewGRF files required -} NetworkGameInfo; - -typedef struct NetworkPlayerInfo { - char company_name[NETWORK_NAME_LENGTH]; // Company name - char password[NETWORK_PASSWORD_LENGTH]; // The password for the player - Year inaugurated_year; // What year the company started in - int64 company_value; // The company value - int64 money; // The amount of money the company has - int64 income; // How much did the company earned last year - uint16 performance; // What was his performance last month? - byte use_password; // 0: No password 1: There is a password - uint16 num_vehicle[NETWORK_VEHICLE_TYPES]; // How many vehicles are there of this type? - uint16 num_station[NETWORK_STATION_TYPES]; // How many stations are there of this type? - char players[NETWORK_PLAYERS_LENGTH]; // The players that control this company (Name1, name2, ..) - uint16 months_empty; // How many months the company is empty -} NetworkPlayerInfo; - -typedef struct NetworkClientInfo { - uint16 client_index; // Index of the client (same as ClientState->index) - char client_name[NETWORK_CLIENT_NAME_LENGTH]; // Name of the client - byte client_lang; // The language of the client - byte client_playas; // As which player is this client playing (PlayerID) - uint32 client_ip; // IP-address of the client (so he can be banned) - Date join_date; // Gamedate the player has joined - char unique_id[NETWORK_NAME_LENGTH]; // Every play sends an unique id so we can indentify him -} NetworkClientInfo; - -typedef struct NetworkGameList { - NetworkGameInfo info; - uint32 ip; - uint16 port; - bool online; // False if the server did not respond (default status) - bool manually; // True if the server was added manually - struct NetworkGameList *next; -} NetworkGameList; - -typedef enum { - NETWORK_JOIN_STATUS_CONNECTING, - NETWORK_JOIN_STATUS_AUTHORIZING, - NETWORK_JOIN_STATUS_WAITING, - NETWORK_JOIN_STATUS_DOWNLOADING, - NETWORK_JOIN_STATUS_PROCESSING, - NETWORK_JOIN_STATUS_REGISTERING, - - NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO, -} NetworkJoinStatus; - -// language ids for server_lang and client_lang -typedef enum { - NETLANG_ANY = 0, - NETLANG_ENGLISH = 1, - NETLANG_GERMAN = 2, - NETLANG_FRENCH = 3, -} NetworkLanguage; - -VARDEF NetworkGameList *_network_game_list; - -VARDEF NetworkGameInfo _network_game_info; -VARDEF NetworkPlayerInfo _network_player_info[MAX_PLAYERS]; -VARDEF NetworkClientInfo _network_client_info[MAX_CLIENT_INFO]; - -VARDEF char _network_player_name[NETWORK_CLIENT_NAME_LENGTH]; -VARDEF char _network_default_ip[NETWORK_HOSTNAME_LENGTH]; - -VARDEF uint16 _network_own_client_index; -VARDEF char _network_unique_id[NETWORK_NAME_LENGTH]; // Our own unique ID - -VARDEF uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode -VARDEF uint32 _frame_counter_max; // To where we may go with our clients - -VARDEF uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients. - -// networking settings -VARDEF uint32 _broadcast_list[MAX_INTERFACES + 1]; - -VARDEF uint16 _network_server_port; -/* We use bind_ip and bind_ip_host, where bind_ip_host is the readable form of - bind_ip_host, and bind_ip the numeric value, because we want a nice number - in the openttd.cfg, but we wants to use the uint32 internally.. */ -VARDEF uint32 _network_server_bind_ip; -VARDEF char _network_server_bind_ip_host[NETWORK_HOSTNAME_LENGTH]; -VARDEF bool _is_network_server; // Does this client wants to be a network-server? -VARDEF char _network_server_name[NETWORK_NAME_LENGTH]; -VARDEF char _network_server_password[NETWORK_PASSWORD_LENGTH]; -VARDEF char _network_rcon_password[NETWORK_PASSWORD_LENGTH]; - -VARDEF uint16 _network_max_join_time; ///< Time a client can max take to join -VARDEF bool _network_pause_on_join; ///< Pause the game when a client tries to join (more chance of succeeding join) - -VARDEF uint16 _redirect_console_to_client; - -VARDEF uint16 _network_sync_freq; -VARDEF uint8 _network_frame_freq; - -VARDEF uint32 _sync_seed_1, _sync_seed_2; -VARDEF uint32 _sync_frame; -VARDEF bool _network_first_time; -// Vars needed for the join-GUI -VARDEF NetworkJoinStatus _network_join_status; -VARDEF uint8 _network_join_waiting; -VARDEF uint16 _network_join_kbytes; -VARDEF uint16 _network_join_kbytes_total; - -VARDEF char _network_last_host[NETWORK_HOSTNAME_LENGTH]; -VARDEF short _network_last_port; -VARDEF uint32 _network_last_host_ip; -VARDEF uint8 _network_reconnect; - -VARDEF bool _network_udp_server; -VARDEF uint16 _network_udp_broadcast; - -VARDEF byte _network_lan_internet; - -VARDEF bool _network_need_advertise; -VARDEF uint32 _network_last_advertise_frame; -VARDEF uint8 _network_advertise_retries; - -VARDEF bool _network_autoclean_companies; -VARDEF uint8 _network_autoclean_unprotected; // Remove a company after X months -VARDEF uint8 _network_autoclean_protected; // Unprotect a company after X months - -VARDEF Year _network_restart_game_year; // If this year is reached, the server automaticly restarts -VARDEF uint8 _network_min_players; // Minimum number of players for game to unpause - -NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info); - -byte NetworkSpectatorCount(void); - -VARDEF char *_network_host_list[10]; -VARDEF char *_network_ban_list[25]; - -void ParseConnectionString(const char **player, const char **port, char *connection_string); -void NetworkUpdateClientInfo(uint16 client_index); -void NetworkAddServer(const char *b); -void NetworkRebuildHostList(void); -bool NetworkChangeCompanyPassword(byte argc, char *argv[]); -void NetworkPopulateCompanyInfo(void); -void UpdateNetworkGameWindow(bool unselect); -void CheckMinPlayers(void); - -void NetworkStartUp(void); -void NetworkUDPClose(void); -void NetworkShutDown(void); -void NetworkGameLoop(void); -void NetworkUDPGameLoop(void); -bool NetworkServerStart(void); -bool NetworkClientConnectGame(const char *host, uint16 port); -void NetworkReboot(void); -void NetworkDisconnect(void); - -VARDEF bool _networking; ///< are we in networking mode? -VARDEF bool _network_server; ///< network-server is active -VARDEF bool _network_available; ///< is network mode available? - -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void NetworkStartUp(void) {} -static inline void NetworkShutDown(void) {} - -#define _networking 0 -#define _network_server 0 -#define _network_available 0 - -#endif /* ENABLE_NETWORK */ - -/* These variables must always be registered! */ -VARDEF bool _network_dedicated; ///< are we a dedicated server? -VARDEF bool _network_advertise; ///< is the server advertising to the master server? -VARDEF PlayerID _network_playas; ///< an id to play as.. (see players.h:Players) - -#endif /* NETWORK_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/config.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,49 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_CONFIG_H +#define NETWORK_CORE_CONFIG_H + +#ifdef ENABLE_NETWORK + +/** DNS hostname of the masterserver */ +#define NETWORK_MASTER_SERVER_HOST "master.openttd.org" +/** Message sent to the masterserver to 'identify' this client as OpenTTD */ +#define NETWORK_MASTER_SERVER_WELCOME_MESSAGE "OpenTTDRegister" + +enum { + NETWORK_MASTER_SERVER_PORT = 3978, ///< The default port of the master server (UDP) + NETWORK_DEFAULT_PORT = 3979, ///< The default port of the game server (TCP & UDP) + + SEND_MTU = 1460, ///< Number of bytes we can pack in a single packet + + NETWORK_GAME_INFO_VERSION = 4, ///< What version of game-info do we use? + NETWORK_COMPANY_INFO_VERSION = 4, ///< What version of company info is this? + NETWORK_MASTER_SERVER_VERSION = 1, ///< What version of master-server-protocol do we use? + + NETWORK_NAME_LENGTH = 80, ///< The maximum length of the server name and map name, in bytes including '\0' + NETWORK_HOSTNAME_LENGTH = 80, ///< The maximum length of the host name, in bytes including '\0' + NETWORK_REVISION_LENGTH = 15, ///< The maximum length of the revision, in bytes including '\0' + NETWORK_PASSWORD_LENGTH = 20, ///< The maximum length of the password, in bytes including '\0' + NETWORK_PLAYERS_LENGTH = 200, ///< The maximum length for the list of players that controls a company, in bytes including '\0' + NETWORK_CLIENT_NAME_LENGTH = 25, ///< The maximum length of a player, in bytes including '\0' + NETWORK_RCONCOMMAND_LENGTH = 500, ///< The maximum length of a rconsole command, in bytes including '\0' + + NETWORK_GRF_NAME_LENGTH = 80, ///< Maximum length of the name of a GRF + /** + * Maximum number of GRFs that can be sent. + * This value is related to number of handles (files) OpenTTD can open. + * This is currently 64 and about 10 are currently used when OpenTTD loads + * without any NewGRFs. Therefore one can only load about 55 NewGRFs, so + * this is not a limit, but rather a way to easily check whether the limit + * imposed by the handle count is reached. Secondly it isn't possible to + * send much more GRF IDs + MD5sums in the PACKET_UDP_SERVER_RESPONSE, due + * to the limited size of UDP packets. + */ + NETWORK_MAX_GRF_COUNT = 55, + + NETWORK_NUM_LANGUAGES = 4, ///< Number of known languages (to the network protocol) + 1 for 'any'. +}; + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_CONFIG_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/game.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/game.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,47 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_GAME_H +#define NETWORK_CORE_GAME_H + +#ifdef ENABLE_NETWORK + +/** + * @file game.h Information about a game that is sent between a + * game server, game client and masterserver. + */ + +/** + * This is the struct used by both client and server + * some fields will be empty on the client (like game_password) by default + * and only filled with data a player enters. + */ +typedef struct NetworkGameInfo { + byte game_info_version; ///< Version of the game info + char server_name[NETWORK_NAME_LENGTH]; ///< Server name + char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) + char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) + bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) + bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match + byte server_lang; ///< Language of the server (we should make a nice table for this) + byte use_password; ///< Is set to != 0 if it uses a password + char server_password[NETWORK_PASSWORD_LENGTH]; ///< On the server: the game password, on the client: != "" if server has password + byte clients_max; ///< Max clients allowed on server + byte clients_on; ///< Current count of clients on server + byte companies_max; ///< Max companies allowed on server + byte companies_on; ///< How many started companies do we have + byte spectators_max; ///< Max spectators allowed on server + byte spectators_on; ///< How many spectators do we have? + Date game_date; ///< Current date + Date start_date; ///< When the game started + char map_name[NETWORK_NAME_LENGTH]; ///< Map which is played ["random" for a randomized map] + uint16 map_width; ///< Map width + uint16 map_height; ///< Map height + byte map_set; ///< Graphical set + bool dedicated; ///< Is this a dedicated server? + char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< RCon password for the server. "" if rcon is disabled + struct GRFConfig *grfconfig; ///< List of NewGRF files used +} NetworkGameInfo; + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_GAME_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/os_abstraction.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/os_abstraction.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,181 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_OS_ABSTRACTION_H +#define NETWORK_CORE_OS_ABSTRACTION_H + +/** + * @file os_abstraction.h Network stuff has many things that needs to be + * included and/or implemented by default. + * All those things are in this file. + */ + +/* Include standard stuff per OS */ + +#ifdef ENABLE_NETWORK + +/* Windows stuff */ +#if defined(WIN32) || defined(WIN64) +#include +#include +#include + +#if !(defined(__MINGW32__) || defined(__CYGWIN__)) + /* Windows has some different names for some types */ + typedef SSIZE_T ssize_t; + typedef int socklen_t; +#endif + +#define GET_LAST_ERROR() WSAGetLastError() +#define EWOULDBLOCK WSAEWOULDBLOCK +/* Windows has some different names for some types */ +typedef unsigned long in_addr_t; +#endif /* WIN32 */ + +/* UNIX stuff */ +#if defined(UNIX) +# define SOCKET int +# define INVALID_SOCKET -1 +# if !defined(__MORPHOS__) && !defined(__AMIGA__) +# define ioctlsocket ioctl +# if !defined(BEOS_NET_SERVER) +# define closesocket close +# endif +# define GET_LAST_ERROR() (errno) +# endif +/* Need this for FIONREAD on solaris */ +# define BSD_COMP + +/* Includes needed for UNIX-like systems */ +# include +# include +# if defined(__BEOS__) && defined(BEOS_NET_SERVER) +# include +# include // snooze() +# include + typedef unsigned long in_addr_t; +# define INADDR_NONE INADDR_BROADCAST +# else +# include +# include +# include +# include +# include +/* According to glibc/NEWS, appeared in glibc-2.3. */ +# if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__INNOTEK_LIBC__) \ + && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) +/* If for any reason ifaddrs.h does not exist on your system, comment out + * the following two lines and an alternative way will be used to fetch + * the list of IPs from the system. */ +# include +# define HAVE_GETIFADDRS +# endif +# if defined(SUNOS) || defined(__MORPHOS__) || defined(__BEOS__) +# define INADDR_NONE 0xffffffff +# endif +# if defined(__BEOS__) && !defined(BEOS_NET_SERVER) + /* needed on Zeta */ +# include +# endif +# endif /* BEOS_NET_SERVER */ + +# if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) + typedef uint32_t in_addr_t; +# endif + +# include +# include +# include +#endif // UNIX + +#ifdef __BEOS__ + typedef int socklen_t; +#endif + +/* OS/2 stuff */ +#if defined(__OS2__) +# define SOCKET int +# define INVALID_SOCKET -1 +# define ioctlsocket ioctl +# define closesocket close +# define GET_LAST_ERROR() (sock_errno()) + +/* Includes needed for OS/2 systems */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define INADDR_NONE 0xffffffff + +typedef int socklen_t; +#if !defined(__INNOTEK_LIBC__) +typedef unsigned long in_addr_t; +#endif /* __INNOTEK_LIBC__ */ +#endif /* OS/2 */ + +/* MorphOS and Amiga stuff */ +#if defined(__MORPHOS__) || defined(__AMIGA__) +# include +# include // required for Open/CloseLibrary() +# if defined(__MORPHOS__) +# include // FIO* defines +# include // SIO* defines +# include +# else /* __AMIGA__ */ +# include +# endif + +/* Make the names compatible */ +# define closesocket(s) CloseSocket(s) +# define GET_LAST_ERROR() Errno() +# define ioctlsocket(s,request,status) IoctlSocket((LONG)s,(ULONG)request,(char*)status) +# define ioctl ioctlsocket + + typedef unsigned int in_addr_t; + typedef long socklen_t; + extern struct Library *SocketBase; + +# ifdef __AMIGA__ + /* for usleep() implementation */ + extern struct Device *TimerBase; + extern struct MsgPort *TimerPort; + extern struct timerequest *TimerRequest; +# endif +#endif // __MORPHOS__ || __AMIGA__ + +static inline bool SetNonBlocking(int d) +{ +#ifdef WIN32 + u_long nonblocking = 1; +#else + int nonblocking = 1; +#endif +#if defined(__BEOS__) && defined(BEOS_NET_SERVER) + return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0; +#else + return ioctlsocket(d, FIONBIO, &nonblocking) == 0; +#endif +} + +static inline bool SetNoDelay(int d) +{ + /* XXX should this be done at all? */ +#if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server + int b = 1; + /* The (const char*) cast is needed for windows */ + return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; +#else + return true; +#endif +} + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_OS_ABSTRACTION_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/packet.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/packet.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,216 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../macros.h" +#include "../../string.h" + +#include "os_abstraction.h" +#include "config.h" +#include "packet.h" + +/** + * @file packet.h Basic functions to create, fill and read packets. + */ + + +/* Do not want to include functions.h and all required headers */ +extern void NORETURN CDECL error(const char *str, ...); + + +/** + * Create a packet for sending + * @param type the of packet + * @return the newly created packet + */ +Packet *NetworkSend_Init(PacketType type) +{ + Packet *packet = malloc(sizeof(Packet)); + /* An error is inplace here, because it simply means we ran out of memory. */ + if (packet == NULL) error("Failed to allocate Packet"); + + /* Skip the size so we can write that in before sending the packet */ + packet->size = sizeof(packet->size); + packet->buffer[packet->size++] = type; + packet->pos = 0; + + return packet; +} + +/** + * Writes the packet size from the raw packet from packet->size + * @param packet the packet to write the size of + */ +void NetworkSend_FillPacketSize(Packet *packet) +{ + packet->buffer[0] = GB(packet->size, 0, 8); + packet->buffer[1] = GB(packet->size, 8, 8); +} + +/** + * The next couple of functions make sure we can send + * uint8, uint16, uint32 and uint64 endian-safe + * over the network. The least significant bytes are + * sent first. + * + * So 0x01234567 would be sent as 67 45 23 01. + */ + +void NetworkSend_uint8(Packet *packet, uint8 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = data; +} + +void NetworkSend_uint16(Packet *packet, uint16 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); +} + +void NetworkSend_uint32(Packet *packet, uint32 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); + packet->buffer[packet->size++] = GB(data, 16, 8); + packet->buffer[packet->size++] = GB(data, 24, 8); +} + +void NetworkSend_uint64(Packet *packet, uint64 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); + packet->buffer[packet->size++] = GB(data, 16, 8); + packet->buffer[packet->size++] = GB(data, 24, 8); + packet->buffer[packet->size++] = GB(data, 32, 8); + packet->buffer[packet->size++] = GB(data, 40, 8); + packet->buffer[packet->size++] = GB(data, 48, 8); + packet->buffer[packet->size++] = GB(data, 56, 8); +} + +/** + * Sends a string over the network. It sends out + * the string + '\0'. No size-byte or something. + */ +void NetworkSend_string(Packet *packet, const char* data) +{ + assert(data != NULL); + assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1); + while ((packet->buffer[packet->size++] = *data++) != '\0') {} +} + + +/** + * Receiving commands + * Again, the next couple of functions are endian-safe + * see the comment before NetworkSend_uint8 for more info. + */ + + +extern uint CloseConnection(NetworkClientState *cs); + +/** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */ +static inline bool CanReadFromPacket(NetworkClientState *cs, Packet *packet, uint bytes_to_read) +{ + /* Don't allow reading from a closed socket */ + if (HasClientQuit(cs)) return false; + + /* Check if variable is within packet-size */ + if (packet->pos + bytes_to_read > packet->size) { + CloseConnection(cs); + return false; + } + + return true; +} + +/** + * Reads the packet size from the raw packet and stores it in the packet->size + * @param packet the packet to read the size of + */ +void NetworkRecv_ReadPacketSize(Packet *packet) +{ + packet->size = (uint16)packet->buffer[0]; + packet->size += (uint16)packet->buffer[1] << 8; +} + +uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet) +{ + uint8 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = packet->buffer[packet->pos++]; + return n; +} + +uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet) +{ + uint16 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint16)packet->buffer[packet->pos++]; + n += (uint16)packet->buffer[packet->pos++] << 8; + return n; +} + +uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet) +{ + uint32 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint32)packet->buffer[packet->pos++]; + n += (uint32)packet->buffer[packet->pos++] << 8; + n += (uint32)packet->buffer[packet->pos++] << 16; + n += (uint32)packet->buffer[packet->pos++] << 24; + return n; +} + +uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet) +{ + uint64 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint64)packet->buffer[packet->pos++]; + n += (uint64)packet->buffer[packet->pos++] << 8; + n += (uint64)packet->buffer[packet->pos++] << 16; + n += (uint64)packet->buffer[packet->pos++] << 24; + n += (uint64)packet->buffer[packet->pos++] << 32; + n += (uint64)packet->buffer[packet->pos++] << 40; + n += (uint64)packet->buffer[packet->pos++] << 48; + n += (uint64)packet->buffer[packet->pos++] << 56; + return n; +} + +/** Reads a string till it finds a '\0' in the stream */ +void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size) +{ + PacketSize pos; + char *bufp = buffer; + + /* Don't allow reading from a closed socket */ + if (HasClientQuit(cs)) return; + + pos = p->pos; + while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {} + + if (size == 0 || pos == p->size) { + *buffer = '\0'; + /* If size was sooner to zero then the string in the stream + * skip till the \0, so than packet can be read out correctly for the rest */ + while (pos < p->size && p->buffer[pos] != '\0') pos++; + pos++; + } + p->pos = pos; + + str_validate(bufp); +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/packet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/packet.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,67 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_PACKET_H +#define NETWORK_CORE_PACKET_H + +#ifdef ENABLE_NETWORK + +/** + * @file packet.h Basic functions to create, fill and read packets. + */ + +typedef struct NetworkClientState NetworkClientState; + +/** + * Queries the network client state struct to determine whether + * the client has quit. It indirectly also queries whether the + * packet is corrupt as the connection will be closed if it is + * reading beyond the boundary of the received packet. + * @param cs the state to query + * @param true if the connection should be considered dropped + */ +bool HasClientQuit(NetworkClientState *cs); + +typedef uint16 PacketSize; ///< Size of the whole packet. +typedef uint8 PacketType; ///< Identifier for the packet + +/** + * Internal entity of a packet. As everything is sent as a packet, + * all network communication will need to call the functions that + * populate the packet. + * Every packet can be at most SEND_MTU bytes. Overflowing this + * limit will give an assertion when sending (i.e. writing) the + * packet. Reading past the size of the packet when receiving + * will return all 0 values and "" in case of the string. + */ +typedef struct Packet { + /** The next packet. Used for queueing packets before sending. */ + struct Packet *next; + /** The size of the whole packet for received packets. For packets + * that will be sent, the value is filled in just before the + * actual transmission. */ + PacketSize size; + /** The current read/write position in the packet */ + PacketSize pos; + /** The buffer of this packet */ + byte buffer[SEND_MTU]; +} Packet; + + +Packet *NetworkSend_Init(PacketType type); +void NetworkSend_FillPacketSize(Packet *packet); +void NetworkSend_uint8 (Packet *packet, uint8 data); +void NetworkSend_uint16(Packet *packet, uint16 data); +void NetworkSend_uint32(Packet *packet, uint32 data); +void NetworkSend_uint64(Packet *packet, uint64 data); +void NetworkSend_string(Packet *packet, const char* data); + +void NetworkRecv_ReadPacketSize(Packet *packet); +uint8 NetworkRecv_uint8 (NetworkClientState *cs, Packet *packet); +uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet); +uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet); +uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet); +void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_PACKET_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/tcp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/tcp.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,227 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../debug.h" +#include "../../openttd.h" +#include "../../variables.h" +#include "../../table/strings.h" +#include "../../functions.h" + +#include "os_abstraction.h" +#include "config.h" +#include "packet.h" +#include "../network_data.h" +#include "tcp.h" + +/** + * @file tcp.c Basic functions to receive and send TCP packets. + */ + +/** + * Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit + * A socket can make errors. When that happens this handles what to do. + * For clients: close connection and drop back to main-menu + * For servers: close connection and that is it + * @param cs the client to close the connection of + * @return the new status + */ +NetworkRecvStatus CloseConnection(NetworkClientState *cs) +{ + NetworkCloseClient(cs); + + /* Clients drop back to the main menu */ + if (!_network_server && _networking) { + _switch_mode = SM_MENU; + _networking = false; + _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; + + return NETWORK_RECV_STATUS_CONN_LOST; + } + + return NETWORK_RECV_STATUS_OKAY; +} + +/** + * Whether the client has quit or not (used in packet.c) + * @param cs the client to check + * @return true if the client has quit + */ +bool HasClientQuit(NetworkClientState *cs) +{ + return cs->has_quit; +} + +/** + * This function puts the packet in the send-queue and it is send as + * soon as possible. This is the next tick, or maybe one tick later + * if the OS-network-buffer is full) + * @param packet the packet to send + * @param cs the client to send to + */ +void NetworkSend_Packet(Packet *packet, NetworkClientState *cs) +{ + Packet *p; + assert(packet != NULL); + + packet->pos = 0; + packet->next = NULL; + + NetworkSend_FillPacketSize(packet); + + /* Locate last packet buffered for the client */ + p = cs->packet_queue; + if (p == NULL) { + /* No packets yet */ + cs->packet_queue = packet; + } else { + /* Skip to the last packet */ + while (p->next != NULL) p = p->next; + p->next = packet; + } +} + +/** + * Sends all the buffered packets out for this client. It stops when: + * 1) all packets are send (queue is empty) + * 2) the OS reports back that it can not send any more + * data right now (full network-buffer, it happens ;)) + * 3) sending took too long + * @param cs the client to send the packets for + */ +bool NetworkSend_Packets(NetworkClientState *cs) +{ + ssize_t res; + Packet *p; + + /* We can not write to this socket!! */ + if (!cs->writable) return false; + if (cs->socket == INVALID_SOCKET) return false; + + p = cs->packet_queue; + while (p != NULL) { + res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong.. close client! */ + DEBUG(net, 0, "send failed with error %d", err); + CloseConnection(cs); + return false; + } + return true; + } + if (res == 0) { + /* Client/server has left us :( */ + CloseConnection(cs); + return false; + } + + p->pos += res; + + /* Is this packet sent? */ + if (p->pos == p->size) { + /* Go to the next packet */ + cs->packet_queue = p->next; + free(p); + p = cs->packet_queue; + } else { + return true; + } + } + + return true; +} + +/** + * Receives a packet for the given client + * @param cs the client to (try to) receive a packet for + * @param status the variable to store the status into + * @return the received packet (or NULL when it didn't receive one) + */ +Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status) +{ + ssize_t res; + Packet *p; + + *status = NETWORK_RECV_STATUS_OKAY; + + if (cs->socket == INVALID_SOCKET) return NULL; + + if (cs->packet_recv == NULL) { + cs->packet_recv = malloc(sizeof(Packet)); + if (cs->packet_recv == NULL) error("Failed to allocate packet"); + /* Set pos to zero! */ + cs->packet_recv->pos = 0; + cs->packet_recv->size = 0; // Can be ommited, just for safety reasons + } + + p = cs->packet_recv; + + /* Read packet size */ + if (p->pos < sizeof(PacketSize)) { + while (p->pos < sizeof(PacketSize)) { + /* Read the size of the packet */ + res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong... (104 is connection reset by peer) */ + if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + *status = CloseConnection(cs); + return NULL; + } + /* Connection would block, so stop for now */ + return NULL; + } + if (res == 0) { + /* Client/server has left */ + *status = CloseConnection(cs); + return NULL; + } + p->pos += res; + } + + NetworkRecv_ReadPacketSize(p); + + if (p->size > SEND_MTU) { + *status = CloseConnection(cs); + return NULL; + } + } + + /* Read rest of packet */ + while (p->pos < p->size) { + res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong... (104 is connection reset by peer) */ + if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + *status = CloseConnection(cs); + return NULL; + } + /* Connection would block */ + return NULL; + } + if (res == 0) { + /* Client/server has left */ + *status = CloseConnection(cs); + return NULL; + } + + p->pos += res; + } + + /* We have a complete packet, return it! */ + p->pos = 2; + p->next = NULL; // Should not be needed, but who knows... + + /* Prepare for receiving a new packet */ + cs->packet_recv = NULL; + + return p; +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/tcp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/tcp.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,60 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_TCP_H +#define NETWORK_CORE_TCP_H + +#ifdef ENABLE_NETWORK + +/** + * @file tcp.h Basic functions to receive and send TCP packets. + */ + +/** + * Enum with all types of UDP packets. + * The order of the first 4 packets MUST not be changed, as + * it protects old clients from joining newer servers + * (because SERVER_ERROR is the respond to a wrong revision) + */ +enum { + PACKET_SERVER_FULL, + PACKET_SERVER_BANNED, + PACKET_CLIENT_JOIN, + PACKET_SERVER_ERROR, + PACKET_CLIENT_COMPANY_INFO, + PACKET_SERVER_COMPANY_INFO, + PACKET_SERVER_CLIENT_INFO, + PACKET_SERVER_NEED_PASSWORD, + PACKET_CLIENT_PASSWORD, + PACKET_SERVER_WELCOME, + PACKET_CLIENT_GETMAP, + PACKET_SERVER_WAIT, + PACKET_SERVER_MAP, + PACKET_CLIENT_MAP_OK, + PACKET_SERVER_JOIN, + PACKET_SERVER_FRAME, + PACKET_SERVER_SYNC, + PACKET_CLIENT_ACK, + PACKET_CLIENT_COMMAND, + PACKET_SERVER_COMMAND, + PACKET_CLIENT_CHAT, + PACKET_SERVER_CHAT, + PACKET_CLIENT_SET_PASSWORD, + PACKET_CLIENT_SET_NAME, + PACKET_CLIENT_QUIT, + PACKET_CLIENT_ERROR, + PACKET_SERVER_QUIT, + PACKET_SERVER_ERROR_QUIT, + PACKET_SERVER_SHUTDOWN, + PACKET_SERVER_NEWGAME, + PACKET_SERVER_RCON, + PACKET_CLIENT_RCON, + PACKET_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +void NetworkSend_Packet(Packet *packet, NetworkClientState *cs); +Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); +bool NetworkSend_Packets(NetworkClientState *cs); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_TCP_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/udp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/udp.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,277 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../date.h" +#include "../../debug.h" +#include "../../macros.h" +#include "../../newgrf_config.h" + +#include "os_abstraction.h" +#include "config.h" +#include "game.h" +#include "packet.h" +#include "udp.h" + +/** + * @file udp.c Basic functions to receive and send UDP packets. + */ + +/** + * Send a packet over UDP + * @param udp the socket to send over + * @param p the packet to send + * @param recv the receiver (target) of the packet + */ +void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv) +{ + int res; + + NetworkSend_FillPacketSize(p); + + /* Send the buffer */ + res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv)); + + /* Check for any errors, but ignore it otherwise */ + if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR()); +} + +/** + * Start listening on the given host and port. + * @param udp the place where the (references to the) UDP are stored + * @param host the host (ip) to listen on + * @param port the port to listen on + * @param broadcast whether to allow broadcast sending/receiving + * @return true if the listening succeeded + */ +bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast) +{ + struct sockaddr_in sin; + + /* Make sure socket is closed */ + closesocket(*udp); + + *udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (*udp == INVALID_SOCKET) { + DEBUG(net, 0, "[udp] failed to start UDP listener"); + return false; + } + + /* set nonblocking mode for socket */ + { + unsigned long blocking = 1; +#ifndef BEOS_NET_SERVER + ioctlsocket(*udp, FIONBIO, &blocking); +#else + setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL); +#endif + } + + sin.sin_family = AF_INET; + /* Listen on all IPs */ + sin.sin_addr.s_addr = host; + sin.sin_port = htons(port); + + if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) { + DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port); + return false; + } + + if (broadcast) { + /* Enable broadcast */ + unsigned long val = 1; +#ifndef BEOS_NET_SERVER // will work around this, some day; maybe. + setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); +#endif + } + + DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port); + + return true; +} + +/** + * Receive a packet at UDP level + * @param udp the socket to receive the packet on + */ +void NetworkUDPReceive(SOCKET udp) +{ + struct sockaddr_in client_addr; + socklen_t client_len; + int nbytes; + Packet p; + int packet_len; + + packet_len = sizeof(p.buffer); + client_len = sizeof(client_addr); + + /* Try to receive anything */ + nbytes = recvfrom(udp, p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); + + /* We got some bytes for the base header of the packet. + * Assume we received the whole packet. */ + if (nbytes > 2) { + NetworkRecv_ReadPacketSize(&p); + + /* Put the position on the right place */ + p.pos = 2; + p.next = NULL; + + /* Handle the packet */ + NetworkHandleUDPPacket(&p, &client_addr); + } +} + + +/** + * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet + * @param p the packet to write the data to + * @param c the configuration to write the GRF ID and MD5 checksum from + */ +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) +{ + uint j; + NetworkSend_uint32(p, c->grfid); + for (j = 0; j < sizeof(c->md5sum); j++) { + NetworkSend_uint8 (p, c->md5sum[j]); + } +} + +/** + * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet + * @param cs the client state (for closing connect on out-of-bounds reading etc) + * @param p the packet to read the data from + * @param c the configuration to write the GRF ID and MD5 checksum to + */ +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c) +{ + uint j; + c->grfid = NetworkRecv_uint32(cs, p); + for (j = 0; j < sizeof(c->md5sum); j++) { + c->md5sum[j] = NetworkRecv_uint8(cs, p); + } +} + + +/** + * Serializes the NetworkGameInfo struct to the packet + * @param p the packet to write the data to + * @param info the NetworkGameInfo struct to serialize + */ +void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info) +{ + NetworkSend_uint8 (p, NETWORK_GAME_INFO_VERSION); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + + /* NETWORK_GAME_INFO_VERSION = 4 */ + { + /* Only send the GRF Identification (GRF_ID and MD5 checksum) of + * the GRFs that are needed, i.e. the ones that the server has + * selected in the NewGRF GUI and not the ones that are used due + * to the fact that they are in [newgrf-static] in openttd.cfg */ + const GRFConfig *c; + uint count = 0; + + /* Count number of GRFs to send information about */ + for (c = info->grfconfig; c != NULL; c = c->next) { + if (!HASBIT(c->flags, GCF_STATIC)) count++; + } + NetworkSend_uint8 (p, count); // Send number of GRFs + + /* Send actual GRF Identifications */ + for (c = info->grfconfig; c != NULL; c = c->next) { + if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(p, c); + } + } + + /* NETWORK_GAME_INFO_VERSION = 3 */ + NetworkSend_uint32(p, info->game_date); + NetworkSend_uint32(p, info->start_date); + + /* NETWORK_GAME_INFO_VERSION = 2 */ + NetworkSend_uint8 (p, info->companies_max); + NetworkSend_uint8 (p, info->companies_on); + NetworkSend_uint8 (p, info->spectators_max); + + /* NETWORK_GAME_INFO_VERSION = 1 */ + NetworkSend_string(p, info->server_name); + NetworkSend_string(p, info->server_revision); + NetworkSend_uint8 (p, info->server_lang); + NetworkSend_uint8 (p, info->use_password); + NetworkSend_uint8 (p, info->clients_max); + NetworkSend_uint8 (p, info->clients_on); + NetworkSend_uint8 (p, info->spectators_on); + NetworkSend_string(p, info->map_name); + NetworkSend_uint16(p, info->map_width); + NetworkSend_uint16(p, info->map_height); + NetworkSend_uint8 (p, info->map_set); + NetworkSend_uint8 (p, info->dedicated); +} + +/** + * Deserializes the NetworkGameInfo struct from the packet + * @param cs the client state (for closing connect on out-of-bounds reading etc) + * @param p the packet to read the data from + * @param info the NetworkGameInfo to deserialize into + */ +void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info) +{ + info->game_info_version = NetworkRecv_uint8(cs, p); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + switch (info->game_info_version) { + case 4: { + GRFConfig *c, **dst = &info->grfconfig; + uint i; + uint num_grfs = NetworkRecv_uint8(cs, p); + + for (i = 0; i < num_grfs; i++) { + c = calloc(1, sizeof(*c)); + NetworkRecv_GRFIdentifier(cs, p, c); + HandleIncomingNetworkGameInfoGRFConfig(c); + + /* Append GRFConfig to the list */ + *dst = c; + dst = &c->next; + } + } /* Fallthrough */ + case 3: + info->game_date = NetworkRecv_uint32(cs, p); + info->start_date = NetworkRecv_uint32(cs, p); + /* Fallthrough */ + case 2: + info->companies_max = NetworkRecv_uint8 (cs, p); + info->companies_on = NetworkRecv_uint8 (cs, p); + info->spectators_max = NetworkRecv_uint8 (cs, p); + /* Fallthrough */ + case 1: + NetworkRecv_string(cs, p, info->server_name, sizeof(info->server_name)); + NetworkRecv_string(cs, p, info->server_revision, sizeof(info->server_revision)); + info->server_lang = NetworkRecv_uint8 (cs, p); + info->use_password = NetworkRecv_uint8 (cs, p); + info->clients_max = NetworkRecv_uint8 (cs, p); + info->clients_on = NetworkRecv_uint8 (cs, p); + info->spectators_on = NetworkRecv_uint8 (cs, p); + if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier + info->game_date = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; + info->start_date = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; + } + NetworkRecv_string(cs, p, info->map_name, sizeof(info->map_name)); + info->map_width = NetworkRecv_uint16(cs, p); + info->map_height = NetworkRecv_uint16(cs, p); + info->map_set = NetworkRecv_uint8 (cs, p); + info->dedicated = NetworkRecv_uint8 (cs, p); + } +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/core/udp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/core/udp.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,62 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_UDP_H +#define NETWORK_CORE_UDP_H + +#ifdef ENABLE_NETWORK + +/** + * @file udp.h Basic functions to receive and send UDP packets. + */ + +///** Sending/receiving of UDP packets **//// + +void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv); +bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast); +void NetworkUDPReceive(SOCKET udp); + +/** + * Function that is called for every received UDP packet. + * @param packet the received packet + * @param client_addr the address of the sender of the packet + */ +void NetworkHandleUDPPacket(Packet *p, struct sockaddr_in *client_addr); + + +///** Sending/receiving of (large) chuncks of UDP packets **//// + + +/** Enum with all types of UDP packets. The order MUST not be changed **/ +enum { + PACKET_UDP_CLIENT_FIND_SERVER, ///< Queries a game server for game information + PACKET_UDP_SERVER_RESPONSE, ///< Reply of the game server with game information + PACKET_UDP_CLIENT_DETAIL_INFO, ///< Queries a game server about details of the game, such as companies + PACKET_UDP_SERVER_DETAIL_INFO, ///< Reply of the game server about details of the game, such as companies + PACKET_UDP_SERVER_REGISTER, ///< Packet to register itself to the master server + PACKET_UDP_MASTER_ACK_REGISTER, ///< Packet indicating registration has succedeed + PACKET_UDP_CLIENT_GET_LIST, ///< Request for serverlist from master server + PACKET_UDP_MASTER_RESPONSE_LIST, ///< Response from master server with server ip's + port's + PACKET_UDP_SERVER_UNREGISTER, ///< Request to be removed from the server-list + PACKET_UDP_CLIENT_GET_NEWGRFS, ///< Requests the name for a list of GRFs (GRF_ID and MD5) + PACKET_UDP_SERVER_NEWGRFS, ///< Sends the list of NewGRF's requested. + PACKET_UDP_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c); +void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info); + +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c); +void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info); + +/** + * Function that is called for every GRFConfig that is read when receiving + * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This + * function must set all appropriate fields. This GRF is later appended to + * the grfconfig list of the NetworkGameInfo. + * @param config the GRF to handle + */ +void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_UDP_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,1451 @@ +/* $Id$ */ + +#include "../stdafx.h" +#include "network_data.h" + +#if defined(WITH_REV) + extern const char _openttd_revision[]; +#elif defined(WITH_REV_HACK) + #define WITH_REV + const char _openttd_revision[] = WITH_REV_HACK; +#else + const char _openttd_revision[] = NOREV_STRING; +#endif + + +#ifdef ENABLE_NETWORK + +#include "../openttd.h" +#include "../debug.h" +#include "../functions.h" +#include "../string.h" +#include "../strings.h" +#include "../map.h" +#include "../command.h" +#include "../variables.h" +#include "../date.h" +#include "../newgrf_config.h" +#include "../table/strings.h" +#include "network_client.h" +#include "network_server.h" +#include "network_udp.h" +#include "network_gamelist.h" +#include "core/udp.h" +#include "core/tcp.h" +#include "network_gui.h" +#include "../console.h" /* IConsoleCmdExec */ +#include /* va_list */ +#include "../md5.h" + +#ifdef __MORPHOS__ +// the library base is required here +struct Library *SocketBase = NULL; +#endif + +// The listen socket for the server +static SOCKET _listensocket; + +// The amount of clients connected +static byte _network_clients_connected = 0; +// The index counter for new clients (is never decreased) +static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1; + +/* Some externs / forwards */ +extern void StateGameLoop(void); + +// Function that looks up the CI for a given client-index +NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index) +{ + NetworkClientInfo *ci; + + for (ci = _network_client_info; ci != endof(_network_client_info); ci++) { + if (ci->client_index == client_index) return ci; + } + + return NULL; +} + +/** Return the CI for a given IP + * @param ip IP of the client we are looking for. This must be in string-format + * @return return a pointer to the corresponding NetworkClientInfo struct or NULL on failure */ +NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip) +{ + NetworkClientInfo *ci; + uint32 ip_number = inet_addr(ip); + + for (ci = _network_client_info; ci != endof(_network_client_info); ci++) { + if (ci->client_ip == ip_number) return ci; + } + + return NULL; +} + +// Function that looks up the CS for a given client-index +NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index) +{ + NetworkClientState *cs; + + for (cs = _clients; cs != &_clients[MAX_CLIENT_INFO]; cs++) { + if (cs->index == client_index) return cs; + } + + return NULL; +} + +// NetworkGetClientName is a server-safe function to get the name of the client +// if the user did not send it yet, Client # is used. +void NetworkGetClientName(char *client_name, size_t size, const NetworkClientState *cs) +{ + const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); + + if (ci->client_name[0] == '\0') { + snprintf(client_name, size, "Client #%4d", cs->index); + } else { + ttd_strlcpy(client_name, ci->client_name, size); + } +} + +byte NetworkSpectatorCount(void) +{ + const NetworkClientState *cs; + byte count = 0; + + FOR_ALL_CLIENTS(cs) { + if (DEREF_CLIENT_INFO(cs)->client_playas == PLAYER_SPECTATOR) count++; + } + + return count; +} + +// This puts a text-message to the console, or in the future, the chat-box, +// (to keep it all a bit more general) +// If 'self_send' is true, this is the client who is sending the message +void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...) +{ + char buf[1024]; + va_list va; + const int duration = 10; // Game days the messages stay visible + char message[1024]; + char temp[1024]; + + va_start(va, str); + vsnprintf(buf, lengthof(buf), str, va); + va_end(va); + + switch (action) { + case NETWORK_ACTION_SERVER_MESSAGE: + color = 1; + snprintf(message, sizeof(message), "*** %s", buf); + break; + case NETWORK_ACTION_JOIN: + color = 1; + GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp)); + snprintf(message, sizeof(message), "*** %s %s", name, temp); + break; + case NETWORK_ACTION_LEAVE: + color = 1; + GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp)); + snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf); + break; + case NETWORK_ACTION_GIVE_MONEY: + if (self_send) { + SetDParamStr(0, name); + SetDParam(1, atoi(buf)); + GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp)); + snprintf(message, sizeof(message), "*** %s", temp); + } else { + SetDParam(0, atoi(buf)); + GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp)); + snprintf(message, sizeof(message), "*** %s %s", name, temp); + } + break; + case NETWORK_ACTION_NAME_CHANGE: + GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp)); + snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf); + break; + case NETWORK_ACTION_CHAT_COMPANY: + SetDParamStr(0, name); + SetDParamStr(1, buf); + GetString(temp, self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY, lastof(temp)); + ttd_strlcpy(message, temp, sizeof(message)); + break; + case NETWORK_ACTION_CHAT_CLIENT: + SetDParamStr(0, name); + SetDParamStr(1, buf); + GetString(temp, self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT, lastof(temp)); + ttd_strlcpy(message, temp, sizeof(message)); + break; + default: + SetDParamStr(0, name); + SetDParamStr(1, buf); + GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp)); + ttd_strlcpy(message, temp, sizeof(message)); + break; + } + + IConsolePrintF(color, "%s", message); + AddTextMessage(color, duration, "%s", message); +} + +// Calculate the frame-lag of a client +uint NetworkCalculateLag(const NetworkClientState *cs) +{ + int lag = cs->last_frame_server - cs->last_frame; + // This client has missed his ACK packet after 1 DAY_TICKS.. + // so we increase his lag for every frame that passes! + // The packet can be out by a max of _net_frame_freq + if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter) + lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq); + + return lag; +} + + +// There was a non-recoverable error, drop back to the main menu with a nice +// error +static void NetworkError(StringID error_string) +{ + _switch_mode = SM_MENU; + _switch_mode_errorstr = error_string; +} + +static void ClientStartError(const char *error) +{ + DEBUG(net, 0, "[client] could not start network: %s",error); + NetworkError(STR_NETWORK_ERR_CLIENT_START); +} + +static void ServerStartError(const char *error) +{ + DEBUG(net, 0, "[server] could not start network: %s",error); + NetworkError(STR_NETWORK_ERR_SERVER_START); +} + +static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs) +{ + // First, send a CLIENT_ERROR to the server, so he knows we are + // disconnection (and why!) + NetworkErrorCode errorno; + + // We just want to close the connection.. + if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { + cs->has_quit = true; + NetworkCloseClient(cs); + _networking = false; + + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + return; + } + + switch (res) { + case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; + case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; + default: errorno = NETWORK_ERROR_GENERAL; break; + } + // This means we fucked up and the server closed the connection + if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && + res != NETWORK_RECV_STATUS_SERVER_BANNED) { + SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno); + + // Dequeue all commands before closing the socket + NetworkSend_Packets(DEREF_CLIENT(0)); + } + + _switch_mode = SM_MENU; + NetworkCloseClient(cs); + _networking = false; +} + +/** Retrieve a string representation of an internal error number + * @param buf buffer where the error message will be stored + * @param err NetworkErrorCode + * @return returns a pointer to the error message (buf) */ +char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last) +{ + /* List of possible network errors, used by + * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */ + static const StringID network_error_strings[] = { + STR_NETWORK_ERR_CLIENT_GENERAL, + STR_NETWORK_ERR_CLIENT_DESYNC, + STR_NETWORK_ERR_CLIENT_SAVEGAME, + STR_NETWORK_ERR_CLIENT_CONNECTION_LOST, + STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR, + STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED, + STR_NETWORK_ERR_CLIENT_NOT_EXPECTED, + STR_NETWORK_ERR_CLIENT_WRONG_REVISION, + STR_NETWORK_ERR_CLIENT_NAME_IN_USE, + STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD, + STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH, + STR_NETWORK_ERR_CLIENT_KICKED, + STR_NETWORK_ERR_CLIENT_CHEATER, + STR_NETWORK_ERR_CLIENT_SERVER_FULL + }; + + if (err >= lengthof(network_error_strings)) err = 0; + + return GetString(buf, network_error_strings[err], last); +} + +/* Count the number of active clients connected */ +static uint NetworkCountPlayers(void) +{ + const NetworkClientState *cs; + uint count = 0; + + FOR_ALL_CLIENTS(cs) { + const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); + if (IsValidPlayer(ci->client_playas)) count++; + } + + return count; +} + +static bool _min_players_paused = false; + +/* Check if the minimum number of players has been reached and pause or unpause the game as appropriate */ +void CheckMinPlayers(void) +{ + if (!_network_dedicated) return; + + if (NetworkCountPlayers() < _network_min_players) { + if (_min_players_paused) return; + + _min_players_paused = true; + DoCommandP(0, 1, 0, NULL, CMD_PAUSE); + NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX); + } else { + if (!_min_players_paused) return; + + _min_players_paused = false; + DoCommandP(0, 0, 0, NULL, CMD_PAUSE); + NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX); + } +} + +// Find all IP-aliases for this host +static void NetworkFindIPs(void) +{ + int i; + +#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */ + /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ + int _netstat(int fd, char **output, int verbose); + + int seek_past_header(char **pos, const char *header) { + char *new_pos = strstr(*pos, header); + if (new_pos == 0) { + return B_ERROR; + } + *pos += strlen(header) + new_pos - *pos + 1; + return B_OK; + } + + int output_length; + char *output_pointer = NULL; + char **output; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + i = 0; + + // If something fails, make sure the list is empty + _broadcast_list[0] = 0; + + if (sock < 0) { + DEBUG(net, 0, "[core] error creating socket"); + return; + } + + output_length = _netstat(sock, &output_pointer, 1); + if (output_length < 0) { + DEBUG(net, 0, "[core] error running _netstat"); + return; + } + + output = &output_pointer; + if (seek_past_header(output, "IP Interfaces:") == B_OK) { + for (;;) { + uint32 n, fields, read; + uint8 i1, i2, i3, i4, j1, j2, j3, j4; + struct in_addr inaddr; + uint32 ip; + uint32 netmask; + + fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n", + &n, &i1,&i2,&i3,&i4, &j1,&j2,&j3,&j4, &read); + read += 1; + if (fields != 9) { + break; + } + + ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4; + netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4; + + if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) { + inaddr.s_addr = htonl(ip | ~netmask); + _broadcast_list[i] = inaddr.s_addr; + i++; + } + if (read < 0) { + break; + } + *output += read; + } + /* XXX - Using either one of these crashes openttd heavily? - wber */ + /*free(output_pointer);*/ + /*free(output);*/ + closesocket(sock); + } +#elif defined(HAVE_GETIFADDRS) + struct ifaddrs *ifap, *ifa; + + // If something fails, make sure the list is empty + _broadcast_list[0] = 0; + + if (getifaddrs(&ifap) != 0) + return; + + i = 0; + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; + if (ifa->ifa_broadaddr == NULL) continue; + if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; + _broadcast_list[i] = ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr; + i++; + } + freeifaddrs(ifap); + +#else /* not HAVE_GETIFADDRS */ + SOCKET sock; +#ifdef WIN32 + DWORD len = 0; + INTERFACE_INFO ifo[MAX_INTERFACES]; + uint j; +#else + char buf[4 * 1024]; // Arbitrary buffer size + struct ifconf ifconf; + const char* buf_end; + const char* p; +#endif + + // If something fails, make sure the list is empty + _broadcast_list[0] = 0; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) return; + +#ifdef WIN32 + memset(&ifo[0], 0, sizeof(ifo)); + if ((WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, &ifo[0], sizeof(ifo), &len, NULL, NULL)) != 0) { + closesocket(sock); + return; + } + + i = 0; + for (j = 0; j < len / sizeof(*ifo); j++) { + if (ifo[j].iiFlags & IFF_LOOPBACK) continue; + if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue; + /* iiBroadcast is unusable, because it always seems to be set to + * 255.255.255.255. + */ + _broadcast_list[i++] = + ifo[j].iiAddress.AddressIn.sin_addr.s_addr | + ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; + } +#else + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) { + closesocket(sock); + return; + } + + i = 0; + buf_end = buf + ifconf.ifc_len; + for (p = buf; p < buf_end;) { + const struct ifreq* req = (const struct ifreq*)p; + + if (req->ifr_addr.sa_family == AF_INET) { + struct ifreq r; + + strncpy(r.ifr_name, req->ifr_name, lengthof(r.ifr_name)); + if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && + r.ifr_flags & IFF_BROADCAST && + ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { + _broadcast_list[i++] = + ((struct sockaddr_in*)&r.ifr_broadaddr)->sin_addr.s_addr; + } + } + + p += sizeof(struct ifreq); +#ifdef AF_LINK + p += req->ifr_addr.sa_len - sizeof(struct sockaddr); +#endif + } +#endif + + closesocket(sock); +#endif /* not HAVE_GETIFADDRS */ + + _broadcast_list[i] = 0; + + DEBUG(net, 3, "Detected broadcast addresses:"); + // Now display to the debug all the detected ips + for (i = 0; _broadcast_list[i] != 0; i++) { + DEBUG(net, 3, "%d) %s", i, inet_ntoa(*(struct in_addr *)&_broadcast_list[i]));//inet_ntoa(inaddr)); + } +} + +// Resolve a hostname to a inet_addr +unsigned long NetworkResolveHost(const char *hostname) +{ + in_addr_t ip; + + // First try: is it an ip address? + ip = inet_addr(hostname); + + // If not try to resolve the name + if (ip == INADDR_NONE) { + struct hostent *he = gethostbyname(hostname); + if (he == NULL) { + DEBUG(net, 0, "Cannot resolve '%s'", hostname); + } else { + struct in_addr addr = *(struct in_addr *)he->h_addr_list[0]; + DEBUG(net, 1, "Resolved '%s' to %s", hostname, inet_ntoa(addr)); + ip = addr.s_addr; + } + } + return ip; +} + +// Converts a string to ip/port/player +// Format: IP#player:port +// +// connection_string will be re-terminated to seperate out the hostname, and player and port will +// be set to the player and port strings given by the user, inside the memory area originally +// occupied by connection_string. +void ParseConnectionString(const char **player, const char **port, char *connection_string) +{ + char *p; + for (p = connection_string; *p != '\0'; p++) { + if (*p == '#') { + *p = '\0'; + *player = ++p; + while (IsValidChar(*p, CS_NUMERAL)) p++; + if (*p == '\0') break; + } else if (*p == ':') { + *port = p + 1; + *p = '\0'; + } + } +} + +// Creates a new client from a socket +// Used both by the server and the client +static NetworkClientState *NetworkAllocClient(SOCKET s) +{ + NetworkClientState *cs; + byte client_no = 0; + + if (_network_server) { + // Can we handle a new client? + if (_network_clients_connected >= MAX_CLIENTS) return NULL; + if (_network_game_info.clients_on >= _network_game_info.clients_max) return NULL; + + // Register the login + client_no = _network_clients_connected++; + } + + cs = DEREF_CLIENT(client_no); + memset(cs, 0, sizeof(*cs)); + cs->socket = s; + cs->last_frame = 0; + cs->has_quit = false; + + cs->last_frame = _frame_counter; + cs->last_frame_server = _frame_counter; + + if (_network_server) { + NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); + memset(ci, 0, sizeof(*ci)); + + cs->index = _network_client_index++; + ci->client_index = cs->index; + ci->client_playas = PLAYER_INACTIVE_CLIENT; + ci->join_date = _date; + + InvalidateWindow(WC_CLIENT_LIST, 0); + } + + return cs; +} + +// Close a connection +void NetworkCloseClient(NetworkClientState *cs) +{ + NetworkClientInfo *ci; + // Socket is already dead + if (cs->socket == INVALID_SOCKET) { + cs->has_quit = true; + return; + } + + DEBUG(net, 1, "Closed client connection %d", cs->index); + + if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) { + // We did not receive a leave message from this client... + NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST; + char str[100]; + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + NetworkClientState *new_cs; + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + GetNetworkErrorMsg(str, errorno, lastof(str)); + + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); + + // Inform other clients of this... strange leaving ;) + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status > STATUS_AUTH && cs != new_cs) { + SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno); + } + } + } + + /* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */ + if (cs->status == STATUS_PRE_ACTIVE && _network_pause_on_join) { + DoCommandP(0, 0, 0, NULL, CMD_PAUSE); + NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX); + } + + closesocket(cs->socket); + cs->writable = false; + cs->has_quit = true; + + // Free all pending and partially received packets + while (cs->packet_queue != NULL) { + Packet *p = cs->packet_queue->next; + free(cs->packet_queue); + cs->packet_queue = p; + } + free(cs->packet_recv); + cs->packet_recv = NULL; + + while (cs->command_queue != NULL) { + CommandPacket *p = cs->command_queue->next; + free(cs->command_queue); + cs->command_queue = p; + } + + // Close the gap in the client-list + ci = DEREF_CLIENT_INFO(cs); + + if (_network_server) { + // We just lost one client :( + if (cs->status > STATUS_INACTIVE) _network_game_info.clients_on--; + _network_clients_connected--; + + while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) { + *cs = *(cs + 1); + *ci = *(ci + 1); + cs++; + ci++; + } + + InvalidateWindow(WC_CLIENT_LIST, 0); + } + + // Reset the status of the last socket + cs->socket = INVALID_SOCKET; + cs->status = STATUS_INACTIVE; + cs->index = NETWORK_EMPTY_INDEX; + ci->client_index = NETWORK_EMPTY_INDEX; + + CheckMinPlayers(); +} + +// A client wants to connect to a server +static bool NetworkConnect(const char *hostname, int port) +{ + SOCKET s; + struct sockaddr_in sin; + + DEBUG(net, 1, "Connecting to %s %d", hostname, port); + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + ClientStartError("socket() failed"); + return false; + } + + if (!SetNoDelay(s)) DEBUG(net, 1, "Setting TCP_NODELAY failed"); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = NetworkResolveHost(hostname); + sin.sin_port = htons(port); + _network_last_host_ip = sin.sin_addr.s_addr; + + /* We failed to connect for which reason what so ever */ + if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) return false; + + if (!SetNonBlocking(s)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error? + + // in client mode, only the first client field is used. it's pointing to the server. + NetworkAllocClient(s); + + _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; + ShowJoinStatusWindow(); + + return true; +} + +// For the server, to accept new clients +static void NetworkAcceptClients(void) +{ + struct sockaddr_in sin; + NetworkClientState *cs; + uint i; + bool banned; + + // Should never ever happen.. is it possible?? + assert(_listensocket != INVALID_SOCKET); + + for (;;) { + socklen_t sin_len = sizeof(sin); + SOCKET s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len); + if (s == INVALID_SOCKET) return; + + SetNonBlocking(s); // XXX error handling? + + DEBUG(net, 1, "Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter); + + SetNoDelay(s); // XXX error handling? + + /* Check if the client is banned */ + banned = false; + for (i = 0; i < lengthof(_network_ban_list); i++) { + if (_network_ban_list[i] == NULL) continue; + + if (sin.sin_addr.s_addr == inet_addr(_network_ban_list[i])) { + Packet *p = NetworkSend_Init(PACKET_SERVER_BANNED); + + DEBUG(net, 1, "Banned ip tried to join (%s), refused", _network_ban_list[i]); + + p->buffer[0] = p->size & 0xFF; + p->buffer[1] = p->size >> 8; + + send(s, p->buffer, p->size, 0); + closesocket(s); + + free(p); + + banned = true; + break; + } + } + /* If this client is banned, continue with next client */ + if (banned) continue; + + cs = NetworkAllocClient(s); + if (cs == NULL) { + // no more clients allowed? + // Send to the client that we are full! + Packet *p = NetworkSend_Init(PACKET_SERVER_FULL); + + p->buffer[0] = p->size & 0xFF; + p->buffer[1] = p->size >> 8; + + send(s, p->buffer, p->size, 0); + closesocket(s); + + free(p); + + continue; + } + + // a new client has connected. We set him at inactive for now + // maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK + // the client stays inactive + cs->status = STATUS_INACTIVE; + + DEREF_CLIENT_INFO(cs)->client_ip = sin.sin_addr.s_addr; // Save the IP of the client + } +} + +// Set up the listen socket for the server +static bool NetworkListen(void) +{ + SOCKET ls; + struct sockaddr_in sin; + + DEBUG(net, 1, "Listening on %s:%d", _network_server_bind_ip_host, _network_server_port); + + ls = socket(AF_INET, SOCK_STREAM, 0); + if (ls == INVALID_SOCKET) { + ServerStartError("socket() on listen socket failed"); + return false; + } + + { // reuse the socket + int reuse = 1; + // The (const char*) cast is needed for windows!! + if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) { + ServerStartError("setsockopt() on listen socket failed"); + return false; + } + } + + if (!SetNonBlocking(ls)) DEBUG(net, 0, "Setting non-blocking mode failed"); // XXX should this be an error? + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = _network_server_bind_ip; + sin.sin_port = htons(_network_server_port); + + if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) { + ServerStartError("bind() failed"); + return false; + } + + if (listen(ls, 1) != 0) { + ServerStartError("listen() failed"); + return false; + } + + _listensocket = ls; + + return true; +} + +// Close all current connections +static void NetworkClose(void) +{ + NetworkClientState *cs; + + FOR_ALL_CLIENTS(cs) { + if (!_network_server) { + SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving"); + NetworkSend_Packets(cs); + } + NetworkCloseClient(cs); + } + + if (_network_server) { + // We are a server, also close the listensocket + closesocket(_listensocket); + _listensocket = INVALID_SOCKET; + DEBUG(net, 1, "Closed listener"); + NetworkUDPClose(); + } +} + +// Inits the network (cleans sockets and stuff) +static void NetworkInitialize(void) +{ + NetworkClientState *cs; + + _local_command_queue = NULL; + + // Clean all client-sockets + memset(_clients, 0, sizeof(_clients)); + for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) { + cs->socket = INVALID_SOCKET; + cs->status = STATUS_INACTIVE; + cs->command_queue = NULL; + } + + // Clean the client_info memory + memset(&_network_client_info, 0, sizeof(_network_client_info)); + memset(&_network_player_info, 0, sizeof(_network_player_info)); + + _sync_frame = 0; + _network_first_time = true; + + _network_reconnect = 0; + + NetworkUDPInitialize(); +} + +// Query a server to fetch his game-info +// If game_info is true, only the gameinfo is fetched, +// else only the client_info is fetched +NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info) +{ + if (!_network_available) return NULL; + + NetworkDisconnect(); + + if (game_info) return NetworkUDPQueryServer(host, port); + + NetworkInitialize(); + + _network_server = false; + + // Try to connect + _networking = NetworkConnect(host, port); + + // We are connected + if (_networking) { + SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)(); + } else { // No networking, close everything down again + NetworkDisconnect(); + } + + return NULL; +} + +/* Validates an address entered as a string and adds the server to + * the list. If you use this function, the games will be marked + * as manually added. */ +void NetworkAddServer(const char *b) +{ + if (*b != '\0') { + NetworkGameList *item; + const char *port = NULL; + const char *player = NULL; + char host[NETWORK_HOSTNAME_LENGTH]; + uint16 rport; + + ttd_strlcpy(host, b, lengthof(host)); + + ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip)); + rport = NETWORK_DEFAULT_PORT; + + ParseConnectionString(&player, &port, host); + if (port != NULL) rport = atoi(port); + + item = NetworkQueryServer(host, rport, true); + item->manually = true; + } +} + +/* Generates the list of manually added hosts from NetworkGameList and + * dumps them into the array _network_host_list. This array is needed + * by the function that generates the config file. */ +void NetworkRebuildHostList(void) +{ + uint i = 0; + const NetworkGameList *item = _network_game_list; + while (item != NULL && i != lengthof(_network_host_list)) { + if (item->manually) { + free(_network_host_list[i]); + _network_host_list[i++] = str_fmt("%s:%i", item->info.hostname, item->port); + } + item = item->next; + } + + for (; i < lengthof(_network_host_list); i++) { + free(_network_host_list[i]); + _network_host_list[i] = NULL; + } +} + +// Used by clients, to connect to a server +bool NetworkClientConnectGame(const char *host, uint16 port) +{ + if (!_network_available) return false; + + if (port == 0) return false; + + ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host)); + _network_last_port = port; + + NetworkDisconnect(); + NetworkUDPClose(); + NetworkInitialize(); + + // Try to connect + _networking = NetworkConnect(host, port); + + // We are connected + if (_networking) { + IConsoleCmdExec("exec scripts/on_client.scr 0"); + NetworkClient_Connected(); + } else { + // Connecting failed + NetworkError(STR_NETWORK_ERR_NOCONNECTION); + } + + return _networking; +} + +static void NetworkInitGameInfo(void) +{ + NetworkClientInfo *ci; + + ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name)); + ttd_strlcpy(_network_game_info.server_password, _network_server_password, sizeof(_network_server_password)); + ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_rcon_password)); + if (_network_game_info.server_name[0] == '\0') + snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server"); + + ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision)); + + // The server is a client too ;) + if (_network_dedicated) { + _network_game_info.clients_on = 0; + _network_game_info.companies_on = 0; + _network_game_info.dedicated = true; + } else { + _network_game_info.clients_on = 1; + _network_game_info.companies_on = 1; + _network_game_info.dedicated = false; + } + + _network_game_info.spectators_on = 0; + + _network_game_info.game_date = _date; + _network_game_info.start_date = ConvertYMDToDate(_patches.starting_year, 0, 1); + _network_game_info.map_width = MapSizeX(); + _network_game_info.map_height = MapSizeY(); + _network_game_info.map_set = _opt.landscape; + + _network_game_info.use_password = (_network_server_password[0] != '\0'); + + // We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it + // The index is NETWORK_SERVER_INDEX ( = 1) + ci = &_network_client_info[MAX_CLIENT_INFO - 1]; + memset(ci, 0, sizeof(*ci)); + + ci->client_index = NETWORK_SERVER_INDEX; + ci->client_playas = _network_dedicated ? PLAYER_SPECTATOR : _local_player; + + ttd_strlcpy(ci->client_name, _network_player_name, sizeof(ci->client_name)); + ttd_strlcpy(ci->unique_id, _network_unique_id, sizeof(ci->unique_id)); +} + +bool NetworkServerStart(void) +{ + if (!_network_available) return false; + + /* Call the pre-scripts */ + IConsoleCmdExec("exec scripts/pre_server.scr 0"); + if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0"); + + NetworkInitialize(); + if (!NetworkListen()) return false; + + // Try to start UDP-server + _network_udp_server = true; + _network_udp_server = NetworkUDPListen(&_udp_server_socket, _network_server_bind_ip, _network_server_port, false); + + _network_server = true; + _networking = true; + _frame_counter = 0; + _frame_counter_server = 0; + _frame_counter_max = 0; + _last_sync_frame = 0; + _network_own_client_index = NETWORK_SERVER_INDEX; + + /* Non-dedicated server will always be player #1 */ + if (!_network_dedicated) _network_playas = 0; + + _network_clients_connected = 0; + + NetworkInitGameInfo(); + + // execute server initialization script + IConsoleCmdExec("exec scripts/on_server.scr 0"); + // if the server is dedicated ... add some other script + if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0"); + + _min_players_paused = false; + CheckMinPlayers(); + + /* Try to register us to the master server */ + _network_last_advertise_frame = 0; + _network_need_advertise = true; + NetworkUDPAdvertise(); + return true; +} + +// The server is rebooting... +// The only difference with NetworkDisconnect, is the packets that is sent +void NetworkReboot(void) +{ + if (_network_server) { + NetworkClientState *cs; + FOR_ALL_CLIENTS(cs) { + SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs); + NetworkSend_Packets(cs); + } + } + + NetworkClose(); + + // Free all queued commands + while (_local_command_queue != NULL) { + CommandPacket *p = _local_command_queue; + _local_command_queue = _local_command_queue->next; + free(p); + } + + _networking = false; + _network_server = false; +} + +// We want to disconnect from the host/clients +void NetworkDisconnect(void) +{ + if (_network_server) { + NetworkClientState *cs; + FOR_ALL_CLIENTS(cs) { + SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs); + NetworkSend_Packets(cs); + } + } + + if (_network_advertise) NetworkUDPRemoveAdvertise(); + + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + + NetworkClose(); + + // Free all queued commands + while (_local_command_queue != NULL) { + CommandPacket *p = _local_command_queue; + _local_command_queue = _local_command_queue->next; + free(p); + } + + _networking = false; + _network_server = false; +} + +// Receives something from the network +static bool NetworkReceive(void) +{ + NetworkClientState *cs; + int n; + fd_set read_fd, write_fd; + struct timeval tv; + + FD_ZERO(&read_fd); + FD_ZERO(&write_fd); + + FOR_ALL_CLIENTS(cs) { + FD_SET(cs->socket, &read_fd); + FD_SET(cs->socket, &write_fd); + } + + // take care of listener port + if (_network_server) FD_SET(_listensocket, &read_fd); + + tv.tv_sec = tv.tv_usec = 0; // don't block at all. +#if !defined(__MORPHOS__) && !defined(__AMIGA__) + n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv); +#else + n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL); +#endif + if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION); + + // accept clients.. + if (_network_server && FD_ISSET(_listensocket, &read_fd)) NetworkAcceptClients(); + + // read stuff from clients + FOR_ALL_CLIENTS(cs) { + cs->writable = !!FD_ISSET(cs->socket, &write_fd); + if (FD_ISSET(cs->socket, &read_fd)) { + if (_network_server) { + NetworkServer_ReadPackets(cs); + } else { + NetworkRecvStatus res; + + // The client already was quiting! + if (cs->has_quit) return false; + + res = NetworkClient_ReadPackets(cs); + if (res != NETWORK_RECV_STATUS_OKAY) { + // The client made an error of which we can not recover + // close the client and drop back to main menu + NetworkClientError(res, cs); + return false; + } + } + } + } + return true; +} + +// This sends all buffered commands (if possible) +static void NetworkSend(void) +{ + NetworkClientState *cs; + FOR_ALL_CLIENTS(cs) { + if (cs->writable) { + NetworkSend_Packets(cs); + + if (cs->status == STATUS_MAP) { + // This client is in the middle of a map-send, call the function for that + SEND_COMMAND(PACKET_SERVER_MAP)(cs); + } + } + } +} + +// Handle the local-command-queue +static void NetworkHandleLocalQueue(void) +{ + CommandPacket *cp, **cp_prev; + + cp_prev = &_local_command_queue; + + while ( (cp = *cp_prev) != NULL) { + + // The queue is always in order, which means + // that the first element will be executed first. + if (_frame_counter < cp->frame) break; + + if (_frame_counter > cp->frame) { + // If we reach here, it means for whatever reason, we've already executed + // past the command we need to execute. + DEBUG(net, 0, "Trying to execute a packet in the past!"); + assert(0); + } + + // We can execute this command + NetworkExecuteCommand(cp); + + *cp_prev = cp->next; + free(cp); + } + + // Just a safety check, to be removed in the future. + // Make sure that no older command appears towards the end of the queue + // In that case we missed executing it. This will never happen. + for (cp = _local_command_queue; cp; cp = cp->next) { + assert(_frame_counter < cp->frame); + } + +} + +static bool NetworkDoClientLoop(void) +{ + _frame_counter++; + + NetworkHandleLocalQueue(); + + StateGameLoop(); + + // Check if we are in sync! + if (_sync_frame != 0) { + if (_sync_frame == _frame_counter) { +#ifdef NETWORK_SEND_DOUBLE_SEED + if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) { +#else + if (_sync_seed_1 != _random_seeds[0][0]) { +#endif + NetworkError(STR_NETWORK_ERR_DESYNC); + DEBUG(net, 0, "Sync error detected!"); + NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0)); + return false; + } + + // If this is the first time we have a sync-frame, we + // need to let the server know that we are ready and at the same + // frame as he is.. so we can start playing! + if (_network_first_time) { + _network_first_time = false; + SEND_COMMAND(PACKET_CLIENT_ACK)(); + } + + _sync_frame = 0; + } else if (_sync_frame < _frame_counter) { + DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter); + _sync_frame = 0; + } + } + + return true; +} + +// We have to do some UDP checking +void NetworkUDPGameLoop(void) +{ + if (_network_udp_server) { + NetworkUDPReceive(_udp_server_socket); + if (_udp_master_socket != INVALID_SOCKET) { + NetworkUDPReceive(_udp_master_socket); + } + } else if (_udp_client_socket != INVALID_SOCKET) { + NetworkUDPReceive(_udp_client_socket); + if (_network_udp_broadcast > 0) _network_udp_broadcast--; + } +} + +// The main loop called from ttd.c +// Here we also have to do StateGameLoop if needed! +void NetworkGameLoop(void) +{ + if (!_networking) return; + + if (!NetworkReceive()) return; + + if (_network_server) { + bool send_frame = false; + + // We first increase the _frame_counter + _frame_counter++; + // Update max-frame-counter + if (_frame_counter > _frame_counter_max) { + _frame_counter_max = _frame_counter + _network_frame_freq; + send_frame = true; + } + + NetworkHandleLocalQueue(); + + // Then we make the frame + StateGameLoop(); + + _sync_seed_1 = _random_seeds[0][0]; +#ifdef NETWORK_SEND_DOUBLE_SEED + _sync_seed_2 = _random_seeds[0][1]; +#endif + + NetworkServer_Tick(send_frame); + } else { + // Client + + // Make sure we are at the frame were the server is (quick-frames) + if (_frame_counter_server > _frame_counter) { + while (_frame_counter_server > _frame_counter) { + if (!NetworkDoClientLoop()) break; + } + } else { + // Else, keep on going till _frame_counter_max + if (_frame_counter_max > _frame_counter) NetworkDoClientLoop(); + } + } + + NetworkSend(); +} + +static void NetworkGenerateUniqueId(void) +{ + md5_state_t state; + md5_byte_t digest[16]; + char hex_output[16*2 + 1]; + char coding_string[NETWORK_NAME_LENGTH]; + int di; + + snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID"); + + /* Generate the MD5 hash */ + md5_init(&state); + md5_append(&state, (const md5_byte_t*)coding_string, strlen(coding_string)); + md5_finish(&state, digest); + + for (di = 0; di < 16; ++di) + sprintf(hex_output + di * 2, "%02x", digest[di]); + + /* _network_unique_id is our id */ + snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output); +} + +// This tries to launch the network for a given OS +void NetworkStartUp(void) +{ + DEBUG(net, 3, "[core] starting network..."); + +#if defined(__MORPHOS__) || defined(__AMIGA__) + /* + * IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_ + * network related function, else: crash. + */ + DEBUG(net, 3, "[core] loading bsd socket library"); + SocketBase = OpenLibrary("bsdsocket.library", 4); + if (SocketBase == NULL) { + DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable"); + _network_available = false; + return; + } + +#if defined(__AMIGA__) + // for usleep() implementation (only required for legacy AmigaOS builds) + TimerPort = CreateMsgPort(); + if (TimerPort != NULL) { + TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest); + if (TimerRequest != NULL) { + if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) { + TimerBase = TimerRequest->tr_node.io_Device; + if (TimerBase == NULL) { + // free ressources... + DEBUG(net, 0, "[core] can't initialize timer, network unavailable"); + _network_available = false; + return; + } + } + } + } +#endif // __AMIGA__ +#endif // __MORPHOS__ / __AMIGA__ + + // Network is available + _network_available = true; + _network_dedicated = false; + _network_last_advertise_frame = 0; + _network_need_advertise = true; + _network_advertise_retries = 0; + + /* Load the ip from the openttd.cfg */ + _network_server_bind_ip = inet_addr(_network_server_bind_ip_host); + /* And put the data back in it in case it was an invalid ip */ + snprintf(_network_server_bind_ip_host, sizeof(_network_server_bind_ip_host), "%s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip)); + + /* Generate an unique id when there is none yet */ + if (_network_unique_id[0] == '\0') NetworkGenerateUniqueId(); + + { + byte cl_max = _network_game_info.clients_max; + byte cp_max = _network_game_info.companies_max; + byte sp_max = _network_game_info.spectators_max; + + memset(&_network_game_info, 0, sizeof(_network_game_info)); + _network_game_info.clients_max = cl_max; + _network_game_info.companies_max = cp_max; + _network_game_info.spectators_max = sp_max; + } + + // Let's load the network in windows + #if defined(WIN32) + { + WSADATA wsa; + DEBUG(net, 3, "[core] loading windows socket library"); + if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { + DEBUG(net, 0, "[core] WSAStartup failed, network unavailable"); + _network_available = false; + return; + } + } + #endif // WIN32 + + NetworkInitialize(); + DEBUG(net, 3, "[core] network online, multiplayer available"); + NetworkFindIPs(); +} + +// This shuts the network down +void NetworkShutDown(void) +{ + NetworkDisconnect(); + NetworkUDPClose(); + + DEBUG(net, 3, "[core] shutting down network"); + + _network_available = false; + +#if defined(__MORPHOS__) || defined(__AMIGA__) + // free allocated ressources +#if defined(__AMIGA__) + if (TimerBase != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong + if (TimerRequest != NULL) DeleteIORequest(TimerRequest); + if (TimerPort != NULL) DeleteMsgPort(TimerPort); +#endif + + if (SocketBase != NULL) CloseLibrary(SocketBase); +#endif + +#if defined(WIN32) + WSACleanup(); +#endif +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,212 @@ +/* $Id$ */ + +#ifndef NETWORK_H +#define NETWORK_H + +#define NOREV_STRING "norev000" + +#ifdef ENABLE_NETWORK + +#include "../player.h" +#include "core/config.h" +#include "core/game.h" + +// If this line is enable, every frame will have a sync test +// this is not needed in normal games. Normal is like 1 sync in 100 +// frames. You can enable this if you have a lot of desyncs on a certain +// game. +// Remember: both client and server have to be compiled with this +// option enabled to make it to work. If one of the two has it disabled +// nothing will happen. +//#define ENABLE_NETWORK_SYNC_EVERY_FRAME + +// In theory sending 1 of the 2 seeds is enough to check for desyncs +// so in theory, this next define can be left off. +//#define NETWORK_SEND_DOUBLE_SEED + +// How many clients can we have? Like.. MAX_PLAYERS - 1 is the amount of +// players that can really play.. so.. a max of 4 spectators.. gives us.. +// MAX_PLAYERS + 3 +#define MAX_CLIENTS (MAX_PLAYERS + 3) + + +// Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1 +#define MAX_CLIENT_INFO (MAX_CLIENTS + 1) + +#define MAX_INTERFACES 9 + + +// How many vehicle/station types we put over the network +#define NETWORK_VEHICLE_TYPES 5 +#define NETWORK_STATION_TYPES 5 + +typedef struct NetworkPlayerInfo { + char company_name[NETWORK_NAME_LENGTH]; // Company name + char password[NETWORK_PASSWORD_LENGTH]; // The password for the player + Year inaugurated_year; // What year the company started in + int64 company_value; // The company value + int64 money; // The amount of money the company has + int64 income; // How much did the company earned last year + uint16 performance; // What was his performance last month? + byte use_password; // 0: No password 1: There is a password + uint16 num_vehicle[NETWORK_VEHICLE_TYPES]; // How many vehicles are there of this type? + uint16 num_station[NETWORK_STATION_TYPES]; // How many stations are there of this type? + char players[NETWORK_PLAYERS_LENGTH]; // The players that control this company (Name1, name2, ..) + uint16 months_empty; // How many months the company is empty +} NetworkPlayerInfo; + +typedef struct NetworkClientInfo { + uint16 client_index; // Index of the client (same as ClientState->index) + char client_name[NETWORK_CLIENT_NAME_LENGTH]; // Name of the client + byte client_lang; // The language of the client + byte client_playas; // As which player is this client playing (PlayerID) + uint32 client_ip; // IP-address of the client (so he can be banned) + Date join_date; // Gamedate the player has joined + char unique_id[NETWORK_NAME_LENGTH]; // Every play sends an unique id so we can indentify him +} NetworkClientInfo; + +typedef struct NetworkGameList { + NetworkGameInfo info; + uint32 ip; + uint16 port; + bool online; // False if the server did not respond (default status) + bool manually; // True if the server was added manually + struct NetworkGameList *next; +} NetworkGameList; + +typedef enum { + NETWORK_JOIN_STATUS_CONNECTING, + NETWORK_JOIN_STATUS_AUTHORIZING, + NETWORK_JOIN_STATUS_WAITING, + NETWORK_JOIN_STATUS_DOWNLOADING, + NETWORK_JOIN_STATUS_PROCESSING, + NETWORK_JOIN_STATUS_REGISTERING, + + NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO, +} NetworkJoinStatus; + +// language ids for server_lang and client_lang +typedef enum { + NETLANG_ANY = 0, + NETLANG_ENGLISH = 1, + NETLANG_GERMAN = 2, + NETLANG_FRENCH = 3, +} NetworkLanguage; + +VARDEF NetworkGameList *_network_game_list; + +VARDEF NetworkGameInfo _network_game_info; +VARDEF NetworkPlayerInfo _network_player_info[MAX_PLAYERS]; +VARDEF NetworkClientInfo _network_client_info[MAX_CLIENT_INFO]; + +VARDEF char _network_player_name[NETWORK_CLIENT_NAME_LENGTH]; +VARDEF char _network_default_ip[NETWORK_HOSTNAME_LENGTH]; + +VARDEF uint16 _network_own_client_index; +VARDEF char _network_unique_id[NETWORK_NAME_LENGTH]; // Our own unique ID + +VARDEF uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode +VARDEF uint32 _frame_counter_max; // To where we may go with our clients + +VARDEF uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients. + +// networking settings +VARDEF uint32 _broadcast_list[MAX_INTERFACES + 1]; + +VARDEF uint16 _network_server_port; +/* We use bind_ip and bind_ip_host, where bind_ip_host is the readable form of + bind_ip_host, and bind_ip the numeric value, because we want a nice number + in the openttd.cfg, but we wants to use the uint32 internally.. */ +VARDEF uint32 _network_server_bind_ip; +VARDEF char _network_server_bind_ip_host[NETWORK_HOSTNAME_LENGTH]; +VARDEF bool _is_network_server; // Does this client wants to be a network-server? +VARDEF char _network_server_name[NETWORK_NAME_LENGTH]; +VARDEF char _network_server_password[NETWORK_PASSWORD_LENGTH]; +VARDEF char _network_rcon_password[NETWORK_PASSWORD_LENGTH]; + +VARDEF uint16 _network_max_join_time; ///< Time a client can max take to join +VARDEF bool _network_pause_on_join; ///< Pause the game when a client tries to join (more chance of succeeding join) + +VARDEF uint16 _redirect_console_to_client; + +VARDEF uint16 _network_sync_freq; +VARDEF uint8 _network_frame_freq; + +VARDEF uint32 _sync_seed_1, _sync_seed_2; +VARDEF uint32 _sync_frame; +VARDEF bool _network_first_time; +// Vars needed for the join-GUI +VARDEF NetworkJoinStatus _network_join_status; +VARDEF uint8 _network_join_waiting; +VARDEF uint16 _network_join_kbytes; +VARDEF uint16 _network_join_kbytes_total; + +VARDEF char _network_last_host[NETWORK_HOSTNAME_LENGTH]; +VARDEF short _network_last_port; +VARDEF uint32 _network_last_host_ip; +VARDEF uint8 _network_reconnect; + +VARDEF bool _network_udp_server; +VARDEF uint16 _network_udp_broadcast; + +VARDEF byte _network_lan_internet; + +VARDEF bool _network_need_advertise; +VARDEF uint32 _network_last_advertise_frame; +VARDEF uint8 _network_advertise_retries; + +VARDEF bool _network_autoclean_companies; +VARDEF uint8 _network_autoclean_unprotected; // Remove a company after X months +VARDEF uint8 _network_autoclean_protected; // Unprotect a company after X months + +VARDEF Year _network_restart_game_year; // If this year is reached, the server automaticly restarts +VARDEF uint8 _network_min_players; // Minimum number of players for game to unpause + +NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info); + +byte NetworkSpectatorCount(void); + +VARDEF char *_network_host_list[10]; +VARDEF char *_network_ban_list[25]; + +void ParseConnectionString(const char **player, const char **port, char *connection_string); +void NetworkUpdateClientInfo(uint16 client_index); +void NetworkAddServer(const char *b); +void NetworkRebuildHostList(void); +bool NetworkChangeCompanyPassword(byte argc, char *argv[]); +void NetworkPopulateCompanyInfo(void); +void UpdateNetworkGameWindow(bool unselect); +void CheckMinPlayers(void); + +void NetworkStartUp(void); +void NetworkUDPClose(void); +void NetworkShutDown(void); +void NetworkGameLoop(void); +void NetworkUDPGameLoop(void); +bool NetworkServerStart(void); +bool NetworkClientConnectGame(const char *host, uint16 port); +void NetworkReboot(void); +void NetworkDisconnect(void); + +VARDEF bool _networking; ///< are we in networking mode? +VARDEF bool _network_server; ///< network-server is active +VARDEF bool _network_available; ///< is network mode available? + +#else /* ENABLE_NETWORK */ +/* Network function stubs when networking is disabled */ + +static inline void NetworkStartUp(void) {} +static inline void NetworkShutDown(void) {} + +#define _networking 0 +#define _network_server 0 +#define _network_available 0 + +#endif /* ENABLE_NETWORK */ + +/* These variables must always be registered! */ +VARDEF bool _network_dedicated; ///< are we a dedicated server? +VARDEF bool _network_advertise; ///< is the server advertising to the master server? +VARDEF PlayerID _network_playas; ///< an id to play as.. (see players.h:Players) + +#endif /* NETWORK_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_client.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_client.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,819 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "../string.h" +#include "../strings.h" +#include "network_data.h" +#include "core/tcp.h" +#include "../date.h" +#include "../table/strings.h" +#include "../functions.h" +#include "network_client.h" +#include "network_gamelist.h" +#include "network_gui.h" +#include "../saveload.h" +#include "../command.h" +#include "../window.h" +#include "../console.h" +#include "../variables.h" +#include "../ai/ai.h" + + +// This file handles all the client-commands + + +// So we don't make too much typos ;) +#define MY_CLIENT DEREF_CLIENT(0) + +static uint32 last_ack_frame; + +// ********** +// Sending functions +// DEF_CLIENT_SEND_COMMAND has no parameters +// ********** + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO) +{ + // + // Packet: CLIENT_COMPANY_INFO + // Function: Request company-info (in detail) + // Data: + // + // + Packet *p; + _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + + p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN) +{ + // + // Packet: CLIENT_JOIN + // Function: Try to join the server + // Data: + // String: OpenTTD Revision (norev000 if no revision) + // String: Player Name (max NETWORK_NAME_LENGTH) + // uint8: Play as Player id (1..MAX_PLAYERS) + // uint8: Language ID + // String: Unique id to find the player back in server-listing + // + + extern const char _openttd_revision[]; + Packet *p; + _network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING; + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + + p = NetworkSend_Init(PACKET_CLIENT_JOIN); + NetworkSend_string(p, _openttd_revision); + NetworkSend_string(p, _network_player_name); // Player name + NetworkSend_uint8(p, _network_playas); // PlayAs + NetworkSend_uint8(p, NETLANG_ANY); // Language + NetworkSend_string(p, _network_unique_id); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password) +{ + // + // Packet: CLIENT_PASSWORD + // Function: Send a password to the server to authorize + // Data: + // uint8: NetworkPasswordType + // String: Password + // + Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD); + NetworkSend_uint8(p, type); + NetworkSend_string(p, password); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GETMAP) +{ + // + // Packet: CLIENT_GETMAP + // Function: Request the map from the server + // Data: + // + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_GETMAP); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_MAP_OK) +{ + // + // Packet: CLIENT_MAP_OK + // Function: Tell the server that we are done receiving/loading the map + // Data: + // + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_MAP_OK); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK) +{ + // + // Packet: CLIENT_ACK + // Function: Tell the server we are done with this frame + // Data: + // uint32: current FrameCounter of the client + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_ACK); + + NetworkSend_uint32(p, _frame_counter); + NetworkSend_Packet(p, MY_CLIENT); +} + +// Send a command packet to the server +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp) +{ + // + // Packet: CLIENT_COMMAND + // Function: Send a DoCommand to the Server + // Data: + // uint8: PlayerID (0..MAX_PLAYERS-1) + // uint32: CommandID (see command.h) + // uint32: P1 (free variables used in DoCommand) + // uint32: P2 + // uint32: Tile + // string: text + // uint8: CallBackID (see callback_table.c) + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_COMMAND); + + NetworkSend_uint8(p, cp->player); + NetworkSend_uint32(p, cp->cmd); + NetworkSend_uint32(p, cp->p1); + NetworkSend_uint32(p, cp->p2); + NetworkSend_uint32(p, (uint32)cp->tile); + NetworkSend_string(p, cp->text); + NetworkSend_uint8(p, cp->callback); + + NetworkSend_Packet(p, MY_CLIENT); +} + +// Send a chat-packet over the network +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType type, int dest, const char *msg) +{ + // + // Packet: CLIENT_CHAT + // Function: Send a chat-packet to the serve + // Data: + // uint8: ActionID (see network_data.h, NetworkAction) + // uint8: Destination Type (see network_data.h, DestType); + // uint8: Destination Player (1..MAX_PLAYERS) + // String: Message (max MAX_TEXT_MSG_LEN) + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_CHAT); + + NetworkSend_uint8(p, action); + NetworkSend_uint8(p, type); + NetworkSend_uint8(p, dest); + NetworkSend_string(p, msg); + NetworkSend_Packet(p, MY_CLIENT); +} + +// Send an error-packet over the network +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno) +{ + // + // Packet: CLIENT_ERROR + // Function: The client made an error and is quiting the game + // Data: + // uint8: ErrorID (see network_data.h, NetworkErrorCode) + // + Packet *p = NetworkSend_Init(PACKET_CLIENT_ERROR); + + NetworkSend_uint8(p, errorno); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password) +{ + // + // Packet: PACKET_CLIENT_SET_PASSWORD + // Function: Set the password for the clients current company + // Data: + // String: Password + // + Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_PASSWORD); + + NetworkSend_string(p, password); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name) +{ + // + // Packet: PACKET_CLIENT_SET_NAME + // Function: Gives the player a new name + // Data: + // String: Name + // + Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_NAME); + + NetworkSend_string(p, name); + NetworkSend_Packet(p, MY_CLIENT); +} + +// Send an quit-packet over the network +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg) +{ + // + // Packet: CLIENT_QUIT + // Function: The client is quiting the game + // Data: + // String: leave-message + // + Packet *p = NetworkSend_Init(PACKET_CLIENT_QUIT); + + NetworkSend_string(p, leavemsg); + NetworkSend_Packet(p, MY_CLIENT); +} + +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command) +{ + Packet *p = NetworkSend_Init(PACKET_CLIENT_RCON); + NetworkSend_string(p, pass); + NetworkSend_string(p, command); + NetworkSend_Packet(p, MY_CLIENT); +} + + +// ********** +// Receiving functions +// DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p +// ********** + +extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm); + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FULL) +{ + // We try to join a server which is full + _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL; + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + + return NETWORK_RECV_STATUS_SERVER_FULL; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_BANNED) +{ + // We try to join a server where we are banned + _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_BANNED; + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + + return NETWORK_RECV_STATUS_SERVER_BANNED; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO) +{ + byte company_info_version; + int i; + + company_info_version = NetworkRecv_uint8(MY_CLIENT, p); + + if (!MY_CLIENT->has_quit && company_info_version == NETWORK_COMPANY_INFO_VERSION) { + byte total; + byte current; + + total = NetworkRecv_uint8(MY_CLIENT, p); + + // There is no data at all.. + if (total == 0) return NETWORK_RECV_STATUS_CLOSE_QUERY; + + current = NetworkRecv_uint8(MY_CLIENT, p); + if (!IsValidPlayer(current)) return NETWORK_RECV_STATUS_CLOSE_QUERY; + + NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name)); + _network_player_info[current].inaugurated_year = NetworkRecv_uint32(MY_CLIENT, p); + _network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p); + _network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p); + _network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p); + _network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p); + _network_player_info[current].use_password = NetworkRecv_uint8(MY_CLIENT, p); + for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) + _network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(MY_CLIENT, p); + for (i = 0; i < NETWORK_STATION_TYPES; i++) + _network_player_info[current].num_station[i] = NetworkRecv_uint16(MY_CLIENT, p); + + NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].players, sizeof(_network_player_info[current].players)); + + InvalidateWindow(WC_NETWORK_WINDOW, 0); + + return NETWORK_RECV_STATUS_OKAY; + } + + return NETWORK_RECV_STATUS_CLOSE_QUERY; +} + +// This packet contains info about the client (playas and name) +// as client we save this in NetworkClientInfo, linked via 'index' +// which is always an unique number on a server. +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) +{ + NetworkClientInfo *ci; + uint16 index = NetworkRecv_uint16(MY_CLIENT, p); + PlayerID playas = NetworkRecv_uint8(MY_CLIENT, p); + char name[NETWORK_NAME_LENGTH]; + char unique_id[NETWORK_NAME_LENGTH]; + + NetworkRecv_string(MY_CLIENT, p, name, sizeof(name)); + NetworkRecv_string(MY_CLIENT, p, unique_id, sizeof(unique_id)); + + if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST; + + /* Do we receive a change of data? Most likely we changed playas */ + if (index == _network_own_client_index) _network_playas = playas; + + ci = NetworkFindClientInfoFromIndex(index); + if (ci != NULL) { + if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) { + // Client name changed, display the change + NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", name); + } else if (playas != ci->client_playas) { + // The player changed from client-player.. + // Do not display that for now + } + + ci->client_playas = playas; + ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); + + InvalidateWindow(WC_CLIENT_LIST, 0); + + return NETWORK_RECV_STATUS_OKAY; + } + + // We don't have this index yet, find an empty index, and put the data there + ci = NetworkFindClientInfoFromIndex(NETWORK_EMPTY_INDEX); + if (ci != NULL) { + ci->client_index = index; + ci->client_playas = playas; + + ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); + ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id)); + + InvalidateWindow(WC_CLIENT_LIST, 0); + + return NETWORK_RECV_STATUS_OKAY; + } + + // Here the program should never ever come..... + return NETWORK_RECV_STATUS_MALFORMED_PACKET; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) +{ + NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p); + + switch (error) { + /* We made an error in the protocol, and our connection is closed.... */ + case NETWORK_ERROR_NOT_AUTHORIZED: + case NETWORK_ERROR_NOT_EXPECTED: + case NETWORK_ERROR_PLAYER_MISMATCH: + _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR; + break; + case NETWORK_ERROR_FULL: + _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL; + break; + case NETWORK_ERROR_WRONG_REVISION: + _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION; + break; + case NETWORK_ERROR_WRONG_PASSWORD: + _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD; + break; + case NETWORK_ERROR_KICKED: + _switch_mode_errorstr = STR_NETWORK_ERR_KICKED; + break; + case NETWORK_ERROR_CHEATER: + _switch_mode_errorstr = STR_NETWORK_ERR_CHEATER; + break; + default: + _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; + } + + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + + return NETWORK_RECV_STATUS_SERVER_ERROR; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD) +{ + NetworkPasswordType type = NetworkRecv_uint8(MY_CLIENT, p); + + switch (type) { + case NETWORK_GAME_PASSWORD: + case NETWORK_COMPANY_PASSWORD: + ShowNetworkNeedPassword(type); + return NETWORK_RECV_STATUS_OKAY; + + default: return NETWORK_RECV_STATUS_MALFORMED_PACKET; + } +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME) +{ + _network_own_client_index = NetworkRecv_uint16(MY_CLIENT, p); + + // Start receiving the map + SEND_COMMAND(PACKET_CLIENT_GETMAP)(); + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT) +{ + _network_join_status = NETWORK_JOIN_STATUS_WAITING; + _network_join_waiting = NetworkRecv_uint8(MY_CLIENT, p); + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + + // We are put on hold for receiving the map.. we need GUI for this ;) + DEBUG(net, 1, "The server is currently busy sending the map to someone else, please wait..." ); + DEBUG(net, 1, "There are %d clients in front of you", _network_join_waiting); + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) +{ + static char filename[256]; + static FILE *file_pointer; + + byte maptype; + + maptype = NetworkRecv_uint8(MY_CLIENT, p); + + if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST; + + // First packet, init some stuff + if (maptype == MAP_PACKET_START) { + // The name for the temp-map + snprintf(filename, lengthof(filename), "%s%snetwork_client.tmp", _paths.autosave_dir, PATHSEP); + + file_pointer = fopen(filename, "wb"); + if (file_pointer == NULL) { + _switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR; + return NETWORK_RECV_STATUS_SAVEGAME; + } + + _frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p); + + _network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING; + _network_join_kbytes = 0; + _network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024; + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + + // The first packet does not contain any more data + return NETWORK_RECV_STATUS_OKAY; + } + + if (maptype == MAP_PACKET_NORMAL) { + // We are still receiving data, put it to the file + fwrite(p->buffer + p->pos, 1, p->size - p->pos, file_pointer); + + _network_join_kbytes = ftell(file_pointer) / 1024; + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + } + + // Check if this was the last packet + if (maptype == MAP_PACKET_END) { + fclose(file_pointer); + + _network_join_status = NETWORK_JOIN_STATUS_PROCESSING; + InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); + + /* The map is done downloading, load it */ + if (!SafeSaveOrLoad(filename, SL_LOAD, GM_NORMAL)) { + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + _switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR; + return NETWORK_RECV_STATUS_SAVEGAME; + } + /* If the savegame has successfully loaded, ALL windows have been removed, + * only toolbar/statusbar and gamefield are visible */ + + _opt_ptr = &_opt; // during a network game you are always in-game + + // Say we received the map and loaded it correctly! + SEND_COMMAND(PACKET_CLIENT_MAP_OK)(); + + /* New company/spectator (invalid player) or company we want to join is not active + * Switch local player to spectator and await the server's judgement */ + if (_network_playas == PLAYER_NEW_COMPANY || !IsValidPlayer(_network_playas) || + !GetPlayer(_network_playas)->is_active) { + + SetLocalPlayer(PLAYER_SPECTATOR); + + if (_network_playas != PLAYER_SPECTATOR) { + /* We have arrived and ready to start playing; send a command to make a new player; + * the server will give us a client-id and let us in */ + _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; + ShowJoinStatusWindow(); + NetworkSend_Command(0, 0, 0, CMD_PLAYER_CTRL, NULL); + } + } else { + // take control over an existing company + SetLocalPlayer(_network_playas); + } + } + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME) +{ + _frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p); + _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p); +#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME + // Test if the server supports this option + // and if we are at the frame the server is + if (p->pos < p->size) { + _sync_frame = _frame_counter_server; + _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p); +#ifdef NETWORK_SEND_DOUBLE_SEED + _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p); +#endif + } +#endif + DEBUG(net, 5, "Received FRAME %d", _frame_counter_server); + + // Let the server know that we received this frame correctly + // We do this only once per day, to save some bandwidth ;) + if (!_network_first_time && last_ack_frame < _frame_counter) { + last_ack_frame = _frame_counter + DAY_TICKS; + DEBUG(net, 4, "Sent ACK at %d", _frame_counter); + SEND_COMMAND(PACKET_CLIENT_ACK)(); + } + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC) +{ + _sync_frame = NetworkRecv_uint32(MY_CLIENT, p); + _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p); +#ifdef NETWORK_SEND_DOUBLE_SEED + _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p); +#endif + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND) +{ + CommandPacket *cp = malloc(sizeof(CommandPacket)); + cp->player = NetworkRecv_uint8(MY_CLIENT, p); + cp->cmd = NetworkRecv_uint32(MY_CLIENT, p); + cp->p1 = NetworkRecv_uint32(MY_CLIENT, p); + cp->p2 = NetworkRecv_uint32(MY_CLIENT, p); + cp->tile = NetworkRecv_uint32(MY_CLIENT, p); + NetworkRecv_string(MY_CLIENT, p, cp->text, sizeof(cp->text)); + cp->callback = NetworkRecv_uint8(MY_CLIENT, p); + cp->frame = NetworkRecv_uint32(MY_CLIENT, p); + cp->next = NULL; + + // The server did send us this command.. + // queue it in our own queue, so we can handle it in the upcoming frame! + + if (_local_command_queue == NULL) { + _local_command_queue = cp; + } else { + // Find last packet + CommandPacket *c = _local_command_queue; + while (c->next != NULL) c = c->next; + c->next = cp; + } + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT) +{ + char name[NETWORK_NAME_LENGTH], msg[MAX_TEXT_MSG_LEN]; + const NetworkClientInfo *ci = NULL, *ci_to; + + NetworkAction action = NetworkRecv_uint8(MY_CLIENT, p); + uint16 index = NetworkRecv_uint16(MY_CLIENT, p); + bool self_send = NetworkRecv_uint8(MY_CLIENT, p); + NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN); + + ci_to = NetworkFindClientInfoFromIndex(index); + if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY; + + /* Did we initiate the action locally? */ + if (self_send) { + switch (action) { + case NETWORK_ACTION_CHAT_CLIENT: + /* For speaking to client we need the client-name */ + snprintf(name, sizeof(name), "%s", ci_to->client_name); + ci = NetworkFindClientInfoFromIndex(_network_own_client_index); + break; + + /* For speaking to company or giving money, we need the player-name */ + case NETWORK_ACTION_GIVE_MONEY: + if (!IsValidPlayer(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY; + /* fallthrough */ + case NETWORK_ACTION_CHAT_COMPANY: { + StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS; + + GetString(name, str, lastof(name)); + ci = NetworkFindClientInfoFromIndex(_network_own_client_index); + } break; + + default: NOT_REACHED(); break; + } + } else { + /* Display message from somebody else */ + snprintf(name, sizeof(name), "%s", ci_to->client_name); + ci = ci_to; + } + + if (ci != NULL) + NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), self_send, name, "%s", msg); + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT) +{ + char str[100]; + uint16 index; + NetworkClientInfo *ci; + + index = NetworkRecv_uint16(MY_CLIENT, p); + GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p), lastof(str)); + + ci = NetworkFindClientInfoFromIndex(index); + if (ci != NULL) { + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str); + + // The client is gone, give the NetworkClientInfo free + ci->client_index = NETWORK_EMPTY_INDEX; + } + + InvalidateWindow(WC_CLIENT_LIST, 0); + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT) +{ + char str[100]; + uint16 index; + NetworkClientInfo *ci; + + index = NetworkRecv_uint16(MY_CLIENT, p); + NetworkRecv_string(MY_CLIENT, p, str, lengthof(str)); + + ci = NetworkFindClientInfoFromIndex(index); + if (ci != NULL) { + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str); + + // The client is gone, give the NetworkClientInfo free + ci->client_index = NETWORK_EMPTY_INDEX; + } else { + DEBUG(net, 0, "Unknown client (%d) is leaving the game", index); + } + + InvalidateWindow(WC_CLIENT_LIST, 0); + + // If we come here it means we could not locate the client.. strange :s + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN) +{ + uint16 index; + NetworkClientInfo *ci; + + index = NetworkRecv_uint16(MY_CLIENT, p); + + ci = NetworkFindClientInfoFromIndex(index); + if (ci != NULL) + NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, ci->client_name, ""); + + InvalidateWindow(WC_CLIENT_LIST, 0); + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN) +{ + _switch_mode_errorstr = STR_NETWORK_SERVER_SHUTDOWN; + + return NETWORK_RECV_STATUS_SERVER_ERROR; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEWGAME) +{ + // To trottle the reconnects a bit, every clients waits + // his _local_player value before reconnecting + // PLAYER_SPECTATOR is currently 255, so to avoid long wait periods + // set the max to 10. + _network_reconnect = min(_local_player + 1, 10); + _switch_mode_errorstr = STR_NETWORK_SERVER_REBOOT; + + return NETWORK_RECV_STATUS_SERVER_ERROR; +} + +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_RCON) +{ + char rcon_out[NETWORK_RCONCOMMAND_LENGTH]; + uint16 color_code; + + color_code = NetworkRecv_uint16(MY_CLIENT, p); + NetworkRecv_string(MY_CLIENT, p, rcon_out, sizeof(rcon_out)); + + IConsolePrint(color_code, rcon_out); + + return NETWORK_RECV_STATUS_OKAY; +} + + + +// The layout for the receive-functions by the client +typedef NetworkRecvStatus NetworkClientPacket(Packet *p); + +// This array matches PacketType. At an incoming +// packet it is matches against this array +// and that way the right function to handle that +// packet is found. +static NetworkClientPacket* const _network_client_packet[] = { + RECEIVE_COMMAND(PACKET_SERVER_FULL), + RECEIVE_COMMAND(PACKET_SERVER_BANNED), + NULL, /*PACKET_CLIENT_JOIN,*/ + RECEIVE_COMMAND(PACKET_SERVER_ERROR), + NULL, /*PACKET_CLIENT_COMPANY_INFO,*/ + RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO), + RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO), + RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD), + NULL, /*PACKET_CLIENT_PASSWORD,*/ + RECEIVE_COMMAND(PACKET_SERVER_WELCOME), + NULL, /*PACKET_CLIENT_GETMAP,*/ + RECEIVE_COMMAND(PACKET_SERVER_WAIT), + RECEIVE_COMMAND(PACKET_SERVER_MAP), + NULL, /*PACKET_CLIENT_MAP_OK,*/ + RECEIVE_COMMAND(PACKET_SERVER_JOIN), + RECEIVE_COMMAND(PACKET_SERVER_FRAME), + RECEIVE_COMMAND(PACKET_SERVER_SYNC), + NULL, /*PACKET_CLIENT_ACK,*/ + NULL, /*PACKET_CLIENT_COMMAND,*/ + RECEIVE_COMMAND(PACKET_SERVER_COMMAND), + NULL, /*PACKET_CLIENT_CHAT,*/ + RECEIVE_COMMAND(PACKET_SERVER_CHAT), + NULL, /*PACKET_CLIENT_SET_PASSWORD,*/ + NULL, /*PACKET_CLIENT_SET_NAME,*/ + NULL, /*PACKET_CLIENT_QUIT,*/ + NULL, /*PACKET_CLIENT_ERROR,*/ + RECEIVE_COMMAND(PACKET_SERVER_QUIT), + RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT), + RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN), + RECEIVE_COMMAND(PACKET_SERVER_NEWGAME), + RECEIVE_COMMAND(PACKET_SERVER_RCON), + NULL, /*PACKET_CLIENT_RCON,*/ +}; + +// If this fails, check the array above with network_data.h +assert_compile(lengthof(_network_client_packet) == PACKET_END); + +// Is called after a client is connected to the server +void NetworkClient_Connected(void) +{ + // Set the frame-counter to 0 so nothing happens till we are ready + _frame_counter = 0; + _frame_counter_server = 0; + last_ack_frame = 0; + // Request the game-info + SEND_COMMAND(PACKET_CLIENT_JOIN)(); +} + +// Reads the packets from the socket-stream, if available +NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs) +{ + Packet *p; + NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY; + + while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) { + byte type = NetworkRecv_uint8(MY_CLIENT, p); + if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->has_quit) { + res = _network_client_packet[type](p); + } else { + res = NETWORK_RECV_STATUS_MALFORMED_PACKET; + DEBUG(net, 0, "[client] received invalid packet type %d", type); + } + + free(p); + } + + return res; +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_client.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,25 @@ +/* $Id$ */ + +#ifndef NETWORK_CLIENT_H +#define NETWORK_CLIENT_H + +#ifdef ENABLE_NETWORK + +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GAME_INFO); +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType desttype, int dest, const char *msg); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name); +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK); +DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command); + +NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs); +void NetworkClient_Connected(void); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CLIENT_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_data.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_data.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,106 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "network_data.h" +#include "../string.h" +#include "network_client.h" +#include "../command.h" +#include "../callback_table.h" + +// Add a command to the local command queue +void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp) +{ + CommandPacket* new_cp = malloc(sizeof(*new_cp)); + + *new_cp = *cp; + + if (cs->command_queue == NULL) { + cs->command_queue = new_cp; + } else { + CommandPacket *c = cs->command_queue; + while (c->next != NULL) c = c->next; + c->next = new_cp; + } +} + +// Prepare a DoCommand to be send over the network +void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) +{ + CommandPacket *c = malloc(sizeof(CommandPacket)); + byte temp_callback; + + c->player = _local_player; + c->next = NULL; + c->tile = tile; + c->p1 = p1; + c->p2 = p2; + c->cmd = cmd; + c->callback = 0; + + temp_callback = 0; + + while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback) + temp_callback++; + if (temp_callback == _callback_table_count) { + DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback); + temp_callback = 0; /* _callback_table[0] == NULL */ + } + + if (_network_server) { + // We are the server, so set the command to be executed next possible frame + c->frame = _frame_counter_max + 1; + } else { + c->frame = 0; // The client can't tell which frame, so just make it 0 + } + + ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text)); + + if (_network_server) { + // If we are the server, we queue the command in our 'special' queue. + // In theory, we could execute the command right away, but then the + // client on the server can do everything 1 tick faster than others. + // So to keep the game fair, we delay the command with 1 tick + // which gives about the same speed as most clients. + NetworkClientState *cs; + + // And we queue it for delivery to the clients + FOR_ALL_CLIENTS(cs) { + if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c); + } + + // Only the server gets the callback, because clients should not get them + c->callback = temp_callback; + if (_local_command_queue == NULL) { + _local_command_queue = c; + } else { + // Find last packet + CommandPacket *cp = _local_command_queue; + while (cp->next != NULL) cp = cp->next; + cp->next = c; + } + + return; + } + + // Clients send their command to the server and forget all about the packet + c->callback = temp_callback; + SEND_COMMAND(PACKET_CLIENT_COMMAND)(c); +} + +// Execute a DoCommand we received from the network +void NetworkExecuteCommand(CommandPacket *cp) +{ + _current_player = cp->player; + _cmd_text = cp->text; + /* cp->callback is unsigned. so we don't need to do lower bounds checking. */ + if (cp->callback > _callback_table_count) { + DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback); + cp->callback = 0; + } + DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND); +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_data.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_data.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,167 @@ +/* $Id$ */ + +#ifndef NETWORK_DATA_H +#define NETWORK_DATA_H + +// Is the network enabled? +#ifdef ENABLE_NETWORK + +#include "../openttd.h" +#include "network.h" +#include "core/os_abstraction.h" +#include "core/config.h" +#include "core/packet.h" + +#define MAX_TEXT_MSG_LEN 1024 /* long long long long sentences :-) */ + +// The client-info-server-index is always 1 +#define NETWORK_SERVER_INDEX 1 +#define NETWORK_EMPTY_INDEX 0 + +typedef struct CommandPacket { + struct CommandPacket *next; + PlayerID player; /// player that is executing the command + uint32 cmd; /// command being executed + uint32 p1; /// parameter p1 + uint32 p2; /// parameter p2 + TileIndex tile; /// tile command being executed on + char text[80]; + uint32 frame; /// the frame in which this packet is executed + byte callback; /// any callback function executed upon successful completion of the command +} CommandPacket; + +typedef enum { + STATUS_INACTIVE, + STATUS_AUTH, // This means that the client is authorized + STATUS_MAP_WAIT, // This means that the client is put on hold because someone else is getting the map + STATUS_MAP, + STATUS_DONE_MAP, + STATUS_PRE_ACTIVE, + STATUS_ACTIVE, +} ClientStatus; + +typedef enum { + MAP_PACKET_START, + MAP_PACKET_NORMAL, + MAP_PACKET_END, +} MapPacket; + +typedef enum { + NETWORK_RECV_STATUS_OKAY, + NETWORK_RECV_STATUS_DESYNC, + NETWORK_RECV_STATUS_SAVEGAME, + NETWORK_RECV_STATUS_CONN_LOST, + NETWORK_RECV_STATUS_MALFORMED_PACKET, + NETWORK_RECV_STATUS_SERVER_ERROR, // The server told us we made an error + NETWORK_RECV_STATUS_SERVER_FULL, + NETWORK_RECV_STATUS_SERVER_BANNED, + NETWORK_RECV_STATUS_CLOSE_QUERY, // Done quering the server +} NetworkRecvStatus; + +typedef enum { + NETWORK_ERROR_GENERAL, // Try to use thisone like never + + // Signals from clients + NETWORK_ERROR_DESYNC, + NETWORK_ERROR_SAVEGAME_FAILED, + NETWORK_ERROR_CONNECTION_LOST, + NETWORK_ERROR_ILLEGAL_PACKET, + + // Signals from servers + NETWORK_ERROR_NOT_AUTHORIZED, + NETWORK_ERROR_NOT_EXPECTED, + NETWORK_ERROR_WRONG_REVISION, + NETWORK_ERROR_NAME_IN_USE, + NETWORK_ERROR_WRONG_PASSWORD, + NETWORK_ERROR_PLAYER_MISMATCH, // Happens in CLIENT_COMMAND + NETWORK_ERROR_KICKED, + NETWORK_ERROR_CHEATER, + NETWORK_ERROR_FULL, +} NetworkErrorCode; + +// Actions that can be used for NetworkTextMessage +typedef enum { + NETWORK_ACTION_JOIN, + NETWORK_ACTION_LEAVE, + NETWORK_ACTION_SERVER_MESSAGE, + NETWORK_ACTION_CHAT, + NETWORK_ACTION_CHAT_COMPANY, + NETWORK_ACTION_CHAT_CLIENT, + NETWORK_ACTION_GIVE_MONEY, + NETWORK_ACTION_NAME_CHANGE, +} NetworkAction; + +typedef enum { + NETWORK_GAME_PASSWORD, + NETWORK_COMPANY_PASSWORD, +} NetworkPasswordType; + +// To keep the clients all together +struct NetworkClientState { // Typedeffed in network_core/packet.h + SOCKET socket; + uint16 index; + uint32 last_frame; + uint32 last_frame_server; + byte lag_test; // This byte is used for lag-testing the client + + ClientStatus status; + bool writable; // is client ready to write to? + bool has_quit; + + Packet *packet_queue; // Packets that are awaiting delivery + Packet *packet_recv; // Partially received packet + + CommandPacket *command_queue; // The command-queue awaiting delivery +}; + +typedef enum { + DESTTYPE_BROADCAST, ///< Send message/notice to all players (All) + DESTTYPE_TEAM, ///< Send message/notice to everyone playing the same company (Team) + DESTTYPE_CLIENT, ///< Send message/notice to only a certain player (Private) +} DestType; + +CommandPacket *_local_command_queue; + +SOCKET _udp_client_socket; // udp client socket +SOCKET _udp_server_socket; // udp server socket +SOCKET _udp_master_socket; // udp master socket + +// Here we keep track of the clients +// (and the client uses [0] for his own communication) +NetworkClientState _clients[MAX_CLIENTS]; +#define DEREF_CLIENT(i) (&_clients[i]) +// This returns the NetworkClientInfo from a NetworkClientState +#define DEREF_CLIENT_INFO(cs) (&_network_client_info[cs - _clients]) + +// Macros to make life a bit more easier +#define DEF_CLIENT_RECEIVE_COMMAND(type) NetworkRecvStatus NetworkPacketReceive_ ## type ## _command(Packet *p) +#define DEF_CLIENT_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(void) +#define DEF_CLIENT_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command +#define DEF_SERVER_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(NetworkClientState *cs, Packet *p) +#define DEF_SERVER_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(NetworkClientState *cs) +#define DEF_SERVER_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command + +#define SEND_COMMAND(type) NetworkPacketSend_ ## type ## _command +#define RECEIVE_COMMAND(type) NetworkPacketReceive_ ## type ## _command + +#define FOR_ALL_CLIENTS(cs) for (cs = _clients; cs != endof(_clients) && cs->socket != INVALID_SOCKET; cs++) +#define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX) + +void NetworkExecuteCommand(CommandPacket *cp); +void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp); + +// from network.c +void NetworkCloseClient(NetworkClientState *cs); +void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...); +void NetworkGetClientName(char *clientname, size_t size, const NetworkClientState *cs); +uint NetworkCalculateLag(const NetworkClientState *cs); +byte NetworkGetCurrentLanguageIndex(void); +NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index); +NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip); +NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index); +unsigned long NetworkResolveHost(const char *hostname); +char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_DATA_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_gamelist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_gamelist.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,74 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "network_data.h" +#include "../newgrf_config.h" + +// This file handles the GameList +// Also, it handles the request to a server for data about the server + +/** Add a new item to the linked gamelist. If the IP and Port match + * return the existing item instead of adding it again + * @param ip the IP-address (inet_addr) of the to-be added item + * @param port the port the server is running on + * @return a point to the newly added or already existing item */ +NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port) +{ + NetworkGameList *item, *prev_item; + + prev_item = NULL; + for (item = _network_game_list; item != NULL; item = item->next) { + if (item->ip == ip && item->port == port) return item; + prev_item = item; + } + + item = malloc(sizeof(*item)); + memset(item, 0, sizeof(*item)); + item->next = NULL; + item->ip = ip; + item->port = port; + + if (prev_item == NULL) { + _network_game_list = item; + } else { + prev_item->next = item; + } + DEBUG(net, 4, "[gamelist] added server to list"); + + UpdateNetworkGameWindow(false); + + return item; +} + +/** Remove an item from the gamelist linked list + * @param remove pointer to the item to be removed */ +void NetworkGameListRemoveItem(NetworkGameList *remove) +{ + NetworkGameList *item, *prev_item; + + prev_item = NULL; + for (item = _network_game_list; item != NULL; item = item->next) { + if (remove == item) { + if (prev_item == NULL) { + _network_game_list = remove->next; + } else { + prev_item->next = remove->next; + } + + /* Remove GRFConfig information */ + ClearGRFConfigList(&remove->info.grfconfig); + free(remove); + remove = NULL; + + DEBUG(net, 4, "[gamelist] removed server from list"); + UpdateNetworkGameWindow(false); + return; + } + prev_item = item; + } +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_gamelist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_gamelist.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,11 @@ +/* $Id$ */ + +#ifndef NETWORK_GAMELIST_H +#define NETWORK_GAMELIST_H + +void NetworkGameListClear(void); +NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port); +void NetworkGameListRemoveItem(NetworkGameList *remove); +void NetworkGameListAddQueriedItem(const NetworkGameInfo *info, bool server_online); + +#endif /* NETWORK_GAMELIST_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_gui.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,1706 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK +#include "../stdafx.h" +#include "../openttd.h" +#include "../string.h" +#include "../strings.h" +#include "../table/sprites.h" +#include "network.h" +#include "../date.h" + +#include "../fios.h" +#include "../table/strings.h" +#include "../functions.h" +#include "network_data.h" +#include "network_client.h" +#include "network_gui.h" +#include "network_gamelist.h" +#include "../window.h" +#include "../gui.h" +#include "../gfx.h" +#include "../command.h" +#include "../variables.h" +#include "network_server.h" +#include "network_udp.h" +#include "../settings.h" +#include "../string.h" +#include "../town.h" +#include "../newgrf.h" + +#define BGC 5 +#define BTC 15 + +typedef struct network_d { + PlayerID company; // select company in network lobby + byte field; // select text-field in start-server and game-listing + NetworkGameList *server; // selected server in lobby and game-listing + FiosItem *map; // selected map in start-server +} network_d; +assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_d)); + +typedef struct network_ql_d { + network_d n; // see above; general stuff + querystr_d q; // text-input in start-server and game-listing + NetworkGameList **sort_list; // list of games (sorted) + list_d l; // accompanying list-administration +} network_ql_d; +assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_ql_d)); + +/* Global to remember sorting after window has been closed */ +static Listing _ng_sorting; + +static char _edit_str_buf[150]; +static bool _chat_tab_completion_active; + +static void ShowNetworkStartServerWindow(void); +static void ShowNetworkLobbyWindow(NetworkGameList *ngl); +extern void SwitchMode(int new_mode); + +static const StringID _connection_types_dropdown[] = { + STR_NETWORK_LAN_INTERNET, + STR_NETWORK_INTERNET_ADVERTISE, + INVALID_STRING_ID +}; + +static const StringID _lan_internet_types_dropdown[] = { + STR_NETWORK_LAN, + STR_NETWORK_INTERNET, + INVALID_STRING_ID +}; + +static const StringID _players_dropdown[] = { + STR_NETWORK_0_PLAYERS, + STR_NETWORK_1_PLAYERS, + STR_NETWORK_2_PLAYERS, + STR_NETWORK_3_PLAYERS, + STR_NETWORK_4_PLAYERS, + STR_NETWORK_5_PLAYERS, + STR_NETWORK_6_PLAYERS, + STR_NETWORK_7_PLAYERS, + STR_NETWORK_8_PLAYERS, + STR_NETWORK_9_PLAYERS, + STR_NETWORK_10_PLAYERS, + INVALID_STRING_ID +}; + +static const StringID _language_dropdown[] = { + STR_NETWORK_LANG_ANY, + STR_NETWORK_LANG_ENGLISH, + STR_NETWORK_LANG_GERMAN, + STR_NETWORK_LANG_FRENCH, + INVALID_STRING_ID +}; + +enum { + NET_PRC__OFFSET_TOP_WIDGET = 54, + NET_PRC__OFFSET_TOP_WIDGET_COMPANY = 52, + NET_PRC__SIZE_OF_ROW = 14, +}; + +/** Update the network new window because a new server is + * found on the network. + * @param unselect unselect the currently selected item */ +void UpdateNetworkGameWindow(bool unselect) +{ + SendWindowMessage(WC_NETWORK_WINDOW, 0, unselect, 0, 0); +} + +static bool _internal_sort_order; // Used for Qsort order-flipping +typedef int CDECL NGameNameSortFunction(const void*, const void*); + +/** Qsort function to sort by name. */ +static int CDECL NGameNameSorter(const void *a, const void *b) +{ + const NetworkGameList *cmp1 = *(const NetworkGameList**)a; + const NetworkGameList *cmp2 = *(const NetworkGameList**)b; + int r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); + + return _internal_sort_order ? -r : r; +} + +/** Qsort function to sort by the amount of clients online on a + * server. If the two servers have the same amount, the one with the + * higher maximum is preferred. */ +static int CDECL NGameClientSorter(const void *a, const void *b) +{ + const NetworkGameList *cmp1 = *(const NetworkGameList**)a; + const NetworkGameList *cmp2 = *(const NetworkGameList**)b; + /* Reverse as per default we are interested in most-clients first */ + int r = cmp1->info.clients_on - cmp2->info.clients_on; + + if (r == 0) r = cmp1->info.clients_max - cmp2->info.clients_max; + if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); + + return _internal_sort_order ? -r : r; +} + +/** Qsort function to sort by joinability. If both servers are the + * same, prefer the non-passworded server first. */ +static int CDECL NGameAllowedSorter(const void *a, const void *b) +{ + const NetworkGameList *cmp1 = *(const NetworkGameList**)a; + const NetworkGameList *cmp2 = *(const NetworkGameList**)b; + /* Reverse default as we are interested in compatible clients first */ + int r = cmp2->info.compatible - cmp1->info.compatible; + + if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password; + if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); + + return _internal_sort_order ? -r : r; +} + +/** (Re)build the network game list as its amount has changed because + * an item has been added or deleted for example + * @param ngl list_d struct that contains all necessary information for sorting */ +static void BuildNetworkGameList(network_ql_d *nqld) +{ + NetworkGameList *ngl_temp; + uint n = 0; + + if (!(nqld->l.flags & VL_REBUILD)) return; + + /* Count the number of games in the list */ + for (ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) n++; + if (n == 0) return; + + /* Create temporary array of games to use for listing */ + free(nqld->sort_list); + nqld->sort_list = malloc(n * sizeof(nqld->sort_list[0])); + if (nqld->sort_list == NULL) error("Could not allocate memory for the network-game-sorting-list"); + nqld->l.list_length = n; + + for (n = 0, ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) { + nqld->sort_list[n++] = ngl_temp; + } + + /* Force resort */ + nqld->l.flags &= ~VL_REBUILD; + nqld->l.flags |= VL_RESORT; +} + +static void SortNetworkGameList(network_ql_d *nqld) +{ + static NGameNameSortFunction * const ngame_sorter[] = { + &NGameNameSorter, + &NGameClientSorter, + &NGameAllowedSorter + }; + + NetworkGameList *item; + uint i; + + if (!(nqld->l.flags & VL_RESORT)) return; + if (nqld->l.list_length == 0) return; + + _internal_sort_order = !!(nqld->l.flags & VL_DESC); + qsort(nqld->sort_list, nqld->l.list_length, sizeof(nqld->sort_list[0]), ngame_sorter[nqld->l.sort_type]); + + /* After sorting ngl->sort_list contains the sorted items. Put these back + * into the original list. Basically nothing has changed, we are only + * shuffling the ->next pointers */ + _network_game_list = nqld->sort_list[0]; + for (item = _network_game_list, i = 1; i != nqld->l.list_length; i++) { + item->next = nqld->sort_list[i]; + item = item->next; + } + item->next = NULL; + + nqld->l.flags &= ~VL_RESORT; +} + +/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */ +static void NetworkGameWindowWndProc(Window *w, WindowEvent *e) +{ + network_d *nd = &WP(w, network_ql_d).n; + list_d *ld = &WP(w, network_ql_d).l; + + switch (e->event) { + case WE_CREATE: /* Focus input box */ + nd->field = 3; + nd->server = NULL; + + WP(w, network_ql_d).sort_list = NULL; + ld->flags = VL_REBUILD | (_ng_sorting.order << (VL_DESC - 1)); + ld->sort_type = _ng_sorting.criteria; + break; + + case WE_PAINT: { + const NetworkGameList *sel = nd->server; + const char *arrow = (ld->flags & VL_DESC) ? DOWNARROW : UPARROW; + + if (ld->flags & VL_REBUILD) { + BuildNetworkGameList(&WP(w, network_ql_d)); + SetVScrollCount(w, ld->list_length); + } + if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d)); + + SetWindowWidgetDisabledState(w, 17, sel == NULL); + /* Join Button disabling conditions */ + SetWindowWidgetDisabledState(w, 16, sel == NULL || // no Selected Server + !sel->online || // Server offline + sel->info.clients_on >= sel->info.clients_max || // Server full + !sel->info.compatible); // Revision mismatch + + SetWindowWidgetHiddenState(w, 18, sel == NULL || + !sel->online || + sel->info.grfconfig == NULL); + + SetDParam(0, 0x00); + SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]); + DrawWindowWidgets(w); + + DrawEditBox(w, &WP(w, network_ql_d).q, 3); + + DrawString(9, 23, STR_NETWORK_CONNECTION, 2); + DrawString(210, 23, STR_NETWORK_PLAYER_NAME, 2); + + /* Sort based on widgets: name, clients, compatibility */ + switch (ld->sort_type) { + case 6 - 6: DoDrawString(arrow, w->widget[6].right - 10, 42, 0x10); break; + case 7 - 6: DoDrawString(arrow, w->widget[7].right - 10, 42, 0x10); break; + case 8 - 6: DoDrawString(arrow, w->widget[8].right - 10, 42, 0x10); break; + } + + { // draw list of games + uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3; + int32 n = 0; + int32 pos = w->vscroll.pos; + uint max_name_width = w->widget[6].right - w->widget[6].left - 5; + const NetworkGameList *cur_item = _network_game_list; + + while (pos > 0 && cur_item != NULL) { + pos--; + cur_item = cur_item->next; + } + + while (cur_item != NULL) { + // show highlighted item with a different colour + if (cur_item == sel) GfxFillRect(w->widget[6].left + 1, y - 2, w->widget[8].right - 1, y + 9, 10); + + SetDParamStr(0, cur_item->info.server_name); + DrawStringTruncated(w->widget[6].left + 5, y, STR_02BD, 16, max_name_width); + + SetDParam(0, cur_item->info.clients_on); + SetDParam(1, cur_item->info.clients_max); + SetDParam(2, cur_item->info.companies_on); + SetDParam(3, cur_item->info.companies_max); + DrawStringCentered(210, y, STR_NETWORK_GENERAL_ONLINE, 2); + + // only draw icons if the server is online + if (cur_item->online) { + // draw a lock if the server is password protected. + if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1); + + // draw red or green icon, depending on compatibility with server. + DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[8].left + 15, y); + + // draw flag according to server language + DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y); + } + + cur_item = cur_item->next; + y += NET_PRC__SIZE_OF_ROW; + if (++n == w->vscroll.cap) break; // max number of games in the window + } + } + + /* Draw the right menu */ + GfxFillRect(311, 43, 539, 92, 157); + if (sel == NULL) { + DrawStringCentered(425, 58, STR_NETWORK_GAME_INFO, 0); + } else if (!sel->online) { + SetDParamStr(0, sel->info.server_name); + DrawStringCentered(425, 68, STR_ORANGE, 0); // game name + + DrawStringCentered(425, 132, STR_NETWORK_SERVER_OFFLINE, 0); // server offline + } else { // show game info + uint16 y = 100; + const uint16 x = w->widget[15].left + 5; + + DrawStringCentered(425, 48, STR_NETWORK_GAME_INFO, 0); + + + SetDParamStr(0, sel->info.server_name); + DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 62, STR_ORANGE, 16); // game name + + SetDParamStr(0, sel->info.map_name); + DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 74, STR_02BD, 16); // map name + + SetDParam(0, sel->info.clients_on); + SetDParam(1, sel->info.clients_max); + SetDParam(2, sel->info.companies_on); + SetDParam(3, sel->info.companies_max); + DrawString(x, y, STR_NETWORK_CLIENTS, 2); + y += 10; + + SetDParam(0, _language_dropdown[sel->info.server_lang]); + DrawString(x, y, STR_NETWORK_LANGUAGE, 2); // server language + y += 10; + + SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set); + DrawString(x, y, STR_NETWORK_TILESET, 2); // tileset + y += 10; + + SetDParam(0, sel->info.map_width); + SetDParam(1, sel->info.map_height); + DrawString(x, y, STR_NETWORK_MAP_SIZE, 2); // map size + y += 10; + + SetDParamStr(0, sel->info.server_revision); + DrawString(x, y, STR_NETWORK_SERVER_VERSION, 2); // server version + y += 10; + + SetDParamStr(0, sel->info.hostname); + SetDParam(1, sel->port); + DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, 2); // server address + y += 10; + + SetDParam(0, sel->info.start_date); + DrawString(x, y, STR_NETWORK_START_DATE, 2); // start date + y += 10; + + SetDParam(0, sel->info.game_date); + DrawString(x, y, STR_NETWORK_CURRENT_DATE, 2); // current date + y += 10; + + y += 2; + + if (!sel->info.compatible) { + DrawStringCentered(425, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch + } else if (sel->info.clients_on == sel->info.clients_max) { + // Show: server full, when clients_on == clients_max + DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full + } else if (sel->info.use_password) { + DrawStringCentered(425, y, STR_NETWORK_PASSWORD, 0); // password warning + } + + y += 10; + } + } break; + + case WE_CLICK: + nd->field = e->we.click.widget; + switch (e->we.click.widget) { + case 0: case 14: /* Close 'X' | Cancel button */ + DeleteWindowById(WC_NETWORK_WINDOW, 0); + break; + case 4: case 5: + ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5 + break; + case 6: /* Sort by name */ + case 7: /* Sort by connected clients */ + case 8: /* Connectivity (green dot) */ + if (ld->sort_type == e->we.click.widget - 6) ld->flags ^= VL_DESC; + ld->flags |= VL_RESORT; + ld->sort_type = e->we.click.widget - 6; + + _ng_sorting.order = !!(ld->flags & VL_DESC); + _ng_sorting.criteria = ld->sort_type; + SetWindowDirty(w); + break; + case 9: { /* Matrix to show networkgames */ + NetworkGameList *cur_item; + uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW; + + if (id_v >= w->vscroll.cap) return; // click out of bounds + id_v += w->vscroll.pos; + + cur_item = _network_game_list; + for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next; + + nd->server = cur_item; + SetWindowDirty(w); + } break; + case 11: /* Find server automatically */ + switch (_network_lan_internet) { + case 0: NetworkUDPSearchGame(); break; + case 1: NetworkUDPQueryMasterServer(); break; + } + break; + case 12: { // Add a server + ShowQueryString( + BindCString(_network_default_ip), + STR_NETWORK_ENTER_IP, + 31 | 0x1000, // maximum number of characters OR + 250, // characters up to this width pixels, whichever is satisfied first + w, CS_ALPHANUMERAL); + } break; + case 13: /* Start server */ + ShowNetworkStartServerWindow(); + break; + case 16: /* Join Game */ + if (nd->server != NULL) { + snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip)); + _network_last_port = nd->server->port; + ShowNetworkLobbyWindow(nd->server); + } + break; + case 17: // Refresh + if (nd->server != NULL) + NetworkQueryServer(nd->server->info.hostname, nd->server->port, true); + break; + case 18: // NewGRF Settings + if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig); + break; + + } break; + + case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ + switch (e->we.dropdown.button) { + case 5: + _network_lan_internet = e->we.dropdown.index; + break; + } + + SetWindowDirty(w); + break; + + case WE_MOUSELOOP: + if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3); + break; + + case WE_MESSAGE: + if (e->we.message.msg != 0) nd->server = NULL; + ld->flags |= VL_REBUILD; + SetWindowDirty(w); + break; + + case WE_KEYPRESS: + if (nd->field != 3) { + if (nd->server != NULL) { + if (e->we.keypress.keycode == WKC_DELETE) { /* Press 'delete' to remove servers */ + NetworkGameListRemoveItem(nd->server); + NetworkRebuildHostList(); + nd->server = NULL; + } + } + break; + } + + if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed + + // The name is only allowed when it starts with a letter! + if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ') { + ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name)); + } else { + ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name)); + } + + break; + + case WE_ON_EDIT_TEXT: + NetworkAddServer(e->we.edittext.str); + NetworkRebuildHostList(); + break; + + case WE_DESTROY: /* Nicely clean up the sort-list */ + free(WP(w, network_ql_d).sort_list); + break; + } +} + +static const Widget _network_game_window_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 549, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, BGC, 0, 549, 14, 263, 0x0, STR_NULL}, + +/* LEFT SIDE */ +{ WWT_PANEL, RESIZE_NONE, BGC, 310, 461, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP}, + +{ WWT_INSET, RESIZE_NONE, BGC, 90, 181, 22, 33, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 170, 180, 23, 32, STR_0225, STR_NETWORK_CONNECTION_TIP}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 170, 42, 53, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 171, 250, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 251, 290, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP}, + +{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 290, 54, 236, (13 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT}, +{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 291, 302, 42, 236, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 30, 130, 246, 257, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 180, 280, 246, 257, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP}, + +/* RIGHT SIDE */ +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 246, 257, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 246, 257, STR_012E_CANCEL, STR_NULL}, + +{ WWT_PANEL, RESIZE_NONE, BGC, 310, 540, 42, 236, 0x0, STR_NULL}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 215, 226, STR_NETWORK_JOIN_GAME, STR_NULL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 197, 208, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL}, + +{ WIDGETS_END}, +}; + +static const WindowDesc _network_game_window_desc = { + WDP_CENTER, WDP_CENTER, 550, 264, + WC_NETWORK_WINDOW,0, + WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, + _network_game_window_widgets, + NetworkGameWindowWndProc, +}; + +void ShowNetworkGameWindow(void) +{ + static bool first = true; + Window *w; + DeleteWindowById(WC_NETWORK_WINDOW, 0); + + /* Only show once */ + if (first) { + char* const *srv; + + first = false; + // add all servers from the config file to our list + for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) { + NetworkAddServer(*srv); + } + + _ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top) + _ng_sorting.order = 0; // sort ascending by default + } + + w = AllocateWindowDesc(&_network_game_window_desc); + if (w != NULL) { + querystr_d *querystr = &WP(w, network_ql_d).q; + + ttd_strlcpy(_edit_str_buf, _network_player_name, lengthof(_edit_str_buf)); + w->vscroll.cap = 13; + + querystr->afilter = CS_ALPHANUMERAL; + InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120); + + UpdateNetworkGameWindow(true); + } +} + +enum { + NSSWND_START = 64, + NSSWND_ROWSIZE = 12 +}; + +/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */ +static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e) +{ + network_d *nd = &WP(w, network_ql_d).n; + + switch (e->event) { + case WE_CREATE: /* focus input box */ + nd->field = 3; + _network_game_info.use_password = (_network_server_password[0] != '\0'); + break; + + case WE_PAINT: { + int y = NSSWND_START, pos; + const FiosItem *item; + + SetDParam( 7, _connection_types_dropdown[_network_advertise]); + SetDParam( 9, _players_dropdown[_network_game_info.clients_max]); + SetDParam(11, _players_dropdown[_network_game_info.companies_max]); + SetDParam(13, _players_dropdown[_network_game_info.spectators_max]); + SetDParam(15, _language_dropdown[_network_game_info.server_lang]); + DrawWindowWidgets(w); + + GfxFillRect(11, 63, 258, 215, 0xD7); + DrawEditBox(w, &WP(w, network_ql_d).q, 3); + + DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2); + + DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2); + + DrawString(280, 63, STR_NETWORK_CONNECTION, 2); + DrawString(280, 95, STR_NETWORK_NUMBER_OF_CLIENTS, 2); + DrawString(280, 127, STR_NETWORK_NUMBER_OF_COMPANIES, 2); + DrawString(280, 159, STR_NETWORK_NUMBER_OF_SPECTATORS, 2); + DrawString(280, 191, STR_NETWORK_LANGUAGE_SPOKEN, 2); + + if (_network_game_info.use_password) DoDrawString("*", 408, 23, 3); + + // draw list of maps + pos = w->vscroll.pos; + while (pos < _fios_num + 1) { + item = _fios_list + pos - 1; + if (item == nd->map || (pos == 0 && nd->map == NULL)) + GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour + + if (pos == 0) { + DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, 9); + } else { + DoDrawString(item->title, 14, y, _fios_colors[item->type] ); + } + pos++; + y += NSSWND_ROWSIZE; + + if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break; + } + } break; + + case WE_CLICK: + nd->field = e->we.click.widget; + switch (e->we.click.widget) { + case 0: /* Close 'X' */ + case 19: /* Cancel button */ + ShowNetworkGameWindow(); + break; + + case 4: /* Set password button */ + ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL); + break; + + case 5: { /* Select map */ + int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE; + + y += w->vscroll.pos; + if (y >= w->vscroll.count) return; + + nd->map = (y == 0) ? NULL : _fios_list + y - 1; + SetWindowDirty(w); + } break; + case 7: case 8: /* Connection type */ + ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8 + break; + case 9: case 10: /* Number of Players (hide 0 and 1 players) */ + ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max, 10, 0, 3); + break; + case 11: case 12: /* Number of Companies (hide 0, 9 and 10 companies; max is 8) */ + ShowDropDownMenu(w, _players_dropdown, _network_game_info.companies_max, 12, 0, 1537); + break; + case 13: case 14: /* Number of Spectators */ + ShowDropDownMenu(w, _players_dropdown, _network_game_info.spectators_max, 14, 0, 0); + break; + case 15: case 16: /* Language */ + ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 16, 0, 0); + break; + case 17: /* Start game */ + _is_network_server = true; + + if (nd->map == NULL) { // start random new game + ShowGenerateLandscape(); + } else { // load a scenario + char *name = FiosBrowseTo(nd->map); + if (name != NULL) { + SetFiosType(nd->map->type); + ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name)); + ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title)); + + DeleteWindow(w); + SwitchMode(SM_START_SCENARIO); + } + } + break; + case 18: /* Load game */ + _is_network_server = true; + /* XXX - WC_NETWORK_WINDOW should stay, but if it stays, it gets + * copied all the elements of 'load game' and upon closing that, it segfaults */ + DeleteWindowById(WC_NETWORK_WINDOW, 0); + ShowSaveLoadDialog(SLD_LOAD_GAME); + break; + } + break; + + case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ + switch (e->we.dropdown.button) { + case 8: _network_advertise = (e->we.dropdown.index != 0); break; + case 10: _network_game_info.clients_max = e->we.dropdown.index; break; + case 12: _network_game_info.companies_max = e->we.dropdown.index; break; + case 14: _network_game_info.spectators_max = e->we.dropdown.index; break; + case 16: _network_game_info.server_lang = e->we.dropdown.index; break; + } + + SetWindowDirty(w); + break; + + case WE_MOUSELOOP: + if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3); + break; + + case WE_KEYPRESS: + if (nd->field == 3) { + if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed + + ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name)); + UpdateTextBufferSize(&WP(w, network_ql_d).q.text); + } + break; + + case WE_ON_EDIT_TEXT: { + ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password)); + _network_game_info.use_password = (_network_server_password[0] != '\0'); + SetWindowDirty(w); + } break; + } +} + +static const Widget _network_start_server_window_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, +{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, BGC, 0, 419, 14, 243, 0x0, STR_NULL}, + +{ WWT_PANEL, RESIZE_NONE, BGC, 100, 272, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP}, + +{ WWT_INSET, RESIZE_NONE, BGC, 10, 271, 62, 216, 0x0, STR_NETWORK_SELECT_MAP_TIP}, +{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 259, 270, 63, 215, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +/* Combo boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */ +{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 77, 88, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 78, 87, STR_0225, STR_NETWORK_CONNECTION_TIP}, +{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 109, 120, STR_NETWORK_COMBO2, STR_NETWORK_NUMBER_OF_CLIENTS_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 110, 119, STR_0225, STR_NETWORK_NUMBER_OF_CLIENTS_TIP}, +{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 141, 152, STR_NETWORK_COMBO3, STR_NETWORK_NUMBER_OF_COMPANIES_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 142, 151, STR_0225, STR_NETWORK_NUMBER_OF_COMPANIES_TIP}, +{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 173, 184, STR_NETWORK_COMBO4, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 174, 183, STR_0225, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, +{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 205, 216, STR_NETWORK_COMBO5, STR_NETWORK_LANGUAGE_TIP}, +{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 206, 215, STR_0225, STR_NETWORK_LANGUAGE_TIP}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 40, 140, 224, 235, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 150, 250, 224, 235, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 260, 360, 224, 235, STR_012E_CANCEL, STR_NULL}, +{ WIDGETS_END}, +}; + +static const WindowDesc _network_start_server_window_desc = { + WDP_CENTER, WDP_CENTER, 420, 244, + WC_NETWORK_WINDOW,0, + WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, + _network_start_server_window_widgets, + NetworkStartServerWindowWndProc, +}; + +static void ShowNetworkStartServerWindow(void) +{ + Window *w; + DeleteWindowById(WC_NETWORK_WINDOW, 0); + + w = AllocateWindowDesc(&_network_start_server_window_desc); + ttd_strlcpy(_edit_str_buf, _network_server_name, lengthof(_edit_str_buf)); + + _saveload_mode = SLD_NEW_GAME; + BuildFileList(); + w->vscroll.cap = 12; + w->vscroll.count = _fios_num+1; + + WP(w, network_ql_d).q.afilter = CS_ALPHANUMERAL; + InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_buf, lengthof(_edit_str_buf), 160); +} + +static byte NetworkLobbyFindCompanyIndex(byte pos) +{ + byte i; + + /* Scroll through all _network_player_info and get the 'pos' item + that is not empty */ + for (i = 0; i < MAX_PLAYERS; i++) { + if (_network_player_info[i].company_name[0] != '\0') { + if (pos-- == 0) return i; + } + } + + return 0; +} + +/* uses network_d WP macro */ +static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e) +{ + network_d *nd = &WP(w, network_d); + + switch (e->event) { + case WE_CREATE: + nd->company = (byte)-1; + break; + + case WE_PAINT: { + const NetworkGameInfo *gi = &nd->server->info; + int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos; + + SetWindowWidgetDisabledState(w, 7, nd->company == (byte)-1); + SetWindowWidgetDisabledState(w, 8, gi->companies_on >= gi->companies_max); + /* You can not join a server as spectator when it has no companies active.. + * it causes some nasty crashes */ + SetWindowWidgetDisabledState(w, 9, gi->spectators_on >= gi->spectators_max || + gi->companies_on == 0); + + DrawWindowWidgets(w); + + SetDParamStr(0, gi->server_name); + DrawString(10, 22, STR_NETWORK_PREPARE_TO_JOIN, 2); + + /* Draw company list */ + pos = w->vscroll.pos; + while (pos < gi->companies_on) { + byte company = NetworkLobbyFindCompanyIndex(pos); + bool income = false; + if (nd->company == company) + GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour + + DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, 16, 135 - 13); + if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, 135, y); + + /* If the company's income was positive puts a green dot else a red dot */ + if (_network_player_info[company].income >= 0) income = true; + DrawSprite(SPR_BLOT | (income ? PALETTE_TO_GREEN : PALETTE_TO_RED), 145, y); + + pos++; + y += NET_PRC__SIZE_OF_ROW; + if (pos >= w->vscroll.cap) break; + } + + /* Draw info about selected company when it is selected in the left window */ + GfxFillRect(174, 39, 403, 75, 157); + DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, 0); + if (nd->company != (byte)-1) { + const uint x = 183; + const uint trunc_width = w->widget[6].right - x; + y = 80; + + SetDParam(0, nd->server->info.clients_on); + SetDParam(1, nd->server->info.clients_max); + SetDParam(2, nd->server->info.companies_on); + SetDParam(3, nd->server->info.companies_max); + DrawString(x, y, STR_NETWORK_CLIENTS, 2); + y += 10; + + SetDParamStr(0, _network_player_info[nd->company].company_name); + DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, 2, trunc_width); + y += 10; + + SetDParam(0, _network_player_info[nd->company].inaugurated_year); + DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, 2); // inauguration year + y += 10; + + SetDParam64(0, _network_player_info[nd->company].company_value); + DrawString(x, y, STR_NETWORK_VALUE, 2); // company value + y += 10; + + SetDParam64(0, _network_player_info[nd->company].money); + DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, 2); // current balance + y += 10; + + SetDParam64(0, _network_player_info[nd->company].income); + DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, 2); // last year's income + y += 10; + + SetDParam(0, _network_player_info[nd->company].performance); + DrawString(x, y, STR_NETWORK_PERFORMANCE, 2); // performance + y += 10; + + SetDParam(0, _network_player_info[nd->company].num_vehicle[0]); + SetDParam(1, _network_player_info[nd->company].num_vehicle[1]); + SetDParam(2, _network_player_info[nd->company].num_vehicle[2]); + SetDParam(3, _network_player_info[nd->company].num_vehicle[3]); + SetDParam(4, _network_player_info[nd->company].num_vehicle[4]); + DrawString(x, y, STR_NETWORK_VEHICLES, 2); // vehicles + y += 10; + + SetDParam(0, _network_player_info[nd->company].num_station[0]); + SetDParam(1, _network_player_info[nd->company].num_station[1]); + SetDParam(2, _network_player_info[nd->company].num_station[2]); + SetDParam(3, _network_player_info[nd->company].num_station[3]); + SetDParam(4, _network_player_info[nd->company].num_station[4]); + DrawString(x, y, STR_NETWORK_STATIONS, 2); // stations + y += 10; + + SetDParamStr(0, _network_player_info[nd->company].players); + DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, 2, trunc_width); // players + } + } break; + + case WE_CLICK: + switch (e->we.click.widget) { + case 0: case 11: /* Close 'X' | Cancel button */ + ShowNetworkGameWindow(); + break; + case 4: { /* Company list */ + uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW; + + if (id_v >= w->vscroll.cap) return; + + id_v += w->vscroll.pos; + nd->company = (id_v >= nd->server->info.companies_on) ? (byte)-1 : NetworkLobbyFindCompanyIndex(id_v); + SetWindowDirty(w); + } break; + case 7: /* Join company */ + if (nd->company != (byte)-1) { + _network_playas = nd->company; + NetworkClientConnectGame(_network_last_host, _network_last_port); + } + break; + case 8: /* New company */ + _network_playas = PLAYER_NEW_COMPANY; + NetworkClientConnectGame(_network_last_host, _network_last_port); + break; + case 9: /* Spectate game */ + _network_playas = PLAYER_SPECTATOR; + NetworkClientConnectGame(_network_last_host, _network_last_port); + break; + case 10: /* Refresh */ + NetworkQueryServer(_network_last_host, _network_last_port, false); // company info + NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data + break; + } break; + + case WE_MESSAGE: + SetWindowDirty(w); + break; + } +} + +static const Widget _network_lobby_window_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, +{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_GAME_LOBBY, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, BGC, 0, 419, 14, 234, 0x0, STR_NULL}, + +// company list +{ WWT_PANEL, RESIZE_NONE, BTC, 10, 155, 38, 49, 0x0, STR_NULL}, +{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 155, 50, 190, (10 << 8) + 1, STR_NETWORK_COMPANY_LIST_TIP}, +{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 156, 167, 38, 190, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST}, + +// company/player info +{ WWT_PANEL, RESIZE_NONE, BGC, 173, 404, 38, 190, 0x0, STR_NULL}, + +// buttons +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 151, 200, 211, STR_NETWORK_JOIN_COMPANY, STR_NETWORK_JOIN_COMPANY_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 151, 215, 226, STR_NETWORK_NEW_COMPANY, STR_NETWORK_NEW_COMPANY_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 158, 268, 200, 211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 158, 268, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 278, 388, 200, 211, STR_012E_CANCEL, STR_NULL}, + +{ WIDGETS_END}, +}; + +static const WindowDesc _network_lobby_window_desc = { + WDP_CENTER, WDP_CENTER, 420, 235, + WC_NETWORK_WINDOW,0, + WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, + _network_lobby_window_widgets, + NetworkLobbyWindowWndProc, +}; + +/* Show the networklobbywindow with the selected server + * @param ngl Selected game pointer which is passed to the new window */ +static void ShowNetworkLobbyWindow(NetworkGameList *ngl) +{ + Window *w; + DeleteWindowById(WC_NETWORK_WINDOW, 0); + + NetworkQueryServer(_network_last_host, _network_last_port, false); // company info + NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data + + w = AllocateWindowDesc(&_network_lobby_window_desc); + if (w != NULL) { + WP(w, network_ql_d).n.server = ngl; + strcpy(_edit_str_buf, ""); + w->vscroll.cap = 10; + } +} + +// The window below gives information about the connected clients +// and also makes able to give money to them, kick them (if server) +// and stuff like that. + +extern void DrawPlayerIcon(PlayerID pid, int x, int y); + +// Every action must be of this form +typedef void ClientList_Action_Proc(byte client_no); + +// Max 10 actions per client +#define MAX_CLIENTLIST_ACTION 10 + +// Some standard bullshit.. defines variables ;) +static void ClientListWndProc(Window *w, WindowEvent *e); +static void ClientListPopupWndProc(Window *w, WindowEvent *e); +static byte _selected_clientlist_item = 255; +static byte _selected_clientlist_y = 0; +static char _clientlist_action[MAX_CLIENTLIST_ACTION][50]; +static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION]; + +enum { + CLNWND_OFFSET = 16, + CLNWND_ROWSIZE = 10 +}; + +static const Widget _client_list_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_NETWORK_CLIENT_LIST, STR_018C_WINDOW_TITLE_DRAG_THIS}, + +{ WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL}, +{ WIDGETS_END}, +}; + +static const Widget _client_list_popup_widgets[] = { +{ WWT_PANEL, RESIZE_NONE, 14, 0, 99, 0, 0, 0, STR_NULL}, +{ WIDGETS_END}, +}; + +static WindowDesc _client_list_desc = { + WDP_AUTO, WDP_AUTO, 250, 1, + WC_CLIENT_LIST,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, + _client_list_widgets, + ClientListWndProc +}; + +// Finds the Xth client-info that is active +static const NetworkClientInfo *NetworkFindClientInfo(byte client_no) +{ + const NetworkClientInfo *ci; + + FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { + if (client_no == 0) return ci; + client_no--; + } + + return NULL; +} + +// Here we start to define the options out of the menu +static void ClientList_Kick(byte client_no) +{ + if (client_no < MAX_PLAYERS) + SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED); +} + +static void ClientList_Ban(byte client_no) +{ + uint i; + uint32 ip = NetworkFindClientInfo(client_no)->client_ip; + + for (i = 0; i < lengthof(_network_ban_list); i++) { + if (_network_ban_list[i] == NULL) { + _network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip)); + break; + } + } + + if (client_no < MAX_PLAYERS) + SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED); +} + +static void ClientList_GiveMoney(byte client_no) +{ + if (NetworkFindClientInfo(client_no) != NULL) + ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas); +} + +static void ClientList_SpeakToClient(byte client_no) +{ + if (NetworkFindClientInfo(client_no) != NULL) + ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index); +} + +static void ClientList_SpeakToCompany(byte client_no) +{ + if (NetworkFindClientInfo(client_no) != NULL) + ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas); +} + +static void ClientList_SpeakToAll(byte client_no) +{ + ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); +} + +static void ClientList_None(byte client_no) +{ + // No action ;) +} + + + +// Help, a action is clicked! What do we do? +static void HandleClientListPopupClick(byte index, byte clientno) { + // A click on the Popup of the ClientList.. handle the command + if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) { + _clientlist_proc[index](clientno); + } +} + +// Finds the amount of clients and set the height correct +static bool CheckClientListHeight(Window *w) +{ + int num = 0; + const NetworkClientInfo *ci; + + // Should be replaced with a loop through all clients + FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { + num++; + } + + num *= CLNWND_ROWSIZE; + + // If height is changed + if (w->height != CLNWND_OFFSET + num + 1) { + // XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1) + SetWindowDirty(w); + w->widget[2].bottom = w->widget[2].top + num + 2; + w->height = CLNWND_OFFSET + num + 1; + SetWindowDirty(w); + return false; + } + return true; +} + +// Finds the amount of actions in the popup and set the height correct +static uint ClientListPopupHeigth(void) { + int i, num = 0; + + // Find the amount of actions + for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) { + if (_clientlist_action[i][0] == '\0') continue; + if (_clientlist_proc[i] == NULL) continue; + num++; + } + + num *= CLNWND_ROWSIZE; + + return num + 1; +} + +// Show the popup (action list) +static Window *PopupClientList(Window *w, int client_no, int x, int y) +{ + int i, h; + const NetworkClientInfo *ci; + DeleteWindowById(WC_TOOLBAR_MENU, 0); + + // Clean the current actions + for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) { + _clientlist_action[i][0] = '\0'; + _clientlist_proc[i] = NULL; + } + + // Fill the actions this client has + // Watch is, max 50 chars long! + + ci = NetworkFindClientInfo(client_no); + if (ci == NULL) return NULL; + + i = 0; + if (_network_own_client_index != ci->client_index) { + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_SpeakToClient; + } + + if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) { + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_SpeakToCompany; + } + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_SpeakToAll; + + if (_network_own_client_index != ci->client_index) { + /* We are no spectator and the player we want to give money to is no spectator */ + if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) { + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_GiveMoney; + } + } + + // A server can kick clients (but not himself) + if (_network_server && _network_own_client_index != ci->client_index) { + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_Kick; + + sprintf(_clientlist_action[i],"Ban"); // XXX GetString? + _clientlist_proc[i++] = &ClientList_Ban; + } + + if (i == 0) { + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i])); + _clientlist_proc[i++] = &ClientList_None; + } + + /* Calculate the height */ + h = ClientListPopupHeigth(); + + // Allocate the popup + w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets); + w->widget[0].bottom = w->widget[0].top + h; + w->widget[0].right = w->widget[0].left + 150; + + w->flags4 &= ~WF_WHITE_BORDER_MASK; + WP(w,menu_d).item_count = 0; + // Save our client + WP(w,menu_d).main_button = client_no; + WP(w,menu_d).sel_index = 0; + // We are a popup + _popup_menu_active = true; + + return w; +} + +/** Main handle for the client popup list + * uses menu_d WP macro */ +static void ClientListPopupWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_PAINT: { + int i, y, sel; + byte colour; + DrawWindowWidgets(w); + + // Draw the actions + sel = WP(w,menu_d).sel_index; + y = 1; + for (i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) { + if (_clientlist_action[i][0] == '\0') continue; + if (_clientlist_proc[i] == NULL) continue; + + if (sel-- == 0) { // Selected item, highlight it + GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0); + colour = 0xC; + } else { + colour = 0x10; + } + + DoDrawString(_clientlist_action[i], 4, y, colour); + } + } break; + + case WE_POPUPMENU_SELECT: { + // We selected an action + int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE; + + if (index >= 0 && e->we.popupmenu.pt.y >= w->top) + HandleClientListPopupClick(index, WP(w,menu_d).main_button); + + DeleteWindowById(WC_TOOLBAR_MENU, 0); + } break; + + case WE_POPUPMENU_OVER: { + // Our mouse hoovers over an action? Select it! + int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE; + + if (index == -1 || index == WP(w,menu_d).sel_index) return; + + WP(w,menu_d).sel_index = index; + SetWindowDirty(w); + } break; + + } +} + +// Main handle for clientlist +static void ClientListWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_PAINT: { + NetworkClientInfo *ci; + int y, i = 0; + byte colour; + + // Check if we need to reset the height + if (!CheckClientListHeight(w)) break; + + DrawWindowWidgets(w); + + y = CLNWND_OFFSET; + + FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { + if (_selected_clientlist_item == i++) { // Selected item, highlight it + GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0); + colour = 0xC; + } else { + colour = 0x10; + } + + if (ci->client_index == NETWORK_SERVER_INDEX) { + DrawString(4, y, STR_NETWORK_SERVER, colour); + } else { + DrawString(4, y, STR_NETWORK_CLIENT, colour); + } + + // Filter out spectators + if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1); + + DoDrawString(ci->client_name, 81, y, colour); + + y += CLNWND_ROWSIZE; + } + } break; + + case WE_CLICK: + // Show the popup with option + if (_selected_clientlist_item != 255) { + PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top); + } + + break; + + case WE_MOUSEOVER: + // -1 means we left the current window + if (e->we.mouseover.pt.y == -1) { + _selected_clientlist_y = 0; + _selected_clientlist_item = 255; + SetWindowDirty(w); + break; + } + // It did not change.. no update! + if (e->we.mouseover.pt.y == _selected_clientlist_y) break; + + // Find the new selected item (if any) + _selected_clientlist_y = e->we.mouseover.pt.y; + if (e->we.mouseover.pt.y > CLNWND_OFFSET) { + _selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE; + } else { + _selected_clientlist_item = 255; + } + + // Repaint + SetWindowDirty(w); + break; + + case WE_DESTROY: case WE_CREATE: + // When created or destroyed, data is reset + _selected_clientlist_item = 255; + _selected_clientlist_y = 0; + break; + } +} + +void ShowClientList(void) +{ + AllocateWindowDescFront(&_client_list_desc, 0); +} + + +static NetworkPasswordType pw_type; + + +void ShowNetworkNeedPassword(NetworkPasswordType npt) +{ + StringID caption; + + pw_type = npt; + switch (npt) { + default: NOT_REACHED(); + case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break; + case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break; + } + ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL); +} + + +static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_PAINT: { + uint8 progress; // used for progress bar + DrawWindowWidgets(w); + + DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, 14); + switch (_network_join_status) { + case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING: + case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO: + progress = 10; // first two stages 10% + break; + case NETWORK_JOIN_STATUS_WAITING: + SetDParam(0, _network_join_waiting); + DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, 14); + progress = 15; // third stage is 15% + break; + case NETWORK_JOIN_STATUS_DOWNLOADING: + SetDParam(0, _network_join_kbytes); + SetDParam(1, _network_join_kbytes_total); + DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, 14); + /* Fallthrough */ + default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */ + progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total; + } + + /* Draw nice progress bar :) */ + DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, 0); + } break; + + case WE_CLICK: + switch (e->we.click.widget) { + case 2: /* Disconnect button */ + NetworkDisconnect(); + DeleteWindow(w); + SwitchMode(SM_MENU); + ShowNetworkGameWindow(); + break; + } + break; + + /* If the server asks for a password, we need to fill it in */ + case WE_ON_EDIT_TEXT_CANCEL: + NetworkDisconnect(); + ShowNetworkGameWindow(); + break; + + case WE_ON_EDIT_TEXT: + SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str); + break; + } +} + +static const Widget _network_join_status_window_widget[] = { +{ WWT_CAPTION, RESIZE_NONE, 14, 0, 249, 0, 13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 84, 0x0, STR_NULL}, +{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 75, 175, 69, 80, STR_NETWORK_DISCONNECT, STR_NULL}, +{ WIDGETS_END}, +}; + +static const WindowDesc _network_join_status_window_desc = { + WDP_CENTER, WDP_CENTER, 250, 85, + WC_NETWORK_STATUS_WINDOW, 0, + WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL, + _network_join_status_window_widget, + NetworkJoinStatusWindowWndProc, +}; + +void ShowJoinStatusWindow(void) +{ + Window *w; + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); + w = AllocateWindowDesc(&_network_join_status_window_desc); + /* Parent the status window to the lobby */ + if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0); +} + +static void SendChat(const char *buf, DestType type, byte dest) +{ + if (buf[0] == '\0') return; + if (!_network_server) { + SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT + type, type, dest, buf); + } else { + NetworkServer_HandleChat(NETWORK_ACTION_CHAT + type, type, dest, buf, NETWORK_SERVER_INDEX); + } +} + +/** + * Find the next item of the list of things that can be auto-completed. + * @param item The current indexed item to return. This function can, and most + * likely will, alter item, to skip empty items in the arrays. + * @return Returns the char that matched to the index. + */ +static const char *ChatTabCompletionNextItem(uint *item) +{ + static char chat_tab_temp_buffer[64]; + + /* First, try clients */ + if (*item < MAX_CLIENT_INFO) { + /* Skip inactive clients */ + while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++; + if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name; + } + + /* Then, try townnames */ + /* Not that the following assumes all town indices are adjacent, ie no + * towns have been deleted. */ + if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) { + const Town *t; + + FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) { + /* Get the town-name via the string-system */ + SetDParam(0, t->townnameparts); + GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer)); + return &chat_tab_temp_buffer[0]; + } + } + + return NULL; +} + +/** + * Find what text to complete. It scans for a space from the left and marks + * the word right from that as to complete. It also writes a \0 at the + * position of the space (if any). If nothing found, buf is returned. + */ +static char *ChatTabCompletionFindText(char *buf) +{ + char *p = strrchr(buf, ' '); + if (p == NULL) return buf; + + *p = '\0'; + return p + 1; +} + +/** + * See if we can auto-complete the current text of the user. + */ +static void ChatTabCompletion(Window *w) +{ + static char _chat_tab_completion_buf[lengthof(_edit_str_buf)]; + Textbuf *tb = &WP(w, querystr_d).text; + uint len, tb_len; + uint item; + char *tb_buf, *pre_buf; + const char *cur_name; + bool second_scan = false; + + item = 0; + + /* Copy the buffer so we can modify it without damaging the real data */ + pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf); + + tb_buf = ChatTabCompletionFindText(pre_buf); + tb_len = strlen(tb_buf); + + while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) { + item++; + + if (_chat_tab_completion_active) { + /* We are pressing TAB again on the same name, is there an other name + * that starts with this? */ + if (!second_scan) { + uint offset; + uint length; + + /* If we are completing at the begin of the line, skip the ': ' we added */ + if (tb_buf == pre_buf) { + offset = 0; + length = tb->length - 2; + } else { + /* Else, find the place we are completing at */ + offset = strlen(pre_buf) + 1; + length = tb->length - offset; + } + + /* Compare if we have a match */ + if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true; + + continue; + } + + /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ + } + + len = strlen(cur_name); + if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) { + /* Save the data it was before completion */ + if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf); + _chat_tab_completion_active = true; + + /* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ + if (pre_buf == tb_buf) { + snprintf(tb->buf, lengthof(_edit_str_buf), "%s: ", cur_name); + } else { + snprintf(tb->buf, lengthof(_edit_str_buf), "%s %s", pre_buf, cur_name); + } + + /* Update the textbuffer */ + UpdateTextBufferSize(&WP(w, querystr_d).text); + + SetWindowDirty(w); + free(pre_buf); + return; + } + } + + if (second_scan) { + /* We walked all posibilities, and the user presses tab again.. revert to original text */ + strcpy(tb->buf, _chat_tab_completion_buf); + _chat_tab_completion_active = false; + + /* Update the textbuffer */ + UpdateTextBufferSize(&WP(w, querystr_d).text); + + SetWindowDirty(w); + } + free(pre_buf); +} + +/* uses querystr_d WP macro + * uses querystr_d->caption to store + * - type of chat message (Private/Team/All) in bytes 0-7 + * - destination of chat message in the case of Team/Private in bytes 8-15 */ +static void ChatWindowWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_CREATE: + SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0); + SETBIT(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys + break; + + case WE_PAINT: { + static const StringID chat_captions[] = { + STR_NETWORK_CHAT_ALL_CAPTION, + STR_NETWORK_CHAT_COMPANY_CAPTION, + STR_NETWORK_CHAT_CLIENT_CAPTION + }; + StringID msg; + + DrawWindowWidgets(w); + + assert(GB(WP(w, querystr_d).caption, 0, 8) < lengthof(chat_captions)); + msg = chat_captions[GB(WP(w, querystr_d).caption, 0, 8)]; + DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, msg, 16); + DrawEditBox(w, &WP(w, querystr_d), 2); + } break; + + case WE_CLICK: + switch (e->we.click.widget) { + case 3: { /* Send */ + DestType type = GB(WP(w, querystr_d).caption, 0, 8); + byte dest = GB(WP(w, querystr_d).caption, 8, 8); + SendChat(WP(w, querystr_d).text.buf, type, dest); + } /* FALLTHROUGH */ + case 0: /* Cancel */ DeleteWindow(w); break; + } + break; + + case WE_MOUSELOOP: + HandleEditBox(w, &WP(w, querystr_d), 2); + break; + + case WE_KEYPRESS: + if (e->we.keypress.keycode == WKC_TAB) { + ChatTabCompletion(w); + } else { + _chat_tab_completion_active = false; + switch (HandleEditBoxKey(w, &WP(w, querystr_d), 2, e)) { + case 1: { /* Return */ + DestType type = GB(WP(w, querystr_d).caption, 0, 8); + byte dest = GB(WP(w, querystr_d).caption, 8, 8); + SendChat(WP(w, querystr_d).text.buf, type, dest); + } /* FALLTHROUGH */ + case 2: /* Escape */ DeleteWindow(w); break; + } + } + break; + + case WE_DESTROY: + SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0); + CLRBIT(_no_scroll, SCROLL_CHAT); + break; + } +} + +static const Widget _chat_window_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_PANEL, RESIZE_NONE, 14, 11, 639, 0, 13, 0x0, STR_NULL}, // background +{ WWT_PANEL, RESIZE_NONE, 14, 75, 577, 1, 12, 0x0, STR_NULL}, // text box +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 578, 639, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button +{ WIDGETS_END}, +}; + +static const WindowDesc _chat_window_desc = { + WDP_CENTER, -26, 640, 14, // x, y, width, height + WC_SEND_NETWORK_MSG,0, + WDF_STD_TOOLTIPS | WDF_DEF_WIDGET, + _chat_window_widgets, + ChatWindowWndProc +}; + +void ShowNetworkChatQueryWindow(DestType type, byte dest) +{ + Window *w; + + DeleteWindowById(WC_SEND_NETWORK_MSG, 0); + + _edit_str_buf[0] = '\0'; + _chat_tab_completion_active = false; + + w = AllocateWindowDesc(&_chat_window_desc); + + LowerWindowWidget(w, 2); + WP(w, querystr_d).caption = GB(type, 0, 8) | (dest << 8); // Misuse of caption + WP(w, querystr_d).afilter = CS_ALPHANUMERAL; + InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 0); +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_gui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_gui.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,26 @@ +/* $Id$ */ + +#ifndef NETWORK_GUI_H +#define NETWORK_GUI_H + +#ifdef ENABLE_NETWORK + +#include "network_data.h" + +void ShowNetworkNeedPassword(NetworkPasswordType npt); +void ShowNetworkGiveMoneyWindow(byte player); // PlayerID +void ShowNetworkChatQueryWindow(DestType type, byte dest); +void ShowJoinStatusWindow(void); +void ShowNetworkGameWindow(void); +void ShowClientList(void); + +#else /* ENABLE_NETWORK */ +/* Network function stubs when networking is disabled */ + +static inline void ShowNetworkChatQueryWindow(byte desttype, byte dest) {} +static inline void ShowClientList(void) {} +static inline void ShowNetworkGameWindow(void) {} + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_GUI_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_server.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_server.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,1528 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../openttd.h" // XXX StringID +#include "../debug.h" +#include "../string.h" +#include "../strings.h" +#include "network_data.h" +#include "core/tcp.h" +#include "../train.h" +#include "../date.h" +#include "../table/strings.h" +#include "../functions.h" +#include "network_server.h" +#include "network_udp.h" +#include "../console.h" +#include "../command.h" +#include "../saveload.h" +#include "../vehicle.h" +#include "../station.h" +#include "../variables.h" +#include "../genworld.h" + +// This file handles all the server-commands + +static void NetworkHandleCommandQueue(NetworkClientState* cs); + +// ********** +// Sending functions +// DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs +// ********** + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci) +{ + // + // Packet: SERVER_CLIENT_INFO + // Function: Sends info about a client + // Data: + // uint16: The index of the client (always unique on a server. 1 = server) + // uint8: As which player the client is playing + // String: The name of the client + // String: The unique id of the client + // + + if (ci->client_index != NETWORK_EMPTY_INDEX) { + Packet *p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO); + NetworkSend_uint16(p, ci->client_index); + NetworkSend_uint8 (p, ci->client_playas); + NetworkSend_string(p, ci->client_name); + NetworkSend_string(p, ci->unique_id); + + NetworkSend_Packet(p, cs); + } +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_COMPANY_INFO) +{ +// + // Packet: SERVER_COMPANY_INFO + // Function: Sends info about the companies + // Data: + // + + int i; + + Player *player; + Packet *p; + + byte active = ActivePlayerCount(); + + if (active == 0) { + p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); + + NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); + NetworkSend_uint8 (p, active); + + NetworkSend_Packet(p, cs); + return; + } + + NetworkPopulateCompanyInfo(); + + FOR_ALL_PLAYERS(player) { + if (!player->is_active) continue; + + p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); + + NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); + NetworkSend_uint8 (p, active); + NetworkSend_uint8 (p, player->index); + + NetworkSend_string(p, _network_player_info[player->index].company_name); + NetworkSend_uint32(p, _network_player_info[player->index].inaugurated_year); + NetworkSend_uint64(p, _network_player_info[player->index].company_value); + NetworkSend_uint64(p, _network_player_info[player->index].money); + NetworkSend_uint64(p, _network_player_info[player->index].income); + NetworkSend_uint16(p, _network_player_info[player->index].performance); + + /* Send 1 if there is a passord for the company else send 0 */ + if (_network_player_info[player->index].password[0] != '\0') { + NetworkSend_uint8(p, 1); + } else { + NetworkSend_uint8(p, 0); + } + + for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) { + NetworkSend_uint16(p, _network_player_info[player->index].num_vehicle[i]); + } + + for (i = 0; i < NETWORK_STATION_TYPES; i++) { + NetworkSend_uint16(p, _network_player_info[player->index].num_station[i]); + } + + if (_network_player_info[player->index].players[0] == '\0') { + NetworkSend_string(p, ""); + } else { + NetworkSend_string(p, _network_player_info[player->index].players); + } + + NetworkSend_Packet(p, cs); + } + + p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); + + NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); + NetworkSend_uint8 (p, 0); + + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error) +{ + // + // Packet: SERVER_ERROR + // Function: The client made an error + // Data: + // uint8: ErrorID (see network_data.h, NetworkErrorCode) + // + + char str[100]; + Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR); + + NetworkSend_uint8(p, error); + NetworkSend_Packet(p, cs); + + GetNetworkErrorMsg(str, error, lastof(str)); + + // Only send when the current client was in game + if (cs->status > STATUS_AUTH) { + NetworkClientState *new_cs; + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str); + + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); + + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status > STATUS_AUTH && new_cs != cs) { + // Some errors we filter to a more general error. Clients don't have to know the real + // reason a joining failed. + if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) + error = NETWORK_ERROR_ILLEGAL_PACKET; + + SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, error); + } + } + } else { + DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->index, str); + } + + cs->has_quit = true; + + // Make sure the data get's there before we close the connection + NetworkSend_Packets(cs); + + // The client made a mistake, so drop his connection now! + NetworkCloseClient(cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type) +{ + // + // Packet: SERVER_NEED_PASSWORD + // Function: Indication to the client that the server needs a password + // Data: + // uint8: Type of password + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD); + NetworkSend_uint8(p, type); + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME) +{ + // + // Packet: SERVER_WELCOME + // Function: The client is joined and ready to receive his map + // Data: + // uint16: Own ClientID + // + + Packet *p; + const NetworkClientState *new_cs; + + // Invalid packet when status is AUTH or higher + if (cs->status >= STATUS_AUTH) return; + + cs->status = STATUS_AUTH; + _network_game_info.clients_on++; + + p = NetworkSend_Init(PACKET_SERVER_WELCOME); + NetworkSend_uint16(p, cs->index); + NetworkSend_Packet(p, cs); + + // Transmit info about all the active clients + FOR_ALL_CLIENTS(new_cs) { + if (new_cs != cs && new_cs->status > STATUS_AUTH) + SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, DEREF_CLIENT_INFO(new_cs)); + } + // Also send the info of the server + SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX)); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WAIT) +{ + // + // Packet: PACKET_SERVER_WAIT + // Function: The client can not receive the map at the moment because + // someone else is already receiving the map + // Data: + // uint8: Clients awaiting map + // + int waiting = 0; + NetworkClientState *new_cs; + Packet *p; + + // Count how many players are waiting in the queue + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status == STATUS_MAP_WAIT) waiting++; + } + + p = NetworkSend_Init(PACKET_SERVER_WAIT); + NetworkSend_uint8(p, waiting); + NetworkSend_Packet(p, cs); +} + +// This sends the map to the client +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP) +{ + // + // Packet: SERVER_MAP + // Function: Sends the map to the client, or a part of it (it is splitted in + // a lot of multiple packets) + // Data: + // uint8: packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END) + // if MAP_PACKET_START: + // uint32: The current FrameCounter + // if MAP_PACKET_NORMAL: + // piece of the map (till max-size of packet) + // if MAP_PACKET_END: + // uint32: seed0 of player + // uint32: seed1 of player + // last 2 are repeated MAX_PLAYERS time + // + + static FILE *file_pointer; + static uint sent_packets; // How many packets we did send succecfully last time + + if (cs->status < STATUS_AUTH) { + // Illegal call, return error and ignore the packet + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED); + return; + } + + if (cs->status == STATUS_AUTH) { + char filename[256]; + Packet *p; + + // Make a dump of the current game + snprintf(filename, lengthof(filename), "%s%snetwork_server.tmp", _paths.autosave_dir, PATHSEP); + if (SaveOrLoad(filename, SL_SAVE) != SL_OK) error("network savedump failed"); + + file_pointer = fopen(filename, "rb"); + fseek(file_pointer, 0, SEEK_END); + + // Now send the _frame_counter and how many packets are coming + p = NetworkSend_Init(PACKET_SERVER_MAP); + NetworkSend_uint8(p, MAP_PACKET_START); + NetworkSend_uint32(p, _frame_counter); + NetworkSend_uint32(p, ftell(file_pointer)); + NetworkSend_Packet(p, cs); + + fseek(file_pointer, 0, SEEK_SET); + + sent_packets = 4; // We start with trying 4 packets + + cs->status = STATUS_MAP; + /* Mark the start of download */ + cs->last_frame = _frame_counter; + cs->last_frame_server = _frame_counter; + } + + if (cs->status == STATUS_MAP) { + uint i; + int res; + for (i = 0; i < sent_packets; i++) { + Packet *p = NetworkSend_Init(PACKET_SERVER_MAP); + NetworkSend_uint8(p, MAP_PACKET_NORMAL); + res = (int)fread(p->buffer + p->size, 1, SEND_MTU - p->size, file_pointer); + + if (ferror(file_pointer)) error("Error reading temporary network savegame!"); + + p->size += res; + NetworkSend_Packet(p, cs); + if (feof(file_pointer)) { + // Done reading! + Packet *p = NetworkSend_Init(PACKET_SERVER_MAP); + NetworkSend_uint8(p, MAP_PACKET_END); + NetworkSend_Packet(p, cs); + + // Set the status to DONE_MAP, no we will wait for the client + // to send it is ready (maybe that happens like never ;)) + cs->status = STATUS_DONE_MAP; + fclose(file_pointer); + + { + NetworkClientState *new_cs; + bool new_map_client = false; + // Check if there is a client waiting for receiving the map + // and start sending him the map + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status == STATUS_MAP_WAIT) { + // Check if we already have a new client to send the map to + if (!new_map_client) { + // If not, this client will get the map + new_cs->status = STATUS_AUTH; + new_map_client = true; + SEND_COMMAND(PACKET_SERVER_MAP)(new_cs); + } else { + // Else, send the other clients how many clients are in front of them + SEND_COMMAND(PACKET_SERVER_WAIT)(new_cs); + } + } + } + } + + // There is no more data, so break the for + break; + } + } + + // Send all packets (forced) and check if we have send it all + NetworkSend_Packets(cs); + if (cs->packet_queue == NULL) { + // All are sent, increase the sent_packets + sent_packets *= 2; + } else { + // Not everything is sent, decrease the sent_packets + if (sent_packets > 1) sent_packets /= 2; + } + } +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index) +{ + // + // Packet: SERVER_JOIN + // Function: A client is joined (all active clients receive this after a + // PACKET_CLIENT_MAP_OK) Mostly what directly follows is a + // PACKET_SERVER_CLIENT_INFO + // Data: + // uint16: Client-Index + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN); + + NetworkSend_uint16(p, client_index); + + NetworkSend_Packet(p, cs); +} + + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME) +{ + // + // Packet: SERVER_FRAME + // Function: Sends the current frame-counter to the client + // Data: + // uint32: Frame Counter + // uint32: Frame Counter Max (how far may the client walk before the server?) + // [uint32: general-seed-1] + // [uint32: general-seed-2] + // (last two depends on compile-settings, and are not default settings) + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_FRAME); + NetworkSend_uint32(p, _frame_counter); + NetworkSend_uint32(p, _frame_counter_max); +#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME + NetworkSend_uint32(p, _sync_seed_1); +#ifdef NETWORK_SEND_DOUBLE_SEED + NetworkSend_uint32(p, _sync_seed_2); +#endif +#endif + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SYNC) +{ + // + // Packet: SERVER_SYNC + // Function: Sends a sync-check to the client + // Data: + // uint32: Frame Counter + // uint32: General-seed-1 + // [uint32: general-seed-2] + // (last one depends on compile-settings, and are not default settings) + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_SYNC); + NetworkSend_uint32(p, _frame_counter); + NetworkSend_uint32(p, _sync_seed_1); + +#ifdef NETWORK_SEND_DOUBLE_SEED + NetworkSend_uint32(p, _sync_seed_2); +#endif + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp) +{ + // + // Packet: SERVER_COMMAND + // Function: Sends a DoCommand to the client + // Data: + // uint8: PlayerID (0..MAX_PLAYERS-1) + // uint32: CommandID (see command.h) + // uint32: P1 (free variables used in DoCommand) + // uint32: P2 + // uint32: Tile + // string: text + // uint8: CallBackID (see callback_table.c) + // uint32: Frame of execution + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_COMMAND); + + NetworkSend_uint8(p, cp->player); + NetworkSend_uint32(p, cp->cmd); + NetworkSend_uint32(p, cp->p1); + NetworkSend_uint32(p, cp->p2); + NetworkSend_uint32(p, cp->tile); + NetworkSend_string(p, cp->text); + NetworkSend_uint8(p, cp->callback); + NetworkSend_uint32(p, cp->frame); + + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, bool self_send, const char *msg) +{ + // + // Packet: SERVER_CHAT + // Function: Sends a chat-packet to the client + // Data: + // uint8: ActionID (see network_data.h, NetworkAction) + // uint16: Client-index + // String: Message (max MAX_TEXT_MSG_LEN) + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT); + + NetworkSend_uint8(p, action); + NetworkSend_uint16(p, client_index); + NetworkSend_uint8(p, self_send); + NetworkSend_string(p, msg); + + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno) +{ + // + // Packet: SERVER_ERROR_QUIT + // Function: One of the clients made an error and is quiting the game + // This packet informs the other clients of that. + // Data: + // uint16: Client-index + // uint8: ErrorID (see network_data.h, NetworkErrorCode) + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT); + + NetworkSend_uint16(p, client_index); + NetworkSend_uint8(p, errorno); + + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg) +{ + // + // Packet: SERVER_ERROR_QUIT + // Function: A client left the game, and this packets informs the other clients + // of that. + // Data: + // uint16: Client-index + // String: leave-message + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT); + + NetworkSend_uint16(p, client_index); + NetworkSend_string(p, leavemsg); + + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN) +{ + // + // Packet: SERVER_SHUTDOWN + // Function: Let the clients know that the server is closing + // Data: + // + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_SHUTDOWN); + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME) +{ + // + // Packet: PACKET_SERVER_NEWGAME + // Function: Let the clients know that the server is loading a new map + // Data: + // + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME); + NetworkSend_Packet(p, cs); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command) +{ + Packet *p = NetworkSend_Init(PACKET_SERVER_RCON); + + NetworkSend_uint16(p, color); + NetworkSend_string(p, command); + NetworkSend_Packet(p, cs); +} + +// ********** +// Receiving functions +// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p +// ********** + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO) +{ + SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs); +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) +{ + char name[NETWORK_CLIENT_NAME_LENGTH]; + char unique_id[NETWORK_NAME_LENGTH]; + NetworkClientInfo *ci; + byte playas; + NetworkLanguage client_lang; + char client_revision[NETWORK_REVISION_LENGTH]; + + NetworkRecv_string(cs, p, client_revision, sizeof(client_revision)); + +#if defined(WITH_REV) || defined(WITH_REV_HACK) + // Check if the client has revision control enabled + if (strcmp(NOREV_STRING, client_revision) != 0 && + strcmp(_network_game_info.server_revision, client_revision) != 0) { + // Different revisions!! + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_REVISION); + return; + } +#endif + + NetworkRecv_string(cs, p, name, sizeof(name)); + playas = NetworkRecv_uint8(cs, p); + client_lang = NetworkRecv_uint8(cs, p); + NetworkRecv_string(cs, p, unique_id, sizeof(unique_id)); + + if (cs->has_quit) return; + + // join another company does not affect these values + switch (playas) { + case PLAYER_NEW_COMPANY: /* New company */ + if (ActivePlayerCount() >= _network_game_info.companies_max) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL); + return; + } + break; + case PLAYER_SPECTATOR: /* Spectator */ + if (NetworkSpectatorCount() >= _network_game_info.spectators_max) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL); + return; + } + break; + default: /* Join another company (companies 1-8 (index 0-7)) */ + if (!IsValidPlayer(playas)) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH); + return; + } + break; + } + + // We need a valid name.. make it Player + if (*name == '\0') ttd_strlcpy(name, "Player", sizeof(name)); + + if (!NetworkFindName(name)) { // Change name if duplicate + // We could not create a name for this player + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NAME_IN_USE); + return; + } + + ci = DEREF_CLIENT_INFO(cs); + + ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); + ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id)); + ci->client_playas = playas; + ci->client_lang = client_lang; + + // We now want a password from the client + // else we do not allow him in! + if (_network_game_info.use_password) { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); + } else { + if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); + } else { + SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); + } + } + + /* Make sure companies to which people try to join are not autocleaned */ + if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0; +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD) +{ + NetworkPasswordType type; + char password[NETWORK_PASSWORD_LENGTH]; + const NetworkClientInfo *ci; + + type = NetworkRecv_uint8(cs, p); + NetworkRecv_string(cs, p, password, sizeof(password)); + + if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) { + // Check game-password + if (strcmp(password, _network_game_info.server_password) != 0) { + // Password is invalid + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD); + return; + } + + ci = DEREF_CLIENT_INFO(cs); + + if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); + return; + } + + // Valid password, allow user + SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); + return; + } else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) { + ci = DEREF_CLIENT_INFO(cs); + + if (strcmp(password, _network_player_info[ci->client_playas].password) != 0) { + // Password is invalid + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD); + return; + } + + SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); + return; + } + + + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); + return; +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP) +{ + const NetworkClientState *new_cs; + + // The client was never joined.. so this is impossible, right? + // Ignore the packet, give the client a warning, and close his connection + if (cs->status < STATUS_AUTH || cs->has_quit) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED); + return; + } + + // Check if someone else is receiving the map + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status == STATUS_MAP) { + // Tell the new client to wait + cs->status = STATUS_MAP_WAIT; + SEND_COMMAND(PACKET_SERVER_WAIT)(cs); + return; + } + } + + // We receive a request to upload the map.. give it to the client! + SEND_COMMAND(PACKET_SERVER_MAP)(cs); +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK) +{ + // Client has the map, now start syncing + if (cs->status == STATUS_DONE_MAP && !cs->has_quit) { + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + NetworkClientState *new_cs; + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, client_name, ""); + + // Mark the client as pre-active, and wait for an ACK + // so we know he is done loading and in sync with us + cs->status = STATUS_PRE_ACTIVE; + NetworkHandleCommandQueue(cs); + SEND_COMMAND(PACKET_SERVER_FRAME)(cs); + SEND_COMMAND(PACKET_SERVER_SYNC)(cs); + + // This is the frame the client receives + // we need it later on to make sure the client is not too slow + cs->last_frame = _frame_counter; + cs->last_frame_server = _frame_counter; + + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status > STATUS_AUTH) { + SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(new_cs, DEREF_CLIENT_INFO(cs)); + SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index); + } + } + + if (_network_pause_on_join) { + /* Now pause the game till the client is in sync */ + DoCommandP(0, 1, 0, NULL, CMD_PAUSE); + + NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX); + } + } else { + // Wrong status for this packet, give a warning to client, and close connection + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); + } +} + +/** Enforce the command flags. + * Eg a server-only command can only be executed by a server, etc. + * @param *cp the commandpacket that is going to be checked + * @param *ci client information for debugging output to console + */ +static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci) +{ + byte flags = GetCommandFlags(cp->cmd); + + if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) { + IConsolePrintF(_icolour_err, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci)); + return false; + } + + if (flags & CMD_OFFLINE) { + IConsolePrintF(_icolour_err, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci)); + return false; + } + + return true; +} + +/** The client has done a command and wants us to handle it + * @param *cs the connected client that has sent the command + * @param *p the packet in which the command was sent + */ +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) +{ + NetworkClientState *new_cs; + const NetworkClientInfo *ci; + byte callback; + + CommandPacket *cp = malloc(sizeof(CommandPacket)); + + // The client was never joined.. so this is impossible, right? + // Ignore the packet, give the client a warning, and close his connection + if (cs->status < STATUS_DONE_MAP || cs->has_quit) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); + return; + } + + cp->player = NetworkRecv_uint8(cs, p); + cp->cmd = NetworkRecv_uint32(cs, p); + cp->p1 = NetworkRecv_uint32(cs, p); + cp->p2 = NetworkRecv_uint32(cs, p); + cp->tile = NetworkRecv_uint32(cs, p); + NetworkRecv_string(cs, p, cp->text, lengthof(cp->text)); + + callback = NetworkRecv_uint8(cs, p); + + if (cs->has_quit) return; + + ci = DEREF_CLIENT_INFO(cs); + + /* Check if cp->cmd is valid */ + if (!IsValidCommand(cp->cmd)) { + IConsolePrintF(_icolour_err, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci)); + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); + return; + } + + if (!CheckCommandFlags(cp, ci)) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED); + return; + } + + /** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs + * to match the player in the packet. If it doesn't, the client has done + * something pretty naughty (or a bug), and will be kicked + */ + if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) { + IConsolePrintF(_icolour_err, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...", + ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1); + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH); + return; + } + + /** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the + * player the correct ID, the server injects p2 and executes the command. Any other p1 + * is prohibited. Pretty ugly and should be redone together with its function. + * @see CmdPlayerCtrl() players.c:655 + */ + if (cp->cmd == CMD_PLAYER_CTRL) { + if (cp->p1 != 0) { + SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER); + return; + } + + /* XXX - Execute the command as a valid player. Normally this would be done by a + * spectator, but that is not allowed any commands. So do an impersonation. The drawback + * of this is that the first company's last_built_tile is also updated... */ + cp->player = 0; + cp->p2 = cs - _clients; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl + } + + // The frame can be executed in the same frame as the next frame-packet + // That frame just before that frame is saved in _frame_counter_max + cp->frame = _frame_counter_max + 1; + cp->next = NULL; + + // Queue the command for the clients (are send at the end of the frame + // if they can handle it ;)) + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status >= STATUS_MAP) { + // Callbacks are only send back to the client who sent them in the + // first place. This filters that out. + cp->callback = (new_cs != cs) ? 0 : callback; + NetworkAddCommandQueue(new_cs, cp); + } + } + + cp->callback = 0; + // Queue the command on the server + if (_local_command_queue == NULL) { + _local_command_queue = cp; + } else { + // Find last packet + CommandPacket *c = _local_command_queue; + while (c->next != NULL) c = c->next; + c->next = cp; + } +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR) +{ + // This packets means a client noticed an error and is reporting this + // to us. Display the error and report it to the other clients + NetworkClientState *new_cs; + char str[100]; + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + NetworkErrorCode errorno = NetworkRecv_uint8(cs, p); + + // The client was never joined.. thank the client for the packet, but ignore it + if (cs->status < STATUS_DONE_MAP || cs->has_quit) { + cs->has_quit = true; + return; + } + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + GetNetworkErrorMsg(str, errorno, lastof(str)); + + DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str); + + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); + + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status > STATUS_AUTH) { + SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno); + } + } + + cs->has_quit = true; +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT) +{ + // The client wants to leave. Display this and report it to the other + // clients. + NetworkClientState *new_cs; + char str[100]; + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + + // The client was never joined.. thank the client for the packet, but ignore it + if (cs->status < STATUS_DONE_MAP || cs->has_quit) { + cs->has_quit = true; + return; + } + + NetworkRecv_string(cs, p, str, lengthof(str)); + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); + + FOR_ALL_CLIENTS(new_cs) { + if (new_cs->status > STATUS_AUTH) { + SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str); + } + } + + cs->has_quit = true; +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK) +{ + uint32 frame = NetworkRecv_uint32(cs, p); + + /* The client is trying to catch up with the server */ + if (cs->status == STATUS_PRE_ACTIVE) { + /* The client is not yet catched up? */ + if (frame + DAY_TICKS < _frame_counter) return; + + /* Now he is! Unpause the game */ + cs->status = STATUS_ACTIVE; + + if (_network_pause_on_join) { + DoCommandP(0, 0, 0, NULL, CMD_PAUSE); + NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", NETWORK_SERVER_INDEX); + } + + CheckMinPlayers(); + + /* Execute script for, e.g. MOTD */ + IConsoleCmdExec("exec scripts/on_server_connect.scr 0"); + } + + // The client received the frame, make note of it + cs->last_frame = frame; + // With those 2 values we can calculate the lag realtime + cs->last_frame_server = _frame_counter; +} + + + +void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index) +{ + NetworkClientState *cs; + const NetworkClientInfo *ci, *ci_own, *ci_to; + + switch (desttype) { + case DESTTYPE_CLIENT: + /* Are we sending to the server? */ + if (dest == NETWORK_SERVER_INDEX) { + ci = NetworkFindClientInfoFromIndex(from_index); + /* Display the text locally, and that is it */ + if (ci != NULL) + NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); + } else { + /* Else find the client to send the message to */ + FOR_ALL_CLIENTS(cs) { + if (cs->index == dest) { + SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); + break; + } + } + } + + // Display the message locally (so you know you have sent it) + if (from_index != dest) { + if (from_index == NETWORK_SERVER_INDEX) { + ci = NetworkFindClientInfoFromIndex(from_index); + ci_to = NetworkFindClientInfoFromIndex(dest); + if (ci != NULL && ci_to != NULL) + NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg); + } else { + FOR_ALL_CLIENTS(cs) { + if (cs->index == from_index) { + SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg); + break; + } + } + } + } + break; + case DESTTYPE_TEAM: { + bool show_local = true; // If this is false, the message is already displayed + // on the client who did sent it. + /* Find all clients that belong to this player */ + ci_to = NULL; + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); + if (ci->client_playas == dest) { + SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); + if (cs->index == from_index) show_local = false; + ci_to = ci; // Remember a client that is in the company for company-name + } + } + + ci = NetworkFindClientInfoFromIndex(from_index); + ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) { + NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); + if (from_index == NETWORK_SERVER_INDEX) show_local = false; + ci_to = ci_own; + } + + /* There is no such player */ + if (ci_to == NULL) break; + + // Display the message locally (so you know you have sent it) + if (ci != NULL && show_local) { + if (from_index == NETWORK_SERVER_INDEX) { + char name[NETWORK_NAME_LENGTH]; + StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS; + GetString(name, str, lastof(name)); + NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg); + } else { + FOR_ALL_CLIENTS(cs) { + if (cs->index == from_index) { + SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg); + } + } + } + } + } + break; + default: + DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype); + /* fall-through to next case */ + case DESTTYPE_BROADCAST: + FOR_ALL_CLIENTS(cs) { + SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); + } + ci = NetworkFindClientInfoFromIndex(from_index); + if (ci != NULL) + NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); + break; + } +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT) +{ + NetworkAction action = NetworkRecv_uint8(cs, p); + DestType desttype = NetworkRecv_uint8(cs, p); + int dest = NetworkRecv_uint8(cs, p); + char msg[MAX_TEXT_MSG_LEN]; + + NetworkRecv_string(cs, p, msg, MAX_TEXT_MSG_LEN); + + NetworkServer_HandleChat(action, desttype, dest, msg, cs->index); +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD) +{ + char password[NETWORK_PASSWORD_LENGTH]; + const NetworkClientInfo *ci; + + NetworkRecv_string(cs, p, password, sizeof(password)); + ci = DEREF_CLIENT_INFO(cs); + + if (IsValidPlayer(ci->client_playas)) { + ttd_strlcpy(_network_player_info[ci->client_playas].password, password, sizeof(_network_player_info[0].password)); + } +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME) +{ + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + NetworkClientInfo *ci; + + NetworkRecv_string(cs, p, client_name, sizeof(client_name)); + ci = DEREF_CLIENT_INFO(cs); + + if (cs->has_quit) return; + + if (ci != NULL) { + // Display change + if (NetworkFindName(client_name)) { + NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", client_name); + ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name)); + NetworkUpdateClientInfo(ci->client_index); + } + } +} + +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON) +{ + char pass[NETWORK_PASSWORD_LENGTH]; + char command[NETWORK_RCONCOMMAND_LENGTH]; + + if (_network_game_info.rcon_password[0] == '\0') return; + + NetworkRecv_string(cs, p, pass, sizeof(pass)); + NetworkRecv_string(cs, p, command, sizeof(command)); + + if (strcmp(pass, _network_game_info.rcon_password) != 0) { + DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->index); + return; + } + + DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->index, command); + + _redirect_console_to_client = cs->index; + IConsoleCmdExec(command); + _redirect_console_to_client = 0; + return; +} + +// The layout for the receive-functions by the server +typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p); + + +// This array matches PacketType. At an incoming +// packet it is matches against this array +// and that way the right function to handle that +// packet is found. +static NetworkServerPacket* const _network_server_packet[] = { + NULL, /*PACKET_SERVER_FULL,*/ + NULL, /*PACKET_SERVER_BANNED,*/ + RECEIVE_COMMAND(PACKET_CLIENT_JOIN), + NULL, /*PACKET_SERVER_ERROR,*/ + RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO), + NULL, /*PACKET_SERVER_COMPANY_INFO,*/ + NULL, /*PACKET_SERVER_CLIENT_INFO,*/ + NULL, /*PACKET_SERVER_NEED_PASSWORD,*/ + RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD), + NULL, /*PACKET_SERVER_WELCOME,*/ + RECEIVE_COMMAND(PACKET_CLIENT_GETMAP), + NULL, /*PACKET_SERVER_WAIT,*/ + NULL, /*PACKET_SERVER_MAP,*/ + RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK), + NULL, /*PACKET_SERVER_JOIN,*/ + NULL, /*PACKET_SERVER_FRAME,*/ + NULL, /*PACKET_SERVER_SYNC,*/ + RECEIVE_COMMAND(PACKET_CLIENT_ACK), + RECEIVE_COMMAND(PACKET_CLIENT_COMMAND), + NULL, /*PACKET_SERVER_COMMAND,*/ + RECEIVE_COMMAND(PACKET_CLIENT_CHAT), + NULL, /*PACKET_SERVER_CHAT,*/ + RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD), + RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME), + RECEIVE_COMMAND(PACKET_CLIENT_QUIT), + RECEIVE_COMMAND(PACKET_CLIENT_ERROR), + NULL, /*PACKET_SERVER_QUIT,*/ + NULL, /*PACKET_SERVER_ERROR_QUIT,*/ + NULL, /*PACKET_SERVER_SHUTDOWN,*/ + NULL, /*PACKET_SERVER_NEWGAME,*/ + NULL, /*PACKET_SERVER_RCON,*/ + RECEIVE_COMMAND(PACKET_CLIENT_RCON), +}; + +// If this fails, check the array above with network_data.h +assert_compile(lengthof(_network_server_packet) == PACKET_END); + +// This update the company_info-stuff +void NetworkPopulateCompanyInfo(void) +{ + char password[NETWORK_PASSWORD_LENGTH]; + const Player *p; + const Vehicle *v; + const Station *s; + const NetworkClientState *cs; + const NetworkClientInfo *ci; + uint i; + uint16 months_empty; + + FOR_ALL_PLAYERS(p) { + if (!p->is_active) { + memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo)); + continue; + } + + // Clean the info but not the password + ttd_strlcpy(password, _network_player_info[p->index].password, sizeof(password)); + months_empty = _network_player_info[p->index].months_empty; + memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo)); + _network_player_info[p->index].months_empty = months_empty; + ttd_strlcpy(_network_player_info[p->index].password, password, sizeof(_network_player_info[p->index].password)); + + // Grap the company name + SetDParam(0, p->name_1); + SetDParam(1, p->name_2); + GetString(_network_player_info[p->index].company_name, STR_JUST_STRING, lastof(_network_player_info[p->index].company_name)); + + // Check the income + if (_cur_year - 1 == p->inaugurated_year) { + // The player is here just 1 year, so display [2], else display[1] + for (i = 0; i < lengthof(p->yearly_expenses[2]); i++) { + _network_player_info[p->index].income -= p->yearly_expenses[2][i]; + } + } else { + for (i = 0; i < lengthof(p->yearly_expenses[1]); i++) { + _network_player_info[p->index].income -= p->yearly_expenses[1][i]; + } + } + + // Set some general stuff + _network_player_info[p->index].inaugurated_year = p->inaugurated_year; + _network_player_info[p->index].company_value = p->old_economy[0].company_value; + _network_player_info[p->index].money = p->money64; + _network_player_info[p->index].performance = p->old_economy[0].performance_history; + } + + // Go through all vehicles and count the type of vehicles + FOR_ALL_VEHICLES(v) { + if (!IsValidPlayer(v->owner)) continue; + + switch (v->type) { + case VEH_Train: + if (IsFrontEngine(v)) _network_player_info[v->owner].num_vehicle[0]++; + break; + + case VEH_Road: + if (v->cargo_type != CT_PASSENGERS) { + _network_player_info[v->owner].num_vehicle[1]++; + } else { + _network_player_info[v->owner].num_vehicle[2]++; + } + break; + + case VEH_Aircraft: + if (v->subtype <= 2) _network_player_info[v->owner].num_vehicle[3]++; + break; + + case VEH_Ship: + _network_player_info[v->owner].num_vehicle[4]++; + break; + + case VEH_Special: + case VEH_Disaster: + break; + } + } + + // Go through all stations and count the types of stations + FOR_ALL_STATIONS(s) { + if (IsValidPlayer(s->owner)) { + NetworkPlayerInfo *npi = &_network_player_info[s->owner]; + + if (s->facilities & FACIL_TRAIN) npi->num_station[0]++; + if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[1]++; + if (s->facilities & FACIL_BUS_STOP) npi->num_station[2]++; + if (s->facilities & FACIL_AIRPORT) npi->num_station[3]++; + if (s->facilities & FACIL_DOCK) npi->num_station[4]++; + } + } + + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + // Register local player (if not dedicated) + if (ci != NULL && IsValidPlayer(ci->client_playas)) + ttd_strlcpy(_network_player_info[ci->client_playas].players, ci->client_name, sizeof(_network_player_info[0].players)); + + FOR_ALL_CLIENTS(cs) { + char client_name[NETWORK_CLIENT_NAME_LENGTH]; + + NetworkGetClientName(client_name, sizeof(client_name), cs); + + ci = DEREF_CLIENT_INFO(cs); + if (ci != NULL && IsValidPlayer(ci->client_playas)) { + if (strlen(_network_player_info[ci->client_playas].players) != 0) + ttd_strlcat(_network_player_info[ci->client_playas].players, ", ", lengthof(_network_player_info[0].players)); + + ttd_strlcat(_network_player_info[ci->client_playas].players, client_name, lengthof(_network_player_info[0].players)); + } + } +} + +// Send a packet to all clients with updated info about this client_index +void NetworkUpdateClientInfo(uint16 client_index) +{ + NetworkClientState *cs; + NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index); + + if (ci == NULL) return; + + FOR_ALL_CLIENTS(cs) { + SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci); + } +} + +/* Check if we want to restart the map */ +static void NetworkCheckRestartMap(void) +{ + if (_network_restart_game_year != 0 && _cur_year >= _network_restart_game_year) { + DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year); + + StartNewGameWithoutGUI(GENERATE_NEW_SEED); + } +} + +/* Check if the server has autoclean_companies activated + Two things happen: + 1) If a company is not protected, it is closed after 1 year (for example) + 2) If a company is protected, protection is disabled after 3 years (for example) + (and item 1. happens a year later) */ +static void NetworkAutoCleanCompanies(void) +{ + const NetworkClientState *cs; + const NetworkClientInfo *ci; + const Player *p; + bool clients_in_company[MAX_PLAYERS]; + + if (!_network_autoclean_companies) return; + + memset(clients_in_company, 0, sizeof(clients_in_company)); + + /* Detect the active companies */ + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); + if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true; + } + + if (!_network_dedicated) { + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true; + } + + /* Go through all the comapnies */ + FOR_ALL_PLAYERS(p) { + /* Skip the non-active once */ + if (!p->is_active || p->is_ai) continue; + + if (!clients_in_company[p->index]) { + /* The company is empty for one month more */ + _network_player_info[p->index].months_empty++; + + /* Is the company empty for autoclean_unprotected-months, and is there no protection? */ + if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') { + /* Shut the company down */ + DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL); + IConsolePrintF(_icolour_def, "Auto-cleaned company #%d", p->index + 1); + } + /* Is the compnay empty for autoclean_protected-months, and there is a protection? */ + if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') { + /* Unprotect the company */ + _network_player_info[p->index].password[0] = '\0'; + IConsolePrintF(_icolour_def, "Auto-removed protection from company #%d", p->index+1); + _network_player_info[p->index].months_empty = 0; + } + } else { + /* It is not empty, reset the date */ + _network_player_info[p->index].months_empty = 0; + } + } +} + +// This function changes new_name to a name that is unique (by adding #1 ...) +// and it returns true if that succeeded. +bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]) +{ + NetworkClientState *new_cs; + bool found_name = false; + byte number = 0; + char original_name[NETWORK_CLIENT_NAME_LENGTH]; + + // We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer + ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH); + + while (!found_name) { + const NetworkClientInfo *ci; + + found_name = true; + FOR_ALL_CLIENTS(new_cs) { + ci = DEREF_CLIENT_INFO(new_cs); + if (strcmp(ci->client_name, new_name) == 0) { + // Name already in use + found_name = false; + break; + } + } + // Check if it is the same as the server-name + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (ci != NULL) { + if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use + } + + if (!found_name) { + // Try a new name ( #1, #2, and so on) + + // Stop if we tried for more than 50 times.. + if (number++ > 50) break; + snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number); + } + } + + return found_name; +} + +// Reads a packet from the stream +bool NetworkServer_ReadPackets(NetworkClientState *cs) +{ + Packet *p; + NetworkRecvStatus res; + while ((p = NetworkRecv_Packet(cs, &res)) != NULL) { + byte type = NetworkRecv_uint8(cs, p); + if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->has_quit) { + _network_server_packet[type](cs, p); + } else { + DEBUG(net, 0, "[server] received invalid packet type %d", type); + } + free(p); + } + + return true; +} + +// Handle the local command-queue +static void NetworkHandleCommandQueue(NetworkClientState* cs) +{ + CommandPacket *cp; + + while ( (cp = cs->command_queue) != NULL) { + SEND_COMMAND(PACKET_SERVER_COMMAND)(cs, cp); + + cs->command_queue = cp->next; + free(cp); + } +} + +// This is called every tick if this is a _network_server +void NetworkServer_Tick(bool send_frame) +{ + NetworkClientState *cs; +#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME + bool send_sync = false; +#endif + +#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME + if (_frame_counter >= _last_sync_frame + _network_sync_freq) { + _last_sync_frame = _frame_counter; + send_sync = true; + } +#endif + + // Now we are done with the frame, inform the clients that they can + // do their frame! + FOR_ALL_CLIENTS(cs) { + // Check if the speed of the client is what we can expect from a client + if (cs->status == STATUS_ACTIVE) { + // 1 lag-point per day + int lag = NetworkCalculateLag(cs) / DAY_TICKS; + if (lag > 0) { + if (lag > 3) { + // Client did still not report in after 4 game-day, drop him + // (that is, the 3 of above, + 1 before any lag is counted) + IConsolePrintF(_icolour_err,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index); + NetworkCloseClient(cs); + continue; + } + + // Report once per time we detect the lag + if (cs->lag_test == 0) { + IConsolePrintF(_icolour_warn,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index); + cs->lag_test = 1; + } + } else { + cs->lag_test = 0; + } + } else if (cs->status == STATUS_PRE_ACTIVE) { + int lag = NetworkCalculateLag(cs); + if (lag > _network_max_join_time) { + IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time); + NetworkCloseClient(cs); + } + } + + if (cs->status >= STATUS_PRE_ACTIVE) { + // Check if we can send command, and if we have anything in the queue + NetworkHandleCommandQueue(cs); + + // Send an updated _frame_counter_max to the client + if (send_frame) SEND_COMMAND(PACKET_SERVER_FRAME)(cs); + +#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME + // Send a sync-check packet + if (send_sync) SEND_COMMAND(PACKET_SERVER_SYNC)(cs); +#endif + } + } + + /* See if we need to advertise */ + NetworkUDPAdvertise(); +} + +void NetworkServerYearlyLoop(void) +{ + NetworkCheckRestartMap(); +} + +void NetworkServerMonthlyLoop(void) +{ + NetworkAutoCleanCompanies(); +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_server.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,39 @@ +/* $Id$ */ + +#ifndef NETWORK_SERVER_H +#define NETWORK_SERVER_H + +#ifdef ENABLE_NETWORK + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP); +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno); +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error); +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN); +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME); +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command); + +bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]); +void NetworkServer_HandleChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index); + +bool NetworkServer_ReadPackets(NetworkClientState *cs); +void NetworkServer_Tick(bool send_frame); +void NetworkServerMonthlyLoop(void); +void NetworkServerYearlyLoop(void); + +static inline const char* GetPlayerIP(const NetworkClientInfo* ci) +{ + struct in_addr addr; + + addr.s_addr = ci->client_ip; + return inet_ntoa(addr); +} + +#else /* ENABLE_NETWORK */ +/* Network function stubs when networking is disabled */ + +static inline void NetworkServerMonthlyLoop(void) {} +static inline void NetworkServerYearlyLoop(void) {} + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_SERVER_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_udp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_udp.c Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,663 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "../string.h" +#include "network_data.h" +#include "../date.h" +#include "../map.h" +#include "network_gamelist.h" +#include "network_udp.h" +#include "../variables.h" +#include "../newgrf_config.h" + +#include "core/udp.h" + +/** + * @file network_udp.c This file handles the UDP related communication. + * + * This is the GameServer <-> MasterServer and GameServer <-> GameClient + * communication before the game is being joined. + */ + +enum { + ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes) + ADVERTISE_RETRY_INTERVAL = 300, // readvertise when no response after this many ticks (9 seconds) + ADVERTISE_RETRY_TIMES = 3 // give up readvertising after this much failed retries +}; + +#define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, struct sockaddr_in *client_addr) + +static NetworkClientState _udp_cs; + +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) +{ + Packet *packet; + // Just a fail-safe.. should never happen + if (!_network_udp_server) + return; + + packet = NetworkSend_Init(PACKET_UDP_SERVER_RESPONSE); + + // Update some game_info + _network_game_info.game_date = _date; + _network_game_info.map_width = MapSizeX(); + _network_game_info.map_height = MapSizeY(); + _network_game_info.map_set = _opt.landscape; + _network_game_info.companies_on = ActivePlayerCount(); + _network_game_info.spectators_on = NetworkSpectatorCount(); + _network_game_info.grfconfig = _grfconfig; + + NetworkSend_NetworkGameInfo(p, &_network_game_info); + + // Let the client know that we are here + NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); + + free(packet); + + DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr)); +} + +void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) +{ + /* Find the matching GRF file */ + const GRFConfig *f = FindGRFConfig(config->grfid, config->md5sum); + if (f == NULL) { + /* Don't know the GRF, so mark game incompatible and the (possibly) + * already resolved name for this GRF (another server has sent the + * name of the GRF already */ + config->name = FindUnknownGRFName(config->grfid, config->md5sum, true); + SETBIT(config->flags, GCF_NOT_FOUND); + } else { + config->filename = f->filename; + config->name = f->name; + config->info = f->info; + } + SETBIT(config->flags, GCF_COPY); +} + +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) +{ + extern const char _openttd_revision[]; + NetworkGameList *item; + + // Just a fail-safe.. should never happen + if (_network_udp_server || _udp_cs.has_quit) return; + + DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port)); + + // Find next item + item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port)); + + NetworkRecv_NetworkGameInfo(&_udp_cs, p, &item->info); + + item->info.compatible = true; + { + /* Checks whether there needs to be a request for names of GRFs and makes + * the request if necessary. GRFs that need to be requested are the GRFs + * that do not exist on the clients system and we do not have the name + * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER. + * The in_request array and in_request_count are used so there is no need + * to do a second loop over the GRF list, which can be relatively expensive + * due to the string comparisons. */ + const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT]; + const GRFConfig *c; + uint in_request_count = 0; + struct sockaddr_in out_addr; + + for (c = item->info.grfconfig; c != NULL; c = c->next) { + if (HASBIT(c->flags, GCF_NOT_FOUND)) item->info.compatible = false; + if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; + in_request[in_request_count] = c; + in_request_count++; + } + + if (in_request_count > 0) { + /* There are 'unknown' GRFs, now send a request for them */ + uint i; + Packet *packet = NetworkSend_Init(PACKET_UDP_CLIENT_GET_NEWGRFS); + + NetworkSend_uint8 (packet, in_request_count); + for (i = 0; i < in_request_count; i++) { + NetworkSend_GRFIdentifier(packet, in_request[i]); + } + + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(item->port); + out_addr.sin_addr.s_addr = item->ip; + NetworkSendUDP_Packet(_udp_client_socket, packet, &out_addr); + free(packet); + } + } + + if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0; + if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0; + + if (item->info.hostname[0] == '\0') + snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr)); + + /* Check if we are allowed on this server based on the revision-match */ + item->info.version_compatible = + strcmp(item->info.server_revision, _openttd_revision) == 0 || + strcmp(item->info.server_revision, NOREV_STRING) == 0; + item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs + + item->online = true; + + UpdateNetworkGameWindow(false); +} + +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO) +{ + NetworkClientState *cs; + NetworkClientInfo *ci; + Packet *packet; + Player *player; + byte current = 0; + int i; + + // Just a fail-safe.. should never happen + if (!_network_udp_server) return; + + packet = NetworkSend_Init(PACKET_UDP_SERVER_DETAIL_INFO); + + /* Send the amount of active companies */ + NetworkSend_uint8 (packet, NETWORK_COMPANY_INFO_VERSION); + NetworkSend_uint8 (packet, ActivePlayerCount()); + + /* Fetch the latest version of everything */ + NetworkPopulateCompanyInfo(); + + /* Go through all the players */ + FOR_ALL_PLAYERS(player) { + /* Skip non-active players */ + if (!player->is_active) continue; + + current++; + + /* Send the information */ + NetworkSend_uint8(packet, current); + + NetworkSend_string(packet, _network_player_info[player->index].company_name); + NetworkSend_uint32(packet, _network_player_info[player->index].inaugurated_year); + NetworkSend_uint64(packet, _network_player_info[player->index].company_value); + NetworkSend_uint64(packet, _network_player_info[player->index].money); + NetworkSend_uint64(packet, _network_player_info[player->index].income); + NetworkSend_uint16(packet, _network_player_info[player->index].performance); + + /* Send 1 if there is a passord for the company else send 0 */ + if (_network_player_info[player->index].password[0] != '\0') { + NetworkSend_uint8(packet, 1); + } else { + NetworkSend_uint8(packet, 0); + } + + for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) + NetworkSend_uint16(packet, _network_player_info[player->index].num_vehicle[i]); + + for (i = 0; i < NETWORK_STATION_TYPES; i++) + NetworkSend_uint16(packet, _network_player_info[player->index].num_station[i]); + + /* Find the clients that are connected to this player */ + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); + if (ci->client_playas == player->index) { + /* The uint8 == 1 indicates that a client is following */ + NetworkSend_uint8(packet, 1); + NetworkSend_string(packet, ci->client_name); + NetworkSend_string(packet, ci->unique_id); + NetworkSend_uint32(packet, ci->join_date); + } + } + /* Also check for the server itself */ + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (ci->client_playas == player->index) { + /* The uint8 == 1 indicates that a client is following */ + NetworkSend_uint8(packet, 1); + NetworkSend_string(packet, ci->client_name); + NetworkSend_string(packet, ci->unique_id); + NetworkSend_uint32(packet, ci->join_date); + } + + /* Indicates end of client list */ + NetworkSend_uint8(packet, 0); + } + + /* And check if we have any spectators */ + FOR_ALL_CLIENTS(cs) { + ci = DEREF_CLIENT_INFO(cs); + if (!IsValidPlayer(ci->client_playas)) { + /* The uint8 == 1 indicates that a client is following */ + NetworkSend_uint8(packet, 1); + NetworkSend_string(packet, ci->client_name); + NetworkSend_string(packet, ci->unique_id); + NetworkSend_uint32(packet, ci->join_date); + } + } + + /* Also check for the server itself */ + ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); + if (!IsValidPlayer(ci->client_playas)) { + /* The uint8 == 1 indicates that a client is following */ + NetworkSend_uint8(packet, 1); + NetworkSend_string(packet, ci->client_name); + NetworkSend_string(packet, ci->unique_id); + NetworkSend_uint32(packet, ci->join_date); + } + + /* Indicates end of client list */ + NetworkSend_uint8(packet, 0); + + NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); + + free(packet); +} + +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST) +{ + int i; + struct in_addr ip; + uint16 port; + uint8 ver; + + /* packet begins with the protocol version (uint8) + * then an uint16 which indicates how many + * ip:port pairs are in this packet, after that + * an uint32 (ip) and an uint16 (port) for each pair + */ + + ver = NetworkRecv_uint8(&_udp_cs, p); + + if (_udp_cs.has_quit) return; + + if (ver == 1) { + for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) { + ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p)); + port = NetworkRecv_uint16(&_udp_cs, p); + NetworkUDPQueryServer(inet_ntoa(ip), port); + } + } +} + +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER) +{ + _network_advertise_retries = 0; + DEBUG(net, 2, "[udp] advertising on master server successfull"); + + /* We are advertised, but we don't want to! */ + if (!_network_advertise) NetworkUDPRemoveAdvertise(); +} + +/** + * A client has requested the names of some NewGRFs. + * + * Replying this can be tricky as we have a limit of SEND_MTU bytes + * in the reply packet and we can send up to 100 bytes per NewGRF + * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name). + * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it + * could be that a packet overflows. To stop this we only reply + * with the first N NewGRFs so that if the first N + 1 NewGRFs + * would be sent, the packet overflows. + * in_reply and in_reply_count are used to keep a list of GRFs to + * send in the reply. + */ +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS) +{ + uint8 num_grfs; + uint i; + + const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT]; + Packet *packet; + uint8 in_reply_count = 0; + uint packet_len = 0; + + /* Just a fail-safe.. should never happen */ + if (_udp_cs.has_quit) return; + + DEBUG(net, 6, "[udp] newgrf data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port)); + + num_grfs = NetworkRecv_uint8 (&_udp_cs, p); + if (num_grfs > NETWORK_MAX_GRF_COUNT) return; + + for (i = 0; i < num_grfs; i++) { + GRFConfig c; + const GRFConfig *f; + + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); + + /* Find the matching GRF file */ + f = FindGRFConfig(c.grfid, c.md5sum); + if (f == NULL) continue; // The GRF is unknown to this server + + /* If the reply might exceed the size of the packet, only reply + * the current list and do not send the other data. + * The name could be an empty string, if so take the filename. */ + packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + + min(strlen((f->name != NULL && strlen(f->name) > 0) ? f->name : f->filename) + 1, NETWORK_GRF_NAME_LENGTH); + if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply + break; + } + in_reply[in_reply_count] = f; + in_reply_count++; + } + + if (in_reply_count == 0) return; + + packet = NetworkSend_Init(PACKET_UDP_SERVER_NEWGRFS); + NetworkSend_uint8 (packet, in_reply_count); + for (i = 0; i < in_reply_count; i++) { + char name[NETWORK_GRF_NAME_LENGTH]; + + /* The name could be an empty string, if so take the filename */ + ttd_strlcpy(name, (in_reply[i]->name != NULL && strlen(in_reply[i]->name) > 0) ? + in_reply[i]->name : in_reply[i]->filename, sizeof(name)); + NetworkSend_GRFIdentifier(packet, in_reply[i]); + NetworkSend_string(packet, name); + } + + NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); + free(packet); +} + +/** The return of the client's request of the names of some NewGRFs */ +DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS) +{ + uint8 num_grfs; + uint i; + + /* Just a fail-safe.. should never happen */ + if (_udp_cs.has_quit) return; + + DEBUG(net, 6, "[udp] newgrf data reply from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port)); + + num_grfs = NetworkRecv_uint8 (&_udp_cs, p); + if (num_grfs > NETWORK_MAX_GRF_COUNT) return; + + for (i = 0; i < num_grfs; i++) { + char *unknown_name; + char name[NETWORK_GRF_NAME_LENGTH]; + GRFConfig c; + + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); + NetworkRecv_string(&_udp_cs, p, name, sizeof(name)); + + /* An empty name is not possible under normal circumstances + * and causes problems when showing the NewGRF list. */ + if (strlen(name) == 0) continue; + + /* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple. + * If it exists and not resolved yet, then name of the fake GRF is + * overwritten with the name from the reply. */ + unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); + if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { + ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH); + } + } +} + + +// The layout for the receive-functions by UDP +typedef void NetworkUDPPacket(Packet *p, struct sockaddr_in *client_addr); + +static NetworkUDPPacket* const _network_udp_packet[] = { + RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER), + RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE), + RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO), + NULL, + NULL, + RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER), + NULL, + RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST), + NULL, + RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS), + RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS), +}; + + +// If this fails, check the array above with network_data.h +assert_compile(lengthof(_network_udp_packet) == PACKET_UDP_END); + + +void NetworkHandleUDPPacket(Packet *p, struct sockaddr_in *client_addr) +{ + byte type; + + /* Fake a client, so we can see when there is an illegal packet */ + _udp_cs.socket = INVALID_SOCKET; + _udp_cs.has_quit = false; + + type = NetworkRecv_uint8(&_udp_cs, p); + + if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL && !_udp_cs.has_quit) { + _network_udp_packet[type](p, client_addr); + } else { + if (!_udp_cs.has_quit) { + DEBUG(net, 0, "[udp] received invalid packet type %d", type); + } else { + DEBUG(net, 0, "[udp] received illegal packet"); + } + } +} + + +// Close UDP connection +void NetworkUDPClose(void) +{ + DEBUG(net, 1, "[udp] closed listeners"); + + if (_network_udp_server) { + if (_udp_server_socket != INVALID_SOCKET) { + closesocket(_udp_server_socket); + _udp_server_socket = INVALID_SOCKET; + } + + if (_udp_master_socket != INVALID_SOCKET) { + closesocket(_udp_master_socket); + _udp_master_socket = INVALID_SOCKET; + } + + _network_udp_server = false; + _network_udp_broadcast = 0; + } else { + if (_udp_client_socket != INVALID_SOCKET) { + closesocket(_udp_client_socket); + _udp_client_socket = INVALID_SOCKET; + } + _network_udp_broadcast = 0; + } +} + +// Broadcast to all ips +static void NetworkUDPBroadCast(SOCKET udp) +{ + Packet* p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER); + uint i; + + for (i = 0; _broadcast_list[i] != 0; i++) { + struct sockaddr_in out_addr; + + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(_network_server_port); + out_addr.sin_addr.s_addr = _broadcast_list[i]; + + DEBUG(net, 4, "[udp] broadcasting to %s", inet_ntoa(out_addr.sin_addr)); + + NetworkSendUDP_Packet(udp, p, &out_addr); + } + + free(p); +} + + +// Request the the server-list from the master server +void NetworkUDPQueryMasterServer(void) +{ + struct sockaddr_in out_addr; + Packet *p; + + if (_udp_client_socket == INVALID_SOCKET) + if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) + return; + + p = NetworkSend_Init(PACKET_UDP_CLIENT_GET_LIST); + + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); + out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); + + // packet only contains protocol version + NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); + + NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr); + + DEBUG(net, 2, "[udp] master server queried at %s:%d", inet_ntoa(out_addr.sin_addr),ntohs(out_addr.sin_port)); + + free(p); +} + +// Find all servers +void NetworkUDPSearchGame(void) +{ + // We are still searching.. + if (_network_udp_broadcast > 0) return; + + // No UDP-socket yet.. + if (_udp_client_socket == INVALID_SOCKET) + if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) + return; + + DEBUG(net, 0, "[udp] searching server"); + + NetworkUDPBroadCast(_udp_client_socket); + _network_udp_broadcast = 300; // Stay searching for 300 ticks +} + +NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port) +{ + struct sockaddr_in out_addr; + Packet *p; + NetworkGameList *item; + + // No UDP-socket yet.. + if (_udp_client_socket == INVALID_SOCKET) + if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) + return NULL; + + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(port); + out_addr.sin_addr.s_addr = NetworkResolveHost(host); + + // Clear item in gamelist + item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port)); + memset(&item->info, 0, sizeof(item->info)); + ttd_strlcpy(item->info.server_name, host, lengthof(item->info.server_name)); + ttd_strlcpy(item->info.hostname, host, lengthof(item->info.hostname)); + item->online = false; + + // Init the packet + p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER); + + NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr); + + free(p); + + UpdateNetworkGameWindow(false); + return item; +} + +/* Remove our advertise from the master-server */ +void NetworkUDPRemoveAdvertise(void) +{ + struct sockaddr_in out_addr; + Packet *p; + + /* Check if we are advertising */ + if (!_networking || !_network_server || !_network_udp_server) return; + + /* check for socket */ + if (_udp_master_socket == INVALID_SOCKET) + if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false)) + return; + + DEBUG(net, 1, "[udp] removing advertise from master server"); + + /* Find somewhere to send */ + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); + out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); + + /* Send the packet */ + p = NetworkSend_Init(PACKET_UDP_SERVER_UNREGISTER); + /* Packet is: Version, server_port */ + NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); + NetworkSend_uint16(p, _network_server_port); + NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr); + + free(p); +} + +/* Register us to the master server + This function checks if it needs to send an advertise */ +void NetworkUDPAdvertise(void) +{ + struct sockaddr_in out_addr; + Packet *p; + + /* Check if we should send an advertise */ + if (!_networking || !_network_server || !_network_udp_server || !_network_advertise) + return; + + /* check for socket */ + if (_udp_master_socket == INVALID_SOCKET) + if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false)) + return; + + if (_network_need_advertise) { + _network_need_advertise = false; + _network_advertise_retries = ADVERTISE_RETRY_TIMES; + } else { + /* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */ + if (_network_advertise_retries == 0) { + if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter) + return; + _network_advertise_retries = ADVERTISE_RETRY_TIMES; + } + + if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter) + return; + } + + _network_advertise_retries--; + _network_last_advertise_frame = _frame_counter; + + /* Find somewhere to send */ + out_addr.sin_family = AF_INET; + out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); + out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); + + DEBUG(net, 1, "[udp] advertising to master server"); + + /* Send the packet */ + p = NetworkSend_Init(PACKET_UDP_SERVER_REGISTER); + /* Packet is: WELCOME_MESSAGE, Version, server_port */ + NetworkSend_string(p, NETWORK_MASTER_SERVER_WELCOME_MESSAGE); + NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); + NetworkSend_uint16(p, _network_server_port); + NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr); + + free(p); +} + +void NetworkUDPInitialize(void) +{ + _udp_client_socket = INVALID_SOCKET; + _udp_server_socket = INVALID_SOCKET; + _udp_master_socket = INVALID_SOCKET; + + _network_udp_server = false; + _network_udp_broadcast = 0; +} + +#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network/network_udp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/network/network_udp.h Wed Jan 03 08:32:17 2007 +0000 @@ -0,0 +1,17 @@ +/* $Id$ */ + +#ifndef NETWORK_UDP_H +#define NETWORK_UDP_H + +#ifdef ENABLE_NETWORK + +void NetworkUDPInitialize(void); +void NetworkUDPSearchGame(void); +void NetworkUDPQueryMasterServer(void); +NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port); +void NetworkUDPAdvertise(void); +void NetworkUDPRemoveAdvertise(void); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_UDP_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_client.c --- a/network_client.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,818 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "debug.h" -#include "string.h" -#include "strings.h" -#include "network_data.h" -#include "date.h" -#include "table/strings.h" -#include "functions.h" -#include "network_client.h" -#include "network_gamelist.h" -#include "network_gui.h" -#include "saveload.h" -#include "command.h" -#include "window.h" -#include "console.h" -#include "variables.h" -#include "ai/ai.h" - - -// This file handles all the client-commands - - -// So we don't make too much typos ;) -#define MY_CLIENT DEREF_CLIENT(0) - -static uint32 last_ack_frame; - -// ********** -// Sending functions -// DEF_CLIENT_SEND_COMMAND has no parameters -// ********** - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO) -{ - // - // Packet: CLIENT_COMPANY_INFO - // Function: Request company-info (in detail) - // Data: - // - // - Packet *p; - _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - - p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN) -{ - // - // Packet: CLIENT_JOIN - // Function: Try to join the server - // Data: - // String: OpenTTD Revision (norev000 if no revision) - // String: Player Name (max NETWORK_NAME_LENGTH) - // uint8: Play as Player id (1..MAX_PLAYERS) - // uint8: Language ID - // String: Unique id to find the player back in server-listing - // - - extern const char _openttd_revision[]; - Packet *p; - _network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING; - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - - p = NetworkSend_Init(PACKET_CLIENT_JOIN); - NetworkSend_string(p, _openttd_revision); - NetworkSend_string(p, _network_player_name); // Player name - NetworkSend_uint8(p, _network_playas); // PlayAs - NetworkSend_uint8(p, NETLANG_ANY); // Language - NetworkSend_string(p, _network_unique_id); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password) -{ - // - // Packet: CLIENT_PASSWORD - // Function: Send a password to the server to authorize - // Data: - // uint8: NetworkPasswordType - // String: Password - // - Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD); - NetworkSend_uint8(p, type); - NetworkSend_string(p, password); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GETMAP) -{ - // - // Packet: CLIENT_GETMAP - // Function: Request the map from the server - // Data: - // - // - - Packet *p = NetworkSend_Init(PACKET_CLIENT_GETMAP); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_MAP_OK) -{ - // - // Packet: CLIENT_MAP_OK - // Function: Tell the server that we are done receiving/loading the map - // Data: - // - // - - Packet *p = NetworkSend_Init(PACKET_CLIENT_MAP_OK); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK) -{ - // - // Packet: CLIENT_ACK - // Function: Tell the server we are done with this frame - // Data: - // uint32: current FrameCounter of the client - // - - Packet *p = NetworkSend_Init(PACKET_CLIENT_ACK); - - NetworkSend_uint32(p, _frame_counter); - NetworkSend_Packet(p, MY_CLIENT); -} - -// Send a command packet to the server -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp) -{ - // - // Packet: CLIENT_COMMAND - // Function: Send a DoCommand to the Server - // Data: - // uint8: PlayerID (0..MAX_PLAYERS-1) - // uint32: CommandID (see command.h) - // uint32: P1 (free variables used in DoCommand) - // uint32: P2 - // uint32: Tile - // string: text - // uint8: CallBackID (see callback_table.c) - // - - Packet *p = NetworkSend_Init(PACKET_CLIENT_COMMAND); - - NetworkSend_uint8(p, cp->player); - NetworkSend_uint32(p, cp->cmd); - NetworkSend_uint32(p, cp->p1); - NetworkSend_uint32(p, cp->p2); - NetworkSend_uint32(p, (uint32)cp->tile); - NetworkSend_string(p, cp->text); - NetworkSend_uint8(p, cp->callback); - - NetworkSend_Packet(p, MY_CLIENT); -} - -// Send a chat-packet over the network -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType type, int dest, const char *msg) -{ - // - // Packet: CLIENT_CHAT - // Function: Send a chat-packet to the serve - // Data: - // uint8: ActionID (see network_data.h, NetworkAction) - // uint8: Destination Type (see network_data.h, DestType); - // uint8: Destination Player (1..MAX_PLAYERS) - // String: Message (max MAX_TEXT_MSG_LEN) - // - - Packet *p = NetworkSend_Init(PACKET_CLIENT_CHAT); - - NetworkSend_uint8(p, action); - NetworkSend_uint8(p, type); - NetworkSend_uint8(p, dest); - NetworkSend_string(p, msg); - NetworkSend_Packet(p, MY_CLIENT); -} - -// Send an error-packet over the network -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno) -{ - // - // Packet: CLIENT_ERROR - // Function: The client made an error and is quiting the game - // Data: - // uint8: ErrorID (see network_data.h, NetworkErrorCode) - // - Packet *p = NetworkSend_Init(PACKET_CLIENT_ERROR); - - NetworkSend_uint8(p, errorno); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password) -{ - // - // Packet: PACKET_CLIENT_SET_PASSWORD - // Function: Set the password for the clients current company - // Data: - // String: Password - // - Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_PASSWORD); - - NetworkSend_string(p, password); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name) -{ - // - // Packet: PACKET_CLIENT_SET_NAME - // Function: Gives the player a new name - // Data: - // String: Name - // - Packet *p = NetworkSend_Init(PACKET_CLIENT_SET_NAME); - - NetworkSend_string(p, name); - NetworkSend_Packet(p, MY_CLIENT); -} - -// Send an quit-packet over the network -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg) -{ - // - // Packet: CLIENT_QUIT - // Function: The client is quiting the game - // Data: - // String: leave-message - // - Packet *p = NetworkSend_Init(PACKET_CLIENT_QUIT); - - NetworkSend_string(p, leavemsg); - NetworkSend_Packet(p, MY_CLIENT); -} - -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command) -{ - Packet *p = NetworkSend_Init(PACKET_CLIENT_RCON); - NetworkSend_string(p, pass); - NetworkSend_string(p, command); - NetworkSend_Packet(p, MY_CLIENT); -} - - -// ********** -// Receiving functions -// DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p -// ********** - -extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm); - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FULL) -{ - // We try to join a server which is full - _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL; - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - - return NETWORK_RECV_STATUS_SERVER_FULL; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_BANNED) -{ - // We try to join a server where we are banned - _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_BANNED; - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - - return NETWORK_RECV_STATUS_SERVER_BANNED; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO) -{ - byte company_info_version; - int i; - - company_info_version = NetworkRecv_uint8(MY_CLIENT, p); - - if (!MY_CLIENT->has_quit && company_info_version == NETWORK_COMPANY_INFO_VERSION) { - byte total; - byte current; - - total = NetworkRecv_uint8(MY_CLIENT, p); - - // There is no data at all.. - if (total == 0) return NETWORK_RECV_STATUS_CLOSE_QUERY; - - current = NetworkRecv_uint8(MY_CLIENT, p); - if (!IsValidPlayer(current)) return NETWORK_RECV_STATUS_CLOSE_QUERY; - - NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name)); - _network_player_info[current].inaugurated_year = NetworkRecv_uint32(MY_CLIENT, p); - _network_player_info[current].company_value = NetworkRecv_uint64(MY_CLIENT, p); - _network_player_info[current].money = NetworkRecv_uint64(MY_CLIENT, p); - _network_player_info[current].income = NetworkRecv_uint64(MY_CLIENT, p); - _network_player_info[current].performance = NetworkRecv_uint16(MY_CLIENT, p); - _network_player_info[current].use_password = NetworkRecv_uint8(MY_CLIENT, p); - for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) - _network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(MY_CLIENT, p); - for (i = 0; i < NETWORK_STATION_TYPES; i++) - _network_player_info[current].num_station[i] = NetworkRecv_uint16(MY_CLIENT, p); - - NetworkRecv_string(MY_CLIENT, p, _network_player_info[current].players, sizeof(_network_player_info[current].players)); - - InvalidateWindow(WC_NETWORK_WINDOW, 0); - - return NETWORK_RECV_STATUS_OKAY; - } - - return NETWORK_RECV_STATUS_CLOSE_QUERY; -} - -// This packet contains info about the client (playas and name) -// as client we save this in NetworkClientInfo, linked via 'index' -// which is always an unique number on a server. -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) -{ - NetworkClientInfo *ci; - uint16 index = NetworkRecv_uint16(MY_CLIENT, p); - PlayerID playas = NetworkRecv_uint8(MY_CLIENT, p); - char name[NETWORK_NAME_LENGTH]; - char unique_id[NETWORK_NAME_LENGTH]; - - NetworkRecv_string(MY_CLIENT, p, name, sizeof(name)); - NetworkRecv_string(MY_CLIENT, p, unique_id, sizeof(unique_id)); - - if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST; - - /* Do we receive a change of data? Most likely we changed playas */ - if (index == _network_own_client_index) _network_playas = playas; - - ci = NetworkFindClientInfoFromIndex(index); - if (ci != NULL) { - if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) { - // Client name changed, display the change - NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", name); - } else if (playas != ci->client_playas) { - // The player changed from client-player.. - // Do not display that for now - } - - ci->client_playas = playas; - ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); - - InvalidateWindow(WC_CLIENT_LIST, 0); - - return NETWORK_RECV_STATUS_OKAY; - } - - // We don't have this index yet, find an empty index, and put the data there - ci = NetworkFindClientInfoFromIndex(NETWORK_EMPTY_INDEX); - if (ci != NULL) { - ci->client_index = index; - ci->client_playas = playas; - - ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); - ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id)); - - InvalidateWindow(WC_CLIENT_LIST, 0); - - return NETWORK_RECV_STATUS_OKAY; - } - - // Here the program should never ever come..... - return NETWORK_RECV_STATUS_MALFORMED_PACKET; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) -{ - NetworkErrorCode error = NetworkRecv_uint8(MY_CLIENT, p); - - switch (error) { - /* We made an error in the protocol, and our connection is closed.... */ - case NETWORK_ERROR_NOT_AUTHORIZED: - case NETWORK_ERROR_NOT_EXPECTED: - case NETWORK_ERROR_PLAYER_MISMATCH: - _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR; - break; - case NETWORK_ERROR_FULL: - _switch_mode_errorstr = STR_NETWORK_ERR_SERVER_FULL; - break; - case NETWORK_ERROR_WRONG_REVISION: - _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION; - break; - case NETWORK_ERROR_WRONG_PASSWORD: - _switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD; - break; - case NETWORK_ERROR_KICKED: - _switch_mode_errorstr = STR_NETWORK_ERR_KICKED; - break; - case NETWORK_ERROR_CHEATER: - _switch_mode_errorstr = STR_NETWORK_ERR_CHEATER; - break; - default: - _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; - } - - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - - return NETWORK_RECV_STATUS_SERVER_ERROR; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD) -{ - NetworkPasswordType type = NetworkRecv_uint8(MY_CLIENT, p); - - switch (type) { - case NETWORK_GAME_PASSWORD: - case NETWORK_COMPANY_PASSWORD: - ShowNetworkNeedPassword(type); - return NETWORK_RECV_STATUS_OKAY; - - default: return NETWORK_RECV_STATUS_MALFORMED_PACKET; - } -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME) -{ - _network_own_client_index = NetworkRecv_uint16(MY_CLIENT, p); - - // Start receiving the map - SEND_COMMAND(PACKET_CLIENT_GETMAP)(); - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT) -{ - _network_join_status = NETWORK_JOIN_STATUS_WAITING; - _network_join_waiting = NetworkRecv_uint8(MY_CLIENT, p); - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - - // We are put on hold for receiving the map.. we need GUI for this ;) - DEBUG(net, 1, "The server is currently busy sending the map to someone else, please wait..." ); - DEBUG(net, 1, "There are %d clients in front of you", _network_join_waiting); - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) -{ - static char filename[256]; - static FILE *file_pointer; - - byte maptype; - - maptype = NetworkRecv_uint8(MY_CLIENT, p); - - if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST; - - // First packet, init some stuff - if (maptype == MAP_PACKET_START) { - // The name for the temp-map - snprintf(filename, lengthof(filename), "%s%snetwork_client.tmp", _paths.autosave_dir, PATHSEP); - - file_pointer = fopen(filename, "wb"); - if (file_pointer == NULL) { - _switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR; - return NETWORK_RECV_STATUS_SAVEGAME; - } - - _frame_counter = _frame_counter_server = _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p); - - _network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING; - _network_join_kbytes = 0; - _network_join_kbytes_total = NetworkRecv_uint32(MY_CLIENT, p) / 1024; - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - - // The first packet does not contain any more data - return NETWORK_RECV_STATUS_OKAY; - } - - if (maptype == MAP_PACKET_NORMAL) { - // We are still receiving data, put it to the file - fwrite(p->buffer + p->pos, 1, p->size - p->pos, file_pointer); - - _network_join_kbytes = ftell(file_pointer) / 1024; - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - } - - // Check if this was the last packet - if (maptype == MAP_PACKET_END) { - fclose(file_pointer); - - _network_join_status = NETWORK_JOIN_STATUS_PROCESSING; - InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0); - - /* The map is done downloading, load it */ - if (!SafeSaveOrLoad(filename, SL_LOAD, GM_NORMAL)) { - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - _switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR; - return NETWORK_RECV_STATUS_SAVEGAME; - } - /* If the savegame has successfully loaded, ALL windows have been removed, - * only toolbar/statusbar and gamefield are visible */ - - _opt_ptr = &_opt; // during a network game you are always in-game - - // Say we received the map and loaded it correctly! - SEND_COMMAND(PACKET_CLIENT_MAP_OK)(); - - /* New company/spectator (invalid player) or company we want to join is not active - * Switch local player to spectator and await the server's judgement */ - if (_network_playas == PLAYER_NEW_COMPANY || !IsValidPlayer(_network_playas) || - !GetPlayer(_network_playas)->is_active) { - - SetLocalPlayer(PLAYER_SPECTATOR); - - if (_network_playas != PLAYER_SPECTATOR) { - /* We have arrived and ready to start playing; send a command to make a new player; - * the server will give us a client-id and let us in */ - _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; - ShowJoinStatusWindow(); - NetworkSend_Command(0, 0, 0, CMD_PLAYER_CTRL, NULL); - } - } else { - // take control over an existing company - SetLocalPlayer(_network_playas); - } - } - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME) -{ - _frame_counter_server = NetworkRecv_uint32(MY_CLIENT, p); - _frame_counter_max = NetworkRecv_uint32(MY_CLIENT, p); -#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME - // Test if the server supports this option - // and if we are at the frame the server is - if (p->pos < p->size) { - _sync_frame = _frame_counter_server; - _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p); -#ifdef NETWORK_SEND_DOUBLE_SEED - _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p); -#endif - } -#endif - DEBUG(net, 5, "Received FRAME %d", _frame_counter_server); - - // Let the server know that we received this frame correctly - // We do this only once per day, to save some bandwidth ;) - if (!_network_first_time && last_ack_frame < _frame_counter) { - last_ack_frame = _frame_counter + DAY_TICKS; - DEBUG(net, 4, "Sent ACK at %d", _frame_counter); - SEND_COMMAND(PACKET_CLIENT_ACK)(); - } - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SYNC) -{ - _sync_frame = NetworkRecv_uint32(MY_CLIENT, p); - _sync_seed_1 = NetworkRecv_uint32(MY_CLIENT, p); -#ifdef NETWORK_SEND_DOUBLE_SEED - _sync_seed_2 = NetworkRecv_uint32(MY_CLIENT, p); -#endif - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND) -{ - CommandPacket *cp = malloc(sizeof(CommandPacket)); - cp->player = NetworkRecv_uint8(MY_CLIENT, p); - cp->cmd = NetworkRecv_uint32(MY_CLIENT, p); - cp->p1 = NetworkRecv_uint32(MY_CLIENT, p); - cp->p2 = NetworkRecv_uint32(MY_CLIENT, p); - cp->tile = NetworkRecv_uint32(MY_CLIENT, p); - NetworkRecv_string(MY_CLIENT, p, cp->text, sizeof(cp->text)); - cp->callback = NetworkRecv_uint8(MY_CLIENT, p); - cp->frame = NetworkRecv_uint32(MY_CLIENT, p); - cp->next = NULL; - - // The server did send us this command.. - // queue it in our own queue, so we can handle it in the upcoming frame! - - if (_local_command_queue == NULL) { - _local_command_queue = cp; - } else { - // Find last packet - CommandPacket *c = _local_command_queue; - while (c->next != NULL) c = c->next; - c->next = cp; - } - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT) -{ - char name[NETWORK_NAME_LENGTH], msg[MAX_TEXT_MSG_LEN]; - const NetworkClientInfo *ci = NULL, *ci_to; - - NetworkAction action = NetworkRecv_uint8(MY_CLIENT, p); - uint16 index = NetworkRecv_uint16(MY_CLIENT, p); - bool self_send = NetworkRecv_uint8(MY_CLIENT, p); - NetworkRecv_string(MY_CLIENT, p, msg, MAX_TEXT_MSG_LEN); - - ci_to = NetworkFindClientInfoFromIndex(index); - if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY; - - /* Did we initiate the action locally? */ - if (self_send) { - switch (action) { - case NETWORK_ACTION_CHAT_CLIENT: - /* For speaking to client we need the client-name */ - snprintf(name, sizeof(name), "%s", ci_to->client_name); - ci = NetworkFindClientInfoFromIndex(_network_own_client_index); - break; - - /* For speaking to company or giving money, we need the player-name */ - case NETWORK_ACTION_GIVE_MONEY: - if (!IsValidPlayer(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY; - /* fallthrough */ - case NETWORK_ACTION_CHAT_COMPANY: { - StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS; - - GetString(name, str, lastof(name)); - ci = NetworkFindClientInfoFromIndex(_network_own_client_index); - } break; - - default: NOT_REACHED(); break; - } - } else { - /* Display message from somebody else */ - snprintf(name, sizeof(name), "%s", ci_to->client_name); - ci = ci_to; - } - - if (ci != NULL) - NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), self_send, name, "%s", msg); - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT) -{ - char str[100]; - uint16 index; - NetworkClientInfo *ci; - - index = NetworkRecv_uint16(MY_CLIENT, p); - GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p), lastof(str)); - - ci = NetworkFindClientInfoFromIndex(index); - if (ci != NULL) { - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str); - - // The client is gone, give the NetworkClientInfo free - ci->client_index = NETWORK_EMPTY_INDEX; - } - - InvalidateWindow(WC_CLIENT_LIST, 0); - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT) -{ - char str[100]; - uint16 index; - NetworkClientInfo *ci; - - index = NetworkRecv_uint16(MY_CLIENT, p); - NetworkRecv_string(MY_CLIENT, p, str, lengthof(str)); - - ci = NetworkFindClientInfoFromIndex(index); - if (ci != NULL) { - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, ci->client_name, "%s", str); - - // The client is gone, give the NetworkClientInfo free - ci->client_index = NETWORK_EMPTY_INDEX; - } else { - DEBUG(net, 0, "Unknown client (%d) is leaving the game", index); - } - - InvalidateWindow(WC_CLIENT_LIST, 0); - - // If we come here it means we could not locate the client.. strange :s - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN) -{ - uint16 index; - NetworkClientInfo *ci; - - index = NetworkRecv_uint16(MY_CLIENT, p); - - ci = NetworkFindClientInfoFromIndex(index); - if (ci != NULL) - NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, ci->client_name, ""); - - InvalidateWindow(WC_CLIENT_LIST, 0); - - return NETWORK_RECV_STATUS_OKAY; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN) -{ - _switch_mode_errorstr = STR_NETWORK_SERVER_SHUTDOWN; - - return NETWORK_RECV_STATUS_SERVER_ERROR; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEWGAME) -{ - // To trottle the reconnects a bit, every clients waits - // his _local_player value before reconnecting - // PLAYER_SPECTATOR is currently 255, so to avoid long wait periods - // set the max to 10. - _network_reconnect = min(_local_player + 1, 10); - _switch_mode_errorstr = STR_NETWORK_SERVER_REBOOT; - - return NETWORK_RECV_STATUS_SERVER_ERROR; -} - -DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_RCON) -{ - char rcon_out[NETWORK_RCONCOMMAND_LENGTH]; - uint16 color_code; - - color_code = NetworkRecv_uint16(MY_CLIENT, p); - NetworkRecv_string(MY_CLIENT, p, rcon_out, sizeof(rcon_out)); - - IConsolePrint(color_code, rcon_out); - - return NETWORK_RECV_STATUS_OKAY; -} - - - -// The layout for the receive-functions by the client -typedef NetworkRecvStatus NetworkClientPacket(Packet *p); - -// This array matches PacketType. At an incoming -// packet it is matches against this array -// and that way the right function to handle that -// packet is found. -static NetworkClientPacket* const _network_client_packet[] = { - RECEIVE_COMMAND(PACKET_SERVER_FULL), - RECEIVE_COMMAND(PACKET_SERVER_BANNED), - NULL, /*PACKET_CLIENT_JOIN,*/ - RECEIVE_COMMAND(PACKET_SERVER_ERROR), - NULL, /*PACKET_CLIENT_COMPANY_INFO,*/ - RECEIVE_COMMAND(PACKET_SERVER_COMPANY_INFO), - RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO), - RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD), - NULL, /*PACKET_CLIENT_PASSWORD,*/ - RECEIVE_COMMAND(PACKET_SERVER_WELCOME), - NULL, /*PACKET_CLIENT_GETMAP,*/ - RECEIVE_COMMAND(PACKET_SERVER_WAIT), - RECEIVE_COMMAND(PACKET_SERVER_MAP), - NULL, /*PACKET_CLIENT_MAP_OK,*/ - RECEIVE_COMMAND(PACKET_SERVER_JOIN), - RECEIVE_COMMAND(PACKET_SERVER_FRAME), - RECEIVE_COMMAND(PACKET_SERVER_SYNC), - NULL, /*PACKET_CLIENT_ACK,*/ - NULL, /*PACKET_CLIENT_COMMAND,*/ - RECEIVE_COMMAND(PACKET_SERVER_COMMAND), - NULL, /*PACKET_CLIENT_CHAT,*/ - RECEIVE_COMMAND(PACKET_SERVER_CHAT), - NULL, /*PACKET_CLIENT_SET_PASSWORD,*/ - NULL, /*PACKET_CLIENT_SET_NAME,*/ - NULL, /*PACKET_CLIENT_QUIT,*/ - NULL, /*PACKET_CLIENT_ERROR,*/ - RECEIVE_COMMAND(PACKET_SERVER_QUIT), - RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT), - RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN), - RECEIVE_COMMAND(PACKET_SERVER_NEWGAME), - RECEIVE_COMMAND(PACKET_SERVER_RCON), - NULL, /*PACKET_CLIENT_RCON,*/ -}; - -// If this fails, check the array above with network_data.h -assert_compile(lengthof(_network_client_packet) == PACKET_END); - -// Is called after a client is connected to the server -void NetworkClient_Connected(void) -{ - // Set the frame-counter to 0 so nothing happens till we are ready - _frame_counter = 0; - _frame_counter_server = 0; - last_ack_frame = 0; - // Request the game-info - SEND_COMMAND(PACKET_CLIENT_JOIN)(); -} - -// Reads the packets from the socket-stream, if available -NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs) -{ - Packet *p; - NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY; - - while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) { - byte type = NetworkRecv_uint8(MY_CLIENT, p); - if (type < PACKET_END && _network_client_packet[type] != NULL && !MY_CLIENT->has_quit) { - res = _network_client_packet[type](p); - } else { - res = NETWORK_RECV_STATUS_MALFORMED_PACKET; - DEBUG(net, 0, "[client] received invalid packet type %d", type); - } - - free(p); - } - - return res; -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_client.h --- a/network_client.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_CLIENT_H -#define NETWORK_CLIENT_H - -#ifdef ENABLE_NETWORK - -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GAME_INFO); -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType desttype, int dest, const char *msg); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name); -DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK); -DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command); - -NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs); -void NetworkClient_Connected(void); - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_CLIENT_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_core.h --- a/network_core.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,184 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_CORE_H -#define NETWORK_CORE_H - -// Network stuff has many things that needs to be included -// by default. All those things are in this file. - -// ============================= -// Include standard stuff per OS - -#ifdef ENABLE_NETWORK - -#if defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_2) - // OSX 10.2 don't have socklen_t defined, so we will define it here - typedef int socklen_t; -#endif - -// Windows stuff -#if defined(WIN32) || defined(WIN64) -#include -#include -#include - -#if !(defined(__MINGW32__) || defined(__CYGWIN__)) - // Windows has some different names for some types.. - typedef SSIZE_T ssize_t; - typedef int socklen_t; -#endif - -#define GET_LAST_ERROR() WSAGetLastError() -#define EWOULDBLOCK WSAEWOULDBLOCK -// Windows has some different names for some types.. -typedef unsigned long in_addr_t; -#endif // WIN32 - -// UNIX stuff -#if defined(UNIX) -# define SOCKET int -# define INVALID_SOCKET -1 -# if !defined(__MORPHOS__) && !defined(__AMIGA__) -# define ioctlsocket ioctl -# if !defined(BEOS_NET_SERVER) -# define closesocket close -# endif -# define GET_LAST_ERROR() (errno) -# endif -// Need this for FIONREAD on solaris -# define BSD_COMP - -// Includes needed for UNIX-like systems -# include -# include -# if defined(__BEOS__) && defined(BEOS_NET_SERVER) -# include -# include // snooze() -# include - typedef unsigned long in_addr_t; -# define INADDR_NONE INADDR_BROADCAST -# else -# include -# include -# include -# include -# include -// According to glibc/NEWS, appeared in glibc-2.3. -# if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__INNOTEK_LIBC__) \ - && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) -// If for any reason ifaddrs.h does not exist on your system, comment out -// the following two lines and an alternative way will be used to fetch -// the list of IPs from the system. -# include -# define HAVE_GETIFADDRS -# endif -# if defined(SUNOS) || defined(__MORPHOS__) || defined(__BEOS__) -# define INADDR_NONE 0xffffffff -# endif -# if defined(__BEOS__) && !defined(BEOS_NET_SERVER) - // needed on Zeta -# include -# endif -# endif // BEOS_NET_SERVER - -# if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) - typedef uint32_t in_addr_t; -# endif - -# include -# include -# include -#endif // UNIX - -#ifdef __BEOS__ - typedef int socklen_t; -#endif - -// OS/2 stuff -#if defined(__OS2__) -# define SOCKET int -# define INVALID_SOCKET -1 -# define ioctlsocket ioctl -# define closesocket close -# define GET_LAST_ERROR() (sock_errno()) - -// Includes needed for OS/2 systems -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# define INADDR_NONE 0xffffffff - -typedef int socklen_t; -#if !defined(__INNOTEK_LIBC__) -typedef unsigned long in_addr_t; -#endif /* __INNOTEK_LIBC__ */ -#endif // OS/2 - -// MorphOS and Amiga stuff -#if defined(__MORPHOS__) || defined(__AMIGA__) -# include -# include // required for Open/CloseLibrary() -# if defined(__MORPHOS__) -# include // FIO* defines -# include // SIO* defines -# include -# else // __AMIGA__ -# include -# endif - -// Make the names compatible -# define closesocket(s) CloseSocket(s) -# define GET_LAST_ERROR() Errno() -# define ioctlsocket(s,request,status) IoctlSocket((LONG)s,(ULONG)request,(char*)status) -# define ioctl ioctlsocket - - typedef unsigned int in_addr_t; - typedef long socklen_t; - extern struct Library *SocketBase; - -# ifdef __AMIGA__ - // for usleep() implementation - extern struct Device *TimerBase; - extern struct MsgPort *TimerPort; - extern struct timerequest *TimerRequest; -# endif -#endif // __MORPHOS__ || __AMIGA__ - -static inline bool SetNonBlocking(int d) -{ - #ifdef WIN32 - u_long nonblocking = 1; - #else - int nonblocking = 1; - #endif - #if defined(__BEOS__) && defined(BEOS_NET_SERVER) - return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0; - #else - return ioctlsocket(d, FIONBIO, &nonblocking) == 0; - #endif -} - -static inline bool SetNoDelay(int d) -{ - // XXX should this be done at all? - #if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server - int b = 1; - // The (const char*) cast is needed for windows - return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; - #else - return true; - #endif -} - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_CORE_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_data.c --- a/network_data.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,473 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "debug.h" -#include "network_data.h" -#include "functions.h" -#include "string.h" -#include "table/strings.h" -#include "network_client.h" -#include "command.h" -#include "callback_table.h" -#include "variables.h" - -// This files handles the send/receive of all packets - -// Create a packet for sending -Packet *NetworkSend_Init(PacketType type) -{ - Packet *packet = malloc(sizeof(Packet)); - // An error is inplace here, because it simply means we ran out of memory. - if (packet == NULL) error("Failed to allocate Packet"); - - // Skip the size so we can write that in before sending the packet - packet->size = sizeof(packet->size); - packet->buffer[packet->size++] = type; - packet->pos = 0; - - return packet; -} - -// The next couple of functions make sure we can send -// uint8, uint16, uint32 and uint64 endian-safe -// over the network. The order it uses is: -// -// 1 2 3 4 -// - -void NetworkSend_uint8(Packet *packet, uint8 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = data; -} - -void NetworkSend_uint16(Packet *packet, uint16 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); -} - -void NetworkSend_uint32(Packet *packet, uint32 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); - packet->buffer[packet->size++] = GB(data, 16, 8); - packet->buffer[packet->size++] = GB(data, 24, 8); -} - -void NetworkSend_uint64(Packet *packet, uint64 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); - packet->buffer[packet->size++] = GB(data, 16, 8); - packet->buffer[packet->size++] = GB(data, 24, 8); - packet->buffer[packet->size++] = GB(data, 32, 8); - packet->buffer[packet->size++] = GB(data, 40, 8); - packet->buffer[packet->size++] = GB(data, 48, 8); - packet->buffer[packet->size++] = GB(data, 56, 8); -} - -// Sends a string over the network. It sends out -// the string + '\0'. No size-byte or something. -void NetworkSend_string(Packet *packet, const char* data) -{ - assert(data != NULL); - assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1); - while ((packet->buffer[packet->size++] = *data++) != '\0') {} -} - -// If PacketSize changes of size, you have to change the 2 packet->size -// lines below matching the size of packet->size/PacketSize! -// (line 'packet->buffer[0] = packet->size & 0xFF;' and below) -assert_compile(sizeof(PacketSize) == 2); - -// This function puts the packet in the send-queue and it is send -// as soon as possible -// (that is: the next tick, or maybe one tick later if the -// OS-network-buffer is full) -void NetworkSend_Packet(Packet *packet, NetworkClientState *cs) -{ - Packet *p; - assert(packet != NULL); - - packet->pos = 0; - packet->next = NULL; - - packet->buffer[0] = GB(packet->size, 0, 8); - packet->buffer[1] = GB(packet->size, 8, 8); - - // Locate last packet buffered for the client - p = cs->packet_queue; - if (p == NULL) { - // No packets yet - cs->packet_queue = packet; - } else { - // Skip to the last packet - while (p->next != NULL) p = p->next; - p->next = packet; - } -} - -// Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit -// A socket can make errors. When that happens -// this handles what to do. -// For clients: close connection and drop back to main-menu -// For servers: close connection and that is it -static NetworkRecvStatus CloseConnection(NetworkClientState *cs) -{ - NetworkCloseClient(cs); - - // Clients drop back to the main menu - if (!_network_server && _networking) { - _switch_mode = SM_MENU; - _networking = false; - _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; - - return NETWORK_RECV_STATUS_CONN_LOST; - } - - return NETWORK_RECV_STATUS_OKAY; -} - -// Sends all the buffered packets out for this client -// it stops when: -// 1) all packets are send (queue is empty) -// 2) the OS reports back that it can not send any more -// data right now (full network-buffer, it happens ;)) -// 3) sending took too long -bool NetworkSend_Packets(NetworkClientState *cs) -{ - ssize_t res; - Packet *p; - - // We can not write to this socket!! - if (!cs->writable) return false; - if (cs->socket == INVALID_SOCKET) return false; - - p = cs->packet_queue; - while (p != NULL) { - res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { // Something went wrong.. close client! - DEBUG(net, 0, "send failed with error %d", err); - CloseConnection(cs); - return false; - } - return true; - } - if (res == 0) { - // Client/server has left us :( - CloseConnection(cs); - return false; - } - - p->pos += res; - - // Is this packet sent? - if (p->pos == p->size) { - // Go to the next packet - cs->packet_queue = p->next; - free(p); - p = cs->packet_queue; - } else { - return true; - } - } - - return true; -} - - -// Receiving commands -// Again, the next couple of functions are endian-safe -// see the comment around NetworkSend_uint8 for more info. -uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet) -{ - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 1 > packet->size) { - CloseConnection(cs); - return 0; - } - - return packet->buffer[packet->pos++]; -} - -uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet) -{ - uint16 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 2 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint16)packet->buffer[packet->pos++]; - n += (uint16)packet->buffer[packet->pos++] << 8; - return n; -} - -uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet) -{ - uint32 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 4 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint32)packet->buffer[packet->pos++]; - n += (uint32)packet->buffer[packet->pos++] << 8; - n += (uint32)packet->buffer[packet->pos++] << 16; - n += (uint32)packet->buffer[packet->pos++] << 24; - return n; -} - -uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet) -{ - uint64 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 8 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint64)packet->buffer[packet->pos++]; - n += (uint64)packet->buffer[packet->pos++] << 8; - n += (uint64)packet->buffer[packet->pos++] << 16; - n += (uint64)packet->buffer[packet->pos++] << 24; - n += (uint64)packet->buffer[packet->pos++] << 32; - n += (uint64)packet->buffer[packet->pos++] << 40; - n += (uint64)packet->buffer[packet->pos++] << 48; - n += (uint64)packet->buffer[packet->pos++] << 56; - return n; -} - -// Reads a string till it finds a '\0' in the stream -void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size) -{ - PacketSize pos; - char *bufp = buffer; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return; - - pos = p->pos; - while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {} - - if (size == 0 || pos == p->size) { - *buffer = '\0'; - // If size was sooner to zero then the string in the stream - // skip till the \0, so the packet can be read out correctly for the rest - while (pos < p->size && p->buffer[pos] != '\0') pos++; - pos++; - } - p->pos = pos; - - str_validate(bufp); -} - -// If PacketSize changes of size, you have to change the 2 packet->size -// lines below matching the size of packet->size/PacketSize! -// (the line: 'p->size = (uint16)p->buffer[0];' and below) -assert_compile(sizeof(PacketSize) == 2); - -Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status) -{ - ssize_t res; - Packet *p; - - *status = NETWORK_RECV_STATUS_OKAY; - - if (cs->socket == INVALID_SOCKET) return NULL; - - if (cs->packet_recv == NULL) { - cs->packet_recv = malloc(sizeof(Packet)); - if (cs->packet_recv == NULL) error("Failed to allocate packet"); - // Set pos to zero! - cs->packet_recv->pos = 0; - cs->packet_recv->size = 0; // Can be ommited, just for safety reasons - } - - p = cs->packet_recv; - - // Read packet size - if (p->pos < sizeof(PacketSize)) { - while (p->pos < sizeof(PacketSize)) { - // Read the size of the packet - res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); - *status = CloseConnection(cs); - return NULL; - } - // Connection would block, so stop for now - return NULL; - } - if (res == 0) { - // Client/server has left - *status = CloseConnection(cs); - return NULL; - } - p->pos += res; - } - - p->size = (uint16)p->buffer[0]; - p->size += (uint16)p->buffer[1] << 8; - - if (p->size > SEND_MTU) { - *status = CloseConnection(cs); - return NULL; - } - } - - // Read rest of packet - while (p->pos < p->size) { - res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); - *status = CloseConnection(cs); - return NULL; - } - // Connection would block - return NULL; - } - if (res == 0) { - // Client/server has left - *status = CloseConnection(cs); - return NULL; - } - - p->pos += res; - } - - // We have a complete packet, return it! - p->pos = 2; - p->next = NULL; // Should not be needed, but who knows... - - // Prepare for receiving a new packet - cs->packet_recv = NULL; - - return p; -} - -// Add a command to the local command queue -void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp) -{ - CommandPacket* new_cp = malloc(sizeof(*new_cp)); - - *new_cp = *cp; - - if (cs->command_queue == NULL) { - cs->command_queue = new_cp; - } else { - CommandPacket *c = cs->command_queue; - while (c->next != NULL) c = c->next; - c->next = new_cp; - } -} - -// Prepare a DoCommand to be send over the network -void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) -{ - CommandPacket *c = malloc(sizeof(CommandPacket)); - byte temp_callback; - - c->player = _local_player; - c->next = NULL; - c->tile = tile; - c->p1 = p1; - c->p2 = p2; - c->cmd = cmd; - c->callback = 0; - - temp_callback = 0; - - while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback) - temp_callback++; - if (temp_callback == _callback_table_count) { - DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback); - temp_callback = 0; /* _callback_table[0] == NULL */ - } - - if (_network_server) { - // We are the server, so set the command to be executed next possible frame - c->frame = _frame_counter_max + 1; - } else { - c->frame = 0; // The client can't tell which frame, so just make it 0 - } - - ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text)); - - if (_network_server) { - // If we are the server, we queue the command in our 'special' queue. - // In theory, we could execute the command right away, but then the - // client on the server can do everything 1 tick faster than others. - // So to keep the game fair, we delay the command with 1 tick - // which gives about the same speed as most clients. - NetworkClientState *cs; - - // And we queue it for delivery to the clients - FOR_ALL_CLIENTS(cs) { - if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c); - } - - // Only the server gets the callback, because clients should not get them - c->callback = temp_callback; - if (_local_command_queue == NULL) { - _local_command_queue = c; - } else { - // Find last packet - CommandPacket *cp = _local_command_queue; - while (cp->next != NULL) cp = cp->next; - cp->next = c; - } - - return; - } - - // Clients send their command to the server and forget all about the packet - c->callback = temp_callback; - SEND_COMMAND(PACKET_CLIENT_COMMAND)(c); -} - -// Execute a DoCommand we received from the network -void NetworkExecuteCommand(CommandPacket *cp) -{ - _current_player = cp->player; - _cmd_text = cp->text; - /* cp->callback is unsigned. so we don't need to do lower bounds checking. */ - if (cp->callback > _callback_table_count) { - DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback); - cp->callback = 0; - } - DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND); -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_data.h --- a/network_data.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_DATA_H -#define NETWORK_DATA_H - -#include "openttd.h" -#include "network.h" -#include "network_core.h" - -// Is the network enabled? -#ifdef ENABLE_NETWORK - -#define SEND_MTU 1460 -#define MAX_TEXT_MSG_LEN 1024 /* long long long long sentences :-) */ - -// The client-info-server-index is always 1 -#define NETWORK_SERVER_INDEX 1 -#define NETWORK_EMPTY_INDEX 0 - -// What version of game-info do we use? -#define NETWORK_GAME_INFO_VERSION 4 -// What version of company info is this? -#define NETWORK_COMPANY_INFO_VERSION 4 -// What version of master-server-protocol do we use? -#define NETWORK_MASTER_SERVER_VERSION 1 - -typedef uint16 PacketSize; - -typedef struct Packet { - struct Packet *next; - PacketSize size; - PacketSize pos; - byte buffer[SEND_MTU]; -} Packet; - -typedef struct CommandPacket { - struct CommandPacket *next; - PlayerID player; /// player that is executing the command - uint32 cmd; /// command being executed - uint32 p1; /// parameter p1 - uint32 p2; /// parameter p2 - TileIndex tile; /// tile command being executed on - char text[80]; - uint32 frame; /// the frame in which this packet is executed - byte callback; /// any callback function executed upon successful completion of the command -} CommandPacket; - -typedef enum { - STATUS_INACTIVE, - STATUS_AUTH, // This means that the client is authorized - STATUS_MAP_WAIT, // This means that the client is put on hold because someone else is getting the map - STATUS_MAP, - STATUS_DONE_MAP, - STATUS_PRE_ACTIVE, - STATUS_ACTIVE, -} ClientStatus; - -typedef enum { - MAP_PACKET_START, - MAP_PACKET_NORMAL, - MAP_PACKET_END, -} MapPacket; - -typedef enum { - NETWORK_RECV_STATUS_OKAY, - NETWORK_RECV_STATUS_DESYNC, - NETWORK_RECV_STATUS_SAVEGAME, - NETWORK_RECV_STATUS_CONN_LOST, - NETWORK_RECV_STATUS_MALFORMED_PACKET, - NETWORK_RECV_STATUS_SERVER_ERROR, // The server told us we made an error - NETWORK_RECV_STATUS_SERVER_FULL, - NETWORK_RECV_STATUS_SERVER_BANNED, - NETWORK_RECV_STATUS_CLOSE_QUERY, // Done quering the server -} NetworkRecvStatus; - -typedef enum { - NETWORK_ERROR_GENERAL, // Try to use thisone like never - - // Signals from clients - NETWORK_ERROR_DESYNC, - NETWORK_ERROR_SAVEGAME_FAILED, - NETWORK_ERROR_CONNECTION_LOST, - NETWORK_ERROR_ILLEGAL_PACKET, - - // Signals from servers - NETWORK_ERROR_NOT_AUTHORIZED, - NETWORK_ERROR_NOT_EXPECTED, - NETWORK_ERROR_WRONG_REVISION, - NETWORK_ERROR_NAME_IN_USE, - NETWORK_ERROR_WRONG_PASSWORD, - NETWORK_ERROR_PLAYER_MISMATCH, // Happens in CLIENT_COMMAND - NETWORK_ERROR_KICKED, - NETWORK_ERROR_CHEATER, - NETWORK_ERROR_FULL, -} NetworkErrorCode; - -// Actions that can be used for NetworkTextMessage -typedef enum { - NETWORK_ACTION_JOIN, - NETWORK_ACTION_LEAVE, - NETWORK_ACTION_SERVER_MESSAGE, - NETWORK_ACTION_CHAT, - NETWORK_ACTION_CHAT_COMPANY, - NETWORK_ACTION_CHAT_CLIENT, - NETWORK_ACTION_GIVE_MONEY, - NETWORK_ACTION_NAME_CHANGE, -} NetworkAction; - -typedef enum { - NETWORK_GAME_PASSWORD, - NETWORK_COMPANY_PASSWORD, -} NetworkPasswordType; - -// To keep the clients all together -typedef struct NetworkClientState { - SOCKET socket; - uint16 index; - uint32 last_frame; - uint32 last_frame_server; - byte lag_test; // This byte is used for lag-testing the client - - ClientStatus status; - bool writable; // is client ready to write to? - bool has_quit; - - Packet *packet_queue; // Packets that are awaiting delivery - Packet *packet_recv; // Partially received packet - - CommandPacket *command_queue; // The command-queue awaiting delivery -} NetworkClientState; - -// What packet types are there -// WARNING: The first 3 packets can NEVER change order again -// it protects old clients from joining newer servers (because SERVER_ERROR -// is the respond to a wrong revision) -typedef enum { - PACKET_SERVER_FULL, - PACKET_SERVER_BANNED, - PACKET_CLIENT_JOIN, - PACKET_SERVER_ERROR, - PACKET_CLIENT_COMPANY_INFO, - PACKET_SERVER_COMPANY_INFO, - PACKET_SERVER_CLIENT_INFO, - PACKET_SERVER_NEED_PASSWORD, - PACKET_CLIENT_PASSWORD, - PACKET_SERVER_WELCOME, - PACKET_CLIENT_GETMAP, - PACKET_SERVER_WAIT, - PACKET_SERVER_MAP, - PACKET_CLIENT_MAP_OK, - PACKET_SERVER_JOIN, - PACKET_SERVER_FRAME, - PACKET_SERVER_SYNC, - PACKET_CLIENT_ACK, - PACKET_CLIENT_COMMAND, - PACKET_SERVER_COMMAND, - PACKET_CLIENT_CHAT, - PACKET_SERVER_CHAT, - PACKET_CLIENT_SET_PASSWORD, - PACKET_CLIENT_SET_NAME, - PACKET_CLIENT_QUIT, - PACKET_CLIENT_ERROR, - PACKET_SERVER_QUIT, - PACKET_SERVER_ERROR_QUIT, - PACKET_SERVER_SHUTDOWN, - PACKET_SERVER_NEWGAME, - PACKET_SERVER_RCON, - PACKET_CLIENT_RCON, - PACKET_END // Should ALWAYS be on the end of this list!! (period) -} PacketType; - -typedef enum { - DESTTYPE_BROADCAST, ///< Send message/notice to all players (All) - DESTTYPE_TEAM, ///< Send message/notice to everyone playing the same company (Team) - DESTTYPE_CLIENT, ///< Send message/notice to only a certain player (Private) -} DestType; - -CommandPacket *_local_command_queue; - -SOCKET _udp_client_socket; // udp client socket -SOCKET _udp_server_socket; // udp server socket -SOCKET _udp_master_socket; // udp master socket - -// Here we keep track of the clients -// (and the client uses [0] for his own communication) -NetworkClientState _clients[MAX_CLIENTS]; -#define DEREF_CLIENT(i) (&_clients[i]) -// This returns the NetworkClientInfo from a NetworkClientState -#define DEREF_CLIENT_INFO(cs) (&_network_client_info[cs - _clients]) - -// Macros to make life a bit more easier -#define DEF_CLIENT_RECEIVE_COMMAND(type) NetworkRecvStatus NetworkPacketReceive_ ## type ## _command(Packet *p) -#define DEF_CLIENT_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(void) -#define DEF_CLIENT_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command -#define DEF_SERVER_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(NetworkClientState *cs, Packet *p) -#define DEF_SERVER_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(NetworkClientState *cs) -#define DEF_SERVER_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command - -#define SEND_COMMAND(type) NetworkPacketSend_ ## type ## _command -#define RECEIVE_COMMAND(type) NetworkPacketReceive_ ## type ## _command - -#define FOR_ALL_CLIENTS(cs) for (cs = _clients; cs != endof(_clients) && cs->socket != INVALID_SOCKET; cs++) -#define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX) - -Packet *NetworkSend_Init(PacketType type); -void NetworkSend_uint8(Packet *packet, uint8 data); -void NetworkSend_uint16(Packet *packet, uint16 data); -void NetworkSend_uint32(Packet *packet, uint32 data); -void NetworkSend_uint64(Packet *packet, uint64 data); -void NetworkSend_string(Packet *packet, const char* data); -void NetworkSend_Packet(Packet *packet, NetworkClientState *cs); - -uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet); -uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet); -uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet); -uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet); -void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size); -Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); - -bool NetworkSend_Packets(NetworkClientState *cs); -void NetworkExecuteCommand(CommandPacket *cp); -void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp); - -// from network.c -void NetworkCloseClient(NetworkClientState *cs); -void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send, const char *name, const char *str, ...); -void NetworkGetClientName(char *clientname, size_t size, const NetworkClientState *cs); -uint NetworkCalculateLag(const NetworkClientState *cs); -byte NetworkGetCurrentLanguageIndex(void); -NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index); -NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip); -NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index); -unsigned long NetworkResolveHost(const char *hostname); -char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last); - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_DATA_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_gamelist.c --- a/network_gamelist.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "debug.h" -#include "network_data.h" -#include "newgrf_config.h" - -// This file handles the GameList -// Also, it handles the request to a server for data about the server - -/** Add a new item to the linked gamelist. If the IP and Port match - * return the existing item instead of adding it again - * @param ip the IP-address (inet_addr) of the to-be added item - * @param port the port the server is running on - * @return a point to the newly added or already existing item */ -NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port) -{ - NetworkGameList *item, *prev_item; - - prev_item = NULL; - for (item = _network_game_list; item != NULL; item = item->next) { - if (item->ip == ip && item->port == port) return item; - prev_item = item; - } - - item = malloc(sizeof(*item)); - memset(item, 0, sizeof(*item)); - item->next = NULL; - item->ip = ip; - item->port = port; - - if (prev_item == NULL) { - _network_game_list = item; - } else { - prev_item->next = item; - } - DEBUG(net, 4, "[gamelist] added server to list"); - - UpdateNetworkGameWindow(false); - - return item; -} - -/** Remove an item from the gamelist linked list - * @param remove pointer to the item to be removed */ -void NetworkGameListRemoveItem(NetworkGameList *remove) -{ - NetworkGameList *item, *prev_item; - - prev_item = NULL; - for (item = _network_game_list; item != NULL; item = item->next) { - if (remove == item) { - if (prev_item == NULL) { - _network_game_list = remove->next; - } else { - prev_item->next = remove->next; - } - - /* Remove GRFConfig information */ - ClearGRFConfigList(&remove->info.grfconfig); - free(remove); - remove = NULL; - - DEBUG(net, 4, "[gamelist] removed server from list"); - UpdateNetworkGameWindow(false); - return; - } - prev_item = item; - } -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_gamelist.h --- a/network_gamelist.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_GAMELIST_H -#define NETWORK_GAMELIST_H - -void NetworkGameListClear(void); -NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port); -void NetworkGameListRemoveItem(NetworkGameList *remove); -void NetworkGameListAddQueriedItem(const NetworkGameInfo *info, bool server_online); - -#endif /* NETWORK_GAMELIST_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_gui.c --- a/network_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1706 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "openttd.h" -#include "string.h" -#include "strings.h" -#include "table/sprites.h" -#include "network.h" -#include "date.h" - -#include "fios.h" -#include "table/strings.h" -#include "functions.h" -#include "network_data.h" -#include "network_client.h" -#include "network_gui.h" -#include "network_gamelist.h" -#include "window.h" -#include "gui.h" -#include "gfx.h" -#include "command.h" -#include "variables.h" -#include "network_server.h" -#include "network_udp.h" -#include "settings.h" -#include "string.h" -#include "town.h" -#include "newgrf.h" - -#define BGC 5 -#define BTC 15 - -typedef struct network_d { - PlayerID company; // select company in network lobby - byte field; // select text-field in start-server and game-listing - NetworkGameList *server; // selected server in lobby and game-listing - FiosItem *map; // selected map in start-server -} network_d; -assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_d)); - -typedef struct network_ql_d { - network_d n; // see above; general stuff - querystr_d q; // text-input in start-server and game-listing - NetworkGameList **sort_list; // list of games (sorted) - list_d l; // accompanying list-administration -} network_ql_d; -assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(network_ql_d)); - -/* Global to remember sorting after window has been closed */ -static Listing _ng_sorting; - -static char _edit_str_buf[150]; -static bool _chat_tab_completion_active; - -static void ShowNetworkStartServerWindow(void); -static void ShowNetworkLobbyWindow(NetworkGameList *ngl); -extern void SwitchMode(int new_mode); - -static const StringID _connection_types_dropdown[] = { - STR_NETWORK_LAN_INTERNET, - STR_NETWORK_INTERNET_ADVERTISE, - INVALID_STRING_ID -}; - -static const StringID _lan_internet_types_dropdown[] = { - STR_NETWORK_LAN, - STR_NETWORK_INTERNET, - INVALID_STRING_ID -}; - -static const StringID _players_dropdown[] = { - STR_NETWORK_0_PLAYERS, - STR_NETWORK_1_PLAYERS, - STR_NETWORK_2_PLAYERS, - STR_NETWORK_3_PLAYERS, - STR_NETWORK_4_PLAYERS, - STR_NETWORK_5_PLAYERS, - STR_NETWORK_6_PLAYERS, - STR_NETWORK_7_PLAYERS, - STR_NETWORK_8_PLAYERS, - STR_NETWORK_9_PLAYERS, - STR_NETWORK_10_PLAYERS, - INVALID_STRING_ID -}; - -static const StringID _language_dropdown[] = { - STR_NETWORK_LANG_ANY, - STR_NETWORK_LANG_ENGLISH, - STR_NETWORK_LANG_GERMAN, - STR_NETWORK_LANG_FRENCH, - INVALID_STRING_ID -}; - -enum { - NET_PRC__OFFSET_TOP_WIDGET = 54, - NET_PRC__OFFSET_TOP_WIDGET_COMPANY = 52, - NET_PRC__SIZE_OF_ROW = 14, -}; - -/** Update the network new window because a new server is - * found on the network. - * @param unselect unselect the currently selected item */ -void UpdateNetworkGameWindow(bool unselect) -{ - SendWindowMessage(WC_NETWORK_WINDOW, 0, unselect, 0, 0); -} - -static bool _internal_sort_order; // Used for Qsort order-flipping -typedef int CDECL NGameNameSortFunction(const void*, const void*); - -/** Qsort function to sort by name. */ -static int CDECL NGameNameSorter(const void *a, const void *b) -{ - const NetworkGameList *cmp1 = *(const NetworkGameList**)a; - const NetworkGameList *cmp2 = *(const NetworkGameList**)b; - int r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); - - return _internal_sort_order ? -r : r; -} - -/** Qsort function to sort by the amount of clients online on a - * server. If the two servers have the same amount, the one with the - * higher maximum is preferred. */ -static int CDECL NGameClientSorter(const void *a, const void *b) -{ - const NetworkGameList *cmp1 = *(const NetworkGameList**)a; - const NetworkGameList *cmp2 = *(const NetworkGameList**)b; - /* Reverse as per default we are interested in most-clients first */ - int r = cmp1->info.clients_on - cmp2->info.clients_on; - - if (r == 0) r = cmp1->info.clients_max - cmp2->info.clients_max; - if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); - - return _internal_sort_order ? -r : r; -} - -/** Qsort function to sort by joinability. If both servers are the - * same, prefer the non-passworded server first. */ -static int CDECL NGameAllowedSorter(const void *a, const void *b) -{ - const NetworkGameList *cmp1 = *(const NetworkGameList**)a; - const NetworkGameList *cmp2 = *(const NetworkGameList**)b; - /* Reverse default as we are interested in compatible clients first */ - int r = cmp2->info.compatible - cmp1->info.compatible; - - if (r == 0) r = cmp1->info.use_password - cmp2->info.use_password; - if (r == 0) r = strcasecmp(cmp1->info.server_name, cmp2->info.server_name); - - return _internal_sort_order ? -r : r; -} - -/** (Re)build the network game list as its amount has changed because - * an item has been added or deleted for example - * @param ngl list_d struct that contains all necessary information for sorting */ -static void BuildNetworkGameList(network_ql_d *nqld) -{ - NetworkGameList *ngl_temp; - uint n = 0; - - if (!(nqld->l.flags & VL_REBUILD)) return; - - /* Count the number of games in the list */ - for (ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) n++; - if (n == 0) return; - - /* Create temporary array of games to use for listing */ - free(nqld->sort_list); - nqld->sort_list = malloc(n * sizeof(nqld->sort_list[0])); - if (nqld->sort_list == NULL) error("Could not allocate memory for the network-game-sorting-list"); - nqld->l.list_length = n; - - for (n = 0, ngl_temp = _network_game_list; ngl_temp != NULL; ngl_temp = ngl_temp->next) { - nqld->sort_list[n++] = ngl_temp; - } - - /* Force resort */ - nqld->l.flags &= ~VL_REBUILD; - nqld->l.flags |= VL_RESORT; -} - -static void SortNetworkGameList(network_ql_d *nqld) -{ - static NGameNameSortFunction * const ngame_sorter[] = { - &NGameNameSorter, - &NGameClientSorter, - &NGameAllowedSorter - }; - - NetworkGameList *item; - uint i; - - if (!(nqld->l.flags & VL_RESORT)) return; - if (nqld->l.list_length == 0) return; - - _internal_sort_order = !!(nqld->l.flags & VL_DESC); - qsort(nqld->sort_list, nqld->l.list_length, sizeof(nqld->sort_list[0]), ngame_sorter[nqld->l.sort_type]); - - /* After sorting ngl->sort_list contains the sorted items. Put these back - * into the original list. Basically nothing has changed, we are only - * shuffling the ->next pointers */ - _network_game_list = nqld->sort_list[0]; - for (item = _network_game_list, i = 1; i != nqld->l.list_length; i++) { - item->next = nqld->sort_list[i]; - item = item->next; - } - item->next = NULL; - - nqld->l.flags &= ~VL_RESORT; -} - -/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */ -static void NetworkGameWindowWndProc(Window *w, WindowEvent *e) -{ - network_d *nd = &WP(w, network_ql_d).n; - list_d *ld = &WP(w, network_ql_d).l; - - switch (e->event) { - case WE_CREATE: /* Focus input box */ - nd->field = 3; - nd->server = NULL; - - WP(w, network_ql_d).sort_list = NULL; - ld->flags = VL_REBUILD | (_ng_sorting.order << (VL_DESC - 1)); - ld->sort_type = _ng_sorting.criteria; - break; - - case WE_PAINT: { - const NetworkGameList *sel = nd->server; - const char *arrow = (ld->flags & VL_DESC) ? DOWNARROW : UPARROW; - - if (ld->flags & VL_REBUILD) { - BuildNetworkGameList(&WP(w, network_ql_d)); - SetVScrollCount(w, ld->list_length); - } - if (ld->flags & VL_RESORT) SortNetworkGameList(&WP(w, network_ql_d)); - - SetWindowWidgetDisabledState(w, 17, sel == NULL); - /* Join Button disabling conditions */ - SetWindowWidgetDisabledState(w, 16, sel == NULL || // no Selected Server - !sel->online || // Server offline - sel->info.clients_on >= sel->info.clients_max || // Server full - !sel->info.compatible); // Revision mismatch - - SetWindowWidgetHiddenState(w, 18, sel == NULL || - !sel->online || - sel->info.grfconfig == NULL); - - SetDParam(0, 0x00); - SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]); - DrawWindowWidgets(w); - - DrawEditBox(w, &WP(w, network_ql_d).q, 3); - - DrawString(9, 23, STR_NETWORK_CONNECTION, 2); - DrawString(210, 23, STR_NETWORK_PLAYER_NAME, 2); - - /* Sort based on widgets: name, clients, compatibility */ - switch (ld->sort_type) { - case 6 - 6: DoDrawString(arrow, w->widget[6].right - 10, 42, 0x10); break; - case 7 - 6: DoDrawString(arrow, w->widget[7].right - 10, 42, 0x10); break; - case 8 - 6: DoDrawString(arrow, w->widget[8].right - 10, 42, 0x10); break; - } - - { // draw list of games - uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3; - int32 n = 0; - int32 pos = w->vscroll.pos; - uint max_name_width = w->widget[6].right - w->widget[6].left - 5; - const NetworkGameList *cur_item = _network_game_list; - - while (pos > 0 && cur_item != NULL) { - pos--; - cur_item = cur_item->next; - } - - while (cur_item != NULL) { - // show highlighted item with a different colour - if (cur_item == sel) GfxFillRect(w->widget[6].left + 1, y - 2, w->widget[8].right - 1, y + 9, 10); - - SetDParamStr(0, cur_item->info.server_name); - DrawStringTruncated(w->widget[6].left + 5, y, STR_02BD, 16, max_name_width); - - SetDParam(0, cur_item->info.clients_on); - SetDParam(1, cur_item->info.clients_max); - SetDParam(2, cur_item->info.companies_on); - SetDParam(3, cur_item->info.companies_max); - DrawStringCentered(210, y, STR_NETWORK_GENERAL_ONLINE, 2); - - // only draw icons if the server is online - if (cur_item->online) { - // draw a lock if the server is password protected. - if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1); - - // draw red or green icon, depending on compatibility with server. - DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[8].left + 15, y); - - // draw flag according to server language - DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y); - } - - cur_item = cur_item->next; - y += NET_PRC__SIZE_OF_ROW; - if (++n == w->vscroll.cap) break; // max number of games in the window - } - } - - /* Draw the right menu */ - GfxFillRect(311, 43, 539, 92, 157); - if (sel == NULL) { - DrawStringCentered(425, 58, STR_NETWORK_GAME_INFO, 0); - } else if (!sel->online) { - SetDParamStr(0, sel->info.server_name); - DrawStringCentered(425, 68, STR_ORANGE, 0); // game name - - DrawStringCentered(425, 132, STR_NETWORK_SERVER_OFFLINE, 0); // server offline - } else { // show game info - uint16 y = 100; - const uint16 x = w->widget[15].left + 5; - - DrawStringCentered(425, 48, STR_NETWORK_GAME_INFO, 0); - - - SetDParamStr(0, sel->info.server_name); - DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 62, STR_ORANGE, 16); // game name - - SetDParamStr(0, sel->info.map_name); - DrawStringCenteredTruncated(w->widget[15].left, w->widget[15].right, 74, STR_02BD, 16); // map name - - SetDParam(0, sel->info.clients_on); - SetDParam(1, sel->info.clients_max); - SetDParam(2, sel->info.companies_on); - SetDParam(3, sel->info.companies_max); - DrawString(x, y, STR_NETWORK_CLIENTS, 2); - y += 10; - - SetDParam(0, _language_dropdown[sel->info.server_lang]); - DrawString(x, y, STR_NETWORK_LANGUAGE, 2); // server language - y += 10; - - SetDParam(0, STR_TEMPERATE_LANDSCAPE + sel->info.map_set); - DrawString(x, y, STR_NETWORK_TILESET, 2); // tileset - y += 10; - - SetDParam(0, sel->info.map_width); - SetDParam(1, sel->info.map_height); - DrawString(x, y, STR_NETWORK_MAP_SIZE, 2); // map size - y += 10; - - SetDParamStr(0, sel->info.server_revision); - DrawString(x, y, STR_NETWORK_SERVER_VERSION, 2); // server version - y += 10; - - SetDParamStr(0, sel->info.hostname); - SetDParam(1, sel->port); - DrawString(x, y, STR_NETWORK_SERVER_ADDRESS, 2); // server address - y += 10; - - SetDParam(0, sel->info.start_date); - DrawString(x, y, STR_NETWORK_START_DATE, 2); // start date - y += 10; - - SetDParam(0, sel->info.game_date); - DrawString(x, y, STR_NETWORK_CURRENT_DATE, 2); // current date - y += 10; - - y += 2; - - if (!sel->info.compatible) { - DrawStringCentered(425, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch - } else if (sel->info.clients_on == sel->info.clients_max) { - // Show: server full, when clients_on == clients_max - DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full - } else if (sel->info.use_password) { - DrawStringCentered(425, y, STR_NETWORK_PASSWORD, 0); // password warning - } - - y += 10; - } - } break; - - case WE_CLICK: - nd->field = e->we.click.widget; - switch (e->we.click.widget) { - case 0: case 14: /* Close 'X' | Cancel button */ - DeleteWindowById(WC_NETWORK_WINDOW, 0); - break; - case 4: case 5: - ShowDropDownMenu(w, _lan_internet_types_dropdown, _network_lan_internet, 5, 0, 0); // do it for widget 5 - break; - case 6: /* Sort by name */ - case 7: /* Sort by connected clients */ - case 8: /* Connectivity (green dot) */ - if (ld->sort_type == e->we.click.widget - 6) ld->flags ^= VL_DESC; - ld->flags |= VL_RESORT; - ld->sort_type = e->we.click.widget - 6; - - _ng_sorting.order = !!(ld->flags & VL_DESC); - _ng_sorting.criteria = ld->sort_type; - SetWindowDirty(w); - break; - case 9: { /* Matrix to show networkgames */ - NetworkGameList *cur_item; - uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET) / NET_PRC__SIZE_OF_ROW; - - if (id_v >= w->vscroll.cap) return; // click out of bounds - id_v += w->vscroll.pos; - - cur_item = _network_game_list; - for (; id_v > 0 && cur_item != NULL; id_v--) cur_item = cur_item->next; - - nd->server = cur_item; - SetWindowDirty(w); - } break; - case 11: /* Find server automatically */ - switch (_network_lan_internet) { - case 0: NetworkUDPSearchGame(); break; - case 1: NetworkUDPQueryMasterServer(); break; - } - break; - case 12: { // Add a server - ShowQueryString( - BindCString(_network_default_ip), - STR_NETWORK_ENTER_IP, - 31 | 0x1000, // maximum number of characters OR - 250, // characters up to this width pixels, whichever is satisfied first - w, CS_ALPHANUMERAL); - } break; - case 13: /* Start server */ - ShowNetworkStartServerWindow(); - break; - case 16: /* Join Game */ - if (nd->server != NULL) { - snprintf(_network_last_host, sizeof(_network_last_host), "%s", inet_ntoa(*(struct in_addr *)&nd->server->ip)); - _network_last_port = nd->server->port; - ShowNetworkLobbyWindow(nd->server); - } - break; - case 17: // Refresh - if (nd->server != NULL) - NetworkQueryServer(nd->server->info.hostname, nd->server->port, true); - break; - case 18: // NewGRF Settings - if (nd->server != NULL) ShowNewGRFSettings(false, false, false, &nd->server->info.grfconfig); - break; - - } break; - - case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ - switch (e->we.dropdown.button) { - case 5: - _network_lan_internet = e->we.dropdown.index; - break; - } - - SetWindowDirty(w); - break; - - case WE_MOUSELOOP: - if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3); - break; - - case WE_MESSAGE: - if (e->we.message.msg != 0) nd->server = NULL; - ld->flags |= VL_REBUILD; - SetWindowDirty(w); - break; - - case WE_KEYPRESS: - if (nd->field != 3) { - if (nd->server != NULL) { - if (e->we.keypress.keycode == WKC_DELETE) { /* Press 'delete' to remove servers */ - NetworkGameListRemoveItem(nd->server); - NetworkRebuildHostList(); - nd->server = NULL; - } - } - break; - } - - if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed - - // The name is only allowed when it starts with a letter! - if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ') { - ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name)); - } else { - ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name)); - } - - break; - - case WE_ON_EDIT_TEXT: - NetworkAddServer(e->we.edittext.str); - NetworkRebuildHostList(); - break; - - case WE_DESTROY: /* Nicely clean up the sort-list */ - free(WP(w, network_ql_d).sort_list); - break; - } -} - -static const Widget _network_game_window_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 549, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, BGC, 0, 549, 14, 263, 0x0, STR_NULL}, - -/* LEFT SIDE */ -{ WWT_PANEL, RESIZE_NONE, BGC, 310, 461, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP}, - -{ WWT_INSET, RESIZE_NONE, BGC, 90, 181, 22, 33, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 170, 180, 23, 32, STR_0225, STR_NETWORK_CONNECTION_TIP}, - -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 170, 42, 53, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 171, 250, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 251, 290, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP}, - -{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 290, 54, 236, (13 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT}, -{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 291, 302, 42, 236, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST}, - -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 30, 130, 246, 257, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 180, 280, 246, 257, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP}, - -/* RIGHT SIDE */ -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 246, 257, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 246, 257, STR_012E_CANCEL, STR_NULL}, - -{ WWT_PANEL, RESIZE_NONE, BGC, 310, 540, 42, 236, 0x0, STR_NULL}, - -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 215, 226, STR_NETWORK_JOIN_GAME, STR_NULL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP}, - -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 197, 208, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL}, - -{ WIDGETS_END}, -}; - -static const WindowDesc _network_game_window_desc = { - WDP_CENTER, WDP_CENTER, 550, 264, - WC_NETWORK_WINDOW,0, - WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, - _network_game_window_widgets, - NetworkGameWindowWndProc, -}; - -void ShowNetworkGameWindow(void) -{ - static bool first = true; - Window *w; - DeleteWindowById(WC_NETWORK_WINDOW, 0); - - /* Only show once */ - if (first) { - char* const *srv; - - first = false; - // add all servers from the config file to our list - for (srv = &_network_host_list[0]; srv != endof(_network_host_list) && *srv != NULL; srv++) { - NetworkAddServer(*srv); - } - - _ng_sorting.criteria = 2; // sort default by collectivity (green-dots on top) - _ng_sorting.order = 0; // sort ascending by default - } - - w = AllocateWindowDesc(&_network_game_window_desc); - if (w != NULL) { - querystr_d *querystr = &WP(w, network_ql_d).q; - - ttd_strlcpy(_edit_str_buf, _network_player_name, lengthof(_edit_str_buf)); - w->vscroll.cap = 13; - - querystr->afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120); - - UpdateNetworkGameWindow(true); - } -} - -enum { - NSSWND_START = 64, - NSSWND_ROWSIZE = 12 -}; - -/* Uses network_ql_d (network_d, querystr_d and list_d) WP macro */ -static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e) -{ - network_d *nd = &WP(w, network_ql_d).n; - - switch (e->event) { - case WE_CREATE: /* focus input box */ - nd->field = 3; - _network_game_info.use_password = (_network_server_password[0] != '\0'); - break; - - case WE_PAINT: { - int y = NSSWND_START, pos; - const FiosItem *item; - - SetDParam( 7, _connection_types_dropdown[_network_advertise]); - SetDParam( 9, _players_dropdown[_network_game_info.clients_max]); - SetDParam(11, _players_dropdown[_network_game_info.companies_max]); - SetDParam(13, _players_dropdown[_network_game_info.spectators_max]); - SetDParam(15, _language_dropdown[_network_game_info.server_lang]); - DrawWindowWidgets(w); - - GfxFillRect(11, 63, 258, 215, 0xD7); - DrawEditBox(w, &WP(w, network_ql_d).q, 3); - - DrawString(10, 22, STR_NETWORK_NEW_GAME_NAME, 2); - - DrawString(10, 43, STR_NETWORK_SELECT_MAP, 2); - - DrawString(280, 63, STR_NETWORK_CONNECTION, 2); - DrawString(280, 95, STR_NETWORK_NUMBER_OF_CLIENTS, 2); - DrawString(280, 127, STR_NETWORK_NUMBER_OF_COMPANIES, 2); - DrawString(280, 159, STR_NETWORK_NUMBER_OF_SPECTATORS, 2); - DrawString(280, 191, STR_NETWORK_LANGUAGE_SPOKEN, 2); - - if (_network_game_info.use_password) DoDrawString("*", 408, 23, 3); - - // draw list of maps - pos = w->vscroll.pos; - while (pos < _fios_num + 1) { - item = _fios_list + pos - 1; - if (item == nd->map || (pos == 0 && nd->map == NULL)) - GfxFillRect(11, y - 1, 258, y + 10, 155); // show highlighted item with a different colour - - if (pos == 0) { - DrawString(14, y, STR_4010_GENERATE_RANDOM_NEW_GAME, 9); - } else { - DoDrawString(item->title, 14, y, _fios_colors[item->type] ); - } - pos++; - y += NSSWND_ROWSIZE; - - if (y >= w->vscroll.cap * NSSWND_ROWSIZE + NSSWND_START) break; - } - } break; - - case WE_CLICK: - nd->field = e->we.click.widget; - switch (e->we.click.widget) { - case 0: /* Close 'X' */ - case 19: /* Cancel button */ - ShowNetworkGameWindow(); - break; - - case 4: /* Set password button */ - ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL); - break; - - case 5: { /* Select map */ - int y = (e->we.click.pt.y - NSSWND_START) / NSSWND_ROWSIZE; - - y += w->vscroll.pos; - if (y >= w->vscroll.count) return; - - nd->map = (y == 0) ? NULL : _fios_list + y - 1; - SetWindowDirty(w); - } break; - case 7: case 8: /* Connection type */ - ShowDropDownMenu(w, _connection_types_dropdown, _network_advertise, 8, 0, 0); // do it for widget 8 - break; - case 9: case 10: /* Number of Players (hide 0 and 1 players) */ - ShowDropDownMenu(w, _players_dropdown, _network_game_info.clients_max, 10, 0, 3); - break; - case 11: case 12: /* Number of Companies (hide 0, 9 and 10 companies; max is 8) */ - ShowDropDownMenu(w, _players_dropdown, _network_game_info.companies_max, 12, 0, 1537); - break; - case 13: case 14: /* Number of Spectators */ - ShowDropDownMenu(w, _players_dropdown, _network_game_info.spectators_max, 14, 0, 0); - break; - case 15: case 16: /* Language */ - ShowDropDownMenu(w, _language_dropdown, _network_game_info.server_lang, 16, 0, 0); - break; - case 17: /* Start game */ - _is_network_server = true; - - if (nd->map == NULL) { // start random new game - ShowGenerateLandscape(); - } else { // load a scenario - char *name = FiosBrowseTo(nd->map); - if (name != NULL) { - SetFiosType(nd->map->type); - ttd_strlcpy(_file_to_saveload.name, name, sizeof(_file_to_saveload.name)); - ttd_strlcpy(_file_to_saveload.title, nd->map->title, sizeof(_file_to_saveload.title)); - - DeleteWindow(w); - SwitchMode(SM_START_SCENARIO); - } - } - break; - case 18: /* Load game */ - _is_network_server = true; - /* XXX - WC_NETWORK_WINDOW should stay, but if it stays, it gets - * copied all the elements of 'load game' and upon closing that, it segfaults */ - DeleteWindowById(WC_NETWORK_WINDOW, 0); - ShowSaveLoadDialog(SLD_LOAD_GAME); - break; - } - break; - - case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ - switch (e->we.dropdown.button) { - case 8: _network_advertise = (e->we.dropdown.index != 0); break; - case 10: _network_game_info.clients_max = e->we.dropdown.index; break; - case 12: _network_game_info.companies_max = e->we.dropdown.index; break; - case 14: _network_game_info.spectators_max = e->we.dropdown.index; break; - case 16: _network_game_info.server_lang = e->we.dropdown.index; break; - } - - SetWindowDirty(w); - break; - - case WE_MOUSELOOP: - if (nd->field == 3) HandleEditBox(w, &WP(w, network_ql_d).q, 3); - break; - - case WE_KEYPRESS: - if (nd->field == 3) { - if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, 3, e) == 1) break; // enter pressed - - ttd_strlcpy(_network_server_name, WP(w, network_ql_d).q.text.buf, sizeof(_network_server_name)); - UpdateTextBufferSize(&WP(w, network_ql_d).q.text); - } - break; - - case WE_ON_EDIT_TEXT: { - ttd_strlcpy(_network_server_password, e->we.edittext.str, lengthof(_network_server_password)); - _network_game_info.use_password = (_network_server_password[0] != '\0'); - SetWindowDirty(w); - } break; - } -} - -static const Widget _network_start_server_window_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, -{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_START_GAME_WINDOW, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, BGC, 0, 419, 14, 243, 0x0, STR_NULL}, - -{ WWT_PANEL, RESIZE_NONE, BGC, 100, 272, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP}, - -{ WWT_INSET, RESIZE_NONE, BGC, 10, 271, 62, 216, 0x0, STR_NETWORK_SELECT_MAP_TIP}, -{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 259, 270, 63, 215, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -/* Combo boxes to control Connection Type / Max Clients / Max Companies / Max Observers / Language */ -{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 77, 88, STR_NETWORK_COMBO1, STR_NETWORK_CONNECTION_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 78, 87, STR_0225, STR_NETWORK_CONNECTION_TIP}, -{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 109, 120, STR_NETWORK_COMBO2, STR_NETWORK_NUMBER_OF_CLIENTS_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 110, 119, STR_0225, STR_NETWORK_NUMBER_OF_CLIENTS_TIP}, -{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 141, 152, STR_NETWORK_COMBO3, STR_NETWORK_NUMBER_OF_COMPANIES_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 142, 151, STR_0225, STR_NETWORK_NUMBER_OF_COMPANIES_TIP}, -{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 173, 184, STR_NETWORK_COMBO4, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 174, 183, STR_0225, STR_NETWORK_NUMBER_OF_SPECTATORS_TIP}, -{ WWT_INSET, RESIZE_NONE, BGC, 280, 410, 205, 216, STR_NETWORK_COMBO5, STR_NETWORK_LANGUAGE_TIP}, -{ WWT_TEXTBTN, RESIZE_NONE, BGC, 399, 409, 206, 215, STR_0225, STR_NETWORK_LANGUAGE_TIP}, - -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 40, 140, 224, 235, STR_NETWORK_START_GAME, STR_NETWORK_START_GAME_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 150, 250, 224, 235, STR_NETWORK_LOAD_GAME, STR_NETWORK_LOAD_GAME_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 260, 360, 224, 235, STR_012E_CANCEL, STR_NULL}, -{ WIDGETS_END}, -}; - -static const WindowDesc _network_start_server_window_desc = { - WDP_CENTER, WDP_CENTER, 420, 244, - WC_NETWORK_WINDOW,0, - WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, - _network_start_server_window_widgets, - NetworkStartServerWindowWndProc, -}; - -static void ShowNetworkStartServerWindow(void) -{ - Window *w; - DeleteWindowById(WC_NETWORK_WINDOW, 0); - - w = AllocateWindowDesc(&_network_start_server_window_desc); - ttd_strlcpy(_edit_str_buf, _network_server_name, lengthof(_edit_str_buf)); - - _saveload_mode = SLD_NEW_GAME; - BuildFileList(); - w->vscroll.cap = 12; - w->vscroll.count = _fios_num+1; - - WP(w, network_ql_d).q.afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_buf, lengthof(_edit_str_buf), 160); -} - -static byte NetworkLobbyFindCompanyIndex(byte pos) -{ - byte i; - - /* Scroll through all _network_player_info and get the 'pos' item - that is not empty */ - for (i = 0; i < MAX_PLAYERS; i++) { - if (_network_player_info[i].company_name[0] != '\0') { - if (pos-- == 0) return i; - } - } - - return 0; -} - -/* uses network_d WP macro */ -static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e) -{ - network_d *nd = &WP(w, network_d); - - switch (e->event) { - case WE_CREATE: - nd->company = (byte)-1; - break; - - case WE_PAINT: { - const NetworkGameInfo *gi = &nd->server->info; - int y = NET_PRC__OFFSET_TOP_WIDGET_COMPANY, pos; - - SetWindowWidgetDisabledState(w, 7, nd->company == (byte)-1); - SetWindowWidgetDisabledState(w, 8, gi->companies_on >= gi->companies_max); - /* You can not join a server as spectator when it has no companies active.. - * it causes some nasty crashes */ - SetWindowWidgetDisabledState(w, 9, gi->spectators_on >= gi->spectators_max || - gi->companies_on == 0); - - DrawWindowWidgets(w); - - SetDParamStr(0, gi->server_name); - DrawString(10, 22, STR_NETWORK_PREPARE_TO_JOIN, 2); - - /* Draw company list */ - pos = w->vscroll.pos; - while (pos < gi->companies_on) { - byte company = NetworkLobbyFindCompanyIndex(pos); - bool income = false; - if (nd->company == company) - GfxFillRect(11, y - 1, 154, y + 10, 10); // show highlighted item with a different colour - - DoDrawStringTruncated(_network_player_info[company].company_name, 13, y, 16, 135 - 13); - if (_network_player_info[company].use_password != 0) DrawSprite(SPR_LOCK, 135, y); - - /* If the company's income was positive puts a green dot else a red dot */ - if (_network_player_info[company].income >= 0) income = true; - DrawSprite(SPR_BLOT | (income ? PALETTE_TO_GREEN : PALETTE_TO_RED), 145, y); - - pos++; - y += NET_PRC__SIZE_OF_ROW; - if (pos >= w->vscroll.cap) break; - } - - /* Draw info about selected company when it is selected in the left window */ - GfxFillRect(174, 39, 403, 75, 157); - DrawStringCentered(290, 50, STR_NETWORK_COMPANY_INFO, 0); - if (nd->company != (byte)-1) { - const uint x = 183; - const uint trunc_width = w->widget[6].right - x; - y = 80; - - SetDParam(0, nd->server->info.clients_on); - SetDParam(1, nd->server->info.clients_max); - SetDParam(2, nd->server->info.companies_on); - SetDParam(3, nd->server->info.companies_max); - DrawString(x, y, STR_NETWORK_CLIENTS, 2); - y += 10; - - SetDParamStr(0, _network_player_info[nd->company].company_name); - DrawStringTruncated(x, y, STR_NETWORK_COMPANY_NAME, 2, trunc_width); - y += 10; - - SetDParam(0, _network_player_info[nd->company].inaugurated_year); - DrawString(x, y, STR_NETWORK_INAUGURATION_YEAR, 2); // inauguration year - y += 10; - - SetDParam64(0, _network_player_info[nd->company].company_value); - DrawString(x, y, STR_NETWORK_VALUE, 2); // company value - y += 10; - - SetDParam64(0, _network_player_info[nd->company].money); - DrawString(x, y, STR_NETWORK_CURRENT_BALANCE, 2); // current balance - y += 10; - - SetDParam64(0, _network_player_info[nd->company].income); - DrawString(x, y, STR_NETWORK_LAST_YEARS_INCOME, 2); // last year's income - y += 10; - - SetDParam(0, _network_player_info[nd->company].performance); - DrawString(x, y, STR_NETWORK_PERFORMANCE, 2); // performance - y += 10; - - SetDParam(0, _network_player_info[nd->company].num_vehicle[0]); - SetDParam(1, _network_player_info[nd->company].num_vehicle[1]); - SetDParam(2, _network_player_info[nd->company].num_vehicle[2]); - SetDParam(3, _network_player_info[nd->company].num_vehicle[3]); - SetDParam(4, _network_player_info[nd->company].num_vehicle[4]); - DrawString(x, y, STR_NETWORK_VEHICLES, 2); // vehicles - y += 10; - - SetDParam(0, _network_player_info[nd->company].num_station[0]); - SetDParam(1, _network_player_info[nd->company].num_station[1]); - SetDParam(2, _network_player_info[nd->company].num_station[2]); - SetDParam(3, _network_player_info[nd->company].num_station[3]); - SetDParam(4, _network_player_info[nd->company].num_station[4]); - DrawString(x, y, STR_NETWORK_STATIONS, 2); // stations - y += 10; - - SetDParamStr(0, _network_player_info[nd->company].players); - DrawStringTruncated(x, y, STR_NETWORK_PLAYERS, 2, trunc_width); // players - } - } break; - - case WE_CLICK: - switch (e->we.click.widget) { - case 0: case 11: /* Close 'X' | Cancel button */ - ShowNetworkGameWindow(); - break; - case 4: { /* Company list */ - uint32 id_v = (e->we.click.pt.y - NET_PRC__OFFSET_TOP_WIDGET_COMPANY) / NET_PRC__SIZE_OF_ROW; - - if (id_v >= w->vscroll.cap) return; - - id_v += w->vscroll.pos; - nd->company = (id_v >= nd->server->info.companies_on) ? (byte)-1 : NetworkLobbyFindCompanyIndex(id_v); - SetWindowDirty(w); - } break; - case 7: /* Join company */ - if (nd->company != (byte)-1) { - _network_playas = nd->company; - NetworkClientConnectGame(_network_last_host, _network_last_port); - } - break; - case 8: /* New company */ - _network_playas = PLAYER_NEW_COMPANY; - NetworkClientConnectGame(_network_last_host, _network_last_port); - break; - case 9: /* Spectate game */ - _network_playas = PLAYER_SPECTATOR; - NetworkClientConnectGame(_network_last_host, _network_last_port); - break; - case 10: /* Refresh */ - NetworkQueryServer(_network_last_host, _network_last_port, false); // company info - NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data - break; - } break; - - case WE_MESSAGE: - SetWindowDirty(w); - break; - } -} - -static const Widget _network_lobby_window_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, -{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 419, 0, 13, STR_NETWORK_GAME_LOBBY, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, BGC, 0, 419, 14, 234, 0x0, STR_NULL}, - -// company list -{ WWT_PANEL, RESIZE_NONE, BTC, 10, 155, 38, 49, 0x0, STR_NULL}, -{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 155, 50, 190, (10 << 8) + 1, STR_NETWORK_COMPANY_LIST_TIP}, -{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 156, 167, 38, 190, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST}, - -// company/player info -{ WWT_PANEL, RESIZE_NONE, BGC, 173, 404, 38, 190, 0x0, STR_NULL}, - -// buttons -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 151, 200, 211, STR_NETWORK_JOIN_COMPANY, STR_NETWORK_JOIN_COMPANY_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 10, 151, 215, 226, STR_NETWORK_NEW_COMPANY, STR_NETWORK_NEW_COMPANY_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 158, 268, 200, 211, STR_NETWORK_SPECTATE_GAME, STR_NETWORK_SPECTATE_GAME_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 158, 268, 215, 226, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 278, 388, 200, 211, STR_012E_CANCEL, STR_NULL}, - -{ WIDGETS_END}, -}; - -static const WindowDesc _network_lobby_window_desc = { - WDP_CENTER, WDP_CENTER, 420, 235, - WC_NETWORK_WINDOW,0, - WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, - _network_lobby_window_widgets, - NetworkLobbyWindowWndProc, -}; - -/* Show the networklobbywindow with the selected server - * @param ngl Selected game pointer which is passed to the new window */ -static void ShowNetworkLobbyWindow(NetworkGameList *ngl) -{ - Window *w; - DeleteWindowById(WC_NETWORK_WINDOW, 0); - - NetworkQueryServer(_network_last_host, _network_last_port, false); // company info - NetworkUDPQueryServer(_network_last_host, _network_last_port); // general data - - w = AllocateWindowDesc(&_network_lobby_window_desc); - if (w != NULL) { - WP(w, network_ql_d).n.server = ngl; - strcpy(_edit_str_buf, ""); - w->vscroll.cap = 10; - } -} - -// The window below gives information about the connected clients -// and also makes able to give money to them, kick them (if server) -// and stuff like that. - -extern void DrawPlayerIcon(PlayerID pid, int x, int y); - -// Every action must be of this form -typedef void ClientList_Action_Proc(byte client_no); - -// Max 10 actions per client -#define MAX_CLIENTLIST_ACTION 10 - -// Some standard bullshit.. defines variables ;) -static void ClientListWndProc(Window *w, WindowEvent *e); -static void ClientListPopupWndProc(Window *w, WindowEvent *e); -static byte _selected_clientlist_item = 255; -static byte _selected_clientlist_y = 0; -static char _clientlist_action[MAX_CLIENTLIST_ACTION][50]; -static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION]; - -enum { - CLNWND_OFFSET = 16, - CLNWND_ROWSIZE = 10 -}; - -static const Widget _client_list_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_NETWORK_CLIENT_LIST, STR_018C_WINDOW_TITLE_DRAG_THIS}, - -{ WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 14 + CLNWND_ROWSIZE + 1, 0x0, STR_NULL}, -{ WIDGETS_END}, -}; - -static const Widget _client_list_popup_widgets[] = { -{ WWT_PANEL, RESIZE_NONE, 14, 0, 99, 0, 0, 0, STR_NULL}, -{ WIDGETS_END}, -}; - -static WindowDesc _client_list_desc = { - WDP_AUTO, WDP_AUTO, 250, 1, - WC_CLIENT_LIST,0, - WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, - _client_list_widgets, - ClientListWndProc -}; - -// Finds the Xth client-info that is active -static const NetworkClientInfo *NetworkFindClientInfo(byte client_no) -{ - const NetworkClientInfo *ci; - - FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { - if (client_no == 0) return ci; - client_no--; - } - - return NULL; -} - -// Here we start to define the options out of the menu -static void ClientList_Kick(byte client_no) -{ - if (client_no < MAX_PLAYERS) - SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED); -} - -static void ClientList_Ban(byte client_no) -{ - uint i; - uint32 ip = NetworkFindClientInfo(client_no)->client_ip; - - for (i = 0; i < lengthof(_network_ban_list); i++) { - if (_network_ban_list[i] == NULL) { - _network_ban_list[i] = strdup(inet_ntoa(*(struct in_addr *)&ip)); - break; - } - } - - if (client_no < MAX_PLAYERS) - SEND_COMMAND(PACKET_SERVER_ERROR)(DEREF_CLIENT(client_no), NETWORK_ERROR_KICKED); -} - -static void ClientList_GiveMoney(byte client_no) -{ - if (NetworkFindClientInfo(client_no) != NULL) - ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas); -} - -static void ClientList_SpeakToClient(byte client_no) -{ - if (NetworkFindClientInfo(client_no) != NULL) - ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index); -} - -static void ClientList_SpeakToCompany(byte client_no) -{ - if (NetworkFindClientInfo(client_no) != NULL) - ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas); -} - -static void ClientList_SpeakToAll(byte client_no) -{ - ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); -} - -static void ClientList_None(byte client_no) -{ - // No action ;) -} - - - -// Help, a action is clicked! What do we do? -static void HandleClientListPopupClick(byte index, byte clientno) { - // A click on the Popup of the ClientList.. handle the command - if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) { - _clientlist_proc[index](clientno); - } -} - -// Finds the amount of clients and set the height correct -static bool CheckClientListHeight(Window *w) -{ - int num = 0; - const NetworkClientInfo *ci; - - // Should be replaced with a loop through all clients - FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { - num++; - } - - num *= CLNWND_ROWSIZE; - - // If height is changed - if (w->height != CLNWND_OFFSET + num + 1) { - // XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1) - SetWindowDirty(w); - w->widget[2].bottom = w->widget[2].top + num + 2; - w->height = CLNWND_OFFSET + num + 1; - SetWindowDirty(w); - return false; - } - return true; -} - -// Finds the amount of actions in the popup and set the height correct -static uint ClientListPopupHeigth(void) { - int i, num = 0; - - // Find the amount of actions - for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) { - if (_clientlist_action[i][0] == '\0') continue; - if (_clientlist_proc[i] == NULL) continue; - num++; - } - - num *= CLNWND_ROWSIZE; - - return num + 1; -} - -// Show the popup (action list) -static Window *PopupClientList(Window *w, int client_no, int x, int y) -{ - int i, h; - const NetworkClientInfo *ci; - DeleteWindowById(WC_TOOLBAR_MENU, 0); - - // Clean the current actions - for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) { - _clientlist_action[i][0] = '\0'; - _clientlist_proc[i] = NULL; - } - - // Fill the actions this client has - // Watch is, max 50 chars long! - - ci = NetworkFindClientInfo(client_no); - if (ci == NULL) return NULL; - - i = 0; - if (_network_own_client_index != ci->client_index) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_SpeakToClient; - } - - if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_SpeakToCompany; - } - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_SpeakToAll; - - if (_network_own_client_index != ci->client_index) { - /* We are no spectator and the player we want to give money to is no spectator */ - if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_GiveMoney; - } - } - - // A server can kick clients (but not himself) - if (_network_server && _network_own_client_index != ci->client_index) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_Kick; - - sprintf(_clientlist_action[i],"Ban"); // XXX GetString? - _clientlist_proc[i++] = &ClientList_Ban; - } - - if (i == 0) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i])); - _clientlist_proc[i++] = &ClientList_None; - } - - /* Calculate the height */ - h = ClientListPopupHeigth(); - - // Allocate the popup - w = AllocateWindow(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets); - w->widget[0].bottom = w->widget[0].top + h; - w->widget[0].right = w->widget[0].left + 150; - - w->flags4 &= ~WF_WHITE_BORDER_MASK; - WP(w,menu_d).item_count = 0; - // Save our client - WP(w,menu_d).main_button = client_no; - WP(w,menu_d).sel_index = 0; - // We are a popup - _popup_menu_active = true; - - return w; -} - -/** Main handle for the client popup list - * uses menu_d WP macro */ -static void ClientListPopupWndProc(Window *w, WindowEvent *e) -{ - switch (e->event) { - case WE_PAINT: { - int i, y, sel; - byte colour; - DrawWindowWidgets(w); - - // Draw the actions - sel = WP(w,menu_d).sel_index; - y = 1; - for (i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) { - if (_clientlist_action[i][0] == '\0') continue; - if (_clientlist_proc[i] == NULL) continue; - - if (sel-- == 0) { // Selected item, highlight it - GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0); - colour = 0xC; - } else { - colour = 0x10; - } - - DoDrawString(_clientlist_action[i], 4, y, colour); - } - } break; - - case WE_POPUPMENU_SELECT: { - // We selected an action - int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE; - - if (index >= 0 && e->we.popupmenu.pt.y >= w->top) - HandleClientListPopupClick(index, WP(w,menu_d).main_button); - - DeleteWindowById(WC_TOOLBAR_MENU, 0); - } break; - - case WE_POPUPMENU_OVER: { - // Our mouse hoovers over an action? Select it! - int index = (e->we.popupmenu.pt.y - w->top) / CLNWND_ROWSIZE; - - if (index == -1 || index == WP(w,menu_d).sel_index) return; - - WP(w,menu_d).sel_index = index; - SetWindowDirty(w); - } break; - - } -} - -// Main handle for clientlist -static void ClientListWndProc(Window *w, WindowEvent *e) -{ - switch (e->event) { - case WE_PAINT: { - NetworkClientInfo *ci; - int y, i = 0; - byte colour; - - // Check if we need to reset the height - if (!CheckClientListHeight(w)) break; - - DrawWindowWidgets(w); - - y = CLNWND_OFFSET; - - FOR_ALL_ACTIVE_CLIENT_INFOS(ci) { - if (_selected_clientlist_item == i++) { // Selected item, highlight it - GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0); - colour = 0xC; - } else { - colour = 0x10; - } - - if (ci->client_index == NETWORK_SERVER_INDEX) { - DrawString(4, y, STR_NETWORK_SERVER, colour); - } else { - DrawString(4, y, STR_NETWORK_CLIENT, colour); - } - - // Filter out spectators - if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1); - - DoDrawString(ci->client_name, 81, y, colour); - - y += CLNWND_ROWSIZE; - } - } break; - - case WE_CLICK: - // Show the popup with option - if (_selected_clientlist_item != 255) { - PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top); - } - - break; - - case WE_MOUSEOVER: - // -1 means we left the current window - if (e->we.mouseover.pt.y == -1) { - _selected_clientlist_y = 0; - _selected_clientlist_item = 255; - SetWindowDirty(w); - break; - } - // It did not change.. no update! - if (e->we.mouseover.pt.y == _selected_clientlist_y) break; - - // Find the new selected item (if any) - _selected_clientlist_y = e->we.mouseover.pt.y; - if (e->we.mouseover.pt.y > CLNWND_OFFSET) { - _selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE; - } else { - _selected_clientlist_item = 255; - } - - // Repaint - SetWindowDirty(w); - break; - - case WE_DESTROY: case WE_CREATE: - // When created or destroyed, data is reset - _selected_clientlist_item = 255; - _selected_clientlist_y = 0; - break; - } -} - -void ShowClientList(void) -{ - AllocateWindowDescFront(&_client_list_desc, 0); -} - - -static NetworkPasswordType pw_type; - - -void ShowNetworkNeedPassword(NetworkPasswordType npt) -{ - StringID caption; - - pw_type = npt; - switch (npt) { - default: NOT_REACHED(); - case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break; - case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break; - } - ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL); -} - - -static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e) -{ - switch (e->event) { - case WE_PAINT: { - uint8 progress; // used for progress bar - DrawWindowWidgets(w); - - DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, 14); - switch (_network_join_status) { - case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING: - case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO: - progress = 10; // first two stages 10% - break; - case NETWORK_JOIN_STATUS_WAITING: - SetDParam(0, _network_join_waiting); - DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, 14); - progress = 15; // third stage is 15% - break; - case NETWORK_JOIN_STATUS_DOWNLOADING: - SetDParam(0, _network_join_kbytes); - SetDParam(1, _network_join_kbytes_total); - DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, 14); - /* Fallthrough */ - default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */ - progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total; - } - - /* Draw nice progress bar :) */ - DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, 0); - } break; - - case WE_CLICK: - switch (e->we.click.widget) { - case 2: /* Disconnect button */ - NetworkDisconnect(); - DeleteWindow(w); - SwitchMode(SM_MENU); - ShowNetworkGameWindow(); - break; - } - break; - - /* If the server asks for a password, we need to fill it in */ - case WE_ON_EDIT_TEXT_CANCEL: - NetworkDisconnect(); - ShowNetworkGameWindow(); - break; - - case WE_ON_EDIT_TEXT: - SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str); - break; - } -} - -static const Widget _network_join_status_window_widget[] = { -{ WWT_CAPTION, RESIZE_NONE, 14, 0, 249, 0, 13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS}, -{ WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 84, 0x0, STR_NULL}, -{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 75, 175, 69, 80, STR_NETWORK_DISCONNECT, STR_NULL}, -{ WIDGETS_END}, -}; - -static const WindowDesc _network_join_status_window_desc = { - WDP_CENTER, WDP_CENTER, 250, 85, - WC_NETWORK_STATUS_WINDOW, 0, - WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL, - _network_join_status_window_widget, - NetworkJoinStatusWindowWndProc, -}; - -void ShowJoinStatusWindow(void) -{ - Window *w; - DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0); - w = AllocateWindowDesc(&_network_join_status_window_desc); - /* Parent the status window to the lobby */ - if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0); -} - -static void SendChat(const char *buf, DestType type, byte dest) -{ - if (buf[0] == '\0') return; - if (!_network_server) { - SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT + type, type, dest, buf); - } else { - NetworkServer_HandleChat(NETWORK_ACTION_CHAT + type, type, dest, buf, NETWORK_SERVER_INDEX); - } -} - -/** - * Find the next item of the list of things that can be auto-completed. - * @param item The current indexed item to return. This function can, and most - * likely will, alter item, to skip empty items in the arrays. - * @return Returns the char that matched to the index. - */ -static const char *ChatTabCompletionNextItem(uint *item) -{ - static char chat_tab_temp_buffer[64]; - - /* First, try clients */ - if (*item < MAX_CLIENT_INFO) { - /* Skip inactive clients */ - while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++; - if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name; - } - - /* Then, try townnames */ - /* Not that the following assumes all town indices are adjacent, ie no - * towns have been deleted. */ - if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) { - const Town *t; - - FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) { - /* Get the town-name via the string-system */ - SetDParam(0, t->townnameparts); - GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer)); - return &chat_tab_temp_buffer[0]; - } - } - - return NULL; -} - -/** - * Find what text to complete. It scans for a space from the left and marks - * the word right from that as to complete. It also writes a \0 at the - * position of the space (if any). If nothing found, buf is returned. - */ -static char *ChatTabCompletionFindText(char *buf) -{ - char *p = strrchr(buf, ' '); - if (p == NULL) return buf; - - *p = '\0'; - return p + 1; -} - -/** - * See if we can auto-complete the current text of the user. - */ -static void ChatTabCompletion(Window *w) -{ - static char _chat_tab_completion_buf[lengthof(_edit_str_buf)]; - Textbuf *tb = &WP(w, querystr_d).text; - uint len, tb_len; - uint item; - char *tb_buf, *pre_buf; - const char *cur_name; - bool second_scan = false; - - item = 0; - - /* Copy the buffer so we can modify it without damaging the real data */ - pre_buf = (_chat_tab_completion_active) ? strdup(_chat_tab_completion_buf) : strdup(tb->buf); - - tb_buf = ChatTabCompletionFindText(pre_buf); - tb_len = strlen(tb_buf); - - while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) { - item++; - - if (_chat_tab_completion_active) { - /* We are pressing TAB again on the same name, is there an other name - * that starts with this? */ - if (!second_scan) { - uint offset; - uint length; - - /* If we are completing at the begin of the line, skip the ': ' we added */ - if (tb_buf == pre_buf) { - offset = 0; - length = tb->length - 2; - } else { - /* Else, find the place we are completing at */ - offset = strlen(pre_buf) + 1; - length = tb->length - offset; - } - - /* Compare if we have a match */ - if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true; - - continue; - } - - /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ - } - - len = strlen(cur_name); - if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) { - /* Save the data it was before completion */ - if (!second_scan) snprintf(_chat_tab_completion_buf, lengthof(_chat_tab_completion_buf), "%s", tb->buf); - _chat_tab_completion_active = true; - - /* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ - if (pre_buf == tb_buf) { - snprintf(tb->buf, lengthof(_edit_str_buf), "%s: ", cur_name); - } else { - snprintf(tb->buf, lengthof(_edit_str_buf), "%s %s", pre_buf, cur_name); - } - - /* Update the textbuffer */ - UpdateTextBufferSize(&WP(w, querystr_d).text); - - SetWindowDirty(w); - free(pre_buf); - return; - } - } - - if (second_scan) { - /* We walked all posibilities, and the user presses tab again.. revert to original text */ - strcpy(tb->buf, _chat_tab_completion_buf); - _chat_tab_completion_active = false; - - /* Update the textbuffer */ - UpdateTextBufferSize(&WP(w, querystr_d).text); - - SetWindowDirty(w); - } - free(pre_buf); -} - -/* uses querystr_d WP macro - * uses querystr_d->caption to store - * - type of chat message (Private/Team/All) in bytes 0-7 - * - destination of chat message in the case of Team/Private in bytes 8-15 */ -static void ChatWindowWndProc(Window *w, WindowEvent *e) -{ - switch (e->event) { - case WE_CREATE: - SendWindowMessage(WC_NEWS_WINDOW, 0, WE_CREATE, w->height, 0); - SETBIT(_no_scroll, SCROLL_CHAT); // do not scroll the game with the arrow-keys - break; - - case WE_PAINT: { - static const StringID chat_captions[] = { - STR_NETWORK_CHAT_ALL_CAPTION, - STR_NETWORK_CHAT_COMPANY_CAPTION, - STR_NETWORK_CHAT_CLIENT_CAPTION - }; - StringID msg; - - DrawWindowWidgets(w); - - assert(GB(WP(w, querystr_d).caption, 0, 8) < lengthof(chat_captions)); - msg = chat_captions[GB(WP(w, querystr_d).caption, 0, 8)]; - DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, msg, 16); - DrawEditBox(w, &WP(w, querystr_d), 2); - } break; - - case WE_CLICK: - switch (e->we.click.widget) { - case 3: { /* Send */ - DestType type = GB(WP(w, querystr_d).caption, 0, 8); - byte dest = GB(WP(w, querystr_d).caption, 8, 8); - SendChat(WP(w, querystr_d).text.buf, type, dest); - } /* FALLTHROUGH */ - case 0: /* Cancel */ DeleteWindow(w); break; - } - break; - - case WE_MOUSELOOP: - HandleEditBox(w, &WP(w, querystr_d), 2); - break; - - case WE_KEYPRESS: - if (e->we.keypress.keycode == WKC_TAB) { - ChatTabCompletion(w); - } else { - _chat_tab_completion_active = false; - switch (HandleEditBoxKey(w, &WP(w, querystr_d), 2, e)) { - case 1: { /* Return */ - DestType type = GB(WP(w, querystr_d).caption, 0, 8); - byte dest = GB(WP(w, querystr_d).caption, 8, 8); - SendChat(WP(w, querystr_d).text.buf, type, dest); - } /* FALLTHROUGH */ - case 2: /* Escape */ DeleteWindow(w); break; - } - } - break; - - case WE_DESTROY: - SendWindowMessage(WC_NEWS_WINDOW, 0, WE_DESTROY, 0, 0); - CLRBIT(_no_scroll, SCROLL_CHAT); - break; - } -} - -static const Widget _chat_window_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_PANEL, RESIZE_NONE, 14, 11, 639, 0, 13, 0x0, STR_NULL}, // background -{ WWT_PANEL, RESIZE_NONE, 14, 75, 577, 1, 12, 0x0, STR_NULL}, // text box -{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 578, 639, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button -{ WIDGETS_END}, -}; - -static const WindowDesc _chat_window_desc = { - WDP_CENTER, -26, 640, 14, // x, y, width, height - WC_SEND_NETWORK_MSG,0, - WDF_STD_TOOLTIPS | WDF_DEF_WIDGET, - _chat_window_widgets, - ChatWindowWndProc -}; - -void ShowNetworkChatQueryWindow(DestType type, byte dest) -{ - Window *w; - - DeleteWindowById(WC_SEND_NETWORK_MSG, 0); - - _edit_str_buf[0] = '\0'; - _chat_tab_completion_active = false; - - w = AllocateWindowDesc(&_chat_window_desc); - - LowerWindowWidget(w, 2); - WP(w, querystr_d).caption = GB(type, 0, 8) | (dest << 8); // Misuse of caption - WP(w, querystr_d).afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&WP(w, querystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 0); -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_gui.h --- a/network_gui.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_GUI_H -#define NETWORK_GUI_H - -#ifdef ENABLE_NETWORK - -#include "network_data.h" - -void ShowNetworkNeedPassword(NetworkPasswordType npt); -void ShowNetworkGiveMoneyWindow(byte player); // PlayerID -void ShowNetworkChatQueryWindow(DestType type, byte dest); -void ShowJoinStatusWindow(void); -void ShowNetworkGameWindow(void); -void ShowClientList(void); - -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void ShowNetworkChatQueryWindow(byte desttype, byte dest) {} -static inline void ShowClientList(void) {} -static inline void ShowNetworkGameWindow(void) {} - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_GUI_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_server.c --- a/network_server.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1527 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "openttd.h" // XXX StringID -#include "debug.h" -#include "string.h" -#include "strings.h" -#include "network_data.h" -#include "train.h" -#include "date.h" -#include "table/strings.h" -#include "functions.h" -#include "network_server.h" -#include "network_udp.h" -#include "console.h" -#include "command.h" -#include "saveload.h" -#include "vehicle.h" -#include "station.h" -#include "variables.h" -#include "genworld.h" - -// This file handles all the server-commands - -static void NetworkHandleCommandQueue(NetworkClientState* cs); - -// ********** -// Sending functions -// DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs -// ********** - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci) -{ - // - // Packet: SERVER_CLIENT_INFO - // Function: Sends info about a client - // Data: - // uint16: The index of the client (always unique on a server. 1 = server) - // uint8: As which player the client is playing - // String: The name of the client - // String: The unique id of the client - // - - if (ci->client_index != NETWORK_EMPTY_INDEX) { - Packet *p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO); - NetworkSend_uint16(p, ci->client_index); - NetworkSend_uint8 (p, ci->client_playas); - NetworkSend_string(p, ci->client_name); - NetworkSend_string(p, ci->unique_id); - - NetworkSend_Packet(p, cs); - } -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_COMPANY_INFO) -{ -// - // Packet: SERVER_COMPANY_INFO - // Function: Sends info about the companies - // Data: - // - - int i; - - Player *player; - Packet *p; - - byte active = ActivePlayerCount(); - - if (active == 0) { - p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); - - NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); - NetworkSend_uint8 (p, active); - - NetworkSend_Packet(p, cs); - return; - } - - NetworkPopulateCompanyInfo(); - - FOR_ALL_PLAYERS(player) { - if (!player->is_active) continue; - - p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); - - NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); - NetworkSend_uint8 (p, active); - NetworkSend_uint8 (p, player->index); - - NetworkSend_string(p, _network_player_info[player->index].company_name); - NetworkSend_uint32(p, _network_player_info[player->index].inaugurated_year); - NetworkSend_uint64(p, _network_player_info[player->index].company_value); - NetworkSend_uint64(p, _network_player_info[player->index].money); - NetworkSend_uint64(p, _network_player_info[player->index].income); - NetworkSend_uint16(p, _network_player_info[player->index].performance); - - /* Send 1 if there is a passord for the company else send 0 */ - if (_network_player_info[player->index].password[0] != '\0') { - NetworkSend_uint8(p, 1); - } else { - NetworkSend_uint8(p, 0); - } - - for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) { - NetworkSend_uint16(p, _network_player_info[player->index].num_vehicle[i]); - } - - for (i = 0; i < NETWORK_STATION_TYPES; i++) { - NetworkSend_uint16(p, _network_player_info[player->index].num_station[i]); - } - - if (_network_player_info[player->index].players[0] == '\0') { - NetworkSend_string(p, ""); - } else { - NetworkSend_string(p, _network_player_info[player->index].players); - } - - NetworkSend_Packet(p, cs); - } - - p = NetworkSend_Init(PACKET_SERVER_COMPANY_INFO); - - NetworkSend_uint8 (p, NETWORK_COMPANY_INFO_VERSION); - NetworkSend_uint8 (p, 0); - - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error) -{ - // - // Packet: SERVER_ERROR - // Function: The client made an error - // Data: - // uint8: ErrorID (see network_data.h, NetworkErrorCode) - // - - char str[100]; - Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR); - - NetworkSend_uint8(p, error); - NetworkSend_Packet(p, cs); - - GetNetworkErrorMsg(str, error, lastof(str)); - - // Only send when the current client was in game - if (cs->status > STATUS_AUTH) { - NetworkClientState *new_cs; - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str); - - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); - - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status > STATUS_AUTH && new_cs != cs) { - // Some errors we filter to a more general error. Clients don't have to know the real - // reason a joining failed. - if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) - error = NETWORK_ERROR_ILLEGAL_PACKET; - - SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, error); - } - } - } else { - DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->index, str); - } - - cs->has_quit = true; - - // Make sure the data get's there before we close the connection - NetworkSend_Packets(cs); - - // The client made a mistake, so drop his connection now! - NetworkCloseClient(cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type) -{ - // - // Packet: SERVER_NEED_PASSWORD - // Function: Indication to the client that the server needs a password - // Data: - // uint8: Type of password - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD); - NetworkSend_uint8(p, type); - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME) -{ - // - // Packet: SERVER_WELCOME - // Function: The client is joined and ready to receive his map - // Data: - // uint16: Own ClientID - // - - Packet *p; - const NetworkClientState *new_cs; - - // Invalid packet when status is AUTH or higher - if (cs->status >= STATUS_AUTH) return; - - cs->status = STATUS_AUTH; - _network_game_info.clients_on++; - - p = NetworkSend_Init(PACKET_SERVER_WELCOME); - NetworkSend_uint16(p, cs->index); - NetworkSend_Packet(p, cs); - - // Transmit info about all the active clients - FOR_ALL_CLIENTS(new_cs) { - if (new_cs != cs && new_cs->status > STATUS_AUTH) - SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, DEREF_CLIENT_INFO(new_cs)); - } - // Also send the info of the server - SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX)); -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WAIT) -{ - // - // Packet: PACKET_SERVER_WAIT - // Function: The client can not receive the map at the moment because - // someone else is already receiving the map - // Data: - // uint8: Clients awaiting map - // - int waiting = 0; - NetworkClientState *new_cs; - Packet *p; - - // Count how many players are waiting in the queue - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status == STATUS_MAP_WAIT) waiting++; - } - - p = NetworkSend_Init(PACKET_SERVER_WAIT); - NetworkSend_uint8(p, waiting); - NetworkSend_Packet(p, cs); -} - -// This sends the map to the client -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP) -{ - // - // Packet: SERVER_MAP - // Function: Sends the map to the client, or a part of it (it is splitted in - // a lot of multiple packets) - // Data: - // uint8: packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END) - // if MAP_PACKET_START: - // uint32: The current FrameCounter - // if MAP_PACKET_NORMAL: - // piece of the map (till max-size of packet) - // if MAP_PACKET_END: - // uint32: seed0 of player - // uint32: seed1 of player - // last 2 are repeated MAX_PLAYERS time - // - - static FILE *file_pointer; - static uint sent_packets; // How many packets we did send succecfully last time - - if (cs->status < STATUS_AUTH) { - // Illegal call, return error and ignore the packet - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED); - return; - } - - if (cs->status == STATUS_AUTH) { - char filename[256]; - Packet *p; - - // Make a dump of the current game - snprintf(filename, lengthof(filename), "%s%snetwork_server.tmp", _paths.autosave_dir, PATHSEP); - if (SaveOrLoad(filename, SL_SAVE) != SL_OK) error("network savedump failed"); - - file_pointer = fopen(filename, "rb"); - fseek(file_pointer, 0, SEEK_END); - - // Now send the _frame_counter and how many packets are coming - p = NetworkSend_Init(PACKET_SERVER_MAP); - NetworkSend_uint8(p, MAP_PACKET_START); - NetworkSend_uint32(p, _frame_counter); - NetworkSend_uint32(p, ftell(file_pointer)); - NetworkSend_Packet(p, cs); - - fseek(file_pointer, 0, SEEK_SET); - - sent_packets = 4; // We start with trying 4 packets - - cs->status = STATUS_MAP; - /* Mark the start of download */ - cs->last_frame = _frame_counter; - cs->last_frame_server = _frame_counter; - } - - if (cs->status == STATUS_MAP) { - uint i; - int res; - for (i = 0; i < sent_packets; i++) { - Packet *p = NetworkSend_Init(PACKET_SERVER_MAP); - NetworkSend_uint8(p, MAP_PACKET_NORMAL); - res = (int)fread(p->buffer + p->size, 1, SEND_MTU - p->size, file_pointer); - - if (ferror(file_pointer)) error("Error reading temporary network savegame!"); - - p->size += res; - NetworkSend_Packet(p, cs); - if (feof(file_pointer)) { - // Done reading! - Packet *p = NetworkSend_Init(PACKET_SERVER_MAP); - NetworkSend_uint8(p, MAP_PACKET_END); - NetworkSend_Packet(p, cs); - - // Set the status to DONE_MAP, no we will wait for the client - // to send it is ready (maybe that happens like never ;)) - cs->status = STATUS_DONE_MAP; - fclose(file_pointer); - - { - NetworkClientState *new_cs; - bool new_map_client = false; - // Check if there is a client waiting for receiving the map - // and start sending him the map - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status == STATUS_MAP_WAIT) { - // Check if we already have a new client to send the map to - if (!new_map_client) { - // If not, this client will get the map - new_cs->status = STATUS_AUTH; - new_map_client = true; - SEND_COMMAND(PACKET_SERVER_MAP)(new_cs); - } else { - // Else, send the other clients how many clients are in front of them - SEND_COMMAND(PACKET_SERVER_WAIT)(new_cs); - } - } - } - } - - // There is no more data, so break the for - break; - } - } - - // Send all packets (forced) and check if we have send it all - NetworkSend_Packets(cs); - if (cs->packet_queue == NULL) { - // All are sent, increase the sent_packets - sent_packets *= 2; - } else { - // Not everything is sent, decrease the sent_packets - if (sent_packets > 1) sent_packets /= 2; - } - } -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index) -{ - // - // Packet: SERVER_JOIN - // Function: A client is joined (all active clients receive this after a - // PACKET_CLIENT_MAP_OK) Mostly what directly follows is a - // PACKET_SERVER_CLIENT_INFO - // Data: - // uint16: Client-Index - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN); - - NetworkSend_uint16(p, client_index); - - NetworkSend_Packet(p, cs); -} - - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME) -{ - // - // Packet: SERVER_FRAME - // Function: Sends the current frame-counter to the client - // Data: - // uint32: Frame Counter - // uint32: Frame Counter Max (how far may the client walk before the server?) - // [uint32: general-seed-1] - // [uint32: general-seed-2] - // (last two depends on compile-settings, and are not default settings) - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_FRAME); - NetworkSend_uint32(p, _frame_counter); - NetworkSend_uint32(p, _frame_counter_max); -#ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME - NetworkSend_uint32(p, _sync_seed_1); -#ifdef NETWORK_SEND_DOUBLE_SEED - NetworkSend_uint32(p, _sync_seed_2); -#endif -#endif - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SYNC) -{ - // - // Packet: SERVER_SYNC - // Function: Sends a sync-check to the client - // Data: - // uint32: Frame Counter - // uint32: General-seed-1 - // [uint32: general-seed-2] - // (last one depends on compile-settings, and are not default settings) - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_SYNC); - NetworkSend_uint32(p, _frame_counter); - NetworkSend_uint32(p, _sync_seed_1); - -#ifdef NETWORK_SEND_DOUBLE_SEED - NetworkSend_uint32(p, _sync_seed_2); -#endif - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp) -{ - // - // Packet: SERVER_COMMAND - // Function: Sends a DoCommand to the client - // Data: - // uint8: PlayerID (0..MAX_PLAYERS-1) - // uint32: CommandID (see command.h) - // uint32: P1 (free variables used in DoCommand) - // uint32: P2 - // uint32: Tile - // string: text - // uint8: CallBackID (see callback_table.c) - // uint32: Frame of execution - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_COMMAND); - - NetworkSend_uint8(p, cp->player); - NetworkSend_uint32(p, cp->cmd); - NetworkSend_uint32(p, cp->p1); - NetworkSend_uint32(p, cp->p2); - NetworkSend_uint32(p, cp->tile); - NetworkSend_string(p, cp->text); - NetworkSend_uint8(p, cp->callback); - NetworkSend_uint32(p, cp->frame); - - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, bool self_send, const char *msg) -{ - // - // Packet: SERVER_CHAT - // Function: Sends a chat-packet to the client - // Data: - // uint8: ActionID (see network_data.h, NetworkAction) - // uint16: Client-index - // String: Message (max MAX_TEXT_MSG_LEN) - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT); - - NetworkSend_uint8(p, action); - NetworkSend_uint16(p, client_index); - NetworkSend_uint8(p, self_send); - NetworkSend_string(p, msg); - - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno) -{ - // - // Packet: SERVER_ERROR_QUIT - // Function: One of the clients made an error and is quiting the game - // This packet informs the other clients of that. - // Data: - // uint16: Client-index - // uint8: ErrorID (see network_data.h, NetworkErrorCode) - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT); - - NetworkSend_uint16(p, client_index); - NetworkSend_uint8(p, errorno); - - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg) -{ - // - // Packet: SERVER_ERROR_QUIT - // Function: A client left the game, and this packets informs the other clients - // of that. - // Data: - // uint16: Client-index - // String: leave-message - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT); - - NetworkSend_uint16(p, client_index); - NetworkSend_string(p, leavemsg); - - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN) -{ - // - // Packet: SERVER_SHUTDOWN - // Function: Let the clients know that the server is closing - // Data: - // - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_SHUTDOWN); - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME) -{ - // - // Packet: PACKET_SERVER_NEWGAME - // Function: Let the clients know that the server is loading a new map - // Data: - // - // - - Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME); - NetworkSend_Packet(p, cs); -} - -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command) -{ - Packet *p = NetworkSend_Init(PACKET_SERVER_RCON); - - NetworkSend_uint16(p, color); - NetworkSend_string(p, command); - NetworkSend_Packet(p, cs); -} - -// ********** -// Receiving functions -// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p -// ********** - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO) -{ - SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs); -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) -{ - char name[NETWORK_CLIENT_NAME_LENGTH]; - char unique_id[NETWORK_NAME_LENGTH]; - NetworkClientInfo *ci; - byte playas; - NetworkLanguage client_lang; - char client_revision[NETWORK_REVISION_LENGTH]; - - NetworkRecv_string(cs, p, client_revision, sizeof(client_revision)); - -#if defined(WITH_REV) || defined(WITH_REV_HACK) - // Check if the client has revision control enabled - if (strcmp(NOREV_STRING, client_revision) != 0 && - strcmp(_network_game_info.server_revision, client_revision) != 0) { - // Different revisions!! - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_REVISION); - return; - } -#endif - - NetworkRecv_string(cs, p, name, sizeof(name)); - playas = NetworkRecv_uint8(cs, p); - client_lang = NetworkRecv_uint8(cs, p); - NetworkRecv_string(cs, p, unique_id, sizeof(unique_id)); - - if (cs->has_quit) return; - - // join another company does not affect these values - switch (playas) { - case PLAYER_NEW_COMPANY: /* New company */ - if (ActivePlayerCount() >= _network_game_info.companies_max) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL); - return; - } - break; - case PLAYER_SPECTATOR: /* Spectator */ - if (NetworkSpectatorCount() >= _network_game_info.spectators_max) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_FULL); - return; - } - break; - default: /* Join another company (companies 1-8 (index 0-7)) */ - if (!IsValidPlayer(playas)) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH); - return; - } - break; - } - - // We need a valid name.. make it Player - if (*name == '\0') ttd_strlcpy(name, "Player", sizeof(name)); - - if (!NetworkFindName(name)) { // Change name if duplicate - // We could not create a name for this player - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NAME_IN_USE); - return; - } - - ci = DEREF_CLIENT_INFO(cs); - - ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name)); - ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id)); - ci->client_playas = playas; - ci->client_lang = client_lang; - - // We now want a password from the client - // else we do not allow him in! - if (_network_game_info.use_password) { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); - } else { - if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); - } else { - SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); - } - } - - /* Make sure companies to which people try to join are not autocleaned */ - if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0; -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD) -{ - NetworkPasswordType type; - char password[NETWORK_PASSWORD_LENGTH]; - const NetworkClientInfo *ci; - - type = NetworkRecv_uint8(cs, p); - NetworkRecv_string(cs, p, password, sizeof(password)); - - if (cs->status == STATUS_INACTIVE && type == NETWORK_GAME_PASSWORD) { - // Check game-password - if (strcmp(password, _network_game_info.server_password) != 0) { - // Password is invalid - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD); - return; - } - - ci = DEREF_CLIENT_INFO(cs); - - if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); - return; - } - - // Valid password, allow user - SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); - return; - } else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) { - ci = DEREF_CLIENT_INFO(cs); - - if (strcmp(password, _network_player_info[ci->client_playas].password) != 0) { - // Password is invalid - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD); - return; - } - - SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); - return; - } - - - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); - return; -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP) -{ - const NetworkClientState *new_cs; - - // The client was never joined.. so this is impossible, right? - // Ignore the packet, give the client a warning, and close his connection - if (cs->status < STATUS_AUTH || cs->has_quit) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED); - return; - } - - // Check if someone else is receiving the map - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status == STATUS_MAP) { - // Tell the new client to wait - cs->status = STATUS_MAP_WAIT; - SEND_COMMAND(PACKET_SERVER_WAIT)(cs); - return; - } - } - - // We receive a request to upload the map.. give it to the client! - SEND_COMMAND(PACKET_SERVER_MAP)(cs); -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK) -{ - // Client has the map, now start syncing - if (cs->status == STATUS_DONE_MAP && !cs->has_quit) { - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - NetworkClientState *new_cs; - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - NetworkTextMessage(NETWORK_ACTION_JOIN, 1, false, client_name, ""); - - // Mark the client as pre-active, and wait for an ACK - // so we know he is done loading and in sync with us - cs->status = STATUS_PRE_ACTIVE; - NetworkHandleCommandQueue(cs); - SEND_COMMAND(PACKET_SERVER_FRAME)(cs); - SEND_COMMAND(PACKET_SERVER_SYNC)(cs); - - // This is the frame the client receives - // we need it later on to make sure the client is not too slow - cs->last_frame = _frame_counter; - cs->last_frame_server = _frame_counter; - - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status > STATUS_AUTH) { - SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(new_cs, DEREF_CLIENT_INFO(cs)); - SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index); - } - } - - if (_network_pause_on_join) { - /* Now pause the game till the client is in sync */ - DoCommandP(0, 1, 0, NULL, CMD_PAUSE); - - NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX); - } - } else { - // Wrong status for this packet, give a warning to client, and close connection - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); - } -} - -/** Enforce the command flags. - * Eg a server-only command can only be executed by a server, etc. - * @param *cp the commandpacket that is going to be checked - * @param *ci client information for debugging output to console - */ -static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci) -{ - byte flags = GetCommandFlags(cp->cmd); - - if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) { - IConsolePrintF(_icolour_err, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci)); - return false; - } - - if (flags & CMD_OFFLINE) { - IConsolePrintF(_icolour_err, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetPlayerIP(ci)); - return false; - } - - return true; -} - -/** The client has done a command and wants us to handle it - * @param *cs the connected client that has sent the command - * @param *p the packet in which the command was sent - */ -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) -{ - NetworkClientState *new_cs; - const NetworkClientInfo *ci; - byte callback; - - CommandPacket *cp = malloc(sizeof(CommandPacket)); - - // The client was never joined.. so this is impossible, right? - // Ignore the packet, give the client a warning, and close his connection - if (cs->status < STATUS_DONE_MAP || cs->has_quit) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); - return; - } - - cp->player = NetworkRecv_uint8(cs, p); - cp->cmd = NetworkRecv_uint32(cs, p); - cp->p1 = NetworkRecv_uint32(cs, p); - cp->p2 = NetworkRecv_uint32(cs, p); - cp->tile = NetworkRecv_uint32(cs, p); - NetworkRecv_string(cs, p, cp->text, lengthof(cp->text)); - - callback = NetworkRecv_uint8(cs, p); - - if (cs->has_quit) return; - - ci = DEREF_CLIENT_INFO(cs); - - /* Check if cp->cmd is valid */ - if (!IsValidCommand(cp->cmd)) { - IConsolePrintF(_icolour_err, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetPlayerIP(ci)); - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); - return; - } - - if (!CheckCommandFlags(cp, ci)) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED); - return; - } - - /** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs - * to match the player in the packet. If it doesn't, the client has done - * something pretty naughty (or a bug), and will be kicked - */ - if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas != cp->player) { - IConsolePrintF(_icolour_err, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...", - ci->client_playas + 1, GetPlayerIP(ci), cp->player + 1); - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH); - return; - } - - /** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the - * player the correct ID, the server injects p2 and executes the command. Any other p1 - * is prohibited. Pretty ugly and should be redone together with its function. - * @see CmdPlayerCtrl() players.c:655 - */ - if (cp->cmd == CMD_PLAYER_CTRL) { - if (cp->p1 != 0) { - SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER); - return; - } - - /* XXX - Execute the command as a valid player. Normally this would be done by a - * spectator, but that is not allowed any commands. So do an impersonation. The drawback - * of this is that the first company's last_built_tile is also updated... */ - cp->player = 0; - cp->p2 = cs - _clients; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl - } - - // The frame can be executed in the same frame as the next frame-packet - // That frame just before that frame is saved in _frame_counter_max - cp->frame = _frame_counter_max + 1; - cp->next = NULL; - - // Queue the command for the clients (are send at the end of the frame - // if they can handle it ;)) - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status >= STATUS_MAP) { - // Callbacks are only send back to the client who sent them in the - // first place. This filters that out. - cp->callback = (new_cs != cs) ? 0 : callback; - NetworkAddCommandQueue(new_cs, cp); - } - } - - cp->callback = 0; - // Queue the command on the server - if (_local_command_queue == NULL) { - _local_command_queue = cp; - } else { - // Find last packet - CommandPacket *c = _local_command_queue; - while (c->next != NULL) c = c->next; - c->next = cp; - } -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR) -{ - // This packets means a client noticed an error and is reporting this - // to us. Display the error and report it to the other clients - NetworkClientState *new_cs; - char str[100]; - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - NetworkErrorCode errorno = NetworkRecv_uint8(cs, p); - - // The client was never joined.. thank the client for the packet, but ignore it - if (cs->status < STATUS_DONE_MAP || cs->has_quit) { - cs->has_quit = true; - return; - } - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - GetNetworkErrorMsg(str, errorno, lastof(str)); - - DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str); - - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); - - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status > STATUS_AUTH) { - SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno); - } - } - - cs->has_quit = true; -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT) -{ - // The client wants to leave. Display this and report it to the other - // clients. - NetworkClientState *new_cs; - char str[100]; - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - // The client was never joined.. thank the client for the packet, but ignore it - if (cs->status < STATUS_DONE_MAP || cs->has_quit) { - cs->has_quit = true; - return; - } - - NetworkRecv_string(cs, p, str, lengthof(str)); - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); - - FOR_ALL_CLIENTS(new_cs) { - if (new_cs->status > STATUS_AUTH) { - SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str); - } - } - - cs->has_quit = true; -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK) -{ - uint32 frame = NetworkRecv_uint32(cs, p); - - /* The client is trying to catch up with the server */ - if (cs->status == STATUS_PRE_ACTIVE) { - /* The client is not yet catched up? */ - if (frame + DAY_TICKS < _frame_counter) return; - - /* Now he is! Unpause the game */ - cs->status = STATUS_ACTIVE; - - if (_network_pause_on_join) { - DoCommandP(0, 0, 0, NULL, CMD_PAUSE); - NetworkServer_HandleChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", NETWORK_SERVER_INDEX); - } - - CheckMinPlayers(); - - /* Execute script for, e.g. MOTD */ - IConsoleCmdExec("exec scripts/on_server_connect.scr 0"); - } - - // The client received the frame, make note of it - cs->last_frame = frame; - // With those 2 values we can calculate the lag realtime - cs->last_frame_server = _frame_counter; -} - - - -void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index) -{ - NetworkClientState *cs; - const NetworkClientInfo *ci, *ci_own, *ci_to; - - switch (desttype) { - case DESTTYPE_CLIENT: - /* Are we sending to the server? */ - if (dest == NETWORK_SERVER_INDEX) { - ci = NetworkFindClientInfoFromIndex(from_index); - /* Display the text locally, and that is it */ - if (ci != NULL) - NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); - } else { - /* Else find the client to send the message to */ - FOR_ALL_CLIENTS(cs) { - if (cs->index == dest) { - SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); - break; - } - } - } - - // Display the message locally (so you know you have sent it) - if (from_index != dest) { - if (from_index == NETWORK_SERVER_INDEX) { - ci = NetworkFindClientInfoFromIndex(from_index); - ci_to = NetworkFindClientInfoFromIndex(dest); - if (ci != NULL && ci_to != NULL) - NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), true, ci_to->client_name, "%s", msg); - } else { - FOR_ALL_CLIENTS(cs) { - if (cs->index == from_index) { - SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg); - break; - } - } - } - } - break; - case DESTTYPE_TEAM: { - bool show_local = true; // If this is false, the message is already displayed - // on the client who did sent it. - /* Find all clients that belong to this player */ - ci_to = NULL; - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (ci->client_playas == dest) { - SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); - if (cs->index == from_index) show_local = false; - ci_to = ci; // Remember a client that is in the company for company-name - } - } - - ci = NetworkFindClientInfoFromIndex(from_index); - ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) { - NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); - if (from_index == NETWORK_SERVER_INDEX) show_local = false; - ci_to = ci_own; - } - - /* There is no such player */ - if (ci_to == NULL) break; - - // Display the message locally (so you know you have sent it) - if (ci != NULL && show_local) { - if (from_index == NETWORK_SERVER_INDEX) { - char name[NETWORK_NAME_LENGTH]; - StringID str = IsValidPlayer(ci_to->client_playas) ? GetPlayer(ci_to->client_playas)->name_1 : STR_NETWORK_SPECTATORS; - GetString(name, str, lastof(name)); - NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg); - } else { - FOR_ALL_CLIENTS(cs) { - if (cs->index == from_index) { - SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg); - } - } - } - } - } - break; - default: - DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype); - /* fall-through to next case */ - case DESTTYPE_BROADCAST: - FOR_ALL_CLIENTS(cs) { - SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg); - } - ci = NetworkFindClientInfoFromIndex(from_index); - if (ci != NULL) - NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas), false, ci->client_name, "%s", msg); - break; - } -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT) -{ - NetworkAction action = NetworkRecv_uint8(cs, p); - DestType desttype = NetworkRecv_uint8(cs, p); - int dest = NetworkRecv_uint8(cs, p); - char msg[MAX_TEXT_MSG_LEN]; - - NetworkRecv_string(cs, p, msg, MAX_TEXT_MSG_LEN); - - NetworkServer_HandleChat(action, desttype, dest, msg, cs->index); -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD) -{ - char password[NETWORK_PASSWORD_LENGTH]; - const NetworkClientInfo *ci; - - NetworkRecv_string(cs, p, password, sizeof(password)); - ci = DEREF_CLIENT_INFO(cs); - - if (IsValidPlayer(ci->client_playas)) { - ttd_strlcpy(_network_player_info[ci->client_playas].password, password, sizeof(_network_player_info[0].password)); - } -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME) -{ - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - NetworkClientInfo *ci; - - NetworkRecv_string(cs, p, client_name, sizeof(client_name)); - ci = DEREF_CLIENT_INFO(cs); - - if (cs->has_quit) return; - - if (ci != NULL) { - // Display change - if (NetworkFindName(client_name)) { - NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", client_name); - ttd_strlcpy(ci->client_name, client_name, sizeof(ci->client_name)); - NetworkUpdateClientInfo(ci->client_index); - } - } -} - -DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON) -{ - char pass[NETWORK_PASSWORD_LENGTH]; - char command[NETWORK_RCONCOMMAND_LENGTH]; - - if (_network_game_info.rcon_password[0] == '\0') return; - - NetworkRecv_string(cs, p, pass, sizeof(pass)); - NetworkRecv_string(cs, p, command, sizeof(command)); - - if (strcmp(pass, _network_game_info.rcon_password) != 0) { - DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->index); - return; - } - - DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->index, command); - - _redirect_console_to_client = cs->index; - IConsoleCmdExec(command); - _redirect_console_to_client = 0; - return; -} - -// The layout for the receive-functions by the server -typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p); - - -// This array matches PacketType. At an incoming -// packet it is matches against this array -// and that way the right function to handle that -// packet is found. -static NetworkServerPacket* const _network_server_packet[] = { - NULL, /*PACKET_SERVER_FULL,*/ - NULL, /*PACKET_SERVER_BANNED,*/ - RECEIVE_COMMAND(PACKET_CLIENT_JOIN), - NULL, /*PACKET_SERVER_ERROR,*/ - RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO), - NULL, /*PACKET_SERVER_COMPANY_INFO,*/ - NULL, /*PACKET_SERVER_CLIENT_INFO,*/ - NULL, /*PACKET_SERVER_NEED_PASSWORD,*/ - RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD), - NULL, /*PACKET_SERVER_WELCOME,*/ - RECEIVE_COMMAND(PACKET_CLIENT_GETMAP), - NULL, /*PACKET_SERVER_WAIT,*/ - NULL, /*PACKET_SERVER_MAP,*/ - RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK), - NULL, /*PACKET_SERVER_JOIN,*/ - NULL, /*PACKET_SERVER_FRAME,*/ - NULL, /*PACKET_SERVER_SYNC,*/ - RECEIVE_COMMAND(PACKET_CLIENT_ACK), - RECEIVE_COMMAND(PACKET_CLIENT_COMMAND), - NULL, /*PACKET_SERVER_COMMAND,*/ - RECEIVE_COMMAND(PACKET_CLIENT_CHAT), - NULL, /*PACKET_SERVER_CHAT,*/ - RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD), - RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME), - RECEIVE_COMMAND(PACKET_CLIENT_QUIT), - RECEIVE_COMMAND(PACKET_CLIENT_ERROR), - NULL, /*PACKET_SERVER_QUIT,*/ - NULL, /*PACKET_SERVER_ERROR_QUIT,*/ - NULL, /*PACKET_SERVER_SHUTDOWN,*/ - NULL, /*PACKET_SERVER_NEWGAME,*/ - NULL, /*PACKET_SERVER_RCON,*/ - RECEIVE_COMMAND(PACKET_CLIENT_RCON), -}; - -// If this fails, check the array above with network_data.h -assert_compile(lengthof(_network_server_packet) == PACKET_END); - -// This update the company_info-stuff -void NetworkPopulateCompanyInfo(void) -{ - char password[NETWORK_PASSWORD_LENGTH]; - const Player *p; - const Vehicle *v; - const Station *s; - const NetworkClientState *cs; - const NetworkClientInfo *ci; - uint i; - uint16 months_empty; - - FOR_ALL_PLAYERS(p) { - if (!p->is_active) { - memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo)); - continue; - } - - // Clean the info but not the password - ttd_strlcpy(password, _network_player_info[p->index].password, sizeof(password)); - months_empty = _network_player_info[p->index].months_empty; - memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo)); - _network_player_info[p->index].months_empty = months_empty; - ttd_strlcpy(_network_player_info[p->index].password, password, sizeof(_network_player_info[p->index].password)); - - // Grap the company name - SetDParam(0, p->name_1); - SetDParam(1, p->name_2); - GetString(_network_player_info[p->index].company_name, STR_JUST_STRING, lastof(_network_player_info[p->index].company_name)); - - // Check the income - if (_cur_year - 1 == p->inaugurated_year) { - // The player is here just 1 year, so display [2], else display[1] - for (i = 0; i < lengthof(p->yearly_expenses[2]); i++) { - _network_player_info[p->index].income -= p->yearly_expenses[2][i]; - } - } else { - for (i = 0; i < lengthof(p->yearly_expenses[1]); i++) { - _network_player_info[p->index].income -= p->yearly_expenses[1][i]; - } - } - - // Set some general stuff - _network_player_info[p->index].inaugurated_year = p->inaugurated_year; - _network_player_info[p->index].company_value = p->old_economy[0].company_value; - _network_player_info[p->index].money = p->money64; - _network_player_info[p->index].performance = p->old_economy[0].performance_history; - } - - // Go through all vehicles and count the type of vehicles - FOR_ALL_VEHICLES(v) { - if (!IsValidPlayer(v->owner)) continue; - - switch (v->type) { - case VEH_Train: - if (IsFrontEngine(v)) _network_player_info[v->owner].num_vehicle[0]++; - break; - - case VEH_Road: - if (v->cargo_type != CT_PASSENGERS) { - _network_player_info[v->owner].num_vehicle[1]++; - } else { - _network_player_info[v->owner].num_vehicle[2]++; - } - break; - - case VEH_Aircraft: - if (v->subtype <= 2) _network_player_info[v->owner].num_vehicle[3]++; - break; - - case VEH_Ship: - _network_player_info[v->owner].num_vehicle[4]++; - break; - - case VEH_Special: - case VEH_Disaster: - break; - } - } - - // Go through all stations and count the types of stations - FOR_ALL_STATIONS(s) { - if (IsValidPlayer(s->owner)) { - NetworkPlayerInfo *npi = &_network_player_info[s->owner]; - - if (s->facilities & FACIL_TRAIN) npi->num_station[0]++; - if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[1]++; - if (s->facilities & FACIL_BUS_STOP) npi->num_station[2]++; - if (s->facilities & FACIL_AIRPORT) npi->num_station[3]++; - if (s->facilities & FACIL_DOCK) npi->num_station[4]++; - } - } - - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - // Register local player (if not dedicated) - if (ci != NULL && IsValidPlayer(ci->client_playas)) - ttd_strlcpy(_network_player_info[ci->client_playas].players, ci->client_name, sizeof(_network_player_info[0].players)); - - FOR_ALL_CLIENTS(cs) { - char client_name[NETWORK_CLIENT_NAME_LENGTH]; - - NetworkGetClientName(client_name, sizeof(client_name), cs); - - ci = DEREF_CLIENT_INFO(cs); - if (ci != NULL && IsValidPlayer(ci->client_playas)) { - if (strlen(_network_player_info[ci->client_playas].players) != 0) - ttd_strlcat(_network_player_info[ci->client_playas].players, ", ", lengthof(_network_player_info[0].players)); - - ttd_strlcat(_network_player_info[ci->client_playas].players, client_name, lengthof(_network_player_info[0].players)); - } - } -} - -// Send a packet to all clients with updated info about this client_index -void NetworkUpdateClientInfo(uint16 client_index) -{ - NetworkClientState *cs; - NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index); - - if (ci == NULL) return; - - FOR_ALL_CLIENTS(cs) { - SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci); - } -} - -/* Check if we want to restart the map */ -static void NetworkCheckRestartMap(void) -{ - if (_network_restart_game_year != 0 && _cur_year >= _network_restart_game_year) { - DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year); - - StartNewGameWithoutGUI(GENERATE_NEW_SEED); - } -} - -/* Check if the server has autoclean_companies activated - Two things happen: - 1) If a company is not protected, it is closed after 1 year (for example) - 2) If a company is protected, protection is disabled after 3 years (for example) - (and item 1. happens a year later) */ -static void NetworkAutoCleanCompanies(void) -{ - const NetworkClientState *cs; - const NetworkClientInfo *ci; - const Player *p; - bool clients_in_company[MAX_PLAYERS]; - - if (!_network_autoclean_companies) return; - - memset(clients_in_company, 0, sizeof(clients_in_company)); - - /* Detect the active companies */ - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true; - } - - if (!_network_dedicated) { - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - if (IsValidPlayer(ci->client_playas)) clients_in_company[ci->client_playas] = true; - } - - /* Go through all the comapnies */ - FOR_ALL_PLAYERS(p) { - /* Skip the non-active once */ - if (!p->is_active || p->is_ai) continue; - - if (!clients_in_company[p->index]) { - /* The company is empty for one month more */ - _network_player_info[p->index].months_empty++; - - /* Is the company empty for autoclean_unprotected-months, and is there no protection? */ - if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') { - /* Shut the company down */ - DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL); - IConsolePrintF(_icolour_def, "Auto-cleaned company #%d", p->index + 1); - } - /* Is the compnay empty for autoclean_protected-months, and there is a protection? */ - if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') { - /* Unprotect the company */ - _network_player_info[p->index].password[0] = '\0'; - IConsolePrintF(_icolour_def, "Auto-removed protection from company #%d", p->index+1); - _network_player_info[p->index].months_empty = 0; - } - } else { - /* It is not empty, reset the date */ - _network_player_info[p->index].months_empty = 0; - } - } -} - -// This function changes new_name to a name that is unique (by adding #1 ...) -// and it returns true if that succeeded. -bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]) -{ - NetworkClientState *new_cs; - bool found_name = false; - byte number = 0; - char original_name[NETWORK_CLIENT_NAME_LENGTH]; - - // We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer - ttd_strlcpy(original_name, new_name, NETWORK_CLIENT_NAME_LENGTH); - - while (!found_name) { - const NetworkClientInfo *ci; - - found_name = true; - FOR_ALL_CLIENTS(new_cs) { - ci = DEREF_CLIENT_INFO(new_cs); - if (strcmp(ci->client_name, new_name) == 0) { - // Name already in use - found_name = false; - break; - } - } - // Check if it is the same as the server-name - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - if (ci != NULL) { - if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use - } - - if (!found_name) { - // Try a new name ( #1, #2, and so on) - - // Stop if we tried for more than 50 times.. - if (number++ > 50) break; - snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number); - } - } - - return found_name; -} - -// Reads a packet from the stream -bool NetworkServer_ReadPackets(NetworkClientState *cs) -{ - Packet *p; - NetworkRecvStatus res; - while ((p = NetworkRecv_Packet(cs, &res)) != NULL) { - byte type = NetworkRecv_uint8(cs, p); - if (type < PACKET_END && _network_server_packet[type] != NULL && !cs->has_quit) { - _network_server_packet[type](cs, p); - } else { - DEBUG(net, 0, "[server] received invalid packet type %d", type); - } - free(p); - } - - return true; -} - -// Handle the local command-queue -static void NetworkHandleCommandQueue(NetworkClientState* cs) -{ - CommandPacket *cp; - - while ( (cp = cs->command_queue) != NULL) { - SEND_COMMAND(PACKET_SERVER_COMMAND)(cs, cp); - - cs->command_queue = cp->next; - free(cp); - } -} - -// This is called every tick if this is a _network_server -void NetworkServer_Tick(bool send_frame) -{ - NetworkClientState *cs; -#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME - bool send_sync = false; -#endif - -#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME - if (_frame_counter >= _last_sync_frame + _network_sync_freq) { - _last_sync_frame = _frame_counter; - send_sync = true; - } -#endif - - // Now we are done with the frame, inform the clients that they can - // do their frame! - FOR_ALL_CLIENTS(cs) { - // Check if the speed of the client is what we can expect from a client - if (cs->status == STATUS_ACTIVE) { - // 1 lag-point per day - int lag = NetworkCalculateLag(cs) / DAY_TICKS; - if (lag > 0) { - if (lag > 3) { - // Client did still not report in after 4 game-day, drop him - // (that is, the 3 of above, + 1 before any lag is counted) - IConsolePrintF(_icolour_err,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index); - NetworkCloseClient(cs); - continue; - } - - // Report once per time we detect the lag - if (cs->lag_test == 0) { - IConsolePrintF(_icolour_warn,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index); - cs->lag_test = 1; - } - } else { - cs->lag_test = 0; - } - } else if (cs->status == STATUS_PRE_ACTIVE) { - int lag = NetworkCalculateLag(cs); - if (lag > _network_max_join_time) { - IConsolePrintF(_icolour_err,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->index, _network_max_join_time); - NetworkCloseClient(cs); - } - } - - if (cs->status >= STATUS_PRE_ACTIVE) { - // Check if we can send command, and if we have anything in the queue - NetworkHandleCommandQueue(cs); - - // Send an updated _frame_counter_max to the client - if (send_frame) SEND_COMMAND(PACKET_SERVER_FRAME)(cs); - -#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME - // Send a sync-check packet - if (send_sync) SEND_COMMAND(PACKET_SERVER_SYNC)(cs); -#endif - } - } - - /* See if we need to advertise */ - NetworkUDPAdvertise(); -} - -void NetworkServerYearlyLoop(void) -{ - NetworkCheckRestartMap(); -} - -void NetworkServerMonthlyLoop(void) -{ - NetworkAutoCleanCompanies(); -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_server.h --- a/network_server.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_SERVER_H -#define NETWORK_SERVER_H - -#ifdef ENABLE_NETWORK - -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP); -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno); -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error); -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN); -DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME); -DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientState *cs, uint16 color, const char *command); - -bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]); -void NetworkServer_HandleChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index); - -bool NetworkServer_ReadPackets(NetworkClientState *cs); -void NetworkServer_Tick(bool send_frame); -void NetworkServerMonthlyLoop(void); -void NetworkServerYearlyLoop(void); - -static inline const char* GetPlayerIP(const NetworkClientInfo* ci) -{ - struct in_addr addr; - - addr.s_addr = ci->client_ip; - return inet_ntoa(addr); -} - -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void NetworkServerMonthlyLoop(void) {} -static inline void NetworkServerYearlyLoop(void) {} - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_SERVER_H */ diff -r d4d00a16ef26 -r bfa6074e2833 network_udp.c --- a/network_udp.c Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,892 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "debug.h" -#include "string.h" -#include "network_data.h" -#include "date.h" -#include "map.h" -#include "network_gamelist.h" -#include "network_udp.h" -#include "variables.h" -#include "newgrf_config.h" - -// -// This file handles all the LAN-stuff -// Stuff like: -// - UDP search over the network -// - -typedef enum { - PACKET_UDP_CLIENT_FIND_SERVER, - PACKET_UDP_SERVER_RESPONSE, - PACKET_UDP_CLIENT_DETAIL_INFO, - PACKET_UDP_SERVER_DETAIL_INFO, // Is not used in OpenTTD itself, only for external querying - PACKET_UDP_SERVER_REGISTER, // Packet to register itself to the master server - PACKET_UDP_MASTER_ACK_REGISTER, // Packet indicating registration has succedeed - PACKET_UDP_CLIENT_GET_LIST, // Request for serverlist from master server - PACKET_UDP_MASTER_RESPONSE_LIST, // Response from master server with server ip's + port's - PACKET_UDP_SERVER_UNREGISTER, // Request to be removed from the server-list - PACKET_UDP_CLIENT_GET_NEWGRFS, // Requests the name for a list of GRFs (GRF_ID and MD5) - PACKET_UDP_SERVER_NEWGRFS, // Sends the list of NewGRF's requested. - PACKET_UDP_END -} PacketUDPType; - -enum { - ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes) - ADVERTISE_RETRY_INTERVAL = 300, // readvertise when no response after this many ticks (9 seconds) - ADVERTISE_RETRY_TIMES = 3 // give up readvertising after this much failed retries -}; - -#define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, struct sockaddr_in *client_addr) -static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* recv); - -static NetworkClientState _udp_cs; - -/** - * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet - * @param p the packet to write the data to - * @param c the configuration to write the GRF ID and MD5 checksum from - */ -static void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) -{ - uint j; - NetworkSend_uint32(p, c->grfid); - for (j = 0; j < sizeof(c->md5sum); j++) { - NetworkSend_uint8 (p, c->md5sum[j]); - } -} - -/** - * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet - * @param p the packet to read the data from - * @param c the configuration to write the GRF ID and MD5 checksum to - */ -static void NetworkRecv_GRFIdentifier(Packet *p, GRFConfig *c) -{ - uint j; - c->grfid = NetworkRecv_uint32(&_udp_cs, p); - for (j = 0; j < sizeof(c->md5sum); j++) { - c->md5sum[j] = NetworkRecv_uint8(&_udp_cs, p); - } -} - -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) -{ - Packet *packet; - // Just a fail-safe.. should never happen - if (!_network_udp_server) - return; - - packet = NetworkSend_Init(PACKET_UDP_SERVER_RESPONSE); - - // Update some game_info - _network_game_info.game_date = _date; - _network_game_info.map_width = MapSizeX(); - _network_game_info.map_height = MapSizeY(); - _network_game_info.map_set = _opt.landscape; - - NetworkSend_uint8 (packet, NETWORK_GAME_INFO_VERSION); - - /* NETWORK_GAME_INFO_VERSION = 4 */ - { - /* Only send the GRF Identification (GRF_ID and MD5 checksum) of - * the GRFs that are needed, i.e. the ones that the server has - * selected in the NewGRF GUI and not the ones that are used due - * to the fact that they are in [newgrf-static] in openttd.cfg */ - const GRFConfig *c; - uint i = 0; - - /* Count number of GRFs to send information about */ - for (c = _grfconfig; c != NULL; c = c->next) { - if (!HASBIT(c->flags, GCF_STATIC)) i++; - } - NetworkSend_uint8 (packet, i); // Send number of GRFs - - /* Send actual GRF Identifications */ - for (c = _grfconfig; c != NULL; c = c->next) { - if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(packet, c); - } - } - - /* NETWORK_GAME_INFO_VERSION = 3 */ - NetworkSend_uint32(packet, _network_game_info.game_date); - NetworkSend_uint32(packet, _network_game_info.start_date); - - /* NETWORK_GAME_INFO_VERSION = 2 */ - NetworkSend_uint8 (packet, _network_game_info.companies_max); - NetworkSend_uint8 (packet, ActivePlayerCount()); - NetworkSend_uint8 (packet, _network_game_info.spectators_max); - - /* NETWORK_GAME_INFO_VERSION = 1 */ - NetworkSend_string(packet, _network_game_info.server_name); - NetworkSend_string(packet, _network_game_info.server_revision); - NetworkSend_uint8 (packet, _network_game_info.server_lang); - NetworkSend_uint8 (packet, _network_game_info.use_password); - NetworkSend_uint8 (packet, _network_game_info.clients_max); - NetworkSend_uint8 (packet, _network_game_info.clients_on); - NetworkSend_uint8 (packet, NetworkSpectatorCount()); - NetworkSend_string(packet, _network_game_info.map_name); - NetworkSend_uint16(packet, _network_game_info.map_width); - NetworkSend_uint16(packet, _network_game_info.map_height); - NetworkSend_uint8 (packet, _network_game_info.map_set); - NetworkSend_uint8 (packet, _network_game_info.dedicated); - - // Let the client know that we are here - NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); - - free(packet); - - DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr)); -} - -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) -{ - extern const char _openttd_revision[]; - NetworkGameList *item; - byte game_info_version; - - // Just a fail-safe.. should never happen - if (_network_udp_server) - return; - - game_info_version = NetworkRecv_uint8(&_udp_cs, p); - - if (_udp_cs.has_quit) return; - - DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port)); - - // Find next item - item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port)); - - item->info.compatible = true; - /* Please observer the order. In the order in which packets are sent - * they are to be received */ - switch (game_info_version) { - case 4: { - GRFConfig *c, **dst = &item->info.grfconfig; - const GRFConfig *f; - uint i; - uint num_grfs = NetworkRecv_uint8(&_udp_cs, p); - - for (i = 0; i < num_grfs; i++) { - c = calloc(1, sizeof(*c)); - NetworkRecv_GRFIdentifier(p, c); - - /* Find the matching GRF file */ - f = FindGRFConfig(c->grfid, c->md5sum); - if (f == NULL) { - /* Don't know the GRF, so mark game incompatible and the (possibly) - * already resolved name for this GRF (another server has sent the - * name of the GRF already */ - item->info.compatible = false; - c->name = FindUnknownGRFName(c->grfid, c->md5sum, true); - SETBIT(c->flags, GCF_NOT_FOUND); - } else { - c->filename = f->filename; - c->name = f->name; - c->info = f->info; - } - SETBIT(c->flags, GCF_COPY); - - /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; - } - } /* Fallthrough */ - case 3: - item->info.game_date = NetworkRecv_uint32(&_udp_cs, p); - item->info.start_date = NetworkRecv_uint32(&_udp_cs, p); - /* Fallthrough */ - case 2: - item->info.companies_max = NetworkRecv_uint8(&_udp_cs, p); - item->info.companies_on = NetworkRecv_uint8(&_udp_cs, p); - item->info.spectators_max = NetworkRecv_uint8(&_udp_cs, p); - /* Fallthrough */ - case 1: - NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name)); - NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision)); - item->info.server_lang = NetworkRecv_uint8(&_udp_cs, p); - item->info.use_password = NetworkRecv_uint8(&_udp_cs, p); - item->info.clients_max = NetworkRecv_uint8(&_udp_cs, p); - item->info.clients_on = NetworkRecv_uint8(&_udp_cs, p); - item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p); - if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier - item->info.game_date = NetworkRecv_uint16(&_udp_cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; - item->info.start_date = NetworkRecv_uint16(&_udp_cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; - } - NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name)); - item->info.map_width = NetworkRecv_uint16(&_udp_cs, p); - item->info.map_height = NetworkRecv_uint16(&_udp_cs, p); - item->info.map_set = NetworkRecv_uint8(&_udp_cs, p); - item->info.dedicated = NetworkRecv_uint8(&_udp_cs, p); - - if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0; - if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0; - - if (item->info.hostname[0] == '\0') - snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr)); - - /* Check if we are allowed on this server based on the revision-match */ - item->info.version_compatible = - strcmp(item->info.server_revision, _openttd_revision) == 0 || - strcmp(item->info.server_revision, NOREV_STRING) == 0; - item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs - break; - } - - { - /* Checks whether there needs to be a request for names of GRFs and makes - * the request if necessary. GRFs that need to be requested are the GRFs - * that do not exist on the clients system and we do not have the name - * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER. - * The in_request array and in_request_count are used so there is no need - * to do a second loop over the GRF list, which can be relatively expensive - * due to the string comparisons. */ - const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT]; - const GRFConfig *c; - uint in_request_count = 0; - struct sockaddr_in out_addr; - - for (c = item->info.grfconfig; c != NULL; c = c->next) { - if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; - in_request[in_request_count] = c; - in_request_count++; - } - - if (in_request_count > 0) { - /* There are 'unknown' GRFs, now send a request for them */ - uint i; - Packet *packet = NetworkSend_Init(PACKET_UDP_CLIENT_GET_NEWGRFS); - - NetworkSend_uint8 (packet, in_request_count); - for (i = 0; i < in_request_count; i++) { - NetworkSend_GRFIdentifier(packet, in_request[i]); - } - - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(item->port); - out_addr.sin_addr.s_addr = item->ip; - NetworkSendUDP_Packet(_udp_client_socket, packet, &out_addr); - free(packet); - } - } - - item->online = true; - - UpdateNetworkGameWindow(false); -} - -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO) -{ - NetworkClientState *cs; - NetworkClientInfo *ci; - Packet *packet; - Player *player; - byte current = 0; - int i; - - // Just a fail-safe.. should never happen - if (!_network_udp_server) return; - - packet = NetworkSend_Init(PACKET_UDP_SERVER_DETAIL_INFO); - - /* Send the amount of active companies */ - NetworkSend_uint8 (packet, NETWORK_COMPANY_INFO_VERSION); - NetworkSend_uint8 (packet, ActivePlayerCount()); - - /* Fetch the latest version of everything */ - NetworkPopulateCompanyInfo(); - - /* Go through all the players */ - FOR_ALL_PLAYERS(player) { - /* Skip non-active players */ - if (!player->is_active) continue; - - current++; - - /* Send the information */ - NetworkSend_uint8(packet, current); - - NetworkSend_string(packet, _network_player_info[player->index].company_name); - NetworkSend_uint32(packet, _network_player_info[player->index].inaugurated_year); - NetworkSend_uint64(packet, _network_player_info[player->index].company_value); - NetworkSend_uint64(packet, _network_player_info[player->index].money); - NetworkSend_uint64(packet, _network_player_info[player->index].income); - NetworkSend_uint16(packet, _network_player_info[player->index].performance); - - /* Send 1 if there is a passord for the company else send 0 */ - if (_network_player_info[player->index].password[0] != '\0') { - NetworkSend_uint8(packet, 1); - } else { - NetworkSend_uint8(packet, 0); - } - - for (i = 0; i < NETWORK_VEHICLE_TYPES; i++) - NetworkSend_uint16(packet, _network_player_info[player->index].num_vehicle[i]); - - for (i = 0; i < NETWORK_STATION_TYPES; i++) - NetworkSend_uint16(packet, _network_player_info[player->index].num_station[i]); - - /* Find the clients that are connected to this player */ - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (ci->client_playas == player->index) { - /* The uint8 == 1 indicates that a client is following */ - NetworkSend_uint8(packet, 1); - NetworkSend_string(packet, ci->client_name); - NetworkSend_string(packet, ci->unique_id); - NetworkSend_uint32(packet, ci->join_date); - } - } - /* Also check for the server itself */ - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - if (ci->client_playas == player->index) { - /* The uint8 == 1 indicates that a client is following */ - NetworkSend_uint8(packet, 1); - NetworkSend_string(packet, ci->client_name); - NetworkSend_string(packet, ci->unique_id); - NetworkSend_uint32(packet, ci->join_date); - } - - /* Indicates end of client list */ - NetworkSend_uint8(packet, 0); - } - - /* And check if we have any spectators */ - FOR_ALL_CLIENTS(cs) { - ci = DEREF_CLIENT_INFO(cs); - if (!IsValidPlayer(ci->client_playas)) { - /* The uint8 == 1 indicates that a client is following */ - NetworkSend_uint8(packet, 1); - NetworkSend_string(packet, ci->client_name); - NetworkSend_string(packet, ci->unique_id); - NetworkSend_uint32(packet, ci->join_date); - } - } - - /* Also check for the server itself */ - ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX); - if (!IsValidPlayer(ci->client_playas)) { - /* The uint8 == 1 indicates that a client is following */ - NetworkSend_uint8(packet, 1); - NetworkSend_string(packet, ci->client_name); - NetworkSend_string(packet, ci->unique_id); - NetworkSend_uint32(packet, ci->join_date); - } - - /* Indicates end of client list */ - NetworkSend_uint8(packet, 0); - - NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); - - free(packet); -} - -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST) -{ - int i; - struct in_addr ip; - uint16 port; - uint8 ver; - - /* packet begins with the protocol version (uint8) - * then an uint16 which indicates how many - * ip:port pairs are in this packet, after that - * an uint32 (ip) and an uint16 (port) for each pair - */ - - ver = NetworkRecv_uint8(&_udp_cs, p); - - if (_udp_cs.has_quit) return; - - if (ver == 1) { - for (i = NetworkRecv_uint16(&_udp_cs, p); i != 0 ; i--) { - ip.s_addr = TO_LE32(NetworkRecv_uint32(&_udp_cs, p)); - port = NetworkRecv_uint16(&_udp_cs, p); - NetworkUDPQueryServer(inet_ntoa(ip), port); - } - } -} - -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER) -{ - _network_advertise_retries = 0; - DEBUG(net, 2, "[udp] advertising on master server successfull"); - - /* We are advertised, but we don't want to! */ - if (!_network_advertise) NetworkUDPRemoveAdvertise(); -} - -/** - * A client has requested the names of some NewGRFs. - * - * Replying this can be tricky as we have a limit of SEND_MTU bytes - * in the reply packet and we can send up to 100 bytes per NewGRF - * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name). - * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it - * could be that a packet overflows. To stop this we only reply - * with the first N NewGRFs so that if the first N + 1 NewGRFs - * would be sent, the packet overflows. - * in_reply and in_reply_count are used to keep a list of GRFs to - * send in the reply. - */ -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS) -{ - uint8 num_grfs; - uint i; - - const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT]; - Packet *packet; - uint8 in_reply_count = 0; - uint packet_len = 0; - - /* Just a fail-safe.. should never happen */ - if (_udp_cs.has_quit) return; - - DEBUG(net, 6, "[udp] newgrf data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port)); - - num_grfs = NetworkRecv_uint8 (&_udp_cs, p); - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - GRFConfig c; - const GRFConfig *f; - - NetworkRecv_GRFIdentifier(p, &c); - - /* Find the matching GRF file */ - f = FindGRFConfig(c.grfid, c.md5sum); - if (f == NULL) continue; // The GRF is unknown to this server - - /* If the reply might exceed the size of the packet, only reply - * the current list and do not send the other data. - * The name could be an empty string, if so take the filename. */ - packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + - min(strlen((f->name != NULL && strlen(f->name) > 0) ? f->name : f->filename) + 1, NETWORK_GRF_NAME_LENGTH); - if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply - break; - } - in_reply[in_reply_count] = f; - in_reply_count++; - } - - if (in_reply_count == 0) return; - - packet = NetworkSend_Init(PACKET_UDP_SERVER_NEWGRFS); - NetworkSend_uint8 (packet, in_reply_count); - for (i = 0; i < in_reply_count; i++) { - char name[NETWORK_GRF_NAME_LENGTH]; - - /* The name could be an empty string, if so take the filename */ - ttd_strlcpy(name, (in_reply[i]->name != NULL && strlen(in_reply[i]->name) > 0) ? - in_reply[i]->name : in_reply[i]->filename, sizeof(name)); - NetworkSend_GRFIdentifier(packet, in_reply[i]); - NetworkSend_string(packet, name); - } - - NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); - free(packet); -} - -/** The return of the client's request of the names of some NewGRFs */ -DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS) -{ - uint8 num_grfs; - uint i; - - /* Just a fail-safe.. should never happen */ - if (_udp_cs.has_quit) return; - - DEBUG(net, 6, "[udp] newgrf data reply from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port)); - - num_grfs = NetworkRecv_uint8 (&_udp_cs, p); - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - char *unknown_name; - char name[NETWORK_GRF_NAME_LENGTH]; - GRFConfig c; - - NetworkRecv_GRFIdentifier(p, &c); - NetworkRecv_string(&_udp_cs, p, name, sizeof(name)); - - /* An empty name is not possible under normal circumstances - * and causes problems when showing the NewGRF list. */ - if (strlen(name) == 0) continue; - - /* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple. - * If it exists and not resolved yet, then name of the fake GRF is - * overwritten with the name from the reply. */ - unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { - ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH); - } - } -} - - -// The layout for the receive-functions by UDP -typedef void NetworkUDPPacket(Packet *p, struct sockaddr_in *client_addr); - -static NetworkUDPPacket* const _network_udp_packet[] = { - RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER), - RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE), - RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO), - NULL, - NULL, - RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER), - NULL, - RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST), - NULL, - RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS), - RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS), -}; - - -// If this fails, check the array above with network_data.h -assert_compile(lengthof(_network_udp_packet) == PACKET_UDP_END); - - -static void NetworkHandleUDPPacket(Packet* p, struct sockaddr_in* client_addr) -{ - byte type; - - /* Fake a client, so we can see when there is an illegal packet */ - _udp_cs.socket = INVALID_SOCKET; - _udp_cs.has_quit = false; - - type = NetworkRecv_uint8(&_udp_cs, p); - - if (type < PACKET_UDP_END && _network_udp_packet[type] != NULL && !_udp_cs.has_quit) { - _network_udp_packet[type](p, client_addr); - } else { - if (!_udp_cs.has_quit) { - DEBUG(net, 0, "[udp] received invalid packet type %d", type); - } else { - DEBUG(net, 0, "[udp] received illegal packet"); - } - } -} - - -// Send a packet over UDP -static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* recv) -{ - int res; - - // Put the length in the buffer - p->buffer[0] = p->size & 0xFF; - p->buffer[1] = p->size >> 8; - - // Send the buffer - res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv)); - - // Check for any errors, but ignore it otherwise - if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR()); -} - -// Start UDP listener -bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast) -{ - struct sockaddr_in sin; - - // Make sure socket is closed - closesocket(*udp); - - *udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (*udp == INVALID_SOCKET) { - DEBUG(net, 0, "[udp] failed to start UDP listener"); - return false; - } - - // set nonblocking mode for socket - { - unsigned long blocking = 1; -#ifndef BEOS_NET_SERVER - ioctlsocket(*udp, FIONBIO, &blocking); -#else - setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL); -#endif - } - - sin.sin_family = AF_INET; - // Listen on all IPs - sin.sin_addr.s_addr = host; - sin.sin_port = htons(port); - - if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) { - DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port); - return false; - } - - if (broadcast) { - /* Enable broadcast */ - unsigned long val = 1; -#ifndef BEOS_NET_SERVER // will work around this, some day; maybe. - setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); -#endif - } - - DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port); - - return true; -} - -// Close UDP connection -void NetworkUDPClose(void) -{ - DEBUG(net, 1, "[udp] closed listeners"); - - if (_network_udp_server) { - if (_udp_server_socket != INVALID_SOCKET) { - closesocket(_udp_server_socket); - _udp_server_socket = INVALID_SOCKET; - } - - if (_udp_master_socket != INVALID_SOCKET) { - closesocket(_udp_master_socket); - _udp_master_socket = INVALID_SOCKET; - } - - _network_udp_server = false; - _network_udp_broadcast = 0; - } else { - if (_udp_client_socket != INVALID_SOCKET) { - closesocket(_udp_client_socket); - _udp_client_socket = INVALID_SOCKET; - } - _network_udp_broadcast = 0; - } -} - -// Receive something on UDP level -void NetworkUDPReceive(SOCKET udp) -{ - struct sockaddr_in client_addr; - socklen_t client_len; - int nbytes; - static Packet *p = NULL; - int packet_len; - - // If p is NULL, malloc him.. this prevents unneeded mallocs - if (p == NULL) p = malloc(sizeof(*p)); - - packet_len = sizeof(p->buffer); - client_len = sizeof(client_addr); - - // Try to receive anything - nbytes = recvfrom(udp, p->buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); - - // We got some bytes.. just asume we receive the whole packet - if (nbytes > 0) { - // Get the size of the buffer - p->size = (uint16)p->buffer[0]; - p->size += (uint16)p->buffer[1] << 8; - // Put the position on the right place - p->pos = 2; - p->next = NULL; - - // Handle the packet - NetworkHandleUDPPacket(p, &client_addr); - - // Free the packet - free(p); - p = NULL; - } -} - -// Broadcast to all ips -static void NetworkUDPBroadCast(SOCKET udp) -{ - Packet* p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER); - uint i; - - for (i = 0; _broadcast_list[i] != 0; i++) { - struct sockaddr_in out_addr; - - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(_network_server_port); - out_addr.sin_addr.s_addr = _broadcast_list[i]; - - DEBUG(net, 4, "[udp] broadcasting to %s", inet_ntoa(out_addr.sin_addr)); - - NetworkSendUDP_Packet(udp, p, &out_addr); - } - - free(p); -} - - -// Request the the server-list from the master server -void NetworkUDPQueryMasterServer(void) -{ - struct sockaddr_in out_addr; - Packet *p; - - if (_udp_client_socket == INVALID_SOCKET) - if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) - return; - - p = NetworkSend_Init(PACKET_UDP_CLIENT_GET_LIST); - - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); - out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); - - // packet only contains protocol version - NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); - - NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr); - - DEBUG(net, 2, "[udp] master server queried at %s:%d", inet_ntoa(out_addr.sin_addr),ntohs(out_addr.sin_port)); - - free(p); -} - -// Find all servers -void NetworkUDPSearchGame(void) -{ - // We are still searching.. - if (_network_udp_broadcast > 0) return; - - // No UDP-socket yet.. - if (_udp_client_socket == INVALID_SOCKET) - if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) - return; - - DEBUG(net, 0, "[udp] searching server"); - - NetworkUDPBroadCast(_udp_client_socket); - _network_udp_broadcast = 300; // Stay searching for 300 ticks -} - -NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port) -{ - struct sockaddr_in out_addr; - Packet *p; - NetworkGameList *item; - - // No UDP-socket yet.. - if (_udp_client_socket == INVALID_SOCKET) - if (!NetworkUDPListen(&_udp_client_socket, 0, 0, true)) - return NULL; - - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(port); - out_addr.sin_addr.s_addr = NetworkResolveHost(host); - - // Clear item in gamelist - item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port)); - memset(&item->info, 0, sizeof(item->info)); - ttd_strlcpy(item->info.server_name, host, lengthof(item->info.server_name)); - ttd_strlcpy(item->info.hostname, host, lengthof(item->info.hostname)); - item->online = false; - - // Init the packet - p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER); - - NetworkSendUDP_Packet(_udp_client_socket, p, &out_addr); - - free(p); - - UpdateNetworkGameWindow(false); - return item; -} - -/* Remove our advertise from the master-server */ -void NetworkUDPRemoveAdvertise(void) -{ - struct sockaddr_in out_addr; - Packet *p; - - /* Check if we are advertising */ - if (!_networking || !_network_server || !_network_udp_server) return; - - /* check for socket */ - if (_udp_master_socket == INVALID_SOCKET) - if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false)) - return; - - DEBUG(net, 1, "[udp] removing advertise from master server"); - - /* Find somewhere to send */ - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); - out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); - - /* Send the packet */ - p = NetworkSend_Init(PACKET_UDP_SERVER_UNREGISTER); - /* Packet is: Version, server_port */ - NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); - NetworkSend_uint16(p, _network_server_port); - NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr); - - free(p); -} - -/* Register us to the master server - This function checks if it needs to send an advertise */ -void NetworkUDPAdvertise(void) -{ - struct sockaddr_in out_addr; - Packet *p; - - /* Check if we should send an advertise */ - if (!_networking || !_network_server || !_network_udp_server || !_network_advertise) - return; - - /* check for socket */ - if (_udp_master_socket == INVALID_SOCKET) - if (!NetworkUDPListen(&_udp_master_socket, _network_server_bind_ip, 0, false)) - return; - - if (_network_need_advertise) { - _network_need_advertise = false; - _network_advertise_retries = ADVERTISE_RETRY_TIMES; - } else { - /* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */ - if (_network_advertise_retries == 0) { - if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter) - return; - _network_advertise_retries = ADVERTISE_RETRY_TIMES; - } - - if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter) - return; - } - - _network_advertise_retries--; - _network_last_advertise_frame = _frame_counter; - - /* Find somewhere to send */ - out_addr.sin_family = AF_INET; - out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT); - out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST); - - DEBUG(net, 1, "[udp] advertising to master server"); - - /* Send the packet */ - p = NetworkSend_Init(PACKET_UDP_SERVER_REGISTER); - /* Packet is: WELCOME_MESSAGE, Version, server_port */ - NetworkSend_string(p, NETWORK_MASTER_SERVER_WELCOME_MESSAGE); - NetworkSend_uint8(p, NETWORK_MASTER_SERVER_VERSION); - NetworkSend_uint16(p, _network_server_port); - NetworkSendUDP_Packet(_udp_master_socket, p, &out_addr); - - free(p); -} - -void NetworkUDPInitialize(void) -{ - _udp_client_socket = INVALID_SOCKET; - _udp_server_socket = INVALID_SOCKET; - _udp_master_socket = INVALID_SOCKET; - - _network_udp_server = false; - _network_udp_broadcast = 0; -} - -#endif /* ENABLE_NETWORK */ diff -r d4d00a16ef26 -r bfa6074e2833 network_udp.h --- a/network_udp.h Tue Jan 02 18:40:37 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* $Id$ */ - -#ifndef NETWORK_UDP_H -#define NETWORK_UDP_H - -#ifdef ENABLE_NETWORK - -void NetworkUDPInitialize(void); -bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast); -void NetworkUDPReceive(SOCKET udp); -void NetworkUDPSearchGame(void); -void NetworkUDPQueryMasterServer(void); -NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port); -void NetworkUDPAdvertise(void); -void NetworkUDPRemoveAdvertise(void); - -#endif /* ENABLE_NETWORK */ - -#endif /* NETWORK_UDP_H */ diff -r d4d00a16ef26 -r bfa6074e2833 newgrf_config.c --- a/newgrf_config.c Tue Jan 02 18:40:37 2007 +0000 +++ b/newgrf_config.c Wed Jan 03 08:32:17 2007 +0000 @@ -9,7 +9,7 @@ #include "string.h" #include "saveload.h" #include "md5.h" -#include "network_data.h" +#include "network/network_data.h" #include "newgrf.h" #include "newgrf_config.h" diff -r d4d00a16ef26 -r bfa6074e2833 newgrf_spritegroup.c --- a/newgrf_spritegroup.c Tue Jan 02 18:40:37 2007 +0000 +++ b/newgrf_spritegroup.c Wed Jan 03 08:32:17 2007 +0000 @@ -11,7 +11,7 @@ static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item); static uint _spritegroup_count = 0; -STATIC_OLD_POOL(SpriteGroup, SpriteGroup, 4, 8000, NULL, SpriteGroupPoolCleanBlock) +STATIC_OLD_POOL(SpriteGroup, SpriteGroup, 9, 250, NULL, SpriteGroupPoolCleanBlock) static void DestroySpriteGroup(SpriteGroup *group) { diff -r d4d00a16ef26 -r bfa6074e2833 npf.c --- a/npf.c Tue Jan 02 18:40:37 2007 +0000 +++ b/npf.c Wed Jan 03 08:32:17 2007 +0000 @@ -14,7 +14,7 @@ #include "tile.h" #include "depot.h" #include "tunnel_map.h" -#include "network.h" +#include "network/network.h" #include "water_map.h" static AyStar _npf_aystar; diff -r d4d00a16ef26 -r bfa6074e2833 oldloader.c --- a/oldloader.c Tue Jan 02 18:40:37 2007 +0000 +++ b/oldloader.c Wed Jan 03 08:32:17 2007 +0000 @@ -16,7 +16,7 @@ #include "signs.h" #include "debug.h" #include "depot.h" -#include "network.h" +#include "network/network.h" #include "ai/ai.h" #include "date.h" diff -r d4d00a16ef26 -r bfa6074e2833 openttd.c --- a/openttd.c Tue Jan 02 18:40:37 2007 +0000 +++ b/openttd.c Wed Jan 03 08:32:17 2007 +0000 @@ -41,7 +41,7 @@ #include "airport.h" #include "console.h" #include "screenshot.h" -#include "network.h" +#include "network/network.h" #include "signs.h" #include "depot.h" #include "waypoint.h" diff -r d4d00a16ef26 -r bfa6074e2833 openttd.vcproj --- a/openttd.vcproj Tue Jan 02 18:40:37 2007 +0000 +++ b/openttd.vcproj Wed Jan 03 08:32:17 2007 +0000 @@ -292,22 +292,31 @@ RelativePath=".\namegen.c"> - - + RelativePath=".\network\core\packet.c"> + RelativePath=".\network\core\tcp.c"> + RelativePath=".\network\core\udp.c"> + RelativePath=".\network\network.c"> + RelativePath=".\network\network_client.c"> + + + + + + + + @@ -542,22 +551,37 @@ RelativePath=".\music.h"> - - + RelativePath=".\network\core\config.h"> + RelativePath=".\network\core\game.h"> + RelativePath=".\network\core\os_abstraction.h"> + RelativePath=".\network\core\packet.h"> + RelativePath=".\network\core\tcp.h"> + + + + + + + + + + + + diff -r d4d00a16ef26 -r bfa6074e2833 openttd_vs80.vcproj --- a/openttd_vs80.vcproj Tue Jan 02 18:40:37 2007 +0000 +++ b/openttd_vs80.vcproj Wed Jan 03 08:32:17 2007 +0000 @@ -653,27 +653,39 @@ > - - + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + @@ -1042,7 +1042,6 @@ //********** START OF MEMORY CODE (in ram)**** //******************************************** -#include "network.h" #include "table/strings.h" #include "table/sprites.h" #include "gfx.h" diff -r d4d00a16ef26 -r bfa6074e2833 settings.c --- a/settings.c Tue Jan 02 18:40:37 2007 +0000 +++ b/settings.c Wed Jan 03 08:32:17 2007 +0000 @@ -28,7 +28,7 @@ #include "sound.h" #include "string.h" #include "variables.h" -#include "network.h" +#include "network/network.h" #include "settings.h" #include "command.h" #include "console.h" diff -r d4d00a16ef26 -r bfa6074e2833 settings_gui.c --- a/settings_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/settings_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -15,7 +15,7 @@ #include "engine.h" #include "screenshot.h" #include "newgrf.h" -#include "network.h" +#include "network/network.h" #include "town.h" #include "variables.h" #include "settings.h" diff -r d4d00a16ef26 -r bfa6074e2833 table/sprites.h --- a/table/sprites.h Tue Jan 02 18:40:37 2007 +0000 +++ b/table/sprites.h Wed Jan 03 08:32:17 2007 +0000 @@ -1314,9 +1314,9 @@ * @see SpriteSetup */ enum SpriteMasks { ///Maximum number of sprites that can be loaded at a given time. - MAX_SPRITES = (1 << SPRITE_WIDTH) - 1, + MAX_SPRITES = 1 << SPRITE_WIDTH, ///The mask to for the main sprite - SPRITE_MASK = MAX_SPRITES, + SPRITE_MASK = MAX_SPRITES - 1, ///The mask for the auxiliary sprite (the one that takes care of recoloring) PALETTE_SPRITE_MASK = ((1 << PALETTE_SPRITE_WIDTH) - 1) << PALETTE_SPRITE_START, ///Mask for the auxiliary sprites if it is locate in the LSBs diff -r d4d00a16ef26 -r bfa6074e2833 town_gui.c --- a/town_gui.c Tue Jan 02 18:40:37 2007 +0000 +++ b/town_gui.c Wed Jan 03 08:32:17 2007 +0000 @@ -14,7 +14,7 @@ #include "gui.h" #include "command.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" static const Widget _town_authority_widgets[] = { diff -r d4d00a16ef26 -r bfa6074e2833 vehicle.c --- a/vehicle.c Tue Jan 02 18:40:37 2007 +0000 +++ b/vehicle.c Wed Jan 03 08:32:17 2007 +0000 @@ -30,7 +30,7 @@ #include "industry_map.h" #include "station_map.h" #include "water_map.h" -#include "network.h" +#include "network/network.h" #include "yapf/yapf.h" #include "date.h" #include "newgrf_engine.h" diff -r d4d00a16ef26 -r bfa6074e2833 video/cocoa_v.m --- a/video/cocoa_v.m Tue Jan 02 18:40:37 2007 +0000 +++ b/video/cocoa_v.m Wed Jan 03 08:32:17 2007 +0000 @@ -54,7 +54,7 @@ #include "../macros.h" #include "../sdl.h" #include "../window.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "../os/macosx/splash.h" diff -r d4d00a16ef26 -r bfa6074e2833 video/dedicated_v.c --- a/video/dedicated_v.c Tue Jan 02 18:40:37 2007 +0000 +++ b/video/dedicated_v.c Wed Jan 03 08:32:17 2007 +0000 @@ -8,7 +8,7 @@ #include "../debug.h" #include "../functions.h" #include "../gfx.h" -#include "../network.h" +#include "../network/network.h" #include "../window.h" #include "../console.h" #include "../variables.h" diff -r d4d00a16ef26 -r bfa6074e2833 video/sdl_v.c --- a/video/sdl_v.c Tue Jan 02 18:40:37 2007 +0000 +++ b/video/sdl_v.c Wed Jan 03 08:32:17 2007 +0000 @@ -11,7 +11,7 @@ #include "../macros.h" #include "../sdl.h" #include "../window.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "sdl_v.h" #include @@ -440,7 +440,9 @@ #if defined(_DEBUG) if (_shift_pressed) #else - if (keys[SDLK_TAB]) + /* Speedup when pressing tab, except when using ALT+TAB + * to switch to another application */ + if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0) #endif { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; diff -r d4d00a16ef26 -r bfa6074e2833 video/win32_v.c --- a/video/win32_v.c Tue Jan 02 18:40:37 2007 +0000 +++ b/video/win32_v.c Wed Jan 03 08:32:17 2007 +0000 @@ -5,7 +5,7 @@ #include "../functions.h" #include "../gfx.h" #include "../macros.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "../win32.h" #include "../window.h"