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

Compare commits

..

51 Commits

Author SHA1 Message Date
celestar
acafa8007b (svn r7978) [0.5] - Fix: Revert the previous commit. it WAS in the wrong dir 2007-01-08 14:00:14 +00:00
celestar
297707d2ab (svn r7977) [0.5] - Fix: Segfault in newgrf loading code. grfmsg changed to DEBUG 2007-01-08 13:57:40 +00:00
Darkvater
20f4c7f489 (svn r7971) Release 0.5.0-RC3 2007-01-07 17:53:34 +00:00
Darkvater
06b5d32983 (svn r7970) -Backport from trunk (r7968, r7969):
- Update year throughout the program to 2007
 - Minor update to changelog, known-bugs file (Bjarni)
2007-01-07 17:38:58 +00:00
Darkvater
34f8ab2f81 (svn r7967) - Prepare 0.5 branch for release. Update readme's, bugs, installers, changelog, etc. to 0.5.0-RC3 2007-01-07 16:43:46 +00:00
Darkvater
315ec78344 (svn r7963) -Backport from trunk (r7716, r7717, r7718):
- Bad signal propagation through tunnel-ends, incompatible railtype signal propagation
 still possible (not fixed).
2007-01-07 14:10:56 +00:00
Darkvater
0bf1d6c49d (svn r7962) -Backport from trunk (r7689, r7696, r7699, r7701, r7704, r7706, r7707, r7713,
r7715, r7723, r7732, r7738, r7742, r7743, r7746, r7754, r7756, r7787, r7800,
 r7803, r7806, r7807, r7819, r7828, r7857, r7884, r7896, r7905):
 - Language file updates.
 - Untranslated strings: Icelandic (217!), Hungarian (2), Galician (140), Finnish (3),
   Brazilian-Portugese (3).
 - Moved Lithuanian from unfinished to finished.
2007-01-07 13:49:54 +00:00
matthijs
6f291a7e6d (svn r7958) - [Debian] Prepare debian packing files for 0.5.0-rc3 2007-01-07 12:44:45 +00:00
Darkvater
04d77258c5 (svn r7957) -Backport from trunk (r7936):
- Only update the signals and YAPF cache on a DC_EXEC action for bridge-building
2007-01-07 12:20:48 +00:00
Darkvater
fbfa0b8009 (svn r7956) -Backport from trunk (r7930):
- wrong TTDPatch GRF flag was set for gradual loading
2007-01-07 12:19:56 +00:00
Darkvater
8960b5740f (svn r7955) -Backport from trunk (r7886):
- [osx] control+enter no longer fullscreens, interfered with team-chat.
2007-01-07 12:19:08 +00:00
Darkvater
30fadfb54b (svn r7954) -Backport from trunk (r7864):
- offset engines/wagons by half width in details window; fixes overflowing for display
2007-01-07 12:18:05 +00:00
Darkvater
b342991853 (svn r7953) -Backport from trunk (r7840, r7843):
- [win32] Update crash window text (+crash.dmp -submit)
2007-01-07 12:16:53 +00:00
Darkvater
0a635c692e (svn r7952) -Backport from trunk (r7823, r7861):
- News windows could still crash due to moving news items around while a news window was still open.
2007-01-07 12:15:36 +00:00
Darkvater
0a211097ac (svn r7951) -Backport from trunk (r7810, r7812):
- Building airport whose size exceeds max station spread-out caused assert. (r7810)
 - rail station build window was not correctly updated after station_spread change (r7812)
2007-01-07 12:13:57 +00:00
Darkvater
1277599c30 (svn r7950) -Backport from trunk (r7760, r7766):
- Sprite usage debug message showed the starting sprite, not current sprite, and only do this during activation (r7760).
 - [OSX] Remove incorrect debug message about missing grf files.
2007-01-07 12:11:54 +00:00
Darkvater
bae0695ac9 (svn r7949) -Backport from trunk (r7733):
- do not use WP(w, querystr_d) and WP(w, def_d) for the same window
2007-01-07 12:07:07 +00:00
Darkvater
630f81c382 (svn r7948) -Backport from trunk (r7731):
- off-by-one error in the date to YMD calculation for first 4 years of a century that was not divisable by 400
2007-01-07 12:06:34 +00:00
Darkvater
2684cb2525 (svn r7947) -Backport from trunk (r7727):
- [sdl] sometimes ALT-TAB could trigger the fast forward
2007-01-07 12:05:47 +00:00
Darkvater
610b6e3953 (svn r7946) -Backport from trunk (r7711, r7795, r7831):
- NewGRF Action 7, GRF check condition 10 didn't ignore unknown GRF IDs (r7354)
 - NewGRF safety scan fixes action E (allow unifont.grf) and Action 0 prop D (bridge) (r7795, r7831)
2007-01-07 11:53:12 +00:00
Darkvater
563857d5bd (svn r7945) -Backport from trunk (r7700):
- Caret randomly jumping back&forth for new randomseed (r7182)
2007-01-07 11:37:23 +00:00
Darkvater
58d18a3ef3 (svn r7944) -Backport from trunk (r7692):
- -OpenTTD didn't compile without network enabled (newgrf sync code)
2007-01-07 11:34:20 +00:00
rubidium
0b7ab719f3 (svn r7893) [0.5] -Fix (FS#485): the configure script did not work work for dash, a sh compatible shell. 2007-01-05 23:43:20 +00:00
Darkvater
f5439821c1 (svn r7694) -Update known-bugs file. 2006-12-31 11:28:42 +00:00
Darkvater
d11a6a439a (svn r7685) - Prepare 0.5 branch for release. Update readme's, bugs, installers, changelog, etc. to 0.5.0-RC2 2006-12-31 01:21:00 +00:00
Darkvater
99096b83bd (svn r7684) -Backport from trunk (r7620):
- Bad signal update through incompatible rail types, bridge.
2006-12-31 00:52:33 +00:00
Darkvater
75c538962d (svn r7683) -Backport from trunk (r7552, r7553, r7574, r7581, r7601, r7611, r7654, r7658):
- Language file updates.
 - Untranslated strings: Turkish (2), Swedish (1), Romanian (3), Norwegian (2),
   Icelandic (217!), Hungarian (2), German (1), Galician (173), Finnish (26),
   Danish (23), Czech (34), Bulgarian (39), Brazilian-Portugese (3)
2006-12-31 00:01:07 +00:00
Darkvater
51cd7bd43b (svn r7682) -Backport from trunk (r7539, r7541, r7603):
- Added esperanto language files to MS projects (r7539).
 - Polish townname generator uses proper UNICODE characters (r7603).
2006-12-30 23:38:41 +00:00
Darkvater
0b67caa8ad (svn r7681) -Backport from trunk (r7585, r7590, r7599):
- Drastically reduce CheckStationSpreadOut CPU usage which got called way too much by the AI.
2006-12-30 23:35:01 +00:00
Darkvater
4ec96ba2d0 (svn r7680) -Backport from trunk (r7586):
- Remove landscaping toolbar from road-toolbar in scenario editor
2006-12-30 23:32:22 +00:00
Darkvater
b93e8d6c71 (svn r7679) -Backport from trunk (r7628):
- [YAPF] suppress 'Train is lost' message if pathfinding ended on the first
   two-way red signal
2006-12-30 23:30:21 +00:00
Darkvater
ac945ced7e (svn r7678) -Fix (r7674): DEBUG macro has been changed 2006-12-30 23:29:33 +00:00
Darkvater
5c190a0c33 (svn r7677) -Backport from trunk (r7657):
- 'Goto Depot' did not work for helicopters going to an airport without depot
2006-12-30 23:26:47 +00:00
Darkvater
b5715acaf8 (svn r7676) -Backport from trunk (r7630, r7631):
- cur/old economy memmove magic (r7630).
 - wrong pointer arithmetic that totally corrupted animated_tiles table, desyncing
   between different endiannes-machines in multiplayer (r7631).
2006-12-30 23:25:57 +00:00
Darkvater
0e7701fbe6 (svn r7675) -Backport from trunk (r7606):
- [NewStations] Add support for variables 45 and 65.
2006-12-30 23:23:43 +00:00
Darkvater
59167f686e (svn r7674) -Backport from trunk (r7580):
- Wrong bounding boxes were computed for certain strings.
2006-12-30 23:22:55 +00:00
Darkvater
0adf61e7fa (svn r7673) -Backport from trunk (r7563):
- [FS#468] Removing towns in scenario editor didn't remove their subsidies.
2006-12-30 23:21:55 +00:00
Darkvater
6fa93f4a7a (svn r7672) -Backport from trunk (r7562):
- [win32] OpenTTD didn't always remember its maximized state on restart.
2006-12-30 23:21:02 +00:00
Darkvater
f3424f51bc (svn r7671) -Backport from trunk (r7560, r7561, r7566):
- No new company could join if 8 clients were connected in less than 8 companies (r7560).
 - [FS#431] internal and visible settings of autorenew could go out of sync (r8561).
 - Server told clients to start syncing from a bad position, causing asserts/crashes (r7566).
2006-12-30 23:20:00 +00:00
Darkvater
6c8f12de78 (svn r7670) -Backport from trunk (r7558, r7559):
- [FS#464] do not wait till a crashed vehicle is removed before starting to load
 other vehicles (r7558).
 - [FS#456] clicking 'full load' can change depot order under certain circumstances (r7559).
2006-12-30 23:14:39 +00:00
Darkvater
953fc9e196 (svn r7669) -Backport from trunk (r7556):
- screenshot no_con didn't remove console from screenshot.
2006-12-30 23:12:05 +00:00
Darkvater
737220f39c (svn r7668) -Backport from trunk (r7555):
- off-by-one error due do truncation on division by 2 in heightmap code.
2006-12-30 23:11:14 +00:00
Darkvater
e00a47d47d (svn r7667) -Backport from trunk (r7549, r7551, r7554, r7582, r7594):
- change size of newgrf GUI to same size as TTDP (no overflows) (r7549).
 - segmentation fault on showing NewGRF settings of a network game (r7551).
 - in Action 0xE, don't deactivate the current GRF (r7554).
 - appending static GRF's could cause duplicate GRF's in the list (r7582).
 - GRF config not cleared when no GRF's are used (r7594).
2006-12-30 23:09:27 +00:00
Darkvater
cf52f00f46 (svn r7666) -Backport from trunk (r7548):
- Some MorphOS changes to get OpenTTD compiled, packaged.
2006-12-30 23:04:14 +00:00
Darkvater
d4b335fffb (svn r7665) -Backport from trunk (r7547):
- When removing a rail station, the cost was added for the full rectangle not for
   only the removed tiles themselves.
2006-12-30 23:03:15 +00:00
Darkvater
652e834ee7 (svn r7664) -Backport from trunk (r7587, r7588, r7600, r7605, r7626, r7629):
- [OSX] universal binary docs, makefile (r7587, r7588, r7626).
 - General documentation update (r7600, r7605).
 - openttd -h showed outdated help for '-n' switch (r7629).
2006-12-30 23:00:52 +00:00
Darkvater
dfab8c779b (svn r7662) -Backport from trunk (r7557, r7624):
- [OSX] makefile fixes (static libfontconfig) (r7557).
 - [FS#470] Install openttd.32.bmp on install so that SDL window has icon (r76240.
2006-12-30 22:55:31 +00:00
Darkvater
bbdbdf3818 (svn r7661) -Backport from trunk (r7550):
- [win32] x64 compile fixed.
2006-12-30 22:53:05 +00:00
Darkvater
0264283116 (svn r7660) -Backport from trunk (r7537, r7539):
- Changelog updates
2006-12-30 22:50:49 +00:00
matthijs
6f97748c80 (svn r7659) - [Debian] Prepare debian packing files for 0.5.0-rc2 2006-12-30 22:36:22 +00:00
Darkvater
65d6403497 (svn r7536) -Branch: add 0.5 branch 2006-12-21 20:56:57 +00:00
1319 changed files with 187603 additions and 364223 deletions

12
.gitignore vendored
View File

@@ -1,12 +0,0 @@
Makefile*
bin/*
bundle/*
!bin/data/chars.grf
!bin/data/openttdd.grf
!bin/data/openttdw.grf
!bin/data/opntitle.grf
!bin/scenario/README
!bin/scripts*
config.*
objs/*
src/rev.cpp

View File

@@ -1,11 +0,0 @@
bin/lang/*
bin/opentd*
bundle/*
config.cache.*
config.log
config.pwd
Makefile
Makefile.am
media/openttd.desktop*
objs/*
src/rev.cpp

7
BUGS Normal file
View File

@@ -0,0 +1,7 @@
/* $Id$ */
KNOWN BUGS / PROBLEMS:
Normal and elrail depots look the same. Use 'X' (transparent buildings)
to distinguish between them
Missing curors / icons for construction (currently using the conventional ones)

39
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -303,9 +303,10 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
@@ -335,5 +336,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -1,10 +1,11 @@
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = OpenTTD
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" \
@@ -76,14 +77,13 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ./src/
INPUT = ./
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.h \
*.hpp \
table/*.h
RECURSIVE = YES
EXCLUDE =
@@ -158,7 +158,7 @@ RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
GENERATE_MAN = YES
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
@@ -185,13 +185,13 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED = DEF_COMMAND
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
@@ -220,6 +220,8 @@ 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

1122
Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,183 +0,0 @@
#
# Creation of bundles
#
# The revision is needed for the bundle name and creating an OSX application bundle.
ifdef REVISION
REV := $(REVISION)
else
# Detect the revision
VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh")
REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ')
endif
# Make sure we have something in REV
ifeq ($(REV),)
REV := norev000
endif
ifndef BUNDLE_NAME
BUNDLE_NAME = openttd-custom-$(REV)-$(OS)
endif
# An OSX application bundle needs the data files, lang files and openttd executable in a different location.
ifdef OSXAPP
DATA_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/data
LANG_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/lang
TTD_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/MacOS
else
DATA_DIR = $(BUNDLE_DIR)/data
LANG_DIR = $(BUNDLE_DIR)/lang
TTD_DIR = $(BUNDLE_DIR)
endif
bundle: all
@echo '[BUNDLE] Constructing bundle'
$(Q)rm -rf "$(BUNDLE_DIR)"
$(Q)mkdir -p "$(BUNDLE_DIR)"
$(Q)mkdir -p "$(BUNDLE_DIR)/docs"
$(Q)mkdir -p "$(BUNDLE_DIR)/media"
$(Q)mkdir -p "$(BUNDLE_DIR)/scripts"
$(Q)mkdir -p "$(TTD_DIR)"
$(Q)mkdir -p "$(DATA_DIR)"
$(Q)mkdir -p "$(LANG_DIR)"
ifdef OSXAPP
$(Q)mkdir -p "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources"
$(Q)echo "APPL????" > "$(BUNDLE_DIR)/$(OSXAPP)/Contents/PkgInfo"
$(Q)cp "$(ROOT_DIR)/os/macosx/openttd.icns" "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/openttd.icns"
$(Q)$(ROOT_DIR)/os/macosx/plistgen.sh "$(BUNDLE_DIR)/$(OSXAPP)" "$(REV)"
$(Q)cp "$(ROOT_DIR)/docs/OSX_install_instructions.txt" "$(BUNDLE_DIR)/docs/"
$(Q)cp "$(ROOT_DIR)/os/macosx/splash.png" "$(DATA_DIR)"
endif
$(Q)cp "$(BIN_DIR)/$(TTD)" "$(TTD_DIR)/"
$(Q)cp "$(BIN_DIR)/data/"*.grf "$(DATA_DIR)/"
$(Q)cp "$(BIN_DIR)/data/"*.obg "$(DATA_DIR)/"
$(Q)cp "$(BIN_DIR)/data/opntitle.dat" "$(DATA_DIR)/"
$(Q)cp "$(BIN_DIR)/lang/"*.lng "$(LANG_DIR)/"
$(Q)cp "$(ROOT_DIR)/readme.txt" "$(BUNDLE_DIR)/"
$(Q)cp "$(ROOT_DIR)/COPYING" "$(BUNDLE_DIR)/"
$(Q)cp "$(ROOT_DIR)/known-bugs.txt" "$(BUNDLE_DIR)/"
$(Q)cp "$(ROOT_DIR)/docs/obg_format.txt" "$(BUNDLE_DIR)/docs/"
$(Q)cp "$(ROOT_DIR)/docs/multiplayer.txt" "$(BUNDLE_DIR)/docs/"
$(Q)cp "$(ROOT_DIR)/docs/32bpp.txt" "$(BUNDLE_DIR)/docs/"
$(Q)cp "$(ROOT_DIR)/changelog.txt" "$(BUNDLE_DIR)/"
ifdef MAN_DIR
$(Q)mkdir -p "$(BUNDLE_DIR)/man/"
$(Q)cp "$(ROOT_DIR)/docs/openttd.6" "$(BUNDLE_DIR)/man/"
$(Q)gzip -9 "$(BUNDLE_DIR)/man/openttd.6"
endif
$(Q)cp "$(ROOT_DIR)/media/openttd.32.xpm" "$(BUNDLE_DIR)/media/"
$(Q)cp "$(ROOT_DIR)/media/openttd."*.png "$(BUNDLE_DIR)/media/"
$(Q)cp "$(BIN_DIR)/scripts/"* "$(BUNDLE_DIR)/scripts/"
ifdef MENU_DIR
$(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/"
$(Q)cat "$(ROOT_DIR)/media/openttd.desktop" | sed s/=openttd/=$(BINARY_NAME)/g > "$(ROOT_DIR)/media/openttd.desktop.install"
endif
ifeq ($(TTD), openttd.exe)
$(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/COPYING" "$(BUNDLE_DIR)/changelog.txt" "$(BUNDLE_DIR)/known-bugs.txt"
ifeq ($(OS), DOS)
$(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi.txt" "$(BUNDLE_DIR)/docs/"
ifndef STRIP
$(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi.exe" "$(TTD_DIR)/"
endif
endif
endif
### Packing the current bundle into several compressed file formats ###
#
# Zips & dmgs do not contain a root folder, i.e. they have files in the root of the zip/dmg.
# gzip, bzip2 and lha archives have a root folder, with the same name as the bundle.
#
# One can supply a custom name by adding BUNDLE_NAME:=<name> to the make command.
#
bundle_zip: bundle
@echo '[BUNDLE] Creating $(BUNDLE_NAME).zip'
$(Q)mkdir -p "$(BUNDLES_DIR)"
$(Q)cd "$(BUNDLE_DIR)" && zip -r $(shell if test -z "$(VERBOSE)"; then echo '-q'; fi) "$(BUNDLES_DIR)/$(BUNDLE_NAME).zip" .
bundle_gzip: bundle
@echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz'
$(Q)mkdir -p "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)"
$(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)/"
$(Q)cd "$(BUNDLES_DIR)/.gzip" && tar -zc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.gz" "$(BUNDLE_NAME)"
$(Q)rm -rf "$(BUNDLES_DIR)/.gzip"
bundle_bzip2: bundle
@echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.bz2'
$(Q)mkdir -p "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)"
$(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)/"
$(Q)cd "$(BUNDLES_DIR)/.bzip2" && tar -jc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.bz2" "$(BUNDLE_NAME)"
$(Q)rm -rf "$(BUNDLES_DIR)/.bzip2"
bundle_lha: bundle
@echo '[BUNDLE] Creating $(BUNDLE_NAME).lha'
$(Q)mkdir -p "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)"
$(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)/"
$(Q)cd "$(BUNDLES_DIR)/.lha" && lha ao6 "$(BUNDLES_DIR)/$(BUNDLE_NAME).lha" "$(BUNDLE_NAME)"
$(Q)rm -rf "$(BUNDLES_DIR)/.lha"
bundle_dmg: bundle
@echo '[BUNDLE] Creating $(BUNDLE_NAME).dmg'
$(Q)mkdir -p "$(BUNDLES_DIR)/OpenTTD $(REV)"
$(Q)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/OpenTTD $(REV)"
$(Q)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/OpenTTD $(REV)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg"
$(Q)rm -fr "$(BUNDLES_DIR)/OpenTTD $(REV)"
bundle_exe: all
@echo '[BUNDLE] Creating $(BUNDLE_NAME).exe'
$(Q)mkdir -p "$(BUNDLES_DIR)"
$(Q)unix2dos "$(ROOT_DIR)/docs/"* "$(ROOT_DIR)/readme.txt" "$(ROOT_DIR)/COPYING" "$(ROOT_DIR)/changelog.txt" "$(ROOT_DIR)/known-bugs.txt"
$(Q)cd $(ROOT_DIR)/os/win32/installer && makensis.exe //DVERSION_INCLUDE=version_$(PLATFORM).txt install.nsi
$(Q)mv $(ROOT_DIR)/os/win32/installer/*$(PLATFORM).exe "$(BUNDLES_DIR)/$(BUNDLE_NAME).exe"
ifdef OSXAPP
install:
@echo '[INSTALL] Cannot install the OSX Application Bundle'
else
install: bundle
@echo '[INSTALL] Installing OpenTTD'
$(Q)install -d "$(INSTALL_BINARY_DIR)"
$(Q)install -d "$(INSTALL_ICON_DIR)"
$(Q)install -d "$(INSTALL_DATA_DIR)/gm"
$(Q)install -d "$(INSTALL_DATA_DIR)/data"
$(Q)install -d "$(INSTALL_DATA_DIR)/lang"
$(Q)install -d "$(INSTALL_DATA_DIR)/scripts"
$(Q)install -d "$(INSTALL_DOC_DIR)"
ifeq ($(TTD), openttd.exe)
$(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}.exe"
else
$(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}"
endif
$(Q)install -m 644 "$(BUNDLE_DIR)/lang/"* "$(INSTALL_DATA_DIR)/lang"
$(Q)install -m 644 "$(BUNDLE_DIR)/data/"* "$(INSTALL_DATA_DIR)/data"
$(Q)install -m 644 "$(BUNDLE_DIR)/scripts/"* "$(INSTALL_DATA_DIR)/scripts"
$(Q)install -m 644 "$(BUNDLE_DIR)/docs/"* "$(INSTALL_DOC_DIR)"
$(Q)install -m 644 "$(BUNDLE_DIR)/"*.txt "$(INSTALL_DOC_DIR)"
$(Q)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(INSTALL_DOC_DIR)"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.xpm" "$(INSTALL_ICON_DIR)/${BINARY_NAME}.32.xpm"
ifdef ICON_THEME_DIR
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/16x16/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.16.png" "$(INSTALL_ICON_THEME_DIR)/16x16/apps/${BINARY_NAME}.png"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/32x32/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.png" "$(INSTALL_ICON_THEME_DIR)/32x32/apps/${BINARY_NAME}.png"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/48x48/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.48.png" "$(INSTALL_ICON_THEME_DIR)/48x48/apps/${BINARY_NAME}.png"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/64x64/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.64.png" "$(INSTALL_ICON_THEME_DIR)/64x64/apps/${BINARY_NAME}.png"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/128x128/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.128.png" "$(INSTALL_ICON_THEME_DIR)/128x128/apps/${BINARY_NAME}.png"
$(Q)install -d "$(INSTALL_ICON_THEME_DIR)/256x256/apps"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.256.png" "$(INSTALL_ICON_THEME_DIR)/256x256/apps/${BINARY_NAME}.png"
else
$(Q)install -m 644 "$(BUNDLE_DIR)/media/"*.png "$(INSTALL_ICON_DIR)"
endif
ifdef MAN_DIR
$(Q)install -d "$(INSTALL_MAN_DIR)"
$(Q)install -m 644 "$(BUNDLE_DIR)/man/openttd.6.gz" "$(INSTALL_MAN_DIR)/${BINARY_NAME}.6.gz"
endif
ifdef MENU_DIR
$(Q)install -d "$(INSTALL_MENU_DIR)"
$(Q)install -m 644 "$(ROOT_DIR)/media/openttd.desktop.install" "$(INSTALL_MENU_DIR)/${BINARY_NAME}.desktop"
endif
endif # OSXAPP

View File

@@ -1,157 +0,0 @@
# Check if we want to show what we are doing
ifdef VERBOSE
Q =
else
Q = @
endif
include Makefile.am
SOURCE_LIST = !!SOURCE_LIST!!
CONFIG_CACHE_SOURCE_LIST = !!CONFIG_CACHE_SOURCE_LIST!!
CONFIG_CACHE_PWD = !!CONFIG_CACHE_PWD!!
CONFIGURE_FILES = !!CONFIGURE_FILES!!
LIPO = !!LIPO!!
BIN_DIR = !!BIN_DIR!!
ICON_THEME_DIR = !!ICON_THEME_DIR!!
MAN_DIR = !!MAN_DIR!!
MENU_DIR = !!MENU_DIR!!
SRC_DIR = !!SRC_DIR!!
ROOT_DIR = !!ROOT_DIR!!
BUNDLE_DIR = "$(ROOT_DIR)/bundle"
BUNDLES_DIR = "$(ROOT_DIR)/bundles"
INSTALL_DIR = !!INSTALL_DIR!!
INSTALL_BINARY_DIR = "$(INSTALL_DIR)/"!!BINARY_DIR!!
INSTALL_MAN_DIR = "$(INSTALL_DIR)/$(MAN_DIR)"
INSTALL_MENU_DIR = "$(INSTALL_DIR)/$(MENU_DIR)"
INSTALL_ICON_DIR = "$(INSTALL_DIR)/"!!ICON_DIR!!
INSTALL_ICON_THEME_DIR = "$(INSTALL_DIR)/$(ICON_THEME_DIR)"
INSTALL_DATA_DIR = "$(INSTALL_DIR)/"!!DATA_DIR!!
INSTALL_DOC_DIR = "$(INSTALL_DIR)/"!!DOC_DIR!!
BINARY_NAME = !!BINARY_NAME!!
STRIP = !!STRIP!!
TTD = !!TTD!!
TTDS = $(SRC_DIRS:%=%/$(TTD))
OS = !!OS!!
OSXAPP = !!OSXAPP!!
REVISION = !!REVISION!!
AWK = !!AWK!!
DISTCC = !!DISTCC!!
RES := $(shell if [ ! -f $(CONFIG_CACHE_PWD) ] || [ "`pwd`" != "`cat $(CONFIG_CACHE_PWD)`" ]; then echo "`pwd`" > $(CONFIG_CACHE_PWD); fi )
RES := $(shell if [ ! -f $(CONFIG_CACHE_SOURCE_LIST) ] || [ -n "`cmp $(CONFIG_CACHE_SOURCE_LIST) $(SOURCE_LIST) 2>/dev/null`" ]; then cp $(SOURCE_LIST) $(CONFIG_CACHE_SOURCE_LIST); fi )
all: config.pwd config.cache
ifdef DISTCC
@if [ -z "`echo '$(MFLAGS)' | grep '\-j'`" ]; then echo; echo "WARNING: you enabled distcc support, but you don't seem to be using the -jN paramter"; echo; fi
endif
@for dir in $(DIRS); do \
$(MAKE) -C $$dir all; \
done
ifdef LIPO
# Lipo is an OSX thing. If it is defined, it means we are building for universal,
# and so we have have to combine the binaries into one big binary
# Remove the last binary made by the last compiled target
$(Q)rm -f $(BIN_DIR)/$(TTD)
# Make all the binaries into one
$(Q)$(LIPO) -create -output $(BIN_DIR)/$(TTD) $(TTDS)
endif
help:
@echo "Available make commands:"
@echo ""
@echo "Compilation:"
@echo " all compile the executable and the lang files"
@echo " lang compile the lang files only"
@echo "Clean up:"
@echo " clean remove the files generated during compilation"
@echo " mrproper remove the files generated during configuration and compilation"
@echo "Run after compilation:"
@echo " run execute openttd after the compilation"
@echo " run-gdb execute openttd in debug mode after the compilation"
@echo " run-prof execute openttd in profiling mode after the compilation"
@echo "Installation:"
@echo " install install the compiled files and the data-files after the compilation"
@echo " bundle create the base for an installation bundle"
@echo " bundle_zip create the zip installation bundle"
@echo " bundle_gzip create the gzip installation bundle"
@echo " bundle_bzip2 create the bzip2 installation bundle"
@echo " bundle_lha create the lha installation bundle"
@echo " bundle_dmg create the dmg installation bundle"
config.pwd: $(CONFIG_CACHE_PWD)
$(MAKE) reconfigure
config.cache: $(CONFIG_CACHE_SOURCE_LIST) $(CONFIGURE_FILES)
$(MAKE) reconfigure
reconfigure:
ifeq ($(shell if test -f config.cache; then echo 1; fi), 1)
@echo "----------------"
@echo "The system detected that source.list or any configure file is altered."
@echo " Going to reconfigure with last known settings..."
@echo "----------------"
# Make sure we don't lock config.cache
@$(shell cat config.cache | sed 's@\\ @\\\\ @g') || exit 1
@echo "----------------"
@echo "Reconfig done. Please re-execute make."
@echo "----------------"
else
@echo "----------------"
@echo "Have not found a configuration, please run configure first."
@echo "----------------"
@exit 1
endif
clean:
@for dir in $(DIRS); do \
$(MAKE) -C $$dir clean; \
done
$(Q)rm -rf $(BUNDLE_TARGET)
lang:
@for dir in $(LANG_DIRS); do \
$(MAKE) -C $$dir all; \
done
mrproper:
@for dir in $(DIRS); do \
$(MAKE) -C $$dir mrproper; \
rm -f $$dir/Makefile; \
done
$(Q)rm -rf objs
$(Q)rm -f Makefile Makefile.am Makefile.bundle
$(Q)rm -f media/openttd.desktop
$(Q)rm -f $(CONFIG_CACHE_SOURCE_LIST) config.cache config.pwd config.log $(CONFIG_CACHE_PWD)
$(Q)rm -rf $(BUNDLE_DIR)
$(Q)rm -rf $(BUNDLES_DIR)
depend:
@for dir in $(SRC_DIRS); do \
$(MAKE) -C $$dir depend; \
done
run: all
$(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS)
run-gdb: all
$(Q)cd !!BIN_DIR!! && gdb --ex run --args ./!!TTD!! $(OPENTTD_ARGS)
run-prof: all
$(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS) && gprof !!TTD!! | less
regression: all
$(Q)cd !!BIN_DIR!! && sh ai/regression/run.sh
%.o:
@for dir in $(SRC_DIRS); do \
$(MAKE) -C $$dir $(@:src/%=%); \
done
%.lng:
@for dir in $(LANG_DIRS); do \
$(MAKE) -C $$dir $@; \
done
include Makefile.bundle

View File

@@ -1,87 +0,0 @@
STRGEN = !!STRGEN!!
ENDIAN_CHECK = !!ENDIAN_CHECK!!
SRC_DIR = !!SRC_DIR!!
LANG_DIR = !!LANG_DIR!!
BIN_DIR = !!BIN_DIR!!
LANGS_SRC = $(shell ls $(LANG_DIR)/*.txt)
LANGS = $(LANGS_SRC:$(LANG_DIR)/%.txt=%.lng)
CXX_BUILD = !!CXX_BUILD!!
CFLAGS_BUILD = !!CFLAGS_BUILD!!
STRGEN_FLAGS = !!STRGEN_FLAGS!!
STAGE = !!STAGE!!
LANG_SUPPRESS= !!LANG_SUPPRESS!!
LANG_OBJS_DIR= !!LANG_OBJS_DIR!!
ifeq ($(LANG_SUPPRESS), yes)
LANG_ERRORS = >/dev/null 2>&1
endif
# Make sure endian_host.h is reasable as if it was in the src/ dir
CFLAGS_BUILD += -I $(LANG_OBJS_DIR)
ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK)
# Check if we want to show what we are doing
ifdef VERBOSE
Q =
E = @true
else
Q = @
E = @echo
endif
RES := $(shell mkdir -p $(BIN_DIR)/lang )
all: table/strings.h $(LANGS)
strgen.o: $(SRC_DIR)/strgen/strgen.cpp endian_host.h $(SRC_DIR)/table/control_codes.h
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) -DSTRGEN -c -o $@ $<
string.o: $(SRC_DIR)/string.cpp endian_host.h
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) -DSTRGEN -c -o $@ $<
alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) -DSTRGEN -c -o $@ $<
lang/english.txt: $(LANG_DIR)/english.txt
$(Q)mkdir -p lang
$(Q)cp $(LANG_DIR)/english.txt lang/english.txt
$(STRGEN): alloc_func.o string.o strgen.o
$(E) '$(STAGE) Compiling and Linking $@'
$(Q)$(CXX_BUILD) $^ -o $@
table/strings.h: lang/english.txt $(STRGEN)
$(E) '$(STAGE) Generating $@'
@mkdir -p table
$(Q)./$(STRGEN) -s $(LANG_DIR) -d table
$(LANGS): %.lng: $(LANG_DIR)/%.txt $(STRGEN) lang/english.txt
$(E) '$(STAGE) Compiling language $(*F)'
$(Q)./$(STRGEN) $(STRGEN_FLAGS) -s $(LANG_DIR) -d $(LANG_OBJS_DIR) $< $(LANG_ERRORS) && cp $@ $(BIN_DIR)/lang || true # Do not fail all languages when one fails
# The targets to compile the endian-code
endian_host.h: $(ENDIAN_CHECK)
$(E) '$(STAGE) Testing endianness for host'
$(Q)./$(ENDIAN_CHECK) > $@
$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp
$(E) '$(STAGE) Compiling and Linking $@'
$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $< -o $@
depend:
clean:
$(E) '$(STAGE) Cleaning up language files'
$(Q)rm -f strgen.o string.o table/strings.h $(STRGEN) $(LANGS) $(LANGS:%=$(BIN_DIR)/lang/%) lang/english.* $(ENDIAN_TARGETS)
mrproper: clean
%.lng:
@echo '$(STAGE) No such language: $(@:%.lng=%)'
.PHONY: all mrproper depend clean

View File

@@ -1,28 +0,0 @@
#
# Makefile for creating bundles of MSVC's binaries in the same way as we make
# the zip bundles for ALL other OSes.
#
# Usage: make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=openttd-<version>-win[32|64]
# or make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=OTTD-win[32|64]-nightly-<revision>
#
# Check if we want to show what we are doing
ifdef VERBOSE
Q =
else
Q = @
endif
AWK = "awk"
ROOT_DIR := $(shell pwd)
BIN_DIR = "$(ROOT_DIR)/bin"
SRC_DIR = "$(ROOT_DIR)/src"
BUNDLE_DIR = "$(ROOT_DIR)/bundle"
BUNDLES_DIR = "$(ROOT_DIR)/bundles"
TTD = openttd.exe
TARGET := $(shell echo $(PLATFORM) | sed "s@win64@x64@;s@win32@Win32@")
all:
$(Q)cp objs/$(TARGET)/Release/$(TTD) $(BIN_DIR)/$(TTD)
include Makefile.bundle.in

View File

@@ -1,278 +0,0 @@
CC_HOST = !!CC_HOST!!
CXX_HOST = !!CXX_HOST!!
CC_BUILD = !!CC_BUILD!!
CXX_BUILD = !!CXX_BUILD!!
WINDRES = !!WINDRES!!
STRIP = !!STRIP!!
CFLAGS = !!CFLAGS!!
CFLAGS_BUILD = !!CFLAGS_BUILD!!
LIBS = !!LIBS!!
LDFLAGS = !!LDFLAGS!!
ROOT_DIR = !!ROOT_DIR!!
BIN_DIR = !!BIN_DIR!!
LANG_DIR = !!LANG_DIR!!
SRC_OBJS_DIR = !!SRC_OBJS_DIR!!
LANG_OBJS_DIR= !!LANG_OBJS_DIR!!
SRC_DIR = !!SRC_DIR!!
SCRIPT_SRC_DIR=!!SCRIPT_SRC_DIR!!
MEDIA_DIR = !!MEDIA_DIR!!
TTD = !!TTD!!
STRGEN = !!STRGEN!!
ENDIAN_CHECK = !!ENDIAN_CHECK!!
ENDIAN_FORCE = !!ENDIAN_FORCE!!
OS = !!OS!!
STAGE = !!STAGE!!
MAKEDEPEND = !!MAKEDEPEND!!
CFLAGS_MAKEDEP= !!CFLAGS_MAKEDEP!!
SORT = !!SORT!!
REVISION = !!REVISION!!
AWK = !!AWK!!
CONFIG_CACHE_COMPILER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_COMPILER!!
CONFIG_CACHE_LINKER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_LINKER!!
CONFIG_CACHE_ENDIAN = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_ENDIAN!!
CONFIG_CACHE_SOURCE = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_SOURCE!!
CONFIG_CACHE_VERSION = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_VERSION!!
OBJS_C := !!OBJS_C!!
OBJS_CPP := !!OBJS_CPP!!
OBJS_MM := !!OBJS_MM!!
OBJS_RC := !!OBJS_RC!!
OBJS := $(OBJS_C) $(OBJS_CPP) $(OBJS_MM) $(OBJS_RC)
SRCS := !!SRCS!!
# All C-files depend on those 3 files
FILE_DEP := $(CONFIG_CACHE_COMPILER) endian_target.h
# Create all dirs and subdirs
RES := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS))))
# Make sure endian_target.h is reasable as if it was in the src/ dir
CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR)
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SCRIPT_SRC_DIR)
ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK)
# Check if we want to show what we are doing
ifdef VERBOSE
Q =
E = @true
else
Q = @
E = @echo
endif
# Our default target
all: $(BIN_DIR)/$(TTD)
# This are 2 rules that are pointing back to STRGEN stuff.
# There is not really a need to have them here, but in case
# some weirdo wants to run 'make' in the 'src' dir and expects
# the languages to be recompiled, this catches that case and
# takes care of it nicely.
$(LANG_OBJS_DIR)/$(STRGEN):
$(MAKE) -C $(LANG_OBJS_DIR) $(STRGEN)
$(LANG_OBJS_DIR)/table/strings.h: $(LANG_DIR)/english.txt $(LANG_OBJS_DIR)/$(STRGEN)
$(MAKE) -C $(LANG_OBJS_DIR) table/strings.h
# Always run version detection, so we always have an accurate modified
# flag
VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh")
MODIFIED := $(shell echo "$(VERSIONS)" | cut -f 3 -d' ')
ifdef REVISION
# Use specified revision (which should be of the form "r000").
REV := $(REVISION)
REV_NR := $(shell echo $(REVISION) | sed "s@[^0-9]@@g")
else
# Use autodetected revisions
REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ')
REV_NR := $(shell echo "$(VERSIONS)" | cut -f 2 -d' ')
endif
# Make sure we have something in REV and REV_NR
ifeq ($(REV),)
REV := norev000
endif
ifeq ($(REV_NR),)
REV_NR := 0
endif
# This helps to recompile if flags change
RES := $(shell if [ "`cat $(CONFIG_CACHE_COMPILER) 2>/dev/null`" != "$(CFLAGS)" ]; then echo "$(CFLAGS)" > $(CONFIG_CACHE_COMPILER); fi )
RES := $(shell if [ "`cat $(CONFIG_CACHE_LINKER) 2>/dev/null`" != "$(LDFLAGS) $(LIBS)" ]; then echo "$(LDFLAGS) $(LIBS)" > $(CONFIG_CACHE_LINKER); fi )
RES := $(shell if [ "`cat $(CONFIG_CACHE_ENDIAN) 2>/dev/null`" != "$(ENDIAN_FORCE)" ]; then echo "$(ENDIAN_FORCE)" > $(CONFIG_CACHE_ENDIAN); fi )
# If there is a change in the source-file-list, make sure we recheck the deps
RES := $(shell if [ "`cat $(CONFIG_CACHE_SOURCE) 2>/dev/null`" != "$(SRCS)" ]; then echo "$(SRCS)" > $(CONFIG_CACHE_SOURCE); fi )
# If there is a change in the revision, make sure we recompile rev.cpp
RES := $(shell if [ "`cat $(CONFIG_CACHE_VERSION) 2>/dev/null`" != "$(REV) $(MODIFIED)" ]; then echo "$(REV) $(MODIFIED)" > $(CONFIG_CACHE_VERSION); fi )
ifndef MAKEDEPEND
# The slow, but always correct, dep-check
DEP_MASK := %.d
DEPS := $(OBJS:%.o=%.d)
# Only include the deps if we are compiling everything
ifeq ($(filter $(ENDIAN_TARGETS) %.o clean mrproper, $(MAKECMDGOALS)),)
-include $(DEPS)
else
# In case we want to compile a single target, include the .d file for it
ifneq ($(filter %.o, $(MAKECMDGOALS)),)
SINGLE_DEP := $(filter %.o, $(MAKECMDGOALS))
-include $(SINGLE_DEP:%.o=%.d)
endif
endif
# Find the deps via GCC. Rarely wrong, but a bit slow
$(OBJS_C:%.o=%.d): %.d: $(SRC_DIR)/%.c $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.c=%.c)'
$(Q)$(CC_HOST) $(CC_CFLAGS) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@
$(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.cpp=%.cpp)'
$(Q)$(CXX_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@
$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
$(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@
$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
$(Q)touch $@
else
# The much faster, but can be wrong, dep-check
DEP_MASK :=
DEPS := Makefile.dep
# Only include the deps if we are not cleaning
ifeq ($(filter $(ENDIAN_TARGETS) depend clean mrproper, $(MAKECMDGOALS)),)
-include Makefile.dep
endif
# Make sure that only 'make depend' ALWAYS triggers a recheck
ifeq ($(filter depend, $(MAKECMDGOALS)),)
Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(CONFIG_CACHE_SOURCE)
else
Makefile.dep: FORCE
endif
$(E) '$(STAGE) DEP CHECK (all files)'
$(Q)rm -f Makefile.dep.tmp
$(Q)touch Makefile.dep.tmp
# Calculate the deps via makedepend
$(Q)$(MAKEDEPEND) -f$(SRC_OBJS_DIR)/Makefile.dep.tmp -o.o -Y -v -- $(CFLAGS_MAKEDEP) -- $(SRCS:%=$(SRC_DIR)/%) 2>/dev/null
# Convert x:/... paths to /x/... for mingw
ifeq ($(OS), MINGW)
@cat Makefile.dep.tmp | sed 's@/\([a-zA-Z]\):\/@\/\1\/@g' > Makefile.dep.tmp.mingw
@cp Makefile.dep.tmp.mingw Makefile.dep.tmp
@rm -f Makefile.dep.tmp.mingw
endif
# Remove all comments and includes that don't start with $(SRC_DIR)
# Remove $(SRC_DIR) from object-file-name
@$(AWK) ' \
/^# DO NOT/ { print $$0 ; next} \
/^#/ {next} \
/: / { \
left = NF - 1; \
for (n = 2; n <= NF; n++) { \
if (match($$n, "^$(ROOT_DIR)") == 0) { \
$$n = ""; \
left--; \
} \
} \
gsub("$(SRC_DIR)/", "", $$1); \
if (left > 0) { \
print $$0; \
$$1 = "Makefile.dep:"; \
print $$0; \
} \
next \
} \
{ \
print $$0 \
} \
' < Makefile.dep.tmp | sed 's@ *@ @g;s@ $$@@' | $(SORT) > Makefile.dep
$(Q)rm -f Makefile.dep.tmp Makefile.dep.tmp.bak
endif
# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps
# being updated. Now the Makefile continues, the deps are recreated
# and all will be fine.
%.h %.hpp %.hpp.sq:
@true
# Compile all the files according to the targets
$(OBJS_CPP): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP)
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
$(Q)$(CXX_HOST) $(CFLAGS) -c -o $@ $<
$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP)
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)'
$(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $<
$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP)
$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
$(Q)$(WINDRES) -o $@ -I $(MEDIA_DIR) $<
$(BIN_DIR)/$(TTD): $(TTD)
$(Q)cp $< $@
$(TTD): $(OBJS) $(CONFIG_CACHE_LINKER)
$(E) '$(STAGE) Linking $@'
ifeq ($(OS), PSP)
# Because of a bug in the PSP GCC tools, linking via CXX results
# in total chaos and more problems then you can handle. So we need
# CC to link OpenTTD for PSP
$(Q)$(CC_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
else
$(Q)$(CXX_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
endif
ifdef STRIP
$(Q)$(STRIP) $@
ifeq ($(OS), DOS)
$(E) '$(STAGE) Adding CWSDPMI stub to $@'
$(Q)$(ROOT_DIR)/os/dos/make_dos_binary_selfcontained.sh $(SRC_OBJS_DIR)/$@
endif
endif
# The targets to compile the endian-code
endian_target.h: $(ENDIAN_CHECK) $(CONFIG_CACHE_ENDIAN)
$(E) '$(STAGE) Testing endianness for target'
$(Q)./$(ENDIAN_CHECK) $(ENDIAN_FORCE) > $@
$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp
$(E) '$(STAGE) Compiling and Linking $@'
$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $< -o $@
# Revision files
$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in
$(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/rev.cpp
$(SRC_DIR)/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/ottdres.rc.in
$(Q)cat $(SRC_DIR)/ottdres.rc.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/ottdres.rc
FORCE:
depend: $(DEPS)
clean:
$(E) '$(STAGE) Cleaning up object files'
$(Q)rm -f $(DEPS) $(OBJS) $(TTD) $(TTD:%=$(BIN_DIR)/%) $(CONFIG_CACHE_COMPILER) $(CONFIG_CACHE_LINKER) $(CONFIG_CACHE_ENDIAN) $(CONFIG_CACHE_SOURCE) $(ENDIAN_TARGETS)
mrproper: clean
$(Q)rm -f $(SRC_DIR)/rev.cpp $(SRC_DIR)/ottdres.rc
%.o:
@echo '$(STAGE) No such source-file: $(@:%.o=%).[c|cpp|mm|rc]'
.PHONY: all mrproper depend clean FORCE

247
ai/ai.c Normal file
View File

@@ -0,0 +1,247 @@
/* $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(PlayerID 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;
_cmd_text = com->text;
DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
/* Free item */
entry_com = com->next;
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(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
{
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->callback = callback;
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_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
{
PlayerID old_lp;
int32 res = 0;
const char* tmp_cmdtext;
/* 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 resets _cmd_text, so backup the pointer */
tmp_cmdtext = _cmd_text;
/* First, do a test-run to see if we can do this */
res = DoCommand(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)) {
return res;
}
/* Restore _cmd_text */
_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, callback);
} else {
#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, callback);
}
/* Set _local_player back */
_local_player = old_lp;
return res;
}
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
}
/**
* 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, or the AI has been disabled */
if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) 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 (!_networking || _network_server) {
/* Check if we want to run AIs (server or SP only) */
const 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(IsValidPlayer(player));
/* 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)
{
/* Called if this AI died */
_ai_player[player].active = false;
}
/**
* Initialize some AI-related stuff.
*/
void AI_Initialize(void)
{
/* First, make sure all AIs are DEAD! */
AI_Uninitialize();
memset(&_ai, 0, sizeof(_ai));
memset(&_ai_player, 0, sizeof(_ai_player));
_ai.enabled = true;
}
/**
* Deinitializer for AI-related stuff.
*/
void AI_Uninitialize(void)
{
const Player* p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
}
}

111
ai/ai.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef AI_H
#define AI_H
#include "../functions.h"
#include "../network.h"
#include "../player.h"
#include "../command.h"
/* How DoCommands look like for an AI */
typedef struct AICommand {
uint32 tile;
uint32 p1;
uint32 p2;
uint32 procc;
CommandCallback* callback;
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)
} 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(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback);
/** 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 */

3938
ai/default/default.c Normal file

File diff suppressed because it is too large Load Diff

8
ai/default/default.h Normal file
View File

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

324
ai/trolly/build.c Normal file
View File

@@ -0,0 +1,324 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../debug.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../road_map.h"
#include "../../tile.h"
#include "../../vehicle.h"
#include "../../command.h"
#include "trolly.h"
#include "../../engine.h"
#include "../../station.h"
#include "../../variables.h"
#include "../../bridge.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 built
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, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
} else {
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 built!");
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 built!");
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 built!");
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 built!");
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 built.. 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 INVALID_ENGINE if not suitable engine is found
EngineID AiNew_PickVehicle(Player *p)
{
if (p->ainew.tbt == AI_TRAIN) {
// Not supported yet
return INVALID_ENGINE;
} else {
EngineID best_veh_index = INVALID_ENGINE;
int32 best_veh_rating = 0;
EngineID start = ROAD_ENGINES_INDEX;
EngineID end = ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES;
EngineID i;
/* Loop through all road vehicles */
for (i = start; i != end; i++) {
const RoadVehicleInfo *rvi = RoadVehInfo(i);
const Engine* e = GetEngine(i);
int32 rating;
int32 ret;
/* Skip vehicles which can't take our cargo type */
if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue;
// Is it availiable?
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
if (!HASBIT(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
/* Rate and compare the engine by speed & capacity */
rating = rvi->max_speed * rvi->capacity;
if (rating <= best_veh_rating) continue;
// Can we build it?
ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
if (CmdFailed(ret)) continue;
best_veh_rating = rating;
best_veh_index = i;
}
return best_veh_index;
}
}
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
Player* p = GetPlayer(_current_player);
if (success) {
p->ainew.state = AI_STATE_GIVE_ORDERS;
p->ainew.veh_id = _new_vehicle_id;
if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) {
/* Cargo type doesn't match, so refit it */
if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
/* Refit failed, so sell the vehicle */
DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
p->ainew.state = AI_STATE_NOTHING;
}
}
} else {
/* XXX this should be handled more gracefully */
p->ainew.state = AI_STATE_NOTHING;
}
}
// Builds the best vehicle possible
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
{
EngineID i = AiNew_PickVehicle(p);
if (i == INVALID_ENGINE) return CMD_ERROR;
if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
if (flag & DC_EXEC) {
return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI);
} else {
return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
}
}
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
{
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);
} else {
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 + TileOffsByDiagDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
// If it fails, ignore it..
if (CmdFailed(ret2)) return ret;
return ret + ret2;
}
}

510
ai/trolly/pathfinder.c Normal file
View File

@@ -0,0 +1,510 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../bridge_map.h"
#include "../../debug.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../tile.h"
#include "../../command.h"
#include "trolly.h"
#include "../../depot.h"
#include "../../tunnel_map.h"
#include "../../bridge.h"
#include "../ai.h"
#define TEST_STATION_NO_DIR 0xFF
// Tests if a station can be build on the given spot
// TODO: make it train compatible
static bool TestCanBuildStationHere(TileIndex tile, byte dir)
{
Player *p = GetPlayer(_current_player);
if (dir == TEST_STATION_NO_DIR) {
int32 ret;
// TODO: currently we only allow spots that can be access from al 4 directions...
// should be fixed!!!
for (dir = 0; dir < 4; dir++) {
ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
if (!CmdFailed(ret)) return true;
}
return false;
}
// return true if command succeeded, so the inverse of CmdFailed()
return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
}
static bool IsRoad(TileIndex tile)
{
return
// MP_STREET, but not a road depot?
(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
(IsTileType(tile, MP_TUNNELBRIDGE) && (
(IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) ||
(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD)
));
}
// 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))
// Check if the current tile is in our end-area
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
{
const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
// It is not allowed to have a station on the end of a bridge or tunnel ;)
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 (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)))
return AYSTAR_FOUND_END_NODE;
return AYSTAR_DONE;
}
// Calculates the hash
// 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)
{
return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
}
// Clear the memory of all the things
static void AyStar_AiPathFinder_Free(AyStar *aystar)
{
AyStarMain_Free(aystar);
free(aystar);
}
static int32 AyStar_AiPathFinder_CalculateG(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_GetNeighbours(AyStar *aystar, OpenListNode *current);
// This creates the AiPathFinder
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo)
{
PathNode start_node;
uint x;
uint y;
// Create AyStar
AyStar *result = malloc(sizeof(AyStar));
init_AyStar(result, AiPathFinder_Hash, 1 << 10);
// Set the function pointers
result->CalculateG = AyStar_AiPathFinder_CalculateG;
result->CalculateH = AyStar_AiPathFinder_CalculateH;
result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
result->free = AyStar_AiPathFinder_Free;
// Set some information
result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
result->max_path_cost = 0;
result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
// Set the user_data to the PathFinderInfo
result->user_target = PathFinderInfo;
// Set the start node
start_node.parent = NULL;
start_node.node.direction = 0;
start_node.node.user_data[0] = 0;
// Now we add all the starting tiles
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++) {
start_node.node.tile = TileXY(x, y);
result->addstart(result, &start_node.node, 0);
}
}
return result;
}
// To reuse AyStar we sometimes have to clean all the memory
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo)
{
PathNode start_node;
uint x;
uint y;
aystar->clear(aystar);
// Set the user_data to the PathFinderInfo
aystar->user_target = PathFinderInfo;
// Set the start node
start_node.parent = NULL;
start_node.node.direction = 0;
start_node.node.user_data[0] = 0;
start_node.node.tile = PathFinderInfo->start_tile_tl;
// Now we add all the starting tiles
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++) {
TileIndex tile = TileXY(x, y);
if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) continue;
if (!TestCanBuildStationHere(tile, TEST_STATION_NO_DIR)) continue;
start_node.node.tile = tile;
aystar->addstart(aystar, &start_node.node, 0);
}
}
}
// The h-value, simple calculation
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
int r, r2;
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
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDiagDir(PathFinderInfo->end_direction));
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDiagDir(PathFinderInfo->end_direction));
} else {
// No direction, so just get the fastest route to the station
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br);
}
// See if the bottomright is faster than the topleft..
if (r2 < r) r = r2;
return r * AI_PATHFINDER_H_MULTIPLER;
}
// 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)
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
uint i = 0;
PathNode *parent = &current->path;
do {
PathFinderInfo->route_extra[i] = parent->node.user_data[0];
PathFinderInfo->route[i++] = parent->node.tile;
if (i > lengthof(PathFinderInfo->route)) {
// We ran out of space for the PathFinder
DEBUG(ai, 0)("[AiPathFinder] Ran out of space in the route[] array!!!");
PathFinderInfo->route_length = -1; // -1 indicates out of space
return;
}
parent = parent->parent;
} while (parent != NULL);
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));
}
// What tiles are around us.
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current)
{
uint i;
int ret;
int dir;
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
aystar->num_neighbours = 0;
// Go through all surrounding tiles and check if they are within the limits
for (i = 0; i < 4; i++) {
TileIndex ctile = current->path.node.tile; // Current tile
TileIndex atile = ctile + TileOffsByDiagDir(i); // Adjacent tile
if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 &&
TileY(atile) > 1 && TileY(atile) < 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 the next step is a bridge, we have to enter it the right way
if (!PathFinderInfo->rail_or_road && IsRoad(atile)) {
if (IsTileType(atile, MP_TUNNELBRIDGE)) {
if (IsTunnel(atile)) {
if (GetTunnelDirection(atile) != i) continue;
} else {
if ((_m[atile].m5 & 1U) != DiagDirToAxis(i)) 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 ||
(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
// We are a bridge/tunnel, how cool!!
// This means we can only point forward.. get the direction from the user_data
if (i != (current->path.node.user_data[0] >> 8)) continue;
}
dir = 0;
// First, check if we have a parent
if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
// If not, this means we are at the starting station
if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
// We do need a direction?
if (AiNew_GetDirection(ctile, atile) != PathFinderInfo->start_direction) {
// We are not pointing the right way, invalid tile
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
if (current->path.parent->parent != NULL) {
// 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);
if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
continue;
}
}
#endif
} else {
// Road check
dir = AiNew_GetRoadDirection(current->path.parent->node.tile, ctile, atile);
if (IsRoad(ctile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
// We have a bridge, how nicely! We should mark it...
dir = 0;
} else {
// It already has road.. check if we miss any bits!
if ((_m[ctile].m5 & dir) != dir) {
// We do miss some pieces :(
dir &= ~_m[ctile].m5;
} else {
dir = 0;
}
}
}
// Only destruct things if it is MP_CLEAR of MP_TREES
if (dir != 0) {
ret = AI_DoCommand(ctile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
if (CmdFailed(ret)) continue;
}
}
}
// The tile can be connected
aystar->neighbours[aystar->num_neighbours].tile = atile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
aystar->neighbours[aystar->num_neighbours++].direction = 0;
}
}
// Next step, check for bridges and tunnels
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
// First we get the dir from this tile and his parent
DiagDirection 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;
Slope tileh = GetTileSlope(tile, NULL);
// Bridges can only be build on land that is not flat
// And if there is a road or rail blocking
if (tileh != SLOPE_FLAT ||
(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_STREET)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_RAILWAY))) {
for (;;) {
new_tile += TileOffsByDiagDir(dir);
// Precheck, is the length allowed?
if (!CheckBridge_Stuff(0, GetBridgeLength(tile, new_tile))) break;
// Check if we hit the station-tile.. we don't like that!
if (TILES_BETWEEN(new_tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) break;
// Try building the bridge..
ret = AI_DoCommand(tile, new_tile, (0 << 8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
if (CmdFailed(ret)) 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
if (aystar->num_neighbours == 11) break;
}
}
// Next, check for tunnels!
// Tunnels can only be built on slopes corresponding to the direction
// For now, we check both sides for this tile.. terraforming gives fuzzy result
if ((dir == DIAGDIR_NE && tileh == SLOPE_NE) ||
(dir == DIAGDIR_SE && tileh == SLOPE_SE) ||
(dir == DIAGDIR_SW && tileh == SLOPE_SW) ||
(dir == DIAGDIR_NW && tileh == SLOPE_NW)) {
// 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);
tileh = GetTileSlope(_build_tunnel_endtile, NULL);
if (!CmdFailed(ret) && (tileh == SLOPE_SW || tileh == SLOPE_SE || tileh == SLOPE_NW || tileh == SLOPE_NE)) {
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++].direction = 0;
}
}
}
}
extern uint GetRailFoundation(Slope tileh, TrackBits bits); // XXX function declaration in .c
extern uint GetRoadFoundation(Slope tileh, uint bits); // XXX function declaration in .c
extern uint GetBridgeFoundation(Slope tileh, Axis); // XXX function declaration in .c
enum {
BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
};
// The most important function: it calculates the g-value
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
int r, res = 0;
Slope tileh = GetTileSlope(current->tile, NULL);
Slope parent_tileh = GetTileSlope(parent->path.node.tile, NULL);
// Check if we hit the end-tile
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...
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
return AYSTAR_INVALID_NODE;
}
// If it was valid, drop out.. we don't build on the endtile
return 0;
}
// Give everything a small penalty
res += AI_PATHFINDER_PENALTY;
if (!PathFinderInfo->rail_or_road) {
// Road has the lovely advantage it can use other road... check if
// the current tile is road, and if so, give a good bonus
if (IsRoad(current->tile)) {
res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
}
}
// 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.
// 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_tileh != SLOPE_FLAT && parent->path.parent != NULL) {
// Skip if the tile was from a bridge or tunnel
if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
if (PathFinderInfo->rail_or_road) {
r = GetRailFoundation(parent_tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
if (r >= 15 || (r == 0 && HASBIT(BRIDGE_NO_FOUNDATION, tileh))) {
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
res += AI_PATHFINDER_FOUNDATION_PENALTY;
}
} else {
if (!IsRoad(parent->path.node.tile) || !IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE)) {
r = GetRoadFoundation(parent_tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
if (r >= 15 || r == 0) {
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
res += AI_PATHFINDER_FOUNDATION_PENALTY;
}
}
}
}
}
// Are we part of a tunnel?
if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
// Tunnels are very expensive when build on long routes..
// Ironicly, we are using BridgeCode here ;)
r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
res += r + (r >> 8);
}
// Are we part of a bridge?
if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
// That means for every length a penalty
res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
// Check if we are going up or down, first for the starting point
// In user_data[0] is at the 8th bit the direction
if (!HASBIT(BRIDGE_NO_FOUNDATION, parent_tileh)) {
if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15) {
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
}
// Second for the end point
if (!HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15) {
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
}
if (parent_tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
// To prevent the AI from taking the fastest way in tiles, but not the fastest way
// in speed, we have to give a good penalty to direction changing
// This way, we get almost the fastest way in tiles, and a very good speed on the track
if (!PathFinderInfo->rail_or_road) {
if (parent->path.parent != NULL &&
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
if (IsRoad(parent->path.node.tile)) {
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
} else {
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
}
}
} else {
// For rail we have 1 exeption: diagonal rail..
// So we fetch 2 raildirection. That of the current one, and of the one before that
if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
// First, see if we are on diagonal path, that is better than straight path
if (dir1 > 1) res -= AI_PATHFINDER_DIAGONAL_BONUS;
// First see if they are different
if (dir1 != dir2) {
// dir 2 and 3 are 1 diagonal track, and 4 and 5.
if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
// It is not, so we changed of direction
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
}
if (parent->path.parent->parent->parent != NULL) {
int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
res += AI_PATHFINDER_CURVE_PENALTY;
}
}
}
}
}
return (res < 0) ? 0 : res;
}

118
ai/trolly/shared.c Normal file
View File

@@ -0,0 +1,118 @@
/* $Id$ */
#include "../../stdafx.h"
#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
// 1 = horz
// 2 = dig up-left
// 3 = dig down-right
// 4 = dig down-left
// 5 = dig up-right
uint x1 = TileX(tile_a);
uint x2 = TileX(tile_b);
uint x3 = TileX(tile_c);
uint y1 = TileY(tile_a);
uint y2 = TileY(tile_b);
uint y3 = TileY(tile_c);
if (y1 == y2 && y2 == y3) return 0;
if (x1 == x2 && x2 == x3) return 1;
if (y2 > y1) return x2 > x3 ? 2 : 4;
if (x2 > x1) return y2 > y3 ? 2 : 5;
if (y1 > y2) return x2 > x3 ? 5 : 3;
if (x1 > x2) return y2 > y3 ? 4 : 3;
return 0;
}
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
{
int x1, x2, x3;
int y1, y2, y3;
int r;
x1 = TileX(tile_a);
x2 = TileX(tile_b);
x3 = TileX(tile_c);
y1 = TileY(tile_a);
y2 = TileY(tile_b);
y3 = TileY(tile_c);
r = 0;
if (x1 < x2) r += 8;
if (y1 < y2) r += 1;
if (x1 > x2) r += 2;
if (y1 > y2) r += 4;
if (x2 < x3) r += 2;
if (y2 < y3) r += 4;
if (x2 > x3) r += 8;
if (y2 > y3) r += 1;
return r;
}
// Get's the direction between 2 tiles seen from tile_a
DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b)
{
if (TileY(tile_a) < TileY(tile_b)) return DIAGDIR_SE;
if (TileY(tile_a) > TileY(tile_b)) return DIAGDIR_NW;
if (TileX(tile_a) < TileX(tile_b)) return DIAGDIR_SW;
return DIAGDIR_NE;
}
// This functions looks up if this vehicle is special for this AI
// and returns his flag
uint AiNew_GetSpecialVehicleFlag(Player* p, Vehicle* v)
{
uint i;
for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
return p->ainew.special_vehicles[i].flag;
}
}
// Not found :(
return 0;
}
bool AiNew_SetSpecialVehicleFlag(Player* p, Vehicle* v, uint flag)
{
int new_id = -1;
uint i;
for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
p->ainew.special_vehicles[i].flag |= flag;
return true;
}
if (new_id == -1 &&
p->ainew.special_vehicles[i].veh_id == 0 &&
p->ainew.special_vehicles[i].flag == 0) {
new_id = i;
}
}
// Out of special_vehicle spots :s
if (new_id == -1) {
DEBUG(ai, 1)("special_vehicles list is too small :(");
return false;
}
p->ainew.special_vehicles[new_id].veh_id = v->index;
p->ainew.special_vehicles[new_id].flag = flag;
return true;
}

1356
ai/trolly/trolly.c Normal file

File diff suppressed because it is too large Load Diff

262
ai/trolly/trolly.h Normal file
View File

@@ -0,0 +1,262 @@
/* $Id$ */
#ifndef AI_TROLLY_H
#define AI_TROLLY_H
#include "../../aystar.h"
#include "../../player.h"
/*
* These defines can be altered to change the behavoir of the AI
*
* WARNING:
* This can also alter the AI in a negative way. I will never claim these settings
* are perfect, but don't change them if you don't know what the effect is.
*/
// How many times it the H multiplied. The higher, the more it will go straight to the
// end point. The lower, how more it will find the route with the lowest cost.
// also: the lower, the longer it takes before route is calculated..
#define AI_PATHFINDER_H_MULTIPLER 100
// How many loops may AyStar do before it stops
// 0 = infinite
#define AI_PATHFINDER_LOOPS_PER_TICK 5
// How long may the AI search for one route?
// 0 = infinite
// This number is the number of tiles tested.
// It takes (AI_PATHFINDER_MAX_SEARCH_NODES / AI_PATHFINDER_LOOPS_PER_TICK) ticks
// to get here.. with 5000 / 10 = 500. 500 / 74 (one day) = 8 days till it aborts
// (that is: if the AI is on VERY FAST! :p
#define AI_PATHFINDER_MAX_SEARCH_NODES 5000
// If you enable this, the AI is not allowed to make 90degree turns
#define AI_PATHFINDER_NO_90DEGREES_TURN
// Below are defines for the g-calculation
// Standard penalty given to a tile
#define AI_PATHFINDER_PENALTY 150
// The penalty given to a tile that is going up
#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)
#define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200
// Same penalty, only for when road already exists
#define AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY 50
// A diagonal track cost the same as a straigh, but a diagonal is faster... so give
// a bonus for using diagonal track
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
#define AI_PATHFINDER_DIAGONAL_BONUS 95
#else
#define AI_PATHFINDER_DIAGONAL_BONUS 75
#endif
// If a roadblock already exists, it gets a bonus
#define AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS 140
// To prevent 3 direction changes in 3 tiles, this penalty is given in such situation
#define AI_PATHFINDER_CURVE_PENALTY 200
// Penalty a bridge gets per length
#define AI_PATHFINDER_BRIDGE_PENALTY 180
// The penalty for a bridge going up
#define AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY 1000
// Tunnels are expensive...
// Because of that, every tile the cost is increased with 1/8th of his value
// This is also true if you are building a tunnel yourself
#define AI_PATHFINDER_TUNNEL_PENALTY 350
/*
* Ai_New defines
*/
// How long may we search cities and industry for a new route?
#define AI_LOCATE_ROUTE_MAX_COUNTER 200
// How many days must there be between building the first station and the second station
// within one city. This number is in days and should be more than 4 months.
#define AI_CHECKCITY_DATE_BETWEEN 180
// How many cargo is needed for one station in a city?
#define AI_CHECKCITY_CARGO_PER_STATION 60
// How much cargo must there not be used in a city before we can build a new station?
#define AI_CHECKCITY_NEEDED_CARGO 50
// When there is already a station which takes the same good and the rating of that
// city is higher then this numer, we are not going to attempt to build anything
// there
#define AI_CHECKCITY_CARGO_RATING 50
// But, there is a chance of 1 out of this number, that we do ;)
#define AI_CHECKCITY_CARGO_RATING_CHANCE 5
// If a city is too small to contain a station, there is a small chance
// that we still do so.. just to make the city bigger!
#define AI_CHECKCITY_CITY_CHANCE 5
// This number indicates for every unit of cargo, how many tiles two stations maybe be away
// from eachother. In other words: if we have 120 units of cargo in one station, and 120 units
// of the cargo in the other station, both stations can be 96 units away from eachother, if the
// next number is 0.4.
#define AI_LOCATEROUTE_BUS_CARGO_DISTANCE 0.4
#define AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE 0.7
// In whole tiles, the minimum distance for a truck route
#define AI_LOCATEROUTE_TRUCK_MIN_DISTANCE 30
// The amount of tiles in a square from -X to +X that is scanned for a station spot
// (so if this number is 10, 20x20 = 400 tiles are scanned for _the_ perfect spot
// Safe values are between 15 and 5
#define AI_FINDSTATION_TILE_RANGE 10
// Building on normal speed goes very fast. Idle this amount of ticks between every
// building part. It is calculated like this: (4 - competitor_speed) * num + 1
// where competitor_speed is between 0 (very slow) to 4 (very fast)
#define AI_BUILDPATH_PAUSE 10
// Minimum % of reliabilty a vehicle has to have before the AI buys it
#define AI_VEHICLE_MIN_RELIABILTY 60
// The minimum amount of money a player should always have
#define AI_MINIMUM_MONEY 15000
// If the most cheap route is build, how much is it going to cost..
// This is to prevent the AI from trying to build a route which can not be paid for
#define AI_MINIMUM_BUS_ROUTE_MONEY 25000
#define AI_MINIMUM_TRUCK_ROUTE_MONEY 35000
// The minimum amount of money before we are going to repay any money
#define AI_MINIMUM_LOAN_REPAY_MONEY 40000
// How many repays do we do if we have enough money to do so?
// Every repay is 10000
#define AI_LOAN_REPAY 2
// How much income must we have before paying back a loan? Month-based (and looked at the last month)
#define AI_MINIMUM_INCOME_FOR_LOAN 7000
// If there is <num> time as much cargo in the station then the vehicle can handle
// reuse the station instead of building a new one!
#define AI_STATION_REUSE_MULTIPLER 2
// No more than this amount of vehicles per station..
#define AI_CHECK_MAX_VEHICLE_PER_STATION 10
// How many thick between building 2 vehicles
#define AI_BUILD_VEHICLE_TIME_BETWEEN DAY_TICKS
// How many days must there between vehicle checks
// The more often, the less non-money-making lines there will be
// but the unfair it may seem to a human player
#define AI_DAYS_BETWEEN_VEHICLE_CHECKS 30
// How money profit does a vehicle needs to make to stay in order
// This is the profit of this year + profit of last year
// But also for vehicles that are just one year old. In other words:
// Vehicles of 2 years do easier meet this setting then vehicles
// of one year. This is a very good thing. New vehicles are filtered,
// while old vehicles stay longer, because we do get less in return.
#define AI_MINIMUM_ROUTE_PROFIT 1000
// A vehicle is considered lost when he his cargo is more than 180 days old
#define AI_VEHICLE_LOST_DAYS 180
// How many times may the AI try to find a route before it gives up
#define AI_MAX_TRIES_FOR_SAME_ROUTE 8
/*
* End of defines
*/
// This stops 90degrees curves
static const byte _illegal_curves[6] = {
255, 255, // Horz and vert, don't have the effect
5, // upleft and upright are not valid
4, // downright and downleft are not valid
2, // downleft and upleft are not valid
3, // upright and downright are not valid
};
enum {
AI_STATE_STARTUP = 0,
AI_STATE_FIRST_TIME,
AI_STATE_NOTHING,
AI_STATE_WAKE_UP,
AI_STATE_LOCATE_ROUTE,
AI_STATE_FIND_STATION,
AI_STATE_FIND_PATH,
AI_STATE_FIND_DEPOT,
AI_STATE_VERIFY_ROUTE,
AI_STATE_BUILD_STATION,
AI_STATE_BUILD_PATH,
AI_STATE_BUILD_DEPOT,
AI_STATE_BUILD_VEHICLE,
AI_STATE_WAIT_FOR_BUILD,
AI_STATE_GIVE_ORDERS,
AI_STATE_START_VEHICLE,
AI_STATE_REPAY_MONEY,
AI_STATE_CHECK_ALL_VEHICLES,
AI_STATE_ACTION_DONE,
AI_STATE_STOP, // Temporary function to stop the AI
};
// Used for tbt (train/bus/truck)
enum {
AI_TRAIN = 0,
AI_BUS,
AI_TRUCK,
};
enum {
AI_ACTION_NONE = 0,
AI_ACTION_BUS_ROUTE,
AI_ACTION_TRUCK_ROUTE,
AI_ACTION_REPAY_LOAN,
AI_ACTION_CHECK_ALL_VEHICLES,
};
// Used for from_type/to_type
enum {
AI_NO_TYPE = 0,
AI_CITY,
AI_INDUSTRY,
};
// Flags for in the vehicle
enum {
AI_VEHICLEFLAG_SELL = 1,
// Remember, flags must be in power of 2
};
#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_STATION_RANGE TileXY(MapMaxX(), MapMaxY())
#define AI_PATHFINDER_NO_DIRECTION (byte)-1
// Flags used in user_data
#define AI_PATHFINDER_FLAG_BRIDGE 1
#define AI_PATHFINDER_FLAG_TUNNEL 2
typedef void AiNew_StateFunction(Player *p);
// ai_new.c
void AiNewDoGameLoop(Player *p);
// ai_pathfinder.c
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo);
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
// ai_shared.c
int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c);
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c);
DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b);
bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag);
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v);
// ai_build.c
bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile);
int AiNew_Build_Station(Player *p, byte type, TileIndex 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_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
EngineID AiNew_PickVehicle(Player *p);
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag);
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag);
#endif /* AI_TROLLY_H */

26
aircraft.h Normal file
View File

@@ -0,0 +1,26 @@
/* $Id$ */
#ifndef AIRCRAFT_H
#define AIRCRAFT_H
#include "station_map.h"
#include "vehicle.h"
static inline bool IsAircraftInHangar(const Vehicle* v)
{
assert(v->type == VEH_Aircraft);
return v->vehstatus & VS_HIDDEN && IsHangarTile(v->tile);
}
static inline bool IsAircraftInHangarStopped(const Vehicle* v)
{
return IsAircraftInHangar(v) && v->vehstatus & VS_STOPPED;
}
uint16 AircraftDefaultCargoCapacity(CargoID cid, EngineID engine_type);
void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2);
void HandleAircraftEnterHangar(Vehicle *v);
#endif /* AIRCRAFT_H */

2121
aircraft_cmd.c Normal file

File diff suppressed because it is too large Load Diff

350
aircraft_gui.c Normal file
View File

@@ -0,0 +1,350 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "aircraft.h"
#include "debug.h"
#include "functions.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "vehicle.h"
#include "gfx.h"
#include "command.h"
#include "engine.h"
#include "viewport.h"
#include "player.h"
#include "depot.h"
#include "vehicle_gui.h"
#include "newgrf_engine.h"
void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) ShowAircraftViewWindow(GetVehicle(_new_vehicle_id));
}
static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
const Vehicle *v = GetVehicle(w->window_number);
SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
/* Disable service-scroller when interval is set to disabled */
SetWindowWidgetDisabledState(w, 5, !_patches.servint_aircraft);
SetWindowWidgetDisabledState(w, 6, !_patches.servint_aircraft);
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
DrawWindowWidgets(w);
/* Draw running cost */
{
int year = v->age / 366;
SetDParam(1, year);
SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
SetDParam(2, v->max_age / 366);
SetDParam(3, _price.aircraft_running * AircraftVehInfo(v->engine_type)->running_cost >> 8);
DrawString(2, 15, STR_A00D_AGE_RUNNING_COST_YR, 0);
}
/* Draw max speed */
{
SetDParam(0, v->max_speed * 128 / 10);
DrawString(2, 25, STR_A00E_MAX_SPEED, 0);
}
/* Draw profit */
{
SetDParam(0, v->profit_this_year);
SetDParam(1, v->profit_last_year);
DrawString(2, 35, STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
}
/* Draw breakdown & reliability */
{
SetDParam(0, v->reliability * 100 >> 16);
SetDParam(1, v->breakdowns_since_last_service);
DrawString(2, 45, STR_A010_RELIABILITY_BREAKDOWNS, 0);
}
/* Draw service interval text */
{
SetDParam(0, v->service_interval);
SetDParam(1, v->date_of_last_service);
DrawString(13, 103, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
}
DrawAircraftImage(v, 3, 57, INVALID_VEHICLE);
{
const Vehicle *u;
int y = 57;
do {
if (v->subtype <= 2) {
SetDParam(0, GetCustomEngineName(v->engine_type));
SetDParam(1, v->build_year);
SetDParam(2, v->value);
DrawString(60, y, STR_A011_BUILT_VALUE, 0);
y += 10;
SetDParam(0, v->cargo_type);
SetDParam(1, v->cargo_cap);
u = v->next;
SetDParam(2, u->cargo_type);
SetDParam(3, u->cargo_cap);
DrawString(60, y, (u->cargo_cap != 0) ? STR_A019_CAPACITY : STR_A01A_CAPACITY, 0);
y += 14;
}
if (v->cargo_count != 0) {
/* Cargo names (fix pluralness) */
SetDParam(0, v->cargo_type);
SetDParam(1, v->cargo_count);
SetDParam(2, v->cargo_source);
DrawString(60, y, STR_8813_FROM, 0);
y += 10;
}
} while ( (v=v->next) != NULL);
}
} break;
case WE_CLICK: {
int mod;
const Vehicle *v;
switch (e->we.click.widget) {
case 2: /* rename */
v = GetVehicle(w->window_number);
SetDParam(0, v->unitnumber);
ShowQueryString(v->string_id, STR_A030_NAME_AIRCRAFT, 31, 150, w->window_class, w->window_number, CS_ALPHANUMERAL);
break;
case 5: /* increase int */
mod = _ctrl_pressed? 5 : 10;
goto do_change_service_int;
case 6: /* decrease int */
mod = _ctrl_pressed?- 5 : -10;
do_change_service_int:
v = GetVehicle(w->window_number);
mod = GetServiceIntervalClamped(mod + v->service_interval);
if (mod == v->service_interval) return;
DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
break;
}
} break;
case WE_ON_EDIT_TEXT:
if (e->we.edittext.str[0] != '\0') {
_cmd_text = e->we.edittext.str;
DoCommandP(0, w->window_number, 0, NULL,
CMD_NAME_VEHICLE | CMD_MSG(STR_A031_CAN_T_NAME_AIRCRAFT));
}
break;
}
}
static const Widget _aircraft_details_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 349, 0, 13, STR_A00C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 350, 389, 0, 13, STR_01AA_NAME, STR_A032_NAME_AIRCRAFT },
{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 14, 55, 0x0, STR_NULL },
{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 56, 101, 0x0, STR_NULL },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 102, 107, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 108, 113, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL },
{ WWT_PANEL, RESIZE_NONE, 14, 11, 389, 102, 113, 0x0, STR_NULL },
{ WIDGETS_END},
};
static const WindowDesc _aircraft_details_desc = {
WDP_AUTO, WDP_AUTO, 390, 114,
WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_aircraft_details_widgets,
AircraftDetailsWndProc
};
static void ShowAircraftDetailsWindow(const Vehicle *v)
{
Window *w;
VehicleID veh = v->index;
DeleteWindowById(WC_VEHICLE_ORDERS, veh);
DeleteWindowById(WC_VEHICLE_DETAILS, veh);
w = AllocateWindowDescFront(&_aircraft_details_desc, veh);
w->caption_color = v->owner;
// w->vscroll.cap = 6;
// w->traindetails_d.tab = 0;
}
static const Widget _aircraft_view_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_RIGHT, 14, 11, 237, 0, 13, STR_A00A, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_STICKYBOX, RESIZE_LR, 14, 238, 249, 0, 13, 0x0, STR_STICKY_BUTTON },
{ WWT_PANEL, RESIZE_RB, 14, 0, 231, 14, 103, 0x0, STR_NULL },
{ WWT_INSET, RESIZE_RB, 14, 2, 229, 16, 101, 0x0, STR_NULL },
{ WWT_PUSHBTN, RESIZE_RTB, 14, 0, 237, 104, 115, 0x0, STR_A027_CURRENT_AIRCRAFT_ACTION },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 14, 31, SPR_CENTRE_VIEW_VEHICLE, STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_SEND_AIRCRAFT_TODEPOT,STR_A02A_SEND_AIRCRAFT_TO_HANGAR },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, SPR_REFIT_VEHICLE, STR_A03B_REFIT_AIRCRAFT_TO_CARRY },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, SPR_SHOW_ORDERS, STR_A028_SHOW_AIRCRAFT_S_ORDERS },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, SPR_SHOW_VEHICLE_DETAILS, STR_A02B_SHOW_AIRCRAFT_DETAILS },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_AIRCRAFT, STR_CLONE_AIRCRAFT_INFO },
{ WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL },
{ WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL },
{ WIDGETS_END},
};
static void AircraftViewWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
const Vehicle *v = GetVehicle(w->window_number);
StringID str;
bool is_localplayer = v->owner == _local_player;
SetWindowWidgetDisabledState(w, 7, !is_localplayer);
SetWindowWidgetDisabledState(w, 8, !IsAircraftInHangarStopped(v) || !is_localplayer);
SetWindowWidgetDisabledState(w, 11, !is_localplayer);
/* draw widgets & caption */
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
DrawWindowWidgets(w);
if (v->vehstatus & VS_CRASHED) {
str = STR_8863_CRASHED;
} else if (v->vehstatus & VS_STOPPED) {
str = STR_8861_STOPPED;
} else {
switch (v->current_order.type) {
case OT_GOTO_STATION: {
SetDParam(0, v->current_order.dest);
SetDParam(1, v->cur_speed * 128 / 10);
str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
} break;
case OT_GOTO_DEPOT: {
/* Aircrafts always go to a station, even if you say depot */
SetDParam(0, v->current_order.dest);
SetDParam(1, v->cur_speed * 128 / 10);
if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
str = STR_HEADING_FOR_HANGAR + _patches.vehicle_speed;
} else {
str = STR_HEADING_FOR_HANGAR_SERVICE + _patches.vehicle_speed;
}
} break;
case OT_LOADING:
str = STR_882F_LOADING_UNLOADING;
break;
default:
if (v->num_orders == 0) {
str = STR_NO_ORDERS + _patches.vehicle_speed;
SetDParam(0, v->cur_speed * 128 / 10);
} else {
str = STR_EMPTY;
}
break;
}
}
/* draw the flag plus orders */
DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
DrawWindowViewport(w);
} break;
case WE_CLICK: {
const Vehicle *v = GetVehicle(w->window_number);
switch (e->we.click.widget) {
case 5: /* start stop */
DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT));
break;
case 6: /* center main view */
ScrollMainWindowTo(v->x_pos, v->y_pos);
break;
case 7: /* goto hangar */
DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_MSG(STR_A012_CAN_T_SEND_AIRCRAFT_TO));
break;
case 8: /* refit */
ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
break;
case 9: /* show orders */
ShowOrdersWindow(v);
break;
case 10: /* show details */
ShowAircraftDetailsWindow(v);
break;
case 11:
/* clone vehicle */
DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneAircraft, CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
break;
}
} break;
case WE_RESIZE:
w->viewport->width += e->we.sizing.diff.x;
w->viewport->height += e->we.sizing.diff.y;
w->viewport->virtual_width += e->we.sizing.diff.x;
w->viewport->virtual_height += e->we.sizing.diff.y;
break;
case WE_DESTROY:
DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
break;
case WE_MOUSELOOP: {
const Vehicle *v = GetVehicle(w->window_number);
bool plane_stopped = IsAircraftInHangarStopped(v);
/* Widget 7 (send to hangar) must be hidden if the plane is already stopped in hangar.
* Widget 11 (clone) should then be shown, since cloning is allowed only while in hangar and stopped.
* This sytem allows to have two buttons, on top of each other*/
if (plane_stopped != IsWindowWidgetHidden(w, 7) || plane_stopped == IsWindowWidgetHidden(w, 11)) {
SetWindowWidgetHiddenState(w, 7, plane_stopped); // send to hangar
SetWindowWidgetHiddenState(w, 11, !plane_stopped); // clone
SetWindowDirty(w);
}
} break;
}
}
static const WindowDesc _aircraft_view_desc = {
WDP_AUTO, WDP_AUTO, 250, 116,
WC_VEHICLE_VIEW ,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_aircraft_view_widgets,
AircraftViewWndProc
};
void ShowAircraftViewWindow(const Vehicle *v)
{
Window *w = AllocateWindowDescFront(&_aircraft_view_desc, v->index);
if (w != NULL) {
w->caption_color = v->owner;
AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
}
}

View File

@@ -1,15 +1,14 @@
/* $Id$ */
/** @file airport.cpp Functions related to airports. */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "map.h"
#include "airport.h"
#include "macros.h"
#include "variables.h"
#include "airport_movement.h"
#include "core/bitmath_func.hpp"
#include "core/alloc_func.hpp"
#include "date_func.h"
#include "settings_type.h"
#include "date.h"
/* Uncomment this to print out a full report of the airport-structure
* You should either use
@@ -18,7 +17,6 @@
* - false: give a summarized report which only shows current and next position */
//#define DEBUG_AIRPORT false
static AirportFTAClass *DummyAirport;
static AirportFTAClass *CountryAirport;
static AirportFTAClass *CityAirport;
static AirportFTAClass *Oilrig;
@@ -30,275 +28,256 @@ static AirportFTAClass *HeliDepot;
static AirportFTAClass *IntercontinentalAirport;
static AirportFTAClass *HeliStation;
static void AirportFTAClass_Constructor(AirportFTAClass *apc,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *apFA,
const TileIndexDiffC *depots, const byte nof_depots,
uint size_x, uint size_y
);
static void AirportFTAClass_Destructor(AirportFTAClass *apc);
void InitializeAirports()
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA);
static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
static byte AirportTestFTA(const AirportFTAClass *apc);
#ifdef DEBUG_AIRPORT
static void AirportPrintOut(const AirportFTAClass *apc, bool full_report);
#endif /* DEBUG_AIRPORT */
void InitializeAirports(void)
{
DummyAirport = new AirportFTAClass(
_airport_moving_data_dummy,
NULL,
NULL,
_airport_entries_dummy,
AirportFTAClass::ALL,
_airport_fta_dummy,
NULL,
0,
0, 0, 0,
0,
0
);
// country airport
CountryAirport = malloc(sizeof(AirportFTAClass));
CountryAirport = new AirportFTAClass(
_airport_moving_data_country,
AirportFTAClass_Constructor(
CountryAirport,
_airport_terminal_country,
NULL,
_airport_entries_country,
AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
16,
ALL,
_airport_fta_country,
_airport_depots_country,
lengthof(_airport_depots_country),
4, 3, 3,
0,
4
4, 3
);
CityAirport = new AirportFTAClass(
_airport_moving_data_town,
// city airport
CityAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CityAirport,
_airport_terminal_city,
NULL,
_airport_entries_city,
AirportFTAClass::ALL,
19,
ALL,
_airport_fta_city,
_airport_depots_city,
lengthof(_airport_depots_city),
6, 6, 5,
0,
5
6, 6
);
MetropolitanAirport = new AirportFTAClass(
_airport_moving_data_metropolitan,
// metropolitan airport
MetropolitanAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
MetropolitanAirport,
_airport_terminal_metropolitan,
NULL,
_airport_entries_metropolitan,
AirportFTAClass::ALL,
20,
ALL,
_airport_fta_metropolitan,
_airport_depots_metropolitan,
lengthof(_airport_depots_metropolitan),
6, 6, 8,
0,
6
6, 6
);
InternationalAirport = new AirportFTAClass(
_airport_moving_data_international,
// international airport
InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
InternationalAirport,
_airport_terminal_international,
_airport_helipad_international,
_airport_entries_international,
AirportFTAClass::ALL,
37,
ALL,
_airport_fta_international,
_airport_depots_international,
lengthof(_airport_depots_international),
7, 7, 17,
0,
8
7, 7
);
IntercontinentalAirport = new AirportFTAClass(
_airport_moving_data_intercontinental,
// intercontintental airport
IntercontinentalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
IntercontinentalAirport,
_airport_terminal_intercontinental,
_airport_helipad_intercontinental,
_airport_entries_intercontinental,
AirportFTAClass::ALL,
43,
ALL,
_airport_fta_intercontinental,
_airport_depots_intercontinental,
lengthof(_airport_depots_intercontinental),
9, 11, 25,
0,
10
9,11
);
Heliport = new AirportFTAClass(
_airport_moving_data_heliport,
// heliport, oilrig
Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
Heliport,
NULL,
_airport_helipad_heliport_oilrig,
_airport_entries_heliport_oilrig,
AirportFTAClass::HELICOPTERS,
7,
HELICOPTERS_ONLY,
_airport_fta_heliport_oilrig,
NULL,
0,
1, 1, 1,
60,
4
1, 1
);
Oilrig = new AirportFTAClass(
_airport_moving_data_oilrig,
NULL,
_airport_helipad_heliport_oilrig,
_airport_entries_heliport_oilrig,
AirportFTAClass::HELICOPTERS,
_airport_fta_heliport_oilrig,
NULL,
0,
1, 1, 0,
54,
3
);
Oilrig = Heliport; // exactly the same structure for heliport/oilrig, so share state machine
CommuterAirport = new AirportFTAClass(
_airport_moving_data_commuter,
// commuter airport
CommuterAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CommuterAirport,
_airport_terminal_commuter,
_airport_helipad_commuter,
_airport_entries_commuter,
AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
22,
ALL,
_airport_fta_commuter,
_airport_depots_commuter,
lengthof(_airport_depots_commuter),
5, 4, 4,
0,
4
5,4
);
HeliDepot = new AirportFTAClass(
_airport_moving_data_helidepot,
// helidepot airport
HeliDepot = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
HeliDepot,
NULL,
_airport_helipad_helidepot,
_airport_entries_helidepot,
AirportFTAClass::HELICOPTERS,
4,
HELICOPTERS_ONLY,
_airport_fta_helidepot,
_airport_depots_helidepot,
lengthof(_airport_depots_helidepot),
2, 2, 2,
0,
4
2,2
);
HeliStation = new AirportFTAClass(
_airport_moving_data_helistation,
// helistation airport
HeliStation = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
HeliStation,
NULL,
_airport_helipad_helistation,
_airport_entries_helistation,
AirportFTAClass::HELICOPTERS,
25,
HELICOPTERS_ONLY,
_airport_fta_helistation,
_airport_depots_helistation,
lengthof(_airport_depots_helistation),
4, 2, 3,
0,
4
4,2
);
}
void UnInitializeAirports()
void UnInitializeAirports(void)
{
delete DummyAirport;
delete CountryAirport;
delete CityAirport;
delete Heliport;
delete MetropolitanAirport;
delete InternationalAirport;
delete CommuterAirport;
delete HeliDepot;
delete IntercontinentalAirport;
delete HeliStation;
AirportFTAClass_Destructor(CountryAirport);
AirportFTAClass_Destructor(CityAirport);
AirportFTAClass_Destructor(Heliport);
AirportFTAClass_Destructor(MetropolitanAirport);
AirportFTAClass_Destructor(InternationalAirport);
AirportFTAClass_Destructor(CommuterAirport);
AirportFTAClass_Destructor(HeliDepot);
AirportFTAClass_Destructor(IntercontinentalAirport);
AirportFTAClass_Destructor(HeliStation);
}
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA);
static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals);
#ifdef DEBUG_AIRPORT
static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report);
#endif
AirportFTAClass::AirportFTAClass(
const AirportMovingData *moving_data_,
const byte *terminals_,
const byte *helipads_,
const byte *entry_points_,
Flags flags_,
static void AirportFTAClass_Constructor(AirportFTAClass *apc,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *apFA,
const TileIndexDiffC *depots_,
const byte nof_depots_,
uint size_x_,
uint size_y_,
byte noise_level_,
byte delta_z_,
byte catchment_
) :
moving_data(moving_data_),
terminals(terminals_),
helipads(helipads_),
airport_depots(depots_),
flags(flags_),
nof_depots(nof_depots_),
nofelements(AirportGetNofElements(apFA)),
entry_points(entry_points_),
size_x(size_x_),
size_y(size_y_),
noise_level(noise_level_),
delta_z(delta_z_),
catchment(catchment_)
const TileIndexDiffC *depots, const byte nof_depots,
uint size_x, uint size_y
)
{
byte nofterminals, nofhelipads;
byte nofterminalgroups, nofhelipadgroups;
apc->size_x = size_x;
apc->size_y = size_y;
/* Set up the terminal and helipad count for an airport.
* TODO: If there are more than 10 terminals or 4 helipads, internal variables
* need to be changed, so don't allow that for now */
uint nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
if (nofterminals > MAX_TERMINALS) {
DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
DEBUG(misc, 0) ("[Ap] Currently only maximum of %d terminals are supported (you wanted %d)", MAX_TERMINALS, nofterminals);
assert(nofterminals <= MAX_TERMINALS);
}
apc->terminals = terminals;
uint nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
if (nofhelipads > MAX_HELIPADS) {
DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
DEBUG(misc, 0) ("[Ap] Currently only maximum of %d helipads are supported (you wanted %d)", MAX_HELIPADS, nofhelipads);
assert(nofhelipads <= MAX_HELIPADS);
}
apc->helipads = helipads;
/* Get the number of elements from the source table. We also double check this
* with the entry point which must be within bounds and use this information
* later on to build and validate the state machine */
for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
if (entry_points[i] >= nofelements) {
DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_points[i], nofelements);
assert(entry_points[i] < nofelements);
}
apc->nofelements = AirportGetNofElements(apFA);
if (entry_point >= apc->nofelements) {
DEBUG(misc, 0) ("[Ap] Entry (%d) must be within the airport (maximum %d)", entry_point, apc->nofelements);
assert(entry_point < apc->nofelements);
}
apc->acc_planes = acc_planes;
apc->entry_point = entry_point;
apc->airport_depots = depots;
apc->nof_depots = nof_depots;
/* Build the state machine itself */
layout = AirportBuildAutomata(nofelements, apFA);
DEBUG(misc, 6, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entries %3d, %3d, %3d, %3d",
nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups,
entry_points[DIAGDIR_NE], entry_points[DIAGDIR_SE], entry_points[DIAGDIR_SW], entry_points[DIAGDIR_NW]);
AirportBuildAutomata(apc, apFA);
DEBUG(misc, 1) ("[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entry %3d",
apc->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, apc->entry_point);
/* Test if everything went allright. This is only a rude static test checking
* the symantic correctness. By no means does passing the test mean that the
* airport is working correctly or will not deadlock for example */
uint ret = AirportTestFTA(nofelements, layout, terminals);
if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
assert(ret == MAX_ELEMENTS);
{ byte ret = AirportTestFTA(apc);
if (ret != MAX_ELEMENTS) DEBUG(misc, 0) ("[Ap] ERROR with element: %d", ret - 1);
assert(ret == MAX_ELEMENTS);
}
#ifdef DEBUG_AIRPORT
AirportPrintOut(nofelements, layout, DEBUG_AIRPORT);
AirportPrintOut(apc, DEBUG_AIRPORT);
#endif
}
AirportFTAClass::~AirportFTAClass()
static void AirportFTAClass_Destructor(AirportFTAClass *apc)
{
for (uint i = 0; i < nofelements; i++) {
AirportFTA *current = layout[i].next;
int i;
AirportFTA *current, *next;
for (i = 0; i < apc->nofelements; i++) {
current = apc->layout[i].next;
while (current != NULL) {
AirportFTA *next = current->next;
next = current->next;
free(current);
current = next;
};
}
free(layout);
free(apc->layout);
free(apc);
}
/** Get the number of elements of a source Airport state automata
@@ -306,10 +285,11 @@ AirportFTAClass::~AirportFTAClass()
* know one element from the other by differing 'position' identifiers */
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
{
int i;
uint16 nofelements = 0;
int temp = apFA[0].position;
for (uint i = 0; i < MAX_ELEMENTS; i++) {
for (i = 0; i < MAX_ELEMENTS; i++) {
if (temp != apFA[i].position) {
nofelements++;
temp = apFA[i].position;
@@ -319,16 +299,17 @@ static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
return nofelements;
}
/** We calculate the terminal/helipod count based on the data passed to us
/* We calculate the terminal/helipod count based on the data passed to us
* This data (terminals) contains an index as a first element as to how many
* groups there are, and then the number of terminals for each group */
static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
{
byte i;
byte nof_terminals = 0;
*groups = 0;
if (terminals != NULL) {
uint i = terminals[0];
i = terminals[0];
*groups = i;
while (i-- > 0) {
terminals++;
@@ -339,56 +320,58 @@ static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
return nof_terminals;
}
static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA)
static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA)
{
AirportFTA *FAutomata = MallocT<AirportFTA>(nofelements);
AirportFTA *current;
AirportFTA *FAutomata = malloc(sizeof(AirportFTA) * apc->nofelements);
uint16 internalcounter = 0;
uint16 i;
for (uint i = 0; i < nofelements; i++) {
AirportFTA *current = &FAutomata[i];
apc->layout = FAutomata;
for (i = 0; i < apc->nofelements; i++) {
current = &apc->layout[i];
current->position = apFA[internalcounter].position;
current->heading = apFA[internalcounter].heading;
current->block = apFA[internalcounter].block;
current->next_position = apFA[internalcounter].next;
/* outgoing nodes from the same position, create linked list */
// outgoing nodes from the same position, create linked list
while (current->position == apFA[internalcounter + 1].position) {
AirportFTA *newNode = MallocT<AirportFTA>(1);
AirportFTA *newNode = malloc(sizeof(AirportFTA));
newNode->position = apFA[internalcounter + 1].position;
newNode->heading = apFA[internalcounter + 1].heading;
newNode->block = apFA[internalcounter + 1].block;
newNode->next_position = apFA[internalcounter + 1].next;
/* create link */
// create link
current->next = newNode;
current = current->next;
internalcounter++;
}
} // while
current->next = NULL;
internalcounter++;
}
return FAutomata;
}
static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals)
static byte AirportTestFTA(const AirportFTAClass *apc)
{
uint next_position = 0;
byte position, i, next_position;
AirportFTA *current, *first;
next_position = 0;
for (uint i = 0; i < nofelements; i++) {
uint position = layout[i].position;
for (i = 0; i < apc->nofelements; i++) {
position = apc->layout[i].position;
if (position != next_position) return i;
const AirportFTA *first = &layout[i];
current = first = &apc->layout[i];
for (const AirportFTA *current = first; current != NULL; current = current->next) {
for (; current != NULL; current = current->next) {
/* A heading must always be valid. The only exceptions are
* - multiple choices as start, identified by a special value of 255
* - terminal group which is identified by a special value of 255 */
if (current->heading > MAX_HEADINGS) {
if (current->heading != 255) return i;
if (current == first && current->next == NULL) return i;
if (current != first && current->next_position > terminals[0]) return i;
if (current != first && current->next_position > apc->terminals[0]) return i;
}
/* If there is only one choice, it must be at the end */
@@ -396,7 +379,7 @@ static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byt
/* Obviously the elements of the linked list must have the same identifier */
if (position != current->position) return i;
/* A next position must be within bounds */
if (current->next_position >= nofelements) return i;
if (current->next_position >= apc->nofelements) return i;
}
next_position++;
}
@@ -404,7 +387,7 @@ static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byt
}
#ifdef DEBUG_AIRPORT
static const char * const _airport_heading_strings[] = {
static const char* const _airport_heading_strings[] = {
"TO_ALL",
"HANGAR",
"TERM1",
@@ -431,17 +414,32 @@ static const char * const _airport_heading_strings[] = {
"DUMMY" // extra heading for 255
};
static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report)
static uint AirportBlockToString(uint32 block)
{
uint i = 0;
if (block & 0xffff0000) { block >>= 16; i += 16; }
if (block & 0x0000ff00) { block >>= 8; i += 8; }
if (block & 0x000000f0) { block >>= 4; i += 4; }
if (block & 0x0000000c) { block >>= 2; i += 2; }
if (block & 0x00000002) { i += 1; }
return i;
}
static void AirportPrintOut(const AirportFTAClass *apc, bool full_report)
{
uint16 i;
if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
for (uint i = 0; i < nofelements; i++) {
for (const AirportFTA *current = &layout[i]; current != NULL; current = current->next) {
for (i = 0; i < apc->nofelements; i++) {
AirportFTA *current = &apc->layout[i];
for (; current != NULL; current = current->next) {
if (full_report) {
byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
current->next_position, _airport_heading_strings[heading],
FindLastBit(current->block));
AirportBlockToString(current->block));
} else {
printf("P:%2d NP:%2d", current->position, current->next_position);
}
@@ -453,8 +451,8 @@ static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool ful
const AirportFTAClass *GetAirport(const byte airport_type)
{
/* FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
* needs constant change if more airports are added */
//FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
// needs constant change if more airports are added
switch (airport_type) {
default: NOT_REACHED();
case AT_SMALL: return CountryAirport;
@@ -467,23 +465,25 @@ const AirportFTAClass *GetAirport(const byte airport_type)
case AT_HELIDEPOT: return HeliDepot;
case AT_INTERCON: return IntercontinentalAirport;
case AT_HELISTATION: return HeliStation;
case AT_DUMMY: return DummyAirport;
}
}
uint32 GetValidAirports()
const AirportMovingData *GetAirportMovingData(byte airport_type, byte position)
{
uint32 mask = 0;
if (_cur_year < 1960 || _settings_game.station.always_small_airport) SetBit(mask, 0); // small airport
if (_cur_year >= 1955) SetBit(mask, 1); // city airport
if (_cur_year >= 1963) SetBit(mask, 2); // heliport
if (_cur_year >= 1980) SetBit(mask, 3); // metropolitan airport
if (_cur_year >= 1990) SetBit(mask, 4); // international airport
if (_cur_year >= 1983) SetBit(mask, 5); // commuter airport
if (_cur_year >= 1976) SetBit(mask, 6); // helidepot
if (_cur_year >= 2002) SetBit(mask, 7); // intercontinental airport
if (_cur_year >= 1980) SetBit(mask, 8); // helistation
return mask;
assert(airport_type < lengthof(_airport_moving_datas));
assert(position < GetAirport(airport_type)->nofelements);
return &_airport_moving_datas[airport_type][position];
}
uint32 GetValidAirports(void)
{
uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
if (_cur_year >= 1980) SETBIT(bytemask, 3); // metropolitan airport
if (_cur_year >= 1990) SETBIT(bytemask, 4); // international airport
if (_cur_year >= 1983) SETBIT(bytemask, 5); // commuter airport
if (_cur_year >= 1976) SETBIT(bytemask, 6); // helidepot
if (_cur_year >= 2002) SETBIT(bytemask, 7); // intercontinental airport
if (_cur_year >= 1980) SETBIT(bytemask, 8); // helistation
return bytemask;
}

163
airport.h Normal file
View File

@@ -0,0 +1,163 @@
/* $Id$ */
#ifndef AIRPORT_H
#define AIRPORT_H
enum {MAX_TERMINALS = 10};
enum {MAX_HELIPADS = 4};
enum {MAX_ELEMENTS = 255};
enum {MAX_HEADINGS = 22};
// Airport types
enum {
AT_SMALL = 0,
AT_LARGE = 1,
AT_HELIPORT = 2,
AT_METROPOLITAN = 3,
AT_INTERNATIONAL = 4,
AT_COMMUTER = 5,
AT_HELIDEPOT = 6,
AT_INTERCON = 7,
AT_HELISTATION = 8,
AT_OILRIG = 15
};
// do not change unless you change v->subtype too. This aligns perfectly with its current setting
enum {
AIRCRAFT_ONLY = 0,
ALL = 1,
HELICOPTERS_ONLY = 2,
};
enum {
AMED_NOSPDCLAMP = 1 << 0,
AMED_TAKEOFF = 1 << 1,
AMED_SLOWTURN = 1 << 2,
AMED_LAND = 1 << 3,
AMED_EXACTPOS = 1 << 4,
AMED_BRAKE = 1 << 5,
AMED_HELI_RAISE = 1 << 6,
AMED_HELI_LOWER = 1 << 7,
};
/* Movement States on Airports (headings target) */
enum {
TO_ALL = 0,
HANGAR = 1,
TERM1 = 2,
TERM2 = 3,
TERM3 = 4,
TERM4 = 5,
TERM5 = 6,
TERM6 = 7,
HELIPAD1 = 8,
HELIPAD2 = 9,
TAKEOFF = 10,
STARTTAKEOFF = 11,
ENDTAKEOFF = 12,
HELITAKEOFF = 13,
FLYING = 14,
LANDING = 15,
ENDLANDING = 16,
HELILANDING = 17,
HELIENDLANDING = 18,
TERM7 = 19,
TERM8 = 20,
HELIPAD3 = 21,
HELIPAD4 = 22
};
// this maps the terminal to its corresponding state and block flag
// currently set for 10 terms, 4 helipads
static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22};
static const byte _airport_terminal_flag[] = {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25};
/* Movement Blocks on Airports */
// blocks (eg_airport_flags)
enum {
TERM1_block = 1 << 0,
TERM2_block = 1 << 1,
TERM3_block = 1 << 2,
TERM4_block = 1 << 3,
TERM5_block = 1 << 4,
TERM6_block = 1 << 5,
HELIPAD1_block = 1 << 6,
HELIPAD2_block = 1 << 7,
RUNWAY_IN_OUT_block = 1 << 8,
RUNWAY_IN_block = 1 << 8,
AIRPORT_BUSY_block = 1 << 8,
RUNWAY_OUT_block = 1 << 9,
TAXIWAY_BUSY_block = 1 << 10,
OUT_WAY_block = 1 << 11,
IN_WAY_block = 1 << 12,
AIRPORT_ENTRANCE_block = 1 << 13,
TERM_GROUP1_block = 1 << 14,
TERM_GROUP2_block = 1 << 15,
HANGAR2_AREA_block = 1 << 16,
TERM_GROUP2_ENTER1_block = 1 << 17,
TERM_GROUP2_ENTER2_block = 1 << 18,
TERM_GROUP2_EXIT1_block = 1 << 19,
TERM_GROUP2_EXIT2_block = 1 << 20,
PRE_HELIPAD_block = 1 << 21,
// blocks for new airports
TERM7_block = 1 << 22,
TERM8_block = 1 << 23,
TERM9_block = 1 << 24,
HELIPAD3_block = 1 << 24,
TERM10_block = 1 << 25,
HELIPAD4_block = 1 << 25,
HANGAR1_AREA_block = 1 << 26,
OUT_WAY2_block = 1 << 27,
IN_WAY2_block = 1 << 28,
RUNWAY_IN2_block = 1 << 29,
RUNWAY_OUT2_block = 1 << 10, // note re-uses TAXIWAY_BUSY
HELIPAD_GROUP_block = 1 << 13, // note re-uses AIRPORT_ENTRANCE
OUT_WAY_block2 = 1 << 31,
// end of new blocks
NOTHING_block = 1 << 30
};
typedef struct AirportMovingData {
int x,y;
byte flag;
byte direction;
} AirportMovingData;
// Finite sTate mAchine --> FTA
typedef struct AirportFTAClass {
byte nofelements; // number of positions the airport consists of
const byte *terminals;
const byte *helipads;
byte entry_point; // when an airplane arrives at this airport, enter it at position entry_point
byte acc_planes; // accept airplanes or helicopters or both
const TileIndexDiffC *airport_depots; // gives the position of the depots on the airports
byte nof_depots; // number of depots this airport has
struct AirportFTA *layout; // state machine for airport
byte size_x;
byte size_y;
} AirportFTAClass;
// internal structure used in openttd - Finite sTate mAchine --> FTA
typedef struct AirportFTA {
byte position; // the position that an airplane is at
byte next_position; // next position from this position
uint32 block; // 32 bit blocks (st->airport_flags), should be enough for the most complex airports
byte heading; // heading (current orders), guiding an airplane to its target on an airport
struct AirportFTA *next; // possible extra movement choices from this position
} AirportFTA;
void InitializeAirports(void);
void UnInitializeAirports(void);
const AirportFTAClass *GetAirport(const byte airport_type);
const AirportMovingData *GetAirportMovingData(byte airport_type, byte position);
/** 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 */

286
airport_gui.c Normal file
View File

@@ -0,0 +1,286 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "sound.h"
#include "command.h"
#include "vehicle.h"
#include "station.h"
#include "airport.h"
#include "depot.h"
static byte _selected_airport_type;
static void ShowBuildAirportPicker(void);
void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(SND_1F_SPLAT, tile);
ResetObjectToPlace();
}
}
static void PlaceAirport(TileIndex 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));
}
static void PlaceAir_DemolishArea(TileIndex tile)
{
VpStartPlaceSizing(tile, 4);
}
enum {
ATW_AIRPORT = 3,
ATW_DEMOLISH = 4
};
static void BuildAirClick_Airport(Window *w)
{
if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker();
}
static void BuildAirClick_Demolish(Window *w)
{
HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceAir_DemolishArea);
}
static void BuildAirClick_Landscaping(Window *w)
{
ShowTerraformToolbar();
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_air_button_proc[] = {
BuildAirClick_Airport,
BuildAirClick_Demolish,
BuildAirClick_Landscaping,
};
static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
break;
case WE_CLICK:
if (e->we.click.widget - 3 >= 0)
_build_air_button_proc[e->we.click.widget - 3](w);
break;
case WE_KEYPRESS: {
switch (e->we.keypress.keycode) {
case '1': BuildAirClick_Airport(w); break;
case '2': BuildAirClick_Demolish(w); break;
case 'l': BuildAirClick_Landscaping(w); break;
default: return;
}
} break;
case WE_PLACE_OBJ:
_place_proc(e->we.place.tile);
break;
case WE_PLACE_DRAG:
VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
break;
case WE_PLACE_MOUSEUP:
if (e->we.place.pt.x != -1) {
DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
}
break;
case WE_ABORT_PLACE_OBJ:
RaiseWindowButtons(w);
w = FindWindowById(WC_BUILD_STATION, 0);
if (w != 0)
WP(w,def_d).close = true;
break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
}
}
static const Widget _air_toolbar_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 73, 0, 13, STR_A000_AIRPORTS, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_STICKYBOX, RESIZE_NONE, 7, 74, 85, 0, 13, 0x0, STR_STICKY_BUTTON },
{ WWT_IMGBTN, RESIZE_NONE, 7, 0, 41, 14, 35, SPR_IMG_AIRPORT, STR_A01E_BUILD_AIRPORT },
{ WWT_IMGBTN, RESIZE_NONE, 7, 42, 63, 14, 35, SPR_IMG_DYNAMITE, STR_018D_DEMOLISH_BUILDINGS_ETC },
{ WWT_IMGBTN, RESIZE_NONE, 7, 64, 85, 14, 35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP },
{ WIDGETS_END},
};
static const WindowDesc _air_toolbar_desc = {
WDP_ALIGN_TBR, 22, 86, 36,
WC_BUILD_TOOLBAR, 0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_air_toolbar_widgets,
BuildAirToolbWndProc
};
void ShowBuildAirToolbar(void)
{
if (!IsValidPlayer(_current_player)) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDescFront(&_air_toolbar_desc, 0);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
}
static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE:
SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
LowerWindowWidget(w, _selected_airport_type + 7);
break;
case WE_PAINT: {
int i; // airport enabling loop
int rad = 4; // default catchment radious
uint32 avail_airports;
const AirportFTAClass *airport;
if (WP(w,def_d).close) return;
avail_airports = GetValidAirports();
RaiseWindowWidget(w, _selected_airport_type + 7);
if (!HASBIT(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
if (!HASBIT(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
LowerWindowWidget(w, _selected_airport_type + 7);
/* 'Country Airport' starts at widget 7, and if its bit is set, it is
* available, so take its opposite value to set the disabled state.
* There are 9 buildable airports
* XXX TODO : all airports should be held in arrays, with all relevant data.
* This should be part of newgrf-airports, i suppose
*/
for (i = 0; i < 9; i++) SetWindowWidgetDisabledState(w, i + 7, !HASBIT(avail_airports, i));
// select default the coverage area to 'Off' (16)
airport = GetAirport(_selected_airport_type);
SetTileSelectSize(airport->size_x, airport->size_y);
if (_patches.modified_catchment) {
switch (_selected_airport_type) {
case AT_OILRIG: rad = CA_AIR_OILPAD; break;
case AT_HELIPORT: rad = CA_AIR_HELIPORT; break;
case AT_SMALL: rad = CA_AIR_SMALL; break;
case AT_LARGE: rad = CA_AIR_LARGE; break;
case AT_METROPOLITAN: rad = CA_AIR_METRO; break;
case AT_INTERNATIONAL: rad = CA_AIR_INTER; break;
case AT_COMMUTER: rad = CA_AIR_COMMUTER; break;
case AT_HELIDEPOT: rad = CA_AIR_HELIDEPOT; break;
case AT_INTERCON: rad = CA_AIR_INTERCON; break;
case AT_HELISTATION: rad = CA_AIR_HELISTATION; break;
}
}
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
DrawWindowWidgets(w);
// strings such as 'Size' and 'Coverage Area'
// 'Coverage Area'
DrawStationCoverageAreaText(2, 206, (uint)-1, rad);
break;
}
case WE_CLICK: {
switch (e->we.click.widget) {
case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
RaiseWindowWidget(w, _selected_airport_type + 7);
_selected_airport_type = e->we.click.widget - 7;
LowerWindowWidget(w, _selected_airport_type + 7);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
case 16: case 17:
_station_show_coverage = e->we.click.widget - 16;
SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
}
} break;
case WE_MOUSELOOP: {
if (WP(w,def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
} break;
case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace();
break;
}
}
static const Widget _build_airport_picker_widgets[] = {
{ 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_3001_AIRPORT_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 52, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 53, 89, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 90, 127, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 128, 177, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 178, 239, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 27, 38, STR_SMALL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 65, 76, STR_CITY_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 141, 152, STR_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 77, 88, STR_METRO_AIRPORT , STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 103, 114, STR_INTERNATIONAL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 39, 50, STR_COMMUTER_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 165, 176, STR_HELIDEPOT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 115, 126, STR_INTERCONTINENTAL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 153, 164, STR_HELISTATION, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 191, 202, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 191, 202, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 14, 27, STR_SMALL_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 52, 65, STR_LARGE_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 90, 103, STR_HUB_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 128, 141, STR_HELIPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 178, 191, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _build_airport_desc = {
WDP_AUTO, WDP_AUTO, 148, 240,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_airport_picker_widgets,
BuildAirportPickerWndProc
};
static void ShowBuildAirportPicker(void)
{
AllocateWindowDesc(&_build_airport_desc);
}
void InitializeAirportGui(void)
{
_selected_airport_type = AT_SMALL;
}

794
airport_movement.h Normal file
View File

@@ -0,0 +1,794 @@
/* $Id$ */
#ifndef AIRPORT_MOVEMENT_H
#define AIRPORT_MOVEMENT_H
// state machine input struct (from external file, etc.)
// Finite sTate mAchine --> FTA
typedef struct AirportFTAbuildup {
byte position; // the position that an airplane is at
byte heading; // the current orders (eg. TAKEOFF, HANGAR, ENDLANDING, etc.)
uint32 block; // the block this position is on on the airport (st->airport_flags)
byte next; // next position from this position
} AirportFTAbuildup;
///////////////////////////////////////////////////////////////////////
/////*********Movement Positions on Airports********************///////
// Country Airfield (small) 4x3
static const AirportMovingData _airport_moving_data_country[22] = {
{ 53, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 53, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 32, 23, AMED_EXACTPOS, 7 }, // 02 Terminal 1
{ 10, 23, AMED_EXACTPOS, 7 }, // 03 Terminal 2
{ 43, 37, 0, 0 }, // 04 Going towards terminal 2
{ 24, 37, 0, 0 }, // 05 Going towards terminal 2
{ 53, 37, 0, 0 }, // 06 Going for takeoff
{ 61, 40, AMED_EXACTPOS, 1 }, // 07 Taxi to start of runway (takeoff)
{ 3, 40, AMED_NOSPDCLAMP, 0 }, // 08 Accelerate to end of runway
{ -79, 40, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 09 Take off
{ 177, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 10 Fly to landing position in air
{ 56, 40, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 11 Going down for land
{ 3, 40, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 12 Just landed, brake until end of runway
{ 7, 40, 0, 0 }, // 13 Just landed, turn around and taxi 1 square
{ 53, 40, 0, 0 }, // 14 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 15 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 17 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Fly around waiting for a landing spot (south)
{ 44, 37, AMED_HELI_RAISE, 0 }, // 19 Helicopter takeoff
{ 44, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 In position above landing spot helicopter
{ 44, 40, AMED_HELI_LOWER, 0 }, // 21 Helicopter landing
};
// Commuter Airfield (small) 5x4
static const AirportMovingData _airport_moving_data_commuter[37] = {
{ 69, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 72, 22, 0, 0 }, // 01 Taxi to right outside depot
{ 8, 22, AMED_EXACTPOS, 5 }, // 01 Taxi to right outside depot
{ 24, 36, AMED_EXACTPOS, 3 }, // 03 Terminal 1
{ 40, 36, AMED_EXACTPOS, 3 }, // 04 Terminal 2
{ 56, 36, AMED_EXACTPOS, 3 }, // 05 Terminal 3
{ 40, 8, AMED_EXACTPOS, 1 }, // 06 Helipad 1
{ 56, 8, AMED_EXACTPOS, 1 }, // 07 Helipad 2
{ 24, 22, 0, 5 }, // 08 Taxiing
{ 40, 22, 0, 5 }, // 09 Taxiing
{ 56, 22, 0, 5 }, // 10 Taxiing
{ 72, 40, 0, 3 }, // 11 Airport OUTWAY
{ 72, 54, AMED_EXACTPOS, 1 }, // 12 Accelerate to end of runway
{ 7, 54, AMED_NOSPDCLAMP, 0 }, // 13 Release control of runway, for smoother movement
{ 5, 54, AMED_NOSPDCLAMP, 0 }, // 14 End of runway
{ -79, 54, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 15 Take off
{ 145, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Fly to landing position in air
{ 73, 54, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 17 Going down for land
{ 3, 54, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 18 Just landed, brake until end of runway
{ 12, 54, 0, 7 }, // 19 Just landed, turn around and taxi
{ 8, 32, 0, 7 }, // 20 Taxi from runway to crossing
{ -31, 149, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (north-east)
{ 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 22 Fly around waiting for a landing spot (north-west)
{ 193, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 Fly around waiting for a landing spot (south-west)
{ 225, 81, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 24 Fly around waiting for a landing spot (south)
// Helicopter
{ 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Bufferspace before helipad
{ 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 26 Bufferspace before helipad
{ 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 27 Get in position for Helipad1
{ 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 28 Get in position for Helipad2
{ 32, 8, AMED_HELI_LOWER, 0 }, // 29 Land at Helipad1
{ 48, 8, AMED_HELI_LOWER, 0 }, // 30 Land at Helipad2
{ 32, 8, AMED_HELI_RAISE, 0 }, // 31 Takeoff Helipad1
{ 48, 8, AMED_HELI_RAISE, 0 }, // 32 Takeoff Helipad2
{ 64, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 33 Go to position for Hangarentrance in air
{ 64, 22, AMED_HELI_LOWER, 0 }, // 34 Land in front of hangar
{ 40, 8, AMED_EXACTPOS, 0 }, // pre-helitakeoff helipad 1
{ 56, 8, AMED_EXACTPOS, 0 }, // pre-helitakeoff helipad 2
};
// City Airport (large) 6x6
static const AirportMovingData _airport_moving_data_town[25] = {
{ 85, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 85, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 26, 41, AMED_EXACTPOS, 5 }, // 02 Terminal 1
{ 56, 20, AMED_EXACTPOS, 3 }, // 03 Terminal 2
{ 38, 8, AMED_EXACTPOS, 5 }, // 04 Terminal 3
{ 65, 6, 0, 0 }, // 05 Taxi to right in infront of terminal 2/3
{ 80, 27, 0, 0 }, // 06 Taxiway terminals 2-3
{ 44, 63, 0, 0 }, // 07 Taxi to Airport center
{ 58, 71, 0, 0 }, // 08 Towards takeoff
{ 72, 85, 0, 0 }, // 09 Taxi to runway (takeoff)
{ 89, 85, AMED_EXACTPOS, 1 }, // 10 Taxi to start of runway (takeoff)
{ 3, 85, AMED_NOSPDCLAMP, 0 }, // 11 Accelerate to end of runway
{ -79, 85, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 12 Take off
{ 177, 85, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 13 Fly to landing position in air
{ 89, 85, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 14 Going down for land
{ 3, 85, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 15 Just landed, brake until end of runway
{ 20, 87, 0, 0 }, // 16 Just landed, turn around and taxi 1 square
{ 36, 71, 0, 0 }, // 17 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 19 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (south)
{ 44, 63, AMED_HELI_RAISE, 0 }, // 22 Helicopter takeoff
{ 28, 74, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 In position above landing spot helicopter
{ 28, 74, AMED_HELI_LOWER, 0 }, // 24 Helicopter landing
};
// Metropolitan Airport (metropolitan) - 2 runways
static const AirportMovingData _airport_moving_data_metropolitan[27] = {
{ 85, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 85, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 26, 41, AMED_EXACTPOS, 5 }, // 02 Terminal 1
{ 56, 20, AMED_EXACTPOS, 3 }, // 03 Terminal 2
{ 38, 8, AMED_EXACTPOS, 5 }, // 04 Terminal 3
{ 65, 6, 0, 0 }, // 05 Taxi to right in infront of terminal 2/3
{ 70, 33, 0, 0 }, // 06 Taxiway terminals 2-3
{ 44, 58, 0, 0 }, // 07 Taxi to Airport center
{ 72, 58, 0, 0 }, // 08 Towards takeoff
{ 72, 69, 0, 0 }, // 09 Taxi to runway (takeoff)
{ 89, 69, AMED_EXACTPOS, 1 }, // 10 Taxi to start of runway (takeoff)
{ 3, 69, AMED_NOSPDCLAMP, 0 }, // 11 Accelerate to end of runway
{ -79, 69, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 12 Take off
{ 177, 85, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 13 Fly to landing position in air
{ 89, 85, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 14 Going down for land
{ 3, 85, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 15 Just landed, brake until end of runway
{ 21, 85, 0, 0 }, // 16 Just landed, turn around and taxi 1 square
{ 21, 69, 0, 0 }, // 17 On Runway-out taxiing to In-Way
{ 21, 54, AMED_EXACTPOS, 5 }, // 18 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 19 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 22 Fly around waiting for a landing spot (south)
{ 44, 58, 0, 0 }, // 23 Helicopter takeoff spot on ground (to clear airport sooner)
{ 44, 63, AMED_HELI_RAISE, 0 }, // 24 Helicopter takeoff
{ 15, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Get in position above landing spot helicopter
{ 15, 54, AMED_HELI_LOWER, 0 }, // 26 Helicopter landing
};
// International Airport (international) - 2 runways, 6 terminals, dedicated helipod
static const AirportMovingData _airport_moving_data_international[51] = {
{ 7, 55, AMED_EXACTPOS, 3 }, // 00 In Hangar 1
{ 100, 21, AMED_EXACTPOS, 3 }, // 01 In Hangar 2
{ 7, 70, 0, 0 }, // 02 Taxi to right outside depot
{ 100, 36, 0, 0 }, // 03 Taxi to right outside depot
{ 38, 70, AMED_EXACTPOS, 5 }, // 04 Terminal 1
{ 38, 54, AMED_EXACTPOS, 5 }, // 05 Terminal 2
{ 38, 38, AMED_EXACTPOS, 5 }, // 06 Terminal 3
{ 70, 70, AMED_EXACTPOS, 1 }, // 07 Terminal 4
{ 70, 54, AMED_EXACTPOS, 1 }, // 08 Terminal 5
{ 70, 38, AMED_EXACTPOS, 1 }, // 09 Terminal 6
{ 104, 71, AMED_EXACTPOS, 1 }, // 10 Helipad 1
{ 104, 55, AMED_EXACTPOS, 1 }, // 11 Helipad 2
{ 22, 87, 0, 0 }, // 12 Towards Terminals 4/5/6, Helipad 1/2
{ 60, 87, 0, 0 }, // 13 Towards Terminals 4/5/6, Helipad 1/2
{ 66, 87, 0, 0 }, // 14 Towards Terminals 4/5/6, Helipad 1/2
{ 86, 87, AMED_EXACTPOS, 7 }, // 15 Towards Terminals 4/5/6, Helipad 1/2
{ 86, 70, 0, 0 }, // 16 In Front of Terminal 4 / Helipad 1
{ 86, 54, 0, 0 }, // 17 In Front of Terminal 5 / Helipad 2
{ 86, 38, 0, 0 }, // 18 In Front of Terminal 6
{ 86, 22, 0, 0 }, // 19 Towards Terminals Takeoff (Taxiway)
{ 66, 22, 0, 0 }, // 20 Towards Terminals Takeoff (Taxiway)
{ 60, 22, 0, 0 }, // 21 Towards Terminals Takeoff (Taxiway)
{ 38, 22, 0, 0 }, // 22 Towards Terminals Takeoff (Taxiway)
{ 22, 70, 0, 0 }, // 23 In Front of Terminal 1
{ 22, 58, 0, 0 }, // 24 In Front of Terminal 2
{ 22, 38, 0, 0 }, // 25 In Front of Terminal 3
{ 22, 22, AMED_EXACTPOS, 7 }, // 26 Going for Takeoff
{ 22, 6, 0, 0 }, // 27 On Runway-out, prepare for takeoff
{ 3, 6, AMED_EXACTPOS, 5 }, // 28 Accelerate to end of runway
{ 60, 6, AMED_NOSPDCLAMP, 0 }, // 29 Release control of runway, for smoother movement
{ 105, 6, AMED_NOSPDCLAMP, 0 }, // 30 End of runway
{ 190, 6, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 31 Take off
{ 193, 104, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 32 Fly to landing position in air
{ 105, 104, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 33 Going down for land
{ 3, 104, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 34 Just landed, brake until end of runway
{ 12, 104, 0, 0 }, // 35 Just landed, turn around and taxi 1 square
{ 7, 84, 0, 0 }, // 36 Taxi from runway to crossing
{ -31, 209, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 37 Fly around waiting for a landing spot (north-east)
{ 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 38 Fly around waiting for a landing spot (north-west)
{ 273, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 39 Fly around waiting for a landing spot (south-west)
{ 305, 81, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 40 Fly around waiting for a landing spot (south)
// Helicopter
{ 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 41 Bufferspace before helipad
{ 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 42 Bufferspace before helipad
{ 96, 71, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 43 Get in position for Helipad1
{ 96, 55, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 44 Get in position for Helipad2
{ 96, 71, AMED_HELI_LOWER, 0 }, // 45 Land at Helipad1
{ 96, 55, AMED_HELI_LOWER, 0 }, // 46 Land at Helipad2
{ 104, 71, AMED_HELI_RAISE, 0 }, // 47 Takeoff Helipad1
{ 104, 55, AMED_HELI_RAISE, 0 }, // 48 Takeoff Helipad2
{ 104, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 49 Go to position for Hangarentrance in air
{ 104, 32, AMED_HELI_LOWER, 0} // 50 Land in HANGAR2_AREA to go to hangar
};
// Intercontinental Airport - 4 runways, 8 terminals, 2 dedicated helipads
static const AirportMovingData _airport_moving_data_intercontinental[77] = {
{ 7, 87, AMED_EXACTPOS, 3 }, // 00 In Hangar 1
{ 135, 72, AMED_EXACTPOS, 3 }, // 01 In Hangar 2
{ 7, 104, 0, 0 }, // 02 Taxi to right outside depot 1
{ 135, 88, 0, 0 }, // 03 Taxi to right outside depot 2
{ 56, 120, AMED_EXACTPOS, 6 }, // 04 Terminal 1
{ 56, 104, AMED_EXACTPOS, 5 }, // 05 Terminal 2
{ 56, 88, AMED_EXACTPOS, 5 }, // 06 Terminal 3
{ 56, 72, AMED_EXACTPOS, 5 }, // 07 Terminal 4
{ 88, 120, AMED_EXACTPOS, 0 }, // 08 Terminal 5
{ 88, 104, AMED_EXACTPOS, 1 }, // 09 Terminal 6
{ 88, 88, AMED_EXACTPOS, 1 }, // 10 Terminal 7
{ 88, 72, AMED_EXACTPOS, 1 }, // 11 Terminal 8
{ 88, 56, AMED_EXACTPOS, 3 }, // 12 Helipad 1
{ 72, 56, AMED_EXACTPOS, 1 }, // 13 Helipad 2
{ 40, 136, 0, 0 }, // 14 Term group 2 enter 1 a
{ 56, 136, 0, 0 }, // 15 Term group 2 enter 1 b
{ 88, 136, 0, 0 }, // 16 Term group 2 enter 2 a
{ 104, 136, 0, 0 }, // 17 Term group 2 enter 2 b
{ 104, 120, 0, 0 }, // 18 Term group 2 - opp term 5
{ 104, 104, 0, 0 }, // 19 Term group 2 - opp term 6 & exit2
{ 104, 88, 0, 0 }, // 20 Term group 2 - opp term 7 & hangar area 2
{ 104, 72, 0, 0 }, // 21 Term group 2 - opp term 8
{ 104, 56, 0, 0 }, // 22 Taxi Term group 2 exit a
{ 104, 40, 0, 0 }, // 23 Taxi Term group 2 exit b
{ 56, 40, 0, 0 }, // 24 Term group 2 exit 2a
{ 40, 40, 0, 0 }, // 25 Term group 2 exit 2b
{ 40, 120, 0, 0 }, // 26 Term group 1 - opp term 1
{ 40, 104, 0, 0 }, // 27 Term group 1 - opp term 2 & hangar area 1
{ 40, 88, 0, 0 }, // 28 Term group 1 - opp term 3
{ 40, 72, 0, 0 }, // 29 Term group 1 - opp term 4
{ 18, 72, 0, 7 }, // 30 Outway 1
{ 8, 40, 0, 7 }, // 31 Airport OUTWAY
{ 8, 24, AMED_EXACTPOS, 5 }, // 32 Accelerate to end of runway
{ 119, 24, AMED_NOSPDCLAMP, 0 }, // 33 Release control of runway, for smoother movement
{ 117, 24, AMED_NOSPDCLAMP, 0 }, // 34 End of runway
{ 197, 24, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 35 Take off
{ 254, 84, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 36 Flying to landing position in air
{ 117, 168, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 37 Going down for land
{ 3, 168, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 38 Just landed, brake until end of runway
{ 8, 168, 0, 0 }, // 39 Just landed, turn around and taxi
{ 8, 144, 0, 7 }, // 40 Taxi from runway
{ 8, 128, 0, 7 }, // 41 Taxi from runway
{ 8, 120, AMED_EXACTPOS, 5 }, // 42 Airport entrance
{ 56, 344, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 43 Fly around waiting for a landing spot (north-east)
{ -200, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 44 Fly around waiting for a landing spot (north-west)
{ 56, -168, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 45 Fly around waiting for a landing spot (south-west)
{ 312, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 46 Fly around waiting for a landing spot (south)
// Helicopter
{ 96, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 47 Bufferspace before helipad
{ 96, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 48 Bufferspace before helipad
{ 82, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 49 Get in position for Helipad1
{ 64, 56, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 50 Get in position for Helipad2
{ 81, 55, AMED_HELI_LOWER, 0 }, // 51 Land at Helipad1
{ 64, 56, AMED_HELI_LOWER, 0 }, // 52 Land at Helipad2
{ 80, 56, AMED_HELI_RAISE, 0 }, // 53 Takeoff Helipad1
{ 64, 56, AMED_HELI_RAISE, 0 }, // 54 Takeoff Helipad2
{ 136, 96, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 55 Go to position for Hangarentrance in air
{ 136, 96, AMED_HELI_LOWER, 0 }, // 56 Land in front of hangar2
{ 126, 104, 0, 3 }, // 57 Outway 2
{ 136, 136, 0, 1 }, // 58 Airport OUTWAY 2
{ 136, 152, AMED_EXACTPOS, 5 }, // 59 Accelerate to end of runway2
{ 16, 152, AMED_NOSPDCLAMP, 0 }, // 60 Release control of runway2, for smoother movement
{ 20, 152, AMED_NOSPDCLAMP, 0 }, // 61 End of runway2
{ -56, 152, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 62 Take off2
{ 24, 8, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 63 Going down for land2
{ 136, 8, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 64 Just landed, brake until end of runway2in
{ 136, 8, 0, 0 }, // 65 Just landed, turn around and taxi
{ 136, 24, 0, 3 }, // 66 Taxi from runway 2in
{ 136, 40, 0, 3 }, // 67 Taxi from runway 2in
{ 136, 56, AMED_EXACTPOS, 1 }, // 68 Airport entrance2
{ -56, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 69 Fly to landing position in air2
{ 88, 40, 0, 0 }, // 70 Taxi Term group 2 exit - opp heli1
{ 72, 40, 0, 0 }, // 71 Taxi Term group 2 exit - opp heli2
{ 88, 57, AMED_EXACTPOS, 3 }, // 72 pre-helitakeoff helipad 1
{ 71, 56, AMED_EXACTPOS, 1 }, // 73 pre-helitakeoff helipad 2
{ 8, 120, AMED_HELI_RAISE, 0 }, // 74 Helitakeoff outside depot 1
{ 136, 104, AMED_HELI_RAISE, 0 }, // 75 Helitakeoff outside depot 2
{ 197, 168, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0} // 76 Fly to landing position in air1
};
// Heliport (heliport)
static const AirportMovingData _airport_moving_data_heliport[9] = {
{ 5, 9, AMED_EXACTPOS, 1 }, // 0 - At heliport terminal
{ 2, 9, AMED_HELI_RAISE, 0 }, // 1 - Take off (play sound)
{ -3, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 - In position above landing spot helicopter
{ -3, 9, AMED_HELI_LOWER, 0 }, // 3 - Land
{ 2, 9, 0, 0 }, // 4 - Goto terminal on ground
{ -31, 59, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - Circle #1 (north-east)
{ -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - Circle #2 (north-west)
{ 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 7 - Circle #3 (south-west)
{ 70, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 8 - Circle #4 (south)
};
// HeliDepot 2x2 (heliport)
static const AirportMovingData _airport_moving_data_helidepot[18] = {
{ 24, 4, AMED_EXACTPOS, 1 }, // 0 - At depot
{ 24, 28, 0, 0 }, // 1 Taxi to right outside depot
{ 5, 38, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 Flying
{ -15, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 3 - Circle #1 (north-east)
{ -15, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 4 - Circle #2 (north-west)
{ 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - Circle #3 (south-west)
{ 49, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - Circle #4 (south-east)
{ 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 7 - PreHelipad
{ 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 8 - Helipad
{ 8, 16, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 9 - Land
{ 8, 16, AMED_HELI_LOWER, 7 }, // 10 - Land
{ 8, 24, AMED_HELI_RAISE, 0 }, // 11 - Take off (play sound)
{ 32, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 12 Air to above hangar area
{ 32, 24, AMED_HELI_LOWER, 7 }, // 13 Taxi to right outside depot
{ 8, 24, AMED_EXACTPOS, 7 }, // 14 - on helipad1
{ 24, 28, AMED_HELI_RAISE, 0 }, // 15 Takeoff right outside depot
{ 8, 24, AMED_HELI_RAISE, 5 }, // 16 - Take off (play sound)
{ 8, 24, AMED_SLOWTURN | AMED_EXACTPOS, 2 }, // 17 - turn on helipad1 for takeoff
};
// HeliDepot 2x2 (heliport)
static const AirportMovingData _airport_moving_data_helistation[33] = {
{ 8, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar2
{ 8, 22, 0, 0 }, // 01 outside hangar 2
{ 116, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 02 Fly to landing position in air
{ 14, 22, AMED_HELI_RAISE, 0 }, // 03 Helitakeoff outside hangar1(play sound)
{ 24, 22, 0, 0 }, // 04 taxiing
{ 40, 22, 0, 0 }, // 05 taxiing
{ 40, 8, AMED_EXACTPOS, 1 }, // 06 Helipad 1
{ 56, 8, AMED_EXACTPOS, 1 }, // 07 Helipad 2
{ 56, 24, AMED_EXACTPOS, 1 }, // 08 Helipad 3
{ 40, 8, AMED_EXACTPOS, 0 }, // 09 pre-helitakeoff helipad 1
{ 56, 8, AMED_EXACTPOS, 0 }, // 10 pre-helitakeoff helipad 2
{ 56, 24, AMED_EXACTPOS, 0 }, // 11 pre-helitakeoff helipad 3
{ 32, 8, AMED_HELI_RAISE, 0 }, // 12 Takeoff Helipad1
{ 48, 8, AMED_HELI_RAISE, 0 }, // 13 Takeoff Helipad2
{ 48, 24, AMED_HELI_RAISE, 0 }, // 14 Takeoff Helipad3
{ 84, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 15 Bufferspace before helipad
{ 68, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Bufferspace before helipad
{ 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 17 Get in position for Helipad1
{ 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Get in position for Helipad2
{ 48, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 1 }, // 19 Get in position for Helipad3
{ 40, 8, AMED_HELI_LOWER, 0 }, // 20 Land at Helipad1
{ 48, 8, AMED_HELI_LOWER, 0 }, // 21 Land at Helipad2
{ 48, 24, AMED_HELI_LOWER, 0 }, // 22 Land at Helipad3
{ 0, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 Go to position for Hangarentrance in air
{ 0, 22, AMED_HELI_LOWER, 0 }, // 24 Land in front of hangar
{ 148, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Fly around waiting for a landing spot (south-east)
{ 148, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 26 Fly around waiting for a landing spot (south-west)
{ 132, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 27 Fly around waiting for a landing spot (south-west)
{ 100, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 28 Fly around waiting for a landing spot (north-east)
{ 84, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 29 Fly around waiting for a landing spot (south-east)
{ 84, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 30 Fly around waiting for a landing spot (south-west)
{ 100, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 31 Fly around waiting for a landing spot (north-west)
{ 132, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 32 Fly around waiting for a landing spot (north-east)
};
// Oilrig
static const AirportMovingData _airport_moving_data_oilrig[9] = {
{ 31, 9, AMED_EXACTPOS, 1 }, // 0 - At oilrig terminal
{ 28, 9, AMED_HELI_RAISE, 0 }, // 1 - Take off (play sound)
{ 23, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 - In position above landing spot helicopter
{ 23, 9, AMED_HELI_LOWER, 0 }, // 3 - Land
{ 28, 9, 0, 0 }, // 4 - Goto terminal on ground
{ -31, 69, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - circle #1 (north-east)
{ -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - circle #2 (north-west)
{ 69, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 7 - circle #3 (south-west)
{ 70, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 8 - circle #4 (south)
};
///////////////////////////////////////////////////////////////////////
/////**********Movement Machine on Airports*********************///////
/* First element of terminals array tells us how many depots there are (to know size of array)
* this may be changed later when airports are moved to external file */
static const TileIndexDiffC _airport_depots_country[] = {{3, 0}};
static const byte _airport_terminal_country[] = {1, 2};
static const AirportFTAbuildup _airport_fta_country[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, AIRPORT_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM1, TERM1_block, 2 }, { 1, TERM2, 0, 4 }, { 1, HELITAKEOFF, 0, 19 }, { 1, 0, 0, 6 },
{ 2, TERM1, TERM1_block, 1 },
{ 3, TERM2, TERM2_block, 5 },
{ 4, 255, AIRPORT_BUSY_block, 0 }, { 4, TERM2, 0, 5 }, { 4, HANGAR, 0, 1 }, { 4, TAKEOFF, 0, 6 }, { 4, HELITAKEOFF, 0, 1 },
{ 5, 255, AIRPORT_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, 0, 0, 4 },
{ 6, 0, AIRPORT_BUSY_block, 7 },
// takeoff
{ 7, TAKEOFF, AIRPORT_BUSY_block, 8 },
{ 8, STARTTAKEOFF, NOTHING_block, 9 },
{ 9, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 10, FLYING, NOTHING_block, 15 }, { 10, LANDING, 0, 11 }, { 10, HELILANDING, 0, 20 },
{ 11, LANDING, AIRPORT_BUSY_block, 12 },
{ 12, 0, AIRPORT_BUSY_block, 13 },
{ 13, ENDLANDING, AIRPORT_BUSY_block, 14 }, { 13, TERM2, 0, 5 }, { 13, 0, 0, 14 },
{ 14, 0, AIRPORT_BUSY_block, 1 },
// In air
{ 15, 0, NOTHING_block, 16 },
{ 16, 0, NOTHING_block, 17 },
{ 17, 0, NOTHING_block, 18 },
{ 18, 0, NOTHING_block, 10 },
{ 19, HELITAKEOFF, NOTHING_block, 0 },
{ 20, HELILANDING, AIRPORT_BUSY_block, 21 },
{ 21, HELIENDLANDING, AIRPORT_BUSY_block, 1 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_commuter[] = { { 4, 0 } };
static const byte _airport_terminal_commuter[] = { 1, 3 };
static const byte _airport_helipad_commuter[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_commuter[] = {
{ 0, HANGAR, NOTHING_block, 1 }, { 0, HELITAKEOFF, HELIPAD2_block, 1 }, { 0, 0, 0, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TAKEOFF, 0, 11 }, { 1, TERM1, TAXIWAY_BUSY_block, 10 }, { 1, TERM2, TAXIWAY_BUSY_block, 10 }, { 1, TERM3, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD1, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD2, TAXIWAY_BUSY_block, 10 }, { 1, HELITAKEOFF, TAXIWAY_BUSY_block, 10 }, { 1, 0, 0, 0 },
{ 2, 255, AIRPORT_ENTRANCE_block, 2 }, { 2, HANGAR, 0, 8 }, { 2, TERM1, 0, 8 }, { 2, TERM2, 0, 8 }, { 2, TERM3, 0, 8 }, { 2, HELIPAD1, 0, 8 }, { 2, HELIPAD2, 0, 8 }, { 2, HELITAKEOFF, 0, 8 }, { 2, 0, 0, 2 },
{ 3, TERM1, TERM1_block, 8 }, { 3, HANGAR, 0, 8 }, { 3, TAKEOFF, 0, 8 }, { 3, 0, 0, 3 },
{ 4, TERM2, TERM2_block, 9 }, { 4, HANGAR, 0, 9 }, { 4, TAKEOFF, 0, 9 }, { 4, 0, 0, 4 },
{ 5, TERM3, TERM3_block, 10 }, { 5, HANGAR, 0, 10 }, { 5, TAKEOFF, 0, 10 }, { 5, 0, 0, 5 },
{ 6, HELIPAD1, HELIPAD1_block, 6 }, { 6, HANGAR, TAXIWAY_BUSY_block, 9 }, { 6, HELITAKEOFF, 0, 35 },
{ 7, HELIPAD2, HELIPAD2_block, 7 }, { 7, HANGAR, TAXIWAY_BUSY_block, 10 }, { 7, HELITAKEOFF, 0, 36 },
{ 8, 255, TAXIWAY_BUSY_block, 8 }, { 8, TAKEOFF, TAXIWAY_BUSY_block, 9 }, { 8, HANGAR, TAXIWAY_BUSY_block, 9 }, { 8, TERM1, TERM1_block, 3 }, { 8, 0, TAXIWAY_BUSY_block, 9 },
{ 9, 255, TAXIWAY_BUSY_block, 9 }, { 9, TAKEOFF, TAXIWAY_BUSY_block, 10 }, { 9, HANGAR, TAXIWAY_BUSY_block, 10 }, { 9, TERM2, TERM2_block, 4 }, { 9, HELIPAD1, HELIPAD1_block, 6 }, { 9, HELITAKEOFF, HELIPAD1_block, 6 }, { 9, TERM1, TAXIWAY_BUSY_block, 8 }, { 9, 0, TAXIWAY_BUSY_block, 10 },
{ 10, 255, TAXIWAY_BUSY_block, 10 }, { 10, TERM3, TERM3_block, 5 }, { 10, HELIPAD1, 0, 9 }, { 10, HELIPAD2, HELIPAD2_block, 7 }, { 10, HELITAKEOFF, HELIPAD2_block, 7 }, { 10, TAKEOFF, TAXIWAY_BUSY_block, 1 }, { 10, HANGAR, TAXIWAY_BUSY_block, 1 }, { 10, 0, TAXIWAY_BUSY_block, 9 },
{ 11, 0, OUT_WAY_block, 12 },
// takeoff
{ 12, TAKEOFF, RUNWAY_IN_OUT_block, 13 },
{ 13, 0, RUNWAY_IN_OUT_block, 14 },
{ 14, STARTTAKEOFF, RUNWAY_IN_OUT_block, 15 },
{ 15, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 16, FLYING, NOTHING_block, 21 }, { 16, LANDING, IN_WAY_block, 17 }, { 16, HELILANDING, 0, 25 },
{ 17, LANDING, RUNWAY_IN_OUT_block, 18 },
{ 18, 0, RUNWAY_IN_OUT_block, 19 },
{ 19, 0, RUNWAY_IN_OUT_block, 20 },
{ 20, ENDLANDING, IN_WAY_block, 2 },
// In Air
{ 21, 0, NOTHING_block, 22 },
{ 22, 0, NOTHING_block, 23 },
{ 23, 0, NOTHING_block, 24 },
{ 24, 0, NOTHING_block, 16 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 25, HELILANDING, PRE_HELIPAD_block, 26 },
{ 26, HELIENDLANDING, PRE_HELIPAD_block, 26 }, { 26, HELIPAD1, 0, 27 }, { 26, HELIPAD2, 0, 28 }, { 26, HANGAR, 0, 33 },
{ 27, 0, NOTHING_block, 29 }, //helipad1 approach
{ 28, 0, NOTHING_block, 30 },
// landing
{ 29, 255, NOTHING_block, 0 }, { 29, HELIPAD1, HELIPAD1_block, 6 },
{ 30, 255, NOTHING_block, 0 }, { 30, HELIPAD2, HELIPAD2_block, 7 },
// Helicopter -- takeoff
{ 31, HELITAKEOFF, NOTHING_block, 0 },
{ 32, HELITAKEOFF, NOTHING_block, 0 },
{ 33, 0, TAXIWAY_BUSY_block, 34 }, // need to go to hangar when waiting in air
{ 34, 0, TAXIWAY_BUSY_block, 1 },
{ 35, 0, HELIPAD1_block, 31 },
{ 36, 0, HELIPAD2_block, 32 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_city[] = { { 5, 0 } };
static const byte _airport_terminal_city[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_city[] = {
{ 0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, 0, 0, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7
{ 2, TERM1, TERM1_block, 7 }, { 2, TAKEOFF, OUT_WAY_block, 7 }, { 2, 0, 0, 7 },
{ 3, TERM2, TERM2_block, 5 }, { 3, TAKEOFF, OUT_WAY_block, 5 }, { 3, 0, 0, 5 },
{ 4, TERM3, TERM3_block, 5 }, { 4, TAKEOFF, OUT_WAY_block, 5 }, { 4, 0, 0, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 },
{ 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, 0, 5 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 },
{ 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, OUT_WAY_block, 8 }, { 7, HELITAKEOFF, 0, 22 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 },
{ 8, 0, OUT_WAY_block, 9 },
{ 9, 0, RUNWAY_IN_OUT_block, 10 },
// takeoff
{ 10, TAKEOFF, RUNWAY_IN_OUT_block, 11 },
{ 11, STARTTAKEOFF, NOTHING_block, 12 },
{ 12, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 13, FLYING, NOTHING_block, 18 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 23 },
{ 14, LANDING, RUNWAY_IN_OUT_block, 15 },
{ 15, 0, RUNWAY_IN_OUT_block, 16 },
{ 16, 0, RUNWAY_IN_OUT_block, 17 },
{ 17, ENDLANDING, IN_WAY_block, 7 },
// In Air
{ 18, 0, NOTHING_block, 19 },
{ 19, 0, NOTHING_block, 20 },
{ 20, 0, NOTHING_block, 21 },
{ 21, 0, NOTHING_block, 13 },
// helicopter
{ 22, HELITAKEOFF, NOTHING_block, 0 },
{ 23, HELILANDING, IN_WAY_block, 24 },
{ 24, HELIENDLANDING, IN_WAY_block, 17 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_metropolitan[] = { { 5, 0 } };
static const byte _airport_terminal_metropolitan[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_metropolitan[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7
{ 2, TERM1, TERM1_block, 7 },
{ 3, TERM2, TERM2_block, 5 },
{ 4, TERM3, TERM3_block, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 },
{ 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, 0, 5 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 },
{ 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, 0, 8 }, { 7, HELITAKEOFF, 0, 23 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 },
{ 8, 0, OUT_WAY_block, 9 },
{ 9, 0, RUNWAY_OUT_block, 10 },
// takeoff
{ 10, TAKEOFF, RUNWAY_OUT_block, 11 },
{ 11, STARTTAKEOFF, NOTHING_block, 12 },
{ 12, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 13, FLYING, NOTHING_block, 19 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 25 },
{ 14, LANDING, RUNWAY_IN_block, 15 },
{ 15, 0, RUNWAY_IN_block, 16 },
{ 16, 255, RUNWAY_IN_block, 0 }, { 16, ENDLANDING, IN_WAY_block, 17 },
{ 17, 255, RUNWAY_OUT_block, 0 }, { 17, ENDLANDING, IN_WAY_block, 18 },
{ 18, ENDLANDING, IN_WAY_block, 7 },
// In Air
{ 19, 0, NOTHING_block, 20 },
{ 20, 0, NOTHING_block, 21 },
{ 21, 0, NOTHING_block, 22 },
{ 22, 0, NOTHING_block, 13 },
// helicopter
{ 23, 0, NOTHING_block, 24 },
{ 24, HELITAKEOFF, NOTHING_block, 0 },
{ 25, HELILANDING, IN_WAY_block, 26 },
{ 26, HELIENDLANDING, IN_WAY_block, 18 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_international[] = { { 0, 3 }, { 6, 1 } };
static const byte _airport_terminal_international[] = { 2, 3, 3 };
static const byte _airport_helipad_international[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_international[] = {
{ 0, HANGAR, NOTHING_block, 2 }, { 0, 255, TERM_GROUP1_block, 0 }, { 0, 255, TERM_GROUP2_ENTER1_block, 1 }, { 0, HELITAKEOFF, HELIPAD1_block, 2 }, { 0, 0, 0, 2 },
{ 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, HELITAKEOFF, HELIPAD2_block, 3 }, { 1, 0, 0, 3 },
{ 2, 255, AIRPORT_ENTRANCE_block, 0 }, { 2, HANGAR, 0, 0 }, { 2, TERM4, 0, 12 }, { 2, TERM5, 0, 12 }, { 2, TERM6, 0, 12 }, { 2, HELIPAD1, 0, 12 }, { 2, HELIPAD2, 0, 12 }, { 2, HELITAKEOFF, 0, 12 }, { 2, 0, 0, 23 },
{ 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, 0, 0, 18 },
{ 4, TERM1, TERM1_block, 23 }, { 4, HANGAR, AIRPORT_ENTRANCE_block, 23 }, { 4, 0, 0, 23 },
{ 5, TERM2, TERM2_block, 24 }, { 5, HANGAR, AIRPORT_ENTRANCE_block, 24 }, { 5, 0, 0, 24 },
{ 6, TERM3, TERM3_block, 25 }, { 6, HANGAR, AIRPORT_ENTRANCE_block, 25 }, { 6, 0, 0, 25 },
{ 7, TERM4, TERM4_block, 16 }, { 7, HANGAR, HANGAR2_AREA_block, 16 }, { 7, 0, 0, 16 },
{ 8, TERM5, TERM5_block, 17 }, { 8, HANGAR, HANGAR2_AREA_block, 17 }, { 8, 0, 0, 17 },
{ 9, TERM6, TERM6_block, 18 }, { 9, HANGAR, HANGAR2_AREA_block, 18 }, { 9, 0, 0, 18 },
{ 10, HELIPAD1, HELIPAD1_block, 10 }, { 10, HANGAR, HANGAR2_AREA_block, 16 }, { 10, HELITAKEOFF, 0, 47 },
{ 11, HELIPAD2, HELIPAD2_block, 11 }, { 11, HANGAR, HANGAR2_AREA_block, 17 }, { 11, HELITAKEOFF, 0, 48 },
{ 12, 0, TERM_GROUP2_ENTER1_block, 13 },
{ 13, 0, TERM_GROUP2_ENTER1_block, 14 },
{ 14, 0, TERM_GROUP2_ENTER2_block, 15 },
{ 15, 0, TERM_GROUP2_ENTER2_block, 16 },
{ 16, 255, TERM_GROUP2_block, 0 }, { 16, TERM4, TERM4_block, 7 }, { 16, HELIPAD1, HELIPAD1_block, 10 }, { 16, HELITAKEOFF, HELIPAD1_block, 10 }, { 16, 0, 0, 17 },
{ 17, 255, TERM_GROUP2_block, 0 }, { 17, TERM5, TERM5_block, 8 }, { 17, TERM4, 0, 16 }, { 17, HELIPAD1, 0, 16 }, { 17, HELIPAD2, HELIPAD2_block, 11 }, { 17, HELITAKEOFF, HELIPAD2_block, 11 }, { 17, 0, 0, 18 },
{ 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM6, TERM6_block, 9 }, { 18, TAKEOFF, 0, 19 }, { 18, HANGAR, HANGAR2_AREA_block, 3 }, { 18, 0, 0, 17 },
{ 19, 0, TERM_GROUP2_EXIT1_block, 20 },
{ 20, 0, TERM_GROUP2_EXIT1_block, 21 },
{ 21, 0, TERM_GROUP2_EXIT2_block, 22 },
{ 22, 0, TERM_GROUP2_EXIT2_block, 26 },
{ 23, 255, TERM_GROUP1_block, 0 }, { 23, TERM1, TERM1_block, 4 }, { 23, HANGAR, AIRPORT_ENTRANCE_block, 2 }, { 23, 0, 0, 24 },
{ 24, 255, TERM_GROUP1_block, 0 }, { 24, TERM2, TERM2_block, 5 }, { 24, TERM1, 0, 23 }, { 24, HANGAR, 0, 23 }, { 24, 0, 0, 25 },
{ 25, 255, TERM_GROUP1_block, 0 }, { 25, TERM3, TERM3_block, 6 }, { 25, TAKEOFF, 0, 26 }, { 25, 0, 0, 24 },
{ 26, 255, TAXIWAY_BUSY_block, 0 }, { 26, TAKEOFF, 0, 27 }, { 26, 0, 0, 25 },
{ 27, 0, OUT_WAY_block, 28 },
// takeoff
{ 28, TAKEOFF, OUT_WAY_block, 29 },
{ 29, 0, RUNWAY_OUT_block, 30 },
{ 30, STARTTAKEOFF, NOTHING_block, 31 },
{ 31, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 32, FLYING, NOTHING_block, 37 }, { 32, LANDING, 0, 33 }, { 32, HELILANDING, 0, 41 },
{ 33, LANDING, RUNWAY_IN_block, 34 },
{ 34, 0, RUNWAY_IN_block, 35 },
{ 35, 0, RUNWAY_IN_block, 36 },
{ 36, ENDLANDING, IN_WAY_block, 36 }, { 36, 255, TERM_GROUP1_block, 0 }, { 36, 255, TERM_GROUP2_ENTER1_block, 1 }, { 36, TERM4, 0, 12 }, { 36, TERM5, 0, 12 }, { 36, TERM6, 0, 12 }, { 36, 0, 0, 2 },
// In Air
{ 37, 0, NOTHING_block, 38 },
{ 38, 0, NOTHING_block, 39 },
{ 39, 0, NOTHING_block, 40 },
{ 40, 0, NOTHING_block, 32 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 41, HELILANDING, PRE_HELIPAD_block, 42 },
{ 42, HELIENDLANDING, PRE_HELIPAD_block, 42 }, { 42, HELIPAD1, 0, 43 }, { 42, HELIPAD2, 0, 44 }, { 42, HANGAR, 0, 49 },
{ 43, 0, NOTHING_block, 45 },
{ 44, 0, NOTHING_block, 46 },
// landing
{ 45, 255, NOTHING_block, 0 }, { 45, HELIPAD1, HELIPAD1_block, 10 },
{ 46, 255, NOTHING_block, 0 }, { 46, HELIPAD2, HELIPAD2_block, 11 },
// Helicopter -- takeoff
{ 47, HELITAKEOFF, NOTHING_block, 0 },
{ 48, HELITAKEOFF, NOTHING_block, 0 },
{ 49, 0, HANGAR2_AREA_block, 50 }, // need to go to hangar when waiting in air
{ 50, 0, HANGAR2_AREA_block, 3 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// intercontinental
static const TileIndexDiffC _airport_depots_intercontinental[] = { { 0, 5 }, { 8, 4 } };
static const byte _airport_terminal_intercontinental[] = { 2, 4, 4 };
static const byte _airport_helipad_intercontinental[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_intercontinental[] = {
{ 0, HANGAR, NOTHING_block, 2 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 0 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 1 }, { 0, TAKEOFF, HANGAR1_AREA_block | TERM_GROUP1_block, 2 }, { 0, 0, 0, 2 },
{ 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, 0, 0, 3 },
{ 2, 255, HANGAR1_AREA_block, 0 }, { 2, 255, TERM_GROUP1_block, 0 }, { 2, 255, TERM_GROUP1_block, 1 }, { 2, HANGAR, 0, 0 }, { 2, TAKEOFF, TERM_GROUP1_block, 27 }, { 2, TERM5, 0, 26 }, { 2, TERM6, 0, 26 }, { 2, TERM7, 0, 26 }, { 2, TERM8, 0, 26 }, { 2, HELIPAD1, 0, 26 }, { 2, HELIPAD2, 0, 26 }, { 2, HELITAKEOFF, 0, 74 }, { 2, 0, 0, 27 },
{ 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 75 }, { 3, 0, 0, 20 },
{ 4, TERM1, TERM1_block, 26 }, { 4, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 26 }, { 4, 0, 0, 26 },
{ 5, TERM2, TERM2_block, 27 }, { 5, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 27 }, { 5, 0, 0, 27 },
{ 6, TERM3, TERM3_block, 28 }, { 6, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 28 }, { 6, 0, 0, 28 },
{ 7, TERM4, TERM4_block, 29 }, { 7, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 7, 0, 0, 29 },
{ 8, TERM5, TERM5_block, 18 }, { 8, HANGAR, HANGAR2_AREA_block, 18 }, { 8, 0, 0, 18 },
{ 9, TERM6, TERM6_block, 19 }, { 9, HANGAR, HANGAR2_AREA_block, 19 }, { 9, 0, 0, 19 },
{ 10, TERM7, TERM7_block, 20 }, { 10, HANGAR, HANGAR2_AREA_block, 20 }, { 10, 0, 0, 20 },
{ 11, TERM8, TERM8_block, 21 }, { 11, HANGAR, HANGAR2_AREA_block, 21 }, { 11, 0, 0, 21 },
{ 12, HELIPAD1, HELIPAD1_block, 12 }, { 12, HANGAR, 0, 70 }, { 12, HELITAKEOFF, 0, 72 },
{ 13, HELIPAD2, HELIPAD2_block, 13 }, { 13, HANGAR, 0, 71 }, { 13, HELITAKEOFF, 0, 73 },
{ 14, 0, TERM_GROUP2_ENTER1_block, 15 },
{ 15, 0, TERM_GROUP2_ENTER1_block, 16 },
{ 16, 0, TERM_GROUP2_ENTER2_block, 17 },
{ 17, 0, TERM_GROUP2_ENTER2_block, 18 },
{ 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM5, TERM5_block, 8 }, { 18, TAKEOFF, 0, 19 }, { 18, HELITAKEOFF, HELIPAD1_block, 19 }, { 18, 0, TERM_GROUP2_EXIT1_block, 19 },
{ 19, 255, TERM_GROUP2_block, 0 }, { 19, TERM6, TERM6_block, 9 }, { 19, TERM5, 0, 18 }, { 19, TAKEOFF, 0, 57 }, { 19, HELITAKEOFF, HELIPAD1_block, 20 }, { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, // add exit to runway out 2
{ 20, 255, TERM_GROUP2_block, 0 }, { 20, TERM7, TERM7_block, 10 }, { 20, TERM5, 0, 19 }, { 20, TERM6, 0, 19 }, { 20, HANGAR, HANGAR2_AREA_block, 3 }, { 20, TAKEOFF, 0, 19 }, { 20, 0, TERM_GROUP2_EXIT1_block, 21 },
{ 21, 255, TERM_GROUP2_block, 0 }, { 21, TERM8, TERM8_block, 11 }, { 21, HANGAR, HANGAR2_AREA_block, 20 }, { 21, TERM5, 0, 20 }, { 21, TERM6, 0, 20 }, { 21, TERM7, 0, 20 }, { 21, TAKEOFF, 0, 20 }, { 21, 0, TERM_GROUP2_EXIT1_block, 22 },
{ 22, 255, TERM_GROUP2_block, 0 }, { 22, HANGAR, 0, 21 }, { 22, TERM5, 0, 21 }, { 22, TERM6, 0, 21 }, { 22, TERM7, 0, 21 }, { 22, TERM8, 0, 21 }, { 22, TAKEOFF, 0, 21 }, { 22, 0, 0, 23 },
{ 23, 0, TERM_GROUP2_EXIT1_block, 70 },
{ 24, 0, TERM_GROUP2_EXIT2_block, 25 },
{ 25, 255, TERM_GROUP2_EXIT2_block, 0 }, { 25, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 25, 0, 0, 29 },
{ 26, 255, TERM_GROUP1_block, 0 }, { 26, TERM1, TERM1_block, 4 }, { 26, HANGAR, HANGAR1_AREA_block, 27 }, { 26, TERM5, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM6, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM7, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM8, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD1, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD2, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELITAKEOFF, TERM_GROUP2_ENTER1_block, 14 }, { 26, 0, 0, 27 },
{ 27, 255, TERM_GROUP1_block, 0 }, { 27, TERM2, TERM2_block, 5 }, { 27, HANGAR, HANGAR1_AREA_block, 2 }, { 27, TERM1, 0, 26 }, { 27, TERM5, 0, 26 }, { 27, TERM6, 0, 26 }, { 27, TERM7, 0, 26 }, { 27, TERM8, 0, 26 }, { 27, HELIPAD1, 0, 14 }, { 27, HELIPAD2, 0, 14 }, { 27, 0, 0, 28 },
{ 28, 255, TERM_GROUP1_block, 0 }, { 28, TERM3, TERM3_block, 6 }, { 28, HANGAR, HANGAR1_AREA_block, 27 }, { 28, TERM1, 0, 27 }, { 28, TERM2, 0, 27 }, { 28, TERM4, 0, 29 }, { 28, TERM5, 0, 14 }, { 28, TERM6, 0, 14 }, { 28, TERM7, 0, 14 }, { 28, TERM8, 0, 14 }, { 28, HELIPAD1, 0, 14 }, { 28, HELIPAD2, 0, 14 }, { 28, 0, 0, 29 },
{ 29, 255, TERM_GROUP1_block, 0 }, { 29, TERM4, TERM4_block, 7 }, { 29, HANGAR, HANGAR1_AREA_block, 27 }, { 29, TAKEOFF, 0, 30 }, { 29, 0, 0, 28 },
{ 30, 0, OUT_WAY_block2, 31 },
{ 31, 0, OUT_WAY_block, 32 },
// takeoff
{ 32, TAKEOFF, RUNWAY_OUT_block, 33 },
{ 33, 0, RUNWAY_OUT_block, 34 },
{ 34, STARTTAKEOFF, NOTHING_block, 35 },
{ 35, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 36, 0, 0, 0 },
{ 37, LANDING, RUNWAY_IN_block, 38 },
{ 38, 0, RUNWAY_IN_block, 39 },
{ 39, 0, RUNWAY_IN_block, 40 },
{ 40, ENDLANDING, RUNWAY_IN_block, 41 },
{ 41, 0, IN_WAY_block, 42 },
{ 42, 255, IN_WAY_block, 0 }, { 42, 255, TERM_GROUP1_block, 0 }, { 42, 255, TERM_GROUP1_block, 1 }, { 42, HANGAR, 0, 2 }, { 42, 0, 0, 26 },
// In Air
{ 43, 0, 0, 44 },
{ 44, FLYING, 0, 45 }, { 44, HELILANDING, 0, 47 }, { 44, LANDING, 0, 69 }, { 44, 0, 0, 45 },
{ 45, 0, 0, 46 },
{ 46, FLYING, 0, 43 }, { 46, LANDING, 0, 76 }, { 46, 0, 0, 43 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 47, HELILANDING, PRE_HELIPAD_block, 48 },
{ 48, HELIENDLANDING, PRE_HELIPAD_block, 48 }, { 48, HELIPAD1, 0, 49 }, { 48, HELIPAD2, 0, 50 }, { 48, HANGAR, 0, 55 },
{ 49, 0, NOTHING_block, 51 },
{ 50, 0, NOTHING_block, 52 },
// landing
{ 51, 255, NOTHING_block, 0 }, { 51, HELIPAD1, HELIPAD1_block, 12 }, { 51, HANGAR, 0, 55 }, { 51, 0, 0, 12 },
{ 52, 255, NOTHING_block, 0 }, { 52, HELIPAD2, HELIPAD2_block, 13 }, { 52, HANGAR, 0, 55 }, { 52, 0, 0, 13 },
// Helicopter -- takeoff
{ 53, HELITAKEOFF, NOTHING_block, 0 },
{ 54, HELITAKEOFF, NOTHING_block, 0 },
{ 55, 0, HANGAR2_AREA_block, 56 }, // need to go to hangar when waiting in air
{ 56, 0, HANGAR2_AREA_block, 3 },
// runway 2 out support
{ 57, 255, OUT_WAY2_block, 0 }, { 57, TAKEOFF, 0, 58 }, { 57, 0, 0, 58 },
{ 58, 0, OUT_WAY2_block, 59 },
{ 59, TAKEOFF, RUNWAY_OUT2_block, 60 }, // takeoff
{ 60, 0, RUNWAY_OUT2_block, 61 },
{ 61, STARTTAKEOFF, NOTHING_block, 62 },
{ 62, ENDTAKEOFF, NOTHING_block, 0 },
// runway 2 in support
{ 63, LANDING, RUNWAY_IN2_block, 64 },
{ 64, 0, RUNWAY_IN2_block, 65 },
{ 65, 0, RUNWAY_IN2_block, 66 },
{ 66, ENDLANDING, RUNWAY_IN2_block, 0 }, { 66, 255, 0, 1 }, { 66, 255, 0, 0 }, { 66, 0, 0, 67 },
{ 67, 0, IN_WAY2_block, 68 },
{ 68, 255, IN_WAY2_block, 0 }, { 68, 255, TERM_GROUP2_block, 1 }, { 68, 255, TERM_GROUP1_block, 0 }, { 68, HANGAR, HANGAR2_AREA_block, 22 }, { 68, 0, 0, 22 },
{ 69, 255, RUNWAY_IN2_block, 0 }, { 69, 0, RUNWAY_IN2_block, 63 },
{ 70, 255, TERM_GROUP2_EXIT1_block, 0 }, { 70, HELIPAD1, HELIPAD1_block, 12 }, { 70, HELITAKEOFF, HELIPAD1_block, 12 }, { 70, 0, 0, 71 },
{ 71, 255, TERM_GROUP2_EXIT1_block, 0 }, { 71, HELIPAD2, HELIPAD2_block, 13 }, { 71, HELITAKEOFF, HELIPAD1_block, 12 }, { 71, 0, 0, 24 },
{ 72, 0, HELIPAD1_block, 53 },
{ 73, 0, HELIPAD2_block, 54 },
{ 74, HELITAKEOFF, NOTHING_block, 0 },
{ 75, HELITAKEOFF, NOTHING_block, 0 },
{ 76, 255, RUNWAY_IN_block, 0 }, { 76, 0, RUNWAY_IN_block, 37 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// heliports, oilrigs don't have depots
static const byte _airport_helipad_heliport_oilrig[] = { 1, 1 };
static const AirportFTAbuildup _airport_fta_heliport_oilrig[] = {
{ 0, HELIPAD1, HELIPAD1_block, 1 },
{ 1, HELITAKEOFF, NOTHING_block, 0 }, // takeoff
{ 2, 255, AIRPORT_BUSY_block, 0 }, { 2, HELILANDING, 0, 3 }, { 2, HELITAKEOFF, 0, 1 },
{ 3, HELILANDING, AIRPORT_BUSY_block, 4 },
{ 4, HELIENDLANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIPAD1, HELIPAD1_block, 0 }, { 4, HELITAKEOFF, 0, 2 },
// In Air
{ 5, 0, NOTHING_block, 6 },
{ 6, 0, NOTHING_block, 7 },
{ 7, 0, NOTHING_block, 8 },
{ 8, FLYING, NOTHING_block, 5 }, { 8, HELILANDING, HELIPAD1_block, 2 }, // landing
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// helidepots
static const TileIndexDiffC _airport_depots_helidepot[] = { { 1, 0 } };
static const byte _airport_helipad_helidepot[] = { 1, 1 };
static const AirportFTAbuildup _airport_fta_helidepot[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELIPAD1, HELIPAD1_block, 14 }, { 1, HELITAKEOFF, 0, 15 }, { 1, 0, 0, 0 },
{ 2, FLYING, NOTHING_block, 3 }, { 2, HELILANDING, PRE_HELIPAD_block, 7 }, { 2, HANGAR, 0, 12 }, { 2, HELITAKEOFF, NOTHING_block, 16 },
// In Air
{ 3, 0, NOTHING_block, 4 },
{ 4, 0, NOTHING_block, 5 },
{ 5, 0, NOTHING_block, 6 },
{ 6, 0, NOTHING_block, 2 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 7, HELILANDING, PRE_HELIPAD_block, 8 },
{ 8, HELIENDLANDING, PRE_HELIPAD_block, 8 }, { 8, HELIPAD1, 0, 9 }, { 8, HANGAR, 0, 12 }, { 8, 0, 0, 2 },
{ 9, 0, NOTHING_block, 10 },
// landing
{ 10, 255, NOTHING_block, 10 }, { 10, HELIPAD1, HELIPAD1_block, 14 }, { 10, HANGAR, 0, 1 }, { 10, 0, 0, 14 },
// Helicopter -- takeoff
{ 11, HELITAKEOFF, NOTHING_block, 0 },
{ 12, 0, HANGAR2_AREA_block, 13 }, // need to go to hangar when waiting in air
{ 13, 0, HANGAR2_AREA_block, 1 },
{ 14, HELIPAD1, HELIPAD1_block, 14 }, { 14, HANGAR, 0, 1 }, { 14, HELITAKEOFF, 0, 17 },
{ 15, HELITAKEOFF, NOTHING_block, 0 }, // takeoff outside depot
{ 16, HELITAKEOFF, 0, 14 },
{ 17, 0, NOTHING_block, 11 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// helistation
static const TileIndexDiffC _airport_depots_helistation[] = { { 0, 0 } };
static const byte _airport_helipad_helistation[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_helistation[] = {
{ 0, HANGAR, NOTHING_block, 8 }, { 0, HELIPAD1, 0, 1 }, { 0, HELIPAD2, 0, 1 }, { 0, HELIPAD3, 0, 1 }, { 0, HELITAKEOFF, 0, 1 }, { 0, 0, 0, 0 },
{ 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELITAKEOFF, 0, 3 }, { 1, 0, 0, 4 },
// landing
{ 2, FLYING, NOTHING_block, 28 }, { 2, HELILANDING, 0, 15 }, { 2, 0, 0, 28 },
// helicopter side
{ 3, HELITAKEOFF, NOTHING_block, 0 }, // helitakeoff outside hangar2
{ 4, 255, TAXIWAY_BUSY_block, 0 }, { 4, HANGAR, HANGAR2_AREA_block, 1 }, { 4, HELITAKEOFF, 0, 1 }, { 4, 0, 0, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, HELIPAD1, HELIPAD1_block, 6 }, { 5, HELIPAD2, HELIPAD2_block, 7 }, { 5, HELIPAD3, HELIPAD3_block, 8 }, { 5, 0, 0, 4 },
{ 6, HELIPAD1, HELIPAD1_block, 5 }, { 6, HANGAR, HANGAR2_AREA_block, 5 }, { 6, HELITAKEOFF, 0, 9 }, { 6, 0, 0, 6 },
{ 7, HELIPAD2, HELIPAD2_block, 5 }, { 7, HANGAR, HANGAR2_AREA_block, 5 }, { 7, HELITAKEOFF, 0, 10 }, { 7, 0, 0, 7 },
{ 8, HELIPAD3, HELIPAD3_block, 5 }, { 8, HANGAR, HANGAR2_AREA_block, 5 }, { 8, HELITAKEOFF, 0, 11 }, { 8, 0, 0, 8 },
{ 9, 0, HELIPAD1_block, 12 },
{ 10, 0, HELIPAD2_block, 13 },
{ 11, 0, HELIPAD3_block, 14 },
{ 12, HELITAKEOFF, NOTHING_block, 0 },
{ 13, HELITAKEOFF, NOTHING_block, 0 },
{ 14, HELITAKEOFF, NOTHING_block, 0 },
// heli - in flight moves
{ 15, HELILANDING, PRE_HELIPAD_block, 16 },
{ 16, HELIENDLANDING, PRE_HELIPAD_block, 16 }, { 16, HELIPAD1, 0, 17 }, { 16, HELIPAD2, 0, 18 }, { 16, HELIPAD3, 0, 19 }, { 16, HANGAR, 0, 23 },
{ 17, 0, NOTHING_block, 20 },
{ 18, 0, NOTHING_block, 21 },
{ 19, 0, NOTHING_block, 22 },
// heli landing
{ 20, 255, NOTHING_block, 0 }, { 20, HELIPAD1, HELIPAD1_block, 6 }, { 20, HANGAR, 0, 23 }, { 20, 0, 0, 6 },
{ 21, 255, NOTHING_block, 0 }, { 21, HELIPAD2, HELIPAD2_block, 7 }, { 21, HANGAR, 0, 23 }, { 21, 0, 0, 7 },
{ 22, 255, NOTHING_block, 0 }, { 22, HELIPAD3, HELIPAD3_block, 8 }, { 22, HANGAR, 0, 23 }, { 22, 0, 0, 8 },
{ 23, 0, HANGAR2_AREA_block, 24 }, // need to go to helihangar when waiting in air
{ 24, 0, HANGAR2_AREA_block, 1 },
{ 25, 0, NOTHING_block, 26 },
{ 26, 0, NOTHING_block, 27 },
{ 27, 0, NOTHING_block, 2 },
{ 28, 0, NOTHING_block, 29 },
{ 29, 0, NOTHING_block, 30 },
{ 30, 0, NOTHING_block, 31 },
{ 31, 0, NOTHING_block, 32 },
{ 32, 0, NOTHING_block, 25 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const AirportMovingData * const _airport_moving_datas[] = {
_airport_moving_data_country, // Country Airfield (small) 4x3
_airport_moving_data_town, // City Airport (large) 6x6
_airport_moving_data_heliport, // Heliport
_airport_moving_data_metropolitan, // Metropolitain Airport (large) - 2 runways
_airport_moving_data_international, // International Airport (xlarge) - 2 runways
_airport_moving_data_commuter, // Commuter Airfield (small) 5x4
_airport_moving_data_helidepot, // Helidepot
_airport_moving_data_intercontinental, // Intercontinental Airport (xxlarge) - 4 runways
_airport_moving_data_helistation, // Helistation
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_airport_moving_data_oilrig // Oilrig
};
#endif /* AIRPORT_MOVEMENT_H */

View File

@@ -1,7 +1,5 @@
/* $Id$ */
/** @file aystar.cpp Implementation of A*. */
/*
* This file has the core function for AyStar
* AyStar is a fast pathfinding routine and is used for things like
@@ -19,42 +17,42 @@
*/
#include "stdafx.h"
#include "openttd.h"
#include "aystar.h"
#include "core/alloc_func.hpp"
int _aystar_stats_open_size;
int _aystar_stats_closed_size;
/* This looks in the Hash if a node exists in ClosedList
* If so, it returns the PathNode, else NULL */
static PathNode *AyStarMain_ClosedList_IsInList(AyStar *aystar, const AyStarNode *node)
// This looks in the Hash if a node exists in ClosedList
// If so, it returns the PathNode, else NULL
static PathNode* AyStarMain_ClosedList_IsInList(AyStar *aystar, const AyStarNode *node)
{
return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
}
/* This adds a node to the ClosedList
* It makes a copy of the data */
// This adds a node to the ClosedList
// It makes a copy of the data
static void AyStarMain_ClosedList_Add(AyStar *aystar, const PathNode *node)
{
/* Add a node to the ClosedList */
PathNode *new_node = MallocT<PathNode>(1);
// Add a node to the ClosedList
PathNode *new_node = malloc(sizeof(*new_node));
*new_node = *node;
Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
}
/* Checks if a node is in the OpenList
* If so, it returns the OpenListNode, else NULL */
// Checks if a node is in the OpenList
// If so, it returns the OpenListNode, else NULL
static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNode *node)
{
return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
}
/* Gets the best node from OpenList
* returns the best node, or NULL of none is found
* Also it deletes the node from the OpenList */
// Gets the best node from OpenList
// returns the best node, or NULL of none is found
// Also it deletes the node from the OpenList
static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
{
/* Return the item the Queue returns.. the best next OpenList item. */
// Return the item the Queue returns.. the best next OpenList item.
OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
if (res != NULL) {
Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
@@ -63,18 +61,18 @@ static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
return res;
}
/* Adds a node to the OpenList
* It makes a copy of node, and puts the pointer of parent in the struct */
// Adds a node to the OpenList
// It makes a copy of node, and puts the pointer of parent in the struct
static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, const AyStarNode *node, int f, int g)
{
/* Add a new Node to the OpenList */
OpenListNode *new_node = MallocT<OpenListNode>(1);
// Add a new Node to the OpenList
OpenListNode *new_node = malloc(sizeof(*new_node));
new_node->g = g;
new_node->path.parent = parent;
new_node->path.node = *node;
Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
/* Add it to the queue */
// Add it to the queue
aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
}
@@ -89,49 +87,49 @@ int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *pare
PathNode *closedlist_parent;
OpenListNode *check;
/* Check the new node against the ClosedList */
// Check the new node against the ClosedList
if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
/* Calculate the G-value for this node */
// Calculate the G-value for this node
new_g = aystar->CalculateG(aystar, current, parent);
/* If the value was INVALID_NODE, we don't do anything with this node */
// If the value was INVALID_NODE, we don't do anything with this node
if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
/* There should not be given any other error-code.. */
// There should not be given any other error-code..
assert(new_g >= 0);
/* Add the parent g-value to the new g-value */
// Add the parent g-value to the new g-value
new_g += parent->g;
if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
/* Calculate the h-value */
// Calculate the h-value
new_h = aystar->CalculateH(aystar, current, parent);
/* There should not be given any error-code.. */
// There should not be given any error-code..
assert(new_h >= 0);
/* The f-value if g + h */
// The f-value if g + h
new_f = new_g + new_h;
/* Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList) */
// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
/* Check if this item is already in the OpenList */
// Check if this item is already in the OpenList
check = AyStarMain_OpenList_IsInList(aystar, current);
if (check != NULL) {
uint i;
/* Yes, check if this g value is lower.. */
// Yes, check if this g value is lower..
if (new_g > check->g) return AYSTAR_DONE;
aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
/* It is lower, so change it to this item */
// It is lower, so change it to this item
check->g = new_g;
check->path.parent = closedlist_parent;
/* Copy user data, will probably have changed */
for (i = 0; i < lengthof(current->user_data); i++) {
check->path.node.user_data[i] = current->user_data[i];
}
/* Readd him in the OpenListQueue */
// Readd him in the OpenListQueue
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
} 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);
}
@@ -153,12 +151,12 @@ int AyStarMain_Loop(AyStar *aystar)
{
int i, r;
/* Get the best node from OpenList */
// Get the best node from OpenList
OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
/* If empty, drop an error */
// If empty, drop an error
if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
/* Check for end node and if found, return that code */
// Check for end node and if found, return that code
if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
if (aystar->FoundEndNode != NULL)
aystar->FoundEndNode(aystar, current);
@@ -166,26 +164,26 @@ int AyStarMain_Loop(AyStar *aystar)
return AYSTAR_FOUND_END_NODE;
}
/* Add the node to the ClosedList */
// Add the node to the ClosedList
AyStarMain_ClosedList_Add(aystar, &current->path);
/* Load the neighbours */
// Load the neighbours
aystar->GetNeighbours(aystar, current);
/* Go through all neighbours */
// Go through all neighbours
for (i = 0; i < aystar->num_neighbours; i++) {
/* Check and add them to the OpenList if needed */
// Check and add them to the OpenList if needed
r = aystar->checktile(aystar, &aystar->neighbours[i], current);
}
/* Free the node */
// Free the node
free(current);
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
/* We've expanded enough nodes */
return AYSTAR_LIMIT_REACHED;
} else {
/* Return that we are still busy */
// Return that we are still busy
return AYSTAR_STILL_BUSY;
}
}
@@ -211,10 +209,10 @@ void AyStarMain_Free(AyStar *aystar)
*/
void AyStarMain_Clear(AyStar *aystar)
{
/* Clean the Queue, but not the elements within. That will be done by
* the hash. */
// Clean the Queue, but not the elements within. That will be done by
// the hash.
aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
/* Clean the hashes */
// Clean the hashes
clear_Hash(&aystar->OpenListHash, true);
clear_Hash(&aystar->ClosedListHash, true);
@@ -235,8 +233,8 @@ void AyStarMain_Clear(AyStar *aystar)
*/
int AyStarMain_Main(AyStar *aystar) {
int r, i = 0;
/* Loop through the OpenList
* Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick */
// Loop through the OpenList
// Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick
while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
#ifdef AYSTAR_DEBUG
switch (r) {
@@ -279,14 +277,14 @@ void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
{
/* Allocated the Hash for the OpenList and ClosedList */
// Allocated the Hash for the OpenList and ClosedList
init_Hash(&aystar->OpenListHash, hash, num_buckets);
init_Hash(&aystar->ClosedListHash, hash, num_buckets);
/* Set up our sorting queue
* BinaryHeap allocates a block of 1024 nodes
* When thatone gets full it reserves an otherone, till this number
* That is why it can stay this high */
// Set up our sorting queue
// BinaryHeap allocates a block of 1024 nodes
// When thatone gets full it reserves an otherone, till this number
// That is why it can stay this high
init_BinaryHeap(&aystar->OpenListQueue, 102400);
aystar->addstart = AyStarMain_AddStartNode;

View File

@@ -1,6 +1,6 @@
/* $Id$ */
/** @file aystar.h
/*
* This file has the header for AyStar
* AyStar is a fast pathfinding routine and is used for things like
* AI_pathfinding and Train_pathfinding.
@@ -12,8 +12,6 @@
#define AYSTAR_H
#include "queue.h"
#include "tile_type.h"
#include "track_type.h"
//#define AYSTAR_DEBUG
enum {
@@ -29,28 +27,31 @@ enum{
AYSTAR_INVALID_NODE = -1,
};
typedef struct AyStarNode AyStarNode;
struct AyStarNode {
TileIndex tile;
Trackdir direction;
uint direction;
uint user_data[2];
};
/* The resulting path has nodes looking like this. */
// The resulting path has nodes looking like this.
typedef struct PathNode PathNode;
struct PathNode {
AyStarNode node;
/* The parent of this item */
// The parent of this item
PathNode *parent;
};
/* For internal use only
* We do not save the h-value, because it is only needed to calculate the f-value.
* h-value should _always_ be the distance left to the end-tile. */
// For internal use only
// We do not save the h-value, because it is only needed to calculate the f-value.
// h-value should _always_ be the distance left to the end-tile.
typedef struct OpenListNode OpenListNode;
struct OpenListNode {
int g;
PathNode path;
};
struct AyStar;
typedef struct AyStar AyStar;
/*
* This function is called to check if the end-tile is found
* return values can be:
@@ -97,7 +98,7 @@ typedef void AyStar_GetNeighbours(AyStar *aystar, OpenListNode *current);
*/
typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current);
/* For internal use, see aystar.cpp */
// For internal use, see aystar.c
typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g);
typedef int AyStar_Main(AyStar *aystar);
typedef int AyStar_Loop(AyStar *aystar);

View File

@@ -1,69 +0,0 @@
#!/bin/sh
# $Id$
if ! [ -f ai/regression/regression.nut ]; then
echo "Make sure you are in the root of OpenTTD before starting this script."
exit 1
fi
cat ai/regression/regression.nut | tr ';' '\n' | awk '
/^function/ {
for (local in locals) {
delete locals[local]
}
if (match($0, "function Regression::Start") || match($0, "function Regression::Stop")) next
locals["this"] = "AIControllerSquirrel"
}
/local/ {
gsub(".*local", "local")
if (match($4, "^AI")) {
sub("\\(.*", "", $4)
locals[$2] = $4
}
}
/Valuate/ {
gsub(".*Valuate\\(", "")
gsub("\\).*", "")
gsub(",.*", "")
gsub("\\.", "::")
print $0
}
/\./ {
for (local in locals) {
if (match($0, local ".")) {
fname = substr($0, index($0, local "."))
sub("\\(.*", "", fname)
sub("\\.", "::", fname)
sub(local, locals[local], fname)
print fname
if (match(locals[local], "List")) {
sub(locals[local], "AIAbstractList", fname)
print fname
}
}
}
# We want to remove everything before the FIRST occurence of AI.
# If we do not remove any other occurences of AI from the string
# we will remove everything before the LAST occurence of AI, so
# do some little magic to make it work the way we want.
sub("AI", "AXXXXY")
gsub("AI", "AXXXXX")
sub(".*AXXXXY", "AI")
if (match($0, "^AI") && match($0, ".")) {
sub("\\(.*", "", $0)
sub("\\.", "::", $0)
print $0
}
}
' | sed 's/ //g' | sort | uniq > tmp.in_regression
grep 'DefSQ.*Method' ../src/ai/api/*.hpp.sq | grep -v 'AIError::' | grep -v 'AIAbstractList::Valuate' | grep -v '::GetClassName' | sed 's/^[^,]*, &//g;s/,[^,]*//g' | sort > tmp.in_api
diff -u tmp.in_regression tmp.in_api | grep -v '^+++' | grep '^+' | sed 's/^+//'
rm -f tmp.in_regression tmp.in_api

View File

@@ -1,17 +0,0 @@
[misc]
display_opt = SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|WAYPOINTS
language = english.lng
[gui]
autosave = off
[game_creation]
town_name = english
[ai_players]
none =
regression =
[vehicle]
road_side = right
plane_speed = 2

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
/* $Id$ */
class Regression extends AIInfo {
function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
function GetName() { return "Regression"; }
function GetShortName() { return "REGR"; }
function GetDescription() { return "This runs regression-tests on all commands. On the same map the result should always be the same."; }
function GetVersion() { return 1; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; }
}
RegisterAI(Regression());

View File

@@ -1,4 +0,0 @@
/* $Id$ */
print(" Required this file");

View File

@@ -1,51 +0,0 @@
#!/bin/sh
# $Id$
if ! [ -f ai/regression/regression.nut ]; then
echo "Make sure you are in the root of OpenTTD before starting this script."
exit 1
fi
cp ai/regression/regression.nut ai/regression/main.nut
cp ai/regression/regression_info.nut ai/regression/info.nut
if [ -f scripts/game_start.scr ]; then
mv scripts/game_start.scr scripts/game_start.scr.regression
fi
params=""
gdb=""
if [ "$1" != "-r" ]; then
params="-snull -mnull -vnull:ticks=30000"
fi
if [ "$1" = "-g" ]; then
gdb="gdb --ex run --args "
fi
if [ -n "$gdb" ]; then
$gdb ./openttd -x -c ai/regression/regression.cfg $params -g ai/regression/regression.sav
else
./openttd -x -c ai/regression/regression.cfg $params -g ai/regression/regression.sav -d ai=2 2>&1 | awk '{ gsub("0x(\\(nil\\)|0+)", "0x00000000", $0); gsub("^dbg: \\[ai\\]", "", $0); gsub("^ ", "ERROR: ", $0); gsub("ERROR: \\[1\\] ", "", $0); gsub("\\[P\\] ", "", $0); print $0; }' > tmp.regression
fi
if [ -z "$gdb" ]; then
res="`diff -ub ai/regression/regression.txt tmp.regression`"
if [ -z "$res" ]; then
echo "Regression test passed!"
else
echo "Regression test failed! Difference:"
echo "$res"
fi
echo ""
echo "Regression test done"
fi
rm -f ai/regression/main.nut ai/regression/info.nut
if [ -f scripts/game_start.scr.regression ]; then
mv scripts/game_start.scr.regression scripts/game_start.scr
fi
if [ "$1" != "-k" ]; then
rm -f tmp.regression
fi

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,31 +0,0 @@
; $Id$
;
; This represents the original graphics as on the non-German Transport
; Tycoon Deluxe DOS CD.
;
[metadata]
name = original_dos
shortname = TTDD
version = 1
description = Original Transport Tycoon Deluxe DOS edition graphics
palette = DOS
[files]
base = TRG1.GRF
logos = TRGI.GRF
arctic = TRGC.GRF
tropical = TRGH.GRF
toyland = TRGT.GRF
extra = OPENTTDD.GRF
[md5s]
TRG1.GRF = 9311676280e5b14077a8ee41c1b42192
TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8
TRGC.GRF = ed446637e034104c5559b32c18afe78d
TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9
TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6
OPENTTDD.GRF = c886c7d5b38a93f2cb1cdc0d33472eb8
[origin]
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
OPENTTDD.GRF = This file was part of your installation.

View File

@@ -1,31 +0,0 @@
; $Id$
;
; This represents the original graphics as on the German Transport
; Tycoon Deluxe DOS CD. It contains one broken sprite.
;
[metadata]
name = original_dos_de
shortname = TTDD
version = 0
description = Original Transport Tycoon Deluxe DOS (German) edition graphics
palette = DOS
[files]
base = TRG1.GRF
logos = TRGI.GRF
arctic = TRGC.GRF
tropical = TRGH.GRF
toyland = TRGT.GRF
extra = OPENTTDD.GRF
[md5s]
TRG1.GRF = 9311676280e5b14077a8ee41c1b42192
TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8
TRGC.GRF = ed446637e034104c5559b32c18afe78d
TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9
TRGT.GRF = fcde1d7e8a74197d72a62695884b909e
OPENTTDD.GRF = c886c7d5b38a93f2cb1cdc0d33472eb8
[origin]
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
OPENTTDD.GRF = This file was part of your installation.

View File

@@ -1,31 +0,0 @@
; $Id$
;
; This represents the original graphics as on the Transport
; Tycoon Deluxe for Windows CD.
;
[metadata]
name = original_windows
shortname = TTDW
version = 0
description = Original Transport Tycoon Deluxe Windows edition graphics
palette = Windows
[files]
base = TRG1R.GRF
logos = TRGIR.GRF
arctic = TRGCR.GRF
tropical = TRGHR.GRF
toyland = TRGTR.GRF
extra = OPENTTDW.GRF
[md5s]
TRG1R.GRF = b04ce593d8c5016e07473a743d7d3358
TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32
TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b
TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1
TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8
OPENTTDW.GRF = b6689105405fa3ea34cb8a5543633d29
[origin]
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
OPENTTDW.GRF = This file was part of your installation.

View File

@@ -1,2 +0,0 @@
start_ai MyAI

View File

@@ -1,2 +0,0 @@
# Show a MOTD
say "Welcome..."

View File

@@ -1,14 +1,12 @@
/* $Id$ */
/** @file bmp.cpp Read and write support for bmps. */
#include "stdafx.h"
#include "openttd.h"
#include "gfx.h"
#include "bmp.h"
#include "core/bitmath_func.hpp"
#include "core/alloc_func.hpp"
#include "macros.h"
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file)
{
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file) {
buffer->pos = -1;
buffer->file = file;
buffer->read = 0;
@@ -322,15 +320,16 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
if (info->bpp <= 8) {
uint i;
/* Reads number of colours if available in info header */
/* Reads number of colors if available in info header */
if (header_size >= 16) {
SkipBytes(buffer, 12); // skip image size and resolution
info->palette_size = ReadDword(buffer); // number of colours in palette
info->palette_size = ReadDword(buffer); // number of colors in palette
SkipBytes(buffer, header_size - 16); // skip the end of info header
}
if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
data->palette = CallocT<Colour>(info->palette_size);
data->palette = calloc(info->palette_size, sizeof(*(data->palette)));
if (data->palette == NULL) return false;
for (i = 0; i < info->palette_size; i++) {
data->palette[i].b = ReadByte(buffer);
@@ -351,7 +350,8 @@ bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
assert(info != NULL && data != NULL);
data->bitmap = CallocT<byte>(info->width * info->height * ((info->bpp == 24) ? 3 : 1));
data->bitmap = calloc(info->width * info->height, ((info->bpp == 24) ? 3 : 1) * sizeof(byte));
if (data->bitmap == NULL) return false;
/* Load image */
SetStreamOffset(buffer, info->offset);

View File

@@ -1,36 +1,32 @@
/* $Id$ */
/** @file bmp.h Read and write support for bmps. */
#ifndef BMP_H
#define BMP_H
#include "gfx_type.h"
struct BmpInfo {
typedef struct {
uint32 offset; ///< offset of bitmap data from .bmp file begining
uint32 width; ///< bitmap width
uint32 height; ///< bitmap height
bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap
uint16 bpp; ///< bits per pixel
uint32 compression; ///< compression method (0 = none, 1 = 8-bit RLE, 2 = 4-bit RLE)
uint32 palette_size; ///< number of colours in palette
};
uint32 palette_size; ///< number of colors in palette
} BmpInfo;
struct BmpData {
typedef struct {
Colour *palette;
byte *bitmap;
};
} BmpData;
#define BMP_BUFFER_SIZE 1024
struct BmpBuffer {
typedef struct {
byte data[BMP_BUFFER_SIZE];
int pos;
int read;
FILE *file;
uint real_pos;
};
} BmpBuffer;
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file);
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data);

31
bridge.h Normal file
View File

@@ -0,0 +1,31 @@
/* $Id$ */
/** @file bridge.h Header file for bridges */
#ifndef BRIDGE_H
#define BRIDGE_H
enum {
MAX_BRIDGES = 13
};
/** Struct containing information about a single bridge type
*/
typedef struct Bridge {
Year 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];
uint GetBridgeFoundation(Slope tileh, Axis axis);
#endif /* BRIDGE_H */

167
bridge_gui.c Normal file
View File

@@ -0,0 +1,167 @@
/* $Id$ */
/** @file bridge_gui.c Graphical user interface for bridge construction*/
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "command.h"
#include "sound.h"
#include "variables.h"
#include "bridge.h"
static struct BridgeData {
uint count;
TileIndex start_tile;
TileIndex end_tile;
byte type;
byte indexes[MAX_BRIDGES];
int32 costs[MAX_BRIDGES];
} _bridgedata;
void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
}
static void BuildBridge(Window *w, int i)
{
DeleteWindow(w);
DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
_bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge,
CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
}
static void BuildBridgeWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
uint i;
DrawWindowWidgets(w);
for (i = 0; i < 4 && i + w->vscroll.pos < _bridgedata.count; i++) {
const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]];
SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
SetDParam(1, b->speed);
SetDParam(0, b->material);
DrawSprite(b->sprite, 3, 15 + i * 22);
DrawString(44, 15 + i * 22 , STR_500D, 0);
}
} break;
case WE_KEYPRESS: {
uint i = e->we.keypress.keycode - '1';
if (i < 9 && i < _bridgedata.count) {
e->we.keypress.cont = false;
BuildBridge(w, i);
}
break;
}
case WE_CLICK:
if (e->we.click.widget == 2) {
uint ind = ((int)e->we.click.pt.y - 14) / 22;
if (ind < 4 && (ind += w->vscroll.pos) < _bridgedata.count)
BuildBridge(w, ind);
}
break;
}
}
static const Widget _build_bridge_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, RESIZE_NONE, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, RESIZE_NONE, 7, 188, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WIDGETS_END},
};
static const WindowDesc _build_bridge_desc = {
WDP_AUTO, WDP_AUTO, 200, 102,
WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_bridge_widgets,
BuildBridgeWndProc
};
static const Widget _build_road_bridge_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, RESIZE_NONE, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, RESIZE_NONE, 7, 188, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WIDGETS_END},
};
static const WindowDesc _build_road_bridge_desc = {
WDP_AUTO, WDP_AUTO, 200, 102,
WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_road_bridge_widgets,
BuildBridgeWndProc
};
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type)
{
uint j = 0;
int32 ret;
StringID errmsg;
DeleteWindowById(WC_BUILD_BRIDGE, 0);
_bridgedata.type = bridge_type;
_bridgedata.start_tile = start;
_bridgedata.end_tile = end;
errmsg = INVALID_STRING_ID;
// only query bridge building possibility once, result is the same for all bridges!
// returns CMD_ERROR on failure, and price on success
ret = DoCommand(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
if (CmdFailed(ret)) {
errmsg = _error_message;
} else {
// check which bridges can be built
int bridge_len; // length of the middle parts of the bridge
int tot_bridgedata_len; // total length of bridge
// get absolute bridge length
bridge_len = GetBridgeLength(start, end);
tot_bridgedata_len = bridge_len + 2;
tot_bridgedata_len = CalcBridgeLenCostFactor(tot_bridgedata_len);
for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
const Bridge *b = &_bridge[bridge_type];
// bridge is accepted, add to list
// 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);
_bridgedata.indexes[j] = bridge_type;
j++;
}
}
}
_bridgedata.count = j;
if (j != 0) {
Window *w = AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc);
w->vscroll.cap = 4;
w->vscroll.count = (byte)j;
} else {
ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
}
}

37
bridge_map.c Normal file
View File

@@ -0,0 +1,37 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "bridge_map.h"
TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
{
TileIndexDiff delta = TileOffsByDiagDir(dir);
assert(DiagDirToAxis(dir) == GetBridgeAxis(tile));
do {
tile += delta;
} while (!IsBridgeRamp(tile));
return tile;
}
TileIndex GetSouthernBridgeEnd(TileIndex t)
{
return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
}
TileIndex GetOtherBridgeEnd(TileIndex tile)
{
TileIndexDiff delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
do {
tile += delta;
} while (!IsBridgeRamp(tile));
return tile;
}

235
bridge_map.h Normal file
View File

@@ -0,0 +1,235 @@
/* $Id$ */
#ifndef BRIDGE_MAP_H
#define BRIDGE_MAP_H
#include "direction.h"
#include "macros.h"
#include "map.h"
#include "rail.h"
#include "road_map.h"
#include "tile.h"
static inline bool IsBridge(TileIndex t)
{
assert(IsTileType(t, MP_TUNNELBRIDGE));
return HASBIT(_m[t].m5, 7);
}
static inline bool IsBridgeTile(TileIndex t)
{
return IsTileType(t, MP_TUNNELBRIDGE) && IsBridge(t);
}
static inline bool IsBridgeRamp(TileIndex t)
{
assert(IsBridgeTile(t));
return !HASBIT(_m[t].m5, 6);
}
static inline bool IsBridgeMiddle(TileIndex t)
{
assert(IsBridgeTile(t));
return HASBIT(_m[t].m5, 6);
}
/**
* Determines which piece of a bridge is contained in the current tile
* @param tile The tile to analyze
* @return the piece
*/
static inline uint GetBridgePiece(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m2, 0, 4);
}
/**
* Determines the type of bridge on a tile
* @param tile The tile to analyze
* @return The bridge type
*/
static inline uint GetBridgeType(TileIndex t)
{
assert(IsBridgeTile(t));
return GB(_m[t].m2, 4, 4);
}
/**
* Get the direction pointing onto the bridge
*/
static inline DiagDirection GetBridgeRampDirection(TileIndex t)
{
assert(IsBridgeRamp(t));
return ReverseDiagDir(XYNSToDiagDir((Axis)GB(_m[t].m5, 0, 1), GB(_m[t].m5, 5, 1)));
}
static inline Axis GetBridgeAxis(TileIndex t)
{
assert(IsBridgeMiddle(t));
return (Axis)GB(_m[t].m5, 0, 1);
}
static inline TransportType GetBridgeTransportType(TileIndex t)
{
assert(IsBridgeTile(t));
return (TransportType)GB(_m[t].m5, 1, 2);
}
static inline bool IsClearUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 0;
}
static inline bool IsWaterUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 1;
}
static inline bool IsTransportUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return HASBIT(_m[t].m5, 5);
}
static inline TransportType GetTransportTypeUnderBridge(TileIndex t)
{
assert(IsTransportUnderBridge(t));
return (TransportType)GB(_m[t].m5, 3, 2);
}
static inline RoadBits GetRoadBitsUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_ROAD);
return GetBridgeAxis(t) == AXIS_X ? ROAD_Y : ROAD_X;
}
static inline Track GetRailUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL);
return AxisToTrack(OtherAxis(GetBridgeAxis(t)));
}
static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
{
return TrackToTrackBits(GetRailUnderBridge(t));
}
/**
* Finds the end of a bridge in the specified direction starting at a middle tile
*/
TileIndex GetBridgeEnd(TileIndex, DiagDirection);
/**
* Finds the southern end of a bridge starting at a middle tile
*/
TileIndex GetSouthernBridgeEnd(TileIndex t);
/**
* Starting at one bridge end finds the other bridge end
*/
TileIndex GetOtherBridgeEnd(TileIndex);
uint GetBridgeHeight(TileIndex t);
static inline void SetClearUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, OWNER_NONE);
SB(_m[t].m5, 3, 3, 0 << 2 | 0);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetWaterUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, OWNER_WATER);
SB(_m[t].m5, 3, 3, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetCanalUnderBridge(TileIndex t, Owner o)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetRailUnderBridge(TileIndex t, Owner o, RailType r)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_RAIL);
SB(_m[t].m3, 0, 4, r);
}
static inline void SetRoadUnderBridge(TileIndex t, Owner o)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_ROAD);
SB(_m[t].m3, 0, 4, 0);
}
static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt)
{
uint northsouth = (d == DIAGDIR_NE || d == DIAGDIR_NW);
SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, o);
_m[t].m2 = bridgetype << 4;
_m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 0 << 6 | northsouth << 5 | tt << 1 | DiagDirToAxis(d);
}
static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD);
_m[t].m3 = 0;
}
static inline void MakeRailBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, RailType r)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL);
_m[t].m3 = r;
}
static inline void MakeBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, TransportType tt)
{
SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = bridgetype << 4 | piece;
_m[t].m3 = 0;
_m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 1 << 6 | 0 << 5 | 0 << 3 | tt << 1 | a;
}
static inline void MakeRoadBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_ROAD);
}
static inline void MakeRailBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, RailType r)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_RAIL);
SB(_m[t].m3, 4, 4, r);
}
#endif /* BRIDGE_MAP_H */

492
build_vehicle_gui.c Normal file
View File

@@ -0,0 +1,492 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "aircraft.h"
#include "debug.h"
#include "functions.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "window.h"
#include "gui.h"
#include "vehicle.h"
#include "gfx.h"
#include "station.h"
#include "command.h"
#include "engine.h"
#include "player.h"
#include "depot.h"
#include "airport.h"
#include "vehicle_gui.h"
#include "newgrf_engine.h"
#include "date.h"
#include "strings.h"
enum BuildVehicleWidgets {
BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
BUILD_VEHICLE_WIDGET_CAPTION,
BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
BUILD_VEHICLE_WIDGET_SORT_TEXT,
BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
BUILD_VEHICLE_WIDGET_LIST,
BUILD_VEHICLE_WIDGET_SCROLLBAR,
BUILD_VEHICLE_WIDGET_PANEL,
BUILD_VEHICLE_WIDGET_BUILD,
BUILD_VEHICLE_WIDGET_RENAME,
BUILD_VEHICLE_WIDGET_RESIZE,
};
static const Widget _build_vehicle_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 239, 0, 13, STR_A005_NEW_AIRCRAFT, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
{ WWT_PANEL, RESIZE_NONE, 14, 81, 227, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 228, 239, 14, 25, STR_0225, STR_SORT_CRITERIA_TIP},
{ WWT_MATRIX, RESIZE_BOTTOM, 14, 0, 227, 26, 121, 0x401, STR_A025_AIRCRAFT_SELECTION_LIST },
{ WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 228, 239, 26, 121, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST },
{ WWT_PANEL, RESIZE_TB, 14, 0, 239, 122, 213, 0x0, STR_NULL },
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 114, 214, 225, STR_A006_BUILD_AIRCRAFT, STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT },
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 115, 227, 214, 225, STR_A037_RENAME, STR_A038_RENAME_AIRCRAFT_TYPE },
{ WWT_RESIZEBOX, RESIZE_TB, 14, 228, 239, 214, 225, 0x0, STR_RESIZE_BUTTON },
{ WIDGETS_END},
};
static bool _internal_sort_order; // descending/ascending
static byte _last_sort_criteria = 0;
static bool _last_sort_order = false;
static int CDECL EngineNumberSorter(const void *a, const void *b)
{
const EngineID va = *(const EngineID*)a;
const EngineID vb = *(const EngineID*)b;
int r = va - vb;
return _internal_sort_order ? -r : r;
}
static int CDECL EngineIntroDateSorter(const void *a, const void *b)
{
const int va = GetEngine(*(const EngineID*)a)->intro_date;
const int vb = GetEngine(*(const EngineID*)b)->intro_date;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL EngineNameSorter(const void *a, const void *b)
{
static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
static char last_name[2][64] = { "\0", "\0" };
const EngineID va = *(const EngineID*)a;
const EngineID vb = *(const EngineID*)b;
int r;
if (va != last_engine[0]) {
last_engine[0] = va;
GetString(last_name[0], GetCustomEngineName(va), lastof(last_name[0]));
}
if (vb != last_engine[1]) {
last_engine[1] = vb;
GetString(last_name[1], GetCustomEngineName(vb), lastof(last_name[1]));
}
r = strcmp(last_name[0], last_name[1]); // sort by name
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL EngineReliabilitySorter(const void *a, const void *b)
{
const int va = GetEngine(*(const EngineID*)a)->reliability;
const int vb = GetEngine(*(const EngineID*)b)->reliability;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
/* Aircraft sorting functions */
static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost;
const int vb = AircraftVehInfo(*(const EngineID*)b)->base_cost;
int r = va - vb;
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineRunningCostSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->running_cost;
const int vb = AircraftVehInfo(*(const EngineID*)b)->running_cost;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->passenger_capacity;
const int vb = AircraftVehInfo(*(const EngineID*)b)->passenger_capacity;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static EngList_SortTypeFunction * const _aircraft_sorter[] = {
&EngineNumberSorter,
&AircraftEngineCostSorter,
&AircraftEngineSpeedSorter,
&EngineIntroDateSorter,
&EngineNameSorter,
&AircraftEngineRunningCostSorter,
&EngineReliabilitySorter,
&AircraftEngineCargoSorter,
};
static const StringID _aircraft_sort_listing[] = {
STR_ENGINE_SORT_ENGINE_ID,
STR_ENGINE_SORT_COST,
STR_SORT_BY_MAX_SPEED,
STR_ENGINE_SORT_INTRO_DATE,
STR_SORT_BY_DROPDOWN_NAME,
STR_ENGINE_SORT_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_ENGINE_SORT_CARGO_CAPACITY,
INVALID_STRING_ID
};
/**
* Draw the purchase info details of an aircraft at a given location.
* @param x,y location where to draw the info
* @param engine_number the engine of which to draw the info of
*/
void DrawAircraftPurchaseInfo(int x, int y, uint w, EngineID engine_number)
{
const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number);
const Engine *e = GetEngine(engine_number);
CargoID cargo;
YearMonthDay ymd;
ConvertDateToYMD(e->intro_date, &ymd);
/* Purchase cost - Max speed */
SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
SetDParam(1, avi->max_speed * 128 / 10);
DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
y += 10;
/* Cargo capacity */
cargo = FindFirstRefittableCargo(engine_number);
if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
SetDParam(0, avi->passenger_capacity);
SetDParam(1, avi->mail_capacity);
DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, 0);
} else {
/* Note, if the default capacity is selected by the refit capacity
* callback, then the capacity shown is likely to be incorrect. */
SetDParam(0, cargo);
SetDParam(1, AircraftDefaultCargoCapacity(cargo, engine_number));
SetDParam(2, STR_9842_REFITTABLE);
DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
}
y += 10;
/* Running cost */
SetDParam(0, avi->running_cost * _price.aircraft_running >> 8);
DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
y += 10;
/* Design date - Life length */
SetDParam(0, ymd.year);
SetDParam(1, e->lifelength);
DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
y += 10;
/* Reliability */
SetDParam(0, e->reliability * 100 >> 16);
DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
y += 10;
/* Additional text from NewGRF */
y += ShowAdditionalText(x, y, w, engine_number);
y += ShowRefitOptionsList(x, y, w, engine_number);
}
void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection)
{
PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
DrawSprite(GetAircraftImage(v, DIR_W) | pal, x + 25, y + 10);
if (v->subtype == 0) {
SpriteID rotor_sprite = GetCustomRotorSprite(v, true);
if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
DrawSprite(rotor_sprite, x + 25, y + 5);
}
if (v->index == selection) {
DrawFrameRect(x - 1, y - 1, x + 58, y + 21, 0xF, FR_BORDERONLY);
}
}
void CcBuildAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
const Vehicle *v = GetVehicle(_new_vehicle_id);
if (v->tile == _backup_orders_tile) {
_backup_orders_tile = 0;
RestoreVehicleOrders(v, _backup_orders_data);
}
ShowAircraftViewWindow(v);
}
}
static void GenerateBuildAircraftList(Window *w)
{
EngineID eid, sel_id;
buildvehicle_d *bv = &WP(w, buildvehicle_d);
EngList_RemoveAll(&bv->eng_list);
/* Make list of all available planes.
* Also check to see if the previously selected plane is still available,
* and if not, reset selection to INVALID_ENGINE. This could be the case
* when planes become obsolete and are removed */
sel_id = INVALID_ENGINE;
for (eid = AIRCRAFT_ENGINES_INDEX; eid < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; eid++) {
if (IsEngineBuildable(eid, VEH_Aircraft, _local_player)) {
const AircraftVehicleInfo *avi = AircraftVehInfo(eid);
switch (bv->filter.acc_planes) {
case HELICOPTERS_ONLY:
if (avi->subtype != 0) continue; // if not helicopter
break;
case AIRCRAFT_ONLY:
if (avi->subtype == 0) continue; // if helicopter
break;
case ALL: break;
}
EngList_Add(&bv->eng_list, eid);
if (eid == bv->sel_engine) sel_id = eid;
}
}
bv->sel_engine = sel_id;
}
static void GenerateBuildList(Window *w)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (bv->vehicle_type) {
case VEH_Aircraft:
GenerateBuildAircraftList(w);
_internal_sort_order = bv->descending_sort_order;
EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]);
break;
default: NOT_REACHED();
}
}
static void DrawBuildAircraftWindow(Window *w)
{
const buildvehicle_d *bv = &WP(w, buildvehicle_d);
SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0);
SetVScrollCount(w, EngList_Count(&bv->eng_list));
DrawWindowWidgets(w);
{
int x = 2;
int y = 27;
EngineID selected_id = bv->sel_engine;
EngineID eid = w->vscroll.pos;
uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list));
for (; eid < max; eid++) {
const EngineID engine = bv->eng_list[eid];
DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10);
DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player));
y += 24;
}
if (selected_id != INVALID_ENGINE) {
const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
DrawAircraftPurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id);
}
}
DrawString(85, 15, _aircraft_sort_listing[bv->sort_criteria], 0x10);
DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
}
static void BuildAircraftClickEvent(Window *w, WindowEvent *e)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (e->we.click.widget) {
case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
bv->descending_sort_order ^= true;
_last_sort_order = bv->descending_sort_order;
GenerateBuildList(w);
SetWindowDirty(w);
break;
case BUILD_VEHICLE_WIDGET_LIST: {
uint i = (e->we.click.pt.y - 26) / 24 + w->vscroll.pos;
uint num_items = EngList_Count(&bv->eng_list);
bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
SetWindowDirty(w);
break;
}
case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
return;
case BUILD_VEHICLE_WIDGET_BUILD: {
EngineID sel_eng = bv->sel_engine;
if (sel_eng != INVALID_ENGINE) {
DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
}
break;
}
case BUILD_VEHICLE_WIDGET_RENAME: {
EngineID sel_eng = bv->sel_engine;
if (sel_eng != INVALID_ENGINE) {
bv->rename_engine = sel_eng;
ShowQueryString(GetCustomEngineName(sel_eng), STR_A039_RENAME_AIRCRAFT_TYPE, 31, 160, w->window_class, w->window_number, CS_ALPHANUMERAL);
}
break;
}
}
}
static void NewAircraftWndProc(Window *w, WindowEvent *e)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (e->event) {
case WE_INVALIDATE_DATA:
GenerateBuildList(w);
break;
case WE_DESTROY:
EngList_Destroy(&bv->eng_list);
break;
case WE_PAINT:
DrawBuildAircraftWindow(w);
break;
case WE_CLICK:
BuildAircraftClickEvent(w, e);
break;
case WE_ON_EDIT_TEXT: {
if (e->we.edittext.str[0] != '\0') {
_cmd_text = e->we.edittext.str;
DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE));
}
break;
}
case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
if (bv->sort_criteria != e->we.dropdown.index) {
bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
GenerateBuildList(w);
}
SetWindowDirty(w);
break;
case WE_RESIZE:
w->vscroll.cap += e->we.sizing.diff.y / 24;
w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
break;
}
}
static const WindowDesc _build_vehicle_desc = {
WDP_AUTO, WDP_AUTO, 240, 226,
WC_BUILD_VEHICLE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_build_vehicle_widgets,
NewAircraftWndProc
};
void ShowBuildVehicleWindow(TileIndex tile, byte type)
{
buildvehicle_d *bv;
Window *w;
DeleteWindowById(WC_BUILD_VEHICLE, tile);
w = AllocateWindowDescFront(&_build_vehicle_desc, tile);
if (w == NULL) return;
w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
w->resize.step_height = GetVehicleListHeight(type);
w->vscroll.cap = 4;
w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
bv = &WP(w, buildvehicle_d);
EngList_Create(&bv->eng_list);
bv->sel_engine = INVALID_ENGINE;
bv->sort_criteria = _last_sort_criteria;
bv->descending_sort_order = _last_sort_order;
bv->vehicle_type = type;
switch (type) {
case VEH_Aircraft: {
byte acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes;
bv->filter.acc_planes = acc_planes;
break;
}
default: NOT_REACHED();
}
GenerateBuildList(w);
/* Select the first plane in the list as default when opening the window */
if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
}

View File

@@ -1,60 +1,61 @@
/* $Id$ */
/** @file callback_table.cpp All command callbacks. */
#include "stdafx.h"
#include "openttd.h"
#include "callback_table.h"
#include "command_type.h"
#include "functions.h"
/* If you add a callback for DoCommandP, also add the callback in here
* see below for the full list!
* If you don't do it, it won't work across the network!! */
// If you add a callback for DoCommandP, also add the callback in here
// see below for the full list!
// If you don't do it, it won't work across the network!!
/* aircraft_gui.cpp */
/* aircraft_gui.c */
CommandCallback CcBuildAircraft;
CommandCallback CcCloneAircraft;
/* airport_gui.cpp */
/* airport_gui.c */
CommandCallback CcBuildAirport;
/* bridge_gui.cpp */
/* bridge_gui.c */
CommandCallback CcBuildBridge;
/* dock_gui.cpp */
/* dock_gui.c */
CommandCallback CcBuildDocks;
CommandCallback CcBuildCanal;
/* depot_gui.cpp */
/* depot_gui.c */
CommandCallback CcCloneVehicle;
/* main_gui.cpp */
/* main_gui.c */
CommandCallback CcPlaySound10;
CommandCallback CcPlaceSign;
CommandCallback CcTerraform;
CommandCallback CcBuildTown;
CommandCallback CcGiveMoney;
/* rail_gui.cpp */
/* rail_gui.c */
CommandCallback CcPlaySound1E;
CommandCallback CcRailDepot;
CommandCallback CcStation;
CommandCallback CcBuildRailTunnel;
/* road_gui.cpp */
/* road_gui.c */
CommandCallback CcPlaySound1D;
CommandCallback CcBuildRoadTunnel;
CommandCallback CcRoadDepot;
/* roadveh_gui.cpp */
/* roadveh_gui.c */
CommandCallback CcBuildRoadVeh;
CommandCallback CcCloneRoadVeh;
/* ship_gui.cpp */
/* ship_gui.c */
CommandCallback CcBuildShip;
CommandCallback CcCloneShip;
/* train_gui.cpp */
/* train_gui.c */
CommandCallback CcBuildWagon;
CommandCallback CcBuildLoco;
CommandCallback CcCloneTrain;
/* ai/ai_core.cpp */
CommandCallback CcAI;
CommandCallback *_callback_table[] = {
@@ -79,9 +80,12 @@ CommandCallback *_callback_table[] = {
/* 0x12 */ CcPlaySound1E,
/* 0x13 */ CcStation,
/* 0x14 */ CcTerraform,
/* 0x15 */ CcAI,
/* 0x16 */ CcCloneVehicle,
/* 0x17 */ CcGiveMoney,
/* 0x15 */ CcCloneAircraft,
/* 0x16 */ CcCloneRoadVeh,
/* 0x17 */ CcCloneShip,
/* 0x18 */ CcCloneTrain,
/* 0x19 */ CcAI,
/* 0x1A */ CcCloneVehicle
};
const int _callback_table_count = lengthof(_callback_table);

View File

@@ -1,11 +1,9 @@
/* $Id$ */
/** @file callback_table.h Table with all command callbacks. */
#ifndef CALLBACK_TABLE_H
#define CALLBACK_TABLE_H
#include "command_type.h"
#include "command.h"
extern CommandCallback *_callback_table[];
extern const int _callback_table_count;

File diff suppressed because it is too large Load Diff

794
clear_cmd.c Normal file
View File

@@ -0,0 +1,794 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "clear_map.h"
#include "rail_map.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "player.h"
#include "tile.h"
#include "viewport.h"
#include "command.h"
#include "tunnel_map.h"
#include "variables.h"
#include "table/sprites.h"
#include "unmovable_map.h"
#include "genworld.h"
#include "industry.h"
typedef struct TerraformerHeightMod {
TileIndex tile;
byte height;
} TerraformerHeightMod;
typedef struct TerraformerState {
int height[4];
uint32 flags;
int direction;
int modheight_count;
int tile_table_count;
int32 cost;
TileIndex *tile_table;
TerraformerHeightMod *modheight;
} TerraformerState;
static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
{
TileIndex *t;
int count;
if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
t = ts->tile_table;
for (count = ts->tile_table_count; count != 0; count--, t++) {
if (*t == tile) return 0;
}
return 1;
}
static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
{
TerraformerHeightMod *mod = ts->modheight;
int count;
for (count = ts->modheight_count; count != 0; count--, mod++) {
if (mod->tile == tile) return mod->height;
}
return TileHeight(tile);
}
static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
{
int count;
TileIndex *t;
count = ts->tile_table_count;
if (count >= 625) return;
for (t = ts->tile_table; count != 0; count--,t++) {
if (*t == tile) return;
}
ts->tile_table[ts->tile_table_count++] = tile;
}
static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
{
TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0));
TerraformAddDirtyTile(ts, tile);
}
static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
{
int r;
int32 ret;
assert(tile < MapSize());
r = TerraformAllowTileProcess(ts, tile);
if (r <= 0) return r;
if (IsTileType(tile, MP_RAILWAY)) {
static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
Slope tileh;
uint z;
// 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.
tileh = GetTileSlope(tile, &z);
if (tileh == unsafe_slope[mode] ||
tileh == ComplementSlope(unsafe_slope[mode])) {
_terraform_err_tile = tile;
_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
return -1;
}
// If we have a single diagonal track there, the other side of
// tile can be terraformed.
if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
/* If terraforming downwards prevent damaging a potential tunnel below.
* This check is only necessary for flat tiles, because if the tile is
* non-flat, then the corner opposing the rail is raised. Only this corner
* can be lowered and this is a safe action
*/
if (tileh == SLOPE_FLAT &&
ts->direction == -1 &&
IsTunnelInWay(tile, z - TILE_HEIGHT)) {
_terraform_err_tile = tile;
_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
return -1;
}
return 0;
}
}
ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) {
_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;
return 0;
}
static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
{
int nh;
TerraformerHeightMod *mod;
int count;
assert(tile < MapSize());
if (height < 0) {
_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
return false;
}
_error_message = STR_1004_TOO_HIGH;
if (height > 15) return false;
nh = TerraformGetHeightOfTile(ts, tile);
if (nh < 0 || height == nh) return false;
if (TerraformProc(ts, tile, 0) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, 0), 3) < 0) return false;
mod = ts->modheight;
count = ts->modheight_count;
for (;;) {
if (count == 0) {
if (ts->modheight_count >= 576) return false;
ts->modheight_count++;
break;
}
if (mod->tile == tile) break;
mod++;
count--;
}
mod->tile = tile;
mod->height = (byte)height;
ts->cost += _price.terraform;
{
int direction = ts->direction, r;
const TileIndexDiffC *ttm;
static const TileIndexDiffC _terraform_tilepos[] = {
{ 1, 0},
{-2, 0},
{ 1, 1},
{ 0, -2}
};
for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
tile += ToTileIndexDiff(*ttm);
r = TerraformGetHeightOfTile(ts, tile);
if (r != height && r-direction != height && r+direction != height) {
if (!TerraformTileHeight(ts, tile, r+direction))
return false;
}
}
}
return true;
}
/** Terraform land
* @param tile tile to terraform
* @param p1 corners to terraform.
* @param p2 direction; eg up or down
*/
int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
TerraformerState ts;
TileIndex t;
int direction;
TerraformerHeightMod modheight_data[576];
TileIndex tile_table_data[625];
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
_terraform_err_tile = 0;
ts.direction = direction = p2 ? 1 : -1;
ts.flags = flags;
ts.modheight_count = ts.tile_table_count = 0;
ts.cost = 0;
ts.modheight = modheight_data;
ts.tile_table = tile_table_data;
/* 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) {
t = tile + TileDiffXY(1, 0);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 2) {
t = tile + TileDiffXY(1, 1);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 4) {
t = tile + TileDiffXY(0, 1);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 8) {
t = tile + TileDiffXY(0, 0);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (direction == -1) {
/* Check if tunnel would take damage */
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
uint z, t;
TileIndex tile = *ti;
z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
if (t <= z) z = t;
if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
}
}
}
if (flags & DC_EXEC) {
/* Clear the landscape at the tiles */
{
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
}
}
/* change the height */
{
int count;
TerraformerHeightMod *mod;
mod = ts.modheight;
for (count = ts.modheight_count; count != 0; count--, mod++) {
TileIndex til = mod->tile;
SetTileHeight(til, mod->height);
TerraformAddDirtyTileAround(&ts, til);
}
}
/* finally mark the dirty tiles dirty */
{
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
MarkTileDirtyByTile(*ti);
}
}
}
return ts.cost;
}
/** Levels a selected (rectangle) area of land
* @param tile end tile of area-drag
* @param p1 start tile of area drag
* @param p2 unused
*/
int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
int size_x, size_y;
int ex;
int ey;
int sx, sy;
uint h, curh;
int32 ret, cost, money;
if (p1 >= MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// remember level height
h = TileHeight(p1);
// make sure sx,sy are smaller than ex,ey
ex = TileX(tile);
ey = TileY(tile);
sx = TileX(p1);
sy = TileY(p1);
if (ex < sx) intswap(ex, sx);
if (ey < sy) intswap(ey, sy);
tile = TileXY(sx, sy);
size_x = ex-sx+1;
size_y = ey-sy+1;
money = GetAvailableMoneyForCommand();
cost = 0;
BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
curh = TileHeight(tile2);
while (curh != h) {
ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
if (CmdFailed(ret)) break;
cost += ret;
if (flags & DC_EXEC) {
if ((money -= ret) < 0) {
_additional_cash_required = ret;
return cost - ret;
}
DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
}
curh += (curh > h) ? -1 : 1;
}
} END_TILE_LOOP(tile2, size_x, size_y, tile)
return (cost == 0) ? CMD_ERROR : cost;
}
/** Purchase a land area. Actually you only purchase one tile, so
* the name is a bit confusing ;p
* @param tile the tile the player is purchasing
* @param p1 unused
* @param p2 unused
*/
int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
int32 cost;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
}
cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(cost)) return CMD_ERROR;
if (flags & DC_EXEC) {
MakeOwnedLand(tile, _current_player);
MarkTileDirtyByTile(tile);
}
return cost + _price.purchase_land * 10;
}
static int32 ClearTile_Clear(TileIndex tile, byte flags)
{
static const int32* clear_price_table[] = {
&_price.clear_1,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_3,
&_price.purchase_land,
&_price.purchase_land,
&_price.clear_2, // XXX unused?
};
int32 price;
if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
price = 0;
} else {
price = *clear_price_table[GetClearGround(tile)];
}
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 tile the tile the player is selling
* @param p1 unused
* @param p2 unused
*/
int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (!IsOwnedLandTile(tile)) return CMD_ERROR;
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"
void DrawClearLandTile(const TileInfo *ti, byte set)
{
DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
}
void DrawHillyLandTile(const TileInfo *ti)
{
if (ti->tileh != SLOPE_FLAT) {
DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
} else {
DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
}
}
void DrawClearLandFence(const TileInfo *ti)
{
byte z = ti->z;
if (ti->tileh & SLOPE_S) {
z += TILE_HEIGHT;
if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT;
}
if (GetFenceSW(ti->tile) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
}
if (GetFenceSE(ti->tile) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
}
}
static void DrawTile_Clear(TileInfo *ti)
{
switch (GetClearGround(ti->tile)) {
case CLEAR_GRASS:
DrawClearLandTile(ti, GetClearDensity(ti->tile));
break;
case CLEAR_ROUGH:
DrawHillyLandTile(ti);
break;
case CLEAR_ROCKS:
DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_FIELDS:
DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_SNOW:
DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_DESERT:
DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
}
DrawClearLandFence(ti);
}
static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
{
uint z;
uint tileh = GetTileSlope(tile, &z);
return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
}
static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh)
{
return tileh;
}
static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac)
{
/* unused */
}
static void AnimateTile_Clear(TileIndex tile)
{
/* unused */
}
void TileLoopClearHelper(TileIndex tile)
{
byte self;
byte neighbour;
TileIndex dirty = INVALID_TILE;
self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
if (GetFenceSW(tile) == 0) {
if (self != neighbour) {
SetFenceSW(tile, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SetFenceSW(tile, 0);
dirty = tile;
}
}
neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
if (GetFenceSE(tile) == 0) {
if (self != neighbour) {
SetFenceSE(tile, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SetFenceSE(tile, 0);
dirty = tile;
}
}
if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
}
/* convert into snowy tiles */
static void TileLoopClearAlps(TileIndex tile)
{
int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
if (k < 0) { // well below the snow line
if (!IsClearGround(tile, CLEAR_SNOW)) return;
if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
} else {
if (!IsClearGround(tile, CLEAR_SNOW)) {
SetClearGroundDensity(tile, CLEAR_SNOW, 0);
} else {
uint density = min((uint)k / TILE_HEIGHT, 3);
if (GetClearDensity(tile) < density) {
AddClearDensity(tile, 1);
} else if (GetClearDensity(tile) > density) {
AddClearDensity(tile, -1);
} else {
return;
}
}
}
MarkTileDirtyByTile(tile);
}
static void TileLoopClearDesert(TileIndex tile)
{
if (IsClearGround(tile, CLEAR_DESERT)) return;
if (GetTropicZone(tile) == TROPICZONE_DESERT) {
SetClearGroundDensity(tile, CLEAR_DESERT, 3);
} else {
if (GetTropicZone(tile + TileDiffXY( 1, 0)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY(-1, 0)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY( 0, 1)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT)
return;
SetClearGroundDensity(tile, CLEAR_DESERT, 1);
}
MarkTileDirtyByTile(tile);
}
static void TileLoop_Clear(TileIndex tile)
{
TileLoopClearHelper(tile);
switch (_opt.landscape) {
case LT_DESERT: TileLoopClearDesert(tile); break;
case LT_HILLY: TileLoopClearAlps(tile); break;
}
switch (GetClearGround(tile)) {
case CLEAR_GRASS:
if (GetClearDensity(tile) == 3) return;
if (_game_mode != GM_EDITOR) {
if (GetClearCounter(tile) < 7) {
AddClearCounter(tile, 1);
return;
} else {
SetClearCounter(tile, 0);
AddClearDensity(tile, 1);
}
} else {
SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
}
break;
case CLEAR_FIELDS: {
uint field_type;
if (_game_mode == GM_EDITOR) return;
if (GetClearCounter(tile) < 7) {
AddClearCounter(tile, 1);
return;
} else {
SetClearCounter(tile, 0);
}
if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
/* This farmfield is no longer farmfield, so make it grass again */
MakeClear(tile, CLEAR_GRASS, 2);
} else {
field_type = GetFieldType(tile);
field_type = (field_type < 8) ? field_type + 1 : 0;
SetFieldType(tile, field_type);
}
break;
}
default:
return;
}
MarkTileDirtyByTile(tile);
}
void GenerateClearTile(void)
{
uint i, gi;
TileIndex tile;
/* add rough tiles */
i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
do {
IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
tile = RandomTile();
if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
} while (--i);
/* add rocky tiles */
i = gi;
do {
uint32 r = Random();
tile = RandomTileSeed(r);
IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
uint j = GB(r, 16, 4) + 5;
for (;;) {
TileIndex tile_new;
SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
do {
if (--j == 0) goto get_out;
tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2));
} while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
tile = tile_new;
}
get_out:;
}
} while (--i);
}
static void ClickTile_Clear(TileIndex tile)
{
/* not used */
}
static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode)
{
return 0;
}
static const StringID _clear_land_str[] = {
STR_080D_GRASS,
STR_080B_ROUGH_LAND,
STR_080A_ROCKS,
STR_080E_FIELDS,
STR_080F_SNOW_COVERED_LAND,
STR_0810_DESERT
};
static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
{
if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
td->str = STR_080C_BARE_LAND;
} else {
td->str = _clear_land_str[GetClearGround(tile)];
}
td->owner = GetTileOwner(tile);
}
static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player)
{
return;
}
void InitializeClearLand(void)
{
_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
}
const TileTypeProcs _tile_type_clear_procs = {
DrawTile_Clear, /* draw_tile_proc */
GetSlopeZ_Clear, /* get_slope_z_proc */
ClearTile_Clear, /* clear_tile_proc */
GetAcceptedCargo_Clear, /* get_accepted_cargo_proc */
GetTileDesc_Clear, /* get_tile_desc_proc */
GetTileTrackStatus_Clear, /* get_tile_track_status_proc */
ClickTile_Clear, /* click_tile_proc */
AnimateTile_Clear, /* animate_tile_proc */
TileLoop_Clear, /* tile_loop_clear */
ChangeTileOwner_Clear, /* change_tile_owner_clear */
NULL, /* get_produced_cargo_proc */
NULL, /* vehicle_enter_tile_proc */
GetSlopeTileh_Clear, /* get_slope_tileh_proc */
};

145
clear_map.h Normal file
View File

@@ -0,0 +1,145 @@
/* $Id$ */
#ifndef CLEAR_MAP_H
#define CLEAR_MAP_H
#include "macros.h"
#include "tile.h"
/* ground type, m5 bits 2...4
* valid densities (bits 0...1) in comments after the enum
*/
typedef enum ClearGround {
CLEAR_GRASS = 0, // 0-3
CLEAR_ROUGH = 1, // 3
CLEAR_ROCKS = 2, // 3
CLEAR_FIELDS = 3, // 3
CLEAR_SNOW = 4, // 0-3
CLEAR_DESERT = 5 // 1,3
} ClearGround;
static inline ClearGround GetClearGround(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 2, 3);
}
static inline bool IsClearGround(TileIndex t, ClearGround ct)
{
return GetClearGround(t) == ct;
}
static inline uint GetClearDensity(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 0, 2);
}
static inline void AddClearDensity(TileIndex t, int d)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 += d;
}
static inline uint GetClearCounter(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 5, 3);
}
static inline void AddClearCounter(TileIndex t, int c)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 += c << 5;
}
static inline void SetClearCounter(TileIndex t, uint c)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
SB(_m[t].m5, 5, 3, c);
}
/* Sets type and density in one go, also sets the counter to 0 */
static inline void SetClearGroundDensity(TileIndex t, ClearGround type, uint density)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 = 0 << 5 | type << 2 | density;
}
static inline uint GetFieldType(TileIndex t)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
return GB(_m[t].m3, 0, 4);
}
static inline void SetFieldType(TileIndex t, uint f)
{
assert(GetClearGround(t) == CLEAR_FIELDS); // XXX incomplete
SB(_m[t].m3, 0, 4, f);
}
static inline uint16 GetIndustryIndexOfField(TileIndex t)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
return _m[t].m2;
}
static inline void SetIndustryIndexOfField(TileIndex t, uint16 i)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
_m[t].m2 = i;
}
/* Is used by tree tiles, too */
static inline uint GetFenceSE(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES));
return GB(_m[t].m4, 2, 3);
}
static inline void SetFenceSE(TileIndex t, uint h)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)); // XXX incomplete
SB(_m[t].m4, 2, 3, h);
}
static inline uint GetFenceSW(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES));
return GB(_m[t].m4, 5, 3);
}
static inline void SetFenceSW(TileIndex t, uint h)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)); // XXX incomplete
SB(_m[t].m4, 5, 3, h);
}
static inline void MakeClear(TileIndex t, ClearGround g, uint density)
{
SetTileType(t, MP_CLEAR);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = 0;
_m[t].m3 = 0;
_m[t].m4 = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, g, density);
}
static inline void MakeField(TileIndex t, uint field_type, uint16 industry)
{
SetTileType(t, MP_CLEAR);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = industry;
_m[t].m3 = field_type;
_m[t].m4 = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, CLEAR_FIELDS, 3);
}
#endif /* CLEAR_MAP_H */

562
command.c Normal file
View File

@@ -0,0 +1,562 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "gui.h"
#include "command.h"
#include "player.h"
#include "network.h"
#include "variables.h"
#include "genworld.h"
const char* _cmd_text = NULL;
#define DEF_COMMAND(yyyy) int32 yyyy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
DEF_COMMAND(CmdBuildRailroadTrack);
DEF_COMMAND(CmdRemoveRailroadTrack);
DEF_COMMAND(CmdBuildSingleRail);
DEF_COMMAND(CmdRemoveSingleRail);
DEF_COMMAND(CmdLandscapeClear);
DEF_COMMAND(CmdBuildBridge);
DEF_COMMAND(CmdBuildRailroadStation);
DEF_COMMAND(CmdRemoveFromRailroadStation);
DEF_COMMAND(CmdConvertRail);
DEF_COMMAND(CmdBuildSingleSignal);
DEF_COMMAND(CmdRemoveSingleSignal);
DEF_COMMAND(CmdTerraformLand);
DEF_COMMAND(CmdPurchaseLandArea);
DEF_COMMAND(CmdSellLandArea);
DEF_COMMAND(CmdBuildTunnel);
DEF_COMMAND(CmdBuildTrainDepot);
DEF_COMMAND(CmdBuildTrainWaypoint);
DEF_COMMAND(CmdRenameWaypoint);
DEF_COMMAND(CmdRemoveTrainWaypoint);
DEF_COMMAND(CmdBuildRoadStop);
DEF_COMMAND(CmdBuildLongRoad);
DEF_COMMAND(CmdRemoveLongRoad);
DEF_COMMAND(CmdBuildRoad);
DEF_COMMAND(CmdRemoveRoad);
DEF_COMMAND(CmdBuildRoadDepot);
DEF_COMMAND(CmdBuildAirport);
DEF_COMMAND(CmdBuildDock);
DEF_COMMAND(CmdBuildShipDepot);
DEF_COMMAND(CmdBuildBuoy);
DEF_COMMAND(CmdPlantTree);
DEF_COMMAND(CmdBuildRailVehicle);
DEF_COMMAND(CmdMoveRailVehicle);
DEF_COMMAND(CmdStartStopTrain);
DEF_COMMAND(CmdSellRailWagon);
DEF_COMMAND(CmdSendTrainToDepot);
DEF_COMMAND(CmdForceTrainProceed);
DEF_COMMAND(CmdReverseTrainDirection);
DEF_COMMAND(CmdModifyOrder);
DEF_COMMAND(CmdSkipOrder);
DEF_COMMAND(CmdDeleteOrder);
DEF_COMMAND(CmdInsertOrder);
DEF_COMMAND(CmdChangeServiceInt);
DEF_COMMAND(CmdRestoreOrderIndex);
DEF_COMMAND(CmdBuildIndustry);
DEF_COMMAND(CmdBuildCompanyHQ);
DEF_COMMAND(CmdSetPlayerFace);
DEF_COMMAND(CmdSetPlayerColor);
DEF_COMMAND(CmdIncreaseLoan);
DEF_COMMAND(CmdDecreaseLoan);
DEF_COMMAND(CmdWantEnginePreview);
DEF_COMMAND(CmdNameVehicle);
DEF_COMMAND(CmdRenameEngine);
DEF_COMMAND(CmdChangeCompanyName);
DEF_COMMAND(CmdChangePresidentName);
DEF_COMMAND(CmdRenameStation);
DEF_COMMAND(CmdSellAircraft);
DEF_COMMAND(CmdStartStopAircraft);
DEF_COMMAND(CmdBuildAircraft);
DEF_COMMAND(CmdSendAircraftToHangar);
DEF_COMMAND(CmdRefitAircraft);
DEF_COMMAND(CmdPlaceSign);
DEF_COMMAND(CmdRenameSign);
DEF_COMMAND(CmdBuildRoadVeh);
DEF_COMMAND(CmdStartStopRoadVeh);
DEF_COMMAND(CmdSellRoadVeh);
DEF_COMMAND(CmdSendRoadVehToDepot);
DEF_COMMAND(CmdTurnRoadVeh);
DEF_COMMAND(CmdRefitRoadVeh);
DEF_COMMAND(CmdPause);
DEF_COMMAND(CmdBuyShareInCompany);
DEF_COMMAND(CmdSellShareInCompany);
DEF_COMMAND(CmdBuyCompany);
DEF_COMMAND(CmdBuildTown);
DEF_COMMAND(CmdRenameTown);
DEF_COMMAND(CmdDoTownAction);
DEF_COMMAND(CmdSetRoadDriveSide);
DEF_COMMAND(CmdChangeDifficultyLevel);
DEF_COMMAND(CmdChangePatchSetting);
DEF_COMMAND(CmdStartStopShip);
DEF_COMMAND(CmdSellShip);
DEF_COMMAND(CmdBuildShip);
DEF_COMMAND(CmdSendShipToDepot);
DEF_COMMAND(CmdRefitShip);
DEF_COMMAND(CmdOrderRefit);
DEF_COMMAND(CmdCloneOrder);
DEF_COMMAND(CmdClearArea);
DEF_COMMAND(CmdGiveMoney);
DEF_COMMAND(CmdMoneyCheat);
DEF_COMMAND(CmdBuildCanal);
DEF_COMMAND(CmdBuildLock);
DEF_COMMAND(CmdPlayerCtrl);
DEF_COMMAND(CmdLevelLand);
DEF_COMMAND(CmdRefitRailVehicle);
DEF_COMMAND(CmdBuildSignalTrack);
DEF_COMMAND(CmdRemoveSignalTrack);
DEF_COMMAND(CmdSetAutoReplace);
DEF_COMMAND(CmdCloneVehicle);
DEF_COMMAND(CmdMassStartStopVehicle);
DEF_COMMAND(CmdDepotSellAllVehicles);
DEF_COMMAND(CmdDepotMassAutoReplace);
/* The master command table */
static const Command _command_proc_table[] = {
{CmdBuildRailroadTrack, 0}, /* 0 */
{CmdRemoveRailroadTrack, 0}, /* 1 */
{CmdBuildSingleRail, 0}, /* 2 */
{CmdRemoveSingleRail, 0}, /* 3 */
{CmdLandscapeClear, 0}, /* 4 */
{CmdBuildBridge, 0}, /* 5 */
{CmdBuildRailroadStation, 0}, /* 6 */
{CmdBuildTrainDepot, 0}, /* 7 */
{CmdBuildSingleSignal, 0}, /* 8 */
{CmdRemoveSingleSignal, 0}, /* 9 */
{CmdTerraformLand, 0}, /* 10 */
{CmdPurchaseLandArea, 0}, /* 11 */
{CmdSellLandArea, 0}, /* 12 */
{CmdBuildTunnel, 0}, /* 13 */
{CmdRemoveFromRailroadStation, 0}, /* 14 */
{CmdConvertRail, 0}, /* 15 */
{CmdBuildTrainWaypoint, 0}, /* 16 */
{CmdRenameWaypoint, 0}, /* 17 */
{CmdRemoveTrainWaypoint, 0}, /* 18 */
{NULL, 0}, /* 19 */
{NULL, 0}, /* 20 */
{CmdBuildRoadStop, 0}, /* 21 */
{NULL, 0}, /* 22 */
{CmdBuildLongRoad, 0}, /* 23 */
{CmdRemoveLongRoad, 0}, /* 24 */
{CmdBuildRoad, 0}, /* 25 */
{CmdRemoveRoad, 0}, /* 26 */
{CmdBuildRoadDepot, 0}, /* 27 */
{NULL, 0}, /* 28 */
{CmdBuildAirport, 0}, /* 29 */
{CmdBuildDock, 0}, /* 30 */
{CmdBuildShipDepot, 0}, /* 31 */
{CmdBuildBuoy, 0}, /* 32 */
{CmdPlantTree, 0}, /* 33 */
{CmdBuildRailVehicle, 0}, /* 34 */
{CmdMoveRailVehicle, 0}, /* 35 */
{CmdStartStopTrain, 0}, /* 36 */
{NULL, 0}, /* 37 */
{CmdSellRailWagon, 0}, /* 38 */
{CmdSendTrainToDepot, 0}, /* 39 */
{CmdForceTrainProceed, 0}, /* 40 */
{CmdReverseTrainDirection, 0}, /* 41 */
{CmdModifyOrder, 0}, /* 42 */
{CmdSkipOrder, 0}, /* 43 */
{CmdDeleteOrder, 0}, /* 44 */
{CmdInsertOrder, 0}, /* 45 */
{CmdChangeServiceInt, 0}, /* 46 */
{CmdBuildIndustry, 0}, /* 47 */
{CmdBuildCompanyHQ, 0}, /* 48 */
{CmdSetPlayerFace, 0}, /* 49 */
{CmdSetPlayerColor, 0}, /* 50 */
{CmdIncreaseLoan, 0}, /* 51 */
{CmdDecreaseLoan, 0}, /* 52 */
{CmdWantEnginePreview, 0}, /* 53 */
{CmdNameVehicle, 0}, /* 54 */
{CmdRenameEngine, 0}, /* 55 */
{CmdChangeCompanyName, 0}, /* 56 */
{CmdChangePresidentName, 0}, /* 57 */
{CmdRenameStation, 0}, /* 58 */
{CmdSellAircraft, 0}, /* 59 */
{CmdStartStopAircraft, 0}, /* 60 */
{CmdBuildAircraft, 0}, /* 61 */
{CmdSendAircraftToHangar, 0}, /* 62 */
{NULL, 0}, /* 63 */
{CmdRefitAircraft, 0}, /* 64 */
{CmdPlaceSign, 0}, /* 65 */
{CmdRenameSign, 0}, /* 66 */
{CmdBuildRoadVeh, 0}, /* 67 */
{CmdStartStopRoadVeh, 0}, /* 68 */
{CmdSellRoadVeh, 0}, /* 69 */
{CmdSendRoadVehToDepot, 0}, /* 70 */
{CmdTurnRoadVeh, 0}, /* 71 */
{CmdRefitRoadVeh, 0}, /* 72 */
{CmdPause, CMD_SERVER}, /* 73 */
{CmdBuyShareInCompany, 0}, /* 74 */
{CmdSellShareInCompany, 0}, /* 75 */
{CmdBuyCompany, 0}, /* 76 */
{CmdBuildTown, CMD_OFFLINE}, /* 77 */
{NULL, 0}, /* 78 */
{NULL, 0}, /* 79 */
{CmdRenameTown, CMD_SERVER}, /* 80 */
{CmdDoTownAction, 0}, /* 81 */
{CmdSetRoadDriveSide, CMD_SERVER}, /* 82 */
{NULL, 0}, /* 83 */
{NULL, 0}, /* 84 */
{CmdChangeDifficultyLevel, CMD_SERVER}, /* 85 */
{CmdStartStopShip, 0}, /* 86 */
{CmdSellShip, 0}, /* 87 */
{CmdBuildShip, 0}, /* 88 */
{CmdSendShipToDepot, 0}, /* 89 */
{NULL, 0}, /* 90 */
{CmdRefitShip, 0}, /* 91 */
{NULL, 0}, /* 92 */
{NULL, 0}, /* 93 */
{NULL, 0}, /* 94 */
{NULL, 0}, /* 95 */
{NULL, 0}, /* 96 */
{NULL, 0}, /* 97 */
{CmdOrderRefit, 0}, /* 98 */
{CmdCloneOrder, 0}, /* 99 */
{CmdClearArea, 0}, /* 100 */
{NULL, 0}, /* 101 */
{CmdMoneyCheat, CMD_OFFLINE}, /* 102 */
{CmdBuildCanal, 0}, /* 103 */
{CmdPlayerCtrl, 0}, /* 104 */
{CmdLevelLand, 0}, /* 105 */
{CmdRefitRailVehicle, 0}, /* 106 */
{CmdRestoreOrderIndex, 0}, /* 107 */
{CmdBuildLock, 0}, /* 108 */
{NULL, 0}, /* 109 */
{CmdBuildSignalTrack, 0}, /* 110 */
{CmdRemoveSignalTrack, 0}, /* 111 */
{NULL, 0}, /* 112 */
{CmdGiveMoney, 0}, /* 113 */
{CmdChangePatchSetting, CMD_SERVER}, /* 114 */
{CmdSetAutoReplace, 0}, /* 115 */
{CmdCloneVehicle, 0}, /* 116 */
{CmdMassStartStopVehicle, 0}, /* 117 */
{CmdDepotSellAllVehicles, 0}, /* 118 */
{CmdDepotMassAutoReplace, 0}, /* 119 */
};
/* This function range-checks a cmd, and checks if the cmd is not NULL */
bool IsValidCommand(uint cmd)
{
cmd &= 0xFF;
return
cmd < lengthof(_command_proc_table) &&
_command_proc_table[cmd].proc != NULL;
}
byte GetCommandFlags(uint cmd)
{
return _command_proc_table[cmd & 0xFF].flags;
}
static int _docommand_recursive;
int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
int32 res;
CommandProc *proc;
/* Do not even think about executing out-of-bounds tile-commands */
if (tile >= MapSize()) {
_cmd_text = NULL;
return CMD_ERROR;
}
proc = _command_proc_table[procc].proc;
if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
_docommand_recursive++;
// only execute the test call if it's toplevel, or we're not execing.
if (_docommand_recursive == 1 || !(flags & DC_EXEC) || (flags & DC_FORCETEST) ) {
res = proc(tile, flags & ~DC_EXEC, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto error;
}
if (_docommand_recursive == 1 &&
!(flags & DC_QUERY_COST) &&
res != 0 &&
!CheckPlayerHasMoney(res)) {
goto error;
}
if (!(flags & DC_EXEC)) {
_docommand_recursive--;
_cmd_text = NULL;
return res;
}
}
/* Execute the command here. All cost-relevant functions set the expenses type
* themselves with "SET_EXPENSES_TYPE(...);" at the beginning of the function */
res = proc(tile, flags, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
error:
_docommand_recursive--;
_cmd_text = NULL;
return CMD_ERROR;
}
// if toplevel, subtract the money.
if (--_docommand_recursive == 0) {
SubtractMoneyFromPlayer(res);
// XXX - Old AI hack which doesn't use DoCommandDP; update last build coord of player
if (tile != 0 && IsValidPlayer(_current_player)) {
GetPlayer(_current_player)->last_build_coordinate = tile;
}
}
_cmd_text = NULL;
return res;
}
int32 GetAvailableMoneyForCommand(void)
{
PlayerID pid = _current_player;
if (!IsValidPlayer(pid)) return 0x7FFFFFFF; // max int
return GetPlayer(pid)->player_money;
}
// toplevel network safe docommand function for the current player. must not be called recursively.
// the callback is called when the command succeeded or failed.
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd)
{
int32 res = 0,res2;
CommandProc *proc;
uint32 flags;
bool notest;
StringID error_part1;
int x = TileX(tile) * TILE_SIZE;
int y = TileY(tile) * TILE_SIZE;
/* Do not even think about executing out-of-bounds tile-commands */
if (tile >= MapSize()) {
_cmd_text = NULL;
return false;
}
assert(_docommand_recursive == 0);
_error_message = INVALID_STRING_ID;
error_part1 = GB(cmd, 16, 16);
_additional_cash_required = 0;
/** Spectator has no rights except for the (dedicated) server which
* is/can be a spectator but as the server it can do anything */
if (_current_player == PLAYER_SPECTATOR && !_network_server) {
ShowErrorMessage(_error_message, error_part1, x, y);
_cmd_text = NULL;
return false;
}
flags = 0;
if (cmd & CMD_AUTO) flags |= DC_AUTO;
if (cmd & CMD_NO_WATER) flags |= DC_NO_WATER;
// get pointer to command handler
assert((cmd & 0xFF) < lengthof(_command_proc_table));
proc = _command_proc_table[cmd & 0xFF].proc;
if (proc == NULL) {
_cmd_text = NULL;
return false;
}
// Some commands have a different output in dryrun than the realrun
// e.g.: if you demolish a whole town, the dryrun would say okay.
// but by really destroying, your rating drops and at a certain point
// it will fail. so res and res2 are different
// CMD_REMOVE_ROAD: This command has special local authority
// restrictions which may cause the test run to fail (the previous
// road fragments still stay there and the town won't let you
// disconnect the road system), but the exec will succeed and this
// fact will trigger an assertion failure. --pasky
notest =
(cmd & 0xFF) == CMD_CLEAR_AREA ||
(cmd & 0xFF) == CMD_CONVERT_RAIL ||
(cmd & 0xFF) == CMD_LEVEL_LAND ||
(cmd & 0xFF) == CMD_REMOVE_ROAD ||
(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD;
_docommand_recursive = 1;
// cost estimation only?
if (!IsGeneratingWorld() && _shift_pressed && IsLocalPlayer() && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) {
// estimate the cost.
res = proc(tile, flags, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
ShowErrorMessage(_error_message, error_part1, x, y);
} else {
ShowEstimatedCostOrIncome(res, x, y);
}
_docommand_recursive = 0;
_cmd_text = NULL;
return false;
}
if (!((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
// first test if the command can be executed.
res = proc(tile, flags, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto show_error;
}
// no money? Only check if notest is off
if (!notest && res != 0 && !CheckPlayerHasMoney(res)) goto show_error;
}
#ifdef ENABLE_NETWORK
/** If we are in network, and the command is not from the network
* send it to the command-queue and abort execution
* If we are a dedicated server temporarily switch local player, otherwise
* the other parties won't be able to execute our command and will desync.
* We also need to do this if the server's company has gone bankrupt
* @todo Rewrite (dedicated) server to something more than a dirty hack!
*/
if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
PlayerID pbck = _local_player;
if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = 0;
NetworkSend_Command(tile, p1, p2, cmd, callback);
if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck;
_docommand_recursive = 0;
_cmd_text = NULL;
return true;
}
#endif /* ENABLE_NETWORK */
// update last build coordinate of player.
if (tile != 0 && IsValidPlayer(_current_player)) {
GetPlayer(_current_player)->last_build_coordinate = tile;
}
/* Actually try and execute the command. If no cost-type is given
* use the construction one */
_yearly_expenses_type = EXPENSES_CONSTRUCTION;
res2 = proc(tile, flags | DC_EXEC, p1, p2);
// If notest is on, it means the result of the test can be different than
// the real command.. so ignore the test
if (!notest && !((cmd & CMD_NO_TEST_IF_IN_NETWORK) && _networking)) {
assert(res == res2); // sanity check
} else {
if (CmdFailed(res2)) {
if (res2 & 0xFFFF) _error_message = res2 & 0xFFFF;
goto show_error;
}
}
SubtractMoneyFromPlayer(res2);
if (IsLocalPlayer() && _game_mode != GM_EDITOR) {
if (res2 != 0) ShowCostOrIncomeAnimation(x, y, GetSlopeZ(x, y), res2);
if (_additional_cash_required) {
SetDParam(0, _additional_cash_required);
ShowErrorMessage(STR_0003_NOT_ENOUGH_CASH_REQUIRES, error_part1, x,y);
if (res2 == 0) goto callb_err;
}
}
_docommand_recursive = 0;
if (callback) callback(true, tile, p1, p2);
_cmd_text = NULL;
return true;
show_error:
// show error message if the command fails?
if (IsLocalPlayer() && error_part1 != 0) {
ShowErrorMessage(_error_message, error_part1, x,y);
}
callb_err:
_docommand_recursive = 0;
if (callback) callback(false, tile, p1, p2);
_cmd_text = NULL;
return false;
}

213
command.h Normal file
View File

@@ -0,0 +1,213 @@
/* $Id$ */
#ifndef COMMAND_H
#define COMMAND_H
enum {
CMD_BUILD_RAILROAD_TRACK = 0,
CMD_REMOVE_RAILROAD_TRACK = 1,
CMD_BUILD_SINGLE_RAIL = 2,
CMD_REMOVE_SINGLE_RAIL = 3,
CMD_LANDSCAPE_CLEAR = 4,
CMD_BUILD_BRIDGE = 5,
CMD_BUILD_RAILROAD_STATION = 6,
CMD_BUILD_TRAIN_DEPOT = 7,
CMD_BUILD_SIGNALS = 8,
CMD_REMOVE_SIGNALS = 9,
CMD_TERRAFORM_LAND = 10,
CMD_PURCHASE_LAND_AREA = 11,
CMD_SELL_LAND_AREA = 12,
CMD_BUILD_TUNNEL = 13,
CMD_REMOVE_FROM_RAILROAD_STATION = 14,
CMD_CONVERT_RAIL = 15,
CMD_BUILD_TRAIN_WAYPOINT = 16,
CMD_RENAME_WAYPOINT = 17,
CMD_REMOVE_TRAIN_WAYPOINT = 18,
CMD_BUILD_ROAD_STOP = 21,
CMD_BUILD_LONG_ROAD = 23,
CMD_REMOVE_LONG_ROAD = 24,
CMD_BUILD_ROAD = 25,
CMD_REMOVE_ROAD = 26,
CMD_BUILD_ROAD_DEPOT = 27,
CMD_BUILD_AIRPORT = 29,
CMD_BUILD_DOCK = 30,
CMD_BUILD_SHIP_DEPOT = 31,
CMD_BUILD_BUOY = 32,
CMD_PLANT_TREE = 33,
CMD_BUILD_RAIL_VEHICLE = 34,
CMD_MOVE_RAIL_VEHICLE = 35,
CMD_START_STOP_TRAIN = 36,
CMD_SELL_RAIL_WAGON = 38,
CMD_SEND_TRAIN_TO_DEPOT = 39,
CMD_FORCE_TRAIN_PROCEED = 40,
CMD_REVERSE_TRAIN_DIRECTION = 41,
CMD_MODIFY_ORDER = 42,
CMD_SKIP_ORDER = 43,
CMD_DELETE_ORDER = 44,
CMD_INSERT_ORDER = 45,
CMD_CHANGE_SERVICE_INT = 46,
CMD_BUILD_INDUSTRY = 47,
CMD_BUILD_COMPANY_HQ = 48,
CMD_SET_PLAYER_FACE = 49,
CMD_SET_PLAYER_COLOR = 50,
CMD_INCREASE_LOAN = 51,
CMD_DECREASE_LOAN = 52,
CMD_WANT_ENGINE_PREVIEW = 53,
CMD_NAME_VEHICLE = 54,
CMD_RENAME_ENGINE = 55,
CMD_CHANGE_COMPANY_NAME = 56,
CMD_CHANGE_PRESIDENT_NAME = 57,
CMD_RENAME_STATION = 58,
CMD_SELL_AIRCRAFT = 59,
CMD_START_STOP_AIRCRAFT = 60,
CMD_BUILD_AIRCRAFT = 61,
CMD_SEND_AIRCRAFT_TO_HANGAR = 62,
CMD_REFIT_AIRCRAFT = 64,
CMD_PLACE_SIGN = 65,
CMD_RENAME_SIGN = 66,
CMD_BUILD_ROAD_VEH = 67,
CMD_START_STOP_ROADVEH = 68,
CMD_SELL_ROAD_VEH = 69,
CMD_SEND_ROADVEH_TO_DEPOT = 70,
CMD_TURN_ROADVEH = 71,
CMD_REFIT_ROAD_VEH = 72,
CMD_PAUSE = 73,
CMD_BUY_SHARE_IN_COMPANY = 74,
CMD_SELL_SHARE_IN_COMPANY = 75,
CMD_BUY_COMPANY = 76,
CMD_BUILD_TOWN = 77,
CMD_RENAME_TOWN = 80,
CMD_DO_TOWN_ACTION = 81,
CMD_SET_ROAD_DRIVE_SIDE = 82,
CMD_CHANGE_DIFFICULTY_LEVEL = 85,
CMD_START_STOP_SHIP = 86,
CMD_SELL_SHIP = 87,
CMD_BUILD_SHIP = 88,
CMD_SEND_SHIP_TO_DEPOT = 89,
CMD_REFIT_SHIP = 91,
CMD_ORDER_REFIT = 98,
CMD_CLONE_ORDER = 99,
CMD_CLEAR_AREA = 100,
CMD_MONEY_CHEAT = 102,
CMD_BUILD_CANAL = 103,
CMD_PLAYER_CTRL = 104, // used in multiplayer to create a new player etc.
CMD_LEVEL_LAND = 105, // level land
CMD_REFIT_RAIL_VEHICLE = 106,
CMD_RESTORE_ORDER_INDEX = 107,
CMD_BUILD_LOCK = 108,
CMD_BUILD_SIGNAL_TRACK = 110,
CMD_REMOVE_SIGNAL_TRACK = 111,
CMD_GIVE_MONEY = 113,
CMD_CHANGE_PATCH_SETTING = 114,
CMD_SET_AUTOREPLACE = 115,
CMD_CLONE_VEHICLE = 116,
CMD_MASS_START_STOP = 117,
CMD_DEPOT_SELL_ALL_VEHICLES = 118,
CMD_DEPOT_MASS_AUTOREPLACE = 119,
};
enum {
DC_EXEC = 0x01,
DC_AUTO = 0x02, // don't allow building on structures
DC_QUERY_COST = 0x04, // query cost only, don't build.
DC_NO_WATER = 0x08, // don't allow building on water
DC_NO_RAIL_OVERLAP = 0x10, // don't allow overlap of rails (used in buildrail)
DC_AI_BUILDING = 0x20, // special building rules for AI
DC_NO_TOWN_RATING = 0x40, // town rating does not disallow you from building
DC_FORCETEST = 0x80, // force test too.
CMD_ERROR = ((int32)0x80000000),
};
#define CMD_MSG(x) ((x)<<16)
enum {
CMD_AUTO = 0x0200,
CMD_NO_WATER = 0x0400,
CMD_NETWORK_COMMAND = 0x0800, // execute the command without sending it on the network
CMD_NO_TEST_IF_IN_NETWORK = 0x1000, // When enabled, the command will bypass the no-DC_EXEC round if in network
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 int32 CommandProc(TileIndex tile, uint32 flags, uint32 p1, uint32 p2);
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 { 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 */
typedef void CommandCallback(bool success, TileIndex tile, uint32 p1, uint32 p2);
int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
#ifdef ENABLE_NETWORK
void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
#endif /* ENABLE_NETWORK */
extern const char* _cmd_text; // Text, which gets sent with a command
bool IsValidCommand(uint cmd);
byte GetCommandFlags(uint cmd);
int32 GetAvailableMoneyForCommand(void);
#endif /* COMMAND_H */

2862
config.lib

File diff suppressed because it is too large Load Diff

458
configure vendored
View File

@@ -1,159 +1,323 @@
#!/bin/sh
check_path_characters() {
if [ -n "`echo $ROOT_DIR | grep '[^-_A-Za-z0-9\/\\\.:]'`" ]; then
echo "WARNING: The path contains a non-alphanumeric character that might cause"
echo " failures in subsequent build stages. Any failures with the build"
echo " will most likely be caused by this."
fi
# This 'configure' script is a very easy wrapper around 'make updateconf'
# It allows cross-compilers to do their job much more easy.
showhelp() {
echo "Configure for OpenTTD"
echo ""
echo "Usage:"
echo " $0 --your_options"
echo ""
echo "Params:"
echo " --debug Create debug-release [no]"
echo " --profile Create profile-release [no]"
echo " --dedicated Make a dedicated build [no]"
echo " --revision Set the revision of the compilation [detected]"
echo " --target-cc Sets the target-compiler [\$CC]"
echo " --target-cxx Sets the C++ target-compiler []"
echo " --host-cc Sets the host-compiler [\$CC]"
echo " --host-cxx Sets the C++ host-compiler []"
echo " --os Sets the OS. Listens to: [detected]"
echo " UNIX, OSX, FREEBSD, MORPHOS"
echo " BEOS, SUNOS, CYGWIN, MINGW, OS2"
echo " --windres Sets the windres (Windows) [windres]"
echo " --force-le Force LE platform [no]"
echo " --force-be Force BE platform [no]"
echo ""
echo "Params that can be used with --with or --without"
echo " (e.g.: --without-static disables static (default))"
echo " static Do you want a static build? [no]"
echo " directmusic Do you want direct-music? [no]"
echo " zlib Do you want zlib-support? [yes]"
echo " sdl Do you want SDL-support? [yes]"
echo " png Do you want PNG-support? [yes]"
echo " iconv Do you want iconv-support? [no]"
echo " network Do you want network-support? [yes]"
echo " cocoa Do you want cocoa-support? (MacOSX) [no]"
echo " freetype Do you want freetype-support? [yes]"
echo " fontconfig Do you want fontconfig-support? [yes]"
echo ""
echo "Params used to configure external libs:"
echo " --static-zlib-path Set the path to your static zlib []"
echo " --sdl-config Where is your sdl-config [sdl-config]"
echo " --libpng-config Where is your libpng-config [libpng-config]"
echo " --freetype-config Where is your freetype-config [freetype-config]"
echo " --fontconfig-config Where is your fontconfig-config [pkg-config fontconfig]"
echo " --with-iconv Set the path to your iconv headers []"
echo " "
}
CONFIGURE_EXECUTABLE="$_"
# On *nix systems those two are equal when ./configure is done
if [ "$0" != "$CONFIGURE_EXECUTABLE" ]; then
# On some systems, when ./configure is triggered from 'make'
# the $_ is filled with 'make'. So if that is true, skip 'make'
# and use $0 (and hope that is correct ;))
if [ -n "`echo $CONFIGURE_EXECUTABLE | grep make`" ]; then
CONFIGURE_EXECUTABLE="$0"
else
CONFIGURE_EXECUTABLE="$CONFIGURE_EXECUTABLE $0"
handle() {
PARAM="$PARAM \"$1=`awk 'BEGIN { FS="="; $0="'"$2"'"; print $2;}'`\""
}
# The things you can use inside this case:
# handle NAME VALUE - Sets the value to give the 'make upgradeconf'
# Value is in form: tag=REAL_VALUE
# ITEM="NAME" - Will set the value as above, only with the next param
# SITEM="NAME" - Will set the var $NAME to the next param
for n in "$@"
do
case "$n" in
--help | -h)
showhelp
exit 0
;;
--debug)
DEBUG_SET=1
ITEM="DEBUG"
;;
--debug=*)
handle "DEBUG" "$n"
;;
--profile)
PARAM="$PARAM PROFILE=1"
;;
--dedicated)
PARAM="$PARAM DEDICATED=1"
;;
--revision=*)
RELEASE=`awk 'BEGIN { FS="="; $0="'"$n"'"; print $2;}'`
;;
--revision)
SITEM="RELEASE"
;;
--target-cc=*)
handle "CC_TARGET" "$n"
;;
--target-cc)
ITEM="CC_TARGET"
;;
--target-cxx=*)
handle "CXX_TARGET" "$n"
;;
--target-cxx)
SITEM="CXX_TARGET"
;;
--host-cc=*)
handle "CC_HOST" "$n"
;;
--host-cc)
ITEM="CC_HOST"
;;
--host-cxx=*)
handle "CXX_HOST" "$n"
;;
--host-cxx)
ITEM="CXX_HOST"
;;
--host-cflags=*)
handle CFLAGS_HOST "$n"
;;
--host-cflags)
ITEM="CFLAGS_HOST"
;;
--os=*)
TARGET_OS=`awk 'BEGIN { FS="="; $0="'"$n"'"; print $2;}'`
;;
--os)
SITEM="TARGET_OS"
;;
--windres=*)
handle WINDRES "$n"
;;
--windres)
ITEM="WINDRES"
;;
--force-le)
PARAM="$PARAM ENDIAN_FORCE=LE"
;;
--force-be)
PARAM="$PARAM ENDIAN_FORCE=BE"
;;
--with-static)
PARAM="$PARAM STATIC=1"
;;
--without-static)
PARAM="$PARAM STATIC="
;;
--with-directmusic)
PARAM="$PARAM WITH_DIRECTMUSIC=1"
;;
--without-directmusic)
PARAM="$PARAM WITH_DIRECTMUSIC="
;;
--with-zlib)
PARAM="$PARAM WITH_ZLIB=1"
;;
--without-zlib)
PARAM="$PARAM WITH_ZLIB="
;;
--with-sdl)
PARAM="$PARAM WITH_SDL=1"
;;
--without-sdl)
PARAM="$PARAM WITH_SDL="
;;
--with-png)
PARAM="$PARAM WITH_PNG=1"
;;
--without-png)
PARAM="$PARAM WITH_PNG="
;;
--with-iconv)
PARAM="$PARAM WITH_ICONV=1"
;;
--with-iconv=*)
PARAM="$PARAM WITH_ICONV=1"
handle WITH_ICONV_PATH "$n"
;;
--without-iconv)
PARAM="$PARAM WITH_ICONV="
;;
--with-cocoa)
PARAM="$PARAM WITH_COCOA=1"
;;
--with-network)
PARAM="$PARAM WITH_NETWORK=1"
;;
--without-network)
PARAM="$PARAM WITH_NETWORK="
;;
--without-cocoa)
PARAM="$PARAM WITH_COCOA="
;;
--with-freetype)
PARAM="$PARAM WITH_FREETYPE=1"
;;
--without-freetype)
PARAM="$PARAM WITH_FREETYPE="
;;
--with-fontconfig)
PARAM="$PARAM WITH_FONTCONFIG=1"
;;
--without-fontconfig)
PARAM="$PARAM WITH_FONTCONFIG="
;;
--static-zlib-path=*)
handle STATIC_ZLIB_PATH "$n"
;;
--static-zlib-path)
ITEM="STATIC_ZLIB_PATH"
;;
--sdl-config=*)
handle SDL_CONFIG "$n"
;;
--sdl-config)
ITEM="SDL_CONFIG"
;;
--libpng-config=*)
handle LIBPNG_CONFIG "$n"
;;
--libpng-config)
ITEM="LIBPNG_CONFIG"
;;
--freetype-config=*)
handle FREETYPE_CONFIG "$n"
;;
--freetype-config)
ITEM="FREETYPE_CONFIG"
;;
--fontconfig-config=*)
handle FONTCONFIG_CONFIG "$n"
;;
--fontconfig-config)
ITEM="FONTCONFIG_CONFIG"
;;
--*=*)
echo -n "Unknown switch "
echo `awk 'BEGIN { FS="="; $0="'"$n"'"; print $1;}'`
exit 1
;;
-*)
echo "Unknown switch $n"
exit 1
;;
*)
if ! test -z "$ITEM"
then
PARAM="$PARAM $ITEM=\"$n\""
ITEM="";
elif ! test -z "$SITEM"
then
export $SITEM="$n"
SITEM=""
else
echo "Unknown switch $n"
exit 1
fi
;;
esac
done
if ! test -z "$TARGET_OS"
then
TARGET_OS=`echo $TARGET_OS | tr '[:lower:]' '[:upper:]'`
case "$TARGET_OS" in
WIN32)
PARAM="$PARAM WIN32=1"
;;
UNIX)
PARAM="$PARAM UNIX=1"
;;
OSX)
PARAM="$PARAM OSX=1 UNIX=1"
;;
FREEBSD)
PARAM="$PARAM FREEBSD=1"
;;
MORPHOS)
PARAM="$PARAM MORPHOS=1 UNIX=1"
;;
BEOS)
PARAM="$PARAM BEOS=1 UNIX=1"
;;
OS2)
PARAM="$PARAM OS2=1 UNIX=1"
;;
SUNOS)
PARAM="$PARAM SUNOS=1 UNIX=1"
;;
CYGWIN)
PARAM="$PARAM CYGWIN=1 WIN32=1"
;;
MINGW)
PARAM="$PARAM MINGW=1 WIN32=1"
;;
*)
echo "Unknown OS: $TARGET_OS"
exit 1
;;
esac
PARAM="$PARAM BYPASS_OS_DETECT=1"
fi
if ! test -z "$DEBUG_SET"
then
if test -z "`echo $PARAM | grep "DEBUG="`"
then
# Someone did --debug, without assigning a value, assume 1
PARAM="$PARAM DEBUG=1"
fi
fi
# Find out where configure is (in what dir)
ROOT_DIR="`dirname $0`"
# For MSYS/MinGW we want to know the FULL path. This as that path is generated
# once you call an outside binary. Having the same path for the rest is needed
# for dependency checking.
# pwd -W returns said FULL path, but doesn't exist on others so fall back.
ROOT_DIR="`cd $ROOT_DIR && (pwd -W 2>/dev/null || pwd 2>/dev/null)`"
check_path_characters
# First remove the Makefile.config, else you can have double entries
rm -f Makefile.config
# Same here as for the ROOT_DIR above
PWD="`pwd -W 2>/dev/null || pwd 2>/dev/null`"
PREFIX="$PWD/bin"
echo "make upgradeconf $PARAM" > ./Makefile.run
. ./Makefile.run
rm -f ./Makefile.run
. $ROOT_DIR/config.lib
# Makefile.config currently doesn't support custom RELEASE (revision), so, we add the line
# yourself!
# Set default dirs
OBJS_DIR="$PWD/objs"
BASE_SRC_OBJS_DIR="$OBJS_DIR"
LANG_OBJS_DIR="$OBJS_DIR/lang"
BIN_DIR="$PREFIX"
SRC_DIR="$ROOT_DIR/src"
LANG_DIR="$SRC_DIR/lang"
MEDIA_DIR="$ROOT_DIR/media"
SOURCE_LIST="$ROOT_DIR/source.list"
if [ "$1" = "--reconfig" ] || [ "$1" = "--reconfigure" ]; then
if [ ! -f "config.cache" ]; then
echo "can't reconfigure, because never configured before"
exit 1
fi
# Make sure we don't lock config.cache
cat config.cache | sed 's@\\ @\\\\ @g' > cache.tmp
sh cache.tmp
RET=$?
rm -f cache.tmp
exit $RET
if ! test -z "$RELEASE"
then
echo "RELEASE=$RELEASE" >> Makefile.config
fi
set_default
detect_params "$@"
check_params
save_params
make_cflags_and_ldflags
EXE=""
if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ] || [ "$os" = "DOS" ] || [ "$os" = "WINCE" ]; then
EXE=".exe"
fi
TTD="openttd$EXE"
STRGEN="strgen$EXE"
ENDIAN_CHECK="endian_check$EXE"
if [ -z "$sort" ]; then
PIPE_SORT="sed s@a@a@"
else
PIPE_SORT="$sort"
fi
if [ ! -f "$LANG_DIR/english.txt" ]; then
echo "Languages not found in $LANG_DIR. Can't continue without it."
echo "Please make sure the dir exists and contains at least english.txt"
fi
# Read the source.list and process it
AWKCOMMAND='
{ }
/^( *)#end/ { if (deep == skip) { skip -= 1; } deep -= 1; next; }
/^( *)#else/ { if (deep == skip) { skip -= 1; } else if (deep - 1 == skip) { skip += 1; } next; }
/^( *)#if/ {
gsub(" ", "", $0);
gsub("^#if ", "", $0);
if (deep != skip) { deep += 1; next; }
deep += 1;
if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; }
if ($0 == "SDL" && "'$sdl_config'" == "") { next; }
if ($0 == "PNG" && "'$png_config'" == "") { next; }
if ($0 == "OSX" && "'$os'" != "OSX") { next; }
if ($0 == "OS2" && "'$os'" != "OS2") { next; }
if ($0 == "PSP" && "'$os'" != "PSP") { next; }
if ($0 == "DEDICATED" && "'$enable_dedicated'" != "1") { next; }
if ($0 == "COCOA" && "'$with_cocoa'" == "0") { next; }
if ($0 == "DOS" && "'$os'" != "DOS") { next; }
if ($0 == "BEOS" && "'$os'" != "BEOS") { next; }
if ($0 == "WIN32" && "'$os'" != "MINGW" &&
"'$os'" != "CYGWIN" && "'$os'" != "MSVC" ) { next; }
if ($0 == "MORPHOS" && "'$os'" != "MORPHOS") { next; }
if ($0 == "WINCE" && "'$os'" != "WINCE") { next; }
if ($0 == "MSVC" && "'$os'" != "MSVC") { next; }
if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; }
if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; }
if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; }
skip += 1;
next;
}
/^( *)#/ { next }
/^$/ { next }
/\.h$/ { next }
/\.hpp$/ { next }
{
if (deep == skip) {
gsub(" ", "", $0);
print $0;
}
}
'
# Read the source.list and process it
# Please escape ALL " within ` because e.g. "" terminates the string in some sh implementations
SRCS="`< $ROOT_DIR/source.list tr '\r' '\n' | $awk \"$AWKCOMMAND\" | $PIPE_SORT`"
OBJS_C="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.c$/ { gsub(\".c$\", \".o\", $0); print $0; }'`"
OBJS_CPP="`echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.cpp$/ { gsub(\".cpp$\", \".o\", $0); print $0; }'`"
OBJS_MM="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.mm$/ { gsub(\".mm$\", \".o\", $0); print $0; }'`"
OBJS_RC="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.rc$/ { gsub(\".rc$\", \".o\", $0); print $0; }'`"
SRCS="` echo \"$SRCS\" | $awk ' { ORS = \" \" } { print $0; }'`"
# In makefiles, we always use -u for sort
if [ -z "$sort" ]; then
sort="sed s@a@a@"
else
sort="$sort -u"
fi
CONFIGURE_FILES="$ROOT_DIR/configure $ROOT_DIR/config.lib $ROOT_DIR/Makefile.in $ROOT_DIR/Makefile.lang.in $ROOT_DIR/Makefile.src.in $ROOT_DIR/Makefile.bundle.in"
generate_main
generate_lang
generate_src
check_path_characters

View File

@@ -1,16 +1,21 @@
/* $Id$ */
/** @file console.cpp Handling of the in-game console. */
#include "stdafx.h"
#include "core/alloc_func.hpp"
#include "core/math_func.hpp"
#include "string_func.h"
#include "console_internal.h"
#include "network/network.h"
#include "network/network_func.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "player.h"
#include "variables.h"
#include "string.h"
#include <stdarg.h>
#include <string.h>
#include "console.h"
#include "network.h"
#include "network_data.h"
#include "network_server.h"
#define ICON_BUFFER 79
#define ICON_HISTORY_SIZE 20
@@ -20,45 +25,244 @@
#define ICON_MAX_ALIAS_LINES 40
#define ICON_TOKEN_COUNT 20
/* console parser */
IConsoleCmd *_iconsole_cmds; ///< list of registred commands
IConsoleVar *_iconsole_vars; ///< list of registred vars
IConsoleAlias *_iconsole_aliases; ///< list of registred aliases
// ** main console ** //
static char *_iconsole_buffer[ICON_BUFFER + 1];
static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
static Textbuf _iconsole_cmdline;
/* ** stdlib ** */
// ** stdlib ** //
byte _stdlib_developer = 1;
bool _stdlib_con_developer = false;
FILE *_iconsole_output_file;
void IConsoleInit()
// ** main console cmd buffer
static char *_iconsole_history[ICON_HISTORY_SIZE];
static byte _iconsole_historypos;
/* *************** */
/* end of header */
/* *************** */
static void IConsoleClearCommand(void)
{
memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
_iconsole_cmdline.length = 0;
_iconsole_cmdline.width = 0;
_iconsole_cmdline.caretpos = 0;
_iconsole_cmdline.caretxoffs = 0;
SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
}
static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
static void IConsoleHistoryAdd(const char *cmd);
static void IConsoleHistoryNavigate(int direction);
// ** console window ** //
static void IConsoleWndProc(Window *w, WindowEvent *e)
{
static byte iconsole_scroll = ICON_BUFFER;
switch (e->event) {
case WE_PAINT: {
int i = iconsole_scroll;
int max = (w->height / ICON_LINE_HEIGHT) - 1;
int delta = 0;
GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
DoDrawString(_iconsole_buffer[i], 5,
w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
i--;
}
/* If the text is longer than the window, don't show the starting ']' */
delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
if (delta > 0) {
DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
delta = 0;
}
DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
if (_iconsole_cmdline.caret)
DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, 12);
break;
}
case WE_MOUSELOOP:
if (HandleCaret(&_iconsole_cmdline))
SetWindowDirty(w);
break;
case WE_DESTROY:
_iconsole_mode = ICONSOLE_CLOSED;
break;
case WE_KEYPRESS:
e->we.keypress.cont = false;
switch (e->we.keypress.keycode) {
case WKC_UP:
IConsoleHistoryNavigate(+1);
SetWindowDirty(w);
break;
case WKC_DOWN:
IConsoleHistoryNavigate(-1);
SetWindowDirty(w);
break;
case WKC_SHIFT | WKC_PAGEUP:
if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
iconsole_scroll = 0;
} else {
iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
}
SetWindowDirty(w);
break;
case WKC_SHIFT | WKC_PAGEDOWN:
if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
iconsole_scroll = ICON_BUFFER;
} else {
iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
}
SetWindowDirty(w);
break;
case WKC_SHIFT | WKC_UP:
if (iconsole_scroll <= 0) {
iconsole_scroll = 0;
} else {
--iconsole_scroll;
}
SetWindowDirty(w);
break;
case WKC_SHIFT | WKC_DOWN:
if (iconsole_scroll >= ICON_BUFFER) {
iconsole_scroll = ICON_BUFFER;
} else {
++iconsole_scroll;
}
SetWindowDirty(w);
break;
case WKC_BACKQUOTE:
IConsoleSwitch();
break;
case WKC_RETURN: case WKC_NUM_ENTER:
IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
IConsoleHistoryAdd(_iconsole_cmdline.buf);
IConsoleCmdExec(_iconsole_cmdline.buf);
IConsoleClearCommand();
break;
case WKC_CTRL | WKC_RETURN:
_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
IConsoleResize(w);
MarkWholeScreenDirty();
break;
case (WKC_CTRL | 'V'):
if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
IConsoleResetHistoryPos();
SetWindowDirty(w);
}
break;
case (WKC_CTRL | 'L'):
IConsoleCmdExec("clear");
break;
case (WKC_CTRL | 'U'):
DeleteTextBufferAll(&_iconsole_cmdline);
SetWindowDirty(w);
break;
case WKC_BACKSPACE: case WKC_DELETE:
if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
IConsoleResetHistoryPos();
SetWindowDirty(w);
}
break;
case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
IConsoleResetHistoryPos();
SetWindowDirty(w);
}
break;
default:
if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
iconsole_scroll = ICON_BUFFER;
InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
IConsoleResetHistoryPos();
SetWindowDirty(w);
} else {
e->we.keypress.cont = true;
}
break;
}
}
}
static const Widget _iconsole_window_widgets[] = {
{WIDGETS_END}
};
static const WindowDesc _iconsole_window_desc = {
0, 0, 2, 2,
WC_CONSOLE, 0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_iconsole_window_widgets,
IConsoleWndProc,
};
void IConsoleInit(void)
{
extern const char _openttd_revision[];
_iconsole_output_file = NULL;
_icolour_def = 1;
_icolour_err = 3;
_icolour_warn = 13;
_icolour_dbg = 5;
_icolour_cmd = 2;
_iconsole_historypos = ICON_HISTORY_SIZE - 1;
_iconsole_mode = ICONSOLE_CLOSED;
#ifdef ENABLE_NETWORK /* Initialize network only variables */
_redirect_console_to_client = INVALID_CLIENT_ID;
_redirect_console_to_client = 0;
#endif
IConsoleGUIInit();
memset(_iconsole_history, 0, sizeof(_iconsole_history));
memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE;
IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
IConsolePrint(12, "------------------------------------");
IConsolePrint(12, "use \"help\" for more information");
IConsolePrint(12, "");
IConsoleStdLibRegister();
IConsoleClearCommand();
IConsoleHistoryAdd("");
}
void IConsoleClearBuffer(void)
{
uint i;
for (i = 0; i <= ICON_BUFFER; i++) {
free(_iconsole_buffer[i]);
_iconsole_buffer[i] = NULL;
}
}
static void IConsoleClear(void)
{
free(_iconsole_cmdline.buf);
IConsoleClearBuffer();
}
static void IConsoleWriteToLogFile(const char *string)
{
if (_iconsole_output_file != NULL) {
/* if there is an console output file ... also print it there */
if (fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 ||
fwrite("\n", 1, 1, _iconsole_output_file) != 1) {
fclose(_iconsole_output_file);
_iconsole_output_file = NULL;
IConsolePrintF(CC_DEFAULT, "cannot write to log file");
}
// if there is an console output file ... also print it there
fwrite(string, strlen(string), 1, _iconsole_output_file);
fwrite("\n", 1, 1, _iconsole_output_file);
}
}
bool CloseConsoleLogIfActive()
bool CloseConsoleLogIfActive(void)
{
if (_iconsole_output_file != NULL) {
IConsolePrintF(CC_DEFAULT, "file output complete");
IConsolePrintF(_icolour_def, "file output complete");
fclose(_iconsole_output_file);
_iconsole_output_file = NULL;
return true;
@@ -67,28 +271,109 @@ bool CloseConsoleLogIfActive()
return false;
}
void IConsoleFree()
void IConsoleFree(void)
{
IConsoleGUIFree();
IConsoleClear();
CloseConsoleLogIfActive();
}
void IConsoleResize(Window *w)
{
switch (_iconsole_mode) {
case ICONSOLE_OPENED:
w->height = _screen.height / 3;
w->width = _screen.width;
break;
case ICONSOLE_FULL:
w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
w->width = _screen.width;
break;
default: return;
}
MarkWholeScreenDirty();
}
void IConsoleSwitch(void)
{
switch (_iconsole_mode) {
case ICONSOLE_CLOSED: {
Window *w = AllocateWindowDesc(&_iconsole_window_desc);
w->height = _screen.height / 3;
w->width = _screen.width;
_iconsole_mode = ICONSOLE_OPENED;
SETBIT(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
} break;
case ICONSOLE_OPENED: case ICONSOLE_FULL:
DeleteWindowById(WC_CONSOLE, 0);
_iconsole_mode = ICONSOLE_CLOSED;
CLRBIT(_no_scroll, SCROLL_CON);
break;
}
MarkWholeScreenDirty();
}
void IConsoleClose(void) {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
void IConsoleOpen(void) {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
/**
* Add the entered line into the history so you can look it back
* scroll, etc. Put it to the beginning as it is the latest text
* @param cmd Text to be entered into the 'history'
*/
static void IConsoleHistoryAdd(const char *cmd)
{
free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
_iconsole_history[0] = strdup(cmd);
IConsoleResetHistoryPos();
}
/**
* Navigate Up/Down in the history of typed commands
* @param direction Go further back in history (+1), go to recently typed commands (-1)
*/
static void IConsoleHistoryNavigate(int direction)
{
int i = _iconsole_historypos + direction;
// watch out for overflows, just wrap around
if (i < 0) i = ICON_HISTORY_SIZE - 1;
if (i >= ICON_HISTORY_SIZE) i = 0;
if (direction > 0)
if (_iconsole_history[i] == NULL) i = 0;
if (direction < 0) {
while (i > 0 && _iconsole_history[i] == NULL) i--;
}
_iconsole_historypos = i;
IConsoleClearCommand();
// copy history to 'command prompt / bash'
assert(_iconsole_history[i] != NULL && IS_INT_INSIDE(i, 0, ICON_HISTORY_SIZE));
ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength);
UpdateTextBufferSize(&_iconsole_cmdline);
}
/**
* Handle the printing of text entered into the console or redirected there
* by any other means. Text can be redirected to other clients in a network game
* by any other means. Text can be redirected to other players in a network game
* as well as to a logfile. If the network server is a dedicated server, all activities
* are also logged. All lines to print are added to a temporary buffer which can be
* used as a history to print them onscreen
* @param colour_code the colour of the command. Red in case of errors, etc.
* @param color_code the colour of the command. Red in case of errors, etc.
* @param string the message entered or output on the console (notice, error, etc.)
*/
void IConsolePrint(ConsoleColour colour_code, const char *string)
void IConsolePrint(uint16 color_code, const char *string)
{
char *str;
#ifdef ENABLE_NETWORK
if (_redirect_console_to_client != INVALID_CLIENT_ID) {
if (_redirect_console_to_client != 0) {
/* Redirect the string to the client */
NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(_redirect_console_to_client), color_code, string);
return;
}
#endif
@@ -97,49 +382,56 @@ void IConsolePrint(ConsoleColour colour_code, const char *string)
* characters and (when applicable) assign it to the console buffer */
str = strdup(string);
str_strip_colours(str);
str_validate(str, str + strlen(str));
str_validate(str);
if (_network_dedicated) {
fprintf(stdout, "%s\n", str);
fflush(stdout);
printf("%s\n", str);
IConsoleWriteToLogFile(str);
free(str); // free duplicated string since it's not used anymore
return;
}
IConsoleWriteToLogFile(str);
IConsoleGUIPrint(colour_code, str);
/* move up all the strings in the buffer one place and do the same for colour
* to accomodate for the new command/message */
free(_iconsole_buffer[0]);
memmove(&_iconsole_buffer[0], &_iconsole_buffer[1], sizeof(_iconsole_buffer[0]) * ICON_BUFFER);
_iconsole_buffer[ICON_BUFFER] = str;
memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER);
_iconsole_cbuffer[ICON_BUFFER] = color_code;
IConsoleWriteToLogFile(_iconsole_buffer[ICON_BUFFER]);
SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
}
/**
* Handle the printing of text entered into the console or redirected there
* by any other means. Uses printf() style format, for more information look
* at IConsolePrint()
* at @IConsolePrint()
*/
void CDECL IConsolePrintF(ConsoleColour colour_code, const char *format, ...)
void CDECL IConsolePrintF(uint16 color_code, const char *s, ...)
{
va_list va;
char buf[ICON_MAX_STREAMSIZE];
va_start(va, format);
vsnprintf(buf, sizeof(buf), format, va);
va_start(va, s);
vsnprintf(buf, sizeof(buf), s, va);
va_end(va);
IConsolePrint(colour_code, buf);
IConsolePrint(color_code, buf);
}
/**
* It is possible to print debugging information to the console,
* which is achieved by using this function. Can only be used by
* debug() in debug.cpp. You need at least a level 2 (developer) for debugging
* @debug() in debug.c. You need at least a level 2 (developer) for debugging
* messages to show up
* @param dbg debugging category
* @param string debugging message
*/
void IConsoleDebug(const char *dbg, const char *string)
void IConsoleDebug(const char *string)
{
if (_stdlib_developer > 1)
IConsolePrintF(CC_DEBUG, "dbg: [%s] %s", dbg, string);
IConsolePrintF(_icolour_dbg, "dbg: %s", string);
}
/**
@@ -150,7 +442,7 @@ void IConsoleDebug(const char *dbg, const char *string)
void IConsoleWarning(const char *string)
{
if (_stdlib_developer > 0)
IConsolePrintF(CC_WARNING, "WARNING: %s", string);
IConsolePrintF(_icolour_warn, "WARNING: %s", string);
}
/**
@@ -159,13 +451,13 @@ void IConsoleWarning(const char *string)
*/
void IConsoleError(const char *string)
{
IConsolePrintF(CC_ERROR, "ERROR: %s", string);
IConsolePrintF(_icolour_err, "ERROR: %s", string);
}
/**
* Change a string into its number representation. Supports
* decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false'
* @param *value the variable a successful conversion will be put in
* @param *value the variable a successfull conversion will be put in
* @param *arg the string to be converted
* @return Return true on success or false on failure
*/
@@ -186,13 +478,12 @@ bool GetArgumentInteger(uint32 *value, const char *arg)
return arg != endptr;
}
/* * *************************
* hooking code *
* *************************/
// * ************************* * //
// * hooking code * //
// * ************************* * //
/**
* General internal hooking code that is the same for both commands and variables
* @param hooks IConsoleHooks structure that will be set according to
* @param hooks @IConsoleHooks structure that will be set according to
* @param type type access trigger
* @param proc function called when the hook criteria is met
*/
@@ -217,9 +508,9 @@ static void IConsoleHookAdd(IConsoleHooks *hooks, IConsoleHookTypes type, IConso
/**
* Handle any special hook triggers. If the hook type is met check if
* there is a function associated with that and if so, execute it
* @param hooks IConsoleHooks structure that will be checked
* @param hooks @IConsoleHooks structure that will be checked
* @param type type of hook, trigger that needs to be activated
* @return true on a successful execution of the hook command or if there
* @return true on a successfull execution of the hook command or if there
* is no hook/trigger present at all. False otherwise
*/
static bool IConsoleHookHandle(const IConsoleHooks *hooks, IConsoleHookTypes type)
@@ -319,7 +610,7 @@ void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc)
{
char *new_cmd = strdup(name);
IConsoleCmd *item_new = MallocT<IConsoleCmd>(1);
IConsoleCmd *item_new = malloc(sizeof(IConsoleCmd));
item_new->next = NULL;
item_new->proc = proc;
@@ -356,7 +647,7 @@ void IConsoleAliasRegister(const char *name, const char *cmd)
{
char *new_alias = strdup(name);
char *cmd_aliased = strdup(cmd);
IConsoleAlias *item_new = MallocT<IConsoleAlias>(1);
IConsoleAlias *item_new = malloc(sizeof(IConsoleAlias));
item_new->next = NULL;
item_new->cmdline = cmd_aliased;
@@ -372,7 +663,7 @@ void IConsoleAliasRegister(const char *name, const char *cmd)
*/
IConsoleAlias *IConsoleAliasGet(const char *name)
{
IConsoleAlias *item;
IConsoleAlias* item;
for (item = _iconsole_aliases; item != NULL; item = item->next) {
if (strcmp(item->name, name) == 0) return item;
@@ -384,9 +675,8 @@ IConsoleAlias *IConsoleAliasGet(const char *name)
/** copy in an argument into the aliasstream */
static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
{
/* len is the amount of bytes to add excluding the '\0'-termination */
int len = min(ICON_MAX_STREAMSIZE - bufpos - 1, (uint)strlen(src));
strecpy(dst, src, dst + len);
int len = min(ICON_MAX_STREAMSIZE - bufpos, (uint)strlen(src));
strncpy(dst, src, len);
return len;
}
@@ -409,25 +699,25 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
memset(&aliasstream, 0, sizeof(aliasstream));
if (_stdlib_con_developer)
IConsolePrintF(CC_DEBUG, "condbg: requested command is an alias; parsing...");
IConsolePrintF(_icolour_dbg, "condbg: requested command is an alias; parsing...");
aliases[0] = aliasstream;
for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) {
if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break;
switch (*cmdptr) {
case '\'': // ' will double for ""
case '\'': /* ' will double for "" */
aliasstream[astream_i++] = '"';
break;
case ';': // Cmd seperator, start new command
case ';': /* Cmd seperator, start new command */
aliasstream[astream_i] = '\0';
aliases[++a_index] = &aliasstream[++astream_i];
cmdptr++;
break;
case '%': // Some or all parameters
case '%': /* Some or all parameters */
cmdptr++;
switch (*cmdptr) {
case '+': { // All parameters seperated: "[param 1]" "[param 2]"
case '+': { /* All parameters seperated: "[param 1]" "[param 2]" */
for (i = 0; i != tokencount; i++) {
aliasstream[astream_i++] = '"';
astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
@@ -435,7 +725,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
aliasstream[astream_i++] = ' ';
}
} break;
case '!': { // Merge the parameters to one: "[param 1] [param 2] [param 3...]"
case '!': { /* Merge the parameters to one: "[param 1] [param 2] [param 3...]" */
aliasstream[astream_i++] = '"';
for (i = 0; i != tokencount; i++) {
astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i);
@@ -444,12 +734,12 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
aliasstream[astream_i++] = '"';
} break;
default: { // One specific parameter: %A = [param 1] %B = [param 2] ...
default: { /* One specific parameter: %A = [param 1] %B = [param 2] ... */
int param = *cmdptr - 'A';
if (param < 0 || param >= tokencount) {
IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline);
IConsolePrintF(_icolour_warn, "Usage of alias '%s': %s", alias->name, alias->cmdline);
return;
}
@@ -471,11 +761,8 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
/**
* Special function for adding string-type variables. They in addition
* also need a 'size' value saying how long their string buffer is.
* @param name name of the variable that will be used
* @param addr memory location the variable will point to
* @param size the length of the string buffer
* @param help the help string shown for the variable
* For more information see IConsoleVarRegister()
* For more information see @IConsoleVarRegister()
*/
void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help)
{
@@ -495,7 +782,7 @@ void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const
void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help)
{
char *new_cmd = strdup(name);
IConsoleVar *item_new = MallocT<IConsoleVar>(1);
IConsoleVar *item_new = malloc(sizeof(IConsoleVar));
item_new->help = (help != NULL) ? strdup(help) : NULL;
@@ -572,7 +859,7 @@ static void IConsoleVarSetStringvalue(const IConsoleVar *var, const char *value)
if (var->type != ICONSOLE_VAR_STRING || var->addr == NULL) return;
IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_PRE_ACTION);
ttd_strlcpy((char*)var->addr, value, var->size);
ttd_strlcpy(var->addr, value, var->size);
IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
IConsoleVarPrintSetValue(var); // print out the new value, giving feedback
return;
@@ -662,7 +949,7 @@ void IConsoleVarPrintGetValue(const IConsoleVar *var)
}
value = IConsoleVarGetStringValue(var);
IConsolePrintF(CC_WARNING, "Current value for '%s' is: %s", var->name, value);
IConsolePrintF(_icolour_warn, "Current value for '%s' is: %s", var->name, value);
}
/**
@@ -672,7 +959,7 @@ void IConsoleVarPrintGetValue(const IConsoleVar *var)
void IConsoleVarPrintSetValue(const IConsoleVar *var)
{
char *value = IConsoleVarGetStringValue(var);
IConsolePrintF(CC_WARNING, "'%s' changed to: %s", var->name, value);
IConsolePrintF(_icolour_warn, "'%s' changed to: %s", var->name, value);
}
/**
@@ -689,9 +976,9 @@ void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[ICON_T
uint32 value;
if (_stdlib_con_developer)
IConsolePrintF(CC_DEBUG, "condbg: requested command is a variable");
IConsolePrintF(_icolour_dbg, "condbg: requested command is a variable");
if (tokencount == 0) { // Just print out value
if (tokencount == 0) { /* Just print out value */
IConsoleVarPrintGetValue(var);
return;
}
@@ -766,13 +1053,13 @@ void IConsoleCmdExec(const char *cmdstr)
for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
IConsoleError("command contains malformed characters, aborting");
IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr);
IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
return;
}
}
if (_stdlib_con_developer)
IConsolePrintF(CC_DEBUG, "condbg: executing cmdline: '%s'", cmdstr);
IConsolePrintF(_icolour_dbg, "condbg: executing cmdline: '%s'", cmdstr);
memset(&tokens, 0, sizeof(tokens));
memset(&tokenstream, 0, sizeof(tokenstream));
@@ -784,7 +1071,7 @@ void IConsoleCmdExec(const char *cmdstr)
if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break;
switch (*cmdptr) {
case ' ': // Token seperator
case ' ': /* Token seperator */
if (!foundtoken) break;
if (longtoken) {
@@ -796,16 +1083,16 @@ void IConsoleCmdExec(const char *cmdstr)
tstream_i++;
break;
case '"': // Tokens enclosed in "" are one token
case '"': /* Tokens enclosed in "" are one token */
longtoken = !longtoken;
break;
case '\\': // Escape character for ""
case '\\': /* Escape character for "" */
if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) {
tokenstream[tstream_i++] = *++cmdptr;
break;
}
/* fallthrough */
default: // Normal character
default: /* Normal character */
tokenstream[tstream_i++] = *cmdptr;
if (!foundtoken) {
@@ -820,7 +1107,7 @@ void IConsoleCmdExec(const char *cmdstr)
uint i;
for (i = 0; tokens[i] != NULL; i++) {
IConsolePrintF(CC_DEBUG, "condbg: token %d is: '%s'", i, tokens[i]);
IConsolePrintF(_icolour_dbg, "condbg: token %d is: '%s'", i, tokens[i]);
}
}

View File

@@ -1,18 +1,14 @@
/* $Id$ */
/** @file console_internal.h Internally used functions for the console. */
#ifndef CONSOLE_H
#define CONSOLE_H
#ifndef CONSOLE_INTERNAL_H
#define CONSOLE_INTERNAL_H
// maximum length of a typed in command
#define ICON_CMDLN_SIZE 255
// maximum length of a totally expanded command
#define ICON_MAX_STREAMSIZE 1024
#include "console_func.h"
enum {
ICON_CMDLN_SIZE = 1024, ///< maximum length of a typed in command
ICON_MAX_STREAMSIZE = 2048, ///< maximum length of a totally expanded command
};
enum IConsoleVarTypes {
typedef enum IConsoleVarTypes {
ICONSOLE_VAR_BOOLEAN,
ICONSOLE_VAR_BYTE,
ICONSOLE_VAR_UINT16,
@@ -20,25 +16,31 @@ enum IConsoleVarTypes {
ICONSOLE_VAR_INT16,
ICONSOLE_VAR_INT32,
ICONSOLE_VAR_STRING
};
} IConsoleVarTypes;
enum IConsoleHookTypes {
typedef enum IConsoleModes {
ICONSOLE_FULL,
ICONSOLE_OPENED,
ICONSOLE_CLOSED
} IConsoleModes;
typedef enum IConsoleHookTypes {
ICONSOLE_HOOK_ACCESS,
ICONSOLE_HOOK_PRE_ACTION,
ICONSOLE_HOOK_POST_ACTION
};
} IConsoleHookTypes;
/** --Hooks--
* Hooks are certain triggers get get accessed/executed on either
* 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();
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
};
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--
* Commands are commands, or functions. They get executed once and any
@@ -49,13 +51,14 @@ struct IConsoleHooks{
*/
typedef bool (IConsoleCmdProc)(byte argc, char *argv[]);
struct IConsoleCmd {
char *name; ///< name of command
IConsoleCmd *next; ///< next command in list
struct IConsoleCmd;
typedef struct IConsoleCmd {
char *name; // name of command
struct IConsoleCmd *next; // next command in list
IConsoleCmdProc *proc; ///< process executed when command is typed
IConsoleHooks hook; ///< any special trigger action that needs executing
};
IConsoleCmdProc *proc; // process executed when command is typed
IConsoleHooks hook; // any special trigger action that needs executing
} IConsoleCmd;
/** --Variables--
* Variables are pointers to real ingame variables which allow for
@@ -66,17 +69,18 @@ struct IConsoleCmd {
* - '++' to increase value by one
* - '--' to decrease value by one
*/
struct IConsoleVar {
char *name; ///< name of the variable
IConsoleVar *next; ///< next variable in list
struct IConsoleVar;
typedef struct IConsoleVar {
char *name; // name of the variable
struct IConsoleVar *next; // next variable in list
void *addr; ///< the address where the variable is pointing at
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
};
void *addr; // the address where the variable is pointing at
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--
* Aliases are like shortcuts for complex functions, variable assignments,
@@ -89,21 +93,42 @@ struct IConsoleVar {
* - "%!" also lists all parameters but presenting them to the aliased command as one argument
* - ";" allows for combining commands (see example 'ng')
*/
struct IConsoleAlias {
char *name; ///< name of the alias
IConsoleAlias *next; ///< next alias in list
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
};
char *cmdline; // command(s) that is/are being aliased
} IConsoleAlias;
/* console parser */
extern IConsoleCmd *_iconsole_cmds; ///< list of registred commands
extern IConsoleVar *_iconsole_vars; ///< list of registred vars
extern IConsoleAlias *_iconsole_aliases; ///< list of registred aliases
VARDEF IConsoleCmd *_iconsole_cmds; // list of registred commands
VARDEF IConsoleVar *_iconsole_vars; // list of registred vars
VARDEF IConsoleAlias *_iconsole_aliases; // list of registred aliases
/* console colors/modes */
VARDEF byte _icolour_def;
VARDEF byte _icolour_err;
VARDEF byte _icolour_warn;
VARDEF byte _icolour_dbg;
VARDEF byte _icolour_cmd;
VARDEF IConsoleModes _iconsole_mode;
/* console functions */
void IConsoleClearBuffer();
void IConsoleOpen();
void IConsoleInit(void);
void IConsoleFree(void);
void IConsoleClearBuffer(void);
void IConsoleResize(Window *w);
void IConsoleSwitch(void);
void IConsoleClose(void);
void IConsoleOpen(void);
/* console output */
void IConsolePrint(uint16 color_code, const char *string);
void CDECL IConsolePrintF(uint16 color_code, const char *s, ...);
void IConsoleDebug(const char *string);
void IConsoleWarning(const char *string);
void IConsoleError(const char *string);
/* Commands */
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc);
@@ -114,15 +139,16 @@ IConsoleAlias *IConsoleAliasGet(const char *name);
/* 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);
IConsoleVar *IConsoleVarGet(const char *name);
IConsoleVar* IConsoleVarGet(const char *name);
void IConsoleVarPrintGetValue(const IConsoleVar *var);
void IConsoleVarPrintSetValue(const IConsoleVar *var);
/* Parser */
void IConsoleCmdExec(const char *cmdstr);
void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[]);
/* console std lib (register ingame commands/aliases/variables) */
void IConsoleStdLibRegister();
void IConsoleStdLibRegister(void);
/* Hooking code */
void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc);
@@ -131,9 +157,4 @@ void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc);
/* Supporting functions */
bool GetArgumentInteger(uint32 *value, const char *arg);
void IConsoleGUIInit();
void IConsoleGUIFree();
void IConsoleGUIPrint(ConsoleColour colour_code, char *string);
#endif /* CONSOLE_INTERNAL_H */
#endif /* CONSOLE_H */

1608
console_cmds.c Normal file

File diff suppressed because it is too large Load Diff

182
currency.c Normal file
View File

@@ -0,0 +1,182 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "currency.h"
#include "news.h"
#include "variables.h"
#include "table/strings.h"
#include "date.h"
// exchange rate prefix symbol_pos
// | separator | postfix |
// | | Euro year | | | name
// | | | | | | |
static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
{ 1, ',', CF_NOEURO, "£", "", 0, STR_CURR_GBP }, // british pounds
{ 2, ',', CF_NOEURO, "$", "", 0, STR_CURR_USD }, // us dollars
{ 2, ',', CF_ISEURO, "", "", 0, STR_CURR_EUR }, // Euro
{ 220, ',', CF_NOEURO, "¥", "", 0, STR_CURR_YEN }, // yen
{ 20, ',', 2002, "", " S.", 1, STR_CURR_ATS }, // austrian schilling
{ 59, ',', 2002, "BEF ", "", 0, STR_CURR_BEF }, // belgian franc
{ 2, ',', CF_NOEURO, "CHF ", "", 0, STR_CURR_CHF }, // swiss franc
{ 41, ',', CF_NOEURO, "", "", 1, STR_CURR_CZK }, // czech koruna
{ 3, '.', 2002, "DM ", "", 0, STR_CURR_DEM }, // deutsche mark
{ 11, '.', CF_NOEURO, "", " kr", 1, STR_CURR_DKK }, // danish krone
{ 245, '.', 2002, "Pts ", "", 0, STR_CURR_ESP }, // spanish pesetas
{ 9, ',', 2002, "", " mk", 1, STR_CURR_FIM }, // finnish markka
{ 10, '.', 2002, "FF ", "", 0, STR_CURR_FRF }, // french francs
{ 500, ',', 2002, "", "Dr.", 1, STR_CURR_GRD }, // greek drachma
{ 378, ',', 2010, "", " Ft", 1, STR_CURR_HUF }, // hungarian forint
{ 130, '.', CF_NOEURO, "", " Kr", 1, STR_CURR_ISK }, // icelandic krona
{ 2850, ',', 2002, "", " L.", 1, STR_CURR_ITL }, // italian lira
{ 3, ',', 2002, "NLG ", "", 0, STR_CURR_NLG }, // dutch gulden
{ 12, '.', CF_NOEURO, "", " Kr", 1, STR_CURR_NOK }, // norwegian krone
{ 6, ' ', CF_NOEURO, "", " zl", 1, STR_CURR_PLN }, // polish zloty
{ 5, '.', CF_NOEURO, "", " Lei", 1, STR_CURR_ROL }, // romanian Lei
{ 50, ' ', CF_NOEURO, "", " p", 1, STR_CURR_RUR }, // russian rouble
{ 352, '.', CF_NOEURO, "", " SIT", 1, STR_CURR_SIT }, // slovenian tolar
{ 13, '.', CF_NOEURO, "", " Kr", 1, STR_CURR_SEK }, // swedish krona
{ 3, '.', CF_NOEURO, "", " YTL", 1, STR_CURR_YTL }, // turkish lira
{ 52, ',', CF_NOEURO, "", " Sk", 1, STR_CURR_SKK }, // slovak koruna
{ 4, ',', CF_NOEURO, "R$ ", "", 0, STR_CURR_BRR }, // brazil real
{ 1, ' ', CF_NOEURO, "", "", 2, STR_CURR_CUSTOM }, // custom currency
};
/* Array of currencies used by the system */
CurrencySpec _currency_specs[NUM_CURRENCY];
/**
* These enums are only declared in order to make sens
* out of the TTDPatch_To_OTTDIndex array that will follow
* Every currency used by Ottd is there, just in case TTDPatch will
* add those missing in its code
**/
enum {
CURR_GBP,
CURR_USD,
CURR_EUR,
CURR_YEN,
CURR_ATS,
CURR_BEF,
CURR_CHF,
CURR_CZK,
CURR_DEM,
CURR_DKK,
CURR_ESP,
CURR_FIM,
CURR_FRF,
CURR_GRD,
CURR_HUF,
CURR_ISK,
CURR_ITL,
CURR_NLG,
CURR_NOK,
CURR_PLN,
CURR_ROL,
CURR_RUR,
CURR_SIT,
CURR_SEK,
CURR_YTL,
};
/**
* This array represent the position of OpenTTD's currencies,
* compared to TTDPatch's ones.
* When a grf sends currencies, they are based on the order defined by TTDPatch.
* So, we must reindex them to our own order.
**/
const byte TTDPatch_To_OTTDIndex[] =
{
CURR_GBP,
CURR_USD,
CURR_FRF,
CURR_DEM,
CURR_YEN,
CURR_ESP,
CURR_HUF,
CURR_PLN,
CURR_ATS,
CURR_BEF,
CURR_DKK,
CURR_FIM,
CURR_GRD,
CURR_CHF,
CURR_NLG,
CURR_ITL,
CURR_SEK,
CURR_RUR,
CURR_EUR,
};
/**
* Will return the ottd's index correspondance to
* the ttdpatch's id. If the id is bigger then the array,
* it is a grf written for ottd, thus returning the same id.
* Only called from newgrf.c
* @param grfcurr_id currency id coming from newgrf
* @return the corrected index
**/
byte GetNewgrfCurrencyIdConverted(byte grfcurr_id)
{
return (grfcurr_id >= lengthof(TTDPatch_To_OTTDIndex)) ? grfcurr_id : TTDPatch_To_OTTDIndex[grfcurr_id];
}
/* get a mask of the allowed currencies depending on the year */
uint GetMaskOfAllowedCurrencies(void)
{
uint mask = 0;
uint i;
for (i = 0; i < NUM_CURRENCY; i++) {
Year to_euro = _currency_specs[i].to_euro;
if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue;
if (to_euro == CF_ISEURO && _cur_year < 2000) continue;
mask |= (1 << i);
}
mask |= (1 << CUSTOM_CURRENCY_ID); // always allow custom currency
return mask;
}
/**
* Verify if the currency chosen by the user is about to be converted to Euro
**/
void CheckSwitchToEuro(void)
{
if (_currency_specs[_opt.currency].to_euro != CF_NOEURO &&
_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
_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);
}
}
/**
* Called only from newgrf.c. Will fill _currency_specs array with
* default values from origin_currency_specs
**/
void ResetCurrencies(void)
{
memcpy(&_currency_specs, &origin_currency_specs, sizeof(origin_currency_specs));
}
/**
* Build a list of currency names StringIDs to use in a dropdown list
* @return Pointer to a (static) array of StringIDs
*/
StringID* BuildCurrencyDropdown(void)
{
/* Allow room for all currencies, plus a terminator entry */
static StringID names[CUSTOM_CURRENCY_ID];
uint i;
/* Add each name */
for (i = 0; i < NUM_CURRENCY; i++) {
names[i] = _currency_specs[i].name;
}
/* Terminate the list */
names[i] = INVALID_STRING_ID;
return names;
}

View File

@@ -1,21 +1,16 @@
/* $Id$ */
/** @file currency.h Functions to handle different currencies. */
#ifndef CURRENCY_H
#define CURRENCY_H
#include "date_type.h"
#include "strings_type.h"
enum {
CF_NOEURO = 0,
CF_ISEURO = 1,
NUM_CURRENCY = 29,
NUM_CURRENCY = 28,
CUSTOM_CURRENCY_ID = NUM_CURRENCY - 1
};
struct CurrencySpec {
typedef struct {
uint16 rate;
char separator;
Year to_euro;
@@ -32,19 +27,19 @@ struct CurrencySpec {
*/
byte symbol_pos;
StringID name;
};
} CurrencySpec;
extern CurrencySpec _currency_specs[NUM_CURRENCY];
/* XXX small hack, but makes the rest of the code a bit nicer to read */
// XXX small hack, but makes the rest of the code a bit nicer to read
#define _custom_currency (_currency_specs[CUSTOM_CURRENCY_ID])
#define _currency ((const CurrencySpec*)&_currency_specs[_game_mode == GM_MENU ? _settings_newgame.locale.currency : _settings_game.locale.currency])
#define _currency ((const CurrencySpec*)&_currency_specs[_opt_ptr->currency])
uint GetMaskOfAllowedCurrencies();
void CheckSwitchToEuro();
void ResetCurrencies(bool preserve_custom = true);
StringID *BuildCurrencyDropdown();
uint GetMaskOfAllowedCurrencies(void);
void CheckSwitchToEuro(void);
void ResetCurrencies(void);
StringID* BuildCurrencyDropdown(void);
byte GetNewgrfCurrencyIdConverted(byte grfcurr_id);
#endif /* CURRENCY_H */

BIN
data/2ccmap.grf Normal file

Binary file not shown.

BIN
data/airports.grf Normal file

Binary file not shown.

BIN
data/autorail.grf Normal file

Binary file not shown.

BIN
data/canalsw.grf Normal file

Binary file not shown.

BIN
data/dosdummy.grf Normal file

Binary file not shown.

BIN
data/elrailsw.grf Normal file

Binary file not shown.

BIN
data/nsignalsw.grf Normal file

Binary file not shown.

BIN
data/openttd.grf Normal file

Binary file not shown.

BIN
data/opntitle.dat Normal file

Binary file not shown.

BIN
data/trkfoundw.grf Normal file

Binary file not shown.

View File

@@ -1,25 +1,20 @@
/* $Id$ */
/** @file date.cpp Handling of dates in our native format and transforming them to something human readable. */
#include "stdafx.h"
#include "openttd.h"
#include "date.h"
#include "variables.h"
#include "settings_type.h"
#include "network/network.h"
#include "network/network_func.h"
#include "currency.h"
#include "window_func.h"
#include "macros.h"
#include "vehicle.h"
#include "network.h"
#include "network_data.h"
#include "network_server.h"
#include "functions.h"
#include "date_func.h"
#include "vehicle_base.h"
#include "debug.h"
#include "rail_gui.h"
#include "saveload/saveload.h"
#include "currency.h"
Year _cur_year; ///< Current year, starting at 0
Month _cur_month; ///< Current month (0..11)
Date _date; ///< Current date in days (day counter)
Year _cur_year;
Month _cur_month;
Date _date;
DateFract _date_fract;
@@ -31,6 +26,10 @@ void SetDate(Date date)
ConvertDateToYMD(date, &ymd);
_cur_year = ymd.year;
_cur_month = ymd.month;
#ifdef ENABLE_NETWORK
_network_last_advertise_frame = 0;
_network_need_advertise = true;
#endif /* ENABLE_NETWORK */
}
#define M(a, b) ((a << 5) | b)
@@ -71,6 +70,11 @@ static const uint16 _accum_days_for_month[] = {
ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
};
static inline bool IsLeapYear(Year yr)
{
return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
}
/**
* Converts a Date to a Year, Month & Day.
* @param date the date to convert from
@@ -84,35 +88,35 @@ void ConvertDateToYMD(Date date, YearMonthDay *ymd)
*/
/* There are 97 leap years in 400 years */
Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97));
int rem = date % (DAYS_IN_YEAR * 400 + 97);
Year yr = 400 * (date / (365 * 400 + 97));
int rem = date % (365 * 400 + 97);
uint16 x;
if (rem >= DAYS_IN_YEAR * 100 + 25) {
if (rem >= 365 * 100 + 25) {
/* There are 25 leap years in the first 100 years after
* every 400th year, as every 400th year is a leap year */
yr += 100;
rem -= DAYS_IN_YEAR * 100 + 25;
rem -= 365 * 100 + 25;
/* There are 24 leap years in the next couple of 100 years */
yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24));
rem = (rem % (DAYS_IN_YEAR * 100 + 24));
yr += 100 * (rem / (365 * 100 + 24));
rem = (rem % (365 * 100 + 24));
}
if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) {
if (!IsLeapYear(yr) && rem >= 365 * 4) {
/* The first 4 year of the century are not always a leap year */
yr += 4;
rem -= DAYS_IN_YEAR * 4;
rem -= 365 * 4;
}
/* There is 1 leap year every 4 years */
yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1));
rem = rem % (DAYS_IN_YEAR * 4 + 1);
yr += 4 * (rem / (365 * 4 + 1));
rem = rem % (365 * 4 + 1);
/* The last (max 3) years to account for; the first one
* can be, but is not necessarily a leap year */
while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) {
rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
while (rem >= (IsLeapYear(yr) ? 366 : 365)) {
rem -= IsLeapYear(yr) ? 366 : 365;
yr++;
}
@@ -149,34 +153,55 @@ Date ConvertYMDToDate(Year year, Month month, Day day)
/* Account for the missing of the 29th of February in non-leap years */
if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
return year * DAYS_IN_YEAR + nr_of_leap_years + days;
return year * 365 + nr_of_leap_years + days;
}
/** Functions used by the IncreaseDate function */
extern void WaypointsDailyLoop();
extern void EnginesDailyLoop();
extern void DisasterDailyLoop();
extern void IndustryDailyLoop();
extern void CompaniesMonthlyLoop();
extern void EnginesMonthlyLoop();
extern void TownsMonthlyLoop();
extern void IndustryMonthlyLoop();
extern void StationMonthlyLoop();
extern void OnNewDay_Train(Vehicle *v);
extern void OnNewDay_RoadVeh(Vehicle *v);
extern void OnNewDay_Aircraft(Vehicle *v);
extern void OnNewDay_Ship(Vehicle *v);
static void OnNewDay_EffectVehicle(Vehicle *v) { /* empty */ }
extern void OnNewDay_DisasterVehicle(Vehicle *v);
extern void CompaniesYearlyLoop();
extern void VehiclesYearlyLoop();
extern void TownsYearlyLoop();
typedef void OnNewVehicleDayProc(Vehicle *v);
extern void ShowEndGameChart();
static OnNewVehicleDayProc * _on_new_vehicle_day_proc[] = {
OnNewDay_Train,
OnNewDay_RoadVeh,
OnNewDay_Ship,
OnNewDay_Aircraft,
OnNewDay_EffectVehicle,
OnNewDay_DisasterVehicle,
};
extern void WaypointsDailyLoop(void);
extern void TextMessageDailyLoop(void);
extern void EnginesDailyLoop(void);
extern void DisasterDailyLoop(void);
extern void PlayersMonthlyLoop(void);
extern void EnginesMonthlyLoop(void);
extern void TownsMonthlyLoop(void);
extern void IndustryMonthlyLoop(void);
extern void StationMonthlyLoop(void);
extern void PlayersYearlyLoop(void);
extern void TrainsYearlyLoop(void);
extern void RoadVehiclesYearlyLoop(void);
extern void AircraftYearlyLoop(void);
extern void ShipsYearlyLoop(void);
extern void ShowEndGameChart(void);
static const Month _autosave_months[] = {
0, ///< never
1, ///< every month
3, ///< every 3 months
6, ///< every 6 months
12, ///< every 12 months
0, // never
1, // every month
3, // every 3 months
6, // every 6 months
12, // every 12 months
};
/**
@@ -190,15 +215,11 @@ static void RunVehicleDayProc(uint daytick)
for (i = daytick; i < total; i += DAY_TICKS) {
Vehicle *v = GetVehicle(i);
if (v->IsValid()) {
/* Call the 32-day callback if needed */
CheckVehicle32Day(v);
v->OnNewDay();
}
if (IsValidVehicle(v)) _on_new_vehicle_day_proc[v->type - 0x10](v);
}
}
void IncreaseDate()
void IncreaseDate(void)
{
YearMonthDay ymd;
@@ -219,13 +240,10 @@ void IncreaseDate()
/* yeah, increase day counter and call various daily loops */
_date++;
#ifdef ENABLE_NETWORK
NetworkChatMessageDailyLoop();
#endif /* ENABLE_NETWORK */
TextMessageDailyLoop();
DisasterDailyLoop();
WaypointsDailyLoop();
IndustryDailyLoop();
if (_game_mode != GM_MENU) {
InvalidateWindowWidget(WC_STATUS_BAR, 0, 0);
@@ -239,26 +257,17 @@ void IncreaseDate()
/* yes, call various monthly loops */
if (_game_mode != GM_MENU) {
if (_debug_desync_level > 2) {
char name[MAX_PATH];
snprintf(name, lengthof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR);
}
if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) {
if (_opt.autosave != 0 && (_cur_month % _autosave_months[_opt.autosave]) == 0) {
_do_autosave = true;
RedrawAutosave();
}
InvalidateWindowClasses(WC_CHEATS);
CompaniesMonthlyLoop();
PlayersMonthlyLoop();
EnginesMonthlyLoop();
TownsMonthlyLoop();
IndustryMonthlyLoop();
StationMonthlyLoop();
#ifdef ENABLE_NETWORK
if (_network_server) NetworkServerMonthlyLoop();
#endif /* ENABLE_NETWORK */
}
/* check if we entered a new year? */
@@ -266,34 +275,30 @@ void IncreaseDate()
_cur_year = ymd.year;
/* yes, call various yearly loops */
CompaniesYearlyLoop();
VehiclesYearlyLoop();
TownsYearlyLoop();
#ifdef ENABLE_NETWORK
PlayersYearlyLoop();
TrainsYearlyLoop();
RoadVehiclesYearlyLoop();
AircraftYearlyLoop();
ShipsYearlyLoop();
if (_network_server) NetworkServerYearlyLoop();
#endif /* ENABLE_NETWORK */
if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
/* check if we reached end of the game */
if (_cur_year == ORIGINAL_END_YEAR) {
ShowEndGameChart();
if (_cur_year == _patches.ending_year) {
ShowEndGameChart();
/* check if we reached the maximum year, decrement dates by a year */
} else if (_cur_year == MAX_YEAR + 1) {
Vehicle *v;
uint days_this_year;
_cur_year--;
days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
days_this_year = IsLeapYear(_cur_year) ? 366 : 365;
_date -= days_this_year;
FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
#ifdef ENABLE_NETWORK
/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
* all of them if the date is set back, else those messages will hang for ever */
NetworkInitChatMessage();
#endif /* ENABLE_NETWORK */
InitTextMessage();
}
if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
if (_patches.auto_euro) CheckSwitchToEuro();
}

View File

@@ -1,9 +1,7 @@
/* $Id$ */
/** @file date_type.h Types related to the dates in OpenTTD. */
#ifndef DATE_TYPE_H
#define DATE_TYPE_H
#ifndef DATE_H
#define DATE_H
/**
* 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On
@@ -11,11 +9,7 @@
* 1 tick is approximately 30 ms.
* 1 day is thus about 2 seconds (74 * 30 = 2220) on a machine that can run OpenTTD normally
*/
enum {
DAY_TICKS = 74, ///< ticks per day
DAYS_IN_YEAR = 365, ///< days per year
DAYS_IN_LEAP_YEAR = 366, ///< sometimes, you need one day more...
};
#define DAY_TICKS 74
/*
* ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR and DAYS_TILL_ORIGINAL_BASE_YEAR are
@@ -26,8 +20,6 @@ enum {
/** The minimum starting year/base year of the original TTD */
#define ORIGINAL_BASE_YEAR 1920
/** The original ending year */
#define ORIGINAL_END_YEAR 2051
/** The maximum year of the original TTD */
#define ORIGINAL_MAX_YEAR 2090
@@ -35,7 +27,7 @@ enum {
* The offset in days from the '_date == 0' till
* 'ConvertYMDToDate(ORIGINAL_BASE_YEAR, 0, 1)'
*/
#define DAYS_TILL_ORIGINAL_BASE_YEAR (DAYS_IN_YEAR * ORIGINAL_BASE_YEAR + ORIGINAL_BASE_YEAR / 4 - ORIGINAL_BASE_YEAR / 100 + ORIGINAL_BASE_YEAR / 400)
#define DAYS_TILL_ORIGINAL_BASE_YEAR (365 * ORIGINAL_BASE_YEAR + ORIGINAL_BASE_YEAR / 4 - ORIGINAL_BASE_YEAR / 100 + ORIGINAL_BASE_YEAR / 400)
/* The absolute minimum & maximum years in OTTD */
#define MIN_YEAR 0
@@ -43,24 +35,25 @@ enum {
* be encoded in a single 32 bits date, about 2^31 / 366 years. */
#define MAX_YEAR 5000000
typedef int32 Date;
typedef uint16 DateFract;
typedef int32 Year;
/* Year and Date are defined elsewhere */
typedef uint8 Month;
typedef uint8 Day;
typedef uint16 DateFract;
/**
* Data structure to convert between Date and triplet (year, month, and day).
* @see ConvertDateToYMD(), ConvertYMDToDate()
*/
struct YearMonthDay {
Year year; ///< Year (0...)
Month month; ///< Month (0..11)
Day day; ///< Day (1..31)
};
typedef struct YearMonthDay {
Year year;
Month month;
Day day;
} YearMonthDay;
static const Year INVALID_YEAR = -1;
static const Date INVALID_DATE = -1;
extern Year _cur_year;
extern Month _cur_month;
extern Date _date;
extern DateFract _date_fract;
#endif /* DATE_TYPE_H */
void SetDate(Date date);
void ConvertDateToYMD(Date date, YearMonthDay *ymd);
Date ConvertYMDToDate(Year year, Month month, Day day);
#endif /* DATE_H */

View File

@@ -1,19 +1,13 @@
/* $Id$ */
/** @file debug.cpp Handling of printing debug messages. */
#include "stdafx.h"
#include <stdio.h>
#include <stdarg.h>
#include "console_func.h"
#include "openttd.h"
#include "console.h"
#include "debug.h"
#include "string_func.h"
#include "network/core/core.h"
#include "fileio_func.h"
#if defined(ENABLE_NETWORK)
SOCKET _debug_socket = INVALID_SOCKET;
#endif /* ENABLE_NETWORK */
#include "functions.h"
#include "string.h"
int _debug_ai_level;
int _debug_driver_level;
@@ -22,22 +16,30 @@ int _debug_map_level;
int _debug_misc_level;
int _debug_ms_level;
int _debug_net_level;
int _debug_sprite_level;
int _debug_spritecache_level;
int _debug_oldloader_level;
int _debug_ntp_level;
int _debug_npf_level;
int _debug_yapf_level;
int _debug_freetype_level;
int _debug_sl_level;
int _debug_station_level;
int _debug_gamelog_level;
int _debug_desync_level;
struct DebugLevel {
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[] = {
@@ -48,70 +50,22 @@ struct DebugLevel {
DEBUG_LEVEL(misc),
DEBUG_LEVEL(ms),
DEBUG_LEVEL(net),
DEBUG_LEVEL(sprite),
DEBUG_LEVEL(spritecache),
DEBUG_LEVEL(oldloader),
DEBUG_LEVEL(ntp),
DEBUG_LEVEL(npf),
DEBUG_LEVEL(yapf),
DEBUG_LEVEL(freetype),
DEBUG_LEVEL(sl),
DEBUG_LEVEL(station),
DEBUG_LEVEL(gamelog),
DEBUG_LEVEL(desync),
DEBUG_LEVEL(freetype)
};
#undef DEBUG_LEVEL
#if !defined(NO_DEBUG_MESSAGES)
static void debug_print(const char *dbg, const char *buf)
{
#if defined(ENABLE_NETWORK)
if (_debug_socket != INVALID_SOCKET) {
char buf2[1024 + 32];
snprintf(buf2, lengthof(buf2), "dbg: [%s] %s\n", dbg, buf);
send(_debug_socket, buf2, (int)strlen(buf2), 0);
} else
#endif /* ENABLE_NETWORK */
if (strcmp(dbg, "desync") != 0) {
#if defined(WINCE)
/* We need to do OTTD2FS twice, but as it uses a static buffer, we need to store one temporary */
TCHAR tbuf[512];
_sntprintf(tbuf, sizeof(tbuf), _T("%s"), OTTD2FS(dbg));
NKDbgPrintfW(_T("dbg: [%s] %s\n"), tbuf, OTTD2FS(buf));
#else
fprintf(stderr, "dbg: [%s] %s\n", dbg, buf);
#endif
IConsoleDebug(dbg, buf);
} else {
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
if (f == NULL) return;
fprintf(f, "%s", buf);
fflush(f);
}
}
void CDECL debug(const char *dbg, const char *format, ...)
{
char buf[1024];
va_list va;
va_start(va, format);
vsnprintf(buf, lengthof(buf), format, va);
va_end(va);
debug_print(dbg, buf);
}
#endif /* NO_DEBUG_MESSAGES */
void SetDebugString(const char *s)
{
int v;
char *end;
const char *t;
/* global debugging level? */
// global debugging level?
if (*s >= '0' && *s <= '9') {
const DebugLevel *i;
@@ -121,19 +75,19 @@ void SetDebugString(const char *s)
for (i = debug_level; i != endof(debug_level); ++i) *i->level = v;
}
/* individual levels */
// individual levels
for (;;) {
const DebugLevel *i;
int *p;
/* skip delimiters */
// skip delimiters
while (*s == ' ' || *s == ',' || *s == '\t') s++;
if (*s == '\0') break;
t = s;
while (*s >= 'a' && *s <= 'z') s++;
/* check debugging levels */
// 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) {
@@ -147,7 +101,7 @@ void SetDebugString(const char *s)
if (p != NULL) {
*p = v;
} else {
ShowInfoF("Unknown debug level '%.*s'", (int)(s - t), t);
ShowInfoF("Unknown debug level '%.*s'", s - t, t);
return;
}
}
@@ -157,10 +111,10 @@ void SetDebugString(const char *s)
* Just return a string with the values of all the debug categorites
* @return string with debug-levels
*/
const char *GetDebugString()
const char *GetDebugString(void)
{
const DebugLevel *i;
static char dbgstr[150];
static char dbgstr[100];
char dbgval[20];
memset(dbgstr, 0, sizeof(dbgstr));
@@ -169,7 +123,7 @@ const char *GetDebugString()
for (i++; i != endof(debug_level); i++) {
snprintf(dbgval, sizeof(dbgval), ", %s=%d", i->name, *i->level);
strecat(dbgstr, dbgval, lastof(dbgstr));
ttd_strlcat(dbgstr, dbgval, sizeof(dbgstr));
}
return dbgstr;

54
debug.h Normal file
View File

@@ -0,0 +1,54 @@
/* $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;
extern int _debug_yapf_level;
extern int _debug_freetype_level;
#endif
void CDECL debug(const char *s, ...);
void SetDebugString(const char *s);
const char *GetDebugString(void);
/* MSVCRT of course has to have a different syntax for long long *sigh* */
#if defined(_MSC_VER) || defined(__MINGW32__)
# define OTTD_PRINTF64 "I64"
#else
# define OTTD_PRINTF64 "ll"
#endif
// Used for profiling
#define TIC() {\
extern uint64 _rdtsc(void);\
uint64 _xxx_ = _rdtsc();\
static uint64 __sum__ = 0;\
static uint32 __i__ = 0;
#define TOC(str, count)\
__sum__ += _rdtsc() - _xxx_;\
if (++__i__ == count) {\
printf("[%s]: %" OTTD_PRINTF64 "u [avg: %.1f]\n", str, __sum__, __sum__/(double)__i__);\
__i__ = 0;\
__sum__ = 0;\
}\
}
#endif /* DEBUG_H */

View File

@@ -1,26 +1,18 @@
/* $Id$ */
/** @file dedicated.cpp Forking support for dedicated servers. */
#include "stdafx.h"
#ifdef ENABLE_NETWORK
#if defined(UNIX) && !defined(__MORPHOS__)
#include "openttd.h"
#include "variables.h"
#include <sys/types.h>
#include <unistd.h>
#if defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx)
/* Solaris has, in certain situation, pid_t defined as long, while in other
* cases it has it defined as int... this handles all cases nicely. */
# define PRINTF_PID_T "%ld"
#else
# define PRINTF_PID_T "%d"
#endif
void DedicatedFork()
void DedicatedFork(void)
{
/* Fork the program */
pid_t pid = fork();
@@ -30,7 +22,7 @@ void DedicatedFork()
exit(1);
case 0: { // We're the child
FILE *f;
FILE* f;
/* Open the log-file to log all stuff too */
f = fopen(_log_file, "a");
@@ -51,9 +43,9 @@ void DedicatedFork()
}
default:
/* We're the parent */
// We're the parent
printf("Loading dedicated server...\n");
printf(" - Forked to background with pid " PRINTF_PID_T "\n", pid);
printf(" - Forked to background with pid %d\n", pid);
exit(0);
}
}
@@ -61,7 +53,6 @@ void DedicatedFork()
#else
/** Empty helper function call for NOT(UNIX and not MORPHOS) systems */
void DedicatedFork() {}
void DedicatedFork(void) {}
#endif /* ENABLE_NETWORK */

127
depot.c Normal file
View File

@@ -0,0 +1,127 @@
/* $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"
/**
* Called if a new block is added to the depot-pool
*/
static void DepotPoolNewBlock(uint start_item)
{
Depot *d;
/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
* TODO - This is just a temporary stage, this will be removed. */
for (d = GetDepot(start_item); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) d->index = start_item++;
}
DEFINE_OLD_POOL(Depot, Depot, DepotPoolNewBlock, 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 *d;
/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
* TODO - This is just a temporary stage, this will be removed. */
for (d = GetDepot(0); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) {
if (!IsValidDepot(d)) {
DepotID index = d->index;
memset(d, 0, sizeof(Depot));
d->index = index;
return d;
}
}
/* Check if we can add a block to the pool */
if (AddBlockToPool(&_Depot_pool)) return AllocateDepot();
return NULL;
}
/**
* Clean up a depot
*/
void DestroyDepot(Depot *depot)
{
/* Clear the tile */
DoClearSquare(depot->xy);
/* Clear the depot from all order-lists */
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, depot->index);
/* Delete the depot-window */
DeleteWindowById(WC_VEHICLE_DEPOT, depot->xy);
}
void InitializeDepots(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, SL_MAX_VERSION),
SLE_VAR(Depot, town_index, SLE_UINT16),
SLE_END()
};
static void Save_DEPT(void)
{
Depot *depot;
FOR_ALL_DEPOTS(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},
};

112
depot.h Normal file
View File

@@ -0,0 +1,112 @@
/* $Id$ */
#ifndef DEPOT_H
#define DEPOT_H
/** @file depot.h Header files for depots (not hangars)
* @see depot.c */
#include "direction.h"
#include "oldpool.h"
#include "tile.h"
#include "variables.h"
struct Depot {
TileIndex xy;
TownID town_index;
DepotID index;
};
DECLARE_OLD_POOL(Depot, Depot, 3, 8000)
/**
* Check if a depot really exists.
*/
static inline bool IsValidDepot(const Depot *depot)
{
return depot != NULL && depot->xy != 0;
}
static inline bool IsValidDepotID(uint index)
{
return index < GetDepotPoolSize() && IsValidDepot(GetDepot(index));
}
void DestroyDepot(Depot *depot);
static inline void DeleteDepot(Depot *depot)
{
DestroyDepot(depot);
depot->xy = 0;
}
void ShowDepotWindow(TileIndex tile, byte type);
#define FOR_ALL_DEPOTS_FROM(d, start) for (d = GetDepot(start); d != NULL; d = (d->index + 1U < GetDepotPoolSize()) ? GetDepot(d->index + 1U) : NULL) if (IsValidDepot(d))
#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 Date GetServiceIntervalClamped(uint index)
{
return (_patches.servint_ispercent) ? clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
}
/**
* 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;
}
}
/**
* 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 >> direction) & tileh) determines whether the depot can be built on the current tileh
*/
static inline bool CanBuildDepotByTileh(uint32 direction, Slope tileh)
{
return ((0x4C >> direction) & tileh) != 0;
}
Depot *GetDepotByTile(TileIndex tile);
void InitializeDepots(void);
Depot *AllocateDepot(void);
void DeleteDepotHighlightOfVehicle(const Vehicle *v);
#endif /* DEPOT_H */

1016
depot_gui.c Normal file

File diff suppressed because it is too large Load Diff

147
direction.h Normal file
View File

@@ -0,0 +1,147 @@
/* $Id$ */
#ifndef DIRECTION_H
#define DIRECTION_H
/* Direction as commonly used in v->direction, 8 way. */
typedef enum Direction {
DIR_N = 0,
DIR_NE = 1, /* Northeast, upper right on your monitor */
DIR_E = 2,
DIR_SE = 3,
DIR_S = 4,
DIR_SW = 5,
DIR_W = 6,
DIR_NW = 7,
DIR_END,
INVALID_DIR = 0xFF,
} Direction;
static inline Direction ReverseDir(Direction d)
{
return (Direction)(4 ^ d);
}
typedef enum DirDiff {
DIRDIFF_SAME = 0,
DIRDIFF_45RIGHT = 1,
DIRDIFF_90RIGHT = 2,
DIRDIFF_REVERSE = 4,
DIRDIFF_90LEFT = 6,
DIRDIFF_45LEFT = 7
} DirDiff;
static inline DirDiff DirDifference(Direction d0, Direction d1)
{
return (DirDiff)((d0 + 8 - d1) % 8);
}
static inline DirDiff ChangeDirDiff(DirDiff d, DirDiff delta)
{
return (DirDiff)((d + delta) % 8);
}
static inline Direction ChangeDir(Direction d, DirDiff delta)
{
return (Direction)((d + delta) % 8);
}
/* Direction commonly used as the direction of entering and leaving tiles, 4-way */
typedef enum DiagDirection {
DIAGDIR_NE = 0, /* Northeast, upper right on your monitor */
DIAGDIR_SE = 1,
DIAGDIR_SW = 2,
DIAGDIR_NW = 3,
DIAGDIR_END,
INVALID_DIAGDIR = 0xFF,
} DiagDirection;
static inline DiagDirection ReverseDiagDir(DiagDirection d)
{
return (DiagDirection)(2 ^ d);
}
typedef enum DiagDirDiff {
DIAGDIRDIFF_SAME = 0,
DIAGDIRDIFF_90RIGHT = 1,
DIAGDIRDIFF_REVERSE = 2,
DIAGDIRDIFF_90LEFT = 3
} DiagDirDiff;
static inline DiagDirection ChangeDiagDir(DiagDirection d, DiagDirDiff delta)
{
return (DiagDirection)((d + delta) % 4);
}
static inline DiagDirection DirToDiagDir(Direction dir)
{
return (DiagDirection)(dir >> 1);
}
static inline Direction DiagDirToDir(DiagDirection dir)
{
return (Direction)(dir * 2 + 1);
}
/* the 2 axis */
typedef enum Axis {
AXIS_X = 0,
AXIS_Y = 1,
AXIS_END
} Axis;
static inline Axis OtherAxis(Axis a)
{
return (Axis)(a ^ 1);
}
static inline Axis DiagDirToAxis(DiagDirection d)
{
return (Axis)(d & 1);
}
/*
* Converts an Axis to a DiagDirection
* Points always in the positive direction, i.e. S[EW]
*/
static inline DiagDirection AxisToDiagDir(Axis a)
{
return (DiagDirection)(2 - a);
}
/**
* Convert an axis and a flag for north/south into a DiagDirection
* @param ns north -> 0, south -> 1
*/
static inline DiagDirection XYNSToDiagDir(Axis xy, uint ns)
{
return (DiagDirection)(xy * 3 ^ ns * 2);
}
static inline bool IsValidDiagDirection(DiagDirection d)
{
return d < DIAGDIR_END;
}
static inline bool IsValidDirection(Direction d)
{
return d < DIR_END;
}
static inline bool IsValidAxis(Axis d)
{
return d < AXIS_END;
}
#endif /* DIRECTION_H */

1001
disaster_cmd.c Normal file

File diff suppressed because it is too large Load Diff

378
dock_gui.c Normal file
View File

@@ -0,0 +1,378 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "window.h"
#include "station.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "sound.h"
#include "command.h"
#include "variables.h"
static void ShowBuildDockStationPicker(void);
static void ShowBuildDocksDepotPicker(void);
static Axis _ship_depot_direction;
void CcBuildDocks(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(SND_02_SPLAT, tile);
ResetObjectToPlace();
}
}
void CcBuildCanal(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) SndPlayTileFx(SND_02_SPLAT, tile);
}
static void PlaceDocks_Dock(TileIndex tile)
{
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)
{
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)
{
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)
{
VpStartPlaceSizing(tile, VPM_X_AND_Y | GUI_PlaceProc_DemolishArea);
}
static void PlaceDocks_BuildCanal(TileIndex tile)
{
VpStartPlaceSizing(tile, VPM_X_OR_Y);
}
static void PlaceDocks_BuildLock(TileIndex tile)
{
DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_LOCKS));
}
enum {
DTW_CANAL = 3,
DTW_LOCK = 4,
DTW_DEMOLISH = 6,
DTW_DEPOT = 7,
DTW_STATION = 8,
DTW_BUOY = 9
};
static void BuildDocksClick_Canal(Window *w)
{
HandlePlacePushButton(w, DTW_CANAL, SPR_CURSOR_CANAL, 1, PlaceDocks_BuildCanal);
}
static void BuildDocksClick_Lock(Window *w)
{
HandlePlacePushButton(w, DTW_LOCK, SPR_CURSOR_LOCK, 1, PlaceDocks_BuildLock);
}
static void BuildDocksClick_Demolish(Window *w)
{
HandlePlacePushButton(w, DTW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceDocks_DemolishArea);
}
static void BuildDocksClick_Depot(Window *w)
{
if (HandlePlacePushButton(w, DTW_DEPOT, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
}
static void BuildDocksClick_Dock(Window *w)
{
if (HandlePlacePushButton(w, DTW_STATION, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
}
static void BuildDocksClick_Buoy(Window *w)
{
HandlePlacePushButton(w, DTW_BUOY, SPR_CURSOR_BOUY, 1, PlaceDocks_Buoy);
}
static void BuildDocksClick_Landscaping(Window *w)
{
ShowTerraformToolbar();
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_docks_button_proc[] = {
BuildDocksClick_Canal,
BuildDocksClick_Lock,
NULL,
BuildDocksClick_Demolish,
BuildDocksClick_Depot,
BuildDocksClick_Dock,
BuildDocksClick_Buoy,
BuildDocksClick_Landscaping,
};
static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
break;
case WE_CLICK:
if (e->we.click.widget - 3 >= 0 && e->we.click.widget != 5) _build_docks_button_proc[e->we.click.widget - 3](w);
break;
case WE_KEYPRESS:
switch (e->we.keypress.keycode) {
case '1': BuildDocksClick_Canal(w); break;
case '2': BuildDocksClick_Lock(w); break;
case '3': BuildDocksClick_Demolish(w); break;
case '4': BuildDocksClick_Depot(w); break;
case '5': BuildDocksClick_Dock(w); break;
case '6': BuildDocksClick_Buoy(w); break;
case 'l': BuildDocksClick_Landscaping(w); break;
default: return;
}
break;
case WE_PLACE_OBJ:
_place_proc(e->we.place.tile);
break;
case WE_PLACE_DRAG: {
VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
return;
}
case WE_PLACE_MOUSEUP:
if (e->we.place.pt.x != -1) {
if ((e->we.place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
GUIPlaceProcDragXY(e);
} else if (e->we.place.userdata == VPM_X_OR_Y) {
DoCommandP(e->we.place.tile, e->we.place.starttile, _ctrl_pressed, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
}
}
break;
case WE_ABORT_PLACE_OBJ:
RaiseWindowButtons(w);
w = FindWindowById(WC_BUILD_STATION, 0);
if (w != NULL) WP(w,def_d).close = true;
w = FindWindowById(WC_BUILD_DEPOT, 0);
if (w != NULL) WP(w,def_d).close = true;
break;
case WE_PLACE_PRESIZE: {
TileIndex tile_from;
TileIndex tile_to;
tile_from = tile_to = e->we.place.tile;
switch (GetTileSlope(tile_from, NULL)) {
case SLOPE_SW: tile_to += TileDiffXY(-1, 0); break;
case SLOPE_SE: tile_to += TileDiffXY( 0, -1); break;
case SLOPE_NW: tile_to += TileDiffXY( 0, 1); break;
case SLOPE_NE: tile_to += TileDiffXY( 1, 0); break;
default: break;
}
VpSetPresizeRange(tile_from, tile_to);
} break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
}
}
static const Widget _build_docks_toolb_widgets[] = {
{ 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_STICKYBOX, RESIZE_NONE, 7, 146, 157, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_IMGBTN, RESIZE_NONE, 7, 0, 21, 14, 35, SPR_IMG_BUILD_CANAL, STR_BUILD_CANALS_TIP},
{ WWT_IMGBTN, RESIZE_NONE, 7, 22, 43, 14, 35, SPR_IMG_BUILD_LOCK, STR_BUILD_LOCKS_TIP},
{ WWT_PANEL, RESIZE_NONE, 7, 44, 47, 14, 35, 0x0, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 7, 48, 69, 14, 35, SPR_IMG_DYNAMITE, STR_018D_DEMOLISH_BUILDINGS_ETC},
{ WWT_IMGBTN, RESIZE_NONE, 7, 70, 91, 14, 35, SPR_IMG_SHIP_DEPOT, STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},
{ WWT_IMGBTN, RESIZE_NONE, 7, 92, 113, 14, 35, SPR_IMG_SHIP_DOCK, STR_981D_BUILD_SHIP_DOCK},
{ WWT_IMGBTN, RESIZE_NONE, 7, 114, 135, 14, 35, SPR_IMG_BOUY, STR_9834_POSITION_BUOY_WHICH_CAN},
{ WWT_IMGBTN, RESIZE_NONE, 7, 136, 157, 14, 35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP},
{ WIDGETS_END},
};
static const WindowDesc _build_docks_toolbar_desc = {
WDP_ALIGN_TBR, 22, 158, 36,
WC_BUILD_TOOLBAR, 0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_docks_toolb_widgets,
BuildDocksToolbWndProc
};
void ShowBuildDocksToolbar(void)
{
if (!IsValidPlayer(_current_player)) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDesc(&_build_docks_toolbar_desc);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
}
static void BuildDockStationWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE: LowerWindowWidget(w, _station_show_coverage + 3); break;
case WE_PAINT: {
int rad;
if (WP(w,def_d).close) return;
DrawWindowWidgets(w);
rad = (_patches.modified_catchment) ? CA_DOCK : 4;
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
DrawStationCoverageAreaText(4, 50, (uint)-1, rad);
break;
}
case WE_CLICK:
switch (e->we.click.widget) {
case 3:
case 4:
RaiseWindowWidget(w, _station_show_coverage + 3);
_station_show_coverage = e->we.click.widget - 3;
LowerWindowWidget(w, _station_show_coverage + 3);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
}
break;
case WE_MOUSELOOP:
if (WP(w,def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
break;
case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace();
break;
}
}
static const Widget _build_dock_station_widgets[] = {
{ 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_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_TEXTBTN, RESIZE_NONE, 14, 74, 133, 30, 40, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 17, 30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _build_dock_station_desc = {
WDP_AUTO, WDP_AUTO, 148, 75,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_dock_station_widgets,
BuildDockStationWndProc
};
static void ShowBuildDockStationPicker(void)
{
AllocateWindowDesc(&_build_dock_station_desc);
}
static void UpdateDocksDirection(void)
{
if (_ship_depot_direction != AXIS_X) {
SetTileSelectSize(1, 2);
} else {
SetTileSelectSize(2, 1);
}
}
static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE: LowerWindowWidget(w, _ship_depot_direction + 3); break;
case WE_PAINT:
DrawWindowWidgets(w);
DrawShipDepotSprite(67, 35, 0);
DrawShipDepotSprite(35, 51, 1);
DrawShipDepotSprite(135, 35, 2);
DrawShipDepotSprite(167, 51, 3);
return;
case WE_CLICK: {
switch (e->we.click.widget) {
case 3:
case 4:
RaiseWindowWidget(w, _ship_depot_direction + 3);
_ship_depot_direction = e->we.click.widget - 3;
LowerWindowWidget(w, _ship_depot_direction + 3);
SndPlayFx(SND_15_BEEP);
UpdateDocksDirection();
SetWindowDirty(w);
break;
}
} break;
case WE_MOUSELOOP:
if (WP(w,def_d).close) DeleteWindow(w);
break;
case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace();
break;
}
}
static const Widget _build_docks_depot_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 203, 0, 13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 203, 14, 85, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 14, 3, 100, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
{ WWT_PANEL, RESIZE_NONE, 14, 103, 200, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
{ WIDGETS_END},
};
static const WindowDesc _build_docks_depot_desc = {
WDP_AUTO, WDP_AUTO, 204, 86,
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_docks_depot_widgets,
BuildDocksDepotWndProc
};
static void ShowBuildDocksDepotPicker(void)
{
AllocateWindowDesc(&_build_docks_depot_desc);
UpdateDocksDirection();
}
void InitializeDockGui(void)
{
_ship_depot_direction = AXIS_X;
}

View File

@@ -1,36 +0,0 @@
32bpp and OpenTTD
=================
OpenTTD has 32bpp support. This means: OpenTTD still is 8bpp, but it has the
posibility to override the graphics with 32bpp. This means that it isn't a
replacement of grf or newgrf, but simply an addition. If you want to use 32bpp
graphics of a newgrf, you do need the newgrf itself too (with 8bpp graphics).
The Format
----------
32bpp images are stored in PNG. They should go in:
data/sprites/<grfname>/<SpriteID>.png
For example, a grfname would be 'openttd' (without .grf, lowercase), and the
SpriteID 3, to override the 3rd sprite in openttd.grf with a 32bpp version.
The format of this PNG can be almost anything, but we advise to use RGBA
format. Alpha-channel is fully supported.
As the core of OpenTTD is 8bpp, and because you of course want company colours
in your images, you will need to add a mask for every sprite that needs colour
remapping. The name is simular as above, only you have to put a 'm' behind the
SpriteID. This image should be a 8bpp palette image, where the palette is the
OpenTTD palette. Upon load of the PNG, the mask is loaded too, and overrides
the RGB (not the Alpha) of the original PNG image, and replacing it with a
8bpp color remapped and converted to 32bpp.
An other thing that OpenTTD needs in your png, is 2 tEXt chunks: x_offs and
y_offs. This to define the x- and y-offset, of course. Use the tool we supply
to add this information. Sadly enough most graphical editors trashes those
chunks upon save, so you have to readd it every time you save your image.
Your images should be the same as the grf, in size.

View File

@@ -1,15 +1,14 @@
STRGEN USAGE
------------
This guide is only interesting for people who want to alter something
themselves without access to translator.openttd.org. Please note that
themselves without access to WT2 (translator2.openttd.org). Please note that
your compiled language file will only be compatible with the OpenTTD version
you have downloaded english.txt, the master language file, for. While this is
not always true, namely when changes in the code have not touched language
files, your safest bet is to assume this 'limitation'.
As a first step you need to compile strgen. This is as easy as typing
'make strgen'. You can download the precompile strgen from:
http://www.openttd.org/download-strgen
'make strgen'. You can also download a precompiled binary from a release,
nightly, etc.
strgen takes as argument a txt file and translates it to a lng file, allowing
it to be used inside OpenTTD. strgen needs the master language file
english.txt to work. Below are some examples of strgen usage.

View File

@@ -0,0 +1,34 @@
This is a guide to compile strgen on gcc
All this is done in the makefile, so it's only interesting for people, who wants to alter something themselves (translators)
HOWTO compile lng files:
First you get strgen compiled (look below/download nightly build/run makefile)
strgen takes the argument of a txt file and translates it to a lng file and places that lng file in the same dir as the txt file.
Example 1:
if you are in the root of your working copy (svn code), you should type
strgen/strgen lang/english.txt
to compile englist.lng. It will be placed in the lang dir
Example 2:
you have strgen but not the source and you want to compile a txt file in the same dir. YOu should type
./strgen english.txt
and you will get english.lng in the same dir
You can change english to whatever language you want
Commands used by strgen
-v --version
strgen will tell what svn revision it is based on
-t
strgen will add <TODO> to the missing strings and use the english strings while compiling
this will need english.txt to be present
-w
strgen will print any missing strings to standard error output(stderr)
this will need english.txt to be present

View File

@@ -13,7 +13,7 @@ Once you have obtained a recent copy of the source, you must build it. Windows b
On UNIX platforms (including OS-X and BeOS), ensure you have a recent GCC (2.9 or above, or 3 and above).You will also need SDL development headers and libraries (libSDL 1.2 or higher). For PNG screenshot support and zlib compressed games, you will need libpng 1.0.12 or higher and zlib 1.2 or higher.
Most UNIX platforms:
First run ./configure, them use make or gmake to compile OpenTTD. You can configure the different compile options via ./configure.
Use make or gmake to compile OpenTTD. You can adjust Makefile.config to compile with other options.
BeOS:
On BeOS, run ./configure and then use jam. There are a variaty of options you can pass to your build tool, these are reported by ./configure.

View File

@@ -50,10 +50,6 @@ To enable music, start OpenTTD with the command line:
If I hear enough responses that both music and sound work together (it might
just be my system), I'll have the defaults changed.
Please note also that the GCC version does not currently support the MCI MIDI
system.
A NOTE ABOUT DEDICATED MULTIPLAYER SERVERS
------------------------------------------
@@ -64,8 +60,6 @@ directly will result in the console not being displayed. You may
still pass any other parameters ('-D' is already passed) to
dedicated.cmd.
You can find the dedicated.cmd file in the os/os2 directory.
=========================
BUILDING THE OS/2 VERSION
=========================
@@ -73,33 +67,16 @@ BUILDING THE OS/2 VERSION
Compiler
--------
Innotek GCC, an OS/2 port of the popular GCC compiler, was used to build OpenTTD.
See www.innotek.de for more information. You WILL need a reasonably UNIX-like
build environment in order to build OpenTTD successfully - the following link
may help to set one up (although some of the links from that page are broken):
Open Watcom 1.3 was used to build OpenTTD (earlier versions will
NOT work). See http://www.openwatcom.org/ to download it. It may
also be possible to build OpenTTD with GCC: I attempted this
before using Open Watcom, but found the tools available for OS/2
at the time to be a bit more tricky to get working.
http://www.mozilla.org/ports/os2/gccsetup.html
Alternatively, Paul Smedley's ready-to-go GCC build environment has been known to
successfully build the game:
http://www.smedley.info/os2ports/index.php?page=build-environment
To build, you should, if your environment is set up well enough, be able to just
type `./configure' (or `sh configure' if you're using the OS/2 shell) and `make'.
You may have to manually specify `--os OS2' on the configure command line, as
configure cannot always detect OS/2 correctly.
A note on Open Watcom
---------------------
Open Watcom C/C++ was previously used to build OpenTTD (version 0.4.x and earlier).
However, due to advanced C++ features used in the YAPF portion of OpenTTD 0.5
in particular, the compiler is no longer able to build the game at the moment.
Hopefully one day Open Watcom will be able to catch up and we will be able to build
the game once again (it's easier than getting an OS/2 UNIX-like environment set up
in my opinion!), but until then, OpenTTD 0.5 and later can only be built with GCC.
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
be no reason of course why the OS/2 version cannot be used, and I
have subsequently built OpenTTD successfully this way.
Libraries Required
------------------
@@ -110,23 +87,42 @@ to an IDE project file and built a library. Do not use the makefiles
provided, they are not designed for Watcom (apart from SDL):
- zlib
http://www.zlib.org/
http://www.zlib.org/ - contains a makefile for OS/2, but is out
of date and uses EMX, ignore this
- libpng
http://www.libpng.org/
http://www.libpng.org/ - contains an EMX/gcc makefile, ignore this
- SDL for OS/2
ftp://ftp.netlabs.org/pub/sdl/sdl-1.2.7-src-20051222.zip used for
0.4.7
- Freetype
http://freetype.sourceforge.net/
Currently, there are no pre-built libraries available for GCC. If you manage to get
OpenTTD working on Watcom though (do let us know if this is the case!), pre-built
versions can be downloaded from the Files section at
If you do not wish to build the libraries yourself, pre-built versions
can be downloaded from the Files section at
http://sourceforge.net/projects/openttd/ - see "os2-useful-v1.1.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
---------
To compile, open the os/os2/openttd.wpj file in the IDE and first build
the strgen.exe target. This will build the .lng file generator, and will
also attempt to build all the language files (plus the table\strings.h
file which is required for openttd.exe to be built). Once strgen.exe and
the language files are built successfully, you can build the openttd.exe
target.
Contact Information
-------------------
@@ -134,6 +130,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
issues, see the Contacting section of readme.txt.
Thanks to Paul Smedley for his help with getting OpenTTD to compile under GCC on OS/2.
- Owen Rudge, 24th June 2007
- Owen Rudge

View File

@@ -1,17 +1,15 @@
Compiling OpenTTD using Microsoft Visual C++
January 2, 2007
December 28, 2006
--------------------------------------------
PLEASE READ THE ENTIRE DOCUMENT BEFORE DOING ANY ACTUAL CHANGES!!
SUPPORTED MSVC COMPILERS
------------------------
OpenTTD includes projects for MSVC 2005.NET and MSVC 2008.NET. Both will
OpenTTD includes projects for MSVC 2003.NET and MSVC 2005.NET. Both will
compile out of the box, providing you have the required libraries/headers;
which ones, see below. There is no support for VS6 or MSVC 2002, or
MSVC 2003.NET. You are therefore strongly encouraged to either upgrade to
MSVC 2005 Express (free) or use GCC.
which ones, see below. There is no support for VS6, you are therefore
strongly encouraged to either upgrade to MSVC 2005 Express (free) or use GCC.
MSVC 2002 probably works as well, but it has not been tested.
1) REQUIRED FILES
-----------------
@@ -20,7 +18,7 @@ downloading; mostly because the DirectX SDK and Platform SDK are about
500MB each.
Download the following files:
* openttd-useful.zip (http://binaries.openttd.org/extra/openttd-useful/)
* openttd-useful.zip (http://sf.net/project/showfiles.php?group_id=103924&package_id=114307)
* DirectX 8.1 SDK (http://neuron.tuke.sk/~mizanin/eng/Dx81sdk-include-lib.rar) (or alternatively the latest DirectX SDK from Microsoft)
* MS Windows Platform SDK (http://www.microsoft.com/downloads/details.aspx?FamilyId=A55B6B43-E24F-4EA3-A93E-40C0EC4F68E5&displaylang=en)
* afxres.h (http://www-d0.fnal.gov/d0dist/dist/packages/d0ve/devel/windows/AFXRES.H)
@@ -29,9 +27,8 @@ Download the following files:
You need an SVN-client to download the source from subversion:
* CLI Subversion (http://subversion.tigris.org/)
* GUI TortoiseSVN (http://tortoisesvn.tigris.org/)
* CLI Subversion (http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91)
* GUI TortoiseSVN (http://tortoisesvn.tigris.org/download.html)
2) INCLUDES AND LIBRARIES
-------------------------
@@ -59,7 +56,6 @@ include\ directory and the library files to the Lib\ directory.
It is recommended to use custom directories so you don't overwrite any
default header or library files.
2.2) CUSTOM DIRECTORIES
-----------------------
If you have put the above include and/or library files into custom folders,
@@ -73,10 +69,9 @@ Tools > Options > Projects and Solutions > VC++ Directories > show directories f
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!!
3) TTD GRAPHICS FILES
---------------------
Copy the following files from Transport Tycoon Deluxe to the bin/data folder
Copy the following files from Transport Tycoon Deluxe to the data folder
* sample.cat
* trg1r.grf
@@ -88,13 +83,12 @@ Copy the following files from Transport Tycoon Deluxe to the bin/data folder
4) COMPILING
------------
Open trunk/openttd_vs[89]0.sln
Open trunk/openttd[_vs80].sln
Set the build mode to 'Release' in
Build > Configuration manager > Active solution configuration > select "Release"
Compile...
If everything works well the binary should be in trunk/objs/Win[32|64]/Release/openttd.exe
If everything works well the binary should be in trunk/Release/openttd.exe
5) EDITING, CHANGING SOURCE CODE
--------------------------------
@@ -103,7 +97,6 @@ Change the startup project to openttd by right-clicking the 'openttd' project
in the Solution Explorer and selecting 'Set as Startup Project'. The 'openttd'
project should now show up bold instead of 'strgen'.
6) PROBLEMS?
------------
If compilation fails, double-check that you are using the latest SVN (!)
@@ -112,4 +105,4 @@ to ask about reasons; or just wait. The problem will most likely solve itself
within a few days as the problem is noticed and fixed.
An up-to-date version of this README can be found on the wiki:
http://wiki.openttd.org/index.php/MicrosoftVisualCExpress
http://wiki.openttd.org/index.php/MicrosoftVisualCExpress

File diff suppressed because it is too large Load Diff

View File

@@ -1,616 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="Author" content="Marcin Grzegorczyk">
<meta name="Description" content="Structure of OpenTTD (OTTD) landscape arrays">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>OpenTTD Landscape externals</title>
</head>
<body>
<h3><a name="Landscape">Landscape</a></h3>
<p>
These are the different house types available on standard game.<br>
<small>Note: In the climate list, 'sub-arctic' means below the snow line, and 'snow' means above the snow line in the sub-arctic climate.</small>
</p>
<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>
<td nowrap valign=top><tt>00</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>01</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>02</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>small block of flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>03</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>church</td>
</tr>
<tr>
<td nowrap valign=top><tt>04</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-arctic, sub-tropical</td>
<td align=left>large office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>05</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>large office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>06</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>town houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>07</tt>..<tt>08</tt>&nbsp; </td>
<td>1&times;2</td>
<td>temperate</td>
<td align=left>hotel</td>
</tr>
<tr>
<td nowrap valign=top><tt>09</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-arctic, sub-tropical&nbsp;&nbsp;</td>
<td align=left>statue</td>
</tr>
<tr>
<td nowrap valign=top><tt>0A</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-arctic, sub-tropical</td>
<td align=left>fountain</td>
</tr>
<tr>
<td nowrap valign=top><tt>0B</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>park (with a pond)</td>
</tr>
<tr>
<td nowrap valign=top><tt>0C</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>park (with an alley)</td>
</tr>
<tr>
<td nowrap valign=top><tt>0D</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>0E</tt>..<tt>10</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>various types of shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>11</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-arctic, sub-tropical</td>
<td align=left>modern office building</td>
</tr>
<tr>
<td nowrap valign=top><tt>12</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>warehouse</td>
</tr>
<tr>
<td nowrap valign=top><tt>13</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>office block (with spiral stairway on the side)</td>
</tr>
<tr>
<td nowrap valign=top><tt>14</tt>..<tt>17</tt>&nbsp; </td>
<td>2&times;2</td>
<td>temperate</td>
<td align=left>stadium</td>
</tr>
<tr>
<td nowrap valign=top><tt>18</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>old houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>19</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>cottages</td>
</tr>
<tr>
<td nowrap valign=top><tt>1A</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>1B</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>1C</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>1D</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>1E</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-tropical</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>1F</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>theatre</td>
</tr>
<tr>
<td nowrap valign=top><tt>20</tt>..<tt>23</tt>&nbsp; </td>
<td>2&times;2</td>
<td>temperate, sub-arctic, sub-tropical</td>
<td align=left>stadium (modern style)</td>
</tr>
<tr>
<td nowrap valign=top><tt>24</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate, sub-arctic, sub-tropical</td>
<td align=left>offices (the modern 'vertical tube' style)</td>
</tr>
<tr>
<td nowrap valign=top><tt>25</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>26</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>27</tt>&nbsp; </td>
<td>1&times;1</td>
<td>temperate</td>
<td align=left>cinema</td>
</tr>
<tr>
<td nowrap valign=top><tt>28</tt>..<tt>2B</tt>&nbsp; </td>
<td>2&times;2</td>
<td>temperate</td>
<td align=left>shopping mall</td>
</tr>
<tr>
<td nowrap valign=top><tt>2C</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>2D</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>2E</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>2F</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>30</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>31</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>32</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic, sub-tropical</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>33</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>34</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>35</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>36</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic, sub-tropical</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>37</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>38</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>39</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>3A</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>3B</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>3C</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>church</td>
</tr>
<tr>
<td nowrap valign=top><tt>3D</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>church</td>
</tr>
<tr>
<td nowrap valign=top><tt>3E</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>3F</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>40</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>41</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>42</tt>..<tt>43</tt>&nbsp; </td>
<td>1&times;2</td>
<td>sub-arctic</td>
<td align=left>hotel</td>
</tr>
<tr>
<td nowrap valign=top><tt>44</tt>..<tt>45</tt>&nbsp; </td>
<td>1&times;2</td>
<td>snow</td>
<td align=left>hotel</td>
</tr>
<tr>
<td nowrap valign=top><tt>46</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic, sub-tropical</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>47</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>48</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-arctic</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>49</tt>&nbsp; </td>
<td>1&times;1</td>
<td>snow</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>4A</tt>..<tt>4B</tt>&nbsp; </td>
<td>2&times;1</td>
<td>sub-arctic</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>4C</tt>..<tt>4D</tt>&nbsp; </td>
<td>2&times;1</td>
<td>snow</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>4E</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>houses (with a tree in a corner)</td>
</tr>
<tr>
<td nowrap valign=top><tt>4F</tt>, <tt>50</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>51</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>houses (suburb-type)</td>
</tr>
<tr>
<td nowrap valign=top><tt>52</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>53</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>church</td>
</tr>
<tr>
<td nowrap valign=top><tt>54</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>houses (with two trees in front)</td>
</tr>
<tr>
<td nowrap valign=top><tt>55</tt>, <tt>56</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>57</tt>..<tt>58</tt>&nbsp; </td>
<td>2&times;1</td>
<td>sub-tropical</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>59</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>flats</td>
</tr>
<tr>
<td nowrap valign=top><tt>5A</tt>&nbsp; </td>
<td>1&times;1</td>
<td>sub-tropical</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>5B</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>church</td>
</tr>
<tr>
<td nowrap valign=top><tt>5C</tt>..<tt>61</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>various types of toyland houses</td>
</tr>
<tr>
<td nowrap valign=top><tt>62</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>63</tt>..<tt>64</tt>&nbsp; </td>
<td>1&times;2</td>
<td>toyland</td>
<td align=left>houses ('shoe' style)</td>
</tr>
<tr>
<td nowrap valign=top><tt>65</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>66</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>igloo</td>
</tr>
<tr>
<td nowrap valign=top><tt>67</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>tepees</td>
</tr>
<tr>
<td nowrap valign=top><tt>68</tt>, <tt>69</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>shops and offices</td>
</tr>
<tr>
<td nowrap valign=top><tt>6A</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>tall office block</td>
</tr>
<tr>
<td nowrap valign=top><tt>6B</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>statue</td>
</tr>
<tr>
<td nowrap valign=top><tt>6C</tt>&nbsp; </td>
<td>1&times;1</td>
<td>toyland</td>
<td align=left>teapot-house</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>
</table>
</body>
</html>

View File

@@ -6,7 +6,6 @@
<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.option{ font-family: "Courier New", Courier, mono; background-color: rgb(255,255, 30); }
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; }
@@ -17,14 +16,13 @@
</head>
<body style="direction: ltr;">
<h3 style="font-weight: bold;">Landscape</h3>
<span style="font-weight: bold;"></span>Six attributes hold the information about a tile.
<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, i.e. other bits define the actual meaning.</li>
<li><span style="font-weight: bold;"><span class="option">~</span></span> - bit is accessed, but does not really have a meaning (e.g. owner of clear land is always OWNER_NONE)</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>
@@ -34,319 +32,235 @@ the array so you can quickly see what is used and what is not.
<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>
<li><span style="font-weight: bold;">m6</span> - 8 bits in size, special meaning : lower 2 bits only valid in tropic climate, upper 2 bits for bridges</li>
<li><span style="font-weight: bold;">m7</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>type_height (8)</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>
<th>m6 (8)</th>
<th>m7 (8)</th>
</tr>
<tr>
<td colspan=2 class="caption">bits</td>
<td class="bits">7654 3210</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>
<td class="bits">7654 3210</td>
</tr>
<tr>
<td rowspan="2">0</td>
<td class="caption">ground</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~~ ~~~~</span></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">XXXX XX<span class="free">OO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td class="caption">farmland</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOO</span>X XXXX</td>
</tr>
<tr>
<td rowspan=4>1</td>
<td rowspan=3>1</td>
<td class="caption">rail</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~</span>X XXXX</td>
<td class="bits"><span class="free">OOOO</span> XXXX <span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> <span class="option">~~</span>XX</td>
<td class="bits"><span class="free">OOOO</span> 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">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">rail with signals</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO</span> XXXX XXXX XXXX</td>
<td class="bits">XXXX <span class="option">~~</span>XX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">depot</td>
<td class="bits">-inherit-</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> <span class="option">~~</span>XX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XX<span class="free">O</span>X <span class="free">O</span>XXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></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">-inherit-</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits"><span class="free">OOOO</span> <span class="option">~~</span>XX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XX<span class="free">O</span>X <span class="free">OOO</span>X</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></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"><span class="option">~~~</span>X XXXX</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX X<span class="free">O</span>XX</td>
<td class="bits">XXX<span class="free">O</span> 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">-inherit-</td>
<td class="bits">XXXX <span class="option">~~</span>XX</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX<span class="free"> OOO</span>X</td>
<td class="bits">XXXX X<span class="free">O</span>XX</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">-inherit-</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"><span class="free">OOOO OOOO</span></td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits">XXX<span class="free">O 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">house</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</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">XXX<span class="option">~ ~~</span>XX</td>
<td class="bits">XX<span class="free">OO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXX<span class="abuse">X XXXX</span></td>
<td class="bits"><span class="abuse">XXXX XX</span>XX</td>
<td class="bits">XXXX <span class="abuse">XXXX</span></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="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="free">OOOO OOOO</span> XXXX XXXX</td>
<td class="bits"><span class="option">~~</span>XX 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>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=6>5</td>
<td class="caption">rail station</td>
<td>5</td>
<td class="caption">station</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~</span>X XXXX</td>
<td class="bits">XXXX XXXX XXXX XXXX</td>
<td class="bits">XXXX <span class="option">~~</span>XX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OO</span>XX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td class="caption">road stop</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td>6</td>
<td class="caption">water</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="option">~~~~ ~</span>XXX</td>
<td class="bits"><span class="free">OO</span>XX XXXX</td>
<td class="bits">XXXX X<span class="free">O</span>XX</td>
</tr>
<tr>
<td class="caption">dock</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="option">~~~~ ~</span>XXX</td>
<td class="bits"><span class="free">OO</span>XX X<span class="free">O</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">airport</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OO</span>XX X<span class="free">O</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">buoy</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="free">OO</span>XX X<span class="free">O</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">oilrig</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="option">~~~~ ~~~~</span></td>
<td class="bits"><span class="free">OO</span>XX X<span class="free">O</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td rowspan=3>6</td>
<td class="caption">sea, shore</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~</span>X XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">X<span class="option">~~</span>X XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">canal, river</td>
<td class="bits">-inherit-</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 OO</span>XX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td class="caption">shipdepot</td>
<td class="bits">-inherit-</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 OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td>8</td>
<td rowspan=6>8</td>
<td class="caption">industry</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXX<span class="free">O</span> <span class="abuse">
XXXX</span></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>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OO</span>XX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td rowspan=2>9</td>
<td class="caption">tunnel entrance</td>
<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="option">~~~</span>X XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits">XXXX <span class="option">~~</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">X<span class="free">OO</span>X XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits">XXXX X<span class="free">O</span>XX</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=3>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">X<span class="free">OOO</span> XXXX</td>
</tr>
<tr>
<td>bridge ramp</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>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX</span> <span class="free">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">XXX<span class="free">O O</span>XXX</td>
</tr>
<tr>
<td rowspan=2>A</td>
<td class="caption">unmovables</td>
<td>bridge middle part</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="option">~~~</span>X XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOO</span>X 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">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
</tr>
<tr>
<td class="caption">company statue</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</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">-inherit-</td>
<td class="bits">XX<span class="free">OO OO</span>XX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
</tr>
</tbody>
</table>

View File

@@ -1,75 +0,0 @@
;
; Example file for the OpenTTD Base Graphics replacement sets.
; This file consists of basically two different parts:
; * metadata
; * information about the files
;
; Metadata contains information about the name, version and palette
; of the graphics set.
;
; == Getting started ==
; - you can't add comments after values
; - you have to fill the MD5 checksum for each file
; - you may not miss any of the metadata or files items
; - `openttd -h` lists all graphics replacements sets it found to be correct
; - `openttd -d grf=1` shows warnings/errors when parsing an .obg file
; - `openttd -I <name>` starts OpenTTD with the given set (case sensitive)
; - adding `graphicsset = <name>` to the misc section of openttd.cfg makes
; OpenTTD start with that graphics set by default
; - there is a command line tool for all platforms called md5sum that can
; create the MD5 checksum you need.
; - all files specified in this file are search relatively to the path where
; this file is found, i.e. if the graphics files are in a subdir you have
; to add that subdir to the names in this file to! It will NOT search for
; a file named like specified in here.
[metadata]
; the name of the pack, preferably less than 16 characters
name = example
; the short name (4 characters), used to identify this set
shortname = XMPL
; the version of this graphics set (read as single integer)
version = 0
; a fairly short description of the set
description = foo
; palette used by the set; either DOS or Windows
palette = DOS
; The files section lists the files that replace sprites.
; The file names are case sensitive.
[files]
; GRF file with the base sprites
base = TRG1.GRF
; GRF file with logos, original terrain generator sprites
logos = TRGI.GRF
; GRF file with extra arctic sprites
arctic = TRGC.GRF
; GRF file with extra tropical sprites
tropical = TRGH.GRF
; GRF file with extra toyland sprites
toyland = TRGT.GRF
; NewGRF file using Actions 5, 7, 9 and A to replace sprites
; Must use a GRF ID starting with FF so it cannot be selected from
; the in-game NewGRF list and (thus) be loaded twice.
extra = OPENTTDD.GRF
; The md5s section lists the MD5 checksum for the files that replace them.
; Note that the list of files is case sensitive. Each GRF listed in the
; files section must be listed here with it's MD5 checksum, otherwise you
; will get a lot of warnings when starting OpenTTD.
[md5s]
TRG1.GRF = 9311676280e5b14077a8ee41c1b42192
TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8
TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9
TRGC.GRF = ed446637e034104c5559b32c18afe78d
TRGT.GRF = fcde1d7e8a74197d72a62695884b909e
OPENTTDD.GRF = f829f62c137d6d7c6e272c481b796dd5
; The origin section provides the possibility to put and extra line into
; the warning that a file is missing/corrupt. This can be used to tell
; them where to find it. It works on the filename specified in the
; files section and if that is not found it will fall back to the default
; as shown below here.
[origin]
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
OPENTTDD.GRF = This file was part of your installation.

View File

@@ -1,52 +1,34 @@
.\" Hey, EMACS: -*- nroff -*-
.\" Please adjust this date whenever revising the manpage.
.Dd Feb 05, 2009
.Dd January 07, 2007
.Dt OPENTTD 6
.Sh NAME
.Nm openttd
.Nd An open source clone of the Microprose game "Transport Tycoon Deluxe"
.Sh SYNOPSIS
.Nm
.Op Fl efhx
.Op Fl a Ar ai
.Op Fl b Ar blitter
.Op Fl c Ar config_file
.Op Fl d Ar [level | cat=lvl[, ...]]
.Op Fl D Ar [host][:port]
.Op Fl g Ar [savegame]
.Op Fl Defhi
.Op Fl G Ar seed
.Op Fl i Ar palette
.Op Fl I Ar graphicsset
.Op Fl l Ar host[:port]
.Op Fl m Ar driver
.Op Fl n Ar host[:port][#player]
.Op Fl d Ar [level | cat=lvl[, ...]]
.Op Fl g Ar [savegame]
.Op Fl n Ar [host[#player][:port]]
.Op Fl r Ar widthxheight
.Op Fl t Ar date
.Op Fl m Ar driver
.Op Fl s Ar driver
.Op Fl t Ar year
.Op Fl v Ar driver
.Sh OPTIONS
.Bl -tag -width ".Fl n Ar host[:port][#player]"
.It Fl a Ar ai
Set the AI, see
.Fl h
.It Fl b Ar blitter
Set the blitter, see
.Fl h
.It Fl c Ar config_file
Use 'config_file' instead of 'openttd.cfg'
.Bl -tag -width ".Fl n Ar host[#player][:port]"
.It Fl D
Start a dedicated server
.It Fl G Ar seed
Seed the pseudo random number generator
.It Fl d Ar [level]
Set debug verbosity for all categories to
.Ar level
or 1 if omitted
.It Fl d Ar cat=level[, ...]
Set debug verbosity for a specific category
.It Fl D Ar [host][:port]
Start a dedicated server. Sets network debug level to 6. If you want to change this, use
.Fl d
after
.Fl D
.It Fl G Ar seed
Seed the pseudo random number generator
.It Fl e
Start in world editor mode
.It Fl f
@@ -57,33 +39,26 @@ Load
.Ar savegame
at start or start a new game if omitted
.It Fl h
Display a summary of all options and available AIs, blitters, drivers and graphic sets
.It Fl i Ar palette
Set the palette, see
.Fl h
.It Fl I Ar graphicsset
Set the graphics set, see
.Fl h
.It Fl l Ar host[:port]
Redirect DEBUG(), See
.Fl D
Display a summary of all options and available drivers
.It Fl i
Force to use the DOS palette (use this if you see a lot of magenta)
.It Fl m Ar driver
Set the music driver, see
.Fl h
.It Fl n Ar host[:port][#player]
.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 year
Set the starting year
.It Fl t Ar date
Set the starting date
.It Fl v Ar driver
Set the video driver, see
.Fl h
.It Fl x
Do not automatically save to config file on exit
.El
.Sh SEE ALSO
http://wiki.openttd.org/, http://www.openttd.org

224
driver.c Normal file
View File

@@ -0,0 +1,224 @@
/* $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
#if defined(__OS2__) && !defined(__INNOTEK_LIBC__)
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 char *last)
{
const DriverClass* dc;
for (dc = _driver_classes; dc != endof(_driver_classes); dc++) {
const DriverDesc* dd;
p += snprintf(p, last - p, "List of %s drivers:\n", dc->name);
for (dd = dc->descs; dd->name != NULL; dd++) {
p += snprintf(p, last - p, "%10s: %s\n", dd->name, dd->longname);
}
p = strecpy(p, "\n", last);
}
return p;
}

13
driver.h Normal file
View File

@@ -0,0 +1,13 @@
/* $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, const char *last);
#endif /* DRIVER_H */

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