1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-30 01:49:10 +00:00

Compare commits

..

1 Commits
0.4.7 ... 0.3.6

Author SHA1 Message Date
darkvater
7423777a18 (svn r1663) Release 0.3.6. 2005-01-25 00:10:06 +00:00
373 changed files with 96210 additions and 128043 deletions

233
Doxyfile
View File

@@ -1,233 +0,0 @@
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = openttd
OUTPUT_DIRECTORY = docs/source/
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = ./
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 2
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ./
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.h \
table/*.h
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = YES
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = YES
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = YES
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = openttd.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

855
Makefile

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,3 @@
/* $Id$ */
// stdafx.cpp : source file that includes just the standard includes // stdafx.cpp : source file that includes just the standard includes
// ttd.pch will be the pre-compiled header // ttd.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information // stdafx.obj will contain the pre-compiled type information

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,7 @@
/* $Id$ */ #ifndef AI_H
#define AI_H
#ifndef AI_TROLLY_H #include "aystar.h"
#define AI_TROLLY_H
#include "../../aystar.h"
#include "../../player.h"
/* /*
* These defines can be altered to change the behavoir of the AI * These defines can be altered to change the behavoir of the AI
@@ -40,8 +37,6 @@
#define AI_PATHFINDER_PENALTY 150 #define AI_PATHFINDER_PENALTY 150
// The penalty given to a tile that is going up // The penalty given to a tile that is going up
#define AI_PATHFINDER_TILE_GOES_UP_PENALTY 450 #define AI_PATHFINDER_TILE_GOES_UP_PENALTY 450
// The penalty given to a tile which would have to use fundation
#define AI_PATHFINDER_FOUNDATION_PENALTY 100
// Changing direction is a penalty, to prevent curved ways (with that: slow ways) // Changing direction is a penalty, to prevent curved ways (with that: slow ways)
#define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200 #define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200
// Same penalty, only for when road already exists // Same penalty, only for when road already exists
@@ -166,33 +161,33 @@
// This stops 90degrees curves // This stops 90degrees curves
static const byte _illegal_curves[6] = { static const byte _illegal_curves[6] = {
255, 255, // Horz and vert, don't have the effect 255, 255, // Horz and vert, don't have the effect
5, // upleft and upright are not valid 5, // upleft and upright are not valid
4, // downright and downleft are not valid 4, // downright and downleft are not valid
2, // downleft and upleft are not valid 2, // downleft and upleft are not valid
3, // upright and downright are not valid 3, // upright and downright are not valid
}; };
enum { enum {
AI_STATE_STARTUP = 0, AI_STATE_STARTUP = 0,
AI_STATE_FIRST_TIME, AI_STATE_FIRST_TIME,
AI_STATE_NOTHING, AI_STATE_NOTHING,
AI_STATE_WAKE_UP, AI_STATE_WAKE_UP,
AI_STATE_LOCATE_ROUTE, AI_STATE_LOCATE_ROUTE,
AI_STATE_FIND_STATION, AI_STATE_FIND_STATION,
AI_STATE_FIND_PATH, AI_STATE_FIND_PATH,
AI_STATE_FIND_DEPOT, AI_STATE_FIND_DEPOT,
AI_STATE_VERIFY_ROUTE, AI_STATE_VERIFY_ROUTE,
AI_STATE_BUILD_STATION, AI_STATE_BUILD_STATION,
AI_STATE_BUILD_PATH, AI_STATE_BUILD_PATH,
AI_STATE_BUILD_DEPOT, AI_STATE_BUILD_DEPOT,
AI_STATE_BUILD_VEHICLE, AI_STATE_BUILD_VEHICLE,
AI_STATE_GIVE_ORDERS, AI_STATE_GIVE_ORDERS,
AI_STATE_START_VEHICLE, AI_STATE_START_VEHICLE,
AI_STATE_REPAY_MONEY, AI_STATE_REPAY_MONEY,
AI_STATE_CHECK_ALL_VEHICLES, AI_STATE_CHECK_ALL_VEHICLES,
AI_STATE_ACTION_DONE, AI_STATE_ACTION_DONE,
AI_STATE_STOP, // Temporary function to stop the AI AI_STATE_STOP, // Temporary function to stop the AI
}; };
// Used for tbt (train/bus/truck) // Used for tbt (train/bus/truck)
@@ -212,7 +207,7 @@ enum {
// Used for from_type/to_type // Used for from_type/to_type
enum { enum {
AI_NO_TYPE = 0, AI_NO_TYPE = 0,
AI_CITY, AI_CITY,
AI_INDUSTRY, AI_INDUSTRY,
}; };
@@ -225,7 +220,7 @@ enum {
#define AI_NO_CARGO 0xFF // Means that there is no cargo defined yet (used for industry) #define AI_NO_CARGO 0xFF // Means that there is no cargo defined yet (used for industry)
#define AI_NEED_CARGO 0xFE // Used when the AI needs to find out a cargo for the route #define AI_NEED_CARGO 0xFE // Used when the AI needs to find out a cargo for the route
#define AI_STATION_RANGE TileXY(MapMaxX(), MapMaxY()) #define AI_STATION_RANGE TILE_XY(MapMaxX(), MapMaxY())
#define AI_PATHFINDER_NO_DIRECTION (byte)-1 #define AI_PATHFINDER_NO_DIRECTION (byte)-1
@@ -243,19 +238,20 @@ AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFin
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo); void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
// ai_shared.c // ai_shared.c
int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c); int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c);
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c); int AiNew_GetRoadDirection(uint tile_a, uint tile_b, uint tile_c);
int AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b); int AiNew_GetDirection(uint tile_a, uint tile_b);
bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag); bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag);
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v); uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v);
// ai_build.c // ai_build.c
bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile); bool AiNew_Build_CompanyHQ(Player *p, uint tile);
int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag); int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag);
int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag); int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag);
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag); int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
int AiNew_PickVehicle(Player *p); int AiNew_PickVehicle(Player *p);
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag); int AiNew_Build_Vehicle(Player *p, uint tile, byte flag);
int AiNew_Build_Depot(Player *p, TileIndex tile, byte direction, byte flag); int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag);
#endif /* AI_TROLLY_H */
#endif

263
ai/ai.c
View File

@@ -1,263 +0,0 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "../variables.h"
#include "../command.h"
#include "../network.h"
#include "ai.h"
#include "default/default.h"
/**
* Dequeues commands put in the queue via AI_PutCommandInQueue.
*/
static void AI_DequeueCommands(byte player)
{
AICommand *com, *entry_com;
entry_com = _ai_player[player].queue;
/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
* to this very same queue (don't argue about this, if it currently doesn't
* happen I can tell you it will happen with AIScript -- TrueLight). If we
* do not make the queue NULL, that commands will be dequeued immediatly.
* Therefor we safe the entry-point to entry_com, and make the queue NULL, so
* the new queue can be safely built up. */
_ai_player[player].queue = NULL;
_ai_player[player].queue_tail = NULL;
/* Dequeue all commands */
while ((com = entry_com) != NULL) {
_current_player = player;
/* Copy the DP back in place */
_cmd_text = com->text;
DoCommandP(com->tile, com->p1, com->p2, NULL, com->procc);
/* Free item */
entry_com = com->next;
if (com->text != NULL)
free(com->text);
free(com);
}
}
/**
* Needed for SP; we need to delay DoCommand with 1 tick, because else events
* will make infinite loops (AIScript).
*/
static void AI_PutCommandInQueue(byte player, uint tile, uint32 p1, uint32 p2, uint procc)
{
AICommand *com;
if (_ai_player[player].queue_tail == NULL) {
/* There is no item in the queue yet, create the queue */
_ai_player[player].queue = malloc(sizeof(AICommand));
_ai_player[player].queue_tail = _ai_player[player].queue;
} else {
/* Add an item at the end */
_ai_player[player].queue_tail->next = malloc(sizeof(AICommand));
_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
}
/* This is our new item */
com = _ai_player[player].queue_tail;
/* Assign the info */
com->tile = tile;
com->p1 = p1;
com->p2 = p2;
com->procc = procc;
com->next = NULL;
com->text = NULL;
/* Copy the cmd_text, if needed */
if (_cmd_text != NULL) {
com->text = strdup(_cmd_text);
_cmd_text = NULL;
}
}
/**
* Executes a raw DoCommand for the AI.
*/
int32 AI_DoCommand(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
PlayerID old_lp;
int32 res = 0;
char *tmp_cmdtext = NULL;
/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
* person.. should we check for those funny jokes?
*/
/* The test already free _cmd_text in most cases, so let's backup the string, else we have a problem ;) */
if (_cmd_text != NULL)
tmp_cmdtext = strdup(_cmd_text);
/* First, do a test-run to see if we can do this */
res = DoCommandByTile(tile, p1, p2, flags & ~DC_EXEC, procc);
/* The command failed, or you didn't want to execute, or you are quering, return */
if ((CmdFailed(res)) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
if (tmp_cmdtext != NULL)
free(tmp_cmdtext);
return res;
}
/* Recover _cmd_text */
if (tmp_cmdtext != NULL)
_cmd_text = tmp_cmdtext;
/* If we did a DC_EXEC, and the command did not return an error, execute it
over the network */
if (flags & DC_AUTO) procc |= CMD_AUTO;
if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
/* NetworkSend_Command needs _local_player to be set correctly, so
adjust it, and put it back right after the function */
old_lp = _local_player;
_local_player = _current_player;
#ifdef ENABLE_NETWORK
/* Send the command */
if (_networking)
/* Network is easy, send it to his handler */
NetworkSend_Command(tile, p1, p2, procc, NULL);
else
#endif
/* If we execute BuildCommands directly in SP, we have a big problem with events
* so we need to delay is for 1 tick */
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc);
/* Set _local_player back */
_local_player = old_lp;
/* Free the temp _cmd_text var */
if (tmp_cmdtext != NULL)
free(tmp_cmdtext);
return res;
}
/**
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
*/
static void AI_RunTick(PlayerID player)
{
extern void AiNewDoGameLoop(Player *p);
Player *p = GetPlayer(player);
_current_player = player;
if (_patches.ainew_active) {
AiNewDoGameLoop(p);
} else {
/* Enable all kind of cheats the old AI needs in order to operate correctly... */
_is_old_ai_player = true;
AiDoGameLoop(p);
_is_old_ai_player = false;
}
}
/**
* The gameloop for AIs.
* Handles one tick for all the AIs.
*/
void AI_RunGameLoop(void)
{
/* Don't do anything if ai is disabled */
if (!_ai.enabled) return;
/* Don't do anything if we are a network-client
* (too bad when a client joins, he thinks the AIs are real, so it wants to control
* them.. this avoids that, while loading a network game in singleplayer, does make
* the AIs to continue ;))
*/
if (_networking && !_network_server && !_ai.network_client)
return;
/* New tick */
_ai.tick++;
/* Make sure the AI follows the difficulty rule.. */
assert(_opt.diff.competitor_speed <= 4);
if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0)
return;
/* Check for AI-client (so joining a network with an AI) */
if (_ai.network_client && _ai_player[_ai.network_playas].active) {
/* Run the script */
AI_DequeueCommands(_ai.network_playas);
AI_RunTick(_ai.network_playas);
} else if (!_networking || _network_server) {
/* Check if we want to run AIs (server or SP only) */
Player *p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) {
/* This should always be true, else something went wrong... */
assert(_ai_player[p->index].active);
/* Run the script */
AI_DequeueCommands(p->index);
AI_RunTick(p->index);
}
}
}
_current_player = OWNER_NONE;
}
/**
* A new AI sees the day of light. You can do here what ever you think is needed.
*/
void AI_StartNewAI(PlayerID player)
{
assert(player < MAX_PLAYERS);
/* Called if a new AI is booted */
_ai_player[player].active = true;
}
/**
* This AI player died. Give it some chance to make a final puf.
*/
void AI_PlayerDied(PlayerID player)
{
if (_ai.network_client && _ai.network_playas == player)
_ai.network_playas = OWNER_SPECTATOR;
/* Called if this AI died */
_ai_player[player].active = false;
}
/**
* Initialize some AI-related stuff.
*/
void AI_Initialize(void)
{
bool ai_network_client = _ai.network_client;
/* First, make sure all AIs are DEAD! */
AI_Uninitialize();
memset(&_ai, 0, sizeof(_ai));
memset(&_ai_player, 0, sizeof(_ai_player));
_ai.network_client = ai_network_client;
_ai.network_playas = OWNER_SPECTATOR;
_ai.enabled = true;
}
/**
* Deinitializer for AI-related stuff.
*/
void AI_Uninitialize(void)
{
Player* p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
}
}

112
ai/ai.h
View File

@@ -1,112 +0,0 @@
#ifndef AI_H
#define AI_H
#include "../functions.h"
#include "../network.h"
#include "../player.h"
/* How DoCommands look like for an AI */
typedef struct AICommand {
uint32 tile;
uint32 p1;
uint32 p2;
uint32 procc;
char *text;
uint uid;
struct AICommand *next;
} AICommand;
/* The struct for an AIScript Player */
typedef struct AIPlayer {
bool active; //! Is this AI active?
AICommand *queue; //! The commands that he has in his queue
AICommand *queue_tail; //! The tail of this queue
} AIPlayer;
/* The struct to keep some data about the AI in general */
typedef struct AIStruct {
/* General */
bool enabled; //! Is AI enabled?
uint tick; //! The current tick (something like _frame_counter, only for AIs)
/* For network-clients (a OpenTTD client who acts as an AI connected to a server) */
bool network_client; //! Are we a network_client?
uint8 network_playas; //! The current network player we are connected as
} AIStruct;
VARDEF AIStruct _ai;
VARDEF AIPlayer _ai_player[MAX_PLAYERS];
// ai.c
void AI_StartNewAI(PlayerID player);
void AI_PlayerDied(PlayerID player);
void AI_RunGameLoop(void);
void AI_Initialize(void);
void AI_Uninitialize(void);
int32 AI_DoCommand(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
/** Is it allowed to start a new AI.
* This function checks some boundries to see if we should launch a new AI.
* @return True if we can start a new AI.
*/
static inline bool AI_AllowNewAI(void)
{
/* If disabled, no AI */
if (!_ai.enabled)
return false;
/* If in network, but no server, no AI */
if (_networking && !_network_server)
return false;
/* If in network, and server, possible AI */
if (_networking && _network_server) {
/* Do we want AIs in multiplayer? */
if (!_patches.ai_in_multiplayer)
return false;
/* Only the NewAI is allowed... sadly enough the old AI just doesn't support this
* system, because all commands are delayed by at least 1 tick, which causes
* a big problem, because it uses variables that are only set AFTER the command
* is really executed... */
if (!_patches.ainew_active)
return false;
}
return true;
}
#define AI_CHANCE16(a,b) ((uint16) AI_Random() <= (uint16)((65536 * a) / b))
#define AI_CHANCE16R(a,b,r) ((uint16)(r = AI_Random()) <= (uint16)((65536 * a) / b))
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint AI_RandomRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandomRange(max);
else
return RandomRange(max);
}
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint32 AI_Random(void)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandom();
else
return Random();
}
#endif /* AI_H */

View File

@@ -1,8 +0,0 @@
/* $Id$ */
#ifndef DEFAULT_H
#define DEFAULT_H
void AiDoGameLoop(Player*);
#endif

View File

@@ -1,273 +0,0 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../debug.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../tile.h"
#include "../../command.h"
#include "trolly.h"
#include "../../engine.h"
#include "../../station.h"
#include "../../variables.h"
#include "../ai.h"
// Build HQ
// Params:
// tile : tile where HQ is going to be build
bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile)
{
if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ)))
return false;
AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
return true;
}
// Build station
// Params:
// type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
// tile : tile where station is going to be build
// length : in case of AI_TRAIN: length of station
// numtracks : in case of AI_TRAIN: tracks of station
// direction : the direction of the station
// flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag)
{
if (type == AI_TRAIN)
return AI_DoCommand(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
if (type == AI_BUS)
return AI_DoCommand(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
}
// Builds a brdige. The second best out of the ones available for this player
// Params:
// tile_a : starting point
// tile_b : end point
// flag : flag passed to DoCommand
int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag)
{
int bridge_type, bridge_len, type, type2;
// Find a good bridgetype (the best money can buy)
bridge_len = GetBridgeLength(tile_a, tile_b);
type = type2 = 0;
for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
type2 = type;
type = bridge_type;
// We found two bridges, exit
if (type2 != 0) break;
}
}
// There is only one bridge that can be build..
if (type2 == 0 && type != 0) type2 = type;
// Now, simply, build the bridge!
if (p->ainew.tbt == AI_TRAIN)
return AI_DoCommand(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
}
// Build the route part by part
// Basicly what this function do, is build that amount of parts of the route
// that go in the same direction. It sets 'part' to the last part of the route builded.
// The return value is the cost for the builded parts
//
// Params:
// PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
// part : Which part we need to build
//
// TODO: skip already builded road-pieces (e.g.: cityroad)
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag)
{
int part = PathFinderInfo->position;
byte *route_extra = PathFinderInfo->route_extra;
TileIndex *route = PathFinderInfo->route;
int dir;
int old_dir = -1;
int cost = 0;
int res;
// We need to calculate the direction with the parent of the parent.. so we skip
// the first pieces and the last piece
if (part < 1) part = 1;
// When we are done, stop it
if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; }
if (PathFinderInfo->rail_or_road) {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
return 0;
}
return cost;
}
// Build normal rail
// Keep it doing till we go an other way
if (route_extra[part-1] == 0 && route_extra[part] == 0) {
while (route_extra[part] == 0) {
// Get the current direction
dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// Build the tile
res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
if (CmdFailed(res)) {
// Problem.. let's just abort it all!
p->ainew.state = AI_STATE_NOTHING;
return 0;
}
cost += res;
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
}
// We want to return the last position, so we go back one
PathFinderInfo->position = part;
} else {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += AI_DoCommand(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
return 0;
}
return cost;
}
// Build normal road
// Keep it doing till we go an other way
// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
// it will wait till the vehicle is gone..
if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
// Get the current direction
dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// There is already some road, and it is a bridge.. don't build!!!
if (!IsTileType(route[part], MP_TUNNELBRIDGE)) {
// Build the tile
res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
// Currently, we ignore CMD_ERRORs!
if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
// Problem.. let's just abort it all!
DEBUG(ai,0)("Darn, the route could not be builded.. aborting!");
p->ainew.state = AI_STATE_NOTHING;
return 0;
}
if (!CmdFailed(res)) cost += res;
}
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
// We want to return the last position, so we go back one
}
if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
PathFinderInfo->position = part;
}
return cost;
}
// This functions tries to find the best vehicle for this type of cargo
// It returns vehicle_id or -1 if not found
int AiNew_PickVehicle(Player *p)
{
if (p->ainew.tbt == AI_TRAIN) {
// Not supported yet
return -1;
} else {
int start, count, i, ret = CMD_ERROR;
start = _cargoc.ai_roadveh_start[p->ainew.cargo];
count = _cargoc.ai_roadveh_count[p->ainew.cargo];
// Let's check it backwards.. we simply want to best engine available..
for (i = start + count - 1; i >= start; i--) {
// Is it availiable?
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
if (!HASBIT(GetEngine(i)->player_avail, _current_player) || GetEngine(i)->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
// Can we build it?
ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
if (!CmdFailed(ret)) break;
}
// We did not find a vehicle :(
if (CmdFailed(ret)) return -1;
return i;
}
}
// Builds the best vehicle possible
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
{
int i = AiNew_PickVehicle(p);
if (i == -1) return CMD_ERROR;
if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
}
int AiNew_Build_Depot(Player *p, TileIndex tile, byte direction, byte flag)
{
static const byte _roadbits_by_dir[4] = {2,1,8,4};
int ret, ret2;
if (p->ainew.tbt == AI_TRAIN)
return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
if (CmdFailed(ret)) return ret;
// Try to build the road from the depot
ret2 = AI_DoCommand(tile + TileOffsByDir(direction), _roadbits_by_dir[direction], 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
// If it fails, ignore it..
if (CmdFailed(ret2)) return ret;
return ret + ret2;
}

File diff suppressed because it is too large Load Diff

258
ai_build.c Normal file
View File

@@ -0,0 +1,258 @@
#include "stdafx.h"
#include "ttd.h"
#include "map.h"
#include "command.h"
#include "ai.h"
#include "engine.h"
// Build HQ
// Params:
// tile : tile where HQ is going to be build
bool AiNew_Build_CompanyHQ(Player *p, uint tile) {
if (DoCommandByTile(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ) == CMD_ERROR)
return false;
DoCommandByTile(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
return true;
}
// Build station
// Params:
// type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
// tile : tile where station is going to be build
// length : in case of AI_TRAIN: length of station
// numtracks : in case of AI_TRAIN: tracks of station
// direction : the direction of the station
// flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
int AiNew_Build_Station(Player *p, byte type, uint tile, byte length, byte numtracks, byte direction, byte flag) {
if (type == AI_TRAIN)
return DoCommandByTile(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
else if (type == AI_BUS)
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_BUS_STATION);
else
return DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRUCK_STATION);
}
// Builds a brdige. The second best out of the ones available for this player
// Params:
// tile_a : starting point
// tile_b : end point
// flag : flag passed to DoCommand
int AiNew_Build_Bridge(Player *p, uint tile_a, uint tile_b, byte flag) {
int bridge_type, bridge_len, type, type2;
// Find a good bridgetype (the best money can buy)
bridge_len = GetBridgeLength(tile_a, tile_b);
type = type2 = 0;
for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
type2 = type;
type = bridge_type;
// We found two bridges, exit
if (type2 != 0)
break;
}
}
// There is only one bridge that can be build..
if (type2 == 0 && type != 0) type2 = type;
// Now, simply, build the bridge!
if (p->ainew.tbt == AI_TRAIN)
return DoCommandByTile(tile_a, tile_b, (0<<8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
else
return DoCommandByTile(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
}
// Build the route part by part
// Basicly what this function do, is build that amount of parts of the route
// that go in the same direction. It sets 'part' to the last part of the route builded.
// The return value is the cost for the builded parts
//
// Params:
// PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
// part : Which part we need to build
//
// TODO: skip already builded road-pieces (e.g.: cityroad)
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag) {
int part = PathFinderInfo->position;
byte *route_extra = PathFinderInfo->route_extra;
TileIndex *route = PathFinderInfo->route;
int dir;
int old_dir = -1;
int cost = 0;
int res;
// We need to calculate the direction with the parent of the parent.. so we skip
// the first pieces and the last piece
if (part < 1) part = 1;
// When we are done, stop it
if (part >= PathFinderInfo->route_length - 1) { PathFinderInfo->position = -2; return 0; }
if (PathFinderInfo->rail_or_road) {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += DoCommandByTile(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (cost == CMD_ERROR) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (cost == CMD_ERROR) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
return 0;
}
return cost;
}
// Build normal rail
// Keep it doing till we go an other way
if (route_extra[part-1] == 0 && route_extra[part] == 0) {
while (route_extra[part] == 0) {
// Get the current direction
dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// Build the tile
res = DoCommandByTile(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
if (res == CMD_ERROR) {
// Problem.. let's just abort it all!
p->ainew.state = AI_STATE_NOTHING;
return 0;
}
cost += res;
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
}
// We want to return the last position, so we go back one
PathFinderInfo->position = part;
} else {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += DoCommandByTile(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (cost == CMD_ERROR) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be build!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (cost == CMD_ERROR) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be build!");
return 0;
}
return cost;
}
// Build normal road
// Keep it doing till we go an other way
// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
// it will wait till the vehicle is gone..
if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
// Get the current direction
dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// There is already some road, and it is a bridge.. don't build!!!
if (!IsTileType(route[part], MP_TUNNELBRIDGE)) {
// Build the tile
res = DoCommandByTile(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
// Currently, we ignore CMD_ERRORs!
if (res == CMD_ERROR && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
// Problem.. let's just abort it all!
DEBUG(ai,0)("Darn, the route could not be builded.. aborting!");
p->ainew.state = AI_STATE_NOTHING;
return 0;
} else {
if (res != CMD_ERROR)
cost += res;
}
}
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
// We want to return the last position, so we go back one
}
if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
PathFinderInfo->position = part;
}
return cost;
}
// This functions tries to find the best vehicle for this type of cargo
// It returns vehicle_id or -1 if not found
int AiNew_PickVehicle(Player *p) {
if (p->ainew.tbt == AI_TRAIN) {
// Not supported yet
return -1;
} else {
int start, count, i, r = CMD_ERROR;
start = _cargoc.ai_roadveh_start[p->ainew.cargo];
count = _cargoc.ai_roadveh_count[p->ainew.cargo];
// Let's check it backwards.. we simply want to best engine available..
for (i=start+count-1;i>=start;i--) {
// Is it availiable?
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
if (!HASBIT(_engines[i].player_avail, _current_player) || _engines[i].reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
// Can we build it?
r = DoCommandByTile(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
if (r != CMD_ERROR) break;
}
// We did not find a vehicle :(
if (r == CMD_ERROR) { return -1; }
return i;
}
}
// Builds the best vehicle possible
int AiNew_Build_Vehicle(Player *p, uint tile, byte flag) {
int i = AiNew_PickVehicle(p);
if (i == -1) return CMD_ERROR;
if (p->ainew.tbt == AI_TRAIN) {
return CMD_ERROR;
} else {
return DoCommandByTile(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
}
}
int AiNew_Build_Depot(Player *p, uint tile, byte direction, byte flag) {
static const byte _roadbits_by_dir[4] = {2,1,8,4};
int r, r2;
if (p->ainew.tbt == AI_TRAIN) {
return DoCommandByTile(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
} else {
r = DoCommandByTile(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
if (r == CMD_ERROR) return r;
// Try to build the road from the depot
r2 = DoCommandByTile(tile + TileOffsByDir(direction), _roadbits_by_dir[direction], 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
// If it fails, ignore it..
if (r2 == CMD_ERROR) return r;
return r + r2;
}
}

1307
ai_new.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,31 @@
/* $Id$ */ #include "stdafx.h"
#include "ttd.h"
#include "../../stdafx.h" #include "map.h"
#include "../../openttd.h" #include "command.h"
#include "../../debug.h" #include "ai.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../tile.h"
#include "../../command.h"
#include "trolly.h"
#include "../../depot.h"
#include "../../variables.h"
#include "../ai.h"
#define TEST_STATION_NO_DIR 0xFF #define TEST_STATION_NO_DIR 0xFF
// Tests if a station can be build on the given spot // Tests if a station can be build on the given spot
// TODO: make it train compatible // TODO: make it train compatible
static bool TestCanBuildStationHere(TileIndex tile, byte dir) static bool TestCanBuildStationHere(uint tile, byte dir)
{ {
Player *p = GetPlayer(_current_player); Player *p = DEREF_PLAYER(_current_player);
if (dir == TEST_STATION_NO_DIR) {
if (dir == TEST_STATION_NO_DIR) { // TODO: currently we only allow spots that can be access from al 4 directions...
int32 ret; // should be fixed!!!
// TODO: currently we only allow spots that can be access from al 4 directions... for (dir=0;dir<4;dir++) {
// should be fixed!!! int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
for (dir = 0; dir < 4; dir++) { if (res != CMD_ERROR)
ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST); return true;
if (!CmdFailed(ret)) return true; }
} return false;
return false; } else {
} int res = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
if (res == CMD_ERROR)
// return true if command succeeded, so the inverse of CmdFailed() return false;
return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST)); }
return true;
} }
@@ -40,12 +33,12 @@ static bool IsRoad(TileIndex tile)
{ {
return return
// MP_STREET, but not a road depot? // MP_STREET, but not a road depot?
(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) || (IsTileType(tile, MP_STREET) && !(_map5[tile] & 0x20)) ||
(IsTileType(tile, MP_TUNNELBRIDGE) && ( (IsTileType(tile, MP_TUNNELBRIDGE) && (
// road tunnel? // road tunnel?
((_m[tile].m5 & 0x80) == 0 && (_m[tile].m5 & 0x4) == 0x4) || ((_map5[tile] & 0x80) == 0 && (_map5[tile] & 0x4) == 0x4) ||
// road bridge? // road bridge?
((_m[tile].m5 & 0x80) != 0 && (_m[tile].m5 & 0x2) == 0x2) ((_map5[tile] & 0x80) != 0 && (_map5[tile] & 0x2) == 0x2)
)); ));
} }
@@ -53,7 +46,6 @@ static bool IsRoad(TileIndex tile)
// Checks if a tile 'a' is between the tiles 'b' and 'c' // Checks if a tile 'a' is between the tiles 'b' and 'c'
#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c)) #define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
// Check if the current tile is in our end-area // Check if the current tile is in our end-area
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current) static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
{ {
@@ -62,13 +54,12 @@ static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *curr
if (current->path.node.user_data[0] != 0) return AYSTAR_DONE; if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES)) if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile, AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile))) if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile,AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
return AYSTAR_FOUND_END_NODE; return AYSTAR_FOUND_END_NODE;
return AYSTAR_DONE; return AYSTAR_DONE;
} }
// Calculates the hash // Calculates the hash
// Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64) // Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
static uint AiPathFinder_Hash(uint key1, uint key2) static uint AiPathFinder_Hash(uint key1, uint key2)
@@ -76,7 +67,6 @@ static uint AiPathFinder_Hash(uint key1, uint key2)
return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5); return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
} }
// Clear the memory of all the things // Clear the memory of all the things
static void AyStar_AiPathFinder_Free(AyStar *aystar) static void AyStar_AiPathFinder_Free(AyStar *aystar)
{ {
@@ -84,19 +74,15 @@ static void AyStar_AiPathFinder_Free(AyStar *aystar)
free(aystar); free(aystar);
} }
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent); static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent); static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current); static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current); static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
// This creates the AiPathFinder // This creates the AiPathFinder
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo) AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo) {
{
PathNode start_node; PathNode start_node;
uint x; uint x,y;
uint y;
// Create AyStar // Create AyStar
AyStar *result = malloc(sizeof(AyStar)); AyStar *result = malloc(sizeof(AyStar));
init_AyStar(result, AiPathFinder_Hash, 1 << 10); init_AyStar(result, AiPathFinder_Hash, 1 << 10);
@@ -125,21 +111,18 @@ AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFin
// Now we add all the starting tiles // Now we add all the starting tiles
for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) { for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) { for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
start_node.node.tile = TileXY(x, y); start_node.node.tile = TILE_XY(x,y);
result->addstart(result, &start_node.node, 0); result->addstart(result, &start_node.node);
} }
} }
return result; return result;
} }
// To reuse AyStar we sometimes have to clean all the memory // To reuse AyStar we sometimes have to clean all the memory
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo) void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo) {
{
PathNode start_node; PathNode start_node;
uint x; uint x,y;
uint y;
aystar->clear(aystar); aystar->clear(aystar);
@@ -155,231 +138,224 @@ void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo
// Now we add all the starting tiles // Now we add all the starting tiles
for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) { for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) { for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
if (!(IsTileType(TileXY(x, y), MP_CLEAR) || IsTileType(TileXY(x, y), MP_TREES))) continue; if (!(IsTileType(TILE_XY(x,y), MP_CLEAR) || IsTileType(TILE_XY(x,y), MP_TREES))) continue;
if (!TestCanBuildStationHere(TileXY(x, y), TEST_STATION_NO_DIR)) continue; if (!TestCanBuildStationHere(TILE_XY(x,y),TEST_STATION_NO_DIR)) continue;
start_node.node.tile = TileXY(x, y); start_node.node.tile = TILE_XY(x,y);
aystar->addstart(aystar, &start_node.node, 0); aystar->addstart(aystar, &start_node.node);
} }
} }
} }
// The h-value, simple calculation // The h-value, simple calculation
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent) static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
int r, r2; int r, r2;
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) { if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate // The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDir(PathFinderInfo->end_direction)); r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDir(PathFinderInfo->end_direction));
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDir(PathFinderInfo->end_direction)); r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br + TileOffsByDir(PathFinderInfo->end_direction));
} else { } else {
// No direction, so just get the fastest route to the station // No direction, so just get the fastest route to the station
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl); r = GetTileDist(current->tile, PathFinderInfo->end_tile_tl);
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br); r2 = GetTileDist(current->tile, PathFinderInfo->end_tile_br);
} }
// See if the bottomright is faster than the topleft.. // See if the bottomright is faster than the topleft..
if (r2 < r) r = r2; if (r2 < r) r = r2;
return r * AI_PATHFINDER_H_MULTIPLER; return r * AI_PATHFINDER_H_MULTIPLER;
} }
// We found the end.. let's get the route back and put it in an array // We found the end.. let's get the route back and put it in an array
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current) static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current) {
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
uint i = 0; uint i = 0;
PathNode *parent = &current->path; PathNode *parent = &current->path;
do { do {
PathFinderInfo->route_extra[i] = parent->node.user_data[0]; PathFinderInfo->route_extra[i] = parent->node.user_data[0];
PathFinderInfo->route[i++] = parent->node.tile; PathFinderInfo->route[i++] = parent->node.tile;
if (i > lengthof(PathFinderInfo->route)) { if (i > lengthof(PathFinderInfo->route)) {
// We ran out of space for the PathFinder // We ran out of space for the PathFinder
DEBUG(ai, 0)("[AiPathFinder] Ran out of space in the route[] array!!!"); DEBUG(ai,0)("[AiPathFinder] Ran out of spacein the route[] array!!!");
PathFinderInfo->route_length = -1; // -1 indicates out of space PathFinderInfo->route_length = -1; // -1 indicates out of space
return; return;
} }
parent = parent->parent; parent = parent->parent;
} while (parent != NULL); } while (parent != NULL);
PathFinderInfo->route_length = i; PathFinderInfo->route_length = i;
DEBUG(ai, 1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash)); DEBUG(ai,1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching",i,Hash_Size(&aystar->ClosedListHash));
} }
// What tiles are around us. // What tiles are around us.
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current) static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current) {
{ uint i;
uint i; int r;
int ret; int dir;
int dir;
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
aystar->num_neighbours = 0; aystar->num_neighbours = 0;
// Go through all surrounding tiles and check if they are within the limits // Go through all surrounding tiles and check if they are within the limits
for (i = 0; i < 4; i++) { for (i=0;i<4;i++) {
TileIndex ctile = current->path.node.tile; // Current tile if (TileX(TileOffsByDir(i) + current->path.node.tile) > 1 &&
TileIndex atile = ctile + TileOffsByDir(i); // Adjacent tile TileX(TileOffsByDir(i) + current->path.node.tile) < MapMaxX() - 1 &&
TileY(TileOffsByDir(i) + current->path.node.tile) > 1 &&
TileY(TileOffsByDir(i) + current->path.node.tile) < MapMaxY() - 1) {
// We also directly test if the current tile can connect to this tile..
// We do this simply by just building the tile!
if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 && // If the next step is a bridge, we have to enter it the right way
TileY(atile) > 1 && TileY(atile) < MapMaxY() - 1) { if (!PathFinderInfo->rail_or_road && IsRoad(current->path.node.tile + TileOffsByDir(i))) {
// We also directly test if the current tile can connect to this tile.. if (IsTileType(current->path.node.tile + TileOffsByDir(i), MP_TUNNELBRIDGE)) {
// We do this simply by just building the tile! // An existing bridge... let's test the direction ;)
if ((_map5[current->path.node.tile + TileOffsByDir(i)] & 1U) != (i & 1)) continue;
// This problem only is valid for tunnels:
// When the last tile was not yet a tunnel, check if we enter from the right side..
if (!IsTileType(current->path.node.tile, MP_TUNNELBRIDGE) && (_map5[current->path.node.tile + TileOffsByDir(i)] & 0x80) == 0) {
if (i != (_map5[current->path.node.tile + TileOffsByDir(i)] & 3U)) continue;
}
}
}
// But also if we are on a bridge, we can only move a certain direction
if (!PathFinderInfo->rail_or_road && IsRoad(current->path.node.tile)) {
if (IsTileType(current->path.node.tile, MP_TUNNELBRIDGE)) {
// An existing bridge/tunnel... let's test the direction ;)
if ((_map5[current->path.node.tile] & 1U) != (i & 1)) continue;
}
}
// If the next step is a bridge, we have to enter it the right way if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
if (!PathFinderInfo->rail_or_road && IsRoad(atile)) { (AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
if (IsTileType(atile, MP_TUNNELBRIDGE)) { // We are a bridge/tunnel, how cool!!
// An existing bridge... let's test the direction ;) // This means we can only point forward.. get the direction from the user_data
if ((_m[atile].m5 & 1U) != (i & 1)) continue; if (i != (current->path.node.user_data[0] >> 8)) continue;
// This problem only is valid for tunnels: }
// When the last tile was not yet a tunnel, check if we enter from the right side.. dir = 0;
if ((_m[atile].m5 & 0x80) == 0) {
if (i != (_m[atile].m5 & 3U)) continue;
}
}
}
// But also if we are on a bridge, we can only move a certain direction
if (!PathFinderInfo->rail_or_road && IsRoad(ctile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
// An existing bridge/tunnel... let's test the direction ;)
if ((_m[ctile].m5 & 1U) != (i & 1)) continue;
}
}
if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 || // First, check if we have a parent
(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) { if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
// We are a bridge/tunnel, how cool!! // If not, this means we are at the starting station
// This means we can only point forward.. get the direction from the user_data if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
if (i != (current->path.node.user_data[0] >> 8)) continue; // We do need a direction?
} if (AiNew_GetDirection(current->path.node.tile, current->path.node.tile + TileOffsByDir(i)) != PathFinderInfo->start_direction)
dir = 0; // We are not pointing the right way, invalid tile
continue;
// First, check if we have a parent }
if (current->path.parent == NULL && current->path.node.user_data[0] == 0) { } else if (current->path.node.user_data[0] == 0) {
// If not, this means we are at the starting station if (PathFinderInfo->rail_or_road) {
if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) { // Rail check
// We do need a direction? dir = AiNew_GetRailDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + TileOffsByDir(i));
if (AiNew_GetDirection(ctile, atile) != PathFinderInfo->start_direction) { r = DoCommandByTile(current->path.node.tile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
// We are not pointing the right way, invalid tile if (r == CMD_ERROR) continue;
continue;
}
}
} else if (current->path.node.user_data[0] == 0) {
if (PathFinderInfo->rail_or_road) {
// Rail check
dir = AiNew_GetRailDirection(current->path.parent->node.tile, ctile, atile);
ret = AI_DoCommand(ctile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
if (CmdFailed(ret)) continue;
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN #ifdef AI_PATHFINDER_NO_90DEGREES_TURN
if (current->path.parent->parent != NULL) { if (current->path.parent->parent != NULL) {
// Check if we don't make a 90degree curve // Check if we don't make a 90degree curve
int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, ctile); int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, current->path.node.tile);
if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) { if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
continue; continue;
} }
} }
#endif #endif
} else { } else {
// Road check // Road check
dir = AiNew_GetRoadDirection(current->path.parent->node.tile, ctile, atile); dir = AiNew_GetRoadDirection(current->path.parent->node.tile, current->path.node.tile, current->path.node.tile + TileOffsByDir(i));
if (IsRoad(ctile)) { if (IsRoad(current->path.node.tile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) { if (IsTileType(current->path.node.tile, MP_TUNNELBRIDGE)) {
// We have a bridge, how nicely! We should mark it... // We have a bridge, how nicely! We should mark it...
dir = 0; dir = 0;
} else { } else {
// It already has road.. check if we miss any bits! // It already has road.. check if we miss any bits!
if ((_m[ctile].m5 & dir) != dir) { if ((_map5[current->path.node.tile] & dir) != dir) {
// We do miss some pieces :( // We do miss some pieces :(
dir &= ~_m[ctile].m5; dir &= ~_map5[current->path.node.tile];
} else { } else {
dir = 0; dir = 0;
} }
} }
} }
// Only destruct things if it is MP_CLEAR of MP_TREES // Only destruct things if it is MP_CLEAR of MP_TREES
if (dir != 0) { if (dir != 0) {
ret = AI_DoCommand(ctile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD); r = DoCommandByTile(current->path.node.tile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
if (CmdFailed(ret)) continue; if (r == CMD_ERROR) continue;
} }
} }
}
}
// The tile can be connected // The tile can be connected
aystar->neighbours[aystar->num_neighbours].tile = atile; aystar->neighbours[aystar->num_neighbours].tile = TileOffsByDir(i) + current->path.node.tile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = 0; aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
aystar->neighbours[aystar->num_neighbours++].direction = 0; aystar->neighbours[aystar->num_neighbours++].direction = 0;
} }
} }
// Next step, check for bridges and tunnels // Next step, check for bridges and tunnels
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) { if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
TileInfo ti;
// First we get the dir from this tile and his parent
int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
// It means we can only walk with the track, so the bridge has to be in the same direction
TileIndex tile = current->path.node.tile;
TileIndex new_tile = tile;
FindLandscapeHeightByTile(&ti, tile); TileInfo ti;
// First we get the dir from this tile and his parent
int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
// It means we can only walk with the track, so the bridge has to be in the same direction
TileIndex tile = current->path.node.tile;
TileIndex new_tile = tile;
// Bridges can only be build on land that is not flat FindLandscapeHeightByTile(&ti, tile);
// And if there is a road or rail blocking
if (ti.tileh != 0 ||
(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_STREET)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_RAILWAY))) {
for (;;) {
new_tile += TileOffsByDir(dir);
// Precheck, is the length allowed? // Bridges can only be build on land that is not flat
if (!CheckBridge_Stuff(0, GetBridgeLength(tile, new_tile))) break; // And if there is a road or rail blocking
if (ti.tileh != 0 ||
(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_STREET)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_RAILWAY))) {
// Check if we hit the station-tile.. we don't like that! for (;;) {
if (TILES_BETWEEN(new_tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) break; new_tile += TileOffsByDir(dir);
// Try building the bridge.. // Precheck, is the length allowed?
ret = AI_DoCommand(tile, new_tile, (0 << 8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE); if (!CheckBridge_Stuff(0,GetBridgeLength(tile, new_tile))) break;
if (CmdFailed(ret)) continue;
// We can build a bridge here.. add him to the neighbours // Check if we hit the station-tile.. we don't like that!
aystar->neighbours[aystar->num_neighbours].tile = new_tile; if (TILES_BETWEEN(new_tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) break;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0; // Try building the bridge..
r = DoCommandByTile(tile, new_tile, (0<<8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
if (r == CMD_ERROR) continue;
// We can build a bridge here.. add him to the neighbours
aystar->neighbours[aystar->num_neighbours].tile = new_tile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0;
// We can only have 12 neighbours, and we need 1 left for tunnels // We can only have 12 neighbours, and we need 1 left for tunnels
if (aystar->num_neighbours == 11) break; if (aystar->num_neighbours == 11) break;
} }
} }
// Next, check for tunnels! // Next, check for tunnels!
// Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction // Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction
// For now, we check both sides for this tile.. terraforming gives fuzzy result // For now, we check both sides for this tile.. terraforming gives fuzzy result
if ((dir == 0 && ti.tileh == 12) || if ((dir == 0 && ti.tileh == 12) ||
(dir == 1 && ti.tileh == 6) || (dir == 1 && ti.tileh == 6) ||
(dir == 2 && ti.tileh == 3) || (dir == 2 && ti.tileh == 3) ||
(dir == 3 && ti.tileh == 9)) { (dir == 3 && ti.tileh == 9)) {
// Now simply check if a tunnel can be build // Now simply check if a tunnel can be build
ret = AI_DoCommand(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL); r = DoCommandByTile(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
FindLandscapeHeightByTile(&ti, _build_tunnel_endtile); FindLandscapeHeightByTile(&ti, _build_tunnel_endtile);
if (!CmdFailed(ret) && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) { if (r != CMD_ERROR && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) {
aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile; aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8); aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0; aystar->neighbours[aystar->num_neighbours++].direction = 0;
} }
} }
} }
} }
extern uint GetRailFoundation(uint tileh, uint bits); extern uint GetRailFoundation(uint tileh, uint bits);
extern uint GetRoadFoundation(uint tileh, uint bits); extern uint GetRoadFoundation(uint tileh, uint bits);
extern uint GetBridgeFoundation(uint tileh, byte direction); extern uint GetBridgeFoundation(uint tileh, byte direction);
enum { enum {
BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12, BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
}; };
// The most important function: it calculates the g-value // The most important function: it calculates the g-value
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent) static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target; Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
int r, res = 0; int r, res = 0;
TileInfo ti, parent_ti; TileInfo ti, parent_ti;
@@ -389,12 +365,11 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile); FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile);
// Check if we hit the end-tile // Check if we hit the end-tile
if (TILES_BETWEEN(current->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) { if (TILES_BETWEEN(current->tile,PathFinderInfo->end_tile_tl,PathFinderInfo->end_tile_br)) {
// We are at the end-tile, check if we had a direction or something... // We are at the end-tile, check if we had a direction or something...
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction) { if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction)
// We are not pointing the right way, invalid tile // We are not pointing the right way, invalid tile
return AYSTAR_INVALID_NODE; return AYSTAR_INVALID_NODE;
}
// If it was valid, drop out.. we don't build on the endtile // If it was valid, drop out.. we don't build on the endtile
return 0; return 0;
} }
@@ -411,11 +386,7 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
} }
// We should give a penalty when the tile is going up or down.. this is one way to do so! // We should give a penalty when the tile is going up or down.. this is one way to do so!
// Too bad we have to count it from the parent.. but that is not so bad. // Too bad we have to count it from the parent.. but that is not so bad
// We also dislike long routes on slopes, since they do not look too realistic
// when there is a flat land all around, they are more expensive to build, and
// especially they essentially block the ability to connect or cross the road
// from one side.
if (parent_ti.tileh != 0 && parent->path.parent != NULL) { if (parent_ti.tileh != 0 && parent->path.parent != NULL) {
// Skip if the tile was from a bridge or tunnel // Skip if the tile was from a bridge or tunnel
if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) { if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
@@ -424,16 +395,12 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information.. // Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
if (r >= 15 || (r == 0 && (BRIDGE_NO_FOUNDATION & (1 << ti.tileh)))) { if (r >= 15 || (r == 0 && (BRIDGE_NO_FOUNDATION & (1 << ti.tileh)))) {
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY; res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
res += AI_PATHFINDER_FOUNDATION_PENALTY;
} }
} else { } else {
if (!(IsRoad(parent->path.node.tile) && IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE))) { if (!(IsRoad(parent->path.node.tile) && IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE))) {
r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile)); r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
if (r >= 15 || r == 0) if (r >= 15 || r == 0)
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY; res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
else
res += AI_PATHFINDER_FOUNDATION_PENALTY;
} }
} }
} }
@@ -462,8 +429,10 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15) if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
} }
if (parent_ti.tileh == 0) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; if (parent_ti.tileh == 0)
if (ti.tileh == 0) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY; res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (ti.tileh == 0)
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
} }
// To prevent the AI from taking the fastest way in tiles, but not the fastest way // To prevent the AI from taking the fastest way in tiles, but not the fastest way
@@ -471,7 +440,7 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
// This way, we get almost the fastest way in tiles, and a very good speed on the track // This way, we get almost the fastest way in tiles, and a very good speed on the track
if (!PathFinderInfo->rail_or_road) { if (!PathFinderInfo->rail_or_road) {
if (parent->path.parent != NULL && if (parent->path.parent != NULL &&
AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) { AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
// When road exists, we don't like turning, but its free, so don't be to piggy about it // When road exists, we don't like turning, but its free, so don't be to piggy about it
if (IsRoad(parent->path.node.tile)) if (IsRoad(parent->path.node.tile))
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY; res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
@@ -505,5 +474,9 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
} }
} }
return (res < 0) ? 0 : res; // Res should never be below zero.. if so, make it zero!
if (res < 0) { res = 0; }
// Return our value
return res;
} }

View File

@@ -1,14 +1,10 @@
/* $Id$ */ #include "stdafx.h"
#include "ttd.h"
#include "map.h"
#include "ai.h"
#include "vehicle.h"
#include "../../stdafx.h" int AiNew_GetRailDirection(uint tile_a, uint tile_b, uint tile_c) {
#include "../../openttd.h"
#include "../../debug.h"
#include "../../map.h"
#include "trolly.h"
#include "../../vehicle.h"
int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
{
// 0 = vert // 0 = vert
// 1 = horz // 1 = horz
// 2 = dig up-left // 2 = dig up-left
@@ -49,8 +45,7 @@ int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
return 0; return 0;
} }
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c) int AiNew_GetRoadDirection(uint tile_a, uint tile_b, uint tile_c) {
{
int x1, x2, x3; int x1, x2, x3;
int y1, y2, y3; int y1, y2, y3;
int r; int r;
@@ -79,8 +74,7 @@ int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
} }
// Get's the direction between 2 tiles seen from tile_a // Get's the direction between 2 tiles seen from tile_a
int AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b) int AiNew_GetDirection(uint tile_a, uint tile_b) {
{
if (TileY(tile_a) < TileY(tile_b)) return 1; if (TileY(tile_a) < TileY(tile_b)) return 1;
if (TileY(tile_a) > TileY(tile_b)) return 3; if (TileY(tile_a) > TileY(tile_b)) return 3;
if (TileX(tile_a) < TileX(tile_b)) return 2; if (TileX(tile_a) < TileX(tile_b)) return 2;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,13 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "debug.h"
#include "map.h" #include "map.h"
#include "airport.h" #include "airport.h"
#include "macros.h"
#include "variables.h"
static AirportFTAClass* CountryAirport; AirportFTAClass *CountryAirport;
static AirportFTAClass* CityAirport; AirportFTAClass *CityAirport;
static AirportFTAClass* Oilrig; AirportFTAClass *Heliport, *Oilrig;
static AirportFTAClass* Heliport; AirportFTAClass *MetropolitanAirport;
static AirportFTAClass* MetropolitanAirport; AirportFTAClass *InternationalAirport;
static AirportFTAClass* InternationalAirport;
static void AirportFTAClass_Constructor(AirportFTAClass *Airport, static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
const byte *terminals, const byte *helipads, const byte *terminals, const byte *helipads,
@@ -177,15 +171,14 @@ static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
// build the state machine // build the state machine
AirportBuildAutomata(Airport, FA); AirportBuildAutomata(Airport, FA);
DEBUG(misc, 1) ("#Elements %2d; #Terminals %2d in %d group(s); #Helipads %2d in %d group(s); Entry Point %d", DEBUG(misc, 1) ("#Elements %2d; #Terminals %2d in %d group(s); #Helipads %2d in %d group(s); Entry Point %d", Airport->nofelements,
Airport->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, Airport->entry_point nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, Airport->entry_point);
);
{ {
byte ret = AirportTestFTA(Airport); byte _retval = AirportTestFTA(Airport);
if (ret != MAX_ELEMENTS) printf("ERROR with element: %d\n", ret - 1); if (_retval != MAX_ELEMENTS) {printf("ERROR with element: %d\n", _retval-1);}
assert(ret == MAX_ELEMENTS); assert(_retval == MAX_ELEMENTS);
} }
// print out full information // print out full information
// true -- full info including heading, block, etc // true -- full info including heading, block, etc
@@ -215,13 +208,12 @@ static uint16 AirportGetNofElements(const AirportFTAbuildup *FA)
int i; int i;
uint16 nofelements = 0; uint16 nofelements = 0;
int temp = FA[0].position; int temp = FA[0].position;
for (i = 0; i < MAX_ELEMENTS; i++) { for (i = 0; i < MAX_ELEMENTS; i++) {
if (temp != FA[i].position) { if (temp != FA[i].position) {
nofelements++; nofelements++;
temp = FA[i].position; temp = FA[i].position;
} }
if (FA[i].position == MAX_ELEMENTS) break; if (FA[i].position == MAX_ELEMENTS) {break;}
} }
return nofelements; return nofelements;
} }
@@ -231,7 +223,7 @@ static void AirportBuildAutomata(AirportFTAClass *Airport, const AirportFTAbuild
AirportFTA *FAutomata; AirportFTA *FAutomata;
AirportFTA *current; AirportFTA *current;
uint16 internalcounter, i; uint16 internalcounter, i;
FAutomata = malloc(sizeof(AirportFTA) * Airport->nofelements); FAutomata = (AirportFTA *)malloc(sizeof(AirportFTA) * Airport->nofelements);
Airport->layout = FAutomata; Airport->layout = FAutomata;
internalcounter = 0; internalcounter = 0;
@@ -243,13 +235,12 @@ static void AirportBuildAutomata(AirportFTAClass *Airport, const AirportFTAbuild
current->next_position = FA[internalcounter].next_in_chain; current->next_position = FA[internalcounter].next_in_chain;
// outgoing nodes from the same position, create linked list // outgoing nodes from the same position, create linked list
while (current->position == FA[internalcounter + 1].position) { while (current->position == FA[internalcounter+1].position) {
AirportFTA* newNode = malloc(sizeof(AirportFTA)); AirportFTA *newNode = (AirportFTA *)malloc(sizeof(AirportFTA));
newNode->position = FA[internalcounter+1].position;
newNode->position = FA[internalcounter + 1].position; newNode->heading = FA[internalcounter+1].heading;
newNode->heading = FA[internalcounter + 1].heading; newNode->block = FA[internalcounter+1].block;
newNode->block = FA[internalcounter + 1].block; newNode->next_position = FA[internalcounter+1].next_in_chain;
newNode->next_position = FA[internalcounter + 1].next_in_chain;
// create link // create link
current->next_in_chain = newNode; current->next_in_chain = newNode;
current = current->next_in_chain; current = current->next_in_chain;
@@ -268,14 +259,14 @@ static byte AirportTestFTA(const AirportFTAClass *Airport)
for (i = 0; i < Airport->nofelements; i++) { for (i = 0; i < Airport->nofelements; i++) {
position = Airport->layout[i].position; position = Airport->layout[i].position;
if (position != next_element) return i; if (position != next_element) {return i;}
temp = &Airport->layout[i]; temp = &Airport->layout[i];
do { do {
if (temp->heading > MAX_HEADINGS && temp->heading != 255) return i; if (temp->heading > MAX_HEADINGS && temp->heading != 255) {return i;}
if (temp->heading == 0 && temp->next_in_chain != 0) return i; if (temp->heading == 0 && temp->next_in_chain != 0) {return i;}
if (position != temp->position) return i; if (position != temp->position) {return i;}
if (temp->next_position >= Airport->nofelements) return i; if (temp->next_position >= Airport->nofelements) {return i;}
temp = temp->next_in_chain; temp = temp->next_in_chain;
} while (temp != NULL); } while (temp != NULL);
next_element++; next_element++;
@@ -283,8 +274,7 @@ static byte AirportTestFTA(const AirportFTAClass *Airport)
return MAX_ELEMENTS; return MAX_ELEMENTS;
} }
#if 0 static const char* const _airport_heading_strings[MAX_HEADINGS+2] = {
static const char* const _airport_heading_strings[] = {
"TO_ALL", "TO_ALL",
"HANGAR", "HANGAR",
"TERM1", "TERM1",
@@ -307,6 +297,7 @@ static const char* const _airport_heading_strings[] = {
"DUMMY" // extra heading for 255 "DUMMY" // extra heading for 255
}; };
/*
static void AirportPrintOut(const AirportFTAClass *Airport, const bool full_report) static void AirportPrintOut(const AirportFTAClass *Airport, const bool full_report)
{ {
AirportFTA *temp; AirportFTA *temp;
@@ -320,18 +311,16 @@ static void AirportPrintOut(const AirportFTAClass *Airport, const bool full_repo
heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading; heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading;
printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position, printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position,
_airport_heading_strings[heading], AirportBlockToString(temp->block)); _airport_heading_strings[heading], AirportBlockToString(temp->block));
} else {
printf("P:%2d NP:%2d", temp->position, temp->next_position);
} }
else { printf("P:%2d NP:%2d", temp->position, temp->next_position);}
while (temp->next_in_chain != NULL) { while (temp->next_in_chain != NULL) {
temp = temp->next_in_chain; temp = temp->next_in_chain;
if (full_report) { if (full_report) {
heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading; heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading;
printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position, printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position,
_airport_heading_strings[heading], AirportBlockToString(temp->block)); _airport_heading_strings[heading], AirportBlockToString(temp->block));
} else {
printf("P:%2d NP:%2d", temp->position, temp->next_position);
} }
else { printf("P:%2d NP:%2d", temp->position, temp->next_position);}
} }
printf("\n"); printf("\n");
} }
@@ -347,8 +336,7 @@ static byte AirportBlockToString(uint32 block)
if (block & 0x0000000c) { block >>= 2; i += 2; } if (block & 0x0000000c) { block >>= 2; i += 2; }
if (block & 0x00000002) { i += 1; } if (block & 0x00000002) { i += 1; }
return i; return i;
} }*/
#endif
const AirportFTAClass* GetAirport(const byte airport_type) const AirportFTAClass* GetAirport(const byte airport_type)
{ {
@@ -370,14 +358,3 @@ const AirportFTAClass* GetAirport(const byte airport_type)
} }
return Airport; return Airport;
} }
uint32 GetValidAirports(void)
{
uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
// 1980-1-1 is --> 21915
// 1990-1-1 is --> 25568
if (_date >= 21915) SETBIT(bytemask, 3); // metropilitan airport 1980
if (_date >= 25568) SETBIT(bytemask, 4); // international airport 1990
return bytemask;
}

View File

@@ -1,5 +1,3 @@
/* $Id$ */
#ifndef AIRPORT_H #ifndef AIRPORT_H
#define AIRPORT_H #define AIRPORT_H
@@ -50,11 +48,4 @@ void InitializeAirports(void);
void UnInitializeAirports(void); void UnInitializeAirports(void);
const AirportFTAClass* GetAirport(const byte airport_type); const AirportFTAClass* GetAirport(const byte airport_type);
/** Get buildable airport bitmask.
* @return get all buildable airports at this given time, bitmasked.
* Bit 0 means the small airport is buildable, etc.
* @todo set availability of airports by year, instead of airplane
*/
uint32 GetValidAirports(void);
#endif /* AIRPORT_H */ #endif /* AIRPORT_H */

View File

@@ -1,10 +1,6 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/sprites.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "window.h" #include "window.h"
#include "gui.h" #include "gui.h"
@@ -15,14 +11,13 @@
#include "vehicle.h" #include "vehicle.h"
#include "station.h" #include "station.h"
#include "airport.h" #include "airport.h"
#include "depot.h"
static byte _selected_airport_type; static byte _selected_airport_type;
static void ShowBuildAirportPicker(void); static void ShowBuildAirportPicker(void);
void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2) void CcBuildAirport(bool success, uint tile, uint32 p1, uint32 p2)
{ {
if (success) { if (success) {
SndPlayTileFx(SND_1F_SPLAT, tile); SndPlayTileFx(SND_1F_SPLAT, tile);
@@ -30,12 +25,12 @@ void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
} }
} }
static void PlaceAirport(TileIndex tile) static void PlaceAirport(uint tile)
{ {
DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE)); DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
} }
static void PlaceAir_DemolishArea(TileIndex tile) static void PlaceAir_DemolishArea(uint tile)
{ {
VpStartPlaceSizing(tile, 4); VpStartPlaceSizing(tile, 4);
} }
@@ -43,7 +38,7 @@ static void PlaceAir_DemolishArea(TileIndex tile)
static void BuildAirClick_Airport(Window *w) static void BuildAirClick_Airport(Window *w)
{ {
if (HandlePlacePushButton(w, 3, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker(); if (HandlePlacePushButton(w, 3, 0xAA4, 1, PlaceAirport)) ShowBuildAirportPicker();
} }
static void BuildAirClick_Demolish(Window *w) static void BuildAirClick_Demolish(Window *w)
@@ -65,7 +60,7 @@ static OnButtonClick * const _build_air_button_proc[] = {
static void BuildAirToolbWndProc(Window *w, WindowEvent *e) static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { switch(e->event) {
case WE_PAINT: case WE_PAINT:
DrawWindowWidgets(w); DrawWindowWidgets(w);
break; break;
@@ -80,7 +75,8 @@ static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
case '1': BuildAirClick_Airport(w); break; case '1': BuildAirClick_Airport(w); break;
case '2': BuildAirClick_Demolish(w); break; case '2': BuildAirClick_Demolish(w); break;
case 'l': BuildAirClick_Landscaping(w); break; case 'l': BuildAirClick_Landscaping(w); break;
default: return; default:
return;
} }
} break; } break;
@@ -106,10 +102,6 @@ static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
if (w != 0) if (w != 0)
WP(w,def_d).close = true; WP(w,def_d).close = true;
break; break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
} }
} }
@@ -137,47 +129,45 @@ void ShowBuildAirToolbar(void)
if (_current_player == OWNER_SPECTATOR) return; if (_current_player == OWNER_SPECTATOR) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0); DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDescFront(&_air_toolbar_desc, 0); AllocateWindowDescFront(&_air_toolbar_desc, 0);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
} }
static void BuildAirportPickerWndProc(Window *w, WindowEvent *e) static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
int sel; int sel;
int rad = 4; // default catchment radious int rad = 4; // default catchment radious
uint32 avail_airports;
if (WP(w,def_d).close) return; if (WP(w,def_d).close)
return;
w->disabled_state = 0;
sel = _selected_airport_type; sel = _selected_airport_type;
avail_airports = GetValidAirports(); // FIXME -- BuildAirportPickerWndProc - set availability of airports by year, instead of airplane
if (!(_avail_aircraft & 1)) { w->disabled_state |= (1<<3); if (sel == AT_SMALL) sel = AT_LARGE; }
if (!HASBIT(avail_airports, 0) && sel == AT_SMALL) sel = AT_LARGE; if (!(_avail_aircraft & 2)) { w->disabled_state |= (1<<4); if (sel == AT_LARGE) sel = AT_SMALL; }
if (!HASBIT(avail_airports, 1) && sel == AT_LARGE) sel = AT_SMALL; if (!(_avail_aircraft & 4)) { w->disabled_state |= (1<<5); } // heliport
// 1980-1-1 is --> 21915
/* 'Country Airport' starts at widget 3, and if its bit is set, it is // 1990-1-1 is --> 25568
* available, so take its opposite value to set the disabled_state. There if (_date < 21915) {w->disabled_state |= (1<<6);} // metropilitan airport 1980
* are only 5 available airports, so XOR with 0x1F (1 1111) */ if (_date < 25568) {w->disabled_state |= (1<<7);} // international airport 1990
w->disabled_state = (avail_airports ^ 0x1F) << 3;
_selected_airport_type = sel; _selected_airport_type = sel;
// select default the coverage area to 'Off' (8) // select default the coverage area to 'Off' (8)
w->click_state = ((1<<3) << sel) | ((1<<8) << _station_show_coverage); w->click_state = ((1<<3) << sel) | ((1<<8) << _station_show_coverage);
SetTileSelectSize(_airport_size_x[sel],_airport_size_y[sel]); SetTileSelectSize(_airport_size_x[sel],_airport_size_y[sel]);
if (_patches.modified_catchment) { if (_patches.modified_catchment) {
switch (sel) { switch (sel) {
case AT_OILRIG: rad = CA_AIR_OILPAD; break; case AT_OILRIG: rad = CA_AIR_OILPAD; break;
case AT_HELIPORT: rad = CA_AIR_HELIPORT; break; case AT_HELIPORT: rad = CA_AIR_HELIPORT; break;
case AT_SMALL: rad = CA_AIR_SMALL; break; case AT_SMALL: rad = CA_AIR_SMALL; break;
case AT_LARGE: rad = CA_AIR_LARGE; break; case AT_LARGE: rad = CA_AIR_LARGE; break;
case AT_METROPOLITAN: rad = CA_AIR_METRO; break; case AT_METROPOLITAN: rad = CA_AIR_METRO; break;
case AT_INTERNATIONAL: rad = CA_AIR_INTER; break; case AT_INTERNATIONAL: rad = CA_AIR_INTER; break;
} }
} }
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
DrawWindowWidgets(w); DrawWindowWidgets(w);
// strings such as 'Size' and 'Coverage Area' // strings such as 'Size' and 'Coverage Area'
@@ -188,7 +178,7 @@ static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
} }
case WE_CLICK: { case WE_CLICK: {
switch (e->click.widget) { switch(e->click.widget) {
case 3: case 4: case 5: case 6: case 7: case 3: case 4: case 5: case 6: case 7:
_selected_airport_type = e->click.widget - 3; _selected_airport_type = e->click.widget - 3;
SndPlayFx(SND_15_BEEP); SndPlayFx(SND_15_BEEP);
@@ -212,7 +202,8 @@ static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
} break; } break;
case WE_DESTROY: case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace(); if (!WP(w,def_d).close)
ResetObjectToPlace();
break; break;
} }
} }
@@ -226,8 +217,8 @@ static const Widget _build_airport_picker_widgets[] = {
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 63, 74, STR_306B_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT}, {WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 63, 74, STR_306B_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 39, 50, STR_305AA_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT}, {WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 39, 50, STR_305AA_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 51, 62, STR_305AB_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT}, {WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 51, 62, STR_305AB_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 88, 98, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 14, 73, 88, 98, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 88, 98, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 74, 133, 88, 98, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WIDGETS_END}, { WIDGETS_END},
}; };

View File

@@ -1,9 +1,8 @@
/* $Id$ */
#ifndef AIRPORT_MOVEMENT_H #ifndef AIRPORT_MOVEMENT_H
#define AIRPORT_MOVEMENT_H #define AIRPORT_MOVEMENT_H
#include "stdafx.h" #include "stdafx.h"
#include "macros.h"
typedef struct AirportMovingData { typedef struct AirportMovingData {
int x,y; int x,y;

View File

@@ -1,5 +1,3 @@
/* $Id$ */
/* /*
* This file has the core function for AyStar * This file has the core function for AyStar
* AyStar is a fast pathfinding routine and is used for things like * AyStar is a fast pathfinding routine and is used for things like
@@ -17,7 +15,7 @@
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "aystar.h" #include "aystar.h"
// This looks in the Hash if a node exists in ClosedList // This looks in the Hash if a node exists in ClosedList
// If so, it returns the PathNode, else NULL // If so, it returns the PathNode, else NULL
@@ -58,7 +56,7 @@ static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
// Adds a node to the OpenList // Adds a node to the OpenList
// It makes a copy of node, and puts the pointer of parent in the struct // It makes a copy of node, and puts the pointer of parent in the struct
static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g) static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g, int userdata)
{ {
// Add a new Node to the OpenList // Add a new Node to the OpenList
OpenListNode* new_node = malloc(sizeof(OpenListNode)); OpenListNode* new_node = malloc(sizeof(OpenListNode));
@@ -122,7 +120,7 @@ int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *pare
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f); aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
} else { } else {
// A new node, add him to the OpenList // A new node, add him to the OpenList
AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g); AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g, 0);
} }
return AYSTAR_DONE; return AYSTAR_DONE;
@@ -250,14 +248,13 @@ int AyStarMain_Main(AyStar *aystar) {
* if wanted. You should make sure that clear() is called before adding nodes * if wanted. You should make sure that clear() is called before adding nodes
* if the AyStar has been used before (though the normal main loop calls * if the AyStar has been used before (though the normal main loop calls
* clear() automatically when the algorithm finishes * clear() automatically when the algorithm finishes
* g is the cost for starting with this node.
*/ */
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g) { void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node) {
#ifdef AYSTAR_DEBUG #ifdef AYSTAR_DEBUG
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
TileX(start_node->tile), TileY(start_node->tile), start_node->direction); TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
#endif #endif
AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g); AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, 0, 0);
} }
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) { void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) {

View File

@@ -1,5 +1,3 @@
/* $Id$ */
/* /*
* This file has the header for AyStar * This file has the header for AyStar
* AyStar is a fast pathfinding routine and is used for things like * AyStar is a fast pathfinding routine and is used for things like
@@ -29,7 +27,7 @@ enum{
typedef struct AyStarNode AyStarNode; typedef struct AyStarNode AyStarNode;
struct AyStarNode { struct AyStarNode {
TileIndex tile; uint tile;
uint direction; uint direction;
uint user_data[2]; uint user_data[2];
}; };
@@ -58,14 +56,6 @@ typedef struct AyStar AyStar;
* AYSTAR_FOUND_END_NODE : indicates this is the end tile * AYSTAR_FOUND_END_NODE : indicates this is the end tile
* AYSTAR_DONE : indicates this is not the end tile (or direction was wrong) * AYSTAR_DONE : indicates this is not the end tile (or direction was wrong)
*/ */
/*
* The 2nd parameter should be OpenListNode, and NOT AyStarNode. AyStarNode is
* part of OpenListNode and so it could be accessed without any problems.
* The good part about OpenListNode is, and how AIs use it, that you can
* access the parent of the current node, and so check if you, for example
* don't try to enter the file tile with a 90-degree curve. So please, leave
* this an OpenListNode, it works just fine -- TrueLight
*/
typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current); typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current);
/* /*
@@ -99,7 +89,7 @@ typedef void AyStar_GetNeighbours(AyStar *aystar, OpenListNode *current);
typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current); typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current);
// For internal use, see aystar.c // For internal use, see aystar.c
typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode* start_node, uint g); typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode* start_node);
typedef int AyStar_Main(AyStar *aystar); typedef int AyStar_Main(AyStar *aystar);
typedef int AyStar_Loop(AyStar *aystar); typedef int AyStar_Loop(AyStar *aystar);
typedef int AyStar_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent); typedef int AyStar_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
@@ -163,7 +153,7 @@ struct AyStar {
}; };
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g); void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node);
int AyStarMain_Main(AyStar *aystar); int AyStarMain_Main(AyStar *aystar);
int AyStarMain_Loop(AyStar *aystar); int AyStarMain_Loop(AyStar *aystar);
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent); int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
@@ -176,4 +166,4 @@ void AyStarMain_Clear(AyStar *aystar);
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets); void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets);
#endif /* AYSTAR_H */ #endif

View File

@@ -1,25 +0,0 @@
/* $Id$ */
/** @file bridge.h Header file for bridges */
#ifndef BRIDGE_H
#define BRIDGE_H
/** Struct containing information about a single bridge type
*/
typedef struct Bridge {
byte avail_year; ///< the year in which the bridge becomes available
byte min_length; ///< the minimum length of the bridge (not counting start and end tile)
byte max_length; ///< the maximum length of the bridge (not counting start and end tile)
uint16 price; ///< the relative price of the bridge
uint16 speed; ///< maximum travel speed
PalSpriteID sprite; ///< the sprite which is used in the GUI (possibly with a recolor sprite)
StringID material; ///< the string that contains the bridge description
PalSpriteID **sprite_table; ///< table of sprites for drawing the bridge
byte flags; ///< bit 0 set: disable drawing of far pillars.
} Bridge;
extern const Bridge orig_bridge[MAX_BRIDGES];
extern Bridge _bridge[MAX_BRIDGES];
#endif /* BRIDGE_H */

View File

@@ -1,11 +1,6 @@
/* $Id$ */
/** @file bridge_gui.c Graphical user interface for bridge construction*/
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "window.h" #include "window.h"
#include "gui.h" #include "gui.h"
@@ -13,19 +8,23 @@
#include "gfx.h" #include "gfx.h"
#include "command.h" #include "command.h"
#include "sound.h" #include "sound.h"
#include "variables.h"
#include "bridge.h"
static struct BridgeData { static struct BridgeData {
uint count; int count;
TileIndex start_tile; TileIndex start_tile;
TileIndex end_tile; TileIndex end_tile;
byte type; byte type;
byte indexes[MAX_BRIDGES]; byte indexes[MAX_BRIDGES];
int32 costs[MAX_BRIDGES]; int32 costs[MAX_BRIDGES];
} _bridgedata; } _bridge;
void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2) extern const uint16 _bridge_type_price_mod[MAX_BRIDGES];
extern const PalSpriteID _bridge_sprites[MAX_BRIDGES];
extern const uint16 _bridge_speeds[MAX_BRIDGES];
extern const StringID _bridge_material[MAX_BRIDGES];
void CcBuildBridge(bool success, uint tile, uint32 p1, uint32 p2)
{ {
if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile); if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
} }
@@ -33,8 +32,7 @@ void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
static void BuildBridge(Window *w, int i) static void BuildBridge(Window *w, int i)
{ {
DeleteWindow(w); DeleteWindow(w);
DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile, DoCommandP(_bridge.end_tile, _bridge.start_tile, _bridge.indexes[i] | (_bridge.type << 8), CcBuildBridge,
_bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge,
CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE)); CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
} }
@@ -42,25 +40,25 @@ static void BuildBridgeWndProc(Window *w, WindowEvent *e)
{ {
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
uint i; int i;
DrawWindowWidgets(w); DrawWindowWidgets(w);
for (i = 0; i < 4 && i + w->vscroll.pos < _bridgedata.count; i++) { for(i=0; i < 4 && i + w->vscroll.pos < _bridge.count; i++) {
const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]]; int ind = _bridge.indexes[i + w->vscroll.pos];
SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]); SetDParam(2, _bridge.costs[i + w->vscroll.pos]);
SetDParam(1, (b->speed >> 4) * 10); SetDParam(1, (_bridge_speeds[ind] >> 4) * 10);
SetDParam(0, b->material); SetDParam(0, _bridge_material[ind]);
DrawSprite(b->sprite, 3, 15 + i * 22); DrawSprite(_bridge_sprites[ind], 3, 15 + i * 22);
DrawString(44, 15 + i * 22 , STR_500D, 0); DrawString(44, 15 + i*22 , STR_500D, 0);
} }
} break; } break;
case WE_KEYPRESS: { case WE_KEYPRESS: {
uint i = e->keypress.keycode - '1'; uint i = e->keypress.keycode - '1';
if (i < 9 && i < _bridgedata.count) { if (i < 9 && i < (uint)_bridge.count) {
e->keypress.cont = false; e->keypress.cont = false;
BuildBridge(w, i); BuildBridge(w, i);
} }
@@ -69,9 +67,9 @@ static void BuildBridgeWndProc(Window *w, WindowEvent *e)
} }
case WE_CLICK: case WE_CLICK:
if (e->click.widget == 2) { if (e->click.widget == 2) {
uint ind = ((int)e->click.pt.y - 14) / 22; uint ind = ((int)e->click.pt.y - 14) / 22;
if (ind < 4 && (ind += w->vscroll.pos) < _bridgedata.count) if (ind < 4 && (ind += w->vscroll.pos) < (uint)_bridge.count)
BuildBridge(w, ind); BuildBridge(w, ind);
} }
break; break;
@@ -112,56 +110,58 @@ static const WindowDesc _build_road_bridge_desc = {
}; };
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type) void ShowBuildBridgeWindow(uint start, uint end, byte bridge_type)
{ {
uint j = 0; int j = 0;
int32 ret; int32 ret;
StringID errmsg; uint16 errmsg;
DeleteWindowById(WC_BUILD_BRIDGE, 0); DeleteWindowById(WC_BUILD_BRIDGE, 0);
_bridgedata.type = bridge_type; _bridge.type = bridge_type;
_bridgedata.start_tile = start; _bridge.start_tile = start;
_bridgedata.end_tile = end; _bridge.end_tile = end;
errmsg = INVALID_STRING_ID; errmsg = 0xFFFF;
// only query bridge building possibility once, result is the same for all bridges! // only query bridge building possibility once, result is the same for all bridges!
// returns CMD_ERROR on failure, and price on success // returns CMD_ERROR on failure, and priCe on success
ret = DoCommandByTile(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE); ret = DoCommandByTile(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
if (CmdFailed(ret)) { if (ret == CMD_ERROR) {
errmsg = _error_message; errmsg = _error_message;
} else { }
// check which bridges can be built // check which bridges can be built
else {
int bridge_len; // length of the middle parts of the bridge int bridge_len; // length of the middle parts of the bridge
int tot_bridgedata_len; // total length of bridge int tot_bridge_len; // total length of bridge
// get absolute bridge length // get absolute bridge length
bridge_len = GetBridgeLength(start, end); bridge_len = GetBridgeLength(start, end);
tot_bridgedata_len = bridge_len + 2; tot_bridge_len = bridge_len + 2;
tot_bridgedata_len = CalcBridgeLenCostFactor(tot_bridgedata_len); tot_bridge_len = CalcBridgeLenCostFactor(tot_bridge_len);
for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
if (CheckBridge_Stuff(bridge_type, bridge_len)) { if (CheckBridge_Stuff(bridge_type, bridge_len)) {
const Bridge *b = &_bridge[bridge_type];
// bridge is accepted, add to list // bridge is accepted, add to list
// add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST) // add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST)
_bridgedata.costs[j] = ret + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8); _bridge.costs[j] = ret + (((int64)tot_bridge_len * _price.build_bridge * _bridge_type_price_mod[bridge_type]) >> 8);
_bridgedata.indexes[j] = bridge_type; _bridge.indexes[j] = bridge_type;
j++; j++;
} }
} }
} }
_bridgedata.count = j; _bridge.count = j;
if (j != 0) { if (j != 0) {
Window *w = AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc); Window *w = AllocateWindowDesc((_bridge.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc);
w->vscroll.cap = 4; w->vscroll.cap = 4;
w->vscroll.count = (byte)j; w->vscroll.count = (byte)j;
} else { } else {
ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * 16, TileY(end) * 16); ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE,
TileX(end) * 16, TileY(end) * 16);
} }
} }

View File

@@ -1,8 +1,5 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "callback_table.h"
#include "functions.h" #include "functions.h"
// If you add a callback for DoCommandP, also add the callback in here // If you add a callback for DoCommandP, also add the callback in here
@@ -11,7 +8,6 @@
/* aircraft_gui.c */ /* aircraft_gui.c */
CommandCallback CcBuildAircraft; CommandCallback CcBuildAircraft;
CommandCallback CcCloneAircraft;
/* airport_gui.c */ /* airport_gui.c */
CommandCallback CcBuildAirport; CommandCallback CcBuildAirport;
@@ -27,6 +23,7 @@ CommandCallback CcBuildCanal;
CommandCallback CcPlaySound10; CommandCallback CcPlaySound10;
CommandCallback CcPlaceSign; CommandCallback CcPlaceSign;
CommandCallback CcTerraform; CommandCallback CcTerraform;
//CommandCallback CcDemolish;
CommandCallback CcBuildTown; CommandCallback CcBuildTown;
/* rail_gui.c */ /* rail_gui.c */
@@ -42,16 +39,13 @@ CommandCallback CcRoadDepot;
/* roadveh_gui.c */ /* roadveh_gui.c */
CommandCallback CcBuildRoadVeh; CommandCallback CcBuildRoadVeh;
CommandCallback CcCloneRoadVeh;
/* ship_gui.c */ /* ship_gui.c */
CommandCallback CcBuildShip; CommandCallback CcBuildShip;
CommandCallback CcCloneShip;
/* train_gui.c */ /* train_gui.c */
CommandCallback CcBuildWagon; CommandCallback CcBuildWagon;
CommandCallback CcBuildLoco; CommandCallback CcBuildLoco;
CommandCallback CcCloneTrain;
CommandCallback *_callback_table[] = { CommandCallback *_callback_table[] = {
/* 0x00 */ NULL, /* 0x00 */ NULL,
@@ -74,11 +68,7 @@ CommandCallback *_callback_table[] = {
/* 0x11 */ CcPlaySound1D, /* 0x11 */ CcPlaySound1D,
/* 0x12 */ CcPlaySound1E, /* 0x12 */ CcPlaySound1E,
/* 0x13 */ CcStation, /* 0x13 */ CcStation,
/* 0x14 */ CcTerraform, /* 0x14 */ CcTerraform
/* 0x15 */ CcCloneAircraft,
/* 0x16 */ CcCloneRoadVeh,
/* 0x17 */ CcCloneShip,
/* 0x18 */ CcCloneTrain,
}; };
const int _callback_table_count = lengthof(_callback_table); const int _callback_table_count = sizeof (_callback_table) / sizeof (*_callback_table);

View File

@@ -1,11 +1,7 @@
/* $Id$ */
#ifndef CALLBACK_TABLE_H #ifndef CALLBACK_TABLE_H
#define CALLBACK_TABLE_H #define CALLBACK_TABLE_H
#include "functions.h"
extern CommandCallback *_callback_table[]; extern CommandCallback *_callback_table[];
extern const int _callback_table_count; extern const int _callback_table_count;
#endif /* CALLBACK_TABLE_H */ #endif

View File

@@ -1,303 +1,3 @@
0.4.7 (2006-03-26)
------------------------------------------------------------------------
- Feature: [OSX] Add support for triple-binaries (PPC, PPC970, i386) (r4102)
- Fix: [OSX] crash when going to fullscreen (r4100)
- Fix: Allow unused wagons to have their first cache set. Fixes faulty cache-warning message and noticably speeds up depot operations (r4094)
- Fix: [NPF] Trains & busses were unable to find a route when leaving a depot or bus stop. (r4072)
0.4.6 (2006-03-22)
------------------------------------------------------------------------
- Codechange: [win32] Show the revision in crash.txt and enable the button to show the crash text in the crash-window (r3965)
- Codechange: Add additional linker information to release builds to help figure out crashes more easily (r3526)
- Fix: [OSX 10.3 and newer] [ 1157244 ] Can't save game if name contains german umlauts (loading savegames with certain chars still look odd) (r4038)
- Fix: [OSX] major speedup for PPC fullscreen (r4034)
- Fix: [Makefile] Make sure the ICON_DIR gets created before copying files there. (r4032)
- Fix: [win32] Change compiler settings to use the multithreaded CRT. This prevents certain crashes on multi-threaded machines. (r4031)
- Fix: [ 1453646 NPF ] Road vehicles planning through the back of depots and stations. (r4029)
- Fix: Use the title of a savegame in the saveload dialog-editbox. (r4018)
- Fix: Improper resolution written to the configuration file when exiting from fullscreen. (r4017)
- Fix: When removing rail track from a tile where only X and Y pieces exist, explicitly update signals in both directions. (r4016)
- Fix: Default the patch-setting 'pause_on_join' to true. (r4015)
- Fix: Slope and height information returned for some tile types is wrong (r4014)
- Fix: Fixes a bug introduced by r3228 which allowed steep rail tiles resulting in ... unwanted effects such as display artifacts. (r4012)
- Fix: Update french translation (r3978)
- Fix: FS#56 - [Crash] Missing glyph(s) in big-font. Added several missing glyphs for the big font. (r3970)
- Fix: [ 1439907 ] Increase client list window width so at least most languages fit. (r3969)
- Fix: Update german and finnish languages. (r3968)
- Fix: Properly set back the owner of a crossing/road-under bridge after removing it. (r3967)
- Fix: [autoreplace]: (FS#67) autoreplacing trains now keep their tile length instead of their pixel length. (r3964)
- Fix: Mark the right tile as dirty. It's just a graphical glitch which happend in r1592. (r3962)
- Fix: Fix crash when resizing news history window. (r3961)
- Fix: Correctly implement minimum search, so road vehicles head twoards the closest station, not the last one in the list. (r3960)
- Fix: [FS#61] The tooltips for raising and lowering land buttons in the scenario editor are interchanged (r3959)
- Fix: Correctly restore the roadside after roadworks are finished. (r3957)
- Fix: [Multistop] Check the status of the destination road stop instead of a station's first road stop. This only has effect with road vehicle queuing disabled. (r3956)
- Fix: validate the setting of max_companies/spectators through the console. (r3955)
- Fix: Improve game-load times. (r3954)
- Fix: On loading a game, GetPlayerRailtypes() didn't account for the fact that vehicles are introduced a year after their introduction date. This will also relieve possible (rare) network desyncs. (r3952)
- Fix: Restore plural forms of cargo types for several languages. (r3951)
- Fix: [win32] Add directives to allow Visual Studio 2005 compilation. (r3950)
- Fix: [ 1415782 ] crash in string code with openbsd/zaurus; alignment issues (r3948)
0.4.5 (2006-01-31)
------------------------------------------------------------------------
- Feature: [newgrf] Implement varaction2 property 0x41 and 0xDA. (2361)
- Feature: giving server_ip a value of 'all' will make the server listen on any interface (2374)
- Feature: shortcut CTRL + U that clears the current input-box (2385)
- Feature: [newgrf] Implement the mechanism for handling newgrf callbacks (2389)
- Feature: [newgrf] Implement the 'refit capacity' callback (2389)
- Feature: saving games happen in a seperate thread (2391)
- Feature: [newgrf] Implement powered wagons, and the callback that goes with it (2414)
- Feature: [newgrf] Implement shorter train vehicles (2428)
- Feature: New display option: 'transparent station signs' (2438)
- Feature: You can now give transfer order to set up feeder systems (2441)
- Feature: Removing tracks with the 'remove' tool, automatically removes signals on the tracks (2469)
- Feature: [localisation] Allow changing the order of parameters in translated strings (2573)
- Feature: [localisation] New way to specify plural forms (2592)
- Feature: [localisation] Support genders (2594)
- Feature: [localisation] Support cases (2597)
- Feature: add support for truncating strings to a given (pixel) length (2607)
- Feature: Overhaul DirectMusic MIDI backend, remove "experimental" status (2712)
- Feature: Change the driver probing algorithm: Use the first music/sound/video which succeeds initialising instead of bailing out after the first. No need to specify -snull if no soundcard is present anymore (2728)
- Feature: The Main Toolbar Dropdown Menu can now display disabled items (2734)
- Feature: Clone vehicles (2764)
- Feature: When starting without a config file determine the language on basis of the current locale (2777)
- Feature: [NewGRF] Add support for "extended bytes" (2872)
- Feature: [localisation] Major step twoards ISO-8859-15: Implement missing characters (2879)
- Feature: Implement the console command rm to remove savegames (2941)
- Feature: Danish town names (2957)
- Feature: Menu option to toggle console (2958)
- Feature: Calculate proportions of non-square giant screenshot correctly (2963)
- Feature: [newgrf] Implement current set of action D (ParamSet) operations (2968)
- Feature: [newgrf] Show a wagon's speed limit in purchase list (2969)
- Feature: [newgrf] Support loading VarAction2 parameter for variables 0x60-0x7F (2971)
- Feature: [newgrf] Add patch option for wagon speed limits (2982)
- Feature: [newgrf] Support loading of bridge attributes and tables from GRF (3004)
- Feature: Native Support for Win64 (3008)
- Feature: OSX now uses quicktime to play midi files (3022)
- Feature: [OSX] Command+Q now works in main menu (3027)
- Feature: Allow unbanning players based on banlist-id (as well as IP) (3067)
- Feature: 'status' and 'clients' now show the IP of the players (3067)
- Feature: Make it possible to create a screenshot from the console that is both big and has no console, or any combination of (3068)
- Feature: [newgrf] Add support for rail vehicle weight greater than 255 tons (3071)
- Feature: 'HOME' icon to saveload dialogs that jumps to the default save/load directory based on the dialog (3096)
- Feature: Turkish translation (3120)
- Feature: [newgrf] Support positioning of rail vehicle visual effects (3132)
- Feature: [newgrf] Support for articulated rail vehicles (3139)
- Feature: [newgrf] Add support for cargo refitting specification by cargo classes (3148)
- Feature: [newgrf] Action 7/9 new value : is it TTDPatch or OpenTTD? (3152)
- Feature: Drag and drop rocky areas in scenario editor (3153)
- Feature: Added patch option to link the terraform toolbar to the rail, road, water and airport toolbars (3157)
- Feature: Right-Click-Scrolling optionally moves in the opposite direction (3222)
- Feature: Native cocoa sound and video drivers for OSX (3281)
- Feature: [newgrf] Allow train running cost class to differ from engine class (3388)
- Feature: Kick and ban now with IP numbers (3407)
- Feature: Allow seeing and setting the maximum amount of companies and spectators for a server. This can be changed/viewed during runtime as well in the console (3427)
- Feature: Allow the network game list to be sorted (by name/clients/compatibility ascending/descending) (3441)
- Feature: Make it possible to ban offline clients (3469)
- Fix: The refit window now shows the correct refit options (2365)
- Fix: Refitting to a cargo which is already carried by some vehicles takes their capacities into account for display (2365)
- Fix: Add 'multihead' TTDPatch option to OpenTTD newgrf flags-emulation (2368)
- Fix: make install tried to install scenarios in the (non-existing) personal dir when USE_HOMEDIR is specified (2371)
- Fix: [console] update the example scripts in the scripts/ directory to reflect the new console functionality (2372)
- Fix: [console] any line starting with a '#' is a comment so ignore it (2372)
- Fix: [console] The special variables whose value can only be set by a custom process should, also print out their newly set value there (2372)
- Fix: [newgrf] Ignore action 0 prop 0x20 (air drag) (2377)
- Fix: [newgrf] Further property stubs, help prevents subsequent incorrect reading of newgrf data (2378)
- Fix: Build year for mail compartment of planes was not set correctly, affected station ratings (2380)
- Fix: Endgame window on easy difficulty resulted in infinite loop (2381)
- Fix: Check the airport type when building an airport (2382)
- Fix: Monkey-testing turned up some command crashes (2383)
- Fix: Check selling land and setting player colour. Also an extra map-bounds check for terraforming (2384)
- Fix: [realistic accel] Very slow trains no longer get an increase in maximum speed when part of them is in a depot (2388)
- Fix: [newgrf] Load power for dual-headed engines correctly (2400)
- Fix: [newgrf] When resolving callbacks, dont ignore wagon overrides (2410)
- Fix: Station ratings aren't affected by speed limits from realistic acceleration anymore (2411)
- Fix: building vehicles without depot crashed the game (2412)
- Fix: certain resolutions caused a crash when minimap was partly dragged outside the game window (2424)
- Fix: Deleting canals under bridges removed bridges first in certain configurations (2436)
- Fix: [NPF] Vehicles try to drive into a tunnel entrance from above (2471)
- Fix: [newgrf] Some road vehicle action 0 properties were loaded as the wrong type (int8,int16,int32) causing undefined results. (like cargo types being wrong) (2474)
- Fix: The console variable autoclean_unprotected was linked to the variable _network_autoclean_protected (2498)
- Fix: Old bug in the PCX writer: The first pixel column contained garbage, the picture was shifted one to the right, and the last column was dropped (2512)
- Fix: Using the mouse wheel could lead to a crash if mouse was not over a widget (2530)
- Fix: blinking 'lock' gfx in multiplayer games (2548)
- Fix: Remove original train pathfinder. Enhanced old pathfinder. (2553)
- Fix: Spaces in the path to the MIDI files caused the win32 MIDI player to fail (2563)
- Fix: set server map name to the loaded name of the game/scenario (2610)
- Fix: Improve the old pathfinder. Changed it to A* instead of Dijkstra. Benchmark shows that NTP is now around 10x faster than NPF (2635)
- Fix: Correctly save and load company_value, it's 64 bits wide, not 32 bits (2684)
- Fix: Volume control works now for the DirectMusic MIDI backend (2712)
- Fix: Change the fence algorithm so it removes fences when no farm tile is adjacent (2739)
- Fix: Tree tiles above the snow line got redrawn disproportionately often (2750)
- Fix: Depots could build trains of the wrong track type (2764)
- Fix: Sort the directories in the scenarion/savegame list (2860)
- Fix: On OS/2 show the trailing \ if the current directory is a root directory (2860)
- Fix: Return a proper version number, when testing the TTDPatch version in the SkipIf action (2862)
- Fix: Change the way NewGRFs are loaded, this saves quite some sprite slots - about 2000 for DBSetXL for example (2868)
- Fix: Several format string vulnerabilities and buffer overflows in the network code (2899)
- Fix: fixed issue where autorenewed vehicles didn't get all stats updated (2912)
- Fix: Exit the child of the extmidi backend with _exit() instead of exit(), because we don't want any atexit handlers - especially flushing output streams - to run, if exec() fails (2938)
- Fix: Server crash with "say"-command (2950)
- Fix: Fix win32 midi volume level control which didn't work (2960)
- Fix: [OSX] quitting the game no longer leaves a process behind that eats all the CPU power (3281)
- Fix: Fix for [ 1216203 ] UFO-broken waypoint (2961)
- Fix: [newgrf] Include missing grf feature canal
- Fix: [newgrf] Add bounds checking to VehicleChangeInfo for vehicles
- Fix: [newgrf] Wagon speed limits don't apply for wagons with livery overrides
- Fix: Align settings pool items to the size of void* to fix bus errors on 64bit architectures which require aligned variables (2976)
- Fix: restart_game_date is an UINT16, not a BYTE. Now setting the game restart year via the console should work (2987)
- Fix: [newgrf] Some GRF files don't specify a name or description, in which case the Action 8 is 8 bytes, not 9 (3005)
- Fix: The finnish markka was never abbreviated with capital letters (3021)
- Fix: Improve handling of non-existent sprite sets (3044)
- Fix: Don't attempt to map and empty sprite group to a vehicle (3045)
- Fix: Fixed typo and hang for BeOS Networking (3053)
- Fix: On Win98 and lower when you go to the root directory of a drive (eg. C:\) you were stuck there indefinitely and couldn't change any directories or see any files (3056)
- Fix: Complete rewrite of autoreplace; multiheaded train engines are replaced correctly (3081)
- Fix: A new train is now made if the front unit is an engine and the former front engine is moved away (3144)
- Fix: There are only 2 possible directions for ship depots, not 4 (3199)
- Fix: Allow bribing up to the maximum rating for bribing, don't disable this option at some arbitrary value early (3201)
- Fix: Don't lower land on tunnel, even with diag tracks on it (3228)
- Fix: Crash when making a screenshotin the main menu (3235)
- Fix: Crash when starting a scenarion via 'New Game' fails (3235)
- Fix: Determine clicked status of sticky icon from window flags rather than the widget click state (3247)
- Fix: Graphical glitch with autorail tool on a certain tile-types (3254)
- Fix: Center the X of the window close button (3302)
- Fix: [newgrf] Unload engine names before loading grf files (3316)
- Fix: Network window crash when it receives invalid information for example from the integrated nightly, so validate the network-input when it is received (3322)
- Fix: Build failed if SDL is built without pthread support (3326)
- Fix: Move initialization of vehicle random_bits to DC_EXEC blocks to allow use of Random() instead of InteractiveRandom(), which will alleviate some possib le network desyncs (3352)
- Fix: The default AI tried to change the service intervals of vehicles via the CMD_CHANGE_TRAIN_SERVICE_INT command - regardless of the type of the vehicle (3367)
- Fix: Out-of-bounds array access when road vehicles overtook in a curve caused desyncs (3371)
- Fix: Update signal states when building or removing rail station blocks (3372)
- Fix: Don't allow trains to get bigger than 100 via drag and drop (3374)
- Fix: Don't reset date in the scenario editor when pressing RandomLand (3376)
- Fix: [newgrf] Running cost should be halved for dual head vehicles (3384)
- Fix: No fence was placed when placing fences and the neighbouring tile is a rail configuration which permits a fence but has a signal (3389)
- Fix: [newgrf] Ignore non-climate dependent cargo types (3394)
- Fix: [newgrf] Only add a random number of days to an engine's base introduction date if that date is not 0 (3410)
- Fix: When changing the server password via the console, actually set the password as well as flag whether it is required (3411)
- Fix: Under certain conditions placing a road tile parallel under a bridge would, instead of failing, succeed and place a perpendicular piece (3413)
- Fix: Disable the Fund New Industry menu item and window when connected to a server as a spectator (3414)
- Fix: Disable the clone and refit buttons in the train view when viewing another player's vehicles, or as a spectator (3415)
- Fix: Disallow building an oil rig above sea level (3416)
- Fix: When removing a town-owned tunnel the player's rating was not reduced (3418)
- Fix: (Possible) game crash on removing track/road under bridge if a vehicle was on the track/road under the bridge and the track/road sloped (3419)
- Fix: [newgrf] Only power should decide whether a rail vehicle is an engine or a wagon. (fixes SHIKI 810 in jpsetw.grf) (3424)
- Fix: Incorrect validating of tree-planting command which can allow a buffer-overflow (3446)
- Fix: [newgrf] When changing the sprite ID of a vehicle, if it is not FD (custom graphics), the value needs to changed from a 16bit array offset to an array index. (fixes tropicstw.grf) (3449)
- Fix: You couldn't remove an item from a list-type of config ingame from the configuration file (3475)
- Fix: [newgrf] Always reinitialize the ttdpatch flags as patch settings may have changed (3486)
- Fix: Price for demolishing a bridge was dependent on orientation and map size (3487)
0.4.0.1 (2005-05-21)
------------------------------------------------------------------------
- Feature: Add 'clear' command and CTRL+L to empty console window
- Feature: add the possibility to print out the current debug-level
- Fix: [MacOSX] default path for midi player on mac is now correct again
- Fix: Updated makefile for FreeBSD
- Fix: Text overflows in about box
- Fix: Link error while compiling as dedicated server
- Fix: Do not execute empty commands
- Fix: Make OpenTTD icon look good on Win2K and earlier
- Fix: NetworkUDPRemoveAdvertise wasn't completely correct
- Fix: Signs in multiplayer didn't work
- Fix: Dedicated server desyncs
- Fix: [ 1197216 ] Error: !invalid string id 0 in GetString, dedicated server endgame crash
- Fix: Don't allow things to be renamed to nothing
- Fix: Windows installer deletes spritecache files on uninstall
- Fix: Depot window did not get redrawn when a non-train-engine was sold
- Fix: Do not scroll the game with the arrow keys when the chatbox is open
- Fix: Remove warning from release build when assertions are no longer active
- Fix: It was possible to open more than one tree window
0.4.0 (2005-05-15)
------------------------------------------------------------------------
- Feature: Bigger maps. Enjoy playing up to 2028x2048 (64 times as big as you were used to!)
- Feature: New realistic acceleration; should be much better. Inlcudes gigger penalty on narrow curves and speedlimits in depots/stations
- Feature: It is now possible to build multiple road stations (up to 8) on a single station (multibus).
- Feature: New PathFinder (NPF). Support for train/road and ship based on A*. No more braindead pathfinding
- Feature: Dynamic towns/industries/stations/vehicles/signs/orders/everything, up to 64K
- Feature: Brand new OldLoader so OpenTTD is TTD(Patch) compatible again. Also endian safe
- Feature: Even better newgrf support, except for callbacks, everything works (ok, almost)
- Feature: Improved multiplayer. More console options, less desyncs and more fun
- Feature: Protected OpenTTD from interference of hacked clients, so it should be safe to play again.
- Feature: [ 1093261 ] Saving vehicle sorting criteria for each vehicle type
- Feature: [ 1107690 ] Resizable orders GUI
- Feature: [ 1166978 ] Focus keyboard on input-box in Multiplayer Menu
- Feature: [ 1174313 ] terrain hotkeys nonfunctional in scenario editor (D,Q,W,E,R,T,Y,U fltr)
- Feature: Complete rework of console and new commands like ls, save, load, help, etc.
- Feature: Signs are shown in the colour of the player who created them
- Feature: Add cheat option to set production of raw-material industries in game
- Feature: Replace trian GUI remembers railtype selected from the dropdown menu
- Feature: Improved Autoreplace
- Feature: many more smaller features :D
- Fix: [ 1108618 ] A wrong error message was displayed when trying to
- Fix: [ 1110407 ] Game does not crash any more when a newgrf file doesn't exist
- Fix: [ 1112469 ] Clearing land for free by reallocating HQ
- Fix: [ 1112469 ] Clearing land for free by reallocating HQ
- Fix: [ 1113037 ] crash when accessing hi-scores in editor, it is now disabled.
- Fix: [ 1113399 ] Game no longer crashes when right-clicking a disabled Full Load button
- Fix: [ 1114100 ] Dedicated server boots again
- Fix: [ 1114950 ] Game crashed sometimes when there were no industries in the map
- Fix: [ 1115200 ] In the main menu, when starting a new game while the load game dialog is open, openttd asserts.
- Fix: [ 1117538 ] non-stop orders are no longer accidently skipped
- Fix: [ 1116619 ] Generate the correct smoke type for diesel trains
- Fix: [ 1119308 ] Max passengers / mail variables are now 32 bit
- Fix: [ 1109400 ] Better test if a string actually contains any console command
- Fix: [ 1108637 ] 'Play scenario' now loads game options and difficulty, 'Load game' starts game with user-selected values.
- Fix: [ 1143587 ] carriages of newgrfs can be refitted again
- Fix: [ 1117730 ] Production values of temperate-climate banks can now be altered
- Fix: [ 1118810 ] openttd: ship_cmd.c:642 ... Assertion failed. Mapwrap fixed in ship_cmd.c (was implicitely ok before biggermaps).
- Fix: [ 1117327 ] Assertion error on kick. When a company is cleaned all its windows need to be closed. For global vehicle lists, the no-staiton index of -1 was not taken into account
- Fix: [ 1114261 ] Speeding up when pressing ALT+TAB (Windows)
- Fix: [ 1149403 ] Signals dissaper after typing text and pressing enter!. Signs in Scenario Editor have no owner so ignore that.
- Fix: [ 1149766 ] Single tile Bridge in Volcano City scenario. Some bridges still had the old single-tile bridge bug that was caused by improper town growth in combination with DC_AUTO. Fixed the scenario.
- Fix: [ 1119147 ] Stop startup memory corruption crash using optimized MSVC6. MSVC6 workaround as it's too stupid again for its own good
- Fix: [ 1101874 ] Dedicated server now accepts '-g' (load game) as param
- Fix: [ 1155696 ] Crash with german umlauts in station names.
- Fix: [ 1158618 ] Segmentation fault when loading savegame, out of bounds array check.
- Fix: [ 1149487 ] Autosave ignoring settings
- Fix: [ 1024703 ] Infinite access for A:\ (win32). Patch [1171208]. Only requery drive(s) if the user changes a directory, also surpress the OS error box that pops up on some windows machines.
- Fix: [ 1095110 ] Create Lake and draggable Create Desert tools
- Fix: [ 1172878 ] Trains "Go to depot" button: click twice skip to next order
- Fix: [ 1146215 ] Engine power not updated w/auto replace" autoreplace now forces an update of the cache.
- Fix: [ 1173690 ] Path displaying as "C:\\" in saveload window win32-only
- Fix: [ 1179892 ] click & drag removal of road assertion fail.
- Fix: [ 1174237 ] Max loan always in euros, use _opt_ptr instead of _opt
- Fix: [ 1184201 ] AI orders its vehicles to a competitor's truck stop.
- Fix: [ 1188986 ] Song in main menu screen should loop when it ends.
- Fix: [ 1188777 ] Non-existing sprite #5125 (presignal). The DOS grf file trgi.grf has 6 less sprites than the windows one.
- Fix: [ 1190625 ] Changing mapsize crashes game with highlighting.
- Fix: [ 1190896 1184378 ] [NPF] Trains ignoring their railtype (mono, maglev)
- Fix: [ 1202115 ] Clicking shipslist on bouy asserts GetPlayer().
- Fix: [ 1187613 ] No HQ present for competitor, disable 'View HQ' button
- Fix: [ 1193048 ] Pre-signal stays red when there is only a single exit signal
- Fix: [ 1185176 ] Train in tunnel is not properly detected by signal code
- Fix: [newgrf] rotors of custom helicopters are displayed correctly in the hangar window
- Fix: Scenario Editor now handles human-made roads better (try to build a city layout before placing the city, finally that works very nice)
- Fix: [Newgrf] helicopters are correctly recognized
- Fix: [autoreplace] made sure that planes only show planes in replace GUI and helicopters only show helicopters
- Fix: (Work around?) crash when generating tropical maps
- Fix: [autoreplace] Cheaters can no longer exploit autoreplace to get vehicles, that's not invented yet
- Fix: [autoreplace] Fixed a stupid bug introduced in r1687, that made a crash if anybody tried to autoreplace anything but an aircraft
- Fix: expand railroad stations beyond maximum spread
- Fix: [autoreplace] fixed a typo that could prevent autoreplaced aircraft from automatically go to a hangar
- Fix: Hacked clients can no longer be used to build vehicles that are not available yet
- Fix: Minimum profit of vehicles was calculated wrong for Performance Rating
- Fix: no longer a station where you only unload is bad for your town-rating
- Fix: Crash in scenario-editor with terraforming out-of-map bounds.
- Fix: Game would crash if you full-screened with the 'fullscreen' button than chose a resolution from the dropdown box that was no longer valid.
- Fix: Scrolling with the arrow keys is now smooth and it now also scrolls exactly in tile direction if e.g. up and left are pressed
- Fix: many more fixes but I am too tired to list them all
0.3.6 (2005-01-24) 0.3.6 (2005-01-24)
------------------------------------------------------------------------ ------------------------------------------------------------------------
- Feature: resizable windows. All useful windows are already made resizable. - Feature: resizable windows. All useful windows are already made resizable.
@@ -428,6 +128,7 @@
- Fix: When deleting an order, the next pointer was not cleared, resulting in some unusual behavoir from time to time - Fix: When deleting an order, the next pointer was not cleared, resulting in some unusual behavoir from time to time
- Fix: You can now also delete automatically found servers by pressing "del" - Fix: You can now also delete automatically found servers by pressing "del"
- Fix: You should no longer be able to delete bridges on any type of underground when there is a vehicle on it - Fix: You should no longer be able to delete bridges on any type of underground when there is a vehicle on it
- Fix: your loan is now substracted from your company value
- Add: A brand new set of icons. - Add: A brand new set of icons.
- Change: AutoRenew is now a client-side patch instead of a game-side patch - Change: AutoRenew is now a client-side patch instead of a game-side patch
- Change: Removed the 'close ALL windows' from the toolbar since shift+del does this. - Change: Removed the 'close ALL windows' from the toolbar since shift+del does this.

View File

@@ -1,16 +1,9 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "player.h"
#include "tile.h"
#include "viewport.h" #include "viewport.h"
#include "command.h" #include "command.h"
#include "variables.h"
#include "table/sprites.h"
typedef struct TerraformerHeightMod { typedef struct TerraformerHeightMod {
TileIndex tile; TileIndex tile;
@@ -37,11 +30,13 @@ static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
TileIndex *t; TileIndex *t;
int count; int count;
if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1; if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY())
return -1;
t = ts->tile_table; t = ts->tile_table;
for (count = ts->tile_table_count; count != 0; count--, t++) { for(count = ts->tile_table_count; count != 0; count--,t++) {
if (*t == tile) return 0; if (*t == tile)
return 0;
} }
return 1; return 1;
@@ -52,8 +47,9 @@ static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
TerraformerHeightMod *mod = ts->modheight; TerraformerHeightMod *mod = ts->modheight;
int count; int count;
for (count = ts->modheight_count; count != 0; count--, mod++) { for(count = ts->modheight_count; count != 0; count--, mod++) {
if (mod->tile == tile) return mod->height; if (mod->tile == tile)
return mod->height;
} }
return TileHeight(tile); return TileHeight(tile);
@@ -66,10 +62,12 @@ static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
count = ts->tile_table_count; count = ts->tile_table_count;
if (count >= 625) return; if (count >= 625)
return;
for(t = ts->tile_table; count != 0; count--,t++) { for(t = ts->tile_table; count != 0; count--,t++) {
if (*t == tile) return; if (*t == tile)
return;
} }
ts->tile_table[ts->tile_table_count++] = tile; ts->tile_table[ts->tile_table_count++] = tile;
@@ -77,39 +75,61 @@ static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile) static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
{ {
TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1)); TerraformAddDirtyTile(ts, tile+TILE_XY(0,-1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1)); TerraformAddDirtyTile(ts, tile+TILE_XY(-1,-1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0)); TerraformAddDirtyTile(ts, tile+TILE_XY(-1,0));
TerraformAddDirtyTile(ts, tile); TerraformAddDirtyTile(ts, tile);
} }
static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode) static int TerraformProc(TerraformerState *ts, uint tile, int mode)
{ {
int r; int r;
int32 ret;
assert(tile < MapSize()); assert(tile < MapSize());
if ((r=TerraformAllowTileProcess(ts, tile)) <= 0) if ((r=TerraformAllowTileProcess(ts, tile)) <= 0)
return r; return r;
if (!IsTileType(tile, MP_RAILWAY)) { if (IsTileType(tile, MP_RAILWAY)) {
int32 ret = DoCommandByTile(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR); static const byte _railway_modes[4] = {8, 0x10, 4, 0x20};
static const byte _railway_dangslopes[4] = {0xd, 0xe, 7, 0xb};
static const byte _railway_dangslopes2[4] = {0x2, 0x1, 0x8, 0x4};
if (CmdFailed(ret)) { // Nothing could be built at the steep slope - this avoids a bug
// when you have a single diagonal track in one corner on a
// basement and then you raise/lower the other corner.
int tileh = GetTileSlope(tile, NULL) & 0xF;
if (tileh == _railway_dangslopes[mode] ||
tileh == _railway_dangslopes2[mode]) {
_terraform_err_tile = tile; _terraform_err_tile = tile;
_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
return -1; return -1;
} }
ts->cost += ret; // If we have a single diagonal track there, the other side of
// tile can be terraformed.
if ((_map5[tile]&~0x40) == _railway_modes[mode])
return 0;
} }
if (ts->tile_table_count >= 625) return -1; ret = DoCommandByTile(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (ret == CMD_ERROR) {
_terraform_err_tile = tile;
return -1;
}
ts->cost += ret;
if (ts->tile_table_count >= 625)
return -1;
ts->tile_table[ts->tile_table_count++] = tile; ts->tile_table[ts->tile_table_count++] = tile;
return 0; return 0;
} }
static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height) static bool TerraformTileHeight(TerraformerState *ts, uint tile, int height)
{ {
int nh; int nh;
TerraformerHeightMod *mod; TerraformerHeightMod *mod;
@@ -124,32 +144,42 @@ static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height
_error_message = STR_1004_TOO_HIGH; _error_message = STR_1004_TOO_HIGH;
if (height > 15) return false; if (height > 0xF)
return false;
nh = TerraformGetHeightOfTile(ts, tile); nh = TerraformGetHeightOfTile(ts, tile);
if (nh < 0 || height == nh) return false; if (nh < 0 || height == nh)
return false;
if (TerraformProc(ts, tile, 0) < 0) return false; if (TerraformProc(ts, tile, 0)<0)
if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false; return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, 0), 3) < 0) return false; if (TerraformProc(ts, tile + TILE_XY(0,-1), 1)<0)
return false;
if (TerraformProc(ts, tile + TILE_XY(-1,-1), 2)<0)
return false;
if (TerraformProc(ts, tile + TILE_XY(-1,0), 3)<0)
return false;
mod = ts->modheight; mod = ts->modheight;
count = ts->modheight_count; count = ts->modheight_count;
for (;;) { for(;;) {
if (count == 0) { if (count == 0) {
if (ts->modheight_count >= 576) if (ts->modheight_count >= 576)
return false; return false;
ts->modheight_count++; ts->modheight_count++;
break; break;
} }
if (mod->tile == tile) break; if (mod->tile == (TileIndex)tile)
break;
mod++; mod++;
count--; count--;
} }
mod->tile = tile; mod->tile = (TileIndex)tile;
mod->height = (byte)height; mod->height = (byte)height;
ts->cost += _price.terraform; ts->cost += _price.terraform;
@@ -179,15 +209,15 @@ static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height
return true; return true;
} }
/** Terraform land /* Terraform land
* @param x,y coordinates to terraform * p1 - corners
* @param p1 corners to terraform. * p2 - direction
* @param p2 direction; eg up or down
*/ */
int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
TerraformerState ts; TerraformerState ts;
TileIndex tile; uint tile;
int direction; int direction;
TerraformerHeightMod modheight_data[576]; TerraformerHeightMod modheight_data[576];
@@ -205,64 +235,51 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
ts.modheight = modheight_data; ts.modheight = modheight_data;
ts.tile_table = tile_table_data; ts.tile_table = tile_table_data;
tile = TileVirtXY(x, y); tile = TILE_FROM_XY(x,y);
/* Make an extra check for map-bounds cause we add tiles to the originating tile */
if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
if (p1 & 1) { if (p1 & 1) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 0), if (!TerraformTileHeight(&ts, tile+TILE_XY(1,0),
TileHeight(tile + TileDiffXY(1, 0)) + direction)) TileHeight(tile + TILE_XY(1, 0)) + direction))
return CMD_ERROR; return CMD_ERROR;
} }
if (p1 & 2) { if (p1 & 2) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 1), if (!TerraformTileHeight(&ts, tile+TILE_XY(1,1),
TileHeight(tile + TileDiffXY(1, 1)) + direction)) TileHeight(tile + TILE_XY(1, 1)) + direction))
return CMD_ERROR; return CMD_ERROR;
} }
if (p1 & 4) { if (p1 & 4) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 1), if (!TerraformTileHeight(&ts, tile+TILE_XY(0,1),
TileHeight(tile + TileDiffXY(0, 1)) + direction)) TileHeight(tile + TILE_XY(0, 1)) + direction))
return CMD_ERROR; return CMD_ERROR;
} }
if (p1 & 8) { if (p1 & 8) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 0), if (!TerraformTileHeight(&ts, tile+TILE_XY(0,0),
TileHeight(tile + TileDiffXY(0, 0)) + direction)) TileHeight(tile + TILE_XY(0, 0)) + direction))
return CMD_ERROR; return CMD_ERROR;
} }
{ /* Check if tunnel or track would take damage */ if (direction == -1) {
/* Check if tunnel would take damage */
int count; int count;
TileIndex *ti = ts.tile_table; TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) { for(count = ts.tile_table_count; count != 0; count--, ti++) {
uint a, b, c, d, r, min; uint z, t;
TileIndex tile = *ti; uint tile = *ti;
_terraform_err_tile = tile; z = TerraformGetHeightOfTile(&ts, tile + TILE_XY(0,0));
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(1,0));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(1,1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TILE_XY(0,1));
if (t <= z) z = t;
a = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); if (!CheckTunnelInWay(tile, z*8))
b = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
c = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
d = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
r = GetTileh(a, b, c, d, &min);
if (IsTileType(tile, MP_RAILWAY)) {
if (IsSteepTileh(r)) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
if (IsPlainRailTile(tile)) {
extern const TrackBits _valid_tileh_slopes[2][15];
if (GetTrackBits(tile) & ~_valid_tileh_slopes[0][r]) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
} else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
}
if (direction == -1 && !CheckTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
_terraform_err_tile = 0;
} }
} }
@@ -271,7 +288,7 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int count; int count;
TileIndex *ti = ts.tile_table; TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) { for(count = ts.tile_table_count; count != 0; count--, ti++) {
DoCommandByTile(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR); DoCommandByTile(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
} }
} }
@@ -280,10 +297,11 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int count; int count;
TerraformerHeightMod *mod; TerraformerHeightMod *mod;
uint til;
mod = ts.modheight; mod = ts.modheight;
for (count = ts.modheight_count; count != 0; count--, mod++) { for(count = ts.modheight_count; count != 0; count--, mod++) {
TileIndex til = mod->tile; til = mod->tile;
SetTileHeight(til, mod->height); SetTileHeight(til, mod->height);
TerraformAddDirtyTileAround(&ts, til); TerraformAddDirtyTileAround(&ts, til);
@@ -294,7 +312,7 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
int count; int count;
TileIndex *ti = ts.tile_table; TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) { for(count = ts.tile_table_count; count != 0; count--, ti++) {
MarkTileDirtyByTile(*ti); MarkTileDirtyByTile(*ti);
} }
} }
@@ -303,21 +321,18 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} }
/** Levels a selected (rectangle) area of land /*
* @param x,y end tile of area-drag * p1 - start
* @param p1 start tile of area drag
* @param p2 unused
*/ */
int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2) int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{ {
int size_x, size_y; int size_x, size_y;
int sx, sy; int sx, sy;
uint h, curh; uint h, curh;
TileIndex tile; uint tile;
int32 ret, cost, money; int32 ret, cost, money;
if (p1 >= MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// remember level height // remember level height
@@ -330,7 +345,7 @@ int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
sy = TileY(p1); sy = TileY(p1);
if (ex < sx) intswap(ex, sx); if (ex < sx) intswap(ex, sx);
if (ey < sy) intswap(ey, sy); if (ey < sy) intswap(ey, sy);
tile = TileXY(sx, sy); tile = TILE_XY(sx,sy);
size_x = ex-sx+1; size_x = ex-sx+1;
size_y = ey-sy+1; size_y = ey-sy+1;
@@ -338,11 +353,11 @@ int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
money = GetAvailableMoneyForCommand(); money = GetAvailableMoneyForCommand();
cost = 0; cost = 0;
BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) { BEGIN_TILE_LOOP(tile2, size_x, size_y, tile)
curh = TileHeight(tile2); curh = TileHeight(tile2);
while (curh != h) { while (curh != h) {
ret = DoCommandByTile(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND); ret = DoCommandByTile(tile2, 8, (curh > h)?0:1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
if (CmdFailed(ret)) break; if (ret == CMD_ERROR) break;
cost += ret; cost += ret;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
@@ -350,39 +365,42 @@ int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
_additional_cash_required = ret; _additional_cash_required = ret;
return cost - ret; return cost - ret;
} }
DoCommandByTile(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); DoCommandByTile(tile2, 8, (curh > h)?0:1, flags, CMD_TERRAFORM_LAND);
} }
curh += (curh > h) ? -1 : 1; curh += (curh > h) ? -1 : 1;
} }
} END_TILE_LOOP(tile2, size_x, size_y, tile) END_TILE_LOOP(tile2, size_x, size_y, tile)
return (cost == 0) ? CMD_ERROR : cost; if (cost == 0) return CMD_ERROR;
return cost;
} }
/** Purchase a land area. Actually you only purchase one tile, so /* Purchase a land area
* the name is a bit confusing ;p * p1 = unused
* @param x,y the tile the player is purchasing * p2 = unused
* @param p1 unused
* @param p2 unused
*/ */
int32 CmdPurchaseLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdPurchaseLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
TileIndex tile; uint tile;
int32 cost; int32 cost;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TileVirtXY(x, y); tile = TILE_FROM_XY(x,y);
if (!EnsureNoVehicle(tile)) return CMD_ERROR; if (!EnsureNoVehicle(tile))
return CMD_ERROR;
if (IsTileType(tile, MP_UNMOVABLE) && _m[tile].m5 == 3 && if (IsTileType(tile, MP_UNMOVABLE) &&
IsTileOwner(tile, _current_player)) _map5[tile] == 3 &&
_map_owner[tile] == _current_player)
return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT); return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
cost = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); cost = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(cost)) return CMD_ERROR; if (cost == CMD_ERROR)
return CMD_ERROR;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
ModifyTile(tile, ModifyTile(tile,
@@ -395,114 +413,91 @@ int32 CmdPurchaseLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
} }
static int32 ClearTile_Clear(TileIndex tile, byte flags) static int32 ClearTile_Clear(uint tile, byte flags)
{ {
static const int32 null = 0; static const int32 * _clear_price_table[] = {
static const int32* clear_price_table[] = { NULL,
&null, &_price.clear_1, &_price.clear_1,&_price.clear_1,
&_price.clear_1, &_price.purchase_land,&_price.purchase_land,&_price.purchase_land,&_price.purchase_land,
&_price.clear_1, &_price.clear_2,&_price.clear_2,&_price.clear_2,&_price.clear_2,
&_price.clear_1, &_price.clear_3,&_price.clear_3,&_price.clear_3,&_price.clear_3,
&_price.purchase_land, &_price.purchase_land,&_price.purchase_land,&_price.purchase_land,&_price.purchase_land,
&_price.purchase_land, &_price.purchase_land,&_price.purchase_land,&_price.purchase_land,&_price.purchase_land,
&_price.purchase_land, &_price.clear_2,&_price.clear_2,&_price.clear_2,&_price.clear_2,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_3,
&_price.clear_3,
&_price.clear_3,
&_price.clear_3,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
}; };
const int32 *price = clear_price_table[GB(_m[tile].m5, 0, 5)]; const int32 *price = _clear_price_table[_map5[tile] & 0x1F];
if (flags & DC_EXEC) DoClearSquare(tile);
return *price;
}
/** Sell a land area. Actually you only sell one tile, so
* the name is a bit confusing ;p
* @param x,y the tile the player is selling
* @param p1 unused
* @param p2 unused
*/
int32 CmdSellLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TileVirtXY(x, y);
if (!IsTileType(tile, MP_UNMOVABLE) || _m[tile].m5 != 3) return CMD_ERROR;
if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (flags & DC_EXEC) if (flags & DC_EXEC)
DoClearSquare(tile); DoClearSquare(tile);
return - _price.purchase_land * 2; if (price == NULL)
return 0;
return *price;
}
int32 CmdSellLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
uint tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TILE_FROM_XY(x,y);
if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
return CMD_ERROR;
if (!EnsureNoVehicle(tile))
return CMD_ERROR;
if (flags & DC_EXEC)
DoClearSquare(tile);
return - _price.purchase_land*2;
} }
#include "table/clear_land.h" #include "table/clear_land.h"
void DrawClearLandTile(const TileInfo *ti, byte set) void DrawClearLandTile(TileInfo *ti, byte set)
{ {
DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19); DrawGroundSprite(0xF54 + _tileh_to_sprite[ti->tileh] + set * 19);
} }
void DrawHillyLandTile(const TileInfo *ti) void DrawHillyLandTile(TileInfo *ti)
{ {
if (ti->tileh != 0) { if (ti->tileh != 0) {
DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]); DrawGroundSprite(0xFA0 + _tileh_to_sprite[ti->tileh]);
} else { } else {
DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]); DrawGroundSprite(_landscape_clear_sprites[((ti->x^ti->y) >> 4) & 0x7]);
} }
} }
void DrawClearLandFence(const TileInfo *ti) void DrawClearLandFence(TileInfo *ti, byte img)
{ {
byte m4 = _m[ti->tile].m4;
byte z = ti->z; byte z = ti->z;
if (ti->tileh & 2) { if (ti->tileh & 2) {
z += 8; z += 8;
if (ti->tileh == 0x17) z += 8; if (ti->tileh == 0x17)
z += 8;
} }
if (GB(m4, 5, 3) != 0) { if (img & 0x38) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GB(m4, 5, 3) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z); DrawGroundSpriteAt(_clear_land_fence_sprites_1[((img >> 3) & 7) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
} }
if (GB(m4, 2, 3) != 0) { if (img & 0x7) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GB(m4, 2, 3) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z); DrawGroundSpriteAt(_clear_land_fence_sprites_1[(img & 7) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
} }
} }
static void DrawTile_Clear(TileInfo *ti) static void DrawTile_Clear(TileInfo *ti)
{ {
switch (GB(ti->map5, 2, 3)) {
switch((ti->map5 & (7<<2)) >> 2) {
case 0: case 0:
DrawClearLandTile(ti, GB(ti->map5, 0, 2)); DrawClearLandTile(ti, (ti->map5 & 3));
break; break;
case 1: case 1:
@@ -510,111 +505,103 @@ static void DrawTile_Clear(TileInfo *ti)
break; break;
case 2: case 2:
DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]); DrawGroundSprite(0xFB7 + _tileh_to_sprite[ti->tileh]);
break; break;
case 3: case 3:
DrawGroundSprite(_clear_land_sprites_1[GB(_m[ti->tile].m3, 0, 4)] + _tileh_to_sprite[ti->tileh]); DrawGroundSprite( _clear_land_sprites_1[_map3_lo[ti->tile]&0xF] + _tileh_to_sprite[ti->tileh]);
break; break;
case 4: case 4:
DrawGroundSprite(_clear_land_sprites_2[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]); DrawGroundSprite( _clear_land_sprites_2[ti->map5&3] + _tileh_to_sprite[ti->tileh]);
break; break;
case 5: case 5:
DrawGroundSprite(_clear_land_sprites_3[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]); DrawGroundSprite( _clear_land_sprites_3[ti->map5&3] + _tileh_to_sprite[ti->tileh]);
break; break;
} }
DrawClearLandFence(ti); DrawClearLandFence(ti, _map3_hi[ti->tile] >> 2);
} }
static uint GetSlopeZ_Clear(const TileInfo* ti) static uint GetSlopeZ_Clear(TileInfo *ti)
{ {
return GetPartialZ(ti->x & 0xF, ti->y & 0xF, ti->tileh) + ti->z; return GetPartialZ(ti->x & 0xF, ti->y & 0xF, ti->tileh) + ti->z;
} }
static uint GetSlopeTileh_Clear(const TileInfo *ti) static uint GetSlopeTileh_Clear(TileInfo *ti)
{ {
return ti->tileh; return ti->tileh;
} }
static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac) static void GetAcceptedCargo_Clear(uint tile, AcceptedCargo ac)
{ {
/* unused */ /* unused */
} }
static void AnimateTile_Clear(TileIndex tile) static void AnimateTile_Clear(uint tile)
{ {
/* unused */ /* unused */
} }
void TileLoopClearHelper(TileIndex tile) void TileLoopClearHelper(uint tile)
{ {
byte self; byte img_1, img_2;
byte neighbour; static byte img_by_map5[8] = { 0,0,0,2, 1,1,0,0, };
TileIndex dirty = INVALID_TILE; uint dirty = -1;
switch (GetTileType(tile)) { img_1 = 0;
case MP_CLEAR: if (IsTileType(tile, MP_CLEAR)) {
self = (GB(_m[tile].m5, 0, 5) == 15); img_1 = img_by_map5[(_map5[tile] & 0x1C) >> 2];
break; } else if (IsTileType(tile, MP_TREES) && (_map2[tile] & 0x30) == 0x20) {
img_1 = 1;
default:
self = 0;
break;
} }
switch (GetTileType(TILE_ADDXY(tile, 1, 0))) { img_2 = 0;
case MP_CLEAR: if (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR)) {
neighbour = (GB(_m[TILE_ADDXY(tile, 1, 0)].m5, 0, 5) == 15); img_2 = img_by_map5[(_map5[TILE_ADDXY(tile, 1, 0)] & 0x1C) >> 2];
break; } else if (IsTileType(TILE_ADDXY(tile, 1, 0), MP_TREES) && (_map2[TILE_ADDXY(tile, 1, 0)] & 0x30) == 0x20) {
img_2 = 1;
default:
neighbour = 0;
break;
} }
if (GB(_m[tile].m4, 5, 3) == 0) { if (!(_map3_hi[tile] & 0xE0)) {
if (self != neighbour) { if ( (img_1&2) != (img_2&2) ) {
SB(_m[tile].m4, 5, 3, 3); _map3_hi[tile] |= 3 << 5;
dirty = tile; dirty = tile;
} }
} else { } else {
if (self == 0 && neighbour == 0) { if (img_1 == 1 && img_2 == 1) {
SB(_m[tile].m4, 5, 3, 0); _map3_hi[tile] &= ~(3 << 5);
dirty = tile; dirty = tile;
} }
} }
switch (GetTileType(TILE_ADDXY(tile, 0, 1))) { img_2 = 0;
case MP_CLEAR: if (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR)) {
neighbour = (GB(_m[TILE_ADDXY(tile, 0, 1)].m5, 0, 5) == 15); img_2 = img_by_map5[(_map5[TILE_ADDXY(tile, 0, 1)] & 0x1C) >> 2];
break; } else if (IsTileType(TILE_ADDXY(tile, 0, 1), MP_TREES) && (_map2[TILE_ADDXY(tile, 0, 1)] & 0x30) == 0x20) {
img_2 = 1;
default:
neighbour = 0;
break;
} }
if (GB(_m[tile].m4, 2, 3) == 0) { if (!(_map3_hi[tile] & 0x1C)) {
if (self != neighbour) { if ( (img_1&2) != (img_2&2) ) {
SB(_m[tile].m4, 2, 3, 3); _map3_hi[tile] |= 3 << 2;
dirty = tile; dirty = tile;
} }
} else { } else {
if (self == 0 && neighbour == 0) { if (img_1 == 1 && img_2 == 1) {
SB(_m[tile].m4, 2, 3, 0); _map3_hi[tile] &= ~(3 << 2);
dirty = tile; dirty = tile;
} }
} }
if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty); if (dirty != (uint) -1)
MarkTileDirtyByTile(dirty);
} }
/* convert into snowy tiles */ /* convert into snowy tiles */
static void TileLoopClearAlps(TileIndex tile) static void TileLoopClearAlps(uint tile)
{ {
int k; int k;
byte m5,tmp; byte m5,tmp;
@@ -622,8 +609,8 @@ static void TileLoopClearAlps(TileIndex tile)
/* distance from snow line, in steps of 8 */ /* distance from snow line, in steps of 8 */
k = GetTileZ(tile) - _opt.snow_line; k = GetTileZ(tile) - _opt.snow_line;
m5 = _m[tile].m5 & 0x1C; m5 = _map5[tile] & 0x1C;
tmp = _m[tile].m5 & 3; tmp = _map5[tile] & 3;
if (k < -8) { if (k < -8) {
/* snow_m2_down */ /* snow_m2_down */
@@ -671,29 +658,30 @@ static void TileLoopClearAlps(TileIndex tile)
return; return;
} }
_m[tile].m5 = m5; _map5[tile] = m5;
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
static void TileLoopClearDesert(TileIndex tile) static void TileLoopClearDesert(uint tile)
{ {
if ((_m[tile].m5 & 0x1C) == 0x14) return; if ( (_map5[tile] & 0x1C) == 0x14)
return;
if (GetMapExtraBits(tile) == 1) { if (GetMapExtraBits(tile) == 1) {
_m[tile].m5 = 0x17; _map5[tile] = 0x17;
} else { } else {
if (GetMapExtraBits(tile + TileDiffXY( 1, 0)) != 1 && if (GetMapExtraBits(tile+TILE_XY(1,0)) != 1 &&
GetMapExtraBits(tile + TileDiffXY(-1, 0)) != 1 && GetMapExtraBits(tile+TILE_XY(-1,0)) != 1 &&
GetMapExtraBits(tile + TileDiffXY( 0, 1)) != 1 && GetMapExtraBits(tile+TILE_XY(0,1)) != 1 &&
GetMapExtraBits(tile + TileDiffXY( 0, -1)) != 1) GetMapExtraBits(tile+TILE_XY(0,-1)) != 1)
return; return;
_m[tile].m5 = 0x15; _map5[tile] = 0x15;
} }
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
static void TileLoop_Clear(TileIndex tile) static void TileLoop_Clear(uint tile)
{ {
byte m5,m3; byte m5,m3;
@@ -705,22 +693,24 @@ static void TileLoop_Clear(TileIndex tile)
TileLoopClearAlps(tile); TileLoopClearAlps(tile);
} }
m5 = _m[tile].m5; m5 = _map5[tile];
if ((m5 & 0x1C) == 0x10 || (m5 & 0x1C) == 0x14) return; if ( (m5 & 0x1C) == 0x10 || (m5 & 0x1C) == 0x14)
return;
if ((m5 & 0x1C) != 0xC) { if ( (m5 & 0x1C) != 0xC) {
if ((m5 & 3) == 3) return; if ( (m5 & 3) == 3)
return;
if (_game_mode != GM_EDITOR) { if (_game_mode != GM_EDITOR) {
m5 += 0x20; m5 += 0x20;
if (m5 >= 0x20) { if (m5 >= 0x20) {
// Didn't overflow // Didn't overflow
_m[tile].m5 = m5; _map5[tile] = m5;
return; return;
} }
/* did overflow, so continue */ /* did overflow, so continue */
} else { } else {
m5 = (GB(Random(), 0, 8) > 21) ? 2 : 6; m5 = ((byte)Random() > 21) ? (2) : (6);
} }
m5++; m5++;
} else if (_game_mode != GM_EDITOR) { } else if (_game_mode != GM_EDITOR) {
@@ -728,47 +718,47 @@ static void TileLoop_Clear(TileIndex tile)
m5 += 0x20; m5 += 0x20;
if (m5 >= 0x20) { if (m5 >= 0x20) {
// Didn't overflow // Didn't overflow
_m[tile].m5 = m5; _map5[tile] = m5;
return; return;
} }
/* overflowed */ /* overflowed */
m3 = _m[tile].m3 + 1; m3 = _map3_lo[tile] + 1;
assert( (m3 & 0xF) != 0); assert( (m3 & 0xF) != 0);
if ( (m3 & 0xF) >= 9) /* NOTE: will not work properly if m3&0xF == 0xF */ if ( (m3 & 0xF) >= 9) /* NOTE: will not work properly if m3&0xF == 0xF */
m3 &= ~0xF; m3 &= ~0xF;
_m[tile].m3 = m3; _map3_lo[tile] = m3;
} }
_m[tile].m5 = m5; _map5[tile] = m5;
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
void GenerateClearTile(void) void GenerateClearTile(void)
{ {
uint i; int i,j;
TileIndex tile; uint tile,tile_new;
uint32 r;
/* add hills */ /* add hills */
i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400); i = (Random() & 0x3FF) | 0x400;
do { do {
tile = RandomTile(); tile = TILE_MASK(Random());
if (IsTileType(tile, MP_CLEAR)) SB(_m[tile].m5, 2, 2, 1); if (IsTileType(tile, MP_CLEAR))
_map5[tile] = (byte)((_map5[tile] & ~(3<<2)) | (1<<2));
} while (--i); } while (--i);
/* add grey squares */ /* add grey squares */
i = ScaleByMapSize(GB(Random(), 0, 7) + 0x80); i = (Random() & 0x7F) | 0x80;
do { do {
uint32 r = Random(); r = Random();
tile = RandomTileSeed(r); tile = TILE_MASK(r);
if (IsTileType(tile, MP_CLEAR)) { if (IsTileType(tile, MP_CLEAR)) {
uint j = GB(r, 16, 4) + 5; j = ((r >> 16) & 0xF) + 5;
for(;;) { for(;;) {
TileIndex tile_new; _map5[tile] = (byte)((_map5[tile] & ~(3<<2)) | (2<<2));
SB(_m[tile].m5, 2, 2, 2);
do { do {
if (--j == 0) goto get_out; if (--j == 0) goto get_out;
tile_new = tile + TileOffsByDir(GB(Random(), 0, 2)); tile_new = tile + TileOffsByDir(Random() & 3);
} while (!IsTileType(tile_new, MP_CLEAR)); } while (!IsTileType(tile_new, MP_CLEAR));
tile = tile_new; tile = tile_new;
} }
@@ -777,17 +767,17 @@ get_out:;
} while (--i); } while (--i);
} }
static void ClickTile_Clear(TileIndex tile) static void ClickTile_Clear(uint tile)
{ {
/* not used */ /* not used */
} }
static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode) static uint32 GetTileTrackStatus_Clear(uint tile, TransportType mode)
{ {
return 0; return 0;
} }
static const StringID _clear_land_str[] = { static const StringID _clear_land_str[4+8-1] = {
STR_080B_ROUGH_LAND, STR_080B_ROUGH_LAND,
STR_080A_ROCKS, STR_080A_ROCKS,
STR_080E_FIELDS, STR_080E_FIELDS,
@@ -801,15 +791,16 @@ static const StringID _clear_land_str[] = {
STR_080D_GRASS, STR_080D_GRASS,
}; };
static void GetTileDesc_Clear(TileIndex tile, TileDesc *td) static void GetTileDesc_Clear(uint tile, TileDesc *td)
{ {
uint i = GB(_m[tile].m5, 2, 3); int i = (_map5[tile]>>2) & 7;
if (i == 0) i = GB(_m[tile].m5, 0, 2) + 8; if (i == 0)
i = (_map5[tile] & 3) + 8;
td->str = _clear_land_str[i - 1]; td->str = _clear_land_str[i - 1];
td->owner = GetTileOwner(tile); td->owner = _map_owner[tile];
} }
static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player) static void ChangeTileOwner_Clear(uint tile, byte old_player, byte new_player)
{ {
return; return;
} }

372
command.c
View File

@@ -1,17 +1,11 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "gui.h" #include "gui.h"
#include "command.h" #include "command.h"
#include "player.h" #include "player.h"
#include "network.h" #include "network.h"
#include "variables.h"
const char* _cmd_text = NULL;
#define DEF_COMMAND(yyyy) int32 yyyy(int x, int y, uint32 flags, uint32 p1, uint32 p2) #define DEF_COMMAND(yyyy) int32 yyyy(int x, int y, uint32 flags, uint32 p1, uint32 p2)
@@ -28,8 +22,8 @@ DEF_COMMAND(CmdBuildRailroadStation);
DEF_COMMAND(CmdRemoveFromRailroadStation); DEF_COMMAND(CmdRemoveFromRailroadStation);
DEF_COMMAND(CmdConvertRail); DEF_COMMAND(CmdConvertRail);
DEF_COMMAND(CmdBuildSingleSignal); DEF_COMMAND(CmdBuildSignals);
DEF_COMMAND(CmdRemoveSingleSignal); DEF_COMMAND(CmdRemoveSignals);
DEF_COMMAND(CmdTerraformLand); DEF_COMMAND(CmdTerraformLand);
@@ -43,7 +37,9 @@ DEF_COMMAND(CmdBuildTrainWaypoint);
DEF_COMMAND(CmdRenameWaypoint); DEF_COMMAND(CmdRenameWaypoint);
DEF_COMMAND(CmdRemoveTrainWaypoint); DEF_COMMAND(CmdRemoveTrainWaypoint);
DEF_COMMAND(CmdBuildRoadStop); DEF_COMMAND(CmdBuildTruckStation);
DEF_COMMAND(CmdBuildBusStation);
DEF_COMMAND(CmdBuildLongRoad); DEF_COMMAND(CmdBuildLongRoad);
DEF_COMMAND(CmdRemoveLongRoad); DEF_COMMAND(CmdRemoveLongRoad);
@@ -69,7 +65,7 @@ DEF_COMMAND(CmdStartStopTrain);
DEF_COMMAND(CmdSellRailWagon); DEF_COMMAND(CmdSellRailWagon);
DEF_COMMAND(CmdSendTrainToDepot); DEF_COMMAND(CmdTrainGotoDepot);
DEF_COMMAND(CmdForceTrainProceed); DEF_COMMAND(CmdForceTrainProceed);
DEF_COMMAND(CmdReverseTrainDirection); DEF_COMMAND(CmdReverseTrainDirection);
@@ -77,12 +73,14 @@ DEF_COMMAND(CmdModifyOrder);
DEF_COMMAND(CmdSkipOrder); DEF_COMMAND(CmdSkipOrder);
DEF_COMMAND(CmdDeleteOrder); DEF_COMMAND(CmdDeleteOrder);
DEF_COMMAND(CmdInsertOrder); DEF_COMMAND(CmdInsertOrder);
DEF_COMMAND(CmdChangeServiceInt); DEF_COMMAND(CmdChangeTrainServiceInt);
DEF_COMMAND(CmdRestoreOrderIndex); DEF_COMMAND(CmdRestoreOrderIndex);
DEF_COMMAND(CmdBuildIndustry); DEF_COMMAND(CmdBuildIndustry);
//DEF_COMMAND(CmdDestroyIndustry);
DEF_COMMAND(CmdBuildCompanyHQ); DEF_COMMAND(CmdBuildCompanyHQ);
DEF_COMMAND(CmdDestroyCompanyHQ);
DEF_COMMAND(CmdSetPlayerFace); DEF_COMMAND(CmdSetPlayerFace);
DEF_COMMAND(CmdSetPlayerColor); DEF_COMMAND(CmdSetPlayerColor);
@@ -103,6 +101,7 @@ DEF_COMMAND(CmdSellAircraft);
DEF_COMMAND(CmdStartStopAircraft); DEF_COMMAND(CmdStartStopAircraft);
DEF_COMMAND(CmdBuildAircraft); DEF_COMMAND(CmdBuildAircraft);
DEF_COMMAND(CmdSendAircraftToHangar); DEF_COMMAND(CmdSendAircraftToHangar);
DEF_COMMAND(CmdChangeAircraftServiceInt);
DEF_COMMAND(CmdRefitAircraft); DEF_COMMAND(CmdRefitAircraft);
DEF_COMMAND(CmdPlaceSign); DEF_COMMAND(CmdPlaceSign);
@@ -113,8 +112,10 @@ DEF_COMMAND(CmdStartStopRoadVeh);
DEF_COMMAND(CmdSellRoadVeh); DEF_COMMAND(CmdSellRoadVeh);
DEF_COMMAND(CmdSendRoadVehToDepot); DEF_COMMAND(CmdSendRoadVehToDepot);
DEF_COMMAND(CmdTurnRoadVeh); DEF_COMMAND(CmdTurnRoadVeh);
DEF_COMMAND(CmdChangeRoadVehServiceInt);
DEF_COMMAND(CmdPause); DEF_COMMAND(CmdPause);
DEF_COMMAND(CmdResume);
DEF_COMMAND(CmdBuyShareInCompany); DEF_COMMAND(CmdBuyShareInCompany);
DEF_COMMAND(CmdSellShareInCompany); DEF_COMMAND(CmdSellShareInCompany);
@@ -126,6 +127,7 @@ DEF_COMMAND(CmdRenameTown);
DEF_COMMAND(CmdDoTownAction); DEF_COMMAND(CmdDoTownAction);
DEF_COMMAND(CmdSetRoadDriveSide); DEF_COMMAND(CmdSetRoadDriveSide);
DEF_COMMAND(CmdSetTownNameType);
DEF_COMMAND(CmdChangeDifficultyLevel); DEF_COMMAND(CmdChangeDifficultyLevel);
DEF_COMMAND(CmdChangePatchSetting); DEF_COMMAND(CmdChangePatchSetting);
@@ -134,8 +136,18 @@ DEF_COMMAND(CmdStartStopShip);
DEF_COMMAND(CmdSellShip); DEF_COMMAND(CmdSellShip);
DEF_COMMAND(CmdBuildShip); DEF_COMMAND(CmdBuildShip);
DEF_COMMAND(CmdSendShipToDepot); DEF_COMMAND(CmdSendShipToDepot);
DEF_COMMAND(CmdChangeShipServiceInt);
DEF_COMMAND(CmdRefitShip); DEF_COMMAND(CmdRefitShip);
DEF_COMMAND(CmdStartNewGame);
DEF_COMMAND(CmdLoadGame);
DEF_COMMAND(CmdCreateScenario);
DEF_COMMAND(CmdSetSinglePlayer);
DEF_COMMAND(CmdSetNewLandscapeType);
DEF_COMMAND(CmdGenRandomNewGame);
DEF_COMMAND(CmdCloneOrder); DEF_COMMAND(CmdCloneOrder);
DEF_COMMAND(CmdClearArea); DEF_COMMAND(CmdClearArea);
@@ -151,199 +163,195 @@ DEF_COMMAND(CmdLevelLand);
DEF_COMMAND(CmdRefitRailVehicle); DEF_COMMAND(CmdRefitRailVehicle);
DEF_COMMAND(CmdBuildSignalTrack); DEF_COMMAND(CmdStartScenario);
DEF_COMMAND(CmdRemoveSignalTrack);
DEF_COMMAND(CmdBuildManySignals);
DEF_COMMAND(CmdReplaceVehicle); DEF_COMMAND(CmdReplaceVehicle);
DEF_COMMAND(CmdCloneVehicle);
/* The master command table */ /* The master command table */
static const Command _command_proc_table[] = { static CommandProc * const _command_proc_table[] = {
{CmdBuildRailroadTrack, 0}, /* 0 */ CmdBuildRailroadTrack, /* 0 */
{CmdRemoveRailroadTrack, 0}, /* 1 */ CmdRemoveRailroadTrack, /* 1 */
{CmdBuildSingleRail, 0}, /* 2 */ CmdBuildSingleRail, /* 2 */
{CmdRemoveSingleRail, 0}, /* 3 */ CmdRemoveSingleRail, /* 3 */
{CmdLandscapeClear, 0}, /* 4 */ CmdLandscapeClear, /* 4 */
{CmdBuildBridge, 0}, /* 5 */ CmdBuildBridge, /* 5 */
{CmdBuildRailroadStation, 0}, /* 6 */ CmdBuildRailroadStation, /* 6 */
{CmdBuildTrainDepot, 0}, /* 7 */ CmdBuildTrainDepot, /* 7 */
{CmdBuildSingleSignal, 0}, /* 8 */ CmdBuildSignals, /* 8 */
{CmdRemoveSingleSignal, 0}, /* 9 */ CmdRemoveSignals, /* 9 */
{CmdTerraformLand, 0}, /* 10 */ CmdTerraformLand, /* 10 */
{CmdPurchaseLandArea, 0}, /* 11 */ CmdPurchaseLandArea, /* 11 */
{CmdSellLandArea, 0}, /* 12 */ CmdSellLandArea, /* 12 */
{CmdBuildTunnel, 0}, /* 13 */ CmdBuildTunnel, /* 13 */
{CmdRemoveFromRailroadStation, 0}, /* 14 */ CmdRemoveFromRailroadStation, /* 14 */
{CmdConvertRail, 0}, /* 15 */ CmdConvertRail, /* 15 */
{CmdBuildTrainWaypoint, 0}, /* 16 */ CmdBuildTrainWaypoint, /* 16 */
{CmdRenameWaypoint, 0}, /* 17 */ CmdRenameWaypoint, /* 17 */
{CmdRemoveTrainWaypoint, 0}, /* 18 */ CmdRemoveTrainWaypoint, /* 18 */
{NULL, 0}, /* 19 */ CmdBuildTruckStation, /* 19 */
{NULL, 0}, /* 20 */ NULL, /* 20 */
{CmdBuildRoadStop, 0}, /* 21 */ CmdBuildBusStation, /* 21 */
{NULL, 0}, /* 22 */ NULL, /* 22 */
{CmdBuildLongRoad, 0}, /* 23 */ CmdBuildLongRoad, /* 23 */
{CmdRemoveLongRoad, 0}, /* 24 */ CmdRemoveLongRoad, /* 24 */
{CmdBuildRoad, 0}, /* 25 */ CmdBuildRoad, /* 25 */
{CmdRemoveRoad, 0}, /* 26 */ CmdRemoveRoad, /* 26 */
{CmdBuildRoadDepot, 0}, /* 27 */ CmdBuildRoadDepot, /* 27 */
{NULL, 0}, /* 28 */ NULL, /* 28 */
{CmdBuildAirport, 0}, /* 29 */ CmdBuildAirport, /* 29 */
{CmdBuildDock, 0}, /* 30 */ CmdBuildDock, /* 30 */
{CmdBuildShipDepot, 0}, /* 31 */ CmdBuildShipDepot, /* 31 */
{CmdBuildBuoy, 0}, /* 32 */ CmdBuildBuoy, /* 32 */
{CmdPlantTree, 0}, /* 33 */ CmdPlantTree, /* 33 */
{CmdBuildRailVehicle, 0}, /* 34 */ CmdBuildRailVehicle, /* 34 */
{CmdMoveRailVehicle, 0}, /* 35 */ CmdMoveRailVehicle, /* 35 */
{CmdStartStopTrain, 0}, /* 36 */ CmdStartStopTrain, /* 36 */
{NULL, 0}, /* 37 */ NULL, /* 37 */
{CmdSellRailWagon, 0}, /* 38 */ CmdSellRailWagon, /* 38 */
{CmdSendTrainToDepot, 0}, /* 39 */ CmdTrainGotoDepot, /* 39 */
{CmdForceTrainProceed, 0}, /* 40 */ CmdForceTrainProceed, /* 40 */
{CmdReverseTrainDirection, 0}, /* 41 */ CmdReverseTrainDirection, /* 41 */
{CmdModifyOrder, 0}, /* 42 */ CmdModifyOrder, /* 42 */
{CmdSkipOrder, 0}, /* 43 */ CmdSkipOrder, /* 43 */
{CmdDeleteOrder, 0}, /* 44 */ CmdDeleteOrder, /* 44 */
{CmdInsertOrder, 0}, /* 45 */ CmdInsertOrder, /* 45 */
{CmdChangeServiceInt, 0}, /* 46 */ CmdChangeTrainServiceInt, /* 46 */
{CmdBuildIndustry, 0}, /* 47 */ CmdBuildIndustry, /* 47 */
{CmdBuildCompanyHQ, 0}, /* 48 */ CmdBuildCompanyHQ, /* 48 */
{CmdSetPlayerFace, 0}, /* 49 */ CmdSetPlayerFace, /* 49 */
{CmdSetPlayerColor, 0}, /* 50 */ CmdSetPlayerColor, /* 50 */
{CmdIncreaseLoan, 0}, /* 51 */ CmdIncreaseLoan, /* 51 */
{CmdDecreaseLoan, 0}, /* 52 */ CmdDecreaseLoan, /* 52 */
{CmdWantEnginePreview, 0}, /* 53 */ CmdWantEnginePreview, /* 53 */
{CmdNameVehicle, 0}, /* 54 */ CmdNameVehicle, /* 54 */
{CmdRenameEngine, 0}, /* 55 */ CmdRenameEngine, /* 55 */
{CmdChangeCompanyName, 0}, /* 56 */ CmdChangeCompanyName, /* 56 */
{CmdChangePresidentName, 0}, /* 57 */ CmdChangePresidentName, /* 57 */
{CmdRenameStation, 0}, /* 58 */ CmdRenameStation, /* 58 */
{CmdSellAircraft, 0}, /* 59 */ CmdSellAircraft, /* 59 */
{CmdStartStopAircraft, 0}, /* 60 */ CmdStartStopAircraft, /* 60 */
CmdBuildAircraft, /* 61 */
CmdSendAircraftToHangar, /* 62 */
CmdChangeAircraftServiceInt, /* 63 */
CmdRefitAircraft, /* 64 */
{CmdBuildAircraft, 0}, /* 61 */ CmdPlaceSign, /* 65 */
{CmdSendAircraftToHangar, 0}, /* 62 */ CmdRenameSign, /* 66 */
{NULL, 0}, /* 63 */
{CmdRefitAircraft, 0}, /* 64 */
{CmdPlaceSign, 0}, /* 65 */ CmdBuildRoadVeh, /* 67 */
{CmdRenameSign, 0}, /* 66 */ CmdStartStopRoadVeh, /* 68 */
CmdSellRoadVeh, /* 69 */
CmdSendRoadVehToDepot, /* 70 */
CmdTurnRoadVeh, /* 71 */
CmdChangeRoadVehServiceInt, /* 72 */
{CmdBuildRoadVeh, 0}, /* 67 */ CmdPause, /* 73 */
{CmdStartStopRoadVeh, 0}, /* 68 */
{CmdSellRoadVeh, 0}, /* 69 */
{CmdSendRoadVehToDepot, 0}, /* 70 */
{CmdTurnRoadVeh, 0}, /* 71 */
{NULL, 0}, /* 72 */
{CmdPause, CMD_SERVER}, /* 73 */ CmdBuyShareInCompany, /* 74 */
CmdSellShareInCompany, /* 75 */
CmdBuyCompany, /* 76 */
{CmdBuyShareInCompany, 0}, /* 74 */ CmdBuildTown, /* 77 */
{CmdSellShareInCompany, 0}, /* 75 */ NULL, /* 78 */
{CmdBuyCompany, 0}, /* 76 */ NULL, /* 79 */
CmdRenameTown, /* 80 */
CmdDoTownAction, /* 81 */
{CmdBuildTown, CMD_OFFLINE}, /* 77 */ CmdSetRoadDriveSide, /* 82 */
{NULL, 0}, /* 78 */ CmdSetTownNameType, /* 83 */
{NULL, 0}, /* 79 */ NULL, /* 84 */
{CmdRenameTown, CMD_SERVER}, /* 80 */ CmdChangeDifficultyLevel, /* 85 */
{CmdDoTownAction, 0}, /* 81 */
{CmdSetRoadDriveSide, CMD_SERVER}, /* 82 */ CmdStartStopShip, /* 86 */
{NULL, 0}, /* 83 */ CmdSellShip, /* 87 */
{NULL, 0}, /* 84 */ CmdBuildShip, /* 88 */
{CmdChangeDifficultyLevel, CMD_SERVER}, /* 85 */ CmdSendShipToDepot, /* 89 */
CmdChangeShipServiceInt, /* 90 */
CmdRefitShip, /* 91 */
{CmdStartStopShip, 0}, /* 86 */ CmdStartNewGame, /* 92 */
{CmdSellShip, 0}, /* 87 */ CmdLoadGame, /* 93 */
{CmdBuildShip, 0}, /* 88 */ CmdCreateScenario, /* 94 */
{CmdSendShipToDepot, 0}, /* 89 */ CmdSetSinglePlayer, /* 95 */
{NULL, 0}, /* 90 */ NULL, /* 96 */
{CmdRefitShip, 0}, /* 91 */ CmdSetNewLandscapeType, /* 97 */
{NULL, 0}, /* 92 */ CmdGenRandomNewGame, /* 98 */
{NULL, 0}, /* 93 */
{NULL, 0}, /* 94 */
{NULL, 0}, /* 95 */
{NULL, 0}, /* 96 */
{NULL, 0}, /* 97 */
{NULL, 0}, /* 98 */
{CmdCloneOrder, 0}, /* 99 */ CmdCloneOrder, /* 99 */
{CmdClearArea, 0}, /* 100 */ CmdClearArea, /* 100 */
{NULL, 0}, /* 101 */ CmdResume, /* 101 */
{CmdMoneyCheat, CMD_OFFLINE}, /* 102 */ CmdMoneyCheat, /* 102 */
{CmdBuildCanal, 0}, /* 103 */ CmdBuildCanal, /* 103 */
{CmdPlayerCtrl, 0}, /* 104 */ CmdPlayerCtrl, /* 104 */
{CmdLevelLand, 0}, /* 105 */ CmdLevelLand, /* 105 */
{CmdRefitRailVehicle, 0}, /* 106 */ CmdRefitRailVehicle, /* 106 */
{CmdRestoreOrderIndex, 0}, /* 107 */ CmdRestoreOrderIndex, /* 107 */
{CmdBuildLock, 0}, /* 108 */ CmdBuildLock, /* 108 */
{NULL, 0}, /* 109 */ CmdStartScenario, /* 109 */
{CmdBuildSignalTrack, 0}, /* 110 */ CmdBuildManySignals, /* 110 */
{CmdRemoveSignalTrack, 0}, /* 111 */ //CmdDestroyIndustry, /* 109 */
{NULL, 0}, /* 112 */ CmdDestroyCompanyHQ, /* 111 */
{CmdGiveMoney, 0}, /* 113 */ CmdGiveMoney, /* 112 */
{CmdChangePatchSetting, CMD_SERVER}, /* 114 */ CmdChangePatchSetting, /* 113 */
{CmdReplaceVehicle, 0}, /* 115 */ CmdReplaceVehicle, /* 114 */
{CmdCloneVehicle, 0}, /* 116 */
}; };
/* This function range-checks a cmd, and checks if the cmd is not NULL */ /* This function range-checks a cmd, and checks if the cmd is not NULL */
bool IsValidCommand(uint cmd) bool IsValidCommand(uint cmd)
{ {
cmd &= 0xFF; cmd = cmd & 0xFF;
return if (cmd >= lengthof(_command_proc_table) || _command_proc_table[cmd] == NULL)
cmd < lengthof(_command_proc_table) && return false;
_command_proc_table[cmd].proc != NULL;
return true;
} }
byte GetCommandFlags(uint cmd) {return _command_proc_table[cmd & 0xFF].flags;}
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc) int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{ {
return DoCommand(TileX(tile) * 16, TileY(tile) * 16, p1, p2, flags, procc); return DoCommand(TileX(tile) * 16, TileY(tile) * 16, p1, p2, flags, procc);
} }
static int _docommand_recursive; //extern void _stdcall Sleep(int s);
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc) int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc)
{ {
int32 res; int32 res;
CommandProc *proc; CommandProc *proc;
/* Do not even think about executing out-of-bounds tile-commands */ proc = _command_proc_table[procc];
if (TileVirtXY(x, y) >= MapSize()) {
_cmd_text = NULL; if (_docommand_recursive == 0) {
return CMD_ERROR; _error_message = INVALID_STRING_ID;
// update last build coord of player
if ( (x|y) != 0 && _current_player < MAX_PLAYERS) {
DEREF_PLAYER(_current_player)->last_build_coordinate = TILE_FROM_XY(x,y);
}
} }
proc = _command_proc_table[procc].proc;
if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
_docommand_recursive++; _docommand_recursive++;
// only execute the test call if it's toplevel, or we're not execing. // only execute the test call if it's toplevel, or we're not execing.
if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) { if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) {
res = proc(x, y, flags&~DC_EXEC, p1, p2); res = proc(x, y, flags&~DC_EXEC, p1, p2);
if (CmdFailed(res)) { if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF; if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto error; goto error;
} }
@@ -355,7 +363,6 @@ int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc)
if (!(flags & DC_EXEC)) { if (!(flags & DC_EXEC)) {
_docommand_recursive--; _docommand_recursive--;
_cmd_text = NULL;
return res; return res;
} }
} }
@@ -363,32 +370,26 @@ int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc)
/* Execute the command here. All cost-relevant functions set the expenses type /* Execute the command here. All cost-relevant functions set the expenses type
* themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */ * themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */
res = proc(x, y, flags, p1, p2); res = proc(x, y, flags, p1, p2);
if (CmdFailed(res)) { if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF; if (res & 0xFFFF) _error_message = res & 0xFFFF;
error: error:
_docommand_recursive--; _docommand_recursive--;
_cmd_text = NULL;
return CMD_ERROR; return CMD_ERROR;
} }
// if toplevel, subtract the money. // if toplevel, subtract the money.
if (--_docommand_recursive == 0) { if (--_docommand_recursive == 0) {
SubtractMoneyFromPlayer(res); SubtractMoneyFromPlayer(res);
// XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player
if ( (x|y) != 0 && _current_player < MAX_PLAYERS) {
GetPlayer(_current_player)->last_build_coordinate = TileVirtXY(x, y);
}
} }
_cmd_text = NULL;
return res; return res;
} }
int32 GetAvailableMoneyForCommand(void) int32 GetAvailableMoneyForCommand(void)
{ {
PlayerID pid = _current_player; uint pid = _current_player;
if (pid >= MAX_PLAYERS) return 0x7FFFFFFF; // max int if (pid >= MAX_PLAYERS) return 0x7FFFFFFF; // max int
return GetPlayer(pid)->player_money; return DEREF_PLAYER(pid)->player_money;
} }
// toplevel network safe docommand function for the current player. must not be called recursively. // toplevel network safe docommand function for the current player. must not be called recursively.
@@ -403,23 +404,15 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
int x = TileX(tile) * 16; int x = TileX(tile) * 16;
int y = TileY(tile) * 16; int y = TileY(tile) * 16;
/* Do not even think about executing out-of-bounds tile-commands */
if (tile >= MapSize()) {
_cmd_text = NULL;
return false;
}
assert(_docommand_recursive == 0); assert(_docommand_recursive == 0);
_error_message = INVALID_STRING_ID; _error_message = INVALID_STRING_ID;
_error_message_2 = cmd >> 16; _error_message_2 = cmd >> 16;
_additional_cash_required = 0; _additional_cash_required = 0;
/** Spectator has no rights except for the dedicated server which // spectator has no rights.
* is a spectator but is the server, so can do anything */ if (_current_player == OWNER_SPECTATOR) {
if (_current_player == OWNER_SPECTATOR && !_network_dedicated) {
ShowErrorMessage(_error_message, _error_message_2, x, y); ShowErrorMessage(_error_message, _error_message_2, x, y);
_cmd_text = NULL;
return false; return false;
} }
@@ -429,11 +422,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
// get pointer to command handler // get pointer to command handler
assert((cmd & 0xFF) < lengthof(_command_proc_table)); assert((cmd & 0xFF) < lengthof(_command_proc_table));
proc = _command_proc_table[cmd & 0xFF].proc; proc = _command_proc_table[cmd & 0xFF];
if (proc == NULL) {
_cmd_text = NULL;
return false;
}
// Some commands have a different output in dryrun than the realrun // Some commands have a different output in dryrun than the realrun
// e.g.: if you demolish a whole town, the dryrun would say okay. // e.g.: if you demolish a whole town, the dryrun would say okay.
@@ -448,16 +437,15 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
(cmd & 0xFF) == CMD_CLEAR_AREA || (cmd & 0xFF) == CMD_CLEAR_AREA ||
(cmd & 0xFF) == CMD_CONVERT_RAIL || (cmd & 0xFF) == CMD_CONVERT_RAIL ||
(cmd & 0xFF) == CMD_LEVEL_LAND || (cmd & 0xFF) == CMD_LEVEL_LAND ||
(cmd & 0xFF) == CMD_REMOVE_ROAD || (cmd & 0xFF) == CMD_REMOVE_ROAD;
(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD;
_docommand_recursive = 1; _docommand_recursive = 1;
// cost estimation only? // cost estimation only?
if (_shift_pressed && IsLocalPlayer() && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) { if (_shift_pressed && _current_player == _local_player && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) {
// estimate the cost. // estimate the cost.
res = proc(x, y, flags, p1, p2); res = proc(x, y, flags, p1, p2);
if (CmdFailed(res)) { if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF; if (res & 0xFFFF) _error_message = res & 0xFFFF;
ShowErrorMessage(_error_message, _error_message_2, x, y); ShowErrorMessage(_error_message, _error_message_2, x, y);
} else { } else {
@@ -465,7 +453,6 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
} }
_docommand_recursive = 0; _docommand_recursive = 0;
_cmd_text = NULL;
return false; return false;
} }
@@ -473,7 +460,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) { if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
// first test if the command can be executed. // first test if the command can be executed.
res = proc(x,y, flags, p1, p2); res = proc(x,y, flags, p1, p2);
if (CmdFailed(res)) { if ((uint32)res >> 16 == 0x8000) {
if (res & 0xFFFF) _error_message = res & 0xFFFF; if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto show_error; goto show_error;
} }
@@ -482,24 +469,17 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
} }
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
/** If we are in network, and the command is not from the network // If we are in network, and the command is not from the network
* send it to the command-queue and abort execution // send it to the command-queue and abort execution
* If we are a dedicated server temporarily switch local player, otherwise
* the other parties won't be able to execute our command and will desync.
* @todo Rewrite dedicated server to something more than a dirty hack!
*/
if (_networking && !(cmd & CMD_NETWORK_COMMAND)) { if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
if (_network_dedicated) _local_player = 0;
NetworkSend_Command(tile, p1, p2, cmd, callback); NetworkSend_Command(tile, p1, p2, cmd, callback);
if (_network_dedicated) _local_player = OWNER_SPECTATOR;
_docommand_recursive = 0; _docommand_recursive = 0;
_cmd_text = NULL;
return true; return true;
} }
#endif /* ENABLE_NETWORK */ #endif /* ENABLE_NETWORK */
// update last build coordinate of player. // update last build coordinate of player.
if ( tile != 0 && _current_player < MAX_PLAYERS) GetPlayer(_current_player)->last_build_coordinate = tile; if ( tile != 0 && _current_player < MAX_PLAYERS) DEREF_PLAYER(_current_player)->last_build_coordinate = tile;
/* Actually try and execute the command. If no cost-type is given /* Actually try and execute the command. If no cost-type is given
* use the construction one */ * use the construction one */
@@ -511,7 +491,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) { if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
assert(res == res2); // sanity check assert(res == res2); // sanity check
} else { } else {
if (CmdFailed(res2)) { if ((uint32)res2 >> 16 == 0x8000) {
if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF; if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
goto show_error; goto show_error;
} }
@@ -519,7 +499,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
SubtractMoneyFromPlayer(res2); SubtractMoneyFromPlayer(res2);
if (IsLocalPlayer() && _game_mode != GM_EDITOR) { if (_current_player == _local_player && _game_mode != GM_EDITOR) {
if (res2 != 0) if (res2 != 0)
ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2); ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
if (_additional_cash_required) { if (_additional_cash_required) {
@@ -532,18 +512,16 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
_docommand_recursive = 0; _docommand_recursive = 0;
if (callback) callback(true, tile, p1, p2); if (callback) callback(true, tile, p1, p2);
_cmd_text = NULL;
return true; return true;
show_error: show_error:
// show error message if the command fails? // show error message if the command fails?
if (IsLocalPlayer() && _error_message_2 != 0) if (_current_player == _local_player && _error_message_2 != 0)
ShowErrorMessage(_error_message, _error_message_2, x,y); ShowErrorMessage(_error_message, _error_message_2, x,y);
callb_err: callb_err:
_docommand_recursive = 0; _docommand_recursive = 0;
if (callback) callback(false, tile, p1, p2); if (callback) callback(false, tile, p1, p2);
_cmd_text = NULL;
return false; return false;
} }

View File

@@ -1,5 +1,3 @@
/* $Id$ */
#ifndef COMMAND_H #ifndef COMMAND_H
#define COMMAND_H #define COMMAND_H
@@ -26,7 +24,8 @@ enum {
CMD_RENAME_WAYPOINT = 17, CMD_RENAME_WAYPOINT = 17,
CMD_REMOVE_TRAIN_WAYPOINT = 18, CMD_REMOVE_TRAIN_WAYPOINT = 18,
CMD_BUILD_ROAD_STOP = 21, CMD_BUILD_TRUCK_STATION = 19,
CMD_BUILD_BUS_STATION = 21,
CMD_BUILD_LONG_ROAD = 23, CMD_BUILD_LONG_ROAD = 23,
CMD_REMOVE_LONG_ROAD = 24, CMD_REMOVE_LONG_ROAD = 24,
CMD_BUILD_ROAD = 25, CMD_BUILD_ROAD = 25,
@@ -58,7 +57,7 @@ enum {
CMD_DELETE_ORDER = 44, CMD_DELETE_ORDER = 44,
CMD_INSERT_ORDER = 45, CMD_INSERT_ORDER = 45,
CMD_CHANGE_SERVICE_INT = 46, CMD_CHANGE_TRAIN_SERVICE_INT = 46,
CMD_BUILD_INDUSTRY = 47, CMD_BUILD_INDUSTRY = 47,
@@ -81,6 +80,7 @@ enum {
CMD_START_STOP_AIRCRAFT = 60, CMD_START_STOP_AIRCRAFT = 60,
CMD_BUILD_AIRCRAFT = 61, CMD_BUILD_AIRCRAFT = 61,
CMD_SEND_AIRCRAFT_TO_HANGAR = 62, CMD_SEND_AIRCRAFT_TO_HANGAR = 62,
CMD_CHANGE_AIRCRAFT_SERVICE_INT = 63,
CMD_REFIT_AIRCRAFT = 64, CMD_REFIT_AIRCRAFT = 64,
CMD_PLACE_SIGN = 65, CMD_PLACE_SIGN = 65,
@@ -91,6 +91,7 @@ enum {
CMD_SELL_ROAD_VEH = 69, CMD_SELL_ROAD_VEH = 69,
CMD_SEND_ROADVEH_TO_DEPOT = 70, CMD_SEND_ROADVEH_TO_DEPOT = 70,
CMD_TURN_ROADVEH = 71, CMD_TURN_ROADVEH = 71,
CMD_CHANGE_ROADVEH_SERVICE_INT = 72,
CMD_PAUSE = 73, CMD_PAUSE = 73,
@@ -104,6 +105,8 @@ enum {
CMD_DO_TOWN_ACTION = 81, CMD_DO_TOWN_ACTION = 81,
CMD_SET_ROAD_DRIVE_SIDE = 82, CMD_SET_ROAD_DRIVE_SIDE = 82,
CMD_SET_TOWN_NAME_TYPE = 83,
CMD_CHANGE_DIFFICULTY_LEVEL = 85, CMD_CHANGE_DIFFICULTY_LEVEL = 85,
@@ -111,11 +114,23 @@ enum {
CMD_SELL_SHIP = 87, CMD_SELL_SHIP = 87,
CMD_BUILD_SHIP = 88, CMD_BUILD_SHIP = 88,
CMD_SEND_SHIP_TO_DEPOT = 89, CMD_SEND_SHIP_TO_DEPOT = 89,
CMD_CHANGE_SHIP_SERVICE_INT = 90,
CMD_REFIT_SHIP = 91, CMD_REFIT_SHIP = 91,
CMD_START_NEW_GAME = 92,
CMD_LOAD_GAME = 93,
CMD_CREATE_SCENARIO = 94,
CMD_SET_SINGLE_PLAYER = 95,
CMD_SET_NEW_LANDSCAPE_TYPE = 97,
CMD_GEN_RANDOM_NEW_GAME = 98,
CMD_CLONE_ORDER = 99, CMD_CLONE_ORDER = 99,
CMD_CLEAR_AREA = 100, CMD_CLEAR_AREA = 100,
CMD_RESUME = 101,
CMD_MONEY_CHEAT = 102, CMD_MONEY_CHEAT = 102,
CMD_BUILD_CANAL = 103, CMD_BUILD_CANAL = 103,
@@ -126,16 +141,15 @@ enum {
CMD_RESTORE_ORDER_INDEX = 107, CMD_RESTORE_ORDER_INDEX = 107,
CMD_BUILD_LOCK = 108, CMD_BUILD_LOCK = 108,
CMD_BUILD_SIGNAL_TRACK = 110, CMD_START_SCENARIO = 109,
CMD_REMOVE_SIGNAL_TRACK = 111, CMD_BUILD_MANY_SIGNALS = 110,
CMD_GIVE_MONEY = 113, //CMD_DESTROY_INDUSTRY = 109,
CMD_CHANGE_PATCH_SETTING = 114, CMD_DESTROY_COMPANY_HQ = 111,
CMD_GIVE_MONEY = 112,
CMD_REPLACE_VEHICLE = 115, CMD_CHANGE_PATCH_SETTING = 113,
CMD_CLONE_VEHICLE = 116,
CMD_REPLACE_VEHICLE = 114,
}; };
enum { enum {
@@ -161,41 +175,14 @@ enum {
CMD_SHOW_NO_ERROR = 0x2000, CMD_SHOW_NO_ERROR = 0x2000,
}; };
/** Command flags for the command table
* @see _command_proc_table
*/
enum {
CMD_SERVER = 0x1, /// the command can only be initiated by the server
CMD_OFFLINE = 0x2, /// the command cannot be executed in a multiplayer game; single-player only
};
typedef struct Command {
CommandProc *proc;
byte flags;
} Command;
//#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0) //#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0)
#define return_cmd_error(errcode) do { return CMD_ERROR | (errcode); } while (0) #define return_cmd_error(errcode) do { return CMD_ERROR | (errcode); } while (0)
/**
* Check the return value of a DoCommand*() function
* @param res the resulting value from the command to be checked
* @return Return true if the command failed, false otherwise
*/
static inline bool CmdFailed(int32 res)
{
// lower 16bits are the StringID of the possible error
return res <= (CMD_ERROR | INVALID_STRING_ID);
}
/* command.c */ /* command.c */
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc); int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc);
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc); int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
extern const char* _cmd_text; // Text, which gets sent with a command
bool IsValidCommand(uint cmd); bool IsValidCommand(uint cmd);
byte GetCommandFlags(uint cmd);
int32 GetAvailableMoneyForCommand(void); int32 GetAvailableMoneyForCommand(void);
#endif /* COMMAND_H */ #endif /* COMMAND_H */

2030
console.c

File diff suppressed because it is too large Load Diff

223
console.h
View File

@@ -1,160 +1,159 @@
/* $Id$ */
#ifndef CONSOLE_H #ifndef CONSOLE_H
#define CONSOLE_H #define CONSOLE_H
// maximum length of a typed in command // ** console parser ** //
#define ICON_CMDLN_SIZE 255
// maximum length of a totally expanded command
#define ICON_MAX_STREAMSIZE 1024
typedef enum IConsoleVarTypes { typedef enum _iconsole_var_types {
ICONSOLE_VAR_NONE,
ICONSOLE_VAR_BOOLEAN, ICONSOLE_VAR_BOOLEAN,
ICONSOLE_VAR_BYTE, ICONSOLE_VAR_BYTE,
ICONSOLE_VAR_UINT8,
ICONSOLE_VAR_UINT16, ICONSOLE_VAR_UINT16,
ICONSOLE_VAR_UINT32, ICONSOLE_VAR_UINT32,
ICONSOLE_VAR_INT16, ICONSOLE_VAR_INT16,
ICONSOLE_VAR_INT32, ICONSOLE_VAR_INT32,
ICONSOLE_VAR_STRING ICONSOLE_VAR_STRING,
} IConsoleVarTypes; ICONSOLE_VAR_POINTER,
ICONSOLE_VAR_REFERENCE,
ICONSOLE_VAR_UNKNOWN
} _iconsole_var_types;
typedef enum IConsoleModes { typedef enum {
ICONSOLE_FULL, ICONSOLE_FULL,
ICONSOLE_OPENED, ICONSOLE_OPENED,
ICONSOLE_CLOSED ICONSOLE_CLOSED
} IConsoleModes; } _iconsole_modes;
typedef enum IConsoleHookTypes { typedef enum _iconsole_hook_types {
ICONSOLE_HOOK_ACCESS, ICONSOLE_HOOK_ACCESS,
ICONSOLE_HOOK_PRE_ACTION, ICONSOLE_HOOK_BEFORE_CHANGE,
ICONSOLE_HOOK_POST_ACTION ICONSOLE_HOOK_BEFORE_EXEC,
} IConsoleHookTypes; ICONSOLE_HOOK_AFTER_CHANGE,
ICONSOLE_HOOK_AFTER_EXEC
} _iconsole_hook_types;
/** --Hooks-- struct _iconsole_var;
* Hooks are certain triggers get get accessed/executed on either typedef bool (*iconsole_var_hook)(struct _iconsole_var* hook_var);
* access, before execution/change or after execution/change. This allows
* for general flow of permissions or special action needed in some cases
*/
typedef bool IConsoleHook(void);
typedef struct IConsoleHooks{
IConsoleHook *access; // trigger when accessing the variable/command
IConsoleHook *pre; // trigger before the variable/command is changed/executed
IConsoleHook *post; // trigger after the variable/command is changed/executed
} IConsoleHooks;
/** --Commands-- typedef struct _iconsole_var {
* Commands are commands, or functions. They get executed once and any // --------------- //
* effect they produce are carried out. The arguments to the commands union {
* are given to them, each input word seperated by a double-quote (") is an argument void* addr;
* If you want to handle multiple words as one, enclose them in double-quotes bool* bool_;
* eg. 'say "hello sexy boy"' byte* byte_;
*/ uint16* uint16_;
typedef bool (IConsoleCmdProc)(byte argc, char *argv[]); uint32* uint32_;
int16* int16_;
int32* int32_;
char* string_;
struct _iconsole_var* reference_;
} data;
char* name;
_iconsole_var_types type;
// -------------- //
iconsole_var_hook hook_access;
iconsole_var_hook hook_before_change;
iconsole_var_hook hook_after_change;
// -------------- //
struct _iconsole_var* _next;
bool _malloc;
} _iconsole_var;
struct IConsoleCmd; struct _iconsole_cmd;
typedef struct IConsoleCmd { typedef bool (*iconsole_cmd_hook)(struct _iconsole_cmd* hook_cmd);
char *name; // name of command
struct IConsoleCmd *next; // next command in list
IConsoleCmdProc *proc; // process executed when command is typed typedef _iconsole_var* (*_iconsole_cmd_addr)(byte argc, char* argv[], byte argt[]);
IConsoleHooks hook; // any special trigger action that needs executing
} IConsoleCmd;
/** --Variables-- typedef struct _iconsole_cmd {
* Variables are pointers to real ingame variables which allow for // -------------- //
* changing while ingame. After changing they keep their new value _iconsole_cmd_addr addr;
* and can be used for debugging, gameplay, etc. It accepts: char* name;
* - no arguments; just print out current value // -------------- //
* - '= <new value>' to assign a new value to the variable iconsole_cmd_hook hook_access;
* - '++' to increase value by one iconsole_cmd_hook hook_before_exec;
* - '--' to decrease value by one iconsole_cmd_hook hook_after_exec;
*/ // -------------- //
struct IConsoleVar; void* _next;
typedef struct IConsoleVar { } _iconsole_cmd;
char *name; // name of the variable
struct IConsoleVar *next; // next variable in list
void *addr; // the address where the variable is pointing at void IConsoleAliasRegister(const char* name, const char* cmdline);
uint32 size; // size of the variable, used for strings
char *help; // the optional help string shown when requesting information
IConsoleVarTypes type; // type of variable (for correct assignment/output)
IConsoleCmdProc *proc; // some variables need really special handling, use a callback function for that
IConsoleHooks hook; // any special trigger action that needs executing
} IConsoleVar;
/** --Aliases-- typedef struct _iconsole_alias {
* Aliases are like shortcuts for complex functions, variable assignments, // -------------- //
* etc. You can use a simple alias to rename a longer command (eg 'lv' for char * cmdline;
* 'list_vars' for example), or concatenate more commands into one char* name;
* (eg. 'ng' for 'load %A; unpause; debug_level 5'). Aliases can parse the arguments void* _next;
* given to them in the command line. } _iconsole_alias;
* - "%A - %Z" substitute arguments 1 t/m 26
* - "%+" lists all parameters keeping them seperated
* - "%!" also lists all parameters but presenting them to the aliased command as one argument
* - ";" allows for combining commands (see example 'ng')
*/
struct IConsoleAlias;
typedef struct IConsoleAlias {
char *name; // name of the alias
struct IConsoleAlias *next; // next alias in list
char *cmdline; // command(s) that is/are being aliased _iconsole_alias* IConsoleAliasGet(const char* name);
} IConsoleAlias;
// ** console parser ** // // ** console parser ** //
IConsoleCmd *_iconsole_cmds; // list of registred commands
IConsoleVar *_iconsole_vars; // list of registred vars
IConsoleAlias *_iconsole_aliases; // list of registred aliases
// ** console colors/modes ** // _iconsole_cmd* _iconsole_cmds; // list of registred commands
VARDEF byte _icolour_def; _iconsole_var* _iconsole_vars; // list of registred vars
VARDEF byte _icolour_err; _iconsole_alias* _iconsole_aliases; // list of registred aliases
VARDEF byte _icolour_warn;
VARDEF byte _icolour_dbg; // ** console colors ** //
VARDEF byte _icolour_cmd; VARDEF byte _iconsole_color_default;
VARDEF IConsoleModes _iconsole_mode; 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 ** //
void SetDebugString(const char* s);
// ** console functions ** // // ** console functions ** //
void IConsoleInit(void); void IConsoleInit(void);
void IConsoleClear(void);
void IConsoleFree(void); void IConsoleFree(void);
void IConsoleClearBuffer(void);
void IConsoleResize(void); void IConsoleResize(void);
void IConsoleSwitch(void); void IConsoleSwitch(void);
void IConsoleClose(void); void IConsoleClose(void);
void IConsoleOpen(void); void IConsoleOpen(void);
// ** console cmd buffer ** //
void IConsoleCmdBufferAdd(const char* cmd);
void IConsoleCmdBufferNavigate(signed char direction);
// ** console output ** // // ** console output ** //
void IConsolePrint(uint16 color_code, const char *string); void IConsolePrint(uint16 color_code, const char* string);
void CDECL IConsolePrintF(uint16 color_code, const char *s, ...); void CDECL IConsolePrintF(uint16 color_code, const char* s, ...);
void IConsoleDebug(const char *string); void IConsoleDebug(const char* string);
void IConsoleWarning(const char *string); void IConsoleError(const char* string);
void IConsoleError(const char *string); void IConsoleWarning(const char* string);
// *** Commands *** // // *** Commands *** //
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc);
void IConsoleAliasRegister(const char *name, const char *cmd); void IConsoleCmdRegister(const char* name, _iconsole_cmd_addr addr);
IConsoleCmd *IConsoleCmdGet(const char *name); _iconsole_cmd* IConsoleCmdGet(const char* name);
IConsoleAlias *IConsoleAliasGet(const char *name);
// *** Variables *** // // *** Variables *** //
void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help);
void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help); void IConsoleVarRegister(const char* name, void* addr, _iconsole_var_types type);
IConsoleVar* IConsoleVarGet(const char *name); void IConsoleVarMemRegister(const char* name, _iconsole_var_types type);
void IConsoleVarPrintGetValue(const IConsoleVar *var); void IConsoleVarInsert(_iconsole_var* item_new, const char* name);
void IConsoleVarPrintSetValue(const IConsoleVar *var); _iconsole_var* IConsoleVarGet(const char* name);
_iconsole_var* IConsoleVarAlloc(_iconsole_var_types type);
void IConsoleVarFree(_iconsole_var* var);
void IConsoleVarSetString(_iconsole_var* var, const char* string);
void IConsoleVarSetValue(_iconsole_var* var, int value);
void IConsoleVarDump(const _iconsole_var* var, const char* dump_desc);
// *** Parser *** // // *** Parser *** //
void IConsoleCmdExec(const char *cmdstr);
void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[]);
// ** console std lib (register ingame commands/aliases/variables) ** // void IConsoleCmdExec(const char* cmdstr);
// ** console std lib ** //
void IConsoleStdLibRegister(void); void IConsoleStdLibRegister(void);
// ** Hooking code ** // // ** hook code ** //
void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc); void IConsoleVarHook(const char* name, _iconsole_hook_types type, iconsole_var_hook proc);
void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc); void IConsoleCmdHook(const char* name, _iconsole_hook_types type, iconsole_cmd_hook proc);
void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc); bool IConsoleVarHookHandle(_iconsole_var* hook_var, _iconsole_hook_types type);
bool IConsoleCmdHookHandle(_iconsole_cmd* hook_cmd, _iconsole_hook_types type);
// ** Supporting functions **//
bool GetArgumentInteger(uint32 *value, const char *arg);
#endif /* CONSOLE_H */ #endif /* CONSOLE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,100 +0,0 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "currency.h"
#include "news.h"
#include "variables.h"
#include "table/strings.h"
// exchange rate prefix
// | separator | postfix
// | | Euro year | |
// | | | | |
CurrencySpec _currency_specs[] = {
{ 1, ',', CF_NOEURO, "\xA3", "" }, // british pounds
{ 2, ',', CF_NOEURO, "$", "" }, // us dollars
{ 2, ',', CF_ISEURO, "<EFBFBD>", "" }, // Euro
{ 200, ',', CF_NOEURO, "\xA5", "" }, // yen
{ 19, ',', 2002, "", " S." }, // austrian schilling
{ 57, ',', 2002, "BEF ", "" }, // belgian franc
{ 2, ',', CF_NOEURO, "CHF ", "" }, // swiss franc
{ 50, ',', CF_NOEURO, "", " Kc" }, // czech koruna // TODO: Should use the "c" with an upside down "^"
{ 4, '.', 2002, "DM ", "" }, // deutsche mark
{ 10, '.', CF_NOEURO, "", " kr" }, // danish krone
{ 200, '.', 2002, "Pts ", "" }, // spanish pesetas
{ 8, ',', 2002, "", " mk" }, // finnish markka
{ 10, '.', 2002, "FF ", "" }, // french francs
{ 480, ',', 2002, "", "Dr." }, // greek drachma
{ 376, ',', 2002, "", " Ft" }, // hungarian forint
{ 130, '.', CF_NOEURO, "", " Kr" }, // icelandic krona
{ 2730, ',', 2002, "", " L." }, // italian lira
{ 3, ',', 2002, "NLG ", "" }, // dutch gulden
{ 11, '.', CF_NOEURO, "", " Kr" }, // norwegian krone
{ 6, ' ', CF_NOEURO, "", " zl" }, // polish zloty
{ 6, '.', CF_NOEURO, "", " Lei" }, // romanian Lei
{ 5, ' ', CF_NOEURO, "", " p" }, // russian rouble
{ 13, '.', CF_NOEURO, "", " Kr" }, // swedish krona
{ 1, ' ', CF_NOEURO, "", "" }, // custom currency
};
const StringID _currency_string_list[] = {
STR_CURR_GBP,
STR_CURR_USD,
STR_CURR_EUR,
STR_CURR_YEN,
STR_CURR_ATS,
STR_CURR_BEF,
STR_CURR_CHF,
STR_CURR_CZK,
STR_CURR_DEM,
STR_CURR_DKK,
STR_CURR_ESP,
STR_CURR_FIM,
STR_CURR_FRF,
STR_CURR_GRD,
STR_CURR_HUF,
STR_CURR_ISK,
STR_CURR_ITL,
STR_CURR_NLG,
STR_CURR_NOK,
STR_CURR_PLN,
STR_CURR_ROL,
STR_CURR_RUR,
STR_CURR_SEK,
STR_CURR_CUSTOM,
INVALID_STRING_ID
};
// NOTE: Make sure both lists are in the same order
// + 1 string list terminator
assert_compile(lengthof(_currency_specs) + 1 == lengthof(_currency_string_list));
// get a mask of the allowed currencies depending on the year
uint GetMaskOfAllowedCurrencies(void)
{
uint mask = 0;
uint i;
for (i = 0; i != lengthof(_currency_specs); i++) {
uint16 to_euro = _currency_specs[i].to_euro;
if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro - MAX_YEAR_BEGIN_REAL) continue;
if (to_euro == CF_ISEURO && _cur_year < 2000 - MAX_YEAR_BEGIN_REAL) continue;
mask |= (1 << i);
}
mask |= (1 << 23); // always allow custom currency
return mask;
}
void CheckSwitchToEuro(void)
{
if (_currency_specs[_opt.currency].to_euro != CF_NOEURO &&
_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
MAX_YEAR_BEGIN_REAL + _cur_year >= _currency_specs[_opt.currency].to_euro) {
_opt.currency = 2; // this is the index of euro above.
AddNewsItem(STR_EURO_INTRODUCE, NEWS_FLAGS(NM_NORMAL, 0, NT_ECONOMY, 0), 0, 0);
}
}

View File

@@ -1,29 +0,0 @@
/* $Id$ */
#ifndef CURRENCY_H
#define CURRENCY_H
enum {
CF_NOEURO = 0,
CF_ISEURO = 1,
};
typedef struct {
uint16 rate;
char separator;
uint16 to_euro;
char prefix[16];
char suffix[16];
} CurrencySpec;
extern CurrencySpec _currency_specs[];
extern const StringID _currency_string_list[];
// XXX small hack, but makes the rest of the code a bit nicer to read
#define _custom_currency (_currency_specs[23])
#define _currency ((const CurrencySpec*)&_currency_specs[_opt_ptr->currency])
uint GetMaskOfAllowedCurrencies(void);
void CheckSwitchToEuro(void);
#endif /* CURRENCY_H */

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
data/signalsw.grf Normal file

Binary file not shown.

126
debug.c
View File

@@ -1,126 +0,0 @@
/* $Id$ */
#include "stdafx.h"
#include <stdio.h>
#include <stdarg.h>
#include "openttd.h"
#include "console.h"
#include "debug.h"
#include "functions.h"
#include "string.h"
int _debug_ai_level;
int _debug_driver_level;
int _debug_grf_level;
int _debug_map_level;
int _debug_misc_level;
int _debug_ms_level;
int _debug_net_level;
int _debug_spritecache_level;
int _debug_oldloader_level;
int _debug_ntp_level;
int _debug_npf_level;
void CDECL debug(const char *s, ...)
{
va_list va;
char buf[1024];
va_start(va, s);
vsnprintf(buf, lengthof(buf), s, va);
va_end(va);
fprintf(stderr, "dbg: %s\n", buf);
IConsoleDebug(buf);
}
typedef struct DebugLevel {
const char *name;
int *level;
} DebugLevel;
#define DEBUG_LEVEL(x) { #x, &_debug_##x##_level }
static const DebugLevel debug_level[] = {
DEBUG_LEVEL(ai),
DEBUG_LEVEL(driver),
DEBUG_LEVEL(grf),
DEBUG_LEVEL(map),
DEBUG_LEVEL(misc),
DEBUG_LEVEL(ms),
DEBUG_LEVEL(net),
DEBUG_LEVEL(spritecache),
DEBUG_LEVEL(oldloader),
DEBUG_LEVEL(ntp),
DEBUG_LEVEL(npf)
};
#undef DEBUG_LEVEL
void SetDebugString(const char *s)
{
int v;
char *end;
const char *t;
// global debugging level?
if (*s >= '0' && *s <= '9') {
const DebugLevel *i;
v = strtoul(s, &end, 0);
s = end;
for (i = debug_level; i != endof(debug_level); ++i) *i->level = v;
}
// individual levels
for (;;) {
const DebugLevel *i;
int *p;
// skip delimiters
while (*s == ' ' || *s == ',' || *s == '\t') s++;
if (*s == '\0') break;
t = s;
while (*s >= 'a' && *s <= 'z') s++;
// check debugging levels
p = NULL;
for (i = debug_level; i != endof(debug_level); ++i)
if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) {
p = i->level;
break;
}
if (*s == '=') s++;
v = strtoul(s, &end, 0);
s = end;
if (p != NULL) {
*p = v;
} else {
ShowInfoF("Unknown debug level '%.*s'", s - t, t);
return;
}
}
}
/** Print out the current debug-level
* Just return a string with the values of all the debug categorites
* @return string with debug-levels
*/
const char *GetDebugString(void)
{
const DebugLevel *i;
static char dbgstr[100];
char dbgval[20];
memset(dbgstr, 0, sizeof(dbgstr));
i = debug_level;
snprintf(dbgstr, sizeof(dbgstr), "%s=%d", i->name, *i->level);
for (i++; i != endof(debug_level); i++) {
snprintf(dbgval, sizeof(dbgval), ", %s=%d", i->name, *i->level);
ttd_strlcat(dbgstr, dbgval, sizeof(dbgstr));
}
return dbgstr;
}

29
debug.h
View File

@@ -1,29 +0,0 @@
/* $Id$ */
#ifndef DEBUG_H
#define DEBUG_H
#ifdef NO_DEBUG_MESSAGES
#define DEBUG(name, level)
#else
#define DEBUG(name, level) if (level == 0 || _debug_ ## name ## _level >= level) debug
extern int _debug_ai_level;
extern int _debug_driver_level;
extern int _debug_grf_level;
extern int _debug_map_level;
extern int _debug_misc_level;
extern int _debug_ms_level;
extern int _debug_net_level;
extern int _debug_spritecache_level;
extern int _debug_oldloader_level;
extern int _debug_ntp_level;
extern int _debug_npf_level;
#endif
void CDECL debug(const char *s, ...);
void SetDebugString(const char *s);
const char *GetDebugString(void);
#endif /* DEBUG_H */

View File

@@ -1,58 +1,328 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "ttd.h"
#include "network.h"
#include "hal.h"
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
#if defined(UNIX) && !defined(__MORPHOS__) #include "gfx.h"
#include "window.h"
#include "command.h"
#include "console.h"
#ifdef WIN32
# include <windows.h> /* GetTickCount */
# include <conio.h>
#endif
#include "openttd.h" #ifdef __OS2__
#include "variables.h" # include <sys/time.h> /* gettimeofday */
# include <sys/types.h>
# include <unistd.h>
# include <conio.h>
# define STDIN 0 /* file descriptor for standard input */
#include <sys/types.h> extern void OS2_SwitchToConsoleMode();
#include <unistd.h> #endif
#ifdef UNIX
# include <sys/time.h> /* gettimeofday */
# include <sys/types.h>
# include <unistd.h>
# include <signal.h>
# define STDIN 0 /* file descriptor for standard input */
#endif
#ifdef __MORPHOS__
/* voids the fork, option will be disabled for morphos build anyway, because MorphOS
* doesn't support forking (could only implemented with lots of code changes here).
*/
int morphos_dummy_fork() { return -1; }
#define fork morphos_dummy_fork
#endif
// This file handles all dedicated-server in- and outputs
static void *_dedicated_video_mem;
#ifdef UNIX
/* We want to fork our dedicated server */
void DedicatedFork(void) void DedicatedFork(void)
{ {
/* Fork the program */ /* Fork the program */
pid_t pid = fork(); _dedicated_pid = fork();
switch (pid) { switch (_dedicated_pid) {
case -1: case -1:
perror("Unable to fork"); perror("Unable to fork");
exit(1); exit(1);
case 0:
case 0: { // We're the child // We're the child
FILE* f;
/* Open the log-file to log all stuff too */ /* Open the log-file to log all stuff too */
f = fopen(_log_file, "a"); _log_file_fd = fopen(_log_file, "a");
if (f == NULL) { if (!_log_file_fd) {
perror("Unable to open logfile"); perror("Unable to open logfile");
exit(1); exit(1);
} }
/* Redirect stdout and stderr to log-file */ /* Redirect stdout and stderr to log-file */
if (dup2(fileno(f), fileno(stdout)) == -1) { if (dup2(fileno(_log_file_fd), fileno(stdout)) == -1) {
perror("Rerouting stdout"); perror("Re-routing stdout");
exit(1); exit(1);
} }
if (dup2(fileno(f), fileno(stderr)) == -1) { if (dup2(fileno(_log_file_fd), fileno(stderr)) == -1) {
perror("Rerouting stderr"); perror("Re-routing stderr");
exit(1); exit(1);
} }
break; break;
}
default: default:
// We're the parent // We're the parent
printf("Loading dedicated server...\n"); printf("Loading dedicated server...\n");
printf(" - Forked to background with pid %d\n", pid); printf(" - Forked to background with pid %d\n", _dedicated_pid);
exit(0); exit(0);
} }
} }
/* Signal handlers */
static void DedicatedSignalHandler(int sig)
{
_exit_game = true;
signal(sig, DedicatedSignalHandler);
}
#endif #endif
#ifdef WIN32
#include <time.h>
HANDLE hEvent;
static HANDLE hThread; // Thread to close
static char _win_console_thread_buffer[200];
/* Windows Console thread. Just loop and signal when input has been received */
void WINAPI CheckForConsoleInput(void)
{
while (true) {
fgets(_win_console_thread_buffer, lengthof(_win_console_thread_buffer), stdin);
SetEvent(hEvent); // signal input waiting that the line is ready
}
}
void CreateWindowsConsoleThread(void)
{
static char tbuffer[9];
/* Create event to signal when console input is ready */
hEvent = CreateEvent(NULL, false, false, _strtime(tbuffer));
if (hEvent == NULL)
error("Cannot create console event!");
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, 0, 0, NULL);
if (hThread == NULL)
error("Cannot create console thread!");
DEBUG(misc, 0) ("Windows console thread started...");
}
void CloseWindowsConsoleThread(void)
{
CloseHandle(hThread);
CloseHandle(hEvent);
DEBUG(misc, 0) ("Windows console thread shut down...");
}
#endif
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;
#ifdef WIN32
// For win32 we need to allocate an console (debug mode does the same)
CreateConsole();
CreateWindowsConsoleThread();
SetConsoleTitle("OpenTTD Dedicated Server");
#endif
#ifdef __OS2__
// For OS/2 we also need to switch to console mode instead of PM mode
OS2_SwitchToConsoleMode();
#endif
DEBUG(misc,0)("Loading dedicated server...");
return NULL;
}
static void DedicatedVideoStop(void)
{
#ifdef WIN32
CloseWindowsConsoleThread();
#endif
free(_dedicated_video_mem);
}
static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {}
static bool DedicatedVideoChangeRes(int w, int h) { return false; }
#if defined(UNIX) || defined(__OS2__)
static bool InputWaiting(void)
{
struct timeval tv;
fd_set readfds;
byte ret;
tv.tv_sec = 0;
tv.tv_usec = 1;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
/* don't care about writefds and exceptfds: */
ret = select(STDIN + 1, &readfds, NULL, NULL, &tv);
if (ret > 0)
return true;
return false;
}
#else
static bool InputWaiting(void)
{
if (WaitForSingleObject(hEvent, 1) == WAIT_OBJECT_0)
return true;
return false;
}
#endif
static void DedicatedHandleKeyInput(void)
{
static char input_line[200] = "";
if (!InputWaiting())
return;
if (_exit_game)
return;
#if defined(UNIX) || defined(__OS2__)
fgets(input_line, lengthof(input_line), stdin);
#else
strncpy(input_line, _win_console_thread_buffer, lengthof(input_line));
#endif
/* XXX - strtok() does not 'forget' \n\r if it is the first character! */
strtok(input_line, "\r\n"); // Forget about the final \n (or \r)
{ /* Remove any special control characters */
uint i;
for (i = 0; i < lengthof(input_line); i++) {
if (input_line[i] == '\n' || input_line[i] == '\r') // cut missed beginning '\0'
input_line[i] = '\0';
if (input_line[i] == '\0')
break;
if (!IS_INT_INSIDE(input_line[i], ' ', 256))
input_line[i] = ' ';
}
}
IConsoleCmdExec(input_line); // execute command
}
static int DedicatedVideoMainLoop(void)
{
#ifndef WIN32
struct timeval tim;
#endif
uint32 next_tick;
uint32 cur_ticks;
#ifdef WIN32
next_tick = GetTickCount() + 30;
#else
gettimeofday(&tim, NULL);
next_tick = (tim.tv_usec / 1000) + 30 + (tim.tv_sec * 1000);
#endif
/* Signal handlers */
#ifdef UNIX
signal(SIGTERM, DedicatedSignalHandler);
signal(SIGINT, DedicatedSignalHandler);
signal(SIGQUIT, DedicatedSignalHandler);
#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
if (_exit_game) return ML_QUIT;
if (!_dedicated_forks)
DedicatedHandleKeyInput();
#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 #else
static void *_dedicated_video_mem;
static const char *DedicatedVideoStart(char **parm) {
DEBUG(misc,0)("OpenTTD compiled without network-support, quiting...");
return NULL;
}
void DedicatedFork(void) {} void DedicatedFork(void) {}
static void DedicatedVideoStop(void) { 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(void) { return ML_QUIT; }
const HalVideoDriver _dedicated_video_driver = {
DedicatedVideoStart,
DedicatedVideoStop,
DedicatedVideoMakeDirty,
DedicatedVideoMainLoop,
DedicatedVideoChangeRes,
};
#endif /* ENABLE_NETWORK */ #endif /* ENABLE_NETWORK */

145
depot.c
View File

@@ -1,145 +0,0 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "depot.h"
#include "functions.h"
#include "tile.h"
#include "map.h"
#include "table/strings.h"
#include "saveload.h"
#include "order.h"
enum {
/* Max depots: 64000 (8 * 8000) */
DEPOT_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */
DEPOT_POOL_MAX_BLOCKS = 8000,
};
/**
* Called if a new block is added to the depot-pool
*/
static void DepotPoolNewBlock(uint start_item)
{
Depot *depot;
FOR_ALL_DEPOTS_FROM(depot, start_item)
depot->index = start_item++;
}
/* Initialize the town-pool */
MemoryPool _depot_pool = { "Depots", DEPOT_POOL_MAX_BLOCKS, DEPOT_POOL_BLOCK_SIZE_BITS, sizeof(Depot), &DepotPoolNewBlock, 0, 0, NULL };
/**
* Gets a depot from a tile
*
* @return Returns the depot if the tile had a depot, else it returns NULL
*/
Depot *GetDepotByTile(TileIndex tile)
{
Depot *depot;
FOR_ALL_DEPOTS(depot) {
if (depot->xy == tile)
return depot;
}
return NULL;
}
/**
* Allocate a new depot
*/
Depot *AllocateDepot(void)
{
Depot *depot;
FOR_ALL_DEPOTS(depot) {
if (!IsValidDepot(depot)) {
uint index = depot->index;
memset(depot, 0, sizeof(Depot));
depot->index = index;
return depot;
}
}
/* Check if we can add a block to the pool */
if (AddBlockToPool(&_depot_pool))
return AllocateDepot();
return NULL;
}
/**
* Delete a depot
*/
void DoDeleteDepot(TileIndex tile)
{
Order order;
Depot *depot;
/* Get the depot */
depot = GetDepotByTile(tile);
/* Clear the tile */
DoClearSquare(tile);
/* Clear the depot */
depot->xy = 0;
/* Clear the depot from all order-lists */
order.type = OT_GOTO_DEPOT;
order.station = depot->index;
DeleteDestinationFromVehicleOrder(order);
/* Delete the depot-window */
DeleteWindowById(WC_VEHICLE_DEPOT, tile);
}
void InitializeDepot(void)
{
CleanPool(&_depot_pool);
AddBlockToPool(&_depot_pool);
}
static const SaveLoad _depot_desc[] = {
SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
SLE_CONDVAR(Depot, xy, SLE_UINT32, 6, 255),
SLE_VAR(Depot,town_index, SLE_UINT16),
SLE_END()
};
static void Save_DEPT(void)
{
Depot *depot;
FOR_ALL_DEPOTS(depot) {
if (IsValidDepot(depot)) {
SlSetArrayIndex(depot->index);
SlObject(depot, _depot_desc);
}
}
}
static void Load_DEPT(void)
{
int index;
while ((index = SlIterateArray()) != -1) {
Depot *depot;
if (!AddBlockIfNeeded(&_depot_pool, index))
error("Depots: failed loading savegame: too many depots");
depot = GetDepot(index);
SlObject(depot, _depot_desc);
}
}
const ChunkHandler _depot_chunk_handlers[] = {
{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
};

148
depot.h
View File

@@ -1,148 +0,0 @@
/* $Id$ */
#ifndef DEPOT_H
#define DEPOT_H
/** @file depot.h Header files for depots (not hangars)
* @see depot.c */
#include "pool.h"
#include "tile.h"
#include "variables.h"
struct Depot {
TileIndex xy;
uint16 town_index;
uint16 index;
};
extern MemoryPool _depot_pool;
/**
* Get the pointer to the depot with index 'index'
*/
static inline Depot *GetDepot(uint index)
{
return (Depot*)GetItemFromPool(&_depot_pool, index);
}
/**
* Get the current size of the DepotPool
*/
static inline uint16 GetDepotPoolSize(void)
{
return _depot_pool.total_items;
}
static inline bool IsDepotIndex(uint index)
{
return index < GetDepotPoolSize();
}
#define FOR_ALL_DEPOTS_FROM(d, start) for (d = GetDepot(start); d != NULL; d = (d->index + 1 < GetDepotPoolSize()) ? GetDepot(d->index + 1) : NULL)
#define FOR_ALL_DEPOTS(d) FOR_ALL_DEPOTS_FROM(d, 0)
#define MIN_SERVINT_PERCENT 5
#define MAX_SERVINT_PERCENT 90
#define MIN_SERVINT_DAYS 30
#define MAX_SERVINT_DAYS 800
/** Get the service interval domain.
* Get the new proposed service interval for the vehicle is indeed, clamped
* within the given bounds. @see MIN_SERVINT_PERCENT ,etc.
* @param index proposed service interval
*/
static inline uint16 GetServiceIntervalClamped(uint index)
{
return (_patches.servint_ispercent) ? clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
}
VARDEF TileIndex _last_built_train_depot_tile;
VARDEF TileIndex _last_built_road_depot_tile;
VARDEF TileIndex _last_built_aircraft_depot_tile;
VARDEF TileIndex _last_built_ship_depot_tile;
/**
* Check if a depot really exists.
*/
static inline bool IsValidDepot(const Depot* depot)
{
return depot->xy != 0; /* XXX: Replace by INVALID_TILE someday */
}
/**
* Check if a tile is a depot of the given type.
*/
static inline bool IsTileDepotType(TileIndex tile, TransportType type)
{
switch(type)
{
case TRANSPORT_RAIL:
return IsTileType(tile, MP_RAILWAY) && (_m[tile].m5 & 0xFC) == 0xC0;
case TRANSPORT_ROAD:
return IsTileType(tile, MP_STREET) && (_m[tile].m5 & 0xF0) == 0x20;
case TRANSPORT_WATER:
return IsTileType(tile, MP_WATER) && (_m[tile].m5 & ~3) == 0x80;
default:
assert(0);
return false;
}
}
/**
* Returns the direction the exit of the depot on the given tile is facing.
*/
static inline DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
{
assert(IsTileDepotType(tile, type));
switch (type)
{
case TRANSPORT_RAIL:
case TRANSPORT_ROAD:
/* Rail and road store a diagonal direction in bits 0 and 1 */
return (DiagDirection)GB(_m[tile].m5, 0, 2);
case TRANSPORT_WATER:
/* Water is stubborn, it stores the directions in a different order. */
switch (GB(_m[tile].m5, 0, 2)) {
case 0: return DIAGDIR_NE;
case 1: return DIAGDIR_SW;
case 2: return DIAGDIR_NW;
case 3: return DIAGDIR_SE;
}
default:
return INVALID_DIAGDIR; /* Not reached */
}
}
/**
Find out if the slope of the tile is suitable to build a depot of given direction
@param direction The direction in which the depot's exit points. Starts with 0 as NE and goes Clockwise
@param tileh The slope of the tile in question
@return true if the construction is possible
This is checked by the ugly 0x4C >> direction magic, which does the following:
0x4C is 0100 1100 and tileh has only bits 0..3 set (steep tiles are ruled out)
So: for direction (only the significant bits are shown)<p>
00 (exit towards NE) we need either bit 2 or 3 set in tileh: 0x4C >> 0 = 1100<p>
01 (exit towards SE) we need either bit 1 or 2 set in tileh: 0x4C >> 1 = 0110<p>
02 (exit towards SW) we need either bit 0 or 1 set in tileh: 0x4C >> 2 = 0011<p>
03 (exit towards NW) we need either bit 0 or 4 set in tileh: 0x4C >> 3 = 1001<p>
So ((0x4C >> p2) & tileh) determines whether the depot can be built on the current tileh
*/
static inline bool CanBuildDepotByTileh(uint32 direction, uint tileh)
{
return (0x4C >> direction) & tileh;
}
Depot *GetDepotByTile(TileIndex tile);
void InitializeDepot(void);
Depot *AllocateDepot(void);
void DoDeleteDepot(TileIndex tile);
#endif /* DEPOT_H */

View File

@@ -1,35 +1,30 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "tile.h"
#include "vehicle.h" #include "vehicle.h"
#include "command.h" #include "command.h"
#include "news.h" #include "news.h"
#include "gfx.h"
#include "station.h" #include "station.h"
#include "waypoint.h"
#include "town.h" #include "town.h"
#include "industry.h" #include "industry.h"
#include "player.h" #include "player.h"
#include "airport_movement.h" #include "airport_movement.h"
#include "sound.h" #include "sound.h"
#include "variables.h"
#include "table/sprites.h"
static void DisasterClearSquare(TileIndex tile) static void DisasterClearSquare(TileIndex tile)
{ {
if (!EnsureNoVehicle(tile)) return; if (!EnsureNoVehicle(tile))
return;
switch (GetTileType(tile)) { switch (TileType(tile)) {
case MP_RAILWAY: case MP_RAILWAY:
if (IS_HUMAN_PLAYER(GetTileOwner(tile)) && !IsRailWaypoint(tile)) DoClearSquare(tile); if (IS_HUMAN_PLAYER(_map_owner[tile])) DoClearSquare(tile);
break; break;
case MP_HOUSE: { case MP_HOUSE: {
PlayerID p = _current_player; byte p = _current_player;
_current_player = OWNER_NONE; _current_player = OWNER_NONE;
DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
_current_player = p; _current_player = p;
@@ -80,7 +75,7 @@ static void InitializeDisasterVehicle(Vehicle *v, int x, int y, byte z, byte dir
v->x_pos = x; v->x_pos = x;
v->y_pos = y; v->y_pos = y;
v->z_pos = z; v->z_pos = z;
v->tile = TileVirtXY(x, y); v->tile = TILE_FROM_XY(x,y);
v->direction = direction; v->direction = direction;
v->subtype = subtype; v->subtype = subtype;
v->x_offs = -1; v->x_offs = -1;
@@ -115,7 +110,7 @@ static void SetDisasterVehiclePos(Vehicle *v, int x, int y, byte z)
v->x_pos = x; v->x_pos = x;
v->y_pos = y; v->y_pos = y;
v->z_pos = z; v->z_pos = z;
v->tile = TileVirtXY(x, y); v->tile = TILE_FROM_XY(x,y);
DisasterVehicleUpdateImage(v); DisasterVehicleUpdateImage(v);
VehiclePositionChanged(v); VehiclePositionChanged(v);
@@ -151,7 +146,7 @@ static void DisasterTick_Zeppeliner(Vehicle *v)
Station *st; Station *st;
int x,y; int x,y;
byte z; byte z;
TileIndex tile; uint tile;
++v->tick_counter; ++v->tick_counter;
@@ -170,19 +165,19 @@ static void DisasterTick_Zeppeliner(Vehicle *v)
} }
if ((v->tick_counter&7)==0) { if ((v->tick_counter&7)==0) {
CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE); CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE_3);
} }
} else if (v->current_order.station == 0) { } else if (v->current_order.station == 0) {
tile = v->tile; /**/ tile = v->tile; /**/
if (IsValidTile(tile) && if (IsTileType(tile, MP_STATION) &&
IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) && IS_HUMAN_PLAYER(_map_owner[tile])) {
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
v->current_order.station = 1; v->current_order.station = 1;
v->age = 0; v->age = 0;
SetDParam(0, _m[tile].m2); SetDParam(0, _map2[tile]);
AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT, AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0), NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
v->index, v->index,
@@ -200,11 +195,11 @@ static void DisasterTick_Zeppeliner(Vehicle *v)
tile = v->tile; /**/ tile = v->tile; /**/
if (IsValidTile(tile) && if (IsTileType(tile, MP_STATION) &&
IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) && IS_HUMAN_PLAYER(_map_owner[tile])) {
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
st = GetStation(_m[tile].m2); st = GetStation(_map2[tile]);
CLRBITS(st->airport_flags, RUNWAY_IN_block); CLRBITS(st->airport_flags, RUNWAY_IN_block);
} }
@@ -221,20 +216,20 @@ static void DisasterTick_Zeppeliner(Vehicle *v)
SetDisasterVehiclePos(v, x, y, z); SetDisasterVehiclePos(v, x, y, z);
if (++v->age == 1) { if (++v->age == 1) {
CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE); CreateEffectVehicleRel(v, 0, 7, 8, EV_CRASHED_SMOKE);
SndPlayVehicleFx(SND_12_EXPLOSION, v); SndPlayVehicleFx(SND_12_EXPLOSION, v);
v->u.disaster.image_override = SPR_BLIMP_CRASHING; v->u.disaster.image_override = 0xF42;
} else if (v->age == 70) { } else if (v->age == 70) {
v->u.disaster.image_override = SPR_BLIMP_CRASHED; v->u.disaster.image_override = 0xF43;
} else if (v->age <= 300) { } else if (v->age <= 300) {
if (!(v->tick_counter&7)) { if (!(v->tick_counter&7)) {
uint32 r = Random(); uint32 r = Random();
CreateEffectVehicleRel(v, CreateEffectVehicleRel(v,
GB(r, 0, 4) - 7, -7 + (r&0xF),
GB(r, 4, 4) - 7, -7 + (r>>4&0xF),
GB(r, 8, 3) + 5, 5 + (r>>8&0x7),
EV_EXPLOSION_SMALL); EV_DEMOLISH);
} }
} else if (v->age == 350) { } else if (v->age == 350) {
v->current_order.station = 3; v->current_order.station = 3;
@@ -242,12 +237,11 @@ static void DisasterTick_Zeppeliner(Vehicle *v)
} }
tile = v->tile;/**/ tile = v->tile;/**/
if (IsValidTile(tile) && if (IsTileType(tile, MP_STATION) &&
IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_map5[tile], 8, 0x43) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) && IS_HUMAN_PLAYER(_map_owner[tile])) {
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
st = GetStation(_m[tile].m2); st = GetStation(_map2[tile]);
SETBITS(st->airport_flags, RUNWAY_IN_block); SETBITS(st->airport_flags, RUNWAY_IN_block);
} }
} }
@@ -261,20 +255,20 @@ static void DisasterTick_UFO(Vehicle *v)
uint dist; uint dist;
byte z; byte z;
v->u.disaster.image_override = (++v->tick_counter & 8) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT; v->u.disaster.image_override = (++v->tick_counter & 8) ? 0xF45 : 0xF44;
if (v->current_order.station == 0) { if (v->current_order.station == 0) {
// fly around randomly // fly around randomly
int x = TileX(v->dest_tile) * 16; int x = TileX(v->dest_tile) * 16;
int y = TileY(v->dest_tile) * 16; int y = TileY(v->dest_tile) * 16;
if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) { if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) {
v->direction = GetDirectionTowards(v, x, y); v->direction = GetDirectionTowards(v, x, y);
GetNewVehiclePos(v, &gp); GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
return; return;
} }
if (++v->age < 6) { if (++v->age < 6) {
v->dest_tile = RandomTile(); v->dest_tile = TILE_MASK(Random());
return; return;
} }
v->current_order.station = 1; v->current_order.station = 1;
@@ -325,7 +319,7 @@ static void DisasterTick_UFO(Vehicle *v)
// destroy? // destroy?
if (v->age > 50) { if (v->age > 50) {
CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE); CreateEffectVehicleRel(v, 0, 7, 8, EV_CRASHED_SMOKE);
SndPlayVehicleFx(SND_12_EXPLOSION, v); SndPlayVehicleFx(SND_12_EXPLOSION, v);
DeleteDisasterVeh(v); DeleteDisasterVeh(v);
} }
@@ -334,11 +328,11 @@ static void DisasterTick_UFO(Vehicle *v)
static void DestructIndustry(Industry *i) static void DestructIndustry(Industry *i)
{ {
TileIndex tile; uint tile;
for (tile = 0; tile != MapSize(); tile++) { for(tile=0; tile != MapSize(); tile++) {
if (IsTileType(tile, MP_INDUSTRY) && _m[tile].m2 == i->index) { if (IsTileType(tile, MP_INDUSTRY) && _map2[tile] == i->index) {
_m[tile].m1 = 0; _map_owner[tile] = 0;
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
} }
@@ -351,7 +345,7 @@ static void DisasterTick_2(Vehicle *v)
v->tick_counter++; v->tick_counter++;
v->u.disaster.image_override = v->u.disaster.image_override =
(v->current_order.station == 1 && v->tick_counter & 4) ? SPR_F_15_FIRING : 0; (v->current_order.station == 1 && v->tick_counter&4) ? 0xF4F : 0;
GetNewVehiclePos(v, &gp); GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
@@ -369,10 +363,10 @@ static void DisasterTick_2(Vehicle *v)
uint32 r = Random(); uint32 r = Random();
CreateEffectVehicleAbove( CreateEffectVehicleAbove(
GB(r, 0, 6) + x, x + (r & 0x3F),
GB(r, 6, 6) + y, y + (r >> 6 & 0x3F),
GB(r, 12, 4), (r >> 12 & 0xF),
EV_EXPLOSION_SMALL); EV_DEMOLISH);
if (++v->age >= 55) if (++v->age >= 55)
v->current_order.station = 3; v->current_order.station = 3;
@@ -393,7 +387,7 @@ static void DisasterTick_2(Vehicle *v)
} }
} else if (v->current_order.station == 0) { } else if (v->current_order.station == 0) {
int x,y; int x,y;
TileIndex tile; uint tile;
int ind; int ind;
x = v->x_pos - 15*16; x = v->x_pos - 15*16;
@@ -402,11 +396,11 @@ static void DisasterTick_2(Vehicle *v)
if ( (uint)x > MapMaxX() * 16-1) if ( (uint)x > MapMaxX() * 16-1)
return; return;
tile = TileVirtXY(x, y); tile = TILE_FROM_XY(x,y);
if (!IsTileType(tile, MP_INDUSTRY)) if (!IsTileType(tile, MP_INDUSTRY))
return; return;
v->dest_tile = ind = _m[tile].m2; v->dest_tile = ind = _map2[tile];
if (GetIndustry(ind)->type == IT_OIL_REFINERY) { if (GetIndustry(ind)->type == IT_OIL_REFINERY) {
v->current_order.station = 1; v->current_order.station = 1;
@@ -422,7 +416,7 @@ static void DisasterTick_3(Vehicle *v)
v->tick_counter++; v->tick_counter++;
v->u.disaster.image_override = v->u.disaster.image_override =
(v->current_order.station == 1 && v->tick_counter & 4) ? SPR_AH_64A_FIRING : 0; (v->current_order.station == 1 && v->tick_counter&4) ? 0xF53 : 0;
GetNewVehiclePos(v, &gp); GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
@@ -440,10 +434,10 @@ static void DisasterTick_3(Vehicle *v)
uint32 r = Random(); uint32 r = Random();
CreateEffectVehicleAbove( CreateEffectVehicleAbove(
GB(r, 0, 6) + x, x + (r & 0x3F),
GB(r, 6, 6) + y, y + (r >> 6 & 0x3F),
GB(r, 12, 4), (r >> 12 & 0xF),
EV_EXPLOSION_SMALL); EV_DEMOLISH);
if (++v->age >= 55) if (++v->age >= 55)
v->current_order.station = 3; v->current_order.station = 3;
@@ -464,7 +458,7 @@ static void DisasterTick_3(Vehicle *v)
} }
} else if (v->current_order.station == 0) { } else if (v->current_order.station == 0) {
int x,y; int x,y;
TileIndex tile; uint tile;
int ind; int ind;
x = v->x_pos - 15*16; x = v->x_pos - 15*16;
@@ -473,11 +467,11 @@ static void DisasterTick_3(Vehicle *v)
if ( (uint)x > MapMaxX() * 16-1) if ( (uint)x > MapMaxX() * 16-1)
return; return;
tile = TileVirtXY(x, y); tile = TILE_FROM_XY(x,y);
if (!IsTileType(tile, MP_INDUSTRY)) if (!IsTileType(tile, MP_INDUSTRY))
return; return;
v->dest_tile = ind = _m[tile].m2; v->dest_tile = ind = _map2[tile];
if (GetIndustry(ind)->type == IT_FACTORY) { if (GetIndustry(ind)->type == IT_FACTORY) {
v->current_order.station = 1; v->current_order.station = 1;
@@ -492,7 +486,8 @@ static void DisasterTick_3b(Vehicle *v)
if (++v->tick_counter & 1) if (++v->tick_counter & 1)
return; return;
if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1; if (++v->cur_image == 0xF40 + 1)
v->cur_image = 0xF3E;
VehiclePositionChanged(v); VehiclePositionChanged(v);
BeginVehicleMove(v); BeginVehicleMove(v);
@@ -507,8 +502,7 @@ static void DisasterTick_4(Vehicle *v)
byte z; byte z;
Vehicle *u,*w; Vehicle *u,*w;
Town *t; Town *t;
TileIndex tile; uint tile,tile_org;
TileIndex tile_org;
v->tick_counter++; v->tick_counter++;
@@ -567,7 +561,7 @@ static void DisasterTick_4(Vehicle *v)
int x = TileX(v->dest_tile) * 16; int x = TileX(v->dest_tile) * 16;
int y = TileY(v->dest_tile) * 16; int y = TileY(v->dest_tile) * 16;
if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) { if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) {
v->direction = GetDirectionTowards(v, x, y); v->direction = GetDirectionTowards(v, x, y);
GetNewVehiclePos(v, &gp); GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
@@ -575,16 +569,16 @@ static void DisasterTick_4(Vehicle *v)
} }
if (++v->age < 6) { if (++v->age < 6) {
v->dest_tile = RandomTile(); v->dest_tile = TILE_MASK(Random());
return; return;
} }
v->current_order.station = 1; v->current_order.station = 1;
tile_org = tile = RandomTile(); tile_org = tile = TILE_MASK(Random());
do { do {
if (IsTileType(tile, MP_RAILWAY) && if (IsTileType(tile, MP_RAILWAY) &&
(_m[tile].m5 & ~3) != 0xC0 && IS_HUMAN_PLAYER(GetTileOwner(tile))) (_map5[tile]&~3)!=0xC0 && IS_HUMAN_PLAYER(_map_owner[tile]))
break; break;
tile = TILE_MASK(tile+1); tile = TILE_MASK(tile+1);
} while (tile != tile_org); } while (tile != tile_org);
v->dest_tile = tile; v->dest_tile = tile;
@@ -616,7 +610,7 @@ static void DisasterTick_4b(Vehicle *v)
return; return;
v->current_order.station = 1; v->current_order.station = 1;
CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE); CreateEffectVehicleRel(u, 0, 7, 8, EV_CRASHED_SMOKE);
SndPlayVehicleFx(SND_12_EXPLOSION, u); SndPlayVehicleFx(SND_12_EXPLOSION, u);
DeleteDisasterVeh(u); DeleteDisasterVeh(u);
@@ -624,16 +618,16 @@ static void DisasterTick_4b(Vehicle *v)
for(i=0; i!=80; i++) { for(i=0; i!=80; i++) {
uint32 r = Random(); uint32 r = Random();
CreateEffectVehicleAbove( CreateEffectVehicleAbove(
GB(r, 0, 6) + v->x_pos - 32, v->x_pos-32+(r&0x3F),
GB(r, 5, 6) + v->y_pos - 32, v->y_pos-32+(r>>5&0x3F),
0, 0,
EV_EXPLOSION_SMALL); EV_DEMOLISH);
} }
BEGIN_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3)) BEGIN_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3))
tile = TILE_MASK(tile); tile = TILE_MASK(tile);
DisasterClearSquare(tile); DisasterClearSquare(tile);
END_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3)) END_TILE_LOOP(tile,6,6,v->tile - TILE_XY(3,3))
} }
} }
@@ -642,7 +636,7 @@ static void DisasterTick_5_and_6(Vehicle *v)
{ {
uint32 r; uint32 r;
GetNewVehiclePosResult gp; GetNewVehiclePosResult gp;
TileIndex tile; uint tile;
v->tick_counter++; v->tick_counter++;
@@ -666,7 +660,7 @@ static void DisasterTick_5_and_6(Vehicle *v)
return; return;
} }
v->direction = (v->direction + (GB(Random(), 0, 1) ? 2 : -2)) & 7; v->direction = (v->direction + ((Random()&1)?2:-2))&7;
} }
@@ -690,6 +684,10 @@ void DisasterVehicle_Tick(Vehicle *v)
_disastervehicle_tick_procs[v->subtype](v); _disastervehicle_tick_procs[v->subtype](v);
} }
void HandleClickOnDisasterVeh(Vehicle *v)
{
// not used
}
void OnNewDay_DisasterVehicle(Vehicle *v) void OnNewDay_DisasterVehicle(Vehicle *v)
{ {
@@ -743,7 +741,7 @@ static void Disaster1_Init(void)
x = TileX(Random()) * 16 + 8; x = TileX(Random()) * 16 + 8;
InitializeDisasterVehicle(v, x, 0, 135, 3, 2); InitializeDisasterVehicle(v, x, 0, 135, 3, 2);
v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2); v->dest_tile = TILE_XY(MapSizeX() / 2, MapSizeY() / 2);
v->age = 0; v->age = 0;
// Allocate shadow too? // Allocate shadow too?
@@ -838,13 +836,14 @@ static void Disaster4_Init(void)
Vehicle *v = ForceAllocateSpecialVehicle(), *u; Vehicle *v = ForceAllocateSpecialVehicle(), *u;
int x,y; int x,y;
if (v == NULL) return; if (v == NULL)
return;
x = TileX(Random()) * 16 + 8; x = TileX(Random()) * 16 + 8;
y = MapMaxX() * 16 - 1; y = MapMaxX() * 16 - 1;
InitializeDisasterVehicle(v, x, y, 135, 7, 9); InitializeDisasterVehicle(v, x, y, 135, 7, 9);
v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2); v->dest_tile = TILE_XY(MapSizeX() / 2, MapSizeY() / 2);
v->age = 0; v->age = 0;
// Allocate shadow too? // Allocate shadow too?
@@ -864,7 +863,8 @@ static void Disaster5_Init(void)
byte dir; byte dir;
uint32 r; uint32 r;
if (v == NULL) return; if (v == NULL)
return;
r = Random(); r = Random();
x = TileX(r) * 16 + 8; x = TileX(r) * 16 + 8;
@@ -884,7 +884,8 @@ static void Disaster6_Init(void)
byte dir; byte dir;
uint32 r; uint32 r;
if (v == NULL) return; if (v == NULL)
return;
r = Random(); r = Random();
x = TileX(r) * 16 + 8; x = TileX(r) * 16 + 8;
@@ -898,32 +899,31 @@ static void Disaster6_Init(void)
static void Disaster7_Init(void) static void Disaster7_Init(void)
{ {
int index = GB(Random(), 0, 4);
Industry *i; Industry *i;
uint m; int maxloop = 15;
int index = Random() & 0xF;
for (m = 0; m < 15; m++) { do {
FOR_ALL_INDUSTRIES(i) { FOR_ALL_INDUSTRIES(i) {
if (i->xy != 0 && i->type == IT_COAL_MINE && --index < 0) { if (i->xy != 0 && i->type == IT_COAL_MINE && --index < 0) {
SetDParam(0, i->town->index); SetDParam(0, i->town->index);
AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES, AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TileDiffXY(1, 1), 0); NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TILE_XY(1,1), 0);
{ {
TileIndex tile = i->xy; uint tile = i->xy;
TileIndexDiff step = TileOffsByDir(GB(Random(), 0, 2)); TileIndexDiff step = TileOffsByDir(Random() & 3);
uint n; int count = 30;
do {
for (n = 0; n < 30; n++) {
DisasterClearSquare(tile); DisasterClearSquare(tile);
tile = TILE_MASK(tile + step); tile = TILE_MASK(tile + step);
} } while (--count);
} }
return; return;
} }
} }
} } while (--maxloop != 0);
} }
static DisasterInitProc * const _disaster_initprocs[] = { static DisasterInitProc * const _disaster_initprocs[] = {
@@ -937,56 +937,60 @@ static DisasterInitProc * const _disaster_initprocs[] = {
Disaster7_Init, Disaster7_Init,
}; };
#define MK(a, b) { (a) - MAX_YEAR_BEGIN_REAL, (b) - MAX_YEAR_BEGIN_REAL } typedef struct {
static const struct { byte min,max;
byte min; } DisasterYears;
byte max;
} _dis_years[] = { #define MK(a,b) {a-20,b-20}
MK(1930, 1955), static const DisasterYears _dis_years[8] = {
MK(1940, 1970), MK(30,55),
MK(1960, 1990), MK(40,70),
MK(1970, 2000), MK(60,90),
MK(2000, 2100), MK(70,100),
MK(1940, 1965), MK(100,200),
MK(1975, 2010), MK(40,65),
MK(1950, 1985) MK(75,110),
MK(50,85),
}; };
#undef MK
static void DoDisaster(void) static void DoDisaster(void)
{ {
byte buf[lengthof(_dis_years)]; byte buf[8];
byte year = _cur_year; byte year = _cur_year;
uint i; int i,j;
uint j;
j = 0; for(i=j=0; i!=lengthof(_dis_years); i++) {
for (i = 0; i != lengthof(_dis_years); i++) { if (year >= _dis_years[i].min &&
if (year >= _dis_years[i].min && year < _dis_years[i].max) buf[j++] = i; year < _dis_years[i].max)
buf[j++] = i;
} }
if (j == 0) return; if (j == 0)
return;
_disaster_initprocs[buf[RandomRange(j)]](); _disaster_initprocs[buf[(uint16)Random() * j >> 16]]();
} }
static void ResetDisasterDelay(void) static void ResetDisasterDelay(void)
{ {
_disaster_delay = GB(Random(), 0, 9) + 730; _disaster_delay = (int)(Random() & 0x1FF) + 730;
} }
void DisasterDailyLoop(void) void DisasterDailyLoop(void)
{ {
if (--_disaster_delay != 0) return; if (--_disaster_delay != 0)
return;
ResetDisasterDelay(); ResetDisasterDelay();
if (_opt.diff.disasters != 0) DoDisaster(); if (_opt.diff.disasters != 0)
DoDisaster();
} }
void StartupDisasters(void) void StartupDisasters(void)
{ {
ResetDisasterDelay(); ResetDisasterDelay();
} }

View File

@@ -1,10 +1,6 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/sprites.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "window.h" #include "window.h"
#include "station.h" #include "station.h"
@@ -13,14 +9,13 @@
#include "gfx.h" #include "gfx.h"
#include "sound.h" #include "sound.h"
#include "command.h" #include "command.h"
#include "variables.h"
static void ShowBuildDockStationPicker(void); static void ShowBuildDockStationPicker(void);
static void ShowBuildDocksDepotPicker(void); static void ShowBuildDocksDepotPicker(void);
static byte _ship_depot_direction; static byte _ship_depot_direction;
void CcBuildDocks(bool success, TileIndex tile, uint32 p1, uint32 p2) void CcBuildDocks(bool success, uint tile, uint32 p1, uint32 p2)
{ {
if (success) { if (success) {
SndPlayTileFx(SND_02_SPLAT, tile); SndPlayTileFx(SND_02_SPLAT, tile);
@@ -28,38 +23,38 @@ void CcBuildDocks(bool success, TileIndex tile, uint32 p1, uint32 p2)
} }
} }
void CcBuildCanal(bool success, TileIndex tile, uint32 p1, uint32 p2) void CcBuildCanal(bool success, uint tile, uint32 p1, uint32 p2)
{ {
if (success) SndPlayTileFx(SND_02_SPLAT, tile); if (success) SndPlayTileFx(SND_02_SPLAT, tile);
} }
static void PlaceDocks_Dock(TileIndex tile) static void PlaceDocks_Dock(uint tile)
{ {
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_DOCK | CMD_AUTO | CMD_MSG(STR_9802_CAN_T_BUILD_DOCK_HERE)); DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_DOCK | CMD_AUTO | CMD_MSG(STR_9802_CAN_T_BUILD_DOCK_HERE));
} }
static void PlaceDocks_Depot(TileIndex tile) static void PlaceDocks_Depot(uint tile)
{ {
DoCommandP(tile, _ship_depot_direction, 0, CcBuildDocks, CMD_BUILD_SHIP_DEPOT | CMD_AUTO | CMD_MSG(STR_3802_CAN_T_BUILD_SHIP_DEPOT)); DoCommandP(tile, _ship_depot_direction, 0, CcBuildDocks, CMD_BUILD_SHIP_DEPOT | CMD_AUTO | CMD_MSG(STR_3802_CAN_T_BUILD_SHIP_DEPOT));
} }
static void PlaceDocks_Buoy(TileIndex tile) static void PlaceDocks_Buoy(uint tile)
{ {
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_BUOY | CMD_AUTO | CMD_MSG(STR_9835_CAN_T_POSITION_BUOY_HERE)); DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_BUOY | CMD_AUTO | CMD_MSG(STR_9835_CAN_T_POSITION_BUOY_HERE));
} }
static void PlaceDocks_DemolishArea(TileIndex tile) static void PlaceDocks_DemolishArea(uint tile)
{ {
VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea); VpStartPlaceSizing(tile, VPM_X_AND_Y);
} }
static void PlaceDocks_BuildCanal(TileIndex tile) static void PlaceDocks_BuildCanal(uint tile)
{ {
VpStartPlaceSizing(tile, VPM_X_OR_Y); VpStartPlaceSizing(tile, VPM_X_OR_Y);
} }
static void PlaceDocks_BuildLock(TileIndex tile) static void PlaceDocks_BuildLock(uint tile)
{ {
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS)); DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS));
} }
@@ -67,12 +62,12 @@ static void PlaceDocks_BuildLock(TileIndex tile)
static void BuildDocksClick_Canal(Window *w) static void BuildDocksClick_Canal(Window *w)
{ {
HandlePlacePushButton(w, 3, SPR_CURSOR_CANAL, 1, PlaceDocks_BuildCanal); HandlePlacePushButton(w, 3, SPR_OPENTTD_BASE + 11, 1, PlaceDocks_BuildCanal);
} }
static void BuildDocksClick_Lock(Window *w) static void BuildDocksClick_Lock(Window *w)
{ {
HandlePlacePushButton(w, 4, SPR_CURSOR_LOCK, 1, PlaceDocks_BuildLock); HandlePlacePushButton(w, 4, SPR_OPENTTD_BASE + 64, 1, PlaceDocks_BuildLock);
} }
static void BuildDocksClick_Demolish(Window *w) static void BuildDocksClick_Demolish(Window *w)
@@ -82,18 +77,18 @@ static void BuildDocksClick_Demolish(Window *w)
static void BuildDocksClick_Depot(Window *w) static void BuildDocksClick_Depot(Window *w)
{ {
if (HandlePlacePushButton(w, 7, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker(); if (HandlePlacePushButton(w, 7, 0x2D1, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
} }
static void BuildDocksClick_Dock(Window *w) static void BuildDocksClick_Dock(Window *w)
{ {
if (HandlePlacePushButton(w, 8, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker(); if (HandlePlacePushButton(w, 8, 0xE54, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
} }
static void BuildDocksClick_Buoy(Window *w) static void BuildDocksClick_Buoy(Window *w)
{ {
HandlePlacePushButton(w, 9, SPR_CURSOR_BOUY, 1, PlaceDocks_Buoy); HandlePlacePushButton(w, 9, 0x2BE, 1, PlaceDocks_Buoy);
} }
static void BuildDocksClick_Landscaping(Window *w) static void BuildDocksClick_Landscaping(Window *w)
@@ -105,7 +100,7 @@ typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_docks_button_proc[] = { static OnButtonClick * const _build_docks_button_proc[] = {
BuildDocksClick_Canal, BuildDocksClick_Canal,
BuildDocksClick_Lock, BuildDocksClick_Lock,
NULL, 0,
BuildDocksClick_Demolish, BuildDocksClick_Demolish,
BuildDocksClick_Depot, BuildDocksClick_Depot,
BuildDocksClick_Dock, BuildDocksClick_Dock,
@@ -120,12 +115,12 @@ static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
DrawWindowWidgets(w); DrawWindowWidgets(w);
break; break;
case WE_CLICK: case WE_CLICK: {
if (e->click.widget - 3 >= 0 && e->click.widget != 5) _build_docks_button_proc[e->click.widget - 3](w); if (e->click.widget - 3 >= 0 && e->click.widget != 5) _build_docks_button_proc[e->click.widget - 3](w);
break; } break;
case WE_KEYPRESS: case WE_KEYPRESS: {
switch (e->keypress.keycode) { switch(e->keypress.keycode) {
case '1': BuildDocksClick_Canal(w); break; case '1': BuildDocksClick_Canal(w); break;
case '2': BuildDocksClick_Lock(w); break; case '2': BuildDocksClick_Lock(w); break;
case '3': BuildDocksClick_Demolish(w); break; case '3': BuildDocksClick_Demolish(w); break;
@@ -133,9 +128,10 @@ static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
case '5': BuildDocksClick_Dock(w); break; case '5': BuildDocksClick_Dock(w); break;
case '6': BuildDocksClick_Buoy(w); break; case '6': BuildDocksClick_Buoy(w); break;
case 'l': BuildDocksClick_Landscaping(w); break; case 'l': BuildDocksClick_Landscaping(w); break;
default: return; default:
return;
} }
break; } break;
case WE_PLACE_OBJ: case WE_PLACE_OBJ:
_place_proc(e->place.tile); _place_proc(e->place.tile);
@@ -148,11 +144,10 @@ static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
case WE_PLACE_MOUSEUP: case WE_PLACE_MOUSEUP:
if (e->click.pt.x != -1) { if (e->click.pt.x != -1) {
if ((e->place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions if (e->place.userdata == VPM_X_AND_Y)
GUIPlaceProcDragXY(e); DoCommandP(e->place.tile, e->place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
} else if (e->place.userdata == VPM_X_OR_Y) { else if(e->place.userdata == VPM_X_OR_Y)
DoCommandP(e->place.tile, e->place.starttile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS)); DoCommandP(e->place.tile, e->place.starttile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
}
} }
break; break;
@@ -161,29 +156,24 @@ static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w); SetWindowDirty(w);
w = FindWindowById(WC_BUILD_STATION, 0); w = FindWindowById(WC_BUILD_STATION, 0);
if (w != NULL) WP(w,def_d).close = true; if (w != NULL) WP(w,def_d).close=true;
w = FindWindowById(WC_BUILD_DEPOT, 0); w = FindWindowById(WC_BUILD_DEPOT, 0);
if (w != NULL) WP(w,def_d).close = true; if (w != NULL) WP(w,def_d).close=true;
break; break;
case WE_PLACE_PRESIZE: { case WE_PLACE_PRESIZE: {
TileIndex tile_from; uint tile_from, tile_to;
TileIndex tile_to;
tile_from = tile_to = e->place.tile; tile_from = tile_to = e->place.tile;
switch (GetTileSlope(tile_from, NULL)) { switch(GetTileSlope(tile_from, NULL)) {
case 3: tile_to += TileDiffXY(-1, 0); break; case 3: tile_to += TILE_XY(-1,0); break;
case 6: tile_to += TileDiffXY( 0, -1); break; case 6: tile_to += TILE_XY(0,-1); break;
case 9: tile_to += TileDiffXY( 0, 1); break; case 9: tile_to += TILE_XY(0,1); break;
case 12: tile_to += TileDiffXY( 1, 0); break; case 12:tile_to += TILE_XY(1,0); break;
} }
VpSetPresizeRange(tile_from, tile_to); VpSetPresizeRange(tile_from, tile_to);
} break; } break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
} }
} }
@@ -191,8 +181,8 @@ static const Widget _build_docks_toolb_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 145, 0, 13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 145, 0, 13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 7, 146, 157, 0, 13, 0x0, STR_STICKY_BUTTON}, { WWT_STICKYBOX, RESIZE_NONE, 7, 146, 157, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 21, 14, 35, SPR_IMG_BUILD_CANAL, STR_BUILD_CANALS_TIP}, { WWT_PANEL, RESIZE_NONE, 7, 0, 21, 14, 35, SPR_OPENTTD_BASE+65, STR_BUILD_CANALS_TIP},
{ WWT_PANEL, RESIZE_NONE, 7, 22, 43, 14, 35, SPR_IMG_BUILD_LOCK, STR_BUILD_LOCKS_TIP}, { WWT_PANEL, RESIZE_NONE, 7, 22, 43, 14, 35, SPR_CANALS_BASE+69, STR_BUILD_LOCKS_TIP},
{ WWT_PANEL, RESIZE_NONE, 7, 44, 47, 14, 35, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 44, 47, 14, 35, 0x0, STR_NULL},
@@ -217,44 +207,42 @@ void ShowBuildDocksToolbar(void)
if (_current_player == OWNER_SPECTATOR) return; if (_current_player == OWNER_SPECTATOR) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0); DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDesc(&_build_docks_toolbar_desc); AllocateWindowDesc(&_build_docks_toolbar_desc);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
} }
static void BuildDockStationWndProc(Window *w, WindowEvent *e) static void BuildDockStationWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { int rad;
case WE_PAINT: {
int rad;
if (WP(w,def_d).close) return; switch(e->event) {
case WE_PAINT: {
if (WP(w,def_d).close)
return;
w->click_state = (1<<3) << _station_show_coverage; w->click_state = (1<<3) << _station_show_coverage;
DrawWindowWidgets(w); DrawWindowWidgets(w);
if (_patches.modified_catchment) {
rad = (_patches.modified_catchment) ? CA_DOCK : 4; rad = CA_DOCK;
if (_station_show_coverage) {
SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
} else { } else {
SetTileSelectBigSize(0, 0, 0, 0); rad = 4;
} }
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
else SetTileSelectBigSize(0, 0, 0, 0);
DrawStringCentered(74, 17, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0); DrawStringCentered(74, 17, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0);
DrawStationCoverageAreaText(4, 50, (uint)-1, rad); DrawStationCoverageAreaText(4, 50, (uint)-1, rad);
break; } break;
}
case WE_CLICK: case WE_CLICK: {
switch (e->click.widget) { switch(e->click.widget) {
case 3: case 3: case 4:
case 4: _station_show_coverage = e->click.widget - 3;
_station_show_coverage = e->click.widget - 3; SndPlayFx(SND_15_BEEP);
SndPlayFx(SND_15_BEEP); SetWindowDirty(w);
SetWindowDirty(w); break;
break;
} }
break; } break;
case WE_MOUSELOOP: case WE_MOUSELOOP: {
if (WP(w,def_d).close) { if (WP(w,def_d).close) {
DeleteWindow(w); DeleteWindow(w);
return; return;
@@ -262,9 +250,11 @@ static void BuildDockStationWndProc(Window *w, WindowEvent *e)
CheckRedrawStationCoverage(w); CheckRedrawStationCoverage(w);
break; break;
}
case WE_DESTROY: case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace(); if (!WP(w,def_d).close)
ResetObjectToPlace();
break; break;
} }
} }
@@ -273,8 +263,8 @@ static const Widget _build_dock_station_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 147, 0, 13, STR_3068_DOCK, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 147, 0, 13, STR_3068_DOCK, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 74, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 74, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 30, 40, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 14, 73, 30, 40, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 30, 40, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 74, 133, 30, 40, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -302,7 +292,7 @@ static void UpdateDocksDirection(void)
static void BuildDocksDepotWndProc(Window *w, WindowEvent *e) static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { switch(e->event) {
case WE_PAINT: case WE_PAINT:
w->click_state = (1<<3) << _ship_depot_direction; w->click_state = (1<<3) << _ship_depot_direction;
DrawWindowWidgets(w); DrawWindowWidgets(w);
@@ -314,7 +304,7 @@ static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
return; return;
case WE_CLICK: { case WE_CLICK: {
switch (e->click.widget) { switch(e->click.widget) {
case 3: case 3:
case 4: case 4:
_ship_depot_direction = e->click.widget - 3; _ship_depot_direction = e->click.widget - 3;
@@ -326,11 +316,13 @@ static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
} break; } break;
case WE_MOUSELOOP: case WE_MOUSELOOP:
if (WP(w,def_d).close) DeleteWindow(w); if (WP(w,def_d).close)
DeleteWindow(w);
break; break;
case WE_DESTROY: case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace(); if (!WP(w,def_d).close)
ResetObjectToPlace();
break; break;
} }
} }

View File

@@ -1,23 +0,0 @@
To install OpenTTD, you should drag the game to any location you want and in that folder, you should create a folder called "data". It should contain:
sample.cat
trg1r.grf
trgcr.grf
trghr.grf
trgir.grf
trgtr.grf
(Alternatively you can use the TTD GRF files from the DOS version: TRG1.GRF, TRGC.GRF, TRGH.GRF, TRGI.GRF, TRGT.GRF. A few minor graphical glitches with the DOS graphics remain. E.g. the autorail button in the rail toolbar doesn't look as nice as with the Windows graphics.)
You should also use the data folder to add any custom grf files if you like
if you want music, you can add a GM folder and add all .gm files from TTD inside it
If you want to use the scenarios, you can copy the scenario folder as well. If you already have one, just copy the content so you don't overwrite old ones that have been removed.
In the end, you should have a folder containing:
OpenTTD (the actual game)
data (containing the grf files)
GM (optional for music)
scenario (optional pregenerated maps)
The game adds some items by itself when it runs, like a save folder and a setting file

View File

@@ -0,0 +1,24 @@
It's gone
The main goal with the package system was to make it as simple as possible to update. The problem was that some files inside the data folder should be updated and not others. Now the data files have been moved inside OpenTTD itself and to make it even easier, the same goes for the lang dir. There will no longer be an issue where people have different versions of grf files, language files and OpenTTD.
To install simply copy OpenTTD into the folder you want
If it is your current folder with outdated grf files, you should remove
canalsw.grf
openttd.grf
opntitle.dat
signalsw.grf
trkfoundw.grf
THE TTD GRF FILES ARE STILL NEEDED!
They need to be inside a folder called "data" in the same folder as OpenTTD. Create it if you have none. It should contain:
sample.cat
trg1r.grf
trgcr.grf
trghr.grf
trgir.grf
trgtr.grf
(Alternatively you can use the TTD GRF files from the DOS version: TRG1.GRF, TRGC.GRF, TRGH.GRF, TRGI.GRF, TRGT.GRF. A few minor graphical glitches with the DOS graphics remain. E.g. the autorail button in the rail toolbar doesn't look as nice as with the Windows graphics.)
You should also use the data folder to add any custom grf files if you like

View File

@@ -1,10 +0,0 @@
There are currently two different downloads for OSX, one is named osx, while the other one is named osx-jaguar
The reason for this is that Apple added more functionality to 10.3 and to make use of that, it will no longer run on OSX 10.2 (codenamed Jaguar). To make the game useable on Jaguar, then a special download is available, but it will miss the bugfixes/features, that relies on newer functionality.
The general download is a universal binary and should work great on all macs using 10.3.9 or newer, no matter what processor it got. You should at all time avoid the Jaguar Build if possible.
Technically the universal binary is a triple binary because it contains code for 3 CPUs and the CPUs in question are PPC (G3+G4), G5 and Intel. The Jaguar build is only optimised for PPC and other (newer) CPUs will not benefit so much from their advanced features. This is another reason to avoid the Jaguar build. It's generally slower on modern CPUs.
Current list of missing features in the Jaguar build:
-Can't save screenshots or savegames if certain chars are in the filename. This mainly applies to European chars and hits German hard as the month Mär (Mar) can't be saved

View File

@@ -0,0 +1,36 @@
Since you are reading this, OpenTTD have crashed. This file tells you how
to fix the most common problems or make to make a bug report, that the
developers can use to track down the problem
If it is an assert, OpenTTD will open the console for you, if it is truly a crash, you have to do it yourself. The Console is located at /Applications/Utilities/Console.
The problem is near the button of the page
The problems are as follows:
NOTE: build from source means to download the source and compile
yourself. If you get one of the build from source error with the version
that is downloaded on a dmg file, you should make a bug report
--Didn't find a needed file:
you just give it the file it asks for. It even tells you what
folder it wants it in
most common version of this problem is "Error: Cannot open file
'data/sample.cat'"
if you get that one, that means that you haven't got all the
needed files from the WINDOWS version of TTD
or if you build from source,
--Error: No available language packs
you need at least one .lng file in your lang folder. This applies
only to people who build from source
--spritecache.c:237: failed assertion `b'
you got an outdated grf file. Update from the data folder in the
source. This applies only to people, who build from source
--assertion error that are not triggered by one of the errors listed in
this file:
you most likely found a bug. Write down the assertion and try to
see if you can reproduce it. If you can, make a
savegame from just before it happens (autosaves are useful here)
and post a bugreport with it on sourceforge
Write what you did to trigger the bug and what assertion it made

View File

@@ -20,11 +20,6 @@ http://sourceforge.net/projects/openttd/ - see "os2-useful.zip".
ftp://ftp.netlabs.org/pub/sdl/sdl-dev-os2-2004-12-22.zip which may ftp://ftp.netlabs.org/pub/sdl/sdl-dev-os2-2004-12-22.zip which may
help solve some problems). help solve some problems).
Please note that SDL release 2005-03-30 does NOT work with OpenTTD,
at least in my experience and the experience of a couple of other
users. If you experience problems with OpenTTD, please try downgrading
to SDL 2004-12-22.
Note that to actually play the game, I have found in my own Note that to actually play the game, I have found in my own
experience that a version of the Scitech Display Drivers or its later experience that a version of the Scitech Display Drivers or its later
incarnation (see www.scitech.com) are necessary for it to work. If incarnation (see www.scitech.com) are necessary for it to work. If
@@ -71,14 +66,13 @@ Compiler
Open Watcom 1.3 was used to build OpenTTD (earlier versions will Open Watcom 1.3 was used to build OpenTTD (earlier versions will
NOT work). See http://www.openwatcom.org/ to download it. It may NOT work). See http://www.openwatcom.org/ to download it. It may
also be possible to build OpenTTD with GCC: I attempted this also be possible to build OpenTTD under OS/2: I attempted this
before using Open Watcom, but found the tools available for OS/2 before using Open Watcom, but found the tools available for OS/2
at the time to be a bit more tricky to get working. at the time to be a bit more tricky to get working.
Due to complexities in my set-up, I actually used the Win32 version Due to complexities in my set-up, I actually used the Win32 version
of Open Watcom to initially compile OpenTTD for OS/2. There should of Open Watcom to initially compile OpenTTD for OS/2. There should
be no reason of course why the OS/2 version cannot be used, and I be no reason of course why the OS/2 version cannot be used.
have subsequently built OpenTTD successfully this way.
Libraries Required Libraries Required
------------------ ------------------
@@ -90,10 +84,10 @@ provided, they are not designed for Watcom (apart from SDL):
- zlib - zlib
http://www.zlib.org/ - contains a makefile for OS/2, but is out http://www.zlib.org/ - contains a makefile for OS/2, but is out
of date and uses EMX, ignore this of date and uses EMX
- libpng - libpng
http://www.libpng.org/ - contains an EMX/gcc makefile, ignore this http://www.libpng.org/ - contains an EMX/gcc makefile
- SDL for OS/2 - SDL for OS/2
For 0.3.5, I used ftp://ftp.netlabs.org/pub/sdl/SDL-1.2.7-src-20040908a.zip - For 0.3.5, I used ftp://ftp.netlabs.org/pub/sdl/SDL-1.2.7-src-20040908a.zip -
@@ -104,18 +98,6 @@ If you do not wish to build the libraries yourself, pre-built versions
can be downloaded from the Files section at can be downloaded from the Files section at
http://sourceforge.net/projects/openttd/ - see "os2-useful.zip". http://sourceforge.net/projects/openttd/ - see "os2-useful.zip".
A Note About Subversion Revision Numbers
----------------------------------------
The project file uses a bit of a hack to find out the SVN revision number and
create an appropriate rev.c file. You'll need the SVN tools in your path
(specifically, "svnversion"). If "svnversion" can't be found, a generic rev.c
with the revision set to "norev000" will be created. To specifically force a
version number, set the environment variable "RELEASE" to the number (eg, "0.3.6")
-before- starting the Open Watcom IDE (which must be launched from the same shell
session). Also, beware, as you WILL cause incompatibilities if you try to
play a multiplayer game with a different version.
Compiling Compiling
--------- ---------
@@ -133,4 +115,4 @@ If you have any questions regarding OS/2 issues, please contact me
(owen@owenrudge.net) and I'll try to help you out. For general OpenTTD (owen@owenrudge.net) and I'll try to help you out. For general OpenTTD
issues, see the Contacting section of readme.txt. issues, see the Contacting section of readme.txt.
- Owen Rudge - Owen Rudge, 26th December 2004

View File

@@ -1,50 +1,54 @@
Compiling OpenTTD using Microsoft Visual C++ 6.0 Compiling OpenTTD using Microsoft Visual C++ 6.0
Step 1: Ingredients ---Step 1
Download the following files: Download the following files:
* Openttd-useful.zip (http://sourceforge.net/project/showfiles.php?group_id=103924&amp;package_id=114307&amp;release_id=228633) * Useful.zip (http://sourceforge.net/project/showfiles.php?group_id=103924&package_id=114307&release_id=228633)
* DirectX 8.1 SDK (http://neuron.tuke.sk/~mizanin/eng/Dx81sdk-include-lib.rar) (or alternatively the latest DirectX SDK from Microsoft) * SDL-1.2.8-VC6.zip (http://www.libsdl.org/release/SDL-devel-1.2.8-VC6.zip)
* The February 2003 Microsoft Platform SDK (http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm) (newer SDK's do not work with MSVC6) * DirectX7.0 SDK (http://www.tt-forums.net/download.php?id=15989) (or alternatively the latest DirectX SDK from Microsoft)
* afxres.h (http://www-d0.fnal.gov/d0dist/dist/packages/d0ve/devel/windows/AFXRES.H) (maybe you not need this) * afxres.h (http://www-d0.fnal.gov/d0dist/dist/packages/d0ve/devel/windows/AFXRES.H)
...and of course the newest source from svn://svn.openttd.org/trunk ...and of course the newest source from svn://svn.openttd.com/trunk
You have to have a SVN-client to download the source: (The alpha version of the new map array can be found at svn://svn.openttd.com/branch/map)
* Command line version (Subversion 1.2.3 Win32 binaries) (http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91) You have to have and SVN-client to download the source:
* GUI TortoiseSVN (http://tortoisesvn.tigris.org/download.html)
Step 2: Includes and Libraries * Command line version (http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91)
* TortoiseSVN (http://tortoisesvn.tigris.org/download.html)
Put the newly downloaded files in the VC lib and include directories (Where "C:\Program Files\Microsoft Visual Studio\VC98" is your local location of VC)
---Step 2
Put the newly downloaded files in the VC lib and include directories (Where C:\program files\ is your local location of VC)
* zconf.h [useful.zip] * zconf.h [useful.zip]
* zlib.h [useful.zip] * zlib.h [useful.zip]
* png.h [useful.zip] * png.h [useful.zip]
* pngconf.h [useful.zip] * pngconf.h [useful.zip]
* afxres.h * afxres.h
in in
C:\Program Files\Microsoft Visual Studio\VC98\Include C:\Program Files\Microsoft Visual Studio\VC98\Include
and and
* zlibstat.lib [useful.zip] * zlibstat.lib [useful.zip]
* libpng.lib [useful.zip] * SDL.lib [SDL.zip]
* libpng.lib [useful.zip]
in in
C:\Program Files\Microsoft Visual Studio\VC98\Lib C:\Program Files\Microsoft Visual Studio\VC98\Lib
Step 3: DirectX SDK ---Step 3: DirectX SDK
(This should work with the latest DirectX SDK as well.) (This should work with the latest DirectX SDK as well.) The installation with DirectX 7 was odd, so you'd better use the version available via the forum, see also the download link on top.
There are 2 folder in the compressed file: Include and Lib There are 2 folder in the compressed file: Include and Lib
@@ -58,17 +62,16 @@ C:\Program Files\Microsoft Visual Studio\VC98\Lib
You can also make custom directories, which is recommended so you don't overwrite VS6 files, for libraries (.lib) and includes/header files (.h) and add it to the VC paths via: You can also make custom directories, for libraries (.lib) and includes/header files (.h) and add it to the VC paths via:
Tools -> Options -> Directories -> show directories for: Tools -> Options -> Directories -> show directories for:
a) include files (the include dir: C:\Program Files\Microsoft Visual Studio\VC98\DirectX 8.1 SDK\include ) a) include files (the include dir: C:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\include )
b) library files (the lib dir, C:\Program Files\Microsoft Visual Studio\VC98\DirectX 8.1 SDK\lib ) b) library files (the lib dir, C:\Program Files\Microsoft Visual Studio\VC98\DirectX 7 SDK\lib )
NOTE: make sure that the directory for the DirectX SDK is the first one in the list, above all others, otherwise compilation will most likely fail!!
Step 4: TTD Graphics files ---Step 4
Copy the following files from Transport Tycoon Deluxe to the data folder Copy the following files from Transport Tycoon Deluxe to the data folder
@@ -77,14 +80,14 @@ Copy the following files from Transport Tycoon Deluxe to the data folder
* trgcr.grf * trgcr.grf
* trghr.grf * trghr.grf
* trgir.grf * trgir.grf
* trgtr.grf * trgtr.grf
Step 5: Compiling ---Step 5
Open trunk/openttd.dsw Open trunk/ttd.dsw
Build menu > Set active configuration > Select: "openttd - Win32 Release" Build menu > Set active configuration > Select: "ttd - Win32 Release with PNG"
Compile... Compile...
@@ -93,12 +96,10 @@ Now it should work, it worked for me :)
From r1319 you can compile branch/map in Debug mode (by Bociusz) From r1319 you can compile branch/map in Debug mode (by Bociusz)
For compiling branch/cargo-packets you have to add cargo.c and .h to this tree's openttd.dsp If it's not working, and you checked that you using the newest SVN (!) report to Bociusz on IRC (irc://irc.freenode.net/#openttd)
If it's not working, and you checked that you using the newest SVN (!) report to Bociusz on IRC (irc://irc.freenode.net/openttd)
Go ahead and make that patch! Happy Hacking! :) Go ahead and make that patch! Happy Hacking! :)
Originally written by Dribbel Originally written by Dribbel
Project file updating by Bociusz Project file updating by Bociusz

View File

@@ -2,29 +2,22 @@
<html> <html>
<head> <head>
<meta name="Author" content="Marcin Grzegorczyk"> <meta name="Author" content="Marcin Grzegorczyk">
<meta name="Description" content="Structure of OpenTTD (OTTD) landscape arrays"> <meta name="Description" content="Structure of Transport Tycoon Deluxe (TTD) savegame files">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>OpenTTD Landscape Internals</title> <title>Transport Tycoon Deluxe savegame internals</title>
</head> </head>
<body> <body>
<h3><a name="Landscape">Landscape</a></h3> <h3><a name="Landscape">Landscape</a></h3>
<p> <p>
Five attributes hold the information about a tile. Five arrays are used to encode the information of the contents of each tile. These arrays are referred to as <a href="#_landscape1">map_owner</a>, <a href="#_landscape2">map2</a>, <a href="#_landscape3">map3_lo</a>, <a href="#_landscape4">type_and_height</a> and <a href="#_landscape5">map5</a>. The known encodings are listed in the table below. The most important value is the class of a tile, stored in the upper 4 bits of the type_and_height array.
These attributes are referred to as
"<span style="font-weight: bold;">type_height</span>",
"<span style="font-weight: bold;">m1</span>",
"<span style="font-weight: bold;">m2</span>",
"<span style="font-weight: bold;">m3</span>",
"<span style="font-weight: bold;">m4</span>" and
"<span style="font-weight: bold;">m5</span>".
The most important value is the class of a tile, stored in the upper 4 bits of the type_height array.
The lower 4 bits are used to encode the height and slope data.
For a graphical represenation of the tile-layout have a look at <a href="landscape_grid.html">Landscape grid</a> page.
</p> </p>
<p> <p>
OTTD's class-specific periodic tile processing routine is called once every +256 ticks for each tile. <a name="OwnershipInfo">Owner values</a> <tt>00</tt> through <tt>07</tt> are companies (they're indices into the <a href="#_CompanyArray">array of companies</a>), <tt>10</tt> is no owner, <tt>11</tt> appears to be reserved for water, <tt>80</tt> and above are towns (in this case the low 7 bits contain an index into the <a href="#_TownArray">town array</a>).
</p>
<p>
TTD's class-specific periodic tile processing routine is called once every +256 ticks for each tile.
</p> </p>
<table border=1 cellpadding=3> <table border=1 cellpadding=3>
@@ -32,7 +25,7 @@ OTTD's class-specific periodic tile processing routine is called once every +256
<tr><td valign=top nowrap><a name="Class0"><tt> 0 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class0"><tt> 0 </tt></a></td><td>
<ul> <ul>
<li>m5 bits 4..0: tile type: <li>map5 bits 4..0: tile type:
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>bare land</td></tr> <tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>bare land</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>1/3 grass</td></tr> <tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>1/3 grass</td></tr>
@@ -40,7 +33,7 @@ OTTD's class-specific periodic tile processing routine is called once every +256
<tr><td nowrap valign=top><tt>03</tt>&nbsp; </td><td align=left>full grass</td></tr> <tr><td nowrap valign=top><tt>03</tt>&nbsp; </td><td align=left>full grass</td></tr>
<tr><td nowrap valign=top><tt>07</tt>&nbsp; </td><td align=left>rough land</td></tr> <tr><td nowrap valign=top><tt>07</tt>&nbsp; </td><td align=left>rough land</td></tr>
<tr><td nowrap valign=top><tt>0B</tt>&nbsp; </td><td align=left>rocks</td></tr> <tr><td nowrap valign=top><tt>0B</tt>&nbsp; </td><td align=left>rocks</td></tr>
<tr><td nowrap valign=top><tt>0F</tt>&nbsp; </td><td align=left>fields; type of fields in m3 bits 3..0 (legal values: 0 through 9)</td></tr> <tr><td nowrap valign=top><tt>0F</tt>&nbsp; </td><td align=left>fields; type of fields in map3_lo bits 3..0 (legal values: 0 through 9)</td></tr>
<tr><td nowrap valign=top><tt>10</tt>&nbsp; </td><td align=left>1/4 snow</td></tr> <tr><td nowrap valign=top><tt>10</tt>&nbsp; </td><td align=left>1/4 snow</td></tr>
<tr><td nowrap valign=top><tt>11</tt>&nbsp; </td><td align=left>2/4 snow</td></tr> <tr><td nowrap valign=top><tt>11</tt>&nbsp; </td><td align=left>2/4 snow</td></tr>
<tr><td nowrap valign=top><tt>12</tt>&nbsp; </td><td align=left>3/4 snow</td></tr> <tr><td nowrap valign=top><tt>12</tt>&nbsp; </td><td align=left>3/4 snow</td></tr>
@@ -49,20 +42,20 @@ OTTD's class-specific periodic tile processing routine is called once every +256
<tr><td nowrap valign=top><tt>17</tt>&nbsp; </td><td align=left>full desert</td></tr> <tr><td nowrap valign=top><tt>17</tt>&nbsp; </td><td align=left>full desert</td></tr>
</table> </table>
</li> </li>
<li>m5 bits 7..5: update counter, incremented on every periodic processing for tile types other than <tt>03</tt>, <tt>07</tt>, <tt>0B</tt> and <tt>10</tt> and above, on wraparound the tile is updated (for fields, the type of fields in m3 is increased, for other types the tile type in m5 is increased) <li>map5 bits 7..6: update counter, incremented on every periodic processing for tile types other than <tt>03</tt>, <tt>07</tt>, <tt>0B</tt> and <tt>10</tt> and above, on wraparound the tile is updated (for fields, the type of fields in map3_lo is increased, for other types the tile type in map5 is increased)
<br>(for snow and desert, these bits are not used, tile is updated on every periodic processing) <br>(for snow and desert, these bits are not used, tile is updated on every periodic processing)
</li> </li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the tile (normally <tt>10</tt>) <li>map_owner: <a href="#OwnershipInfo">owner</a> of the tile (normally <tt>10</tt>)
</li> </li>
<li>m4 bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none); bits 4..2: same for the SE border <li>map3_hi bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none); bits 4..2: same for the SE border
</li> </li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class1"><tt> 1 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class1"><tt> 1 </tt></a></td><td>
m5 bit 7 clear: railway track map5 bit 7 clear: railway track
<ul> <ul>
<li>m5 bits 0..5: track layout: bit set = track present: <li>map5 bits 0..5: track layout: bit set = track present:
<table> <table>
<tr><td nowrap valign=top>bit 0: </td><td align=left>in the X direction</td></tr> <tr><td nowrap valign=top>bit 0: </td><td align=left>in the X direction</td></tr>
<tr><td nowrap valign=top>bit 1: </td><td align=left>in the Y direction</td></tr> <tr><td nowrap valign=top>bit 1: </td><td align=left>in the Y direction</td></tr>
@@ -71,9 +64,9 @@ m5 bit 7 clear: railway track
<tr><td nowrap valign=top>bit 4: </td><td align=left>in the west corner (direction N-S)</td></tr> <tr><td nowrap valign=top>bit 4: </td><td align=left>in the west corner (direction N-S)</td></tr>
<tr><td nowrap valign=top>bit 5: </td><td align=left>in the east corner (direction N-S)</td></tr> <tr><td nowrap valign=top>bit 5: </td><td align=left>in the east corner (direction N-S)</td></tr>
</table></li> </table></li>
<li>m5 bit 6 set = with signals: <li>map5 bit 6 set = with signals:
<ul> <ul>
<li>m3 bits 7..4: bit set = signal present: <li>map3_lo bits 7..4: bit set = signal present:
<ul> <ul>
<li>For track in the X direction: <li>For track in the X direction:
<table> <table>
@@ -100,8 +93,8 @@ m5 bit 7 clear: railway track
<tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the N direction on the track in the W corner</td></tr> <tr><td nowrap valign=top>bit 7: </td><td align=left>signal in the N direction on the track in the W corner</td></tr>
</table></li> </table></li>
</ul></li> </ul></li>
<li>m2 bits 7..4: bit clear = signal shows red; same bits as in m3</li> <li>map2 bits 7..4: bit clear = signal shows red; same bits as in map3_lo</li>
<li>OpenTTD bits in m4: <li>OpenTTD bits in map3_hi:
<table> <table>
<tr><td nowrap valign=top>bits 1..0: </td><td align=left>type of signal:</td></tr> <tr><td nowrap valign=top>bits 1..0: </td><td align=left>type of signal:</td></tr>
<tr><td nowrap valign=top><tt>00</tt>: </td><td align=left>normal signals</td></tr> <tr><td nowrap valign=top><tt>00</tt>: </td><td align=left>normal signals</td></tr>
@@ -111,9 +104,9 @@ m5 bit 7 clear: railway track
<tr><td nowrap valign=top>bit 2: </td><td align=left>set = semaphore signals, clear = light signals</td></tr> <tr><td nowrap valign=top>bit 2: </td><td align=left>set = semaphore signals, clear = light signals</td></tr>
</table></li> </table></li>
</ul></li> </ul></li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the track <li>map_owner: <a href="#OwnershipInfo">owner</a> of the track
</li> </li>
<li>m2 bits 0..3: <li>map2 bits 0..3:
<table> <table>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on bare land</td></tr> <tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on bare land</td></tr>
<tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on grass, no fences</td></tr> <tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on grass, no fences</td></tr>
@@ -129,64 +122,60 @@ m5 bit 7 clear: railway track
<tr><td nowrap valign=top><tt>B</tt>&nbsp; </td><td align=left>fence on the N side (track in the S corner)</td></tr> <tr><td nowrap valign=top><tt>B</tt>&nbsp; </td><td align=left>fence on the N side (track in the S corner)</td></tr>
<tr><td nowrap valign=top><tt>C</tt>&nbsp; </td><td align=left>on snow or desert</td></tr> <tr><td nowrap valign=top><tt>C</tt>&nbsp; </td><td align=left>on snow or desert</td></tr>
</table></li> </table></li>
<li>m3 bits 0..3 = <a name="TrackType">track type</a>: <tt>0</tt> - conventional railway, <tt>1</tt> - monorail, <tt>2</tt> - maglev <li>map3_lo bits 0..3 = <a name="TrackType">track type</a>: <tt>0</tt> - conventional railway, <tt>1</tt> - monorail, <tt>2</tt> - maglev
</li>
</ul> </ul>
m5 bits 7 and 6 set: railway depot / checkpoints map5 bits 7 and 6 set: railway depot / checkpoints
<ul> <ul>
<li>m5 value C0..C3: railway depot <li>map5 value C0..C3: railway depot
<br>m5 bits 1..0 - direction: exit towards: <tt>00</tt> = NE, <tt>01</tt> = SE, <tt>02</tt> = SW, <tt>03</tt> = NW</li> <br>map5 bits 1..0 - direction: exit towards: <tt>00</tt> = NE, <tt>01</tt> = SE, <tt>02</tt> = SW, <tt>03</tt> = NW</li>
<li>m5 value C4..C5: checkpoint <li>map5 value C4..C5: checkpoint
<br>bit 0: clear = in X direction, set = in Y direction <br>bit 0: clear = in X direction, set = in Y direction
<br> <br>
<br> <br>
<li>m1: <a href="#OwnershipInfo">owner</a> of the depot / checkpoint</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the depot / checkpoint</li>
<li>m2: For waypoints, index into the array of waypoints.</li> <li>map3_lo bits 0..3 = <a href="#TrackType">track type</a></li>
<li>m3 bits 0..3 = <a href="#TrackType">track type</a></li> <li>map3_lo bit 4 = use custom sprite (valid only for the checkpoint)</li>
<li>m3 bit 4 = use custom sprite (valid only for the checkpoint)</li> <li>map3_hi = custom station id</li>
<li>m4 bits 0..3 = ground type, as per m2 bits 0..3 for railway tiles.</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class2"><tt> 2 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class2"><tt> 2 </tt></a></td><td>
m5 bits 7..4 clear: road map5 bits 7..4 clear: road
<ul> <ul>
<li>m5 bits 3..0: road layout: bit set = road piece present: <li>map5 bits 3..0: road layout: bit set = road piece present:
<table> <table>
<tr><td nowrap valign=top>bit 0: </td><td align=left>NW piece</td></tr> <tr><td nowrap valign=top>bit 0: </td><td align=left>NW piece</td></tr>
<tr><td nowrap valign=top>bit 1: </td><td align=left>SW piece</td></tr> <tr><td nowrap valign=top>bit 1: </td><td align=left>SW piece</td></tr>
<tr><td nowrap valign=top>bit 2: </td><td align=left>SE piece</td></tr> <tr><td nowrap valign=top>bit 2: </td><td align=left>SE piece</td></tr>
<tr><td nowrap valign=top>bit 3: </td><td align=left>NE piece</td></tr> <tr><td nowrap valign=top>bit 3: </td><td align=left>NE piece</td></tr>
</table></li> </table></li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the road</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the road</li>
<li>m2: Index into the array of towns, 0 for non-town roads</li> <li>map2 bits 0..2: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> - paved, <tt>3</tt> - with streetlights, <tt>5</tt> - tree-lined, <tt>6</tt> - on grass with road works, <tt>7</tt> - paved with road works</li>
<li>m4 bits 0..3: counter for the roadworks</li> <li>map3_hi bit 7 set = on snow or desert</li>
<li>m4 bits 4..6: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> - paved, <tt>3</tt> - with streetlights, <tt>5</tt> - tree-lined, <tt>6</tt> - on grass with road works, <tt>7</tt> - paved with road works</li>
<li>m4 bit 7 set = on snow or desert</li>
</ul> </ul>
m5 bit 4 set, bits 7..5 clear: level crossing map5 bit 4 set, bits 7..5 clear: level crossing
<ul> <ul>
<li>m5 bit 3: clear - road in the X direction, set - road in the Y direction (railway track always perpendicular)</li> <li>map5 bit 3: clear - road in the X direction, set - road in the Y direction (railway track always perpendicular)</li>
<li>m5 bit 2: set if crossing lights are on</li> <li>map5 bit 2: set if crossing lights are on</li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the railway track</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the railway track</li>
<li>m2: Index into the array of towns, 0 for non-town roads</li> <li>map2 bits 0..2: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> or higher - paved</li>
<li>m3 bits 0..7: <a href="#OwnershipInfo">owner</a> of the road</li> <li>map3_lo bits 0..7: <a href="#OwnershipInfo">owner</a> of the road</li>
<li>m4 bits 3..0: <a href="#TrackType">track type</a></li> <li>map3_hi bits 3..0: <a href="#TrackType">track type</a></li>
<li>m4 bits 4..6: <tt>0</tt> - on bare land, <tt>1</tt> - on grass, <tt>2</tt> or higher - paved</li> <li>map3_hi bit 7 set = on snow or desert</li>
<li>m4 bit 7 set = on snow or desert</li>
</ul> </ul>
m5 bit 5 set: road depot map5 bit 5 set: road depot
<ul> <ul>
<li>m5 bits 3..0 - direction: exit towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li> <li>map5 bits 3..0 - direction: exit towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the depot</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the depot</li>
<li>m4 bit 7 set = on snow or desert (not displayed, but set internally)</li> <li>map3_hi bit 7 set = on snow or desert (not displayed, but set internally)</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class3"><tt> 3 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class3"><tt> 3 </tt></a></td><td>
Town building Town building
<ul> <ul>
<li>m2: Index into the array of towns</li> <li>map2: <a name="HouseTypes">town building type</a>:
<li>m4: <a name="HouseTypes">town building type</a>:
<p><small>Note: In the climate list, 'sub-arctic' means below the <a href="#_snowline">snow line</a>, and 'snow' means above the snow line in the sub-arctic climate.</small></p> <p><small>Note: In the climate list, 'sub-arctic' means below the <a href="#_snowline">snow line</a>, and 'snow' means above the snow line in the sub-arctic climate.</small></p>
<table> <table>
<tr><th align=left>Type&nbsp;</th><th align=left>Size&nbsp;</th><th align=left>Climates&nbsp;</th><th align=left>Description</th></tr> <tr><th align=left>Type&nbsp;</th><th align=left>Size&nbsp;</th><th align=left>Climates&nbsp;</th><th align=left>Description</th></tr>
@@ -276,13 +265,13 @@ Town building
<tr><td nowrap valign=top><tt>6D</tt>&nbsp; </td><td>1&times;1</td><td>toyland</td><td align=left>piggy-bank</td></tr> <tr><td nowrap valign=top><tt>6D</tt>&nbsp; </td><td>1&times;1</td><td>toyland</td><td align=left>piggy-bank</td></tr>
<tr><td colspan=2></td></tr> <!-- spacer -- -- (and I don't mean a walk) --> <tr><td colspan=2></td></tr> <!-- spacer -- -- (and I don't mean a walk) -->
</table></li> </table></li>
<li>m3 bits 7..6: stage of construction (<tt>3</tt> = completed)</li> <li>map3_lo bits 7..6: stage of construction (<tt>3</tt> = completed)</li>
<li>m5 bits 2..0: construction counter, for buildings under construction incremented on every periodic tile processing, on wraparound the stage of construction in m3 is increased</li> <li>map5 bits 2..0: construction counter, for buildings under construction incremented on every periodic tile processing, on wraparound the stage of construction in map3_lo is increased</li>
<li>for large office blocks (types <tt>04</tt> and <tt>05</tt>): <li>for large office blocks (types <tt>04</tt> and <tt>05</tt>):
<ul> <ul>
<li>m1 bits 6..0: position of the lift</li> <li>map_owner bits 6..0: position of the lift</li>
<li>m1 bit 7: if set the lift is moving</li> <li>map_owner bit 7: if set the lift is moving</li>
<li>m5 bit 7: if set then m5 bits 5..0 hold the destination floor of the lift, which could be 0..6, except 1, so the building has 6 effective floors. This due to the fact that the first floor is 2 'normal' floors high. One 'normal' floor has a height of 6 lift positions.</li> <li>map5 bit 7: if set then map5 bits 5..0 hold the final position of the lift divided by 6 (valid values 0..6 except 1)</li>
</ul></li> </ul></li>
</ul> </ul>
</td></tr> </td></tr>
@@ -290,9 +279,9 @@ Town building
<tr><td valign=top nowrap><a name="Class4"><tt> 4 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class4"><tt> 4 </tt></a></td><td>
Trees Trees
<ul> <ul>
<li>m5 bits 7..6: number of trees minus one</li> <li>map5 bits 7..6: number of trees minus one</li>
<li>m5 bits 2..0: growth status: <tt>0</tt>..<tt>2</tt> - one of trees is growing, <tt>3</tt> - all trees are fully grown, <tt>4</tt>..<tt>6</tt> - one of trees is withering</li> <li>map5 bits 2..0: growth status: <tt>0</tt>..<tt>2</tt> - one of trees is growing, <tt>3</tt> - all trees are fully grown, <tt>4</tt>..<tt>6</tt> - one of trees is withering</li>
<li>m3 bits 7..0: type of trees: <li>map3_lo bits 7..0: type of trees:
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>0B</tt>&nbsp; </td><td align=left>temperate climate trees</td></tr> <tr><td nowrap valign=top><tt>00</tt>..<tt>0B</tt>&nbsp; </td><td align=left>temperate climate trees</td></tr>
<tr><td nowrap valign=top><tt>0C</tt>..<tt>13</tt>&nbsp; </td><td align=left>sub-arctic climate trees</td></tr> <tr><td nowrap valign=top><tt>0C</tt>..<tt>13</tt>&nbsp; </td><td align=left>sub-arctic climate trees</td></tr>
@@ -303,24 +292,24 @@ Trees
</table> </table>
(note: the actually displayed set of trees depends on both type and number of trees) (note: the actually displayed set of trees depends on both type and number of trees)
</li> </li>
<li>m4 bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none)</li> <li>map3_hi bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none)</li>
<li>m4 bits 4..2: type of hedge on the SE border of the tile (1 through 6, or 0=none)</li> <li>map3_hi bits 4..2: type of hedge on the SE border of the tile (1 through 6, or 0=none)</li>
<li>m2 bits 5..4: <li>map2 bits 5..4:
<table> <table>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on grass</td></tr> <tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=left>on grass</td></tr>
<tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on rough land</td></tr> <tr><td nowrap valign=top><tt>1</tt>&nbsp; </td><td align=left>on rough land</td></tr>
<tr><td nowrap valign=top><tt>2</tt>&nbsp; </td><td align=left>on snow or desert; m2 bits 7..6 - amount of snow or desert (for desert always set to 3 in TTD) <tr><td nowrap valign=top><tt>2</tt>&nbsp; </td><td align=left>on snow or desert; map2 bits 7..6 - amount of snow or desert (for desert always set to 3 in TTD)
</td></tr> </td></tr>
</table></li> </table></li>
<li>m2 bits 3..0: update counter, incremented on every periodic processing, on wraparound the growth status is updated (or, if it's <tt>3</tt>, a random action is taken)</li> <li>map2 bits 3..0: update counter, incremented on every periodic processing, on wraparound the growth status is updated (or, if it's <tt>3</tt>, a random action is taken)</li>
<li>m1: <a href="#OwnershipInfo">owner</a> (normally <tt>10</tt>)</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> (normally <tt>10</tt>)</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class5"><tt> 5 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class5"><tt> 5 </tt></a></td><td>
Station tile Station tile
<ul> <ul>
<li>m5: tile type: <li>map5: tile type:
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>07</tt>&nbsp; </td><td align=left>railway station <tr><td nowrap valign=top><tt>00</tt>..<tt>07</tt>&nbsp; </td><td align=left>railway station
<br><tt>00</tt>..<tt>01</tt> - open platform, <tt>02</tt>..<tt>03</tt> - open platform with station building, <tt>04</tt>....<tt>07</tt> - roofed platform <br><tt>00</tt>..<tt>01</tt> - open platform, <tt>02</tt>..<tt>03</tt> - open platform with station building, <tt>04</tt>....<tt>07</tt> - roofed platform
@@ -378,17 +367,17 @@ exit towards: <tt>47</tt> - NE, <tt>48</tt> - SE, <tt>49</tt> - SW, <tt>4A</tt>
<tr><td colspan=2></td></tr> <!-- spacer --> <tr><td colspan=2></td></tr> <!-- spacer -->
</table> </table>
</li> </li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the station</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the station</li>
<li>m2: index into the <a href="#_StationArray">array of stations</a></li> <li>map2: index into the <a href="#_StationArray">array of stations</a></li>
<li>m3 bits 0..3: <a href="#TrackType">track type</a> for railway stations, must be 0 for all the other stations</li> <li>map3_lo bits 0..3: <a href="#TrackType">track type</a> for railway stations, must be 0 for all the other stations</li>
<li>m3 bit 4 = use custom sprite (valid only railway stations FOR NOW)</li> <li>map3_lo bit 4 = use custom sprite (valid only railway stations FOR NOW)</li>
<li>m4 = custom station id</li> <li>map3_hi = custom station id</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class6"><tt> 6 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class6"><tt> 6 </tt></a></td><td>
<ul> <ul>
<li>m5: tile type: <li>map5: tile type:
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>water</td></tr> <tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>water</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>coast or riverbank</td></tr> <tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>coast or riverbank</td></tr>
@@ -419,7 +408,7 @@ exit towards: <tt>47</tt> - NE, <tt>48</tt> - SE, <tt>49</tt> - SW, <tt>4A</tt>
</table> </table>
</td></tr> </td></tr>
</table></li> </table></li>
<li>m1: <a href="#OwnershipInfo">owner</a> (for water and coasts normally <tt>11</tt>)</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> (for water and coasts normally <tt>11</tt>)</li>
</ul> </ul>
</td></tr> </td></tr>
@@ -433,19 +422,19 @@ Tiles of this class form an invisible, one tile wide border at the south (bottom
<tr><td valign=top nowrap><a name="Class8"><tt> 8 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class8"><tt> 8 </tt></a></td><td>
Industry tile Industry tile
<ul> <ul>
<li>m5: type: <li>map5: type:
<br><small>(note: this is not the same as the <a href="#industry.type">industry type</a> stored in the <a href="#_IndustryArray">array of industries</a>)</small> <br><small>(note: this is not the same as the <a href="#industry.type">industry type</a> stored in the <a href="#_IndustryArray">array of industries</a>)</small>
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>..<tt>06</tt>&nbsp; </td><td align=left>coal mine <tr><td nowrap valign=top><tt>00</tt>..<tt>06</tt>&nbsp; </td><td align=left>coal mine
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr> <tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in m1 bits 5..0; m1 bit 6 set = sound already generated</td></tr> <tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>07</tt>..<tt>0A</tt>&nbsp; </td><td align=left>power station <tr><td nowrap valign=top><tt>07</tt>..<tt>0A</tt>&nbsp; </td><td align=left>power station
<table> <table>
<tr><td nowrap valign=top><tt>08</tt>&nbsp; </td><td align=left>chimney</td></tr> <tr><td nowrap valign=top><tt>08</tt>&nbsp; </td><td align=left>chimney</td></tr>
<tr><td nowrap valign=top><tt>0A</tt>&nbsp; </td><td align=left>transformer; animation progress in m1 bits 5..2 (valid range <tt>0</tt>..<tt>7</tt>)</td></tr> <tr><td nowrap valign=top><tt>0A</tt>&nbsp; </td><td align=left>transformer; animation progress in map_owner bits 5..2 (valid range <tt>0</tt>..<tt>7</tt>)</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>0B</tt>..<tt>0F</tt>&nbsp; </td><td align=left>sawmill</td></tr> <tr><td nowrap valign=top><tt>0B</tt>..<tt>0F</tt>&nbsp; </td><td align=left>sawmill</td></tr>
@@ -459,7 +448,7 @@ Industry tile
<tr><td nowrap valign=top><tt>1D</tt>..<tt>20</tt>&nbsp; </td><td align=left>oil wells <tr><td nowrap valign=top><tt>1D</tt>..<tt>20</tt>&nbsp; </td><td align=left>oil wells
<table> <table>
<tr><td nowrap valign=top><tt>1D</tt>&nbsp; </td><td align=left>not animated</td></tr> <tr><td nowrap valign=top><tt>1D</tt>&nbsp; </td><td align=left>not animated</td></tr>
<tr><td nowrap valign=top><tt>1E</tt>..<tt>20</tt>&nbsp; </td><td align=left>various stages of animation; progress of animation in m1 bits 1..0</td></tr> <tr><td nowrap valign=top><tt>1E</tt>..<tt>20</tt>&nbsp; </td><td align=left>various stages of animation; progress of animation in map_owner bits 1..0</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>21</tt>..<tt>26</tt>&nbsp; </td><td align=left>farm</td></tr> <tr><td nowrap valign=top><tt>21</tt>..<tt>26</tt>&nbsp; </td><td align=left>farm</td></tr>
@@ -468,7 +457,7 @@ Industry tile
<tr><td nowrap valign=top><tt>2F</tt>..<tt>33</tt>&nbsp; </td><td align=left>copper ore mine <tr><td nowrap valign=top><tt>2F</tt>..<tt>33</tt>&nbsp; </td><td align=left>copper ore mine
<table> <table>
<tr><td nowrap valign=top><tt>2F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr> <tr><td nowrap valign=top><tt>2F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>30</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in m1 bits 5..0; m1 bit 6 set = sound already generated</td></tr> <tr><td nowrap valign=top><tt>30</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
<tr><td nowrap valign=top><tt>31</tt>&nbsp; </td><td align=left>chimney</td></tr> <tr><td nowrap valign=top><tt>31</tt>&nbsp; </td><td align=left>chimney</td></tr>
</table> </table>
</td></tr> </td></tr>
@@ -479,7 +468,7 @@ Industry tile
<tr><td nowrap valign=top><tt>48</tt>..<tt>58</tt>&nbsp; </td><td align=left>gold mine <tr><td nowrap valign=top><tt>48</tt>..<tt>58</tt>&nbsp; </td><td align=left>gold mine
<table> <table>
<tr><td nowrap valign=top><tt>4F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr> <tr><td nowrap valign=top><tt>4F</tt>&nbsp; </td><td align=left>wheel tower when not animated</td></tr>
<tr><td nowrap valign=top><tt>58</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in m1 bits 5..0; m1 bit 6 set = sound already generated</td></tr> <tr><td nowrap valign=top><tt>58</tt>&nbsp; </td><td align=left>wheel tower when animated; animation state in map_owner bits 5..0; map_owner bit 6 set = sound already generated</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>59</tt>..<tt>5A</tt>&nbsp; </td><td align=left>bank (sub-arctic or sub-tropical climate)</td></tr> <tr><td nowrap valign=top><tt>59</tt>..<tt>5A</tt>&nbsp; </td><td align=left>bank (sub-arctic or sub-tropical climate)</td></tr>
@@ -506,9 +495,9 @@ Industry tile
<tr><td nowrap valign=top><tt>8A</tt>..<tt>8D</tt>&nbsp; </td><td align=left>toy shop</td></tr> <tr><td nowrap valign=top><tt>8A</tt>..<tt>8D</tt>&nbsp; </td><td align=left>toy shop</td></tr>
<tr><td nowrap valign=top><tt>8E</tt>..<tt>93</tt>&nbsp; </td><td align=left>toy factory <tr><td nowrap valign=top><tt>8E</tt>..<tt>93</tt>&nbsp; </td><td align=left>toy factory
<table> <table>
<tr><td nowrap valign=top><tt>8F</tt>&nbsp; </td><td align=left>animated part; animation state in m3 (valid range <tt>00</tt>..<tt>31</tt>)<br> <tr><td nowrap valign=top><tt>8F</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>31</tt>)<br>
tile animation is started (m4 zeroed) on the periodic processing if <a href="#industry.didtransform">field <tt>2C</tt></a> in the corresponding industry array entry is nonzero<br> tile animation is started (map3_hi zeroed) on the periodic processing if <a href="#industry.didtransform">field <tt>2C</tt></a> in the corresponding industry array entry is nonzero<br>
while the animation is in progress (see the <a href="#_AnimatedTilesList">array at <tt>04328</tt></a>) m4 holds the number of animation cycles that have already taken place; when this number reaches 8 the animation is stopped</td></tr> while the animation is in progress (see the <a href="#_AnimatedTilesList">array at <tt>04328</tt></a>) map3_hi holds the number of animation cycles that have already taken place; when this number reaches 8 the animation is stopped</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>94</tt>..<tt>9B</tt>&nbsp; </td><td align=left>plastic fountains (various stages of cyclic animation)</td></tr> <tr><td nowrap valign=top><tt>94</tt>..<tt>9B</tt>&nbsp; </td><td align=left>plastic fountains (various stages of cyclic animation)</td></tr>
@@ -516,69 +505,69 @@ while the animation is in progress (see the <a href="#_AnimatedTilesList">array
<tr><td nowrap valign=top><tt>A0</tt>..<tt>A3</tt>&nbsp; </td><td align=left>bubble generator <tr><td nowrap valign=top><tt>A0</tt>..<tt>A3</tt>&nbsp; </td><td align=left>bubble generator
<table> <table>
<tr><td nowrap valign=top><tt>A1</tt>&nbsp; </td><td align=left>generators</td></tr> <tr><td nowrap valign=top><tt>A1</tt>&nbsp; </td><td align=left>generators</td></tr>
<tr><td nowrap valign=top><tt>A2</tt>&nbsp; </td><td align=left>bubble capture facility; animation state in m3 (valid range <tt>00</tt>..<tt>27</tt>)</td></tr> <tr><td nowrap valign=top><tt>A2</tt>&nbsp; </td><td align=left>bubble capture facility; animation state in map3_lo (valid range <tt>00</tt>..<tt>27</tt>)</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>A4</tt>..<tt>A6</tt>&nbsp; </td><td align=left>toffee quarry <tr><td nowrap valign=top><tt>A4</tt>..<tt>A6</tt>&nbsp; </td><td align=left>toffee quarry
<table> <table>
<tr><td nowrap valign=top><tt>A5</tt>&nbsp; </td><td align=left>animated part; animation state in m3 (valid range <tt>00</tt>..<tt>45</tt>)</td></tr> <tr><td nowrap valign=top><tt>A5</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>45</tt>)</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td nowrap valign=top><tt>A7</tt>..<tt>AE</tt>&nbsp; </td><td align=left>sugar mine <tr><td nowrap valign=top><tt>A7</tt>..<tt>AE</tt>&nbsp; </td><td align=left>sugar mine
<table> <table>
<tr><td nowrap valign=top><tt>AE</tt>&nbsp; </td><td align=left>animated part; animation state in m3 (valid range <tt>00</tt>..<tt>5F</tt>)</td></tr> <tr><td nowrap valign=top><tt>AE</tt>&nbsp; </td><td align=left>animated part; animation state in map3_lo (valid range <tt>00</tt>..<tt>5F</tt>)</td></tr>
</table> </table>
</td></tr> </td></tr>
<tr><td colspan=2></td></tr> <!-- spacer --> <tr><td colspan=2></td></tr> <!-- spacer -->
</table></li> </table></li>
<li>m2: index into the <a href="#_IndustryArray">array of industries</a> <li>map2: index into the <a href="#_IndustryArray">array of industries</a>
</li> </li>
<li>m1 bit 7: clear = under construction <li>map_owner bit 7: clear = under construction
<ul> <ul>
<li>m1 bits 4..2: construction counter, for buildings under construction incremented on every periodic tile processing <li>map_owner bits 4..2: construction counter, for buildings under construction incremented on every periodic tile processing
</li> </li>
</ul></li> </ul></li>
<li>m1 bits 1..0: stage of construction (<tt>3</tt> = completed), incremented when the construction counter wraps around <li>map_owner bits 1..0: stage of construction (<tt>3</tt> = completed), incremented when the construction counter wraps around
<br>the meaning is different for some animated tiles which are never under construction (types <tt>01</tt>, <tt>1E</tt>..<tt>20</tt>, <tt>30</tt>, <tt>58</tt>; see above) <br>the meaning is different for some animated tiles which are never under construction (types <tt>01</tt>, <tt>1E</tt>..<tt>20</tt>, <tt>30</tt>, <tt>58</tt>; see above)
</li> </li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="Class9"><tt> 9 </tt></a></td><td> <tr><td valign=top nowrap><a name="Class9"><tt> 9 </tt></a></td><td>
m5 bits 7..4 clear: tunnel entrance/exit map5 bits 7..4 clear: tunnel entrance/exit
<ul> <ul>
<li>m5 bits 3..2: <tt>0</tt> - railway tunnel, <tt>1</tt> - road tunnel</li> <li>map5 bits 3..2: <tt>0</tt> - railway tunnel, <tt>1</tt> - road tunnel</li>
<li>m5 bits 1..0 - direction: entrance towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li> <li>map5 bits 1..0 - direction: entrance towards: <tt>0</tt> = NE, <tt>1</tt> = SE, <tt>2</tt> = SW, <tt>3</tt> = NW</li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the tunnel</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the tunnel</li>
<li>m3 bits 3..0 = <a href="#TrackType">track type</a> for railway tunnel, must be 0 for road tunnel</li> <li>map3_lo bits 3..0 = <a href="#TrackType">track type</a> for railway tunnel, must be 0 for road tunnel</li>
<li>m4 bit 7 set = on snow or desert</li> <li>map3_hi bit 7 set = on snow or desert</li>
</ul> </ul>
m5 bit 7 set: bridge map5 bit 7 set: bridge
<ul><li> <ul><li>
m5 bit 6 clear: bridge ending map5 bit 6 clear: bridge ending
<ul> <ul>
<li>m5 bit 5: clear - northern, set - southern ending</li> <li>map5 bit 5: clear - northern, set - southern ending</li>
<li>m3 bits 3..0 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li> <li>map3_lo bits 3..0 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the bridge</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the bridge</li>
</ul> </ul>
m5 bit 6 set: bridge middle part map5 bit 6 set: bridge middle part
<ul> <ul>
<li>m5 bit 5 clear: <li>map5 bit 5 clear:
<ul> <ul>
<li>m5 bits 4..3: land under bridge: <tt>0</tt> - grass, snow or desert, <tt>1</tt> - water</li> <li>map5 bits 4..3: land under bridge: <tt>0</tt> - grass, snow or desert, <tt>1</tt> - water</li>
</ul> </ul>
m5 bit 5 set: map5 bit 5 set:
<ul> <ul>
<li>m5 bits 4..3: transport route under bridge: <tt>0</tt> - railway, <tt>1</tt> - road</li> <li>map5 bits 4..3: transport route under bridge: <tt>0</tt> - railway, <tt>1</tt> - road</li>
</ul> </ul>
<li>m3 bits 7..4 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li> <li>map3_lo bits 7..4 = <a href="#TrackType">type of track</a> on the bridge, must be 0 for road bridge</li>
<li>m3 bits 3..0 = <a href="#TrackType">type of track</a> under the bridge, if any</li> <li>map3_lo bits 3..0 = <a href="#TrackType">type of track</a> under the bridge, if any</li>
<li>m2 bits 3..0: bridge piece (<tt>0</tt>..<tt>5</tt>) <li>map2 bits 3..0: bridge piece (<tt>0</tt>..<tt>5</tt>)
<li>m1: <a href="#OwnershipInfo">owner</a> of the land under bridge</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the land under bridge</li>
</ul></li> </ul></li>
<li>m5 bits 2..1: <tt>0</tt> - railway bridge, <tt>1</tt> - road bridge</li> <li>map5 bits 2..1: <tt>0</tt> - railway bridge, <tt>1</tt> - road bridge</li>
<li>m5 bit 0: clear - bridge in the X direction, set - bridge in the Y direction</li> <li>map5 bit 0: clear - bridge in the X direction, set - bridge in the Y direction</li>
<li>m2 bits 7..4: <a name="BridgeType">bridge type</a>: <li>map2 bits 7..4: <a name="BridgeType">bridge type</a>:
<table> <table>
<tr><th align=left>Type&nbsp;</th><th align=left>Max. speed (mph)&nbsp;</th><th align=left>Description</th></tr> <tr><th align=left>Type&nbsp;</th><th align=left>Max. speed (mph)&nbsp;</th><th align=left>Description</th></tr>
<tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=center>20</td><td align=left>wooden</td></tr> <tr><td nowrap valign=top><tt>0</tt>&nbsp; </td><td align=center>20</td><td align=left>wooden</td></tr>
@@ -593,13 +582,13 @@ m5 bit 5 set:
<tr><td nowrap valign=top><tt>9</tt>&nbsp; </td><td align=center>160</td><td align=left>girder, steel</td></tr> <tr><td nowrap valign=top><tt>9</tt>&nbsp; </td><td align=center>160</td><td align=left>girder, steel</td></tr>
<tr><td nowrap valign=top><tt>A</tt>&nbsp; </td><td align=center>200</td><td align=left>tubular, steel</td></tr> <tr><td nowrap valign=top><tt>A</tt>&nbsp; </td><td align=center>200</td><td align=left>tubular, steel</td></tr>
</table></li> </table></li>
<li>m4 bit 7 set = on snow or desert</li> <li>map3_hi bit 7 set = on snow or desert</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td valign=top nowrap><a name="ClassA"><tt> A </tt></a></td><td> <tr><td valign=top nowrap><a name="ClassA"><tt> A </tt></a></td><td>
<ul> <ul>
<li>m5: tile type: <li>map5: tile type:
<table> <table>
<tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>transmitter</td></tr> <tr><td nowrap valign=top><tt>00</tt>&nbsp; </td><td align=left>transmitter</td></tr>
<tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>lighthouse</td></tr> <tr><td nowrap valign=top><tt>01</tt>&nbsp; </td><td align=left>lighthouse</td></tr>
@@ -608,18 +597,18 @@ m5 bit 5 set:
<tr><td nowrap valign=top><tt>80</tt>..<tt>93</tt>&nbsp; </td><td align=left>company headquarters (5 sets of 4 tiles each, updated quarterly depending on the company performance)</td></tr> <tr><td nowrap valign=top><tt>80</tt>..<tt>93</tt>&nbsp; </td><td align=left>company headquarters (5 sets of 4 tiles each, updated quarterly depending on the company performance)</td></tr>
</table> </table>
</li> </li>
<li>m1: <a href="#OwnershipInfo">owner</a> of the object (for lighthouses and transmitters normally <tt>10</tt>)</li> <li>map_owner: <a href="#OwnershipInfo">owner</a> of the object (for lighthouses and transmitters normally <tt>10</tt>)</li>
</ul> </ul>
</td></tr> </td></tr>
<tr><td colspan=2> <tr><td colspan=2>
Classes <tt>B</tt> through <tt>F</tt> are reserved. The presence of a tile in one of the reserved classes will crash OTTD. Classes <tt>B</tt> through <tt>F</tt> are reserved. The presence of a tile in one of the reserved classes will crash TTD.
</td></tr> </td></tr>
</table> </table>
<hr> <hr>
Original Copyright &copy; 2003 by Marcin Grzegorczyk for TTDLX.<br> Copyright &copy; 2003 by Marcin Grzegorczyk.<br>
Transport Tycoon and Transport Tycoon Deluxe are Copyright &copy; by Chris Sawyer. All the other trademarks are the property of their respective owners.<br> Transport Tycoon and Transport Tycoon Deluxe are Copyright &copy; by Chris Sawyer. All the other trademarks are the property of their respective owners.<br>
</body> </body>

View File

@@ -1,251 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<meta name="Description" content="Structure of OpenTTD (OTTD) landscape arrays #2">
<title>OpenTTD Landscape Internals - #2</title>
<style type="text/css">
span.abuse { font-family: "Courier New", Courier, mono; background-color: rgb(255, 58, 31); }
span.free { font-family: "Courier New", Courier, mono; background-color: rgb(30, 178, 54); }
span.used { font-family: "Courier New", Courier, mono; }
td.bits { white-space: nowrap; text-align: center; font-family: "Courier New", Courier, mono; }
td.caption { white-space: nowrap; text-align: left; }
td li { white-space: nowrap; text-align: left; }
th { white-space: nowrap; text-align: center; }
</style>
</head>
<body style="direction: ltr;">
<h3 style="font-weight: bold;">Landscape</h3>
<span style="font-weight: bold;"></span>Five attributes hold the information about a tile.
This can be seen in the <a href="landscape.html">Landscape</a> document. This page tries to give an overview of used and free bits of
the array so you can quickly see what is used and what is not.
<ul>
<li><span style="font-weight: bold;"><span class="free">O</span></span> - bit is free</li>
<li><span style="font-weight: bold;"><span class="used">X</span></span> - bit is used</li>
<li><span style="font-weight: bold;"><span class="abuse">&nbsp;</span></span> - bit of attribute is abused for different purposes</li>
</ul>
<p>
<ul>
<li><span style="font-weight: bold;">type_height</span> - 8 bits in size, stores tile height (lower 4 bits) and tile class (upper 4 bits)</li>
<li><span style="font-weight: bold;">m1</span> - 8 bits in size, used to identify the owner of that tile (eg piece of rail, bridge, etc.)</li>
<li><span style="font-weight: bold;">m2</span> - 16 bits in size, used to identify the index of the given tile (object) in the (object-)array</li>
<li><span style="font-weight: bold;">m3</span> - 8 bits in size, is used for general storage</li>
<li><span style="font-weight: bold;">m4</span> - 8 bits in size, is used for general storage</li>
<li><span style="font-weight: bold;">m5</span> - 8 bits in size, is used for general storage</li>
</ul>
<table align=center border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<th colspan=2>class</th>
<th>m1 (8)</th>
<th>m2 (16)</th>
<th>m3 (8)</th>
<th>m4 (8)</th>
<th>type_height (8)</th>
<th>m5 (8)</th>
</tr>
<tr>
<td colspan=2 class="caption">bits</td>
<td class="bits">7654 3210</td>
<td class="bits">FEDC BA98 7654 3210</td>
<td class="bits">7654 3210</td>
<td class="bits">7654 3210</td>
<td class="bits">7654 3210</td>
<td class="bits">7654 3210</td>
</tr>
<tr>
<td>0</td>
<td class="caption">ground</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td rowspan=3>1</td>
<td class="caption">rail</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span> XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO O</span>XXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td class="caption">depot</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
</tr>
<tr>
<td class="caption">waypoint</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOO</span>X XXXX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
</tr>
<tr>
<td rowspan=3>2</td>
<td class="caption">road</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td class="caption">level crossing</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XX<span class="free">OO</span></td>
</tr>
<tr>
<td class="caption">road depot</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>3</td>
<td class="caption">town</td>
<td class="bits"><span class="abuse">XXXX XXXX</span></td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">X<span class="free">O</span>XX XXXX</td>
</tr>
<tr>
<td>4</td>
<td class="caption">trees</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span> XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO O</span>XXX</td>
</tr>
<tr>
<td>5</td>
<td class="caption">station</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOO</span>X XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>6</td>
<td class="caption">water</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td rowspan=6>8</td>
<td class="caption">industry</td>
<td class="bits"><span class="abuse">X</span><span class="free">OO</span><span class="abuse">X XXXX</span></td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>bubble/sugar/toffee</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>toy factory</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>gold/copper/coal</td>
<td class="bits"><span class="abuse">XX</span><span class="free">OO OO</span><span class="abuse">XX</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>oil wells</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OO</span><span class="abuse">XX</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>power station</td>
<td class="bits"><span class="abuse">X</span><span class="free">O</span><span class="abuse">XX XX</span><span class="free">OO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td rowspan=2>9</td>
<td class="caption">tunnel</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>bridge</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX XXXX</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>A</td>
<td class="caption">various (HQ)</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@@ -1,68 +1,50 @@
.\" Hey, EMACS: -*- nroff -*- .\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH OPENTTD 6 "September 16, 2004"
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.Dd March 26, 2006 .\"
.Dt OPENTTD 6 .\" Some roff macros, for reference:
.Sh NAME .\" .nh disable hyphenation
.Nm openttd .\" .hy enable hyphenation
.Nd An open source clone of the Microprose game "Transport Tycoon Deluxe" .\" .ad l left justify
.Sh SYNOPSIS .\" .ad b justify to both left and right margins
.Nm .\" .nf disable filling
.Op Fl Defhi .\" .fi enable filling
.Op Fl G Ar seed .\" .br insert line break
.Op Fl d Ar [level | cat=lvl[, ...]] .\" .sp <n> insert n+1 empty lines
.Op Fl g Ar [savegame] .\" for manpage-specific macros, see man(7)
.Op Fl n Ar [host[#player][:port]] .SH NAME
.Op Fl r Ar widthxheight openttd \- An open source clone of the Microprose game "Transport Tycoon Deluxe"
.Op Fl t Ar date .SH SYNOPSIS
.Op Fl m Ar driver .B openttd
.Op Fl s Ar driver .RI [ options ]
.Op Fl v Ar driver .br
.Sh OPTIONS .SH DESCRIPTION
.Bl -tag -width ".Fl n Ar host[#player][:port]" Unfortunately, there is no real manpage for openttd yet. Hopefully someone
.It Fl D will write one soon. For now you should use
Start a dedicated server .B openttd -h
.It Fl G Ar seed for more information, or check our Wiki manual: http://wiki.openttd.org/
Seed the pseudo random number generator .PP
.It Fl d Ar [level] .\" TeX users may be more comfortable with the \fB<whatever>\fP and
Set debug verbosity for all categories to .\" \fI<whatever>\fP escape sequences to invoke bold face and italics,
.Ar level .\" respectively.
or 1 if omitted .\" \fBopenttd\fP is a program that...
.It Fl d Ar cat=level[, ...] .SH OPTIONS
Set debug verbosity for a specific category Wouldn't we like to have something here?
.It Fl e .\" below are commented out, to serve as layout examples for when somebody
Start in world editor mode .\" does actually fill this page
.It Fl f .\" .TP
Fork into background (dedicated only, see .\" .B \-h, \-\-help
.Fl D ) .\" Show summary of options.
.It Fl g Ar [savegame] .\" .TP
Load .\" .B \-v, \-\-version
.Ar savegame .\" Show version of program.
at start or start a new game if omitted .\" .SH SEE ALSO
.It Fl h .\" .BR bar (1),
Display a summary of all options and available drivers .\" .BR baz (1).
.It Fl i .br
Force to use the DOS palette (use this if you see a lot of magenta) .SH AUTHOR
.It Fl m Ar driver This manual page was written by Matthijs Kooijman <matthijs@katherina.student.utwente.nl>,
Set the music driver, see for the Debian project (but may be used by others).
.Fl h
.It Fl n
Start a network server
.It Fl n Ar host[#player][:port]
Join a network game, optionally specify player to play as and port to connect to
.It Fl r Ar widthxheight
Set the resolution
.It Fl s Ar driver
Set the sound driver, see
.Fl h
.It Fl t Ar date
Set the starting date
.It Fl v Ar driver
Set the video driver, see
.Fl h
.El
.Sh SEE ALSO
http://wiki.openttd.org/
.Sh HISTORY
Transport Tycoon Deluxe was written by Chris Sawyer and published by Microprose.
.Nm
is a free reimplementation.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

38
docs/textcolor.txt Normal file
View File

@@ -0,0 +1,38 @@
0,9,10,2,3,13,9,9,0,10,4,15,6,11,14,1
dark blue=0 =0
pale_green=1 =9
pink=2 =10
yellow=3 =2
red=4 =3
light blue=5 =13
green=6 =9
dark green=7 =9
blue=8 =0
cream=9 =10
mauve=10 =4
purple=11 =15
orange=12 =6
brown=13 =11
grey=14 =14
white=15 =1
=blue=0
=white=1
=yellow=2
=red=3
=blue=4
=grey=5
=orange=6
=green=7
=light yellow=8
=light green=9
=cream=10
=brown=11
=white=12
=light blue=13
=dark grey=14
=purple=15
=black=16
=dark green=17=not good
=dark grey=21

224
driver.c
View File

@@ -1,224 +0,0 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "driver.h"
#include "functions.h"
#include "hal.h"
#include "string.h"
#include "music/bemidi.h"
#include "music/dmusic.h"
#include "music/extmidi.h"
#include "music/null_m.h"
#include "music/os2_m.h"
#include "music/win32_m.h"
#include "music/qtmidi.h"
#include "sound/null_s.h"
#include "sound/sdl_s.h"
#include "sound/cocoa_s.h"
#include "sound/win32_s.h"
#include "video/dedicated_v.h"
#include "video/null_v.h"
#include "video/sdl_v.h"
#include "video/cocoa_v.h"
#include "video/win32_v.h"
typedef struct DriverDesc {
const char* name;
const char* longname;
const HalCommonDriver* drv;
} DriverDesc;
typedef struct DriverClass {
const DriverDesc *descs;
const char *name;
const HalCommonDriver** drv;
} DriverClass;
#define M(x, y, z) { x, y, (const HalCommonDriver *)(void *)z }
static const DriverDesc _music_driver_descs[] = {
#ifdef __BEOS__
M("bemidi", "BeOS MIDI Driver", &_bemidi_music_driver),
#endif
#ifdef __OS2__
M("os2", "OS/2 Music Driver", &_os2_music_driver),
#endif
#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
M("dmusic", "DirectMusic MIDI Driver", &_dmusic_midi_driver),
#endif
#ifdef WIN32
M("win32", "Win32 MIDI Driver", &_win32_music_driver),
#endif
#if defined(__APPLE__) && !defined(DEDICATED)
M("qt", "QuickTime MIDI Driver", &_qtime_music_driver),
#endif
#ifdef UNIX
#if !defined(__MORPHOS__) && !defined(__AMIGA__)
M("extmidi", "External MIDI Driver", &_extmidi_music_driver),
#endif
#endif
M("null", "Null Music Driver", &_null_music_driver),
M(NULL, NULL, NULL)
};
static const DriverDesc _sound_driver_descs[] = {
#ifdef WIN32
M("win32", "Win32 WaveOut Driver", &_win32_sound_driver),
#endif
#ifdef WITH_SDL
M("sdl", "SDL Sound Driver", &_sdl_sound_driver),
#endif
#ifdef WITH_COCOA
M("cocoa", "Cocoa Sound Driver", &_cocoa_sound_driver),
#endif
M("null", "Null Sound Driver", &_null_sound_driver),
M(NULL, NULL, NULL)
};
static const DriverDesc _video_driver_descs[] = {
#ifdef WIN32
M("win32", "Win32 GDI Video Driver", &_win32_video_driver),
#endif
#ifdef WITH_SDL
M("sdl", "SDL Video Driver", &_sdl_video_driver),
#endif
#ifdef WITH_COCOA
M("cocoa", "Cocoa Video Driver", &_cocoa_video_driver),
#endif
M("null", "Null Video Driver", &_null_video_driver),
#ifdef ENABLE_NETWORK
M("dedicated", "Dedicated Video Driver", &_dedicated_video_driver),
#endif
M(NULL, NULL, NULL)
};
#undef M
#define M(x, y, z) { x, y, (const HalCommonDriver **)(void *)z }
static const DriverClass _driver_classes[] = {
M(_video_driver_descs, "video", &_video_driver),
M(_sound_driver_descs, "sound", &_sound_driver),
M(_music_driver_descs, "music", &_music_driver)
};
#undef M
static const DriverDesc* GetDriverByName(const DriverDesc* dd, const char* name)
{
for (; dd->name != NULL; dd++) {
if (strcmp(dd->name, name) == 0) return dd;
}
return NULL;
}
void LoadDriver(int driver, const char *name)
{
const DriverClass *dc = &_driver_classes[driver];
const DriverDesc *dd;
const char *err;
if (*name == '\0') {
for (dd = dc->descs; dd->name != NULL; dd++) {
err = dd->drv->start(NULL);
if (err == NULL) break;
DEBUG(driver, 1) ("Probing %s driver \"%s\" failed with error: %s",
dc->name, dd->name, err
);
}
if (dd->name == NULL) {
error("Couldn't find any suitable %s driver", dc->name);
}
DEBUG(driver, 1)
("Successfully probed %s driver \"%s\"", dc->name, dd->name);
*dc->drv = dd->drv;
} else {
char* parm;
char buffer[256];
const char* parms[32];
// Extract the driver name and put parameter list in parm
ttd_strlcpy(buffer, name, sizeof(buffer));
parm = strchr(buffer, ':');
parms[0] = NULL;
if (parm != NULL) {
uint np = 0;
// Tokenize the parm.
do {
*parm++ = '\0';
if (np < lengthof(parms) - 1)
parms[np++] = parm;
while (*parm != '\0' && *parm != ',')
parm++;
} while (*parm == ',');
parms[np] = NULL;
}
dd = GetDriverByName(dc->descs, buffer);
if (dd == NULL)
error("No such %s driver: %s\n", dc->name, buffer);
if (*dc->drv != NULL) (*dc->drv)->stop();
*dc->drv = NULL;
err = dd->drv->start(parms);
if (err != NULL) {
error("Unable to load driver %s(%s). The error was: %s\n",
dd->name, dd->longname, err
);
}
*dc->drv = dd->drv;
}
}
static const char* GetDriverParam(const char* const* parm, const char* name)
{
size_t len;
if (parm == NULL) return NULL;
len = strlen(name);
for (; *parm != NULL; parm++) {
const char* p = *parm;
if (strncmp(p, name, len) == 0) {
if (p[len] == '=') return p + len + 1;
if (p[len] == '\0') return p + len;
}
}
return NULL;
}
bool GetDriverParamBool(const char* const* parm, const char* name)
{
return GetDriverParam(parm, name) != NULL;
}
int GetDriverParamInt(const char* const* parm, const char* name, int def)
{
const char* p = GetDriverParam(parm, name);
return p != NULL ? atoi(p) : def;
}
char *GetDriverList(char* p)
{
const DriverClass* dc;
for (dc = _driver_classes; dc != endof(_driver_classes); dc++) {
const DriverDesc* dd;
p += sprintf(p, "List of %s drivers:\n", dc->name);
for (dd = dc->descs; dd->name != NULL; dd++) {
p += sprintf(p, "%10s: %s\n", dd->name, dd->longname);
}
p += sprintf(p, "\n");
}
return p;
}

View File

@@ -1,13 +0,0 @@
/* $Id$ */
#ifndef DRIVER_H
#define DRIVER_H
void LoadDriver(int driver, const char *name);
bool GetDriverParamBool(const char* const* parm, const char* name);
int GetDriverParamInt(const char* const* parm, const char* name, int def);
char *GetDriverList(char* p);
#endif /* DRIVER_H */

View File

@@ -1,67 +1,60 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "viewport.h" #include "viewport.h"
#include "command.h" #include "command.h"
#include "table/sprites.h"
static void DrawTile_Dummy(TileInfo *ti) static void DrawTile_Dummy(TileInfo *ti)
{ {
DrawGroundSpriteAt(SPR_SHADOW_CELL, ti->x, ti->y, ti->z); DrawGroundSpriteAt(0x3EC, ti->x, ti->y, ti->z);
} }
static uint GetSlopeZ_Dummy(const TileInfo* ti) static uint GetSlopeZ_Dummy(TileInfo *ti) {
{ return GetPartialZ(ti->x&0xF, ti->y&0xF, ti->tileh) + ti->z;
return 0;
} }
static uint GetSlopeTileh_Dummy(const TileInfo* ti) static uint GetSlopeTileh_Dummy(TileInfo *ti) {
{ return ti->tileh;
return 0;
} }
static int32 ClearTile_Dummy(TileIndex tile, byte flags) static int32 ClearTile_Dummy(uint tile, byte flags) {
{
return_cmd_error(STR_0001_OFF_EDGE_OF_MAP); return_cmd_error(STR_0001_OFF_EDGE_OF_MAP);
} }
static void GetAcceptedCargo_Dummy(TileIndex tile, AcceptedCargo ac) static void GetAcceptedCargo_Dummy(uint tile, AcceptedCargo ac)
{ {
/* not used */ /* not used */
} }
static void GetTileDesc_Dummy(TileIndex tile, TileDesc *td) static void GetTileDesc_Dummy(uint tile, TileDesc *td)
{ {
td->str = STR_EMPTY; td->str = STR_EMPTY;
td->owner = OWNER_NONE; td->owner = OWNER_NONE;
} }
static void AnimateTile_Dummy(TileIndex tile) static void AnimateTile_Dummy(uint tile)
{ {
/* not used */ /* not used */
} }
static void TileLoop_Dummy(TileIndex tile) static void TileLoop_Dummy(uint tile)
{ {
/* not used */ /* not used */
} }
static void ClickTile_Dummy(TileIndex tile) static void ClickTile_Dummy(uint tile)
{ {
/* not used */ /* not used */
} }
static void ChangeTileOwner_Dummy(TileIndex tile, PlayerID old_player, PlayerID new_player) static void ChangeTileOwner_Dummy(uint tile, byte old_player, byte new_player)
{ {
/* not used */ /* not used */
} }
static uint32 GetTileTrackStatus_Dummy(TileIndex tile, TransportType mode) static uint32 GetTileTrackStatus_Dummy(uint tile, TransportType mode)
{ {
return 0; return 0;
} }
@@ -82,3 +75,4 @@ const TileTypeProcs _tile_type_dummy_procs = {
NULL, /* vehicle_leave_tile_proc */ NULL, /* vehicle_leave_tile_proc */
GetSlopeTileh_Dummy, /* get_slope_tileh_proc */ GetSlopeTileh_Dummy, /* get_slope_tileh_proc */
}; };

594
economy.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,6 @@
/* $Id$ */
#ifndef ECONOMY_H #ifndef ECONOMY_H
#define ECONOMY_H #define ECONOMY_H
void ResetPriceBaseMultipliers(void);
void SetPriceBaseMultiplier(uint price, byte factor);
typedef struct { typedef struct {
// Maximum possible loan // Maximum possible loan
int32 max_loan; int32 max_loan;
@@ -52,19 +47,32 @@ typedef struct ScoreInfo {
int score; // How much score it will give int score; // How much score it will give
} ScoreInfo; } ScoreInfo;
extern const ScoreInfo _score_info[]; static const ScoreInfo score_info[] = {
extern int _score_part[MAX_PLAYERS][NUM_SCORE]; {SCORE_VEHICLES, 120, 100},
{SCORE_STATIONS, 80, 100},
{SCORE_MIN_PROFIT, 10000, 100},
{SCORE_MIN_INCOME, 50000, 50},
{SCORE_MAX_INCOME, 100000, 100},
{SCORE_DELIVERED, 40000, 400},
{SCORE_CARGO, 8, 50},
{SCORE_MONEY, 10000000, 50},
{SCORE_LOAN, 250000, 50},
{SCORE_TOTAL, 0, 0}
};
int _score_part[MAX_PLAYERS][NUM_SCORE];
int UpdateCompanyRatingAndValue(Player *p, bool update); int UpdateCompanyRatingAndValue(Player *p, bool update);
void UpdatePlayerHouse(Player *p, uint score); void UpdatePlayerHouse(Player *p, uint score);
VARDEF Subsidy _subsidies[MAX_PLAYERS]; VARDEF Subsidy _subsidies[MAX_PLAYERS];
Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode); Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode);
void DeleteSubsidyWithIndustry(uint16 index); void DeleteSubsidyWithIndustry(uint16 index);
void DeleteSubsidyWithStation(uint16 index); void DeleteSubsidyWithStation(uint16 index);
void RemoteSubsidyAdd(Subsidy *s_new);
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type); int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
uint MoveGoodsToStation(TileIndex tile, int w, int h, int type, uint amount); uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount);
#endif /* ECONOMY_H */ #endif /* ECONOMY_H */

View File

@@ -1,5 +1,3 @@
/* $Id$ */
#include <stdio.h> #include <stdio.h>
// This pretty simple file checks if the system is LITTLE_ENDIAN or BIG_ENDIAN // This pretty simple file checks if the system is LITTLE_ENDIAN or BIG_ENDIAN
@@ -10,43 +8,15 @@
// that says or TTD_LITTLE_ENDIAN, or TTD_BIG_ENDIAN. Makefile takes // that says or TTD_LITTLE_ENDIAN, or TTD_BIG_ENDIAN. Makefile takes
// care of the real writing to the file. // care of the real writing to the file.
int main (int argc, char *argv[]) { int main () {
unsigned char EndianTest[2] = { 1, 0 }; unsigned char EndianTest[2] = { 1, 0 };
int force_BE = 0, force_LE = 0, force_PREPROCESSOR = 0; printf("#ifndef ENDIAN_H\n#define ENDIAN_H\n");
if( *(short *) EndianTest == 1 )
printf("#define TTD_LITTLE_ENDIAN\n");
else
printf("#define TTD_BIG_ENDIAN\n");
if (argc > 1 && strcmp(argv[1], "BE") == 0) printf("#endif\n");
force_BE = 1;
if (argc > 1 && strcmp(argv[1], "LE") == 0)
force_LE = 1;
if (argc > 1 && strcmp(argv[1], "PREPROCESSOR") == 0)
force_PREPROCESSOR = 1;
printf("#ifndef ENDIAN_H\n#define ENDIAN_H\n"); return 0;
if (force_LE == 1) {
printf("#define TTD_LITTLE_ENDIAN\n");
} else {
if (force_BE == 1) {
printf("#define TTD_BIG_ENDIAN\n");
} else {
if (force_PREPROCESSOR == 1) {
// adding support for universal binaries on OSX
// Universal binaries supports both PPC and x86
// If a compiler for OSX gets this setting, it will always pick the correct endian and no test is needed
printf("#ifdef __BIG_ENDIAN__\n");
printf("#define TTD_BIG_ENDIAN\n");
printf("#else\n");
printf("#define TTD_LITTLE_ENDIAN\n");
printf("#endif\n");
} else {
if ( *(short *) EndianTest == 1 )
printf("#define TTD_LITTLE_ENDIAN\n");
else
printf("#define TTD_BIG_ENDIAN\n");
}
}
}
printf("#endif\n");
return 0;
} }

879
engine.c

File diff suppressed because it is too large Load Diff

259
engine.h
View File

@@ -1,13 +1,7 @@
/* $Id$ */
#ifndef ENGINE_H #ifndef ENGINE_H
#define ENGINE_H #define ENGINE_H
/** @file engine.h
*/
#include "sprite.h" #include "sprite.h"
#include "pool.h"
typedef struct RailVehicleInfo { typedef struct RailVehicleInfo {
byte image_index; byte image_index;
@@ -15,20 +9,11 @@ typedef struct RailVehicleInfo {
byte base_cost; byte base_cost;
uint16 max_speed; uint16 max_speed;
uint16 power; uint16 power;
uint16 weight; byte weight;
byte running_cost_base; byte running_cost_base;
byte running_cost_class;
byte engclass; // 0: steam, 1: diesel, 2: electric byte engclass; // 0: steam, 1: diesel, 2: electric
byte capacity; byte capacity;
byte cargo_type; byte cargo_type;
byte callbackmask; // see CallbackMask enum
uint16 pow_wag_power;
byte pow_wag_weight;
byte visual_effect; // NOTE: this is not 100% implemented yet, at the moment it is only used as a 'fallback' value
// for when the 'powered wagon' callback fails. But it should really also determine what
// kind of visual effect to generate for a vehicle (default, steam, diesel, electric).
// Same goes for the callback result, which atm is only used to check if a wagon is powered.
byte shorten_factor; // length on main map for this type is 8 - shorten_factor
} RailVehicleInfo; } RailVehicleInfo;
typedef struct ShipVehicleInfo { typedef struct ShipVehicleInfo {
@@ -64,17 +49,12 @@ typedef struct RoadVehicleInfo {
byte cargo_type; byte cargo_type;
} RoadVehicleInfo; } RoadVehicleInfo;
/** Information about a vehicle
* @see table/engines.h
*/
typedef struct EngineInfo { typedef struct EngineInfo {
uint16 base_intro; uint16 base_intro;
byte unk2; ///< Carriages have the highest bit set in this one byte unk2;
byte lifelength; byte lifelength;
byte base_life; byte base_life;
byte railtype:4; byte railtype_climates;
byte climates:4;
uint32 refit_mask;
} EngineInfo; } EngineInfo;
typedef struct Engine { typedef struct Engine {
@@ -99,100 +79,31 @@ enum {
RVI_WAGON = 2, RVI_WAGON = 2,
}; };
enum {
NUM_VEHICLE_TYPES = 6
};
enum {
INVALID_ENGINE = 0xFFFF,
};
void AddTypeToEngines(void); void AddTypeToEngines(void);
void StartupEngines(void); void StartupEngines(void);
enum GlobalCargo {
GC_PASSENGERS = 0,
GC_COAL = 1,
GC_MAIL = 2,
GC_OIL = 3,
GC_LIVESTOCK = 4,
GC_GOODS = 5,
GC_GRAIN = 6, // GC_WHEAT / GC_MAIZE
GC_WOOD = 7,
GC_IRON_ORE = 8,
GC_STEEL = 9,
GC_VALUABLES = 10, // GC_GOLD / GC_DIAMONDS
GC_PAPER = 11,
GC_FOOD = 12,
GC_FRUIT = 13,
GC_COPPER_ORE = 14,
GC_WATER = 15,
GC_RUBBER = 16,
GC_SUGAR = 17,
GC_TOYS = 18,
GC_BATTERIES = 19,
GC_CANDY = 20,
GC_TOFFEE = 21,
GC_COLA = 22,
GC_COTTON_CANDY = 23,
GC_BUBBLES = 24,
GC_PLASTIC = 25,
GC_FIZZY_DRINKS = 26,
GC_PAPER_TEMP = 27,
GC_UNDEFINED = 28, // undefined; unused slot in arctic climate
GC_DEFAULT = 29,
GC_PURCHASE = 30,
GC_INVALID = 255,
NUM_GLOBAL_CID = 31
};
// This enum lists the implemented callbacks
// Use as argument for the GetCallBackResult function (see comments there)
enum CallbackID {
// Powered wagons, if the result is lower as 0x40 then the wagon is powered
// TODO: interpret the rest of the result, aka "visual effects"
CBID_WAGON_POWER = 0x10,
// Vehicle length, returns the amount of 1/8's the vehicle is shorter
// only for train vehicles
CBID_VEH_LENGTH = 0x11,
// Refit capacity, the passed vehicle needs to have its ->cargo_type set to
// the cargo we are refitting to, returns the new cargo capacity
CBID_REFIT_CAP = 0x15,
CBID_ARTIC_ENGINE = 0x16,
};
// bit positions for rvi->callbackmask, indicates which callbacks are used by an engine
// (some callbacks are always used, and dont appear here)
enum CallbackMask {
CBM_WAGON_POWER = 0,
CBM_VEH_LENGTH = 1,
CBM_REFIT_CAP = 3,
CBM_ARTIC_ENGINE = 4,
};
extern byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
enum { enum {
CALLBACK_FAILED = 0xFFFF CID_DEFAULT = 29,
CID_PURCHASE = 30,
NUM_CID = 31,
}; };
extern byte _local_cargo_id_ctype[NUM_CID];
extern byte _local_cargo_id_landscape[NUM_CID];
VARDEF const uint32 _default_refitmasks[NUM_VEHICLE_TYPES]; extern uint32 _engine_refit_masks[256];
VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
VARDEF const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID];
VARDEF const uint32 cargo_classes[16];
void SetWagonOverrideSprites(EngineID engine, struct SpriteGroup *group, byte *train_id, int trains); extern byte _engine_original_sprites[256];
void SetCustomEngineSprites(EngineID engine, byte cargo, struct SpriteGroup *group); void SetWagonOverrideSprites(byte engine, struct SpriteGroup *group, byte *train_id, int trains);
void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group);
// loaded is in percents, overriding_engine 0xffff is none // loaded is in percents, overriding_engine 0xffff is none
int GetCustomEngineSprite(EngineID engine, const Vehicle *v, byte direction); int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction);
uint16 GetCallBackResult(uint16 callback_info, EngineID engine, const Vehicle *v);
bool UsesWagonOverride(const Vehicle *v);
#define GetCustomVehicleSprite(v, direction) GetCustomEngineSprite(v->engine_type, v, direction) #define GetCustomVehicleSprite(v, direction) GetCustomEngineSprite(v->engine_type, v, direction)
#define GetCustomVehicleIcon(et, direction) GetCustomEngineSprite(et, NULL, direction) #define GetCustomVehicleIcon(et, direction) GetCustomEngineSprite(et, NULL, direction)
typedef enum VehicleTrigger { enum VehicleTrigger {
VEHICLE_TRIGGER_NEW_CARGO = 1, VEHICLE_TRIGGER_NEW_CARGO = 1,
// Externally triggered only for the first vehicle in chain // Externally triggered only for the first vehicle in chain
VEHICLE_TRIGGER_DEPOT = 2, VEHICLE_TRIGGER_DEPOT = 2,
@@ -200,22 +111,28 @@ typedef enum VehicleTrigger {
VEHICLE_TRIGGER_EMPTY = 4, VEHICLE_TRIGGER_EMPTY = 4,
// Not triggered externally (called for the whole chain if we got NEW_CARGO) // Not triggered externally (called for the whole chain if we got NEW_CARGO)
VEHICLE_TRIGGER_ANY_NEW_CARGO = 8, VEHICLE_TRIGGER_ANY_NEW_CARGO = 8,
} VehicleTrigger; };
void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger); void TriggerVehicle(Vehicle *veh, enum VehicleTrigger trigger);
void SetCustomEngineName(EngineID engine, const char *name); void SetCustomEngineName(int engine, char *name);
StringID GetCustomEngineName(EngineID engine); StringID GetCustomEngineName(int engine);
void DrawTrainEngine(int x, int y, EngineID engine, uint32 image_ormod); void DrawTrainEngine(int x, int y, int engine, uint32 image_ormod);
void DrawRoadVehEngine(int x, int y, EngineID engine, uint32 image_ormod); void DrawRoadVehEngine(int x, int y, int engine, uint32 image_ormod);
void DrawShipEngine(int x, int y, EngineID engine, uint32 image_ormod); void DrawShipEngine(int x, int y, int engine, uint32 image_ormod);
void DrawAircraftEngine(int x, int y, EngineID engine, uint32 image_ormod); void DrawAircraftEngine(int x, int y, int engine, uint32 image_ormod);
void DrawTrainEngineInfo(int engine, int x, int y, int maxw);
void DrawRoadVehEngineInfo(int engine, int x, int y, int maxw);
void DrawShipEngineInfo(int engine, int x, int y, int maxw);
void DrawAircraftEngineInfo(int engine, int x, int y, int maxw);
void AcceptEnginePreview(Engine *e, int player);
void LoadCustomEngineNames(void); void LoadCustomEngineNames(void);
void DeleteCustomEngineNames(void); void DeleteCustomEngineNames(void);
bool IsEngineBuildable(uint engine, byte type);
enum { enum {
NUM_NORMAL_RAIL_ENGINES = 54, NUM_NORMAL_RAIL_ENGINES = 54,
@@ -231,137 +148,39 @@ enum {
ROAD_ENGINES_INDEX = NUM_TRAIN_ENGINES, ROAD_ENGINES_INDEX = NUM_TRAIN_ENGINES,
}; };
VARDEF Engine _engines[TOTAL_NUM_ENGINES]; VARDEF Engine _engines[TOTAL_NUM_ENGINES];
#define FOR_ALL_ENGINES(e) for (e = _engines; e != endof(_engines); e++) #define DEREF_ENGINE(i) (&_engines[i])
static inline Engine* GetEngine(EngineID i)
{
assert(i < lengthof(_engines));
return &_engines[i];
}
VARDEF StringID _engine_name_strings[TOTAL_NUM_ENGINES]; VARDEF StringID _engine_name_strings[TOTAL_NUM_ENGINES];
static inline bool IsEngineIndex(uint index)
{
return index < TOTAL_NUM_ENGINES;
}
/* Access Vehicle Data */ /* Access Vehicle Data */
//#include "table/engines.h" //#include "table/engines.h"
extern const EngineInfo orig_engine_info[TOTAL_NUM_ENGINES];
extern const RailVehicleInfo orig_rail_vehicle_info[NUM_TRAIN_ENGINES];
extern const ShipVehicleInfo orig_ship_vehicle_info[NUM_SHIP_ENGINES];
extern const AircraftVehicleInfo orig_aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
extern const RoadVehicleInfo orig_road_vehicle_info[NUM_ROAD_ENGINES];
extern EngineInfo _engine_info[TOTAL_NUM_ENGINES]; extern EngineInfo _engine_info[TOTAL_NUM_ENGINES];
extern RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES]; extern RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
extern ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES]; extern ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
extern AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES]; extern AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
extern RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES]; extern RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
static inline const RailVehicleInfo* RailVehInfo(EngineID e) static inline RailVehicleInfo *RailVehInfo(uint e)
{ {
assert(e < lengthof(_rail_vehicle_info)); assert(e < lengthof(_rail_vehicle_info));
return &_rail_vehicle_info[e]; return &_rail_vehicle_info[e];
} }
static inline const ShipVehicleInfo* ShipVehInfo(EngineID e) static inline ShipVehicleInfo *ShipVehInfo(uint e)
{ {
assert(e >= SHIP_ENGINES_INDEX && e < SHIP_ENGINES_INDEX + lengthof(_ship_vehicle_info)); assert(e - SHIP_ENGINES_INDEX < lengthof(_ship_vehicle_info));
return &_ship_vehicle_info[e - SHIP_ENGINES_INDEX]; return &_ship_vehicle_info[e - SHIP_ENGINES_INDEX];
} }
static inline const AircraftVehicleInfo* AircraftVehInfo(EngineID e) static inline AircraftVehicleInfo *AircraftVehInfo(uint e)
{ {
assert(e >= AIRCRAFT_ENGINES_INDEX && e < AIRCRAFT_ENGINES_INDEX + lengthof(_aircraft_vehicle_info)); assert(e - AIRCRAFT_ENGINES_INDEX < lengthof(_aircraft_vehicle_info));
return &_aircraft_vehicle_info[e - AIRCRAFT_ENGINES_INDEX]; return &_aircraft_vehicle_info[e - AIRCRAFT_ENGINES_INDEX];
} }
static inline const RoadVehicleInfo* RoadVehInfo(EngineID e) static inline RoadVehicleInfo *RoadVehInfo(uint e)
{ {
assert(e >= ROAD_ENGINES_INDEX && e < ROAD_ENGINES_INDEX + lengthof(_road_vehicle_info)); assert(e - ROAD_ENGINES_INDEX < lengthof(_road_vehicle_info));
return &_road_vehicle_info[e - ROAD_ENGINES_INDEX]; return &_road_vehicle_info[e - ROAD_ENGINES_INDEX];
} }
void UnloadWagonOverrides(void); #endif
void UnloadCustomEngineSprites(void);
void UnloadCustomEngineNames(void);
/************************************************************************
* Engine Replacement stuff
************************************************************************/
/**
* Struct to store engine replacements. DO NOT USE outside of engine.c. Is
* placed here so the only exception to this rule, the saveload code, can use
* it.
*/
struct EngineRenew {
uint16 index;
EngineID from;
EngineID to;
struct EngineRenew *next;
};
typedef struct EngineRenew EngineRenew;
/**
* Memory pool for engine renew elements. DO NOT USE outside of engine.c. Is
* placed here so the only exception to this rule, the saveload code, can use
* it.
*/
extern MemoryPool _engine_renew_pool;
/**
* DO NOT USE outside of engine.c. Is
* placed here so the only exception to this rule, the saveload code, can use
* it.
*/
static inline EngineRenew *GetEngineRenew(uint16 index)
{
return (EngineRenew*)GetItemFromPool(&_engine_renew_pool, index);
}
/**
* A list to group EngineRenew directives together (such as per-player).
*/
typedef EngineRenew* EngineRenewList;
/**
* Remove all engine replacement settings for the player.
* @param er The renewlist for a given player.
* @return The new renewlist for the player.
*/
void RemoveAllEngineReplacement(EngineRenewList* erl);
/**
* Retrieve the engine replacement in a given renewlist for an original engine type.
* @param erl The renewlist to search in.
* @param engine Engine type to be replaced.
* @return The engine type to replace with, or INVALID_ENGINE if no
* replacement is in the list.
*/
EngineID EngineReplacement(EngineRenewList erl, EngineID engine);
/**
* Add an engine replacement to the given renewlist.
* @param erl The renewlist to add to.
* @param old_engine The original engine type.
* @param new_engine The replacement engine type.
* @param flags The calling command flags.
* @return 0 on success, CMD_ERROR on failure.
*/
int32 AddEngineReplacement(EngineRenewList* erl, EngineID old_engine, EngineID new_engine, uint32 flags);
/**
* Remove an engine replacement from a given renewlist.
* @param erl The renewlist from which to remove the replacement
* @param engine The original engine type.
* @param flags The calling command flags.
* @return 0 on success, CMD_ERROR on failure.
*/
int32 RemoveEngineReplacement(EngineRenewList* erl, EngineID engine, uint32 flags);
#endif /* ENGINE_H */

View File

@@ -1,10 +1,6 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h"
#include "functions.h"
#include "window.h" #include "window.h"
#include "gui.h" #include "gui.h"
#include "viewport.h" #include "viewport.h"
@@ -12,16 +8,18 @@
#include "engine.h" #include "engine.h"
#include "command.h" #include "command.h"
#include "news.h" #include "news.h"
#include "variables.h"
static StringID GetEngineCategoryName(EngineID engine) static StringID GetEngineCategoryName(byte engine)
{ {
if (engine < NUM_TRAIN_ENGINES) { if (engine < NUM_TRAIN_ENGINES) {
switch (GetEngine(engine)->railtype) { switch (_engines[engine].railtype) {
case RAILTYPE_RAIL: return STR_8102_RAILROAD_LOCOMOTIVE; case 0:
case RAILTYPE_MONO: return STR_8106_MONORAIL_LOCOMOTIVE; return STR_8102_RAILROAD_LOCOMOTIVE;
case RAILTYPE_MAGLEV: return STR_8107_MAGLEV_LOCOMOTIVE; case 1:
return STR_8106_MONORAIL_LOCOMOTIVE;
case 2:
return STR_8107_MAGLEV_LOCOMOTIVE;
} }
} }
@@ -35,7 +33,7 @@ static StringID GetEngineCategoryName(EngineID engine)
} }
static const Widget _engine_preview_widgets[] = { static const Widget _engine_preview_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 5, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 5, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 5, 11, 299, 0, 13, STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 5, 11, 299, 0, 13, STR_8100_MESSAGE_FROM_VEHICLE_MANUFACTURE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, RESIZE_NONE, 5, 0, 299, 14, 191, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 5, 0, 299, 14, 191, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 5, 85, 144, 172, 183, STR_00C9_NO, STR_NULL}, { WWT_PUSHTXTBTN, RESIZE_NONE, 5, 85, 144, 172, 183, STR_00C9_NO, STR_NULL},
@@ -43,19 +41,14 @@ static const Widget _engine_preview_widgets[] = {
{ WIDGETS_END}, { WIDGETS_END},
}; };
typedef void DrawEngineProc(int x, int y, EngineID engine, uint32 image_ormod); typedef void DrawEngineProc(int x, int y, int engine, uint32 image_ormod);
typedef void DrawEngineInfoProc(EngineID, int x, int y, int maxw); typedef void DrawEngineInfoProc(int x, int y, int engine, int maxw);
typedef struct DrawEngineInfo { typedef struct DrawEngineInfo {
DrawEngineProc *engine_proc; DrawEngineProc *engine_proc;
DrawEngineInfoProc *info_proc; DrawEngineInfoProc *info_proc;
} DrawEngineInfo; } DrawEngineInfo;
static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw);
static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw);
static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw);
static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw);
static const DrawEngineInfo _draw_engine_list[4] = { static const DrawEngineInfo _draw_engine_list[4] = {
{DrawTrainEngine,DrawTrainEngineInfo}, {DrawTrainEngine,DrawTrainEngineInfo},
{DrawRoadVehEngine,DrawRoadVehEngineInfo}, {DrawRoadVehEngine,DrawRoadVehEngineInfo},
@@ -65,40 +58,39 @@ static const DrawEngineInfo _draw_engine_list[4] = {
static void EnginePreviewWndProc(Window *w, WindowEvent *e) static void EnginePreviewWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { byte eng;
case WE_PAINT: { int engine;
EngineID engine = w->window_number; const DrawEngineInfo *dei;
const DrawEngineInfo* dei; int width;
int width;
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w); DrawWindowWidgets(w);
engine = w->window_number;
SetDParam(0, GetEngineCategoryName(engine)); SetDParam(0, GetEngineCategoryName(engine));
DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296); DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
DrawStringCentered(w->width >> 1, 80, GetCustomEngineName(engine), 0x10); DrawStringCentered(w->width >> 1, 80, GetCustomEngineName(engine), 0x10);
(dei = _draw_engine_list,engine < NUM_TRAIN_ENGINES) || eng = (byte)engine;
(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) || (dei = _draw_engine_list,eng < NUM_TRAIN_ENGINES) ||
(dei++,engine < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) || (dei++,eng < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES) ||
(dei++,eng < NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES) ||
(dei++, true); (dei++, true);
width = w->width; width = w->width;
dei->engine_proc(width >> 1, 100, engine, 0); dei->engine_proc(width >> 1, 100, engine, 0);
dei->info_proc(engine, width >> 1, 130, width - 52); dei->info_proc(engine, width >> 1, 130, width - 52);
break; break;
}
case WE_CLICK: case WE_CLICK:
switch (e->click.widget) { switch(e->click.widget) {
case 3: case 3: DeleteWindow(w); break;
DeleteWindow(w); case 4:
break; DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
DeleteWindow(w);
case 4: break;
DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
DeleteWindow(w);
break;
} }
break; break;
} }
@@ -113,7 +105,7 @@ static const WindowDesc _engine_preview_desc = {
}; };
void ShowEnginePreviewWindow(EngineID engine) void ShowEnginePreviewWindow(int engine)
{ {
Window *w; Window *w;
@@ -121,30 +113,9 @@ void ShowEnginePreviewWindow(EngineID engine)
w->window_number = engine; w->window_number = engine;
} }
static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
{
const RailVehicleInfo *rvi = RailVehInfo(engine);
uint multihead = (rvi->flags & RVI_MULTIHEAD) ? 1 : 0;
SetDParam(0, (_price.build_railvehicle >> 3) * rvi->base_cost >> 5);
SetDParam(2, rvi->max_speed * 10 >> 4);
SetDParam(3, rvi->power << multihead);
SetDParam(1, rvi->weight << multihead);
SetDParam(4, rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8 << multihead);
if (rvi->capacity != 0) {
SetDParam(5, _cargoc.names_long[rvi->cargo_type]);
SetDParam(6, rvi->capacity << multihead);
} else {
SetDParam(5, STR_8838_N_A);
}
DrawStringMultiCenter(x, y, STR_885B_COST_WEIGHT_T_SPEED_POWER, maxw);
}
void DrawNewsNewTrainAvail(Window *w) void DrawNewsNewTrainAvail(Window *w)
{ {
EngineID engine; int engine;
DrawNewsBorder(w); DrawNewsBorder(w);
@@ -158,34 +129,22 @@ void DrawNewsNewTrainAvail(Window *w)
DrawStringMultiCenter(w->width >> 1, 57, STR_885A, w->width - 2); DrawStringMultiCenter(w->width >> 1, 57, STR_885A, w->width - 2);
DrawTrainEngine(w->width >> 1, 88, engine, 0); DrawTrainEngine(w->width >> 1, 88, engine, 0);
GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE); GfxFillRect(25, 56, w->width - 56, 112, 0x4323);
DrawTrainEngineInfo(engine, w->width >> 1, 129, w->width - 52); DrawTrainEngineInfo(engine, w->width >> 1, 129, w->width - 52);
} }
StringID GetNewsStringNewTrainAvail(const NewsItem *ni) StringID GetNewsStringNewTrainAvail(NewsItem *ni)
{ {
EngineID engine = ni->string_id; int engine = ni->string_id;
SetDParam(0, STR_8859_NEW_NOW_AVAILABLE); SetDParam(0, STR_8859_NEW_NOW_AVAILABLE);
SetDParam(1, GetEngineCategoryName(engine)); SetDParam(1, GetEngineCategoryName(engine));
SetDParam(2, GetCustomEngineName(engine)); SetDParam(2, GetCustomEngineName(engine));
return STR_02B6; return STR_02B6;
} }
static void DrawAircraftEngineInfo(EngineID engine, int x, int y, int maxw)
{
const AircraftVehicleInfo *avi = AircraftVehInfo(engine);
SetDParam(0, (_price.aircraft_base >> 3) * avi->base_cost >> 5);
SetDParam(1, avi->max_speed << 3);
SetDParam(2, avi->passenger_capacity);
SetDParam(3, avi->mail_capacity);
SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
DrawStringMultiCenter(x, y, STR_A02E_COST_MAX_SPEED_CAPACITY, maxw);
}
void DrawNewsNewAircraftAvail(Window *w) void DrawNewsNewAircraftAvail(Window *w)
{ {
EngineID engine; int engine;
DrawNewsBorder(w); DrawNewsBorder(w);
@@ -198,35 +157,21 @@ void DrawNewsNewAircraftAvail(Window *w)
DrawStringMultiCenter(w->width >> 1, 57, STR_A02D, w->width - 2); DrawStringMultiCenter(w->width >> 1, 57, STR_A02D, w->width - 2);
DrawAircraftEngine(w->width >> 1, 93, engine, 0); DrawAircraftEngine(w->width >> 1, 93, engine, 0);
GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE); GfxFillRect(25, 56, w->width - 56, 110, 0x4323);
DrawAircraftEngineInfo(engine, w->width >> 1, 131, w->width - 52); DrawAircraftEngineInfo(engine, w->width >> 1, 131, w->width - 52);
} }
StringID GetNewsStringNewAircraftAvail(const NewsItem *ni) StringID GetNewsStringNewAircraftAvail(NewsItem *ni)
{ {
EngineID engine = ni->string_id; int engine = ni->string_id;
SetDParam(0, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE); SetDParam(0, STR_A02C_NEW_AIRCRAFT_NOW_AVAILABLE);
SetDParam(1, GetCustomEngineName(engine)); SetDParam(1, GetCustomEngineName(engine));
return STR_02B6; return STR_02B6;
} }
static void DrawRoadVehEngineInfo(EngineID engine, int x, int y, int maxw)
{
const RoadVehicleInfo *rvi = RoadVehInfo(engine);
SetDParam(0, (_price.roadveh_base >> 3) * rvi->base_cost >> 5);
SetDParam(1, rvi->max_speed * 10 >> 5);
SetDParam(2, rvi->running_cost * _price.roadveh_running >> 8);
SetDParam(4, rvi->capacity);
SetDParam(3, _cargoc.names_long[rvi->cargo_type]);
DrawStringMultiCenter(x, y, STR_902A_COST_SPEED_RUNNING_COST, maxw);
}
void DrawNewsNewRoadVehAvail(Window *w) void DrawNewsNewRoadVehAvail(Window *w)
{ {
EngineID engine; int engine;
DrawNewsBorder(w); DrawNewsBorder(w);
@@ -238,32 +183,21 @@ void DrawNewsNewRoadVehAvail(Window *w)
DrawStringMultiCenter(w->width >> 1, 57, STR_9029, w->width - 2); DrawStringMultiCenter(w->width >> 1, 57, STR_9029, w->width - 2);
DrawRoadVehEngine(w->width >> 1, 88, engine, 0); DrawRoadVehEngine(w->width >> 1, 88, engine, 0);
GfxFillRect(25, 56, w->width - 56, 112, 0x323 | USE_COLORTABLE); GfxFillRect(25, 56, w->width - 56, 112, 0x4323);
DrawRoadVehEngineInfo(engine, w->width >> 1, 129, w->width - 52); DrawRoadVehEngineInfo(engine, w->width >> 1, 129, w->width - 52);
} }
StringID GetNewsStringNewRoadVehAvail(const NewsItem *ni) StringID GetNewsStringNewRoadVehAvail(NewsItem *ni)
{ {
EngineID engine = ni->string_id; int engine = ni->string_id;
SetDParam(0, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE); SetDParam(0, STR_9028_NEW_ROAD_VEHICLE_NOW_AVAILABLE);
SetDParam(1, GetCustomEngineName(engine)); SetDParam(1, GetCustomEngineName(engine));
return STR_02B6; return STR_02B6;
} }
static void DrawShipEngineInfo(EngineID engine, int x, int y, int maxw)
{
const ShipVehicleInfo *svi = ShipVehInfo(engine);
SetDParam(0, svi->base_cost * (_price.ship_base >> 3) >> 5);
SetDParam(1, svi->max_speed * 10 >> 5);
SetDParam(2, _cargoc.names_long[svi->cargo_type]);
SetDParam(3, svi->capacity);
SetDParam(4, svi->running_cost * _price.ship_running >> 8);
DrawStringMultiCenter(x, y, STR_982E_COST_MAX_SPEED_CAPACITY, maxw);
}
void DrawNewsNewShipAvail(Window *w) void DrawNewsNewShipAvail(Window *w)
{ {
EngineID engine; int engine;
DrawNewsBorder(w); DrawNewsBorder(w);
@@ -276,13 +210,13 @@ void DrawNewsNewShipAvail(Window *w)
DrawStringMultiCenter(w->width >> 1, 57, STR_982D, w->width - 2); DrawStringMultiCenter(w->width >> 1, 57, STR_982D, w->width - 2);
DrawShipEngine(w->width >> 1, 93, engine, 0); DrawShipEngine(w->width >> 1, 93, engine, 0);
GfxFillRect(25, 56, w->width - 56, 110, 0x323 | USE_COLORTABLE); GfxFillRect(25, 56, w->width - 56, 110, 0x4323);
DrawShipEngineInfo(engine, w->width >> 1, 131, w->width - 52); DrawShipEngineInfo(engine, w->width >> 1, 131, w->width - 52);
} }
StringID GetNewsStringNewShipAvail(const NewsItem *ni) StringID GetNewsStringNewShipAvail(NewsItem *ni)
{ {
EngineID engine = ni->string_id; int engine = ni->string_id;
SetDParam(0, STR_982C_NEW_SHIP_NOW_AVAILABLE); SetDParam(0, STR_982C_NEW_SHIP_NOW_AVAILABLE);
SetDParam(1, GetCustomEngineName(engine)); SetDParam(1, GetCustomEngineName(engine));
return STR_02B6; return STR_02B6;

104
extmidi.c Normal file
View File

@@ -0,0 +1,104 @@
#ifndef __BEOS__
#ifndef __MORPHOS__
#include "stdafx.h"
#include "ttd.h"
#include "hal.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef EXTERNAL_PLAYER
#define EXTERNAL_PLAYER "timidity"
#endif
static pid_t _pid;
static void extmidi_kill(void)
{
if (_pid > 0) {
kill(_pid, SIGKILL);
while (waitpid(_pid, NULL, WNOHANG) != _pid);
}
_pid = 0;
}
static char *extmidi_start(char **parm)
{
_pid = 0;
return NULL;
}
static void extmidi_stop(void)
{
extmidi_kill();
}
static void extmidi_play_song(const char *filename)
{
extmidi_kill();
_pid = fork();
if (_pid < 0) {
fprintf(stderr, "extmidi: couldn't fork: %s\n", strerror(errno));
_pid = 0;
return;
}
if (_pid == 0) {
#if defined(MIDI_ARG)
execlp(EXTERNAL_PLAYER, "extmidi", MIDI_ARG, filename, NULL);
#else
execlp(EXTERNAL_PLAYER, "extmidi", filename, NULL);
#endif
fprintf(stderr, "extmidi: couldn't execl: %s\n", strerror(errno));
exit(0);
}
usleep(500);
if (_pid == waitpid(_pid, NULL, WNOHANG)) {
fprintf(stderr, "extmidi: play song failed\n");
_pid = 0;
usleep(5000);
}
}
static void extmidi_stop_song(void)
{
extmidi_kill();
}
static bool extmidi_is_playing(void)
{
if (_pid == 0)
return 0;
if (waitpid(_pid, NULL, WNOHANG) == _pid) {
_pid = 0;
return 0;
}
return 1;
}
static void extmidi_set_volume(byte vol)
{
fprintf(stderr, "extmidi: set volume not implemented\n");
}
const HalMusicDriver _extmidi_music_driver = {
extmidi_start,
extmidi_stop,
extmidi_play_song,
extmidi_stop_song,
extmidi_is_playing,
extmidi_set_volume,
};
#endif /* __MORPHOS__ */
#endif /* __BEOS__ */

View File

@@ -1,11 +1,6 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "fileio.h" #include "fileio.h"
#include "functions.h"
#include "macros.h"
#include "variables.h"
#if defined(UNIX) || defined(__OS2__) #if defined(UNIX) || defined(__OS2__)
#include <ctype.h> // required for tolower() #include <ctype.h> // required for tolower()
#endif #endif
@@ -105,73 +100,6 @@ void FioCloseAll(void)
FioCloseFile(i); FioCloseFile(i);
} }
bool FiosCheckFileExists(const char *filename)
{
FILE *f;
char buf[MAX_PATH];
sprintf(buf, "%s%s", _path.data_dir, filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// Make lower case and try again
for(s=buf + strlen(_path.data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
#if defined SECOND_DATA_DIR
// tries in the 2nd data directory
if (f == NULL) {
sprintf(buf, "%s%s", _path.second_data_dir, filename);
for(s=buf + strlen(_path.second_data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
#endif
}
#endif
if (f == NULL)
return false;
else {
fclose(f);
return true;
}
}
FILE *FioFOpenFile(const char *filename)
{
FILE *f;
char buf[MAX_PATH];
sprintf(buf, "%s%s", _path.data_dir, filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// Make lower case and try again
for(s=buf + strlen(_path.data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
#if defined SECOND_DATA_DIR
// tries in the 2nd data directory
if (f == NULL) {
sprintf(buf, "%s%s", _path.second_data_dir, filename);
for(s=buf + strlen(_path.second_data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
#endif
}
#endif
return f;
}
void FioOpenFile(int slot, const char *filename) void FioOpenFile(int slot, const char *filename)
{ {
FILE *f; FILE *f;
@@ -196,10 +124,6 @@ void FioOpenFile(int slot, const char *filename)
*s = tolower(*s); *s = tolower(*s);
f = fopen(buf, "rb"); f = fopen(buf, "rb");
} }
if (f == NULL)
sprintf(buf, "%s%s", _path.data_dir, filename); //makes it print the primary datadir path instead of the secundary one
#endif #endif
} }
#endif #endif
@@ -211,3 +135,5 @@ void FioOpenFile(int slot, const char *filename)
_fio.handles[slot] = f; _fio.handles[slot] = f;
FioSeekToFile(slot << 24); FioSeekToFile(slot << 24);
} }

View File

@@ -1,5 +1,3 @@
/* $Id$ */
#ifndef FILEIO_H #ifndef FILEIO_H
#define FILEIO_H #define FILEIO_H
@@ -10,10 +8,8 @@ byte FioReadByte(void);
uint16 FioReadWord(void); uint16 FioReadWord(void);
uint32 FioReadDword(void); uint32 FioReadDword(void);
void FioCloseAll(void); void FioCloseAll(void);
FILE *FioFOpenFile(const char *filename);
void FioOpenFile(int slot, const char *filename); void FioOpenFile(int slot, const char *filename);
void FioReadBlock(void *ptr, uint size); void FioReadBlock(void *ptr, uint size);
void FioSkipBytes(int n); void FioSkipBytes(int n);
bool FiosCheckFileExists(const char *filename);
#endif /* FILEIO_H */ #endif /* FILEIO_H */

View File

@@ -1,28 +1,39 @@
/* $Id$ */
#ifndef FUNCTIONS_H #ifndef FUNCTIONS_H
#define FUNCTIONS_H #define FUNCTIONS_H
/* vehicle.c */
/* window.c */
/* landscape.c */ /* landscape.c */
void FindLandscapeHeight(TileInfo *ti, uint x, uint y); void FindLandscapeHeight(TileInfo *ti, uint x, uint y);
void FindLandscapeHeightByTile(TileInfo *ti, TileIndex tile); void FindLandscapeHeightByTile(TileInfo *ti, uint tile);
uint GetTileSlope(uint tile, int *h);
int GetTileZ(uint tile);
void DoClearSquare(TileIndex tile); void DoClearSquare(uint tile);
void CDECL ModifyTile(TileIndex tile, uint flags, ...); void CDECL ModifyTile(uint tile, uint flags, ...);
void SetMapExtraBits(uint tile, byte flags);
uint GetMapExtraBits(uint tile);
void RunTileLoop(void); void RunTileLoop(void);
uint GetPartialZ(int x, int y, int corners); uint GetPartialZ(int x, int y, int corners);
uint GetSlopeZ(int x, int y); uint GetSlopeZ(int x, int y);
uint32 GetTileTrackStatus(TileIndex tile, TransportType mode); uint32 GetTileTrackStatus(uint tile, TransportType mode);
void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac); void GetAcceptedCargo(uint tile, AcceptedCargo ac);
void ChangeTileOwner(TileIndex tile, byte old_player, byte new_player); void ChangeTileOwner(uint tile, byte old_player, byte new_player);
void AnimateTile(TileIndex tile); void AnimateTile(uint tile);
void ClickTile(TileIndex tile); void ClickTile(uint tile);
void GetTileDesc(TileIndex tile, TileDesc *td); void GetTileDesc(uint tile, TileDesc *td);
void DrawTile(TileInfo *ti); void DrawTile(TileInfo *ti);
void UpdateTownMaxPass(Town *t);
bool IsValidTile(TileIndex tile); uint TileAddWrap(TileIndex tile, int addx, int addy);
enum {
TILE_WRAPPED = (uint)-1
};
bool IsValidTile(uint tile);
static inline Point RemapCoords(int x, int y, int z) static inline Point RemapCoords(int x, int y, int z)
{ {
@@ -43,34 +54,50 @@ static inline Point RemapCoords2(int x, int y)
return RemapCoords(x, y, GetSlopeZ(x, y)); return RemapCoords(x, y, GetSlopeZ(x, y));
} }
/* game.c */
byte *GetString(byte *buffr, uint16 string);
void InjectDparam(int amount);
int32 GetParamInt32(void);
int GetParamInt16(void);
int GetParamInt8(void);
int GetParamUint16(void);
/* clear_land.c */ /* clear_land.c */
void DrawHillyLandTile(const TileInfo *ti); void DrawHillyLandTile(TileInfo *ti);
void DrawClearLandTile(const TileInfo *ti, byte set); void DrawClearLandTile(TileInfo *ti, byte set);
void DrawClearLandFence(const TileInfo *ti); void DrawClearLandFence(TileInfo *ti, byte img);
void TileLoopClearHelper(TileIndex tile); void TileLoopClearHelper(uint tile);
/* station_land.c */
void StationPickerDrawSprite(int x, int y, int railtype, int image);
/* track_land.c */
void DrawTrainDepotSprite(int x, int y, int image, int railtype);
void DrawWaypointSprite(int x, int y, int image, int railtype);
/* road_land.c */ /* road_land.c */
void DrawRoadDepotSprite(int x, int y, int image); void DrawRoadDepotSprite(int x, int y, int image);
/* water_land.c */ /* water_land.c */
void DrawShipDepotSprite(int x, int y, int image); void DrawShipDepotSprite(int x, int y, int image);
void TileLoop_Water(TileIndex tile); void TileLoop_Water(uint tile);
/* players.c */ /* players.c */
bool CheckPlayerHasMoney(int32 cost); bool CheckPlayerHasMoney(int32 cost);
void SubtractMoneyFromPlayer(int32 cost); void SubtractMoneyFromPlayer(int32 cost);
void SubtractMoneyFromPlayerFract(PlayerID player, int32 cost); void SubtractMoneyFromPlayerFract(byte player, int32 cost);
bool CheckOwnership(PlayerID owner); bool CheckOwnership(byte owner);
bool CheckTileOwnership(TileIndex tile); bool CheckTileOwnership(uint tile);
StringID GetPlayerNameString(PlayerID player, uint index); StringID GetPlayerNameString(byte player, byte index);
/* standard */ /* standard */
void ShowInfo(const char *str); void ShowInfo(const char *str);
void CDECL ShowInfoF(const char *str, ...); void CDECL ShowInfoF(const char *str, ...);
void NORETURN CDECL error(const char *str, ...); void NORETURN CDECL error(const char *str, ...);
/* openttd.c */ /* ttd.c */
// ************** // **************
// * Warning: DO NOT enable this unless you understand what it does // * Warning: DO NOT enable this unless you understand what it does
@@ -84,21 +111,6 @@ void NORETURN CDECL error(const char *str, ...);
//#define RANDOM_DEBUG //#define RANDOM_DEBUG
// Enable this to produce higher quality random numbers.
// Doesn't work with network yet.
//#define MERSENNE_TWISTER
// Mersenne twister functions
void SeedMT(uint32 seed);
uint32 RandomMT(void);
#ifdef MERSENNE_TWISTER
static inline uint32 Random(void) { return RandomMT(); }
uint RandomRange(uint max);
#else
#ifdef RANDOM_DEBUG #ifdef RANDOM_DEBUG
#define Random() DoRandom(__LINE__, __FILE__) #define Random() DoRandom(__LINE__, __FILE__)
uint32 DoRandom(int line, const char *file); uint32 DoRandom(int line, const char *file);
@@ -108,21 +120,12 @@ uint32 RandomMT(void);
uint32 Random(void); uint32 Random(void);
uint RandomRange(uint max); uint RandomRange(uint max);
#endif #endif
#endif // MERSENNE_TWISTER
static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); }
static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); }
void InitPlayerRandoms(void);
uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */ uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */
uint InteractiveRandomRange(uint max); uint InteractiveRandomRange(uint max);
// Used for profiling
#define TIC() { extern uint32 _rdtsc(void); uint32 _xxx_ = _rdtsc(); static float __avg__;
#define TOC(s) _xxx_ = _rdtsc() - _xxx_; __avg__=__avg__*0.99+_xxx_*0.01; printf("%s: %8d %f\n", s, _xxx_,__avg__); }
void SetDate(uint date); void SetDate(uint date);
/* facedraw.c */ /* facedraw.c */
void DrawPlayerFace(uint32 face, int color, int x, int y); void DrawPlayerFace(uint32 face, int color, int x, int y);
@@ -139,18 +142,18 @@ void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...
void UndrawTextMessage(void); void UndrawTextMessage(void);
void TextMessageDailyLoop(void); void TextMessageDailyLoop(void);
bool AddAnimatedTile(TileIndex tile); bool AddAnimatedTile(uint tile);
void DeleteAnimatedTile(TileIndex tile); void DeleteAnimatedTile(uint tile);
void AnimateAnimatedTiles(void); void AnimateAnimatedTiles(void);
void InitializeAnimatedTiles(void); void InitializeAnimatedTiles(void);
/* tunnelbridge_cmd.c */ /* tunnelbridge_cmd.c */
bool CheckTunnelInWay(TileIndex tile, int z); bool CheckTunnelInWay(uint tile, int z);
bool CheckBridge_Stuff(byte bridge_type, uint bridge_len); bool CheckBridge_Stuff(byte bridge_type, int bridge_len);
uint32 GetBridgeLength(TileIndex begin, TileIndex end); uint32 GetBridgeLength(TileIndex begin, TileIndex end);
int CalcBridgeLenCostFactor(int x); int CalcBridgeLenCostFactor(int x);
typedef void CommandCallback(bool success, TileIndex tile, uint32 p1, uint32 p2); typedef void CommandCallback(bool success, uint tile, uint32 p1, uint32 p2);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd); bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
/* network.c */ /* network.c */
@@ -160,43 +163,52 @@ void NetworkShutDown(void);
void NetworkGameLoop(void); void NetworkGameLoop(void);
void NetworkUDPGameLoop(void); void NetworkUDPGameLoop(void);
bool NetworkServerStart(void); bool NetworkServerStart(void);
bool NetworkClientConnectGame(const char* host, unsigned short port); bool NetworkClientConnectGame(const byte* host, unsigned short port);
void NetworkReboot(void); void NetworkReboot(void);
void NetworkDisconnect(void); void NetworkDisconnect(void);
void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback); void NetworkSend_Command(uint32 tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
/* misc_cmd.c */ /* misc_cmd.c */
void PlaceTreesRandomly(void); void PlaceTreesRandomly(void);
uint GetTileDist(TileIndex xy1, TileIndex xy2);
uint GetTileDist1D(TileIndex xy1, TileIndex xy2);
uint GetTileDist1Db(TileIndex xy1, TileIndex xy2);
uint GetTileDistAdv(TileIndex xy1, TileIndex xy2);
bool CheckDistanceFromEdge(TileIndex tile, uint distance);
void InitializeLandscapeVariables(bool only_constants); void InitializeLandscapeVariables(bool only_constants);
/* misc.c */ /* misc.c */
void DeleteName(StringID id); void DeleteName(StringID id);
char *GetName(int id, char *buff); byte *GetName(int id, byte *buff);
// AllocateNameUnique also tests if the name used is not used anywere else // AllocateNameUnique also tests if the name used is not used anywere else
// and if it is used, it returns an error. // and if it is used, it returns an error.
#define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true) #define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true)
#define AllocateName(name, skip) RealAllocateName(name, skip, false) #define AllocateName(name, skip) RealAllocateName(name, skip, false)
StringID RealAllocateName(const char *name, byte skip, bool check_double); StringID RealAllocateName(const byte *name, byte skip, bool check_double);
void ConvertDayToYMD(YearMonthDay *ymd, uint16 date); void ConvertDayToYMD(YearMonthDay *ymd, uint16 date);
uint ConvertYMDToDay(uint year, uint month, uint day); uint ConvertYMDToDay(uint year, uint month, uint day);
uint ConvertIntDate(uint date); uint ConvertIntDate(uint date);
void CSleep(int milliseconds);
/* misc functions */ /* misc functions */
void MarkTileDirty(int x, int y); void MarkTileDirty(int x, int y);
void MarkTileDirtyByTile(TileIndex tile); void MarkTileDirtyByTile(TileIndex tile);
void InvalidateWindow(WindowClass cls, WindowNumber number); void InvalidateWindow(byte cls, WindowNumber number);
void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index); void InvalidateWindowWidget(byte cls, WindowNumber number, byte widget_index);
void InvalidateWindowClasses(WindowClass cls); void InvalidateWindowClasses(byte cls);
void DeleteWindowById(WindowClass cls, WindowNumber number); void DeleteWindowById(WindowClass cls, WindowNumber number);
void DeleteWindowByClass(WindowClass cls); void DeleteWindowByClass(WindowClass cls);
void SetObjectToPlaceWnd(CursorID icon, byte mode, Window *w); void SetObjectToPlaceWnd(int icon, byte mode, Window *w);
void SetObjectToPlace(CursorID icon, byte mode, WindowClass window_class, WindowNumber window_num); void SetObjectToPlace(int icon, byte mode, WindowClass window_class, WindowNumber window_num);
void ResetObjectToPlace(void); void ResetObjectToPlace(void);
bool ScrollWindowToTile(TileIndex tile, Window * w);
bool ScrollWindowTo(int x, int y, Window * w); bool ScrollWindowTo(int x, int y, Window * w);
bool ScrollMainWindowToTile(TileIndex tile); bool ScrollMainWindowToTile(TileIndex tile);
@@ -207,28 +219,40 @@ bool EnsureNoVehicle(TileIndex tile);
bool EnsureNoVehicleZ(TileIndex tile, byte z); bool EnsureNoVehicleZ(TileIndex tile, byte z);
void MarkAllViewportsDirty(int left, int top, int right, int bottom); void MarkAllViewportsDirty(int left, int top, int right, int bottom);
void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost); void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost);
void ShowFeederIncomeAnimation(int x, int y, int z, int32 cost);
void DrawFoundation(TileInfo *ti, uint f); void DrawFoundation(TileInfo *ti, uint f);
bool CheckIfAuthorityAllows(TileIndex tile); bool CheckIfAuthorityAllows(uint tile);
Town *ClosestTownFromTile(TileIndex tile, uint threshold); Town *ClosestTownFromTile(uint tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max); void ChangeTownRating(Town *t, int add, int max);
uint GetRoadBitsByTile(TileIndex tile); uint GetRoadBitsByTile(TileIndex tile);
int GetTownRadiusGroup(const Town *t, TileIndex tile); int GetTownRadiusGroup(Town *t, uint tile);
void ShowNetworkChatQueryWindow(byte desttype, byte dest); void ShowNetworkChatQueryWindow(byte desttype, byte dest);
void ShowNetworkGiveMoneyWindow(byte player); void ShowNetworkGiveMoneyWindow(byte player);
void ShowNetworkNeedGamePassword(void); void ShowNetworkNeedGamePassword(void);
void ShowNetworkNeedCompanyPassword(void); void ShowNetworkNeedCompanyPassword(void);
void ShowRenameWaypointWindow(Waypoint *cp);
int FindFirstBit(uint32 x); int FindFirstBit(uint32 x);
void ShowHighscoreTable(int difficulty, int8 rank); void ShowHighscoreTable(int difficulty, int8 rank);
void ShowEndGameChart(void); void ShowEndGameChart(void);
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng); TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
enum SaveOrLoadResult {
SL_OK = 0, // completed successfully
SL_ERROR = 1, // error that was caught before internal structures were modified
SL_REINIT = 2, // error that was caught in the middle of updating game state, need to clear it. (can only happen during load)
};
enum SaveOrLoadMode {
SL_INVALID = -1,
SL_LOAD = 0,
SL_SAVE = 1,
SL_OLD_LOAD = 2,
};
int SaveOrLoad(const char *filename, int mode);
void AfterLoadTown(void); void AfterLoadTown(void);
void GenRandomNewGame(uint32 rnd1, uint32 rnd2);
void StartScenarioEditor(uint32 rnd1, uint32 rnd2);
void AskExitGame(void); void AskExitGame(void);
void AskExitToGameMenu(void); void AskExitToGameMenu(void);
@@ -247,21 +271,25 @@ enum {
}; };
void ShowSaveLoadDialog(int mode); void ShowSaveLoadDialog(int mode);
void ttd_strlcpy(char *dst, const char *src, size_t size);
void ttd_strlcat(char *dst, const char *src, size_t size);
// callback from drivers that is called if the game size changes dynamically // callback from drivers that is called if the game size changes dynamically
void GameSizeChanged(void); void GameSizeChanged(void);
bool FileExists(const char *filename); bool FileExists(const char *filename);
bool ReadLanguagePack(int index); bool ReadLanguagePack(int index);
void InitializeLanguagePacks(void); void InitializeLanguagePacks(void);
void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); byte *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
int GetLanguageList(char **languages, int max); int GetLanguageList(char **languages, int max);
void CheckSwitchToEuro(void);
void LoadFromConfig(void); void LoadFromConfig(void);
void SaveToConfig(void); void SaveToConfig(void);
void CheckConfig(void);
int ttd_main(int argc, char* argv[]); int ttd_main(int argc, char* argv[]);
byte GetOSVersion(void);
void DeterminePaths(void); void DeterminePaths(void);
char * CDECL str_fmt(const char *str, ...);
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
void CSleep(int milliseconds);
#endif /* FUNCTIONS_H */ #endif /* FUNCTIONS_H */

1286
gfx.c

File diff suppressed because it is too large Load Diff

96
gfx.h
View File

@@ -1,9 +1,6 @@
/* $Id$ */
#ifndef GFX_H #ifndef GFX_H
#define GFX_H #define GFX_H
typedef byte Pixel;
typedef struct ColorList { typedef struct ColorList {
byte unk0, unk1, unk2; byte unk0, unk1, unk2;
@@ -13,20 +10,28 @@ typedef struct ColorList {
} ColorList; } ColorList;
struct DrawPixelInfo { struct DrawPixelInfo {
Pixel *dst_ptr; byte *dst_ptr;
int left, top, width, height; int left, top, width, height;
int pitch; int pitch;
uint16 zoom; uint16 zoom;
}; };
typedef struct SpriteHdr {
byte info;
byte height;
uint16 width;
int16 x_offs, y_offs;
} SpriteHdr;
assert_compile(sizeof(SpriteHdr) == 8);
typedef struct CursorVars { typedef struct CursorVars {
Point pos, size, offs, delta; Point pos, size, offs, delta;
Point draw_pos, draw_size; Point draw_pos, draw_size;
CursorID sprite; uint32 sprite;
int wheel; // mouse wheel movement int wheel; // mouse wheel movement
const CursorID *animate_list, *animate_cur; const uint16 *animate_list, *animate_cur;
uint animate_timeout; uint animate_timeout;
bool visible; bool visible;
@@ -37,69 +42,55 @@ typedef struct CursorVars {
void RedrawScreenRect(int left, int top, int right, int bottom); void RedrawScreenRect(int left, int top, int right, int bottom);
void GfxScroll(int left, int top, int width, int height, int xo, int yo); void GfxScroll(int left, int top, int width, int height, int xo, int yo);
int DrawStringCentered(int x, int y, uint16 str, uint16 color);
int DrawString(int x, int y, uint16 str, uint16 color);
// XXX doesn't really belong here, but the only void DrawStringCenterUnderline(int x, int y, uint16 str, uint16 color);
// consumers always use it in conjunction with DoDrawString() int DoDrawString(const byte *string, int x, int y, uint16 color);
#define UPARROW "\x80" void DrawStringRightAligned(int x, int y, uint16 str, uint16 color);
#define DOWNARROW "\xAA"
int DrawStringCentered(int x, int y, StringID str, uint16 color);
int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color);
int DoDrawStringCentered(int x, int y, const char *str, uint16 color);
int DrawString(int x, int y, StringID str, uint16 color);
int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw);
int DoDrawString(const char *string, int x, int y, uint16 color);
int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw);
void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color);
void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color);
void DrawStringRightAligned(int x, int y, StringID str, uint16 color);
void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw);
void GfxFillRect(int left, int top, int right, int bottom, int 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 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); void DrawFrameRect(int left, int top, int right, int bottom, int color, int flags);
uint16 GetDrawStringPlayerColor(PlayerID player); uint16 GetDrawStringPlayerColor(byte player);
int GetStringWidth(const char *str); int GetStringWidth(const byte *str);
void LoadStringWidthTable(void); void LoadStringWidthTable(void);
void DrawStringMultiCenter(int x, int y, StringID str, int maxw); void DrawStringMultiCenter(int x, int y, uint16 str, int maxw);
void DrawStringMultiLine(int x, int y, StringID str, int maxw); void DrawStringMultiLine(int x, int y, uint16 str, int maxw);
void DrawDirtyBlocks(void); void DrawDirtyBlocks(void);
void SetDirtyBlocks(int left, int top, int right, int bottom); void SetDirtyBlocks(int left, int top, int right, int bottom);
void MarkWholeScreenDirty(void); void MarkWholeScreenDirty(void);
void GfxInitPalettes(void); void GfxInitPalettes(void);
bool FillDrawPixelInfo(DrawPixelInfo* n, const DrawPixelInfo* o, int left, int top, int width, int height); bool FillDrawPixelInfo(DrawPixelInfo *n, DrawPixelInfo *o, int left, int top, int width, int height);
/* window.c */ /* window.c */
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); void DrawOverlappedWindowForAll(int left, int top, int right, int bottom);
/* spritecache.c */
byte *GetSpritePtr(uint sprite);
void GfxInitSpriteMem(byte *ptr, uint32 size);
void GfxLoadSprites(void);
void SetMouseCursor(uint cursor); void SetMouseCursor(uint cursor);
void SetAnimatedMouseCursor(const CursorID *table); void SetAnimatedMouseCursor(const uint16 *table);
void CursorTick(void); void CursorTick(void);
void DrawMouseCursor(void); void DrawMouseCursor(void);
void ScreenSizeChanged(void); void ScreenSizeChanged(void);
void UndrawMouseCursor(void); void UndrawMouseCursor(void);
bool ChangeResInGame(int w, int h); bool ChangeResInGame(int w, int h);
void SortResolutions(int count); void ToggleFullScreen(const bool full_screen);
void ToggleFullScreen(bool fs);
typedef struct {
int xoffs, yoffs;
int xsize, ysize;
} SpriteDimension;
const SpriteDimension *GetSpriteDimension(uint sprite);
/* gfx.c */ /* gfx.c */
#define ASCII_LETTERSTART 32
VARDEF int _stringwidth_base; VARDEF int _stringwidth_base;
VARDEF byte _stringwidth_table[0x2A0]; VARDEF byte _stringwidth_table[0x2A0];
static inline byte GetCharacterWidth(uint key)
{
assert(key >= ASCII_LETTERSTART && key - ASCII_LETTERSTART < lengthof(_stringwidth_table));
return _stringwidth_table[key - ASCII_LETTERSTART];
}
VARDEF DrawPixelInfo _screen; VARDEF DrawPixelInfo _screen;
VARDEF DrawPixelInfo *_cur_dpi; VARDEF DrawPixelInfo *_cur_dpi;
@@ -111,21 +102,18 @@ VARDEF int _pal_last_dirty;
VARDEF bool _use_dos_palette; VARDEF bool _use_dos_palette;
typedef struct Colour { /* spritecache.c */
byte r; //enum { NUM_SPRITES = 0x1320 };
byte g; //enum { NUM_SPRITES = 0x1500 };
byte b; enum { NUM_SPRITES = 0x3500 }; // 1500 + space for custom GRF sets
} Colour;
extern Colour _cur_palette[256]; /* tables.h */
extern byte _palettes[4][256 * 3];
VARDEF byte _cur_palette[768];
typedef enum StringColorFlags { typedef enum StringColorFlags {
IS_PALETTE_COLOR = 0x100, // color value is already a real palette color index, not an index of a StringColor IS_PALETTE_COLOR = 0x100, // color value is already a real palette color index, not an index of a StringColor
} StringColorFlags; } StringColorFlags;
#ifdef _DEBUG
extern bool _dbg_screen_rect;
#endif #endif
#endif /* GFX_H */

382
gfxinit.c
View File

@@ -1,382 +0,0 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "functions.h"
#include "gfx.h"
#include "gfxinit.h"
#include "spritecache.h"
#include "table/sprites.h"
#include "fileio.h"
#include "newgrf.h"
#include "md5.h"
#include "variables.h"
#include <ctype.h>
typedef struct MD5File {
const char * const filename; // filename
const md5_byte_t hash[16]; // md5 sum of the file
} MD5File;
typedef struct FileList {
const MD5File basic[5]; // grf files that always have to be loaded
const MD5File landscape[3]; // landscape specific grf files
} FileList;
enum {
SKIP = 0xFFFE,
END = 0xFFFF
};
#include "table/files.h"
#include "table/landscape_sprite.h"
static const SpriteID * const _landscape_spriteindexes[] = {
_landscape_spriteindexes_1,
_landscape_spriteindexes_2,
_landscape_spriteindexes_3,
};
static const SpriteID * const _slopes_spriteindexes[] = {
_slopes_spriteindexes_0,
_slopes_spriteindexes_1,
_slopes_spriteindexes_2,
_slopes_spriteindexes_3,
};
static uint LoadGrfFile(const char* filename, uint load_index, int file_index)
{
uint load_index_org = load_index;
FioOpenFile(file_index, filename);
DEBUG(spritecache, 2) ("Reading grf-file ``%s''", filename);
while (LoadNextSprite(load_index, file_index)) {
load_index++;
if (load_index >= MAX_SPRITES) {
error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
}
}
DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index);
return load_index - load_index_org;
}
static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index)
{
uint start;
FioOpenFile(file_index, filename);
DEBUG(spritecache, 2) ("Reading indexed grf-file ``%s''", filename);
while ((start = *index_tbl++) != END) {
uint end = *index_tbl++;
if (start == SKIP) { // skip sprites (amount in second var)
SkipSprites(end);
} else { // load sprites and use indexes from start to end
do {
#ifdef NDEBUG
LoadNextSprite(start, file_index);
#else
bool b = LoadNextSprite(start, file_index);
assert(b);
#endif
} while (++start <= end);
}
}
}
/* Check that the supplied MD5 hash matches that stored for the supplied filename */
static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn)
{
uint i;
/* Loop through each byte of the file MD5 and the stored MD5... */
for (i = 0; i < 16; i++) if (file.hash[i] != digest[i]) break;
/* If all bytes of the MD5's match (i.e. the MD5's match)... */
if (i == 16) {
return true;
} else {
if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename);
return false;
};
}
/* Calculate and check the MD5 hash of the supplied filename.
* returns true if the checksum is correct */
static bool FileMD5(const MD5File file, bool warn)
{
FILE *f;
char buf[MAX_PATH];
// open file
sprintf(buf, "%s%s", _path.data_dir, file.filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// make lower case and check again
for (s = buf + strlen(_path.data_dir) - 1; *s != '\0'; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
#endif
if (f != NULL) {
md5_state_t filemd5state;
md5_byte_t buffer[1024];
md5_byte_t digest[16];
size_t len;
md5_init(&filemd5state);
while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0)
md5_append(&filemd5state, buffer, len);
if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf);
fclose(f);
md5_finish(&filemd5state, digest);
return CheckMD5Digest(file, digest, warn);
} else { // file not found
return false;
}
}
/* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF)
* by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly.
* If neither are found, Windows palette is assumed.
*
* (Note: Also checks sample.cat for corruption) */
void CheckExternalFiles(void)
{
uint i;
// count of files from this version
uint dos = 0;
uint win = 0;
for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++;
for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++;
for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++;
for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++;
if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false))
fprintf(stderr, "Your sample.cat file is corrupted or missing!\n");
/*
* forced DOS palette via command line -> leave it that way
* all Windows files present -> Windows palette
* all DOS files present -> DOS palette
* no Windows files present and any DOS file present -> DOS palette
* otherwise -> Windows palette
*/
if (_use_dos_palette) {
return;
} else if (win == 5) {
_use_dos_palette = false;
} else if (dos == 5 || (win == 0 && dos > 0)) {
_use_dos_palette = true;
} else {
_use_dos_palette = false;
}
}
static const SpriteID trg1idx[] = {
0, 1, // Mouse cursor, ZZZ
/* Medium font */
2, 92, // ' ' till 'z'
SKIP, 36,
160, 160, // Move <20> to the correct position
98, 98, // Up arrow
131, 133,
SKIP, 1, // skip currency sign
135, 135,
SKIP, 1,
137, 137,
SKIP, 1,
139, 139,
140, 140, // TODO Down arrow
141, 141,
142, 142, // TODO Check mark
143, 143, // TODO Cross
144, 144,
145, 145, // TODO Right arrow
146, 149,
118, 122, // Transport markers
SKIP, 2,
157, 157,
114, 115, // Small up/down arrows
SKIP, 1,
161, 225,
/* Small font */
226, 316, // ' ' till 'z'
SKIP, 36,
384, 384, // Move <20> to the correct position
322, 322, // Up arrow
355, 357,
SKIP, 1, // skip currency sign
359, 359,
SKIP, 1,
361, 361,
SKIP, 1,
363, 363,
364, 364, // TODO Down arrow
365, 366,
SKIP, 1,
368, 368,
369, 369, // TODO Right arrow
370, 373,
SKIP, 7,
381, 381,
SKIP, 3,
385, 449,
/* Big font */
450, 540, // ' ' till 'z'
SKIP, 36,
608, 608, // Move <20> to the correct position
SKIP, 1,
579, 581,
SKIP, 1,
583, 583,
SKIP, 5,
589, 589,
SKIP, 15,
605, 605,
SKIP, 3,
609, 625,
SKIP, 1,
627, 632,
SKIP, 1,
634, 639,
SKIP, 1,
641, 657,
SKIP, 1,
659, 664,
SKIP, 2,
667, 671,
SKIP, 1,
673, 673,
/* Graphics */
674, 4792,
END
};
/* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the
* amount of sprites and add them to the end of the list, with the index of
* the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no
* correspondence of any kind with the ID's in the grf file, but results in
* a maximum use of sprite slots. */
#define OPENTTD_SPRITES_COUNT 95
static const SpriteID _openttd_grf_indexes[] = {
SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc
134, 134, // euro symbol medium size
582, 582, // euro symbol large size
358, 358, // euro symbol tiny
SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons
648, 648, // nordic char: <20>
616, 616, // nordic char: <20>
666, 666, // nordic char: <20>
634, 634, // nordic char: <20>
SPR_PIN_UP, SPR_CURSOR_CLONE, // more icons
382, 383, // <20> <20> tiny
158, 159, // <20> <20> medium
606, 607, // <20> <20> large
360, 360, // <20> tiny
362, 362, // <20> tiny
136, 136, // <20> medium
138, 138, // <20> medium
584, 584, // <20> large
586, 586, // <20> large
626, 626, // <20> large
658, 658, // <20> large
374, 374, // <20> tiny
378, 378, // <20> tiny
150, 150, // <20> medium
154, 154, // <20> medium
598, 598, // <20> large
602, 602, // <20> large
640, 640, // <20> large
672, 672, // <20> large
380, 380, // <20> tiny
156, 156, // <20> medium
604, 604, // <20> large
317, 320, // { | } ~ tiny
93, 96, // { | } ~ medium
541, 544, // { | } ~ large
SPR_HOUSE_ICON, SPR_HOUSE_ICON,
585, 585, // <20> large
587, 587, // <20> large
592, 592, // <20> large
594, 597, // <20> <20> <20> <20> large
633, 633, // <20> large
665, 665, // <20> large
END
};
static byte _sprite_page_to_load = 0xFF;
static void LoadSpriteTables(void)
{
const FileList* files = _use_dos_palette ? &files_dos : &files_win;
uint load_index;
uint i;
LoadGrfIndexed(files->basic[0].filename, trg1idx, 0);
DupSprite( 2, 130); // non-breaking space medium
DupSprite(226, 354); // non-breaking space tiny
DupSprite(450, 578); // non-breaking space large
load_index = 4793;
for (i = 1; files->basic[i].filename != NULL; i++) {
load_index += LoadGrfFile(files->basic[i].filename, load_index, i);
}
if (_sprite_page_to_load != 0) {
LoadGrfIndexed(
files->landscape[_sprite_page_to_load - 1].filename,
_landscape_spriteindexes[_sprite_page_to_load - 1],
i++
);
}
assert(load_index == SPR_CANALS_BASE);
load_index += LoadGrfFile("canalsw.grf", load_index, i++);
assert(load_index == SPR_SLOPES_BASE);
LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
load_index = SPR_AUTORAIL_BASE;
load_index += LoadGrfFile("autorail.grf", load_index, i++);
assert(load_index == SPR_OPENTTD_BASE);
LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++);
load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT;
LoadNewGRF(load_index, i);
}
void GfxLoadSprites(void)
{
// Need to reload the sprites only if the landscape changed
if (_sprite_page_to_load != _opt.landscape) {
_sprite_page_to_load = _opt.landscape;
// Sprite cache
DEBUG(spritecache, 1) ("Loading sprite set %d.", _sprite_page_to_load);
GfxInitSpriteMem();
LoadSpriteTables();
GfxInitPalettes();
}
}

View File

@@ -1,9 +0,0 @@
/* $Id$ */
#ifndef GFXINIT_H
#define GFXINIT_H
void CheckExternalFiles(void);
void GfxLoadSprites(void);
#endif /* GFXINIT_H */

View File

@@ -1,19 +1,11 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h"
#include "functions.h"
#include "window.h" #include "window.h"
#include "gui.h" #include "gui.h"
#include "gfx.h" #include "gfx.h"
#include "player.h" #include "player.h"
#include "economy.h" #include "economy.h"
#include "signs.h"
#include "strings.h"
#include "debug.h"
#include "variables.h"
static uint _legend_excludebits; static uint _legend_excludebits;
static uint _legend_cargobits; static uint _legend_cargobits;
@@ -44,7 +36,7 @@ typedef struct GraphDrawer {
#define INVALID_VALUE 0x80000000 #define INVALID_VALUE 0x80000000
static void DrawGraph(const GraphDrawer *gw) static void DrawGraph(GraphDrawer *gw)
{ {
int i,j,k; int i,j,k;
@@ -52,7 +44,7 @@ static void DrawGraph(const GraphDrawer *gw)
int color; int color;
int right, bottom; int right, bottom;
int num_x, num_dataset; int num_x, num_dataset;
const uint64 *row_ptr, *col_ptr; uint64 *row_ptr, *col_ptr;
int64 mx; int64 mx;
int adj_height; int adj_height;
uint64 y_scaling, tmp; uint64 y_scaling, tmp;
@@ -219,18 +211,20 @@ void DrawPlayerIcon(int p, int x, int y)
static void GraphLegendWndProc(Window *w, WindowEvent *e) static void GraphLegendWndProc(Window *w, WindowEvent *e)
{ {
const Player* p; Player *p;
switch(e->event) { switch(e->event) {
case WE_PAINT: case WE_PAINT:
FOR_ALL_PLAYERS(p) { FOR_ALL_PLAYERS(p) {
if (!p->is_active) SETBIT(_legend_excludebits, p->index); if (!p->is_active)
SETBIT(_legend_excludebits, p->index);
} }
w->click_state = (~_legend_excludebits) << 3; w->click_state = ((~_legend_excludebits) << 3);
DrawWindowWidgets(w); DrawWindowWidgets(w);
FOR_ALL_PLAYERS(p) { FOR_ALL_PLAYERS(p) {
if (!p->is_active) continue; if (!p->is_active)
continue;
DrawPlayerIcon(p->index, 4, 18+p->index*12); DrawPlayerIcon(p->index, 4, 18+p->index*12);
@@ -243,7 +237,7 @@ static void GraphLegendWndProc(Window *w, WindowEvent *e)
case WE_CLICK: case WE_CLICK:
if (IS_INT_INSIDE(e->click.widget, 3, 11)) { if (IS_INT_INSIDE(e->click.widget, 3, 11)) {
_legend_excludebits ^= (1 << (e->click.widget - 3)); _legend_excludebits ^= (1 << (e->click.widget-3));
SetWindowDirty(w); SetWindowDirty(w);
InvalidateWindow(WC_INCOME_GRAPH, 0); InvalidateWindow(WC_INCOME_GRAPH, 0);
InvalidateWindow(WC_OPERATING_PROFIT, 0); InvalidateWindow(WC_OPERATING_PROFIT, 0);
@@ -256,7 +250,7 @@ static void GraphLegendWndProc(Window *w, WindowEvent *e)
} }
static const Widget _graph_legend_widgets[] = { static const Widget _graph_legend_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0,STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0,STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, { WWT_IMGBTN, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0,STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
@@ -289,7 +283,7 @@ static void ShowGraphLegend(void)
static void SetupGraphDrawerForPlayers(GraphDrawer *gd) static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
{ {
const Player* p; Player *p;
uint excludebits = _legend_excludebits; uint excludebits = _legend_excludebits;
int nums; int nums;
int mo,yr; int mo,yr;
@@ -323,7 +317,7 @@ static void OperatingProfitWndProc(Window *w, WindowEvent *e)
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
GraphDrawer gd; GraphDrawer gd;
const Player* p; Player *p;
int i,j; int i,j;
int numd; int numd;
@@ -333,7 +327,7 @@ static void OperatingProfitWndProc(Window *w, WindowEvent *e)
gd.top = 18; gd.top = 18;
gd.height = 136; gd.height = 136;
gd.include_neg = true; gd.include_neg = true;
gd.format_str_y_axis = STR_CURRCOMPACT; gd.format_str_y_axis = STR_CURRCOMPACT32;
gd.color_3 = 0x10; gd.color_3 = 0x10;
gd.color_2 = 0xD7; gd.color_2 = 0xD7;
gd.bg_line_color = 0xE; gd.bg_line_color = 0xE;
@@ -364,7 +358,7 @@ static void OperatingProfitWndProc(Window *w, WindowEvent *e)
} }
static const Widget _operating_profit_widgets[] = { static const Widget _operating_profit_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL},
@@ -397,7 +391,7 @@ static void IncomeGraphWndProc(Window *w, WindowEvent *e)
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
GraphDrawer gd; GraphDrawer gd;
const Player* p; Player *p;
int i,j; int i,j;
int numd; int numd;
@@ -407,7 +401,7 @@ static void IncomeGraphWndProc(Window *w, WindowEvent *e)
gd.top = 18; gd.top = 18;
gd.height = 104; gd.height = 104;
gd.include_neg = false; gd.include_neg = false;
gd.format_str_y_axis = STR_CURRCOMPACT; gd.format_str_y_axis = STR_CURRCOMPACT32;
gd.color_3 = 0x10; gd.color_3 = 0x10;
gd.color_2 = 0xD7; gd.color_2 = 0xD7;
gd.bg_line_color = 0xE; gd.bg_line_color = 0xE;
@@ -439,7 +433,7 @@ static void IncomeGraphWndProc(Window *w, WindowEvent *e)
} }
static const Widget _income_graph_widgets[] = { static const Widget _income_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
@@ -470,7 +464,7 @@ static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
GraphDrawer gd; GraphDrawer gd;
const Player* p; Player *p;
int i,j; int i,j;
int numd; int numd;
@@ -512,7 +506,7 @@ static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
} }
static const Widget _delivered_cargo_graph_widgets[] = { static const Widget _delivered_cargo_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
@@ -543,7 +537,7 @@ static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
GraphDrawer gd; GraphDrawer gd;
const Player* p; Player *p;
int i,j; int i,j;
int numd; int numd;
@@ -587,7 +581,7 @@ static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
} }
static const Widget _performance_history_widgets[] = { static const Widget _performance_history_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
@@ -619,7 +613,7 @@ static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
switch(e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
GraphDrawer gd; GraphDrawer gd;
const Player* p; Player *p;
int i,j; int i,j;
int numd; int numd;
@@ -629,7 +623,7 @@ static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
gd.top = 18; gd.top = 18;
gd.height = 200; gd.height = 200;
gd.include_neg = false; gd.include_neg = false;
gd.format_str_y_axis = STR_CURRCOMPACT; gd.format_str_y_axis = STR_CURRCOMPACT64;
gd.color_3 = 0x10; gd.color_3 = 0x10;
gd.color_2 = 0xD7; gd.color_2 = 0xD7;
gd.bg_line_color = 0xE; gd.bg_line_color = 0xE;
@@ -661,7 +655,7 @@ static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
} }
static const Widget _company_value_graph_widgets[] = { static const Widget _company_value_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
@@ -715,7 +709,7 @@ static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
gd.top = 24; gd.top = 24;
gd.height = 104; gd.height = 104;
gd.include_neg = false; gd.include_neg = false;
gd.format_str_y_axis = STR_CURRCOMPACT; gd.format_str_y_axis = STR_CURRCOMPACT32;
gd.color_3 = 16; gd.color_3 = 16;
gd.color_2 = 215; gd.color_2 = 215;
gd.bg_line_color = 14; gd.bg_line_color = 14;
@@ -813,60 +807,69 @@ static inline StringID GetPerformanceTitleFromValue(uint value)
return _performance_titles[minu(value, 1000) >> 6]; return _performance_titles[minu(value, 1000) >> 6];
} }
static int CDECL PerfHistComp(const void* elem1, const void* elem2) static int CDECL _perf_hist_comp(const void *elem1, const void *elem2 ) {
{ const Player *p1 = *(const Player* const *)elem1;
const Player* p1 = *(const Player* const*)elem1; const Player *p2 = *(const Player* const *)elem2;
const Player* p2 = *(const Player* const*)elem2; int32 v = p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
return (v!=0) | (v >> (sizeof(int32)*8-1));
return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
} }
static void CompanyLeagueWndProc(Window *w, WindowEvent *e) static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
{ {
switch (e->event) { switch(e->event) {
case WE_PAINT: { case WE_PAINT: {
const Player* plist[MAX_PLAYERS]; Player *p;
const Player* p; Player *plist[MAX_PLAYERS];
uint pl_num; size_t pl_num, i;
uint i;
DrawWindowWidgets(w); DrawWindowWidgets(w);
pl_num = 0; pl_num=0;
FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p; FOR_ALL_PLAYERS(p) {
if (p->is_active)
qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp); plist[pl_num++] = p;
for (i = 0; i != pl_num; i++) {
p = plist[i];
SetDParam(0, i + STR_01AC_1ST);
SetDParam(1, p->name_1);
SetDParam(2, p->name_2);
SetDParam(3, GetPlayerNameString(p->index, 4));
SetDParam(5, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
DrawPlayerIcon(p->index, 27, 16 + i * 10);
}
break;
} }
assert(pl_num > 0);
qsort(plist, pl_num, sizeof(Player*), _perf_hist_comp);
i = 0;
do {
SetDParam(0, i + 1 + STR_01AB);
p = plist[i];
SetDParam(1, p->name_1);
SetDParam(2, p->name_2);
SetDParam(3, GetPlayerNameString(p->index, 4));
/* WARNING ugly hack!
GetPlayerNameString sets up (Player #) if the player is human in an extra DPARAM16
It seems that if player is non-human, nothing is set up, so param is 0. GetString doesn't like
that because there is another param after it.
So we'll just shift the rating one back if player is AI and all is fine
*/
SetDParam((IS_HUMAN_PLAYER(p->index) ? 5 : 4), GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
DrawPlayerIcon(p->index, 27, 16 + i * 10);
} while (++i != pl_num);
break;
}
} }
} }
static const Widget _company_league_widgets[] = { static const Widget _company_league_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 387, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 399, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL},
{ WIDGETS_END}, { WIDGETS_END},
}; };
static const WindowDesc _company_league_desc = { static const WindowDesc _company_league_desc = {
-1, -1, 400, 97, -1, -1, 400, 97,
WC_COMPANY_LEAGUE,0, WC_COMPANY_LEAGUE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_company_league_widgets, _company_league_widgets,
CompanyLeagueWndProc CompanyLeagueWndProc
}; };
@@ -898,7 +901,7 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
// Paint the player icons // Paint the player icons
for (i=0;i<MAX_PLAYERS;i++) { for (i=0;i<MAX_PLAYERS;i++) {
if (!GetPlayer(i)->is_active) { if (!DEREF_PLAYER(i)->is_active) {
// Check if we have the player as an active player // Check if we have the player as an active player
if (!(w->disabled_state & (1 << (i+13)))) { if (!(w->disabled_state & (1 << (i+13)))) {
// Bah, player gone :( // Bah, player gone :(
@@ -932,8 +935,8 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
for (i=0;i<NUM_SCORE;i++) { for (i=0;i<NUM_SCORE;i++) {
y += 20; y += 20;
val = _score_part[owner][i]; val = _score_part[owner][i];
needed = _score_info[i].needed; needed = score_info[i].needed;
score = _score_info[i].score; score = score_info[i].score;
// SCORE_TOTAL has his own rulez ;) // SCORE_TOTAL has his own rulez ;)
if (i == SCORE_TOTAL) { if (i == SCORE_TOTAL) {
needed = total_score; needed = total_score;
@@ -1018,7 +1021,7 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
// Hide the player who are not active // Hide the player who are not active
for (i=0;i<MAX_PLAYERS;i++) { for (i=0;i<MAX_PLAYERS;i++) {
if (!GetPlayer(i)->is_active) { if (!DEREF_PLAYER(i)->is_active) {
w->disabled_state += 1 << (i+13); w->disabled_state += 1 << (i+13);
} }
} }
@@ -1057,7 +1060,7 @@ static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
} }
static const Widget _performance_rating_detail_widgets[] = { static const Widget _performance_rating_detail_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL},
@@ -1095,147 +1098,3 @@ void ShowPerformanceRatingDetail(void)
{ {
AllocateWindowDescFront(&_performance_rating_detail_desc, 0); AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
} }
static uint16 _num_sign_sort;
static char _bufcache[64];
static uint16 _last_sign_idx;
static int CDECL SignNameSorter(const void *a, const void *b)
{
char buf1[64];
SignStruct *ss;
const uint16 cmp1 = *(const uint16 *)a;
const uint16 cmp2 = *(const uint16 *)b;
ss = GetSign(cmp1);
GetString(buf1, ss->str);
if (cmp2 != _last_sign_idx) {
_last_sign_idx = cmp2;
ss = GetSign(cmp2);
GetString(_bufcache, ss->str);
}
return strcmp(buf1, _bufcache); // sort by name
}
static void GlobalSortSignList(void)
{
const SignStruct *ss;
uint32 n = 0;
_num_sign_sort = 0;
/* Create array for sorting */
_sign_sort = realloc(_sign_sort, GetSignPoolSize() * sizeof(_sign_sort[0]));
if (_sign_sort == NULL)
error("Could not allocate memory for the sign-sorting-list");
FOR_ALL_SIGNS(ss) {
if(ss->str != STR_NULL) {
_sign_sort[n++] = ss->index;
_num_sign_sort++;
}
}
qsort(_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);
_sign_sort_dirty = false;
DEBUG(misc, 1) ("Resorting global sign list...");
}
static void SignListWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
int y = 16; // offset from top of widget
if (_sign_sort_dirty)
GlobalSortSignList();
SetVScrollCount(w, _num_sign_sort);
SetDParam(0, w->vscroll.count);
DrawWindowWidgets(w);
/* No signs? */
if (w->vscroll.count == 0) {
DrawString(2, y, STR_304A_NONE, 0);
return;
}
{ const SignStruct *ss;
uint16 i;
/* Start drawing the signs */
for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
ss = GetSign(_sign_sort[i]);
if (ss->owner != OWNER_NONE)
DrawPlayerIcon(ss->owner, 4, y + 1);
DrawString(22, y, ss->str, 8);
y += 10;
}
}
} break;
case WE_CLICK: {
switch (e->click.widget) {
case 3: {
uint32 id_v = (e->click.pt.y - 15) / 10;
SignStruct *ss;
if (id_v >= w->vscroll.cap)
return;
id_v += w->vscroll.pos;
if (id_v >= w->vscroll.count)
return;
ss = GetSign(_sign_sort[id_v]);
ScrollMainWindowToTile(TileVirtXY(ss->x, ss->y));
} break;
}
} break;
case WE_RESIZE:
w->vscroll.cap += e->sizing.diff.y / 10;
break;
}
}
static const Widget _sign_list_widget[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_RIGHT, 14, 11, 345, 0, 13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_LR, 14, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, RESIZE_RB, 14, 0, 345, 14, 137, 0x0, STR_NULL},
{ WWT_SCROLLBAR, RESIZE_LRB, 14, 346, 357, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_RESIZEBOX, RESIZE_LRTB, 14, 346, 357, 126, 137, 0x0, STR_RESIZE_BUTTON},
{ WIDGETS_END},
};
static const WindowDesc _sign_list_desc = {
-1, -1, 358, 138,
WC_SIGN_LIST,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_sign_list_widget,
SignListWndProc
};
void ShowSignList(void)
{
Window *w;
w = AllocateWindowDescFront(&_sign_list_desc, 0);
if (w != NULL) {
w->vscroll.cap = 12;
w->resize.step_height = 10;
w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
}
}

82
gui.h
View File

@@ -1,22 +1,18 @@
/* $Id$ */
#ifndef GUI_H #ifndef GUI_H
#define GUI_H #define GUI_H
#include "station.h"
#include "window.h" #include "window.h"
/* main_gui.c */ /* main_gui.c */
void SetupColorsAndInitialWindow(void); void SetupColorsAndInitialWindow(void);
void CcPlaySound10(bool success, TileIndex tile, uint32 p1, uint32 p2); void CcPlaySound10(bool success, uint tile, uint32 p1, uint32 p2);
void CcBuildCanal(bool success, TileIndex tile, uint32 p1, uint32 p2);
void CcTerraform(bool success, TileIndex tile, uint32 p1, uint32 p2);
/* settings_gui.c */ /* settings_gui.c */
void ShowGameOptions(void); void ShowGameOptions(void);
void ShowGameDifficulty(void); void ShowGameDifficulty(void);
void ShowPatchesSelection(void); void ShowPatchesSelection(void);
void ShowNewgrf(void); void ShowNewgrf(void);
void ShowCustCurrency(void);
/* graph_gui.c */ /* graph_gui.c */
void ShowOperatingProfitGraph(void); void ShowOperatingProfitGraph(void);
@@ -34,47 +30,39 @@ void ShowMessageOptions(void);
void ShowMessageHistory(void); void ShowMessageHistory(void);
/* traintoolb_gui.c */ /* traintoolb_gui.c */
void ShowBuildRailToolbar(RailType railtype, int button); void ShowBuildRailToolbar(int index, int button);
void PlaceProc_BuyLand(TileIndex tile); void PlaceProc_BuyLand(uint tile);
/* train_gui.c */ /* train_gui.c */
void ShowPlayerTrains(PlayerID player, StationID station); void ShowPlayerTrains(int player, int station);
void ShowTrainViewWindow(const Vehicle *v); void ShowTrainViewWindow(Vehicle *v);
void ShowOrdersWindow(const Vehicle* v); void ShowTrainDetailsWindow(Vehicle *v);
void ShowOrdersWindow(Vehicle *v);
void ShowRoadVehViewWindow(const Vehicle* v); void ShowRoadVehViewWindow(Vehicle *v);
/* road_gui.c */ /* road_gui.c */
void ShowBuildRoadToolbar(void); void ShowBuildRoadToolbar(void);
void ShowBuildRoadScenToolbar(void); void ShowBuildRoadScenToolbar(void);
void ShowPlayerRoadVehicles(PlayerID player, StationID station); void ShowPlayerRoadVehicles(int player, int station);
/* dock_gui.c */ /* dock_gui.c */
void ShowBuildDocksToolbar(void); void ShowBuildDocksToolbar(void);
void ShowPlayerShips(PlayerID player, StationID station); void ShowPlayerShips(int player, int station);
void ShowShipViewWindow(const Vehicle* v); void ShowShipViewWindow(Vehicle *v);
/* aircraft_gui.c */ /* aircraft_gui.c */
void ShowBuildAirToolbar(void); void ShowBuildAirToolbar(void);
void ShowPlayerAircraft(PlayerID player, StationID station); void ShowPlayerAircraft(int player, int station);
/* terraform_gui.c */ /* terraform_gui.c */
void PlaceProc_DemolishArea(uint tile);
void PlaceProc_LowerLand(uint tile);
void PlaceProc_RaiseLand(uint tile);
void PlaceProc_LevelLand(uint tile);
void ShowTerraformToolbar(void); void ShowTerraformToolbar(void);
void PlaceProc_DemolishArea(TileIndex tile);
void PlaceProc_LevelLand(TileIndex tile);
bool GUIPlaceProcDragXY(const WindowEvent *we);
enum { // max 32 - 4 = 28 types
GUI_PlaceProc_DemolishArea = 0 << 4,
GUI_PlaceProc_LevelArea = 1 << 4,
GUI_PlaceProc_DesertArea = 2 << 4,
GUI_PlaceProc_WaterArea = 3 << 4,
GUI_PlaceProc_ConvertRailArea = 4 << 4,
GUI_PlaceProc_RockyArea = 5 << 4,
};
/* misc_gui.c */ /* misc_gui.c */
void PlaceLandBlockInfo(void); void PlaceLandBlockInfo(void);
void ShowAboutWindow(void); void ShowAboutWindow(void);
@@ -83,47 +71,39 @@ void ShowBuildTreesScenToolbar(void);
void ShowTownDirectory(void); void ShowTownDirectory(void);
void ShowIndustryDirectory(void); void ShowIndustryDirectory(void);
void ShowSubsidiesList(void); void ShowSubsidiesList(void);
void ShowPlayerStations(PlayerID player); void ShowPlayerStations(int player);
void ShowPlayerFinances(PlayerID player); void ShowPlayerFinances(int player);
void ShowPlayerCompany(PlayerID player); void ShowPlayerCompany(int player);
void ShowSignList(void);
void ShowEstimatedCostOrIncome(int32 cost, int x, int y); void ShowEstimatedCostOrIncome(int32 cost, int x, int y);
void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y); void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y);
void DrawStationCoverageAreaText(int sx, int sy, uint mask,int rad); void DrawStationCoverageAreaText(int sx, int sy, uint mask,int rad);
void CheckRedrawStationCoverage(const Window* w); void CheckRedrawStationCoverage(Window *w);
void ShowSmallMap(void); void ShowSmallMap(void);
void ShowExtraViewPortWindow(void); void ShowExtraViewPortWindow(void);
void SetVScrollCount(Window *w, int num); void SetVScrollCount(Window *w, int num);
void SetVScroll2Count(Window *w, int num); void SetVScroll2Count(Window *w, int num);
void SetHScrollCount(Window *w, int num); void SetHScrollCount(Window *w, int num);
int HandleEditBoxKey(Window *w, int wid, WindowEvent *we);
void ShowCheatWindow(void); void ShowCheatWindow(void);
void AskForNewGameToStart(void); void AskForNewGameToStart(void);
void DrawEditBox(Window *w, querystr_d *string, int wid); void DrawEditBox(Window *w, int wid);
void HandleEditBox(Window *w, querystr_d *string, int wid); void HandleEditBox(Window *w, int wid);
int HandleEditBoxKey(Window *w, querystr_d *string, int wid, WindowEvent *we);
bool HandleCaret(Textbuf *tb);
void DeleteTextBufferAll(Textbuf *tb);
bool DeleteTextBufferChar(Textbuf *tb, int delmode);
bool InsertTextBufferChar(Textbuf *tb, byte key);
bool InsertTextBufferClipboard(Textbuf *tb);
bool MoveTextBufferPos(Textbuf *tb, int navmode);
void UpdateTextBufferSize(Textbuf *tb);
void BuildFileList(void); void BuildFileList(void);
void SetFiosType(const byte fiostype); void SetFiosType(const byte fiostype);
/* FIOS_TYPE_FILE, FIOS_TYPE_OLDFILE etc. different colours */ /* FIOS_TYPE_FILE, FIOS_TYPE_OLDFILE etc. different colours */
extern const byte _fios_colors[]; static const byte _fios_colors[] = {13, 9, 9, 6, 5, 6, 5};
/* network gui */ /* network gui */
void ShowNetworkGameWindow(void); void ShowNetworkGameWindow(void);
void ShowChatWindow(StringID str, StringID caption, int maxlen, int maxwidth, WindowClass window_class, WindowNumber window_number); void ShowChatWindow(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
/* bridge_gui.c */ /* bridge_gui.c */
void ShowBuildBridgeWindow(uint start, uint end, byte type); void ShowBuildBridgeWindow(uint start, uint end, byte type);
@@ -136,14 +116,14 @@ enum {
bool DoZoomInOutWindow(int how, Window * w); bool DoZoomInOutWindow(int how, Window * w);
void ShowBuildIndustryWindow(void); void ShowBuildIndustryWindow(void);
void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, WindowClass window_class, WindowNumber window_number); void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
void ShowMusicWindow(void); void ShowMusicWindow(void);
/* main_gui.c */ /* main_gui.c */
VARDEF byte _newspaper_flag;
VARDEF byte _construct_mode;
VARDEF byte _station_show_coverage; VARDEF byte _station_show_coverage;
VARDEF PlaceProc *_place_proc; VARDEF PlaceProc *_place_proc;
VARDEF bool _no_button_sound;
/* vehicle_gui.c */
void InitializeGUI(void);
#endif /* GUI_H */ #endif /* GUI_H */

91
hal.h
View File

@@ -1,29 +1,31 @@
/* $Id$ */
#ifndef HAL_H #ifndef HAL_H
#define HAL_H #define HAL_H
typedef struct { typedef struct {
const char *(*start)(const char * const *parm); char *(*start)(char **parm);
void (*stop)(void); void (*stop)(void);
} HalCommonDriver; } HalCommonDriver;
typedef struct { typedef struct {
const char *(*start)(const char * const *parm); const char *(*start)(char **parm);
void (*stop)(void); void (*stop)(void);
void (*make_dirty)(int left, int top, int width, int height); void (*make_dirty)(int left, int top, int width, int height);
void (*main_loop)(void); int (*main_loop)(void);
bool (*change_resolution)(int w, int h); bool (*change_resolution)(int w, int h);
void (*toggle_fullscreen)(bool fullscreen);
} HalVideoDriver; } HalVideoDriver;
enum {
ML_QUIT = 0,
ML_SWITCHDRIVER = 1,
};
typedef struct { typedef struct {
const char *(*start)(const char * const *parm); char *(*start)(char **parm);
void (*stop)(void); void (*stop)(void);
} HalSoundDriver; } HalSoundDriver;
typedef struct { typedef struct {
const char *(*start)(const char * const *parm); char *(*start)(char **parm);
void (*stop)(void); void (*stop)(void);
void (*play_song)(const char *filename); void (*play_song)(const char *filename);
@@ -32,10 +34,49 @@ typedef struct {
void (*set_volume)(byte vol); void (*set_volume)(byte vol);
} HalMusicDriver; } HalMusicDriver;
typedef struct {
const char *name;
const char *longname;
const void *drv;
uint32 flags;
} DriverDesc;
enum {
HALERR_OK = 0,
HALERR_ERROR = 1,
};
extern const HalMusicDriver _null_music_driver;
extern const HalVideoDriver _null_video_driver;
extern const HalSoundDriver _null_sound_driver;
VARDEF HalMusicDriver *_music_driver; VARDEF HalMusicDriver *_music_driver;
VARDEF HalSoundDriver *_sound_driver; VARDEF HalSoundDriver *_sound_driver;
VARDEF HalVideoDriver *_video_driver; VARDEF HalVideoDriver *_video_driver;
extern const DriverDesc _video_driver_descs[];
extern const DriverDesc _sound_driver_descs[];
extern const DriverDesc _music_driver_descs[];
#if defined(WITH_SDL)
extern const HalSoundDriver _sdl_sound_driver;
extern const HalVideoDriver _sdl_video_driver;
#endif
#if defined(UNIX)
extern const HalMusicDriver _extmidi_music_driver;
#endif
#if defined(__BEOS__)
extern const HalMusicDriver _bemidi_music_driver;
#endif
#if defined(__OS2__)
extern const HalMusicDriver _os2_music_driver;
#endif
extern const HalVideoDriver _dedicated_video_driver;
enum DriverType { enum DriverType {
VIDEO_DRIVER = 0, VIDEO_DRIVER = 0,
SOUND_DRIVER = 1, SOUND_DRIVER = 1,
@@ -43,16 +84,37 @@ enum DriverType {
}; };
extern void GameLoop(void); extern void GameLoop(void);
extern bool _dbg_screen_rect;
void LoadDriver(int driver, const char *name);
char *GetDriverParam(char **parm, const char *name);
bool GetDriverParamBool(char **parm, const char *name);
int GetDriverParamInt(char **parm, const char *name, int def);
// Deals with finding savegames // Deals with finding savegames
typedef struct { typedef struct {
uint16 id;
byte type; byte type;
uint64 mtime; uint64 mtime;
char title[64]; char title[64];
char name[256-12-64]; char name[256-12-64];
int old_extension;
} FiosItem; } FiosItem;
// extensions of old savegames, scenarios
static const char* const _old_extensions[] = {
// old savegame types
"ss1", // Transport Tycoon Deluxe preset game
"sv1", // Transport Tycoon Deluxe (Patch) saved game
"sv2", // Transport Tycoon Deluxe (Patch) saved 2-player game
// old scenario game type
"sv0", // Transport Tycoon Deluxe (Patch) scenario
"ss0", // Transport Tycoon Deluxe preset scenario
};
enum { enum {
FIOS_TYPE_DRIVE = 0, FIOS_TYPE_DRIVE = 0,
FIOS_TYPE_PARENT = 1, FIOS_TYPE_PARENT = 1,
@@ -61,7 +123,6 @@ enum {
FIOS_TYPE_OLDFILE = 4, FIOS_TYPE_OLDFILE = 4,
FIOS_TYPE_SCENARIO = 5, FIOS_TYPE_SCENARIO = 5,
FIOS_TYPE_OLD_SCENARIO = 6, FIOS_TYPE_OLD_SCENARIO = 6,
FIOS_TYPE_DIRECT = 7,
}; };
@@ -83,14 +144,14 @@ FiosItem *FiosGetScenarioList(int *num, int mode);
void FiosFreeSavegameList(void); void FiosFreeSavegameList(void);
// Browse to. Returns a filename w/path if we reached a file. // Browse to. Returns a filename w/path if we reached a file.
char *FiosBrowseTo(const FiosItem *item); char *FiosBrowseTo(const FiosItem *item);
// Return path, free space and stringID // Get descriptive texts.
StringID FiosGetDescText(const char **path, uint32 *tot); // Returns a path as well as a
// string describing the path.
StringID FiosGetDescText(const char **path);
// Delete a name // Delete a name
bool FiosDelete(const char *name); void FiosDelete(const char *name);
// Make a filename from a name // Make a filename from a name
void FiosMakeSavegameName(char *buf, const char *name, size_t size); void FiosMakeSavegameName(char *buf, const char *name);
int CDECL compare_FiosItems(const void *a, const void *b);
void CreateConsole(void); void CreateConsole(void);

View File

@@ -1,15 +1,11 @@
/* $Id$ */
#ifndef INDUSTRY_H #ifndef INDUSTRY_H
#define INDUSTRY_H #define INDUSTRY_H
#include "pool.h"
struct Industry { struct Industry {
TileIndex xy; TileIndex xy;
byte width; /* swapped order of w/h with town */ byte width; /* swapped order of w/h with town */
byte height; byte height;
const Town* town; Town *town;
byte produced_cargo[2]; byte produced_cargo[2];
uint16 cargo_waiting[2]; uint16 cargo_waiting[2];
byte production_rate[2]; byte production_rate[2];
@@ -31,40 +27,22 @@ struct Industry {
uint16 index; uint16 index;
}; };
extern MemoryPool _industry_pool;
/**
* Check if an Industry really exists.
*/
static inline bool IsValidIndustry(Industry* industry)
{
return industry->xy != 0; /* XXX: Replace by INVALID_TILE someday */
}
/**
* Get the pointer to the industry with index 'index'
*/
static inline Industry *GetIndustry(uint index)
{
return (Industry*)GetItemFromPool(&_industry_pool, index);
}
/**
* Get the current size of the IndustryPool
*/
static inline uint16 GetIndustryPoolSize(void)
{
return _industry_pool.total_items;
}
#define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1 < GetIndustryPoolSize()) ? GetIndustry(i->index + 1) : NULL)
#define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0)
VARDEF int _total_industries; // For the AI: the amount of industries active VARDEF int _total_industries; // For the AI: the amount of industries active
VARDEF uint16 *_industry_sort; VARDEF Industry _industries[90];
VARDEF bool _industry_sort_dirty; VARDEF uint _industries_size;
VARDEF uint16 *_industry_sort;
static inline Industry *GetIndustry(uint index)
{
assert(index < _industries_size);
return &_industries[index];
}
#define FOR_ALL_INDUSTRIES(i) for(i = _industries; i != &_industries[_industries_size]; i++)
VARDEF bool _industry_sort_dirty;
void DeleteIndustry(Industry *is); void DeleteIndustry(Industry *is);
enum { enum {
@@ -107,4 +85,4 @@ enum {
IT_SUGAR_MINE = 36, IT_SUGAR_MINE = 36,
}; };
#endif /* INDUSTRY_H */ #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,27 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "debug.h"
#include "functions.h"
#include "strings.h"
#include "table/strings.h" #include "table/strings.h"
#include "table/sprites.h"
#include "map.h" #include "map.h"
#include "gui.h" //#include "gui.h"
#include "window.h" #include "window.h"
#include "gfx.h" #include "gfx.h"
#include "command.h" #include "command.h"
#include "viewport.h" #include "viewport.h"
#include "industry.h" #include "industry.h"
#include "town.h" #include "town.h"
#include "variables.h"
/* Present in table/build_industry.h" */ static const byte _build_industry_types[4][12] = {
extern const byte _build_industry_types[4][12]; { 1, 2, 4, 6, 8, 0, 3, 5, 9, 11, 18 },
{ 1, 14, 4, 13, 7, 0, 3, 9, 11, 15 },
{ 25, 13, 4, 23, 22, 11, 17, 10, 24, 19, 20, 21 },
{ 27, 30, 31, 33, 26, 28, 29, 32, 34, 35, 36 },
};
extern const byte _industry_type_costs[37]; extern const byte _industry_type_costs[37];
static void UpdateIndustryProduction(Industry *i); static void UpdateIndustryProduction(Industry *i);
extern void DrawArrowButtons(int x, int y, int state); extern void DrawArrowButtons(int x, int y, int state);
extern void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
static void BuildIndustryWndProc(Window *w, WindowEvent *e) static void BuildIndustryWndProc(Window *w, WindowEvent *e)
{ {
@@ -30,7 +29,7 @@ static void BuildIndustryWndProc(Window *w, WindowEvent *e)
case WE_PAINT: case WE_PAINT:
DrawWindowWidgets(w); DrawWindowWidgets(w);
if (_thd.place_mode == 1 && _thd.window_class == WC_BUILD_INDUSTRY) { if (_thd.place_mode == 1 && _thd.window_class == WC_BUILD_INDUSTRY) {
int ind_type = _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1]; int ind_type = _build_industry_types[_opt.landscape][WP(w,def_d).data_1];
SetDParam(0, (_price.build_industry >> 5) * _industry_type_costs[ind_type]); SetDParam(0, (_price.build_industry >> 5) * _industry_type_costs[ind_type]);
DrawStringCentered(85, w->height - 21, STR_482F_COST, 0); DrawStringCentered(85, w->height - 21, STR_482F_COST, 0);
@@ -40,13 +39,13 @@ static void BuildIndustryWndProc(Window *w, WindowEvent *e)
case WE_CLICK: { case WE_CLICK: {
int wid = e->click.widget; int wid = e->click.widget;
if (wid >= 3) { if (wid >= 3) {
if (HandlePlacePushButton(w, wid, SPR_CURSOR_INDUSTRY, 1, NULL)) if (HandlePlacePushButton(w, wid, 0xFF1, 1, NULL))
WP(w,def_d).data_1 = wid - 3; WP(w,def_d).data_1 = wid - 3;
} }
} break; } break;
case WE_PLACE_OBJ: case WE_PLACE_OBJ:
if (DoCommandP(e->place.tile, _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY))) if (DoCommandP(e->place.tile, _build_industry_types[_opt.landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)))
ResetObjectToPlace(); ResetObjectToPlace();
break; break;
@@ -61,11 +60,11 @@ static const Widget _build_industry_land0_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -73,11 +72,11 @@ static const Widget _build_industry_land1_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -85,11 +84,11 @@ static const Widget _build_industry_land2_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -97,10 +96,10 @@ static const Widget _build_industry_land3_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -109,18 +108,18 @@ static const Widget _build_industry_land0_widgets_extra[] = {
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 84, 95, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 84, 95, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 97, 108, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 97, 108, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 110, 121, STR_0245_OIL_RIG, STR_CONSTRUCT_OIL_RIG_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 110, 121, STR_0245_OIL_RIG, STR_CONSTRUCT_OIL_RIG_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 123, 134, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 123, 134, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 136, 147, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 136, 147, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 149, 160, STR_0249_IRON_ORE_MINE, STR_CONSTRUCT_IRON_ORE_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 149, 160, STR_0249_IRON_ORE_MINE, STR_CONSTRUCT_IRON_ORE_MINE_TIP},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -130,17 +129,17 @@ static const Widget _build_industry_land1_widgets_extra[] = {
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 174, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 174, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_024F_GOLD_MINE, STR_CONSTRUCT_GOLD_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_024F_GOLD_MINE, STR_CONSTRUCT_GOLD_MINE_TIP},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -149,19 +148,19 @@ static const Widget _build_industry_land2_widgets_extra[] = {
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 200, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 200, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_024A_OIL_WELLS,STR_CONSTRUCT_OIL_WELLS_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_024A_OIL_WELLS,STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0255_DIAMOND_MINE, STR_CONSTRUCT_DIAMOND_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0255_DIAMOND_MINE, STR_CONSTRUCT_DIAMOND_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0256_COPPER_ORE_MINE, STR_CONSTRUCT_COPPER_ORE_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0256_COPPER_ORE_MINE, STR_CONSTRUCT_COPPER_ORE_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0251_FRUIT_PLANTATION, STR_CONSTRUCT_FRUIT_PLANTATION_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0251_FRUIT_PLANTATION, STR_CONSTRUCT_FRUIT_PLANTATION_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0252_RUBBER_PLANTATION,STR_CONSTRUCT_RUBBER_PLANTATION_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0252_RUBBER_PLANTATION,STR_CONSTRUCT_RUBBER_PLANTATION_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 159+3, 170+3, STR_0253_WATER_SUPPLY, STR_CONSTRUCT_WATER_SUPPLY_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 159+3, 170+3, STR_0253_WATER_SUPPLY, STR_CONSTRUCT_WATER_SUPPLY_TIP},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -170,18 +169,18 @@ static const Widget _build_industry_land3_widgets_extra[] = {
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68+3, 79+3, STR_0257_COTTON_CANDY_FOREST,STR_CONSTRUCT_COTTON_CANDY_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 68+3, 79+3, STR_0257_COTTON_CANDY_FOREST,STR_CONSTRUCT_COTTON_CANDY_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0259_BATTERY_FARM, STR_CONSTRUCT_BATTERY_FARM_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0259_BATTERY_FARM, STR_CONSTRUCT_BATTERY_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_025A_COLA_WELLS, STR_CONSTRUCT_COLA_WELLS_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_025A_COLA_WELLS, STR_CONSTRUCT_COLA_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_025D_PLASTIC_FOUNTAINS,STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_025D_PLASTIC_FOUNTAINS,STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_025F_BUBBLE_GENERATOR, STR_CONSTRUCT_BUBBLE_GENERATOR_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_025F_BUBBLE_GENERATOR, STR_CONSTRUCT_BUBBLE_GENERATOR_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0260_TOFFEE_QUARRY, STR_CONSTRUCT_TOFFEE_QUARRY_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0260_TOFFEE_QUARRY, STR_CONSTRUCT_TOFFEE_QUARRY_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0261_SUGAR_MINE, STR_CONSTRUCT_SUGAR_MINE_TIP}, { WWT_CLOSEBOX, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0261_SUGAR_MINE, STR_CONSTRUCT_SUGAR_MINE_TIP},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -267,11 +266,10 @@ static const WindowDesc * const _industry_window_desc[2][4] = {
void ShowBuildIndustryWindow(void) void ShowBuildIndustryWindow(void)
{ {
if (_current_player == OWNER_SPECTATOR) return; AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt.landscape],0);
AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt_ptr->landscape],0);
} }
#define NEED_ALTERB ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES)) #define NEED_ALTERB (_game_mode == GM_EDITOR && i->accepts_cargo[0] == CT_INVALID)
static void IndustryViewWndProc(Window *w, WindowEvent *e) static void IndustryViewWndProc(Window *w, WindowEvent *e)
{ {
// WP(w,vp2_d).data_1 is for the editbox line // WP(w,vp2_d).data_1 is for the editbox line
@@ -282,9 +280,12 @@ static void IndustryViewWndProc(Window *w, WindowEvent *e)
case WE_PAINT: { case WE_PAINT: {
const Industry *i; const Industry *i;
StringID str; StringID str;
// in editor, use bulldoze to destroy industry
// Destroy Industry button costing money removed per request of dominik
//w->disabled_state = (_patches.extra_dynamite && !_networking && _game_mode != GM_EDITOR) ? 0 : (1 << 6);
i = GetIndustry(w->window_number); i = GetIndustry(w->window_number);
SetDParam(0, w->window_number); SetDParam(0, i->town->index);
SetDParam(1, i->type + STR_4802_COAL_MINE);
DrawWindowWidgets(w); DrawWindowWidgets(w);
if (i->accepts_cargo[0] != CT_INVALID) { if (i->accepts_cargo[0] != CT_INVALID) {
@@ -304,9 +305,8 @@ static void IndustryViewWndProc(Window *w, WindowEvent *e)
if (i->produced_cargo[0] != CT_INVALID) { if (i->produced_cargo[0] != CT_INVALID) {
DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0); DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0);
SetDParam(0, _cargoc.names_long[i->produced_cargo[0]]);
SetDParam(1, i->total_production[0]); SetDParam(1, i->total_production[0]);
SetDParam(0, _cargoc.names_long_s[i->produced_cargo[0]] + ((i->total_production[0]!=1)<<5));
SetDParam(2, i->pct_transported[0] * 100 >> 8); SetDParam(2, i->pct_transported[0] * 100 >> 8);
DrawString(4 + (NEED_ALTERB ? 30 : 0), 127, STR_482B_TRANSPORTED, 0); DrawString(4 + (NEED_ALTERB ? 30 : 0), 127, STR_482B_TRANSPORTED, 0);
// Let's put out those buttons.. // Let's put out those buttons..
@@ -314,8 +314,8 @@ static void IndustryViewWndProc(Window *w, WindowEvent *e)
DrawArrowButtons(5, 127, (WP(w,vp2_d).data_2 == 1 ? WP(w,vp2_d).data_3 : 0)); DrawArrowButtons(5, 127, (WP(w,vp2_d).data_2 == 1 ? WP(w,vp2_d).data_3 : 0));
if (i->produced_cargo[1] != CT_INVALID) { if (i->produced_cargo[1] != CT_INVALID) {
SetDParam(0, _cargoc.names_long[i->produced_cargo[1]]);
SetDParam(1, i->total_production[1]); SetDParam(1, i->total_production[1]);
SetDParam(0, _cargoc.names_long_s[i->produced_cargo[1]] + ((i->total_production[1]!=1)<<5));
SetDParam(2, i->pct_transported[1] * 100 >> 8); SetDParam(2, i->pct_transported[1] * 100 >> 8);
DrawString(4 + (NEED_ALTERB ? 30 : 0), 137, STR_482B_TRANSPORTED, 0); DrawString(4 + (NEED_ALTERB ? 30 : 0), 137, STR_482B_TRANSPORTED, 0);
// Let's put out those buttons.. // Let's put out those buttons..
@@ -339,8 +339,12 @@ static void IndustryViewWndProc(Window *w, WindowEvent *e)
i = GetIndustry(w->window_number); i = GetIndustry(w->window_number);
// We should work if needed.. // We should only work in editor
if (!NEED_ALTERB) if (_game_mode != GM_EDITOR)
return;
// And if the industry is raw-material producer
if (i->accepts_cargo[0] != CT_INVALID)
return; return;
x = e->click.pt.x; x = e->click.pt.x;
@@ -379,7 +383,18 @@ static void IndustryViewWndProc(Window *w, WindowEvent *e)
break; break;
case 6: case 6:
i = GetIndustry(w->window_number); i = GetIndustry(w->window_number);
ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1)); ScrollMainWindowToTile(i->xy + TILE_XY(1,1));
break;
case 7:
// Destroy Industry button costing money removed per request of dominik
//i = GetIndustry(w->window_number);
/* passing only i->xy is not safe if industry has a weird shape like:
_ X X
X X X
_ <--- grass, no industry, but i->xy points there (first top-left tile)!,
so passing i->xy to destroy industry will fail in called procedure
*/
//DoCommandP(i->xy, w->window_number, 0, CcPlaySound10, CMD_DESTROY_INDUSTRY | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
break; break;
} }
} }
@@ -420,7 +435,7 @@ static void UpdateIndustryProduction(Industry *i)
} }
static const Widget _industry_view_widgets[] = { static const Widget _industry_view_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 9, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 9, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 9, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 9, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 9, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON}, { WWT_STICKYBOX, RESIZE_NONE, 9, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 14, 105, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 14, 105, 0x0, STR_NULL},
@@ -428,6 +443,8 @@ static const Widget _industry_view_widgets[] = {
{ WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 106, 147, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 106, 147, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 9, 0, 129, 148, 159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON}, { WWT_PUSHTXTBTN, RESIZE_NONE, 9, 0, 129, 148, 159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
{ WWT_IMGBTN, RESIZE_NONE, 9, 130, 259, 148, 159, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 9, 130, 259, 148, 159, 0x0, STR_NULL},
// Destroy Industry button costing money removed per request of dominik
//{ WWT_PUSHTXTBTN, RESIZE_NONE, 9, 130, 259, 148, 159, STR_INDUSTRYDIR_DESTROY, STR_482C_DESTROY_INDUSTRY},
{ WIDGETS_END}, { WIDGETS_END},
}; };
@@ -451,12 +468,12 @@ void ShowIndustryViewWindow(int industry)
WP(w,vp2_d).data_2 = 0; WP(w,vp2_d).data_2 = 0;
WP(w,vp2_d).data_3 = 0; WP(w,vp2_d).data_3 = 0;
i = GetIndustry(w->window_number); i = GetIndustry(w->window_number);
AssignWindowViewport(w, 3, 17, 0xFE, 0x56, i->xy + TileDiffXY(1, 1), 1); AssignWindowViewport(w, 3, 17, 0xFE, 0x56, i->xy + TILE_XY(1,1), 1);
} }
} }
static const Widget _industry_directory_widgets[] = { static const Widget _industry_directory_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 13, 11, 495, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_CAPTION, RESIZE_NONE, 13, 11, 495, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 13, 496, 507, 0, 13, 0x0, STR_STICKY_BUTTON}, { WWT_STICKYBOX, RESIZE_NONE, 13, 496, 507, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 100, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP}, { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 100, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
@@ -480,7 +497,7 @@ static byte _industry_sort_order;
static int CDECL GeneralIndustrySorter(const void *a, const void *b) static int CDECL GeneralIndustrySorter(const void *a, const void *b)
{ {
char buf1[96]; char buf1[96];
uint16 val; byte val;
Industry *i = GetIndustry(*(const uint16*)a); Industry *i = GetIndustry(*(const uint16*)a);
Industry *j = GetIndustry(*(const uint16*)b); Industry *j = GetIndustry(*(const uint16*)b);
int r = 0; int r = 0;
@@ -493,28 +510,28 @@ static int CDECL GeneralIndustrySorter(const void *a, const void *b)
// FIXME - Production & Transported sort need to be inversed...but, WTF it does not wanna! // FIXME - Production & Transported sort need to be inversed...but, WTF it does not wanna!
// FIXME - And no simple --> "if (!(_industry_sort_order & 1)) r = -r;" hack at the bottom!! // FIXME - And no simple --> "if (!(_industry_sort_order & 1)) r = -r;" hack at the bottom!!
case 2: { /* Sort by Production */ case 2: { /* Sort by Production */
if (i->produced_cargo[0] != CT_INVALID && j->produced_cargo[0] != CT_INVALID) { // both industries produce cargo? if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { // both industries produce cargo?
if (i->produced_cargo[1] == CT_INVALID) // producing one or two things? if (i->produced_cargo[1] == 0xFF) // producing one or two things?
r = j->total_production[0] - i->total_production[0]; r = j->total_production[0] - i->total_production[0];
else else
r = (j->total_production[0] + j->total_production[1]) / 2 - (i->total_production[0] + i->total_production[1]) / 2; r = (j->total_production[0] + j->total_production[1]) / 2 - (i->total_production[0] + i->total_production[1]) / 2;
} else if (i->produced_cargo[0] == CT_INVALID && j->produced_cargo[0] == CT_INVALID) // none of them producing anything, let them go to the name-sorting } else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) // none of them producing anything, let them go to the name-sorting
r = 0; r = 0;
else if (i->produced_cargo[0] == CT_INVALID) // end up the non-producer industry first/last in list else if (i->produced_cargo[0] == 0xFF) // end up the non-producer industry first/last in list
r = 1; r = 1;
else else
r = -1; r = -1;
break; break;
} }
case 3: /* Sort by Transported amount */ case 3: /* Sort by Transported amount */
if (i->produced_cargo[0] != CT_INVALID && j->produced_cargo[0] != CT_INVALID) { // both industries produce cargo? if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { // both industries produce cargo?
if (i->produced_cargo[1] == CT_INVALID) // producing one or two things? if (i->produced_cargo[1] == 0xFF) // producing one or two things?
r = (j->pct_transported[0] * 100 >> 8) - (i->pct_transported[0] * 100 >> 8); r = (j->pct_transported[0] * 100 >> 8) - (i->pct_transported[0] * 100 >> 8);
else else
r = ((j->pct_transported[0] * 100 >> 8) + (j->pct_transported[1] * 100 >> 8)) / 2 - ((i->pct_transported[0] * 100 >> 8) + (i->pct_transported[1] * 100 >> 8)) / 2; r = ((j->pct_transported[0] * 100 >> 8) + (j->pct_transported[1] * 100 >> 8)) / 2 - ((i->pct_transported[0] * 100 >> 8) + (i->pct_transported[1] * 100 >> 8)) / 2;
} else if (i->produced_cargo[0] == CT_INVALID && j->produced_cargo[0] == CT_INVALID) // none of them producing anything, let them go to the name-sorting } else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) // none of them producing anything, let them go to the name-sorting
r = 0; r = 0;
else if (i->produced_cargo[0] == CT_INVALID) // end up the non-producer industry first/last in list else if (i->produced_cargo[0] == 0xFF) // end up the non-producer industry first/last in list
r = 1; r = 1;
else else
r = -1; r = -1;
@@ -523,13 +540,13 @@ static int CDECL GeneralIndustrySorter(const void *a, const void *b)
// default to string sorting if they are otherwise equal // default to string sorting if they are otherwise equal
if (r == 0) { if (r == 0) {
SetDParam(0, i->town->index); SetDParam(0, i->town->townnameparts);
GetString(buf1, STR_TOWN); GetString(buf1, i->town->townnametype);
if ( (val=*(const uint16*)b) != _last_industry_idx) { if ( (val=*(const uint16*)b) != _last_industry_idx) {
_last_industry_idx = val; _last_industry_idx = val;
SetDParam(0, j->town->index); SetDParam(0, j->town->townnameparts);
GetString(_bufcache, STR_TOWN); GetString(_bufcache, j->town->townnametype);
} }
r = strcmp(buf1, _bufcache); r = strcmp(buf1, _bufcache);
} }
@@ -544,7 +561,7 @@ static void MakeSortedIndustryList(void)
int n = 0; int n = 0;
/* Create array for sorting */ /* Create array for sorting */
_industry_sort = realloc(_industry_sort, GetIndustryPoolSize() * sizeof(_industry_sort[0])); _industry_sort = realloc(_industry_sort, _industries_size * sizeof(_industry_sort[0]));
if (_industry_sort == NULL) if (_industry_sort == NULL)
error("Could not allocate memory for the industry-sorting-list"); error("Could not allocate memory for the industry-sorting-list");
@@ -575,29 +592,30 @@ static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
MakeSortedIndustryList(); MakeSortedIndustryList();
} }
SetVScrollCount(w, _num_industry_sort); w->vscroll.count = _num_industry_sort;
DrawWindowWidgets(w); DrawWindowWidgets(w);
DoDrawString(_industry_sort_order & 1 ? DOWNARROW : UPARROW, _indicator_positions[_industry_sort_order>>1], 15, 0x10); DoDrawString(_industry_sort_order & 1 ? "\xAA" : "\xA0", _indicator_positions[_industry_sort_order>>1], 15, 0x10);
p = w->vscroll.pos; p = w->vscroll.pos;
n = 0; n = 0;
while (p < _num_industry_sort) { while (p < _num_industry_sort) {
i = GetIndustry(_industry_sort[p]); i = GetIndustry(_industry_sort[p]);
SetDParam(0, i->index); SetDParam(0, i->town->index);
if (i->produced_cargo[0] != CT_INVALID) { SetDParam(1, i->type + STR_4802_COAL_MINE);
SetDParam(1, _cargoc.names_long[i->produced_cargo[0]]); if (i->produced_cargo[0] != 0xFF) {
SetDParam(2, i->total_production[0]); SetDParam(3, i->total_production[0]);
SetDParam(2, _cargoc.names_long_s[i->produced_cargo[0]] + ((i->total_production[0]!=1)<<5));
if (i->produced_cargo[1] != CT_INVALID) { if (i->produced_cargo[1] != 0xFF) {
SetDParam(3, _cargoc.names_long[i->produced_cargo[1]]); SetDParam(5, i->total_production[1]);
SetDParam(4, i->total_production[1]); SetDParam(4, _cargoc.names_long_s[i->produced_cargo[1]] + ((i->total_production[1]!=1)<<5));
SetDParam(5, i->pct_transported[0] * 100 >> 8); SetDParam(6, i->pct_transported[0] * 100 >> 8);
SetDParam(6, i->pct_transported[1] * 100 >> 8); SetDParam(7, i->pct_transported[1] * 100 >> 8);
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0); DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0);
} else { } else {
SetDParam(3, i->pct_transported[0] * 100 >> 8); SetDParam(4, i->pct_transported[0] * 100 >> 8);
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM, 0); DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM, 0);
} }
} else { } else {

View File

@@ -1,114 +1,87 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "table/strings.h" #include "table/strings.h"
#include "functions.h"
#include "window.h" #include "window.h"
#include "gui.h" #include "gui.h"
#include "viewport.h"
#include "gfx.h" #include "gfx.h"
#include "player.h" #include "player.h"
#include "command.h"
#include "console.h"
#include "network.h" #include "network.h"
#include "variables.h"
extern void SwitchMode(int new_mode); extern void SwitchMode(int new_mode);
/*
static void ShowSelectTutorialWindow()
{
}
*/
static const Widget _select_game_widgets[] = { static const Widget _select_game_widgets[] = {
{ WWT_CAPTION, RESIZE_NONE, 13, 0, 335, 0, 13, STR_0307_OPENTTD, STR_NULL}, { WWT_CAPTION, RESIZE_NONE, 13, 0, 335, 0, 13, STR_0307_OPENTTD, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 13, 0, 335, 14, 196, STR_NULL, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 13, 0, 335, 14, 196, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 22, 33, STR_0140_NEW_GAME, STR_02FB_START_A_NEW_GAME}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 22, 33, STR_0140_NEW_GAME, STR_02FB_START_A_NEW_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 22, 33, STR_0141_LOAD_GAME, STR_02FC_LOAD_A_SAVED_GAME}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 22, 33, STR_0141_LOAD_GAME, STR_02FC_LOAD_A_SAVED_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 40, 51, STR_0220_CREATE_SCENARIO,STR_02FE_CREATE_A_CUSTOMIZED_GAME}, //{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 177, 188, STR_0142_TUTORIAL_DEMONSTRATION, STR_02FD_VIEW_DEMONSTRATIONS_TUTORIALS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 40, 51, STR_029A_PLAY_SCENARIO, STR_0303_START_A_NEW_GAME_USING}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 177, 188, STR_CONFIG_PATCHES, STR_CONFIG_PATCHES_TIP},
{ WWT_PANEL_2, RESIZE_NONE, 12, 10, 86, 59, 113, 0x1312, STR_030E_SELECT_TEMPERATE_LANDSCAPE}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 40, 51, STR_0220_CREATE_SCENARIO,STR_02FE_CREATE_A_CUSTOMIZED_GAME},
{ WWT_PANEL_2, RESIZE_NONE, 12, 90, 166, 59, 113, 0x1314, STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 136, 147, STR_SINGLE_PLAYER, STR_02FF_SELECT_SINGLE_PLAYER_GAME},
{ WWT_PANEL_2, RESIZE_NONE, 12, 170, 246, 59, 113, 0x1316, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 136, 147, STR_MULTIPLAYER, STR_0300_SELECT_MULTIPLAYER_GAME},
{ WWT_PANEL_2, RESIZE_NONE, 12, 250, 326, 59, 113, 0x1318, STR_0311_SELECT_TOYLAND_LANDSCAPE}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 159, 170, STR_0148_GAME_OPTIONS, STR_0301_DISPLAY_GAME_OPTIONS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 159, 170, STR_01FE_DIFFICULTY, STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
{ WWT_PANEL, RESIZE_NONE, 12, 219, 254, 120, 131, STR_NULL, STR_NULL}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 40, 51, STR_029A_PLAY_SCENARIO, STR_0303_START_A_NEW_GAME_USING},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 255, 266, 120, 131, STR_0225, STR_NULL}, { WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 177, 188, STR_0304_QUIT, STR_0305_QUIT_OPENTTD},
{ WWT_PANEL, RESIZE_NONE, 12, 279, 314, 120, 131, STR_NULL, STR_NULL}, { WWT_PANEL_2, RESIZE_NONE, 12, 10, 85, 69, 122, 0x1312, STR_030E_SELECT_TEMPERATE_LANDSCAPE},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 315, 326, 120, 131, STR_0225, STR_NULL}, { WWT_PANEL_2, RESIZE_NONE, 12, 90, 165, 69, 122, 0x1314, STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
{ WWT_PANEL_2, RESIZE_NONE, 12, 170, 245, 69, 122, 0x1316, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 138, 149, STR_SINGLE_PLAYER, STR_02FF_SELECT_SINGLE_PLAYER_GAME}, { WWT_PANEL_2, RESIZE_NONE, 12, 250, 325, 69, 122, 0x1318, STR_0311_SELECT_TOYLAND_LANDSCAPE},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 138, 149, STR_MULTIPLAYER, STR_0300_SELECT_MULTIPLAYER_GAME}, { WIDGETS_END},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 159, 170, STR_0148_GAME_OPTIONS, STR_0301_DISPLAY_GAME_OPTIONS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 159, 170, STR_01FE_DIFFICULTY, STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 177, 188, STR_CONFIG_PATCHES, STR_CONFIG_PATCHES_TIP},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 177, 188, STR_0304_QUIT, STR_0305_QUIT_OPENTTD},
{ WIDGETS_END },
}; };
extern void HandleOnEditText(WindowEvent *e); extern void HandleOnEditText(WindowEvent *e);
extern void HandleOnEditTextCancel(void); extern void HandleOnEditTextCancel(void);
static inline void CreateScenario(void) {_switch_mode = SM_EDITOR;} static void SelectGameWndProc(Window *w, WindowEvent *e) {
switch(e->event) {
static inline void SetNewLandscapeType(byte landscape)
{
_opt_newgame.landscape = landscape;
InvalidateWindowClasses(WC_SELECT_GAME);
}
static void SelectGameWndProc(Window *w, WindowEvent *e)
{
/* We do +/- 6 for the map_xy because 64 is 2^6, but it is the lowest available element */
static const StringID mapsizes[] = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
switch (e->event) {
case WE_PAINT: case WE_PAINT:
w->click_state = (w->click_state & ~(1 << 14) & ~(0xF << 6)) | (1 << (_opt_newgame.landscape + 6)) | (1 << 14); w->click_state = (w->click_state & ~(0xC0) & ~(0xF << 12)) | (1 << (_new_opt.landscape+12)) | (1<<6);
SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level); SetDParam(0, STR_6801_EASY + _new_opt.diff_level);
DrawWindowWidgets(w); DrawWindowWidgets(w);
DrawStringRightAligned(216, 121, STR_MAPSIZE, 0);
DrawString(223, 121, mapsizes[_patches.map_x - 6], 0x10);
DrawString(270, 121, STR_BY, 0);
DrawString(283, 121, mapsizes[_patches.map_y - 6], 0x10);
break; break;
case WE_CLICK: case WE_CLICK:
switch (e->click.widget) { switch(e->click.widget) {
case 2: AskForNewGameToStart(); break; case 2: DoCommandP(0, 0, 0, NULL, CMD_START_NEW_GAME); break;
case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break; case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
case 4: CreateScenario(); break; case 4: ShowPatchesSelection(); break;
case 5: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; case 5: DoCommandP(0, InteractiveRandom(), 0, NULL, CMD_CREATE_SCENARIO); break;
case 6: case 7: case 8: case 9: case 7:
SetNewLandscapeType(e->click.widget - 6); #ifdef ENABLE_NETWORK
break;
case 10: case 11: /* Mapsize X */
ShowDropDownMenu(w, mapsizes, _patches.map_x - 6, 11, 0, 0);
break;
case 12: case 13: /* Mapsize Y */
ShowDropDownMenu(w, mapsizes, _patches.map_y - 6, 13, 0, 0);
break;
case 15:
#ifdef ENABLE_NETWORK
if (!_network_available) { if (!_network_available) {
ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0); ShowErrorMessage(-1, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
} else } else
ShowNetworkGameWindow(); ShowNetworkGameWindow();
#else #else
ShowErrorMessage(INVALID_STRING_ID ,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0); ShowErrorMessage(-1 ,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
#endif #endif /* ENABLE_NETWORK */
break; break;
case 16: ShowGameOptions(); break; case 8: ShowGameOptions(); break;
case 17: ShowGameDifficulty(); break; case 9: ShowGameDifficulty(); break;
case 18: ShowPatchesSelection(); break; case 10:ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
case 19: AskExitGame(); break; case 11:AskExitGame(); break;
case 12: case 13: case 14: case 15:
DoCommandP(0, e->click.widget - 12, 0, NULL, CMD_SET_NEW_LANDSCAPE_TYPE);
break;
}
case WE_KEYPRESS:
switch(e->keypress.keycode) {
case WKC_BACKQUOTE: IConsoleSwitch(); break;
} }
break; break;
case WE_ON_EDIT_TEXT: HandleOnEditText(e); break; case WE_ON_EDIT_TEXT: HandleOnEditText(e); break;
case WE_ON_EDIT_TEXT_CANCEL: HandleOnEditTextCancel(); break; case WE_ON_EDIT_TEXT_CANCEL: HandleOnEditTextCancel(); break;
case WE_DROPDOWN_SELECT: /* Mapsize selection */
switch (e->dropdown.button) {
case 11: _patches.map_x = e->dropdown.index + 6; break;
case 13: _patches.map_y = e->dropdown.index + 6; break;
}
SetWindowDirty(w);
break;
} }
} }
@@ -126,34 +99,94 @@ void ShowSelectGameWindow(void)
AllocateWindowDesc(&_select_game_desc); AllocateWindowDesc(&_select_game_desc);
} }
void GenRandomNewGame(uint32 rnd1, uint32 rnd2)
// p1 = mode
// 0 - start new game
// 1 - close new game dialog
int32 CmdStartNewGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
_random_seeds[0][0] = rnd1; if (!(flags & DC_EXEC))
_random_seeds[0][1] = rnd2; return 0;
switch(p1) {
case 0: // show select game window
AskForNewGameToStart();
break;
case 1: // close select game window
DeleteWindowById(WC_SAVELOAD, 0);
break;
}
return 0;
}
int32 CmdGenRandomNewGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
// this forces stuff into test mode.
_docommand_recursive = 0;
_random_seeds[0][0] = p1;
_random_seeds[0][1] = p2;
SwitchMode(SM_NEWGAME); SwitchMode(SM_NEWGAME);
return 0;
} }
void StartScenarioEditor(uint32 rnd1, uint32 rnd2) int32 CmdLoadGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
_random_seeds[0][0] = rnd1; if (!(flags & DC_EXEC))
_random_seeds[0][1] = rnd2; return 0;
// ShowSaveLoadDialog(0);
return 0;
}
int32 CmdCreateScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
_switch_mode = SM_EDITOR;
return 0;
}
int32 CmdSetSinglePlayer(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
printf("CmdSetSinglePlayer\n");
return 0;
}
int32 CmdStartScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (!(flags & DC_EXEC))
return 0;
// this forces stuff into test mode.
_docommand_recursive = 0;
_random_seeds[0][0] = p1;
_random_seeds[0][1] = p2;
SwitchMode(SM_START_SCENARIO); SwitchMode(SM_START_SCENARIO);
return 0;
} }
static const Widget _ask_abandon_game_widgets[] = { static const Widget _ask_abandon_game_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_NULL},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_00C7_QUIT, STR_NULL}, { WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_00C7_QUIT, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL},
{ WIDGETS_END }, { WIDGETS_END},
}; };
static void AskAbandonGameWndProc(Window* w, WindowEvent* e) static void AskAbandonGameWndProc(Window *w, WindowEvent *e) {
{ switch(e->event) {
switch (e->event) {
case WE_PAINT: case WE_PAINT:
DrawWindowWidgets(w); DrawWindowWidgets(w);
#if defined(_WIN32) #if defined(_WIN32)
@@ -171,23 +204,22 @@ static void AskAbandonGameWndProc(Window* w, WindowEvent* e)
#else #else
SetDParam(0, STR_0134_UNIX); SetDParam(0, STR_0134_UNIX);
#endif #endif
DrawStringMultiCenter(90, 38, STR_00CA_ARE_YOU_SURE_YOU_WANT_TO, 178); DrawStringMultiCenter(0x5A, 0x26, STR_00CA_ARE_YOU_SURE_YOU_WANT_TO, 178);
return; return;
case WE_CLICK: case WE_CLICK:
switch (e->click.widget) { switch(e->click.widget) {
case 3: DeleteWindow(w); break; case 3:
case 4: _exit_game = true; break; DeleteWindow(w);
break;
case 4:
_exit_game = true;
break;
} }
break; break;
case WE_KEYPRESS: /* Exit game on pressing 'Enter' */ case WE_KEYPRESS: /* Exit game on pressing 'Enter' */
switch (e->keypress.keycode) { if (e->keypress.keycode == WKC_RETURN)
case WKC_RETURN: _exit_game = true;
case WKC_NUM_ENTER:
_exit_game = true;
break;
}
break; break;
} }
} }
@@ -207,37 +239,40 @@ void AskExitGame(void)
static const Widget _ask_quit_game_widgets[] = { static const Widget _ask_quit_game_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_TEXTBTN, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_NULL},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_0161_QUIT_GAME, STR_NULL}, { WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_0161_QUIT_GAME, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL}, { WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL},
{ WIDGETS_END }, { WIDGETS_END},
}; };
static void AskQuitGameWndProc(Window* w, WindowEvent* e) static void AskQuitGameWndProc(Window *w, WindowEvent *e) {
{ switch(e->event) {
switch (e->event) { case WE_PAINT:
case WE_PAINT: DrawWindowWidgets(w);
DrawWindowWidgets(w); DrawStringMultiCenter(0x5A, 0x26,
DrawStringMultiCenter( _game_mode != GM_EDITOR ? STR_0160_ARE_YOU_SURE_YOU_WANT_TO :
90, 38, STR_029B_ARE_YOU_SURE_YOU_WANT_TO,
_game_mode != GM_EDITOR ? 178);
STR_0160_ARE_YOU_SURE_YOU_WANT_TO : STR_029B_ARE_YOU_SURE_YOU_WANT_TO, return;
178
);
break;
case WE_CLICK: case WE_CLICK:
switch (e->click.widget) { switch(e->click.widget) {
case 3: DeleteWindow(w); break; case 3:
case 4: _switch_mode = SM_MENU; break; DeleteWindow(w);
}
break; break;
case 4:
_switch_mode = SM_MENU;
break;
}
break;
case WE_KEYPRESS: /* Return to main menu on pressing 'Enter' */
if (e->keypress.keycode == WKC_RETURN)
_switch_mode = SM_MENU;
break;
case WE_KEYPRESS: /* Return to main menu on pressing 'Enter' */
if (e->keypress.keycode == WKC_RETURN) _switch_mode = SM_MENU;
break;
} }
} }
@@ -254,3 +289,13 @@ void AskExitToGameMenu(void)
{ {
AllocateWindowDescFront(&_ask_quit_game_desc, 0); AllocateWindowDescFront(&_ask_quit_game_desc, 0);
} }
int32 CmdSetNewLandscapeType(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
if (flags & DC_EXEC) {
// XXX: some stuff
_new_opt.landscape = p1;
InvalidateWindowClasses(WC_SELECT_GAME);
}
return 0;
}

View File

@@ -1,6 +1,6 @@
README README
------------------------------------------------------------------------ ------------------------------------------------------------------------
All bugs listed below are marked as known. Please do not submit any bugs All bugs listed below are marked as known. Please do not submit any bugs
that are the same as these. If you do, don't act surprised, because that are the same as these. If you do, don't act surprised, because
we WILL flame you!! we WILL flame you!!
@@ -11,109 +11,65 @@ go to: http://www.tt-forums.net/viewtopic.php?t=9576
Of course if you have more knowledge about any of these bugs, have more Of course if you have more knowledge about any of these bugs, have more
specifics, we welcome you to report them. React to the given bug indicated specifics, we welcome you to report them. React to the given bug indicated
by the number below on http://sourceforge.net/tracker/?group_id=103924&atid=636365 by the number below on http://sourceforge.net/tracker/?group_id=103924&atid=636365
or http://bugs.openttd.org. If the the bug report is closed, it has been fixed, which then can be verified
If the bug report is closed, it has been fixed, which then can be verified
in the latest SVN version. in the latest SVN version.
Bugs for 0.4.7 Bugs for 0.3.6
------------------------------------------------------------------------
URL: http://bugs.openttd.org
-80 Medium Crash when switching from windowed to fullscreen
-78 Low Save vs. Autosave
-77 Low cocoa video driver got an artifact in fullscreen
-74 Low message settings
-73 vehicle selection bug
-71 Invalid last_vehicle for station (crash)
-68 wagon replacements
-66 wagon re-fitting
-65 short wagons bug
-63 Initial Volume Level not restored
-57 (Ship) Pathfinder problem
-55 Assertion on TrainController (train_cmd.c:2840)
-52 desync when server saves game (on slow hardware)
-51 Windows doesn't support CUSTOM_LANG_DIR
-50 Trains chosing an alternative path when encountering a 1-way presignal instead of waiting
-47 Low rating calculation and cargo loading priority
-45 Low NORETURN wrongly declared for gcc
-20 Low Saving files when run from gdb 2005-12-06 Unconfirmed
- 9 Low [MorphOS] write to NULL when going to device root in filerequester 2005-11-28 Assigned Christian Rosentreter
------------------------------------------------------------------------ ------------------------------------------------------------------------
URL: http://sourceforge.net/tracker/?atid=636365&group_id=103924&func=browse URL: http://sourceforge.net/tracker/?atid=636365&group_id=103924&func=browse
-1108615 Catchment area mis-behaving
-1108610 console logging file type
-1108442 autorenew takes precedence over autoreplace
-1107889 server crash and assertion error
-1106356 re-offered prototypes
-1104670 Vans in the depot
-1104519 train pathfinding with new patch
-1104105 script error (r1547)
-1103068 game crashes after reversing train in deport
-1101874 load savegames (and autosave) with dedicated server
-1099694 incorrect player colors
-1099233 production down before it's working
-1098696 Airport shadow remains after crashing
-1098238 Crash after lone wagon sighting
-1093191 2 problems with multiplayer savegames
-1085486 Subsidies: Only count when station is in right suburb
-1083710 Reverse train in depot crashes OpenTTD
-1074610 overtaking at signals bug
-1060686 changing (load) order doesn't take effect immediately
-1053339 depot/station looping
-1033300 signal bug
-1030918 Negative city population
-1024703 Infinite access of A: when saving and no disk in drive
-997251 Realistic acceleration: Trains don't slow down in curves
-996503 Sound volume bug
-992677 BeOS MIDI does not initialise on newer BeOS releases
-985475 Different kinds of signals in same tile?
-978372 Inconsistent stopping
-968036 Ship blocked at the edge
-1458368 Ships cannot be sent to depot when loading with NPF on, transfer not working Minor Bugs for 0.3.6
-1454591 Street junctions not able to converted
-1453676 crash in windowed mode when moving mouse back to openttd
-1436419 Vehicles profits gone negitive.......bug
-1434000 Error in Transfer-Function
-1433315 non-existant crash reporting
-1432871 Wrong signalstate when track over track
-1427531 Newspapers problem
-1417453 Makefile and Variables issue
-1397638 Economics bug?
-1395628 Trackpad panning/scrolling broken
-1394799 Dual headed engines disagreement
-1393415 NPF & one-way sigs
-1393411 "Void Order" reporting.
-1390260 Mis-reporting of Plane Crash
-1389999 Child windows not sticking
-1389986 Shares problem (nightly 3330)
-1380497 problems with competitors during multiplayer
-1362784 Incorrect vehicule profit calcul with inflation on
-1299162 Music volume too low
-1250094 Towns Shrink when center tile is built on
-1244842 Multiplayer interface bug (0.4.0.1)
-1212267 station visited twice when servicing
-1211764 AI companies behave weird on the stock market
-1208170 Duplicate station names can be created
-1197116 Some stations are cargo-less
-1188897 Station with cargo enroute_from INVALID_STATION
-1181888 Invaild Station Order => Crash
-1174829 Waypoint / Orders Bug
-1168820 Some mouse and keyboard events are lost
-1167810 Cargo payment after deleting stations (st->xy = 0)
-1116638 "More, but smaller changes" deficiency
-1106356 re-offered prototypes
-1085486 Subsidies: Only count when station is in right suburb
Minor Bugs for 0.4.7
------------------------------------------------------------------------ ------------------------------------------------------------------------
URL: http://sourceforge.net/tracker/?atid=669662&group_id=103924&func=browse URL: http://sourceforge.net/tracker/?atid=669662&group_id=103924&func=browse
-1424115 Reversed arrow sign in list view column headers -1106889 Chat Interface enhancements
-1412033 autoreplace not possible on monorail/maglev trains -1104968 void order message
-1412031 fast forward scrolling is also fast forward :) -1104358 train lost message - history
-1394316 Multistop traffic jam -1102174 Bug if 3 people buy 25% shares in one company
-1394231 Autorenew glitch on helicopters -1099429 show vehicle speed, text too long
-1387424 overtake insolvent company is to cheap -1090495 Bridges and straight lakesides
-1382782 Loan interest calculated 'wrong' -1087407 wrong message in history
-1372891 Performance loss with NTP & NPF -1084620 Minor bug considering buses/trucks
-1342383 Last built rail type not cleared when starting new game -1034310 color mauve in diagrams
-1296259 Autosave override for multiplayer games -1031184 Smoke visible through tunnel
-1242753 Town population minus 10 -1030661 It's possible to build a tunnel under oil wells
-1236320 Bug in main menu allows moving screen -1009171 Canals and locks at sea level cause flooding
-1201284 permanent hilight in a depot -993516 Canal + bouy -> wrong graphics.
-1193870 keep the date counter running -987891 Large UFO destruction bug
-1185852 Scrollbars get arbitrarily small -987884 farm fences
-1184634 Replace vehicles window bug -987883 Aircraft landing/taking off
-1183253 Incorrect Load vs Loading Sprites -987880 company league table updating
-1183251 Hangar sprite does not update when refit. -985924 aircraft taxi speed
-1160732 little bug with transparency -980276 Overflow in factory directory
-1117731 Editor-StartingDate -976824 transmitter base
-1114237 Wrong autoreplace hint -941694 Clipping problems stations/vehicles on slopes
-1108046 game freezes -936997 Stationname too long to fit in trainwindow bug
-1106889 Chat Interface enhancements
-1104358 train lost message - history
-1102174 Bug if 3 people buy 25% shares in one company
-1087407 wrong message in history
-1084620 Minor bug considering buses/trucks
-1034310 color mauve in diagrams
-1030661 It's possible to build a tunnel under oil wells
-1009171 Canals and locks at sea level cause flooding
-0993516 Canal + bouy -> wrong graphics.
-0987891 Large UFO destruction bug
-0987883 Aircraft landing/taking off
-0987880 company league table updating
-0985924 aircraft taxi speed
-0941694 Clipping problems stations/vehicles on slopes

View File

@@ -1,18 +1,11 @@
/* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" #include "ttd.h"
#include "functions.h"
#include "map.h" #include "map.h"
#include "player.h"
#include "spritecache.h"
#include "table/sprites.h"
#include "tile.h"
#include <stdarg.h> #include <stdarg.h>
#include "gfx.h"
#include "viewport.h" #include "viewport.h"
#include "command.h" #include "command.h"
#include "vehicle.h" #include "vehicle.h"
#include "variables.h"
extern const TileTypeProcs extern const TileTypeProcs
_tile_type_clear_procs, _tile_type_clear_procs,
@@ -47,24 +40,69 @@ const byte _tileh_to_sprite[32] = {
0,0,0,0,0,0,0,16,0,0,0,17,0,15,18,0, 0,0,0,0,0,0,0,16,0,0,0,17,0,15,18,0,
}; };
const byte _inclined_tileh[] = { uint GetTileSlope(uint tile, int *h)
3, 9, 3, 6, 12, 6, 12, 9
};
void FindLandscapeHeightByTile(TileInfo *ti, TileIndex tile)
{ {
assert(tile < MapSize()); uint a,b,c,d,min;
int r;
if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) {
if (h)
*h = 0;
return 0;
}
assert(tile < MapSize() && TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
min = a = TileHeight(tile);
b = TileHeight(tile + TILE_XY(1,0));
if (min >= b) min = b;
c = TileHeight(tile + TILE_XY(0,1));
if (min >= c) min = c;
d = TileHeight(tile + TILE_XY(1,1));
if (min >= d) min = d;
r = 0;
if ((a-=min)!=0) { r += (--a << 4) + 8; }
if ((c-=min)!=0) { r += (--c << 4) + 4; }
if ((d-=min)!=0) { r += (--d << 4) + 2; }
if ((b-=min)!=0) { r += (--b << 4) + 1; }
if (h != 0)
*h = min * 8;
return r;
}
int GetTileZ(uint tile)
{
int h;
GetTileSlope(tile, &h);
return h;
}
void FindLandscapeHeightByTile(TileInfo *ti, uint tile)
{
if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) {
ti->tileh = 0;
ti->type = MP_VOID;
ti->tile = 0;
ti->map5 = 0;
ti->z = 0;
return;
}
ti->tile = tile; ti->tile = tile;
ti->map5 = _m[tile].m5; ti->map5 = _map5[tile];
ti->type = GetTileType(tile); ti->type = TileType(tile);
ti->tileh = GetTileSlope(tile, &ti->z); ti->tileh = GetTileSlope(tile, &ti->z);
// ti->z = min * 8;
} }
/* find the landscape height for the coordinates x y */ /* find the landscape height for the coordinates x y */
void FindLandscapeHeight(TileInfo *ti, uint x, uint y) void FindLandscapeHeight(TileInfo *ti, uint x, uint y)
{ {
int tile;
ti->x = x; ti->x = x;
ti->y = y; ti->y = y;
@@ -77,7 +115,8 @@ void FindLandscapeHeight(TileInfo *ti, uint x, uint y)
return; return;
} }
FindLandscapeHeightByTile(ti, TileVirtXY(x, y)); tile = TILE_FROM_XY(x,y);
FindLandscapeHeightByTile(ti, tile);
} }
uint GetPartialZ(int x, int y, int corners) uint GetPartialZ(int x, int y, int corners)
@@ -178,29 +217,38 @@ uint GetPartialZ(int x, int y, int corners)
uint GetSlopeZ(int x, int y) uint GetSlopeZ(int x, int y)
{ {
TileInfo ti; TileInfo ti;
// int z;
FindLandscapeHeight(&ti, x, y); FindLandscapeHeight(&ti, x, y);
/*
z = ti.z;
x &= 0xF;
y &= 0xF;
assert(z < 256);
*/
return _tile_type_procs[ti.type]->get_slope_z_proc(&ti); return _tile_type_procs[ti.type]->get_slope_z_proc(&ti);
} }
// direction=true: check for foundation in east and south corner // direction=true: check for foundation in east and south corner
// direction=false: check for foundation in west and south corner // direction=false: check for foundation in west and south corner
static bool hasFoundation(const TileInfo* ti, bool direction) static bool hasFoundation(TileInfo *ti, bool direction)
{ {
bool south, other; // southern corner and east/west corner bool south, other; // southern corner and east/west corner
uint slope = _tile_type_procs[ti->type]->get_slope_tileh_proc(ti); uint slope = _tile_type_procs[ti->type]->get_slope_tileh_proc(ti);
uint tileh = ti->tileh; uint tileh = ti->tileh;
if (slope == 0 && slope != tileh) tileh = 15; if(slope==0 && slope!=tileh) tileh=15;
south = (tileh & 2) != (slope & 2); south = (tileh & 2) != (slope & 2);
if (direction) { if(direction)
other = (tileh & 4) != (slope & 4); other = (tileh & 4) != (slope & 4);
} else { else
other = (tileh & 1) != (slope & 1); other = (tileh & 1) != (slope & 1);
}
return south || other; return south || other;
} }
void DrawFoundation(TileInfo *ti, uint f) void DrawFoundation(TileInfo *ti, uint f)
@@ -208,16 +256,16 @@ void DrawFoundation(TileInfo *ti, uint f)
uint32 sprite_base = SPR_SLOPES_BASE-14; uint32 sprite_base = SPR_SLOPES_BASE-14;
TileInfo ti2; TileInfo ti2;
FindLandscapeHeight(&ti2, ti->x, ti->y - 1); FindLandscapeHeight(&ti2, ti->x, ti->y-1);
if (hasFoundation(&ti2, true)) sprite_base += 22; // foundation in NW direction if(hasFoundation( &ti2, true )) sprite_base += 22; // foundation in NW direction
FindLandscapeHeight(&ti2, ti->x - 1, ti->y); FindLandscapeHeight(&ti2, ti->x-1, ti->y);
if (hasFoundation(&ti2, false)) sprite_base += 22 * 2; // foundation in NE direction if(hasFoundation( &ti2, false )) sprite_base += 22*2; // foundation in NE direction
if (f < 15) { if (f < 15) {
// leveled foundation // leveled foundation
if (sprite_base < SPR_SLOPES_BASE) sprite_base = SPR_FOUNDATION_BASE + 1; // use original slope sprites if( sprite_base < SPR_SLOPES_BASE ) sprite_base = 990; // use original slope sprites
AddSortableSpriteToDraw(f - 1 + sprite_base, ti->x, ti->y, 16, 16, 7, ti->z); AddSortableSpriteToDraw(f-1 + sprite_base, ti->x, ti->y, 16, 16, 7, ti->z);
ti->z += 8; ti->z += 8;
ti->tileh = 0; ti->tileh = 0;
OffsetGroundSprite(31, 1); OffsetGroundSprite(31, 1);
@@ -226,7 +274,7 @@ void DrawFoundation(TileInfo *ti, uint f)
sprite_base += 14; sprite_base += 14;
AddSortableSpriteToDraw( AddSortableSpriteToDraw(
HASBIT((1<<1) | (1<<2) | (1<<4) | (1<<8), ti->tileh) ? sprite_base + (f - 15) : SPR_FOUNDATION_BASE + ti->tileh, HASBIT( (1<<1) | (1<<2) | (1<<4) | (1<<8), ti->tileh) ? sprite_base + (f - 15) : ti->tileh + 0x3DE - 1,
ti->x, ti->y, 1, 1, 1, ti->z ti->x, ti->y, 1, 1, 1, ti->z
); );
@@ -235,7 +283,7 @@ void DrawFoundation(TileInfo *ti, uint f)
} }
} }
void DoClearSquare(TileIndex tile) void DoClearSquare(uint tile)
{ {
ModifyTile(tile, ModifyTile(tile,
MP_SETTYPE(MP_CLEAR) | MP_SETTYPE(MP_CLEAR) |
@@ -245,30 +293,30 @@ void DoClearSquare(TileIndex tile)
); );
} }
uint32 GetTileTrackStatus(TileIndex tile, TransportType mode) uint32 GetTileTrackStatus(uint tile, TransportType mode)
{ {
return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode); return _tile_type_procs[TileType(tile)]->get_tile_track_status_proc(tile, mode);
} }
void ChangeTileOwner(TileIndex tile, byte old_player, byte new_player) void ChangeTileOwner(uint tile, byte old_player, byte new_player)
{ {
_tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_player, new_player); _tile_type_procs[TileType(tile)]->change_tile_owner_proc(tile, old_player, new_player);
} }
void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac) void GetAcceptedCargo(uint tile, AcceptedCargo ac)
{ {
memset(ac, 0, sizeof(AcceptedCargo)); memset(ac, 0, sizeof(AcceptedCargo));
_tile_type_procs[GetTileType(tile)]->get_accepted_cargo_proc(tile, ac); _tile_type_procs[TileType(tile)]->get_accepted_cargo_proc(tile, ac);
} }
void AnimateTile(TileIndex tile) void AnimateTile(uint tile)
{ {
_tile_type_procs[GetTileType(tile)]->animate_tile_proc(tile); _tile_type_procs[TileType(tile)]->animate_tile_proc(tile);
} }
void ClickTile(TileIndex tile) void ClickTile(uint tile)
{ {
_tile_type_procs[GetTileType(tile)]->click_tile_proc(tile); _tile_type_procs[TileType(tile)]->click_tile_proc(tile);
} }
void DrawTile(TileInfo *ti) void DrawTile(TileInfo *ti)
@@ -276,39 +324,33 @@ void DrawTile(TileInfo *ti)
_tile_type_procs[ti->type]->draw_tile_proc(ti); _tile_type_procs[ti->type]->draw_tile_proc(ti);
} }
void GetTileDesc(TileIndex tile, TileDesc *td) void GetTileDesc(uint tile, TileDesc *td)
{ {
_tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td); _tile_type_procs[TileType(tile)]->get_tile_desc_proc(tile, td);
} }
/** Clear a piece of landscape /* Clear a piece of landscape
* @param x,y coordinates of clearance * p1 = 0,
* @param p1 unused * p2 = 0
* @param p2 unused
*/ */
int32 CmdLandscapeClear(int x, int y, uint32 flags, uint32 p1, uint32 p2) int32 CmdLandscapeClear(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{ {
TileIndex tile = TileVirtXY(x, y); uint tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags); tile = TILE_FROM_XY(x,y);
return _tile_type_procs[TileType(tile)]->clear_tile_proc(tile, flags);
} }
/** Clear a big piece of landscape // p1 = end tile
* @param x,y end coordinates of area dragging
* @param p1 start tile of area dragging
* @param p2 unused
*/
int32 CmdClearArea(int ex, int ey, uint32 flags, uint32 p1, uint32 p2) int32 CmdClearArea(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{ {
int32 cost, ret, money; int32 cost,ret, money;
int sx,sy; int sx,sy;
int x,y; int x,y;
bool success = false; bool success = false;
if (p1 >= MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// make sure sx,sy are smaller than ex,ey // make sure sx,sy are smaller than ex,ey
@@ -320,73 +362,73 @@ int32 CmdClearArea(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
money = GetAvailableMoneyForCommand(); money = GetAvailableMoneyForCommand();
cost = 0; cost = 0;
for (x = sx; x <= ex; x += 16) { for(x=sx; x<=ex; x+=16) {
for (y = sy; y <= ey; y += 16) { for(y=sy; y<=ey; y+=16) {
ret = DoCommandByTile(TileVirtXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR); ret = DoCommandByTile(TILE_FROM_XY(x,y), 0, 0, flags &~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) continue; if (ret == CMD_ERROR) continue;
cost += ret; cost += ret;
success = true; success = true;
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
if (ret > 0 && (money -= ret) < 0) { if ( ret>0 && (money -= ret) < 0) {
_additional_cash_required = ret; _additional_cash_required = ret;
return cost - ret; return cost - ret;
} }
DoCommandByTile(TileVirtXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR); DoCommandByTile(TILE_FROM_XY(x,y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
// draw explosion animation... // draw explosion animation...
if ((x == sx || x == ex) && (y == sy || y == ey)) { if ((x==sx || x==ex) && (y==sy || y==ey)) {
// big explosion in each corner, or small explosion for single tiles // big explosion in each corner, or small explosion for single tiles
CreateEffectVehicleAbove(x + 8, y + 8, 2, CreateEffectVehicleAbove(x + 8,y + 8, 2, sy==ey && sx==ex ? EV_DEMOLISH : EV_CRASHED_SMOKE);
sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
);
} }
} }
} }
} }
return (success) ? cost : CMD_ERROR; if (!success)
cost = CMD_ERROR;
return cost;
} }
/* utility function used to modify a tile */ /* utility function used to modify a tile */
void CDECL ModifyTile(TileIndex tile, uint flags, ...) void CDECL ModifyTile(uint tile, uint flags, ...)
{ {
va_list va; va_list va;
int i; int i;
va_start(va, flags); va_start(va, flags);
if ((i = GB(flags, 8, 4)) != 0) { if ((i = (flags >> 8) & 0xF) != 0) {
SetTileType(tile, i - 1); SetTileType(tile, i - 1);
} }
if (flags & (MP_MAP2_CLEAR | MP_MAP2)) { if (flags & (MP_MAP2_CLEAR | MP_MAP2)) {
int x = 0; int x = 0;
if (flags & MP_MAP2) x = va_arg(va, int); if (flags & MP_MAP2) x = va_arg(va, int);
_m[tile].m2 = x; _map2[tile] = x;
} }
if (flags & (MP_MAP3LO_CLEAR | MP_MAP3LO)) { if (flags & (MP_MAP3LO_CLEAR | MP_MAP3LO)) {
int x = 0; int x = 0;
if (flags & MP_MAP3LO) x = va_arg(va, int); if (flags & MP_MAP3LO) x = va_arg(va, int);
_m[tile].m3 = x; _map3_lo[tile] = x;
} }
if (flags & (MP_MAP3HI_CLEAR | MP_MAP3HI)) { if (flags & (MP_MAP3HI_CLEAR | MP_MAP3HI)) {
int x = 0; int x = 0;
if (flags & MP_MAP3HI) x = va_arg(va, int); if (flags & MP_MAP3HI) x = va_arg(va, int);
_m[tile].m4 = x; _map3_hi[tile] = x;
} }
if (flags & (MP_MAPOWNER|MP_MAPOWNER_CURRENT)) { if (flags & (MP_MAPOWNER|MP_MAPOWNER_CURRENT)) {
PlayerID x = _current_player; byte x = _current_player;
if (flags & MP_MAPOWNER) x = va_arg(va, int); if (flags & MP_MAPOWNER) x = va_arg(va, int);
_m[tile].m1 = x; _map_owner[tile] = x;
} }
if (flags & MP_MAP5) { if (flags & MP_MAP5) {
_m[tile].m5 = va_arg(va, int); _map5[tile] = va_arg(va, int);
} }
va_end(va); va_end(va);
@@ -395,6 +437,17 @@ void CDECL ModifyTile(TileIndex tile, uint flags, ...)
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }
void SetMapExtraBits(uint tile, byte bits)
{
_map_extra_bits[tile >> 2] &= ~(3 << ((tile&3)*2));
_map_extra_bits[tile >> 2] |= (bits&3) << ((tile&3)*2);
}
uint GetMapExtraBits(uint tile)
{
assert(tile < MapSize());
return (_map_extra_bits[tile >> 2] >> (tile & 3) * 2) & 3;
}
#define TILELOOP_BITS 4 #define TILELOOP_BITS 4
#define TILELOOP_SIZE (1 << TILELOOP_BITS) #define TILELOOP_SIZE (1 << TILELOOP_BITS)
@@ -403,7 +456,7 @@ void CDECL ModifyTile(TileIndex tile, uint flags, ...)
void RunTileLoop(void) void RunTileLoop(void)
{ {
TileIndex tile; uint tile;
uint count; uint count;
tile = _cur_tileloop_tile; tile = _cur_tileloop_tile;
@@ -411,12 +464,12 @@ void RunTileLoop(void)
assert( (tile & ~TILELOOP_ASSERTMASK) == 0); assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE); count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
do { do {
_tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile); _tile_type_procs[TileType(tile)]->tile_loop_proc(tile);
if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) { if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
tile += TILELOOP_SIZE; /* no overflow */ tile += TILELOOP_SIZE; /* no overflow */
} else { } else {
tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */ tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE-1) + TILE_XY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
} }
} while (--count); } while (--count);
assert( (tile & ~TILELOOP_ASSERTMASK) == 0); assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
@@ -429,38 +482,40 @@ void RunTileLoop(void)
void InitializeLandscape(void) void InitializeLandscape(void)
{ {
uint map_size; uint map_size = MapSize();
uint i; uint i;
memset(_map_owner, OWNER_NONE, map_size);
memset(_map2, 0, map_size * sizeof(uint16));
memset(_map3_lo, 0, map_size);
memset(_map3_hi, 0, map_size);
memset(_map_extra_bits, 0, map_size / 4);
memset(_map_type_and_height, MP_CLEAR << 4, map_size);
map_size = MapSize(); // create void tiles on the border
for (i = 0; i < map_size; i++) { for (i = 0; i != MapMaxY(); i++)
_m[i].type_height = MP_CLEAR << 4; _map_type_and_height[ i * MapSizeX() + MapMaxY() ] = MP_VOID << 4;
_m[i].m1 = OWNER_NONE; memset(_map_type_and_height + MapMaxY() * MapSizeX(), MP_VOID << 4, MapSizeX());
_m[i].m2 = 0;
_m[i].m3 = 0;
_m[i].m4 = 0;
_m[i].m5 = 3;
_m[i].extra = 0;
}
// create void tiles at the border memset(_map5, 3, map_size);
for (i = 0; i < MapMaxY(); ++i)
SetTileType(i * MapSizeX() + MapMaxX(), MP_VOID);
for (i = 0; i < MapSizeX(); ++i)
SetTileType(MapSizeX() * MapMaxY() + i, MP_VOID);
} }
void ConvertGroundTilesIntoWaterTiles(void) void ConvertGroundTilesIntoWaterTiles(void)
{ {
TileIndex tile = 0; uint tile = 0;
uint h; int h;
for (tile = 0; tile < MapSize(); ++tile) { while(true) {
if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == 0 && h == 0) { if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == 0 && h == 0) {
SetTileType(tile, MP_WATER); SetTileType(tile, MP_WATER);
_m[tile].m5 = 0; _map5[tile] = 0;
SetTileOwner(tile, OWNER_WATER); _map_owner[tile] = OWNER_WATER;
}
tile++;
if (TileX(tile) == MapMaxX()) {
tile += TILE_XY(-(int)MapMaxX(), 1);
if (TileY(tile) == MapMaxY())
break;
} }
} }
} }
@@ -471,17 +526,13 @@ static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
static void GenerateTerrain(int type, int flag) static void GenerateTerrain(int type, int flag)
{ {
uint32 r; uint32 r;
uint x; uint x,y;
uint y; int w,h;
uint w; byte *p,*tile;
uint h;
const Sprite* template;
const byte *p;
Tile* tile;
byte direction; byte direction;
r = Random(); r = Random();
template = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845); p = GetSpritePtr((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845);
x = r & MapMaxX(); x = r & MapMaxX();
y = (r >> MapLogX()) & MapMaxY(); y = (r >> MapLogX()) & MapMaxY();
@@ -490,37 +541,29 @@ static void GenerateTerrain(int type, int flag)
if (x < 2 || y < 2) if (x < 2 || y < 2)
return; return;
direction = GB(r, 22, 2); direction = (byte)(r >> 22) & 3;
if (direction & 1) { w = p[2];
w = template->height; h = p[1];
h = template->width; if (direction & 1) { w = p[1]; h = p[2]; }
} else { p += 8;
w = template->width;
h = template->height;
}
p = template->data;
if (flag & 4) { if (flag & 4) {
uint xw = x * MapSizeY(); if (!(flag & 2)) {
uint yw = y * MapSizeX(); if (!(flag & 1)) {
uint bias = (MapSizeX() + MapSizeY()) * 16; if (x + y > 190)
return;
switch (flag & 3) { } else {
case 0: if (y < 30 + x)
if (xw + yw > MapSize() - bias) return; return;
break; }
} else {
case 1: if (!(flag & 1)) {
if (yw < xw + bias) return; if (x + y < 256)
break; return;
} else {
case 2: if (x < 30 + y)
if (xw + yw < MapSize() + bias) return; return;
break; }
case 3:
if (xw < yw + bias) return;
break;
} }
} }
@@ -530,66 +573,54 @@ static void GenerateTerrain(int type, int flag)
if (y + h >= MapMaxY() - 1) if (y + h >= MapMaxY() - 1)
return; return;
tile = &_m[TileXY(x, y)]; tile = &_map_type_and_height[TILE_XY(x,y)];
switch (direction) { if (direction == 0) {
case 0: do {
int w_cur = w;
byte *tile_cur = tile;
do { do {
Tile* tile_cur = tile; if (*p >= *tile_cur) *tile_cur = *p;
uint w_cur; p++;
tile_cur++;
for (w_cur = w; w_cur != 0; --w_cur) { } while (--w_cur != 0);
if (*p >= tile_cur->type_height) tile_cur->type_height = *p; tile += TILE_XY(0,1);
p++; } while (--h != 0);
tile_cur++; } else if (direction == 1) {
} do {
tile += TileDiffXY(0, 1); int h_cur = h;
} while (--h != 0); byte *tile_cur = tile;
break;
case 1:
do { do {
Tile* tile_cur = tile; if (*p >= *tile_cur) *tile_cur = *p;
uint h_cur; p++;
tile_cur+=TILE_XY(0,1);
for (h_cur = h; h_cur != 0; --h_cur) { } while (--h_cur != 0);
if (*p >= tile_cur->type_height) tile_cur->type_height = *p; tile++;
p++; } while (--w != 0);
tile_cur += TileDiffXY(0, 1); } else if (direction == 2) {
} tile += w - 1;
tile++; do {
} while (--w != 0); int w_cur = w;
break; byte *tile_cur = tile;
case 2:
tile += TileDiffXY(w - 1, 0);
do { do {
Tile* tile_cur = tile; if (*p >= *tile_cur) *tile_cur = *p;
uint w_cur; p++;
tile_cur--;
for (w_cur = w; w_cur != 0; --w_cur) { } while (--w_cur != 0);
if (*p >= tile_cur->type_height) tile_cur->type_height = *p; tile += TILE_XY(0,1);
p++; } while (--h != 0);
tile_cur--; } else {
} tile += (h - 1) * TILE_XY(0,1);
tile += TileDiffXY(0, 1); do {
} while (--h != 0); int h_cur = h;
break; byte *tile_cur = tile;
case 3:
tile += TileDiffXY(0, h - 1);
do { do {
Tile* tile_cur = tile; if (*p >= *tile_cur) *tile_cur = *p;
uint h_cur; p++;
tile_cur-=TILE_XY(0,1);
for (h_cur = h; h_cur != 0; --h_cur) { } while (--h_cur != 0);
if (*p >= tile_cur->type_height) tile_cur->type_height = *p; tile++;
p++; } while (--w != 0);
tile_cur -= TileDiffXY(0, 1);
}
tile++;
} while (--w != 0);
break;
} }
} }
@@ -598,28 +629,28 @@ static void GenerateTerrain(int type, int flag)
static void CreateDesertOrRainForest(void) static void CreateDesertOrRainForest(void)
{ {
TileIndex tile; uint tile;
const TileIndexDiffC *data; const TileIndexDiffC *data;
uint i; int i;
for (tile = 0; tile != MapSize(); ++tile) { for (tile = 0; tile != MapSize(); ++tile) {
for (data = _make_desert_or_rainforest_data; for (data = _make_desert_or_rainforest_data;
data != endof(_make_desert_or_rainforest_data); ++data) { data != endof(_make_desert_or_rainforest_data); ++data) {
TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data)); TileIndex t = tile + ToTileIndexDiff(*data);
if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break; if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break;
} }
if (data == endof(_make_desert_or_rainforest_data)) if (data == endof(_make_desert_or_rainforest_data))
SetMapExtraBits(tile, 1); SetMapExtraBits(tile, 1);
} }
for (i = 0; i != 256; i++) for(i=0; i!=256; i++)
RunTileLoop(); RunTileLoop();
for (tile = 0; tile != MapSize(); ++tile) { for (tile = 0; tile != MapSize(); ++tile) {
for (data = _make_desert_or_rainforest_data; for (data = _make_desert_or_rainforest_data;
data != endof(_make_desert_or_rainforest_data); ++data) { data != endof(_make_desert_or_rainforest_data); ++data) {
TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data)); TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
if (IsTileType(t, MP_CLEAR) && (_m[t].m5 & 0x1c) == 0x14) break; if (IsTileType(t, MP_CLEAR) && (_map5[t] & 0x1c) == 0x14) break;
} }
if (data == endof(_make_desert_or_rainforest_data)) if (data == endof(_make_desert_or_rainforest_data))
SetMapExtraBits(tile, 2); SetMapExtraBits(tile, 2);
@@ -628,35 +659,45 @@ static void CreateDesertOrRainForest(void)
void GenerateLandscape(void) void GenerateLandscape(void)
{ {
uint i; int i,flag;
uint flag;
uint32 r; uint32 r;
if (_opt.landscape == LT_HILLY) { if (_opt.landscape == LT_HILLY) {
for (i = ScaleByMapSize((Random() & 0x7F) + 950); i != 0; --i) i = ((Random() & 0x7F) + 950) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(2, 0); GenerateTerrain(2, 0);
} while (--i);
r = Random(); r = Random();
flag = GB(r, 0, 2) | 4; flag = (r & 3) | 4;
for (i = ScaleByMapSize(GB(r, 16, 7) + 450); i != 0; --i) i = (((r >> 16) & 0x7F) + 450) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(4, flag); GenerateTerrain(4, flag);
} while (--i);
} else if (_opt.landscape == LT_DESERT) { } else if (_opt.landscape == LT_DESERT) {
for (i = ScaleByMapSize((Random()&0x7F) + 170); i != 0; --i) i = ((Random()&0x7F) + 170) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(0, 0); GenerateTerrain(0, 0);
} while (--i);
r = Random(); r = Random();
flag = GB(r, 0, 2) | 4; flag = (r & 3) | 4;
for (i = ScaleByMapSize(GB(r, 16, 8) + 1700); i != 0; --i) i = (((r >> 16) & 0xFF) + 1700) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(0, flag); GenerateTerrain(0, flag);
} while (--i);
flag ^= 2; flag ^= 2;
for (i = ScaleByMapSize((Random() & 0x7F) + 410); i != 0; --i) i = ((Random() & 0x7F) + 410) * LANDSCAPE_SIZE_FACTOR;
do {
GenerateTerrain(3, flag); GenerateTerrain(3, flag);
} while (--i);
} else { } else {
i = ScaleByMapSize((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes) * 256 + 100); i = ((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes)*256 + 100) * LANDSCAPE_SIZE_FACTOR;
for (; i != 0; --i) do {
GenerateTerrain(_opt.diff.terrain_type, 0); GenerateTerrain(_opt.diff.terrain_type, 0);
} while (--i);
} }
ConvertGroundTilesIntoWaterTiles(); ConvertGroundTilesIntoWaterTiles();
@@ -689,13 +730,32 @@ TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
int rn = rng; int rn = rng;
uint32 r = Random(); uint32 r = Random();
return TILE_MASK(TileXY( return TILE_XY(
TileX(a) + (GB(r, 0, 8) * rn * 2 >> 8) - rn, TileX(a) + ((byte)r * rn * 2 >> 8) - rn,
TileY(a) + (GB(r, 8, 8) * rn * 2 >> 8) - rn TileY(a) + ((byte)(r >> 8) * rn * 2 >> 8) - rn
)); );
} }
bool IsValidTile(TileIndex tile) // This function checks if we add addx/addy to tile, if we
// do wrap around the edges. For example, tile = (10,2) and
// addx = +3 and addy = -4. This function will now return
// TILE_WRAPPED, because the y is wrapped. This is needed in
// for example, farmland. When the tile is not wrapped,
// the result will be tile + TILE_XY(addx, addy)
uint TileAddWrap(TileIndex tile, int addx, int addy)
{
uint x, y;
x = TileX(tile) + addx;
y = TileY(tile) + addy;
// Are we about to wrap?
if (x < MapMaxX() && y < MapMaxY())
return tile + TILE_XY(addx, addy);
return TILE_WRAPPED;
}
bool IsValidTile(uint tile)
{ {
return (tile < MapSizeX() * MapMaxY() && TileX(tile) != MapMaxX()); return (tile < MapSizeX() * MapMaxY() && TileX(tile) != MapMaxX());
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
##name Original vehicle names (ENG) ##name Original vehicle names (ENG)
##ownname Original vehicle names (ENG) ##ownname Original vehicle names (ENG)
##isocode xx
##id 0x8000 ##id 0x8000
STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam) STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam)

Some files were not shown because too many files have changed in this diff Show More