mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-07 06:39:08 +00:00
(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)
This commit is contained in:
parent
4fada121bd
commit
9f14d652a9
@ -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(2): " + AIBase.RandRange(2));
|
||||||
print(" RandRange(2): " + AIBase.RandRange(2));
|
print(" RandRange(2): " + AIBase.RandRange(2));
|
||||||
print(" RandRange(9): " + AIBase.RandRange(9));
|
print(" RandRange(1000000): " + AIBase.RandRange(1000000)); // 32 bit tests
|
||||||
print(" RandRange(9): " + AIBase.RandRange(9));
|
print(" RandRange(1000000): " + AIBase.RandRange(1000000));
|
||||||
print(" RandRange(9): " + AIBase.RandRange(9));
|
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));
|
print(" Chance(1, 2): " + AIBase.Chance(1, 2));
|
||||||
print(" Chance(1, 2): " + AIBase.Chance(1, 2));
|
print(" Chance(1, 2): " + AIBase.Chance(1, 2));
|
||||||
|
@ -96,10 +96,10 @@
|
|||||||
RandRange(1): 0
|
RandRange(1): 0
|
||||||
RandRange(2): 0
|
RandRange(2): 0
|
||||||
RandRange(2): 0
|
RandRange(2): 0
|
||||||
RandRange(2): 1
|
RandRange(2): 0
|
||||||
RandRange(9): 6
|
RandRange(1000000): 987346
|
||||||
RandRange(9): 7
|
RandRange(1000000): 781750
|
||||||
RandRange(9): 4
|
RandRange(1000000): 191841
|
||||||
Chance(1, 2): true
|
Chance(1, 2): true
|
||||||
Chance(1, 2): false
|
Chance(1, 2): false
|
||||||
Chance(1, 2): false
|
Chance(1, 2): false
|
||||||
|
@ -24,9 +24,9 @@ uint32 Randomizer::Next()
|
|||||||
return this->state[1] = ROR(s, 3) - 1;
|
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)
|
void Randomizer::SetSeed(uint32 seed)
|
||||||
@ -55,9 +55,8 @@ uint32 DoRandom(int line, const char *file)
|
|||||||
return _random.Next();
|
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 ((uint64)DoRandom(line, file) * (uint64)max) >> 32;
|
||||||
return GB(DoRandom(line, file), 0, 16) * max >> 16;
|
|
||||||
}
|
}
|
||||||
#endif /* RANDOM_DEBUG */
|
#endif /* RANDOM_DEBUG */
|
||||||
|
@ -48,7 +48,7 @@ struct Randomizer {
|
|||||||
* @param max the maximum value of the returned random number
|
* @param max the maximum value of the returned random number
|
||||||
* @return the random number
|
* @return the random number
|
||||||
*/
|
*/
|
||||||
uint32 Next(uint16 max);
|
uint32 Next(uint32 max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Re)set the state of the random number generator.
|
* (Re)set the state of the random number generator.
|
||||||
@ -92,16 +92,15 @@ void SetRandomSeed(uint32 seed);
|
|||||||
#endif
|
#endif
|
||||||
uint32 DoRandom(int line, const char *file);
|
uint32 DoRandom(int line, const char *file);
|
||||||
#define RandomRange(max) DoRandomRange(max, __LINE__, __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
|
#else
|
||||||
static FORCEINLINE uint32 Random()
|
static FORCEINLINE uint32 Random()
|
||||||
{
|
{
|
||||||
return _random.Next();
|
return _random.Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCEINLINE uint32 RandomRange(uint max)
|
static FORCEINLINE uint32 RandomRange(uint32 max)
|
||||||
{
|
{
|
||||||
assert(max <= UINT16_MAX);
|
|
||||||
return _random.Next(max);
|
return _random.Next(max);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -111,7 +110,7 @@ static FORCEINLINE uint32 InteractiveRandom()
|
|||||||
return _interactive_random.Next();
|
return _interactive_random.Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCEINLINE uint32 InteractiveRandomRange(uint16 max)
|
static FORCEINLINE uint32 InteractiveRandomRange(uint32 max)
|
||||||
{
|
{
|
||||||
return _interactive_random.Next(max);
|
return _interactive_random.Next(max);
|
||||||
}
|
}
|
||||||
|
@ -297,6 +297,11 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
|||||||
/* use INVALID_OWNER as new_owner to delete the company. */
|
/* use INVALID_OWNER as new_owner to delete the company. */
|
||||||
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
|
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;
|
Town *t;
|
||||||
CompanyID old = _current_company;
|
CompanyID old = _current_company;
|
||||||
|
|
||||||
@ -471,21 +476,6 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
|
|||||||
MarkWholeScreenDirty();
|
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)
|
static void CompanyCheckBankrupt(Company *c)
|
||||||
{
|
{
|
||||||
/* If the company has money again, it does not go bankrupt */
|
/* 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);
|
SetDParamStr(2, cni->company_name);
|
||||||
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_BANKRUPT, cni);
|
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_BANKRUPT, cni);
|
||||||
|
|
||||||
/* Remove the company */
|
|
||||||
ChangeNetworkOwner(c->index, COMPANY_SPECTATOR);
|
|
||||||
ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
|
ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
|
||||||
|
|
||||||
if (c->is_ai) AI::Stop(c->index);
|
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);
|
AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_MERGER, cni);
|
||||||
AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
|
AI::BroadcastNewEvent(new AIEventCompanyMerger(ci, _current_company));
|
||||||
|
|
||||||
/* original code does this a little bit differently */
|
|
||||||
ChangeNetworkOwner(ci, _current_company);
|
|
||||||
ChangeOwnershipOfCompanyItems(ci, _current_company);
|
ChangeOwnershipOfCompanyItems(ci, _current_company);
|
||||||
|
|
||||||
if (c->bankrupt_value == 0) {
|
if (c->bankrupt_value == 0) {
|
||||||
|
@ -1892,8 +1892,7 @@ void GenerateIndustries()
|
|||||||
|
|
||||||
/* Add the remaining industries according to their probabilities */
|
/* Add the remaining industries according to their probabilities */
|
||||||
for (uint i = 0; i < total_amount; i++) {
|
for (uint i = 0; i < total_amount; i++) {
|
||||||
/* RandomRange() can only deal with 16 bit, which is not enough here. */
|
uint32 r = RandomRange(total_prob);
|
||||||
uint32 r = ((uint64)Random() * (uint64)total_prob) >> 32;
|
|
||||||
IndustryType it = 0;
|
IndustryType it = 0;
|
||||||
while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) {
|
while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) {
|
||||||
r -= industry_probs[it];
|
r -= industry_probs[it];
|
||||||
|
@ -453,6 +453,8 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
|
|||||||
|
|
||||||
if (MY_CLIENT->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
if (MY_CLIENT->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
|
||||||
|
|
||||||
|
if (!Company::IsValidID(playas)) playas = COMPANY_SPECTATOR;
|
||||||
|
|
||||||
ci = NetworkFindClientInfoFromClientID(client_id);
|
ci = NetworkFindClientInfoFromClientID(client_id);
|
||||||
if (ci != NULL) {
|
if (ci != NULL) {
|
||||||
if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
|
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 */
|
* 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;
|
ci->client_playas = playas;
|
||||||
strecpy(ci->client_name, name, lastof(ci->client_name));
|
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);
|
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()
|
void NetworkUpdateClientName()
|
||||||
{
|
{
|
||||||
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_network_own_client_id);
|
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_network_own_client_id);
|
||||||
|
@ -47,6 +47,7 @@ void NetworkStartDebugLog(NetworkAddress address);
|
|||||||
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
||||||
|
|
||||||
void NetworkUpdateClientInfo(ClientID client_id);
|
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 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 NetworkClientRequestMove(CompanyID company, const char *pass = "");
|
||||||
void NetworkClientSendRcon(const char *password, const char *command);
|
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 ***/
|
/*** Commands ran by the server ***/
|
||||||
void NetworkServerMonthlyLoop();
|
void NetworkServerMonthlyLoop();
|
||||||
void NetworkServerYearlyLoop();
|
void NetworkServerYearlyLoop();
|
||||||
void NetworkServerChangeOwner(Owner current_owner, Owner new_owner);
|
|
||||||
void NetworkServerSendConfigUpdate();
|
void NetworkServerSendConfigUpdate();
|
||||||
void NetworkServerShowStatusToConsole();
|
void NetworkServerShowStatusToConsole();
|
||||||
bool NetworkServerStart();
|
bool NetworkServerStart();
|
||||||
|
@ -1099,9 +1099,9 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DESTTYPE_TEAM: {
|
case DESTTYPE_TEAM: {
|
||||||
bool show_local = true; // If this is false, the message is already displayed
|
/* If this is false, the message is already displayed on the client who sent it. */
|
||||||
/* on the client who did sent it.
|
bool show_local = true;
|
||||||
* Find all clients that belong to this company */
|
/* Find all clients that belong to this company */
|
||||||
ci_to = NULL;
|
ci_to = NULL;
|
||||||
FOR_ALL_CLIENT_SOCKETS(cs) {
|
FOR_ALL_CLIENT_SOCKETS(cs) {
|
||||||
ci = cs->GetInfo();
|
ci = cs->GetInfo();
|
||||||
@ -1694,27 +1694,6 @@ void NetworkServerMonthlyLoop()
|
|||||||
NetworkAutoCleanCompanies();
|
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)
|
const char *GetClientIP(NetworkClientInfo *ci)
|
||||||
{
|
{
|
||||||
return ci->client_address.GetHostname();
|
return ci->client_address.GetHostname();
|
||||||
|
@ -402,6 +402,9 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern
|
|||||||
size_t len = (Engine::GetPoolSize() - engine_pool_size) * sizeof(*_gted);
|
size_t len = (Engine::GetPoolSize() - engine_pool_size) * sizeof(*_gted);
|
||||||
memset(_gted + engine_pool_size, 0, len);
|
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);
|
grfmsg(5, "Created new engine at index %d for GRFID %x, type %d, index %d", e->index, BSWAP32(file->grfid), type, internal_id);
|
||||||
|
|
||||||
|
@ -390,17 +390,17 @@ static int DeterminePluralForm(int64 count)
|
|||||||
case 2:
|
case 2:
|
||||||
return n > 1;
|
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:
|
* Used in:
|
||||||
* Latvian */
|
* Latvian */
|
||||||
case 3:
|
case 3:
|
||||||
return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
|
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:
|
* Used in:
|
||||||
* Gaelige (Irish) */
|
* Gaelige (Irish) */
|
||||||
case 4:
|
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]
|
/* Three forms, special case for numbers ending in 1[2-9]
|
||||||
* Used in:
|
* Used in:
|
||||||
@ -463,6 +463,12 @@ static int DeterminePluralForm(int64 count)
|
|||||||
default:
|
default:
|
||||||
NOT_REACHED();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ static const PluralForm _plural_forms[] = {
|
|||||||
{ 1, "Only one form" },
|
{ 1, "Only one form" },
|
||||||
{ 2, "Two forms, singular used for zero and 1" },
|
{ 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 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 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 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" },
|
{ 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" },
|
{ 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" },
|
{ 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" },
|
{ 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:
|
/* Flags:
|
||||||
|
Loading…
Reference in New Issue
Block a user