diff --git a/economy.c b/economy.c index cf23e65fda..68fd142e11 100644 --- a/economy.c +++ b/economy.c @@ -11,6 +11,7 @@ #include "economy.h" #include "industry.h" #include "town.h" +#include "network.h" void UpdatePlayerHouse(Player *p, uint score) { @@ -807,11 +808,11 @@ static void FindSubsidyPassengerRoute(FoundRoute *fr) fr->distance = (uint)-1; - fr->from = from = DEREF_TOWN(RandomRange(_total_towns)); + fr->from = from = DEREF_TOWN(InteractiveRandomRange(_total_towns)); if (from->xy == 0 || from->population < 400) return; - fr->to = to = DEREF_TOWN(RandomRange(_total_towns)); + fr->to = to = DEREF_TOWN(InteractiveRandomRange(_total_towns)); if (from==to || to->xy == 0 || to->population < 400 || to->pct_pass_transported > 42) return; @@ -826,12 +827,12 @@ static void FindSubsidyCargoRoute(FoundRoute *fr) fr->distance = (uint)-1; - fr->from = i = DEREF_INDUSTRY(RandomRange(_total_industries)); + fr->from = i = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries)); if (i->xy == 0) return; // Randomize cargo type - if (Random()&1 && i->produced_cargo[1] != 0xFF) { + if (InteractiveRandom()&1 && i->produced_cargo[1] != 0xFF) { cargo = i->produced_cargo[1]; trans = i->pct_transported[1]; total = i->total_production[1]; @@ -851,7 +852,7 @@ static void FindSubsidyCargoRoute(FoundRoute *fr) if (cargo == CT_GOODS || cargo == CT_FOOD) { // The destination is a town - Town *t = DEREF_TOWN(RandomRange(_total_towns)); + Town *t = DEREF_TOWN(InteractiveRandomRange(_total_towns)); // Only want big towns if (t->xy == 0 || t->population < 900) @@ -860,7 +861,7 @@ static void FindSubsidyCargoRoute(FoundRoute *fr) fr->to = t; } else { // The destination is an industry - Industry *i2 = DEREF_INDUSTRY(RandomRange(_total_industries)); + Industry *i2 = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries)); // The industry must accept the cargo if (i == i2 || i2->xy == 0 || @@ -890,6 +891,25 @@ static bool CheckSubsidyDuplicate(Subsidy *s) return false; } +void RemoteSubsidyAdd(Subsidy *s_new) +{ + Subsidy *s; + Pair pair; + + // search the first free subsidy + for(s=_subsidies; s != endof(_subsidies); s++) + if (s->cargo_type == 0xFF) + break; + + memcpy(s,s_new,sizeof(Subsidy)); + + pair = SetupSubsidyDecodeParam(s, 0); + AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b); + + InvalidateWindow(WC_SUBSIDIES_LIST, 0); + +} + static void SubsidyMonthlyHandler() { Subsidy *s; @@ -921,8 +941,10 @@ static void SubsidyMonthlyHandler() } } + if ((_networking) && (!_networking_server)) return; + // 25% chance to go on - if (CHANCE16(1,4)) { + if (ICHANCE16(1,4)) { // Find a free slot s = _subsidies; while (s->cargo_type != 0xFF) { @@ -948,12 +970,13 @@ static void SubsidyMonthlyHandler() if (!CheckSubsidyDuplicate(s)) { s->age = 0; pair = SetupSubsidyDecodeParam(s, 0); + if (_networking_server) NetworkSendEvent(NET_EVENT_SUBSIDY,sizeof(Subsidy),s); AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b); modified = true; break; } } - } while (--n); + } while (n--); } no_add:; if (modified) diff --git a/economy.h b/economy.h index 690fc61fcd..c9c043ff1e 100644 --- a/economy.h +++ b/economy.h @@ -70,6 +70,7 @@ VARDEF Subsidy _subsidies[MAX_PLAYERS]; Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode); void DeleteSubsidyWithIndustry(byte index); void DeleteSubsidyWithStation(byte index); +void RemoteSubsidyAdd(Subsidy *s_new); int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type); uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount); diff --git a/functions.h b/functions.h index ab9ec0b4e8..7d729c0ee9 100644 --- a/functions.h +++ b/functions.h @@ -100,6 +100,8 @@ uint RandomRange(uint max); void InitPlayerRandoms(); uint32 InteractiveRandom(); /* Used for random sequences that are not the same on the other end of the multiplayer link */ +uint InteractiveRandomRange(uint max); + void SetDate(uint date); /* facedraw.c */ void DrawPlayerFace(uint32 face, int color, int x, int y); @@ -132,6 +134,7 @@ void NetworkListen(); void NetworkInitialize(); void NetworkShutdown(); void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback); +void NetworkSendEvent(uint16 type, uint16 data_len, void * data); void NetworkStartSync(bool fcreset); void NetworkClose(bool client); void NetworkSendReadyPacket(); diff --git a/macros.h b/macros.h index 40c923f7e9..6bde10e4a9 100644 --- a/macros.h +++ b/macros.h @@ -170,6 +170,7 @@ static INLINE int FindFirstBit2x64(int value) #define CHANCE16(a,b) ((uint16)Random() <= (uint16)((65536 * a) / b)) +#define ICHANCE16(a,b) ((uint16)InteractiveRandom() <= (uint16)((65536 * a) / b)) #define CHANCE16R(a,b,r) ((uint16)(r=Random()) <= (uint16)((65536 * a) / b)) #define CHANCE16I(a,b,v) ((uint16)(v) <= (uint16)((65536 * a) / b)) diff --git a/misc.c b/misc.c index dcaf494db0..b353c5e27b 100644 --- a/misc.c +++ b/misc.c @@ -44,6 +44,11 @@ uint32 InteractiveRandom() return _random_seeds[1][1] = ROR(s, 3); } +uint InteractiveRandomRange(uint max) +{ + return (uint16)InteractiveRandom() * max >> 16; +} + void InitPlayerRandoms() { int i; diff --git a/network.c b/network.c index 5ec84508f3..6d7cadab83 100644 --- a/network.c +++ b/network.c @@ -4,6 +4,7 @@ #include "command.h" #include "player.h" #include "console.h" +#include "economy.h" #if defined(WIN32) # include @@ -87,6 +88,7 @@ enum { PACKET_TYPE_FSYNC, PACKET_TYPE_XMIT, PACKET_TYPE_COMMAND, + PACKET_TYPE_EVENT, }; // sent from client -> server whenever the client wants to exec a command. @@ -102,6 +104,13 @@ typedef struct CommandPacket { uint32 dp[8]; } CommandPacket; +typedef struct EventPacket { + byte packet_length; + byte packet_type; + byte event_type; + byte data_start; +} EventPacket; + #define COMMAND_PACKET_BASE_SIZE (sizeof(CommandPacket) - 8 * sizeof(uint32)) // sent from server -> client periodically to tell the client about the current tick in the server @@ -343,9 +352,9 @@ static void QueueClear(CommandQueue *nq) static int GetNextSyncFrame() { uint32 newframe; - if (_frame_fsync_last == 0) return -1; - newframe = (_frame_fsync_last + 9); - if ( (newframe + 4) > _frame_counter_max) return -1; + if (_frame_fsync_last == 0) return -5; + newframe = (_frame_fsync_last + 16); + if ( (newframe + 4) > _frame_counter_max) return -5; return (_frame_counter_max - newframe); } @@ -367,7 +376,7 @@ void NetworkProcessCommands() if (!(nq->head = qp->next)) nq->last = &nq->head; if (qp->frame < _frame_counter && _networking_sync) { - DEBUG(net,0) ("error: !qp->cp.frame < _frame_counter, %d < %d\n", qp->frame, _frame_counter); + DEBUG(net,0) ("warning: !qp->cp.frame < _frame_counter, %d < %d [%d]\n", qp->frame, _frame_counter, _frame_counter_srv+4); } // run the command @@ -495,6 +504,25 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman } } +void NetworkSendEvent(uint16 type, uint16 data_len, void * data) +{ + EventPacket * ep; + ClientState *cs; + + // encode the event ... add its data + ep=malloc(data_len+sizeof(EventPacket)-1); + ep->event_type = type; + ep->packet_length = data_len+sizeof(EventPacket)-1; + ep->packet_type = PACKET_TYPE_EVENT; + memcpy(&ep->data_start,data,data_len); + + // send it to the peers + for(cs=_clients; cs->socket != INVALID_SOCKET; cs++) if (!cs->inactive) SendBytes(cs, ep, ep->packet_length); + + // free the temp packet + free(ep); +} + // client: // server sends a command from another player that we should execute. // put it in the command queue. @@ -572,6 +600,15 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np) } } +static void HandleEventPacket(EventPacket *ep) +{ + switch (ep->event_type) { + case NET_EVENT_SUBSIDY: + RemoteSubsidyAdd((Subsidy *)&ep->data_start); + break; + } +} + // sent from server -> client periodically to tell the client about the current tick in the server // and how far the client may progress. static void HandleSyncPacket(SyncPacket *sp) @@ -785,6 +822,9 @@ static bool ReadPackets(ClientState *cs) case PACKET_TYPE_READY: HandleReadyPacket((ReadyPacket*)packet, cs); break; + case PACKET_TYPE_EVENT: + HandleEventPacket((EventPacket*)packet); + break; default: DEBUG (net,0) ("net: unknown packet type"); } @@ -1907,6 +1947,7 @@ void NetworkConnect(const char *hostname, int port) {} void NetworkReceive() {} void NetworkSend() {} void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {} +void NetworkSendEvent(uint16 type, uint16 data_len, void * data) {}; void NetworkProcessCommands() {} void NetworkStartSync(bool fcreset) {} void NetworkSendReadyPacket() {} diff --git a/network.h b/network.h index df4871ba99..9b8169069d 100644 --- a/network.h +++ b/network.h @@ -24,6 +24,10 @@ typedef struct NetworkGameList { struct NetworkGameList * _next; } NetworkGameList; +enum { + NET_EVENT_SUBSIDY = 0, +}; + NetworkGameInfo _network_game; NetworkGameList * _network_game_list; diff --git a/ttd.c b/ttd.c index 2e760e1882..88021d6a83 100644 --- a/ttd.c +++ b/ttd.c @@ -889,7 +889,7 @@ void StateGameLoop() // store the random seed to be able to detect out of sync errors _sync_seed_1 = _random_seeds[0][0]; _sync_seed_2 = _random_seeds[0][1]; - if (_networking) disable_computer=true; + if (_networking) disable_computer=true; if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) { char buf[100];