summaryrefslogtreecommitdiff
path: root/ttd.c
diff options
context:
space:
mode:
authortruelight <truelight@openttd.org>2004-12-04 17:54:56 +0000
committertruelight <truelight@openttd.org>2004-12-04 17:54:56 +0000
commitb8f6d41418982163965dd5beb0b39dbdce1fbe8f (patch)
tree68d3e795694a875138c369707ed74b5b4b022d49 /ttd.c
parent0434287ef826a4ed72cd8528a52a86ae8b70a948 (diff)
downloadopenttd-b8f6d41418982163965dd5beb0b39dbdce1fbe8f.tar.xz
(svn r942) -Merged branch/network back into the trunk
Diffstat (limited to 'ttd.c')
-rw-r--r--ttd.c298
1 files changed, 174 insertions, 124 deletions
diff --git a/ttd.c b/ttd.c
index f3b269f35..7fd59d05a 100644
--- a/ttd.c
+++ b/ttd.c
@@ -24,6 +24,7 @@
#include "ai.h"
#include "console.h"
#include "screenshot.h"
+#include "network.h"
#include <stdarg.h>
@@ -53,7 +54,7 @@ extern void HalGameLoop();
uint32 _pixels_redrawn;
bool _dbg_screen_rect;
-bool disable_computer;
+bool disable_computer; // We should get ride of this thing.. is only used for a debug-cheat
static byte _os_version = 0;
void CDECL error(const char *s, ...) {
@@ -299,17 +300,21 @@ static void showhelp()
p = strecpy(buf,
"Command line options:\n"
- " -v drv = Set video driver (see below)\n"
- " -s drv = Set sound driver (see below)\n"
- " -m drv = Set music driver (see below)\n"
- " -r res = Set resolution (for instance 800x600)\n"
- " -h = Display this help text\n"
- " -t date= Set starting date\n"
- " -d dbg = Debug mode\n"
- " -l lng = Select Language\n"
- " -e = Start Editor\n"
- " -g = Start new game immediately (can optionally take a game to load)\n"
- " -G seed= Set random seed\n"
+ " -v drv = Set video driver (see below)\n"
+ " -s drv = Set sound driver (see below)\n"
+ " -m drv = Set music driver (see below)\n"
+ " -r res = Set resolution (for instance 800x600)\n"
+ " -h = Display this help text\n"
+ " -t date = Set starting date\n"
+ " -d [dbg] = Debug mode\n"
+ " -l lng = Select Language\n"
+ " -e = Start Editor\n"
+ " -g [savegame] = Start new/save game immediately\n"
+ " -G seed = Set random seed\n"
+ " -n [ip#player:port] = Start networkgame\n"
+ " -D = Start dedicated server\n"
+ " -i = Ignore wrong grf\n"
+ " -p #player = Player as #player (deprecated) (network only)\n"
);
for(i=0; i!=lengthof(_driver_classes); i++,dc++) {
@@ -474,11 +479,40 @@ void ParseResolution(int res[2], char *s)
res[1] = strtoul(t + 1, NULL, 0);
}
+void LoadIntroGame()
+{
+ char filename[256];
+ _game_mode = GM_MENU;
+ _display_opt &= ~DO_TRANS_BUILDINGS; // don't make buildings transparent in intro
+
+ _opt_mod_ptr = &_new_opt;
+ GfxLoadSprites();
+ LoadStringWidthTable();
+
+ // Setup main window
+ InitWindowSystem();
+ SetupColorsAndInitialWindow();
+
+ // Generate a world.
+ sprintf(filename, "%sopntitle.dat", _path.data_dir);
+ if (SaveOrLoad(filename, SL_LOAD) != SL_OK)
+ GenerateWorld(1); // if failed loading, make empty world.
+
+ _opt.currency = _new_opt.currency;
+
+ _pause = 0;
+ _local_player = 0;
+ MarkWholeScreenDirty();
+
+ // Play main theme
+ if (_music_driver->is_song_playing()) ResetMusic();
+}
+
int ttd_main(int argc, char* argv[])
{
MyGetOptData mgo;
int i;
- int network = 0;
+ bool network = false;
char *network_conn = NULL;
char *language = NULL;
char musicdriver[16], sounddriver[16], videodriver[16];
@@ -486,25 +520,31 @@ int ttd_main(int argc, char* argv[])
uint startdate = -1;
_ignore_wrong_grf = false;
musicdriver[0] = sounddriver[0] = videodriver[0] = 0;
- _networking_override=false;
_game_mode = GM_MENU;
_switch_mode = SM_MENU;
_switch_mode_errorstr = INVALID_STRING_ID;
- MyGetOptInit(&mgo, argc-1, argv+1, "m:s:v:hn::l:eit:d::r:g::G:cp:");
+ // The last param of the following function means this:
+ // a letter means: it accepts that param (e.g.: -h)
+ // a ':' behind it means: it need a param (e.g.: -m<driver>)
+ // a '::' behind it means: it can optional have a param (e.g.: -d<debug>)
+ MyGetOptInit(&mgo, argc-1, argv+1, "m:s:v:hDn::l:eit:d::r:g::G:p:");
while ((i = MyGetOpt(&mgo)) != -1) {
switch(i) {
case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break;
case 's': ttd_strlcpy(sounddriver, mgo.opt, sizeof(sounddriver)); break;
case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break;
+ case 'D': {
+ sprintf(musicdriver,"null");
+ sprintf(sounddriver,"null");
+ sprintf(videodriver,"dedicated");
+ } break;
case 'n': {
- network = 1;
- _networking_override=true;
- if (mgo.opt) {
+ network = true;
+ if (mgo.opt)
+ // Optional, you can give an IP
network_conn = mgo.opt;
- network++;
- }
else
network_conn = NULL;
} break;
@@ -536,7 +576,8 @@ int ttd_main(int argc, char* argv[])
break;
case 'p': {
int i = atoi(mgo.opt);
- if (IS_INT_INSIDE(i, 0, MAX_PLAYERS)) _network_playas = i + 1;
+ // Play as an other player in network games
+ if (IS_INT_INSIDE(i, 1, MAX_PLAYERS)) _network_playas = i;
break;
}
case -2:
@@ -556,9 +597,6 @@ int ttd_main(int argc, char* argv[])
if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; }
if (startdate != -1) _patches.starting_date = startdate;
- // initialize network-core
- NetworkCoreInit();
-
// enumerate language files
InitializeLanguagePacks();
@@ -586,6 +624,11 @@ int ttd_main(int argc, char* argv[])
MusicLoop();
_savegame_sort_order = 1; // default sorting of savegames is by date, newest first
+#ifdef ENABLE_NETWORK
+ // initialize network-core
+ NetworkStartUp();
+#endif /* ENABLE_NETWORK */
+
// Default difficulty level
_opt_mod_ptr = &_new_opt;
@@ -593,27 +636,45 @@ int ttd_main(int argc, char* argv[])
if (_opt_mod_ptr->diff_level == 9)
SetDifficultyLevel(0, _opt_mod_ptr);
- if ((network) && (_network_available)) {
- NetworkLobbyInit();
- if (network_conn!=NULL) {
- NetworkCoreConnectGame(network_conn,_network_server_port);
- } else {
- NetworkCoreConnectGame("auto",_network_server_port);
- }
- }
-
// initialize the ingame console
IConsoleInit();
InitPlayerRandoms();
+#ifdef ENABLE_NETWORK
+ if ((network) && (_network_available)) {
+ if (network_conn != NULL) {
+ const byte *port = NULL;
+ const byte *player = NULL;
+ uint16 rport;
+
+ rport = NETWORK_DEFAULT_PORT;
+
+ ParseConnectionString(&player, &port, network_conn);
+
+ if (player != NULL) _network_playas = atoi(player);
+ if (port != NULL) rport = atoi(port);
+
+ LoadIntroGame();
+ _switch_mode = SM_NONE;
+ NetworkClientConnectGame(network_conn, rport);
+ } else {
+// NetworkCoreConnectGame("auto", _network_server_port);
+ }
+ }
+#endif /* ENABLE_NETWORK */
+
while (_video_driver->main_loop() == ML_SWITCHDRIVER) {}
IConsoleFree();
+#ifdef ENABLE_NETWORK
if (_network_available) {
- // shutdown network-core
- NetworkCoreShutdown();
- }
+ // Shut down the network and close any open connections
+ NetworkDisconnect();
+ NetworkUDPClose();
+ NetworkShutDown();
+ }
+#endif /* ENABLE_NETWORK */
_video_driver->stop();
_music_driver->stop();
@@ -638,35 +699,6 @@ static void ShowScreenshotResult(bool b)
}
-static void LoadIntroGame()
-{
- char filename[256];
- _game_mode = GM_MENU;
- _display_opt &= ~DO_TRANS_BUILDINGS; // don't make buildings transparent in intro
-
- _opt_mod_ptr = &_new_opt;
- GfxLoadSprites();
- LoadStringWidthTable();
-
- // Setup main window
- InitWindowSystem();
- SetupColorsAndInitialWindow();
-
- // Generate a world.
- sprintf(filename, "%sopntitle.dat", _path.data_dir);
- if (SaveOrLoad(filename, SL_LOAD) != SL_OK)
- GenerateWorld(1); // if failed loading, make empty world.
-
- _opt.currency = _new_opt.currency;
-
- _pause = 0;
- _local_player = 0;
- MarkWholeScreenDirty();
-
- // Play main theme
- if (_music_driver->is_song_playing()) ResetMusic();
-}
-
void MakeNewGame()
{
_game_mode = GM_NORMAL;
@@ -686,10 +718,15 @@ void MakeNewGame()
// Randomize world
GenerateWorld(0);
- // Create a single player
- DoStartupNewPlayer(false);
+ // In a dedicated server, the server does not play
+ if (_network_dedicated) {
+ _local_player = OWNER_SPECTATOR;
+ } else {
+ // Create a single player
+ DoStartupNewPlayer(false);
- _local_player = 0;
+ _local_player = 0;
+ }
MarkWholeScreenDirty();
}
@@ -766,7 +803,7 @@ void StartScenario()
MarkWholeScreenDirty();
}
-static bool SafeSaveOrLoad(const char *filename, int mode, int newgm)
+bool SafeSaveOrLoad(const char *filename, int mode, int newgm)
{
byte ogm = _game_mode;
int r;
@@ -788,25 +825,55 @@ static bool SafeSaveOrLoad(const char *filename, int mode, int newgm)
return true;
}
-static void SwitchMode(int new_mode)
+void SwitchMode(int new_mode)
{
_in_state_game_loop = true;
+#ifdef ENABLE_NETWORK
+ // If we are saving something, the network stays in his current state
+ if (new_mode != SM_SAVE) {
+ // If the network is active, make it not-active
+ if (_networking) {
+ if (_network_server && (new_mode == SM_LOAD || new_mode == SM_NEWGAME)) {
+ NetworkReboot();
+ NetworkUDPClose();
+ } else {
+ NetworkDisconnect();
+ NetworkUDPClose();
+ }
+ }
+
+ // If we are a server, we restart the server
+ if (_is_network_server) {
+ // But not if we are going to the menu
+ if (new_mode != SM_MENU) {
+ NetworkServerStart();
+ } else {
+ // This client no longer wants to be a network-server
+ _is_network_server = false;
+ }
+ }
+ }
+#endif /* ENABLE_NETWORK */
+
switch(new_mode) {
case SM_EDITOR: // Switch to scenario editor
MakeNewEditorWorld();
break;
case SM_NEWGAME:
- if (_networking) { NetworkStartSync(true); } // UGLY HACK HACK HACK
+ if (_network_server)
+ snprintf(_network_game_info.map_name, 40, "Random");
MakeNewGame();
break;
+ case SM_START_SCENARIO:
+ StartScenario();
+ break;
+
normal_load:
case SM_LOAD: { // Load game
- if (_networking) { NetworkStartSync(true); } // UGLY HACK HACK HACK
-
_error_message = INVALID_STRING_ID;
if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
ShowErrorMessage(_error_message, STR_4009_GAME_LOAD_FAILED, 0, 0);
@@ -814,6 +881,8 @@ normal_load:
_opt_mod_ptr = &_opt;
_local_player = 0;
DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // decrease pause counter (was increased from opening load dialog)
+ if (_network_server)
+ snprintf(_network_game_info.map_name, 40, "Loaded game");
}
break;
}
@@ -836,6 +905,9 @@ normal_load:
_generating_world = false;
// delete all stations owned by a player
DeleteAllPlayerStations();
+
+ if (_network_server)
+ snprintf(_network_game_info.map_name, 40, "Loaded scenario");
} else
ShowErrorMessage(INVALID_STRING_ID, STR_4009_GAME_LOAD_FAILED, 0, 0);
@@ -844,10 +916,6 @@ normal_load:
case SM_MENU: // Switch to game menu
-
- if ((_networking) && (!_networking_override)) NetworkCoreDisconnect();
- _networking_override=false;
-
LoadIntroGame();
break;
@@ -877,18 +945,17 @@ normal_load:
// The state must not be changed from anywhere
// but here.
// That check is enforced in DoCommand.
-static void StateGameLoop()
+void StateGameLoop()
{
// dont execute the state loop during pause
if (_pause) return;
_in_state_game_loop = true;
- _frame_counter++;
-
- // 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;
+ // _frame_counter is increased somewhere else when in network-mode
+ // Sidenote: _frame_counter is ONLY used for _savedump in non-MP-games
+ // Should that not be deleted? If so, the next 2 lines can also be deleted
+ if (!_networking)
+ _frame_counter++;
if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) {
char buf[100];
@@ -915,13 +982,16 @@ static void StateGameLoop()
CallVehicleTicks();
CallLandscapeTick();
- if (!disable_computer)
+ // To bad the AI does not work in multiplayer, because states are not saved
+ // perfectly
+ if (!disable_computer && !_networking)
RunOtherPlayersLoop();
CallWindowTickEvent();
NewsLoop();
_current_player = p;
}
+
_in_state_game_loop = false;
}
@@ -992,43 +1062,25 @@ void GameLoop()
_timer_counter+=8;
CursorTick();
- // incomming packets
- NetworkCoreLoop(true);
-
- if (_networking_sync) {
- // client: make sure client's time is synched to the server by running frames quickly up to where the server is.
- if (!_networking_server) {
- while (_frame_counter < _frame_counter_srv) {
- NetworkCoreLoop(true);
- StateGameLoop();
- NetworkProcessCommands(); // need to process queue to make sure that packets get executed.
- NetworkCoreLoop(false);
- }
- // client: don't exceed the max count told by the server
- if (_frame_counter < _frame_counter_max) {
- StateGameLoop();
- NetworkProcessCommands();
- }
- // client: send the ready packet
- NetworkSendReadyPacket();
- } else {
- // server: work on to the frame max
- if (_frame_counter < _frame_counter_max) {
- StateGameLoop();
- NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it.
- NetworkSendFrameSyncPackets();
- }
- // server: wait until all clients were ready for going on
- if (_frame_counter == _frame_counter_max) {
- if (NetworkCheckClientReady()) NetworkSendSyncPackets();
- }
- }
+#ifdef ENABLE_NETWORK
+ // Check for UDP stuff
+ NetworkUDPGameLoop();
+
+ if (_networking) {
+ // Multiplayer
+ NetworkGameLoop();
} else {
- // server/client/standalone: not synced --> state game loop
+ if (_network_reconnect > 0 && --_network_reconnect == 0) {
+ // This means that we want to reconnect to the last host
+ // We do this here, because it means that the network is really closed
+ NetworkClientConnectGame(_network_last_host, _network_last_port);
+ }
+ // Singleplayer
StateGameLoop();
- // server/client: process queued network commands
- if (_networking) NetworkProcessCommands();
}
+#else
+ StateGameLoop();
+#endif /* ENABLE_NETWORK */
if (!_pause && _display_opt&DO_FULL_ANIMATION)
DoPaletteAnimations();
@@ -1038,10 +1090,6 @@ void GameLoop()
MouseLoop();
- // send outgoing packets.
- NetworkCoreLoop(false);
-
-
if (_game_mode != GM_MENU)
MusicLoop();
}
@@ -1174,7 +1222,9 @@ bool AfterLoadGame(uint version)
// If Load Scenario / New (Scenario) Game is used,
// a player does not exist yet. So create one here.
- if (!_players[0].is_active)
+ // 1 exeption: network-games. Those can have 0 players
+ // But this exeption is not true for network_servers!
+ if (!_players[0].is_active && (!_networking || (_networking && _network_server)))
DoStartupNewPlayer(false);
DoZoomInOutWindow(ZOOM_NONE, w); // update button status