From 9f14d652a94f88da2fbf7741aba408fe0f40fd34 Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 17 Apr 2010 12:00:59 +0000 Subject: [PATCH] (svn r19653) [1.0] -Backport from trunk: - Fix: RandomRange() is used for bigger ranges in many cases, so generally extent it to handle 32 bits (r19652) - Fix: When a company is sold, move connected clients to spectators [FS#3745] (r19651) - Fix: A client would not be properly moved when moved while joining, e.g. when entering a company's password. This caused the client to be in the wrong company (according to the rest of the clients) and the client being kicked on the first command [FS#3760] (r19648) - Fix: Trains loaded above the original IDs did not have a default railtypelabel assigned to them, causing them to be unavailable. Could cause desyncs if the multiplayer game was not started from a savegame [FS#3768] (r19647) --- bin/ai/regression/regression.nut | 6 +++--- bin/ai/regression/regression.txt | 8 ++++---- src/core/random_func.cpp | 9 ++++----- src/core/random_func.hpp | 9 ++++----- src/economy.cpp | 24 +++++------------------- src/industry_cmd.cpp | 3 +-- src/network/network_client.cpp | 19 +++++++++++++++++++ src/network/network_func.h | 2 +- src/network/network_server.cpp | 27 +++------------------------ src/newgrf.cpp | 3 +++ src/strings.cpp | 12 +++++++++--- src/table/strgen_tables.h | 3 ++- 12 files changed, 58 insertions(+), 67 deletions(-) diff --git a/bin/ai/regression/regression.nut b/bin/ai/regression/regression.nut index a54c643c3c..6a49eef1fd 100644 --- a/bin/ai/regression/regression.nut +++ b/bin/ai/regression/regression.nut @@ -192,9 +192,9 @@ function Regression::Base() print(" RandRange(2): " + AIBase.RandRange(2)); print(" RandRange(2): " + AIBase.RandRange(2)); print(" RandRange(2): " + AIBase.RandRange(2)); - print(" RandRange(9): " + AIBase.RandRange(9)); - print(" RandRange(9): " + AIBase.RandRange(9)); - print(" RandRange(9): " + AIBase.RandRange(9)); + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); // 32 bit tests + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt index d53666106d..c45cb1d5e7 100644 --- a/bin/ai/regression/regression.txt +++ b/bin/ai/regression/regression.txt @@ -96,10 +96,10 @@ RandRange(1): 0 RandRange(2): 0 RandRange(2): 0 - RandRange(2): 1 - RandRange(9): 6 - RandRange(9): 7 - RandRange(9): 4 + RandRange(2): 0 + RandRange(1000000): 987346 + RandRange(1000000): 781750 + RandRange(1000000): 191841 Chance(1, 2): true Chance(1, 2): false Chance(1, 2): false diff --git a/src/core/random_func.cpp b/src/core/random_func.cpp index 588bcb7b28..1c53d99c7d 100644 --- a/src/core/random_func.cpp +++ b/src/core/random_func.cpp @@ -24,9 +24,9 @@ uint32 Randomizer::Next() return this->state[1] = ROR(s, 3) - 1; } -uint32 Randomizer::Next(uint16 max) +uint32 Randomizer::Next(uint32 max) { - return GB(this->Next(), 0, 16) * max >> 16; + return ((uint64)this->Next() * (uint64)max) >> 32; } void Randomizer::SetSeed(uint32 seed) @@ -55,9 +55,8 @@ uint32 DoRandom(int line, const char *file) return _random.Next(); } -uint DoRandomRange(uint max, int line, const char *file) +uint32 DoRandomRange(uint32 max, int line, const char *file) { - assert(max <= UINT16_MAX); - return GB(DoRandom(line, file), 0, 16) * max >> 16; + return ((uint64)DoRandom(line, file) * (uint64)max) >> 32; } #endif /* RANDOM_DEBUG */ diff --git a/src/core/random_func.hpp b/src/core/random_func.hpp index 03d49d718b..e0e31a08cc 100644 --- a/src/core/random_func.hpp +++ b/src/core/random_func.hpp @@ -48,7 +48,7 @@ struct Randomizer { * @param max the maximum value of the returned random number * @return the random number */ - uint32 Next(uint16 max); + uint32 Next(uint32 max); /** * (Re)set the state of the random number generator. @@ -92,16 +92,15 @@ void SetRandomSeed(uint32 seed); #endif uint32 DoRandom(int line, const char *file); #define RandomRange(max) DoRandomRange(max, __LINE__, __FILE__) - uint DoRandomRange(uint max, int line, const char *file); + uint32 DoRandomRange(uint32 max, int line, const char *file); #else static FORCEINLINE uint32 Random() { return _random.Next(); } - static FORCEINLINE uint32 RandomRange(uint max) + static FORCEINLINE uint32 RandomRange(uint32 max) { - assert(max <= UINT16_MAX); return _random.Next(max); } #endif @@ -111,7 +110,7 @@ static FORCEINLINE uint32 InteractiveRandom() return _interactive_random.Next(); } -static FORCEINLINE uint32 InteractiveRandomRange(uint16 max) +static FORCEINLINE uint32 InteractiveRandomRange(uint32 max) { return _interactive_random.Next(max); } diff --git a/src/economy.cpp b/src/economy.cpp index d326336a59..7548513e75 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -297,6 +297,11 @@ int UpdateCompanyRatingAndValue(Company *c, bool update) /* use INVALID_OWNER as new_owner to delete the company. */ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) { +#ifdef ENABLE_NETWORK + /* In all cases, make spectators of clients connected to that company */ + if (_networking) NetworkClientsToSpectators(old_owner); +#endif /* ENABLE_NETWORK */ + Town *t; CompanyID old = _current_company; @@ -471,21 +476,6 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) MarkWholeScreenDirty(); } -static void ChangeNetworkOwner(Owner current_owner, Owner new_owner) -{ -#ifdef ENABLE_NETWORK - if (!_networking) return; - - if (current_owner == _local_company) { - SetLocalCompany(new_owner); - } - - if (!_network_server) return; - - NetworkServerChangeOwner(current_owner, new_owner); -#endif /* ENABLE_NETWORK */ -} - static void CompanyCheckBankrupt(Company *c) { /* If the company has money again, it does not go bankrupt */ @@ -547,8 +537,6 @@ static void CompanyCheckBankrupt(Company *c) SetDParamStr(2, cni->company_name); AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_BANKRUPT, cni); - /* Remove the company */ - ChangeNetworkOwner(c->index, COMPANY_SPECTATOR); ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); if (c->is_ai) AI::Stop(c->index); @@ -1459,8 +1447,6 @@ static void DoAcquireCompany(Company *c) AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_MERGER, cni); AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company)); - /* original code does this a little bit differently */ - ChangeNetworkOwner(ci, _current_company); ChangeOwnershipOfCompanyItems(ci, _current_company); if (c->bankrupt_value == 0) { diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 13d11c8cbf..ec62c41a93 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1892,8 +1892,7 @@ void GenerateIndustries() /* Add the remaining industries according to their probabilities */ for (uint i = 0; i < total_amount; i++) { - /* RandomRange() can only deal with 16 bit, which is not enough here. */ - uint32 r = ((uint64)Random() * (uint64)total_prob) >> 32; + uint32 r = RandomRange(total_prob); IndustryType it = 0; while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) { r -= industry_probs[it]; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 65d7e3d14e..fc280ed972 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -453,6 +453,8 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) if (MY_CLIENT->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; + if (!Company::IsValidID(playas)) playas = COMPANY_SPECTATOR; + ci = NetworkFindClientInfoFromClientID(client_id); if (ci != NULL) { if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) { @@ -463,6 +465,10 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) * Do not display that for now */ } + /* Make sure we're in the company the server tells us to be in, + * for the rare case that we get moved while joining. */ + if (client_id == _network_own_client_id) SetLocalCompany(playas); + ci->client_playas = playas; strecpy(ci->client_name, name, lastof(ci->client_name)); @@ -1023,6 +1029,19 @@ void NetworkClientRequestMove(CompanyID company_id, const char *pass) SEND_COMMAND(PACKET_CLIENT_MOVE)(company_id, pass); } +void NetworkClientsToSpectators(CompanyID cid) +{ + /* If our company is changing owner, go to spectators */ + if (cid == _local_company) SetLocalCompany(COMPANY_SPECTATOR); + + NetworkClientInfo *ci; + FOR_ALL_CLIENT_INFOS(ci) { + if (ci->client_playas != cid) continue; + NetworkTextMessage(NETWORK_ACTION_COMPANY_SPECTATOR, CC_DEFAULT, false, ci->client_name); + ci->client_playas = COMPANY_SPECTATOR; + } +} + void NetworkUpdateClientName() { NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_network_own_client_id); diff --git a/src/network/network_func.h b/src/network/network_func.h index afc24aeb81..72539e5011 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -47,6 +47,7 @@ void NetworkStartDebugLog(NetworkAddress address); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); +void NetworkClientsToSpectators(CompanyID cid); void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = NULL, const char *join_company_password = NULL); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); @@ -61,7 +62,6 @@ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode); /*** Commands ran by the server ***/ void NetworkServerMonthlyLoop(); void NetworkServerYearlyLoop(); -void NetworkServerChangeOwner(Owner current_owner, Owner new_owner); void NetworkServerSendConfigUpdate(); void NetworkServerShowStatusToConsole(); bool NetworkServerStart(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index eeae864c59..697a6630b0 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1099,9 +1099,9 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co } 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 company */ + /* If this is false, the message is already displayed on the client who sent it. */ + bool show_local = true; + /* Find all clients that belong to this company */ ci_to = NULL; FOR_ALL_CLIENT_SOCKETS(cs) { ci = cs->GetInfo(); @@ -1694,27 +1694,6 @@ void NetworkServerMonthlyLoop() NetworkAutoCleanCompanies(); } -void NetworkServerChangeOwner(Owner current_owner, Owner new_owner) -{ - /* The server has to handle all administrative issues, for example - * updating and notifying all clients of what has happened */ - NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER); - - /* The server has just changed from owner */ - if (current_owner == ci->client_playas) { - ci->client_playas = new_owner; - NetworkUpdateClientInfo(CLIENT_ID_SERVER); - } - - /* Find all clients that were in control of this company, and mark them as new_owner */ - FOR_ALL_CLIENT_INFOS(ci) { - if (current_owner == ci->client_playas) { - ci->client_playas = new_owner; - NetworkUpdateClientInfo(ci->client_id); - } - } -} - const char *GetClientIP(NetworkClientInfo *ci) { return ci->client_address.GetHostname(); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 24673bd402..fa2686680c 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -402,6 +402,9 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern size_t len = (Engine::GetPoolSize() - engine_pool_size) * sizeof(*_gted); memset(_gted + engine_pool_size, 0, len); } + if (type == VEH_TRAIN) { + _gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label; + } grfmsg(5, "Created new engine at index %d for GRFID %x, type %d, index %d", e->index, BSWAP32(file->grfid), type, internal_id); diff --git a/src/strings.cpp b/src/strings.cpp index 21767fcaf5..f07139f0a0 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -390,17 +390,17 @@ static int DeterminePluralForm(int64 count) case 2: return n > 1; - /* Three forms, special case for zero + /* Three forms, special case for 0 and ending in 1, except those ending in 11 * Used in: * Latvian */ case 3: return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2; - /* Three forms, special case for one and two + /* Five forms, special case for one, two, 3 to 6 and 7 to 10 * Used in: * Gaelige (Irish) */ case 4: - return n == 1 ? 0 : n == 2 ? 1 : 2; + return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4; /* Three forms, special case for numbers ending in 1[2-9] * Used in: @@ -463,6 +463,12 @@ static int DeterminePluralForm(int64 count) default: NOT_REACHED(); } + + /* Four forms: one, 0 and everything ending in 02..10, everything ending in 11..19. + * Used in: + * Maltese */ + case 12: + return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3); } } diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index 40a1b7fa35..b37133d538 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -155,7 +155,7 @@ static const PluralForm _plural_forms[] = { { 1, "Only one form" }, { 2, "Two forms, singular used for zero and 1" }, { 3, "Three forms, special case for 0 and ending in 1, except those ending in 11" }, - { 3, "Three forms, special case for 1 and 2" }, + { 5, "Five forms, special case for one, two, 3 to 6 and 7 to 10" }, { 3, "Three forms, special case for numbers ending in 1[2-9]" }, { 3, "Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]" }, { 3, "Three forms, special case for 1 and some numbers ending in 2, 3, or 4" }, @@ -163,6 +163,7 @@ static const PluralForm _plural_forms[] = { { 2, "Two forms, singular used for everything ending in 1 but not in 11" }, { 3, "Three forms, special case for 1 and 2, 3, or 4" }, { 2, "Two forms, cases for numbers ending with a consonant and with a vowel" }, + { 4, "Four forms: one, 0 and everything ending in 02..10, everything ending in 11..19" }, }; /* Flags: