Changeset - r543:efdb197f91ad
[Not reviewed]
master
! ! !
truelight - 19 years ago 2004-12-04 17:54:56
truelight@openttd.org
(svn r942) -Merged branch/network back into the trunk
42 files changed:
0 comments (0 inline, 0 general)
Makefile
Show inline comments
 
@@ -69,7 +69,7 @@
 
#
 
# Paths:
 
# INSTALL: If not set, the game uses the directory of the binary to
 
# store everything (lang, data, gm, save and openttd.cfg), this is the `old' behaviour. 
 
# store everything (lang, data, gm, save and openttd.cfg), this is the `old' behaviour.
 
# In this case, none of the following paths are used, you also should _not_
 
# use `make install', but copy the required stuff yourself (or just play out
 
# of you source directory, which should work fine).
 
@@ -83,7 +83,7 @@
 
# PREFIX:	Normally /usr/local
 
# BINARY_DIR:	The location of the binary, normally games. (Will be prefixed
 
#		with $PREFIX)
 
# DATA_DIR: 	The location of the data (lang, data and gm), normally 
 
# DATA_DIR: 	The location of the data (lang, data and gm), normally
 
#		share/games/openttd. (Will be prefixed with $PREFIX)
 
# PERSONAL_DIR:	The directory where openttd.cfg and the save folder will be
 
#		stored. You cannot use ~ here, define USE_HOMEDIR for that.
 
@@ -157,7 +157,7 @@ endif
 
# this is used if there aren't any makefile.config
 
ifndef CONFIG_INCLUDED
 
# sets network on by default if there aren't any config file
 
ENABLE_NETWORK:=1   
 
ENABLE_NETWORK:=1
 

	
 
# paths for make install
 
# disabled as they would break it for some (many?) people if they were default
 
@@ -287,6 +287,7 @@ BASECFLAGS += -g
 
else
 
ifdef PROFILE
 
BASECFLAGS += -pg
 
LDFLAGS += -pg
 
else
 
# Release mode
 
ifndef MORPHOS
 
@@ -457,9 +458,11 @@ CDEFS += -DMIDI_ARG=\"$(MIDI_ARG)\"
 
endif
 
endif
 

	
 
# Experimental
 
ifdef WITH_NETWORK
 
CDEFS += -DENABLE_NETWORK
 
ifdef QNX
 
LIBS += -lsocket
 
endif
 
ifdef UNIX
 
ifndef OSX
 
ifndef MORPHOS
 
@@ -516,18 +519,21 @@ endif
 
C_SOURCES = \
 
	ai.c ai_build.c ai_new.c ai_pathfinder.c ai_shared.c aircraft_cmd.c \
 
	aircraft_gui.c airport.c airport_gui.c aystar.c bridge_gui.c \
 
	clear_cmd.c command.c console.c console_cmds.c disaster_cmd.c dock_gui.c dummy_land.c economy.c \
 
	callback_table.c clear_cmd.c command.c console.c console_cmds.c \
 
	dedicated.c disaster_cmd.c dock_gui.c dummy_land.c economy.c \
 
	engine.c engine_gui.c fileio.c gfx.c graph_gui.c newgrf.c \
 
	industry_cmd.c industry_gui.c intro_gui.c landscape.c main_gui.c \
 
	minilzo.c misc.c misc_cmd.c misc_gui.c music_gui.c namegen.c network.c \
 
	network_gui.c news_gui.c oldloader.c order_cmd.c order_gui.c \
 
	pathfind.c player_gui.c players.c queue.c rail_cmd.c rail_gui.c rev.c \
 
	road_cmd.c road_gui.c roadveh_cmd.c roadveh_gui.c saveload.c \
 
	screenshot.c settings.c settings_gui.c ship_cmd.c ship_gui.c \
 
	smallmap_gui.c sound.c sprite.c spritecache.c station_cmd.c station_gui.c \
 
	strings.c subsidy_gui.c terraform_gui.c texteff.c town_cmd.c \
 
	town_gui.c train_cmd.c train_gui.c tree_cmd.c ttd.c tunnelbridge_cmd.c \
 
	unmovable_cmd.c vehicle.c vehicle_gui.c viewport.c water_cmd.c widget.c window.c
 
	network_client.c network_data.c network_gamelist.c network_gui.c \
 
	network_server.c network_udp.c news_gui.c oldloader.c order_cmd.c \
 
	order_gui.c pathfind.c player_gui.c players.c queue.c rail_cmd.c \
 
	rail_gui.c rev.c road_cmd.c road_gui.c roadveh_cmd.c roadveh_gui.c \
 
	saveload.c screenshot.c settings.c settings_gui.c ship_cmd.c \
 
	ship_gui.c smallmap_gui.c sound.c sprite.c spritecache.c station_cmd.c \
 
	station_gui.c strings.c subsidy_gui.c terraform_gui.c texteff.c \
 
	town_cmd.c town_gui.c train_cmd.c train_gui.c tree_cmd.c ttd.c \
 
	tunnelbridge_cmd.c unmovable_cmd.c vehicle.c vehicle_gui.c viewport.c \
 
	water_cmd.c widget.c window.c
 
CXX_SOURCES =
 

	
 
ifdef WITH_SDL
 
@@ -670,8 +676,8 @@ ifeq ($(INSTALL),)
 
	is set correctly up - run \"make upgradeconf\")
 
endif
 

	
 
ifeq ($(PREFIX), ) 
 
	$(error no prefix set - check makefile.config) 
 
ifeq ($(PREFIX), )
 
	$(error no prefix set - check makefile.config)
 
endif
 
#	We compare against the non prefixed version here, so we won't install
 
#	if only the prefix has been set
ai_new.c
Show inline comments
 
@@ -830,7 +830,7 @@ static int AiNew_HowManyVehicles(Player 
 
    	tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16;
 
    	// We want a vehicle in a station once a month at least, so, calculate it!
 
    	// (the * 2 is because we have 2 stations ;))
 
    	amount = ((int)(((float)length / (float)tiles_a_day / 30 * 2))) * 2;
 
			amount = length * 2 * 2 / tiles_a_day / 30;
 
    	if (amount == 0) amount = 1;
 
   		return amount;
 
	} else if (p->ainew.tbt == AI_TRUCK) {
 
@@ -853,7 +853,7 @@ static int AiNew_HowManyVehicles(Player 
 
    	// We want all the cargo to be gone in a month.. so, we know the cargo it delivers
 
    	//  we know what the vehicle takes with him, and we know the time it takes him
 
    	//  to get back here.. now let's do some math!
 
    	amount = (int)(((float)length / (float)tiles_a_day / 30 * 2) * ((float)max_cargo / (float)RoadVehInfo(i)->capacity));
 
			amount = 2 * length * max_cargo / tiles_a_day / 30 / RoadVehInfo(i)->capacity;
 
    	amount += 1;
 
    	return amount;
 
	} else {
aircraft_gui.c
Show inline comments
 
@@ -25,7 +25,7 @@ static void DrawAircraftImage(Vehicle *v
 
	}
 
}
 

	
 
static void CcBuildAircraft(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildAircraft(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	Vehicle *v;
 

	
airport_gui.c
Show inline comments
 
@@ -16,7 +16,7 @@ static byte _selected_airport_type;
 
static void ShowBuildAirportPicker();
 

	
 

	
 
static void CcBuildAirport(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildAirport(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_1F_SPLAT, tile);
bridge_gui.c
Show inline comments
 
@@ -23,7 +23,7 @@ extern const PalSpriteID _bridge_sprites
 
extern const uint16 _bridge_speeds[MAX_BRIDGES];
 
extern const StringID _bridge_material[MAX_BRIDGES];
 

	
 
static void CcBuildBridge(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildBridge(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
 
}
callback_table.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "ttd.h"
 
#include "functions.h"
 

	
 
// If you add a callback for DoCommandP, also add the callback in here
 
//   see below for the full list!
 
// If you don't do it, it won't work across the network!!
 

	
 
/* aircraft_gui.c */
 
CommandCallback CcBuildAircraft;
 

	
 
/* airport_gui.c */
 
CommandCallback CcBuildAirport;
 

	
 
/* bridge_gui.c */
 
CommandCallback CcBuildBridge;
 

	
 
/* dock_gui.c */
 
CommandCallback CcBuildDocks;
 
CommandCallback CcBuildCanal;
 

	
 
/* main_gui.c */
 
CommandCallback CcPlaySound10;
 
CommandCallback CcPlaceSign;
 
CommandCallback CcTerraform;
 
//CommandCallback CcDemolish;
 
CommandCallback CcBuildTown;
 

	
 
/* rail_gui.c */
 
CommandCallback CcPlaySound1E;
 
CommandCallback CcRailDepot;
 
CommandCallback CcStation;
 
CommandCallback CcBuildRailTunnel;
 

	
 
/* road_gui.c */
 
CommandCallback CcPlaySound1D;
 
CommandCallback CcBuildRoadTunnel;
 
CommandCallback CcRoadDepot;
 

	
 
/* roadveh_gui.c */
 
CommandCallback CcBuildRoadVeh;
 

	
 
/* ship_gui.c */
 
CommandCallback CcBuildShip;
 

	
 
/* train_gui.c */
 
CommandCallback CcBuildWagon;
 
CommandCallback CcBuildLoco;
 

	
 
CommandCallback *_callback_table[] = {
 
	/* 0x00 */ NULL,
 
	/* 0x01 */ CcBuildAircraft,
 
	/* 0x02 */ CcBuildAirport,
 
	/* 0x03 */ CcBuildBridge,
 
	/* 0x04 */ CcBuildCanal,
 
	/* 0x05 */ CcBuildDocks,
 
	/* 0x06 */ CcBuildLoco,
 
	/* 0x07 */ CcBuildRoadVeh,
 
	/* 0x08 */ CcBuildShip,
 
	/* 0x09 */ CcBuildTown,
 
	/* 0x0A */ CcBuildRoadTunnel,
 
	/* 0x0B */ CcBuildRailTunnel,
 
	/* 0x0C */ CcBuildWagon,
 
	/* 0x0D */ CcRoadDepot,
 
	/* 0x0E */ CcRailDepot,
 
	/* 0x0F */ CcPlaceSign,
 
	/* 0x10 */ CcPlaySound10,
 
	/* 0x11 */ CcPlaySound1D,
 
	/* 0x12 */ CcPlaySound1E,
 
	/* 0x13 */ CcStation,
 
	/* 0x14 */ CcTerraform
 
};
 

	
 
const int _callback_table_count = sizeof (_callback_table) / sizeof (*_callback_table);
callback_table.h
Show inline comments
 
new file 100644
 
#ifndef CALLBACK_TABLE_H
 
#define CALLBACK_TABLE_H
 

	
 
extern CommandCallback *_callback_table[];
 
extern const int _callback_table_count;
 

	
 
#endif
command.c
Show inline comments
 
@@ -4,6 +4,7 @@
 
#include "gui.h"
 
#include "command.h"
 
#include "player.h"
 
#include "network.h"
 

	
 
#define DEF_COMMAND(yyyy) int32 yyyy(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 

	
 
@@ -128,6 +129,7 @@ DEF_COMMAND(CmdSetRoadDriveSide);
 
DEF_COMMAND(CmdSetTownNameType);
 

	
 
DEF_COMMAND(CmdChangeDifficultyLevel);
 
DEF_COMMAND(CmdChangePatchSetting);
 

	
 
DEF_COMMAND(CmdStartStopShip);
 
DEF_COMMAND(CmdSellShip);
 
@@ -149,6 +151,7 @@ DEF_COMMAND(CmdCloneOrder);
 

	
 
DEF_COMMAND(CmdClearArea);
 

	
 
DEF_COMMAND(CmdGiveMoney);
 
DEF_COMMAND(CmdMoneyCheat);
 
DEF_COMMAND(CmdBuildCanal);
 
DEF_COMMAND(CmdBuildLock);
 
@@ -301,6 +304,8 @@ static CommandProc * const _command_proc
 
	CmdBuildManySignals,					/* 110 */
 
	//CmdDestroyIndustry,						/* 109 */
 
	CmdDestroyCompanyHQ,					/* 111 */
 
	CmdGiveMoney,									/* 112 */
 
	CmdChangePatchSetting,				/* 113 */
 
};
 

	
 
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
 
@@ -386,15 +391,6 @@ bool DoCommandP(TileIndex tile, uint32 p
 

	
 
	assert(_docommand_recursive == 0);
 

	
 
	if (_networking && !(cmd & CMD_NET_INSTANT) && _pause) {
 
		// When the game is paused, and we are in a network game
 
		//  we do not allow any commands. This is because
 
		//  of some technical reasons
 
		ShowErrorMessage(-1, STR_MULTIPLAYER_PAUSED, x, y);
 
		_docommand_recursive = 0;
 
		return true;
 
	}
 

	
 
	_error_message = INVALID_STRING_ID;
 
	_error_message_2 = cmd >> 16;
 
	_additional_cash_required = 0;
 
@@ -413,7 +409,10 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	assert((cmd & 0xFF) < lengthof(_command_proc_table));
 
	proc = _command_proc_table[cmd & 0xFF];
 

	
 
	// this command is a notest command?
 
	// Some commands have a different output in dryrun then the realrun
 
	//  e.g.: if you demolish a whole town, the dryrun would say okay.
 
	//  but by really destroying, your rating drops and at a certain point
 
	//  it will fail. so res and res2 are different
 
	// CMD_REMOVE_ROAD: This command has special local authority
 
	// restrictions which may cause the test run to fail (the previous
 
	// road fragments still stay there and the town won't let you
 
@@ -426,12 +425,10 @@ bool DoCommandP(TileIndex tile, uint32 p
 
		(cmd & 0xFF) == CMD_TRAIN_GOTO_DEPOT ||
 
		(cmd & 0xFF) == CMD_REMOVE_ROAD;
 

	
 
	if (_networking && (cmd & CMD_ASYNC)) notest = true;
 

	
 
	_docommand_recursive = 1;
 

	
 
	// cost estimation only?
 
	if (_shift_pressed && _current_player == _local_player && !(cmd & CMD_DONT_NETWORK)) {
 
	if (_shift_pressed && _current_player == _local_player && !(cmd & CMD_NETWORK_COMMAND)) {
 
		// estimate the cost.
 
		res = proc(x, y, flags, p1, p2);
 
		if ((uint32)res >> 16 == 0x8000) {
 
@@ -446,30 +443,26 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	}
 

	
 

	
 

	
 
	// unless the command is a notest command, check if it can be executed.
 
	if (!notest) {
 
	if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
 
		// first test if the command can be executed.
 
		res = proc(x,y, flags, p1, p2);
 
		if ((uint32)res >> 16 == 0x8000) {
 
			if (res & 0xFFFF) _error_message = res & 0xFFFF;
 
			goto show_error;
 
		}
 
		// no money?
 
		if (res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
 
		// no money? Only check if notest is off
 
		if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
 
	}
 

	
 
	// put the command in a network queue and execute it later?
 
	if (_networking && !(cmd & CMD_DONT_NETWORK)) {
 
		if (!(cmd & CMD_NET_INSTANT)) {
 
			NetworkSendCommand(tile, p1, p2, cmd, callback);
 
			_docommand_recursive = 0;
 
			return true;
 
		} else {
 
			// Instant Command ... Relay and Process then
 
			NetworkSendCommand(tile, p1, p2, cmd, callback);
 
		}
 
#ifdef ENABLE_NETWORK
 
	// If we are in network, and the command is not from the network
 
	//   send it to the command-queue and abort execution
 
	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
 
		NetworkSend_Command(tile, p1, p2, cmd, callback);
 
		_docommand_recursive = 0;
 
		return true;
 
	}
 
#endif /* ENABLE_NETWORK */
 

	
 
	// update last build coordinate of player.
 
	if ( tile != 0 && _current_player < MAX_PLAYERS) DEREF_PLAYER(_current_player)->last_build_coordinate = tile;
 
@@ -478,6 +471,8 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	_yearly_expenses_type = 0;
 
	res2 = proc(x,y, flags|DC_EXEC, p1, p2);
 

	
 
	// If notest is on, it means the result of the test can be different then
 
	//   the real command.. so ignore the test
 
	if (!notest) {
 
		assert(res == res2); // sanity check
 
	} else {
command.h
Show inline comments
 
@@ -146,6 +146,8 @@ enum {
 

	
 
	//CMD_DESTROY_INDUSTRY = 109,
 
	CMD_DESTROY_COMPANY_HQ = 111,
 
	CMD_GIVE_MONEY = 112,
 
	CMD_CHANGE_PATCH_SETTING = 113,
 
};
 

	
 
enum {
 
@@ -166,9 +168,8 @@ enum {
 
enum {
 
	CMD_AUTO = 0x200,
 
	CMD_NO_WATER = 0x400,
 
	CMD_DONT_NETWORK = 0x800,		// execute the command without sending it on the network
 
	CMD_ASYNC = 0x1000,					// execute the command asynchronously without testing first in networking
 
	CMD_NET_INSTANT = 0x2000,
 
	CMD_NETWORK_COMMAND = 0x800,		// execute the command without sending it on the network
 
	CMD_NO_TEST_IF_IN_NETWORK = 0x1000, // When enabled, the command will bypass the no-DC_EXEC round if in network
 
};
 

	
 
//#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0)
console.c
Show inline comments
 
@@ -10,6 +10,7 @@
 
#include <stdarg.h>
 
#include <string.h>
 
#include "console.h"
 
#include "network.h"
 

	
 
#ifdef WIN32
 
#include <windows.h>
 
@@ -19,19 +20,15 @@
 
#define ICON_CMDBUF_SIZE 20
 
#define ICON_CMDLN_SIZE 255
 
#define ICON_LINE_HEIGHT 12
 

	
 
typedef enum {
 
	ICONSOLE_OPENED,
 
	ICONSOLE_CLOSED
 
} _iconsole_modes;
 
#define ICON_RIGHT_BORDERWIDTH 10
 
#define ICON_BOTTOM_BORDERWIDTH 12
 

	
 
// ** main console ** //
 
static bool _iconsole_inited;
 
static char* _iconsole_buffer[ICON_BUFFER + 1];
 
static char _iconsole_cbuffer[ICON_BUFFER + 1];
 
static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
 
static char _iconsole_cmdline[ICON_CMDLN_SIZE];
 
static byte _iconsole_cmdpos;
 
static _iconsole_modes _iconsole_mode = ICONSOLE_CLOSED;
 
static Window* _iconsole_win = NULL;
 
static byte _iconsole_scroll;
 

	
 
@@ -104,14 +101,20 @@ static void IConsoleWndProc(Window* w, W
 
		{
 
			int i = _iconsole_scroll;
 
			int max = (w->height / ICON_LINE_HEIGHT) - 1;
 
			int delta = 0;
 
			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
 
			while ((i > _iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
 
				DoDrawString(_iconsole_buffer[i], 5,
 
					w->height - (_iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
 
				i--;
 
			}
 
			DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _iconsole_color_commands);
 
			DoDrawString(_iconsole_cmdline, 10, w->height - ICON_LINE_HEIGHT, _iconsole_color_commands);
 
			delta = w->width - 10 - GetStringWidth(_iconsole_cmdline) - ICON_RIGHT_BORDERWIDTH;
 
			if (delta > 0) {
 
				DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _iconsole_color_commands);
 
				delta = 0;
 
			}
 

	
 
			DoDrawString(_iconsole_cmdline, 10 + delta, w->height - ICON_LINE_HEIGHT, _iconsole_color_commands);
 
			break;
 
		}
 
		case WE_TICK:
 
@@ -119,11 +122,15 @@ static void IConsoleWndProc(Window* w, W
 
			if (_icursor_counter > _icursor_rate) {
 
				int posx;
 
				int posy;
 
				int delta;
 

	
 
				_icursor_state = !_icursor_state;
 

	
 
				_cur_dpi = &_screen;
 
				posx = 10 + GetStringWidth(_iconsole_cmdline);
 
				delta = w->width - 10 - GetStringWidth(_iconsole_cmdline) - ICON_RIGHT_BORDERWIDTH;
 
				if (delta > 0)
 
					delta = 0;
 
				posx = 10 + GetStringWidth(_iconsole_cmdline) + delta;
 
				posy = w->height - 3;
 
				GfxFillRect(posx, posy, posx + 5, posy + 1, _icursor_state ? 14 : 0);
 
				_video_driver->make_dirty(posx, posy, 5, 1);
 
@@ -183,10 +190,20 @@ static void IConsoleWndProc(Window* w, W
 
					break;
 
				case WKC_RETURN:
 
					IConsolePrintF(_iconsole_color_commands, "] %s", _iconsole_cmdline);
 
					_iconsole_cmdbufferpos = 19;
 
					IConsoleCmdBufferAdd(_iconsole_cmdline);
 
					IConsoleCmdExec(_iconsole_cmdline);
 
					IConsoleClearCommand();
 
					break;
 
				case WKC_CTRL | WKC_RETURN:
 
					if (_iconsole_mode == ICONSOLE_FULL) {
 
						_iconsole_mode = ICONSOLE_OPENED;
 
					} else {
 
						_iconsole_mode = ICONSOLE_FULL;
 
					}
 
					IConsoleResize();
 
					MarkWholeScreenDirty();
 
					break;
 
				case WKC_BACKSPACE:
 
					if (_iconsole_cmdpos != 0) _iconsole_cmdpos--;
 
					_iconsole_cmdline[_iconsole_cmdpos] = 0;
 
@@ -239,9 +256,9 @@ void IConsoleInit(void)
 
	}
 
	IConsoleStdLibRegister();
 
	#if defined(WITH_REV)
 
	IConsolePrintF(13, "OpenTTD Game Console Revision 4 - %s", _openttd_revision);
 
	IConsolePrintF(13, "OpenTTD Game Console Revision 5 - %s", _openttd_revision);
 
	#else
 
	IConsolePrint(13, "OpenTTD Game Console Revision 4");
 
	IConsolePrint(13, "OpenTTD Game Console Revision 5");
 
	#endif
 
	IConsolePrint(12, "---------------------------------");
 
	IConsolePrint(12, "use \"help\" for more info");
 
@@ -266,9 +283,17 @@ void IConsoleFree(void)
 

	
 
void IConsoleResize(void)
 
{
 
	if (_iconsole_win != NULL) {
 
		_iconsole_win->height = _screen.height / 3;
 
		_iconsole_win->width = _screen.width;
 
	switch (_iconsole_mode) {
 
		case ICONSOLE_OPENED:
 
			_iconsole_win->height = _screen.height / 3;
 
			_iconsole_win->width = _screen.width;
 
			break;
 
		case ICONSOLE_FULL:
 
			_iconsole_win->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
 
			_iconsole_win->width = _screen.width;
 
			break;
 
		default:
 
			break;
 
	}
 
}
 

	
 
@@ -286,6 +311,11 @@ void IConsoleSwitch(void)
 
			_iconsole_win = NULL;
 
			_iconsole_mode = ICONSOLE_CLOSED;
 
			break;
 
		case ICONSOLE_FULL:
 
			DeleteWindowById(WC_CONSOLE, 0);
 
			_iconsole_win = NULL;
 
			_iconsole_mode = ICONSOLE_CLOSED;
 
			break;
 
	}
 
}
 

	
 
@@ -331,15 +361,20 @@ void IConsoleCmdBufferNavigate(signed ch
 
	_iconsole_cmdpos = strlen(_iconsole_cmdbuffer[i]);
 
}
 

	
 
void IConsolePrint(byte color_code, const char* string)
 
void IConsolePrint(uint16 color_code, const char* string)
 
{
 
	char* _ex;
 
	char* _new;
 
	char _exc;
 
	char _newc;
 
	uint16 _exc;
 
	uint16 _newc;
 
	char* i;
 
	int j;
 

	
 
	if (_network_dedicated) {
 
		printf("%s\n", string);
 
		return;
 
	}
 

	
 
	if (!_iconsole_inited) return;
 

	
 
	_newc = color_code;
 
@@ -362,7 +397,7 @@ void IConsolePrint(byte color_code, cons
 
}
 

	
 

	
 
void CDECL IConsolePrintF(byte color_code, const char* s, ...)
 
void CDECL IConsolePrintF(uint16 color_code, const char* s, ...)
 
{
 
	va_list va;
 
	char buf[1024];
 
@@ -384,7 +419,7 @@ void CDECL IConsolePrintF(byte color_cod
 
void IConsoleDebug(const char* string)
 
{
 
	if (_stdlib_developer > 1)
 
		IConsolePrintF(_iconsole_color_debug, "DEBUG: %s", string);
 
		IConsolePrintF(_iconsole_color_debug, "dbg: %s", string);
 
}
 

	
 
void IConsoleError(const char* string)
 
@@ -446,7 +481,7 @@ void IConsoleVarRegister(const char* nam
 
	item_new = malloc(sizeof(_iconsole_var)); /* XXX unchecked malloc */
 

	
 
	item_new->name = malloc(strlen(name) + 2); /* XXX unchecked malloc */
 
	sprintf(item_new->name, "*%s", name);
 
	sprintf(item_new->name, "%s", name);
 

	
 
	item_new->_next = NULL;
 
	switch (type) {
 
@@ -454,6 +489,7 @@ void IConsoleVarRegister(const char* nam
 
			item_new->data.bool_ = addr;
 
			break;
 
		case ICONSOLE_VAR_BYTE:
 
		case ICONSOLE_VAR_UINT8:
 
			item_new->data.byte_ = addr;
 
			break;
 
		case ICONSOLE_VAR_UINT16:
 
@@ -507,7 +543,7 @@ void IConsoleVarInsert(_iconsole_var* va
 
	if (var->_next != NULL) return;
 

	
 
	var->name = malloc(strlen(name) + 2); /* XXX unchecked malloc */
 
	sprintf(var->name, "*%s", name);
 
	sprintf(var->name, "%s", name);
 

	
 
	item = _iconsole_vars;
 
	if (item == NULL) {
 
@@ -540,6 +576,7 @@ void IConsoleVarInsert(_iconsole_var* va
 
			item->_malloc = true;
 
			break;
 
		case ICONSOLE_VAR_BYTE:
 
		case ICONSOLE_VAR_UINT8:
 
			item->data.byte_ = malloc(sizeof(*item->data.byte_));
 
			*item->data.byte_ = 0;
 
			item->_malloc = true;
 
@@ -607,6 +644,7 @@ void IConsoleVarSetValue(_iconsole_var* 
 
			*var->data.bool_ = (value != 0);
 
			break;
 
		case ICONSOLE_VAR_BYTE:
 
		case ICONSOLE_VAR_UINT8:
 
			*var->data.byte_ = value;
 
			break;
 
		case ICONSOLE_VAR_UINT16:
 
@@ -629,6 +667,7 @@ void IConsoleVarSetValue(_iconsole_var* 
 

	
 
void IConsoleVarDump(const _iconsole_var* var, const char* dump_desc)
 
{
 
	if (var == NULL) return;
 
	if (dump_desc == NULL) dump_desc = var->name;
 

	
 
	switch (var->type) {
 
@@ -638,6 +677,7 @@ void IConsoleVarDump(const _iconsole_var
 
			break;
 
		break;
 
		case ICONSOLE_VAR_BYTE:
 
		case ICONSOLE_VAR_UINT8:
 
			IConsolePrintF(_iconsole_color_default, "%s = %u",
 
				dump_desc, *var->data.byte_);
 
			break;
 
@@ -703,7 +743,10 @@ void IConsoleVarHook(const char* name, _
 

	
 
bool IConsoleVarHookHandle(_iconsole_var* hook_var, _iconsole_hook_types type)
 
{
 
	iconsole_var_hook proc = NULL;
 
	iconsole_var_hook proc;
 
	if (hook_var == NULL) return false;
 

	
 
	proc = NULL;
 
	switch (type) {
 
		case ICONSOLE_HOOK_BEFORE_CHANGE:
 
			proc = hook_var->hook_before_change;
 
@@ -802,6 +845,7 @@ void IConsoleCmdExec(const char* cmdstr)
 
	i = 0;
 
	c = 0;
 
	tokens[c] = tokenstream;
 
	tokentypes[c] = ICONSOLE_VAR_UNKNOWN;
 
	while (i < l && c < lengthof(tokens) - 1) {
 
		if (cmdstr[i] == '"') {
 
			if (longtoken) {
 
@@ -812,9 +856,12 @@ void IConsoleCmdExec(const char* cmdstr)
 
					skip_lt_change = true;
 
				} else {
 
					longtoken = !longtoken;
 
					tokentypes[c] = ICONSOLE_VAR_STRING;
 
				}
 
			} else
 
			} else {
 
				longtoken = !longtoken;
 
				tokentypes[c] = ICONSOLE_VAR_STRING;
 
			}
 
			if (!skip_lt_change) {
 
				if (!longtoken) {
 
					if (valid_token) {
 
@@ -822,6 +869,7 @@ void IConsoleCmdExec(const char* cmdstr)
 
						*tokenstream = '\0';
 
						tokenstream++;
 
						tokens[c] = tokenstream;
 
						tokentypes[c] = ICONSOLE_VAR_UNKNOWN;
 
						valid_token = false;
 
					}
 
				}
 
@@ -833,6 +881,7 @@ void IConsoleCmdExec(const char* cmdstr)
 
				*tokenstream = '\0';
 
				tokenstream++;
 
				tokens[c] = tokenstream;
 
				tokentypes[c] = ICONSOLE_VAR_UNKNOWN;
 
				valid_token = false;
 
			}
 
		} else {
 
@@ -853,28 +902,29 @@ void IConsoleCmdExec(const char* cmdstr)
 
	//** interpreting **//
 

	
 
	for (i = 0; i < c; i++) {
 
		tokentypes[i] = ICONSOLE_VAR_UNKNOWN;
 
		if (tokens[i] != NULL && i > 0 && strlen(tokens[i]) > 0) {
 
			if (tokens[i][0] == '*') {
 
			if (IConsoleVarGet((char *)tokens[i]) != NULL) {
 
				// change the variable to an pointer if execution_mode != 4 is
 
				// being prepared. execution_mode 4 is used to assign 
 
				// being prepared. execution_mode 4 is used to assign
 
				// one variables data to another one
 
				// [token 0 and 2]
 
				if (!((i == 2) && (tokentypes[1] == ICONSOLE_VAR_UNKNOWN) &&
 
					(strcmp(tokens[1], "<<") == 0))) {
 
					var = IConsoleVarGet(tokens[i]);
 
					// only look for another variable if it isnt an longtoken == string with ""
 
					var = NULL;
 
					if (tokentypes[i]!=ICONSOLE_VAR_STRING) var = IConsoleVarGet(tokens[i]);
 
					if (var != NULL) {
 
						// pointer to the data --> token
 
						tokens[i] = (char *) var->data.addr; /* XXX: maybe someone finds an cleaner way to do this */ 
 
						tokens[i] = (char *) var->data.addr; /* XXX: maybe someone finds an cleaner way to do this */
 
						tokentypes[i] = var->type;
 
					}
 
				}
 
			}
 
			if (tokens[i] != NULL && tokens[i][0] == '@' && tokens[i][1] == '*') {
 
				var = IConsoleVarGet(tokens[i] + 1);
 
			if (tokens[i] != NULL && tokens[i][0] == '@' && (IConsoleVarGet(tokens[i]+1) != NULL)) {
 
				var = IConsoleVarGet(tokens[i]+1);
 
				if (var != NULL) {
 
					// pointer to the _iconsole_var struct --> token
 
					tokens[i] = (char *) var; /* XXX: maybe someone finds an cleaner way to do this */ 
 
					tokens[i] = (char *) var; /* XXX: maybe someone finds an cleaner way to do this */
 
					tokentypes[i] = ICONSOLE_VAR_REFERENCE;
 
				}
 
			}
 
@@ -960,6 +1010,7 @@ void IConsoleCmdExec(const char* cmdstr)
 
						break;
 
					}
 
					case ICONSOLE_VAR_BYTE:
 
					case ICONSOLE_VAR_UINT8:
 
					{
 
						if (strcmp(tokens[1], "=") == 0) {
 
							if (c == 3)
 
@@ -1088,9 +1139,9 @@ void IConsoleCmdExec(const char* cmdstr)
 
							IConsoleError("operation not supported");
 
						break;
 
					}
 
					case ICONSOLE_VAR_NONE: 
 
					case ICONSOLE_VAR_REFERENCE: 
 
					case ICONSOLE_VAR_UNKNOWN: 
 
					case ICONSOLE_VAR_NONE:
 
					case ICONSOLE_VAR_REFERENCE:
 
					case ICONSOLE_VAR_UNKNOWN:
 
						IConsoleError("operation not supported");
 
						break;
 
				}
 
@@ -1140,6 +1191,7 @@ void IConsoleCmdExec(const char* cmdstr)
 
							IConsoleVarDump(var, NULL);
 
							break;
 
						case ICONSOLE_VAR_BYTE:
 
						case ICONSOLE_VAR_UINT8:
 
							*var->data.byte_ = *result->data.byte_;
 
							IConsoleVarDump(var, NULL);
 
							break;
console.h
Show inline comments
 
@@ -7,6 +7,7 @@ typedef enum _iconsole_var_types {
 
	ICONSOLE_VAR_NONE,
 
	ICONSOLE_VAR_BOOLEAN,
 
	ICONSOLE_VAR_BYTE,
 
	ICONSOLE_VAR_UINT8,
 
	ICONSOLE_VAR_UINT16,
 
	ICONSOLE_VAR_UINT32,
 
	ICONSOLE_VAR_INT16,
 
@@ -17,6 +18,12 @@ typedef enum _iconsole_var_types {
 
	ICONSOLE_VAR_UNKNOWN
 
} _iconsole_var_types;
 

	
 
typedef enum {
 
	ICONSOLE_FULL,
 
	ICONSOLE_OPENED,
 
	ICONSOLE_CLOSED
 
} _iconsole_modes;
 

	
 
typedef enum _iconsole_hook_types {
 
	ICONSOLE_HOOK_ACCESS,
 
	ICONSOLE_HOOK_BEFORE_CHANGE,
 
@@ -80,6 +87,7 @@ VARDEF byte _iconsole_color_error;
 
VARDEF byte _iconsole_color_warning;
 
VARDEF byte _iconsole_color_debug;
 
VARDEF byte _iconsole_color_commands;
 
VARDEF _iconsole_modes _iconsole_mode;
 

	
 
// ** ttd.c functions ** //
 

	
 
@@ -100,8 +108,8 @@ void IConsoleCmdBufferAdd(const char* cm
 
void IConsoleCmdBufferNavigate(signed char direction);
 

	
 
// ** console output ** //
 
void IConsolePrint(byte color_code, const char* string);
 
void CDECL IConsolePrintF(byte color_code, const char* s, ...);
 
void IConsolePrint(uint16 color_code, const char* string);
 
void CDECL IConsolePrintF(uint16 color_code, const char* s, ...);
 
void IConsoleDebug(const char* string);
 
void IConsoleError(const char* string);
 
void IConsoleWarning(const char* string);
console_cmds.c
Show inline comments
 
@@ -5,10 +5,10 @@
 
#include "engine.h"
 
#include "functions.h"
 
#include "variables.h"
 

	
 
#if defined(WIN32)
 
#	define ENABLE_NETWORK
 
#endif
 
#include "network_data.h"
 
#include "network_client.h"
 
#include "network_server.h"
 
#include "command.h"
 

	
 

	
 
// ** scriptfile handling ** //
 
@@ -39,6 +39,8 @@ static uint32 GetArgumentInteger(const c
 
/* variable and command hooks   */
 
/* **************************** */
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetwork)
 
{
 
	if (_networking) {
 
@@ -48,26 +50,44 @@ DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetwork
 
	return true;
 
}
 

	
 
#if 0 /* Not used atm */
 
DEF_CONSOLE_VAR_HOOK(ConVarHookNoNetwork)
 
{
 
	if (_networking) {
 
		IConsoleError("This variable is forbidden in multiplayer.");
 
		return false;
 
	}
 
	return true;
 
}
 
#endif
 

	
 
DEF_CONSOLE_VAR_HOOK(ConVarHookNoNetClient)
 
{
 
	if (!_networking_server) {
 
	if (!_network_server) {
 
		IConsoleError("This variable only makes sense for a network server.");
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetClient)
 
{
 
	if (!_networking || !_network_server) {
 
		IConsoleError("This command is only available for a network server.");
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD_HOOK(ConCmdHookNoNetServer)
 
{
 
	if (!_networking || _network_server) {
 
		IConsoleError("You can not use this command for you are a network-server.");
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD_HOOK(ConCmdHookNeedNetwork)
 
{
 
	if (!_networking) {
 
		IConsoleError("Not connected. Multiplayer only command.");
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
/* **************************** */
 
/* reset commands               */
 
/* **************************** */
 
@@ -100,41 +120,130 @@ DEF_CONSOLE_CMD(ConScrollToTile)
 
	return 0;
 
}
 

	
 

	
 
// ********************************* //
 
// * Network Core Console Commands * //
 
// ********************************* //
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CONSOLE_CMD(ConStatus)
 
{
 
	const char *status;
 
	int lag;
 
	const ClientState *cs;
 
	const NetworkClientInfo *ci;
 
	FOR_ALL_CLIENTS(cs) {
 
		lag = NetworkCalculateLag(cs);
 
		ci = DEREF_CLIENT_INFO(cs);
 

	
 
		switch (cs->status) {
 
			case STATUS_INACTIVE:
 
				status = "inactive";
 
				break;
 
			case STATUS_AUTH:
 
				status = "authorized";
 
				break;
 
			case STATUS_MAP:
 
				status = "loading map";
 
				break;
 
			case STATUS_DONE_MAP:
 
				status = "done map";
 
				break;
 
			case STATUS_PRE_ACTIVE:
 
				status = "ready";
 
				break;
 
			case STATUS_ACTIVE:
 
				status = "active";
 
				break;
 
			default:
 
				status = "unknown";
 
				break;
 
		}
 
		IConsolePrintF(8, "Client #%d/%s  status: %s  frame-lag: %d  play-as: %d",
 
			cs->index, ci->client_name, status, lag, ci->client_playas);
 
	}
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConKick)
 
{
 
	NetworkClientInfo *ci;
 

	
 
	if (argc == 2) {
 
		uint32 index = atoi(argv[1]);
 
		if (index == NETWORK_SERVER_INDEX) {
 
			IConsolePrint(_iconsole_color_default, "Silly boy, you can not kick yourself!");
 
			return NULL;
 
		}
 
		if (index == 0) {
 
			IConsoleError("Invalid Client-ID");
 
			return NULL;
 
		}
 

	
 
		ci = NetworkFindClientInfoFromIndex(index);
 

	
 
		if (ci != NULL) {
 
			SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
 
			return NULL;
 
		} else {
 
			IConsoleError("Client-ID not found");
 
			return NULL;
 
		}
 
	}
 

	
 
	IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: kick <client-id>. For client-ids, see 'clients'.");
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNetworkClients)
 
{
 
	NetworkClientInfo *ci;
 
	for (ci = _network_client_info; ci != &_network_client_info[MAX_CLIENT_INFO]; ci++) {
 
		if (ci->client_index != NETWORK_EMPTY_INDEX) {
 
			IConsolePrintF(8,"Client #%d   name: %s  play-as: %d", ci->client_index, ci->client_name, ci->client_playas);
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNetworkConnect)
 
{
 
	char* ip;
 
	const char *port = NULL;
 
	const char *player = NULL;
 
	const byte *port = NULL;
 
	const byte *player = NULL;
 
	uint16 rport;
 

	
 
	if (argc<2) return NULL;
 

	
 
	if (_networking) {
 
		// We are in network-mode, first close it!
 
		NetworkDisconnect();
 
	}
 

	
 
	ip = argv[1];
 
	rport = _network_server_port;
 
	rport = NETWORK_DEFAULT_PORT;
 

	
 
	ParseConnectionString(&player, &port, ip);
 

	
 
	IConsolePrintF(_iconsole_color_default, "Connecting to %s...", ip);
 
	if (player!=NULL) {
 
	if (player != NULL) {
 
		_network_playas = atoi(player);
 
		IConsolePrintF(_iconsole_color_default, "    player-no: %s", player);
 
	}
 
	if (port!=NULL) {
 
	if (port != NULL) {
 
		rport = atoi(port);
 
		IConsolePrintF(_iconsole_color_default, "    port: %s", port);
 
	}
 

	
 
	NetworkCoreConnectGame(ip, rport);
 
	NetworkClientConnectGame(ip, rport);
 

	
 
	return NULL;
 
}
 

	
 
#endif
 
#endif /* ENABLE_NETWORK */
 

	
 
/* ******************************** */
 
/*   script file console commands   */
 
@@ -148,7 +257,7 @@ DEF_CONSOLE_CMD(ConExec)
 
	if (argc<2) return NULL;
 

	
 
	doerror = true;
 
	_script_file = fopen(argv[1], "rb");
 
	_script_file = fopen(argv[1], "r");
 

	
 
	if (_script_file == NULL) {
 
		if (argc>2) if (atoi(argv[2])==0) doerror=false;
 
@@ -158,9 +267,11 @@ DEF_CONSOLE_CMD(ConExec)
 

	
 
	_script_running = true;
 

	
 
	fgets(cmd, sizeof(cmd), _script_file);
 
	while (!feof(_script_file) && _script_running) {
 
		strtok(cmd, "\r\n");
 
		IConsoleCmdExec(cmd);
 
		fgets(cmd, sizeof(cmd), _script_file);
 
		IConsoleCmdExec(cmd);
 
	}
 

	
 
	_script_running = false;
 
@@ -209,6 +320,19 @@ DEF_CONSOLE_CMD(ConEchoC)
 
	return NULL;
 
}
 

	
 
extern void SwitchMode(int new_mode);
 

	
 
DEF_CONSOLE_CMD(ConNewGame)
 
{
 
	_docommand_recursive = 0;
 

	
 
	_random_seeds[0][0] = Random();
 
	_random_seeds[0][1] = InteractiveRandom();
 

	
 
	SwitchMode(SM_NEWGAME);
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConPrintF)
 
{
 
	if (argc < 3) return NULL;
 
@@ -299,15 +423,15 @@ DEF_CONSOLE_CMD(ConHelp)
 
{
 
	IConsolePrint(13, " -- console help -- ");
 
	IConsolePrint( 1, " variables: [command to list them: list_vars]");
 
	IConsolePrint( 1, " *temp_string = \"my little \"");
 
	IConsolePrint( 1, " temp_string = \"my little \"");
 
	IConsolePrint( 1, "");
 
	IConsolePrint( 1, " commands: [command to list them: list_cmds]");
 
	IConsolePrint( 1, " [command] [\"string argument with spaces\"] [argument 2] ...");
 
	IConsolePrint( 1, " printf \"%s world\" *temp_string");
 
	IConsolePrint( 1, " printf \"%s world\" temp_string");
 
	IConsolePrint( 1, "");
 
	IConsolePrint( 1, " command/variable returning a value into an variable:");
 
	IConsolePrint( 1, " *temp_uint16 << random");
 
	IConsolePrint( 1, " *temp_uint16 << *temp_uint16_2");
 
	IConsolePrint( 1, " temp_uint16 << random");
 
	IConsolePrint( 1, " temp_uint16 << temp_uint16_2");
 
	IConsolePrint( 1, "");
 
	return NULL;
 
}
 
@@ -362,6 +486,131 @@ DEF_CONSOLE_CMD(ConListDumpVariables)
 
	return NULL;
 
}
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CONSOLE_CMD(ConSay)
 
{
 
	if (argc == 2) {
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
 
		else
 
			NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX);
 
	} else
 
		IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say \"<msg>\"");
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConSayPlayer)
 
{
 
	if (argc == 3) {
 
		if (atoi(argv[1]) < 1 || atoi(argv[1]) > MAX_PLAYERS) {
 
			IConsolePrintF(_iconsole_color_default, "Unknown player. Player range is between 1 and %d.", MAX_PLAYERS);
 
			return NULL;
 
		}
 

	
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2]);
 
		else
 
			NetworkServer_HandleChat(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
 
	} else
 
		IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say_player <playerno> \"<msg>\"");
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConSayClient)
 
{
 
	if (argc == 3) {
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
 
		else
 
			NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
 
	} else
 
		IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: say_client <clientno> \"<msg>\"");
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConSetServerName) {
 
	if (argc == 2) {
 
		strncpy(_network_server_name, argv[1], 40);
 
		IConsolePrintF(_iconsole_color_default, "Server-name changed to '%s'", _network_server_name);
 
		ttd_strlcpy(_network_game_info.server_name, _network_server_name, 40);
 
	} else if (argc == 1) {
 
		IConsolePrintF(_iconsole_color_default, "Current server-name is '%s'", _network_server_name);
 
		IConsolePrint(_iconsole_color_default, "  Usage: setservername \"<GameName>\".");
 
	} else {
 
		IConsolePrint(_iconsole_color_default, "Unknow usage. Usage: setservername \"<ServerName>\".");
 
	}
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConClientName) {
 
	NetworkClientInfo *ci;
 
	ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 

	
 
	if (argc == 2 && ci != NULL) {
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(argv[1]);
 
		else {
 
			if (NetworkFindName(argv[1])) {
 
				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, ci->client_name, argv[1]);
 
				ttd_strlcpy(ci->client_name, argv[1], 40);
 
				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
 
			}
 
		}
 
	} else {
 
		IConsolePrint(_iconsole_color_default, "With 'name' you can change your network-player name.");
 
		IConsolePrint(_iconsole_color_default, "  Usage: name \"<name>\".");
 
	}
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConProtect) {
 
	// Protect a company with a password
 
	if (_local_player >= MAX_PLAYERS) {
 
		IConsolePrintF(_iconsole_color_default, "You have to own a company to make use of this command.");
 
		return NULL;
 
	}
 
	if (argc == 2) {
 
		if (strncmp(argv[1], "*", 20) == 0) {
 
			_network_player_info[_local_player].password[0] = '\0';
 
		} else {
 
			strncpy(_network_player_info[_local_player].password, argv[1], 20);
 
		}
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
 
		IConsolePrintF(_iconsole_color_default, "Company protected with '%s'", _network_player_info[_local_player].password);
 
	} else {
 
		IConsolePrint(_iconsole_color_default, "Protect sets a password on the company, so no-one without the correct password can join.");
 
		IConsolePrint(_iconsole_color_default, "  Usage: protect \"<password>\".   Use * as <password> to set no password.");
 
	}
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConSetPassword) {
 
	if (argc == 2) {
 
		// Change server password
 
		if (strncmp(argv[1], "*", 20) == 0) {
 
			_network_game_info.server_password[0] = '\0';
 
			_network_game_info.use_password = 0;
 
		} else {
 
			strncpy(_network_game_info.server_password, argv[1], 20);
 
			_network_game_info.use_password = 1;
 
		}
 
		IConsolePrintF(_iconsole_color_default, "Game-password changed to '%s'", _network_game_info.server_password);
 
	} else if (argc == 1) {
 
		IConsolePrintF(_iconsole_color_default, "Current game-password is set to '%s'", _network_game_info.server_password);
 
		IConsolePrint(_iconsole_color_default, "  Usage: setpassword \"<password>\".   Use * as <password> to set no password.");
 
	} else {
 
		IConsolePrint(_iconsole_color_default, "Unknow usage. Usage: setpassword \"<password>\".   Use * as <password> to set no password.");
 
	}
 

	
 
	return 0;
 
}
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#ifdef _DEBUG
 
/* ****************************************** */
 
/*  debug commands and variables */
 
@@ -390,7 +639,7 @@ void IConsoleDebugLibRegister()
 
/*  console command and variable registration */
 
/* ****************************************** */
 

	
 
void IConsoleStdLibRegister()
 
void IConsoleStdLibRegister(void)
 
{
 
	// stdlib
 
	extern byte _stdlib_developer; /* XXX extern in .c */
 
@@ -402,8 +651,9 @@ void IConsoleStdLibRegister()
 
	// functions [please add them alphabetically]
 
#ifdef ENABLE_NETWORK
 
	IConsoleCmdRegister("connect", ConNetworkConnect);
 
	IConsoleCmdHook("connect", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetwork);
 
#endif
 
	IConsoleCmdHook("connect", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetServer);
 
	IConsoleCmdRegister("clients", ConNetworkClients);
 
#endif /* ENABLE_NETWORK */
 
	IConsoleCmdRegister("debug_level",  ConDebugLevel);
 
	IConsoleCmdRegister("dump_vars",    ConListDumpVariables);
 
	IConsoleCmdRegister("echo",         ConEcho);
 
@@ -415,26 +665,50 @@ void IConsoleStdLibRegister()
 
	IConsoleCmdRegister("info_var",     ConInfoVar);
 
	IConsoleCmdRegister("list_cmds",    ConListCommands);
 
	IConsoleCmdRegister("list_vars",    ConListVariables);
 
#ifdef ENABLE_NETWORK
 
	IConsoleCmdRegister("kick",         ConKick);
 
	IConsoleCmdHook("kick", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient);
 
	IConsoleCmdRegister("protect", ConProtect);
 
	IConsoleCmdRegister("name",         ConClientName);
 
#endif
 
	IConsoleCmdRegister("newgame",         ConNewGame);
 
	IConsoleCmdRegister("printf",       ConPrintF);
 
	IConsoleCmdRegister("printfc",      ConPrintFC);
 
	IConsoleCmdRegister("quit",         ConExit);
 
	IConsoleCmdRegister("random",       ConRandom);
 
	IConsoleCmdRegister("resetengines", ConResetEngines);
 
#ifdef ENABLE_NETWORK
 
	IConsoleCmdHook("resetengines", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetwork);
 
#endif /* ENABLE_NETWORK */
 
	IConsoleCmdRegister("return",     ConReturn);
 
#ifdef ENABLE_NETWORK
 
	IConsoleCmdRegister("say",        ConSay);
 
	IConsoleCmdHook("say", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork);
 
	IConsoleCmdRegister("say_player", ConSayPlayer);
 
	IConsoleCmdHook("say_player", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork);
 
	IConsoleCmdRegister("say_client", ConSayClient);
 
	IConsoleCmdHook("say_client", ICONSOLE_HOOK_ACCESS, ConCmdHookNeedNetwork);
 
#endif /* ENABLE_NETWORK */
 
	IConsoleCmdRegister("screenshot", ConScreenShot);
 
	IConsoleCmdRegister("script",     ConScript);
 
	IConsoleCmdRegister("scrollto",   ConScrollToTile);
 
#ifdef ENABLE_NETWORK
 
	IConsoleCmdRegister("setservername", ConSetServerName);
 
	IConsoleCmdHook("setservername", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient);
 
	IConsoleCmdRegister("setpassword", ConSetPassword);
 
	IConsoleCmdHook("setpassword", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient);
 
	IConsoleCmdRegister("status",   ConStatus);
 
	IConsoleCmdHook("status", ICONSOLE_HOOK_ACCESS, ConCmdHookNoNetClient);
 
#endif /* ENABLE_NETWORK */
 

	
 
	// variables [please add them alphabeticaly]
 
	IConsoleVarRegister("developer", &_stdlib_developer, ICONSOLE_VAR_BYTE);
 
#ifdef ENABLE_NETWORK
 
	IConsoleVarRegister("net_client_timeout", &_network_client_timeout, ICONSOLE_VAR_UINT16);
 
	IConsoleVarHook("*net_client_timeout", ICONSOLE_HOOK_ACCESS, ConVarHookNoNetClient);
 
	IConsoleVarRegister("net_ready_ahead", &_network_ready_ahead, ICONSOLE_VAR_UINT16);
 
	IConsoleVarRegister("net_frame_freq", &_network_frame_freq, ICONSOLE_VAR_UINT8);
 
	IConsoleVarHook("*net_frame_freq", ICONSOLE_HOOK_ACCESS, ConVarHookNoNetClient);
 
	IConsoleVarRegister("net_sync_freq", &_network_sync_freq, ICONSOLE_VAR_UINT16);
 
	IConsoleVarHook("*net_sync_freq", ICONSOLE_HOOK_ACCESS, ConVarHookNoNetClient);
 
#endif
 
#endif /* ENABLE_NETWORK */
 

	
 

	
 
}
dedicated.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "ttd.h"
 
#include "network.h"
 
#include "hal.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "gfx.h"
 
#include "window.h"
 
#include "command.h"
 
#include "console.h"
 
#ifdef WIN32
 
#	include <windows.h> /* GetTickCount */
 
#	include <conio.h>
 
#endif
 
#ifdef UNIX
 
#	include <sys/time.h> /* gettimeofday */
 
#	include <sys/types.h>
 
#	include <unistd.h>
 
#	define STDIN 0  /* file descriptor for standard input */
 
#endif
 

	
 
// This file handles all dedicated-server in- and outputs
 

	
 
static void *_dedicated_video_mem;
 

	
 
static const char *DedicatedVideoStart(char **parm) {
 
	_screen.width = _screen.pitch = _cur_resolution[0];
 
	_screen.height = _cur_resolution[1];
 
	_dedicated_video_mem = malloc(_cur_resolution[0]*_cur_resolution[1]);
 

	
 
	_debug_net_level = 6;
 
	_debug_misc_level = 0;
 

	
 
	DEBUG(misc,0)("Loading dedicated server...");
 
	return NULL;
 
}
 
static void DedicatedVideoStop() { free(_dedicated_video_mem); }
 
static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
 
static bool DedicatedVideoChangeRes(int w, int h) { return false; }
 

	
 
#ifdef UNIX
 

	
 
bool InputWaiting()
 
{
 
	struct timeval tv;
 
	fd_set readfds;
 

	
 
	tv.tv_sec = 0;
 
	tv.tv_usec = 1;
 

	
 
	FD_ZERO(&readfds);
 
	FD_SET(STDIN, &readfds);
 

	
 
	/* don't care about writefds and exceptfds: */
 
	select(STDIN+1, &readfds, NULL, NULL, &tv);
 

	
 
	if (FD_ISSET(STDIN, &readfds))
 
		return true;
 
	else
 
		return false;
 
}
 
#else
 
bool InputWaiting()
 
{
 
	return kbhit();
 
}
 
#endif
 

	
 
static int DedicatedVideoMainLoop() {
 
#ifndef WIN32
 
	struct timeval tim;
 
#else
 
	char input;
 
#endif
 
	uint32 next_tick;
 
	uint32 cur_ticks;
 
	char input_line[200];
 

	
 
#ifdef WIN32
 
	next_tick = GetTickCount() + 30;
 
#else
 
	gettimeofday(&tim, NULL);
 
	next_tick = (tim.tv_usec / 1000) + 30 + (tim.tv_sec * 1000);
 
#endif
 

	
 
	// Load the dedicated server stuff
 
	_is_network_server = true;
 
	_network_dedicated = true;
 
	_switch_mode = SM_NONE;
 
	_network_playas = OWNER_SPECTATOR;
 
	_local_player = OWNER_SPECTATOR;
 
	DoCommandP(0, Random(), InteractiveRandom(), NULL, CMD_GEN_RANDOM_NEW_GAME);
 
	// Done loading, start game!
 

	
 
	if (!_networking) {
 
		DEBUG(net, 1)("Dedicated server could not be launced. Aborting..");
 
		return ML_QUIT;
 
	}
 

	
 
	while (true) {
 
		InteractiveRandom(); // randomness
 

	
 
#ifdef UNIX
 
		if (InputWaiting()) {
 
			fgets(input_line, 200, stdin);
 
			// Forget about the final \n (or \r)
 
			strtok(input_line, "\r\n");
 
			IConsoleCmdExec(input_line);
 
		}
 
#else
 
		if (InputWaiting()) {
 
			input = getch();
 
			printf("%c", input);
 
			if (input != '\r')
 
				snprintf(input_line, 200, "%s%c", input_line, input);
 
			else {
 
				printf("\n");
 
				IConsoleCmdExec(input_line);
 
				sprintf(input_line, "");
 
			}
 
		}
 
#endif
 

	
 
		if (_exit_game) return ML_QUIT;
 

	
 
#ifdef WIN32
 
		cur_ticks = GetTickCount();
 
#else
 
		gettimeofday(&tim, NULL);
 
		cur_ticks = (tim.tv_usec / 1000) + (tim.tv_sec * 1000);
 
#endif
 

	
 
		if (cur_ticks >= next_tick) {
 
			next_tick += 30;
 

	
 
			GameLoop();
 
			_screen.dst_ptr = _dedicated_video_mem;
 
			UpdateWindows();
 
		}
 
		CSleep(1);
 
	}
 

	
 
	return ML_QUIT;
 
}
 

	
 

	
 
const HalVideoDriver _dedicated_video_driver = {
 
	DedicatedVideoStart,
 
	DedicatedVideoStop,
 
	DedicatedVideoMakeDirty,
 
	DedicatedVideoMainLoop,
 
	DedicatedVideoChangeRes,
 
};
 

	
 
#else
 

	
 
static void *_dedicated_video_mem;
 

	
 
static const char *DedicatedVideoStart(char **parm) {
 
	DEBUG(misc,0)("OpenTTD compiled without network-support, quiting...");
 

	
 
	return NULL;
 
}
 

	
 
static void DedicatedVideoStop() { free(_dedicated_video_mem); }
 
static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
 
static bool DedicatedVideoChangeRes(int w, int h) { return false; }
 
static int DedicatedVideoMainLoop() { return ML_QUIT; }
 

	
 
const HalVideoDriver _dedicated_video_driver = {
 
	DedicatedVideoStart,
 
	DedicatedVideoStop,
 
	DedicatedVideoMakeDirty,
 
	DedicatedVideoMainLoop,
 
	DedicatedVideoChangeRes,
 
};
 

	
 
#endif /* ENABLE_NETWORK */
dock_gui.c
Show inline comments
 
@@ -13,7 +13,7 @@ static void ShowBuildDocksDepotPicker();
 

	
 
static byte _ship_depot_direction;
 

	
 
static void CcBuildDocks(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildDocks(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_02_SPLAT, tile);
 
@@ -21,7 +21,7 @@ static void CcBuildDocks(bool success, u
 
	}
 
}
 

	
 
static void CcBuildCanal(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildCanal(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) SndPlayTileFx(SND_02_SPLAT, tile);
 
}
docs/Manual.txt
Show inline comments
 
@@ -90,7 +90,7 @@ Virtually any settings - train numbers, 
 

	
 
2.11 Network Play 
 

	
 
OpenTTD now supports rudimentary TCP/IP based network play. This is not supported on all platforms. To start a server, use the '-n' CLI switch, and start a client with '-n' and the servers IP adress. The OpenTTD network play runs over port 12345, so you may need to open this on your firewall.
 
See multiplayer.txt for more info.
 

	
 
2.12 Rail Recycling.
 

	
docs/console.txt
Show inline comments
 
@@ -40,13 +40,13 @@ VARIABLES:
 
VARIABLE HANDLING:
 
------------------
 

	
 
*developer = 0
 
*developer ++
 
developer = 0
 
developer ++
 

	
 
*temp_string = test
 
*temp_string = "my little"
 
temp_string = test
 
temp_string = "my little"
 

	
 
printf "%s world" *temp_string
 
printf "%s world" temp_string
 

	
 

	
 
---------------------------------------------------
docs/multiplayer.txt
Show inline comments
 
@@ -18,11 +18,18 @@ 2. Connecting to a Server
 
   - select one in the list below the buttons
 
   - click on "join game".
 

	
 
 - if you want to play over the internet you should have the ip of the game server you want connect to.
 
   - click direct connect
 
 - if you want to play over the internet you should have the ip or hostname of the game server you want connect to.
 
   - click add server
 
   - type in the ip address or hostname
 
   - if you want to add a port use :<port>
 
   - if you want to connect as an special player use #<player-no>
 
   
 
 - now you can select a company and press: "Join company", to help that company
 
 - or you can press "Spectate game", to spectate the game
 
 - or you can press "New company", and start your own company (if there are slots free)
 
 
 
 - you see a progressbar how far you are with joining the server.
 
 
 
 - happy playing
 
   
 
3. Connecting to a Server over the Console
 

	
 
@@ -33,38 +40,32 @@ 3. Connecting to a Server over the Conso
 

	
 
4. Playing Internet-Games
 

	
 
 - since OpenTTD 0.3.4 you can also play internet games over higher latency connections.
 
 - to do this the gameservers sync frequency should be highered to a decent value.
 
   - open the console [on the server]
 
   - type in the following command:
 
   
 
    ] *net_sync_freq = <4-80>
 
    
 
    default value: 4
 
    
 
   - this is lowering the sync frequency of the server and your game should be less laggy.
 
   - this is a server variable: it has nothing to do with the clients
 
   
 
 - you can also change when the clients ready packet is sent if you still have lags.
 
   - open the console
 
   - type in the following command:
 
   
 
    ] *net_ready_ahead = <1-8>
 
    
 
    default value: 1
 
    
 
   - in that way your client is sending its "i am ready for next sync" a bit earlier
 
     thats quite good for games where some players have higher latencies than the others.
 
   - this is a client variable: it has nothing to do with the server
 
 - since OpenTTD 0.3.5 the network protocol has been rewritten and is very stable, even over slow connections.
 
 
 
 - it can happen that a connection is that slow, or you have that many clients connected to your server, that your clients start to loose their connection. Some things you can do about it:
 
 
 
 - net_frame_freq:
 
    change it in console with: net_frame_freq = <number>
 
	the number should be between the 0 and 10, not much higher. It indicates the delay between clicking and showing up. The higher, the more you notice it, but the less bandwidth you use.
 
	
 
 - net_sync_freq:
 
    change it in console with: net_sync_freq = <number>
 
	the number should be between the 50 and 1000, not much lower, not much higer. It indicates the time between sync-frames. A sync-frame is a frame which checks if all clients are still in sync. When the value it too high, clients can desync in 1960, but the server detects it in 1970. Not really handy. The lower the value, the more bandwidth it uses.
 
	
 
 NB: changing net_frame_freq has more effect on the bandwidth then net_sync_freq. You should never change net_sync_freq!
 
 
 
 - to change the client timeout time
 
   - open the console [on the server]
 
   - type in the following command:
 
   
 
    ] *net_client_timeout = <30-x>
 
    
 
    default value: 300
 
   
 
   - warning: a too low value will disconnect your clients if they have a short lag
 
   
 
  
 
\ No newline at end of file
 

	
 
5. Some useful things
 

	
 
 - You can protect your company so nobody else can join uninvited. You do this with opening the console and then enter: protect <password>, where <password> is your password.
 
 
 
 - You can give other players some money via the ClientList (under the 'head' in the mainbar).
 
 
 
 - You can chat with other players via SHIFT+T or via the ClientList
 
 
 
 - Servers can now kick players, so don't make them use it!
 
 
 
 - From 0.3.5, desyncs should not happen anymore
 
 
 
 - From 0.3.5, patch-settings are also synced. You can now play without deleting openttd.cfg, and with, for example, extra large trains enabled.
 
 
economy.c
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include "network.h"
 
#include "sound.h"
 
#include "engine.h"
 
#include "network_data.h"
 

	
 
void UpdatePlayerHouse(Player *p, uint score)
 
{
 
@@ -139,7 +140,7 @@ int UpdateCompanyRatingAndValue(Player *
 
		PlayerEconomyEntry *pee;
 
		int numec;
 
		int32 min_income;
 
		uint32 max_income;
 
		int32 max_income;
 

	
 
		numec = min(p->num_valid_stat_ent, 12);
 
		if (numec != 0) {
 
@@ -346,6 +347,7 @@ static void PlayersCheckBankrupt(Player 
 
	int owner;
 
	int64 val;
 

	
 
	// If the player has money again, it does not go bankrupt
 
	if (p->player_money >= 0) {
 
		p->quarters_of_bankrupcy = 0;
 
		return;
 
@@ -355,43 +357,65 @@ static void PlayersCheckBankrupt(Player 
 

	
 
	owner = p->index;
 

	
 
	if (p->quarters_of_bankrupcy == 2) {
 
year_2:
 
		AddNewsItem( (StringID)(owner + 16),
 
			NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
	} else if (p->quarters_of_bankrupcy == 3) {
 
		if (IS_HUMAN_PLAYER(owner))
 
			goto year_2;
 
	switch (p->quarters_of_bankrupcy) {
 
		case 2:
 
			AddNewsItem( (StringID)(owner + 16),
 
				NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 
			break;
 
		case 3: {
 
			/* XXX - In multiplayer, should we ask other players if it wants to take
 
		          over when it is a human company? -- TrueLight */
 
			if (IS_HUMAN_PLAYER(owner)) {
 
				AddNewsItem( (StringID)(owner + 16),
 
					NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 
				break;
 
			}
 

	
 
		val = CalculateCompanyValue(p);
 
		if (val == 0) goto year_4;
 

	
 
		p->bankrupt_value = val;
 
		p->bankrupt_asked = 1 << owner;
 
		p->bankrupt_timeout = 0;
 
	} else if (p->quarters_of_bankrupcy == 4) {
 
year_4:
 
		DeletePlayerWindows(owner);
 
			// Check if the company has any value.. if not, declare it bankrupt
 
			//  right now
 
			val = CalculateCompanyValue(p);
 
			if (val > 0) {
 
				p->bankrupt_value = val;
 
				p->bankrupt_asked = 1 << owner; // Don't ask the owner
 
				p->bankrupt_timeout = 0;
 
				break;
 
			}
 
			// Else, falltrue to case 4...
 
		}
 
		case 4: {
 
			// Close everything the owner has open
 
			DeletePlayerWindows(owner);
 

	
 
		if (IS_HUMAN_PLAYER(owner)) {
 
// what does this code do??
 
			InitNewsItemStructs();
 
			DeleteWindowById(WC_NEWS_WINDOW, 0);
 
		}
 
//		Show bankrupt news
 
			SetDParam(0, p->name_1);
 
			SetDParam(1, p->name_2);
 
			AddNewsItem( (StringID)(owner + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
// Show bankrupt news
 
		SetDParam(0, p->name_1);
 
		SetDParam(1, p->name_2);
 
		AddNewsItem( (StringID)(owner + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
		if (IS_HUMAN_PLAYER(owner)) {
 
			p->bankrupt_asked = 255;
 
			p->bankrupt_timeout = 0x456;
 
		} else {
 
			p->money64 = p->player_money = 100000000;
 
			ChangeOwnershipOfPlayerItems(owner, 0xFF); // 255 is no owner
 
			p->is_active = false;
 
			// If the player is human, and it is no network play, leave the player playing
 
			if (IS_HUMAN_PLAYER(owner) && !_networking) {
 
				p->bankrupt_asked = 255;
 
				p->bankrupt_timeout = 0x456;
 
			} else {
 
				// If we are the server, make sure it is clear that his player is no
 
				//  longer with us!
 
				if (IS_HUMAN_PLAYER(owner) && _network_server) {
 
					NetworkClientInfo *ci;
 
					ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
					ci->client_playas = (byte)(OWNER_SPECTATOR + 1);
 
					// Send the new info to all the clients
 
					NetworkUpdateClientInfo(_network_own_client_index);
 
				}
 
				// Make sure the player no longer controls the company
 
				if (IS_HUMAN_PLAYER(owner) && owner == _local_player) {
 
					// Switch the player to spectator..
 
					_local_player = OWNER_SPECTATOR;
 
				}
 
				// Convert everything the player owns to NO_OWNER
 
				p->money64 = p->player_money = 100000000;
 
				ChangeOwnershipOfPlayerItems(owner, 0xFF); // 255 is no owner
 
				// Register the player as not-active
 
				p->is_active = false;
 
			}
 
		}
 
	}
 
}
 
@@ -811,11 +835,11 @@ static void FindSubsidyPassengerRoute(Fo
 

	
 
	fr->distance = (uint)-1;
 

	
 
	fr->from = from = DEREF_TOWN(InteractiveRandomRange(_total_towns));
 
	fr->from = from = DEREF_TOWN(RandomRange(_total_towns));
 
	if (from->xy == 0 || from->population < 400)
 
		return;
 

	
 
	fr->to = to = DEREF_TOWN(InteractiveRandomRange(_total_towns));
 
	fr->to = to = DEREF_TOWN(RandomRange(_total_towns));
 
	if (from==to || to->xy == 0 || to->population < 400 || to->pct_pass_transported > 42)
 
		return;
 

	
 
@@ -830,12 +854,12 @@ static void FindSubsidyCargoRoute(FoundR
 

	
 
	fr->distance = (uint)-1;
 

	
 
	fr->from = i = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries));
 
	fr->from = i = DEREF_INDUSTRY(RandomRange(_total_industries));
 
	if (i->xy == 0)
 
		return;
 

	
 
	// Randomize cargo type
 
	if (InteractiveRandom()&1 && i->produced_cargo[1] != 0xFF) {
 
	if (Random()&1 && i->produced_cargo[1] != 0xFF) {
 
		cargo = i->produced_cargo[1];
 
		trans = i->pct_transported[1];
 
		total = i->total_production[1];
 
@@ -855,7 +879,7 @@ static void FindSubsidyCargoRoute(FoundR
 

	
 
	if (cargo == CT_GOODS || cargo == CT_FOOD) {
 
		// The destination is a town
 
		Town *t = DEREF_TOWN(InteractiveRandomRange(_total_towns));
 
		Town *t = DEREF_TOWN(RandomRange(_total_towns));
 

	
 
		// Only want big towns
 
		if (t->xy == 0 || t->population < 900)
 
@@ -864,7 +888,7 @@ static void FindSubsidyCargoRoute(FoundR
 
		fr->to = t;
 
	} else {
 
		// The destination is an industry
 
		Industry *i2 = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries));
 
		Industry *i2 = DEREF_INDUSTRY(RandomRange(_total_industries));
 

	
 
		// The industry must accept the cargo
 
		if (i == i2 || i2->xy == 0 ||
 
@@ -943,10 +967,8 @@ static void SubsidyMonthlyHandler()
 
		}
 
	}
 

	
 
	if ((_networking) && (!_networking_server)) return;
 

	
 
	// 25% chance to go on
 
	if (ICHANCE16(1,4)) {
 
	if (CHANCE16(1,4)) {
 
		// Find a free slot
 
		s = _subsidies;
 
		while (s->cargo_type != 0xFF) {
 
@@ -972,7 +994,6 @@ 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;
engine.c
Show inline comments
 
@@ -783,7 +783,7 @@ int32 CmdRenameEngine(int x, int y, uint
 
{
 
	StringID str;
 

	
 
	str = AllocateName((byte*)_decode_parameters, 0);
 
	str = AllocateNameUnique((byte*)_decode_parameters, 0);
 
	if (str == 0)
 
		return CMD_ERROR;
 

	
functions.h
Show inline comments
 
#ifndef FUNCTIONS_H
 
#define FUNCTIONS_H
 

	
 
#include "network.h"
 

	
 
/* vehicle.c */
 

	
 
/* window.c */
 
@@ -96,8 +94,28 @@ void CDECL ShowInfoF(const char *str, ..
 
void NORETURN CDECL error(const char *str, ...);
 

	
 
/* ttd.c */
 
uint32 Random();
 
uint RandomRange(uint max);
 

	
 
// **************
 
// * Warning: DO NOT enable this unless you understand what it does
 
// *
 
// * If enabled, in a network game all randoms will be dumped to the
 
// *  stdout if the first client joins (or if you are a client). This
 
// *  is to help finding desync problems.
 
// *
 
// * Warning: DO NOT enable this unless you understand what it does
 
// **************
 

	
 
//#define RANDOM_DEBUG
 

	
 
#ifdef RANDOM_DEBUG
 
	#define Random() DoRandom(__LINE__, __FILE__)
 
	uint32 DoRandom(uint line, char *file);
 
	#define RandomRange(max) DoRandomRange(max, __LINE__, __FILE__)
 
	uint DoRandomRange(uint max, uint line, char *file);
 
#else
 
	uint32 Random();
 
	uint RandomRange(uint max);
 
#endif
 

	
 
void InitPlayerRandoms();
 

	
 
@@ -114,6 +132,12 @@ void AddTextEffect(StringID msg, int x, 
 
void InitTextEffects();
 
void DrawTextEffects(DrawPixelInfo *dpi);
 

	
 
void InitTextMessage();
 
void DrawTextMessage();
 
void AddTextMessage(uint16 color, uint8 duration, const char *message, ...);
 
void UndrawTextMessage();
 
void TextMessageDailyLoop();
 

	
 
bool AddAnimatedTile(uint tile);
 
void DeleteAnimatedTile(uint tile);
 
void AnimateAnimatedTiles();
 
@@ -125,46 +149,21 @@ bool CheckBridge_Stuff(byte bridge_type,
 
uint32 GetBridgeLength(TileIndex begin, TileIndex end);
 
int CalcBridgeLenCostFactor(int x);
 

	
 
/* network.c */
 
typedef void CommandCallback(bool success, uint tile, uint32 p1, uint32 p2);
 
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
 

	
 
void NetworkReceive();
 
void NetworkSend();
 
void NetworkProcessCommands();
 
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();
 
void NetworkSendSyncPackets();
 
void NetworkSendFrameSyncPackets();
 
bool NetworkCheckClientReady();
 

	
 
void NetworkIPListInit();
 

	
 
void NetworkCoreInit();
 
void NetworkCoreShutdown();
 
void NetworkCoreDisconnect();
 
void NetworkCoreLoop(bool incomming);
 
bool NetworkCoreConnectGame(const byte* b, unsigned short port);
 
bool NetworkCoreConnectGameStruct(NetworkGameList * item);
 
bool NetworkCoreStartGame();
 

	
 
void NetworkLobbyShutdown();
 
void NetworkLobbyInit();
 

	
 
void NetworkGameListClear();
 
NetworkGameList * NetworkGameListAdd();
 
void NetworkGameListFromLAN();
 
void NetworkGameListFromInternet();
 
NetworkGameList * NetworkGameListItem(uint16 index);
 

	
 
void NetworkGameFillDefaults();
 
void NetworkGameChangeDate(uint16 newdate);
 
/* network.c */
 
void NetworkUDPClose(void);
 
void NetworkStartUp();
 
void NetworkShutDown(void);
 
void NetworkGameLoop(void);
 
void NetworkUDPGameLoop(void);
 
bool NetworkServerStart(void);
 
bool NetworkClientConnectGame(const byte* host, unsigned short port);
 
void NetworkQueryServer(const byte* host, unsigned short port, bool game_info);
 
void NetworkReboot();
 
void NetworkDisconnect();
 
void NetworkSend_Command(uint32 tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
 

	
 
/* misc_cmd.c */
 
void PlaceTreesRandomly();
 
@@ -180,11 +179,16 @@ void InitializeLandscapeVariables(bool o
 
/* misc.c */
 
void DeleteName(StringID id);
 
byte *GetName(int id, byte *buff);
 
StringID AllocateName(const byte *name, byte skip);
 

	
 
// AllocateNameUnique also tests if the name used is not used anywere else
 
//  and if it is used, it returns an error.
 
#define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true)
 
#define AllocateName(name, skip) RealAllocateName(name, skip, false)
 
StringID RealAllocateName(const byte *name, byte skip, bool check_double);
 
void ConvertDayToYMD(YearMonthDay *ymd, uint16 date);
 
uint ConvertYMDToDay(uint year, uint month, uint day);
 
uint ConvertIntDate(uint date);
 

	
 
void CSleep(int milliseconds);
 

	
 

	
 
/* misc functions */
 
@@ -221,6 +225,10 @@ void ChangeTownRating(Town *t, int add, 
 
uint GetRoadBitsByTile(TileIndex tile);
 
int GetTownRadiusGroup(Town *t, uint tile);
 
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
 
void ShowNetworkChatQueryWindow(byte desttype, byte dest);
 
void ShowNetworkGiveMoneyWindow(byte player);
 
void ShowNetworkNeedGamePassword();
 
void ShowNetworkNeedCompanyPassword();
 
void ShowRenameSignWindow(SignStruct *ss);
 
void ShowRenameWaypointWindow(Waypoint *cp);
 
int FindFirstBit(uint32 x);
gfx.c
Show inline comments
 
@@ -17,7 +17,8 @@ static byte _string_colorremap[3];
 
static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8];
 

	
 

	
 
static void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch)
 

	
 
void memcpy_pitch(void *d, void *s, int w, int h, int spitch, int dpitch)
 
{
 
	byte *dp = (byte*)d;
 
	byte *sp = (byte*)s;
 
@@ -41,6 +42,7 @@ void GfxScroll(int left, int top, int wi
 

	
 
	if (_cursor.visible)
 
		UndrawMouseCursor();
 
	UndrawTextMessage();
 

	
 
	p = _screen.pitch;
 

	
 
@@ -254,7 +256,7 @@ enum {
 

	
 

	
 
/* returns right coordinate */
 
int DrawString(int x, int y, uint16 str, byte color)
 
int DrawString(int x, int y, uint16 str, uint16 color)
 
{
 
	GetString(str_buffr, str);
 
	assert(strlen(str_buffr) < sizeof(str_buffr) - 1);
 
@@ -262,7 +264,7 @@ int DrawString(int x, int y, uint16 str,
 
}
 

	
 

	
 
void DrawStringRightAligned(int x, int y, uint16 str, byte color)
 
void DrawStringRightAligned(int x, int y, uint16 str, uint16 color)
 
{
 
	GetString(str_buffr, str);
 
	assert(strlen(str_buffr) < sizeof(str_buffr) - 1);
 
@@ -270,7 +272,7 @@ void DrawStringRightAligned(int x, int y
 
}
 

	
 

	
 
int DrawStringCentered(int x, int y, uint16 str, byte color)
 
int DrawStringCentered(int x, int y, uint16 str, uint16 color)
 
{
 
	int w;
 

	
 
@@ -283,7 +285,7 @@ int DrawStringCentered(int x, int y, uin
 
	return w;
 
}
 

	
 
void DrawStringCenterUnderline(int x, int y, uint16 str, byte color)
 
void DrawStringCenterUnderline(int x, int y, uint16 str, uint16 color)
 
{
 
	int w = DrawStringCentered(x, y, str, color);
 
	GfxFillRect(x-(w>>1), y+10, x-(w>>1)+w, y+10, _string_colorremap[1]);
 
@@ -472,12 +474,15 @@ void DrawFrameRect(int left, int top, in
 
	}
 
}
 

	
 
int DoDrawString(const byte *string, int x, int y, byte color) {
 
int DoDrawString(const byte *string, int x, int y, uint16 real_color) {
 
	DrawPixelInfo *dpi = _cur_dpi;
 
	int base = _stringwidth_base;
 
	byte c;
 
	byte color;
 
	int xo = x, yo = y;
 

	
 
	color = real_color & 0xFF;
 

	
 
	if (color != 0xFE) {
 
		if (x >= dpi->left + dpi->width ||
 
				x + _screen.width*2 <= dpi->left ||
 
@@ -487,8 +492,13 @@ int DoDrawString(const byte *string, int
 

	
 
		if (color != 0xFF) {
 
switch_color:;
 
			_string_colorremap[1] = _string_colormap[color].text;
 
			_string_colorremap[2] = _string_colormap[color].shadow;
 
			if (real_color & 0x100) {
 
				_string_colorremap[1] = color;
 
				_string_colorremap[2] = 215;
 
			} else {
 
				_string_colorremap[1] = _string_colormap[color].text;
 
				_string_colorremap[2] = _string_colormap[color].shadow;
 
			}
 
			_color_remap_ptr = _string_colorremap;
 
		}
 
	}
 
@@ -1684,6 +1694,7 @@ void RedrawScreenRect(int left, int top,
 
			UndrawMouseCursor();
 
		}
 
	}
 
	UndrawTextMessage();
 

	
 
#if defined(_DEBUG)
 
	if (_dbg_screen_rect)
 
@@ -1921,9 +1932,18 @@ void ToggleFullScreen(const bool full_sc
 
{
 
	_fullscreen = full_screen;
 
	/* use preset resolutions, not _screen.height and _screen.width. On windows for example
 
	   if Desktop-size is 1280x1024, and gamesize is also 1280x1024, _screen.height will be 
 
		 only 1000 because of possible start-bar. For this reason you cannot switch to 
 
	   if Desktop-size is 1280x1024, and gamesize is also 1280x1024, _screen.height will be
 
		 only 1000 because of possible start-bar. For this reason you cannot switch to
 
		 fullscreen mode from this resolution. Use of preset resolution will fix this */
 
	if (!_video_driver->change_resolution(_cur_resolution[0], _cur_resolution[1]))
 
		_fullscreen ^= true; // switching resolution failed, put back full_screen to original status
 
}
 

	
 
uint16 GetDrawStringPlayerColor(byte player)
 
{
 
	// Get the color for DrawString-subroutines which matches the color
 
	//  of the player
 
	if (player == OWNER_SPECTATOR || player == OWNER_SPECTATOR - 1)
 
			return 1;
 
	return (_color_list[_player_colors[player]].window_color_1b) | 0x100;
 
}
gfx.h
Show inline comments
 
@@ -42,14 +42,15 @@ typedef struct CursorVars {
 

	
 
void RedrawScreenRect(int left, int top, int right, int bottom);
 
void GfxScroll(int left, int top, int width, int height, int xo, int yo);
 
int DrawStringCentered(int x, int y, uint16 str, byte color);
 
int DrawString(int x, int y, uint16 str, byte color);
 
void DrawStringCenterUnderline(int x, int y, uint16 str, byte color);
 
int DoDrawString(const byte *string, int x, int y, byte color);
 
void DrawStringRightAligned(int x, int y, uint16 str, byte color);
 
int DrawStringCentered(int x, int y, uint16 str, uint16 color);
 
int DrawString(int x, int y, uint16 str, uint16 color);
 
void DrawStringCenterUnderline(int x, int y, uint16 str, uint16 color);
 
int DoDrawString(const byte *string, int x, int y, uint16 color);
 
void DrawStringRightAligned(int x, int y, uint16 str, uint16 color);
 
void GfxFillRect(int left, int top, int right, int bottom, int color);
 
void GfxDrawLine(int left, int top, int right, int bottom, int color);
 
void DrawFrameRect(int left, int top, int right, int bottom, int color, int flags);
 
uint16 GetDrawStringPlayerColor(byte player);
 

	
 
int GetStringWidth(const byte *str);
 
void LoadStringWidthTable();
gui.h
Show inline comments
 
@@ -93,6 +93,12 @@ void AskForNewGameToStart();
 
void DrawEditBox(Window *w, int wid);
 
void HandleEditBox(Window *w, int wid);
 

	
 
void BuildFileList();
 
void SetFiosType(const byte fiostype);
 

	
 
/*	FIOS_TYPE_FILE, FIOS_TYPE_OLDFILE etc. different colours */
 
static const byte _fios_colors[] = {13, 9, 9, 6, 5, 6, 5};
 

	
 

	
 
/* network gui */
 
void ShowNetworkGameWindow();
hal.h
Show inline comments
 
@@ -71,6 +71,8 @@ extern const HalMusicDriver _extmidi_mus
 
extern const HalMusicDriver _bemidi_music_driver;
 
#endif
 

	
 
extern const HalVideoDriver _dedicated_video_driver;
 

	
 
enum DriverType {
 
	VIDEO_DRIVER = 0,
 
	SOUND_DRIVER = 1,
 
@@ -119,6 +121,12 @@ enum {
 
	FIOS_TYPE_OLD_SCENARIO = 6,
 
};
 

	
 

	
 
// Variables to display file lists
 
FiosItem *_fios_list;
 
int _fios_num;
 
int _saveload_mode;
 

	
 
// get the name of an oldstyle savegame
 
void GetOldSaveGameName(char *title, const char *file);
 
// get the name of an oldstyle scenario
industry_cmd.c
Show inline comments
 
@@ -969,7 +969,9 @@ static void MaybePlantFarmField(Industry
 
{
 
	uint tile;
 
	if (CHANCE16(1,8)) {
 
		tile = TileAddWrap(i->xy, ((i->width>>1) + Random() % 31 - 16), ((i->height>>1) + Random() % 31 - 16));
 
		int x = (i->width>>1) + Random() % 31 - 16;
 
		int y = (i->height>>1) + Random() % 31 - 16;
 
		tile = TileAddWrap(i->xy, x, y);
 
		if (tile != TILE_WRAPPED)
 
			PlantFarmField(tile);
 
	}
 
@@ -1391,7 +1393,7 @@ static Industry *AllocateIndustry()
 
	for(i=_industries; i != endof(_industries); i++) {
 
		if (i->xy == 0) {
 
			int index = i - _industries;
 
		    if (index > _total_industries) _total_industries++;
 
		    if (index > _total_industries) _total_industries = index;
 
			return i;
 
		}
 
	}
 
@@ -1476,7 +1478,9 @@ static void DoCreateNewIndustry(Industry
 
	if (i->type == IT_FARM || i->type == IT_FARM_2) {
 
		tile = i->xy + TILE_XY((i->width >> 1), (i->height >> 1));
 
		for(j=0; j!=50; j++) {
 
			uint new_tile = TileAddWrap(tile, Random() % 31 - 16, Random() % 31 - 16);
 
			int x = Random() % 31 - 16;
 
			int y = Random() % 31 - 16;
 
			uint new_tile = TileAddWrap(tile, x, y);
 
			if (new_tile != TILE_WRAPPED)
 
				PlantFarmField(new_tile);
 
		}
 
@@ -1898,8 +1902,7 @@ static void Load_INDY()
 
	_total_industries = 0;
 
	while ((index = SlIterateArray()) != -1) {
 
		SlObject(DEREF_INDUSTRY(index), _industry_desc);
 
		if (index + 1 > _total_industries)
 
		    _total_industries = index + 1;
 
		if (index > _total_industries) _total_industries = index;
 
	}
 
}
 

	
intro_gui.c
Show inline comments
 
@@ -8,9 +8,9 @@
 
#include "player.h"
 
#include "command.h"
 
#include "console.h"
 
#include "network.h"
 

	
 
extern void MakeNewGame();
 
extern void StartScenario();
 
extern void SwitchMode(int new_mode);
 

	
 
/*
 
static void ShowSelectTutorialWindow()
 
@@ -39,11 +39,13 @@ static const Widget _select_game_widgets
 
{   WIDGETS_END},
 
};
 

	
 
extern void HandleOnEditText(WindowEvent *e);
 
extern void HandleOnEditTextCancel();
 

	
 
static void SelectGameWndProc(Window *w, WindowEvent *e) {
 
	switch(e->event) {
 
	case WE_PAINT:
 
		w->click_state = (w->click_state & ~(0xC0) & ~(0xF << 12)) | (1 << (_new_opt.landscape+12)) | (!_networking?(1<<6):(1<<7));
 
		w->disabled_state = _networking ? 0x30 : 0;
 
		w->click_state = (w->click_state & ~(0xC0) & ~(0xF << 12)) | (1 << (_new_opt.landscape+12)) | (1<<6);
 
		SetDParam(0, STR_6801_EASY + _new_opt.diff_level);
 
		DrawWindowWidgets(w);
 
		break;
 
@@ -54,17 +56,16 @@ static void SelectGameWndProc(Window *w,
 
		case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
 
		case 4: ShowPatchesSelection(); break;
 
		case 5: DoCommandP(0, InteractiveRandom(), 0, NULL, CMD_CREATE_SCENARIO); break;
 
		case 6:
 
			if (_networking)
 
				DoCommandP(0, 0, 0, NULL, CMD_SET_SINGLE_PLAYER);
 
			break;
 
		case 7:
 
#ifdef ENABLE_NETWORK
 
			if (!_network_available) {
 
				ShowErrorMessage(-1,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
 
			} else {
 
				ShowNetworkGameWindow();
 
				ShowErrorMessage(-1, TEMP_STRING_NO_NETWORK, 0, 0);
 
			}
 
#else
 
			ShowErrorMessage(-1,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
 
#endif /* ENABLE_NETWORK */
 
			break;
 
		case 8: ShowGameOptions(); break;
 
		case 9: ShowGameDifficulty(); break;
 
@@ -79,7 +80,11 @@ static void SelectGameWndProc(Window *w,
 
		case WKC_BACKQUOTE: IConsoleSwitch(); break;
 
		}
 
		break;
 

	
 
	case WE_ON_EDIT_TEXT: HandleOnEditText(e); break;
 
	case WE_ON_EDIT_TEXT_CANCEL: HandleOnEditTextCancel(); break;
 
	}
 

	
 
}
 

	
 
static const WindowDesc _select_game_desc = {
 
@@ -128,9 +133,7 @@ int32 CmdGenRandomNewGame(int x, int y, 
 
	_random_seeds[0][0] = p1;
 
	_random_seeds[0][1] = p2;
 

	
 
	if (_networking) { NetworkStartSync(true); }
 

	
 
	MakeNewGame();
 
	SwitchMode(SM_NEWGAME);
 
	return 0;
 
}
 

	
 
@@ -169,9 +172,7 @@ int32 CmdStartScenario(int x, int y, uin
 
	_random_seeds[0][0] = p1;
 
	_random_seeds[0][1] = p2;
 

	
 
	if (_networking) { NetworkStartSync(true); }
 

	
 
	StartScenario();
 
	SwitchMode(SM_START_SCENARIO);
 
	return 0;
 
}
 

	
lang/english.txt
Show inline comments
 
@@ -1062,10 +1062,10 @@ STR_CONFIG_PATCHES_CURRENCY				:{CURRENC
 
STR_CONFIG_PATCHES_QUERY_CAPT			:{WHITE}Change setting value
 
STR_CONFIG_PATCHES_SERVICE_INTERVAL_INCOMPATIBLE	:{WHITE}Some or all of the default service interval(s) below are incompatible with chosen setting! 5-90% and 30-800 days are valid
 

	
 
STR_TEMPERATE_LANDSCAPE			:temperate landscape
 
STR_SUB_ARCTIC_LANDSCAPE		:sub-arctic landscape
 
STR_SUB_TROPICAL_LANDSCAPE	:sub-tropical landscape
 
STR_TOYLAND_LANDSCAPE				:toyland landscape
 
STR_TEMPERATE_LANDSCAPE			:Temperate landscape
 
STR_SUB_ARCTIC_LANDSCAPE		:Sub-arctic landscape
 
STR_SUB_TROPICAL_LANDSCAPE	:Sub-tropical landscape
 
STR_TOYLAND_LANDSCAPE				:Toyland landscape
 

	
 
STR_CHEATS										:{WHITE}Cheats
 
STR_CHEATS_TIP								:{BLACK}Checkboxes indicate if you have used this cheat before
 
@@ -1184,37 +1184,46 @@ TEMP_AI_ACTIVATED						:{WHITE}Warning: 
 

	
 
############ network gui strings
 

	
 
TEMP_STRING_NO_NETWORK						:{WHITE}Network interface is not yet fully operational!{}Not working items have been disabled.
 

	
 
STR_NETWORK_MULTIPLAYER						:{WHITE}Multiplayer
 

	
 
STR_NETWORK_FIND_SERVER						:{BLACK}Find server
 
STR_NETWORK_FIND_SERVER_TIP				:{BLACK}Search network for a server
 
STR_NETWORK_DIRECT_CONNECT				:{BLACK}Direct connect
 
STR_NETWORK_ENTER_IP							:{BLACK}Enter the IP address of the server
 
STR_NETWORK_DIRECT_CONNECT_TIP		:{BLACK}Connect to a known IP
 
STR_NETWORK_START_SERVER					:{BLACK}Start server
 
STR_NETWORK_START_SERVER_TIP			:{BLACK}Start an own server
 

	
 
STR_NETWORK_PLAYER_NAME						:{BLACK}Player name:
 
STR_NETWORK_ENTER_NAME_TIP				:{BLACK}This is the name other players will identify you by
 

	
 
STR_NETWORK_SELECT_CONNECTION			:{BLACK}Select connection type:
 
STR_NETWORK_CONNECTION_TYPE_TIP		:{BLACK}Choose between an internet game or a local area nework game
 
STR_NETWORK_CONNECTION						:{BLACK}Connection:
 
STR_NETWORK_CONNECTION_TIP				:{BLACK}Choose between an internet game or a local area nework game
 
STR_NETWORK_COMBO1								:{BLACK}{SKIP}{SKIP}{STRING}
 
STR_NETWORK_LAN										:LAN
 
STR_NETWORK_INTERNET							:Internet
 

	
 
STR_NETWORK_START_SERVER					:{BLACK}Start server
 
STR_NETWORK_START_SERVER_TIP			:{BLACK}Start an own server
 

	
 
STR_NETWORK_GAME_NAME							:{BLACK}Name
 
STR_NETWORK_GAME_NAME_TIP					:{BLACK}Name of the game
 
STR_NETWORK_PLAYERS								:{BLACK}#/#
 
STR_NETWORK_PLAYERS_TIP						:{BLACK}Players currently in this game / Maximum number of players
 
STR_NETWORK_MAP_SIZE							:{BLACK}Size
 
STR_NETWORK_MAP_SIZE_TIP					:{BLACK}Size of the map
 
STR_NETWORK_INFO_ICONS_TIP				:{BLACK}Language, server version, etc.
 
STR_NETWORK_CLICK_GAME_TO_SELECT	:{BLACK}Click a game from the list to select it
 

	
 
STR_NETWORK_PLAYERS_VAL						:{BLACK}{COMMA8}/{COMMA8}
 
STR_NETWORK_FIND_SERVER						:{BLACK}Find server
 
STR_NETWORK_FIND_SERVER_TIP				:{BLACK}Search network for a server
 
STR_NETWORK_ADD_SERVER						:{BLACK}Add server
 
STR_NETWORK_ADD_SERVER_TIP				:{BLACK}Adds a server to the list which will always be checked for running games.
 
STR_NETWORK_ENTER_IP							:{BLACK}Enter the address of the host
 

	
 
STR_NETWORK_CLIENTS_ONLINE				:{BLACK}{COMMA16}/{COMMA16}
 
STR_NETWORK_CLIENTS_CAPTION 			:{BLACK}Clients
 
STR_NETWORK_CLIENTS_CAPTION_TIP		:{BLACK}Clients online / clients max
 
STR_NETWORK_GAME_INFO							:{SILVER}GAME INFO
 
STR_ORANGE												:{ORANGE}{STRING}
 
STR_NETWORK_CLIENTS								:{SILVER}Clients:  {WHITE}{COMMA8} / {COMMA8}
 
STR_NETWORK_LANGUAGE							:{SILVER}Language:  {WHITE}{STRING}
 
STR_NETWORK_TILESET								:{SILVER}Tileset:  {WHITE}{STRING}
 
STR_NETWORK_MAP_SIZE							:{SILVER}Map size:  {WHITE}{COMMA16}x{COMMA16}
 
STR_NETWORK_SERVER_VERSION				:{SILVER}Server version:  {WHITE}{STRING}
 
STR_NETWORK_SERVER_ADDRESS				:{SILVER}Server address:  {WHITE}{STRING}
 
STR_NETWORK_START_DATE						:{SILVER}Start date:  {WHITE}{DATE_SHORT}
 
STR_NETWORK_CURRENT_DATE					:{SILVER}Current date:  {WHITE}{DATE_SHORT}
 
STR_NETWORK_PASSWORD							:{SILVER}Password protected!
 
STR_NETWORK_SERVER_OFFLINE				:{SILVER}SERVER OFFLINE
 
STR_NETWORK_SERVER_FULL						:{SILVER}SERVER FULL
 

	
 
STR_NETWORK_JOIN_GAME							:{BLACK}Join game
 

	
 
@@ -1223,20 +1232,25 @@ STR_NETWORK_START_GAME_WINDOW			:{WHITE}
 

	
 
STR_NETWORK_NEW_GAME_NAME					:{BLACK}Game name:
 
STR_NETWORK_NEW_GAME_NAME_TIP			:{BLACK}The game name will be displayed to other players in the multiplayer game selection menu
 
STR_NETWORK_PASSWORD							:{BLACK}Password:
 
STR_NETWORK_SET_PASSWORD					:{BLACK}Set password
 
STR_NETWORK_PASSWORD_TIP					:{BLACK}Protect your game with a password if you don't want other people to join it
 
STR_NETWORK_SELECT_MAP						:{BLACK}Select a map:
 
STR_NETWORK_SELECT_MAP_TIP				:{BLACK}Which map do you want to play?
 
STR_NETWORK_NUMBER_OF_PLAYERS			:{BLACK}Number of players:
 
STR_NETWORK_NUMBER_OF_PLAYERS_TIP	:{BLACK}Choose a maximum number of players. Not all slots need to be filled.
 
STR_NETWORK_NUMBER_OF_CLIENTS			:{BLACK}Maximum allowed clients:
 
STR_NETWORK_NUMBER_OF_CLIENTS_TIP	:{BLACK}Choose a maximum number of clients. Not all slots need to be filled.
 
STR_NETWORK_COMBO2								:{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
 
STR_NETWORK_2_PLAYERS							:2 players
 
STR_NETWORK_3_PLAYERS							:3 players
 
STR_NETWORK_4_PLAYERS							:4 players
 
STR_NETWORK_5_PLAYERS							:5 players
 
STR_NETWORK_6_PLAYERS							:6 players
 
STR_NETWORK_7_PLAYERS							:7 players
 
STR_NETWORK_8_PLAYERS							:8 players
 
STR_NETWORK_2_CLIENTS							:2 clients
 
STR_NETWORK_3_CLIENTS							:3 clients
 
STR_NETWORK_4_CLIENTS							:4 clients
 
STR_NETWORK_5_CLIENTS							:5 clients
 
STR_NETWORK_6_CLIENTS							:6 clients
 
STR_NETWORK_7_CLIENTS							:7 clients
 
STR_NETWORK_8_CLIENTS							:8 clients
 
STR_NETWORK_9_CLIENTS							:9 clients
 
STR_NETWORK_10_CLIENTS						:10 clients
 
STR_NETWORK_LANGUAGE_SPOKEN				:{BLACK}Language spoken:
 
STR_NETWORK_LANGUAGE_TIP					:{BLACK}Other players will know which language is spoken on the server.
 
STR_NETWORK_COMBO3								:{BLACK}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{SKIP}{STRING}
 
STR_NETWORK_START_GAME						:{BLACK}Start Game
 
STR_NETWORK_START_GAME_TIP				:{BLACK}Start a new network game from a random map, or scenario
 
STR_NETWORK_LOAD_GAME							:{BLACK}Load Game
 
@@ -1244,17 +1258,61 @@ STR_NETWORK_LOAD_GAME_TIP					:{BLACK}Re
 
STR_NETWORK_LOAD_SCENARIO					:{BLACK}Load Scenario
 
STR_NETWORK_LOAD_SCENARIO_TIP			:{BLACK}Start a new network game from a scenario
 

	
 
############ Leave those lines in this order!!
 
STR_NETWORK_LANG_ANY							:Any
 
STR_NETWORK_LANG_ENGLISH					:English
 
STR_NETWORK_LANG_GERMAN						:German
 
STR_NETWORK_LANG_FRENCH						:French
 
############ End of leave-in-this-order
 

	
 
STR_NETWORK_GAME_LOBBY						:{WHITE}Multiplayer game lobby
 

	
 
STR_NETWORK_SEND									:{BLACK}Send
 
STR_NETWORK_SEND_TIP							:{BLACK}Send a message to the other players
 
STR_NETWORK_COMPANY_NAME					:{BLACK}Company name:
 
STR_NETWORK_COMPANY_NAME_TIP			:{BLACK}Change the name of your company. Hit enter to apply changes
 
STR_NETWORK_PREPARE_TO_JOIN				:{BLACK}Preparing to join:   {ORANGE}{STRING}
 
STR_NETWORK_COMPANY_LIST_TIP			:{BLACK}A list of all companies currently in this game. You can either join one or start a
 
STR_NETWORK_NEW_COMPANY						:{BLACK}New company
 
STR_NETWORK_NEW_COMPANY_TIP				:{BLACK}Open a new company
 
STR_NETWORK_SPECTATE_GAME					:{BLACK}Spectate game
 
STR_NETWORK_SPECTATE_GAME_TIP			:{BLACK}Watch the game as a spectator
 
STR_NETWORK_NEW_COMPANY						:{BLACK}New company
 
STR_NETWORK_NEW_COMPANY_TIP				:{BLACK}Open a new company
 
STR_NETWORK_READY									:{BLACK}Ready
 
STR_NETWORK_JOIN_COMPANY					:{BLACK}Join company
 
STR_NETWORK_JOIN_COMPANY_TIP			:{BLACK}Help managing this company
 
STR_NETWORK_REFRESH								:{BLACK}Refresh server
 
STR_NETWORK_REFRESH_TIP						:{BLACK}Refresh the server info
 

	
 
STR_NETWORK_COMPANY_INFO					:{SILVER}COMPANY INFO
 

	
 
STR_NETWORK_COMPANY_NAME					:{SILVER}Company name:  {WHITE}{STRING}
 
STR_NETWORK_INAUGURATION_YEAR			:{SILVER}Inauguration:  {WHITE}{NUMU16}
 
STR_NETWORK_VALUE									:{SILVER}Company value:  {WHITE}{CURRENCY64}
 
STR_NETWORK_CURRENT_BALANCE				:{SILVER}Current balance:  {WHITE}{CURRENCY64}
 
STR_NETWORK_LAST_YEARS_INCOME			:{SILVER}Last year's income:  {WHITE}{CURRENCY64}
 
STR_NETWORK_PERFORMANCE						:{SILVER}Performance:  {WHITE}{NUMU16}
 

	
 
STR_NETWORK_VEHICLES							:{SILVER}Vehicles:  {WHITE}{NUMU16} {TRAIN}, {NUMU16} {LORRY}, {NUMU16} {BUS}, {NUMU16} {PLANE}, {NUMU16} {SHIP}
 
STR_NETWORK_STATIONS							:{SILVER}Stations:  {WHITE}{NUMU16} {TRAIN}, {NUMU16} {LORRY}, {NUMU16} {BUS}, {NUMU16} {PLANE}, {NUMU16} {SHIP}
 
STR_NETWORK_PLAYERS								:{SILVER}Players:  {WHITE}{STRING}
 

	
 
STR_NETWORK_CONNECTING			:{WHITE}Connecting...
 

	
 
############ Leave those lines in this order!!
 
STR_NETWORK_CONNECTING_1	:{BLACK}(1/6) Connecting..
 
STR_NETWORK_CONNECTING_2	:{BLACK}(2/6) Authorizing..
 
STR_NETWORK_CONNECTING_3	:{BLACK}(3/6) Waiting..
 
STR_NETWORK_CONNECTING_4	:{BLACK}(4/6) Downloading map..
 
STR_NETWORK_CONNECTING_5	:{BLACK}(5/6) Processing data..
 

	
 
STR_NETWORK_CONNECTING_SPECIAL_1	:{BLACK}Fetching game info..
 
STR_NETWORK_CONNECTING_SPECIAL_2	:{BLACK}Fetching company info..
 
############ End of leave-in-this-order
 
STR_NETWORK_CONNECTING_WAITING			:{BLACK}{INT32} client(s) in front of us
 
STR_NETWORK_CONNECTING_DOWNLOADING	:{BLACK}{INT32} / {INT32} kbytes downloaded so far
 

	
 
STR_NETWORK_DISCONNECT			:{BLACK}Disconnect
 

	
 
STR_NETWORK_CHAT_QUERY_CAPTION			:{WHITE}Enter your text message to send
 
STR_NETWORK_GIVE_MONEY_CAPTION			:{WHITE}Enter the amount of money you want to give
 
STR_NETWORK_NEED_GAME_PASSWORD_CAPTION		:{WHITE}Server is protected. Enter password
 
STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION	:{WHITE}Company is protected. Enter password
 
STR_NETWORK_CLIENT_LIST						:{WHITE}Client List
 

	
 
STR_NETWORK_ERR_NOTAVAILABLE			:{WHITE} No network devices found or compiled without ENABLE_NETWORK
 
STR_NETWORK_ERR_NOSERVER			:{WHITE} Could not find any network games
 
@@ -1262,7 +1320,34 @@ STR_NETWORK_ERR_NOCONNECTION			:{WHITE} 
 
STR_NETWORK_ERR_DESYNC				:{WHITE} Network-Game synchronization failed.
 
STR_NETWORK_ERR_LOSTCONNECTION			:{WHITE} Network-Game connection lost.
 
STR_NETWORK_ERR_SAVEGAMEERROR			:{WHITE} Could not load server-savegame.
 
STR_NETWORK_ERR_SERVER_START			:{WHITE} Could not start the server.
 
STR_NETWORK_ERR_CLIENT_START			:{WHITE} Could not connect.
 
STR_NETWORK_ERR_TIMEOUT					:{WHITE} Connection #{NUMU16} timed out.
 
STR_NETWORK_ERR_SERVER_ERROR		:{WHITE} We made a protocol-error and our connection is closed.
 
STR_NETWORK_ERR_WRONG_REVISION	:{WHITE} The revision of this client does not match the revision of the server.
 
STR_NETWORK_ERR_WRONG_PASSWORD	:{WHITE} Wrong password.
 
STR_NETWORK_ERR_SERVER_FULL	:{WHITE} The server is full
 
STR_NETWORK_ERR_KICKED	:{WHITE} You are kicked out of the server
 

	
 
STR_NETWORK_ERR_LEFT							:has left the game
 
############ Leave those lines in this order!!
 
STR_NETWORK_ERR_CLIENT_GENERAL					:general error
 
STR_NETWORK_ERR_CLIENT_DESYNC						:desync error
 
STR_NETWORK_ERR_CLIENT_SAVEGAME					:could not load map
 
STR_NETWORK_ERR_CLIENT_CONNECTION_LOST	:connection lost
 
STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR		:protocol error
 
STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED		:not authorized
 
STR_NETWORK_ERR_CLIENT_NOT_EXPECTED			:received strange packet
 
STR_NETWORK_ERR_CLIENT_WRONG_REVISION		:wrong revision
 
STR_NETWORK_ERR_CLIENT_NAME_IN_USE			:name already in use
 
STR_NETWORK_ERR_CLIENT_WRONG_PASSWORD		:wrong game-password
 
STR_NETWORK_ERR_CLIENT_PLAYER_MISMATCH	:wrong player-id in DoCommand
 
STR_NETWORK_ERR_CLIENT_KICKED						:kicked by server
 
############ End of leave-in-this-order
 
STR_NETWORK_CLIENT_JOINED					:has joined the game
 
STR_NETWORK_GIVE_MONEY						:gave you some money ({CURRENCY})
 
STR_NETWORK_SERVER_SHUTDOWN				:{WHITE} The server closed the session
 
STR_NETWORK_SERVER_REBOOT					:{WHITE} The server is restarting...{}Please wait...
 

	
 
############ end network gui strings
 

	
macros.h
Show inline comments
 
@@ -170,7 +170,6 @@ static inline int FindFirstBit2x64(int v
 

	
 

	
 
#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))
 

	
main_gui.c
Show inline comments
 
@@ -12,6 +12,13 @@
 
#include "vehicle.h"
 
#include "console.h"
 
#include "sound.h"
 
#include "network.h"
 

	
 
#ifdef ENABLE_NETWORK
 
#include "network_data.h"
 
#include "network_client.h"
 
#include "network_server.h"
 
#endif /* ENABLE_NETWORK */
 

	
 
#include "table/animcursors.h"
 

	
 
@@ -35,7 +42,19 @@ extern void GenerateWorld(int mode);
 
extern void GenerateIndustries();
 
extern void GenerateTowns();
 

	
 
static void HandleOnEditText(WindowEvent *e) {
 
extern uint GetCurrentCurrencyRate();
 

	
 
void HandleOnEditTextCancel() {
 
	switch(_rename_what) {
 
#ifdef ENABLE_NETWORK
 
	case 4:
 
		NetworkDisconnect();
 
		break;
 
#endif /* ENABLE_NETWORK */
 
	}
 
}
 

	
 
void HandleOnEditText(WindowEvent *e) {
 
	byte *b = e->edittext.str;
 
	int id;
 
	memcpy(_decode_parameters, b, 32);
 
@@ -52,6 +71,36 @@ static void HandleOnEditText(WindowEvent
 
			return;
 
		DoCommandP(0, id, 0, NULL, CMD_RENAME_WAYPOINT | CMD_MSG(STR_CANT_CHANGE_WAYPOINT_NAME));
 
		break;
 
#ifdef ENABLE_NETWORK
 
	case 2:
 
		// Speak to..
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT + (id & 0xFF), id & 0xFF, (id >> 8) & 0xFF, e->edittext.str);
 
		else
 
			NetworkServer_HandleChat(NETWORK_ACTION_CHAT + (id & 0xFF), id & 0xFF, (id >> 8) & 0xFF, e->edittext.str, NETWORK_SERVER_INDEX);
 
		break;
 
	case 3: {
 
		// Give money
 
		int32 money = atoi(e->edittext.str) / GetCurrentCurrencyRate();
 
		char msg[100];
 
		// Give 'id' the money, and substract it from ourself
 
		if (!DoCommandP(0, money, id, NULL, CMD_GIVE_MONEY)) break;
 

	
 
		// Inform the player of this action
 
		SetDParam(0, money);
 
		GetString(msg, STR_NETWORK_GIVE_MONEY);
 

	
 
		if (!_network_server)
 
			SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_PLAYER, id + 1, msg);
 
		else
 
			NetworkServer_HandleChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_PLAYER, id + 1, msg, NETWORK_SERVER_INDEX);
 
		break;
 
	}
 
	case 4: {// Game-Password and Company-Password
 
		SEND_COMMAND(PACKET_CLIENT_PASSWORD)(id, e->edittext.str);
 
		break;
 
	}
 
#endif /* ENABLE_NETWORK */
 
	}
 
}
 

	
 
@@ -88,9 +137,9 @@ typedef void ToolbarButtonProc(Window *w
 

	
 
static void ToolbarPauseClick(Window *w)
 
{
 
	if (_networking && !_networking_server) { return;} // only server can pause the game
 
	if (_networking && !_network_server) { return;} // only server can pause the game
 

	
 
	if (DoCommandP(0, _pause?0:1, 0, NULL, CMD_PAUSE | CMD_NET_INSTANT))
 
	if (DoCommandP(0, _pause?0:1, 0, NULL, CMD_PAUSE))
 
		SndPlayFx(SND_15_BEEP);
 
}
 

	
 
@@ -111,7 +160,7 @@ static void MenuClickSettings(int index)
 
	case 1: ShowGameDifficulty(); return;
 
	case 2: ShowPatchesSelection(); return;
 
	case 3: ShowNewgrf(); return;
 
	
 

	
 
	case 5: _display_opt ^= DO_SHOW_TOWN_NAMES; MarkWholeScreenDirty(); return;
 
	case 6: _display_opt ^= DO_SHOW_STATION_NAMES; MarkWholeScreenDirty(); return;
 
	case 7: _display_opt ^= DO_SHOW_SIGNS; MarkWholeScreenDirty(); return;
 
@@ -194,9 +243,20 @@ static void MenuClickFinances(int index)
 
	ShowPlayerFinances(index);
 
}
 

	
 
#ifdef ENABLE_NETWORK
 
extern void ShowClientList();
 
#endif /* ENABLE_NETWORK */
 

	
 
static void MenuClickCompany(int index)
 
{
 
	ShowPlayerCompany(index);
 
	if (_networking && index == 0) {
 
#ifdef ENABLE_NETWORK
 
		ShowClientList();
 
#endif /* ENABLE_NETWORK */
 
	} else {
 
		if (_networking) index--;
 
		ShowPlayerCompany(index);
 
	}
 
}
 

	
 

	
 
@@ -270,6 +330,37 @@ static void MenuClickBuildAir(int index)
 
	ShowBuildAirToolbar();
 
}
 

	
 
#ifdef ENABLE_NETWORK
 
void ShowNetworkChatQueryWindow(byte desttype, byte dest)
 
{
 
	_rename_id = desttype + (dest << 8);
 
	_rename_what = 2;
 
	ShowQueryString(STR_EMPTY, STR_NETWORK_CHAT_QUERY_CAPTION, 60, 250, 1, 0);
 
}
 

	
 
void ShowNetworkGiveMoneyWindow(byte player)
 
{
 
	_rename_id = player;
 
	_rename_what = 3;
 
	ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, 180, 1, 0);
 
}
 

	
 
void ShowNetworkNeedGamePassword()
 
{
 
	_rename_id = NETWORK_GAME_PASSWORD;
 
	_rename_what = 4;
 
	ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_GAME_PASSWORD_CAPTION, 20, 180, WC_SELECT_GAME, 0);
 
}
 

	
 
void ShowNetworkNeedCompanyPassword()
 
{
 
	_rename_id = NETWORK_COMPANY_PASSWORD;
 
	_rename_what = 4;
 
	ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, 20, 180, WC_SELECT_GAME, 0);
 
}
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
void ShowRenameSignWindow(SignStruct *ss)
 
{
 
	_rename_id = ss - _sign_list;
 
@@ -286,7 +377,7 @@ void ShowRenameWaypointWindow(Waypoint *
 
	ShowQueryString(STR_WAYPOINT_RAW, STR_EDIT_WAYPOINT_NAME, 30, 180, 1, 0);
 
}
 

	
 
static void CcPlaceSign(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcPlaceSign(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		ShowRenameSignWindow(_new_sign_struct);
 
@@ -483,6 +574,12 @@ static void UpdatePlayerMenuHeight(Windo
 
			num++;
 
	}
 

	
 
	// Increase one to fit in PlayerList in the menu when
 
	//  in network
 
	if (_networking && WP(w,menu_d).main_button == 9) {
 
		num++;
 
	}
 

	
 
	if (WP(w,menu_d).item_count != num) {
 
		WP(w,menu_d).item_count = num;
 
		SetWindowDirty(w);
 
@@ -493,6 +590,8 @@ static void UpdatePlayerMenuHeight(Windo
 
	}
 
}
 

	
 
extern void DrawPlayerIcon(int p, int x, int y);
 

	
 
static void PlayerMenuWndProc(Window *w, WindowEvent *e)
 
{
 
	switch(e->event) {
 
@@ -510,12 +609,23 @@ static void PlayerMenuWndProc(Window *w,
 
		sel = WP(w,menu_d).sel_index;
 
		chk = WP(w,menu_d).checked_items; // let this mean gray items.
 

	
 
		// 9 = playerlist
 
		if (_networking && WP(w,menu_d).main_button == 9) {
 
			if (sel == 0) {
 
				GfxFillRect(x, y, x + 238, y + 9, 0);
 
			}
 
			DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, 0x0);
 
			y += 10;
 
			sel--;
 
		}
 

	
 
		FOR_ALL_PLAYERS(p) {
 
			if (p->is_active) {
 
				if (p->index == sel) {
 
					GfxFillRect(x, y, x + 0xEE, y + 9, 0);
 
					GfxFillRect(x, y, x + 238, y + 9, 0);
 
				}
 
				DrawSprite( ((p->player_color + 0x307)<<16)+0x82EB, x+2, y+1);
 

	
 
				DrawPlayerIcon(p->index, x + 2, y + 1);
 

	
 
				SetDParam(0, p->name_1);
 
				SetDParam(1, p->name_2);
 
@@ -523,12 +633,13 @@ static void PlayerMenuWndProc(Window *w,
 

	
 
				color = (byte)((p->index==sel) ? 0xC : 0x10);
 
				if (chk&1) color = 14;
 
				DrawString(x+0x13, y, STR_7021, color);
 
				DrawString(x + 19, y, STR_7021, color);
 

	
 
				y += 10;
 
			}
 
			chk >>= 1;
 
		}
 

	
 
		break;
 
		}
 

	
 
@@ -540,9 +651,15 @@ static void PlayerMenuWndProc(Window *w,
 
		}
 

	
 
	case WE_POPUPMENU_SELECT: {
 
		int index = GetPlayerIndexFromMenu(GetMenuItemIndex(w, e->popupmenu.pt.x, e->popupmenu.pt.y));
 
		int index = GetMenuItemIndex(w, e->popupmenu.pt.x, e->popupmenu.pt.y);
 
		int action_id = WP(w,menu_d).action_id;
 

	
 
		// We have a new entry at the top of the list of menu 9 when networking
 
		//  so keep that in count
 
		if (!_networking || (WP(w,menu_d).main_button == 9 && index > 0)) {
 
			index = GetPlayerIndexFromMenu(index-1)+1;
 
		}
 

	
 
		if (index < 0) {
 
			Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
 
			if (GetWidgetFromPos(w2, e->popupmenu.pt.x - w2->left, e->popupmenu.pt.y - w2->top) == WP(w,menu_d).main_button)
 
@@ -560,7 +677,15 @@ static void PlayerMenuWndProc(Window *w,
 
	case WE_POPUPMENU_OVER: {
 
		int index;
 
		UpdatePlayerMenuHeight(w);
 
		index = GetPlayerIndexFromMenu(GetMenuItemIndex(w, e->popupmenu.pt.x, e->popupmenu.pt.y));
 
		index = GetMenuItemIndex(w, e->popupmenu.pt.x, e->popupmenu.pt.y);
 

	
 
		// We have a new entry at the top of the list of menu 9 when networking
 
		//  so keep that in count
 
		if (index != -1) {
 
			if (!_networking || (WP(w,menu_d).main_button == 9 && index != 0)) {
 
				index = GetPlayerIndexFromMenu(index-1)+1;
 
			}
 
		}
 

	
 
		if (index == -1 || index == WP(w,menu_d).sel_index)
 
			return;
 
@@ -612,7 +737,10 @@ static Window *PopupMainPlayerToolbMenu(
 
	w = AllocateWindow(x, 0x16, 0xF1, 0x52, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
 
	w->flags4 &= ~WF_WHITE_BORDER_MASK;
 
	WP(w,menu_d).item_count = 0;
 
	WP(w,menu_d).sel_index = _local_player != OWNER_SPECTATOR ? _local_player : 0;
 
	WP(w,menu_d).sel_index = (_local_player != OWNER_SPECTATOR) ? _local_player : 0;
 
	if (_networking && main_button == 9 && _local_player != OWNER_SPECTATOR) {
 
		WP(w,menu_d).sel_index++;
 
	}
 
	WP(w,menu_d).action_id = main_button;
 
	WP(w,menu_d).main_button = main_button;
 
	WP(w,menu_d).checked_items = gray;
 
@@ -988,7 +1116,7 @@ static void AskResetLandscape(uint mode)
 
	AllocateWindowDescFront(&_ask_reset_landscape_desc, mode);
 
}
 

	
 
static void CcTerraform(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcTerraform(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_1F_SPLAT, tile);
 
@@ -1000,7 +1128,7 @@ static void CcTerraform(bool success, ui
 
static void CommonRaiseLowerBigLand(uint tile, int mode)
 
{
 
	int size;
 
	uint h;
 
	byte h;
 

	
 
	_error_message_2 = mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
 

	
 
@@ -1049,7 +1177,7 @@ static void PlaceProc_LowerBigLand(uint 
 
	CommonRaiseLowerBigLand(tile, 0);
 
}
 

	
 
//static void CcDemolish(bool success, uint tile, uint32 p1, uint32 p2)
 
//void CcDemolish(bool success, uint tile, uint32 p1, uint32 p2)
 
//{
 
//	if (success) {
 
		//SndPlayTileFx(0x10, tile);
 
@@ -1257,7 +1385,7 @@ static void ToolbarScenGenLand(Window *w
 
	AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0);
 
}
 

	
 
static void CcBuildTown(bool success, uint tile, uint32 p1, uint32 p2)
 
void CcBuildTown(bool success, uint tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_1F_SPLAT, tile);
 
@@ -1713,7 +1841,7 @@ static void MainToolbarWndProc(Window *w
 
		case WKC_CTRL  | 'S': _make_screenshot = 1; break;
 
		case WKC_CTRL  | 'G': _make_screenshot = 2; break;
 
		case WKC_BACKQUOTE: IConsoleSwitch(); e->keypress.cont=false; break;
 
		case WKC_CTRL | WKC_ALT | 'C': if(!_networking) ShowCheatWindow(); break;
 
		case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
 
		}
 
	} break;
 

	
 
@@ -2201,6 +2329,12 @@ static void MainWindowWndProc(Window *w,
 
			MarkWholeScreenDirty();
 
			break;
 

	
 
#ifdef ENABLE_NETWORK
 
		case 'T' | WKC_SHIFT:
 
			ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
 
			break;
 
#endif /* ENABLE_NETWORK */
 

	
 
		default:
 
			return;
 
		}
 
@@ -2247,7 +2381,7 @@ void SetupColorsAndInitialWindow()
 

	
 
		if (_networking) { // if networking, disable fast-forward button
 
			w->disabled_state |= (1 << 1);
 
			if (!_networking_server) // if not server, disable pause button
 
			if (!_network_server) // if not server, disable pause button
 
				w->disabled_state |= (1 << 0);
 
		}
 

	
makefiledir/Makefile.libdetection
Show inline comments
 
# this file detects what OS and libs the computer have/are running
 
 
# Automatically recognize if building on Win32
 
ifdef WINDIR
 
ifndef UNIX
 
WIN32:=1
 
CYGWIN:=1
 
MINGW:=1
 
STATIC:=1
 
SKIP_STATIC_CHECK:=1
 
endif
 
else
 
UNIX:=1
 
endif
 
 
# Automatically recognize if building on FreeBSD
 
ifeq ($(shell uname),FreeBSD)
 
FREEBSD:=1
 
endif
 
 
# Automatically recognize if building on MacOSX
 
ifeq ($(VENDOR), apple)
 
OSX:=1
 
# OSX uses the unix setup too
 
UNIX:=1
 
endif
 
 
# Automatically recognize if building on MorphOS
 
ifeq ($(shell uname), MorphOS)
 
MORPHOS:=1
 
# MorphOS uses UNIX setup too
 
UNIX:=1
 
endif
 
 
# Automatically recognize if building on BeOS
 
ifeq ($(shell uname), BeOS)
 
BEOS:=1
 
# BeOS uses UNIX setup too
 
UNIX:=1
 
# Except that in BeOS 5.0 we need to use net_server, not BONE networking
 
ifeq ($(shell uname -r), 5.0)
 
BEOS_NET_SERVER:=1
 
endif
 
endif
 
 
# Automatically recognize if building on SunOS/Solaris
 
ifeq ($(shell uname), SunOS)
 
SUNOS:=1
 
# SunOS uses UNIX setup too
 
UNIX:=1
 
endif
 
 
# FreeBSD uses sdl11 instead of sdl
 
ifdef FREEBSD
 
SDL-CONFIG:=sdl11-config
 
else
 
SDL-CONFIG:=sdl-config
 
endif
 
 
 
# Library detections
 
WITH_SDL:=$(shell $(SDL-CONFIG) --version 2>/dev/null)
 
 
# libpng detection
 
ifdef FREEBSD
 
# a little hack was needed for FreeBSD because it misses libpng-config
 
WITH_PNG:=$(shell ls /usr/lib | grep "libpng" 2>/dev/null) $(shell \
 
ls /usr/local/lib | grep "libpng" 2>/dev/null)
 
ifdef WITH_PNG
 
# makes the flag look nicer in makefile.config
 
WITH_PNG:=1
 
endif
 
else
 
WITH_PNG:=$(shell libpng-config --version 2>/dev/null)
 
endif
 
 
ifdef WITH_PNG
 
# LibPNG depends on Zlib
 
WITH_ZLIB:=1
 
else
 
# We go looking for zlib with a little hack
 
WITH_ZLIB:=$(shell ls /usr/include | grep "zlib.h" 2>/dev/null) \
 
$(shell ls /usr/local/include | grep "zlib.h" 2>/dev/null)
 
ifdef WITH_ZLIB
 
WITH_ZLIB:=1
 
endif
 
endif
 
 
 
# sets the default paths
 
ifdef UNIX
 
ifndef OSX
 
ifndef MORPHOS
 
ifndef BIN_DIR
 
#BINARY_DIR:=
 
#DATA_DIR_PREFIX:=
 
#INSTALL_DIR:=/usr/local/
 
#USE_HOMEDIR:=
 
endif
 
endif
 
endif
 
endif
 
 
# workaround
 
# cygwin have problems with libpng, so we will just disable it for now until the problem is solved
 
ifdef CYGWIN
 
WITH_PNG:=
 
endif
 
\ No newline at end of file
 
# this file detects what OS and libs the computer have/are running
 

	
 
# Automatically recognize if building on Win32
 
ifdef WINDIR
 
ifndef UNIX
 
WIN32:=1
 
CYGWIN:=1
 
MINGW:=1
 
STATIC:=1
 
SKIP_STATIC_CHECK:=1
 
endif
 
else
 
UNIX:=1
 
endif
 

	
 
# Automatically recognize if building on FreeBSD
 
ifeq ($(shell uname),FreeBSD)
 
FREEBSD:=1
 
endif
 

	
 
# Automatically recognize if building on MacOSX
 
ifeq ($(VENDOR), apple)
 
OSX:=1
 
# OSX uses the unix setup too
 
UNIX:=1
 
endif
 

	
 
# Automatically recognize if building on MorphOS
 
ifeq ($(shell uname), MorphOS)
 
MORPHOS:=1
 
# MorphOS uses UNIX setup too
 
UNIX:=1
 
endif
 

	
 
# Automatically recognize if building on BeOS
 
ifeq ($(shell uname), BeOS)
 
BEOS:=1
 
# BeOS uses UNIX setup too
 
UNIX:=1
 
# Except that in BeOS 5.0 we need to use net_server, not BONE networking
 
ifeq ($(shell uname -r), 5.0)
 
BEOS_NET_SERVER:=1
 
endif
 
endif
 

	
 
# Automatically recognize if building on SunOS/Solaris
 
ifeq ($(shell uname), SunOS)
 
SUNOS:=1
 
# SunOS uses UNIX setup too
 
UNIX:=1
 
endif
 

	
 
# FreeBSD uses sdl11 instead of sdl
 
ifdef FREEBSD
 
SDL-CONFIG:=sdl11-config
 
else
 
SDL-CONFIG:=sdl-config
 
endif
 

	
 
# Networking, enabled by default
 
WITH_NETWORK:=1
 

	
 
# Library detections
 
WITH_SDL:=$(shell $(SDL-CONFIG) --version 2>/dev/null)
 

	
 
# libpng detection
 
ifdef FREEBSD
 
# a little hack was needed for FreeBSD because it misses libpng-config
 
WITH_PNG:=$(shell ls /usr/lib | grep "libpng" 2>/dev/null) $(shell \
 
ls /usr/local/lib | grep "libpng" 2>/dev/null)
 
ifdef WITH_PNG
 
# makes the flag look nicer in makefile.config
 
WITH_PNG:=1
 
endif
 
else
 
WITH_PNG:=$(shell libpng-config --version 2>/dev/null)
 
endif
 

	
 
ifdef WITH_PNG
 
# LibPNG depends on Zlib
 
WITH_ZLIB:=1
 
else
 
# We go looking for zlib with a little hack
 
WITH_ZLIB:=$(shell ls /usr/include | grep "zlib.h" 2>/dev/null) \
 
$(shell ls /usr/local/include | grep "zlib.h" 2>/dev/null)
 
ifdef WITH_ZLIB
 
WITH_ZLIB:=1
 
endif
 
endif
 

	
 

	
 
# sets the default paths
 
ifdef UNIX
 
ifndef OSX
 
ifndef MORPHOS
 
ifndef BIN_DIR
 
#BINARY_DIR:=
 
#DATA_DIR_PREFIX:=
 
#INSTALL_DIR:=/usr/local/
 
#USE_HOMEDIR:=
 
endif
 
endif
 
endif
 
endif
 

	
 
# workaround
 
# cygwin have problems with libpng, so we will just disable it for now until the problem is solved
 
ifdef CYGWIN
 
WITH_PNG:=
 
endif
misc.c
Show inline comments
 
@@ -5,6 +5,7 @@
 
#include "gfx.h"
 
#include "assert.h"
 
#include "saveload.h"
 
#include "network.h"
 

	
 
extern void StartupEconomy();
 
extern void InitNewsItemStructs();
 
@@ -16,21 +17,24 @@ static inline uint32 ROR(uint32 x, int n
 
	return (x >> n) + (x << ((sizeof(x)*8)-n));
 
}
 

	
 
// For multiplayer, we introduced this new way of random-seeds
 
//  It is player-based, so 2 clients can do 2 commands at the same time
 
//  without the game desyncing.
 
// It is not used for non-multiplayer games
 
#ifdef ENABLE_NETWORK
 
	#define PLAYER_SEED_RANDOM
 
/* XXX - Player-seeds don't seem to be used anymore.. which is a good thing
 
     so I just disabled them for now. If there are no problems, we can remove
 
     it completely! -- TrueLight */
 
#undef PLAYER_SEED_RANDOM
 

	
 
#ifdef RANDOM_DEBUG
 
#include "network_data.h"
 

	
 
uint32 DoRandom(uint line, char *file)
 
#else
 
	#undef PLAYER_SEED_RANDOM
 
uint32 Random()
 
#endif
 
{
 
#ifdef RANDOM_DEBUG
 
	if (_networking && (DEREF_CLIENT(0)->status != STATUS_INACTIVE || !_network_server))
 
		printf("Random [%d/%d] %s:%d\n",_frame_counter, _current_player, file, line);
 
#endif
 

	
 
// its for now not used at all because it is still desyncing :(
 
#undef PLAYER_SEED_RANDOM
 

	
 
uint32 Random()
 
{
 
#ifdef PLAYER_SEED_RANDOM
 
	if (_current_player>=MAX_PLAYERS || !_networking) {
 
		uint32 s = _random_seeds[0][0];
 
@@ -41,6 +45,7 @@ uint32 Random()
 
		uint32 s = _player_seeds[_current_player][0];
 
		uint32 t = _player_seeds[_current_player][1];
 
		_player_seeds[_current_player][0] = s + ROR(t ^ 0x1234567F, 7);
 
		DEBUG(net, 1)("[NET-Seeds] Player seed called!");
 
		return _player_seeds[_current_player][1] = ROR(s, 3);
 
	}
 
#else
 
@@ -51,10 +56,17 @@ uint32 Random()
 
#endif
 
}
 

	
 
#ifdef RANDOM_DEBUG
 
uint DoRandomRange(uint max, uint line, char *file)
 
{
 
	return (uint16)DoRandom(line, file) * max >> 16;
 
}
 
#else
 
uint RandomRange(uint max)
 
{
 
	return (uint16)Random() * max >> 16;
 
}
 
#endif
 

	
 
uint32 InteractiveRandom()
 
{
 
@@ -75,7 +87,7 @@ void InitPlayerRandoms()
 
	for (i=0; i<MAX_PLAYERS; i++) {
 
		_player_seeds[i][0]=InteractiveRandom();
 
		_player_seeds[i][1]=InteractiveRandom();
 
		}
 
	}
 
}
 

	
 
void SetDate(uint date)
 
@@ -86,6 +98,51 @@ void SetDate(uint date)
 
	_cur_month = ymd.month;
 
}
 

	
 

	
 
// multi os compatible sleep function
 

	
 
#if defined(__AMIGA__)
 
// usleep() implementation
 
#	include <devices/timer.h>
 
#	include <dos/dos.h>
 

	
 
	static struct Device      *TimerBase    = NULL;
 
	static struct MsgPort     *TimerPort    = NULL;
 
	static struct timerequest *TimerRequest = NULL;
 
#endif // __AMIGA__
 

	
 
void CSleep(int milliseconds)
 
{
 
	#if defined(WIN32)
 
		Sleep(milliseconds);
 
	#endif
 
	#if defined(UNIX)
 
		#if !defined(__BEOS__) && !defined(__AMIGAOS__)
 
			usleep(milliseconds * 1000);
 
		#endif
 
		#ifdef __BEOS__
 
			snooze(milliseconds * 1000);
 
		#endif
 
		#if defined(__AMIGAOS__) && !defined(__MORPHOS__)
 
		{
 
			ULONG signals;
 
			ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
 

	
 
			// send IORequest
 
			TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
 
			TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
 
			TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
 
			SendIO((struct IORequest *)TimerRequest);
 

	
 
			if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
 
				AbortIO((struct IORequest *)TimerRequest);
 
			}
 
			WaitIO((struct IORequest *)TimerRequest);
 
		}
 
		#endif // __AMIGAOS__ && !__MORPHOS__
 
	#endif
 
}
 

	
 
void InitializeClearLand();
 
void InitializeRail();
 
void InitializeRailGui();
 
@@ -160,6 +217,7 @@ void InitializeGame()
 
	InitializeCheats();
 

	
 
	InitTextEffects();
 
	InitTextMessage();
 
	InitializeAnimatedTiles();
 

	
 
	InitializeLandscapeVariables(false);
 
@@ -171,6 +229,9 @@ void GenerateWorld(int mode)
 
{
 
	int i;
 

	
 
	// Make sure everything is done via OWNER_NONE
 
	_current_player = OWNER_NONE;
 

	
 
	_generating_world = true;
 
	InitializeGame();
 
	SetObjectToPlace(1, 0, 0, 0);
 
@@ -252,7 +313,7 @@ static void InitializeNameMgr()
 
	memset(_name_array, 0, sizeof(_name_array));
 
}
 

	
 
StringID AllocateName(const byte *name, byte skip)
 
StringID RealAllocateName(const byte *name, byte skip, bool check_double)
 
{
 
	int free_item = -1;
 
	const byte *names;
 
@@ -266,7 +327,7 @@ StringID AllocateName(const byte *name, 
 
			if (free_item == -1)
 
				free_item = i;
 
		} else {
 
			if (str_eq(names, name)) {
 
			if (check_double && str_eq(names, name)) {
 
				_error_message = STR_0132_CHOSEN_NAME_IN_USE_ALREADY;
 
				return 0;
 
			}
 
@@ -575,9 +636,9 @@ void IncreaseDate()
 
	/* yeah, increse day counter and call various daily loops */
 
	_date++;
 

	
 
	NetworkGameChangeDate(_date);
 
	_vehicle_id_ctr_day = 0;
 

	
 
	_vehicle_id_ctr_day = 0;
 
	TextMessageDailyLoop();
 

	
 
	DisasterDailyLoop();
 
	WaypointsDailyLoop();
 
@@ -593,8 +654,6 @@ void IncreaseDate()
 
		return;
 
	_cur_month = ymd.month;
 

	
 
//	printf("Month %d, %X\n", ymd.month, _random_seeds[0][0]);
 

	
 
	/* yes, call various monthly loops */
 
	if (_game_mode != GM_MENU) {
 
		if (HASBIT(_autosave_months[_opt.autosave], _cur_month)) {
misc_cmd.c
Show inline comments
 
@@ -8,6 +8,7 @@
 
#include "window.h"
 
#include "saveload.h"
 
#include "economy.h"
 
#include "network.h"
 

	
 
/* p1 = player
 
   p2 = face
 
@@ -124,7 +125,7 @@ int32 CmdChangeCompanyName(int x, int y,
 
	StringID str,old_str;
 
	Player *p;
 

	
 
	str = AllocateName((byte*)_decode_parameters, 4);
 
	str = AllocateNameUnique((byte*)_decode_parameters, 4);
 
	if (str == 0)
 
		return CMD_ERROR;
 

	
 
@@ -146,7 +147,7 @@ int32 CmdChangePresidentName(int x, int 
 
	StringID str,old_str;
 
	Player *p;
 

	
 
	str = AllocateName((byte*)_decode_parameters, 4);
 
	str = AllocateNameUnique((byte*)_decode_parameters, 4);
 
	if (str == 0)
 
		return CMD_ERROR;
 

	
 
@@ -228,7 +229,7 @@ int32 CmdRenameSign(int x, int y, uint32
 
	SignStruct *ss;
 

	
 
	if (_decode_parameters[0] != 0 && !p2) {
 
		str = AllocateName((byte*)_decode_parameters, 0);
 
		str = AllocateNameUnique((byte*)_decode_parameters, 0);
 
		if (str == 0)
 
			return CMD_ERROR;
 

	
 
@@ -280,6 +281,22 @@ int32 CmdMoneyCheat(int x, int y, uint32
 
	return (int32)p1;
 
}
 

	
 
int32 CmdGiveMoney(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 

	
 
	if (flags & DC_EXEC) {
 
		// Add money to player
 
		byte old_cp = _current_player;
 
		_current_player = p2;
 
		SubtractMoneyFromPlayer(-(int32)p1);
 
		_current_player = old_cp;
 
	}
 

	
 
	// Subtract money from local-player
 
	return (int32)p1;
 
}
 

	
 
int32 CmdChangeDifficultyLevel(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	if (flags & DC_EXEC) {
 
@@ -289,6 +306,9 @@ int32 CmdChangeDifficultyLevel(int x, in
 
		} else {
 
			_opt_mod_ptr->diff_level = p2;
 
		}
 
		// If we are a network-client, update the difficult setting (if it is open)
 
		if (_networking && !_network_server && FindWindowById(WC_GAME_OPTIONS, 0) != NULL)
 
			memcpy(&_opt_mod_temp, _opt_mod_ptr, sizeof(GameOptions));
 
		InvalidateWindow(WC_GAME_OPTIONS, 0);
 
	}
 
	return 0;
misc_gui.c
Show inline comments
 
@@ -10,11 +10,12 @@
 
#include "player.h"
 
#include "town.h"
 
#include "sound.h"
 
#include "network.h"
 

	
 
#include "hal.h" // Fios items
 
#include "hal.h" // for file list
 

	
 
bool _query_string_active;
 
static void SetFiosType(const byte fiostype);
 
void SetFiosType(const byte fiostype);
 

	
 
typedef struct LandInfoData {
 
	Town *town;
 
@@ -24,7 +25,6 @@ typedef struct LandInfoData {
 
	TileDesc td;
 
} LandInfoData;
 

	
 

	
 
static void LandInfoWndProc(Window *w, WindowEvent *e)
 
{
 
	LandInfoData *lid;
 
@@ -764,6 +764,7 @@ void DrawEditBox(Window *w, int wid)
 

	
 
static void QueryStringWndProc(Window *w, WindowEvent *e)
 
{
 
	static bool closed = false;
 
	switch(e->event) {
 
	case WE_PAINT: {
 
//		int x;
 
@@ -779,7 +780,7 @@ static void QueryStringWndProc(Window *w
 
		case 3: DeleteWindow(w); break;
 
		case 4:
 
press_ok:;
 
			if (str_eq(WP(w,querystr_d).buf, WP(w,querystr_d).buf + MAX_QUERYSTR_LEN)) {
 
			if (str_eq(WP(w,querystr_d).buf, WP(w,querystr_d).buf + MAX_QUERYSTR_LEN) && (WP(w,querystr_d).maxlen & 0x1000) == 0) {
 
				DeleteWindow(w);
 
			} else {
 
				byte *buf = WP(w,querystr_d).buf;
 
@@ -788,6 +789,10 @@ press_ok:;
 
				Window *parent;
 

	
 
				DeleteWindow(w);
 

	
 
				// Mask the edit-box as closed, so we don't send out a CANCEL
 
				closed = true;
 

	
 
				parent = FindWindowById(wnd_class, wnd_num);
 
				if (parent != NULL) {
 
					WindowEvent e;
 
@@ -818,7 +823,20 @@ press_ok:;
 
		}
 
	} break;
 

	
 
	case WE_CREATE:
 
		closed = false;
 
		break;
 

	
 
	case WE_DESTROY:
 
		// If the window is not closed yet, it means it still needs to send a CANCEL
 
		if (!closed) {
 
			Window *parent = FindWindowById(WP(w,querystr_d).wnd_class, WP(w,querystr_d).wnd_num);
 
			if (parent != NULL) {
 
				WindowEvent e;
 
				e.event = WE_ON_EDIT_TEXT_CANCEL;
 
				parent->wndproc(parent, &e);
 
			}
 
		}
 
		_query_string_active = false;
 
		break;
 
	}
 
@@ -933,11 +951,7 @@ static const Widget _save_dialog_scen_wi
 
};
 

	
 

	
 
static FiosItem *_fios_list;
 
static int _fios_num;
 
static int _saveload_mode;
 

	
 
static void BuildFileList()
 
void BuildFileList()
 
{
 
	FiosFreeSavegameList();
 
	if(_saveload_mode==SLD_NEW_GAME || _saveload_mode==SLD_LOAD_SCENARIO || _saveload_mode==SLD_SAVE_SCENARIO)
 
@@ -957,9 +971,6 @@ static void DrawFiosTexts()
 
	DoDrawString(path, 2, 27, 16);
 
}
 

	
 
/*	FIOS_TYPE_FILE, FIOS_TYPE_OLDFILE etc. different colours */
 
static const byte _fios_colors[] = {13, 9, 9, 6, 5, 6, 5};
 

	
 
#if defined(_WIN32)
 
	extern int CDECL compare_FiosItems (const void *a, const void *b);
 
#else
 
@@ -1185,7 +1196,7 @@ void ShowSaveLoadDialog(int mode)
 
	}
 

	
 
	// pause is only used in single-player, non-editor mode
 
	if(_game_mode != GM_MENU && !_networking && (_game_mode != GM_EDITOR))
 
	if(_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR)
 
		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 

	
 
	BuildFileList();
 
@@ -1282,7 +1293,7 @@ static void SelectScenarioWndProc(Window
 
	}
 
}
 

	
 
static void SetFiosType(const byte fiostype)
 
void SetFiosType(const byte fiostype)
 
{
 
	switch (fiostype) {
 
	case FIOS_TYPE_FILE: case FIOS_TYPE_SCENARIO:
network.c
Show inline comments
 
#include "stdafx.h"
 
#include "ttd.h"
 
#include "network_data.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "gui.h"
 
#include "command.h"
 
#include "player.h"
 
#include "console.h"
 
#include "economy.h"
 

	
 
#if defined(WIN32)
 
#	include <windows.h>
 
#	include <winsock.h>
 
#include "network_client.h"
 
#include "network_server.h"
 
#include "network_udp.h"
 
#include "network_gamelist.h"
 
#include "console.h" /* IConsoleCmdExec */
 
#include <stdarg.h> /* va_list */
 

	
 
# pragma comment (lib, "ws2_32.lib")
 
# define ENABLE_NETWORK
 
# define GET_LAST_ERROR() WSAGetLastError()
 
# define EWOULDBLOCK WSAEWOULDBLOCK
 
#endif
 
// The listen socket for the server
 
static SOCKET _listensocket;
 

	
 
// Network copy of patches, so the patches of a client are not fucked up
 
//  after he joined a server
 
static Patches network_tmp_patches;
 

	
 
#if defined(UNIX)
 
// Make compatible with WIN32 names
 
#	define SOCKET int
 
#	define INVALID_SOCKET -1
 
// we need different defines for MorphOS and AmigaOS
 
#if !defined(__MORPHOS__) && !defined(__AMIGA__)
 
#	define ioctlsocket ioctl
 
# define closesocket close
 
# define GET_LAST_ERROR() errno
 
#endif
 
// Need this for FIONREAD on solaris
 
#	define BSD_COMP
 
#	include <unistd.h>
 
#	include <sys/ioctl.h>
 
// 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;
 

	
 
// Function that looks up the CI for a given client-index
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
 
{
 
	NetworkClientInfo *ci;
 

	
 
// Socket stuff
 
#	include <sys/socket.h>
 
#	include <netinet/in.h>
 
#	include <arpa/inet.h>
 
# 	include <errno.h>
 
# 	include <sys/time.h>
 
// NetDB
 
#   include <netdb.h>
 
	for (ci = _network_client_info; ci != &_network_client_info[MAX_CLIENT_INFO]; ci++)
 
		if (ci->client_index == client_index)
 
			return ci;
 

	
 
# ifndef TCP_NODELAY
 
#  define TCP_NODELAY 0x0001
 
# endif
 
	return NULL;
 
}
 

	
 
#endif
 

	
 
// Function that looks up the CS for a given client-index
 
ClientState *NetworkFindClientStateFromIndex(uint16 client_index)
 
{
 
	ClientState *cs;
 

	
 
#if defined(__MORPHOS__) || defined(__AMIGA__)
 
#	include <exec/types.h>
 
#	include <proto/exec.h> 		// required for Open/CloseLibrary()
 
#	if defined(__MORPHOS__)
 
#		include <sys/filio.h> 	// FION#? defines
 
#	else // __AMIGA__
 
#		include	<proto/socket.h>
 
#	endif
 
	for (cs = _clients; cs != &_clients[MAX_CLIENT_INFO]; cs++)
 
		if (cs->index == client_index)
 
			return cs;
 

	
 
// make source compatible with bsdsocket.library functions
 
# define closesocket(s)     						CloseSocket(s)
 
# define GET_LAST_ERROR() 							Errno()
 
#	define ioctlsocket(s,request,status)  IoctlSocket((LONG)s,(ULONG)request,(char*)status)
 

	
 
struct Library *SocketBase = NULL;
 
	return NULL;
 
}
 

	
 
#if !defined(__MORPHOS__)
 
// usleep() implementation
 
#include <devices/timer.h>
 
#include <dos/dos.h>
 

	
 
struct Device       *TimerBase    = NULL;
 
struct MsgPort      *TimerPort    = NULL;
 
struct timerequest  *TimerRequest = NULL;
 
#endif
 

	
 
#endif /* __MORPHOS__ || __AMIGA__ */
 

	
 

	
 
#define SEND_MTU 1460
 

	
 
#if defined(ENABLE_NETWORK)
 
// NetworkGetClientName is a server-safe function to get the name of the client
 
//  if the user did not send it yet, Client #<no> is used.
 
void NetworkGetClientName(char *client_name, size_t size, ClientState *cs)
 
{
 
	NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
	if (ci->client_name[0] == '\0')
 
		snprintf(client_name, size, "Client #%d", cs->index);
 
	else
 
		snprintf(client_name, size, "%s", ci->client_name);
 
}
 

	
 
enum {
 
	PACKET_TYPE_WELCOME = 0,
 
	PACKET_TYPE_READY,
 
	PACKET_TYPE_ACK,
 
	PACKET_TYPE_SYNC,
 
	PACKET_TYPE_FSYNC,
 
	PACKET_TYPE_XMIT,
 
	PACKET_TYPE_COMMAND,
 
	PACKET_TYPE_EVENT,
 
};
 

	
 
// sent from client -> server whenever the client wants to exec a command.
 
// send from server -> client when another player execs a command.
 
typedef struct CommandPacket {
 
	byte packet_length;
 
	byte packet_type;
 
	uint16 cmd;
 
	uint32 p1,p2;
 
	TileIndex tile;
 
	byte player;// player id, this is checked by the server.
 
	byte when;  // offset from the current max_frame value minus 1. this is set by the server.
 
	uint32 dp[8];
 
} CommandPacket;
 
// This puts a text-message to the console, or in the future, the chat-box,
 
//  (to keep it all a bit more general)
 
void NetworkTextMessage(NetworkAction action, uint16 color, const char *name, const char *str, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 
	const int duration = 10; // Game days the messages stay visible
 

	
 
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
 
// and how far the client may progress.
 
typedef struct SyncPacket {
 
	byte packet_length;
 
	byte packet_type;
 
	byte frames; // how many more frames may the client execute? this is relative to the old value of max.
 
	byte server; // where is the server currently executing? this is negatively relative to the old value of max.
 
	uint32 random_seed_1; // current random state at server. used to detect out of sync.
 
	uint32 random_seed_2;
 
} SyncPacket;
 

	
 
typedef struct FrameSyncPacket {
 
	byte packet_length;
 
	byte packet_type;
 
	byte frames; // where is the server currently executing? this is negatively relative to the old value of max.
 
} FrameSyncPacket;
 
	va_start(va, str);
 
	vsprintf(buf, str, va);
 
	va_end(va);
 

	
 
// sent from server -> client as an acknowledgement that the server received the command.
 
// the command will be executed at the current value of "max".
 
typedef struct AckPacket {
 
	byte packet_length;
 
	byte packet_type;
 
	int16 when;
 
} AckPacket;
 

	
 
typedef struct ReadyPacket {
 
	byte packet_length;
 
	byte packet_type;
 
} ReadyPacket;
 

	
 
typedef struct FilePacketHdr {
 
	byte packet_length;
 
	byte packet_type;
 
} FilePacketHdr;
 
	switch (action) {
 
		case NETWORK_ACTION_JOIN_LEAVE:
 
			IConsolePrintF(color, "*** %s %s", name, buf);
 
			AddTextMessage(color, duration, "*** %s %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_GIVE_MONEY:
 
			IConsolePrintF(color, "*** %s %s", name, buf);
 
			AddTextMessage(color, duration, "*** %s %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_PLAYER:
 
			IConsolePrintF(color, "[Team] %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Team] %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_CLIENT:
 
			IConsolePrintF(color, "[Private] %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Private] %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_TO_CLIENT:
 
			IConsolePrintF(color, "[Private] To %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Private] To %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_TO_PLAYER:
 
			IConsolePrintF(color, "[Team] To %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Team] To %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_NAME_CHANGE:
 
			IConsolePrintF(color, "*** %s changed his name to %s", name, buf);
 
			AddTextMessage(color, duration, "*** %s changed his name to %s", name, buf);
 
			break;
 
		default:
 
			IConsolePrintF(color, "[All] %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[All] %s: %s", name, buf);
 
			break;
 
	}
 
}
 

	
 
// sent from server to client when the client has joined.
 
typedef struct WelcomePacket {
 
	byte packet_length;
 
	byte packet_type;
 
	uint32 player_seeds[MAX_PLAYERS][2];
 
	uint32 frames_max;
 
	uint32 frames_srv;
 
	uint32 frames_cnt;
 
} WelcomePacket;
 
// Calculate the frame-lag of a client
 
uint NetworkCalculateLag(const ClientState *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);
 

	
 
typedef struct Packet Packet;
 
struct Packet {
 
	Packet *next; // this one has to be the first element.
 
	uint siz;
 
	byte buf[SEND_MTU]; // packet payload
 
};
 

	
 
typedef struct ClientState {
 
	int socket;
 
	bool inactive; // disable sending of commands/syncs to client
 
	bool writable;
 
	bool ready;
 
	uint timeout;
 
	uint xmitpos;
 

	
 
	uint eaten;
 
	Packet *head, **last;
 

	
 
	uint buflen;											// receive buffer len
 
	byte buf[1024];										// receive buffer
 
} ClientState;
 
	return lag;
 
}
 

	
 

	
 
typedef struct QueuedCommand QueuedCommand;
 
struct QueuedCommand {
 
	QueuedCommand *next;
 
	CommandPacket cp;
 
	CommandCallback *callback;
 
	uint32 cmd;
 
	uint32 frame;
 
};
 

	
 
typedef struct CommandQueue CommandQueue;
 
struct CommandQueue {
 
	QueuedCommand *head, **last;
 
};
 

	
 
#define MAX_CLIENTS (MAX_PLAYERS + 1)
 

	
 
// packets waiting to be executed, for each of the players.
 
// this list is sorted in frame order, so the item on the front will be executed first.
 
static CommandQueue _command_queue;
 

	
 
// in the client, this is the list of commands that have not yet been acked.
 
// when it is acked, it will be moved to the appropriate position at the end of the player queue.
 
static CommandQueue _ack_queue;
 
// There was a non-recoverable error, drop back to the main menu with a nice
 
//  error
 
void NetworkError(StringID error_string)
 
{
 
	_switch_mode = SM_MENU;
 
	_switch_mode_errorstr = error_string;
 
}
 

	
 
static ClientState _clients[MAX_CLIENTS];
 
static int _num_clients;
 

	
 
// keep a history of the 16 most recent seeds to be able to capture out of sync errors.
 
static uint32 _my_seed_list[16][2];
 
static bool _network_ready_sent;
 
static uint32 _frame_fsync_last;
 

	
 
typedef struct FutureSeeds {
 
	uint32 frame;
 
	uint32 seed[2];
 
} FutureSeeds;
 
void ClientStartError(char *error) {
 
	DEBUG(net, 0)("[NET] Client could not start network: %s",error);
 
	NetworkError(STR_NETWORK_ERR_CLIENT_START);
 
}
 

	
 
// remember some future seeds that the server sent to us.
 
static FutureSeeds _future_seed[8];
 
static uint _num_future_seed;
 

	
 
static SOCKET _listensocket; // tcp socket
 
void ServerStartError(char *error) {
 
	DEBUG(net, 0)("[NET] Server could not start network: %s",error);
 
	NetworkError(STR_NETWORK_ERR_SERVER_START);
 
}
 

	
 
static SOCKET _udp_client_socket; // udp server socket
 
static SOCKET _udp_server_socket; // udp client socket
 

	
 
typedef struct UDPPacket {
 
	byte command_code;
 
	byte data_len;
 
	byte command_check;
 
	byte data[255];
 
} UDPPacket;
 
void NetworkClientError(byte res, ClientState *cs) {
 
	// First, send a CLIENT_ERROR to the server, so he knows we are
 
	//  disconnection (and why!)
 
	NetworkErrorCode errorno;
 

	
 
enum {
 
	NET_UDPCMD_SERVERSEARCH = 1,
 
	NET_UDPCMD_SERVERACTIVE,
 
	NET_UDPCMD_GETSERVERINFO,
 
	NET_UDPCMD_SERVERINFO,
 
};
 
	// We just want to close the connection..
 
	if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
 
		cs->quited = true;
 
		CloseClient(cs);
 
		_networking = false;
 

	
 
void NetworkUDPSend(bool client, struct sockaddr_in recv,struct UDPPacket packet);
 
static void HandleCommandPacket(ClientState *cs, CommandPacket *np);
 
static void CloseClient(ClientState *cs);
 
void NetworkSendWelcome(ClientState *cs, bool direct);
 

	
 
uint32 _network_ip_list[10]; // network ip list
 

	
 
// this is set to point to the savegame
 
static byte *_transmit_file;
 
static size_t _transmit_file_size;
 

	
 
static FILE *_recv_file;
 
		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 
		return;
 
	}
 

	
 
/* multi os compatible sleep function */
 
void CSleep(int milliseconds) {
 
#if defined(WIN32)
 
Sleep(milliseconds);
 
#endif
 
#if defined(UNIX)
 
#if !defined(__BEOS__) && !defined(__MORPHOS__) && !defined(__AMIGAOS__)
 
usleep(milliseconds*1000);
 
#endif
 
#ifdef __BEOS__
 
snooze(milliseconds*1000);
 
#endif
 
#if defined(__MORPHOS__)
 
usleep(milliseconds*1000);
 
#endif
 
#if defined(__AMIGAOS__) && !defined(__MORPHOS__)
 
{
 
	ULONG signals;
 
	ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
 
	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;
 
	}
 
	// This means we fucked up and the server closed the connection
 
	if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL) {
 
		SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
 

	
 
	// send IORequest
 
	TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
 
	TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
 
	TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
 
	SendIO((struct IORequest *)TimerRequest);
 
		// Dequeue all commands before closing the socket
 
		NetworkSend_Packets(DEREF_CLIENT(0));
 
	}
 

	
 
	if ( !((signals = Wait(TimerSigBit|SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
 
		AbortIO((struct IORequest *)TimerRequest);
 
	}
 
	WaitIO((struct IORequest *)TimerRequest);
 
}
 
#endif // __AMIGAOS__ && !__MORPHOS__
 
#endif
 
	_switch_mode = SM_MENU;
 
	CloseClient(cs);
 
	_networking = false;
 
}
 

	
 
//////////////////////////////////////////////////////////////////////
 

	
 
// ****************************** //
 
// * Network Error Handlers     * //
 
// ****************************** //
 

	
 
static void NetworkHandleSaveGameError()
 
{
 
		_networking_sync = false;
 
		_networking_queuing = true;
 
		_switch_mode = SM_MENU;
 
		_switch_mode_errorstr = STR_NETWORK_ERR_SAVEGAMEERROR;
 
}
 

	
 
static void NetworkHandleConnectionLost()
 
{
 
		_networking_sync = false;
 
		_networking_queuing = true;
 
		_switch_mode = SM_MENU;
 
		_switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
 
}
 

	
 
static void NetworkHandleDeSync()
 
// Find all IP-aliases for this host
 
void NetworkFindIPs(void)
 
{
 
	DEBUG(net, 0) ("NET: error: network sync error at frame %i", _frame_counter);
 
	{
 
		int i;
 
		for (i=15; i>=0; i--) DEBUG(net,0) ("NET frame %i: [0]=%i, [1]=%i",_frame_counter-(i+1),_my_seed_list[i][0],_my_seed_list[i][1]);
 
		for (i=0; i<8; i++) DEBUG(net,0) ("NET frame %i: [0]=%i, [1]=%i",_frame_counter+i,_future_seed[i].seed[0],_future_seed[i].seed[1]);
 
	int i, last;
 

	
 
#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
 
	_network_ip_list[0] = 0;
 

	
 
	if (sock < 0) {
 
		DEBUG(net, 0)("Error creating socket!");
 
		return;
 
	}
 

	
 
	output_length = _netstat(sock, &output_pointer, 1);
 
	if (output_length < 0) {
 
		DEBUG(net, 0)("Error running _netstat!");
 
		return;
 
	}
 
	_networking_sync = false;
 
	_networking_queuing = true;
 
	_switch_mode = SM_MENU;
 
	_switch_mode_errorstr = STR_NETWORK_ERR_DESYNC;
 
}
 

	
 
	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;
 
			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;
 
			}
 
			inaddr.s_addr = htonl((uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4);
 
			if (inaddr.s_addr != 0) {
 
				_network_ip_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
 
	_network_ip_list[0] = 0;
 

	
 
	if (getifaddrs(&ifap) != 0)
 
		return;
 

	
 
// ****************************** //
 
// * TCP Packets and Handlers   * //
 
// ****************************** //
 
	i = 0;
 
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
 
		if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
 
			continue;
 
		_network_ip_list[i] = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
 
		i++;
 
	}
 
	freeifaddrs(ifap);
 

	
 
#else /* not HAVE_GETIFADDRS */
 

	
 
	unsigned long len = 0;
 
	SOCKET sock;
 
	IFREQ ifo[MAX_INTERFACES];
 

	
 
#ifndef WIN32
 
	struct ifconf if_conf;
 
#endif
 

	
 
	// If something fails, make sure the list is empty
 
	_network_ip_list[0] = 0;
 

	
 
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 
		return;
 
	}
 

	
 
static QueuedCommand *AllocQueuedCommand(CommandQueue *nq)
 
{
 
	QueuedCommand *qp = (QueuedCommand*)calloc(sizeof(QueuedCommand), 1);
 
	assert(qp);
 
	*nq->last = qp;
 
	nq->last = &qp->next;
 
	return qp;
 
#ifdef WIN32
 
	// On windows it is easy
 
	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;
 
	}
 
#else
 
	// On linux a bit harder
 
	if_conf.ifc_len = (sizeof (struct ifreq)) * MAX_INTERFACES;
 
	if_conf.ifc_buf = (char *)&ifo[0];
 
	if ((ioctl(sock, SIOCGIFCONF, &if_conf)) == -1) {
 
		closesocket(sock);
 
		return;
 
	}
 
	len = if_conf.ifc_len;
 
#endif /* WIN32 */
 

	
 
	// Now walk through all IPs and list them
 
	for (i = 0; i < (int)(len / sizeof(IFREQ)); i++) {
 
		// Request IP for this interface
 
#ifdef WIN32
 
		_network_ip_list[i] = *(&ifo[i].iiAddress.AddressIn.sin_addr.s_addr);
 
#else
 
		if ((ioctl(sock, SIOCGIFADDR, &ifo[i])) != 0) {
 
			closesocket(sock);
 
			return;
 
		}
 

	
 
		_network_ip_list[i] = ((struct sockaddr_in *)&ifo[i].ifr_addr)->sin_addr.s_addr;
 
#endif
 
	}
 

	
 
	closesocket(sock);
 

	
 
#endif /* not HAVE_GETIFADDRS */
 

	
 
	_network_ip_list[i] = 0;
 
	last = i - 1;
 

	
 
	DEBUG(net, 3)("Detected IPs:");
 
	// Now display to the debug all the detected ips
 
	i = 0;
 
	while (_network_ip_list[i] != 0) {
 
		// Also check for non-used ips (127.0.0.1)
 
		if (_network_ip_list[i] == inet_addr("127.0.0.1")) {
 
			// If there is an ip after thisone, put him in here
 
			if (last > i)
 
				_network_ip_list[i] = _network_ip_list[last];
 
			// Clear the last ip
 
			_network_ip_list[last] = 0;
 
			// And we have 1 ip less
 
			last--;
 
			continue;
 
		}
 

	
 
		DEBUG(net, 3)(" %d) %s", i, inet_ntoa(*(struct in_addr *)&_network_ip_list[i]));//inet_ntoa(inaddr));
 
		i++;
 
	}
 
}
 

	
 
static void QueueClear(CommandQueue *nq)
 
// Resolve a hostname to a inet_addr
 
unsigned long NetworkResolveHost(const char *hostname)
 
{
 
	QueuedCommand *qp;
 
	while ((qp=nq->head)) {
 
		// unlink it.
 
		if (!(nq->head = qp->next)) nq->last = &nq->head;
 
		free(qp);
 
	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) ("[NET] Cannot resolve %s", hostname);
 
		} else {
 
			struct in_addr addr = *(struct in_addr *)he->h_addr_list[0];
 
			DEBUG(net, 1) ("[NET] Resolved %s to %s", hostname, inet_ntoa(addr));
 
			ip = addr.s_addr;
 
		}
 
	nq->last = &nq->head;
 
}
 

	
 
static int GetNextSyncFrame()
 
{
 
	uint32 newframe;
 
	if (_frame_fsync_last == 0) return -11;
 
	newframe = (_frame_fsync_last + 11); // do not use a multiple of 4 since that screws up sync-packets
 
	return (_frame_counter_max - newframe);
 

	
 
	}
 
	return ip;
 
}
 

	
 
// go through the player queues for each player and see if there are any pending commands
 
// that should be executed this frame. if there are, execute them.
 
void NetworkProcessCommands()
 
// 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 byte **player, const byte **port, byte *connection_string)
 
{
 
	CommandQueue *nq;
 
	QueuedCommand *qp;
 
	byte old_player;
 

	
 
	// queue mode ?
 
	if (_networking_queuing)
 
		return;
 

	
 
	nq = &_command_queue;
 
	while ( (qp=nq->head) && (!_networking_sync || qp->frame <= _frame_counter)) {
 
		// unlink it.
 
		if (!(nq->head = qp->next)) nq->last = &nq->head;
 

	
 
		if (qp->frame < _frame_counter && _networking_sync) {
 
			DEBUG(net,0) ("warning: !qp->cp.frame < _frame_counter, %d < %d [%d]\n", qp->frame, _frame_counter, _frame_counter_srv+4);
 
		}
 

	
 
		// run the command
 
		old_player = _current_player;
 
		_current_player = qp->cp.player;
 
		memcpy(_decode_parameters, qp->cp.dp, (qp->cp.packet_length - COMMAND_PACKET_BASE_SIZE));
 

	
 
		DoCommandP(qp->cp.tile, qp->cp.p1, qp->cp.p2, qp->callback, qp->cmd | CMD_DONT_NETWORK);
 
		free(qp);
 
		_current_player = old_player;
 
	}
 

	
 
	if (!_networking_server) {
 
		// remember the random seed so we can check if we're out of sync.
 
		_my_seed_list[_frame_counter & 15][0] = _sync_seed_1;
 
		_my_seed_list[_frame_counter & 15][1] = _sync_seed_2;
 

	
 
		while (_num_future_seed) {
 
			assert(_future_seed[0].frame >= _frame_counter);
 
			if (_future_seed[0].frame != _frame_counter) break;
 
			if (_future_seed[0].seed[0] != _sync_seed_1 ||_future_seed[0].seed[1] != _sync_seed_2) NetworkHandleDeSync();
 
			memmove(_future_seed, _future_seed + 1, --_num_future_seed * sizeof(FutureSeeds));
 
	byte *p;
 
	for (p = connection_string; *p != '\0'; p++) {
 
		if (*p == '#') {
 
			*player = p + 1;
 
			*p = '\0';
 
		} else if (*p == ':') {
 
			*port = p + 1;
 
			*p = '\0';
 
		}
 
	}
 
}
 

	
 
// send a packet to a client
 
static void SendBytes(ClientState *cs, void *bytes, uint len)
 
// Creates a new client from a socket
 
//   Used both by the server and the client
 
static ClientState *AllocClient(SOCKET s)
 
{
 
	byte *b = (byte*)bytes;
 
	uint n;
 
	Packet *p;
 

	
 
	assert(len != 0);
 
	ClientState *cs;
 
	NetworkClientInfo *ci;
 
	byte client_no;
 

	
 
	// see if there's space in the last packet?
 
	if (!cs->head || (p = (Packet*)cs->last, p->siz == sizeof(p->buf)))
 
		p = NULL;
 
	client_no = 0;
 

	
 
	do {
 
		if (!p) {
 
			// need to allocate a new packet buffer.
 
			p = (Packet*)malloc(sizeof(Packet));
 
	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;
 

	
 
			// insert at the end of the linked list.
 
			*cs->last = p;
 
			cs->last = &p->next;
 
			p->next = NULL;
 
			p->siz = 0;
 
		}
 
		// Register the login
 
		client_no = _network_clients_connected++;
 
	}
 

	
 
	cs = &_clients[client_no];
 
	memset(cs, 0, sizeof(*cs));
 
	cs->socket = s;
 
	cs->last_frame = 0;
 
	cs->quited = false;
 

	
 
		// copy bytes to packet.
 
		n = minu(sizeof(p->buf) - p->siz, len);
 
		memcpy(p->buf + p->siz, b, n);
 
		p->siz += n;
 
		b += n;
 
		p = NULL;
 
	} while (len -= n);
 
}
 
	if (_network_server) {
 
		ci = &_network_client_info[client_no];
 
		memset(ci, 0, sizeof(*ci));
 

	
 
// send data direct to a client
 
static void SendDirectBytes(ClientState *cs, void *bytes, uint len)
 
{
 
	char *buf = (char*)bytes;
 
	uint n;
 
		cs->index = _network_client_index++;
 
		ci->client_index = cs->index;
 
		ci->join_date = _date;
 

	
 
	n = send(cs->socket, buf, len, 0);
 
	if (n == -1) {
 
				int err = GET_LAST_ERROR();
 
				DEBUG(net, 0) ("NET: %i] send() failed with error %d", _frame_counter, err);
 
				CloseClient(cs);
 
			}
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	return cs;
 
}
 

	
 
// client:
 
//   add it to the client's ack queue, and send the command to the server
 
// server:
 
//   add it to the server's player queue, and send it to all clients.
 
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback)
 
// Close a connection
 
void CloseClient(ClientState *cs)
 
{
 
	int nump;
 
	QueuedCommand *qp;
 
	ClientState *cs;
 
	CommandPacket cp;
 

	
 
	if (!(cmd & CMD_NET_INSTANT)) {
 
		qp = AllocQueuedCommand(_networking_server ? &_command_queue : &_ack_queue);
 
	} else {
 
		qp = (QueuedCommand*)calloc(sizeof(QueuedCommand), 1);
 
		}
 
	qp->cp.packet_type = PACKET_TYPE_COMMAND;
 
	qp->cp.tile = tile;
 
	qp->cp.p1 = p1;
 
	qp->cp.p2 = p2;	
 
	qp->cp.cmd = (uint16)cmd;
 
	qp->cp.player = _local_player;
 
	qp->cp.when = 0;
 
	qp->cmd = cmd;
 
	qp->callback = callback;
 
	NetworkClientInfo *ci;
 
	// Socket is already dead
 
	if (cs->socket == INVALID_SOCKET) return;
 

	
 
	// so the server knows when to execute it.
 
	qp->frame = _frame_counter_max - GetNextSyncFrame();
 

	
 
	// calculate the amount of extra bytes.
 
	nump = 8;
 
	while ( nump != 0 && ((uint32*)_decode_parameters)[nump-1] == 0) nump--;
 
	qp->cp.packet_length = COMMAND_PACKET_BASE_SIZE + nump * sizeof(uint32);
 
	if (nump != 0) memcpy(qp->cp.dp, _decode_parameters, nump * sizeof(uint32));
 

	
 
	cp = qp->cp;
 

	
 
	// convert to little endian
 
	cp.tile = TO_LE16(cp.tile);
 
	cp.p1 = TO_LE32(cp.p1);
 
	cp.p2 = TO_LE32(cp.p2);
 
	cp.cmd = TO_LE16(cp.cmd);
 

	
 
	// send it to the peers
 
	for(cs=_clients; cs->socket != INVALID_SOCKET; cs++) if (!cs->inactive) SendBytes(cs, &cp, cp.packet_length);
 

	
 
	if (cmd & CMD_NET_INSTANT) {
 
		free(qp);
 
	}
 
}
 

	
 
void NetworkSendEvent(uint16 type, uint16 data_len, void * data)
 
{
 
	EventPacket * ep;
 
	ClientState *cs;
 
	DEBUG(net, 1) ("[NET] Closed client connection");
 

	
 
	// 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);
 
}
 
	if (!cs->quited && _network_server && cs->status > STATUS_INACTIVE) {
 
		// We did not receive a leave message from this client...
 
		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
 
		char str1[100], str2[100];
 
		char client_name[NETWORK_NAME_LENGTH];
 
		ClientState *new_cs;
 

	
 
// client:
 
//   server sends a command from another player that we should execute.
 
//   put it in the command queue.
 
//
 
// server:
 
//   client sends a command that it wants to execute.
 
//   fill the when field so the client knows when to execute it.
 
//   put it in the appropriate player queue.
 
//   send it to all other clients.
 
//   send an ack packet to the actual client.
 

	
 
static void HandleCommandPacket(ClientState *cs, CommandPacket *np)
 
{
 
	QueuedCommand *qp;
 
	ClientState *c;
 
	AckPacket ap;
 
	uint16 cmd;
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
	DEBUG(net, 2) ("NET: %i] cmd size %d", _frame_counter, np->packet_length);
 
	assert(np->packet_length >= COMMAND_PACKET_BASE_SIZE);
 

	
 
	cmd = FROM_LE16(np->cmd);
 
		GetString(str1, STR_NETWORK_ERR_LEFT);
 
		GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 

	
 
	if (!(cmd & CMD_NET_INSTANT)) {
 
		// put it into the command queue
 
		qp = AllocQueuedCommand(&_command_queue);
 
	} else {
 
		qp = (QueuedCommand*)calloc(sizeof(QueuedCommand), 1);
 
	}
 
	qp->cp = *np;
 

	
 
	qp->frame = _frame_counter_max - GetNextSyncFrame();
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
	qp->callback = NULL;
 

	
 
	// extra params
 
	memcpy(&qp->cp.dp, np->dp, np->packet_length - COMMAND_PACKET_BASE_SIZE);
 

	
 
	ap.packet_type = PACKET_TYPE_ACK;
 
	ap.when = TO_LE16(GetNextSyncFrame());
 
	ap.packet_length = sizeof(AckPacket);
 
	DEBUG(net,4)("NET: %i] NewACK: frame=%i %i",_frame_counter, ap.when,_frame_counter_max - GetNextSyncFrame());
 

	
 
	// send it to the peers
 
	if (_networking_server) {
 
		for(c=_clients; c->socket != INVALID_SOCKET; c++) {
 
			if (c == cs) {
 
				if (!(cmd & CMD_NET_INSTANT)) SendDirectBytes(c, &ap, ap.packet_length);
 
			} else {
 
				if (!cs->inactive) SendBytes(c, &qp->cp, qp->cp.packet_length);
 
		// 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);
 
			}
 
		}
 
	}
 

	
 
// convert from little endian to big endian?
 
#if defined(TTD_BIG_ENDIAN)
 
	qp->cp.cmd = FROM_LE16(qp->cp.cmd);
 
	qp->cp.tile = FROM_LE16(qp->cp.tile);
 
	qp->cp.p1 = FROM_LE32(qp->cp.p1);
 
	qp->cp.p2 = FROM_LE32(qp->cp.p2);
 
#endif
 

	
 
	qp->cmd = qp->cp.cmd;
 

	
 
	if (cmd & CMD_NET_INSTANT) {
 
		byte p = _current_player;
 
		_current_player = qp->cp.player;
 
		memcpy(_decode_parameters, qp->cp.dp, (qp->cp.packet_length - COMMAND_PACKET_BASE_SIZE));
 
		DoCommandP(qp->cp.tile, qp->cp.p1, qp->cp.p2, qp->callback, qp->cmd | CMD_DONT_NETWORK);
 
		free(qp);
 
		_current_player = p;
 
		}
 
}
 
	closesocket(cs->socket);
 
	cs->writable = false;
 

	
 
static void HandleEventPacket(EventPacket *ep)
 
{
 
	switch (ep->event_type) {
 
		case NET_EVENT_SUBSIDY:
 
			RemoteSubsidyAdd((Subsidy *)&ep->data_start);
 
			break;
 
	// 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;
 
	}
 
}
 

	
 
// 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)
 
{
 
	uint32 s1,s2;
 

	
 
	_frame_counter_srv = _frame_counter_max - sp->server;
 
	_frame_counter_max += sp->frames;
 

	
 
	// reset network ready packet state
 
	_network_ready_sent = false;
 

	
 
	// queueing only?
 
	if (_networking_queuing || _frame_counter == 0)
 
		return;
 

	
 
	s1 = FROM_LE32(sp->random_seed_1);
 
	s2 = FROM_LE32(sp->random_seed_2);
 

	
 
	DEBUG(net, 3) ("NET: %i] sync seeds: 1=%i 2=%i",_frame_counter, sp->random_seed_1, sp->random_seed_2);
 
	free(cs->packet_recv);
 
	cs->packet_recv = NULL;
 

	
 
	if (_frame_counter_srv <= _frame_counter) {
 
		// we are ahead of the server check if the seed is in our list.
 
		if (_frame_counter_srv + 16 > _frame_counter) {
 
			// the random seed exists in our array check it.
 
			if (s1 != _my_seed_list[_frame_counter_srv & 0xF][0] || s2 != _my_seed_list[_frame_counter_srv & 0xF][1]) NetworkHandleDeSync();
 
		}
 
	} else {
 
		// the server's frame has not been executed yet. store the server's seed in a list.
 
		if (_num_future_seed < lengthof(_future_seed)) {
 
			_future_seed[_num_future_seed].frame = _frame_counter_srv;
 
			_future_seed[_num_future_seed].seed[0] = s1;
 
			_future_seed[_num_future_seed].seed[1] = s2;
 
			_num_future_seed++;
 
		}
 
	while (cs->command_queue != NULL) {
 
		CommandPacket *p = cs->command_queue->next;
 
		free(cs->command_queue);
 
		cs->command_queue = p;
 
	}
 
}
 

	
 
static void HandleFSyncPacket(FrameSyncPacket *fsp)
 
{
 
	DEBUG(net,3)("NET: %i] FSYNC: srv=%i %i",_frame_counter, fsp->frames,(_frame_counter_max - fsp->frames));
 
	if (fsp->frames < 1) return;
 
	_frame_fsync_last = _frame_counter_srv = _frame_counter_max - fsp->frames;
 
}
 

	
 
// sent from server -> client as an acknowledgement that the server received the command.
 
// the command will be executed at the current value of "max".
 
static void HandleAckPacket(AckPacket * ap)
 
{
 
	QueuedCommand *q;
 
	// move a packet from the ack queue to the end of this player's queue.
 
	q = _ack_queue.head;
 
	assert(q);
 
	if (!(_ack_queue.head = q->next)) _ack_queue.last = &_ack_queue.head;
 
	q->next = NULL;
 

	
 
	q->frame = (_frame_counter_max - (FROM_LE16(ap->when)));
 
	// Close the gap in the client-list
 
	ci = DEREF_CLIENT_INFO(cs);
 

	
 
	*_command_queue.last = q;
 
	_command_queue.last = &q->next;
 

	
 
	DEBUG(net, 2) ("NET %i] ack [frame=%i]",_frame_counter,q->frame);
 
}
 

	
 
static void HandleFilePacket(FilePacketHdr *fp)
 
{
 
	int n = fp->packet_length - sizeof(FilePacketHdr);
 
	char tempfile[512];
 

	
 
	sprintf(tempfile, "%s/networkc.tmp",  _path.personal_dir);
 

	
 
	if (n == 0) {
 
		assert(_networking_queuing);
 
		assert(!_networking_sync);
 
		// eof
 
		if (_recv_file) { fclose(_recv_file); _recv_file = NULL; }
 
	if (_network_server) {
 
		// We just lost one client :(
 
		if (cs->status > STATUS_INACTIVE)
 
			_network_game_info.clients_on--;
 
		_network_clients_connected--;
 

	
 
		// attempt loading the game.
 
		_game_mode = GM_NORMAL;
 
		if (SaveOrLoad(tempfile, SL_LOAD) != SL_OK) {
 
				NetworkCoreDisconnect();
 
				NetworkHandleSaveGameError();
 
				return;
 
				}
 
		// sync to server.
 
		_networking_queuing = false;
 
		NetworkStartSync(false);
 

	
 
		if (_network_playas == 0) {
 
			// send a command to make a new player
 
			_local_player = 0;
 
			NetworkSendCommand(0, 0, 0, CMD_PLAYER_CTRL, NULL);
 
			_local_player = OWNER_SPECTATOR;
 
		} else {
 
			// take control over an existing company
 
			if (DEREF_PLAYER(_network_playas-1)->is_active)
 
				_local_player = _network_playas-1;
 
			else
 
				_local_player = OWNER_SPECTATOR;
 
		while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) {
 
			*cs = *(cs + 1);
 
			*ci = *(ci + 1);
 
			cs++;
 
			ci++;
 
		}
 

	
 
	} else {
 
		if(!_recv_file) {
 
			_recv_file = fopen(tempfile, "wb");
 
			if (!_recv_file) error("can't open savefile");
 
		}
 
		fwrite( (char*)fp + sizeof(*fp), n, 1, _recv_file);
 
	}
 
}
 

	
 
static void HandleWelcomePacket(WelcomePacket *wp)
 
{
 
	int i;
 
	for (i=0; i<MAX_PLAYERS; i++) {
 

	
 
		_player_seeds[i][0] = FROM_LE32(wp->player_seeds[i][0]);
 
		_player_seeds[i][1] = FROM_LE32(wp->player_seeds[i][1]);
 
		}
 
	if (wp->frames_srv != 0) {
 
		_frame_counter_max = FROM_LE32(wp->frames_max);
 
		_frame_counter_srv = FROM_LE32(wp->frames_srv);
 
	}
 
	if (wp->frames_cnt != 0) {
 
		_frame_counter = FROM_LE32(wp->frames_cnt);
 
	}
 
}
 

	
 
static void HandleReadyPacket(ReadyPacket *rp, ClientState *cs)
 
{
 
	cs->ready=true;
 
	cs->timeout=_network_client_timeout;
 
	DEBUG(net,1) ("NET: %i] ready packet recv", _frame_counter);
 
}
 

	
 

	
 
static void CloseClient(ClientState *cs)
 
{
 
	Packet *p, *next;
 

	
 
	DEBUG(net, 1) ("[NET][TCP] closed client connection");
 

	
 
	assert(cs->socket != INVALID_SOCKET);
 

	
 
	closesocket(cs->socket);
 

	
 
	// free buffers
 
	for(p = cs->head; p; p=next) {
 
		next = p->next;
 
		free(p);
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	// copy up structs...
 
	while ((cs+1)->socket != INVALID_SOCKET) {
 
		*cs = *(cs+1);
 
		cs++;
 
	}
 
	// Reset the status of the last socket
 
	cs->socket = INVALID_SOCKET;
 

	
 
	if (_networking_server) _network_game.players_on--;
 

	
 
	_num_clients--;
 
	cs->status = STATUS_INACTIVE;
 
	cs->index = NETWORK_EMPTY_INDEX;
 
	ci->client_index = NETWORK_EMPTY_INDEX;
 
}
 

	
 
#define NETWORK_BUFFER_SIZE 4096
 
static bool ReadPackets(ClientState *cs)
 
{
 
	byte network_buffer[NETWORK_BUFFER_SIZE];
 
	uint pos,size;
 
	unsigned long recv_bytes;
 

	
 
	size = cs->buflen;
 

	
 
	for(;;) {
 
		if (size != 0) memcpy(network_buffer, cs->buf, size);
 
extern void ShowJoinStatusWindow();
 

	
 
		recv_bytes = recv(cs->socket, (char*)network_buffer + size, sizeof(network_buffer) - size, 0);
 
		if ( recv_bytes == (unsigned long)-1) {
 
			int err = GET_LAST_ERROR();
 
			if (err == EWOULDBLOCK) break;
 
			DEBUG(net, 0) ("[NET] recv() failed with error %d", err);
 
			CloseClient(cs);
 
			return false;
 
		}
 
		// no more bytes for now?
 
		if (recv_bytes == 0)
 
			break;
 
// A client wants to connect to a server
 
bool NetworkConnect(const char *hostname, int port)
 
{
 
	SOCKET s;
 
	struct sockaddr_in sin;
 

	
 
	DEBUG(net, 1) ("[NET] Connecting to %s %d", hostname, port);
 

	
 
		size += recv_bytes; // number of bytes read.
 
		pos = 0;
 
		while (size >= 2) {
 
			byte *packet = network_buffer + pos;
 
			// whole packet not there yet?
 
			if (size < packet[0]) break;
 
			size -= packet[0];
 
			pos += packet[0];
 
			switch(packet[1]) {
 
			case PACKET_TYPE_WELCOME:
 
				HandleWelcomePacket((WelcomePacket *)packet);
 
				break;
 
			case PACKET_TYPE_COMMAND:
 
				HandleCommandPacket(cs, (CommandPacket*)packet);
 
				break;
 
			case PACKET_TYPE_SYNC:
 
				assert(_networking_sync || _networking_queuing);
 
				assert(!_networking_server);
 
				HandleSyncPacket((SyncPacket*)packet);
 
				break;
 
			case PACKET_TYPE_FSYNC:
 
				HandleFSyncPacket((FrameSyncPacket *)packet);
 
				break;
 
			case PACKET_TYPE_ACK:
 
				assert(!_networking_server);
 
				HandleAckPacket((AckPacket*)packet);
 
				break;
 
			case PACKET_TYPE_XMIT:
 
				HandleFilePacket((FilePacketHdr*)packet);
 
				break;
 
			case PACKET_TYPE_READY:
 
				HandleReadyPacket((ReadyPacket*)packet, cs);
 
				break;
 
			case PACKET_TYPE_EVENT:
 
				HandleEventPacket((EventPacket*)packet);
 
				break;
 
			default:
 
				DEBUG (net,0) ("NET: %i] unknown packet type",_frame_counter);
 
			}
 
		}
 
	s = socket(AF_INET, SOCK_STREAM, 0);
 
	if (s == INVALID_SOCKET) {
 
		ClientStartError("socket() failed");
 
		return false;
 
	}
 

	
 
		assert(size < sizeof(cs->buf));
 

	
 
		memcpy(cs->buf, network_buffer + pos, size);
 
	{ // set nodelay /* 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!!
 
		if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) != 0)
 
			DEBUG(net, 1)("[NET] Setting TCP_NODELAY failed");
 
		#endif
 
	}
 

	
 
	cs->buflen = size;
 
	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;
 

	
 
	if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) {
 
		// We failed to connect for which reason what so ever
 
		return false;
 
	}
 

	
 
	{ // set nonblocking mode for socket..
 
		unsigned long blocking = 1;
 
		#if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
		byte nonblocking = 1;
 
		if (setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(blocking)) != 0)
 
		#else
 
		if (ioctlsocket(s, FIONBIO, &blocking) != 0)
 
		#endif
 
			DEBUG(net, 0)("[NET] Setting non-blocking failed"); /* XXX should this be an error? */
 
	}
 

	
 
	// in client mode, only the first client field is used. it's pointing to the server.
 
	AllocClient(s);
 

	
 
	ShowJoinStatusWindow();
 

	
 
	memcpy(&network_tmp_patches, &_patches, sizeof(_patches));
 

	
 
	return true;
 
}
 

	
 

	
 
static bool SendPackets(ClientState *cs)
 
{
 
	Packet *p;
 
	int n;
 
	uint nskip = cs->eaten, nsent = nskip;
 

	
 
	// try sending as much as possible.
 
	for(p=cs->head; p ;p = p->next) {
 
		if (p->siz) {
 
			assert(nskip < p->siz);
 

	
 
			n = send(cs->socket, p->buf + nskip, p->siz - nskip, 0);
 
			if (n == -1) {
 
				int err = GET_LAST_ERROR();
 
				if (err == EWOULDBLOCK) break;
 
				DEBUG(net, 0) ("[NET] send() failed with error %d", err);
 
				CloseClient(cs);
 
				return false;
 
			}
 
			nsent += n;
 
			// send was not able to send it all? then we assume that the os buffer is full and break.
 
			if (nskip + n != p->siz)
 
				break;
 
			nskip = 0;
 
		}
 
	}
 

	
 
	// nsent bytes in the linked list are not invalid. free as many buffers as possible.
 
	// don't actually free the last buffer.
 
	while (nsent) {
 
		p = cs->head;
 
		assert(p->siz != 0);
 

	
 
		// some bytes of the packet are still unsent.
 
		if ( (int)(nsent - p->siz) < 0)
 
			break;
 
		nsent -= p->siz;
 
		p->siz = 0;
 
		if (p->next) {
 
			cs->head = p->next;
 
			free(p);
 
		}
 
	}
 

	
 
	cs->eaten = nsent;
 

	
 
	return true;
 
}
 

	
 
// transmit the file..
 
static void SendXmit(ClientState *cs)
 
{
 
	uint pos, n;
 
	FilePacketHdr hdr;
 
	int p;
 

	
 
	// if too many unsent bytes left in buffer, don't send more.
 
	if (cs->head && cs->head->next)
 
		return;
 

	
 
	pos = cs->xmitpos - 1;
 

	
 
	p = 20;
 
	do {
 
		// compute size of data to xmit
 
		n = minu(_transmit_file_size - pos, 248);
 

	
 
		hdr.packet_length = n + sizeof(hdr);
 
		hdr.packet_type = PACKET_TYPE_XMIT;
 
		SendBytes(cs, &hdr, sizeof(hdr));
 

	
 
		if (n == 0) {
 
			pos = -1; // eof
 
			break;
 
		}
 
		SendBytes(cs, _transmit_file + pos, n);
 
		pos += n;
 
	} while (--p);
 

	
 
	cs->xmitpos = pos + 1;
 

	
 
	if (cs->xmitpos == 0) {
 
		NetworkSendWelcome(cs,false);
 
	}
 

	
 
	DEBUG(net, 2) ("[NET] client xmit at %d", pos + 1);
 
}
 

	
 
static ClientState *AllocClient(SOCKET s)
 
{
 
	ClientState *cs;
 

	
 
	if (_num_clients == MAX_CLIENTS)
 
		return NULL;
 

	
 
	if (_networking_server) _network_game.players_on++;
 

	
 
	cs = &_clients[_num_clients++];
 
	memset(cs, 0, sizeof(*cs));
 
	cs->last = &cs->head;
 
	cs->socket = s;
 
	cs->timeout = _network_client_timeout;
 
	return cs;
 
}
 

	
 
void NetworkSendReadyPacket()
 
{
 
	if ((!_network_ready_sent) && (_frame_counter + _network_ready_ahead >= _frame_counter_max)) {
 
		ReadyPacket rp;
 

	
 
		DEBUG(net,1) ("NET: %i] ready packet sent", _frame_counter);
 

	
 
		rp.packet_type = PACKET_TYPE_READY;
 
		rp.packet_length = sizeof(rp);
 
		SendBytes(_clients, &rp, sizeof(rp));
 
		_network_ready_sent = true;
 
	}
 
}
 

	
 
void NetworkSendSyncPackets()
 
{
 
	ClientState *cs;
 
	uint32 new_max;
 
	SyncPacket sp;
 

	
 
	new_max = _frame_counter + (int)_network_sync_freq;
 

	
 
	DEBUG(net,3) ("NET: %i] serv: sync max=%i, seed1=%i, seed2=%i",_frame_counter,new_max,_sync_seed_1,_sync_seed_2);
 

	
 
	sp.packet_length = sizeof(sp);
 
	sp.packet_type = PACKET_TYPE_SYNC;
 
	sp.frames = new_max - _frame_counter_max;
 
	sp.server = _frame_counter_max - _frame_counter;
 
	sp.random_seed_1 = TO_LE32(_sync_seed_1);
 
	sp.random_seed_2 = TO_LE32(_sync_seed_2);
 
	_frame_counter_max = new_max;
 

	
 
	// send it to all the clients and mark them unready
 
	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
		cs->ready=false;
 
		SendBytes(cs, &sp, sp.packet_length);
 
	}
 

	
 
}
 

	
 
void NetworkSendFrameSyncPackets()
 
{
 
	ClientState *cs;
 
	FrameSyncPacket fsp;
 
	if ((_frame_counter + 4) < _frame_counter_max) if ((_frame_fsync_last + 4 < _frame_counter)) {
 
		// this packet mantains some information about on which frame the server is
 
		fsp.frames = _frame_counter_max - _frame_counter;
 
		fsp.packet_type = PACKET_TYPE_FSYNC;
 
		fsp.packet_length = sizeof (FrameSyncPacket);
 
		// send it to all the clients and mark them unready
 
		for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
			SendBytes(cs, &fsp, fsp.packet_length);
 
		}
 
		_frame_fsync_last = _frame_counter;
 
	}
 

	
 
}
 

	
 
void NetworkSendWelcome(ClientState *cs, bool direct) {
 
	WelcomePacket wp;
 
	int i;
 
	wp.packet_type = PACKET_TYPE_WELCOME;
 
	wp.packet_length = sizeof(WelcomePacket);
 
	for (i=0; i<MAX_PLAYERS; i++) {
 
		wp.player_seeds[i][0]=TO_LE32(_player_seeds[i][0]);
 
		wp.player_seeds[i][1]=TO_LE32(_player_seeds[i][1]);
 
		}
 
	if (direct) {
 
		wp.frames_max=0;
 
		wp.frames_srv=0;
 
		wp.frames_cnt=TO_LE32(_frame_counter);
 
		SendDirectBytes(cs,(void *)&wp,wp.packet_length);
 
	} else {
 
		wp.frames_max=TO_LE32(_frame_counter_max);
 
		wp.frames_srv=TO_LE32(_frame_counter_srv);
 
		wp.frames_cnt=0;
 
		SendBytes(cs,(void *)&wp,wp.packet_length);
 
	}
 
}
 

	
 
static void NetworkAcceptClients()
 
// For the server, to accept new clients
 
static void NetworkAcceptClients(void)
 
{
 
	struct sockaddr_in sin;
 
	SOCKET s;
 
@@ -1040,200 +559,362 @@ static void NetworkAcceptClients()
 
	LONG sin_len; // for some reason we need a 'LONG' under MorphOS
 
#endif
 

	
 
	// Should never ever happen.. is it possible??
 
	assert(_listensocket != INVALID_SOCKET);
 

	
 
	for(;;) {
 
	for (;;) {
 
		sin_len = sizeof(sin);
 
		s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len);
 
		if (s == INVALID_SOCKET) return;
 

	
 
		// set nonblocking mode for client socket
 
		#if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
		{ unsigned long blocking = 1; byte nonblocking = 1; setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(blocking)); }
 
		#else
 
		{ unsigned long blocking = 1; ioctlsocket(s, FIONBIO, &blocking); }
 
		#endif
 

	
 
		DEBUG(net, 1) ("NET: %i] got client from %s", _frame_counter, inet_ntoa(sin.sin_addr));
 
		DEBUG(net, 1) ("[NET] Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter);
 

	
 
		// set nodelay
 
		#if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server...
 
		// The (const char*) cast is needed for windows!!
 
		{int b = 1; setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b));}
 
		#endif
 

	
 
		cs = AllocClient(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;
 
		}
 

	
 
		if (_networking_sync) {
 
			// a new client has connected. it needs a snapshot.
 
			cs->inactive = true;
 
		// 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;
 

	
 
		{
 
			// Save the IP of the client
 
			NetworkClientInfo *ci;
 
			ci = DEREF_CLIENT_INFO(cs);
 
			ci->client_ip = sin.sin_addr.s_addr;
 
		}
 
	}
 

	
 
	// when a new client has joined. it needs different information depending on if it's at the game menu or in an active game.
 
	// Game menu:
 
	//  - list of players already in the game (name, company name, face, color)
 
	//  - list of game settings and patch settings
 
	// Active game:
 
	//  - the state of the world (includes player name, company name, player face, player color)
 
	//  - list of the patch settings
 

	
 
	// Networking can be in several "states".
 
	//  * not sync - games don't need to be in sync, and frame counter is not synced. for example intro screen. all commands are executed immediately.
 
	//  * sync - games are in sync
 
}
 

	
 
static void SendQueuedCommandsToNewClient(ClientState *cs)
 
{
 
	// send the commands in the server queue to the new client.
 
	QueuedCommand *qp;
 
	SyncPacket sp;
 
	uint32 frame;
 

	
 
	DEBUG(net, 2) ("NET: %i] sending queued commands to client",_frame_counter);
 

	
 
	sp.packet_length = sizeof(sp);
 
	sp.packet_type = PACKET_TYPE_SYNC;
 
	sp.random_seed_1 = sp.random_seed_2 = 0;
 
	sp.server = 0;
 

	
 
	frame = _frame_counter;
 

	
 
	for(qp=_command_queue.head; qp; qp = qp->next) {
 
		DEBUG(net, 4) ("NET: %i] sending cmd to be executed at %d (old %d)", _frame_counter, qp->frame, frame);
 
		if (qp->frame > frame) {
 
			assert(qp->frame <= _frame_counter_max);
 
			sp.frames = qp->frame - frame;
 
			frame = qp->frame;
 
			SendBytes(cs, &sp, sizeof(sp));
 
		}
 
		SendBytes(cs, &qp->cp, qp->cp.packet_length);
 
	}
 

	
 
	if (frame < _frame_counter_max) {
 
		DEBUG(net, 4) ("NET: %i] sending queued sync %d (%d)",_frame_counter, _frame_counter_max, frame);
 
		sp.frames = _frame_counter_max - frame;
 
		SendBytes(cs, &sp, sizeof(sp));
 
	}
 

	
 
}
 

	
 
bool NetworkCheckClientReady()
 
{
 
	bool ready_all = true;
 
	uint16 count = 0;
 
	ClientState *cs;
 

	
 
	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
		count++;
 
		ready_all = ready_all && (cs->ready || cs->inactive || (cs->xmitpos>0));
 
		if (!cs->ready) cs->timeout-=1;
 
		if (cs->timeout == 0) {
 
			SetDParam(0,count);
 
			ShowErrorMessage(-1,STR_NETWORK_ERR_TIMEOUT,0,0);
 
			CloseClient(cs);
 
			}
 
		}
 
	return ready_all;
 
}
 

	
 
// ************************** //
 
// * TCP Networking         * //
 
// ************************** //
 

	
 
unsigned long NetworkResolveHost(const char *hostname)
 
// Set up the listen socket for the server
 
bool NetworkListen(void)
 
{
 
	struct hostent* remotehost;
 

	
 
	if ((hostname[0]<0x30) || (hostname[0]>0x39)) {
 
		// seems to be an hostname [first character is no number]
 
		remotehost = gethostbyname(hostname);
 
		if (remotehost == NULL) {
 
			DEBUG(net, 1) ("[NET][IP] cannot resolve %s", hostname);
 
			return 0;
 
		} else {
 
			DEBUG(net, 1) ("[NET][IP] resolved %s to %s",hostname, inet_ntoa(*(struct in_addr *) remotehost->h_addr_list[0]));
 
			return inet_addr(inet_ntoa(*(struct in_addr *) remotehost->h_addr_list[0]));
 
			}
 
	} else {
 
		// seems to be an ip [first character is a number]
 
		return inet_addr(hostname);
 
		}
 

	
 
}
 

	
 
bool NetworkConnect(const char *hostname, int port)
 
{
 
	SOCKET s;
 
	struct sockaddr_in sin;
 
	int b;
 

	
 
	DEBUG(net, 1) ("[NET][TCP] Connecting to %s %d", hostname, port);
 

	
 
	s = socket(AF_INET, SOCK_STREAM, 0);
 
	if (s == INVALID_SOCKET) error("socket() failed");
 

	
 
	b = 1;
 
	setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b));
 

	
 
	sin.sin_family = AF_INET;
 
	sin.sin_addr.s_addr = NetworkResolveHost(hostname);
 
	sin.sin_port = htons(port);
 

	
 
	if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) {
 
		NetworkClose(true);
 
		return false;
 
		}
 

	
 
	// set nonblocking mode for socket..
 
	{ unsigned long blocking = 1; ioctlsocket(s, FIONBIO, &blocking); }
 

	
 
	// in client mode, only the first client field is used. it's pointing to the server.
 
	AllocClient(s);
 

	
 
	// queue packets.. because we're waiting for the savegame.
 
	_networking_queuing = true;
 
	_frame_counter_max = 0;
 

	
 
	return true;
 
}
 

	
 
void NetworkListen()
 
{
 

	
 
	SOCKET ls;
 
	struct sockaddr_in sin;
 
	int port;
 

	
 
	port = _network_server_port;
 

	
 
	DEBUG(net, 1) ("[NET][TCP] listening on port %d", port);
 
	DEBUG(net, 1) ("[NET] Listening on port %d", port);
 

	
 
	ls = socket(AF_INET, SOCK_STREAM, 0);
 
	if (ls == INVALID_SOCKET)
 
		error("socket() on listen socket failed");
 

	
 
	// reuse the socket
 
	{
 
		int reuse = 1; if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1)
 
			error("setsockopt() on listen socket failed");
 
	if (ls == INVALID_SOCKET) {
 
		ServerStartError("socket() on listen socket failed");
 
		return false;
 
	}
 

	
 
	// set nonblocking mode for socket
 
	{ unsigned long blocking = 1; ioctlsocket(ls, FIONBIO, &blocking); }
 
	{ // 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;
 
		}
 
	}
 

	
 
	{ // set nonblocking mode for socket
 
		unsigned long blocking = 1;
 
		#if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
		byte nonblocking = 1;
 
		if (setsockopt(ls, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(blocking)) != 0)
 
		#else
 
		if (ioctlsocket(ls, FIONBIO, &blocking) != 0)
 
		#endif
 
			DEBUG(net, 0)("[NET] Setting non-blocking failed"); /* XXX should this be an error? */
 
	}
 

	
 
	sin.sin_family = AF_INET;
 
	sin.sin_addr.s_addr = 0;
 
	sin.sin_port = htons(port);
 

	
 
	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0)
 
		error("bind() failed");
 
	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
 
		ServerStartError("bind() failed");
 
		return false;
 
	}
 

	
 
	if (listen(ls, 1) != 0)
 
		error("listen() failed");
 
	if (listen(ls, 1) != 0) {
 
		ServerStartError("listen() failed");
 
		return false;
 
	}
 

	
 
	_listensocket = ls;
 

	
 
	return true;
 
}
 

	
 
// Close all current connections
 
void NetworkClose(void)
 
{
 
	ClientState *cs;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		if (!_network_server) {
 
			SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
 
			NetworkSend_Packets(cs);
 
		}
 
		CloseClient(cs);
 
	}
 

	
 
	if (_network_server) {
 
		// We are a server, also close the listensocket
 
		closesocket(_listensocket);
 
		_listensocket = INVALID_SOCKET;
 
		DEBUG(net, 1) ("[NET] Closed listener");
 
		NetworkUDPClose();
 
	}
 
}
 

	
 
// Inits the network (cleans sockets and stuff)
 
void NetworkInitialize(void)
 
{
 
	ClientState *cs;
 

	
 
	_local_command_queue = NULL;
 

	
 
	// Clean all client-sockets
 
	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;
 

	
 
	InitPlayerRandoms();
 

	
 
	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
 
void NetworkQueryServer(const byte* host, unsigned short port, bool game_info)
 
{
 
	if (!_network_available) return;
 

	
 
	NetworkDisconnect();
 

	
 
	if (game_info) {
 
		NetworkUDPQueryServer(host, port);
 
		return;
 
	}
 

	
 
	NetworkInitialize();
 

	
 
	_network_server = false;
 

	
 
	// Try to connect
 
	_networking = NetworkConnect(host, port);
 

	
 
//	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
 
//	_network_last_port = port;
 

	
 
	// We are connected
 
	if (_networking) {
 
		SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
 
		return;
 
	}
 

	
 
	// No networking, close everything down again
 
	NetworkDisconnect();
 
}
 

	
 
// Used by clients, to connect to a server
 
bool NetworkClientConnectGame(const byte* host, unsigned short 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;
 
}
 

	
 
void NetworkReceive()
 
void NetworkInitGameInfo(void)
 
{
 
#if defined(WITH_REV)
 
		extern char _openttd_revision[];
 
#else
 
		const char _openttd_revision[] = "norev000";
 
#endif
 
	NetworkClientInfo *ci;
 

	
 
	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
 
	if (_network_game_info.server_name[0] == '\0')
 
		snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
 

	
 
	// The server is a client too ;)
 
	if (_network_dedicated) {
 
		_network_game_info.clients_on = 0;
 
		_network_game_info.dedicated = true;
 
	} else {
 
		_network_game_info.clients_on = 1;
 
		_network_game_info.dedicated = false;
 
	}
 
	strncpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
 
	_network_game_info.spectators_on = 0;
 
	_network_game_info.game_date = _date;
 
	_network_game_info.start_date = ConvertIntDate(_patches.starting_date);
 
	_network_game_info.map_width = TILES_X;
 
	_network_game_info.map_height = TILES_Y;
 
	_network_game_info.map_set = _opt.landscape;
 

	
 
	if (_network_game_info.server_password[0] == '\0') {
 
		_network_game_info.use_password = 0;
 
	} else {
 
		_network_game_info.use_password = 1;
 
	}
 

	
 
	// 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;
 
	if (_network_dedicated)
 
		ci->client_playas = OWNER_SPECTATOR;
 
	else
 
		ci->client_playas = _local_player + 1;
 
	strncpy(ci->client_name, _network_player_name, sizeof(ci->client_name));
 
}
 

	
 
bool NetworkServerStart(void)
 
{
 
	if (!_network_available) return false;
 

	
 
	NetworkInitialize();
 
	if (!NetworkListen())
 
		return false;
 

	
 
	// Try to start UDP-server
 
	_network_udp_server = true;
 
	_network_udp_server = NetworkUDPListen(0, _network_server_port);
 

	
 
	_network_server = true;
 
	_networking = true;
 
	_frame_counter = 0;
 
	_frame_counter_server = 0;
 
	_frame_counter_max = 0;
 
	_network_own_client_index = NETWORK_SERVER_INDEX;
 

	
 
	_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");
 
	return true;
 
}
 

	
 
// The server is rebooting...
 
// The only difference with NetworkDisconnect, is the packets that is sent
 
void NetworkReboot(void)
 
{
 
	if (_network_server) {
 
		ClientState *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) {
 
		ClientState *cs;
 
		FOR_ALL_CLIENTS(cs) {
 
			SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(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);
 
	}
 

	
 
	if (_networking && !_network_server) {
 
		memcpy(&_patches, &network_tmp_patches, sizeof(_patches));
 
	}
 

	
 
	_networking = false;
 
	_network_server = false;
 
}
 

	
 
// Receives something from the network
 
bool NetworkReceive(void)
 
{
 
	ClientState *cs;
 
	int n;
 
@@ -1243,13 +924,13 @@ void NetworkReceive()
 
	FD_ZERO(&read_fd);
 
	FD_ZERO(&write_fd);
 

	
 
	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
	FOR_ALL_CLIENTS(cs) {
 
		FD_SET(cs->socket, &read_fd);
 
		FD_SET(cs->socket, &write_fd);
 
	}
 

	
 
	// take care of listener port
 
	if (_networking_server) {
 
	if (_network_server) {
 
		FD_SET(_listensocket, &read_fd);
 
	}
 

	
 
@@ -1259,428 +940,257 @@ void NetworkReceive()
 
#else
 
	n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
 
#endif
 
	if ((n == -1) && (!_networking_server)) NetworkHandleConnectionLost();
 
	if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION);
 

	
 
	// accept clients..
 
	if (_networking_server && FD_ISSET(_listensocket, &read_fd))
 
	if (_network_server && FD_ISSET(_listensocket, &read_fd))
 
		NetworkAcceptClients();
 

	
 
	// read stuff from clients
 
	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
	FOR_ALL_CLIENTS(cs) {
 
		cs->writable = !!FD_ISSET(cs->socket, &write_fd);
 
		if (FD_ISSET(cs->socket, &read_fd)) {
 
			if (!ReadPackets(cs))
 
				cs--;
 
			if (_network_server)
 
				NetworkServer_ReadPackets(cs);
 
			else {
 
				byte res;
 
				// The client already was quiting!
 
				if (cs->quited) return false;
 
				if ((res = NetworkClient_ReadPackets(cs)) != 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;
 
}
 

	
 
	// if we're a server, and any client needs a snapshot, create a snapshot and send all commands from the server queue to the client.
 
	if (_networking_server && _transmit_file == NULL) {
 
		bool didsave = false;
 
// This sends all buffered commands (if possible)
 
static void NetworkSend(void)
 
{
 
	ClientState *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);
 
			}
 
		}
 
	}
 
}
 

	
 
		for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
			if (cs->inactive) {
 
				cs->inactive = false;
 
				// found a client waiting for a snapshot. make a snapshot.
 
				if (!didsave) {
 
					char filename[256];
 
					sprintf(filename, "%snetwork.tmp",  _path.autosave_dir);
 
					didsave = true;
 
					if (SaveOrLoad(filename, SL_SAVE) != SL_OK) error("network savedump failed");
 
					_transmit_file = ReadFileToMem(filename, &_transmit_file_size, 500000);
 
					if (_transmit_file == NULL) error("network savedump failed to load");
 
// Handle the local-command-queue
 
void NetworkHandleLocalQueue(void)
 
{
 
	if (_local_command_queue != NULL) {
 
		CommandPacket *cp;
 
		CommandPacket *cp_prev;
 

	
 
		cp = _local_command_queue;
 
		cp_prev = NULL;
 

	
 
		while (cp != NULL) {
 
			if (_frame_counter > cp->frame) {
 
				// We can execute this command
 
				NetworkExecuteCommand(cp);
 

	
 
				if (cp_prev != NULL) {
 
					cp_prev->next = cp->next;
 
					free(cp);
 
					cp = cp_prev->next;
 
				} else {
 
					// This means we are at our first packet
 
					_local_command_queue = cp->next;
 
					free(cp);
 
					cp = _local_command_queue;
 
				}
 
				// and start sending the file..
 
				cs->xmitpos = 1;
 

	
 
				// send queue of commands to client.
 
				SendQueuedCommandsToNewClient(cs);
 

	
 
				NetworkSendWelcome(cs, true);
 
			} else {
 
				// Command is in the future, skip to next
 
				//  (commands don't have to be in order in the queue!!)
 
				cp_prev = cp;
 
				cp = cp->next;
 
			}
 
		}
 
	}
 
}
 

	
 
void NetworkSend()
 

	
 
extern void StateGameLoop();
 

	
 
bool NetworkDoClientLoop(void)
 
{
 
	ClientState *cs;
 
	void *free_xmit;
 
	_frame_counter++;
 

	
 
	free_xmit = _transmit_file;
 
	NetworkHandleLocalQueue();
 

	
 
	StateGameLoop();
 

	
 
	// send stuff to all clients
 
	for(cs=_clients;cs->socket != INVALID_SOCKET; cs++) {
 
		if (cs->xmitpos) {
 
			if (cs->writable)
 
				SendXmit(cs);
 
			free_xmit = NULL;
 
		}
 
		if (cs->writable)	{
 
			if (!SendPackets(cs)) cs--;
 
	// 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)("[NET] 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)("[NET] Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter);
 
			_sync_frame = 0;
 
		}
 
	}
 

	
 
	// no clients left that xmit the file, free it.
 
	if (free_xmit) {
 
		_transmit_file = NULL;
 
		free(free_xmit);
 
	}
 
	return true;
 
}
 

	
 

	
 
void NetworkInitialize()
 
// We have to do some UDP checking
 
void NetworkUDPGameLoop(void)
 
{
 
	ClientState *cs;
 

	
 
	QueueClear(&_command_queue);
 
	QueueClear(&_ack_queue);
 
	_command_queue.last = &_command_queue.head;
 
	_network_game_list = NULL;
 

	
 
	// invalidate all clients
 
	for(cs=_clients; cs != &_clients[MAX_CLIENTS]; cs++)
 
		cs->socket = INVALID_SOCKET;
 

	
 
}
 

	
 
void NetworkClose(bool client)
 
{
 

	
 
	ClientState *cs;
 
	// invalidate all clients
 

	
 
	for(cs=_clients; cs != &_clients[MAX_CLIENTS]; cs++) if (cs->socket != INVALID_SOCKET) {
 
		CloseClient(cs);
 
		}
 

	
 
	if (!client) {
 
		// if in servermode --> close listener
 
		closesocket(_listensocket);
 
		_listensocket= INVALID_SOCKET;
 
		DEBUG(net, 1) ("[NET][TCP] closed listener on port %i", _network_server_port);
 
	if (_network_udp_server)
 
		NetworkUDPReceive();
 
	else if (_udp_client_socket != INVALID_SOCKET) {
 
		NetworkUDPReceive();
 
		if (_network_udp_broadcast > 0)
 
			_network_udp_broadcast--;
 
	}
 
}
 

	
 
void NetworkShutdown()
 
// The main loop called from ttd.c
 
//  Here we also have to do StateGameLoop if needed!
 
void NetworkGameLoop(void)
 
{
 
	_networking_server = false;
 
	_networking = false;
 
	_networking_sync = false;
 
	_frame_counter = 0;
 
	_frame_counter_max = 0;
 
	_frame_counter_srv = 0;
 
}
 
	if (!_networking) return;
 

	
 
// switch to synced mode.
 
void NetworkStartSync(bool fcreset)
 
{
 
	DEBUG(net, 3) ("[NET][SYNC] switching to synced game mode");
 
	_networking_sync = true;
 
	_frame_counter = 0;
 
	if (!NetworkReceive()) return;
 

	
 
	if (fcreset) {
 
		_frame_counter_max = 0;
 
		_frame_counter_srv = 0;
 
		_frame_fsync_last = 0;
 
		}
 
	_num_future_seed = 0;
 
	_sync_seed_1 = _sync_seed_2 = 0;
 
	memset(_my_seed_list, 0, sizeof(_my_seed_list));
 
}
 
	if (_network_server) {
 
		// We first increase the _frame_counter
 
		_frame_counter++;
 

	
 
// ************************** //
 
// * UDP Network Extensions * //
 
// ************************** //
 
		NetworkHandleLocalQueue();
 

	
 
void NetworkUDPListen(bool client)
 
{
 
	SOCKET udp;
 
	struct sockaddr_in sin;
 
	int port;
 

	
 
	if (client) { port = _network_client_port; } else { port = _network_server_port; };
 
		// Then we make the frame
 
		StateGameLoop();
 

	
 
	DEBUG(net, 1) ("[NET][UDP] listening on port %i", port);
 

	
 
	udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 

	
 
	// this disables network
 
	_network_available = !(udp == INVALID_SOCKET);
 
		_sync_seed_1 = _random_seeds[0][0];
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
		_sync_seed_2 = _random_seeds[0][1];
 
#endif
 

	
 
	// set nonblocking mode for socket
 
	{ unsigned long blocking = 1; ioctlsocket(udp, FIONBIO, &blocking); }
 

	
 
	sin.sin_family = AF_INET;
 
	sin.sin_addr.s_addr = 0;
 
	sin.sin_port = htons(port);
 

	
 
	if (bind(udp, (struct sockaddr*)&sin, sizeof(sin)) != 0)
 
		DEBUG(net, 1) ("[NET][UDP] error: bind failed on port %i", port);
 

	
 
		NetworkServer_Tick();
 
	} else {
 
		// Client
 

	
 
	// enable broadcasting
 
	{ unsigned long val=1; setsockopt(udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); }
 
	// allow reusing
 
	{ unsigned long val=1; setsockopt(udp, SOL_SOCKET, SO_REUSEADDR, (char *) &val , sizeof(val)); }
 

	
 
	if (client) { _udp_client_socket = udp; } else { _udp_server_socket = udp; } ;
 

	
 
}
 

	
 
void NetworkUDPClose(bool client)
 
{
 
	if (client) {
 
		DEBUG(net, 1) ("[NET][UDP] closed listener on port %i", _network_client_port);
 
		closesocket(_udp_client_socket);
 
		_udp_client_socket = INVALID_SOCKET;
 
		// 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 {
 
		DEBUG(net, 1) ("[NET][UDP] closed listener on port %i", _network_server_port);
 
		closesocket(_udp_server_socket);
 
		_udp_server_socket = INVALID_SOCKET;
 
		};
 
			// Else, keep on going till _frame_counter_max
 
			if (_frame_counter_max > _frame_counter) {
 
				NetworkDoClientLoop();
 
			}
 
		}
 
	}
 

	
 
void NetworkUDPReceive(bool client)
 
{
 
	struct sockaddr_in client_addr;
 
#ifndef __MORPHOS__
 
	int client_len;
 
#else
 
	LONG client_len; // for some reason we need a 'LONG' under MorphOS
 
#endif
 
	int nbytes;
 
	struct UDPPacket packet;
 
	int packet_len;
 

	
 
	SOCKET udp;
 
	if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
 

	
 
	packet_len = sizeof(packet);
 
	client_len = sizeof(client_addr);
 

	
 
	nbytes = recvfrom(udp, (char *) &packet, packet_len , 0, (struct sockaddr *) &client_addr, &client_len);
 
	if (nbytes>0) {
 
		if (packet.command_code==packet.command_check) switch (packet.command_code) {
 

	
 
 		case NET_UDPCMD_SERVERSEARCH:
 
 			if (!client) {
 
				packet.command_check=packet.command_code=NET_UDPCMD_SERVERINFO;
 
				memcpy(&packet.data,&_network_game,sizeof(_network_game));
 
				packet.data_len=sizeof(_network_game);
 
 				NetworkUDPSend(client,client_addr, packet);
 
 			}
 
 			break;
 
		case NET_UDPCMD_GETSERVERINFO:
 
			if (!client) {
 
				packet.command_check=packet.command_code=NET_UDPCMD_SERVERINFO;
 
				memcpy(&packet.data,&_network_game,sizeof(_network_game));
 
				packet.data_len=sizeof(_network_game);
 
				NetworkUDPSend(client,client_addr, packet);
 
			}
 
			break;
 
		case NET_UDPCMD_SERVERINFO:
 
 			if (client) {
 
				NetworkGameList * item;
 

	
 
				item = (NetworkGameList *) NetworkGameListAdd();
 
				item -> ip = inet_addr(inet_ntoa(client_addr.sin_addr));
 
				item -> port = ntohs(client_addr.sin_port);
 

	
 
				memcpy(item,&packet.data,packet.data_len);
 
 			}
 
 			break;
 
		}
 
	}
 
}
 

	
 
void NetworkUDPBroadCast(bool client, struct UDPPacket packet)
 
{
 
	int i=0, res;
 
	struct sockaddr_in out_addr;
 
	uint32 bcaddr;
 
	byte * bcptr;
 

	
 
	SOCKET udp;
 
	if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
 

	
 
	while (_network_ip_list[i]!=0) {
 
		bcaddr=_network_ip_list[i];
 
		out_addr.sin_family = AF_INET;
 
		if (client) { out_addr.sin_port = htons(_network_server_port); } else { out_addr.sin_port = htons(_network_client_port); };
 
		bcptr = (byte *) &bcaddr;
 
		bcptr[3]=255;
 
		out_addr.sin_addr.s_addr = bcaddr;
 
		res=sendto(udp,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &out_addr,sizeof(out_addr));
 
		if (res==-1) DEBUG(net, 1)("udp: broadcast error: %i",GET_LAST_ERROR());
 
		i++;
 
	}
 

	
 
}
 

	
 
void NetworkUDPSend(bool client, struct sockaddr_in recv,struct UDPPacket packet)
 
{
 
	SOCKET udp;
 
	if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
 

	
 
	sendto(udp,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &recv,sizeof(recv));
 
	NetworkSend();
 
}
 

	
 

	
 
bool NetworkUDPSearchGame(const byte ** _network_detected_serverip, unsigned short * _network_detected_serverport)
 
{
 
	struct UDPPacket packet;
 
	int timeout=3000;
 

	
 
	NetworkGameListClear();
 

	
 
	DEBUG(net, 0) ("[NET][UDP] searching server");
 
	*_network_detected_serverip = "255.255.255.255";
 
	*_network_detected_serverport = 0;
 

	
 
	packet.command_check=packet.command_code=NET_UDPCMD_SERVERSEARCH;
 
	packet.data_len=0;
 
	NetworkUDPBroadCast(true, packet);
 
	while (timeout>=0) {
 
		CSleep(100);
 
		timeout-=100;
 
	    NetworkUDPReceive(true);
 

	
 
		if (_network_game_count>0) {
 
			NetworkGameList * item;
 
			item = (NetworkGameList *) NetworkGameListItem(0);
 
			*_network_detected_serverip=inet_ntoa(*(struct in_addr *) &item->ip);
 
			*_network_detected_serverport=item->port;
 
 			timeout=-1;
 
 			DEBUG(net, 0) ("[NET][UDP] server found on %s", *_network_detected_serverip);
 
 			}
 

	
 
		}
 

	
 
	return (*_network_detected_serverport>0);
 

	
 
}
 

	
 

	
 
// *************************** //
 
// * New Network Core System * //
 
// *************************** //
 

	
 
void NetworkIPListInit()
 
// This tries to launch the network for a given OS
 
void NetworkStartUp(void)
 
{
 
	struct hostent* he = NULL;
 
	char hostname[250];
 
	uint32 bcaddr;
 
	int i=0;
 

	
 
	gethostname(hostname,250);
 
	DEBUG(net, 2) ("[NET][IP] init for host %s", hostname);
 
	he=gethostbyname((char *) hostname);
 

	
 
	if (he == NULL) {
 
		he = gethostbyname("localhost");
 
		}
 

	
 
	if (he == NULL) {
 
		bcaddr = inet_addr("127.0.0.1");
 
		he = gethostbyaddr(inet_ntoa(*(struct in_addr *) &bcaddr), sizeof(bcaddr), AF_INET);
 
		}
 
	DEBUG(net, 3) ("[NET][Core] Starting network...");
 
	// Network is available
 
	_network_available = true;
 
	_network_dedicated = false;
 

	
 
	if (he == NULL) {
 
		DEBUG(net, 2) ("[NET][IP] cannot resolve %s", hostname);
 
	} else {
 
		while(he->h_addr_list[i]) {
 
			bcaddr = inet_addr(inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
 
			_network_ip_list[i]=bcaddr;
 
			DEBUG(net, 2) ("[NET][IP] add %s",inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
 
			i++;
 
		}
 

	
 
	}
 
	_network_ip_list[i]=0;
 
	memset(&_network_game_info, 0, sizeof(_network_game_info));
 

	
 
}
 

	
 
/* *************************************************** */
 
	/* XXX - Hard number here, because the strings can currently handle no more
 
	    then 10 clients -- TrueLight */
 
	_network_game_info.clients_max = 10;
 

	
 
void NetworkCoreInit()
 
{
 
	DEBUG(net, 3) ("[NET][Core] init()");
 
	_network_available = true;
 
	_network_client_timeout = 300;
 
	_network_ready_ahead = 1;
 

	
 
	// [win32] winsock startup
 

	
 
	// Let's load the network in windows
 
	#if defined(WIN32)
 
	{
 
		WSADATA wsa;
 
		DEBUG(net, 3) ("[NET][Core] using windows socket library");
 
		DEBUG(net, 3) ("[NET][Core] Loading windows socket library");
 
		if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
 
			DEBUG(net, 3) ("[NET][Core] error: WSAStartup failed");
 
			_network_available=false;
 
			}
 
			DEBUG(net, 0) ("[NET][Core] Error: WSAStartup failed. Network not available.");
 
			_network_available = false;
 
			return;
 
		}
 
	}
 
	#else
 

	
 
	// [morphos/amigaos] bsd-socket startup
 

	
 
	#if defined(__MORPHOS__) || defined(__AMIGA__)
 
	{
 
		DEBUG(misc,3) ("[NET][Core] using bsd socket library");
 
		if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) {
 
			DEBUG(net, 3) ("[NET][Core] Couldn't open bsdsocket.library version 4.");
 
			_network_available=false;
 
		#if defined(__MORPHOS__) || defined(__AMIGA__)
 
		{
 
			DEBUG(misc,3) ("[NET][Core] Loading bsd socket library");
 
			if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) {
 
				DEBUG(net, 0) ("[NET][Core] Error: couldn't open bsdsocket.library version 4. Network not available.");
 
				_network_available = false;
 
				return;
 
			}
 

	
 
		#if !defined(__MORPHOS__)
 
		// for usleep() implementation (only required for legacy AmigaOS builds)
 
		if ( (TimerPort = CreateMsgPort()) ) {
 
			if ( (TimerRequest = (struct timerequest *) CreateIORequest(TimerPort, sizeof(struct timerequest))) ) {
 
				if ( OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) TimerRequest, 0) == 0 ) {
 
					if ( !(TimerBase = TimerRequest->tr_node.io_Device) ) {
 
						// free ressources...
 
						DEBUG(net, 3) ("[NET][Core] Couldn't initialize timer.");
 
						_network_available=false;
 
			#if defined(__AMIGA__)
 
			// for usleep() implementation (only required for legacy AmigaOS builds)
 
			if ( (TimerPort = CreateMsgPort()) ) {
 
				if ( (TimerRequest = (struct timerequest *) CreateIORequest(TimerPort, sizeof(struct timerequest))) ) {
 
					if ( OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) TimerRequest, 0) == 0 ) {
 
						if ( !(TimerBase = TimerRequest->tr_node.io_Device) ) {
 
							// free ressources...
 
							DEBUG(net, 0) ("[NET][Core] Error: couldn't initialize timer. Network not available.");
 
							_network_available = false;
 
							return;
 
						}
 
					}
 
				}
 
			}
 
			#endif // __AMIGA__
 
		}
 
		#endif
 

	
 
	}
 
	#else
 

	
 
	// [linux/macos] unix-socket startup
 

	
 
		DEBUG(net, 3) ("[NET][Core] using unix socket library");
 
		#endif // __MORPHOS__ / __AMIGA__
 
	#endif // WIN32
 

	
 
	#endif
 

	
 
	#endif
 

	
 

	
 
	if (_network_available) {
 
		DEBUG(net, 3) ("[NET][Core] OK: multiplayer available");
 
		// initiate network ip list
 
		NetworkIPListInit();
 
	} else
 
		DEBUG(net, 3) ("[NET][Core] FAILED: multiplayer not available");
 
	NetworkInitialize();
 
	DEBUG(net, 3) ("[NET][Core] Network online. Multiplayer available.");
 
	NetworkFindIPs();
 
}
 

	
 
/* *************************************************** */
 
// This shuts the network down
 
void NetworkShutDown(void)
 
{
 
	DEBUG(net, 3) ("[NET][Core] Shutting down the network.");
 

	
 
void NetworkCoreShutdown()
 
{
 
	DEBUG(net, 3) ("[NET][Core] shutdown()");
 
	_network_available = false;
 

	
 
	#if defined(__MORPHOS__) || defined(__AMIGA__)
 
	{
 
		// free allocated ressources
 
		#if !defined(__MORPHOS__)
 
		if (TimerBase)    { CloseDevice((struct IORequest *) TimerRequest); }
 
		if (TimerRequest) { DeleteIORequest(TimerRequest); }
 
		if (TimerPort)    { DeleteMsgPort(TimerPort); }
 
			if (TimerBase)    { CloseDevice((struct IORequest *) TimerRequest); }
 
			if (TimerRequest) { DeleteIORequest(TimerRequest); }
 
			if (TimerPort)    { DeleteMsgPort(TimerPort); }
 
		#endif
 

	
 
		if (SocketBase) {
 
@@ -1690,290 +1200,15 @@ void NetworkCoreShutdown()
 
	#endif
 

	
 
	#if defined(WIN32)
 
	{ WSACleanup();}
 
	{
 
		WSACleanup();
 
	}
 
	#endif
 
}
 

	
 
/* *************************************************** */
 

	
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string)
 
{
 
	byte c = 0;
 
	while (connection_string[c] != '\0') {
 
		if (connection_string[c] == '#') {
 
			*player = &connection_string[c+1];
 
			connection_string[c] = '\0';
 
		}
 
		if (connection_string[c] == ':') {
 
			*port = &connection_string[c+1];
 
			connection_string[c] = '\0';
 
		}
 
		c++;
 
	}
 
}
 

	
 
bool NetworkCoreConnectGame(const byte* b, unsigned short port)
 
{
 
	if (!_network_available) return false;
 

	
 
	if (strcmp(b,"auto")==0) {
 
		// do autodetect
 
		NetworkUDPSearchGame(&b, &port);
 
	}
 

	
 
	if (port==0) {
 
		// autodetection failed
 
		if (_networking_override) NetworkLobbyShutdown();
 
		ShowErrorMessage(-1, STR_NETWORK_ERR_NOSERVER, 0, 0);
 
		_switch_mode_errorstr = STR_NETWORK_ERR_NOSERVER;
 
		return false;
 
	}
 

	
 
	NetworkInitialize();
 
	_networking = NetworkConnect(b, port);
 
	if (_networking) {
 
		NetworkLobbyShutdown();
 
		IConsoleCmdExec("exec scripts/on_client.scr 0");
 
	} else {
 
		if (_networking_override)
 
			NetworkLobbyShutdown();
 

	
 
		ShowErrorMessage(-1, STR_NETWORK_ERR_NOCONNECTION,0,0);
 
		_switch_mode_errorstr = STR_NETWORK_ERR_NOCONNECTION;
 
	}
 
	return _networking;
 
}
 

	
 
/* *************************************************** */
 

	
 
bool NetworkCoreConnectGameStruct(NetworkGameList * item)
 
{
 
	return NetworkCoreConnectGame(inet_ntoa(*(struct in_addr *) &item->ip),item->port);
 
}
 

	
 
/* *************************************************** */
 

	
 
bool NetworkCoreStartGame()
 
{
 
	if (!_network_available) return false;
 
	NetworkLobbyShutdown();
 
	NetworkInitialize();
 
	NetworkListen();
 
	NetworkUDPListen(false);
 
	_networking_server = true;
 
	_networking = true;
 
	NetworkGameFillDefaults(); // clears the network game info
 
	_network_game.players_on++; // the serverplayer is online
 
	// execute server initialization script
 
	IConsoleCmdExec("exec scripts/on_server.scr 0");
 
	return true;
 
}
 

	
 
/* *************************************************** */
 

	
 
void NetworkCoreDisconnect()
 
{
 
	/* terminate server */
 
	if (_networking_server) {
 
		NetworkUDPClose(false);
 
		NetworkClose(false);
 
		}
 

	
 
	/* terminate client connection */
 
	else if (_networking) {
 
		NetworkClose(true);
 
		}
 

	
 
	NetworkShutdown();
 
}
 

	
 
/* *************************************************** */
 

	
 
void NetworkCoreLoop(bool incomming)
 
{
 
	if (incomming) {
 
		// incomming
 
		if ( _udp_client_socket != INVALID_SOCKET ) NetworkUDPReceive(true);
 
		if ( _udp_server_socket != INVALID_SOCKET ) NetworkUDPReceive(false);
 

	
 
		if (_networking)
 
			NetworkReceive();
 

	
 
	} else {
 
		if ( _udp_client_socket != INVALID_SOCKET ) NetworkUDPReceive(true);
 
		if ( _udp_server_socket != INVALID_SOCKET ) NetworkUDPReceive(false);
 

	
 
		if (_networking)
 
			NetworkSend();
 
	}
 
}
 

	
 
void NetworkLobbyInit()
 
{
 
	DEBUG(net, 3) ("[NET][Lobby] init()");
 
	NetworkUDPListen(true);
 
}
 

	
 
void NetworkLobbyShutdown()
 
{
 
	DEBUG(net, 3) ("[NET][Lobby] shutdown()");
 
	NetworkUDPClose(true);
 
}
 

	
 

	
 
// ******************************** //
 
// * Network Game List Extensions * //
 
// ******************************** //
 

	
 
void NetworkGameListClear()
 
{
 
	NetworkGameList * item;
 
	NetworkGameList * next;
 

	
 
	DEBUG(net, 4) ("[NET][G-List] cleared server list");
 

	
 
	item = _network_game_list;
 
#else
 

	
 
	while (item != NULL) {
 
		next = (NetworkGameList *) item -> _next;
 
		free (item);
 
		item = next;
 
	}
 
	_network_game_list=NULL;
 
	_network_game_count=0;
 
}
 

	
 
NetworkGameList * NetworkGameListAdd()
 
{
 
	NetworkGameList * item;
 
	NetworkGameList * before;
 

	
 
	DEBUG(net, 4) ("[NET][G-List] added server to list");
 

	
 
	item = _network_game_list;
 
	before = item;
 
	while (item != NULL) {
 
		before = item;
 
		item = (NetworkGameList *) item -> _next;
 
	}
 

	
 
	item = malloc(sizeof(NetworkGameList));
 
	item -> _next = NULL;
 

	
 
	if (before == NULL) {
 
		_network_game_list = item;
 
	} else
 
		before -> _next = item;
 

	
 
	_network_game_count++;
 
	return item;
 
}
 

	
 
void NetworkGameListFromLAN()
 
{
 
	struct UDPPacket packet;
 
	DEBUG(net, 2) ("[NET][G-List] searching server over lan");
 
	NetworkGameListClear();
 
	packet.command_check=packet.command_code=NET_UDPCMD_SERVERSEARCH;
 
	packet.data_len=0;
 
	NetworkUDPBroadCast(true,packet);
 
}
 

	
 
void NetworkGameListFromInternet()
 
{
 
	DEBUG(net, 2) ("[NET][G-List] searching servers over internet");
 
	NetworkGameListClear();
 

	
 
	// **TODO** masterserver communication [internet protocol list]
 
}
 

	
 
NetworkGameList * NetworkGameListItem(uint16 index)
 
{
 
	NetworkGameList * item;
 
	NetworkGameList * next;
 
	uint16 cnt = 0;
 

	
 
	item = _network_game_list;
 

	
 
	while ((item != NULL) && (cnt != index)) {
 
		next = (NetworkGameList *) item -> _next;
 
		item = next;
 
		cnt++;
 
	}
 

	
 
	return item;
 
}
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string) {}
 
void NetworkUpdateClientInfo(uint16 client_index) {}
 

	
 
// *************************** //
 
// * Network Game Extensions * //
 
// *************************** //
 

	
 
void NetworkGameFillDefaults()
 
{
 
	NetworkGameInfo * game = &_network_game;
 
	#if defined(WITH_REV)
 
		extern char _openttd_revision[];
 
	#else
 
		const char _openttd_revision[] = "norev000";
 
	#endif
 

	
 
	DEBUG(net, 4) ("[NET][G-Info] setting defaults");
 

	
 
	ttd_strlcpy(game->server_name, "OpenTTD Game", sizeof(game->server_name));
 
	game->game_password[0]='\0';
 
	game->map_name[0]='\0';
 
	ttd_strlcpy(game->server_revision, _openttd_revision, sizeof(game->server_revision));
 
	game->game_date=0;
 

	
 
	game->map_height=0;
 
	game->map_width=0;
 
	game->map_set=0;
 

	
 
	game->players_max=8;
 
	game->players_on=0;
 

	
 
	game->server_lang=_dynlang.curr;
 
}
 

	
 
void NetworkGameChangeDate(uint16 newdate)
 
{
 
	if (_networking_server)
 
		_network_game.game_date = newdate;
 
}
 

	
 
#else // not ENABLE_NETWORK
 

	
 
// stubs
 
void NetworkInitialize() {}
 
void NetworkShutdown() {}
 
void NetworkListen() {}
 
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() {}
 
void NetworkSendSyncPackets() {}
 
void NetworkSendFrameSyncPackets() {}
 
bool NetworkCheckClientReady() { return true; }
 
void NetworkCoreInit() { _network_available=false; };
 
void NetworkCoreShutdown() {};
 
void NetworkCoreDisconnect() {};
 
void NetworkCoreLoop(bool incomming) {};
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string) {};
 
bool NetworkCoreConnectGame(const byte* b, unsigned short port) {return false;};
 
bool NetworkCoreStartGame() {return false;};
 
void NetworkLobbyShutdown() {};
 
void NetworkLobbyInit() {};
 
void NetworkGameListClear() {};
 
NetworkGameList * NetworkGameListAdd() {return NULL;};
 
void NetworkGameListFromLAN() {};
 
void NetworkGameListFromInternet() {};
 
void NetworkGameFillDefaults() {};
 
NetworkGameList * NetworkGameListItem(uint16 index) {return NULL;};
 
bool NetworkCoreConnectGameStruct(NetworkGameList * item) {return false;};
 
void NetworkGameChangeDate(uint16 newdate) {};
 

	
 
#endif
 
#endif /* ENABLE_NETWORK */
network.h
Show inline comments
 
#ifndef NETWORK_H
 
#define NETWORK_H
 

	
 
#include "network_core.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
// 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 NETWORK_DISCOVER_PORT 3978
 
#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
 

	
 
#define NETWORK_NAME_LENGTH 80
 
#define NETWORK_HOSTNAME_LENGTH 80
 
#define NETWORK_REVISION_LENGTH 10
 
#define NETWORK_PASSWORD_LENGTH 20
 
#define NETWORK_PLAYERS_LENGTH 200
 

	
 
// 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[40];			// name of the game
 
	char server_revision[8];	// server game version
 
	byte server_lang;					// langid
 
	byte players_max;					// max players allowed on server
 
	byte players_on;					// current count of players on server
 
	uint16 game_date;					// current date
 
	char game_password[10];		// should fit ... 10 chars
 
	char map_name[40];				// map which is played ["random" for a randomized map]
 
	uint map_width;						// map width / 8
 
	uint map_height;					// map height / 8
 
	byte map_set;							// graphical set
 
	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
 
	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 spectators_on;															// How many spectators do we have?
 
	uint16 game_date;																// Current date
 
	uint16 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?
 
} NetworkGameInfo;
 

	
 
//typedef struct NetworkGameList;
 
typedef struct NetworkPlayerInfo {
 
	char company_name[NETWORK_NAME_LENGTH];					// Company name
 
	char password[NETWORK_PASSWORD_LENGTH];					// The password for the player
 
	byte 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?
 
	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, ..)
 
} NetworkPlayerInfo;
 

	
 
typedef struct NetworkClientInfo {
 
	uint16 client_index;														// Index of the client (same as ClientState->index)
 
	char client_name[NETWORK_NAME_LENGTH];					// Name of the client
 
	byte client_lang;																// The language of the client
 
	byte client_playas;															// As which player is this client playing
 
	uint32 client_ip;																// IP-address of the client (so he can be banned)
 
	uint16 join_date;																// Gamedate the player has joined
 
} NetworkClientInfo;
 

	
 
typedef struct NetworkGameList {
 
	NetworkGameInfo item;
 
	NetworkGameInfo info;
 
	uint32 ip;
 
	uint16 port;
 
	struct NetworkGameList * _next;
 
	bool online;																		// False if the server did not respond (default status)
 
	struct NetworkGameList *next;
 
} NetworkGameList;
 

	
 
enum {
 
	NET_EVENT_SUBSIDY = 0,
 
};
 
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_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_NAME_LENGTH];
 
VARDEF char _network_default_ip[NETWORK_HOSTNAME_LENGTH];
 

	
 
VARDEF uint16 _network_own_client_index;
 

	
 
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
 

	
 
// networking settings
 
VARDEF uint32 _network_ip_list[MAX_INTERFACES + 1]; // Network IPs
 
VARDEF uint16 _network_game_count;
 

	
 
NetworkGameInfo _network_game;
 
NetworkGameList * _network_game_list;
 
VARDEF uint16 _network_lobby_company_count;
 

	
 
VARDEF uint _network_client_port;
 
VARDEF uint _network_server_port;
 
VARDEF bool _is_network_server; // Does this client wants to be a network-server?
 
VARDEF char _network_server_name[NETWORK_NAME_LENGTH];
 

	
 
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;
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
// Those variables must always be registered!
 
VARDEF bool _networking;
 
VARDEF bool _network_available;  // is network mode available?
 
VARDEF bool _network_server; // network-server is active
 
VARDEF bool _network_dedicated; // are we a dedicated server?
 
VARDEF byte _network_playas; // an id to play as..
 

	
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string);
 
void NetworkUpdateClientInfo(uint16 client_index);
 

	
 
#endif /* NETWORK_H */
network_client.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "network_data.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "network_client.h"
 
#include "network_gamelist.h"
 
#include "command.h"
 
#include "gfx.h"
 
#include "window.h"
 
#include "settings.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;
 

	
 
void NetworkRecvPatchSettings(Packet *p);
 

	
 
// **********
 
// 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:
 
	//    <none>
 
	//
 
	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
 
	//
 

	
 
#if defined(WITH_REV)
 
		extern char _openttd_revision[];
 
#else
 
		const char _openttd_revision[] = "norev000";
 
#endif
 
	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); // Password
 
	NetworkSend_uint8(p, NETLANG_ANY); // Language
 
	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:
 
	//    <none>
 
	//
 

	
 
	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:
 
	//    <none>
 
	//
 

	
 
	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
 
	//    uint32: decode_params
 
	//      10 times the last one (lengthof(cp->dp))
 
	//    uint8:  CallBackID (see callback_table.c)
 
	//
 

	
 
	int i;
 
	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);
 
	for (i = 0; i < lengthof(cp->dp); i++) {
 
		NetworkSend_uint32(p, cp->dp[i]);
 
	}
 
	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 desttype, 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, desttype);
 
	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);
 
}
 

	
 

	
 
// **********
 
// 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_COMPANY_INFO)
 
{
 
	byte company_info_version;
 
	int i;
 

	
 
	company_info_version = NetworkRecv_uint8(p);
 

	
 
	if (company_info_version == 1) {
 
		byte total;
 
		byte current;
 

	
 
		total = NetworkRecv_uint8(p);
 
		_network_lobby_company_count = total;
 

	
 
		// There is no data at all..
 
		if (total == 0)
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		current = NetworkRecv_uint8(p) - 1;
 
		if (current >= MAX_PLAYERS)
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		NetworkRecv_string(p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
 
		_network_player_info[current].inaugurated_year = NetworkRecv_uint8(p);
 
		_network_player_info[current].company_value = NetworkRecv_uint64(p);
 
		_network_player_info[current].money = NetworkRecv_uint64(p);
 
		_network_player_info[current].income = NetworkRecv_uint64(p);
 
		_network_player_info[current].performance = NetworkRecv_uint16(p);
 
		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
 
			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(p);
 
		for (i = 0; i < NETWORK_STATION_TYPES; i++)
 
			_network_player_info[current].num_station[i] = NetworkRecv_uint16(p);
 

	
 
		NetworkRecv_string(p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
 

	
 
		InvalidateWindow(WC_NETWORK_WINDOW, 0);
 

	
 
		if (total == current + 1)
 
			// This was the last one
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
		else
 
			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(p);
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	if (ci != NULL) {
 
		byte playas;
 
		char name[NETWORK_NAME_LENGTH];
 

	
 
		playas = NetworkRecv_uint8(p);
 
		NetworkRecv_string(p, name, sizeof(name));
 

	
 
		if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
 
			// Client name changed, display the change
 
			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, ci->client_name, 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));
 
		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 = NetworkRecv_uint8(p);
 
		NetworkRecv_string(p, ci->client_name, sizeof(ci->client_name));
 
		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(p);
 

	
 
	if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED ||
 
			error == NETWORK_ERROR_PLAYER_MISMATCH) {
 
		// We made an error in the protocol, and our connection is closed.... :(
 
		_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
 
	} else if (error == NETWORK_ERROR_WRONG_REVISION) {
 
		// Wrong revision :(
 
		_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
 
	} else if (error == NETWORK_ERROR_WRONG_PASSWORD) {
 
		// Wrong password
 
		_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
 
	} else if (error == NETWORK_ERROR_KICKED) {
 
		_switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
 
	}
 

	
 
	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	return NETWORK_RECV_STATUS_SERVER_ERROR;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
 
{
 
	NetworkPasswordType type;
 
	type = NetworkRecv_uint8(p);
 

	
 
	if (type == NETWORK_GAME_PASSWORD) {
 
		ShowNetworkNeedGamePassword();
 
		return NETWORK_RECV_STATUS_OKAY;
 
	} else if (type == NETWORK_COMPANY_PASSWORD) {
 
		ShowNetworkNeedCompanyPassword();
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
 
{
 
	_network_own_client_index = NetworkRecv_uint16(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(p);
 
	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	// We are put on hold for receiving the map.. we need GUI for this ;)
 
	DEBUG(net, 1)("[NET] The server is currently busy sending the map to someone else.. please hold..." );
 
	DEBUG(net, 1)("[NET]  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(p);
 

	
 
	// First packet, init some stuff
 
	if (maptype == MAP_PACKET_START) {
 
		// The name for the temp-map
 
		sprintf(filename, "%s%snetwork_client.tmp",  _path.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(p);
 

	
 
		_network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING;
 
		_network_join_kbytes = 0;
 
		_network_join_kbytes_total = NetworkRecv_uint32(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);
 
	}
 

	
 
	if (maptype == MAP_PACKET_PATCH) {
 
		NetworkRecvPatchSettings(p);
 
	}
 

	
 
	// Check if this was the last packet
 
	if (maptype == MAP_PACKET_END) {
 
		// We also get, very nice, the player_seeds in this packet
 
		int i;
 
		for (i = 0; i < MAX_PLAYERS; i++) {
 
			_player_seeds[i][0] = NetworkRecv_uint32(p);
 
			_player_seeds[i][1] = NetworkRecv_uint32(p);
 
		}
 

	
 
		fclose(file_pointer);
 

	
 
		_network_join_status = NETWORK_JOIN_STATUS_PROCESSING;
 
		InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
		// The map is done downloading, load it
 
		// Load the map
 
		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;
 
		}
 
		_opt_mod_ptr = &_opt;
 

	
 
		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
		// Say we received the map and loaded it correctly!
 
		SEND_COMMAND(PACKET_CLIENT_MAP_OK)();
 

	
 
		if (_network_playas == 0 || _network_playas > MAX_PLAYERS ||
 
				!DEREF_PLAYER(_network_playas - 1)->is_active) {
 

	
 
			if (_network_playas == OWNER_SPECTATOR) {
 
				// The client wants to be a spectator..
 
				_local_player = OWNER_SPECTATOR;
 
			} else {
 
				// send a command to make a new player
 
				_local_player = 0;
 
				NetworkSend_Command(0, 0, 0, CMD_PLAYER_CTRL, NULL);
 
				_local_player = OWNER_SPECTATOR;
 
			}
 
		} else {
 
			// take control over an existing company
 
			_local_player = _network_playas - 1;
 
		}
 

	
 
		// Remeber the player
 
		if (_local_player != OWNER_SPECTATOR)
 
			_network_playas = _local_player + 1;
 
		else
 
			_network_playas = OWNER_SPECTATOR;
 
	}
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_FRAME)
 
{
 
	_frame_counter_server = NetworkRecv_uint32(p);
 
	_frame_counter_max = NetworkRecv_uint32(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(p);
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
		_sync_seed_2 = NetworkRecv_uint32(p);
 
#endif
 
	}
 
#endif
 
	DEBUG(net, 7)("[NET] 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,6)("[NET] 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(p);
 
	_sync_seed_1 = NetworkRecv_uint32(p);
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
	_sync_seed_2 = NetworkRecv_uint32(p);
 
#endif
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMMAND)
 
{
 
	int i;
 
	CommandPacket *cp = malloc(sizeof(CommandPacket));
 
	cp->player = NetworkRecv_uint8(p);
 
	cp->cmd = NetworkRecv_uint32(p);
 
	cp->p1 = NetworkRecv_uint32(p);
 
	cp->p2 = NetworkRecv_uint32(p);
 
	cp->tile = NetworkRecv_uint32(p);
 
	for (i = 0; i < lengthof(cp->dp); i++)
 
		cp->dp[i] = NetworkRecv_uint32(p);
 
	cp->callback = NetworkRecv_uint8(p);
 
	cp->frame = NetworkRecv_uint32(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)
 
{
 
	NetworkAction action = NetworkRecv_uint8(p);
 
	char msg[MAX_TEXT_MSG_LEN];
 
	NetworkClientInfo *ci, *ci_to;
 
	uint16 index;
 
	char name[NETWORK_NAME_LENGTH];
 

	
 
	index = NetworkRecv_uint16(p);
 
	NetworkRecv_string(p, msg, MAX_TEXT_MSG_LEN);
 

	
 
	ci_to = NetworkFindClientInfoFromIndex(index);
 
	if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
 

	
 
	if (action == NETWORK_ACTION_CHAT_TO_CLIENT) {
 
		snprintf(name, 80, "%s", ci_to->client_name);
 
		ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
	} else if (action == NETWORK_ACTION_CHAT_TO_PLAYER) {
 
		GetString(name, DEREF_PLAYER(ci_to->client_playas-1)->name_1);
 
		ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
	} else {
 
		snprintf(name, 80, "%s", ci_to->client_name);
 
		ci = ci_to;
 
	}
 

	
 
	if (ci != NULL)
 
		NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas-1), name, "%s", msg);
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
 
{
 
	int errorno;
 
	char str1[100], str2[100];
 
	uint16 index;
 
	NetworkClientInfo *ci;
 

	
 
	index = NetworkRecv_uint16(p);
 
	errorno = NetworkRecv_uint8(p);
 

	
 
	GetString(str1, STR_NETWORK_ERR_LEFT);
 
	GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	if (ci != NULL) {
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, ci->client_name, "%s (%s)", str1, str2);
 

	
 
		// 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 str1[100], str2[100];
 
	uint16 index;
 
	NetworkClientInfo *ci;
 

	
 
	index = NetworkRecv_uint16(p);
 
	NetworkRecv_string(p, str2, 100);
 

	
 
	GetString(str1, STR_NETWORK_ERR_LEFT);
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	if (ci != NULL) {
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, ci->client_name, "%s (%s)", str1, str2);
 

	
 
		// The client is gone, give the NetworkClientInfo free
 
		ci->client_index = NETWORK_EMPTY_INDEX;
 
	} else {
 
		DEBUG(net, 0)("[NET] Error - 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)
 
{
 
	char str1[100];
 
	uint16 index;
 
	NetworkClientInfo *ci;
 

	
 
	index = NetworkRecv_uint16(p);
 

	
 
	GetString(str1, STR_NETWORK_CLIENT_JOINED);
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	if (ci != NULL) {
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, ci->client_name, "%s", str1);
 
	}
 

	
 
	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
 
	// OWNER_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;
 
}
 

	
 

	
 

	
 

	
 
// 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),
 
	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),
 
};
 

	
 
// If this fails, check the array above with network_data.h
 
assert_compile(lengthof(_network_client_packet) == PACKET_END);
 

	
 
extern const SettingDesc patch_settings[];
 

	
 
// This is a TEMPORARY solution to get the patch-settings
 
//  to the client. When the patch-settings are saved in the savegame
 
//  this should be removed!!
 
void NetworkRecvPatchSettings(Packet *p)
 
{
 
	const SettingDesc *item;
 

	
 
	item = patch_settings;
 

	
 
	while (item->name != NULL) {
 
		switch (item->flags) {
 
			case SDT_BOOL:
 
			case SDT_INT8:
 
			case SDT_UINT8:
 
				*(uint8 *)(item->ptr) = NetworkRecv_uint8(p);
 
				break;
 
			case SDT_INT16:
 
			case SDT_UINT16:
 
				*(uint16 *)(item->ptr) = NetworkRecv_uint16(p);
 
				break;
 
			case SDT_INT32:
 
			case SDT_UINT32:
 
				*(uint32 *)(item->ptr) = NetworkRecv_uint32(p);
 
				break;
 
		}
 
		item++;
 
	}
 
}
 

	
 
// 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(ClientState *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(p);
 
		if (type < PACKET_END && _network_client_packet[type] != NULL) {
 
			res = _network_client_packet[type](p);
 
		}	else {
 
			res = NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
			DEBUG(net, 0)("[NET][client] Received invalid packet type %d", type);
 
		}
 

	
 
		free(p);
 
	}
 

	
 
	return res;
 
}
 

	
 
#endif /* ENABLE_NETWORK */
network_client.h
Show inline comments
 
new file 100644
 
#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);
 

	
 
NetworkRecvStatus NetworkClient_ReadPackets(ClientState *cs);
 
void NetworkClient_Connected(void);
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif // NETWORK_CLIENT_H
network_core.h
Show inline comments
 
new file 100644
 
#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
 

	
 
// Windows stuff
 
#if defined(WIN32)
 
#	include <windows.h>
 
#	include <winsock2.h>
 
#	include <ws2tcpip.h>
 
#	pragma comment (lib, "ws2_32.lib")
 
#	define ENABLE_NETWORK // On windows, the network is always enabled
 
#	define GET_LAST_ERROR() WSAGetLastError()
 
#	define EWOULDBLOCK WSAEWOULDBLOCK
 
// Windows has some different names for some types..
 
typedef SSIZE_T ssize_t;
 
typedef unsigned long in_addr_t;
 
typedef INTERFACE_INFO IFREQ;
 
#endif // WIN32
 

	
 
// UNIX stuff
 
#if defined(UNIX)
 
#	define SOCKET int
 
#	define INVALID_SOCKET -1
 
typedef struct ifreq IFREQ;
 
#	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 <unistd.h>
 
#	include <sys/ioctl.h>
 
#	if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
#		include <be/net/socket.h>
 
#		include <be/kernel/OS.h> // snooze()
 
#		include <be/net/netdb.h>
 
		typedef unsigned long in_addr_t;
 
#		define INADDR_NONE INADDR_BROADCAST
 
#	else
 
#		include <sys/socket.h>
 
#		include <netinet/in.h>
 
#		include <netinet/tcp.h>
 
#		include <arpa/inet.h>
 
#		include <net/if.h>
 
#		include <ifaddrs.h>
 
// If for any reason ifaddrs.h does not exist on a system, remove define below
 
//   and an other system will be used to fetch ips from the system
 
#		define HAVE_GETIFADDRS
 
#	endif // BEOS_NET_SERVER
 
#	include <errno.h>
 
#	include <sys/time.h>
 
#	include <netdb.h>
 
#endif // UNIX
 

	
 
// MorphOS and Amiga stuff
 
#if defined(__MORPHOS__) || defined(__AMIGA__)
 
#	include <exec/types.h>
 
#	include <proto/exec.h>		// required for Open/CloseLibrary()
 
#	if defined(__MORPHOS__)
 
#		include <sys/filio.h> 	// FION#? defines
 
#	else // __AMIGA__
 
#		include	<proto/socket.h>
 
#	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)
 

	
 
	struct Library *SocketBase = NULL;
 
#endif // __MORPHOS__ || __AMIGA__
 

	
 
#endif // NETWORK_CORE_H
network_data.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "network_data.h"
 

	
 
// Is the network enabled?
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "network_client.h"
 
#include "command.h"
 
#include "callback_table.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 & 0xFF;
 
}
 

	
 
void NetworkSend_uint16(Packet *packet, uint16 data)
 
{
 
	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
 
	packet->buffer[packet->size++] = data & 0xFF;
 
	packet->buffer[packet->size++] = (data >> 8) & 0xFF;
 
}
 

	
 
void NetworkSend_uint32(Packet *packet, uint32 data)
 
{
 
	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
 
	packet->buffer[packet->size++] = data & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >> 8) & 0xFF;
 
}
 

	
 
void NetworkSend_uint64(Packet *packet, uint64 data)
 
{
 
	assert(packet->size < sizeof(packet->buffer) - sizeof(data));
 
	packet->buffer[packet->size++] = data & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >> 8) & 0xFF;
 
}
 

	
 
// 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, ClientState *cs)
 
{
 
	Packet *p;
 
	assert(packet != NULL);
 

	
 
	packet->pos = 0;
 
	packet->next = NULL;
 

	
 
	packet->buffer[0] = packet->size & 0xFF;
 
	packet->buffer[1] = packet->size >> 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
 
NetworkRecvStatus CloseConnection(ClientState *cs)
 
{
 
	CloseClient(cs);
 

	
 
	// Clients drop back to the main menu
 
	if (!_network_server) {
 
		_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(ClientState *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) ("[NET] 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(Packet *packet)
 
{
 
	return packet->buffer[packet->pos++];
 
}
 

	
 
uint16 NetworkRecv_uint16(Packet *packet)
 
{
 
	uint16 n;
 
	n  = (uint16)packet->buffer[packet->pos++];
 
	n += (uint16)packet->buffer[packet->pos++] << 8;
 
	return n;
 
}
 

	
 
uint32 NetworkRecv_uint32(Packet *packet)
 
{
 
	uint32 n;
 
	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(Packet *packet)
 
{
 
	uint64 n;
 
	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(Packet *p, char* buffer, size_t size)
 
{
 
	int pos;
 
	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;
 
}
 

	
 
// 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(ClientState *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..
 
					if (err != 104) // 104 is Connection Reset by Peer
 
						DEBUG(net, 0) ("[NET] 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 us :(
 
				*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..
 
				if (err != 104) // 104 is Connection Reset by Peer
 
					DEBUG(net, 0) ("[NET] recv() failed with error %d", err);
 
				*status = CloseConnection(cs);
 
				return NULL;
 
			}
 
			// Connection would block
 
			return NULL;
 
		}
 
		if (res == 0) {
 
			// Client/server has left us :(
 
			*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(ClientState *cs, CommandPacket *cp)
 
{
 
	CommandPacket *new_cp = malloc(sizeof(CommandPacket));
 

	
 
	*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;
 
	}
 
}
 

	
 
// If this fails, make sure you change the following line below:
 
//   'memcpy(qp->dp, _decode_parameters, 10 * sizeof(uint32));'
 
// Also, in network_data.h, change the size of CommandPacket->dp!
 
// (this protection is there to make sure in network.h dp is of the right size!)
 
assert_compile(sizeof(_decode_parameters) == 20 * sizeof(uint32));
 

	
 
// Prepare a DoCommand to be send over the network
 
void NetworkSend_Command(uint32 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) ("[NET] 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
 
	}
 

	
 
	// Copy the _decode_parameters to dp
 
	memcpy(c->dp, _decode_parameters, 20 * sizeof(uint32));
 

	
 
	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 then others.
 
		//   So to keep the game fair, we delay the command with 1 tick
 
		//   which gives about the same speed as most clients.
 
		ClientState *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;
 
	memcpy(_decode_parameters, cp->dp, sizeof(cp->dp));
 
	/* cp->callback is unsigned. so we don't need to do lower bounds checking. */
 
	if (cp->callback > _callback_table_count) {
 
		DEBUG(net,0) ("[NET] 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 */
network_data.h
Show inline comments
 
new file 100644
 
#ifndef NETWORK_DATA_H
 
#define NETWORK_DATA_H
 

	
 
#include "ttd.h"
 
#include "network.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 1
 
// What version of company info is this?
 
#define NETWORK_COMPANY_INFO_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;
 
	byte player;
 
	uint32 cmd;
 
	uint32 p1;
 
	uint32 p2;
 
	uint32 tile; // Always make it uint32, so it is bigmap compatible
 
	uint32 dp[20]; // decode_params
 
	uint32 frame; // In which frame must this packet be executed?
 
	byte callback;
 
} 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_PATCH,
 
	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_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,
 
} NetworkErrorCode;
 

	
 
// Actions that can be used for NetworkTextMessage
 
typedef enum {
 
	NETWORK_ACTION_JOIN_LEAVE,
 
	NETWORK_ACTION_CHAT,
 
	NETWORK_ACTION_CHAT_PLAYER,
 
	NETWORK_ACTION_CHAT_CLIENT,
 
	NETWORK_ACTION_CHAT_TO_CLIENT,
 
	NETWORK_ACTION_CHAT_TO_PLAYER,
 
	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 ClientState {
 
	int 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 quited;
 

	
 
	Packet *packet_queue; // Packets that are awaiting delivery
 
	Packet *packet_recv; // Partially received packet
 

	
 
	CommandPacket *command_queue; // The command-queue awaiting delivery
 
} ClientState;
 

	
 
// 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_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_END // Should ALWAYS be on the end of this list!! (period)
 
} PacketType;
 

	
 
typedef enum {
 
	DESTTYPE_BROADCAST,
 
	DESTTYPE_PLAYER,
 
	DESTTYPE_CLIENT
 
} DestType;
 

	
 
CommandPacket *_local_command_queue;
 

	
 
SOCKET _udp_client_socket; // udp client socket
 

	
 
// Here we keep track of the clients
 
//  (and the client uses [0] for his own communication)
 
ClientState _clients[MAX_CLIENTS];
 
#define DEREF_CLIENT(i) (&_clients[i])
 
// This returns the NetworkClientInfo from a ClientState
 
#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(ClientState *cs, Packet *p)
 
#define DEF_SERVER_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(ClientState *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 != &_clients[MAX_CLIENTS] && cs->socket != INVALID_SOCKET; cs++)
 

	
 
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, ClientState *cs);
 

	
 
uint8 NetworkRecv_uint8(Packet *packet);
 
uint16 NetworkRecv_uint16(Packet *packet);
 
uint32 NetworkRecv_uint32(Packet *packet);
 
uint64 NetworkRecv_uint64(Packet *packet);
 
void NetworkRecv_string(Packet *packet, char* buffer, size_t size);
 
Packet *NetworkRecv_Packet(ClientState *cs, NetworkRecvStatus *status);
 

	
 
bool NetworkSend_Packets(ClientState *cs);
 
void NetworkExecuteCommand(CommandPacket *cp);
 
void NetworkAddCommandQueue(ClientState *cs, CommandPacket *cp);
 

	
 
// from network.c
 
void CloseClient(ClientState *cs);
 
void NetworkTextMessage(NetworkAction action, uint16 color, const char *name, const char *str, ...);
 
void NetworkGetClientName(char *clientname, size_t size, ClientState *cs);
 
uint NetworkCalculateLag(const ClientState *cs);
 
byte NetworkGetCurrentLanguageIndex();
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index);
 
ClientState *NetworkFindClientStateFromIndex(uint16 client_index);
 
unsigned long NetworkResolveHost(const char *hostname);
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif // NETWORK_DATA_H
network_gamelist.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "network_data.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
//
 
// This file handles the GameList
 
// Also, it handles the request to a server for data about the server
 

	
 
extern void UpdateNetworkGameWindow(bool unselect);
 

	
 
void NetworkGameListClear(void)
 
{
 
	NetworkGameList *item;
 
	NetworkGameList *next;
 

	
 
	item = _network_game_list;
 

	
 
	while (item != NULL) {
 
		next = item->next;
 
		free(item);
 
		item = next;
 
	}
 
	_network_game_list = NULL;
 
	_network_game_count = 0;
 

	
 
	UpdateNetworkGameWindow(true);
 

	
 
	DEBUG(net, 4)("[NET][GameList] Cleared list");
 
}
 

	
 
NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port)
 
{
 
	NetworkGameList *item;
 

	
 
	item = _network_game_list;
 
	if (item != NULL) {
 
		while (item->next != NULL) {
 
			if (item->ip == ip && item->port == port)
 
				return item;
 
			item = item->next;
 
		}
 

	
 
		if (item->ip == ip && item->port == port)
 
			return item;
 

	
 
		item->next = malloc(sizeof(*item));
 
		item = item->next;
 
	} else {
 
		item = malloc(sizeof(*item));
 
		_network_game_list = item;
 
	}
 

	
 
	DEBUG(net, 4) ("[NET][GameList] Added server to list");
 

	
 
	memset(item, 0, sizeof(*item));
 

	
 
	item->next = NULL;
 
	item->ip = ip;
 
	item->port = port;
 
	_network_game_count++;
 

	
 
	UpdateNetworkGameWindow(false);
 

	
 
	return item;
 
}
 

	
 
void NetworkGameListAddQueriedItem(NetworkGameInfo *info, bool server_online)
 
{
 
	// We queried a server and now we are going to add it to the list
 
	NetworkGameList *item;
 

	
 
	item = NetworkGameListAddItem(_network_last_host_ip, _network_last_port);
 
	item->online = server_online;
 
	memcpy(&item->info, info, sizeof(NetworkGameInfo));
 
	ttd_strlcpy(item->info.hostname, _network_last_host, sizeof(item->info.hostname));
 

	
 
	UpdateNetworkGameWindow(false);
 
}
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 

	
network_gamelist.h
Show inline comments
 
new file 100644
 
#ifndef NETWORK_GAMELIST_H
 
#define NETWORK_GAMELIST_H
 

	
 
void NetworkGameListClear(void);
 
NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port);
 
void NetworkGameListAddQueriedItem(NetworkGameInfo *info, bool server_online);
 

	
 
#endif /* NETWORK_GAMELIST_H */

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)