1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-14 10:09:11 +00:00

Compare commits

..

49 Commits

Author SHA1 Message Date
bjarni
32a2a6b523 (svn r4046) missed a file in last commit 2006-03-22 22:43:03 +00:00
bjarni
316e189bd7 (svn r4045) -Fix: [OSX] fixed header issue 2006-03-22 22:42:14 +00:00
Darkvater
c88ceb9a3e (svn r4043) - Set release version on the executable for VS2003,VS6 and makefile. 2006-03-22 22:30:38 +00:00
Darkvater
d49a748b91 (svn r4042) - Release 0.4.6 2006-03-22 22:26:36 +00:00
matthijs
bb7c37b515 (svn r4041) [Debian] Change next version number to 0.4.6 instead of 0.4.5.1. 2006-03-22 22:26:16 +00:00
Darkvater
ec54b3ac24 (svn r4040) - Prepare 0.4.5 branch for release. Update readme's, bugs, installers and makefile, changelog, etc. to 0.4.6 2006-03-22 22:25:46 +00:00
bjarni
a9032183df (svn r4038) -backport (3966, 3972 and 4019) -Fix: [OSX 10.3 and newer] [ 1157244 ] Can't save game if name contains german umlauts (loading savegames with certain chars still look a bit odd) 2006-03-22 21:40:26 +00:00
bjarni
90feff4982 (svn r4037) -backported (3676): updated the install readme for OSX 2006-03-22 21:24:26 +00:00
matthijs
e434485dd8 (svn r4036) * Prepare debian release files for 0.4.5.1 release. 2006-03-22 21:18:33 +00:00
matthijs
dcc4ccf4e9 (svn r4035) - Backport from trunk (4033):
- Codechange: [Debian] Update debian packaging files to use debconf for user interaction.
2006-03-22 21:16:31 +00:00
bjarni
ef7e4abf7f (svn r4034) merged 3618:3971 for video/cocoa_v.m (major speedup for PPC fullscreen fix) 2006-03-22 21:11:05 +00:00
matthijs
5d0ed8fab8 (svn r4032) -Backport from trunk (3507):
- Fix: [Makefile] Make sure the ICON_DIR gets created before copying files there.
  - Fix: Fix small syntactic error in the manpage.
2006-03-22 21:04:13 +00:00
Darkvater
ed7df6e2bf (svn r4031) - Backport from trunk (r4030):
- [win32] Change compiler settings to use the multithreaded CRT. This prevents
  certain crashes on multi-threaded machines.
2006-03-22 20:46:07 +00:00
Darkvater
7cf9e0d8ca (svn r4029) - Backport from trunk (r4023):
Fix: [ 1453646 NPF ] Road vehicles planning through the back of depots and stations.
2006-03-22 20:33:30 +00:00
celestar
85141929a8 (svn r4018) -Backport from trunk (4001:4002):
Add length parameter to FiosMakeSavegameName() and use this function for creating the full path instead of home-brewn snprintf.
	Use the title of a savegame in the saveload dialog-editbox. This gets rid of the '.sav' appended to each game as well as properly showing UTF-8 saves when this is implemented. Also don't change the text if the save has failed.
2006-03-22 11:26:08 +00:00
celestar
f4d5c1b01b (svn r4017) -Backport from trunk (3999): Change the order of DestroyWindow and ChangeDisplay. On some machines a sizechange messagequeue is handled before sending WM_DISPLAYCHANGE resulting in an improper resolution written to the configuration file when exiting from fullscreen. (Frostregen) 2006-03-22 11:24:27 +00:00
celestar
31d6286cb4 (svn r4016) -Backport from trunk (3998): When removing rail track from a tile where only X and Y pieces exist, explicitly update signals in both directions. 2006-03-22 11:23:22 +00:00
celestar
ca0a0cdbfd (svn r4015) -Backport from trunk: Default the patch-setting 'pause_on_join' to true. 2006-03-22 11:17:21 +00:00
celestar
04572ed7fe (svn r4014) -Backport from trunk: Slope and height information returned for some tile types is wrong 2006-03-22 11:13:20 +00:00
celestar
ebfef9683e (svn r4013) -Fix last commit. CheckTunnelInWay works differently from IsTunnelInWay :S 2006-03-22 11:11:52 +00:00
celestar
c05d3dd558 (svn r4012) -Backport from trunk (3992, 3995): Rewrote the code to determine whether a rail-tile can be terraformed.
Fixes a bug where you could terraform a tunnel (fixed by r3228, but reverted that one)
Fixes a bug introduced by r3228 which allowed steep rail tiles resulting in ... unwanted effects such as display artifacts.
2006-03-22 10:32:07 +00:00
Darkvater
6e029fe97d (svn r3978) - Change all STRING1's back to STRING in french.txt because these {STRINGn} are only applicable to english.txt. Fixup of r3973. Sorry. Backport of r3977 from trunk 2006-03-19 09:03:25 +00:00
belugas
26ed195319 (svn r3975) Update french translation, adding STRING1 where needed, as well as other omissions.
Thanks to Darkvater for this opportunity. 
No typo this time
2006-03-19 01:52:05 +00:00
Darkvater
7170357a10 (svn r3970) - FS#56 - [Crash] Missing glyph(s) in big-font. Added several missing glyphs for the big font. Backport of r3940 from trunk 2006-03-18 16:03:55 +00:00
Darkvater
e4bbd3b41c (svn r3969) - [ 1439907 ] Increase client list window width so at least most languages fit (wikipedian). Backport of r3933 from trunk 2006-03-18 16:03:04 +00:00
Darkvater
5ed5e6beed (svn r3968) - Update german and finnish languages. Backport of r3932, r3943 from trunk 2006-03-18 16:02:19 +00:00
Darkvater
5de94db9df (svn r3967) - Fix: Properly set back the owner of a crossing/road-under bridge after removing it. For crossings we can always use .m2 because it is already 0 when not owned by a town. Backport of r3876, r3893 from trunk 2006-03-18 16:00:02 +00:00
Darkvater
6b664a3ba0 (svn r3965) - [win32] Remove mapfile generation and generate a pdb file instead. This and the corresponding executable is enough to trace the source of a crash given by crash.txt by using WinDbg for example. Mapfiles are a bit deprecated in the newer VS environments.
- [win32] Show the revision in crash.txt and enable the button to show the crash text in the crash-window 
- Backport of r3871, r3872 from trunk
2006-03-18 15:51:04 +00:00
Darkvater
beee5698f9 (svn r3964) -Fix: [autoreplace]: (FS#67) autoreplacing trains now keep their tile length instead of their pixel length. Backport of r3811 from trunk 2006-03-18 15:49:00 +00:00
Darkvater
a86ec733a0 (svn r3963) Update debian packaging files to the ones used for releasing 0.4.5 (see os/debian/changelog for details).
Fix a small debconf issue which was in the 0.4.5 release. Backport of r3801 from trunk
2006-03-18 15:48:15 +00:00
Darkvater
37c1135d6b (svn r3962) -Fix: Mark the right tile as dirty. It's just a graphical glitch which happend in r1592. Backport of r3792 from trunk 2006-03-18 15:47:16 +00:00
Darkvater
923dee9bec (svn r3961) - Fix crash when resizing news history window. Backport of r3778 from trunk 2006-03-18 15:46:09 +00:00
Darkvater
1856976d8e (svn r3960) -Fix: Correctly implement minimum search, so road vehicles head twoards the closest station, not the last one in the list. Backport of r3751 from trunk 2006-03-18 15:45:23 +00:00
Darkvater
818a5a596f (svn r3959) -Fix: [FS#61] The tooltips for raising and lowering land buttons in the scenario editor are interchanged (Reported and fixed by lc). Backport of r3749 from trunk 2006-03-18 15:32:38 +00:00
Darkvater
2be4b388ec (svn r3958) Change HASBIT() to return 0/1 instead of 0/value of tested bit. Backport of r3747 from trunk 2006-03-18 15:31:34 +00:00
Darkvater
300aba48cc (svn r3957) -Fix: Correctly restore the roadside after roadworks are finished. Backport of r3680 from trunk 2006-03-18 15:29:24 +00:00
Darkvater
f470a87dea (svn r3956) - Fix: [Multistop] Check the status of the destination road stop instead of a station's first road stop. This only has effect with road vehicle queuing disabled. Backport of r3663, r3681 from trunk 2006-03-18 15:28:26 +00:00
Darkvater
4b938510a5 (svn r3955) - Fix: validate the setting of max_companies/spectators through the console. Backport of r3591, r3593 from trunk 2006-03-18 15:25:25 +00:00
Darkvater
7ddae93da8 (svn r3954) - Explicitly update v->first in TrainConsistChanged() if necessary, as this is far faster than brute forcing it later.
- When loading a game, call TrainConsistChanged() for each train head separately before updating images, as v->first is used extensively in GetTrainImage() for custom graphics. This gives a significant speed improvement on loading a game. 
- Rewrite GetFreeUnitNumber() so that only one loop of vehicles is required. Instead a list of used/unused numbers is created and the first unused number is chosen. This significantly improves performance in large games. 
- Improve game-load times. Backport of r3570-3572 from trunk
2006-03-18 15:22:27 +00:00
Darkvater
f75365fcf4 (svn r3953) - Grr, compile before you commit. Wrong merge of 3529/3553 in r3948 2006-03-18 15:19:30 +00:00
Darkvater
e89a98d296 (svn r3952) - Fix: On loading a game, GetPlayerRailtypes() didn't account for the fact that vehicles are introduced a year after their introduction date. This will also relieve possible (rare) network desyncs. Backport of r3565 from trunk 2006-03-18 15:17:57 +00:00
Darkvater
8157969b2b (svn r3951) - Restore plural forms of cargo types for several languages. Backport of r3560 from trunk. 2006-03-18 15:16:12 +00:00
Darkvater
b3ccef7045 (svn r3950) - Add directives to allow Visual Studio 2005 compilation. Backport of r3551 from trunk. 2006-03-18 15:14:34 +00:00
Darkvater
af0fb58264 (svn r3949) - Revert r3467, was total nonesense, my fault. Backport of r3532 from trunk 2006-03-18 15:13:35 +00:00
Darkvater
5f2e2ef32a (svn r3948) - Fix: [ 1415782 ] crash in string code with openbsd/zaurus; alignment issues (thanks Tron for the help). Backport of r3529, r3553 from trunk 2006-03-18 15:12:24 +00:00
Darkvater
8353c1260a (svn r3526) - Codechange: Add additional linker information to release builds to help figure out crashes more easily 2006-02-03 17:24:37 +00:00
Darkvater
8de919ce50 (svn r3519) - [0.4.5-Branch] backport changes from abused tags/ (nothing important) 2006-02-01 22:02:47 +00:00
Darkvater
f9cacc9f5c (svn r3518) - Add proper revision numbers for bugfixing branch 2006-02-01 21:53:12 +00:00
Darkvater
af3ac4954a (svn r3517) - Branch: added branch for stable 0.4.5 2006-02-01 21:47:10 +00:00
853 changed files with 171342 additions and 298293 deletions

11
.gitignore vendored
View File

@@ -1,11 +0,0 @@
Makefile*
bin/*
!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

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

@@ -5,6 +5,7 @@ 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" \
@@ -83,7 +84,6 @@ FILE_PATTERNS = *.c \
*.cpp \
*.c++ \
*.h \
*.hpp \
table/*.h
RECURSIVE = YES
EXCLUDE =
@@ -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

1018
Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,274 +0,0 @@
# Auto-generated file -- DO NOT EDIT
# 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!!
CONFIGURE_FILES = !!CONFIGURE_FILES!!
LIPO = !!LIPO!!
BIN_DIR = !!BIN_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_ICON_DIR = "$(INSTALL_DIR)/"!!ICON_DIR!!
INSTALL_DATA_DIR = "$(INSTALL_DIR)/"!!DATA_DIR!!
TTD = !!TTD!!
TTDS = $(SRC_DIRS:%=%/$(TTD))
OS = !!OS!!
OSXAPP = !!OSXAPP!!
REVISION = !!REVISION!!
AWK = !!AWK!!
DISTCC = !!DISTCC!!
RES := $(shell if ! [ -f $(CONFIG_CACHE_SOURCE_LIST) ] || [ -n "`cmp $(CONFIG_CACHE_SOURCE_LIST) $(SOURCE_LIST)`" ]; then cp $(SOURCE_LIST) $(CONFIG_CACHE_SOURCE_LIST); fi )
all: 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.cache: $(CONFIG_CACHE_SOURCE_LIST) $(CONFIGURE_FILES)
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. Now compiling..."
@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
$(Q)rm -f $(CONFIG_CACHE_SOURCE_LIST) config.cache config.log
$(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
%.o:
@for dir in $(SRC_DIRS); do \
$(MAKE) -C $$dir $(@:src/%=%); \
done
%.lng:
@for dir in $(LANG_DIRS); do \
$(MAKE) -C $$dir $@; \
done
#
# Creation of bundles
#
# The revision is needed for the bundle name and creating an OSX application bundle.
ifdef REVISION
REV := $(REVISION)
else
# Are we a SVN dir?
ifeq ($(shell if test -d $(SRC_DIR)/.svn; then echo 1; fi), 1)
# Find if the local source if modified
REV_MODIFIED := $(shell svnversion $(SRC_DIR) | sed -n 's/.*\(M\).*/\1/p' )
# Find the revision like: rXXXX-branch
REV := $(shell LC_ALL=C svn info $(SRC_DIR) | $(AWK) '/^URL:.*branches/ { split($$2, a, "/"); BRANCH="-"a[5] } /^Last Changed Rev:/ { REV="r"$$4"$(REV_MODIFIED)" } END { print REV BRANCH }')
endif
endif
# Make sure we have something in REV
ifeq ($(REV),)
REV := norev000
endif
ifndef BUNDLE_NAME
BUNDLE_NAME = OTTD-$(OS)-custom-$(REV)
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)/scenario"
$(Q)mkdir -p "$(BUNDLE_DIR)/scenario/heightmap"
$(Q)mkdir -p "$(BUNDLE_DIR)/media"
$(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/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)/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)/docs/"
$(Q)cp "$(ROOT_DIR)/media/openttd.64.png" "$(BUNDLE_DIR)/media/"
$(Q)cp "$(ROOT_DIR)/media/openttd.32.xpm" "$(BUNDLE_DIR)/media/"
$(Q)cp "$(ROOT_DIR)/media/openttd.32.bmp" "$(BUNDLE_DIR)/media/"
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/scenario/\"*.scn 2> /dev/null`"; then echo 1; fi), 1)
$(Q)cp "$(BIN_DIR)/scenario/"*.scn "$(BUNDLE_DIR)/scenario/"
endif
ifeq ($(shell if test -n "`ls -l \"$(BIN_DIR)/scenario/heightmaps/\"* 2>/dev/null`"; then echo 1; fi), 1)
$(Q)cp "$(BIN_DIR)/scenario/heightmaps/"* "$(BUNDLE_DIR)/scenario/heightmap/"
endif
ifeq ($(TTD), openttd.exe)
$(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/COPYING"
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)"
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)/docs"
$(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)"
$(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)/docs/"* "$(INSTALL_DATA_DIR)/docs"
$(Q)install -m 644 "$(BUNDLE_DIR)/media/"* "$(INSTALL_ICON_DIR)"
$(Q)cp -R "$(BUNDLE_DIR)/scenario" "$(INSTALL_DATA_DIR)"
endif # OSXAPP

View File

@@ -1,89 +0,0 @@
# Auto-generated file -- DO NOT EDIT
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,309 +0,0 @@
# Auto-generated file -- DO NOT EDIT
CC_HOST = !!CC_HOST!!
CXX_HOST = !!CXX_HOST!!
CC_BUILD = !!CC_BUILD!!
CXX_BUILD = !!CXX_BUILD!!
WINDRES = !!WINDRES!!
STRIP = !!STRIP!!
CC_CFLAGS = !!CC_CFLAGS!!
CFLAGS = !!CFLAGS!!
CFLAGS_BUILD = !!CFLAGS_BUILD!!
LIBS = !!LIBS!!
LDFLAGS = !!LDFLAGS!!
BIN_DIR = !!BIN_DIR!!
LANG_DIR = !!LANG_DIR!!
SRC_OBJS_DIR = !!SRC_OBJS_DIR!!
LANG_OBJS_DIR= !!LANG_OBJS_DIR!!
SRC_DIR = !!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!!
GCC295 = !!GCC295!!
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) $(LANG_OBJS_DIR)/table/strings.h 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)
ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK)
# This 'sed' basicly just removes 'const' from the line if it is a 2+D array
# For more information, please check:
# http://maillist.openttd.org/pipermail/devs/2007-April/000284.html
# http://maillist.openttd.org/pipermail/devs/2007-February/000248.html
GCC295_FIX=sed -r 's/^(\t*)(.*)( const )([A-Za-z0-9_ ]+(\[.*\]){2,})(( = \{)|(;))(.*)$$/\1\2 \4\6\8\9/g'
# This 'sed' removes the 3rd '4' in the # lines of the -E output of
# gcc 2.95.3 and lower, as it should indicate that it is a C-linkage, but the
# compiler can't handle that information (just don't ask). So we remove it
# and then it compiles happily and without bitching :)
# Furthermore gcc 2.95 has some trouble with protected and private when
# accessing the protected/private stuff of the enclosing class (or the
# super class of the enclosing class).
GCC295_FIX_2=sed -e 's|\(^\# [0-9][0-9]* "[^"]*"[ 0-9]*\) 4$$|\1|g;s|private:|public:|g;s|protected:|public:|g'
# 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
# Make the revision number
ifdef REVISION
REV := $(REVISION)
REV_NR := $(shell echo $(REVISION) | sed "s/[^0-9]//g")
else
# Are we a SVN dir?
ifeq ($(shell if test -d $(SRC_DIR)/.svn; then echo 1; fi), 1)
# Find if the local source if modified
REV_MODIFIED := $(shell svnversion $(SRC_DIR) | sed -n 's/.*\(M\).*/\1/p' )
# Find the revision like: rXXXX-branch
REV := $(shell LC_ALL=C svn info $(SRC_DIR) | $(AWK) '/^URL:.*branch/ { split($$2, a, "/"); BRANCH="-"a[5] } /^Last Changed Rev:/ { REV="r"$$4"$(REV_MODIFIED)" } END { print REV BRANCH }')
REV_NR := $(shell LC_ALL=C svn info $(SRC_DIR) | $(AWK) '/^Last Changed Rev:/ { print $$4 }')
else
# Are we a git dir?
ifeq ($(shell if test -d $(SRC_DIR)/../.git; then echo 1; fi), 1)
# Find the revision like: gXXXXM-branch
REV := g$(shell if head=`LC_ALL=C git rev-parse --verify HEAD 2>/dev/null`; then echo "$$head" | cut -c1-8; fi)$(shell if cd "$(SRC_DIR)/.." && git diff-index HEAD src | read dummy; then echo M; fi)$(shell git branch|grep '[*]' | sed 's/\* /-/;s/^-master$$//')
REV_NR := $(shell LC_ALL=C cd "$(SRC_DIR)/.." && git log --pretty=format:%s src | grep -m 1 "^(svn r[0-9]*)" | sed "s/.*(svn r\([0-9]*\)).*/\1/" )
else
# Are we a hg (Mercurial) dir?
ifeq ($(shell if test -d $(SRC_DIR)/../.hg; then echo 1; fi), 1)
# Find the revision like: hXXXXM-branch
REV := h$(shell if head=`LC_ALL=C hg tip 2>/dev/null`; then echo "$$head" | head -n 1 | cut -c19-26; fi)$(shell if hg status $(SRC_DIR) | grep -v '^?' | read dummy; then echo M; fi)$(shell hg branch | sed 's/^/-/;s/^-default$$//')
REV_NR := $(shell LC_ALL=C hg log -k "svn" -l 1 --template "{desc}\n" $(SRC_DIR) | grep -m 1 "^(svn r[0-9]*)" | sed "s/.*(svn r\([0-9]*\)).*/\1/" )
endif
endif
endif
endif
# Make sure we have something in REV
ifeq ($(REV),)
REV := norev000
REV_NR := 0
endif
# This helps to recompile if flags change
RES := $(shell if [ "`cat $(CONFIG_CACHE_COMPILER) 2>/dev/null`" != "$(CC_CFLAGS) $(CFLAGS)" ]; then echo "$(CC_CFLAGS) $(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)" ]; then echo "$(REV)" > $(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, "^$(SRC_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 file is deleted without the deps
# being updated. Now the Makefile continues, the deps are recreated
# and all will be fine.
%.h %.hpp:
@true
# Compile all the files according to the targets
$(OBJS_C): %.o: $(SRC_DIR)/%.c $(DEP_MASK) $(FILE_DEP)
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.c=%.c)'
$(Q)$(CC_HOST) $(CC_CFLAGS) $(CFLAGS) -c -o $@ $<
$(OBJS_CPP): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP)
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
ifeq ($(GCC295), 1)
$(Q)$(CXX_HOST) -E $(CFLAGS) $< | $(GCC295_FIX) | $(GCC295_FIX_2) | $(CXX_HOST) $(CFLAGS) -c -o $@ -x c++ -
else
$(Q)$(CXX_HOST) $(CFLAGS) -c -o $@ $<
endif
$(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) $@
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#@@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

10
StdAfx.c Normal file
View File

@@ -0,0 +1,10 @@
/* $Id$ */
// stdafx.cpp : source file that includes just the standard includes
// ttd.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View File

@@ -3,22 +3,15 @@
#include "../stdafx.h"
#include "../openttd.h"
#include "../variables.h"
#include "../command_func.h"
#include "../network/network.h"
#include "../core/alloc_func.hpp"
#include "../player_func.h"
#include "../player_base.h"
#include "../command.h"
#include "../network.h"
#include "ai.h"
#include "default/default.h"
#include "../signal_func.h"
AIStruct _ai;
AIPlayer _ai_player[MAX_PLAYERS];
/**
* Dequeues commands put in the queue via AI_PutCommandInQueue.
*/
static void AI_DequeueCommands(PlayerID player)
static void AI_DequeueCommands(byte player)
{
AICommand *com, *entry_com;
@@ -37,12 +30,14 @@ static void AI_DequeueCommands(PlayerID player)
while ((com = entry_com) != NULL) {
_current_player = player;
/* Copy the DP back in place */
_cmd_text = com->text;
DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
DoCommandP(com->tile, com->p1, com->p2, NULL, com->procc);
/* Free item */
entry_com = com->next;
free(com->text);
if (com->text != NULL)
free(com->text);
free(com);
}
}
@@ -51,17 +46,17 @@ static void AI_DequeueCommands(PlayerID player)
* 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, uint32 procc, CommandCallback* callback)
static void AI_PutCommandInQueue(byte player, uint tile, uint32 p1, uint32 p2, uint procc)
{
AICommand *com;
if (_ai_player[player].queue_tail == NULL) {
/* There is no item in the queue yet, create the queue */
_ai_player[player].queue = MallocT<AICommand>(1);
_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 = MallocT<AICommand>(1);
_ai_player[player].queue_tail->next = malloc(sizeof(AICommand));
_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
}
@@ -73,7 +68,6 @@ static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uin
com->p1 = p1;
com->p2 = p2;
com->procc = procc;
com->callback = callback;
com->next = NULL;
com->text = NULL;
@@ -87,61 +81,64 @@ static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uin
/**
* Executes a raw DoCommand for the AI.
*/
CommandCost AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint32 procc, CommandCallback* callback)
int32 AI_DoCommand(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
PlayerID old_lp;
CommandCost res;
const char* tmp_cmdtext;
int32 res = 0;
char *tmp_cmdtext = NULL;
/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
* person.. should we check for those funny jokes?
*/
/* The test already resets _cmd_text, so backup the pointer */
tmp_cmdtext = _cmd_text;
/* The test already free _cmd_text in most cases, so let's backup the string, else we have a problem ;) */
if (_cmd_text != NULL)
tmp_cmdtext = strdup(_cmd_text);
/* First, do a test-run to see if we can do this */
res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
res = DoCommandByTile(tile, p1, p2, flags & ~DC_EXEC, procc);
/* The command failed, or you didn't want to execute, or you are quering, return */
if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
if ((CmdFailed(res)) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
if (tmp_cmdtext != NULL)
free(tmp_cmdtext);
return res;
}
/* Restore _cmd_text */
_cmd_text = tmp_cmdtext;
/* Recover _cmd_text */
if (tmp_cmdtext != NULL)
_cmd_text = tmp_cmdtext;
/* If we did a DC_EXEC, and the command did not return an error, execute it
over the network */
if (flags & DC_AUTO) procc |= CMD_AUTO;
if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
/* NetworkSend_Command needs _local_player to be set correctly, so
* adjust it, and put it back right after the function */
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) {
if (_networking)
/* Network is easy, send it to his handler */
NetworkSend_Command(tile, p1, p2, procc, callback);
} else {
#else
{
NetworkSend_Command(tile, p1, p2, procc, NULL);
else
#endif
/* If we execute BuildCommands directly in SP, we have a big problem with events
* so we need to delay is for 1 tick */
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
}
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc);
/* Set _local_player back */
_local_player = old_lp;
/* Free the temp _cmd_text var */
if (tmp_cmdtext != NULL)
free(tmp_cmdtext);
return res;
}
CommandCost AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint32 procc)
{
return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
}
/**
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
*/
@@ -160,9 +157,6 @@ static void AI_RunTick(PlayerID player)
AiDoGameLoop(p);
_is_old_ai_player = false;
}
/* AI could change some track, so update signals */
UpdateSignalsInBuffer();
}
@@ -170,25 +164,35 @@ static void AI_RunTick(PlayerID player)
* The gameloop for AIs.
* Handles one tick for all the AIs.
*/
void AI_RunGameLoop()
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;
/* Don't do anything if we are a network-client
* (too bad when a client joins, he thinks the AIs are real, so it wants to control
* them.. this avoids that, while loading a network game in singleplayer, does make
* the AIs to continue ;))
*/
if (_networking && !_network_server && !_ai.network_client)
return;
/* New tick */
_ai.tick++;
/* Make sure the AI follows the difficulty rule.. */
assert(_opt.diff.competitor_speed <= 4);
if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
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) {
if (_ai.network_client && _ai_player[_ai.network_playas].active) {
/* Run the script */
AI_DequeueCommands(_ai.network_playas);
AI_RunTick(_ai.network_playas);
} else if (!_networking || _network_server) {
/* Check if we want to run AIs (server or SP only) */
const Player* p;
Player *p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) {
@@ -210,7 +214,7 @@ void AI_RunGameLoop()
*/
void AI_StartNewAI(PlayerID player)
{
assert(IsValidPlayer(player));
assert(player < MAX_PLAYERS);
/* Called if a new AI is booted */
_ai_player[player].active = true;
@@ -221,6 +225,9 @@ void AI_StartNewAI(PlayerID player)
*/
void AI_PlayerDied(PlayerID player)
{
if (_ai.network_client && _ai.network_playas == player)
_ai.network_playas = OWNER_SPECTATOR;
/* Called if this AI died */
_ai_player[player].active = false;
}
@@ -228,23 +235,27 @@ void AI_PlayerDied(PlayerID player)
/**
* Initialize some AI-related stuff.
*/
void AI_Initialize()
void AI_Initialize(void)
{
bool ai_network_client = _ai.network_client;
/* First, make sure all AIs are DEAD! */
AI_Uninitialize();
memset(&_ai, 0, sizeof(_ai));
memset(&_ai_player, 0, sizeof(_ai_player));
_ai.network_client = ai_network_client;
_ai.network_playas = OWNER_SPECTATOR;
_ai.enabled = true;
}
/**
* Deinitializer for AI-related stuff.
*/
void AI_Uninitialize()
void AI_Uninitialize(void)
{
const Player* p;
Player* p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) AI_PlayerDied(p->index);

View File

@@ -1,58 +1,57 @@
/* $Id$ */
#ifndef AI_H
#define AI_H
#include "../network/network.h"
#include "../command_type.h"
#include "../core/random_func.hpp"
#include "../settings_type.h"
#include "../functions.h"
#include "../network.h"
#include "../player.h"
/* How DoCommands look like for an AI */
struct AICommand {
typedef struct AICommand {
uint32 tile;
uint32 p1;
uint32 p2;
uint32 procc;
CommandCallback *callback;
char *text;
uint uid;
AICommand *next;
};
struct AICommand *next;
} AICommand;
/* The struct for an AIScript Player */
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
};
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 */
struct AIStruct {
typedef struct AIStruct {
/* General */
bool enabled; ///< Is AI enabled?
uint tick; ///< The current tick (something like _frame_counter, only for AIs)
};
bool enabled; //! Is AI enabled?
uint tick; //! The current tick (something like _frame_counter, only for AIs)
extern AIStruct _ai;
extern AIPlayer _ai_player[MAX_PLAYERS];
/* For network-clients (a OpenTTD client who acts as an AI connected to a server) */
bool network_client; //! Are we a network_client?
uint8 network_playas; //! The current network player we are connected as
} AIStruct;
VARDEF AIStruct _ai;
VARDEF AIPlayer _ai_player[MAX_PLAYERS];
// ai.c
void AI_StartNewAI(PlayerID player);
void AI_PlayerDied(PlayerID player);
void AI_RunGameLoop();
void AI_Initialize();
void AI_Uninitialize();
CommandCost AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
CommandCost AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback);
void AI_RunGameLoop(void);
void AI_Initialize(void);
void AI_Uninitialize(void);
int32 AI_DoCommand(uint tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
/** Is it allowed to start a new AI.
* This function checks some boundries to see if we should launch a new AI.
* @return True if we can start a new AI.
*/
static inline bool AI_AllowNewAI()
static inline bool AI_AllowNewAI(void)
{
/* If disabled, no AI */
if (!_ai.enabled)
@@ -79,8 +78,8 @@ static inline bool AI_AllowNewAI()
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))
#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.
@@ -99,7 +98,7 @@ static inline uint AI_RandomRange(uint max)
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint32 AI_Random()
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.

3979
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

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

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

View File

@@ -2,20 +2,15 @@
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../bridge_map.h"
#include "../../debug.h"
#include "../../command_func.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 "../../tunnelbridge_map.h"
#include "../ai.h"
#include "../../variables.h"
#include "../../player_base.h"
#include "../../player_func.h"
#include "../../tunnelbridge.h"
#include "../ai.h"
#define TEST_STATION_NO_DIR 0xFF
@@ -26,27 +21,32 @@ static bool TestCanBuildStationHere(TileIndex tile, byte dir)
Player *p = GetPlayer(_current_player);
if (dir == TEST_STATION_NO_DIR) {
CommandCost ret;
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, _players_ainew[p->index].tbt, tile, 1, 1, dir, DC_QUERY_COST);
if (CmdSucceeded(ret)) return true;
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 CmdSucceeded(AiNew_Build_Station(p, _players_ainew[p->index].tbt, tile, 1, 1, dir, DC_QUERY_COST));
return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
}
static bool IsRoad(TileIndex tile)
{
return
// MP_ROAD, but not a road depot?
(IsTileType(tile, MP_ROAD) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
(IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD);
// MP_STREET, but not a road depot?
(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
(IsTileType(tile, MP_TUNNELBRIDGE) && (
// road tunnel?
((_m[tile].m5 & 0x80) == 0 && (_m[tile].m5 & 0x4) == 0x4) ||
// road bridge?
((_m[tile].m5 & 0x80) != 0 && (_m[tile].m5 & 0x2) == 0x2)
));
}
@@ -57,8 +57,7 @@ static bool IsRoad(TileIndex tile)
// Check if the current tile is in our end-area
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
{
const Ai_PathFinderInfo* PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
Ai_PathFinderInfo *PathFinderInfo = (Ai_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))
@@ -82,7 +81,7 @@ static uint AiPathFinder_Hash(uint key1, uint key2)
static void AyStar_AiPathFinder_Free(AyStar *aystar)
{
AyStarMain_Free(aystar);
delete aystar;
free(aystar);
}
@@ -99,7 +98,7 @@ AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFin
uint x;
uint y;
// Create AyStar
AyStar *result = new AyStar();
AyStar *result = malloc(sizeof(AyStar));
init_AyStar(result, AiPathFinder_Hash, 1 << 10);
// Set the function pointers
result->CalculateG = AyStar_AiPathFinder_CalculateG;
@@ -156,11 +155,9 @@ void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo
// 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;
if (!(IsTileType(TileXY(x, y), MP_CLEAR) || IsTileType(TileXY(x, y), MP_TREES))) continue;
if (!TestCanBuildStationHere(TileXY(x, y), TEST_STATION_NO_DIR)) continue;
start_node.node.tile = TileXY(x, y);
aystar->addstart(aystar, &start_node.node, 0);
}
}
@@ -170,13 +167,12 @@ void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo
// The h-value, simple calculation
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
const Ai_PathFinderInfo* PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
Ai_PathFinderInfo *PathFinderInfo = (Ai_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));
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDir(PathFinderInfo->end_direction));
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDir(PathFinderInfo->end_direction));
} else {
// No direction, so just get the fastest route to the station
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
@@ -200,21 +196,22 @@ static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *curre
PathFinderInfo->route[i++] = parent->node.tile;
if (i > lengthof(PathFinderInfo->route)) {
// We ran out of space for the PathFinder
DEBUG(ai, 0, "No more space in pathfinder route[] array");
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, "Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash));
DEBUG(ai, 1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash));
}
// What tiles are around us.
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current)
{
CommandCost ret;
uint i;
int ret;
int dir;
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
@@ -222,9 +219,9 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
aystar->num_neighbours = 0;
// Go through all surrounding tiles and check if they are within the limits
for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
for (i = 0; i < 4; i++) {
TileIndex ctile = current->path.node.tile; // Current tile
TileIndex atile = ctile + TileOffsByDiagDir(i); // Adjacent tile
TileIndex atile = ctile + TileOffsByDir(i); // Adjacent tile
if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 &&
TileY(atile) > 1 && TileY(atile) < MapMaxY() - 1) {
@@ -234,7 +231,20 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
// 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 (GetTunnelBridgeDirection(atile) != i) continue;
// An existing bridge... let's test the direction ;)
if ((_m[atile].m5 & 1U) != (i & 1)) continue;
// This problem only is valid for tunnels:
// When the last tile was not yet a tunnel, check if we enter from the right side..
if ((_m[atile].m5 & 0x80) == 0) {
if (i != (_m[atile].m5 & 3U)) continue;
}
}
}
// But also if we are on a bridge, we can only move a certain direction
if (!PathFinderInfo->rail_or_road && IsRoad(ctile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
// An existing bridge/tunnel... let's test the direction ;)
if ((_m[ctile].m5 & 1U) != (i & 1)) continue;
}
}
@@ -242,7 +252,7 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
(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 ((uint)i != (current->path.node.user_data[0] >> 8)) continue;
if (i != (current->path.node.user_data[0] >> 8)) continue;
}
dir = 0;
@@ -280,9 +290,9 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
dir = 0;
} else {
// It already has road.. check if we miss any bits!
if ((GetAnyRoadBits(ctile, ROADTYPE_ROAD) & dir) != dir) {
if ((_m[ctile].m5 & dir) != dir) {
// We do miss some pieces :(
dir &= ~GetAnyRoadBits(ctile, ROADTYPE_ROAD);
dir &= ~_m[ctile].m5;
} else {
dir = 0;
}
@@ -305,23 +315,25 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
// Next step, check for bridges and tunnels
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
TileInfo ti;
// First we get the dir from this tile and his parent
DiagDirection dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
int dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
// It means we can only walk with the track, so the bridge has to be in the same direction
TileIndex tile = current->path.node.tile;
TileIndex new_tile = tile;
Slope tileh = GetTileSlope(tile, NULL);
FindLandscapeHeightByTile(&ti, tile);
// 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_ROAD)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_RAILWAY))) {
if (ti.tileh != 0 ||
(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_STREET)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDir(dir), MP_RAILWAY))) {
for (;;) {
new_tile += TileOffsByDiagDir(dir);
new_tile += TileOffsByDir(dir);
// Precheck, is the length allowed?
if (!CheckBridge_Stuff(0, GetTunnelBridgeLength(tile, new_tile))) break;
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;
@@ -339,13 +351,16 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
}
// Next, check for tunnels!
// Tunnels can only be built on slopes corresponding to the direction
// Tunnels can only be build with tileh of 3, 6, 9 or 12, depending on the direction
// For now, we check both sides for this tile.. terraforming gives fuzzy result
if (tileh == InclinedSlope(dir)) {
if ((dir == 0 && ti.tileh == 12) ||
(dir == 1 && ti.tileh == 6) ||
(dir == 2 && ti.tileh == 3) ||
(dir == 3 && ti.tileh == 9)) {
// 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 (CmdSucceeded(ret) && IsInclinedSlope(tileh)) {
FindLandscapeHeightByTile(&ti, _build_tunnel_endtile);
if (!CmdFailed(ret) && (ti.tileh == 3 || ti.tileh == 6 || ti.tileh == 9 || ti.tileh == 12)) {
aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0;
@@ -355,16 +370,23 @@ static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *curr
}
extern Foundation GetRailFoundation(Slope tileh, TrackBits bits); // XXX function declaration in .c
extern Foundation GetRoadFoundation(Slope tileh, RoadBits bits); // XXX function declaration in .c
extern uint GetRailFoundation(uint tileh, uint bits);
extern uint GetRoadFoundation(uint tileh, uint bits);
extern uint GetBridgeFoundation(uint tileh, byte direction);
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 res = 0;
Slope tileh = GetTileSlope(current->tile, NULL);
Slope parent_tileh = GetTileSlope(parent->path.node.tile, NULL);
int r, res = 0;
TileInfo ti, parent_ti;
// Gather some information about the tile..
FindLandscapeHeightByTile(&ti, current->tile);
FindLandscapeHeightByTile(&parent_ti, parent->path.node.tile);
// Check if we hit the end-tile
if (TILES_BETWEEN(current->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) {
@@ -394,24 +416,24 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
// 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) {
if (parent_ti.tileh != 0 && 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) {
Foundation f = GetRailFoundation(parent_tileh, (TrackBits)(1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile)));
if (IsInclinedFoundation(f) || (!IsFoundation(f) && IsInclinedSlope(parent_tileh))) {
r = GetRailFoundation(parent_ti.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 && (BRIDGE_NO_FOUNDATION & (1 << ti.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)) {
Foundation f = GetRoadFoundation(parent_tileh, (RoadBits)AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
if (IsInclinedFoundation(f) || (!IsFoundation(f) && IsInclinedSlope(parent_tileh))) {
if (!(IsRoad(parent->path.node.tile) && IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE))) {
r = GetRoadFoundation(parent_ti.tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
if (r >= 15 || r == 0)
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
else
res += AI_PATHFINDER_FOUNDATION_PENALTY;
}
}
}
}
@@ -419,22 +441,29 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
// Are we part of a tunnel?
if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
int r;
// Tunnels are very expensive when build on long routes..
// Ironicly, we are using BridgeCode here ;)
r = AI_PATHFINDER_TUNNEL_PENALTY * GetTunnelBridgeLength(current->tile, parent->path.node.tile);
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 * GetTunnelBridgeLength(current->tile, parent->path.node.tile);
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 (!HasBridgeFlatRamp(parent_tileh, (Axis)((current->user_data[0] >> 8) & 1))) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (!(BRIDGE_NO_FOUNDATION & (1 << parent_ti.tileh))) {
if (GetBridgeFoundation(parent_ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
// Second for the end point
if (!HasBridgeFlatRamp(tileh, (Axis)((current->user_data[0] >> 8) & 1))) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (!(BRIDGE_NO_FOUNDATION & (1 << ti.tileh))) {
if (GetBridgeFoundation(ti.tileh, (current->user_data[0] >> 8) & 1) < 15)
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
if (parent_ti.tileh == 0) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (ti.tileh == 0) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
// To prevent the AI from taking the fastest way in tiles, but not the fastest way
@@ -444,11 +473,10 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
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)) {
if (IsRoad(parent->path.node.tile))
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
} else {
else
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
}
}
} else {
// For rail we have 1 exeption: diagonal rail..
@@ -457,7 +485,7 @@ static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current,
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;
if (dir1 > 1) { res -= AI_PATHFINDER_DIAGONAL_BONUS; }
// First see if they are different
if (dir1 != dir2) {

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

@@ -0,0 +1,124 @@
/* $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
int x1, x2, x3;
int y1, y2, y3;
x1 = TileX(tile_a);
x2 = TileX(tile_b);
x3 = TileX(tile_c);
y1 = TileY(tile_a);
y2 = TileY(tile_b);
y3 = TileY(tile_c);
if (y1 == y2 && y2 == y3) return 0;
if (x1 == x2 && x2 == x3) return 1;
if (y2 > y1) {
if (x2 > x3) return 2;
else return 4;
}
if (x2 > x1) {
if (y2 > y3) return 2;
else return 5;
}
if (y1 > y2) {
if (x2 > x3) return 5;
else return 3;
}
if (x1 > x2) {
if (y2 > y3) return 4;
else return 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
int AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b)
{
if (TileY(tile_a) < TileY(tile_b)) return 1;
if (TileY(tile_a) > TileY(tile_b)) return 3;
if (TileX(tile_a) < TileX(tile_b)) return 2;
return 0;
}
// This functions looks up if this vehicle is special for this AI
// and returns his flag
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v) {
int 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 i, new_id = -1;
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;
}

1364
ai/trolly/trolly.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,7 @@
#define AI_TROLLY_H
#include "../../aystar.h"
#include "../../player_type.h"
#include "../../vehicle_type.h"
#include "../../date_type.h"
#include "../../player.h"
/*
* These defines can be altered to change the behavoir of the AI
@@ -189,7 +187,6 @@ enum {
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,
@@ -241,22 +238,6 @@ typedef void AiNew_StateFunction(Player *p);
// ai_new.c
void AiNewDoGameLoop(Player *p);
struct Ai_PathFinderInfo {
TileIndex start_tile_tl; ///< tl = top-left
TileIndex start_tile_br; ///< br = bottom-right
TileIndex end_tile_tl; ///< tl = top-left
TileIndex end_tile_br; ///< br = bottom-right
DiagDirection start_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION
DiagDirection end_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION
TileIndex route[500];
byte route_extra[500]; ///< Some extra information about the route like bridge/tunnel
int route_length;
int position; ///< Current position in the build-path, needed to build the path
bool rail_or_road; ///< true = rail, false = road
};
// ai_pathfinder.c
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo);
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
@@ -264,77 +245,17 @@ 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);
int 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);
CommandCost AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag);
CommandCost AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag);
CommandCost AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
EngineID AiNew_PickVehicle(Player *p);
CommandCost AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag);
CommandCost AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag);
/* The amount of memory reserved for the AI-special-vehicles */
#define AI_MAX_SPECIAL_VEHICLES 100
struct Ai_SpecialVehicle {
VehicleID veh_id;
uint32 flag;
};
struct PlayerAiNew {
uint8 state;
uint tick;
uint idle;
int temp; ///< A value used in more than one function, but it just temporary
///< The use is pretty simple: with this we can 'think' about stuff
///< in more than one tick, and more than one AI. A static will not
///< do, because they are not saved. This way, the AI is almost human ;)
int counter; ///< For the same reason as temp, we have counter. It can count how
///< long we are trying something, and just abort if it takes too long
/* Pathfinder stuff */
Ai_PathFinderInfo path_info;
AyStar *pathfinder;
/* Route stuff */
CargoID cargo;
byte tbt; ///< train/bus/truck 0/1/2 AI_TRAIN/AI_BUS/AI_TRUCK
Money new_cost;
byte action;
int last_id; ///< here is stored the last id of the searched city/industry
Date last_vehiclecheck_date; // Used in CheckVehicle
Ai_SpecialVehicle special_vehicles[AI_MAX_SPECIAL_VEHICLES]; ///< Some vehicles have some special flags
TileIndex from_tile;
TileIndex to_tile;
DiagDirectionByte from_direction;
DiagDirectionByte to_direction;
bool from_deliver; ///< True if this is the station that GIVES cargo
bool to_deliver;
TileIndex depot_tile;
DiagDirectionByte depot_direction;
byte amount_veh; ///< How many vehicles we are going to build in this route
byte cur_veh; ///< How many vehicles did we bought?
VehicleID veh_id; ///< Used when bought a vehicle
VehicleID veh_main_id; ///< The ID of the first vehicle, for shared copy
int from_ic; ///< ic = industry/city. This is the ID of them
byte from_type; ///< AI_NO_TYPE/AI_CITY/AI_INDUSTRY
int to_ic;
byte to_type;
};
extern PlayerAiNew _players_ainew[MAX_PLAYERS];
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);
int AiNew_PickVehicle(Player *p);
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag);
int AiNew_Build_Depot(Player *p, TileIndex tile, byte direction, byte flag);
#endif /* AI_TROLLY_H */

1995
aircraft_cmd.c Normal file

File diff suppressed because it is too large Load Diff

1195
aircraft_gui.c Normal file

File diff suppressed because it is too large Load Diff

383
airport.c Normal file
View File

@@ -0,0 +1,383 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "map.h"
#include "airport.h"
#include "macros.h"
#include "variables.h"
static AirportFTAClass* CountryAirport;
static AirportFTAClass* CityAirport;
static AirportFTAClass* Oilrig;
static AirportFTAClass* Heliport;
static AirportFTAClass* MetropolitanAirport;
static AirportFTAClass* InternationalAirport;
static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *FA,
const TileIndexDiffC *depots, const byte nof_depots);
static void AirportFTAClass_Destructor(AirportFTAClass *Airport);
static uint16 AirportGetNofElements(const AirportFTAbuildup *FA);
static void AirportBuildAutomata(AirportFTAClass *Airport, const AirportFTAbuildup *FA);
static byte AirportTestFTA(const AirportFTAClass *Airport);
/*static void AirportPrintOut(const AirportFTAClass *Airport, const bool full_report);
static byte AirportBlockToString(uint32 block);*/
void InitializeAirports(void)
{
// country airport
CountryAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CountryAirport,
_airport_terminal_country,
NULL,
16,
ALL,
_airport_fta_country,
_airport_depots_country,
lengthof(_airport_depots_country)
);
// city airport
CityAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CityAirport,
_airport_terminal_city,
NULL,
19,
ALL,
_airport_fta_city,
_airport_depots_city,
lengthof(_airport_depots_city)
);
// metropolitan airport
MetropolitanAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
MetropolitanAirport,
_airport_terminal_metropolitan,
NULL,
20,
ALL,
_airport_fta_metropolitan,
_airport_depots_metropolitan,
lengthof(_airport_depots_metropolitan)
);
// international airport
InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
InternationalAirport,
_airport_terminal_international,
_airport_helipad_international,
37,
ALL,
_airport_fta_international,
_airport_depots_international,
lengthof(_airport_depots_international)
);
// heliport, oilrig
Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
Heliport,
NULL,
_airport_helipad_heliport_oilrig,
7,
HELICOPTERS_ONLY,
_airport_fta_heliport_oilrig,
NULL,
0
);
Oilrig = Heliport; // exactly the same structure for heliport/oilrig, so share state machine
}
void UnInitializeAirports(void)
{
AirportFTAClass_Destructor(CountryAirport);
AirportFTAClass_Destructor(CityAirport);
AirportFTAClass_Destructor(Heliport);
AirportFTAClass_Destructor(MetropolitanAirport);
AirportFTAClass_Destructor(InternationalAirport);
}
static void AirportFTAClass_Constructor(AirportFTAClass *Airport,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *FA,
const TileIndexDiffC *depots, const byte nof_depots)
{
byte nofterminals, nofhelipads;
byte nofterminalgroups = 0;
byte nofhelipadgroups = 0;
const byte * curr;
int i;
nofterminals = nofhelipads = 0;
//now we read the number of terminals we have
if (terminals != NULL) {
i = terminals[0];
nofterminalgroups = i;
curr = terminals;
while (i-- > 0) {
curr++;
assert(*curr != 0); //we don't want to have an empty group
nofterminals += *curr;
}
}
Airport->terminals = terminals;
//read helipads
if (helipads != NULL) {
i = helipads[0];
nofhelipadgroups = i;
curr = helipads;
while (i-- > 0) {
curr++;
assert(*curr != 0); //no empty groups please
nofhelipads += *curr;
}
}
Airport->helipads = helipads;
// if there are more terminals than 6, internal variables have to be changed, so don't allow that
// same goes for helipads
if (nofterminals > MAX_TERMINALS) { printf("Currently only maximum of %2d terminals are supported (you wanted %2d)\n", MAX_TERMINALS, nofterminals);}
if (nofhelipads > MAX_HELIPADS) { printf("Currently only maximum of %2d helipads are supported (you wanted %2d)\n", MAX_HELIPADS, nofhelipads);}
// terminals/helipads are divided into groups. Groups are computed by dividing the number
// of terminals by the number of groups. Half in half. If #terminals is uneven, first group
// will get the less # of terminals
assert(nofterminals <= MAX_TERMINALS);
assert(nofhelipads <= MAX_HELIPADS);
Airport->nofelements = AirportGetNofElements(FA);
// check
if (entry_point >= Airport->nofelements) {printf("Entry point (%2d) must be within the airport positions (which is max %2d)\n", entry_point, Airport->nofelements);}
assert(entry_point < Airport->nofelements);
Airport->acc_planes = acc_planes;
Airport->entry_point = entry_point;
Airport->airport_depots = depots;
Airport->nof_depots = nof_depots;
// build the state machine
AirportBuildAutomata(Airport, FA);
DEBUG(misc, 1) ("#Elements %2d; #Terminals %2d in %d group(s); #Helipads %2d in %d group(s); Entry Point %d",
Airport->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, Airport->entry_point
);
{
byte ret = AirportTestFTA(Airport);
if (ret != MAX_ELEMENTS) printf("ERROR with element: %d\n", ret - 1);
assert(ret == MAX_ELEMENTS);
}
// print out full information
// true -- full info including heading, block, etc
// false -- short info, only position and next position
//AirportPrintOut(Airport, false);
}
static void AirportFTAClass_Destructor(AirportFTAClass *Airport)
{
int i;
AirportFTA *current, *next;
for (i = 0; i < Airport->nofelements; i++) {
current = Airport->layout[i].next_in_chain;
while (current != NULL) {
next = current->next_in_chain;
free(current);
current = next;
};
}
free(Airport->layout);
free(Airport);
}
static uint16 AirportGetNofElements(const AirportFTAbuildup *FA)
{
int i;
uint16 nofelements = 0;
int temp = FA[0].position;
for (i = 0; i < MAX_ELEMENTS; i++) {
if (temp != FA[i].position) {
nofelements++;
temp = FA[i].position;
}
if (FA[i].position == MAX_ELEMENTS) break;
}
return nofelements;
}
static void AirportBuildAutomata(AirportFTAClass *Airport, const AirportFTAbuildup *FA)
{
AirportFTA *FAutomata;
AirportFTA *current;
uint16 internalcounter, i;
FAutomata = malloc(sizeof(AirportFTA) * Airport->nofelements);
Airport->layout = FAutomata;
internalcounter = 0;
for (i = 0; i < Airport->nofelements; i++) {
current = &Airport->layout[i];
current->position = FA[internalcounter].position;
current->heading = FA[internalcounter].heading;
current->block = FA[internalcounter].block;
current->next_position = FA[internalcounter].next_in_chain;
// outgoing nodes from the same position, create linked list
while (current->position == FA[internalcounter + 1].position) {
AirportFTA* newNode = malloc(sizeof(AirportFTA));
newNode->position = FA[internalcounter + 1].position;
newNode->heading = FA[internalcounter + 1].heading;
newNode->block = FA[internalcounter + 1].block;
newNode->next_position = FA[internalcounter + 1].next_in_chain;
// create link
current->next_in_chain = newNode;
current = current->next_in_chain;
internalcounter++;
} // while
current->next_in_chain = NULL;
internalcounter++;
}
}
static byte AirportTestFTA(const AirportFTAClass *Airport)
{
byte position, i, next_element;
AirportFTA *temp;
next_element = 0;
for (i = 0; i < Airport->nofelements; i++) {
position = Airport->layout[i].position;
if (position != next_element) return i;
temp = &Airport->layout[i];
do {
if (temp->heading > MAX_HEADINGS && temp->heading != 255) return i;
if (temp->heading == 0 && temp->next_in_chain != 0) return i;
if (position != temp->position) return i;
if (temp->next_position >= Airport->nofelements) return i;
temp = temp->next_in_chain;
} while (temp != NULL);
next_element++;
}
return MAX_ELEMENTS;
}
#if 0
static const char* const _airport_heading_strings[] = {
"TO_ALL",
"HANGAR",
"TERM1",
"TERM2",
"TERM3",
"TERM4",
"TERM5",
"TERM6",
"HELIPAD1",
"HELIPAD2",
"TAKEOFF",
"STARTTAKEOFF",
"ENDTAKEOFF",
"HELITAKEOFF",
"FLYING",
"LANDING",
"ENDLANDING",
"HELILANDING",
"HELIENDLANDING",
"DUMMY" // extra heading for 255
};
static void AirportPrintOut(const AirportFTAClass *Airport, const bool full_report)
{
AirportFTA *temp;
uint16 i;
byte heading;
printf("(P = Current Position; NP = Next Position)\n");
for (i = 0; i < Airport->nofelements; i++) {
temp = &Airport->layout[i];
if (full_report) {
heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading;
printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position,
_airport_heading_strings[heading], AirportBlockToString(temp->block));
} else {
printf("P:%2d NP:%2d", temp->position, temp->next_position);
}
while (temp->next_in_chain != NULL) {
temp = temp->next_in_chain;
if (full_report) {
heading = (temp->heading == 255) ? MAX_HEADINGS+1 : temp->heading;
printf("Pos:%2d NPos:%2d Heading:%15s Block:%2d\n", temp->position, temp->next_position,
_airport_heading_strings[heading], AirportBlockToString(temp->block));
} else {
printf("P:%2d NP:%2d", temp->position, temp->next_position);
}
}
printf("\n");
}
}
static byte AirportBlockToString(uint32 block)
{
byte 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;
}
#endif
const AirportFTAClass* GetAirport(const byte airport_type)
{
AirportFTAClass *Airport = NULL;
//FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
// needs constant change if more airports are added
switch (airport_type) {
case AT_SMALL: Airport = CountryAirport; break;
case AT_LARGE: Airport = CityAirport; break;
case AT_METROPOLITAN: Airport = MetropolitanAirport; break;
case AT_HELIPORT: Airport = Heliport; break;
case AT_OILRIG: Airport = Oilrig; break;
case AT_INTERNATIONAL: Airport = InternationalAirport; break;
default:
#ifdef DEBUG__
printf("Airport AircraftNextAirportPos_and_Order not yet implemented\n");
#endif
assert(airport_type <= AT_INTERNATIONAL);
}
return Airport;
}
uint32 GetValidAirports(void)
{
uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
// 1980-1-1 is --> 21915
// 1990-1-1 is --> 25568
if (_date >= 21915) SETBIT(bytemask, 3); // metropilitan airport 1980
if (_date >= 25568) SETBIT(bytemask, 4); // international airport 1990
return bytemask;
}

60
airport.h Normal file
View File

@@ -0,0 +1,60 @@
/* $Id$ */
#ifndef AIRPORT_H
#define AIRPORT_H
#include "airport_movement.h"
enum {MAX_TERMINALS = 6};
enum {MAX_HELIPADS = 2};
// Airport types
enum {
AT_SMALL = 0,
AT_LARGE = 1,
AT_HELIPORT = 2,
AT_METROPOLITAN = 3,
AT_INTERNATIONAL = 4,
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
};
// 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
} 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_in_chain; // possible extra movement choices from this position
} AirportFTA;
void InitializeAirports(void);
void UnInitializeAirports(void);
const AirportFTAClass* GetAirport(const byte airport_type);
/** Get buildable airport bitmask.
* @return get all buildable airports at this given time, bitmasked.
* Bit 0 means the small airport is buildable, etc.
* @todo set availability of airports by year, instead of airplane
*/
uint32 GetValidAirports(void);
#endif /* AIRPORT_H */

251
airport_gui.c Normal file
View File

@@ -0,0 +1,251 @@
/* $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);
}
static void BuildAirClick_Airport(Window *w)
{
if (HandlePlacePushButton(w, 3, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker();
}
static void BuildAirClick_Demolish(Window *w)
{
HandlePlacePushButton(w, 4, 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->click.widget - 3 >= 0)
_build_air_button_proc[e->click.widget - 3](w);
break;
case WE_KEYPRESS: {
switch (e->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->place.tile);
break;
case WE_PLACE_DRAG: {
VpSelectTilesWithMethod(e->place.pt.x, e->place.pt.y, e->place.userdata);
return;
}
case WE_PLACE_MOUSEUP:
if (e->place.pt.x != -1) {
DoCommandP(e->place.tile, e->place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
}
break;
case WE_ABORT_PLACE_OBJ:
UnclickWindowButtons(w);
SetWindowDirty(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_PANEL, RESIZE_NONE, 7, 0, 41, 14, 35, 0x2E8, STR_A01E_BUILD_AIRPORT},
{ WWT_PANEL, RESIZE_NONE, 7, 42, 63, 14, 35, 0x2BF, STR_018D_DEMOLISH_BUILDINGS_ETC},
{ WWT_PANEL, RESIZE_NONE, 7, 64, 85, 14, 35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP},
{ WIDGETS_END},
};
static const WindowDesc _air_toolbar_desc = {
640-86, 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 (_current_player == OWNER_SPECTATOR) 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_PAINT: {
int sel;
int rad = 4; // default catchment radious
uint32 avail_airports;
if (WP(w,def_d).close) return;
sel = _selected_airport_type;
avail_airports = GetValidAirports();
if (!HASBIT(avail_airports, 0) && sel == AT_SMALL) sel = AT_LARGE;
if (!HASBIT(avail_airports, 1) && sel == AT_LARGE) sel = AT_SMALL;
/* 'Country Airport' starts at widget 3, and if its bit is set, it is
* available, so take its opposite value to set the disabled_state. There
* are only 5 available airports, so XOR with 0x1F (1 1111) */
w->disabled_state = (avail_airports ^ 0x1F) << 3;
_selected_airport_type = sel;
// select default the coverage area to 'Off' (8)
w->click_state = ((1<<3) << sel) | ((1<<8) << _station_show_coverage);
SetTileSelectSize(_airport_size_x[sel],_airport_size_y[sel]);
if (_patches.modified_catchment) {
switch (sel) {
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;
}
}
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
DrawWindowWidgets(w);
// strings such as 'Size' and 'Coverage Area'
DrawStringCentered(74, 16, STR_305B_SIZE, 0);
DrawStringCentered(74, 78, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0);
DrawStationCoverageAreaText(2, 104, (uint)-1, rad);
break;
}
case WE_CLICK: {
switch (e->click.widget) {
case 3: case 4: case 5: case 6: case 7:
_selected_airport_type = e->click.widget - 3;
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
case 8: case 9:
_station_show_coverage = e->click.widget - 8;
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, 130, 0x0, STR_NULL},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 73, 27, 38, STR_3059_SMALL, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 74, 145, 27, 38, STR_305A_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 63, 74, STR_306B_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 39, 50, STR_305AA_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{WWT_NODISTXTBTN, RESIZE_NONE, 14, 2, 145, 51, 62, STR_305AB_LARGE, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 88, 98, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 88, 98, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WIDGETS_END},
};
static const WindowDesc _build_airport_desc = {
-1, -1, 148, 131, // height, 130+1
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;
_last_built_aircraft_depot_tile = 0;
}

469
airport_movement.h Normal file
View File

@@ -0,0 +1,469 @@
/* $Id$ */
#ifndef AIRPORT_MOVEMENT_H
#define AIRPORT_MOVEMENT_H
#include "stdafx.h"
typedef struct AirportMovingData {
int x,y;
byte flag;
byte direction;
} AirportMovingData;
// 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_in_chain; // next position from this position
} AirportFTAbuildup;
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,
};
enum {MAX_ELEMENTS = 255};
enum {MAX_HEADINGS = 18};
///////////////////////////////////////////////////////////////////////
///////***********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
};
///////////////////////////////////////////////////////////////////////
///////**********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,
NOTHING_block = 1 << 30
};
///////////////////////////////////////////////////////////////////////
/////*********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
};
// 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
};
// 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)
};
// 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 depots 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_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
};
// 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
};
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
NULL,
NULL,
NULL,
NULL,
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 */
/*
* This file has the core function for AyStar
* AyStar is a fast pathfinding routine and is used for things like
@@ -21,31 +19,26 @@
#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)
static PathNode *AyStarMain_ClosedList_IsInList(AyStar *aystar, 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
static void AyStarMain_ClosedList_Add(AyStar *aystar, const PathNode *node)
static void AyStarMain_ClosedList_Add(AyStar *aystar, PathNode *node)
{
// Add a node to the ClosedList
PathNode *new_node = MallocT<PathNode>(1);
PathNode *new_node = malloc(sizeof(PathNode));
*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
static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNode *node)
static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, AyStarNode *node)
{
return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
}
@@ -56,20 +49,19 @@ static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNo
static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
{
// Return the item the Queue returns.. the best next OpenList item.
OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
if (res != NULL) {
OpenListNode* res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
if (res != NULL)
Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
}
return res;
}
// 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)
static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, AyStarNode *node, int f, int g)
{
// Add a new Node to the OpenList
OpenListNode *new_node = MallocT<OpenListNode>(1);
OpenListNode* new_node = malloc(sizeof(OpenListNode));
new_node->g = g;
new_node->path.parent = parent;
new_node->path.node = *node;
@@ -82,10 +74,9 @@ static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, const AySt
/*
* Checks one tile and calculate his f-value
* return values:
* AYSTAR_DONE : indicates we are done
* AYSTAR_DONE : indicates we are done
*/
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent) {
int new_f, new_g, new_h;
PathNode *closedlist_parent;
OpenListNode *check;
@@ -116,8 +107,7 @@ int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *pare
closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
// Check if this item is already in the OpenList
check = AyStarMain_OpenList_IsInList(aystar, current);
if (check != NULL) {
if ((check = AyStarMain_OpenList_IsInList(aystar, current)) != NULL) {
uint i;
// Yes, check if this g value is lower..
if (new_g > check->g) return AYSTAR_DONE;
@@ -126,9 +116,8 @@ int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *pare
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++) {
for (i=0;i<lengthof(current->user_data);i++)
check->path.node.user_data[i] = current->user_data[i];
}
// Readd him in the OpenListQueue
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
} else {
@@ -143,15 +132,14 @@ int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *pare
* This function is the core of AyStar. It handles one item and checks
* his neighbour items. If they are valid, they are added to be checked too.
* return values:
* AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
* has been found.
* AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
* reached.
* AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
* AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
* AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
* has been found.
* AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
* reached.
* AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
* AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
*/
int AyStarMain_Loop(AyStar *aystar)
{
int AyStarMain_Loop(AyStar *aystar) {
int i, r;
// Get the best node from OpenList
@@ -174,7 +162,7 @@ int AyStarMain_Loop(AyStar *aystar)
aystar->GetNeighbours(aystar, current);
// Go through all neighbours
for (i = 0; i < aystar->num_neighbours; i++) {
for (i=0;i<aystar->num_neighbours;i++) {
// Check and add them to the OpenList if needed
r = aystar->checktile(aystar, &aystar->neighbours[i], current);
}
@@ -182,20 +170,18 @@ int AyStarMain_Loop(AyStar *aystar)
// Free the node
free(current);
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes)
/* We've expanded enough nodes */
return AYSTAR_LIMIT_REACHED;
} else {
else
// Return that we are still busy
return AYSTAR_STILL_BUSY;
}
}
/*
* This function frees the memory it allocated
*/
void AyStarMain_Free(AyStar *aystar)
{
void AyStarMain_Free(AyStar *aystar) {
aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
/* 2nd argument above is false, below is true, to free the values only
* once */
@@ -210,8 +196,7 @@ void AyStarMain_Free(AyStar *aystar)
* This function make the memory go back to zero
* This function should be called when you are using the same instance again.
*/
void AyStarMain_Clear(AyStar *aystar)
{
void AyStarMain_Clear(AyStar *aystar) {
// Clean the Queue, but not the elements within. That will be done by
// the hash.
aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
@@ -227,9 +212,9 @@ void AyStarMain_Clear(AyStar *aystar)
/*
* This is the function you call to run AyStar.
* return values:
* AYSTAR_FOUND_END_NODE : indicates we found an end node.
* AYSTAR_NO_PATH : indicates that there was no path found.
* AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
* AYSTAR_FOUND_END_NODE : indicates we found an end node.
* AYSTAR_NO_PATH : indicates that there was no path found.
* AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
* When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
* aystar->clear() is called. Note that when you stop the algorithm halfway,
* you should still call clear() yourself!
@@ -240,26 +225,24 @@ int AyStarMain_Main(AyStar *aystar) {
// 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) {
case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
case AYSTAR_LIMIT_REACHED: printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
default: break;
}
if (r == AYSTAR_FOUND_END_NODE)
printf("[AyStar] Found path!\n");
else if (r == AYSTAR_EMPTY_OPENLIST)
printf("[AyStar] OpenList run dry, no path found\n");
else if (r == AYSTAR_LIMIT_REACHED)
printf("[AyStar] Exceeded search_nodes, no path found\n");
#endif
if (r != AYSTAR_STILL_BUSY) {
if (r != AYSTAR_STILL_BUSY)
/* We're done, clean up */
_aystar_stats_open_size = aystar->OpenListHash.size;
_aystar_stats_closed_size = aystar->ClosedListHash.size;
aystar->clear(aystar);
}
switch (r) {
case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
case AYSTAR_EMPTY_OPENLIST:
case AYSTAR_LIMIT_REACHED: return AYSTAR_NO_PATH;
default: return AYSTAR_STILL_BUSY;
}
// Check result-value
if (r == AYSTAR_FOUND_END_NODE) return AYSTAR_FOUND_END_NODE;
// Check if we have some left in the OpenList
if (r == AYSTAR_EMPTY_OPENLIST || r == AYSTAR_LIMIT_REACHED) return AYSTAR_NO_PATH;
// Return we are still busy
return AYSTAR_STILL_BUSY;
}
/*
@@ -269,8 +252,7 @@ int AyStarMain_Main(AyStar *aystar) {
* clear() automatically when the algorithm finishes
* g is the cost for starting with this node.
*/
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
{
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g) {
#ifdef AYSTAR_DEBUG
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
@@ -278,8 +260,7 @@ void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g);
}
void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
{
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets) {
// Allocated the Hash for the OpenList and ClosedList
init_Hash(&aystar->OpenListHash, hash, num_buckets);
init_Hash(&aystar->ClosedListHash, hash, num_buckets);
@@ -290,10 +271,10 @@ void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
// That is why it can stay this high
init_BinaryHeap(&aystar->OpenListQueue, 102400);
aystar->addstart = AyStarMain_AddStartNode;
aystar->main = AyStarMain_Main;
aystar->loop = AyStarMain_Loop;
aystar->free = AyStarMain_Free;
aystar->clear = AyStarMain_Clear;
aystar->checktile = AyStarMain_CheckTile;
aystar->addstart = AyStarMain_AddStartNode;
aystar->main = AyStarMain_Main;
aystar->loop = AyStarMain_Loop;
aystar->free = AyStarMain_Free;
aystar->clear = AyStarMain_Clear;
aystar->checktile = AyStarMain_CheckTile;
}

View File

@@ -1,18 +1,17 @@
/* $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.
* For more information about AyStar (A* Algorithm), you can look at
* http://en.wikipedia.org/wiki/A-star_search_algorithm
* http://en.wikipedia.org/wiki/A-star_search_algorithm
*/
#ifndef AYSTAR_H
#define AYSTAR_H
#include "queue.h"
#include "tile_type.h"
//#define AYSTAR_DEBUG
enum {
@@ -28,13 +27,15 @@ enum{
AYSTAR_INVALID_NODE = -1,
};
typedef struct AyStarNode AyStarNode;
struct AyStarNode {
TileIndex tile;
int direction;
uint direction;
uint user_data[2];
};
// The resulting path has nodes looking like this.
typedef struct PathNode PathNode;
struct PathNode {
AyStarNode node;
// The parent of this item
@@ -44,17 +45,18 @@ struct PathNode {
// 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:
* AYSTAR_FOUND_END_NODE : indicates this is the end tile
* AYSTAR_DONE : indicates this is not the end tile (or direction was wrong)
* AYSTAR_FOUND_END_NODE : indicates this is the end tile
* AYSTAR_DONE : indicates this is not the end tile (or direction was wrong)
*/
/*
* The 2nd parameter should be OpenListNode, and NOT AyStarNode. AyStarNode is
@@ -69,8 +71,8 @@ typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current);
/*
* This function is called to calculate the G-value for AyStar Algorithm.
* return values can be:
* AYSTAR_INVALID_NODE : indicates an item is not valid (e.g.: unwalkable)
* Any value >= 0 : the g-value for this tile
* AYSTAR_INVALID_NODE : indicates an item is not valid (e.g.: unwalkable)
* Any value >= 0 : the g-value for this tile
*/
typedef int32 AyStar_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
@@ -79,7 +81,7 @@ typedef int32 AyStar_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNod
* Mostly, this must result the distance (Manhattan way) between the
* current point and the end point
* return values can be:
* Any value >= 0 : the h-value for this tile
* Any value >= 0 : the h-value for this tile
*/
typedef int32 AyStar_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
@@ -97,7 +99,7 @@ typedef void AyStar_GetNeighbours(AyStar *aystar, OpenListNode *current);
typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current);
// For internal use, see aystar.c
typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g);
typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode* start_node, uint g);
typedef int AyStar_Main(AyStar *aystar);
typedef int AyStar_Loop(AyStar *aystar);
typedef int AyStar_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
@@ -110,11 +112,11 @@ struct AyStar {
/* These should point to the application specific routines that do the
* actual work */
AyStar_CalculateG *CalculateG;
AyStar_CalculateH *CalculateH;
AyStar_GetNeighbours *GetNeighbours;
AyStar_EndNodeCheck *EndNodeCheck;
AyStar_FoundEndNode *FoundEndNode;
AyStar_CalculateG* CalculateG;
AyStar_CalculateH* CalculateH;
AyStar_GetNeighbours* GetNeighbours;
AyStar_EndNodeCheck* EndNodeCheck;
AyStar_FoundEndNode* FoundEndNode;
/* These are completely untouched by AyStar, they can be accesed by
* the application specific routines to input and output data.
@@ -142,12 +144,12 @@ struct AyStar {
/* These will contain the methods for manipulating the AyStar. Only
* main() should be called externally */
AyStar_AddStartNode *addstart;
AyStar_Main *main;
AyStar_Loop *loop;
AyStar_Free *free;
AyStar_Clear *clear;
AyStar_CheckTile *checktile;
AyStar_AddStartNode* addstart;
AyStar_Main* main;
AyStar_Loop* loop;
AyStar_Free* free;
AyStar_Clear* clear;
AyStar_CheckTile* checktile;
/* These will contain the open and closed lists */
@@ -171,7 +173,7 @@ void AyStarMain_Clear(AyStar *aystar);
/* Initialize an AyStar. You should fill all appropriate fields before
* callling init_AyStar (see the declaration of AyStar for which fields are
* internal */
void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets);
void init_AyStar(AyStar* aystar, Hash_HashProc hash, uint num_buckets);
#endif /* AYSTAR_H */

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +0,0 @@
You can place you scenarios in this dir.
This file is really here to make the Makefile happy, it should be modified to
properly handle scenarios (or maybe even not at all...).

25
bridge.h Normal file
View File

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

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 >> 4) * 10);
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->keypress.keycode - '1';
if (i < 9 && i < _bridgedata.count) {
e->keypress.cont = false;
BuildBridge(w, i);
}
break;
}
case WE_CLICK:
if (e->click.widget == 2) {
uint ind = ((int)e->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 = {
-1, -1, 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 = {
-1, -1, 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 = DoCommandByTile(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) * 16, TileY(end) * 16);
}
}

View File

@@ -1,60 +1,57 @@
/* $Id$ */
/** @file callback_table.cpp */
#include "stdafx.h"
#include "openttd.h"
#include "callback_table.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 */
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 CcAI;
CommandCallback CcCloneTrain;
CommandCallback *_callback_table[] = {
/* 0x00 */ NULL,
@@ -78,9 +75,10 @@ CommandCallback *_callback_table[] = {
/* 0x12 */ CcPlaySound1E,
/* 0x13 */ CcStation,
/* 0x14 */ CcTerraform,
/* 0x15 */ CcAI,
/* 0x16 */ CcCloneVehicle,
/* 0x17 */ CcGiveMoney,
/* 0x15 */ CcCloneAircraft,
/* 0x16 */ CcCloneRoadVeh,
/* 0x17 */ CcCloneShip,
/* 0x18 */ CcCloneTrain,
};
const int _callback_table_count = lengthof(_callback_table);

View File

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

File diff suppressed because it is too large Load Diff

837
clear_cmd.c Normal file
View File

@@ -0,0 +1,837 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "player.h"
#include "tile.h"
#include "viewport.h"
#include "command.h"
#include "variables.h"
#include "table/sprites.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;
assert(tile < MapSize());
if ((r=TerraformAllowTileProcess(ts, tile)) <= 0)
return r;
if (!IsTileType(tile, MP_RAILWAY)) {
int32 ret = DoCommandByTile(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 x,y coordinates to terraform
* @param p1 corners to terraform.
* @param p2 direction; eg up or down
*/
int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TerraformerState ts;
TileIndex tile;
int direction;
TerraformerHeightMod modheight_data[576];
TileIndex tile_table_data[625];
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
_error_message = INVALID_STRING_ID;
_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;
tile = TileVirtXY(x, y);
/* Make an extra check for map-bounds cause we add tiles to the originating tile */
if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
if (p1 & 1) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 0),
TileHeight(tile + TileDiffXY(1, 0)) + direction))
return CMD_ERROR;
}
if (p1 & 2) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(1, 1),
TileHeight(tile + TileDiffXY(1, 1)) + direction))
return CMD_ERROR;
}
if (p1 & 4) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 1),
TileHeight(tile + TileDiffXY(0, 1)) + direction))
return CMD_ERROR;
}
if (p1 & 8) {
if (!TerraformTileHeight(&ts, tile + TileDiffXY(0, 0),
TileHeight(tile + TileDiffXY(0, 0)) + direction))
return CMD_ERROR;
}
{ /* Check if tunnel or track would take damage */
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
uint a, b, c, d, r, min;
TileIndex tile = *ti;
_terraform_err_tile = tile;
a = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
b = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
c = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
d = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
r = GetTileh(a, b, c, d, &min);
if (IsTileType(tile, MP_RAILWAY)) {
if (IsSteepTileh(r)) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
if (IsPlainRailTile(tile)) {
extern const TrackBits _valid_tileh_slopes[2][15];
if (GetTrackBits(tile) & ~_valid_tileh_slopes[0][r]) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
} else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
}
if (direction == -1 && !CheckTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
_terraform_err_tile = 0;
}
}
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++) {
DoCommandByTile(*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 x,y end tile of area-drag
* @param p1 start tile of area drag
* @param p2 unused
*/
int32 CmdLevelLand(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
{
int size_x, size_y;
int sx, sy;
uint h, curh;
TileIndex tile;
int32 ret, cost, money;
if (p1 >= MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// remember level height
h = TileHeight(p1);
ex >>= 4; ey >>= 4;
// make sure sx,sy are smaller than ex,ey
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 = DoCommandByTile(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;
}
DoCommandByTile(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 x,y the tile the player is purchasing
* @param p1 unused
* @param p2 unused
*/
int32 CmdPurchaseLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile;
int32 cost;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TileVirtXY(x, y);
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (IsTileType(tile, MP_UNMOVABLE) && _m[tile].m5 == 3 &&
IsTileOwner(tile, _current_player))
return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
cost = DoCommandByTile(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(cost)) return CMD_ERROR;
if (flags & DC_EXEC) {
ModifyTile(tile,
MP_SETTYPE(MP_UNMOVABLE) | MP_MAPOWNER_CURRENT | MP_MAP5,
3 /* map5 */
);
}
return cost + _price.purchase_land * 10;
}
static int32 ClearTile_Clear(TileIndex tile, byte flags)
{
static const int32 null = 0;
static const int32* clear_price_table[] = {
&null,
&_price.clear_1,
&_price.clear_1,
&_price.clear_1,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_3,
&_price.clear_3,
&_price.clear_3,
&_price.clear_3,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
&_price.clear_2,
};
const int32 *price = clear_price_table[GB(_m[tile].m5, 0, 5)];
if (flags & DC_EXEC) DoClearSquare(tile);
return *price;
}
/** Sell a land area. Actually you only sell one tile, so
* the name is a bit confusing ;p
* @param x,y the tile the player is selling
* @param p1 unused
* @param p2 unused
*/
int32 CmdSellLandArea(int x, int y, uint32 flags, uint32 p1, uint32 p2)
{
TileIndex tile;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
tile = TileVirtXY(x, y);
if (!IsTileType(tile, MP_UNMOVABLE) || _m[tile].m5 != 3) return CMD_ERROR;
if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (flags & DC_EXEC)
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 != 0) {
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 m4 = _m[ti->tile].m4;
byte z = ti->z;
if (ti->tileh & 2) {
z += 8;
if (ti->tileh == 0x17) z += 8;
}
if (GB(m4, 5, 3) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GB(m4, 5, 3) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
}
if (GB(m4, 2, 3) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GB(m4, 2, 3) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
}
}
static void DrawTile_Clear(TileInfo *ti)
{
switch (GB(ti->map5, 2, 3)) {
case 0:
DrawClearLandTile(ti, GB(ti->map5, 0, 2));
break;
case 1:
DrawHillyLandTile(ti);
break;
case 2:
DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
break;
case 3:
DrawGroundSprite(_clear_land_sprites_1[GB(_m[ti->tile].m3, 0, 4)] + _tileh_to_sprite[ti->tileh]);
break;
case 4:
DrawGroundSprite(_clear_land_sprites_2[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
break;
case 5:
DrawGroundSprite(_clear_land_sprites_3[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
break;
}
DrawClearLandFence(ti);
}
static uint GetSlopeZ_Clear(const TileInfo* ti)
{
return GetPartialZ(ti->x & 0xF, ti->y & 0xF, ti->tileh) + ti->z;
}
static uint GetSlopeTileh_Clear(const TileInfo *ti)
{
return ti->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;
switch (GetTileType(tile)) {
case MP_CLEAR:
self = (GB(_m[tile].m5, 0, 5) == 15);
break;
default:
self = 0;
break;
}
switch (GetTileType(TILE_ADDXY(tile, 1, 0))) {
case MP_CLEAR:
neighbour = (GB(_m[TILE_ADDXY(tile, 1, 0)].m5, 0, 5) == 15);
break;
default:
neighbour = 0;
break;
}
if (GB(_m[tile].m4, 5, 3) == 0) {
if (self != neighbour) {
SB(_m[tile].m4, 5, 3, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SB(_m[tile].m4, 5, 3, 0);
dirty = tile;
}
}
switch (GetTileType(TILE_ADDXY(tile, 0, 1))) {
case MP_CLEAR:
neighbour = (GB(_m[TILE_ADDXY(tile, 0, 1)].m5, 0, 5) == 15);
break;
default:
neighbour = 0;
break;
}
if (GB(_m[tile].m4, 2, 3) == 0) {
if (self != neighbour) {
SB(_m[tile].m4, 2, 3, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SB(_m[tile].m4, 2, 3, 0);
dirty = tile;
}
}
if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
}
/* convert into snowy tiles */
static void TileLoopClearAlps(TileIndex tile)
{
int k;
byte m5,tmp;
/* distance from snow line, in steps of 8 */
k = GetTileZ(tile) - _opt.snow_line;
m5 = _m[tile].m5 & 0x1C;
tmp = _m[tile].m5 & 3;
if (k < -8) {
/* snow_m2_down */
if (m5 != 0x10)
return;
if (tmp == 0)
m5 = 3;
} else if (k == -8) {
/* snow_m1 */
if (m5 != 0x10) {
m5 = 0x10;
} else if (tmp != 0) {
m5 = (tmp - 1) + 0x10;
} else
return;
} else if (k < 8) {
/* snow_0 */
if (m5 != 0x10) {
m5 = 0x10;
} else if (tmp != 1) {
m5 = 1;
if (tmp != 0)
m5 = tmp - 1;
m5 += 0x10;
} else
return;
} else if (k == 8) {
/* snow_p1 */
if (m5 != 0x10) {
m5 = 0x10;
} else if (tmp != 2) {
m5 = 2;
if (tmp <= 2)
m5 = tmp + 1;
m5 += 0x10;
} else
return;
} else {
/* snow_p2_up */
if (m5 != 0x10) {
m5 = 0x10;
} else if (tmp != 3) {
m5 = tmp + 1 + 0x10;
} else
return;
}
_m[tile].m5 = m5;
MarkTileDirtyByTile(tile);
}
static void TileLoopClearDesert(TileIndex tile)
{
if ((_m[tile].m5 & 0x1C) == 0x14) return;
if (GetMapExtraBits(tile) == 1) {
_m[tile].m5 = 0x17;
} else {
if (GetMapExtraBits(tile + TileDiffXY( 1, 0)) != 1 &&
GetMapExtraBits(tile + TileDiffXY(-1, 0)) != 1 &&
GetMapExtraBits(tile + TileDiffXY( 0, 1)) != 1 &&
GetMapExtraBits(tile + TileDiffXY( 0, -1)) != 1)
return;
_m[tile].m5 = 0x15;
}
MarkTileDirtyByTile(tile);
}
static void TileLoop_Clear(TileIndex tile)
{
byte m5,m3;
TileLoopClearHelper(tile);
if (_opt.landscape == LT_DESERT) {
TileLoopClearDesert(tile);
} else if (_opt.landscape == LT_HILLY) {
TileLoopClearAlps(tile);
}
m5 = _m[tile].m5;
if ((m5 & 0x1C) == 0x10 || (m5 & 0x1C) == 0x14) return;
if ((m5 & 0x1C) != 0xC) {
if ((m5 & 3) == 3) return;
if (_game_mode != GM_EDITOR) {
m5 += 0x20;
if (m5 >= 0x20) {
// Didn't overflow
_m[tile].m5 = m5;
return;
}
/* did overflow, so continue */
} else {
m5 = (GB(Random(), 0, 8) > 21) ? 2 : 6;
}
m5++;
} else if (_game_mode != GM_EDITOR) {
/* handle farm field */
m5 += 0x20;
if (m5 >= 0x20) {
// Didn't overflow
_m[tile].m5 = m5;
return;
}
/* overflowed */
m3 = _m[tile].m3 + 1;
assert( (m3 & 0xF) != 0);
if ( (m3 & 0xF) >= 9) /* NOTE: will not work properly if m3&0xF == 0xF */
m3 &= ~0xF;
_m[tile].m3 = m3;
}
_m[tile].m5 = m5;
MarkTileDirtyByTile(tile);
}
void GenerateClearTile(void)
{
uint i;
TileIndex tile;
/* add hills */
i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
do {
tile = RandomTile();
if (IsTileType(tile, MP_CLEAR)) SB(_m[tile].m5, 2, 2, 1);
} while (--i);
/* add grey squares */
i = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
do {
uint32 r = Random();
tile = RandomTileSeed(r);
if (IsTileType(tile, MP_CLEAR)) {
uint j = GB(r, 16, 4) + 5;
for(;;) {
TileIndex tile_new;
SB(_m[tile].m5, 2, 2, 2);
do {
if (--j == 0) goto get_out;
tile_new = tile + TileOffsByDir(GB(Random(), 0, 2));
} while (!IsTileType(tile_new, MP_CLEAR));
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_080B_ROUGH_LAND,
STR_080A_ROCKS,
STR_080E_FIELDS,
STR_080F_SNOW_COVERED_LAND,
STR_0810_DESERT,
0,
0,
STR_080C_BARE_LAND,
STR_080D_GRASS,
STR_080D_GRASS,
STR_080D_GRASS,
};
static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
{
uint i = GB(_m[tile].m5, 2, 3);
if (i == 0) i = GB(_m[tile].m5, 0, 2) + 8;
td->str = _clear_land_str[i - 1];
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 * 8;
}
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 */
NULL, /* vehicle_leave_tile_proc */
GetSlopeTileh_Clear, /* get_slope_tileh_proc */
};

549
command.c Normal file
View File

@@ -0,0 +1,549 @@
/* $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"
const char* _cmd_text = NULL;
#define DEF_COMMAND(yyyy) int32 yyyy(int x, int y, 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(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(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(CmdReplaceVehicle);
DEF_COMMAND(CmdCloneVehicle);
/* 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 */
{NULL, 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 */
{NULL, 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 */
{CmdReplaceVehicle, 0}, /* 115 */
{CmdCloneVehicle, 0}, /* 116 */
};
/* 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;}
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
return DoCommand(TileX(tile) * 16, TileY(tile) * 16, p1, p2, flags, procc);
}
static int _docommand_recursive;
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
int32 res;
CommandProc *proc;
/* Do not even think about executing out-of-bounds tile-commands */
if (TileVirtXY(x, y) >= 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(x, y, flags&~DC_EXEC, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
goto error;
}
if (_docommand_recursive == 1) {
if (!(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(x, y, 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 ( (x|y) != 0 && _current_player < MAX_PLAYERS) {
GetPlayer(_current_player)->last_build_coordinate = TileVirtXY(x, y);
}
}
_cmd_text = NULL;
return res;
}
int32 GetAvailableMoneyForCommand(void)
{
PlayerID pid = _current_player;
if (pid >= MAX_PLAYERS) 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;
int x = TileX(tile) * 16;
int y = TileY(tile) * 16;
/* Do not even think about executing out-of-bounds tile-commands */
if (tile >= MapSize()) {
_cmd_text = NULL;
return false;
}
assert(_docommand_recursive == 0);
_error_message = INVALID_STRING_ID;
_error_message_2 = cmd >> 16;
_additional_cash_required = 0;
/** Spectator has no rights except for the dedicated server which
* is a spectator but is the server, so can do anything */
if (_current_player == OWNER_SPECTATOR && !_network_dedicated) {
ShowErrorMessage(_error_message, _error_message_2, 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 (_shift_pressed && IsLocalPlayer() && !(cmd & (CMD_NETWORK_COMMAND | CMD_SHOW_NO_ERROR))) {
// estimate the cost.
res = proc(x, y, flags, p1, p2);
if (CmdFailed(res)) {
if (res & 0xFFFF) _error_message = res & 0xFFFF;
ShowErrorMessage(_error_message, _error_message_2, 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(x,y, 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.
* @todo Rewrite dedicated server to something more than a dirty hack!
*/
if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
if (_network_dedicated) _local_player = 0;
NetworkSend_Command(tile, p1, p2, cmd, callback);
if (_network_dedicated) _local_player = OWNER_SPECTATOR;
_docommand_recursive = 0;
_cmd_text = NULL;
return true;
}
#endif /* ENABLE_NETWORK */
// update last build coordinate of player.
if ( tile != 0 && _current_player < MAX_PLAYERS) 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(x,y, 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_message_2, 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_message_2 != 0)
ShowErrorMessage(_error_message, _error_message_2, x,y);
callb_err:
_docommand_recursive = 0;
if (callback) callback(false, tile, p1, p2);
_cmd_text = NULL;
return false;
}

201
command.h Normal file
View File

@@ -0,0 +1,201 @@
/* $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_TRAIN_GOTO_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_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_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_REPLACE_VEHICLE = 115,
CMD_CLONE_VEHICLE = 116,
};
enum {
DC_EXEC = 1,
DC_AUTO = 2, // don't allow building on structures
DC_QUERY_COST = 4, // query cost only, don't build.
DC_NO_WATER = 8, // 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 = 0x200,
CMD_NO_WATER = 0x400,
CMD_NETWORK_COMMAND = 0x800, // execute the command without sending it on the network
CMD_NO_TEST_IF_IN_NETWORK = 0x1000, // When enabled, the command will bypass the no-DC_EXEC round if in network
CMD_SHOW_NO_ERROR = 0x2000,
};
/** Command flags for the command table
* @see _command_proc_table
*/
enum {
CMD_SERVER = 0x1, /// the command can only be initiated by the server
CMD_OFFLINE = 0x2, /// the command cannot be executed in a multiplayer game; single-player only
};
typedef struct Command {
CommandProc *proc;
byte flags;
} Command;
//#define return_cmd_error(errcode) do { _error_message=(errcode); return CMD_ERROR; } while(0)
#define return_cmd_error(errcode) do { 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 */
int32 DoCommand(int x, int y, uint32 p1, uint32 p2, uint32 flags, uint procc);
int32 DoCommandByTile(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
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 */

2384
config.lib

File diff suppressed because it is too large Load Diff

134
configure vendored
View File

@@ -1,134 +0,0 @@
#!/bin/sh
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"
fi
fi
# Find out where configure is (in what dir)
ROOT_DIR="`dirname $0`"
ROOT_DIR="`cd $ROOT_DIR && pwd`"
PWD="`pwd`"
PREFIX="`pwd`/bin"
. $ROOT_DIR/config.lib
# 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
rm -f cache.tmp
exit $?
fi
set_default
detect_params "$@"
check_params
save_params
make_cflags_and_ldflags
EXE=""
if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ] || [ "$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
SRCS="`< $ROOT_DIR/source.list tr '\r' '\n' | $awk '
{ }
/^( *)#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 == "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 == "BEOS" && "'$os'" != "BEOS") { next; }
if ($0 == "WIN32" && "'$os'" != "MINGW" &&
"'$os'" != "CYGWIN" && "'$os'" != "MSVC" ) { 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 == "NO_THREADS" && "'$with_threads'" == "0") { next; }
skip += 1;
next;
}
/^( *)#/ { next }
/^$/ { next }
/\.h$/ { next }
/\.hpp$/ { next }
{
if (deep == skip) {
gsub(" ", "", $0);
print $0;
}
}
' | $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"
generate_main
generate_lang
generate_src

View File

@@ -1,25 +1,21 @@
/* $Id$ */
/** @file console.cpp */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "window.h"
#include "gui.h"
#include "textbuf_gui.h"
#include "window_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/network.h"
#include "network/network_data.h"
#include "network/network_server.h"
#include "core/alloc_func.hpp"
#include "window_func.h"
#include "string_func.h"
#include "gfx_func.h"
#include "table/strings.h"
#include "network.h"
#include "network_data.h"
#include "network_server.h"
#define ICON_BUFFER 79
#define ICON_HISTORY_SIZE 20
@@ -29,67 +25,55 @@
#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
/* console colors/modes */
byte _icolour_def;
byte _icolour_err;
byte _icolour_warn;
byte _icolour_dbg;
byte _icolour_cmd;
IConsoleModes _iconsole_mode;
/* ** main console ** */
// ** main console ** //
static Window *_iconsole_win; // Pointer to console window
static bool _iconsole_inited;
static char *_iconsole_buffer[ICON_BUFFER + 1];
static uint16 _iconsole_cbuffer[ICON_BUFFER + 1];
static Textbuf _iconsole_cmdline;
static byte _iconsole_scroll;
/* ** stdlib ** */
// ** stdlib ** //
byte _stdlib_developer = 1;
bool _stdlib_con_developer = false;
FILE *_iconsole_output_file;
/* ** main console cmd buffer ** */
// ** main console cmd buffer
static char *_iconsole_history[ICON_HISTORY_SIZE];
static byte _iconsole_historypos;
/* *************** *
* end of header *
* *************** */
/* *************** */
/* end of header */
/* *************** */
static void IConsoleClearCommand()
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));
SetWindowDirty(_iconsole_win);
}
static inline void IConsoleResetHistoryPos() {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
static inline void IConsoleResetHistoryPos(void) {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
static void IConsoleHistoryAdd(const char *cmd);
static void IConsoleHistoryAdd(const char* cmd);
static void IConsoleHistoryNavigate(int direction);
/* ** console window ** */
static void IConsoleWndProc(Window *w, WindowEvent *e)
// ** 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 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)) {
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]);
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 ']' */
@@ -102,7 +86,7 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
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, TC_WHITE);
DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, 12);
break;
}
case WE_MOUSELOOP:
@@ -110,11 +94,12 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w);
break;
case WE_DESTROY:
_iconsole_win = NULL;
_iconsole_mode = ICONSOLE_CLOSED;
break;
case WE_KEYPRESS:
e->we.keypress.cont = false;
switch (e->we.keypress.keycode) {
e->keypress.cont = false;
switch (e->keypress.keycode) {
case WKC_UP:
IConsoleHistoryNavigate(+1);
SetWindowDirty(w);
@@ -124,35 +109,31 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
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;
}
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;
}
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;
}
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;
}
if (_iconsole_scroll >= ICON_BUFFER)
_iconsole_scroll = ICON_BUFFER;
else
++_iconsole_scroll;
SetWindowDirty(w);
break;
case WKC_BACKQUOTE:
@@ -167,7 +148,7 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
break;
case WKC_CTRL | WKC_RETURN:
_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
IConsoleResize(w);
IConsoleResize();
MarkWholeScreenDirty();
break;
case (WKC_CTRL | 'V'):
@@ -184,26 +165,25 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
SetWindowDirty(w);
break;
case WKC_BACKSPACE: case WKC_DELETE:
if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
if (DeleteTextBufferChar(&_iconsole_cmdline, e->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)) {
if (MoveTextBufferPos(&_iconsole_cmdline, e->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);
if (IsValidAsciiChar(e->keypress.ascii)) {
_iconsole_scroll = ICON_BUFFER;
InsertTextBufferChar(&_iconsole_cmdline, e->keypress.ascii);
IConsoleResetHistoryPos();
SetWindowDirty(w);
} else {
e->we.keypress.cont = true;
}
} else
e->keypress.cont = true;
break;
}
}
@@ -214,14 +194,14 @@ static const Widget _iconsole_window_widgets[] = {
};
static const WindowDesc _iconsole_window_desc = {
0, 0, 2, 2, 2, 2,
WC_CONSOLE, WC_NONE,
0, 0, 2, 2,
WC_CONSOLE, 0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_iconsole_window_widgets,
IConsoleWndProc,
};
void IConsoleInit()
void IConsoleInit(void)
{
extern const char _openttd_revision[];
_iconsole_output_file = NULL;
@@ -229,9 +209,12 @@ void IConsoleInit()
_icolour_err = 3;
_icolour_warn = 13;
_icolour_dbg = 5;
_icolour_cmd = TC_GOLD;
_icolour_cmd = 2;
_iconsole_scroll = ICON_BUFFER;
_iconsole_historypos = ICON_HISTORY_SIZE - 1;
_iconsole_inited = true;
_iconsole_mode = ICONSOLE_CLOSED;
_iconsole_win = NULL;
#ifdef ENABLE_NETWORK /* Initialize network only variables */
_redirect_console_to_client = 0;
@@ -240,8 +223,8 @@ void IConsoleInit()
memset(_iconsole_history, 0, sizeof(_iconsole_history));
memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer));
memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer));
_iconsole_cmdline.buf = CallocT<char>(ICON_CMDLN_SIZE); // create buffer and zero it
_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE;
_iconsole_cmdline.buf = calloc(ICON_CMDLN_SIZE, sizeof(*_iconsole_cmdline.buf)); // create buffer and zero it
_iconsole_cmdline.maxlength = ICON_CMDLN_SIZE - 1;
IConsolePrintF(13, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
IConsolePrint(12, "------------------------------------");
@@ -252,7 +235,7 @@ void IConsoleInit()
IConsoleHistoryAdd("");
}
void IConsoleClearBuffer()
void IConsoleClearBuffer(void)
{
uint i;
for (i = 0; i <= ICON_BUFFER; i++) {
@@ -261,22 +244,22 @@ void IConsoleClearBuffer()
}
}
static void IConsoleClear()
static void IConsoleClear(void)
{
free(_iconsole_cmdline.buf);
IConsoleClearBuffer();
}
static void IConsoleWriteToLogFile(const char *string)
static void IConsoleWriteToLogFile(const char* string)
{
if (_iconsole_output_file != NULL) {
/* if there is an console output file ... also print it there */
// 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(_icolour_def, "file output complete");
@@ -288,58 +271,62 @@ bool CloseConsoleLogIfActive()
return false;
}
void IConsoleFree()
void IConsoleFree(void)
{
_iconsole_inited = false;
IConsoleClear();
CloseConsoleLogIfActive();
}
void IConsoleResize(Window *w)
void IConsoleResize(void)
{
_iconsole_win = FindWindowById(WC_CONSOLE, 0);
switch (_iconsole_mode) {
case ICONSOLE_OPENED:
w->height = _screen.height / 3;
w->width = _screen.width;
_iconsole_win->height = _screen.height / 3;
_iconsole_win->width = _screen.width;
break;
case ICONSOLE_FULL:
w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
w->width = _screen.width;
_iconsole_win->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
_iconsole_win->width = _screen.width;
break;
default: return;
default: break;
}
MarkWholeScreenDirty();
}
void IConsoleSwitch()
void IConsoleSwitch(void)
{
switch (_iconsole_mode) {
case ICONSOLE_CLOSED: {
Window *w = AllocateWindowDesc(&_iconsole_window_desc);
w->height = _screen.height / 3;
w->width = _screen.width;
case ICONSOLE_CLOSED:
_iconsole_win = AllocateWindowDesc(&_iconsole_window_desc);
_iconsole_win->height = _screen.height / 3;
_iconsole_win->width = _screen.width;
_iconsole_mode = ICONSOLE_OPENED;
SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
} break;
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_win = NULL;
_iconsole_mode = ICONSOLE_CLOSED;
ClrBit(_no_scroll, SCROLL_CON);
CLRBIT(_no_scroll, SCROLL_CON);
break;
}
MarkWholeScreenDirty();
}
void IConsoleClose() {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
void IConsoleOpen() {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
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)
static void IConsoleHistoryAdd(const char* cmd)
{
free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
@@ -356,7 +343,7 @@ static void IConsoleHistoryNavigate(int direction)
{
int i = _iconsole_historypos + direction;
/* watch out for overflows, just wrap around */
// watch out for overflows, just wrap around
if (i < 0) i = ICON_HISTORY_SIZE - 1;
if (i >= ICON_HISTORY_SIZE) i = 0;
@@ -369,8 +356,8 @@ static void IConsoleHistoryNavigate(int direction)
_iconsole_historypos = i;
IConsoleClearCommand();
/* copy history to 'command prompt / bash' */
assert(_iconsole_history[i] != NULL && IsInsideMM(i, 0, ICON_HISTORY_SIZE));
// 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);
}
@@ -384,9 +371,8 @@ static void IConsoleHistoryNavigate(int direction)
* @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(uint16 color_code, const char *string)
void IConsolePrint(uint16 color_code, const char* string)
{
char *str;
#ifdef ENABLE_NETWORK
if (_redirect_console_to_client != 0) {
/* Redirect the string to the client */
@@ -395,38 +381,38 @@ void IConsolePrint(uint16 color_code, const char *string)
}
#endif
/* Create a copy of the string, strip if of colours and invalid
* characters and (when applicable) assign it to the console buffer */
str = strdup(string);
str_strip_colours(str);
str_validate(str);
if (_network_dedicated) {
fprintf(stdout, "%s\n", str);
fflush(stdout);
IConsoleWriteToLogFile(str);
free(str); // free duplicated string since it's not used anymore
printf("%s\n", string);
IConsoleWriteToLogFile(string);
return;
}
if (!_iconsole_inited) return;
/* 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;
_iconsole_buffer[ICON_BUFFER] = strdup(string);
{ // filter out unprintable characters
char *i;
for (i = _iconsole_buffer[ICON_BUFFER]; *i != '\0'; i++)
if (!IsValidAsciiChar((byte)*i)) *i = ' ';
}
memmove(&_iconsole_cbuffer[0], &_iconsole_cbuffer[1], sizeof(_iconsole_cbuffer[0]) * ICON_BUFFER);
_iconsole_cbuffer[ICON_BUFFER] = color_code;
IConsoleWriteToLogFile(_iconsole_buffer[ICON_BUFFER]);
IConsoleWriteToLogFile(string);
SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
if (_iconsole_win != NULL) SetWindowDirty(_iconsole_win);
}
/**
* 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(uint16 color_code, const char *s, ...)
{
@@ -443,15 +429,13 @@ void CDECL IConsolePrintF(uint16 color_code, const char *s, ...)
/**
* 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(_icolour_dbg, "dbg: [%s] %s", dbg, string);
IConsolePrintF(_icolour_dbg, "dbg: %s", string);
}
/**
@@ -459,7 +443,7 @@ void IConsoleDebug(const char *dbg, const char *string)
* errors or mishaps, but non-fatal. You need at least a level 1 (developer) for
* debugging messages to show up
*/
void IConsoleWarning(const char *string)
void IConsoleWarning(const char* string)
{
if (_stdlib_developer > 0)
IConsolePrintF(_icolour_warn, "WARNING: %s", string);
@@ -469,7 +453,7 @@ void IConsoleWarning(const char *string)
* It is possible to print error information to the console. This can include
* game errors, or errors in general you would want the user to notice
*/
void IConsoleError(const char *string)
void IConsoleError(const char* string)
{
IConsolePrintF(_icolour_err, "ERROR: %s", string);
}
@@ -477,7 +461,7 @@ void IConsoleError(const char *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
*/
@@ -498,13 +482,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
*/
@@ -529,9 +512,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)
@@ -586,41 +569,40 @@ void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *
* three types, just with different variables. Yes, templates would be handy. It was
* either this define or an even more ugly void* magic function
*/
#define IConsoleAddSorted(_base, item_new, IConsoleType, type) \
{ \
IConsoleType *item, *item_before; \
/* first command */ \
if (_base == NULL) { \
_base = item_new; \
return; \
} \
\
item_before = NULL; \
item = _base; \
\
/* BEGIN - Alphabetically insert the commands into the linked list */ \
while (item != NULL) { \
int i = strcmp(item->name, item_new->name); \
if (i == 0) { \
IConsoleError(type " with this name already exists; insertion aborted"); \
free(item_new); \
return; \
} \
\
if (i > 0) break; /* insert at this position */ \
\
item_before = item; \
item = item->next; \
} \
\
if (item_before == NULL) { \
_base = item_new; \
} else { \
item_before->next = item_new; \
} \
\
item_new->next = item; \
/* END - Alphabetical insert */ \
#define IConsoleAddSorted(_base, item_new, IConsoleType, type) \
{ \
IConsoleType *item, *item_before; \
/* first command */ \
if (_base == NULL) { \
_base = item_new; \
return; \
} \
\
item_before = NULL; \
item = _base; \
\
/* BEGIN - Alphabetically insert the commands into the linked list */ \
while (item != NULL) { \
int i = strcmp(item->name, item_new->name); \
if (i == 0) { \
IConsoleError(type " with this name already exists; insertion aborted"); \
free(item_new); \
return; \
} \
\
if (i > 0) break; /* insert at this position */ \
\
item_before = item; \
item = item->next; \
} \
\
if (item_before == NULL) { \
_base = item_new; \
} else \
item_before->next = item_new; \
\
item_new->next = item; \
/* END - Alphabetical insert */ \
}
/**
@@ -631,7 +613,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;
@@ -668,7 +650,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;
@@ -696,7 +678,7 @@ IConsoleAlias *IConsoleAliasGet(const char *name)
/** copy in an argument into the aliasstream */
static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
{
int len = min(ICON_MAX_STREAMSIZE - bufpos, (uint)strlen(src));
int len = min(ICON_MAX_STREAMSIZE - bufpos, strlen(src));
strncpy(dst, src, len);
return len;
@@ -709,11 +691,11 @@ static inline int IConsoleCopyInParams(char *dst, const char *src, uint bufpos)
* @param tokencount the number of parameters passed
* @param *tokens are the parameters given to the original command (0 is the first param)
*/
static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT])
static void IConsoleAliasExec(const IConsoleAlias* alias, byte tokencount, char* tokens[ICON_TOKEN_COUNT])
{
const char *cmdptr;
char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE];
uint i;
int i;
uint a_index, astream_i;
memset(&aliases, 0, sizeof(aliases));
@@ -727,18 +709,18 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
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);
@@ -746,7 +728,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);
@@ -755,7 +737,7 @@ 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) {
@@ -776,17 +758,14 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
}
}
for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn
for (i = 0; i <= (int)a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn
}
/**
* 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)
{
@@ -806,7 +785,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;
@@ -878,12 +857,12 @@ static void IConsoleVarSetValue(const IConsoleVar *var, uint32 value)
* @param *var the variable in question
* @param *value the new value
*/
static void IConsoleVarSetStringvalue(const IConsoleVar *var, const char *value)
static void IConsoleVarSetStringvalue(const IConsoleVar *var, 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((char*)var->addr, (char*)value, var->size);
IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_POST_ACTION);
IConsoleVarPrintSetValue(var); // print out the new value, giving feedback
return;
@@ -1075,7 +1054,7 @@ void IConsoleCmdExec(const char *cmdstr)
if (cmdstr[0] == '#') return; // comments
for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
if (!IsValidAsciiChar(*cmdptr)) {
IConsoleError("command contains malformed characters, aborting");
IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
return;
@@ -1107,16 +1086,10 @@ 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 ""
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) {
@@ -1129,10 +1102,8 @@ void IConsoleCmdExec(const char *cmdstr)
if (_stdlib_con_developer) {
uint i;
for (i = 0; tokens[i] != NULL; i++) {
for (i = 0; tokens[i] != NULL; i++)
IConsolePrintF(_icolour_dbg, "condbg: token %d is: '%s'", i, tokens[i]);
}
}
if (tokens[0] == '\0') return; // don't execute empty commands
@@ -1140,33 +1111,31 @@ void IConsoleCmdExec(const char *cmdstr)
* First try commands, then aliases, and finally variables. Execute
* the found action taking into account its hooking code
*/
cmd = IConsoleCmdGet(tokens[0]);
if (cmd != NULL) {
cmd = IConsoleCmdGet(tokens[0]);
if (cmd != NULL) {
if (IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_ACCESS)) {
IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_PRE_ACTION);
if (cmd->proc(t_index, tokens)) { // index started with 0
IConsoleHookHandle(&cmd->hook, ICONSOLE_HOOK_POST_ACTION);
} else {
cmd->proc(0, NULL); // if command failed, give help
}
} else cmd->proc(0, NULL); // if command failed, give help
}
return;
}
return;
}
t_index--; // ignore the variable-name for comfort for both aliases and variaables
alias = IConsoleAliasGet(tokens[0]);
if (alias != NULL) {
IConsoleAliasExec(alias, t_index, &tokens[1]);
return;
}
t_index--; // ignore the variable-name for comfort for both aliases and variaables
alias = IConsoleAliasGet(tokens[0]);
if (alias != NULL) {
IConsoleAliasExec(alias, t_index, &tokens[1]);
return;
}
var = IConsoleVarGet(tokens[0]);
if (var != NULL) {
if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS)) {
IConsoleVarExec(var, t_index, &tokens[1]);
}
return;
}
var = IConsoleVarGet(tokens[0]);
if (var != NULL) {
if (IConsoleHookHandle(&var->hook, ICONSOLE_HOOK_ACCESS))
IConsoleVarExec(var, t_index, &tokens[1]);
IConsoleError("command or variable not found");
return;
}
IConsoleError("command or variable not found");
}

View File

@@ -1,18 +1,14 @@
/* $Id$ */
/** @file console.h */
#ifndef CONSOLE_H
#define CONSOLE_H
#include "window_type.h"
/* maximum length of a typed in command */
// maximum length of a typed in command
#define ICON_CMDLN_SIZE 255
/* maximum length of a totally expanded command */
// maximum length of a totally expanded command
#define ICON_MAX_STREAMSIZE 1024
enum IConsoleVarTypes {
typedef enum IConsoleVarTypes {
ICONSOLE_VAR_BOOLEAN,
ICONSOLE_VAR_BYTE,
ICONSOLE_VAR_UINT16,
@@ -20,31 +16,31 @@ enum IConsoleVarTypes {
ICONSOLE_VAR_INT16,
ICONSOLE_VAR_INT32,
ICONSOLE_VAR_STRING
};
} IConsoleVarTypes;
enum IConsoleModes {
typedef enum IConsoleModes {
ICONSOLE_FULL,
ICONSOLE_OPENED,
ICONSOLE_CLOSED
};
} IConsoleModes;
enum IConsoleHookTypes {
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
@@ -55,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
@@ -72,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,
@@ -95,67 +93,68 @@ 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
// ** console parser ** //
IConsoleCmd *_iconsole_cmds; // list of registred commands
IConsoleVar *_iconsole_vars; // list of registred vars
IConsoleAlias *_iconsole_aliases; // list of registred aliases
/* console colors/modes */
extern byte _icolour_def;
extern byte _icolour_err;
extern byte _icolour_warn;
extern byte _icolour_dbg;
extern byte _icolour_cmd;
extern IConsoleModes _iconsole_mode;
// ** 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 IConsoleInit();
void IConsoleFree();
void IConsoleClearBuffer();
void IConsoleResize(Window *w);
void IConsoleSwitch();
void IConsoleClose();
void IConsoleOpen();
// ** console functions ** //
void IConsoleInit(void);
void IConsoleFree(void);
void IConsoleClearBuffer(void);
void IConsoleResize(void);
void IConsoleSwitch(void);
void IConsoleClose(void);
void IConsoleOpen(void);
/* console output */
// ** console output ** //
void IConsolePrint(uint16 color_code, const char *string);
void CDECL IConsolePrintF(uint16 color_code, const char *s, ...);
void IConsoleDebug(const char *dbg, const char *string);
void IConsoleDebug(const char *string);
void IConsoleWarning(const char *string);
void IConsoleError(const char *string);
/* Commands */
// *** Commands *** //
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc);
void IConsoleAliasRegister(const char *name, const char *cmd);
IConsoleCmd *IConsoleCmdGet(const char *name);
IConsoleAlias *IConsoleAliasGet(const char *name);
/* Variables */
// *** Variables *** //
void IConsoleVarRegister(const char *name, void *addr, IConsoleVarTypes type, const char *help);
void IConsoleVarStringRegister(const char *name, void *addr, uint32 size, const char *help);
IConsoleVar* IConsoleVarGet(const char *name);
void IConsoleVarPrintGetValue(const IConsoleVar *var);
void IConsoleVarPrintSetValue(const IConsoleVar *var);
/* Parser */
// *** Parser *** //
void IConsoleCmdExec(const char *cmdstr);
void IConsoleVarExec(const IConsoleVar *var, byte tokencount, char *token[]);
/* console std lib (register ingame commands/aliases/variables) */
void IConsoleStdLibRegister();
// ** console std lib (register ingame commands/aliases/variables) ** //
void IConsoleStdLibRegister(void);
/* Hooking code */
// ** Hooking code ** //
void IConsoleCmdHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc);
void IConsoleVarHookAdd(const char *name, IConsoleHookTypes type, IConsoleHook *proc);
void IConsoleVarProcAdd(const char *name, IConsoleCmdProc *proc);
/* Supporting functions */
// ** Supporting functions **//
bool GetArgumentInteger(uint32 *value, const char *arg);
#endif /* CONSOLE_H */

View File

@@ -1,42 +1,22 @@
/* $Id$ */
/** @file console_cmds.cpp */
#include "stdafx.h"
#include "openttd.h"
#include "console.h"
#include "debug.h"
#include "engine.h"
#include "landscape.h"
#include "saveload.h"
#include "variables.h"
#include "network/network_data.h"
#include "network/network_client.h"
#include "network/network_server.h"
#include "network/network_udp.h"
#include "command_func.h"
#include "settings_func.h"
#include "fios.h"
#include "fileio.h"
#include "station.h"
#include "screenshot.h"
#include "genworld.h"
#include "network/network.h"
#include "strings_func.h"
#include "viewport_func.h"
#include "window_func.h"
#include "functions.h"
#include "map_func.h"
#include "date_func.h"
#include "vehicle_func.h"
#include "string_func.h"
#include "player_func.h"
#include "player_base.h"
#include "settings_type.h"
#ifdef ENABLE_NETWORK
#include "table/strings.h"
#endif /* ENABLE_NETWORK */
#include "saveload.h"
#include "string.h"
#include "variables.h"
#include "network_data.h"
#include "network_client.h"
#include "network_server.h"
#include "network_udp.h"
#include "command.h"
#include "settings.h"
#include "hal.h" /* for file list */
#include "vehicle.h"
// ** scriptfile handling ** //
static FILE *_script_file;
@@ -44,7 +24,7 @@ static bool _script_running;
// ** console command / variable defines ** //
#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[])
#define DEF_CONSOLE_HOOK(function) static bool function()
#define DEF_CONSOLE_HOOK(function) static bool function(void)
/* **************************** */
@@ -53,7 +33,7 @@ static bool _script_running;
#ifdef ENABLE_NETWORK
static inline bool NetworkAvailable()
static inline bool NetworkAvailable(void)
{
if (!_network_available) {
IConsoleError("You cannot use this command because there is no network available.");
@@ -111,6 +91,28 @@ static void IConsoleHelp(const char *str)
IConsolePrintF(_icolour_warn, "- %s", str);
}
DEF_CONSOLE_CMD(ConStopAllVehicles)
{
Vehicle* v;
if (argc == 0) {
IConsoleHelp("Stops all vehicles in the game. For debugging only! Use at your own risk... Usage: 'stopall'");
return true;
}
FOR_ALL_VEHICLES(v) {
if (IsValidVehicle(v)) {
/* Code ripped from CmdStartStopTrain. Can't call it, because of
* ownership problems, so we'll duplicate some code, for now */
if (v->type == VEH_Train)
v->u.rail.days_since_order_progr = 0;
v->vehstatus |= VS_STOPPED;
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
}
return true;
}
DEF_CONSOLE_CMD(ConResetEngines)
{
if (argc == 0) {
@@ -141,17 +143,6 @@ DEF_CONSOLE_CMD(ConResetTile)
return false;
}
DEF_CONSOLE_CMD(ConStopAllVehicles)
{
if (argc == 0) {
IConsoleHelp("Stops all vehicles in the game. For debugging only! Use at your own risk... Usage: 'stopall'");
return true;
}
StopAllVehicles();
return true;
}
#endif /* _DEBUG */
DEF_CONSOLE_CMD(ConScrollToTile)
@@ -165,10 +156,6 @@ DEF_CONSOLE_CMD(ConScrollToTile)
if (argc == 2) {
uint32 result;
if (GetArgumentInteger(&result, argv[1])) {
if (result >= MapSize()) {
IConsolePrint(_icolour_err, "Tile does not exist");
return true;
}
ScrollMainWindowToTile((TileIndex)result);
return true;
}
@@ -177,7 +164,8 @@ DEF_CONSOLE_CMD(ConScrollToTile)
return false;
}
extern void BuildFileList();
extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm);
extern void BuildFileList(void);
extern void SetFiosType(const byte fiostype);
/* Save the map to a file */
@@ -189,34 +177,21 @@ DEF_CONSOLE_CMD(ConSave)
}
if (argc == 2) {
char *filename = str_fmt("%s.sav", argv[1]);
char buf[200];
snprintf(buf, lengthof(buf), "%s%s%s.sav", _path.save_dir, PATHSEP, argv[1]);
IConsolePrint(_icolour_def, "Saving map...");
if (SaveOrLoad(filename, SL_SAVE, SAVE_DIR) != SL_OK) {
IConsolePrint(_icolour_err, "Saving map failed");
} else {
IConsolePrintF(_icolour_def, "Map sucessfully saved to %s", filename);
}
free(filename);
if (SaveOrLoad(buf, SL_SAVE) != SL_OK) {
IConsolePrint(_icolour_err, "SaveMap failed");
} else
IConsolePrintF(_icolour_def, "Map sucessfully saved to %s", buf);
return true;
}
return false;
}
/* Explicitly save the configuration */
DEF_CONSOLE_CMD(ConSaveConfig)
{
if (argc == 0) {
IConsoleHelp("Saves the current config, typically to 'openttd.cfg'.");
return true;
}
SaveToConfig();
IConsolePrint(_icolour_def, "Saved config.");
return true;
}
static const FiosItem* GetFiosItem(const char* file)
{
int i;
@@ -229,14 +204,14 @@ static const FiosItem* GetFiosItem(const char* file)
if (strcmp(file, _fios_list[i].title) == 0) break;
}
if (i == _fios_num) { // If no name matches, try to parse it as number
if (i == _fios_num) { /* If no name matches, try to parse it as number */
char* endptr;
i = strtol(file, &endptr, 10);
if (file == endptr || *endptr != '\0') i = -1;
}
return IsInsideMM(i, 0, _fios_num) ? &_fios_list[i] : NULL;
return IS_INT_INSIDE(i, 0, _fios_num) ? &_fios_list[i] : NULL;
}
@@ -265,9 +240,8 @@ DEF_CONSOLE_CMD(ConLoad)
} break;
default: IConsolePrintF(_icolour_err, "%s: Not a savegame.", file);
}
} else {
} else
IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
}
FiosFreeSavegameList();
return true;
@@ -291,9 +265,8 @@ DEF_CONSOLE_CMD(ConRemove)
if (item != NULL) {
if (!FiosDelete(item->name))
IConsolePrintF(_icolour_err, "%s: Failed to delete file", file);
} else {
} else
IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
}
FiosFreeSavegameList();
return true;
@@ -343,9 +316,8 @@ DEF_CONSOLE_CMD(ConChangeDirectory)
break;
default: IConsolePrintF(_icolour_err, "%s: Not a directory.", file);
}
} else {
} else
IConsolePrintF(_icolour_err, "%s: No such file or directory.", file);
}
FiosFreeSavegameList();
return true;
@@ -361,7 +333,7 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory)
}
// XXX - Workaround for broken file handling
FiosGetSavegameList(SLD_LOAD_GAME);
FiosGetSavegameList(&_fios_num, SLD_LOAD_GAME);
FiosFreeSavegameList();
FiosGetDescText(&path, NULL);
@@ -429,9 +401,8 @@ DEF_CONSOLE_CMD(ConBan)
banip = inet_ntoa(*(struct in_addr *)&ci->client_ip);
SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
IConsolePrint(_icolour_def, "Client banned");
} else {
} else
IConsolePrint(_icolour_def, "Client not online, banned IP");
}
/* Add user to ban-list */
for (index = 0; index < lengthof(_network_ban_list); index++) {
@@ -462,7 +433,7 @@ DEF_CONSOLE_CMD(ConUnBan)
for (i = 0; i < lengthof(_network_ban_list); i++) {
if (_network_ban_list[i] == NULL) continue;
if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) {
if (strncmp(_network_ban_list[i], argv[1], strlen(_network_ban_list[i])) == 0 || index == i) {
free(_network_ban_list[i]);
_network_ban_list[i] = NULL;
IConsolePrint(_icolour_def, "IP unbanned.");
@@ -500,12 +471,11 @@ DEF_CONSOLE_CMD(ConPauseGame)
return true;
}
if (_pause_game == 0) {
if (_pause == 0) {
DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
IConsolePrint(_icolour_def, "Game paused.");
} else {
} else
IConsolePrint(_icolour_def, "Game is already paused.");
}
return true;
}
@@ -517,12 +487,11 @@ DEF_CONSOLE_CMD(ConUnPauseGame)
return true;
}
if (_pause_game != 0) {
if (_pause != 0) {
DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
IConsolePrint(_icolour_def, "Game unpaused.");
} else {
} else
IConsolePrint(_icolour_def, "Game is already unpaused.");
}
return true;
}
@@ -543,18 +512,9 @@ DEF_CONSOLE_CMD(ConRcon)
DEF_CONSOLE_CMD(ConStatus)
{
static const char* const stat_str[] = {
"inactive",
"authorizing",
"authorized",
"waiting",
"loading map",
"map done",
"ready",
"active"
};
NetworkTCPSocketHandler *cs;
static const char *stat_str[] = {"inactive", "authorized", "waiting", "loading map", "map done", "ready", "active"};
const char *status;
const NetworkClientState *cs;
if (argc == 0) {
IConsoleHelp("List the status of all clients connected to the server. Usage 'status'");
@@ -564,13 +524,10 @@ DEF_CONSOLE_CMD(ConStatus)
FOR_ALL_CLIENTS(cs) {
int lag = NetworkCalculateLag(cs);
const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
const char* status;
status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
status = (cs->status <= STATUS_ACTIVE) ? stat_str[cs->status] : "unknown";
IConsolePrintF(8, "Client #%1d name: '%s' status: '%s' frame-lag: %3d company: %1d IP: %s unique-id: '%s'",
cs->index, ci->client_name, status, lag,
ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
GetPlayerIP(ci), ci->unique_id);
cs->index, ci->client_name, status, lag, ci->client_playas, GetPlayerIP(ci), ci->unique_id);
}
return true;
@@ -594,18 +551,18 @@ DEF_CONSOLE_CMD(ConServerInfo)
return true;
}
DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount)
{
if (_network_game_info.clients_max > MAX_CLIENTS) {
_network_game_info.clients_max = MAX_CLIENTS;
DEF_CONSOLE_HOOK(ConHookValidateMaxClientsCount) {
/* XXX - hardcoded, string limiation -- TrueLight
* XXX - also see network.c:NetworkStartup ~1356 */
if (_network_game_info.clients_max > 10) {
_network_game_info.clients_max = 10;
IConsoleError("Maximum clients out of bounds, truncating to limit.");
}
return true;
}
DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount)
{
DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount) {
if (_network_game_info.companies_max > MAX_PLAYERS) {
_network_game_info.companies_max = MAX_PLAYERS;
IConsoleError("Maximum companies out of bounds, truncating to limit.");
@@ -614,9 +571,8 @@ DEF_CONSOLE_HOOK(ConHookValidateMaxCompaniesCount)
return true;
}
DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount)
{
/* XXX see ConHookValidateMaxClientsCount */
DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount) {
/* XXX @see ConHookValidateMaxClientsCount */
if (_network_game_info.spectators_max > 10) {
_network_game_info.spectators_max = 10;
IConsoleError("Maximum spectators out of bounds, truncating to limit.");
@@ -625,12 +581,6 @@ DEF_CONSOLE_HOOK(ConHookValidateMaxSpectatorsCount)
return true;
}
DEF_CONSOLE_HOOK(ConHookCheckMinPlayers)
{
CheckMinPlayers();
return true;
}
DEF_CONSOLE_CMD(ConKick)
{
NetworkClientInfo *ci;
@@ -664,19 +614,18 @@ DEF_CONSOLE_CMD(ConKick)
if (ci != NULL) {
SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
} else {
} else
IConsoleError("Client not found");
}
return true;
}
DEF_CONSOLE_CMD(ConResetCompany)
{
const Player *p;
NetworkTCPSocketHandler *cs;
const NetworkClientInfo *ci;
PlayerID index;
Player *p;
NetworkClientState *cs;
NetworkClientInfo *ci;
byte index;
if (argc == 0) {
IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company <company-id>'");
@@ -686,15 +635,16 @@ DEF_CONSOLE_CMD(ConResetCompany)
if (argc != 2) return false;
index = (PlayerID)(atoi(argv[1]) - 1);
index = atoi(argv[1]);
/* Check valid range */
if (!IsValidPlayer(index)) {
if (index < 1 || index > MAX_PLAYERS) {
IConsolePrintF(_icolour_err, "Company does not exist. Company-id must be between 1 and %d.", MAX_PLAYERS);
return true;
}
/* Check if company does exist */
index--;
p = GetPlayer(index);
if (!p->is_active) {
IConsoleError("Company does not exist.");
@@ -709,13 +659,13 @@ DEF_CONSOLE_CMD(ConResetCompany)
/* Check if the company has active players */
FOR_ALL_CLIENTS(cs) {
ci = DEREF_CLIENT_INFO(cs);
if (ci->client_playas == index) {
if (ci->client_playas - 1 == index) {
IConsoleError("Cannot remove company: a client is connected to that company.");
return true;
}
}
ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
if (ci->client_playas == index) {
if (ci->client_playas - 1 == index) {
IConsoleError("Cannot remove company: the server is connected to that company.");
return true;
}
@@ -736,11 +686,11 @@ DEF_CONSOLE_CMD(ConNetworkClients)
return true;
}
FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
IConsolePrintF(8, "Client #%1d name: '%s' company: %1d IP: %s",
ci->client_index, ci->client_name,
ci->client_playas + (IsValidPlayer(ci->client_playas) ? 1 : 0),
GetPlayerIP(ci));
for (ci = _network_client_info; ci != &_network_client_info[MAX_CLIENT_INFO]; ci++) {
if (ci->client_index != NETWORK_EMPTY_INDEX) {
IConsolePrintF(8, "Client #%1d name: '%s' company: %1d IP: %s",
ci->client_index, ci->client_name, ci->client_playas, GetPlayerIP(ci));
}
}
return true;
@@ -755,32 +705,24 @@ DEF_CONSOLE_CMD(ConNetworkConnect)
if (argc == 0) {
IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect <ip>'");
IConsoleHelp("IP can contain port and player: 'IP[[#Player]:Port]', eg: 'server.ottd.org#2:443'");
IConsoleHelp("Player #255 is spectator all others are a certain company with Company 1 being #1");
IConsoleHelp("IP can contain port and player: 'IP#Player:Port', eg: 'server.ottd.org#2:443'");
return true;
}
if (argc < 2) return false;
if (_networking) NetworkDisconnect(); // we are in network-mode, first close it!
if (_networking) // We are in network-mode, first close it!
NetworkDisconnect();
ip = argv[1];
/* Default settings: default port and new company */
rport = NETWORK_DEFAULT_PORT;
_network_playas = PLAYER_NEW_COMPANY;
ParseConnectionString(&player, &port, ip);
IConsolePrintF(_icolour_def, "Connecting to %s...", ip);
if (player != NULL) {
_network_playas = (PlayerID)atoi(player);
IConsolePrintF(_icolour_def, " player-no: %d", _network_playas);
/* From a user pov 0 is a new player, internally it's different and all
* players are offset by one to ease up on users (eg players 1-8 not 0-7) */
if (_network_playas != PLAYER_SPECTATOR) {
_network_playas--;
if (!IsValidPlayer(_network_playas)) return false;
}
_network_playas = atoi(player);
IConsolePrintF(_icolour_def, " player-no: %s", player);
}
if (port != NULL) {
rport = atoi(port);
@@ -810,7 +752,7 @@ DEF_CONSOLE_CMD(ConExec)
if (argc < 2) return false;
_script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
_script_file = fopen(argv[1], "r");
if (_script_file == NULL) {
if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found");
@@ -834,7 +776,7 @@ DEF_CONSOLE_CMD(ConExec)
IConsoleError("Encountered errror while trying to read from script file");
_script_running = false;
FioFCloseFile(_script_file);
fclose(_script_file);
return true;
}
@@ -852,7 +794,7 @@ DEF_CONSOLE_CMD(ConReturn)
/* **************************** */
/* default console commands */
/* **************************** */
extern bool CloseConsoleLogIfActive();
extern bool CloseConsoleLogIfActive(void);
DEF_CONSOLE_CMD(ConScript)
{
@@ -900,61 +842,20 @@ DEF_CONSOLE_CMD(ConEchoC)
return true;
}
extern void SwitchMode(int new_mode);
DEF_CONSOLE_CMD(ConNewGame)
{
if (argc == 0) {
IConsoleHelp("Start a new game. Usage: 'newgame [seed]'");
IConsoleHelp("The server can force a new game using 'newgame'; any client joined will rejoin after the server is done generating the new game.");
IConsoleHelp("Start a new game. Usage: 'newgame'");
IConsoleHelp("The server can force a new game using 'newgame', any client using it will part and start a single-player game");
return true;
}
StartNewGameWithoutGUI((argc == 2) ? (uint)atoi(argv[1]) : GENERATE_NEW_SEED);
GenRandomNewGame(Random(), InteractiveRandom());
return true;
}
extern void SwitchMode(int new_mode);
DEF_CONSOLE_CMD(ConRestart)
{
if (argc == 0) {
IConsoleHelp("Restart game. Usage: 'restart'");
IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
return true;
}
/* Don't copy the _newgame pointers to the real pointers, so call SwitchMode directly */
_patches.map_x = MapLogX();
_patches.map_y = FindFirstBit(MapSizeY());
SwitchMode(SM_NEWGAME);
return true;
}
DEF_CONSOLE_CMD(ConGetSeed)
{
if (argc == 0) {
IConsoleHelp("Returns the seed used to create this game. Usage: 'getseed'");
IConsoleHelp("The seed can be used to reproduce the exact same map as the game started with.");
return true;
}
IConsolePrintF(_icolour_def, "Generation Seed: %u", _patches.generation_seed);
return true;
}
DEF_CONSOLE_CMD(ConGetDate)
{
if (argc == 0) {
IConsoleHelp("Returns the current date (day-month-year) of the game. Usage: 'getdate'");
return true;
}
YearMonthDay ymd;
ConvertDateToYMD(_date, &ymd);
IConsolePrintF(_icolour_def, "Date: %d-%d-%d", ymd.day, ymd.month + 1, ymd.year);
return true;
}
DEF_CONSOLE_CMD(ConAlias)
{
IConsoleAlias *alias;
@@ -986,10 +887,10 @@ DEF_CONSOLE_CMD(ConScreenShot)
if (argc > 3) return false;
SetScreenshotType(SC_VIEWPORT);
_make_screenshot = 1;
if (argc > 1) {
if (strcmp(argv[1], "big") == 0 || (argc == 3 && strcmp(argv[2], "big") == 0))
SetScreenshotType(SC_WORLD);
_make_screenshot = 2;
if (strcmp(argv[1], "no_con") == 0 || (argc == 3 && strcmp(argv[2], "no_con") == 0))
IConsoleClose();
@@ -1066,9 +967,7 @@ DEF_CONSOLE_CMD(ConDebugLevel)
if (argc == 1) {
IConsolePrintF(_icolour_def, "Current debug-level: '%s'", GetDebugString());
} else {
SetDebugString(argv[1]);
}
} else SetDebugString(argv[1]);
return true;
}
@@ -1080,8 +979,6 @@ DEF_CONSOLE_CMD(ConExit)
return true;
}
if (_game_mode == GM_NORMAL && _patches.autosave_on_exit) DoExitSave();
_exit_game = true;
return true;
}
@@ -1222,39 +1119,8 @@ DEF_CONSOLE_CMD(ConSay)
if (!_network_server) {
SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
} else {
} else
NetworkServer_HandleChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX);
}
return true;
}
DEF_CONSOLE_CMD(ConPlayers)
{
Player *p;
if (argc == 0) {
IConsoleHelp("List the in-game details of all clients connected to the server. Usage 'players'");
return true;
}
NetworkPopulateCompanyInfo();
FOR_ALL_PLAYERS(p) {
char buffer[512];
if (!p->is_active) continue;
const NetworkPlayerInfo *npi = &_network_player_info[p->index];
GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index], lastof(buffer));
IConsolePrintF(8, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: %" OTTD_PRINTF64 "d Loan: %" OTTD_PRINTF64 "d Value: %" OTTD_PRINTF64 "d (T:%d, R:%d, P:%d, S:%d) %sprotected",
p->index + 1, buffer, npi->company_name, p->inaugurated_year, (int64)p->player_money, (int64)p->current_loan, (int64)CalculateCompanyValue(p),
/* trains */ npi->num_vehicle[0],
/* lorry + bus */ npi->num_vehicle[1] + npi->num_vehicle[2],
/* planes */ npi->num_vehicle[3],
/* ships */ npi->num_vehicle[4],
/* protected */ StrEmpty(npi->password) ? "un" : "");
}
return true;
}
@@ -1275,10 +1141,9 @@ DEF_CONSOLE_CMD(ConSayPlayer)
}
if (!_network_server) {
SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2]);
} else {
NetworkServer_HandleChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
}
SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2]);
} else
NetworkServer_HandleChat(NETWORK_ACTION_CHAT_PLAYER, DESTTYPE_PLAYER, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
return true;
}
@@ -1295,16 +1160,15 @@ DEF_CONSOLE_CMD(ConSayClient)
if (!_network_server) {
SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
} else {
} else
NetworkServer_HandleChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
}
return true;
}
DEF_CONSOLE_HOOK(ConHookServerPW)
{
if (strcmp(_network_server_password, "*") == 0) {
if (strncmp(_network_server_password, "*", NETWORK_PASSWORD_LENGTH) == 0) {
_network_server_password[0] = '\0';
_network_game_info.use_password = 0;
} else {
@@ -1317,7 +1181,7 @@ DEF_CONSOLE_HOOK(ConHookServerPW)
DEF_CONSOLE_HOOK(ConHookRconPW)
{
if (strcmp(_network_rcon_password, "*") == 0)
if (strncmp(_network_rcon_password, "*", NETWORK_PASSWORD_LENGTH) == 0)
_network_rcon_password[0] = '\0';
ttd_strlcpy(_network_game_info.rcon_password, _network_rcon_password, sizeof(_network_game_info.rcon_password));
@@ -1325,33 +1189,29 @@ DEF_CONSOLE_HOOK(ConHookRconPW)
return true;
}
extern void HashCurrentCompanyPassword();
/* Also use from within player_gui to change the password graphically */
bool NetworkChangeCompanyPassword(byte argc, char *argv[])
{
if (argc == 0) {
if (!IsValidPlayer(_local_player)) return true; // dedicated server
if (_local_player >= MAX_PLAYERS) return true; // dedicated server
IConsolePrintF(_icolour_warn, "Current value for 'company_pw': %s", _network_player_info[_local_player].password);
return true;
}
if (!IsValidPlayer(_local_player)) {
if (_local_player >= MAX_PLAYERS) {
IConsoleError("You have to own a company to make use of this command.");
return false;
}
if (argc != 1) return false;
if (strcmp(argv[0], "*") == 0) argv[0][0] = '\0';
if (strncmp(argv[0], "*", sizeof(_network_player_info[_local_player].password)) == 0)
argv[0][0] = '\0';
ttd_strlcpy(_network_player_info[_local_player].password, argv[0], sizeof(_network_player_info[_local_player].password));
if (!_network_server) {
if (!_network_server)
SEND_COMMAND(PACKET_CLIENT_SET_PASSWORD)(_network_player_info[_local_player].password);
} else {
HashCurrentCompanyPassword();
}
IConsolePrintF(_icolour_warn, "'company_pw' changed to: %s", _network_player_info[_local_player].password);
@@ -1364,7 +1224,7 @@ DEF_CONSOLE_HOOK(ConProcPlayerName)
if (ci == NULL) return false;
/* Don't change the name if it is the same as the old name */
// Don't change the name if it is the same as the old name
if (strcmp(ci->client_name, _network_player_name) != 0) {
if (!_network_server) {
SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_network_player_name);
@@ -1408,7 +1268,6 @@ DEF_CONSOLE_CMD(ConProcServerIP)
IConsolePrintF(_icolour_warn, "'server_ip' changed to: %s", inet_ntoa(*(struct in_addr *)&_network_server_bind_ip));
return true;
}
#endif /* ENABLE_NETWORK */
DEF_CONSOLE_CMD(ConPatch)
{
@@ -1422,35 +1281,12 @@ DEF_CONSOLE_CMD(ConPatch)
if (argc == 2) {
IConsoleGetPatchSetting(argv[1]);
} else {
uint32 val;
if (GetArgumentInteger(&val, argv[2])) {
if (!IConsoleSetPatchSetting(argv[1], val)) {
if (_network_server) {
IConsoleError("This command/variable is not available during network games.");
} else {
IConsoleError("This command/variable is only available to a network server.");
}
}
}
}
} else
IConsoleSetPatchSetting(argv[1], argv[2]);
return true;
}
DEF_CONSOLE_CMD(ConListPatches)
{
if (argc == 0) {
IConsoleHelp("List patch options. Usage: 'list_patches'");
return true;
}
if (argc != 1) return false;
IConsoleListPatches();
return true;
}
#endif /* ENABLE_NETWORK */
DEF_CONSOLE_CMD(ConListDumpVariables)
{
@@ -1478,14 +1314,13 @@ DEF_CONSOLE_CMD(ConListDumpVariables)
/* debug commands and variables */
/* ****************************************** */
static void IConsoleDebugLibRegister()
static void IConsoleDebugLibRegister(void)
{
/* debugging variables and functions */
extern bool _stdlib_con_developer; // XXX extern in .cpp
// debugging variables and functions
extern bool _stdlib_con_developer; /* XXX extern in .c */
IConsoleVarRegister("con_developer", &_stdlib_con_developer, ICONSOLE_VAR_BOOLEAN, "Enable/disable console debugging information (internal)");
IConsoleCmdRegister("resettile", ConResetTile);
IConsoleCmdRegister("stopall", ConStopAllVehicles);
IConsoleAliasRegister("dbg_echo", "echo %A; echo %B");
IConsoleAliasRegister("dbg_echo2", "echo %!");
}
@@ -1495,12 +1330,12 @@ static void IConsoleDebugLibRegister()
/* console command and variable registration */
/* ****************************************** */
void IConsoleStdLibRegister()
void IConsoleStdLibRegister(void)
{
/* stdlib */
extern byte _stdlib_developer; // XXX extern in .cpp
// stdlib
extern byte _stdlib_developer; /* XXX extern in .c */
/* default variables and functions */
// default variables and functions
IConsoleCmdRegister("debug_level", ConDebugLevel);
IConsoleCmdRegister("dump_vars", ConListDumpVariables);
IConsoleCmdRegister("echo", ConEcho);
@@ -1515,9 +1350,6 @@ void IConsoleStdLibRegister()
IConsoleCmdRegister("list_vars", ConListVariables);
IConsoleCmdRegister("list_aliases", ConListAliases);
IConsoleCmdRegister("newgame", ConNewGame);
IConsoleCmdRegister("restart", ConRestart);
IConsoleCmdRegister("getseed", ConGetSeed);
IConsoleCmdRegister("getdate", ConGetDate);
IConsoleCmdRegister("quit", ConExit);
IConsoleCmdRegister("resetengines", ConResetEngines);
IConsoleCmdRegister("return", ConReturn);
@@ -1528,13 +1360,11 @@ void IConsoleStdLibRegister()
IConsoleCmdRegister("load", ConLoad);
IConsoleCmdRegister("rm", ConRemove);
IConsoleCmdRegister("save", ConSave);
IConsoleCmdRegister("saveconfig", ConSaveConfig);
IConsoleCmdRegister("ls", ConListFiles);
IConsoleCmdRegister("cd", ConChangeDirectory);
IConsoleCmdRegister("pwd", ConPrintWorkingDirectory);
IConsoleCmdRegister("clear", ConClearBuffer);
IConsoleCmdRegister("patch", ConPatch);
IConsoleCmdRegister("list_patches", ConListPatches);
IConsoleCmdRegister("stopall", ConStopAllVehicles);
IConsoleAliasRegister("dir", "ls");
IConsoleAliasRegister("del", "rm %+");
@@ -1548,13 +1378,12 @@ void IConsoleStdLibRegister()
/* networking variables and functions */
#ifdef ENABLE_NETWORK
/* Network hooks; only active in network */
IConsoleCmdHookAdd ("stopall", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork);
IConsoleCmdHookAdd ("resetengines", ICONSOLE_HOOK_ACCESS, ConHookNoNetwork);
/*** Networking commands ***/
IConsoleCmdRegister("say", ConSay);
IConsoleCmdHookAdd("say", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
IConsoleCmdRegister("players", ConPlayers);
IConsoleCmdHookAdd("players", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleCmdRegister("say_player", ConSayPlayer);
IConsoleCmdHookAdd("say_player", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork);
IConsoleCmdRegister("say_client", ConSayClient);
@@ -1590,6 +1419,9 @@ void IConsoleStdLibRegister()
IConsoleCmdRegister("unpause", ConUnPauseGame);
IConsoleCmdHookAdd("unpause", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleCmdRegister("patch", ConPatch);
IConsoleCmdHookAdd("patch", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
/*** Networking variables ***/
IConsoleVarRegister("net_frame_freq", &_network_frame_freq, ICONSOLE_VAR_BYTE, "The amount of frames before a command will be (visibly) executed. Default value: 1");
IConsoleVarHookAdd("net_frame_freq", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
@@ -1647,14 +1479,8 @@ void IConsoleStdLibRegister()
IConsoleVarHookAdd("autoclean_protected", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarRegister("autoclean_unprotected", &_network_autoclean_unprotected, ICONSOLE_VAR_BYTE, "Automatically shut down inactive companies after the given amount of months");
IConsoleVarHookAdd("autoclean_unprotected", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarRegister("restart_game_year", &_network_restart_game_year, ICONSOLE_VAR_UINT16, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this");
IConsoleVarHookAdd("restart_game_year", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarRegister("min_players", &_network_min_players, ICONSOLE_VAR_BYTE, "Automatically pause the game when the number of active players passes below the given amount");
IConsoleVarHookAdd("min_players", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarHookAdd("min_players", ICONSOLE_HOOK_POST_ACTION, ConHookCheckMinPlayers);
IConsoleVarRegister("reload_cfg", &_network_reload_cfg, ICONSOLE_VAR_BOOLEAN, "reload the entire config file between the end of this game, and starting the next new game - dedicated servers");
IConsoleVarHookAdd("reload_cfg", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
IConsoleVarRegister("restart_game_date", &_network_restart_game_date, ICONSOLE_VAR_UINT16, "Auto-restart the server when Jan 1st of the set year is reached. Use '0' to disable this");
IConsoleVarHookAdd("restart_game_date", ICONSOLE_HOOK_ACCESS, ConHookServerOnly);
#endif /* ENABLE_NETWORK */

100
currency.c Normal file
View File

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

29
currency.h Normal file
View File

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

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/nsignalsw.grf Normal file

Binary file not shown.

BIN
data/openttd.grf Normal file

Binary file not shown.

BIN
data/trkfoundw.grf Normal file

Binary file not shown.

View File

@@ -1,19 +1,13 @@
/* $Id$ */
/** @file debug.cpp */
#include "stdafx.h"
#include <stdio.h>
#include <stdarg.h>
#include "openttd.h"
#include "console.h"
#include "debug.h"
#include "string_func.h"
#include "network/core/core.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,20 +16,28 @@ 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;
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[] = {
@@ -46,58 +48,20 @@ 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(npf)
};
#undef DEBUG_LEVEL
#if !defined(NO_DEBUG_MESSAGES)
void CDECL debug(const char *dbg, ...)
{
va_list va;
va_start(va, dbg);
const char *s;
char buf[1024];
s = va_arg(va, const char*);
vsnprintf(buf, lengthof(buf), s, va);
va_end(va);
#if defined(ENABLE_NETWORK)
if (_debug_socket != INVALID_SOCKET) {
char buf2[lengthof(buf) + 32];
snprintf(buf2, lengthof(buf2), "dbg: [%s] %s\n", dbg, buf);
send(_debug_socket, buf2, strlen(buf2), 0);
} else
#endif /* ENABLE_NETWORK */
{
#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);
}
}
#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;
@@ -107,19 +71,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) {
@@ -143,10 +107,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));
@@ -160,20 +124,3 @@ const char *GetDebugString()
return dbgstr;
}
#ifdef DEBUG_DUMP_COMMANDS
#include "fileio.h"
void CDECL DebugDumpCommands(const char *s, ...)
{
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
if (f == NULL) return;
va_list va;
va_start(va, s);
vfprintf(f, s, va);
va_end(va);
fflush(f);
}
#endif /* DEBUG_DUMP_COMMANDS */

29
debug.h Normal file
View File

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

View File

@@ -1,7 +1,5 @@
/* $Id$ */
/** @file dedicated.cpp */
#include "stdafx.h"
#ifdef ENABLE_NETWORK
@@ -14,15 +12,7 @@
#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();
@@ -53,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);
}
}
@@ -63,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 */

145
depot.c Normal file
View File

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

148
depot.h Normal file
View File

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

992
disaster_cmd.c Normal file
View File

@@ -0,0 +1,992 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "tile.h"
#include "vehicle.h"
#include "command.h"
#include "news.h"
#include "station.h"
#include "waypoint.h"
#include "town.h"
#include "industry.h"
#include "player.h"
#include "airport_movement.h"
#include "sound.h"
#include "variables.h"
#include "table/sprites.h"
static void DisasterClearSquare(TileIndex tile)
{
if (!EnsureNoVehicle(tile)) return;
switch (GetTileType(tile)) {
case MP_RAILWAY:
if (IS_HUMAN_PLAYER(GetTileOwner(tile)) && !IsRailWaypoint(tile)) DoClearSquare(tile);
break;
case MP_HOUSE: {
PlayerID p = _current_player;
_current_player = OWNER_NONE;
DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
_current_player = p;
break;
}
case MP_TREES:
case MP_CLEAR:
DoClearSquare(tile);
break;
default:
break;
}
}
static const SpriteID _disaster_images_1[] = {0xF41,0xF41,0xF41,0xF41,0xF41,0xF41,0xF41,0xF41};
static const SpriteID _disaster_images_2[] = {0xF44,0xF44,0xF44,0xF44,0xF44,0xF44,0xF44,0xF44};
static const SpriteID _disaster_images_3[] = {0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E,0xF4E};
static const SpriteID _disaster_images_4[] = {0xF46,0xF46,0xF47,0xF47,0xF48,0xF48,0xF49,0xF49};
static const SpriteID _disaster_images_5[] = {0xF4A,0xF4A,0xF4B,0xF4B,0xF4C,0xF4C,0xF4D,0xF4D};
static const SpriteID _disaster_images_6[] = {0xF50,0xF50,0xF50,0xF50,0xF50,0xF50,0xF50,0xF50};
static const SpriteID _disaster_images_7[] = {0xF51,0xF51,0xF51,0xF51,0xF51,0xF51,0xF51,0xF51};
static const SpriteID _disaster_images_8[] = {0xF52,0xF52,0xF52,0xF52,0xF52,0xF52,0xF52,0xF52};
static const SpriteID _disaster_images_9[] = {0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E,0xF3E};
static const SpriteID * const _disaster_images[] = {
_disaster_images_1,_disaster_images_1,
_disaster_images_2,_disaster_images_2,
_disaster_images_3,_disaster_images_3,
_disaster_images_8,_disaster_images_8,_disaster_images_9,
_disaster_images_6,_disaster_images_6,
_disaster_images_7,_disaster_images_7,
_disaster_images_4,_disaster_images_5,
};
static void DisasterVehicleUpdateImage(Vehicle *v)
{
int img = v->u.disaster.image_override;
if (img == 0)
img = _disaster_images[v->subtype][v->direction];
v->cur_image = img;
}
static void InitializeDisasterVehicle(Vehicle *v, int x, int y, byte z, byte direction, byte subtype)
{
v->type = VEH_Disaster;
v->x_pos = x;
v->y_pos = y;
v->z_pos = z;
v->tile = TileVirtXY(x, y);
v->direction = direction;
v->subtype = subtype;
v->x_offs = -1;
v->y_offs = -1;
v->sprite_width = 2;
v->sprite_height = 2;
v->z_height = 5;
v->owner = OWNER_NONE;
v->vehstatus = VS_UNCLICKABLE;
v->u.disaster.image_override = 0;
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->current_order.station = 0;
DisasterVehicleUpdateImage(v);
VehiclePositionChanged(v);
BeginVehicleMove(v);
EndVehicleMove(v);
}
static void DeleteDisasterVeh(Vehicle *v)
{
DeleteVehicleChain(v);
}
static void SetDisasterVehiclePos(Vehicle *v, int x, int y, byte z)
{
Vehicle *u;
int yt;
BeginVehicleMove(v);
v->x_pos = x;
v->y_pos = y;
v->z_pos = z;
v->tile = TileVirtXY(x, y);
DisasterVehicleUpdateImage(v);
VehiclePositionChanged(v);
EndVehicleMove(v);
if ( (u=v->next) != NULL) {
BeginVehicleMove(u);
u->x_pos = x;
u->y_pos = yt = y - 1 - (max(z - GetSlopeZ(x, y-1), 0) >> 3);
u->z_pos = GetSlopeZ(x,yt);
u->direction = v->direction;
DisasterVehicleUpdateImage(u);
VehiclePositionChanged(u);
EndVehicleMove(u);
if ( (u=u->next) != NULL) {
BeginVehicleMove(u);
u->x_pos = x;
u->y_pos = y;
u->z_pos = z + 5;
VehiclePositionChanged(u);
EndVehicleMove(u);
}
}
}
static void DisasterTick_Zeppeliner(Vehicle *v)
{
GetNewVehiclePosResult gp;
Station *st;
int x,y;
byte z;
TileIndex tile;
++v->tick_counter;
if (v->current_order.station < 2) {
if (v->tick_counter&1)
return;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (v->current_order.station == 1) {
if (++v->age == 38) {
v->current_order.station = 2;
v->age = 0;
}
if ((v->tick_counter&7)==0) {
CreateEffectVehicleRel(v, 0, -17, 2, EV_SMOKE);
}
} else if (v->current_order.station == 0) {
tile = v->tile; /**/
if (IsValidTile(tile) &&
IsTileType(tile, MP_STATION) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) &&
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
v->current_order.station = 1;
v->age = 0;
SetDParam(0, _m[tile].m2);
AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
v->index,
0);
}
}
if (v->y_pos >= ((int)MapSizeY() + 9) * 16 - 1)
DeleteDisasterVeh(v);
return;
}
if (v->current_order.station > 2) {
if (++v->age <= 13320)
return;
tile = v->tile; /**/
if (IsValidTile(tile) &&
IsTileType(tile, MP_STATION) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) &&
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
st = GetStation(_m[tile].m2);
CLRBITS(st->airport_flags, RUNWAY_IN_block);
}
SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos);
DeleteDisasterVeh(v);
return;
}
x = v->x_pos;
y = v->y_pos;
z = GetSlopeZ(x,y);
if (z < v->z_pos)
z = v->z_pos - 1;
SetDisasterVehiclePos(v, x, y, z);
if (++v->age == 1) {
CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
SndPlayVehicleFx(SND_12_EXPLOSION, v);
v->u.disaster.image_override = SPR_BLIMP_CRASHING;
} else if (v->age == 70) {
v->u.disaster.image_override = SPR_BLIMP_CRASHED;
} else if (v->age <= 300) {
if (!(v->tick_counter&7)) {
uint32 r = Random();
CreateEffectVehicleRel(v,
GB(r, 0, 4) - 7,
GB(r, 4, 4) - 7,
GB(r, 8, 3) + 5,
EV_EXPLOSION_SMALL);
}
} else if (v->age == 350) {
v->current_order.station = 3;
v->age = 0;
}
tile = v->tile;/**/
if (IsValidTile(tile) &&
IsTileType(tile, MP_STATION) &&
IS_BYTE_INSIDE(_m[tile].m5, 8, 0x43) &&
IS_HUMAN_PLAYER(GetTileOwner(tile))) {
st = GetStation(_m[tile].m2);
SETBITS(st->airport_flags, RUNWAY_IN_block);
}
}
// UFO starts in the middle, and flies around a bit until it locates
// a road vehicle which it targets.
static void DisasterTick_UFO(Vehicle *v)
{
GetNewVehiclePosResult gp;
Vehicle *u;
uint dist;
byte z;
v->u.disaster.image_override = (++v->tick_counter & 8) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT;
if (v->current_order.station == 0) {
// fly around randomly
int x = TileX(v->dest_tile) * 16;
int y = TileY(v->dest_tile) * 16;
if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) {
v->direction = GetDirectionTowards(v, x, y);
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
return;
}
if (++v->age < 6) {
v->dest_tile = RandomTile();
return;
}
v->current_order.station = 1;
FOR_ALL_VEHICLES(u) {
if (u->type == VEH_Road && IS_HUMAN_PLAYER(u->owner)) {
v->dest_tile = u->index;
v->age = 0;
return;
}
}
DeleteDisasterVeh(v);
} else {
// target a vehicle
u = GetVehicle(v->dest_tile);
if (u->type != VEH_Road) {
DeleteDisasterVeh(v);
return;
}
dist = abs(v->x_pos - u->x_pos) + abs(v->y_pos - u->y_pos);
if (dist < 16 && !(u->vehstatus&VS_HIDDEN) && u->breakdown_ctr==0) {
u->breakdown_ctr = 3;
u->breakdown_delay = 140;
}
v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos);
GetNewVehiclePos(v, &gp);
z = v->z_pos;
if (dist <= 16 && z > u->z_pos) z--;
SetDisasterVehiclePos(v, gp.x, gp.y, z);
if (z <= u->z_pos && (u->vehstatus&VS_HIDDEN)==0) {
v->age++;
if (u->u.road.crashed_ctr == 0) {
u->u.road.crashed_ctr++;
u->vehstatus |= VS_CRASHED;
AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
u->index,
0);
}
}
// destroy?
if (v->age > 50) {
CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE);
SndPlayVehicleFx(SND_12_EXPLOSION, v);
DeleteDisasterVeh(v);
}
}
}
static void DestructIndustry(Industry *i)
{
TileIndex tile;
for (tile = 0; tile != MapSize(); tile++) {
if (IsTileType(tile, MP_INDUSTRY) && _m[tile].m2 == i->index) {
_m[tile].m1 = 0;
MarkTileDirtyByTile(tile);
}
}
}
// Airplane which destroys an oil refinery
static void DisasterTick_2(Vehicle *v)
{
GetNewVehiclePosResult gp;
v->tick_counter++;
v->u.disaster.image_override =
(v->current_order.station == 1 && v->tick_counter & 4) ? SPR_F_15_FIRING : 0;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (gp.x < -160) {
DeleteDisasterVeh(v);
return;
}
if (v->current_order.station == 2) {
if (!(v->tick_counter&3)) {
Industry *i = GetIndustry(v->dest_tile);
int x = TileX(i->xy) * 16;
int y = TileY(i->xy) * 16;
uint32 r = Random();
CreateEffectVehicleAbove(
GB(r, 0, 6) + x,
GB(r, 6, 6) + y,
GB(r, 12, 4),
EV_EXPLOSION_SMALL);
if (++v->age >= 55)
v->current_order.station = 3;
}
} else if (v->current_order.station == 1) {
if (++v->age == 112) {
Industry *i;
v->current_order.station = 2;
v->age = 0;
i = GetIndustry(v->dest_tile);
DestructIndustry(i);
SetDParam(0, i->town->index);
AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
SndPlayTileFx(SND_12_EXPLOSION, i->xy);
}
} else if (v->current_order.station == 0) {
int x,y;
TileIndex tile;
int ind;
x = v->x_pos - 15*16;
y = v->y_pos;
if ( (uint)x > MapMaxX() * 16-1)
return;
tile = TileVirtXY(x, y);
if (!IsTileType(tile, MP_INDUSTRY))
return;
v->dest_tile = ind = _m[tile].m2;
if (GetIndustry(ind)->type == IT_OIL_REFINERY) {
v->current_order.station = 1;
v->age = 0;
}
}
}
// Helicopter which destroys a factory
static void DisasterTick_3(Vehicle *v)
{
GetNewVehiclePosResult gp;
v->tick_counter++;
v->u.disaster.image_override =
(v->current_order.station == 1 && v->tick_counter & 4) ? SPR_AH_64A_FIRING : 0;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (gp.x > (int)MapSizeX() * 16 + 9*16 - 1) {
DeleteDisasterVeh(v);
return;
}
if (v->current_order.station == 2) {
if (!(v->tick_counter&3)) {
Industry *i = GetIndustry(v->dest_tile);
int x = TileX(i->xy) * 16;
int y = TileY(i->xy) * 16;
uint32 r = Random();
CreateEffectVehicleAbove(
GB(r, 0, 6) + x,
GB(r, 6, 6) + y,
GB(r, 12, 4),
EV_EXPLOSION_SMALL);
if (++v->age >= 55)
v->current_order.station = 3;
}
} else if (v->current_order.station == 1) {
if (++v->age == 112) {
Industry *i;
v->current_order.station = 2;
v->age = 0;
i = GetIndustry(v->dest_tile);
DestructIndustry(i);
SetDParam(0, i->town->index);
AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy, 0);
SndPlayTileFx(SND_12_EXPLOSION, i->xy);
}
} else if (v->current_order.station == 0) {
int x,y;
TileIndex tile;
int ind;
x = v->x_pos - 15*16;
y = v->y_pos;
if ( (uint)x > MapMaxX() * 16-1)
return;
tile = TileVirtXY(x, y);
if (!IsTileType(tile, MP_INDUSTRY))
return;
v->dest_tile = ind = _m[tile].m2;
if (GetIndustry(ind)->type == IT_FACTORY) {
v->current_order.station = 1;
v->age = 0;
}
}
}
// Helicopter rotor blades
static void DisasterTick_3b(Vehicle *v)
{
if (++v->tick_counter & 1)
return;
if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1;
VehiclePositionChanged(v);
BeginVehicleMove(v);
EndVehicleMove(v);
}
// Big UFO which lands on a piece of rail.
// Will be shot down by a plane
static void DisasterTick_4(Vehicle *v)
{
GetNewVehiclePosResult gp;
byte z;
Vehicle *u,*w;
Town *t;
TileIndex tile;
TileIndex tile_org;
v->tick_counter++;
if (v->current_order.station == 1) {
int x = TileX(v->dest_tile) * 16 + 8;
int y = TileY(v->dest_tile) * 16 + 8;
if (abs(v->x_pos - x) + abs(v->y_pos - y) >= 8) {
v->direction = GetDirectionTowards(v, x, y);
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
return;
}
z = GetSlopeZ(v->x_pos, v->y_pos);
if (z < v->z_pos) {
SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos - 1);
return;
}
v->current_order.station = 2;
FOR_ALL_VEHICLES(u) {
if (u->type == VEH_Train || u->type == VEH_Road) {
if (abs(u->x_pos - v->x_pos) + abs(u->y_pos - v->y_pos) <= 12*16) {
u->breakdown_ctr = 5;
u->breakdown_delay = 0xF0;
}
}
}
t = ClosestTownFromTile(v->dest_tile, (uint)-1);
SetDParam(0, t->index);
AddNewsItem(STR_B004_UFO_LANDS_NEAR,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ACCIDENT, 0),
v->tile,
0);
u = ForceAllocateSpecialVehicle();
if (u == NULL) {
DeleteDisasterVeh(v);
return;
}
InitializeDisasterVehicle(u, -6*16, v->y_pos, 135, 5, 11);
u->u.disaster.unk2 = v->index;
w = ForceAllocateSpecialVehicle();
if (w == NULL)
return;
u->next = w;
InitializeDisasterVehicle(w, -6*16, v->y_pos, 0, 5, 12);
w->vehstatus |= VS_DISASTER;
} else if (v->current_order.station < 1) {
int x = TileX(v->dest_tile) * 16;
int y = TileY(v->dest_tile) * 16;
if (abs(x - v->x_pos) + abs(y - v->y_pos) >= 16) {
v->direction = GetDirectionTowards(v, x, y);
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
return;
}
if (++v->age < 6) {
v->dest_tile = RandomTile();
return;
}
v->current_order.station = 1;
tile_org = tile = RandomTile();
do {
if (IsTileType(tile, MP_RAILWAY) &&
(_m[tile].m5 & ~3) != 0xC0 && IS_HUMAN_PLAYER(GetTileOwner(tile)))
break;
tile = TILE_MASK(tile+1);
} while (tile != tile_org);
v->dest_tile = tile;
v->age = 0;
} else
return;
}
// The plane which will shoot down the UFO
static void DisasterTick_4b(Vehicle *v)
{
GetNewVehiclePosResult gp;
Vehicle *u;
int i;
v->tick_counter++;
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
if (gp.x > (int)MapSizeX() * 16 + 9*16 - 1) {
DeleteDisasterVeh(v);
return;
}
if (v->current_order.station == 0) {
u = GetVehicle(v->u.disaster.unk2);
if (abs(v->x_pos - u->x_pos) > 16)
return;
v->current_order.station = 1;
CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE);
SndPlayVehicleFx(SND_12_EXPLOSION, u);
DeleteDisasterVeh(u);
for(i=0; i!=80; i++) {
uint32 r = Random();
CreateEffectVehicleAbove(
GB(r, 0, 6) + v->x_pos - 32,
GB(r, 5, 6) + v->y_pos - 32,
0,
EV_EXPLOSION_SMALL);
}
BEGIN_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
tile = TILE_MASK(tile);
DisasterClearSquare(tile);
END_TILE_LOOP(tile, 6, 6, v->tile - TileDiffXY(3, 3))
}
}
// Submarine handler
static void DisasterTick_5_and_6(Vehicle *v)
{
uint32 r;
GetNewVehiclePosResult gp;
TileIndex tile;
v->tick_counter++;
if (++v->age > 8880) {
VehiclePositionChanged(v);
BeginVehicleMove(v);
EndVehicleMove(v);
DeleteVehicle(v);
return;
}
if (!(v->tick_counter&1))
return;
tile = v->tile + TileOffsByDir(v->direction >> 1);
if (IsValidTile(tile) &&
(r=GetTileTrackStatus(tile,TRANSPORT_WATER),(byte)(r+(r >> 8)) == 0x3F) &&
!CHANCE16(1,90)) {
GetNewVehiclePos(v, &gp);
SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos);
return;
}
v->direction = (v->direction + (GB(Random(), 0, 1) ? 2 : -2)) & 7;
}
static void DisasterTick_NULL(Vehicle *v) {}
typedef void DisasterVehicleTickProc(Vehicle *v);
static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = {
DisasterTick_Zeppeliner,DisasterTick_NULL,
DisasterTick_UFO,DisasterTick_NULL,
DisasterTick_2,DisasterTick_NULL,
DisasterTick_3,DisasterTick_NULL,DisasterTick_3b,
DisasterTick_4,DisasterTick_NULL,
DisasterTick_4b,DisasterTick_NULL,
DisasterTick_5_and_6,
DisasterTick_5_and_6,
};
void DisasterVehicle_Tick(Vehicle *v)
{
_disastervehicle_tick_procs[v->subtype](v);
}
void OnNewDay_DisasterVehicle(Vehicle *v)
{
// not used
}
typedef void DisasterInitProc(void);
// Zeppeliner which crashes on a small airport
static void Disaster0_Init(void)
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
Station *st;
int x;
if (v == NULL)
return;
/* Pick a random place, unless we find
a small airport */
x = TileX(Random()) * 16 + 8;
FOR_ALL_STATIONS(st) {
if (st->xy && st->airport_tile != 0 &&
st->airport_type <= 1 &&
IS_HUMAN_PLAYER(st->owner)) {
x = (TileX(st->xy) + 2) * 16;
break;
}
}
InitializeDisasterVehicle(v, x, 0, 135, 3, 0);
// Allocate shadow too?
u = ForceAllocateSpecialVehicle();
if (u != NULL) {
v->next = u;
InitializeDisasterVehicle(u, x, 0, 0, 3, 1);
u->vehstatus |= VS_DISASTER;
}
}
static void Disaster1_Init(void)
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
int x;
if (v == NULL)
return;
x = TileX(Random()) * 16 + 8;
InitializeDisasterVehicle(v, x, 0, 135, 3, 2);
v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
v->age = 0;
// Allocate shadow too?
u = ForceAllocateSpecialVehicle();
if (u != NULL) {
v->next = u;
InitializeDisasterVehicle(u,x,0,0,3,3);
u->vehstatus |= VS_DISASTER;
}
}
static void Disaster2_Init(void)
{
Industry *i, *found;
Vehicle *v,*u;
int x,y;
found = NULL;
FOR_ALL_INDUSTRIES(i) {
if (i->xy != 0 &&
i->type == IT_OIL_REFINERY &&
(found==NULL || CHANCE16(1,2))) {
found = i;
}
}
if (found == NULL)
return;
v = ForceAllocateSpecialVehicle();
if (v == NULL)
return;
x = (MapSizeX() + 9) * 16 - 1;
y = TileY(found->xy) * 16 + 37;
InitializeDisasterVehicle(v,x,y, 135,1,4);
u = ForceAllocateSpecialVehicle();
if (u != NULL) {
v->next = u;
InitializeDisasterVehicle(u,x,y,0,3,5);
u->vehstatus |= VS_DISASTER;
}
}
static void Disaster3_Init(void)
{
Industry *i, *found;
Vehicle *v,*u,*w;
int x,y;
found = NULL;
FOR_ALL_INDUSTRIES(i) {
if (i->xy != 0 &&
i->type == IT_FACTORY &&
(found==NULL || CHANCE16(1,2))) {
found = i;
}
}
if (found == NULL)
return;
v = ForceAllocateSpecialVehicle();
if (v == NULL)
return;
x = -16 * 16;
y = TileY(found->xy) * 16 + 37;
InitializeDisasterVehicle(v,x,y, 135,5,6);
u = ForceAllocateSpecialVehicle();
if (u != NULL) {
v->next = u;
InitializeDisasterVehicle(u,x,y,0,5,7);
u->vehstatus |= VS_DISASTER;
w = ForceAllocateSpecialVehicle();
if (w != NULL) {
u->next = w;
InitializeDisasterVehicle(w,x,y,140,5,8);
}
}
}
static void Disaster4_Init(void)
{
Vehicle *v = ForceAllocateSpecialVehicle(), *u;
int x,y;
if (v == NULL) return;
x = TileX(Random()) * 16 + 8;
y = MapMaxX() * 16 - 1;
InitializeDisasterVehicle(v, x, y, 135, 7, 9);
v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2);
v->age = 0;
// Allocate shadow too?
u = ForceAllocateSpecialVehicle();
if (u != NULL) {
v->next = u;
InitializeDisasterVehicle(u,x,y,0,7,10);
u->vehstatus |= VS_DISASTER;
}
}
// Submarine type 1
static void Disaster5_Init(void)
{
Vehicle *v = ForceAllocateSpecialVehicle();
int x,y;
byte dir;
uint32 r;
if (v == NULL) return;
r = Random();
x = TileX(r) * 16 + 8;
y = 8;
dir = 3;
if (r & 0x80000000) { y = MapMaxX() * 16 - 8 - 1; dir = 7; }
InitializeDisasterVehicle(v, x, y, 0, dir,13);
v->age = 0;
}
// Submarine type 2
static void Disaster6_Init(void)
{
Vehicle *v = ForceAllocateSpecialVehicle();
int x,y;
byte dir;
uint32 r;
if (v == NULL) return;
r = Random();
x = TileX(r) * 16 + 8;
y = 8;
dir = 3;
if (r & 0x80000000) { y = MapMaxX() * 16 - 8 - 1; dir = 7; }
InitializeDisasterVehicle(v, x, y, 0, dir,14);
v->age = 0;
}
static void Disaster7_Init(void)
{
int index = GB(Random(), 0, 4);
Industry *i;
uint m;
for (m = 0; m < 15; m++) {
FOR_ALL_INDUSTRIES(i) {
if (i->xy != 0 && i->type == IT_COAL_MINE && --index < 0) {
SetDParam(0, i->town->index);
AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ACCIDENT,0), i->xy + TileDiffXY(1, 1), 0);
{
TileIndex tile = i->xy;
TileIndexDiff step = TileOffsByDir(GB(Random(), 0, 2));
uint n;
for (n = 0; n < 30; n++) {
DisasterClearSquare(tile);
tile = TILE_MASK(tile + step);
}
}
return;
}
}
}
}
static DisasterInitProc * const _disaster_initprocs[] = {
Disaster0_Init,
Disaster1_Init,
Disaster2_Init,
Disaster3_Init,
Disaster4_Init,
Disaster5_Init,
Disaster6_Init,
Disaster7_Init,
};
#define MK(a, b) { (a) - MAX_YEAR_BEGIN_REAL, (b) - MAX_YEAR_BEGIN_REAL }
static const struct {
byte min;
byte max;
} _dis_years[] = {
MK(1930, 1955),
MK(1940, 1970),
MK(1960, 1990),
MK(1970, 2000),
MK(2000, 2100),
MK(1940, 1965),
MK(1975, 2010),
MK(1950, 1985)
};
#undef MK
static void DoDisaster(void)
{
byte buf[lengthof(_dis_years)];
byte year = _cur_year;
uint i;
uint j;
j = 0;
for (i = 0; i != lengthof(_dis_years); i++) {
if (year >= _dis_years[i].min && year < _dis_years[i].max) buf[j++] = i;
}
if (j == 0) return;
_disaster_initprocs[buf[RandomRange(j)]]();
}
static void ResetDisasterDelay(void)
{
_disaster_delay = GB(Random(), 0, 9) + 730;
}
void DisasterDailyLoop(void)
{
if (--_disaster_delay != 0) return;
ResetDisasterDelay();
if (_opt.diff.disasters != 0) DoDisaster();
}
void StartupDisasters(void)
{
ResetDisasterDelay();
}

366
dock_gui.c Normal file
View File

@@ -0,0 +1,366 @@
/* $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 byte _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));
}
static void BuildDocksClick_Canal(Window *w)
{
HandlePlacePushButton(w, 3, SPR_CURSOR_CANAL, 1, PlaceDocks_BuildCanal);
}
static void BuildDocksClick_Lock(Window *w)
{
HandlePlacePushButton(w, 4, SPR_CURSOR_LOCK, 1, PlaceDocks_BuildLock);
}
static void BuildDocksClick_Demolish(Window *w)
{
HandlePlacePushButton(w, 6, ANIMCURSOR_DEMOLISH, 1, PlaceDocks_DemolishArea);
}
static void BuildDocksClick_Depot(Window *w)
{
if (HandlePlacePushButton(w, 7, SPR_CURSOR_SHIP_DEPOT, 1, PlaceDocks_Depot)) ShowBuildDocksDepotPicker();
}
static void BuildDocksClick_Dock(Window *w)
{
if (HandlePlacePushButton(w, 8, SPR_CURSOR_DOCK, 3, PlaceDocks_Dock)) ShowBuildDockStationPicker();
}
static void BuildDocksClick_Buoy(Window *w)
{
HandlePlacePushButton(w, 9, 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->click.widget - 3 >= 0 && e->click.widget != 5) _build_docks_button_proc[e->click.widget - 3](w);
break;
case WE_KEYPRESS:
switch (e->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->place.tile);
break;
case WE_PLACE_DRAG: {
VpSelectTilesWithMethod(e->place.pt.x, e->place.pt.y, e->place.userdata);
return;
}
case WE_PLACE_MOUSEUP:
if (e->click.pt.x != -1) {
if ((e->place.userdata & 0xF) == VPM_X_AND_Y) { // dragged actions
GUIPlaceProcDragXY(e);
} else if (e->place.userdata == VPM_X_OR_Y) {
DoCommandP(e->place.tile, e->place.starttile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_AUTO | CMD_MSG(STR_CANT_BUILD_CANALS));
}
}
break;
case WE_ABORT_PLACE_OBJ:
UnclickWindowButtons(w);
SetWindowDirty(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->place.tile;
switch (GetTileSlope(tile_from, NULL)) {
case 3: tile_to += TileDiffXY(-1, 0); break;
case 6: tile_to += TileDiffXY( 0, -1); break;
case 9: tile_to += TileDiffXY( 0, 1); break;
case 12: tile_to += TileDiffXY( 1, 0); 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_PANEL, RESIZE_NONE, 7, 0, 21, 14, 35, SPR_IMG_BUILD_CANAL, STR_BUILD_CANALS_TIP},
{ WWT_PANEL, RESIZE_NONE, 7, 22, 43, 14, 35, SPR_IMG_BUILD_LOCK, STR_BUILD_LOCKS_TIP},
{ WWT_PANEL, RESIZE_NONE, 7, 44, 47, 14, 35, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 48, 69, 14, 35, 703, STR_018D_DEMOLISH_BUILDINGS_ETC},
{ WWT_PANEL, RESIZE_NONE, 7, 70, 91, 14, 35, 748, STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},
{ WWT_PANEL, RESIZE_NONE, 7, 92, 113, 14, 35, 746, STR_981D_BUILD_SHIP_DOCK},
{ WWT_PANEL, RESIZE_NONE, 7, 114, 135, 14, 35, 693, STR_9834_POSITION_BUOY_WHICH_CAN},
{ WWT_PANEL, RESIZE_NONE, 7, 136, 157, 14, 35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP},
{ WIDGETS_END},
};
static const WindowDesc _build_docks_toolbar_desc = {
640-158, 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 (_current_player == OWNER_SPECTATOR) 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_PAINT: {
int rad;
if (WP(w,def_d).close) return;
w->click_state = (1<<3) << _station_show_coverage;
DrawWindowWidgets(w);
rad = (_patches.modified_catchment) ? CA_DOCK : 4;
if (_station_show_coverage) {
SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
} else {
SetTileSelectBigSize(0, 0, 0, 0);
}
DrawStringCentered(74, 17, STR_3066_COVERAGE_AREA_HIGHLIGHT, 0);
DrawStationCoverageAreaText(4, 50, (uint)-1, rad);
break;
}
case WE_CLICK:
switch (e->click.widget) {
case 3:
case 4:
_station_show_coverage = e->click.widget - 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},
{ WIDGETS_END},
};
static const WindowDesc _build_dock_station_desc = {
-1, -1, 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 != 0) {
SetTileSelectSize(1, 2);
} else {
SetTileSelectSize(2, 1);
}
}
static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT:
w->click_state = (1<<3) << _ship_depot_direction;
DrawWindowWidgets(w);
DrawShipDepotSprite(67, 35, 0);
DrawShipDepotSprite(35, 51, 1);
DrawShipDepotSprite(135, 35, 2);
DrawShipDepotSprite(167, 51, 3);
return;
case WE_CLICK: {
switch (e->click.widget) {
case 3:
case 4:
_ship_depot_direction = e->click.widget - 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 = {
-1, -1, 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 = 0;
}

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,59 +0,0 @@
STRGEN USAGE
------------
This guide is only interesting for people who want to alter something
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 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.
EXAMPLES
--------
Example 1:
if you are in the root of your working copy (svn code), you should type
strgen/strgen -s lang lang/english.txt
to compile englist.txt into english.lng. It will be placed in the lang dir
Example 2:
you only have the strgen executable (no working copy) and you want to compile
a txt file in the same directory. You should type
./strgen english.txt
and you will get and english.lng in the same dir
Example 3:
you have strgen somewhere, english.txt in /usr/openttd/lang and you want the
resulting language file to go to /tmp. Use
./strgen -s /usr/openttd/lang -d /tmp english.txt
You can interchange english.txt to whichever language you want to generate a
.lng file for.
STRGEN COMMAND SWITCHES
-----------------------
-v | --version
strgen will tell what svn revision it was last modified
-t | --todo
strgen will add <TODO> to any untranslated/missing strings and use the english
strings while compiling the language file
-w | --warning
strgen will print any missing strings or wrongly translated (bad format)
to standard error output(stderr)
-h | --help | -?
Print out a summarized help message explaining these switches
-s | --source_dir
strgen will search for the master file english.txt in the directory specified
by this switch instead of the current directory
-d | --dest_dir
strgen will put <language>.lng in the directory specified by this switch; if
no dest_dir is given, output is the same as source_dir

View File

@@ -0,0 +1,49 @@
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
here are a very useful tool for translators:
http://openttd.rulez.org/
HOWTO compile strgen:
(this should be useless as you can just type make)
Goto the main dir
Compile by typing
gcc strgen/strgen.c -o strgen/strgen -DUNIX
or if you want it to tell the revision too
gcc strgen/strgen.c rev.o -o strgen/strgen -DUNIX -DWITH_REV (this is the one the makefile uses)
you now have a program called strgen in the strgen directory

View File

@@ -2,9 +2,9 @@ Welcome to the manual for OpenTTD. The latest release version at the time of wr
1 Obtaining OpenTTD.
You can obtain built binaries of OpenTTD for the 4 supported platforms - Win32, Linux,-x86, BeOS 5 and MacOS-X from the projects Sourceforge page, at http://sourceforge.net/projects/openttd . For the non-Win32 builds you will need libSDL.so, libpng.so and zlib.so compiled for your platform. Some builds will include these.
You can obtain built binaries of OpenTTD for the 4 supported platforms - Win32, Linux,-x86, BeOS 5 and MacOS-X from the projects Sourceforge page, at http://sourceforge.net/projects/openttd . For the non-Win32 builds you will need libSDL.so, libpng.so and zlib.so compiled for your platform. Some builds will include these.
If you use another platform, such as FreeBSD, which has POSIX file i/o and an SDL port, you should be able to build OpenTTD from its source. This is available in the proejcts Subversion repository at svn://svn.openttd.com . The module name is "trunk".
If you use another platform, such as FreeBSD, which has POSIX file i/o and an SDL port, you should be able to build OpenTTD from its source. This is available in the proejcts Subversion repository at svn://svn.openttd.com . The module name is "trunk".
1.1 Building OpenTTD.
@@ -13,16 +13,17 @@ 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.
1.2 Installing OpenTTD.
On Windows, insert your "Transport Tycoon Deluxe for Windows 95" disk. You can use a DOS version, but your graphics will be purple. NB: Even if your version of Transport Tycoon Deluxe ran on Windows 95, it may still be the DOS version. Then run the OpenTTD installer.
On Windows, insert your "Transport Tycoon Deluxe for Windows 95" disk. You can use a DOS version, but your graphics will be purple. NB: Even if your version of Transport Tycoon Deluxe ran on Windows 95, it may still be the DOS version. Then run the OpenTTD installer.
On UNIX platforms; decompress your OpenTTD archive, or otherwise run the installer. You should be left with an OpenTTD directory on your system. In this directory, make a subdirectory called 'data', and into this place the sample.cat file and all the .grf files from the install CD of 'Transport Tycoon Deluxe for Windows 95".
On UNIX platforms; decompress your OpenTTD archive, or otherwise run the installer. You should be left with an OpenTTD directory on your system. In this directory, make a subdirectory called 'data', and into this place the sample.cat file and all the .grf files from the install CD of 'Transport Tycoon Deluxe for Windows 95".
(Alternatively you can use the TTD GRF files from the DOS version: TRG1.GRF, TRGC.GRF, TRGH.GRF, TRGI.GRF, TRGT.GRF. A few minor graphical glitches with the DOS graphics remain. E.g. the autorail button in the rail toolbar doesn't look as nice as with the Windows graphics.)
If you want MIDI music, copy the 'gm' folder from the original game directory/CD to the OpenTTD folder.
@@ -37,7 +38,7 @@ On BeOS and Mac OS-X, just double click the ttd binary in the Tracker/Finder. Yo
1.4 Configuring OpenTTD
OpenTTD's launch menu contains three configuration menus - Difficulty Settings, Configure Patches and Game Settings. Most of these menus can be configured from within a running game as well.
OpenTTD's launch menu contains three configuration menus - Difficulty Settings, Configure Patches and Game Settings. Most of these menus can be configured from within a running game as well.
Difficulty Settings lets you configure settings that affect the difficulty of playing the game. These include when your (computer-controlled) competitors can start building, how many of them there are, and how intelligent they are. You can also control how much the subsidy mutliplier is for subsidised routes, and how stable/volitile the in-game economy is. You can also set how you want the terrain to be configured in a random game.
@@ -51,13 +52,14 @@ This section of the manual is written with the assumption that you already know
2.2 Station Construction
In OpenTTD, you can build rail stations up to seven squares long and with up to seven platforms. You can also have stations spreading across far larger distances, allowing a large rail station to be connected to a large airport, for instance.
In OpenTTD, you can build rail stations up to seven squares long and with up to seven platforms. You can also have stations spreading across far larger distances, allowing a large rail station to be connected to a large airport, for instance.
However, there is an even more noticable difference in rail station construction. You may now add platforms and lenght to a station after it has been built, and you may also add platforms of a different type. Users of TTDPatch will be used to this behaviour. But beyond what TTDPatch has, you can make stations of uneven lenght/width, and even ones with perpendicular tracks. You can also delete single tiles or tracks from a station, by holding down Shift before pressing the station construction button.
2.3 Checkpoint Stations
Checkpoint stations (the small blue item in the rail construction window) are small 1x1 stations. They must be built on top of pre-existing track. They do not accept or produce carge of any kind. They exist solely for use as route points. They become useful when dealing with large networks where trains may attempt to route themselves along undesirable or impossible routes. As an alternative to checkpoint stations, you can also direct trains to visit depots along the way. This has the advantage of also servicing the train and hence the train will rarely to never need to depart from its route to be serviced.
Checkpoint stations (the small blue item in the rail construction window) are small 1x1 stations. They must be built on top of pre-existing track. They do not accept or produce carge of any kind. They exist solely for use as route points. They become useful when dealing with large networks where trains may attempt to route themselves along undesirable or impossible routes. As an alternative to checkpoint stations, you can also direct trains to visit depots along the way. This has the advantage of also servicing the train and hence the train will rarely to never need to depart from its route to be serviced.
2.4 Freeform Rail Laying.
@@ -73,7 +75,7 @@ This allows you to build roads, rails, stations and depots on slopes. It also al
2.7 Long Bridges
OpenTTD allows you to constuct bridges up to 127 squares - half the size of the current map. This means that the crossing of large estuaries, such at the Bristol Channel in the original "West Country 90210" scenario can be acheived with one bridge instead of many bridges with staging points.
OpenTTD allows you to constuct bridges up to 127 squares - half the size of the current map. This means that the crossing of large estuaries, such at the Bristol Channel in the original "West Country 90210" scenario can be acheived with one bridge instead of many bridges with staging points.
2.8 Long trains
@@ -87,7 +89,7 @@ This addition to OpenTTD allows you to see the current speed of any vehicle in t
Virtually any settings - train numbers, start date, what vehicles your competitors can use, etc - can be set in OpenTTD. Just use the Configure Patches menu on the main screen.
2.11 Network Play
2.11 Network Play
See multiplayer.txt for more info.
@@ -97,4 +99,4 @@ This button, at the end of the train construction window, lets you 'recycle' tra
2.13 Canal Building
This button, at the end of the water construction window, lets you build canals and shiplifts across the landscape. These act just like normal water.
This button, at the end of the water construction window, lets you build canals and shiplifts across the landscape. These act just like normal water.

View File

@@ -20,4 +20,4 @@ data (containing the grf files)
GM (optional for music)
scenario (optional pregenerated maps)
The game adds some items by itself when it runs, like a save folder and a setting file
The game adds some items by itself when it runs, like a save folder and a setting file

View File

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

View File

@@ -0,0 +1,62 @@
Compiling and developing OpenTTD on MandrakeLinux 10.0 Official
A quick guide to get started with OpenTTD development on Linux.
---------------------------------------------------------------
1.) RPMs:
Most packages that are required for development (like gcc) should already be installed on your box. You will require those RPMs additionally:
- libsdl1.2-devel-1.2.7-2mdk
- subversion-1.0.1-1mdk (+ dependencies)
- libsvn_ra_svn1_0-1.0.1-1mdk
2.) Subversion:
To obtain the source code from the subversion server type
$ svn co svn://svn.openttd.com/openttd/trunk openttd
from command line to dump the code into the directory 'openttd'.
To update your working copy to the latest revision use
$ svn update
Don't worry, your version will be merged with the latest version.
The command
$ svn diff > mypatch.diff
creates a patch file (aka diff file) which you can submit to the developers to share your improvements.
You can undo changes to a file with
$svn revert filename
3.) Required data files:
Copy the following files from Transport Tycoon Deluxe to openttd/data/
sample.cat
trg1r.grf
trgcr.grf
trghr.grf
trgir.grf
trgtr.grf
(Alternatively you can use the TTD GRF files from the DOS version: TRG1.GRF, TRGC.GRF, TRGH.GRF, TRGI.GRF, TRGT.GRF. A few minor graphical glitches with the DOS graphics remain. E.g. the autorail button in the rail toolbar doesn't look as nice as with the Windows graphics.)
4.) Compiling and running:
Compile OpenTTD with
$ make
and run it with
$ ./ttd
5.) Playing the soundtrack:
If you want the original TTD music you need to copy the whole /gm/ directory from Windows. Additionally the TiMidity driver is required:
TiMidity++-2.12.0-0.pre1.4mdk (+ dependencies)
To run OpenTTD with music support type
$ ./ttd -m extmidi
X.) Last Update: $Date: 2004-06-01 19:08:09 +0200 (Tue, 01 Jun 2004) $
Written for revision $Rev: 710 $

View File

@@ -15,13 +15,15 @@ LIBRARIES REQUIRED FOR END USERS
SDL.DLL (SDL 1.2.7) and FSLib.dll are required to use this program:
these can be downloaded from the Files section at
http://sourceforge.net/projects/openttd/ - see "os2-useful-v1.1.zip".
Version 20051222 of SDL or later is required. This can be found at
http://sdl.netlabs.org/.
http://sourceforge.net/projects/openttd/ - see "os2-useful.zip".
(Note that a newer version of SDL is now available at
ftp://ftp.netlabs.org/pub/sdl/sdl-dev-os2-2004-12-22.zip which may
help solve some problems).
Please note that earlier SDL releases will probably NOT work with
OpenTTD. If you experience problems with OpenTTD, please check
your SDL and FSLib.dll versions (both must match).
Please note that SDL release 2005-03-30 does NOT work with OpenTTD,
at least in my experience and the experience of a couple of other
users. If you experience problems with OpenTTD, please try downgrading
to SDL 2004-12-22.
Note that to actually play the game, I have found in my own
experience that a version of the Scitech Display Drivers or its later
@@ -50,10 +52,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 +62,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 +69,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,22 +89,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
For 0.3.5, I used ftp://ftp.netlabs.org/pub/sdl/SDL-1.2.7-src-20040908a.zip -
take SDL.dll and SDL.lib from the src/ directory. Note that 20041222 is
out now, which is recommended for stability updates.
- Freetype
http://freetype.sourceforge.net/
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.zip".
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
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 +133,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,115 +0,0 @@
Compiling OpenTTD using Microsoft Visual C++
January 2, 2007
--------------------------------------------
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
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.
1) REQUIRED FILES
-----------------
You might already have some of the files already installed, so check before
downloading; mostly because the DirectX SDK and Platform SDK are about
500MB each.
Download the following files:
* 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)
...and of course the newest source from svn://svn.openttd.org/trunk
You need an SVN-client to download the source from subversion:
* CLI Subversion (http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91)
* GUI TortoiseSVN (http://tortoisesvn.tigris.org/download.html)
2) INCLUDES AND LIBRARIES
-------------------------
Put the newly downloaded files in the VC lib\ and include\ directories; where
"C:\Program Files\Microsoft Visual Studio 8\VC" is your location of Visual C.
If you are compiling for an x64 system, use the include\ and lib\ directories
from the win64/ folder.
* openttd-useful.zip\include\*
* afxresh.h
to > C:\Program Files\Microsoft Visual Studio 8\VC\Include
* openttd-useful.zip\lib\*
to > C:\Program Files\Microsoft Visual Studio 8\VC\Lib
Custom directories might be recommended, check 2.2)
2.1) INCLUDES AND LIBRARIES - DIRECTX/PLATFORM SDK
--------------------------------------------------
Basically the same procedure as with the useful zip file, providing
you are not using the Microsoft installer. Put the include files in the
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,
MSVC will not find them by default. You need to add these paths to VC through:
Tools > Options > Projects and Solutions > VC++ Directories > show directories for
* Include files: Add the DirectX/Platform SDK include dir you've created
* Library files: Add the path to the SDK custom lib dir
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
* sample.cat
* trg1r.grf
* trgcr.grf
* trghr.grf
* trgir.grf
* trgtr.grf
4) COMPILING
------------
Open trunk/openttd_vs[89]0.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
5) EDITING, CHANGING SOURCE CODE
--------------------------------
Set the build mode (back to) 'Debug'
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 (!)
source. If it still doesn't work, check in on IRC (irc://irc.oftc.net/openttd),
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

View File

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

58
docs/console.txt Normal file
View File

@@ -0,0 +1,58 @@
OPENTTD INGAME CONSOLE DOCUMENTATION
====================================
http://wiki.openttd.org/index.php/OpenTTDDevBlackBook
for detailed information
*** WARNING **
This document is out of date
*** WARNING **
HOTKEY: BACKQUOTE (aka tilde, the key left to "1")
COMMANDS:
---------
echo [string]
echoc [color-code] [string]
exit
debug_level [0-9]
dump_vars [filter]
help
list_cmds [filter]
list_vars [filter]
printf [formatstring] [var] [var] [var]....
printfc [color-code] [formatstring] [var] [var] [var]....
quit
random
screenshot ["big"/"no_con"]
VARIABLES:
----------
*con_developer
-> true = console debugging info
-> false = no output
*developer
-> 0 = no output
-> 1 = console error output [like command not found]
-> 2 = console error and debug output
*cursor_rate
-> 1-12 = defines the cursor blink interval
VARIABLE HANDLING:
------------------
developer = 0
developer ++
temp_string = test
temp_string = "my little"
printf "%s world" temp_string
---------------------------------------------------
feel free to add more commands and use this in-game
console for your debugging / enhancements

20
docs/directmusic.txt Normal file
View File

@@ -0,0 +1,20 @@
Notes about DirectMusic driver for Win32
----------------------------------------
If compiling under MinGW32, you require the DirectX 7.0 files for MinGW32, available from
http://alleg.sourceforge.net/files/dx70_mgw.zip.
If compiling under MSVC 6.0, you require the equivalent for MSVC, available from
http://alleg.sourceforge.net/files/dx70_min.zip. MSVC 7.0/7.1 include header files that
are recent enough.
If you do not want to compile the DirectMusic driver, undefine WIN32_ENABLE_DIRECTMUSIC_SUPPORT
in stdafx.h.
Bugs, etc
---------
- The volume control doesn't work properly. I'll fix this soon.
Owen Rudge
14th March 2004

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

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,110 +32,72 @@ 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>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"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XXXX XX<span class="free">OO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">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>
</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 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"><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 OOOO O</span>XXX <span class="free">O</span>XXX</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">OO OO</span>XX</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">OOO</span>X XXXX</td>
<td class="bits"><span class="free">OOOO</span> XXXX</td>
<td class="bits">XX<span class="free">OO 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">-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">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
@@ -146,207 +106,143 @@ the array so you can quickly see what is used and what is not.
<td class="caption">level crossing</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX <span class="option">~~</span>XX</td>
<td class="bits"><span class="free">O</span>XXX XXXX</td>
<td class="bits">XX<span class="free">OO</span> XXXX</td>
<td class="bits">XX<span class="free">OO OO</span>XX</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"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits">X<span class="free">OOO 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"><span class="free">OOO</span>X XXXX</td>
<td class="bits">XXXX XXXX</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">road stop</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO O</span>XXX</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"><span class="free">OOOO OOOO</span></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>6</td>
<td class="caption">water</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">X<span class="free">OOO</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>
</tr>
<tr>
<td>bubble/sugar/toffee</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OO</span>XX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>toy factory</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OOOO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>gold/copper/coal</td>
<td class="bits"><span class="abuse">XX</span><span class="free">OO OO</span><span class="abuse">XX</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>oil wells</td>
<td class="bits"><span class="abuse">X</span><span class="free">OOO OO</span><span class="abuse">XX</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td>power station</td>
<td class="bits"><span class="abuse">X</span><span class="free">O</span><span class="abuse">XX XX</span><span class="free">OO</span></td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
</tr>
<tr>
<td rowspan=2>9</td>
<td class="caption">tunnel entrance</td>
<td class="caption">tunnel</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</span> <span class="option">~</span><span class="abuse">XXX</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">X<span class="free">OOO</span> <span class="option">~</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>
</tr>
<tr>
<td>bridge ramp</td>
<td class="bits">-inherit-</td>
<td class="bits">-inherit-</td>
<td class="bits"><span class="free">OOOO OOOO</span> XXXX <span class="free">OOOO</span></td>
<td class="bits"><span class="free">OOOO</span> <span class="option">~</span><span class="abuse">XXX</span></td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">X<span class="free">OOO</span> <span class="option">~</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>
</tr>
<tr>
<td rowspan=2>A</td>
<td class="caption">unmovables</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="option">~~~</span>X XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>bridge</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO</span> <span class="abuse">XXXX XXXX</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">X<span class="free">OOO OOOO</span></td>
<td class="bits">XXXX XXXX</td>
<td class="bits">XXXX XXXX</td>
</tr>
<tr>
<td>A</td>
<td class="caption">various (HQ)</td>
<td class="bits">XXXX XXXX</td>
<td class="bits"><span class="free">OOOO OOOO OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits">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">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>
<td class="bits">XXXX XXXX</td>
</tr>
</tbody>
</table>

View File

@@ -9,7 +9,7 @@ Multiplayer Manual for OpenTTD (0.3.5)
- Type in a game name
- Select the type of game ('LAN/Internet' or 'Internet (advertise)'. With the last one
other people are able to see you online. Else they need your IP and port to join)
- Click "start game", "load game" or "load scenario"
- Click "start game" ,"load game" or "load scenario"
- Start playing
@@ -46,7 +46,7 @@ Multiplayer Manual for OpenTTD (0.3.5)
- Open the console and type in the following command:
connect <ip/host>:<port>#<player-no>
]connect <ip/host>:<port>#<player-no>
4. Playing Internet-Games
@@ -54,9 +54,7 @@ Multiplayer Manual for OpenTTD (0.3.5)
- Since OpenTTD 0.3.5 the network protocol has been rewritten and is very stable, even over slow connections.
- Servers with a red dot behind it have a different version then you have. You will not be able to join those servers.
- Servers with a yellow dot behind it have NewGRFs that you do not have. You will not be able to join those servers.
- Server with a red dot behind it have a different version then you have. You will not be able to join those servers.
- It can happen that a connection is that slow, or you have that many clients connected to your server, that your clients start to loose their connection. Some things you can do about it:
@@ -112,10 +110,3 @@ Multiplayer Manual for OpenTTD (0.3.5)
- From 0.3.5, desyncs should not happen anymore
- From 0.3.5, patch-settings are also synced. You can now play without deleting openttd.cfg, and with, for example, extra large trains enabled.
7. Troubleshooting
------------------
- My advertised server does not show up in the 'advertised server list' (servers.openttd.org)
Run openttd with the '-d net=2' parameter, as this will show whether it receives replies from the master server.
If it does not receive replies it is most likely that you need to configure your router to forward the OpenTTD ports 3979 (both TCP and UDP) to the computer that is hosting the game.

View File

@@ -1,6 +1,6 @@
.\" Hey, EMACS: -*- nroff -*-
.\" Please adjust this date whenever revising the manpage.
.Dd Sep 15, 2007
.Dd March 22, 2006
.Dt OPENTTD 6
.Sh NAME
.Nm openttd
@@ -11,14 +11,14 @@
.Op Fl G Ar seed
.Op Fl d Ar [level | cat=lvl[, ...]]
.Op Fl g Ar [savegame]
.Op Fl n Ar host[:port][#player]
.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 v Ar driver
.Sh OPTIONS
.Bl -tag -width ".Fl n Ar host[:port][#player]"
.Bl -tag -width ".Fl n Ar host[#player][:port]"
.It Fl D
Start a dedicated server
.It Fl G Ar seed
@@ -45,7 +45,9 @@ 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
@@ -59,7 +61,7 @@ Set the video driver, see
.Fl h
.El
.Sh SEE ALSO
http://wiki.openttd.org/, http://www.openttd.org
http://wiki.openttd.org/
.Sh HISTORY
Transport Tycoon Deluxe was written by Chris Sawyer and published by Microprose.
.Nm

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

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);
#endif /* DRIVER_H */

84
dummy_land.c Normal file
View File

@@ -0,0 +1,84 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "viewport.h"
#include "command.h"
#include "table/sprites.h"
static void DrawTile_Dummy(TileInfo *ti)
{
DrawGroundSpriteAt(SPR_SHADOW_CELL, ti->x, ti->y, ti->z);
}
static uint GetSlopeZ_Dummy(const TileInfo* ti)
{
return 0;
}
static uint GetSlopeTileh_Dummy(const TileInfo* ti)
{
return 0;
}
static int32 ClearTile_Dummy(TileIndex tile, byte flags)
{
return_cmd_error(STR_0001_OFF_EDGE_OF_MAP);
}
static void GetAcceptedCargo_Dummy(TileIndex tile, AcceptedCargo ac)
{
/* not used */
}
static void GetTileDesc_Dummy(TileIndex tile, TileDesc *td)
{
td->str = STR_EMPTY;
td->owner = OWNER_NONE;
}
static void AnimateTile_Dummy(TileIndex tile)
{
/* not used */
}
static void TileLoop_Dummy(TileIndex tile)
{
/* not used */
}
static void ClickTile_Dummy(TileIndex tile)
{
/* not used */
}
static void ChangeTileOwner_Dummy(TileIndex tile, PlayerID old_player, PlayerID new_player)
{
/* not used */
}
static uint32 GetTileTrackStatus_Dummy(TileIndex tile, TransportType mode)
{
return 0;
}
const TileTypeProcs _tile_type_dummy_procs = {
DrawTile_Dummy, /* draw_tile_proc */
GetSlopeZ_Dummy, /* get_slope_z_proc */
ClearTile_Dummy, /* clear_tile_proc */
GetAcceptedCargo_Dummy, /* get_accepted_cargo_proc */
GetTileDesc_Dummy, /* get_tile_desc_proc */
GetTileTrackStatus_Dummy, /* get_tile_track_status_proc */
ClickTile_Dummy, /* click_tile_proc */
AnimateTile_Dummy, /* animate_tile_proc */
TileLoop_Dummy, /* tile_loop_clear */
ChangeTileOwner_Dummy, /* change_tile_owner_clear */
NULL, /* get_produced_cargo_proc */
NULL, /* vehicle_enter_tile_proc */
NULL, /* vehicle_leave_tile_proc */
GetSlopeTileh_Dummy, /* get_slope_tileh_proc */
};

1695
economy.c Normal file

File diff suppressed because it is too large Load Diff

70
economy.h Normal file
View File

@@ -0,0 +1,70 @@
/* $Id$ */
#ifndef ECONOMY_H
#define ECONOMY_H
void ResetPriceBaseMultipliers(void);
void SetPriceBaseMultiplier(uint price, byte factor);
typedef struct {
// Maximum possible loan
int32 max_loan;
int32 max_loan_unround;
// Economy fluctuation status
int fluct;
// Interest
byte interest_rate;
byte infl_amount;
byte infl_amount_pr;
} Economy;
VARDEF Economy _economy;
typedef struct Subsidy {
byte cargo_type;
byte age;
uint16 from;
uint16 to;
} Subsidy;
enum {
SCORE_VEHICLES = 0,
SCORE_STATIONS = 1,
SCORE_MIN_PROFIT = 2,
SCORE_MIN_INCOME = 3,
SCORE_MAX_INCOME = 4,
SCORE_DELIVERED = 5,
SCORE_CARGO = 6,
SCORE_MONEY = 7,
SCORE_LOAN = 8,
SCORE_TOTAL = 9, // This must always be the last entry
NUM_SCORE = 10, // How many scores are there..
SCORE_MAX = 1000, // The max score that can be in the performance history
// the scores together of score_info is allowed to be more!
};
typedef struct ScoreInfo {
byte id; // Unique ID of the score
int needed; // How much you need to get the perfect score
int score; // How much score it will give
} ScoreInfo;
extern const ScoreInfo _score_info[];
extern int _score_part[MAX_PLAYERS][NUM_SCORE];
int UpdateCompanyRatingAndValue(Player *p, bool update);
void UpdatePlayerHouse(Player *p, uint score);
VARDEF Subsidy _subsidies[MAX_PLAYERS];
Pair SetupSubsidyDecodeParam(const Subsidy* s, bool mode);
void DeleteSubsidyWithIndustry(uint16 index);
void DeleteSubsidyWithStation(uint16 index);
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
uint MoveGoodsToStation(TileIndex tile, int w, int h, int type, uint amount);
#endif /* ECONOMY_H */

52
endian_check.c Normal file
View File

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

1305
engine.c Normal file

File diff suppressed because it is too large Load Diff

367
engine.h Normal file
View File

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

289
engine_gui.c Normal file
View File

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

213
fileio.c Normal file
View File

@@ -0,0 +1,213 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "fileio.h"
#include "functions.h"
#include "macros.h"
#include "variables.h"
#if defined(UNIX) || defined(__OS2__)
#include <ctype.h> // required for tolower()
#endif
/*************************************************/
/* FILE IO ROUTINES ******************************/
/*************************************************/
#define FIO_BUFFER_SIZE 512
typedef struct {
byte *buffer, *buffer_end;
uint32 pos;
FILE *cur_fh;
FILE *handles[32];
byte buffer_start[512];
} Fio;
static Fio _fio;
// Get current position in file
uint32 FioGetPos(void)
{
return _fio.pos + (_fio.buffer - _fio.buffer_start) - FIO_BUFFER_SIZE;
}
void FioSeekTo(uint32 pos, int mode)
{
if (mode == SEEK_CUR) pos += FioGetPos();
_fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE;
fseek(_fio.cur_fh, (_fio.pos=pos), SEEK_SET);
}
// Seek to a file and a position
void FioSeekToFile(uint32 pos)
{
FILE *f = _fio.handles[pos >> 24];
assert(f != NULL);
_fio.cur_fh = f;
FioSeekTo(pos & 0xFFFFFF, SEEK_SET);
}
byte FioReadByte(void)
{
if (_fio.buffer == _fio.buffer_end) {
_fio.pos += FIO_BUFFER_SIZE;
fread(_fio.buffer = _fio.buffer_start, 1, FIO_BUFFER_SIZE, _fio.cur_fh);
}
return *_fio.buffer++;
}
void FioSkipBytes(int n)
{
for(;;) {
int m = min(_fio.buffer_end - _fio.buffer, n);
_fio.buffer += m;
n -= m;
if (n == 0) break;
FioReadByte();
n--;
}
}
uint16 FioReadWord(void)
{
byte b = FioReadByte();
return (FioReadByte() << 8) | b;
}
uint32 FioReadDword(void)
{
uint b = FioReadWord();
return (FioReadWord() << 16) | b;
}
void FioReadBlock(void *ptr, uint size)
{
FioSeekTo(FioGetPos(), SEEK_SET);
_fio.pos += size;
fread(ptr, 1, size, _fio.cur_fh);
}
static inline void FioCloseFile(int slot)
{
if (_fio.handles[slot] != NULL) {
fclose(_fio.handles[slot]);
_fio.handles[slot] = NULL;
}
}
void FioCloseAll(void)
{
int i;
for (i = 0; i != lengthof(_fio.handles); i++)
FioCloseFile(i);
}
bool FiosCheckFileExists(const char *filename)
{
FILE *f;
char buf[MAX_PATH];
sprintf(buf, "%s%s", _path.data_dir, filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// Make lower case and try again
for(s=buf + strlen(_path.data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
#if defined SECOND_DATA_DIR
// tries in the 2nd data directory
if (f == NULL) {
sprintf(buf, "%s%s", _path.second_data_dir, filename);
for(s=buf + strlen(_path.second_data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
#endif
}
#endif
if (f == NULL)
return false;
else {
fclose(f);
return true;
}
}
FILE *FioFOpenFile(const char *filename)
{
FILE *f;
char buf[MAX_PATH];
sprintf(buf, "%s%s", _path.data_dir, filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// Make lower case and try again
for(s=buf + strlen(_path.data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
#if defined SECOND_DATA_DIR
// tries in the 2nd data directory
if (f == NULL) {
sprintf(buf, "%s%s", _path.second_data_dir, filename);
for(s=buf + strlen(_path.second_data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
#endif
}
#endif
return f;
}
void FioOpenFile(int slot, const char *filename)
{
FILE *f;
char buf[MAX_PATH];
sprintf(buf, "%s%s", _path.data_dir, filename);
f = fopen(buf, "rb");
#if !defined(WIN32)
if (f == NULL) {
char *s;
// Make lower case and try again
for(s=buf + strlen(_path.data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
#if defined SECOND_DATA_DIR
// tries in the 2nd data directory
if (f == NULL) {
sprintf(buf, "%s%s", _path.second_data_dir, filename);
for(s=buf + strlen(_path.second_data_dir) - 1; *s != 0; s++)
*s = tolower(*s);
f = fopen(buf, "rb");
}
if (f == NULL)
sprintf(buf, "%s%s", _path.data_dir, filename); //makes it print the primary datadir path instead of the secundary one
#endif
}
#endif
if (f == NULL)
error("Cannot open file '%s'", buf);
FioCloseFile(slot); // if file was opened before, close it
_fio.handles[slot] = f;
FioSeekToFile(slot << 24);
}

19
fileio.h Normal file
View File

@@ -0,0 +1,19 @@
/* $Id$ */
#ifndef FILEIO_H
#define FILEIO_H
void FioSeekTo(uint32 pos, int mode);
void FioSeekToFile(uint32 pos);
uint32 FioGetPos(void);
byte FioReadByte(void);
uint16 FioReadWord(void);
uint32 FioReadDword(void);
void FioCloseAll(void);
FILE *FioFOpenFile(const char *filename);
void FioOpenFile(int slot, const char *filename);
void FioReadBlock(void *ptr, uint size);
void FioSkipBytes(int n);
bool FiosCheckFileExists(const char *filename);
#endif /* FILEIO_H */

267
functions.h Normal file
View File

@@ -0,0 +1,267 @@
/* $Id$ */
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
/* landscape.c */
void FindLandscapeHeight(TileInfo *ti, uint x, uint y);
void FindLandscapeHeightByTile(TileInfo *ti, TileIndex tile);
void DoClearSquare(TileIndex tile);
void CDECL ModifyTile(TileIndex tile, uint flags, ...);
void RunTileLoop(void);
uint GetPartialZ(int x, int y, int corners);
uint GetSlopeZ(int x, int y);
uint32 GetTileTrackStatus(TileIndex tile, TransportType mode);
void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac);
void ChangeTileOwner(TileIndex tile, byte old_player, byte new_player);
void AnimateTile(TileIndex tile);
void ClickTile(TileIndex tile);
void GetTileDesc(TileIndex tile, TileDesc *td);
void DrawTile(TileInfo *ti);
void UpdateTownMaxPass(Town *t);
bool IsValidTile(TileIndex tile);
static inline Point RemapCoords(int x, int y, int z)
{
#if !defined(NEW_ROTATION)
Point pt;
pt.x = (y - x) * 2;
pt.y = y + x - z;
#else
Point pt;
pt.x = (x + y) * 2;
pt.y = x - y - z;
#endif
return pt;
}
static inline Point RemapCoords2(int x, int y)
{
return RemapCoords(x, y, GetSlopeZ(x, y));
}
/* clear_land.c */
void DrawHillyLandTile(const TileInfo *ti);
void DrawClearLandTile(const TileInfo *ti, byte set);
void DrawClearLandFence(const TileInfo *ti);
void TileLoopClearHelper(TileIndex tile);
/* road_land.c */
void DrawRoadDepotSprite(int x, int y, int image);
/* water_land.c */
void DrawShipDepotSprite(int x, int y, int image);
void TileLoop_Water(TileIndex tile);
/* players.c */
bool CheckPlayerHasMoney(int32 cost);
void SubtractMoneyFromPlayer(int32 cost);
void SubtractMoneyFromPlayerFract(PlayerID player, int32 cost);
bool CheckOwnership(PlayerID owner);
bool CheckTileOwnership(TileIndex tile);
StringID GetPlayerNameString(PlayerID player, uint index);
/* standard */
void ShowInfo(const char *str);
void CDECL ShowInfoF(const char *str, ...);
void NORETURN CDECL error(const char *str, ...);
/* openttd.c */
// **************
// * Warning: DO NOT enable this unless you understand what it does
// *
// * If enabled, in a network game all randoms will be dumped to the
// * stdout if the first client joins (or if you are a client). This
// * is to help finding desync problems.
// *
// * Warning: DO NOT enable this unless you understand what it does
// **************
//#define RANDOM_DEBUG
// Enable this to produce higher quality random numbers.
// Doesn't work with network yet.
//#define MERSENNE_TWISTER
// Mersenne twister functions
void SeedMT(uint32 seed);
uint32 RandomMT(void);
#ifdef MERSENNE_TWISTER
static inline uint32 Random(void) { return RandomMT(); }
uint RandomRange(uint max);
#else
#ifdef RANDOM_DEBUG
#define Random() DoRandom(__LINE__, __FILE__)
uint32 DoRandom(int line, const char *file);
#define RandomRange(max) DoRandomRange(max, __LINE__, __FILE__)
uint DoRandomRange(uint max, int line, const char *file);
#else
uint32 Random(void);
uint RandomRange(uint max);
#endif
#endif // MERSENNE_TWISTER
static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); }
static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); }
uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */
uint InteractiveRandomRange(uint max);
// Used for profiling
#define TIC() { extern uint32 _rdtsc(void); uint32 _xxx_ = _rdtsc(); static float __avg__;
#define TOC(s) _xxx_ = _rdtsc() - _xxx_; __avg__=__avg__*0.99+_xxx_*0.01; printf("%s: %8d %f\n", s, _xxx_,__avg__); }
void SetDate(uint date);
/* facedraw.c */
void DrawPlayerFace(uint32 face, int color, int x, int y);
/* texteff.c */
void MoveAllTextEffects(void);
void AddTextEffect(StringID msg, int x, int y, uint16 duration);
void InitTextEffects(void);
void DrawTextEffects(DrawPixelInfo *dpi);
void InitTextMessage(void);
void DrawTextMessage(void);
void CDECL AddTextMessage(uint16 color, uint8 duration, const char *message, ...);
void UndrawTextMessage(void);
void TextMessageDailyLoop(void);
bool AddAnimatedTile(TileIndex tile);
void DeleteAnimatedTile(TileIndex tile);
void AnimateAnimatedTiles(void);
void InitializeAnimatedTiles(void);
/* tunnelbridge_cmd.c */
bool CheckTunnelInWay(TileIndex tile, int z);
bool CheckBridge_Stuff(byte bridge_type, uint bridge_len);
uint32 GetBridgeLength(TileIndex begin, TileIndex end);
int CalcBridgeLenCostFactor(int x);
typedef void CommandCallback(bool success, TileIndex tile, uint32 p1, uint32 p2);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
/* network.c */
void NetworkUDPClose(void);
void NetworkStartUp(void);
void NetworkShutDown(void);
void NetworkGameLoop(void);
void NetworkUDPGameLoop(void);
bool NetworkServerStart(void);
bool NetworkClientConnectGame(const char* host, unsigned short port);
void NetworkReboot(void);
void NetworkDisconnect(void);
void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
/* misc_cmd.c */
void PlaceTreesRandomly(void);
void InitializeLandscapeVariables(bool only_constants);
/* misc.c */
void DeleteName(StringID id);
char *GetName(int id, char *buff);
// AllocateNameUnique also tests if the name used is not used anywere else
// and if it is used, it returns an error.
#define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true)
#define AllocateName(name, skip) RealAllocateName(name, skip, false)
StringID RealAllocateName(const char *name, byte skip, bool check_double);
void ConvertDayToYMD(YearMonthDay *ymd, uint16 date);
uint ConvertYMDToDay(uint year, uint month, uint day);
uint ConvertIntDate(uint date);
/* misc functions */
void MarkTileDirty(int x, int y);
void MarkTileDirtyByTile(TileIndex tile);
void InvalidateWindow(WindowClass cls, WindowNumber number);
void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index);
void InvalidateWindowClasses(WindowClass cls);
void DeleteWindowById(WindowClass cls, WindowNumber number);
void DeleteWindowByClass(WindowClass cls);
void SetObjectToPlaceWnd(CursorID icon, byte mode, Window *w);
void SetObjectToPlace(CursorID icon, byte mode, WindowClass window_class, WindowNumber window_num);
void ResetObjectToPlace(void);
bool ScrollWindowTo(int x, int y, Window * w);
bool ScrollMainWindowToTile(TileIndex tile);
bool ScrollMainWindowTo(int x, int y);
void DrawSprite(uint32 img, int x, int y);
uint GetCorrectTileHeight(TileIndex tile);
bool EnsureNoVehicle(TileIndex tile);
bool EnsureNoVehicleZ(TileIndex tile, byte z);
void MarkAllViewportsDirty(int left, int top, int right, int bottom);
void ShowCostOrIncomeAnimation(int x, int y, int z, int32 cost);
void ShowFeederIncomeAnimation(int x, int y, int z, int32 cost);
void DrawFoundation(TileInfo *ti, uint f);
bool CheckIfAuthorityAllows(TileIndex tile);
Town *ClosestTownFromTile(TileIndex tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max);
uint GetRoadBitsByTile(TileIndex tile);
int GetTownRadiusGroup(const Town *t, TileIndex tile);
void ShowNetworkChatQueryWindow(byte desttype, byte dest);
void ShowNetworkGiveMoneyWindow(byte player);
void ShowNetworkNeedGamePassword(void);
void ShowNetworkNeedCompanyPassword(void);
int FindFirstBit(uint32 x);
void ShowHighscoreTable(int difficulty, int8 rank);
void ShowEndGameChart(void);
TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
void AfterLoadTown(void);
void GenRandomNewGame(uint32 rnd1, uint32 rnd2);
void StartScenarioEditor(uint32 rnd1, uint32 rnd2);
void AskExitGame(void);
void AskExitToGameMenu(void);
void RedrawAutosave(void);
StringID RemapOldStringID(StringID s);
void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str);
enum {
SLD_LOAD_GAME = 0,
SLD_LOAD_SCENARIO = 1,
SLD_SAVE_GAME = 2,
SLD_SAVE_SCENARIO = 3,
SLD_NEW_GAME = 4,
};
void ShowSaveLoadDialog(int mode);
// callback from drivers that is called if the game size changes dynamically
void GameSizeChanged(void);
bool FileExists(const char *filename);
bool ReadLanguagePack(int index);
void InitializeLanguagePacks(void);
void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize);
int GetLanguageList(char **languages, int max);
void LoadFromConfig(void);
void SaveToConfig(void);
void CheckConfig(void);
int ttd_main(int argc, char* argv[]);
void DeterminePaths(void);
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
void CSleep(int milliseconds);
#endif /* FUNCTIONS_H */

1984
gfx.c Normal file

File diff suppressed because it is too large Load Diff

131
gfx.h Normal file
View File

@@ -0,0 +1,131 @@
/* $Id$ */
#ifndef GFX_H
#define GFX_H
typedef byte Pixel;
typedef struct ColorList {
byte unk0, unk1, unk2;
byte window_color_1a, window_color_1b;
byte window_color_bga, window_color_bgb;
byte window_color_2;
} ColorList;
struct DrawPixelInfo {
Pixel *dst_ptr;
int left, top, width, height;
int pitch;
uint16 zoom;
};
typedef struct CursorVars {
Point pos, size, offs, delta;
Point draw_pos, draw_size;
CursorID sprite;
int wheel; // mouse wheel movement
const CursorID *animate_list, *animate_cur;
uint animate_timeout;
bool visible;
bool dirty;
bool fix_at;
} CursorVars;
void RedrawScreenRect(int left, int top, int right, int bottom);
void GfxScroll(int left, int top, int width, int height, int xo, int yo);
// XXX doesn't really belong here, but the only
// consumers always use it in conjunction with DoDrawString()
#define UPARROW "\x80"
#define DOWNARROW "\xAA"
int DrawStringCentered(int x, int y, StringID str, uint16 color);
int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color);
int DoDrawStringCentered(int x, int y, const char *str, uint16 color);
int DrawString(int x, int y, StringID str, uint16 color);
int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw);
int DoDrawString(const char *string, int x, int y, uint16 color);
int DoDrawStringTruncated(const char *str, int x, int y, uint16 color, uint maxw);
void DrawStringCenterUnderline(int x, int y, StringID str, uint16 color);
void DrawStringCenterUnderlineTruncated(int xl, int xr, int y, StringID str, uint16 color);
void DrawStringRightAligned(int x, int y, StringID str, uint16 color);
void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw);
void GfxFillRect(int left, int top, int right, int bottom, int color);
void GfxDrawLine(int left, int top, int right, int bottom, int color);
void DrawFrameRect(int left, int top, int right, int bottom, int color, int flags);
uint16 GetDrawStringPlayerColor(PlayerID player);
int GetStringWidth(const char *str);
void LoadStringWidthTable(void);
void DrawStringMultiCenter(int x, int y, StringID str, int maxw);
void DrawStringMultiLine(int x, int y, StringID str, int maxw);
void DrawDirtyBlocks(void);
void SetDirtyBlocks(int left, int top, int right, int bottom);
void MarkWholeScreenDirty(void);
void GfxInitPalettes(void);
bool FillDrawPixelInfo(DrawPixelInfo* n, const DrawPixelInfo* o, int left, int top, int width, int height);
/* window.c */
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom);
void SetMouseCursor(uint cursor);
void SetAnimatedMouseCursor(const CursorID *table);
void CursorTick(void);
void DrawMouseCursor(void);
void ScreenSizeChanged(void);
void UndrawMouseCursor(void);
bool ChangeResInGame(int w, int h);
void SortResolutions(int count);
void ToggleFullScreen(bool fs);
/* gfx.c */
#define ASCII_LETTERSTART 32
VARDEF int _stringwidth_base;
VARDEF byte _stringwidth_table[0x2A0];
static inline byte GetCharacterWidth(uint key)
{
assert(key >= ASCII_LETTERSTART && key - ASCII_LETTERSTART < lengthof(_stringwidth_table));
return _stringwidth_table[key - ASCII_LETTERSTART];
}
VARDEF DrawPixelInfo _screen;
VARDEF DrawPixelInfo *_cur_dpi;
VARDEF ColorList _color_list[16];
VARDEF CursorVars _cursor;
VARDEF int _pal_first_dirty;
VARDEF int _pal_last_dirty;
VARDEF bool _use_dos_palette;
typedef struct Colour {
byte r;
byte g;
byte b;
} Colour;
extern Colour _cur_palette[256];
typedef enum StringColorFlags {
IS_PALETTE_COLOR = 0x100, // color value is already a real palette color index, not an index of a StringColor
} StringColorFlags;
#ifdef _DEBUG
extern bool _dbg_screen_rect;
#endif
#endif /* GFX_H */

382
gfxinit.c Normal file
View File

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

9
gfxinit.h Normal file
View File

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

1241
graph_gui.c Normal file

File diff suppressed because it is too large Load Diff

149
gui.h Normal file
View File

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

97
hal.h Normal file
View File

@@ -0,0 +1,97 @@
/* $Id$ */
#ifndef HAL_H
#define HAL_H
typedef struct {
const char *(*start)(const char * const *parm);
void (*stop)(void);
} HalCommonDriver;
typedef struct {
const char *(*start)(const char * const *parm);
void (*stop)(void);
void (*make_dirty)(int left, int top, int width, int height);
void (*main_loop)(void);
bool (*change_resolution)(int w, int h);
void (*toggle_fullscreen)(bool fullscreen);
} HalVideoDriver;
typedef struct {
const char *(*start)(const char * const *parm);
void (*stop)(void);
} HalSoundDriver;
typedef struct {
const char *(*start)(const char * const *parm);
void (*stop)(void);
void (*play_song)(const char *filename);
void (*stop_song)(void);
bool (*is_song_playing)(void);
void (*set_volume)(byte vol);
} HalMusicDriver;
VARDEF HalMusicDriver *_music_driver;
VARDEF HalSoundDriver *_sound_driver;
VARDEF HalVideoDriver *_video_driver;
enum DriverType {
VIDEO_DRIVER = 0,
SOUND_DRIVER = 1,
MUSIC_DRIVER = 2,
};
extern void GameLoop(void);
// Deals with finding savegames
typedef struct {
byte type;
uint64 mtime;
char title[64];
char name[256-12-64];
} FiosItem;
enum {
FIOS_TYPE_DRIVE = 0,
FIOS_TYPE_PARENT = 1,
FIOS_TYPE_DIR = 2,
FIOS_TYPE_FILE = 3,
FIOS_TYPE_OLDFILE = 4,
FIOS_TYPE_SCENARIO = 5,
FIOS_TYPE_OLD_SCENARIO = 6,
FIOS_TYPE_DIRECT = 7,
};
// Variables to display file lists
FiosItem *_fios_list;
int _fios_num;
int _saveload_mode;
// get the name of an oldstyle savegame
void GetOldSaveGameName(char *title, const char *file);
// get the name of an oldstyle scenario
void GetOldScenarioGameName(char *title, const char *file);
// Get a list of savegames
FiosItem *FiosGetSavegameList(int *num, int mode);
// Get a list of scenarios
FiosItem *FiosGetScenarioList(int *num, int mode);
// Free the list of savegames
void FiosFreeSavegameList(void);
// Browse to. Returns a filename w/path if we reached a file.
char *FiosBrowseTo(const FiosItem *item);
// Return path, free space and stringID
StringID FiosGetDescText(const char **path, uint32 *tot);
// Delete a name
bool FiosDelete(const char *name);
// Make a filename from a name
void FiosMakeSavegameName(char *buf, const char *name, size_t size);
int CDECL compare_FiosItems(const void *a, const void *b);
void CreateConsole(void);
#endif /* HAL_H */

110
industry.h Normal file
View File

@@ -0,0 +1,110 @@
/* $Id$ */
#ifndef INDUSTRY_H
#define INDUSTRY_H
#include "pool.h"
struct Industry {
TileIndex xy;
byte width; /* swapped order of w/h with town */
byte height;
const Town* town;
byte produced_cargo[2];
uint16 cargo_waiting[2];
byte production_rate[2];
byte accepts_cargo[3];
byte prod_level;
uint16 last_mo_production[2];
uint16 last_mo_transported[2];
byte pct_transported[2];
uint16 total_production[2];
uint16 total_transported[2];
uint16 counter;
byte type;
byte owner;
byte color_map;
byte last_prod_year;
byte was_cargo_delivered;
uint16 index;
};
extern MemoryPool _industry_pool;
/**
* Check if an Industry really exists.
*/
static inline bool IsValidIndustry(Industry* industry)
{
return industry->xy != 0; /* XXX: Replace by INVALID_TILE someday */
}
/**
* Get the pointer to the industry with index 'index'
*/
static inline Industry *GetIndustry(uint index)
{
return (Industry*)GetItemFromPool(&_industry_pool, index);
}
/**
* Get the current size of the IndustryPool
*/
static inline uint16 GetIndustryPoolSize(void)
{
return _industry_pool.total_items;
}
#define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1 < GetIndustryPoolSize()) ? GetIndustry(i->index + 1) : NULL)
#define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0)
VARDEF int _total_industries; // For the AI: the amount of industries active
VARDEF uint16 *_industry_sort;
VARDEF bool _industry_sort_dirty;
void DeleteIndustry(Industry *is);
enum {
IT_COAL_MINE = 0,
IT_POWER_STATION = 1,
IT_SAWMILL = 2,
IT_FOREST = 3,
IT_OIL_REFINERY = 4,
IT_OIL_RIG = 5,
IT_FACTORY = 6,
IT_PRINTING_WORKS = 7,
IT_STEEL_MILL = 8,
IT_FARM = 9,
IT_COPPER_MINE = 10,
IT_OIL_WELL = 11,
IT_BANK = 12,
IT_FOOD_PROCESS = 13,
IT_PAPER_MILL = 14,
IT_GOLD_MINE = 15,
IT_BANK_2 = 16,
IT_DIAMOND_MINE = 17,
IT_IRON_MINE = 18,
IT_FRUIT_PLANTATION = 19,
IT_RUBBER_PLANTATION = 20,
IT_WATER_SUPPLY = 21,
IT_WATER_TOWER = 22,
IT_FACTORY_2 = 23,
IT_FARM_2 = 24,
IT_LUMBER_MILL = 25,
IT_COTTON_CANDY = 26,
IT_CANDY_FACTORY = 27,
IT_BATTERY_FARM = 28,
IT_COLA_WELLS = 29,
IT_TOY_SHOP = 30,
IT_TOY_FACTORY = 31,
IT_PLASTIC_FOUNTAINS = 32,
IT_FIZZY_DRINK_FACTORY = 33,
IT_BUBBLE_GENERATOR = 34,
IT_TOFFEE_QUARRY = 35,
IT_SUGAR_MINE = 36,
};
#endif /* INDUSTRY_H */

1984
industry_cmd.c Normal file

File diff suppressed because it is too large Load Diff

688
industry_gui.c Normal file
View File

@@ -0,0 +1,688 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "functions.h"
#include "strings.h"
#include "table/strings.h"
#include "table/sprites.h"
#include "map.h"
#include "gui.h"
#include "window.h"
#include "gfx.h"
#include "command.h"
#include "viewport.h"
#include "industry.h"
#include "town.h"
#include "variables.h"
/* Present in table/build_industry.h" */
extern const byte _build_industry_types[4][12];
extern const byte _industry_type_costs[37];
static void UpdateIndustryProduction(Industry *i);
extern void DrawArrowButtons(int x, int y, int state);
static void BuildIndustryWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
if (_thd.place_mode == 1 && _thd.window_class == WC_BUILD_INDUSTRY) {
int ind_type = _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1];
SetDParam(0, (_price.build_industry >> 5) * _industry_type_costs[ind_type]);
DrawStringCentered(85, w->height - 21, STR_482F_COST, 0);
}
break;
case WE_CLICK: {
int wid = e->click.widget;
if (wid >= 3) {
if (HandlePlacePushButton(w, wid, SPR_CURSOR_INDUSTRY, 1, NULL))
WP(w,def_d).data_1 = wid - 3;
}
} break;
case WE_PLACE_OBJ:
if (DoCommandP(e->place.tile, _build_industry_types[_opt_ptr->landscape][WP(w,def_d).data_1], 0, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)))
ResetObjectToPlace();
break;
case WE_ABORT_PLACE_OBJ:
w->click_state = 0;
SetWindowDirty(w);
break;
}
}
static const Widget _build_industry_land0_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL},
{ WIDGETS_END},
};
static const Widget _build_industry_land1_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WIDGETS_END},
};
static const Widget _build_industry_land2_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WIDGETS_END},
};
static const Widget _build_industry_land3_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 115, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WIDGETS_END},
};
static const Widget _build_industry_land0_widgets_extra[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY,STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION,STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_0242_SAWMILL, STR_0264_CONSTRUCT_SAWMILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0247_STEEL_MILL, STR_0269_CONSTRUCT_STEEL_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 84, 95, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 97, 108, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 110, 121, STR_0245_OIL_RIG, STR_CONSTRUCT_OIL_RIG_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 123, 134, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 136, 147, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 149, 160, STR_0249_IRON_ORE_MINE, STR_CONSTRUCT_IRON_ORE_MINE_TIP},
{ WIDGETS_END},
};
static const Widget _build_industry_land1_widgets_extra[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 174, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0241_POWER_STATION, STR_0263_CONSTRUCT_POWER_STATION},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024C_PAPER_MILL, STR_026E_CONSTRUCT_PAPER_MILL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_024E_PRINTING_WORKS, STR_0270_CONSTRUCT_PRINTING_WORKS},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0240_COAL_MINE, STR_CONSTRUCT_COAL_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0243_FOREST, STR_CONSTRUCT_FOREST_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_024A_OIL_WELLS, STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_024F_GOLD_MINE, STR_CONSTRUCT_GOLD_MINE_TIP},
{ WIDGETS_END},
};
static const Widget _build_industry_land2_widgets_extra[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 200, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0250_LUMBER_MILL, STR_0273_CONSTRUCT_LUMBER_MILL_TO},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_024D_FOOD_PROCESSING_PLANT,STR_026F_CONSTRUCT_FOOD_PROCESSING},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_0244_OIL_REFINERY, STR_0266_CONSTRUCT_OIL_REFINERY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_0246_FACTORY, STR_0268_CONSTRUCT_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68, 79, STR_0254_WATER_TOWER, STR_0277_CONSTRUCT_WATER_TOWER_CAN},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_024A_OIL_WELLS,STR_CONSTRUCT_OIL_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_0255_DIAMOND_MINE, STR_CONSTRUCT_DIAMOND_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_0256_COPPER_ORE_MINE, STR_CONSTRUCT_COPPER_ORE_MINE_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_0248_FARM, STR_CONSTRUCT_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0251_FRUIT_PLANTATION, STR_CONSTRUCT_FRUIT_PLANTATION_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0252_RUBBER_PLANTATION,STR_CONSTRUCT_RUBBER_PLANTATION_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 159+3, 170+3, STR_0253_WATER_SUPPLY, STR_CONSTRUCT_WATER_SUPPLY_TIP},
{ WIDGETS_END},
};
static const Widget _build_industry_land3_widgets_extra[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 169, 14, 187, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 16, 27, STR_0258_CANDY_FACTORY, STR_027B_CONSTRUCT_CANDY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 29, 40, STR_025B_TOY_SHOP, STR_027E_CONSTRUCT_TOY_SHOP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 42, 53, STR_025C_TOY_FACTORY, STR_027F_CONSTRUCT_TOY_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 55, 66, STR_025E_FIZZY_DRINK_FACTORY, STR_0281_CONSTRUCT_FIZZY_DRINK_FACTORY},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 68+3, 79+3, STR_0257_COTTON_CANDY_FOREST,STR_CONSTRUCT_COTTON_CANDY_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 81+3, 92+3, STR_0259_BATTERY_FARM, STR_CONSTRUCT_BATTERY_FARM_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 94+3, 105+3, STR_025A_COLA_WELLS, STR_CONSTRUCT_COLA_WELLS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 107+3, 118+3, STR_025D_PLASTIC_FOUNTAINS,STR_CONSTRUCT_PLASTIC_FOUNTAINS_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 120+3, 131+3, STR_025F_BUBBLE_GENERATOR, STR_CONSTRUCT_BUBBLE_GENERATOR_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 133+3, 144+3, STR_0260_TOFFEE_QUARRY, STR_CONSTRUCT_TOFFEE_QUARRY_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 167, 146+3, 157+3, STR_0261_SUGAR_MINE, STR_CONSTRUCT_SUGAR_MINE_TIP},
{ WIDGETS_END},
};
static const WindowDesc _build_industry_land0_desc = {
-1, -1, 170, 116,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land0_widgets,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land1_desc = {
-1, -1, 170, 116,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land1_widgets,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land2_desc = {
-1, -1, 170, 116,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land2_widgets,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land3_desc = {
-1, -1, 170, 116,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land3_widgets,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land0_desc_extra = {
-1, -1, 170, 188,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land0_widgets_extra,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land1_desc_extra = {
-1, -1, 170, 175,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land1_widgets_extra,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land2_desc_extra = {
-1, -1, 170, 201,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land2_widgets_extra,
BuildIndustryWndProc
};
static const WindowDesc _build_industry_land3_desc_extra = {
-1, -1, 170, 188,
WC_BUILD_INDUSTRY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_industry_land3_widgets_extra,
BuildIndustryWndProc
};
static const WindowDesc * const _industry_window_desc[2][4] = {
{
&_build_industry_land0_desc,
&_build_industry_land1_desc,
&_build_industry_land2_desc,
&_build_industry_land3_desc,
},
{
&_build_industry_land0_desc_extra,
&_build_industry_land1_desc_extra,
&_build_industry_land2_desc_extra,
&_build_industry_land3_desc_extra,
},
};
void ShowBuildIndustryWindow(void)
{
if (_current_player == OWNER_SPECTATOR) return;
AllocateWindowDescFront(_industry_window_desc[_patches.build_rawmaterial_ind][_opt_ptr->landscape],0);
}
#define NEED_ALTERB ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES))
static void IndustryViewWndProc(Window *w, WindowEvent *e)
{
// WP(w,vp2_d).data_1 is for the editbox line
// WP(w,vp2_d).data_2 is for the clickline
// WP(w,vp2_d).data_3 is for the click pos (left or right)
switch(e->event) {
case WE_PAINT: {
const Industry *i;
StringID str;
i = GetIndustry(w->window_number);
SetDParam(0, w->window_number);
DrawWindowWidgets(w);
if (i->accepts_cargo[0] != CT_INVALID) {
SetDParam(0, _cargoc.names_s[i->accepts_cargo[0]]);
str = STR_4827_REQUIRES;
if (i->accepts_cargo[1] != CT_INVALID) {
SetDParam(1, _cargoc.names_s[i->accepts_cargo[1]]);
str++;
if (i->accepts_cargo[2] != CT_INVALID) {
SetDParam(2, _cargoc.names_s[i->accepts_cargo[2]]);
str++;
}
}
DrawString(2, 107, str, 0);
}
if (i->produced_cargo[0] != CT_INVALID) {
DrawString(2, 117, STR_482A_PRODUCTION_LAST_MONTH, 0);
SetDParam(0, _cargoc.names_long[i->produced_cargo[0]]);
SetDParam(1, i->total_production[0]);
SetDParam(2, i->pct_transported[0] * 100 >> 8);
DrawString(4 + (NEED_ALTERB ? 30 : 0), 127, STR_482B_TRANSPORTED, 0);
// Let's put out those buttons..
if (NEED_ALTERB)
DrawArrowButtons(5, 127, (WP(w,vp2_d).data_2 == 1 ? WP(w,vp2_d).data_3 : 0));
if (i->produced_cargo[1] != CT_INVALID) {
SetDParam(0, _cargoc.names_long[i->produced_cargo[1]]);
SetDParam(1, i->total_production[1]);
SetDParam(2, i->pct_transported[1] * 100 >> 8);
DrawString(4 + (NEED_ALTERB ? 30 : 0), 137, STR_482B_TRANSPORTED, 0);
// Let's put out those buttons..
if (NEED_ALTERB)
DrawArrowButtons(5, 137, (WP(w,vp2_d).data_2 == 2 ? WP(w,vp2_d).data_3 : 0));
}
}
DrawWindowViewport(w);
}
break;
case WE_CLICK: {
Industry *i;
switch(e->click.widget) {
case 5: {
int line;
int x;
byte b;
i = GetIndustry(w->window_number);
// We should work if needed..
if (!NEED_ALTERB)
return;
x = e->click.pt.x;
line = (e->click.pt.y - 127) / 10;
if (e->click.pt.y >= 127 && IS_INT_INSIDE(line, 0, 2) && i->produced_cargo[line]) {
if (IS_INT_INSIDE(x, 5, 25) ) {
// clicked buttons
if (x < 15) {
// decrease
i->production_rate[line] /= 2;
if (i->production_rate[line] < 4)
i->production_rate[line] = 4;
} else {
// increase
b = i->production_rate[line] * 2;
if (i->production_rate[line] >= 128)
b=255;
i->production_rate[line] = b;
}
UpdateIndustryProduction(i);
SetWindowDirty(w);
w->flags4 |= 5 << WF_TIMEOUT_SHL;
WP(w,vp2_d).data_2 = line+1;
WP(w,vp2_d).data_3 = (x < 15 ? 1 : 2);
} else if (IS_INT_INSIDE(x, 34, 160)) {
// clicked the text
WP(w,vp2_d).data_1 = line;
SetDParam(0, i->production_rate[line] * 8);
ShowQueryString(STR_CONFIG_PATCHES_INT32,
STR_CONFIG_GAME_PRODUCTION,
10, 100, w->window_class,
w->window_number);
}
}
}
break;
case 6:
i = GetIndustry(w->window_number);
ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1));
break;
}
}
break;
case WE_TIMEOUT:
WP(w,vp2_d).data_2 = 0;
WP(w,vp2_d).data_3 = 0;
SetWindowDirty(w);
break;
case WE_ON_EDIT_TEXT:
if (*e->edittext.str) {
Industry *i;
int val;
int line;
i = GetIndustry(w->window_number);
line = WP(w,vp2_d).data_1;
val = atoi(e->edittext.str);
if (!IS_INT_INSIDE(val, 32, 2040)) {
if (val < 32) val = 32;
else val = 2040;
}
i->production_rate[line] = (byte)(val / 8);
UpdateIndustryProduction(i);
SetWindowDirty(w);
}
}
}
static void UpdateIndustryProduction(Industry *i)
{
if (i->produced_cargo[0] != CT_INVALID)
i->total_production[0] = 8 * i->production_rate[0];
if (i->produced_cargo[1] != CT_INVALID)
i->total_production[1] = 8 * i->production_rate[1];
}
static const Widget _industry_view_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 9, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 9, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 9, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 14, 105, 0x0, STR_NULL},
{ WWT_6, RESIZE_NONE, 9, 2, 257, 16, 103, 0x0, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 9, 0, 259, 106, 147, 0x0, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 9, 0, 129, 148, 159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
{ WWT_IMGBTN, RESIZE_NONE, 9, 130, 259, 148, 159, 0x0, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _industry_view_desc = {
-1, -1, 260, 160,
WC_INDUSTRY_VIEW,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_industry_view_widgets,
IndustryViewWndProc
};
void ShowIndustryViewWindow(int industry)
{
Window *w;
Industry *i;
w = AllocateWindowDescFront(&_industry_view_desc, industry);
if (w) {
w->flags4 |= WF_DISABLE_VP_SCROLL;
WP(w,vp2_d).data_1 = 0;
WP(w,vp2_d).data_2 = 0;
WP(w,vp2_d).data_3 = 0;
i = GetIndustry(w->window_number);
AssignWindowViewport(w, 3, 17, 0xFE, 0x56, i->xy + TileDiffXY(1, 1), 1);
}
}
static const Widget _industry_directory_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 13, 11, 495, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_NONE, 13, 496, 507, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 100, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 101, 200, 14, 25, STR_SORT_BY_TYPE, STR_SORT_ORDER_TIP},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 201, 300, 14, 25, STR_SORT_BY_PRODUCTION, STR_SORT_ORDER_TIP},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 13, 301, 400, 14, 25, STR_SORT_BY_TRANSPORTED, STR_SORT_ORDER_TIP},
{ WWT_PANEL, RESIZE_NONE, 13, 401, 495, 14, 25, 0x0, STR_NULL},
{ WWT_IMGBTN, RESIZE_BOTTOM, 13, 0, 495, 26, 189, 0x0, STR_200A_TOWN_NAMES_CLICK_ON_NAME},
{ WWT_SCROLLBAR, RESIZE_BOTTOM, 13, 496, 507, 14, 177, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_RESIZEBOX, RESIZE_TB, 13, 496, 507, 178, 189, 0x0, STR_RESIZE_BUTTON},
{ WIDGETS_END},
};
static uint _num_industry_sort;
static char _bufcache[96];
static uint16 _last_industry_idx;
static byte _industry_sort_order;
static int CDECL GeneralIndustrySorter(const void *a, const void *b)
{
char buf1[96];
uint16 val;
Industry *i = GetIndustry(*(const uint16*)a);
Industry *j = GetIndustry(*(const uint16*)b);
int r = 0;
switch (_industry_sort_order >> 1) {
/* case 0: Sort by Name (handled later) */
case 1: /* Sort by Type */
r = i->type - j->type;
break;
// FIXME - Production & Transported sort need to be inversed...but, WTF it does not wanna!
// FIXME - And no simple --> "if (!(_industry_sort_order & 1)) r = -r;" hack at the bottom!!
case 2: { /* Sort by Production */
if (i->produced_cargo[0] != CT_INVALID && j->produced_cargo[0] != CT_INVALID) { // both industries produce cargo?
if (i->produced_cargo[1] == CT_INVALID) // producing one or two things?
r = j->total_production[0] - i->total_production[0];
else
r = (j->total_production[0] + j->total_production[1]) / 2 - (i->total_production[0] + i->total_production[1]) / 2;
} else if (i->produced_cargo[0] == CT_INVALID && j->produced_cargo[0] == CT_INVALID) // none of them producing anything, let them go to the name-sorting
r = 0;
else if (i->produced_cargo[0] == CT_INVALID) // end up the non-producer industry first/last in list
r = 1;
else
r = -1;
break;
}
case 3: /* Sort by Transported amount */
if (i->produced_cargo[0] != CT_INVALID && j->produced_cargo[0] != CT_INVALID) { // both industries produce cargo?
if (i->produced_cargo[1] == CT_INVALID) // producing one or two things?
r = (j->pct_transported[0] * 100 >> 8) - (i->pct_transported[0] * 100 >> 8);
else
r = ((j->pct_transported[0] * 100 >> 8) + (j->pct_transported[1] * 100 >> 8)) / 2 - ((i->pct_transported[0] * 100 >> 8) + (i->pct_transported[1] * 100 >> 8)) / 2;
} else if (i->produced_cargo[0] == CT_INVALID && j->produced_cargo[0] == CT_INVALID) // none of them producing anything, let them go to the name-sorting
r = 0;
else if (i->produced_cargo[0] == CT_INVALID) // end up the non-producer industry first/last in list
r = 1;
else
r = -1;
break;
}
// default to string sorting if they are otherwise equal
if (r == 0) {
SetDParam(0, i->town->index);
GetString(buf1, STR_TOWN);
if ( (val=*(const uint16*)b) != _last_industry_idx) {
_last_industry_idx = val;
SetDParam(0, j->town->index);
GetString(_bufcache, STR_TOWN);
}
r = strcmp(buf1, _bufcache);
}
if (_industry_sort_order & 1) r = -r;
return r;
}
static void MakeSortedIndustryList(void)
{
Industry *i;
int n = 0;
/* Create array for sorting */
_industry_sort = realloc(_industry_sort, GetIndustryPoolSize() * sizeof(_industry_sort[0]));
if (_industry_sort == NULL)
error("Could not allocate memory for the industry-sorting-list");
FOR_ALL_INDUSTRIES(i) {
if(i->xy)
_industry_sort[n++] = i->index;
}
_num_industry_sort = n;
_last_industry_idx = 0xFFFF; // used for "cache"
qsort(_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
DEBUG(misc, 1) ("Resorting Industries list...");
}
static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
case WE_PAINT: {
int n;
uint p;
Industry *i;
static const uint16 _indicator_positions[4] = {88, 187, 284, 387};
if (_industry_sort_dirty) {
_industry_sort_dirty = false;
MakeSortedIndustryList();
}
SetVScrollCount(w, _num_industry_sort);
DrawWindowWidgets(w);
DoDrawString(_industry_sort_order & 1 ? DOWNARROW : UPARROW, _indicator_positions[_industry_sort_order>>1], 15, 0x10);
p = w->vscroll.pos;
n = 0;
while (p < _num_industry_sort) {
i = GetIndustry(_industry_sort[p]);
SetDParam(0, i->index);
if (i->produced_cargo[0] != CT_INVALID) {
SetDParam(1, _cargoc.names_long[i->produced_cargo[0]]);
SetDParam(2, i->total_production[0]);
if (i->produced_cargo[1] != CT_INVALID) {
SetDParam(3, _cargoc.names_long[i->produced_cargo[1]]);
SetDParam(4, i->total_production[1]);
SetDParam(5, i->pct_transported[0] * 100 >> 8);
SetDParam(6, i->pct_transported[1] * 100 >> 8);
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_TWO, 0);
} else {
SetDParam(3, i->pct_transported[0] * 100 >> 8);
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM, 0);
}
} else {
DrawString(4, 28+n*10, STR_INDUSTRYDIR_ITEM_NOPROD, 0);
}
p++;
if (++n == w->vscroll.cap)
break;
}
} break;
case WE_CLICK:
switch(e->click.widget) {
case 3: {
_industry_sort_order = _industry_sort_order==0 ? 1 : 0;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 4: {
_industry_sort_order = _industry_sort_order==2 ? 3 : 2;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 5: {
_industry_sort_order = _industry_sort_order==4 ? 5 : 4;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 6: {
_industry_sort_order = _industry_sort_order==6 ? 7 : 6;
_industry_sort_dirty = true;
SetWindowDirty(w);
} break;
case 8: {
int y = (e->click.pt.y - 28) / 10;
uint16 p;
Industry *c;
if (!IS_INT_INSIDE(y, 0, w->vscroll.cap))
return;
p = y + w->vscroll.pos;
if (p < _num_industry_sort) {
c = GetIndustry(_industry_sort[p]);
ScrollMainWindowToTile(c->xy);
}
} break;
}
break;
case WE_4:
SetWindowDirty(w);
break;
case WE_RESIZE:
w->vscroll.cap += e->sizing.diff.y / 10;
break;
}
}
/* Industry List */
static const WindowDesc _industry_directory_desc = {
-1, -1, 508, 190,
WC_INDUSTRY_DIRECTORY,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_industry_directory_widgets,
IndustryDirectoryWndProc
};
void ShowIndustryDirectory(void)
{
/* Industry List */
Window *w;
w = AllocateWindowDescFront(&_industry_directory_desc, 0);
if (w) {
w->vscroll.cap = 16;
w->resize.height = w->height - 6 * 10; // minimum 10 items
w->resize.step_height = 10;
SetWindowDirty(w);
}
}

256
intro_gui.c Normal file
View File

@@ -0,0 +1,256 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "window.h"
#include "gui.h"
#include "gfx.h"
#include "player.h"
#include "network.h"
#include "variables.h"
extern void SwitchMode(int new_mode);
static const Widget _select_game_widgets[] = {
{ WWT_CAPTION, RESIZE_NONE, 13, 0, 335, 0, 13, STR_0307_OPENTTD, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 13, 0, 335, 14, 196, STR_NULL, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 22, 33, STR_0140_NEW_GAME, STR_02FB_START_A_NEW_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 22, 33, STR_0141_LOAD_GAME, STR_02FC_LOAD_A_SAVED_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 40, 51, STR_0220_CREATE_SCENARIO,STR_02FE_CREATE_A_CUSTOMIZED_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 40, 51, STR_029A_PLAY_SCENARIO, STR_0303_START_A_NEW_GAME_USING},
{ WWT_PANEL_2, RESIZE_NONE, 12, 10, 86, 59, 113, 0x1312, STR_030E_SELECT_TEMPERATE_LANDSCAPE},
{ WWT_PANEL_2, RESIZE_NONE, 12, 90, 166, 59, 113, 0x1314, STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},
{ WWT_PANEL_2, RESIZE_NONE, 12, 170, 246, 59, 113, 0x1316, STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE},
{ WWT_PANEL_2, RESIZE_NONE, 12, 250, 326, 59, 113, 0x1318, STR_0311_SELECT_TOYLAND_LANDSCAPE},
{ WWT_PANEL, RESIZE_NONE, 12, 219, 254, 120, 131, STR_NULL, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 255, 266, 120, 131, STR_0225, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 12, 279, 314, 120, 131, STR_NULL, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 315, 326, 120, 131, STR_0225, STR_NULL},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 138, 149, STR_SINGLE_PLAYER, STR_02FF_SELECT_SINGLE_PLAYER_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 138, 149, STR_MULTIPLAYER, STR_0300_SELECT_MULTIPLAYER_GAME},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 159, 170, STR_0148_GAME_OPTIONS, STR_0301_DISPLAY_GAME_OPTIONS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 159, 170, STR_01FE_DIFFICULTY, STR_0302_DISPLAY_DIFFICULTY_OPTIONS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 10, 167, 177, 188, STR_CONFIG_PATCHES, STR_CONFIG_PATCHES_TIP},
{ WWT_PUSHTXTBTN, RESIZE_NONE, 12, 168, 325, 177, 188, STR_0304_QUIT, STR_0305_QUIT_OPENTTD},
{ WIDGETS_END },
};
extern void HandleOnEditText(WindowEvent *e);
extern void HandleOnEditTextCancel(void);
static inline void CreateScenario(void) {_switch_mode = SM_EDITOR;}
static inline void SetNewLandscapeType(byte landscape)
{
_opt_newgame.landscape = landscape;
InvalidateWindowClasses(WC_SELECT_GAME);
}
static void SelectGameWndProc(Window *w, WindowEvent *e)
{
/* We do +/- 6 for the map_xy because 64 is 2^6, but it is the lowest available element */
static const StringID mapsizes[] = {STR_64, STR_128, STR_256, STR_512, STR_1024, STR_2048, INVALID_STRING_ID};
switch (e->event) {
case WE_PAINT:
w->click_state = (w->click_state & ~(1 << 14) & ~(0xF << 6)) | (1 << (_opt_newgame.landscape + 6)) | (1 << 14);
SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
DrawWindowWidgets(w);
DrawStringRightAligned(216, 121, STR_MAPSIZE, 0);
DrawString(223, 121, mapsizes[_patches.map_x - 6], 0x10);
DrawString(270, 121, STR_BY, 0);
DrawString(283, 121, mapsizes[_patches.map_y - 6], 0x10);
break;
case WE_CLICK:
switch (e->click.widget) {
case 2: AskForNewGameToStart(); break;
case 3: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
case 4: CreateScenario(); break;
case 5: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
case 6: case 7: case 8: case 9:
SetNewLandscapeType(e->click.widget - 6);
break;
case 10: case 11: /* Mapsize X */
ShowDropDownMenu(w, mapsizes, _patches.map_x - 6, 11, 0, 0);
break;
case 12: case 13: /* Mapsize Y */
ShowDropDownMenu(w, mapsizes, _patches.map_y - 6, 13, 0, 0);
break;
case 15:
#ifdef ENABLE_NETWORK
if (!_network_available) {
ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
} else
ShowNetworkGameWindow();
#else
ShowErrorMessage(INVALID_STRING_ID ,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
#endif
break;
case 16: ShowGameOptions(); break;
case 17: ShowGameDifficulty(); break;
case 18: ShowPatchesSelection(); break;
case 19: AskExitGame(); break;
}
break;
case WE_ON_EDIT_TEXT: HandleOnEditText(e); break;
case WE_ON_EDIT_TEXT_CANCEL: HandleOnEditTextCancel(); break;
case WE_DROPDOWN_SELECT: /* Mapsize selection */
switch (e->dropdown.button) {
case 11: _patches.map_x = e->dropdown.index + 6; break;
case 13: _patches.map_y = e->dropdown.index + 6; break;
}
SetWindowDirty(w);
break;
}
}
static const WindowDesc _select_game_desc = {
WDP_CENTER, WDP_CENTER, 336, 197,
WC_SELECT_GAME,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_select_game_widgets,
SelectGameWndProc
};
void ShowSelectGameWindow(void)
{
AllocateWindowDesc(&_select_game_desc);
}
void GenRandomNewGame(uint32 rnd1, uint32 rnd2)
{
_random_seeds[0][0] = rnd1;
_random_seeds[0][1] = rnd2;
SwitchMode(SM_NEWGAME);
}
void StartScenarioEditor(uint32 rnd1, uint32 rnd2)
{
_random_seeds[0][0] = rnd1;
_random_seeds[0][1] = rnd2;
SwitchMode(SM_START_SCENARIO);
}
static const Widget _ask_abandon_game_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_00C7_QUIT, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL},
{ WIDGETS_END },
};
static void AskAbandonGameWndProc(Window* w, WindowEvent* e)
{
switch (e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
#if defined(_WIN32)
SetDParam(0, STR_0133_WINDOWS);
#elif defined(__APPLE__)
SetDParam(0, STR_0135_OSX);
#elif defined(__BEOS__)
SetDParam(0, STR_OSNAME_BEOS);
#elif defined(__MORPHOS__)
SetDParam(0, STR_OSNAME_MORPHOS);
#elif defined(__AMIGA__)
SetDParam(0, STR_OSNAME_AMIGAOS);
#elif defined(__OS2__)
SetDParam(0, STR_OSNAME_OS2);
#else
SetDParam(0, STR_0134_UNIX);
#endif
DrawStringMultiCenter(90, 38, STR_00CA_ARE_YOU_SURE_YOU_WANT_TO, 178);
return;
case WE_CLICK:
switch (e->click.widget) {
case 3: DeleteWindow(w); break;
case 4: _exit_game = true; break;
}
break;
case WE_KEYPRESS: /* Exit game on pressing 'Enter' */
switch (e->keypress.keycode) {
case WKC_RETURN:
case WKC_NUM_ENTER:
_exit_game = true;
break;
}
break;
}
}
static const WindowDesc _ask_abandon_game_desc = {
WDP_CENTER, WDP_CENTER, 180, 92,
WC_ASK_ABANDON_GAME,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
_ask_abandon_game_widgets,
AskAbandonGameWndProc
};
void AskExitGame(void)
{
AllocateWindowDescFront(&_ask_abandon_game_desc, 0);
}
static const Widget _ask_quit_game_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 179, 0, 13, STR_0161_QUIT_GAME, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 4, 0, 179, 14, 91, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 25, 84, 72, 83, STR_00C9_NO, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 12, 95, 154, 72, 83, STR_00C8_YES, STR_NULL},
{ WIDGETS_END },
};
static void AskQuitGameWndProc(Window* w, WindowEvent* e)
{
switch (e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
DrawStringMultiCenter(
90, 38,
_game_mode != GM_EDITOR ?
STR_0160_ARE_YOU_SURE_YOU_WANT_TO : STR_029B_ARE_YOU_SURE_YOU_WANT_TO,
178
);
break;
case WE_CLICK:
switch (e->click.widget) {
case 3: DeleteWindow(w); break;
case 4: _switch_mode = SM_MENU; break;
}
break;
case WE_KEYPRESS: /* Return to main menu on pressing 'Enter' */
if (e->keypress.keycode == WKC_RETURN) _switch_mode = SM_MENU;
break;
}
}
static const WindowDesc _ask_quit_game_desc = {
WDP_CENTER, WDP_CENTER, 180, 92,
WC_QUIT_GAME,0,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
_ask_quit_game_widgets,
AskQuitGameWndProc
};
void AskExitToGameMenu(void)
{
AllocateWindowDescFront(&_ask_quit_game_desc, 0);
}

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